@@ -10,65 +10,31 @@ import type {GeoJSON, GeoJSONPolygon, GeoJSONMultiPolygon} from '@mapbox/geojson
10
10
import MercatorCoordinate from '../../../geo/mercator_coordinate' ;
11
11
import EXTENT from '../../../data/extent' ;
12
12
import Point from '@mapbox/point-geometry' ;
13
+ import type { CanonicalTileID } from '../../../source/tile_id' ;
13
14
14
15
type GeoJSONPolygons = | GeoJSONPolygon | GeoJSONMultiPolygon ;
15
16
17
+ // minX, minY, maxX, maxY
16
18
type BBox = [ number , number , number , number ] ;
17
-
18
- function calcBBox ( bbox : BBox , geom , type ) {
19
- if ( type === 'Point' ) {
20
- updateBBox ( bbox , geom ) ;
21
- } else if ( type === 'MultiPoint' || type === 'LineString' ) {
22
- for ( let i = 0 ; i < geom . length ; ++ i ) {
23
- updateBBox ( bbox , geom [ i ] ) ;
24
- }
25
- } else if ( type === 'Polygon' || type === 'MultiLineString' ) {
26
- for ( let i = 0 ; i < geom . length ; i ++ ) {
27
- for ( let j = 0 ; j < geom [ i ] . length ; j ++ ) {
28
- updateBBox ( bbox , geom [ i ] [ j ] ) ;
29
- }
30
- }
31
- } else if ( type === 'MultiPolygon' ) {
32
- for ( let i = 0 ; i < geom . length ; i ++ ) {
33
- for ( let j = 0 ; j < geom [ i ] . length ; j ++ ) {
34
- for ( let k = 0 ; k < geom [ i ] [ j ] . length ; k ++ ) {
35
- updateBBox ( bbox , geom [ i ] [ j ] [ k ] ) ;
36
- }
37
- }
38
- }
39
- }
40
- }
41
-
42
19
function updateBBox ( bbox : BBox , coord : Point ) {
43
20
bbox [ 0 ] = Math . min ( bbox [ 0 ] , coord [ 0 ] ) ;
44
21
bbox [ 1 ] = Math . min ( bbox [ 1 ] , coord [ 1 ] ) ;
45
22
bbox [ 2 ] = Math . max ( bbox [ 2 ] , coord [ 0 ] ) ;
46
23
bbox [ 3 ] = Math . max ( bbox [ 3 ] , coord [ 1 ] ) ;
47
24
}
48
25
49
- function boxWithinBox ( bbox1 , bbox2 ) {
26
+ function boxWithinBox ( bbox1 : BBox , bbox2 : BBox ) {
50
27
if ( bbox1 [ 0 ] <= bbox2 [ 0 ] ) return false ;
51
28
if ( bbox1 [ 2 ] >= bbox2 [ 2 ] ) return false ;
52
29
if ( bbox1 [ 1 ] <= bbox2 [ 1 ] ) return false ;
53
30
if ( bbox1 [ 3 ] >= bbox2 [ 3 ] ) return false ;
54
31
return true ;
55
32
}
56
33
57
- function getLngLatPoint ( coord : Point , canonical ) {
34
+ function getTileCoordinates ( p , canonical : CanonicalTileID ) {
35
+ const coord = MercatorCoordinate . fromLngLat ( { lng : p [ 0 ] , lat : p [ 1 ] } , 0 ) ;
58
36
const tilesAtZoom = Math . pow ( 2 , canonical . z ) ;
59
- const x = ( coord . x / EXTENT + canonical . x ) / tilesAtZoom ;
60
- const y = ( coord . y / EXTENT + canonical . y ) / tilesAtZoom ;
61
- const p = new MercatorCoordinate ( x , y ) . toLngLat ( ) ;
62
-
63
- return [ p . lng , p . lat ] ;
64
- }
65
-
66
- function getLngLatPoints ( line , canonical ) {
67
- const coords = [ ] ;
68
- for ( let i = 0 ; i < line . length ; ++ i ) {
69
- coords . push ( getLngLatPoint ( line [ i ] , canonical ) ) ;
70
- }
71
- return coords ;
37
+ return [ Math . round ( coord . x * tilesAtZoom * EXTENT ) , Math . round ( coord . y * tilesAtZoom * EXTENT ) ] ;
72
38
}
73
39
74
40
function onBoundary ( p , p1 , p2 ) {
@@ -97,13 +63,10 @@ function pointWithinPolygon(point, rings) {
97
63
}
98
64
99
65
function pointWithinPolygons ( point , polygons ) {
100
- if ( polygons . type === 'Polygon' ) {
101
- return pointWithinPolygon ( point , polygons . coordinates ) ;
66
+ for ( let i = 0 ; i < polygons . length ; i ++ ) {
67
+ if ( pointWithinPolygon ( point , polygons [ i ] ) ) return true ;
102
68
}
103
- for ( let i = 0 ; i < polygons . coordinates . length ; i ++ ) {
104
- if ( ! pointWithinPolygon ( point , polygons . coordinates [ i ] ) ) return false ;
105
- }
106
- return true ;
69
+ return false ;
107
70
}
108
71
109
72
function perp ( v1 , v2 ) {
@@ -168,59 +131,120 @@ function lineStringWithinPolygon(line, polygon) {
168
131
}
169
132
170
133
function lineStringWithinPolygons ( line , polygons ) {
171
- if ( polygons . type === 'Polygon' ) {
172
- return lineStringWithinPolygon ( line , polygons . coordinates ) ;
134
+ for ( let i = 0 ; i < polygons . length ; i ++ ) {
135
+ if ( lineStringWithinPolygon ( line , polygons [ i ] ) ) return true ;
173
136
}
174
- for ( let i = 0 ; i < polygons . coordinates . length ; i ++ ) {
175
- if ( ! lineStringWithinPolygon ( line , polygons . coordinates [ i ] ) ) return false ;
137
+ return false ;
138
+ }
139
+
140
+ function getTilePolygon ( coordinates , bbox , canonical ) {
141
+ const polygon = [ ] ;
142
+ for ( let i = 0 ; i < coordinates . length ; i ++ ) {
143
+ const ring = [ ] ;
144
+ for ( let j = 0 ; j < coordinates [ i ] . length ; j ++ ) {
145
+ const coord = getTileCoordinates ( coordinates [ i ] [ j ] , canonical ) ;
146
+ updateBBox ( bbox , coord ) ;
147
+ ring . push ( coord ) ;
148
+ }
149
+ polygon . push ( ring ) ;
176
150
}
177
- return true ;
151
+ return polygon ;
178
152
}
179
153
180
- function pointsWithinPolygons ( ctx : EvaluationContext , polygonGeometry : GeoJSONPolygons , polyBBox : BBox ) {
154
+ function getTilePolygons ( coordinates , bbox , canonical ) {
155
+ const polygons = [ ] ;
156
+ for ( let i = 0 ; i < coordinates . length ; i ++ ) {
157
+ const polygon = getTilePolygon ( coordinates [ i ] , bbox , canonical ) ;
158
+ polygons . push ( polygon ) ;
159
+ }
160
+ return polygons ;
161
+ }
162
+
163
+ function pointsWithinPolygons ( ctx : EvaluationContext , polygonGeometry : GeoJSONPolygons ) {
181
164
const pointBBox = [ Infinity , Infinity , - Infinity , - Infinity ] ;
182
- const lngLatPoints = [ ] ;
165
+ const polyBBox = [ Infinity , Infinity , - Infinity , - Infinity ] ;
166
+ const canonical = ctx . canonicalID ( ) ;
167
+ const shifts = [ canonical . x * EXTENT , canonical . y * EXTENT ] ;
168
+ const tilePoints = [ ] ;
169
+
183
170
for ( const points of ctx . geometry ( ) ) {
184
171
for ( const point of points ) {
185
- const p = getLngLatPoint ( point , ctx . canonicalID ( ) ) ;
186
- lngLatPoints . push ( p ) ;
172
+ const p = [ point . x + shifts [ 0 ] , point . y + shifts [ 1 ] ] ;
187
173
updateBBox ( pointBBox , p ) ;
174
+ tilePoints . push ( p ) ;
175
+ }
176
+ }
177
+
178
+ if ( polygonGeometry . type === 'Polygon' ) {
179
+ const tilePolygon = getTilePolygon ( polygonGeometry . coordinates , polyBBox , canonical ) ;
180
+ if ( ! boxWithinBox ( pointBBox , polyBBox ) ) return false ;
181
+
182
+ for ( const point of tilePoints ) {
183
+ if ( ! pointWithinPolygon ( point , tilePolygon ) ) return false ;
188
184
}
189
185
}
190
- if ( ! boxWithinBox ( pointBBox , polyBBox ) ) return false ;
191
- for ( let i = 0 ; i < lngLatPoints . length ; ++ i ) {
192
- if ( ! pointWithinPolygons ( lngLatPoints [ i ] , polygonGeometry ) ) return false ;
186
+
187
+ if ( polygonGeometry . type === 'MultiPolygon' ) {
188
+ const tilePolygons = getTilePolygons ( polygonGeometry . coordinates , polyBBox , canonical ) ;
189
+ if ( ! boxWithinBox ( pointBBox , polyBBox ) ) return false ;
190
+
191
+ for ( const point of tilePoints ) {
192
+ if ( ! pointWithinPolygons ( point , tilePolygons ) ) return false ;
193
+ }
193
194
}
195
+
194
196
return true ;
195
197
}
196
198
197
- function linesWithinPolygons ( ctx : EvaluationContext , polygonGeometry : GeoJSONPolygons , polyBBox : BBox ) {
199
+ function linesWithinPolygons ( ctx : EvaluationContext , polygonGeometry : GeoJSONPolygons ) {
198
200
const lineBBox = [ Infinity , Infinity , - Infinity , - Infinity ] ;
199
- const lineCoords = [ ] ;
201
+ const polyBBox = [ Infinity , Infinity , - Infinity , - Infinity ] ;
202
+
203
+ const canonical = ctx . canonicalID ( ) ;
204
+ const shifts = [ canonical . x * EXTENT , canonical . y * EXTENT ] ;
205
+ const tileLines = [ ] ;
206
+
200
207
for ( const line of ctx . geometry ( ) ) {
201
- const lineCoord = getLngLatPoints ( line , ctx . canonicalID ( ) ) ;
202
- lineCoords . push ( lineCoord ) ;
203
- calcBBox ( lineBBox , lineCoord , 'LineString' ) ;
208
+ const tileLine = [ ] ;
209
+ for ( const point of line ) {
210
+ const p = [ point . x + shifts [ 0 ] , point . y + shifts [ 1 ] ] ;
211
+ updateBBox ( lineBBox , p ) ;
212
+ tileLine . push ( p ) ;
213
+ }
214
+ tileLines . push ( tileLine ) ;
204
215
}
205
- if ( ! boxWithinBox ( lineBBox , polyBBox ) ) return false ;
206
- for ( let i = 0 ; i < lineCoords . length ; ++ i ) {
207
- if ( ! lineStringWithinPolygons ( lineCoords [ i ] , polygonGeometry ) ) return false ;
216
+
217
+ if ( polygonGeometry . type === 'Polygon' ) {
218
+ const tilePolygon = getTilePolygon ( polygonGeometry . coordinates , polyBBox , canonical ) ;
219
+ if ( ! boxWithinBox ( lineBBox , polyBBox ) ) return false ;
220
+
221
+ for ( const line of tileLines ) {
222
+ if ( ! lineStringWithinPolygon ( line , tilePolygon ) ) return false ;
223
+ }
224
+ }
225
+
226
+ if ( polygonGeometry . type === 'MultiPolygon' ) {
227
+ const tilePolygons = getTilePolygons ( polygonGeometry . coordinates , polyBBox , canonical ) ;
228
+
229
+ if ( ! boxWithinBox ( lineBBox , polyBBox ) ) return false ;
230
+
231
+ for ( const line of tileLines ) {
232
+ if ( ! lineStringWithinPolygons ( line , tilePolygons ) ) return false ;
233
+ }
208
234
}
209
235
return true ;
236
+
210
237
}
211
238
212
239
class Within implements Expression {
213
240
type : Type ;
214
241
geojson : GeoJSON
215
242
geometries : GeoJSONPolygons ;
216
- polyBBox : BBox ;
217
243
218
244
constructor ( geojson : GeoJSON , geometries : GeoJSONPolygons ) {
219
245
this . type = BooleanType ;
220
246
this . geojson = geojson ;
221
247
this . geometries = geometries ;
222
- this . polyBBox = [ Infinity , Infinity , - Infinity , - Infinity ] ;
223
- calcBBox ( this . polyBBox , this . geometries . coordinates , this . geometries . type ) ;
224
248
}
225
249
226
250
static parse ( args : $ReadOnlyArray < mixed > , context : ParsingContext ) {
@@ -250,9 +274,9 @@ class Within implements Expression {
250
274
evaluate ( ctx : EvaluationContext ) {
251
275
if ( ctx . geometry ( ) != null && ctx . canonicalID ( ) != null ) {
252
276
if ( ctx . geometryType ( ) === 'Point' ) {
253
- return pointsWithinPolygons ( ctx , this . geometries , this . polyBBox ) ;
277
+ return pointsWithinPolygons ( ctx , this . geometries ) ;
254
278
} else if ( ctx . geometryType ( ) === 'LineString' ) {
255
- return linesWithinPolygons ( ctx , this . geometries , this . polyBBox ) ;
279
+ return linesWithinPolygons ( ctx , this . geometries ) ;
256
280
}
257
281
}
258
282
return false ;
0 commit comments