1
- import rbush from "rbush" ;
2
- import union from "@turf/union" ;
3
- import { polygon , featureCollection } from "@turf/helpers" ;
4
- import turfBBox from "@turf/bbox" ;
5
- import { flattenEach } from "@turf/meta" ;
1
+ import { polygon as createPolygon , multiPolygon } from "@turf/helpers" ;
2
+ import polygonClipping from "polygon-clipping" ;
6
3
7
4
/**
8
5
* Takes any type of {@link Polygon|polygon} and an optional mask and returns a {@link Polygon|polygon} exterior ring with holes.
@@ -24,63 +21,38 @@ function mask(polygon, mask) {
24
21
// Define mask
25
22
var maskPolygon = createMask ( mask ) ;
26
23
27
- // Define polygon
28
- var separated = separatePolygons ( polygon ) ;
29
- var polygonOuters = separated [ 0 ] ;
30
- var polygonInners = separated [ 1 ] ;
24
+ var polygonOuters = null ;
25
+ if ( polygon . type === "FeatureCollection" ) polygonOuters = unionFc ( polygon ) ;
26
+ else
27
+ polygonOuters = createGeomFromPolygonClippingOutput (
28
+ polygonClipping . union ( polygon . geometry . coordinates )
29
+ ) ;
31
30
32
- // Union Outers & Inners
33
- polygonOuters = unionPolygons ( polygonOuters ) ;
34
- polygonInners = unionPolygons ( polygonInners ) ;
31
+ polygonOuters . geometry . coordinates . forEach ( function ( contour ) {
32
+ maskPolygon . geometry . coordinates . push ( contour [ 0 ] ) ;
33
+ } ) ;
35
34
36
- // Create masked area
37
- var masked = buildMask ( maskPolygon , polygonOuters , polygonInners ) ;
38
- return masked ;
35
+ return maskPolygon ;
39
36
}
40
37
41
- /**
42
- * Build Mask
43
- *
44
- * @private
45
- * @param {Feature<Polygon> } maskPolygon Mask Outer
46
- * @param {FeatureCollection<Polygon> } polygonOuters Polygon Outers
47
- * @param {FeatureCollection<Polygon> } polygonInners Polygon Inners
48
- * @returns {Feature<Polygon> } Feature Polygon
49
- */
50
- function buildMask ( maskPolygon , polygonOuters , polygonInners ) {
51
- var coordinates = [ ] ;
52
- coordinates . push ( maskPolygon . geometry . coordinates [ 0 ] ) ;
53
-
54
- flattenEach ( polygonOuters , function ( feature ) {
55
- coordinates . push ( feature . geometry . coordinates [ 0 ] ) ;
56
- } ) ;
57
-
58
- flattenEach ( polygonInners , function ( feature ) {
59
- coordinates . push ( feature . geometry . coordinates [ 0 ] ) ;
60
- } ) ;
61
- return polygon ( coordinates ) ;
38
+ function unionFc ( fc ) {
39
+ var unioned =
40
+ fc . features . length === 2
41
+ ? polygonClipping . union (
42
+ fc . features [ 0 ] . geometry . coordinates ,
43
+ fc . features [ 1 ] . geometry . coordinates
44
+ )
45
+ : polygonClipping . union . apply (
46
+ polygonClipping ,
47
+ fc . features . map ( function ( f ) {
48
+ return f . geometry . coordinates ;
49
+ } )
50
+ ) ;
51
+ return createGeomFromPolygonClippingOutput ( unioned ) ;
62
52
}
63
53
64
- /**
65
- * Separate Polygons to inners & outers
66
- *
67
- * @private
68
- * @param {FeatureCollection|Feature<Polygon|MultiPolygon> } poly GeoJSON Feature
69
- * @returns {Array<FeatureCollection<Polygon>, FeatureCollection<Polygon>> } Outer & Inner lines
70
- */
71
- function separatePolygons ( poly ) {
72
- var outers = [ ] ;
73
- var inners = [ ] ;
74
- flattenEach ( poly , function ( feature ) {
75
- var coordinates = feature . geometry . coordinates ;
76
- var featureOuter = coordinates [ 0 ] ;
77
- var featureInner = coordinates . slice ( 1 ) ;
78
- outers . push ( polygon ( [ featureOuter ] ) ) ;
79
- featureInner . forEach ( function ( inner ) {
80
- inners . push ( polygon ( [ inner ] ) ) ;
81
- } ) ;
82
- } ) ;
83
- return [ featureCollection ( outers ) , featureCollection ( inners ) ] ;
54
+ function createGeomFromPolygonClippingOutput ( unioned ) {
55
+ return multiPolygon ( unioned ) ;
84
56
}
85
57
86
58
/**
@@ -101,95 +73,7 @@ function createMask(mask) {
101
73
] ,
102
74
] ;
103
75
var coordinates = ( mask && mask . geometry . coordinates ) || world ;
104
- return polygon ( coordinates ) ;
105
- }
106
-
107
- /**
108
- * Union Polygons
109
- *
110
- * @private
111
- * @param {FeatureCollection<Polygon> } polygons collection of polygons
112
- * @returns {FeatureCollection<Polygon> } polygons only apply union if they collide
113
- */
114
- function unionPolygons ( polygons ) {
115
- if ( polygons . features . length <= 1 ) return polygons ;
116
-
117
- var tree = createIndex ( polygons ) ;
118
- var results = [ ] ;
119
- var removed = { } ;
120
-
121
- flattenEach ( polygons , function ( currentFeature , currentIndex ) {
122
- // Exclude any removed features
123
- if ( removed [ currentIndex ] ) return true ;
124
-
125
- // Don't search for itself
126
- tree . remove ( { index : currentIndex } , filterByIndex ) ;
127
- removed [ currentIndex ] = true ;
128
-
129
- // Keep applying the union operation until no more overlapping features
130
- while ( true ) {
131
- var bbox = turfBBox ( currentFeature ) ;
132
- var search = tree . search ( {
133
- minX : bbox [ 0 ] ,
134
- minY : bbox [ 1 ] ,
135
- maxX : bbox [ 2 ] ,
136
- maxY : bbox [ 3 ] ,
137
- } ) ;
138
- if ( search . length > 0 ) {
139
- var polys = search . map ( function ( item ) {
140
- removed [ item . index ] = true ;
141
- tree . remove ( { index : item . index } , filterByIndex ) ;
142
- return item . geojson ;
143
- } ) ;
144
-
145
- for ( var i = 0 , l = polys . length ; i < l ; i ++ ) {
146
- currentFeature = union ( currentFeature , polys [ i ] ) ;
147
- }
148
- }
149
- // Done
150
- if ( search . length === 0 ) break ;
151
- }
152
- results . push ( currentFeature ) ;
153
- } ) ;
154
-
155
- return featureCollection ( results ) ;
156
- }
157
-
158
- /**
159
- * Filter by Index - RBush helper function
160
- *
161
- * @private
162
- * @param {Object } a remove item
163
- * @param {Object } b search item
164
- * @returns {boolean } true if matches
165
- */
166
- function filterByIndex ( a , b ) {
167
- return a . index === b . index ;
168
- }
169
-
170
- /**
171
- * Create RBush Tree Index
172
- *
173
- * @private
174
- * @param {FeatureCollection<any> } features GeoJSON FeatureCollection
175
- * @returns {RBush } RBush Tree
176
- */
177
- function createIndex ( features ) {
178
- var tree = rbush ( ) ;
179
- var load = [ ] ;
180
- flattenEach ( features , function ( feature , index ) {
181
- var bbox = turfBBox ( feature ) ;
182
- load . push ( {
183
- minX : bbox [ 0 ] ,
184
- minY : bbox [ 1 ] ,
185
- maxX : bbox [ 2 ] ,
186
- maxY : bbox [ 3 ] ,
187
- geojson : feature ,
188
- index : index ,
189
- } ) ;
190
- } ) ;
191
- tree . load ( load ) ;
192
- return tree ;
76
+ return createPolygon ( coordinates ) ;
193
77
}
194
78
195
79
export default mask ;
0 commit comments