@@ -6,7 +6,7 @@ use num_traits::Float;
6
6
7
7
use crate :: algorithm:: winding_order:: twice_signed_ring_area;
8
8
9
- /// Signed planar area of a geometry.
9
+ /// Signed and unsigned planar area of a geometry.
10
10
///
11
11
/// # Examples
12
12
///
@@ -88,16 +88,31 @@ where
88
88
}
89
89
}
90
90
91
+ /// **Note.** The implementation handles polygons whose
92
+ /// holes do not all have the same orientation. The sign of
93
+ /// the output is the same as that of the exterior shell.
91
94
impl < T > Area < T > for Polygon < T >
92
95
where
93
96
T : Float ,
94
97
{
95
98
fn signed_area ( & self ) -> T {
96
- self . interiors ( )
99
+ let area = get_linestring_area ( self . exterior ( ) ) ;
100
+
101
+ // We could use winding order here, but that would
102
+ // result in computing the shoelace formula twice.
103
+ let is_negative = area < T :: zero ( ) ;
104
+
105
+ let area = self . interiors ( )
97
106
. iter ( )
98
- . fold ( get_linestring_area ( self . exterior ( ) ) , |total, next| {
99
- total - get_linestring_area ( next)
100
- } )
107
+ . fold ( area. abs ( ) , |total, next| {
108
+ total - get_linestring_area ( next) . abs ( )
109
+ } ) ;
110
+
111
+ if is_negative {
112
+ -area
113
+ } else {
114
+ area
115
+ }
101
116
}
102
117
103
118
fn unsigned_area ( & self ) -> T {
@@ -131,6 +146,12 @@ where
131
146
}
132
147
}
133
148
149
+ /// **Note.** The implementation is a straight-forward
150
+ /// summation of the signed areas of the individual
151
+ /// polygons. In particular, `unsigned_area` is not
152
+ /// necessarily the sum of the `unsigned_area` of the
153
+ /// constituent polygons unless they are all oriented the
154
+ /// same.
134
155
impl < T > Area < T > for MultiPolygon < T >
135
156
where
136
157
T : Float ,
@@ -406,4 +427,102 @@ mod test {
406
427
407
428
assert_eq ! ( polygon_area * 2. , multi_polygon. unsigned_area( ) ) ;
408
429
}
430
+
431
+ #[ test]
432
+ fn area_north_america_cutout ( ) {
433
+ let poly = polygon ! [
434
+ exterior: [
435
+ ( x: -102.902861858977 , y: 31.6943450891131 ) ,
436
+ ( x: -102.917375513247 , y: 31.6990175356827 ) ,
437
+ ( x: -102.917887344527 , y: 31.7044889522597 ) ,
438
+ ( x: -102.938892711173 , y: 31.7032871894594 ) ,
439
+ ( x: -102.939919687305 , y: 31.7142296141915 ) ,
440
+ ( x: -102.946922353444 , y: 31.713828170995 ) ,
441
+ ( x: -102.954642979004 , y: 31.7210594956594 ) ,
442
+ ( x: -102.960927457803 , y: 31.7130240707676 ) ,
443
+ ( x: -102.967929895872 , y: 31.7126214137469 ) ,
444
+ ( x: -102.966383373178 , y: 31.6962079209847 ) ,
445
+ ( x: -102.973384192133 , y: 31.6958049292994 ) ,
446
+ ( x: -102.97390013779 , y: 31.701276160078 ) ,
447
+ ( x: -102.980901394769 , y: 31.7008727405409 ) ,
448
+ ( x: -102.987902575456 , y: 31.7004689164622 ) ,
449
+ ( x: -102.986878877087 , y: 31.7127206248263 ) ,
450
+ ( x: -102.976474089689 , y: 31.7054378797983 ) ,
451
+ ( x: -102.975448432121 , y: 31.7176893134691 ) ,
452
+ ( x: -102.96619351228 , y: 31.7237224912303 ) ,
453
+ ( x: -102.976481009643 , y: 31.7286309669534 ) ,
454
+ ( x: -102.976997412845 , y: 31.7341016591658 ) ,
455
+ ( x: -102.978030448215 , y: 31.7450427747035 ) ,
456
+ ( x: -102.985035821671 , y: 31.7446391683265 ) ,
457
+ ( x: -102.985552968771 , y: 31.7501095683386 ) ,
458
+ ( x: -102.992558780682 , y: 31.7497055338313 ) ,
459
+ ( x: -102.993594334215 , y: 31.7606460184322 ) ,
460
+ ( x: -102.973746840657 , y: 31.7546100958509 ) ,
461
+ ( x: -102.966082339116 , y: 31.767730116605 ) ,
462
+ ( x: -102.959074676589 , y: 31.768132602064 ) ,
463
+ ( x: -102.95206693787 , y: 31.7685346826851 ) ,
464
+ ( x: -102.953096767614 , y: 31.7794749110023 ) ,
465
+ ( x: -102.953611796704 , y: 31.7849448911322 ) ,
466
+ ( x: -102.952629078076 , y: 31.7996518517642 ) ,
467
+ ( x: -102.948661251495 , y: 31.8072257578725 ) ,
468
+ ( x: -102.934638176282 , y: 31.8080282207231 ) ,
469
+ ( x: -102.927626524626 , y: 31.8084288446215 ) ,
470
+ ( x: -102.927113253813 , y: 31.8029591283411 ) ,
471
+ ( x: -102.920102042027 , y: 31.8033593239799 ) ,
472
+ ( x: -102.919076759513 , y: 31.792419577395 ) ,
473
+ ( x: -102.912066503301 , y: 31.7928193216213 ) ,
474
+ ( x: -102.911554491357 , y: 31.7873492912889 ) ,
475
+ ( x: -102.904544675025 , y: 31.7877486073783 ) ,
476
+ ( x: -102.904033254331 , y: 31.7822784646103 ) ,
477
+ ( x: -102.903521909259 , y: 31.7768082325431 ) ,
478
+ ( x: -102.895800463718 , y: 31.7695748336589 ) ,
479
+ ( x: -102.889504111843 , y: 31.7776055573633 ) ,
480
+ ( x: -102.882495099915 , y: 31.7780036124077 ) ,
481
+ ( x: -102.868476849997 , y: 31.7787985077398 ) ,
482
+ ( x: -102.866950998738 , y: 31.7623869292283 ) ,
483
+ ( x: -102.873958615171 , y: 31.7619897531194 ) ,
484
+ ( x: -102.87888647278 , y: 31.7688910039026 ) ,
485
+ ( x: -102.879947237315 , y: 31.750650764952 ) ,
486
+ ( x: -102.886953672823 , y: 31.750252825268 ) ,
487
+ ( x: -102.89396003296 , y: 31.7498544807869 ) ,
488
+ ( x: -102.892939355062 , y: 31.7389128078806 ) ,
489
+ ( x: -102.913954892669 , y: 31.7377154844276 ) ,
490
+ ( x: -102.913443122277 , y: 31.7322445829725 ) ,
491
+ ( x: -102.912931427507 , y: 31.7267735918962 ) ,
492
+ ( x: -102.911908264767 , y: 31.7158313407426 ) ,
493
+ ( x: -102.904905220014 , y: 31.7162307607961 ) ,
494
+ ( x: -102.904394266551 , y: 31.7107594775392 ) ,
495
+ ( x: -102.903372586049 , y: 31.6998166417321 ) ,
496
+ ( x: -102.902861858977 , y: 31.6943450891131 ) ,
497
+ ] ,
498
+ interiors: [
499
+ [
500
+ ( x: -102.916514879554 , y: 31.7650686485918 ) ,
501
+ ( x: -102.921022256876 , y: 31.7770831833398 ) ,
502
+ ( x: -102.93367363719 , y: 31.771184865332 ) ,
503
+ ( x: -102.916514879554 , y: 31.7650686485918 ) ,
504
+ ] ,
505
+ [
506
+ ( x: -102.935483140202 , y: 31.7419852607081 ) ,
507
+ ( x: -102.932452314332 , y: 31.7328567234689 ) ,
508
+ ( x: -102.918345099146 , y: 31.7326099897391 ) ,
509
+ ( x: -102.925566322952 , y: 31.7552505533503 ) ,
510
+ ( x: -102.928990700436 , y: 31.747856686604 ) ,
511
+ ( x: -102.935996606762 , y: 31.7474559134477 ) ,
512
+ ( x: -102.939021176592 , y: 31.7539885279379 ) ,
513
+ ( x: -102.944714388971 , y: 31.7488395547293 ) ,
514
+ ( x: -102.935996606762 , y: 31.7474559134477 ) ,
515
+ ( x: -102.935483140202 , y: 31.7419852607081 ) ,
516
+ ] ,
517
+ [
518
+ ( x: -102.956498858767 , y: 31.7407805824758 ) ,
519
+ ( x: -102.960959476367 , y: 31.7475080456347 ) ,
520
+ ( x: -102.972817445204 , y: 31.742072061889 ) ,
521
+ ( x: -102.956498858767 , y: 31.7407805824758 ) ,
522
+ ]
523
+ ] ,
524
+ ] ;
525
+ // Value from shapely
526
+ assert_relative_eq ! ( poly. unsigned_area( ) , 0.006547948219252177 , max_relative = 0.0001 ) ;
527
+ }
409
528
}
0 commit comments