@deck.gl/geo-layers 9.3.7 → 9.4.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dist.dev.js +159 -26
- package/dist/index.cjs +151 -27
- package/dist/index.cjs.map +3 -3
- package/dist/mesh-layer/mesh-layer-vertex.glsl.d.ts +1 -1
- package/dist/mesh-layer/mesh-layer-vertex.glsl.d.ts.map +1 -1
- package/dist/mesh-layer/mesh-layer-vertex.glsl.js +3 -4
- package/dist/mesh-layer/mesh-layer-vertex.glsl.js.map +1 -1
- package/dist/mesh-layer/mesh-layer.d.ts +1 -1
- package/dist/mesh-layer/mesh-layer.d.ts.map +1 -1
- package/dist/mesh-layer/mesh-layer.js +7 -14
- package/dist/mesh-layer/mesh-layer.js.map +1 -1
- package/dist/terrain-layer/terrain-layer.d.ts.map +1 -1
- package/dist/terrain-layer/terrain-layer.js +45 -5
- package/dist/terrain-layer/terrain-layer.js.map +1 -1
- package/dist/tileset-2d/tile-2d-header.d.ts +1 -0
- package/dist/tileset-2d/tile-2d-header.d.ts.map +1 -1
- package/dist/tileset-2d/tile-2d-header.js +3 -5
- package/dist/tileset-2d/tile-2d-header.js.map +1 -1
- package/dist/tileset-2d/tile-2d-traversal.d.ts.map +1 -1
- package/dist/tileset-2d/tile-2d-traversal.js +23 -1
- package/dist/tileset-2d/tile-2d-traversal.js.map +1 -1
- package/dist/tileset-2d/tileset-2d.d.ts +5 -0
- package/dist/tileset-2d/tileset-2d.d.ts.map +1 -1
- package/dist/tileset-2d/tileset-2d.js +85 -0
- package/dist/tileset-2d/tileset-2d.js.map +1 -1
- package/dist.min.js +21 -22
- package/package.json +6 -6
- package/src/mesh-layer/mesh-layer-vertex.glsl.ts +3 -4
- package/src/mesh-layer/mesh-layer.ts +7 -17
- package/src/terrain-layer/terrain-layer.ts +64 -4
- package/src/tileset-2d/tile-2d-header.ts +4 -4
- package/src/tileset-2d/tile-2d-traversal.ts +33 -1
- package/src/tileset-2d/tileset-2d.ts +101 -1
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "deck.gl layers supporting geospatial use cases and GIS formats",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"version": "9.
|
|
6
|
+
"version": "9.4.0-alpha.1",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -57,13 +57,13 @@
|
|
|
57
57
|
"long": "^3.2.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@deck.gl/core": "~9.3.0",
|
|
61
|
-
"@deck.gl/extensions": "~9.3.0",
|
|
62
|
-
"@deck.gl/layers": "~9.3.0",
|
|
63
|
-
"@deck.gl/mesh-layers": "~9.3.0",
|
|
60
|
+
"@deck.gl/core": "~9.3.0-beta.2",
|
|
61
|
+
"@deck.gl/extensions": "~9.3.0-beta.2",
|
|
62
|
+
"@deck.gl/layers": "~9.3.0-beta.2",
|
|
63
|
+
"@deck.gl/mesh-layers": "~9.3.0-beta.2",
|
|
64
64
|
"@loaders.gl/core": "^4.4.3",
|
|
65
65
|
"@luma.gl/core": "~9.3.3",
|
|
66
66
|
"@luma.gl/engine": "~9.3.3"
|
|
67
67
|
},
|
|
68
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "a30177af4ec82fd612d116d1528deac09f1800b4"
|
|
69
69
|
}
|
|
@@ -11,11 +11,10 @@ in vec3 normals;
|
|
|
11
11
|
in vec3 colors;
|
|
12
12
|
in vec2 texCoords;
|
|
13
13
|
in vec4 uvRegions;
|
|
14
|
-
in
|
|
14
|
+
in float rowIndexes;
|
|
15
15
|
|
|
16
16
|
// Instance attributes
|
|
17
17
|
in vec4 instanceColors;
|
|
18
|
-
in vec3 instancePickingColors;
|
|
19
18
|
in vec3 instanceModelMatrixCol0;
|
|
20
19
|
in vec3 instanceModelMatrixCol1;
|
|
21
20
|
in vec3 instanceModelMatrixCol2;
|
|
@@ -41,9 +40,9 @@ void main(void) {
|
|
|
41
40
|
geometry.uv = uv;
|
|
42
41
|
|
|
43
42
|
if (mesh.pickFeatureIds) {
|
|
44
|
-
geometry.pickingColor =
|
|
43
|
+
geometry.pickingColor = picking_getPickingColorFromIndex(rowIndexes);
|
|
45
44
|
} else {
|
|
46
|
-
geometry.pickingColor =
|
|
45
|
+
geometry.pickingColor = picking_getPickingColorFromInstanceID();
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
mat3 instanceModelMatrix = mat3(instanceModelMatrixCol0, instanceModelMatrixCol1, instanceModelMatrixCol2);
|
|
@@ -75,12 +75,13 @@ export default class MeshLayer<DataT = any, ExtraProps extends {} = {}> extends
|
|
|
75
75
|
if (featureIds) {
|
|
76
76
|
// attributeManager is always defined in a primitive layer
|
|
77
77
|
attributeManager!.add({
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
/** Feature id for each mesh vertex. */
|
|
79
|
+
rowIndexes: {
|
|
80
|
+
type: 'uint32',
|
|
81
|
+
size: 1,
|
|
81
82
|
noAlloc: true,
|
|
82
83
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
83
|
-
update: this.
|
|
84
|
+
update: this.calculateFeatureIdsPickingIndexes
|
|
84
85
|
}
|
|
85
86
|
});
|
|
86
87
|
}
|
|
@@ -179,21 +180,10 @@ export default class MeshLayer<DataT = any, ExtraProps extends {} = {}> extends
|
|
|
179
180
|
);
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
|
|
183
|
+
calculateFeatureIdsPickingIndexes(attribute) {
|
|
183
184
|
// This updater is only called if featureIds is not null
|
|
184
185
|
const featureIds = this.props.featureIds!;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const pickingColor = [];
|
|
188
|
-
for (let index = 0; index < featureIds.length; index++) {
|
|
189
|
-
this.encodePickingColor(featureIds[index], pickingColor);
|
|
190
|
-
|
|
191
|
-
value[index * 3] = pickingColor[0];
|
|
192
|
-
value[index * 3 + 1] = pickingColor[1];
|
|
193
|
-
value[index * 3 + 2] = pickingColor[2];
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
attribute.value = value;
|
|
186
|
+
attribute.value = new Uint32Array(featureIds);
|
|
197
187
|
}
|
|
198
188
|
|
|
199
189
|
finalizeState(context: LayerContext) {
|
|
@@ -30,6 +30,10 @@ import type {
|
|
|
30
30
|
import {getURLFromTemplate, Tile2DHeader, URLTemplate, urlType} from '../tileset-2d/index';
|
|
31
31
|
|
|
32
32
|
const DUMMY_DATA = [1];
|
|
33
|
+
const TILE_OVERLAP_PIXELS = 1;
|
|
34
|
+
const MIN_TERRAIN_MESH_MAX_ERROR = 1;
|
|
35
|
+
const MAX_LATITUDE = 90;
|
|
36
|
+
const MAX_LONGITUDE = 180;
|
|
33
37
|
|
|
34
38
|
const defaultProps: DefaultProps<TerrainLayerProps> = {
|
|
35
39
|
...TileLayer.defaultProps,
|
|
@@ -70,6 +74,35 @@ function urlTemplateToUpdateTrigger(template: URLTemplate): string {
|
|
|
70
74
|
return template || '';
|
|
71
75
|
}
|
|
72
76
|
|
|
77
|
+
function getOverlappedBounds(bounds: Bounds, tileSize: number, clampLngLat: boolean): Bounds {
|
|
78
|
+
const xPad = ((bounds[2] - bounds[0]) / tileSize) * TILE_OVERLAP_PIXELS;
|
|
79
|
+
const yPad = ((bounds[3] - bounds[1]) / tileSize) * TILE_OVERLAP_PIXELS;
|
|
80
|
+
const overlappedBounds: Bounds = [
|
|
81
|
+
bounds[0] - xPad,
|
|
82
|
+
bounds[1] - yPad,
|
|
83
|
+
bounds[2] + xPad,
|
|
84
|
+
bounds[3] + yPad
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
if (!clampLngLat) {
|
|
88
|
+
return overlappedBounds;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return [
|
|
92
|
+
Math.max(overlappedBounds[0], -MAX_LONGITUDE),
|
|
93
|
+
Math.max(overlappedBounds[1], -MAX_LATITUDE),
|
|
94
|
+
Math.min(overlappedBounds[2], MAX_LONGITUDE),
|
|
95
|
+
Math.min(overlappedBounds[3], MAX_LATITUDE)
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getEffectiveMeshMaxError(meshMaxError: number): number {
|
|
100
|
+
if (!Number.isFinite(meshMaxError) || meshMaxError <= 0) {
|
|
101
|
+
return MIN_TERRAIN_MESH_MAX_ERROR;
|
|
102
|
+
}
|
|
103
|
+
return Math.max(meshMaxError, MIN_TERRAIN_MESH_MAX_ERROR);
|
|
104
|
+
}
|
|
105
|
+
|
|
73
106
|
type ElevationDecoder = {rScaler: number; gScaler: number; bScaler: number; offset: number};
|
|
74
107
|
type TerrainLoadProps = {
|
|
75
108
|
bounds: Bounds;
|
|
@@ -80,6 +113,12 @@ type TerrainLoadProps = {
|
|
|
80
113
|
};
|
|
81
114
|
|
|
82
115
|
type MeshAndTexture = [MeshAttributes | null, TextureSource | null];
|
|
116
|
+
type MeshBoundingBox = [min: number[], max: number[]];
|
|
117
|
+
type MeshWithBoundingBox = MeshAttributes & {
|
|
118
|
+
header?: {
|
|
119
|
+
boundingBox?: MeshBoundingBox;
|
|
120
|
+
};
|
|
121
|
+
};
|
|
83
122
|
|
|
84
123
|
/** All properties supported by TerrainLayer */
|
|
85
124
|
export type TerrainLayerProps = _TerrainLayerProps &
|
|
@@ -170,14 +209,15 @@ export default class TerrainLayer<ExtraPropsT extends {} = {}> extends Composite
|
|
|
170
209
|
if (!elevationData) {
|
|
171
210
|
return null;
|
|
172
211
|
}
|
|
212
|
+
const effectiveMeshMaxError = getEffectiveMeshMaxError(meshMaxError);
|
|
173
213
|
let loadOptions = this.getLoadOptions();
|
|
174
214
|
loadOptions = {
|
|
175
215
|
...loadOptions,
|
|
176
216
|
terrain: {
|
|
177
|
-
skirtHeight: this.state.isTiled ?
|
|
217
|
+
skirtHeight: this.state.isTiled ? effectiveMeshMaxError * 2 : 0,
|
|
178
218
|
...loadOptions?.terrain,
|
|
179
219
|
bounds,
|
|
180
|
-
meshMaxError,
|
|
220
|
+
meshMaxError: effectiveMeshMaxError,
|
|
181
221
|
elevationDecoder
|
|
182
222
|
}
|
|
183
223
|
};
|
|
@@ -204,10 +244,15 @@ export default class TerrainLayer<ExtraPropsT extends {} = {}> extends Composite
|
|
|
204
244
|
topRight = [bbox.right, bbox.top];
|
|
205
245
|
}
|
|
206
246
|
const bounds: Bounds = [bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]];
|
|
247
|
+
const overlappedBounds = getOverlappedBounds(
|
|
248
|
+
bounds,
|
|
249
|
+
this.props.tileSize,
|
|
250
|
+
viewport instanceof GlobeViewport
|
|
251
|
+
);
|
|
207
252
|
|
|
208
253
|
const terrain = this.loadTerrain({
|
|
209
254
|
elevationData: dataUrl,
|
|
210
|
-
bounds,
|
|
255
|
+
bounds: overlappedBounds,
|
|
211
256
|
elevationDecoder,
|
|
212
257
|
meshMaxError,
|
|
213
258
|
signal
|
|
@@ -238,12 +283,27 @@ export default class TerrainLayer<ExtraPropsT extends {} = {}> extends Composite
|
|
|
238
283
|
|
|
239
284
|
const [mesh, texture] = data;
|
|
240
285
|
|
|
286
|
+
const {viewport} = this.context;
|
|
287
|
+
// Bounds are baked with projectFlat. In GlobeView projectFlat is identity,
|
|
288
|
+
// so tiled terrain meshes are in lng/lat degrees instead of common-space
|
|
289
|
+
// web-mercator units.
|
|
290
|
+
const isGlobe = viewport instanceof GlobeViewport;
|
|
291
|
+
const boundingBox = (mesh as MeshWithBoundingBox | null)?.header?.boundingBox;
|
|
292
|
+
const hasLngLatBounds =
|
|
293
|
+
boundingBox &&
|
|
294
|
+
boundingBox.every(
|
|
295
|
+
([x, y]) =>
|
|
296
|
+
x >= -MAX_LONGITUDE && x <= MAX_LONGITUDE && y >= -MAX_LATITUDE && y <= MAX_LATITUDE
|
|
297
|
+
);
|
|
298
|
+
const coordinateSystem =
|
|
299
|
+
isGlobe && hasLngLatBounds ? COORDINATE_SYSTEM.LNGLAT : COORDINATE_SYSTEM.CARTESIAN;
|
|
300
|
+
|
|
241
301
|
return new SubLayerClass(props, {
|
|
242
302
|
data: DUMMY_DATA,
|
|
243
303
|
mesh,
|
|
244
304
|
texture,
|
|
245
305
|
_instanced: false,
|
|
246
|
-
coordinateSystem
|
|
306
|
+
coordinateSystem,
|
|
247
307
|
getPosition: d => [0, 0, 0],
|
|
248
308
|
getColor: color,
|
|
249
309
|
wireframe,
|
|
@@ -10,6 +10,7 @@ import type {Layer} from '@deck.gl/core';
|
|
|
10
10
|
export type TileLoadDataProps<DataT = any> = {
|
|
11
11
|
requestScheduler: RequestScheduler;
|
|
12
12
|
getData: (props: TileLoadProps) => Promise<DataT>;
|
|
13
|
+
getRequestPriority: (tile: Tile2DHeader<DataT>) => number;
|
|
13
14
|
onLoad: (tile: Tile2DHeader<DataT>) => void;
|
|
14
15
|
onError: (error: any, tile: Tile2DHeader<DataT>) => void;
|
|
15
16
|
};
|
|
@@ -106,6 +107,7 @@ export class Tile2DHeader<DataT = any> {
|
|
|
106
107
|
/* eslint-disable max-statements */
|
|
107
108
|
private async _loadData({
|
|
108
109
|
getData,
|
|
110
|
+
getRequestPriority,
|
|
109
111
|
requestScheduler,
|
|
110
112
|
onLoad,
|
|
111
113
|
onError
|
|
@@ -116,10 +118,8 @@ export class Tile2DHeader<DataT = any> {
|
|
|
116
118
|
this._abortController = new AbortController();
|
|
117
119
|
const {signal} = this._abortController;
|
|
118
120
|
|
|
119
|
-
// @ts-expect-error (2345)
|
|
120
|
-
const requestToken = await requestScheduler.scheduleRequest(this,
|
|
121
|
-
return tile.isSelected ? 1 : -1;
|
|
122
|
-
});
|
|
121
|
+
// @ts-expect-error (2345) loaders.gl's RequestScheduler callback type is too narrow.
|
|
122
|
+
const requestToken = await requestScheduler.scheduleRequest(this, getRequestPriority);
|
|
123
123
|
|
|
124
124
|
if (!requestToken) {
|
|
125
125
|
this._isCancelled = true;
|
|
@@ -91,6 +91,11 @@ class OSMNode {
|
|
|
91
91
|
return false;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
// Globe: reject tiles occluded by the near hemisphere
|
|
95
|
+
if (project && this.beyondHorizon(viewport.cameraPosition, project, elevationBounds[1])) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
94
99
|
// Avoid loading overlapping tiles - if a descendant is requested, do not request the ancester
|
|
95
100
|
if (!this.childVisible) {
|
|
96
101
|
let {z} = this;
|
|
@@ -129,6 +134,33 @@ class OSMNode {
|
|
|
129
134
|
return result;
|
|
130
135
|
}
|
|
131
136
|
|
|
137
|
+
beyondHorizon(
|
|
138
|
+
cameraPosition: number[],
|
|
139
|
+
project: (xyz: number[]) => number[],
|
|
140
|
+
elevation: number
|
|
141
|
+
): boolean {
|
|
142
|
+
const cx = cameraPosition[0];
|
|
143
|
+
const cy = cameraPosition[1];
|
|
144
|
+
const cz = cameraPosition[2];
|
|
145
|
+
const cMag = Math.sqrt(cx * cx + cy * cy + cz * cz);
|
|
146
|
+
|
|
147
|
+
const camLng = (Math.atan2(cx, -cy) * 180) / Math.PI;
|
|
148
|
+
const camLat = (Math.asin(cz / cMag) * 180) / Math.PI;
|
|
149
|
+
|
|
150
|
+
const [west, north] = osmTile2lngLat(this.x, this.y, this.z);
|
|
151
|
+
const [east, south] = osmTile2lngLat(this.x + 1, this.y + 1, this.z);
|
|
152
|
+
|
|
153
|
+
const tileCenterLng = (west + east) / 2;
|
|
154
|
+
const wrappedCamLng = tileCenterLng + (((camLng - tileCenterLng + 540) % 360) - 180);
|
|
155
|
+
const closestLng = Math.max(west, Math.min(wrappedCamLng, east));
|
|
156
|
+
const closestLat = Math.max(south, Math.min(camLat, north));
|
|
157
|
+
|
|
158
|
+
const closest = project([closestLng, closestLat, elevation]);
|
|
159
|
+
const dot = closest[0] * cx + closest[1] * cy + closest[2] * cz;
|
|
160
|
+
const magSq = closest[0] * closest[0] + closest[1] * closest[1] + closest[2] * closest[2];
|
|
161
|
+
return dot <= magSq;
|
|
162
|
+
}
|
|
163
|
+
|
|
132
164
|
insideBounds([minX, minY, maxX, maxY]: Bounds): boolean {
|
|
133
165
|
const scale = Math.pow(2, this.z);
|
|
134
166
|
const extent = TILE_SIZE / scale;
|
|
@@ -191,7 +223,7 @@ export function getOSMTileIndices(
|
|
|
191
223
|
bounds?: Bounds
|
|
192
224
|
): TileIndex[] {
|
|
193
225
|
const project: ((xyz: number[]) => number[]) | null =
|
|
194
|
-
viewport instanceof _GlobeViewport
|
|
226
|
+
viewport instanceof _GlobeViewport
|
|
195
227
|
? // eslint-disable-next-line @typescript-eslint/unbound-method
|
|
196
228
|
viewport.projectPosition
|
|
197
229
|
: null;
|
|
@@ -10,7 +10,7 @@ import {Matrix4, equals, NumericArray} from '@math.gl/core';
|
|
|
10
10
|
import {Tile2DHeader} from './tile-2d-header';
|
|
11
11
|
|
|
12
12
|
import {getTileIndices, tileToBoundingBox, getCullBounds, transformBox} from './utils';
|
|
13
|
-
import {Bounds, TileIndex, ZRange} from './types';
|
|
13
|
+
import {Bounds, TileBoundingBox, TileIndex, ZRange} from './types';
|
|
14
14
|
import {TileLoadProps} from './types';
|
|
15
15
|
import {memoize} from './memoize';
|
|
16
16
|
|
|
@@ -48,6 +48,9 @@ export type RefinementStrategy =
|
|
|
48
48
|
| RefinementStrategyFunction;
|
|
49
49
|
|
|
50
50
|
const DEFAULT_CACHE_SCALE = 5;
|
|
51
|
+
const SELECTED_TILE_PRIORITY = 0;
|
|
52
|
+
const VISIBLE_TILE_PRIORITY = 1e8;
|
|
53
|
+
const MAX_TILE_DISTANCE_PRIORITY = VISIBLE_TILE_PRIORITY - SELECTED_TILE_PRIORITY - 1;
|
|
51
54
|
|
|
52
55
|
const STRATEGIES = {
|
|
53
56
|
[STRATEGY_DEFAULT]: updateTileStateDefault,
|
|
@@ -437,6 +440,102 @@ export class Tileset2D {
|
|
|
437
440
|
|
|
438
441
|
private _getCullBounds = memoize(getCullBounds);
|
|
439
442
|
|
|
443
|
+
private _getRequestPriority(tile: Tile2DHeader): number {
|
|
444
|
+
if (!tile.isSelected && !tile.isVisible) {
|
|
445
|
+
return -1;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// RequestScheduler loads lower priority values first.
|
|
449
|
+
const distance = this._getTileDistancePriority(tile);
|
|
450
|
+
if (tile.isSelected) {
|
|
451
|
+
return SELECTED_TILE_PRIORITY + distance;
|
|
452
|
+
}
|
|
453
|
+
return VISIBLE_TILE_PRIORITY + distance;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
private _getTileDistancePriority(tile: Tile2DHeader): number {
|
|
457
|
+
const {width, height} = this._viewport || {};
|
|
458
|
+
if (!this._viewport || !width || !height) {
|
|
459
|
+
return 0;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
try {
|
|
463
|
+
const points = this._getTileScreenCorners(tile.bbox);
|
|
464
|
+
const center: [number, number] = [width / 2, height / 2];
|
|
465
|
+
if (points.length === 4) {
|
|
466
|
+
if (this._isPointInPolygon(center, points)) {
|
|
467
|
+
return 0;
|
|
468
|
+
}
|
|
469
|
+
const distance = points.reduce((minDistance, point, i) => {
|
|
470
|
+
const nextPoint = points[(i + 1) % points.length];
|
|
471
|
+
return Math.min(
|
|
472
|
+
minDistance,
|
|
473
|
+
this._getPointToSegmentDistanceSquared(center, point, nextPoint)
|
|
474
|
+
);
|
|
475
|
+
}, Number.MAX_SAFE_INTEGER);
|
|
476
|
+
return Math.min(distance, MAX_TILE_DISTANCE_PRIORITY);
|
|
477
|
+
}
|
|
478
|
+
} catch {
|
|
479
|
+
// Some viewport/tile combinations are not projectable. Keep them valid but last in tier.
|
|
480
|
+
}
|
|
481
|
+
return MAX_TILE_DISTANCE_PRIORITY;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
private _getTileScreenCorners(bbox: TileBoundingBox): [number, number][] {
|
|
485
|
+
const coordinates: [number, number][] =
|
|
486
|
+
'west' in bbox
|
|
487
|
+
? [
|
|
488
|
+
[bbox.west, bbox.south],
|
|
489
|
+
[bbox.east, bbox.south],
|
|
490
|
+
[bbox.east, bbox.north],
|
|
491
|
+
[bbox.west, bbox.north]
|
|
492
|
+
]
|
|
493
|
+
: [
|
|
494
|
+
[bbox.left, bbox.top],
|
|
495
|
+
[bbox.right, bbox.top],
|
|
496
|
+
[bbox.right, bbox.bottom],
|
|
497
|
+
[bbox.left, bbox.bottom]
|
|
498
|
+
];
|
|
499
|
+
|
|
500
|
+
return coordinates
|
|
501
|
+
.map(coordinate => this._viewport!.project(coordinate))
|
|
502
|
+
.filter(([x, y]) => Number.isFinite(x) && Number.isFinite(y)) as [number, number][];
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
private _isPointInPolygon(point: [number, number], polygon: [number, number][]): boolean {
|
|
506
|
+
let inside = false;
|
|
507
|
+
const [x, y] = point;
|
|
508
|
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
|
509
|
+
const [xi, yi] = polygon[i];
|
|
510
|
+
const [xj, yj] = polygon[j];
|
|
511
|
+
if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) {
|
|
512
|
+
inside = !inside;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return inside;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
private _getPointToSegmentDistanceSquared(
|
|
519
|
+
point: [number, number],
|
|
520
|
+
segmentStart: [number, number],
|
|
521
|
+
segmentEnd: [number, number]
|
|
522
|
+
): number {
|
|
523
|
+
const [x, y] = point;
|
|
524
|
+
const [x1, y1] = segmentStart;
|
|
525
|
+
const [x2, y2] = segmentEnd;
|
|
526
|
+
const dx = x2 - x1;
|
|
527
|
+
const dy = y2 - y1;
|
|
528
|
+
const lengthSquared = dx * dx + dy * dy;
|
|
529
|
+
const t = lengthSquared
|
|
530
|
+
? Math.max(0, Math.min(1, ((x - x1) * dx + (y - y1) * dy) / lengthSquared))
|
|
531
|
+
: 0;
|
|
532
|
+
const segmentX = x1 + t * dx;
|
|
533
|
+
const segmentY = y1 + t * dy;
|
|
534
|
+
const distanceX = x - segmentX;
|
|
535
|
+
const distanceY = y - segmentY;
|
|
536
|
+
return distanceX * distanceX + distanceY * distanceY;
|
|
537
|
+
}
|
|
538
|
+
|
|
440
539
|
private _pruneRequests(): void {
|
|
441
540
|
const {maxRequests = 0} = this.opts;
|
|
442
541
|
|
|
@@ -542,6 +641,7 @@ export class Tileset2D {
|
|
|
542
641
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
543
642
|
tile.loadData({
|
|
544
643
|
getData: this.opts.getTileData,
|
|
644
|
+
getRequestPriority: this._getRequestPriority.bind(this),
|
|
545
645
|
requestScheduler: this._requestScheduler,
|
|
546
646
|
onLoad: this.onTileLoad,
|
|
547
647
|
onError: this.opts.onTileError
|