@loaders.gl/tiles 5.0.0-alpha.10 → 5.0.0-alpha.11
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 +8975 -8931
- package/dist/dist.min.js +3 -3
- package/dist/index.cjs +122 -57
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/spatial/i3s-spatial-transformer.d.ts +16 -0
- package/dist/spatial/i3s-spatial-transformer.d.ts.map +1 -1
- package/dist/spatial/i3s-spatial-transformer.js +45 -0
- package/dist/spatial/i3s-spatial-transformer.js.map +1 -1
- package/dist/spatial/spatial-coordinate-transformer.d.ts.map +1 -1
- package/dist/spatial/spatial-coordinate-transformer.js +8 -8
- package/dist/spatial/spatial-coordinate-transformer.js.map +1 -1
- package/dist/spatial/spatial-resource-registry.d.ts +3 -0
- package/dist/spatial/spatial-resource-registry.d.ts.map +1 -1
- package/dist/spatial/spatial-resource-registry.js +12 -3
- package/dist/spatial/spatial-resource-registry.js.map +1 -1
- package/dist/spatial/tiles-3d-spatial-transformer.d.ts.map +1 -1
- package/dist/spatial/tiles-3d-spatial-transformer.js +0 -12
- package/dist/spatial/tiles-3d-spatial-transformer.js.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.d.ts +8 -1
- package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-3d.js +42 -9
- package/dist/tileset-3d/common/tileset-3d.js.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/common/tileset-traverser.js +2 -3
- package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts +1 -0
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.d.ts.map +1 -1
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js +12 -4
- package/dist/tileset-3d/format-3d-tiles/tileset-3d-traverser.js.map +1 -1
- package/package.json +11 -11
- package/src/index.ts +2 -1
- package/src/spatial/i3s-spatial-transformer.ts +64 -0
- package/src/spatial/spatial-coordinate-transformer.ts +9 -8
- package/src/spatial/spatial-resource-registry.ts +14 -3
- package/src/spatial/tiles-3d-spatial-transformer.ts +0 -12
- package/src/tileset-3d/common/tileset-3d.ts +54 -12
- package/src/tileset-3d/common/tileset-traverser.ts +2 -4
- package/src/tileset-3d/format-3d-tiles/tileset-3d-traverser.ts +16 -4
|
@@ -6,8 +6,8 @@ import type {Geoid} from '@math.gl/geoid';
|
|
|
6
6
|
import {Vector3} from '@math.gl/core';
|
|
7
7
|
import {Ellipsoid} from '@math.gl/geospatial';
|
|
8
8
|
import type {ReadonlyCRSDefinition} from '@math.gl/crs';
|
|
9
|
-
import {Projection} from '@math.gl/projection';
|
|
10
|
-
import {getGeoidModel} from './spatial-resource-registry';
|
|
9
|
+
import type {Projection} from '@math.gl/projection';
|
|
10
|
+
import {getGeoidModel, getSpatialProjectionEngine} from './spatial-resource-registry';
|
|
11
11
|
import {
|
|
12
12
|
normalizeCrsIdentifier,
|
|
13
13
|
WGS84_GEOCENTRIC_CRS,
|
|
@@ -64,6 +64,7 @@ export class SpatialCoordinateTransformer {
|
|
|
64
64
|
*/
|
|
65
65
|
constructor(spatialReference: TilesetSpatialReference, options: TilesetSpatialOptions = {}) {
|
|
66
66
|
this.spatialReference = spatialReference;
|
|
67
|
+
const projectionEngine = getSpatialProjectionEngine();
|
|
67
68
|
validateTransformRequest(spatialReference);
|
|
68
69
|
const outputCrs = spatialReference.targetCrs || spatialReference.sourceCrs;
|
|
69
70
|
this.sourceIsGeocentric = isWgs84Geocentric(spatialReference.sourceCrs);
|
|
@@ -77,7 +78,7 @@ export class SpatialCoordinateTransformer {
|
|
|
77
78
|
!this.sourceIsGeocentric &&
|
|
78
79
|
!this.outputIsGeocentric
|
|
79
80
|
) {
|
|
80
|
-
this.horizontalProjection =
|
|
81
|
+
this.horizontalProjection = projectionEngine.createProjection({
|
|
81
82
|
from: getHorizontalProjectionDefinition(spatialReference.sourceCrs),
|
|
82
83
|
to: getHorizontalProjectionDefinition(spatialReference.targetCrs),
|
|
83
84
|
enforceAxis: false
|
|
@@ -90,14 +91,14 @@ export class SpatialCoordinateTransformer {
|
|
|
90
91
|
this.outputIsGeocentric
|
|
91
92
|
) {
|
|
92
93
|
if (!this.sourceIsGeographic && !this.sourceIsGeocentric) {
|
|
93
|
-
this.geographicProjection =
|
|
94
|
+
this.geographicProjection = projectionEngine.createProjection({
|
|
94
95
|
from: getHorizontalProjectionDefinition(spatialReference.sourceCrs),
|
|
95
96
|
to: WGS84_GEOGRAPHIC_CRS,
|
|
96
97
|
enforceAxis: false
|
|
97
98
|
});
|
|
98
99
|
}
|
|
99
100
|
if (!this.outputIsGeographic && !this.outputIsGeocentric) {
|
|
100
|
-
this.heightOutputProjection =
|
|
101
|
+
this.heightOutputProjection = projectionEngine.createProjection({
|
|
101
102
|
from: WGS84_GEOGRAPHIC_CRS,
|
|
102
103
|
to: getHorizontalProjectionDefinition(outputCrs),
|
|
103
104
|
enforceAxis: false
|
|
@@ -153,7 +154,7 @@ export class SpatialCoordinateTransformer {
|
|
|
153
154
|
}
|
|
154
155
|
|
|
155
156
|
if (this.horizontalProjection) {
|
|
156
|
-
const projected = this.horizontalProjection.
|
|
157
|
+
const projected = this.horizontalProjection.projectSync(result.slice(0, 3));
|
|
157
158
|
result.splice(0, projected.length, ...projected);
|
|
158
159
|
}
|
|
159
160
|
return result;
|
|
@@ -220,7 +221,7 @@ export class SpatialCoordinateTransformer {
|
|
|
220
221
|
if (this.sourceIsGeographic) {
|
|
221
222
|
return coordinate.slice(0, 3);
|
|
222
223
|
}
|
|
223
|
-
return this.geographicProjection!.
|
|
224
|
+
return this.geographicProjection!.projectSync(coordinate.slice(0, 3));
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
/** Convert one conventional WGS84 geographic coordinate to the selected output CRS. */
|
|
@@ -231,7 +232,7 @@ export class SpatialCoordinateTransformer {
|
|
|
231
232
|
if (this.outputIsGeographic) {
|
|
232
233
|
return coordinate.slice(0, 3);
|
|
233
234
|
}
|
|
234
|
-
return this.heightOutputProjection!.
|
|
235
|
+
return this.heightOutputProjection!.projectSync(coordinate.slice(0, 3));
|
|
235
236
|
}
|
|
236
237
|
}
|
|
237
238
|
|
|
@@ -3,10 +3,19 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import {Geoid, parsePGM} from '@math.gl/geoid';
|
|
6
|
-
import {
|
|
6
|
+
import {FullProjectionEngine, parseNTv2Grid} from '@math.gl/projection';
|
|
7
|
+
import type {DatumGrid, ProjectionEngine} from '@math.gl/projection';
|
|
7
8
|
import type {ReadonlyCRSDefinition} from '@math.gl/crs';
|
|
8
9
|
|
|
9
10
|
const geoidModels = new Map<string, Geoid>();
|
|
11
|
+
const projectionAliases: Record<string, ReadonlyCRSDefinition> = {};
|
|
12
|
+
const datumGrids: Record<string, DatumGrid> = {};
|
|
13
|
+
let spatialProjectionEngine: ProjectionEngine = new FullProjectionEngine();
|
|
14
|
+
|
|
15
|
+
/** Returns the projection engine containing application-registered spatial resources. */
|
|
16
|
+
export function getSpatialProjectionEngine(): ProjectionEngine {
|
|
17
|
+
return spatialProjectionEngine;
|
|
18
|
+
}
|
|
10
19
|
|
|
11
20
|
/**
|
|
12
21
|
* Registers an application-supplied CRS alias for deterministic coordinate transformations.
|
|
@@ -18,7 +27,8 @@ const geoidModels = new Map<string, Geoid>();
|
|
|
18
27
|
*/
|
|
19
28
|
export function registerSpatialCrs(name: string, definition: ReadonlyCRSDefinition): void {
|
|
20
29
|
validateResourceName(name, 'CRS');
|
|
21
|
-
|
|
30
|
+
projectionAliases[name] = definition;
|
|
31
|
+
spatialProjectionEngine = new FullProjectionEngine({aliases: projectionAliases, datumGrids});
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
/**
|
|
@@ -29,7 +39,8 @@ export function registerSpatialCrs(name: string, definition: ReadonlyCRSDefiniti
|
|
|
29
39
|
*/
|
|
30
40
|
export function registerSpatialDatumGrid(name: string, data: ArrayBuffer): void {
|
|
31
41
|
validateResourceName(name, 'datum grid');
|
|
32
|
-
|
|
42
|
+
datumGrids[name] = parseNTv2Grid(data);
|
|
43
|
+
spatialProjectionEngine = new FullProjectionEngine({aliases: projectionAliases, datumGrids});
|
|
33
44
|
}
|
|
34
45
|
|
|
35
46
|
/**
|
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import {SpatialCoordinateTransformer} from './spatial-coordinate-transformer';
|
|
6
|
-
import {getSpatialCoordinateFrame} from './get-spatial-coordinate-frame';
|
|
7
6
|
import {Matrix4} from '@math.gl/core';
|
|
8
|
-
import {Ellipsoid} from '@math.gl/geospatial';
|
|
9
7
|
import type {TilesetSpatialOptions, TilesetSpatialReference} from './spatial-types';
|
|
10
8
|
|
|
11
9
|
/** Structural 3D Tiles volume shape used by the source adapter. */
|
|
@@ -80,16 +78,6 @@ export class Tiles3DSpatialTransformer {
|
|
|
80
78
|
|
|
81
79
|
/** Transforms one WGS84 region sample into the selected output frame. */
|
|
82
80
|
private transformRegionSample(sample: number[]): number[] {
|
|
83
|
-
const [longitudeDegrees, latitudeDegrees, height] = sample;
|
|
84
|
-
const targetCrs = this.spatialReference.targetCrs || this.spatialReference.sourceCrs;
|
|
85
|
-
if (targetCrs && getSpatialCoordinateFrame(targetCrs) === 'geocentric') {
|
|
86
|
-
const cartesian = Ellipsoid.WGS84.cartographicToCartesian([
|
|
87
|
-
longitudeDegrees,
|
|
88
|
-
latitudeDegrees,
|
|
89
|
-
height
|
|
90
|
-
]);
|
|
91
|
-
return Array.from(cartesian);
|
|
92
|
-
}
|
|
93
81
|
return this.geographicCoordinateTransformer.transformPosition(sample);
|
|
94
82
|
}
|
|
95
83
|
}
|
|
@@ -73,7 +73,7 @@ export type Tileset3DProps = {
|
|
|
73
73
|
/**
|
|
74
74
|
* Enables replacement traversal that may skip hierarchy levels while retaining ready ancestors
|
|
75
75
|
* as coverage. This trades temporary overdraw for faster refinement on deep trees.
|
|
76
|
-
*
|
|
76
|
+
* Defaults to `true` for 3D Tiles and `false` for I3S. Set to `false` to request every level.
|
|
77
77
|
*/
|
|
78
78
|
skipLevelOfDetail?: boolean;
|
|
79
79
|
/**
|
|
@@ -393,7 +393,8 @@ export class Tileset3D {
|
|
|
393
393
|
_cache = new TilesetCache();
|
|
394
394
|
_requestScheduler: RequestScheduler;
|
|
395
395
|
|
|
396
|
-
|
|
396
|
+
/** Drawn fallback instances retained independently for each viewport tree. */
|
|
397
|
+
private _heldTiles: Set<Tile3D> = new Set();
|
|
397
398
|
private updatePromise: Promise<number> | null = null;
|
|
398
399
|
tilesetInitializationPromise: Promise<void>;
|
|
399
400
|
|
|
@@ -425,6 +426,7 @@ export class Tileset3D {
|
|
|
425
426
|
...suppliedOptions,
|
|
426
427
|
cacheBytes,
|
|
427
428
|
maximumCacheOverflowBytes,
|
|
429
|
+
skipLevelOfDetail: suppliedOptions.skipLevelOfDetail ?? source.type === TILESET_TYPE.TILES3D,
|
|
428
430
|
memoryAdjustedScreenSpaceError:
|
|
429
431
|
suppliedOptions.memoryAdjustedScreenSpaceError ?? usesTiles3DCacheDefaults
|
|
430
432
|
};
|
|
@@ -782,28 +784,50 @@ export class Tileset3D {
|
|
|
782
784
|
|
|
783
785
|
this.selectedTiles = this.options.onTraversalComplete(this.selectedTiles);
|
|
784
786
|
|
|
785
|
-
const
|
|
787
|
+
const selectedTiles = new Set(this.selectedTiles);
|
|
786
788
|
const hasUndrawnTiles = this.selectedTiles.some(tile => !tile.tileDrawn);
|
|
787
789
|
|
|
788
790
|
let heldBackCount = 0;
|
|
789
791
|
if (hasUndrawnTiles) {
|
|
790
|
-
|
|
791
|
-
this.
|
|
792
|
+
const activeRoots = new Set(
|
|
793
|
+
Object.keys(this.frameStateData).map(viewportId => this.roots[viewportId])
|
|
794
|
+
);
|
|
795
|
+
const descendantReadiness = new Map<Tile3D, boolean>();
|
|
796
|
+
for (const tile of this.selectedTiles) {
|
|
797
|
+
for (let ancestor = tile.parent; ancestor; ancestor = ancestor.parent) {
|
|
798
|
+
descendantReadiness.set(
|
|
799
|
+
ancestor,
|
|
800
|
+
(descendantReadiness.get(ancestor) ?? true) && tile.tileDrawn
|
|
801
|
+
);
|
|
802
|
+
}
|
|
792
803
|
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
804
|
+
// Drawing can finish between traversals. Promote only previously selected
|
|
805
|
+
// geometry that actually drew; pending tiles cannot provide visible fallback.
|
|
806
|
+
for (const tile of previousSelectedTiles) {
|
|
807
|
+
if (tile.tileDrawn) this._heldTiles.add(tile);
|
|
808
|
+
}
|
|
809
|
+
for (const tile of this._heldTiles) {
|
|
810
|
+
let root = tile;
|
|
811
|
+
while (root.parent) root = root.parent;
|
|
812
|
+
// Removed viewport trees cannot contribute fallback to the remaining views.
|
|
813
|
+
if (!activeRoots.has(root)) {
|
|
814
|
+
this._heldTiles.delete(tile);
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
if (selectedTiles.has(tile)) continue;
|
|
818
|
+
if (
|
|
819
|
+
tile.contentAvailable &&
|
|
820
|
+
!this._hasDrawnReplacement(tile, selectedTiles, descendantReadiness)
|
|
821
|
+
) {
|
|
798
822
|
tile._selectedFrame = this._frameNumber;
|
|
799
823
|
this.selectedTiles.push(tile);
|
|
800
824
|
heldBackCount++;
|
|
801
825
|
} else {
|
|
802
|
-
this._heldTiles.delete(
|
|
826
|
+
this._heldTiles.delete(tile);
|
|
803
827
|
}
|
|
804
828
|
}
|
|
805
829
|
} else {
|
|
806
|
-
this._heldTiles =
|
|
830
|
+
this._heldTiles = selectedTiles;
|
|
807
831
|
}
|
|
808
832
|
|
|
809
833
|
if (heldBackCount > 0) {
|
|
@@ -825,6 +849,24 @@ export class Tileset3D {
|
|
|
825
849
|
}
|
|
826
850
|
}
|
|
827
851
|
|
|
852
|
+
/**
|
|
853
|
+
* Releases fallback geometry once its own selected replacement has drawn.
|
|
854
|
+
* Unrelated pending branches must not delay this region's handoff. When no related
|
|
855
|
+
* replacement is selected, retain the fallback until the complete selection has drawn.
|
|
856
|
+
*/
|
|
857
|
+
private _hasDrawnReplacement(
|
|
858
|
+
tile: Tile3D,
|
|
859
|
+
selectedTiles: Set<Tile3D>,
|
|
860
|
+
descendantReadiness: Map<Tile3D, boolean>
|
|
861
|
+
): boolean {
|
|
862
|
+
for (let ancestor = tile.parent; ancestor; ancestor = ancestor.parent) {
|
|
863
|
+
if (selectedTiles.has(ancestor)) {
|
|
864
|
+
return ancestor.tileDrawn;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
return descendantReadiness.get(tile) === true;
|
|
868
|
+
}
|
|
869
|
+
|
|
828
870
|
_tilesChanged(oldSelectedTiles: Tile3D[], selectedTiles: Tile3D[]): boolean {
|
|
829
871
|
if (oldSelectedTiles.length !== selectedTiles.length) {
|
|
830
872
|
return true;
|
|
@@ -236,11 +236,9 @@ export class TilesetTraverser {
|
|
|
236
236
|
} else {
|
|
237
237
|
childRefines = child.contentAvailable;
|
|
238
238
|
}
|
|
239
|
+
// Readiness controls replacement, not discovery. Visit every sibling so
|
|
240
|
+
// one unavailable child cannot serialize requests or hide ready siblings.
|
|
239
241
|
refines = refines && childRefines;
|
|
240
|
-
|
|
241
|
-
if (!refines) {
|
|
242
|
-
return false;
|
|
243
|
-
}
|
|
244
242
|
}
|
|
245
243
|
}
|
|
246
244
|
|
|
@@ -70,7 +70,9 @@ export class Tileset3DTraverser extends TilesetTraverser {
|
|
|
70
70
|
if (!tile.hasRenderContent) {
|
|
71
71
|
this.emptyTiles[tile.id] = tile;
|
|
72
72
|
this.loadTile(tile, frameState);
|
|
73
|
-
|
|
73
|
+
// A known empty terminal branch needs no fallback geometry. Lazy child groups still
|
|
74
|
+
// report hasChildren while unresolved, so they retain coverage until materialized.
|
|
75
|
+
if (stoppedRefining && (!tile.hasEmptyContent || tile.hasChildren)) {
|
|
74
76
|
this.selectDesiredTile(tile, frameState);
|
|
75
77
|
}
|
|
76
78
|
} else if (tile.refine === TILE_REFINEMENT.ADD) {
|
|
@@ -121,7 +123,7 @@ export class Tileset3DTraverser extends TilesetTraverser {
|
|
|
121
123
|
if (child.isVisibleAndInRequestVolume) {
|
|
122
124
|
stack.push(child);
|
|
123
125
|
hasVisibleChild = true;
|
|
124
|
-
} else if (this.options.loadSiblings) {
|
|
126
|
+
} else if (this.options.loadSiblings && child._inRequestVolume) {
|
|
125
127
|
this.loadTile(child, frameState);
|
|
126
128
|
this.touchTile(child, frameState);
|
|
127
129
|
}
|
|
@@ -234,6 +236,11 @@ export class Tileset3DTraverser extends TilesetTraverser {
|
|
|
234
236
|
while (fallbackTile) {
|
|
235
237
|
if (this.shouldSelectTile(fallbackTile, frameState)) {
|
|
236
238
|
this.selectTile(fallbackTile, frameState);
|
|
239
|
+
if (fallbackTile !== tile) {
|
|
240
|
+
// On zoom-out the desired coarse level may still be unavailable. Preserve
|
|
241
|
+
// nearby detail that already drew while the ancestor fills uncovered pixels.
|
|
242
|
+
this.selectLoadedDescendants(tile, frameState, true);
|
|
243
|
+
}
|
|
237
244
|
return;
|
|
238
245
|
}
|
|
239
246
|
fallbackTile = fallbackTile.parent;
|
|
@@ -246,8 +253,13 @@ export class Tileset3DTraverser extends TilesetTraverser {
|
|
|
246
253
|
*
|
|
247
254
|
* @param root - Unavailable tile whose descendants are searched.
|
|
248
255
|
* @param frameState - Current culling state.
|
|
256
|
+
* @param drawnOnly - Reuse drawn detail without starting obsolete GPU work.
|
|
249
257
|
*/
|
|
250
|
-
private selectLoadedDescendants(
|
|
258
|
+
private selectLoadedDescendants(
|
|
259
|
+
root: Tile3D,
|
|
260
|
+
frameState: FrameState,
|
|
261
|
+
drawnOnly: boolean = false
|
|
262
|
+
): void {
|
|
251
263
|
const stack: Array<{tile: Tile3D; depth: number}> = [{tile: root, depth: 0}];
|
|
252
264
|
while (stack.length > 0) {
|
|
253
265
|
const {tile, depth} = stack.pop() as {tile: Tile3D; depth: number};
|
|
@@ -256,7 +268,7 @@ export class Tileset3DTraverser extends TilesetTraverser {
|
|
|
256
268
|
if (!child.isVisibleAndInRequestVolume) {
|
|
257
269
|
continue;
|
|
258
270
|
}
|
|
259
|
-
if (child.
|
|
271
|
+
if (this.shouldSelectTile(child, frameState) && (!drawnOnly || child.tileDrawn)) {
|
|
260
272
|
this.selectTile(child, frameState);
|
|
261
273
|
this.touchTile(child, frameState);
|
|
262
274
|
} else if (depth < 1) {
|