1- import {
2- BBox ,
3- Feature ,
4- Geometry ,
5- LineString ,
6- MultiPoint ,
7- MultiPolygon ,
8- Point ,
9- Polygon ,
10- } from "geojson" ;
11- import { bbox as calcBbox } from "@turf/bbox" ;
12- import { booleanPointOnLine } from "@turf/boolean-point-on-line" ;
13- import { booleanPointInPolygon } from "@turf/boolean-point-in-polygon" ;
14- import { getGeom } from "@turf/invariant" ;
15- import { feature , featureCollection , lineString } from "@turf/helpers" ;
16- import { lineSplit } from "@turf/line-split" ;
1+ import { Feature , Geometry } from "geojson" ;
2+ import { booleanContains } from "@turf/boolean-contains" ;
173
184/**
195 * Tests whether geometry a is contained by geometry b.
@@ -35,252 +21,7 @@ function booleanWithin(
3521 feature1 : Feature < any > | Geometry ,
3622 feature2 : Feature < any > | Geometry
3723) : boolean {
38- var geom1 = getGeom ( feature1 ) ;
39- var geom2 = getGeom ( feature2 ) ;
40- var type1 = geom1 . type ;
41- var type2 = geom2 . type ;
42-
43- switch ( type1 ) {
44- case "Point" :
45- switch ( type2 ) {
46- case "MultiPoint" :
47- return isPointInMultiPoint ( geom1 , geom2 ) ;
48- case "LineString" :
49- return booleanPointOnLine ( geom1 , geom2 , { ignoreEndVertices : true } ) ;
50- case "Polygon" :
51- case "MultiPolygon" :
52- return booleanPointInPolygon ( geom1 , geom2 , { ignoreBoundary : true } ) ;
53- default :
54- throw new Error ( "feature2 " + type2 + " geometry not supported" ) ;
55- }
56- case "MultiPoint" :
57- switch ( type2 ) {
58- case "MultiPoint" :
59- return isMultiPointInMultiPoint ( geom1 , geom2 ) ;
60- case "LineString" :
61- return isMultiPointOnLine ( geom1 , geom2 ) ;
62- case "Polygon" :
63- case "MultiPolygon" :
64- return isMultiPointInPoly ( geom1 , geom2 ) ;
65- default :
66- throw new Error ( "feature2 " + type2 + " geometry not supported" ) ;
67- }
68- case "LineString" :
69- switch ( type2 ) {
70- case "LineString" :
71- return isLineOnLine ( geom1 , geom2 ) ;
72- case "Polygon" :
73- case "MultiPolygon" :
74- return isLineInPoly ( geom1 , geom2 ) ;
75- default :
76- throw new Error ( "feature2 " + type2 + " geometry not supported" ) ;
77- }
78- case "Polygon" :
79- switch ( type2 ) {
80- case "Polygon" :
81- case "MultiPolygon" :
82- return isPolyInPoly ( geom1 , geom2 ) ;
83- default :
84- throw new Error ( "feature2 " + type2 + " geometry not supported" ) ;
85- }
86- default :
87- throw new Error ( "feature1 " + type1 + " geometry not supported" ) ;
88- }
89- }
90-
91- function isPointInMultiPoint ( point : Point , multiPoint : MultiPoint ) {
92- var i ;
93- var output = false ;
94- for ( i = 0 ; i < multiPoint . coordinates . length ; i ++ ) {
95- if ( compareCoords ( multiPoint . coordinates [ i ] , point . coordinates ) ) {
96- output = true ;
97- break ;
98- }
99- }
100- return output ;
101- }
102-
103- function isMultiPointInMultiPoint (
104- multiPoint1 : MultiPoint ,
105- multiPoint2 : MultiPoint
106- ) {
107- for ( var i = 0 ; i < multiPoint1 . coordinates . length ; i ++ ) {
108- var anyMatch = false ;
109- for ( var i2 = 0 ; i2 < multiPoint2 . coordinates . length ; i2 ++ ) {
110- if (
111- compareCoords ( multiPoint1 . coordinates [ i ] , multiPoint2 . coordinates [ i2 ] )
112- ) {
113- anyMatch = true ;
114- }
115- }
116- if ( ! anyMatch ) {
117- return false ;
118- }
119- }
120- return true ;
121- }
122-
123- function isMultiPointOnLine ( multiPoint : MultiPoint , lineString : LineString ) {
124- var foundInsidePoint = false ;
125-
126- for ( var i = 0 ; i < multiPoint . coordinates . length ; i ++ ) {
127- if ( ! booleanPointOnLine ( multiPoint . coordinates [ i ] , lineString ) ) {
128- return false ;
129- }
130- if ( ! foundInsidePoint ) {
131- foundInsidePoint = booleanPointOnLine (
132- multiPoint . coordinates [ i ] ,
133- lineString ,
134- { ignoreEndVertices : true }
135- ) ;
136- }
137- }
138- return foundInsidePoint ;
139- }
140-
141- function isMultiPointInPoly ( multiPoint : MultiPoint , polygon : Polygon ) {
142- var oneInside = false ;
143- for ( var i = 0 ; i < multiPoint . coordinates . length ; i ++ ) {
144- // All points must be inside polygon (boundary OK)
145- if ( ! booleanPointInPolygon ( multiPoint . coordinates [ i ] , polygon ) ) {
146- return false ;
147- }
148- // Track if at least one point is strictly in the interior
149- if ( ! oneInside ) {
150- oneInside = booleanPointInPolygon ( multiPoint . coordinates [ i ] , polygon , {
151- ignoreBoundary : true ,
152- } ) ;
153- }
154- }
155- // At least one point must be in the interior (not just on boundary)
156- return oneInside ;
157- }
158-
159- function isLineOnLine ( lineString1 : LineString , lineString2 : LineString ) {
160- for ( var i = 0 ; i < lineString1 . coordinates . length ; i ++ ) {
161- if ( ! booleanPointOnLine ( lineString1 . coordinates [ i ] , lineString2 ) ) {
162- return false ;
163- }
164- }
165- return true ;
166- }
167-
168- function splitLineIntoSegmentsOnPolygon (
169- linestring : LineString ,
170- polygon : Polygon
171- ) {
172- const coords = linestring . coordinates ;
173-
174- const outputSegments : Feature < LineString > [ ] = [ ] ;
175-
176- for ( let i = 0 ; i < coords . length - 1 ; i ++ ) {
177- const seg = lineString ( [ coords [ i ] , coords [ i + 1 ] ] ) ;
178- const split = lineSplit ( seg , feature ( polygon ) ) ;
179-
180- if ( split . features . length === 0 ) {
181- outputSegments . push ( seg ) ;
182- } else {
183- outputSegments . push ( ...split . features ) ;
184- }
185- }
186-
187- return featureCollection ( outputSegments ) ;
188- }
189-
190- function isLineInPoly ( linestring : LineString , polygon : Polygon ) {
191- const polyBbox = calcBbox ( polygon ) ;
192- const lineBbox = calcBbox ( linestring ) ;
193-
194- if ( ! doBBoxOverlap ( polyBbox , lineBbox ) ) {
195- return false ;
196- }
197-
198- for ( const coord of linestring . coordinates ) {
199- if ( ! booleanPointInPolygon ( coord , polygon ) ) {
200- return false ;
201- }
202- }
203-
204- let isContainedByPolygonBoundary = false ;
205- // split intersecting segments and verify their inclusion
206- const lineSegments = splitLineIntoSegmentsOnPolygon ( linestring , polygon ) ;
207-
208- for ( const lineSegment of lineSegments . features ) {
209- const midpoint = getMidpoint (
210- lineSegment . geometry . coordinates [ 0 ] ,
211- lineSegment . geometry . coordinates [ 1 ]
212- ) ;
213-
214- // make sure all segments do not intersect with polygon exterior
215- if ( ! booleanPointInPolygon ( midpoint , polygon ) ) {
216- return false ;
217- }
218-
219- // make sure at least 1 segment intersects with the polygon's interior
220- if (
221- ! isContainedByPolygonBoundary &&
222- booleanPointInPolygon ( midpoint , polygon , { ignoreBoundary : true } )
223- ) {
224- isContainedByPolygonBoundary = true ;
225- }
226- }
227-
228- return isContainedByPolygonBoundary ;
229- }
230-
231- /**
232- * Is Polygon2 in Polygon1
233- * Only takes into account outer rings
234- *
235- * @private
236- * @param {Polygon } geometry1
237- * @param {Polygon|MultiPolygon } geometry2
238- * @returns {boolean } true/false
239- */
240- function isPolyInPoly ( geometry1 : Polygon , geometry2 : Polygon | MultiPolygon ) {
241- var poly1Bbox = calcBbox ( geometry1 ) ;
242- var poly2Bbox = calcBbox ( geometry2 ) ;
243- if ( ! doBBoxOverlap ( poly2Bbox , poly1Bbox ) ) {
244- return false ;
245- }
246- for ( var i = 0 ; i < geometry1 . coordinates [ 0 ] . length ; i ++ ) {
247- if ( ! booleanPointInPolygon ( geometry1 . coordinates [ 0 ] [ i ] , geometry2 ) ) {
248- return false ;
249- }
250- }
251- return true ;
252- }
253-
254- function doBBoxOverlap ( bbox1 : BBox , bbox2 : BBox ) {
255- if ( bbox1 [ 0 ] > bbox2 [ 0 ] ) return false ;
256- if ( bbox1 [ 2 ] < bbox2 [ 2 ] ) return false ;
257- if ( bbox1 [ 1 ] > bbox2 [ 1 ] ) return false ;
258- if ( bbox1 [ 3 ] < bbox2 [ 3 ] ) return false ;
259- return true ;
260- }
261-
262- /**
263- * compareCoords
264- *
265- * @private
266- * @param {Position } pair1 point [x,y]
267- * @param {Position } pair2 point [x,y]
268- * @returns {boolean } true/false if coord pairs match
269- */
270- function compareCoords ( pair1 : number [ ] , pair2 : number [ ] ) {
271- return pair1 [ 0 ] === pair2 [ 0 ] && pair1 [ 1 ] === pair2 [ 1 ] ;
272- }
273-
274- /**
275- * getMidpoint
276- *
277- * @private
278- * @param {Position } pair1 point [x,y]
279- * @param {Position } pair2 point [x,y]
280- * @returns {Position } midpoint of pair1 and pair2
281- */
282- function getMidpoint ( pair1 : number [ ] , pair2 : number [ ] ) {
283- return [ ( pair1 [ 0 ] + pair2 [ 0 ] ) / 2 , ( pair1 [ 1 ] + pair2 [ 1 ] ) / 2 ] ;
24+ return booleanContains ( feature2 , feature1 ) ;
28425}
28526
28627export { booleanWithin } ;
0 commit comments