@loaders.gl/tiles 4.0.0-beta.1 → 4.0.0-beta.3
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/constants.js.map +1 -0
- package/dist/dist.dev.js +8162 -0
- package/dist/index.cjs +2537 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/{esm/tileset → tileset}/format-3d-tiles/tileset-3d-traverser.js +2 -2
- package/dist/tileset/format-3d-tiles/tileset-3d-traverser.js.map +1 -0
- package/dist/{esm/tileset → tileset}/format-i3s/i3s-pending-tiles-register.js +1 -2
- package/dist/tileset/format-i3s/i3s-pending-tiles-register.js.map +1 -0
- package/dist/{esm/tileset → tileset}/format-i3s/i3s-tile-manager.js +3 -4
- package/dist/tileset/format-i3s/i3s-tile-manager.js.map +1 -0
- package/dist/{esm/tileset → tileset}/format-i3s/i3s-tileset-traverser.js +7 -8
- package/dist/tileset/format-i3s/i3s-tileset-traverser.js.map +1 -0
- package/dist/tileset/helpers/3d-tiles-options.js.map +1 -0
- package/dist/tileset/helpers/bounding-volume.d.ts +1 -1
- package/dist/tileset/helpers/bounding-volume.d.ts.map +1 -1
- package/dist/{esm/tileset → tileset}/helpers/bounding-volume.js +16 -6
- package/dist/tileset/helpers/bounding-volume.js.map +1 -0
- package/dist/tileset/helpers/frame-state.js.map +1 -0
- package/dist/tileset/helpers/i3s-lod.js.map +1 -0
- package/dist/tileset/helpers/tiles-3d-lod.js.map +1 -0
- package/dist/tileset/helpers/transform-utils.js.map +1 -0
- package/dist/{esm/tileset → tileset}/helpers/zoom.js +2 -2
- package/dist/tileset/helpers/zoom.js.map +1 -0
- package/dist/tileset/tile-3d.d.ts.map +1 -1
- package/dist/{esm/tileset → tileset}/tile-3d.js +55 -56
- package/dist/tileset/tile-3d.js.map +1 -0
- package/dist/tileset/tileset-3d.d.ts.map +1 -1
- package/dist/{esm/tileset → tileset}/tileset-3d.js +68 -62
- package/dist/tileset/tileset-3d.js.map +1 -0
- package/dist/{esm/tileset → tileset}/tileset-cache.js +4 -5
- package/dist/tileset/tileset-cache.js.map +1 -0
- package/dist/{esm/tileset → tileset}/tileset-traverser.js +12 -13
- package/dist/tileset/tileset-traverser.js.map +1 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/doubly-linked-list-node.js +11 -0
- package/dist/utils/doubly-linked-list-node.js.map +1 -0
- package/dist/{esm/utils → utils}/doubly-linked-list.js +4 -5
- package/dist/utils/doubly-linked-list.js.map +1 -0
- package/dist/{esm/utils → utils}/managed-array.js +3 -4
- package/dist/utils/managed-array.js.map +1 -0
- package/package.json +20 -12
- package/src/tileset/helpers/bounding-volume.ts +53 -24
- package/src/tileset/helpers/zoom.ts +5 -5
- package/src/tileset/tile-3d.ts +1 -1
- package/src/tileset/tileset-3d.ts +12 -10
- package/dist/bundle.d.ts +0 -2
- package/dist/bundle.d.ts.map +0 -1
- package/dist/dist.min.js +0 -9227
- package/dist/es5/bundle.js +0 -6
- package/dist/es5/bundle.js.map +0 -1
- package/dist/es5/constants.js +0 -48
- package/dist/es5/constants.js.map +0 -1
- package/dist/es5/index.js +0 -93
- package/dist/es5/index.js.map +0 -1
- package/dist/es5/tileset/format-3d-tiles/tileset-3d-traverser.js +0 -70
- package/dist/es5/tileset/format-3d-tiles/tileset-3d-traverser.js.map +0 -1
- package/dist/es5/tileset/format-i3s/i3s-pending-tiles-register.js +0 -45
- package/dist/es5/tileset/format-i3s/i3s-pending-tiles-register.js.map +0 -1
- package/dist/es5/tileset/format-i3s/i3s-tile-manager.js +0 -84
- package/dist/es5/tileset/format-i3s/i3s-tile-manager.js.map +0 -1
- package/dist/es5/tileset/format-i3s/i3s-tileset-traverser.js +0 -143
- package/dist/es5/tileset/format-i3s/i3s-tileset-traverser.js.map +0 -1
- package/dist/es5/tileset/helpers/3d-tiles-options.js +0 -12
- package/dist/es5/tileset/helpers/3d-tiles-options.js.map +0 -1
- package/dist/es5/tileset/helpers/bounding-volume.js +0 -176
- package/dist/es5/tileset/helpers/bounding-volume.js.map +0 -1
- package/dist/es5/tileset/helpers/frame-state.js +0 -129
- package/dist/es5/tileset/helpers/frame-state.js.map +0 -1
- package/dist/es5/tileset/helpers/i3s-lod.js +0 -60
- package/dist/es5/tileset/helpers/i3s-lod.js.map +0 -1
- package/dist/es5/tileset/helpers/tiles-3d-lod.js +0 -103
- package/dist/es5/tileset/helpers/tiles-3d-lod.js.map +0 -1
- package/dist/es5/tileset/helpers/transform-utils.js +0 -50
- package/dist/es5/tileset/helpers/transform-utils.js.map +0 -1
- package/dist/es5/tileset/helpers/zoom.js +0 -63
- package/dist/es5/tileset/helpers/zoom.js.map +0 -1
- package/dist/es5/tileset/tile-3d.js +0 -536
- package/dist/es5/tileset/tile-3d.js.map +0 -1
- package/dist/es5/tileset/tileset-3d.js +0 -855
- package/dist/es5/tileset/tileset-3d.js.map +0 -1
- package/dist/es5/tileset/tileset-cache.js +0 -82
- package/dist/es5/tileset/tileset-cache.js.map +0 -1
- package/dist/es5/tileset/tileset-traverser.js +0 -321
- package/dist/es5/tileset/tileset-traverser.js.map +0 -1
- package/dist/es5/types.js +0 -2
- package/dist/es5/types.js.map +0 -1
- package/dist/es5/utils/doubly-linked-list-node.js +0 -21
- package/dist/es5/utils/doubly-linked-list-node.js.map +0 -1
- package/dist/es5/utils/doubly-linked-list.js +0 -88
- package/dist/es5/utils/doubly-linked-list.js.map +0 -1
- package/dist/es5/utils/managed-array.js +0 -126
- package/dist/es5/utils/managed-array.js.map +0 -1
- package/dist/esm/bundle.js +0 -4
- package/dist/esm/bundle.js.map +0 -1
- package/dist/esm/constants.js.map +0 -1
- package/dist/esm/index.js +0 -10
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/tileset/format-3d-tiles/tileset-3d-traverser.js.map +0 -1
- package/dist/esm/tileset/format-i3s/i3s-pending-tiles-register.js.map +0 -1
- package/dist/esm/tileset/format-i3s/i3s-tile-manager.js.map +0 -1
- package/dist/esm/tileset/format-i3s/i3s-tileset-traverser.js.map +0 -1
- package/dist/esm/tileset/helpers/3d-tiles-options.js.map +0 -1
- package/dist/esm/tileset/helpers/bounding-volume.js.map +0 -1
- package/dist/esm/tileset/helpers/frame-state.js.map +0 -1
- package/dist/esm/tileset/helpers/i3s-lod.js.map +0 -1
- package/dist/esm/tileset/helpers/tiles-3d-lod.js.map +0 -1
- package/dist/esm/tileset/helpers/transform-utils.js.map +0 -1
- package/dist/esm/tileset/helpers/zoom.js.map +0 -1
- package/dist/esm/tileset/tile-3d.js.map +0 -1
- package/dist/esm/tileset/tileset-3d.js.map +0 -1
- package/dist/esm/tileset/tileset-cache.js.map +0 -1
- package/dist/esm/tileset/tileset-traverser.js.map +0 -1
- package/dist/esm/types.js.map +0 -1
- package/dist/esm/utils/doubly-linked-list-node.js +0 -12
- package/dist/esm/utils/doubly-linked-list-node.js.map +0 -1
- package/dist/esm/utils/doubly-linked-list.js.map +0 -1
- package/dist/esm/utils/managed-array.js.map +0 -1
- package/src/bundle.ts +0 -4
- /package/dist/{esm/constants.js → constants.js} +0 -0
- /package/dist/{esm/tileset → tileset}/helpers/3d-tiles-options.js +0 -0
- /package/dist/{esm/tileset → tileset}/helpers/frame-state.js +0 -0
- /package/dist/{esm/tileset → tileset}/helpers/i3s-lod.js +0 -0
- /package/dist/{esm/tileset → tileset}/helpers/tiles-3d-lod.js +0 -0
- /package/dist/{esm/tileset → tileset}/helpers/transform-utils.js +0 -0
- /package/dist/{esm/types.js → types.js} +0 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2537 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
LOD_METRIC_TYPE: () => LOD_METRIC_TYPE,
|
|
24
|
+
TILESET_TYPE: () => TILESET_TYPE,
|
|
25
|
+
TILE_CONTENT_STATE: () => TILE_CONTENT_STATE,
|
|
26
|
+
TILE_REFINEMENT: () => TILE_REFINEMENT,
|
|
27
|
+
TILE_TYPE: () => TILE_TYPE,
|
|
28
|
+
Tile3D: () => Tile3D,
|
|
29
|
+
Tileset3D: () => Tileset3D,
|
|
30
|
+
TilesetCache: () => TilesetCache,
|
|
31
|
+
TilesetTraverser: () => TilesetTraverser,
|
|
32
|
+
calculateTransformProps: () => calculateTransformProps,
|
|
33
|
+
createBoundingVolume: () => createBoundingVolume,
|
|
34
|
+
getFrameState: () => getFrameState,
|
|
35
|
+
getLodStatus: () => getLodStatus
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(src_exports);
|
|
38
|
+
|
|
39
|
+
// src/tileset/tileset-3d.ts
|
|
40
|
+
var import_core10 = require("@math.gl/core");
|
|
41
|
+
var import_geospatial6 = require("@math.gl/geospatial");
|
|
42
|
+
var import_stats = require("@probe.gl/stats");
|
|
43
|
+
var import_loader_utils4 = require("@loaders.gl/loader-utils");
|
|
44
|
+
|
|
45
|
+
// src/utils/doubly-linked-list-node.ts
|
|
46
|
+
var DoublyLinkedListNode = class {
|
|
47
|
+
constructor(item, previous, next) {
|
|
48
|
+
this.item = item;
|
|
49
|
+
this.previous = previous;
|
|
50
|
+
this.next = next;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// src/utils/doubly-linked-list.ts
|
|
55
|
+
var DoublyLinkedList = class {
|
|
56
|
+
constructor() {
|
|
57
|
+
this.head = null;
|
|
58
|
+
this.tail = null;
|
|
59
|
+
this._length = 0;
|
|
60
|
+
}
|
|
61
|
+
get length() {
|
|
62
|
+
return this._length;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Adds the item to the end of the list
|
|
66
|
+
* @param {*} [item]
|
|
67
|
+
* @return {DoublyLinkedListNode}
|
|
68
|
+
*/
|
|
69
|
+
add(item) {
|
|
70
|
+
const node = new DoublyLinkedListNode(item, this.tail, null);
|
|
71
|
+
if (this.tail) {
|
|
72
|
+
this.tail.next = node;
|
|
73
|
+
this.tail = node;
|
|
74
|
+
} else {
|
|
75
|
+
this.head = node;
|
|
76
|
+
this.tail = node;
|
|
77
|
+
}
|
|
78
|
+
++this._length;
|
|
79
|
+
return node;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Removes the given node from the list
|
|
83
|
+
* @param {DoublyLinkedListNode} node
|
|
84
|
+
*/
|
|
85
|
+
remove(node) {
|
|
86
|
+
if (!node) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (node.previous && node.next) {
|
|
90
|
+
node.previous.next = node.next;
|
|
91
|
+
node.next.previous = node.previous;
|
|
92
|
+
} else if (node.previous) {
|
|
93
|
+
node.previous.next = null;
|
|
94
|
+
this.tail = node.previous;
|
|
95
|
+
} else if (node.next) {
|
|
96
|
+
node.next.previous = null;
|
|
97
|
+
this.head = node.next;
|
|
98
|
+
} else {
|
|
99
|
+
this.head = null;
|
|
100
|
+
this.tail = null;
|
|
101
|
+
}
|
|
102
|
+
node.next = null;
|
|
103
|
+
node.previous = null;
|
|
104
|
+
--this._length;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Moves nextNode after node
|
|
108
|
+
* @param {DoublyLinkedListNode} node
|
|
109
|
+
* @param {DoublyLinkedListNode} nextNode
|
|
110
|
+
*/
|
|
111
|
+
splice(node, nextNode) {
|
|
112
|
+
if (node === nextNode) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
this.remove(nextNode);
|
|
116
|
+
this._insert(node, nextNode);
|
|
117
|
+
}
|
|
118
|
+
_insert(node, nextNode) {
|
|
119
|
+
const oldNodeNext = node.next;
|
|
120
|
+
node.next = nextNode;
|
|
121
|
+
if (this.tail === node) {
|
|
122
|
+
this.tail = nextNode;
|
|
123
|
+
} else {
|
|
124
|
+
oldNodeNext.previous = nextNode;
|
|
125
|
+
}
|
|
126
|
+
nextNode.next = oldNodeNext;
|
|
127
|
+
nextNode.previous = node;
|
|
128
|
+
++this._length;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// src/tileset/tileset-cache.ts
|
|
133
|
+
var TilesetCache = class {
|
|
134
|
+
constructor() {
|
|
135
|
+
this._list = new DoublyLinkedList();
|
|
136
|
+
this._sentinel = this._list.add("sentinel");
|
|
137
|
+
this._trimTiles = false;
|
|
138
|
+
}
|
|
139
|
+
reset() {
|
|
140
|
+
this._list.splice(this._list.tail, this._sentinel);
|
|
141
|
+
}
|
|
142
|
+
touch(tile) {
|
|
143
|
+
const node = tile._cacheNode;
|
|
144
|
+
if (node) {
|
|
145
|
+
this._list.splice(this._sentinel, node);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
add(tileset, tile, addCallback) {
|
|
149
|
+
if (!tile._cacheNode) {
|
|
150
|
+
tile._cacheNode = this._list.add(tile);
|
|
151
|
+
if (addCallback) {
|
|
152
|
+
addCallback(tileset, tile);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
unloadTile(tileset, tile, unloadCallback) {
|
|
157
|
+
const node = tile._cacheNode;
|
|
158
|
+
if (!node) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
this._list.remove(node);
|
|
162
|
+
tile._cacheNode = null;
|
|
163
|
+
if (unloadCallback) {
|
|
164
|
+
unloadCallback(tileset, tile);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
unloadTiles(tileset, unloadCallback) {
|
|
168
|
+
const trimTiles = this._trimTiles;
|
|
169
|
+
this._trimTiles = false;
|
|
170
|
+
const list = this._list;
|
|
171
|
+
const maximumMemoryUsageInBytes = tileset.maximumMemoryUsage * 1024 * 1024;
|
|
172
|
+
const sentinel = this._sentinel;
|
|
173
|
+
let node = list.head;
|
|
174
|
+
while (node !== sentinel && (tileset.gpuMemoryUsageInBytes > maximumMemoryUsageInBytes || trimTiles)) {
|
|
175
|
+
const tile = node.item;
|
|
176
|
+
node = node.next;
|
|
177
|
+
this.unloadTile(tileset, tile, unloadCallback);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
trim() {
|
|
181
|
+
this._trimTiles = true;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// src/tileset/helpers/transform-utils.ts
|
|
186
|
+
var import_geospatial = require("@math.gl/geospatial");
|
|
187
|
+
var import_core = require("@math.gl/core");
|
|
188
|
+
var import_loader_utils = require("@loaders.gl/loader-utils");
|
|
189
|
+
function calculateTransformProps(tileHeader, tile) {
|
|
190
|
+
(0, import_loader_utils.assert)(tileHeader);
|
|
191
|
+
(0, import_loader_utils.assert)(tile);
|
|
192
|
+
const { rtcCenter, gltfUpAxis } = tile;
|
|
193
|
+
const {
|
|
194
|
+
computedTransform,
|
|
195
|
+
boundingVolume: { center }
|
|
196
|
+
} = tileHeader;
|
|
197
|
+
let modelMatrix = new import_core.Matrix4(computedTransform);
|
|
198
|
+
if (rtcCenter) {
|
|
199
|
+
modelMatrix.translate(rtcCenter);
|
|
200
|
+
}
|
|
201
|
+
switch (gltfUpAxis) {
|
|
202
|
+
case "Z":
|
|
203
|
+
break;
|
|
204
|
+
case "Y":
|
|
205
|
+
const rotationY = new import_core.Matrix4().rotateX(Math.PI / 2);
|
|
206
|
+
modelMatrix = modelMatrix.multiplyRight(rotationY);
|
|
207
|
+
break;
|
|
208
|
+
case "X":
|
|
209
|
+
const rotationX = new import_core.Matrix4().rotateY(-Math.PI / 2);
|
|
210
|
+
modelMatrix = modelMatrix.multiplyRight(rotationX);
|
|
211
|
+
break;
|
|
212
|
+
default:
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
if (tile.isQuantized) {
|
|
216
|
+
modelMatrix.translate(tile.quantizedVolumeOffset).scale(tile.quantizedVolumeScale);
|
|
217
|
+
}
|
|
218
|
+
const cartesianOrigin = new import_core.Vector3(center);
|
|
219
|
+
tile.cartesianModelMatrix = modelMatrix;
|
|
220
|
+
tile.cartesianOrigin = cartesianOrigin;
|
|
221
|
+
const cartographicOrigin = import_geospatial.Ellipsoid.WGS84.cartesianToCartographic(
|
|
222
|
+
cartesianOrigin,
|
|
223
|
+
new import_core.Vector3()
|
|
224
|
+
);
|
|
225
|
+
const fromFixedFrameMatrix = import_geospatial.Ellipsoid.WGS84.eastNorthUpToFixedFrame(cartesianOrigin);
|
|
226
|
+
const toFixedFrameMatrix = fromFixedFrameMatrix.invert();
|
|
227
|
+
tile.cartographicModelMatrix = toFixedFrameMatrix.multiplyRight(modelMatrix);
|
|
228
|
+
tile.cartographicOrigin = cartographicOrigin;
|
|
229
|
+
if (!tile.coordinateSystem) {
|
|
230
|
+
tile.modelMatrix = tile.cartographicModelMatrix;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/tileset/helpers/frame-state.ts
|
|
235
|
+
var import_core2 = require("@math.gl/core");
|
|
236
|
+
var import_culling = require("@math.gl/culling");
|
|
237
|
+
var import_geospatial2 = require("@math.gl/geospatial");
|
|
238
|
+
var scratchVector = new import_core2.Vector3();
|
|
239
|
+
var scratchPosition = new import_core2.Vector3();
|
|
240
|
+
var cullingVolume = new import_culling.CullingVolume([
|
|
241
|
+
new import_culling.Plane(),
|
|
242
|
+
new import_culling.Plane(),
|
|
243
|
+
new import_culling.Plane(),
|
|
244
|
+
new import_culling.Plane(),
|
|
245
|
+
new import_culling.Plane(),
|
|
246
|
+
new import_culling.Plane()
|
|
247
|
+
]);
|
|
248
|
+
function getFrameState(viewport, frameNumber) {
|
|
249
|
+
const { cameraDirection, cameraUp, height } = viewport;
|
|
250
|
+
const { metersPerUnit } = viewport.distanceScales;
|
|
251
|
+
const viewportCenterCartesian = worldToCartesian(viewport, viewport.center);
|
|
252
|
+
const enuToFixedTransform = import_geospatial2.Ellipsoid.WGS84.eastNorthUpToFixedFrame(viewportCenterCartesian);
|
|
253
|
+
const cameraPositionCartographic = viewport.unprojectPosition(viewport.cameraPosition);
|
|
254
|
+
const cameraPositionCartesian2 = import_geospatial2.Ellipsoid.WGS84.cartographicToCartesian(
|
|
255
|
+
cameraPositionCartographic,
|
|
256
|
+
new import_core2.Vector3()
|
|
257
|
+
);
|
|
258
|
+
const cameraDirectionCartesian = new import_core2.Vector3(
|
|
259
|
+
// @ts-ignore
|
|
260
|
+
enuToFixedTransform.transformAsVector(new import_core2.Vector3(cameraDirection).scale(metersPerUnit))
|
|
261
|
+
).normalize();
|
|
262
|
+
const cameraUpCartesian = new import_core2.Vector3(
|
|
263
|
+
// @ts-ignore
|
|
264
|
+
enuToFixedTransform.transformAsVector(new import_core2.Vector3(cameraUp).scale(metersPerUnit))
|
|
265
|
+
).normalize();
|
|
266
|
+
commonSpacePlanesToWGS84(viewport);
|
|
267
|
+
const ViewportClass = viewport.constructor;
|
|
268
|
+
const { longitude, latitude, width, bearing, zoom } = viewport;
|
|
269
|
+
const topDownViewport = new ViewportClass({
|
|
270
|
+
longitude,
|
|
271
|
+
latitude,
|
|
272
|
+
height,
|
|
273
|
+
width,
|
|
274
|
+
bearing,
|
|
275
|
+
zoom,
|
|
276
|
+
pitch: 0
|
|
277
|
+
});
|
|
278
|
+
return {
|
|
279
|
+
camera: {
|
|
280
|
+
position: cameraPositionCartesian2,
|
|
281
|
+
direction: cameraDirectionCartesian,
|
|
282
|
+
up: cameraUpCartesian
|
|
283
|
+
},
|
|
284
|
+
viewport,
|
|
285
|
+
topDownViewport,
|
|
286
|
+
height,
|
|
287
|
+
cullingVolume,
|
|
288
|
+
frameNumber,
|
|
289
|
+
// TODO: This can be the same between updates, what number is unique for between updates?
|
|
290
|
+
sseDenominator: 1.15
|
|
291
|
+
// Assumes fovy = 60 degrees
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function limitSelectedTiles(tiles, frameState, maximumTilesSelected) {
|
|
295
|
+
if (maximumTilesSelected === 0 || tiles.length <= maximumTilesSelected) {
|
|
296
|
+
return [tiles, []];
|
|
297
|
+
}
|
|
298
|
+
const tuples = [];
|
|
299
|
+
const { longitude: viewportLongitude, latitude: viewportLatitude } = frameState.viewport;
|
|
300
|
+
for (const [index, tile] of tiles.entries()) {
|
|
301
|
+
const [longitude, latitude] = tile.header.mbs;
|
|
302
|
+
const deltaLon = Math.abs(viewportLongitude - longitude);
|
|
303
|
+
const deltaLat = Math.abs(viewportLatitude - latitude);
|
|
304
|
+
const distance = Math.sqrt(deltaLat * deltaLat + deltaLon * deltaLon);
|
|
305
|
+
tuples.push([index, distance]);
|
|
306
|
+
}
|
|
307
|
+
const tuplesSorted = tuples.sort((a, b) => a[1] - b[1]);
|
|
308
|
+
const selectedTiles = [];
|
|
309
|
+
for (let i = 0; i < maximumTilesSelected; i++) {
|
|
310
|
+
selectedTiles.push(tiles[tuplesSorted[i][0]]);
|
|
311
|
+
}
|
|
312
|
+
const unselectedTiles = [];
|
|
313
|
+
for (let i = maximumTilesSelected; i < tuplesSorted.length; i++) {
|
|
314
|
+
unselectedTiles.push(tiles[tuplesSorted[i][0]]);
|
|
315
|
+
}
|
|
316
|
+
return [selectedTiles, unselectedTiles];
|
|
317
|
+
}
|
|
318
|
+
function commonSpacePlanesToWGS84(viewport) {
|
|
319
|
+
const frustumPlanes = viewport.getFrustumPlanes();
|
|
320
|
+
const nearCenterCommon = closestPointOnPlane(frustumPlanes.near, viewport.cameraPosition);
|
|
321
|
+
const nearCenterCartesian = worldToCartesian(viewport, nearCenterCommon);
|
|
322
|
+
const cameraCartesian = worldToCartesian(viewport, viewport.cameraPosition, scratchPosition);
|
|
323
|
+
let i = 0;
|
|
324
|
+
cullingVolume.planes[i++].fromPointNormal(
|
|
325
|
+
nearCenterCartesian,
|
|
326
|
+
scratchVector.copy(nearCenterCartesian).subtract(cameraCartesian)
|
|
327
|
+
);
|
|
328
|
+
for (const dir in frustumPlanes) {
|
|
329
|
+
if (dir === "near") {
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const plane = frustumPlanes[dir];
|
|
333
|
+
const posCommon = closestPointOnPlane(plane, nearCenterCommon, scratchPosition);
|
|
334
|
+
const cartesianPos = worldToCartesian(viewport, posCommon, scratchPosition);
|
|
335
|
+
cullingVolume.planes[i++].fromPointNormal(
|
|
336
|
+
cartesianPos,
|
|
337
|
+
// Want the normal to point into the frustum since that's what culling expects
|
|
338
|
+
scratchVector.copy(nearCenterCartesian).subtract(cartesianPos)
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function closestPointOnPlane(plane, refPoint, out = new import_core2.Vector3()) {
|
|
343
|
+
const distanceToRef = plane.normal.dot(refPoint);
|
|
344
|
+
out.copy(plane.normal).scale(plane.distance - distanceToRef).add(refPoint);
|
|
345
|
+
return out;
|
|
346
|
+
}
|
|
347
|
+
function worldToCartesian(viewport, point, out = new import_core2.Vector3()) {
|
|
348
|
+
const cartographicPos = viewport.unprojectPosition(point);
|
|
349
|
+
return import_geospatial2.Ellipsoid.WGS84.cartographicToCartesian(cartographicPos, out);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/tileset/helpers/zoom.ts
|
|
353
|
+
var import_core3 = require("@math.gl/core");
|
|
354
|
+
var import_culling2 = require("@math.gl/culling");
|
|
355
|
+
var import_geospatial3 = require("@math.gl/geospatial");
|
|
356
|
+
var WGS84_RADIUS_X = 6378137;
|
|
357
|
+
var WGS84_RADIUS_Y = 6378137;
|
|
358
|
+
var WGS84_RADIUS_Z = 6356752314245179e-9;
|
|
359
|
+
var scratchVector2 = new import_core3.Vector3();
|
|
360
|
+
function getZoomFromBoundingVolume(boundingVolume, cartorgraphicCenter) {
|
|
361
|
+
if (boundingVolume instanceof import_culling2.OrientedBoundingBox) {
|
|
362
|
+
const { halfAxes } = boundingVolume;
|
|
363
|
+
const obbSize = getObbSize(halfAxes);
|
|
364
|
+
return Math.log2(WGS84_RADIUS_Z / (obbSize + cartorgraphicCenter[2]));
|
|
365
|
+
} else if (boundingVolume instanceof import_culling2.BoundingSphere) {
|
|
366
|
+
const { radius } = boundingVolume;
|
|
367
|
+
return Math.log2(WGS84_RADIUS_Z / (radius + cartorgraphicCenter[2]));
|
|
368
|
+
} else if (boundingVolume.width && boundingVolume.height) {
|
|
369
|
+
const { width, height } = boundingVolume;
|
|
370
|
+
const zoomX = Math.log2(WGS84_RADIUS_X / width);
|
|
371
|
+
const zoomY = Math.log2(WGS84_RADIUS_Y / height);
|
|
372
|
+
return (zoomX + zoomY) / 2;
|
|
373
|
+
}
|
|
374
|
+
return 1;
|
|
375
|
+
}
|
|
376
|
+
function getZoomFromFullExtent(fullExtent, cartorgraphicCenter, cartesianCenter) {
|
|
377
|
+
import_geospatial3.Ellipsoid.WGS84.cartographicToCartesian(
|
|
378
|
+
[fullExtent.xmax, fullExtent.ymax, fullExtent.zmax],
|
|
379
|
+
scratchVector2
|
|
380
|
+
);
|
|
381
|
+
const extentSize = Math.sqrt(
|
|
382
|
+
Math.pow(scratchVector2[0] - cartesianCenter[0], 2) + Math.pow(scratchVector2[1] - cartesianCenter[1], 2) + Math.pow(scratchVector2[2] - cartesianCenter[2], 2)
|
|
383
|
+
);
|
|
384
|
+
return Math.log2(WGS84_RADIUS_Z / (extentSize + cartorgraphicCenter[2]));
|
|
385
|
+
}
|
|
386
|
+
function getZoomFromExtent(extent, cartorgraphicCenter, cartesianCenter) {
|
|
387
|
+
const [xmin, ymin, xmax, ymax] = extent;
|
|
388
|
+
return getZoomFromFullExtent(
|
|
389
|
+
{ xmin, xmax, ymin, ymax, zmin: 0, zmax: 0 },
|
|
390
|
+
cartorgraphicCenter,
|
|
391
|
+
cartesianCenter
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
function getObbSize(halfAxes) {
|
|
395
|
+
halfAxes.getColumn(0, scratchVector2);
|
|
396
|
+
const axeY = halfAxes.getColumn(1);
|
|
397
|
+
const axeZ = halfAxes.getColumn(2);
|
|
398
|
+
const farthestVertex = scratchVector2.add(axeY).add(axeZ);
|
|
399
|
+
const size = farthestVertex.len();
|
|
400
|
+
return size;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// src/tileset/tile-3d.ts
|
|
404
|
+
var import_core7 = require("@math.gl/core");
|
|
405
|
+
var import_culling4 = require("@math.gl/culling");
|
|
406
|
+
var import_core8 = require("@loaders.gl/core");
|
|
407
|
+
|
|
408
|
+
// src/constants.ts
|
|
409
|
+
var TILE_CONTENT_STATE = {
|
|
410
|
+
UNLOADED: 0,
|
|
411
|
+
// Has never been requested
|
|
412
|
+
LOADING: 1,
|
|
413
|
+
// Is waiting on a pending request
|
|
414
|
+
PROCESSING: 2,
|
|
415
|
+
// Request received. Contents are being processed for rendering. Depending on the content, it might make its own requests for external data.
|
|
416
|
+
READY: 3,
|
|
417
|
+
// Ready to render.
|
|
418
|
+
EXPIRED: 4,
|
|
419
|
+
// Is expired and will be unloaded once new content is loaded.
|
|
420
|
+
FAILED: 5
|
|
421
|
+
// Request failed.
|
|
422
|
+
};
|
|
423
|
+
var TILE_REFINEMENT = /* @__PURE__ */ ((TILE_REFINEMENT2) => {
|
|
424
|
+
TILE_REFINEMENT2[TILE_REFINEMENT2["ADD"] = 1] = "ADD";
|
|
425
|
+
TILE_REFINEMENT2[TILE_REFINEMENT2["REPLACE"] = 2] = "REPLACE";
|
|
426
|
+
return TILE_REFINEMENT2;
|
|
427
|
+
})(TILE_REFINEMENT || {});
|
|
428
|
+
var TILE_TYPE = /* @__PURE__ */ ((TILE_TYPE2) => {
|
|
429
|
+
TILE_TYPE2["EMPTY"] = "empty";
|
|
430
|
+
TILE_TYPE2["SCENEGRAPH"] = "scenegraph";
|
|
431
|
+
TILE_TYPE2["POINTCLOUD"] = "pointcloud";
|
|
432
|
+
TILE_TYPE2["MESH"] = "mesh";
|
|
433
|
+
return TILE_TYPE2;
|
|
434
|
+
})(TILE_TYPE || {});
|
|
435
|
+
var TILESET_TYPE = /* @__PURE__ */ ((TILESET_TYPE2) => {
|
|
436
|
+
TILESET_TYPE2["I3S"] = "I3S";
|
|
437
|
+
TILESET_TYPE2["TILES3D"] = "TILES3D";
|
|
438
|
+
return TILESET_TYPE2;
|
|
439
|
+
})(TILESET_TYPE || {});
|
|
440
|
+
var LOD_METRIC_TYPE = /* @__PURE__ */ ((LOD_METRIC_TYPE2) => {
|
|
441
|
+
LOD_METRIC_TYPE2["GEOMETRIC_ERROR"] = "geometricError";
|
|
442
|
+
LOD_METRIC_TYPE2["MAX_SCREEN_THRESHOLD"] = "maxScreenThreshold";
|
|
443
|
+
return LOD_METRIC_TYPE2;
|
|
444
|
+
})(LOD_METRIC_TYPE || {});
|
|
445
|
+
var TILE3D_OPTIMIZATION_HINT = {
|
|
446
|
+
NOT_COMPUTED: -1,
|
|
447
|
+
USE_OPTIMIZATION: 1,
|
|
448
|
+
SKIP_OPTIMIZATION: 0
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
// src/tileset/helpers/bounding-volume.ts
|
|
452
|
+
var import_core4 = require("@math.gl/core");
|
|
453
|
+
var import_culling3 = require("@math.gl/culling");
|
|
454
|
+
var import_geospatial4 = require("@math.gl/geospatial");
|
|
455
|
+
var import_loader_utils2 = require("@loaders.gl/loader-utils");
|
|
456
|
+
function defined(x) {
|
|
457
|
+
return x !== void 0 && x !== null;
|
|
458
|
+
}
|
|
459
|
+
var scratchPoint = new import_core4.Vector3();
|
|
460
|
+
var scratchScale = new import_core4.Vector3();
|
|
461
|
+
var scratchNorthWest = new import_core4.Vector3();
|
|
462
|
+
var scratchSouthEast = new import_core4.Vector3();
|
|
463
|
+
var scratchCenter = new import_core4.Vector3();
|
|
464
|
+
var scratchXAxis = new import_core4.Vector3();
|
|
465
|
+
var scratchYAxis = new import_core4.Vector3();
|
|
466
|
+
var scratchZAxis = new import_core4.Vector3();
|
|
467
|
+
function createBoundingVolume(boundingVolumeHeader, transform, result) {
|
|
468
|
+
(0, import_loader_utils2.assert)(boundingVolumeHeader, "3D Tile: boundingVolume must be defined");
|
|
469
|
+
if (boundingVolumeHeader.box) {
|
|
470
|
+
return createBox(boundingVolumeHeader.box, transform, result);
|
|
471
|
+
}
|
|
472
|
+
if (boundingVolumeHeader.region) {
|
|
473
|
+
return createObbFromRegion(boundingVolumeHeader.region);
|
|
474
|
+
}
|
|
475
|
+
if (boundingVolumeHeader.sphere) {
|
|
476
|
+
return createSphere(boundingVolumeHeader.sphere, transform, result);
|
|
477
|
+
}
|
|
478
|
+
throw new Error("3D Tile: boundingVolume must contain a sphere, region, or box");
|
|
479
|
+
}
|
|
480
|
+
function getCartographicBounds(boundingVolumeHeader, boundingVolume) {
|
|
481
|
+
if (boundingVolumeHeader.box) {
|
|
482
|
+
return orientedBoundingBoxToCartographicBounds(boundingVolume);
|
|
483
|
+
}
|
|
484
|
+
if (boundingVolumeHeader.region) {
|
|
485
|
+
const [west, south, east, north, minHeight, maxHeight] = boundingVolumeHeader.region;
|
|
486
|
+
return [
|
|
487
|
+
[(0, import_core4.degrees)(west), (0, import_core4.degrees)(south), minHeight],
|
|
488
|
+
[(0, import_core4.degrees)(east), (0, import_core4.degrees)(north), maxHeight]
|
|
489
|
+
];
|
|
490
|
+
}
|
|
491
|
+
if (boundingVolumeHeader.sphere) {
|
|
492
|
+
return boundingSphereToCartographicBounds(boundingVolume);
|
|
493
|
+
}
|
|
494
|
+
throw new Error("Unkown boundingVolume type");
|
|
495
|
+
}
|
|
496
|
+
function createBox(box, transform, result) {
|
|
497
|
+
const center = new import_core4.Vector3(box[0], box[1], box[2]);
|
|
498
|
+
transform.transform(center, center);
|
|
499
|
+
let origin = [];
|
|
500
|
+
if (box.length === 10) {
|
|
501
|
+
const halfSize = box.slice(3, 6);
|
|
502
|
+
const quaternion = new import_core4.Quaternion();
|
|
503
|
+
quaternion.fromArray(box, 6);
|
|
504
|
+
const x = new import_core4.Vector3([1, 0, 0]);
|
|
505
|
+
const y = new import_core4.Vector3([0, 1, 0]);
|
|
506
|
+
const z = new import_core4.Vector3([0, 0, 1]);
|
|
507
|
+
x.transformByQuaternion(quaternion);
|
|
508
|
+
x.scale(halfSize[0]);
|
|
509
|
+
y.transformByQuaternion(quaternion);
|
|
510
|
+
y.scale(halfSize[1]);
|
|
511
|
+
z.transformByQuaternion(quaternion);
|
|
512
|
+
z.scale(halfSize[2]);
|
|
513
|
+
origin = [...x.toArray(), ...y.toArray(), ...z.toArray()];
|
|
514
|
+
} else {
|
|
515
|
+
origin = [...box.slice(3, 6), ...box.slice(6, 9), ...box.slice(9, 12)];
|
|
516
|
+
}
|
|
517
|
+
const xAxis = transform.transformAsVector(origin.slice(0, 3));
|
|
518
|
+
const yAxis = transform.transformAsVector(origin.slice(3, 6));
|
|
519
|
+
const zAxis = transform.transformAsVector(origin.slice(6, 9));
|
|
520
|
+
const halfAxes = new import_core4.Matrix3([
|
|
521
|
+
xAxis[0],
|
|
522
|
+
xAxis[1],
|
|
523
|
+
xAxis[2],
|
|
524
|
+
yAxis[0],
|
|
525
|
+
yAxis[1],
|
|
526
|
+
yAxis[2],
|
|
527
|
+
zAxis[0],
|
|
528
|
+
zAxis[1],
|
|
529
|
+
zAxis[2]
|
|
530
|
+
]);
|
|
531
|
+
if (defined(result)) {
|
|
532
|
+
result.center = center;
|
|
533
|
+
result.halfAxes = halfAxes;
|
|
534
|
+
return result;
|
|
535
|
+
}
|
|
536
|
+
return new import_culling3.OrientedBoundingBox(center, halfAxes);
|
|
537
|
+
}
|
|
538
|
+
function createSphere(sphere, transform, result) {
|
|
539
|
+
const center = new import_core4.Vector3(sphere[0], sphere[1], sphere[2]);
|
|
540
|
+
transform.transform(center, center);
|
|
541
|
+
const scale = transform.getScale(scratchScale);
|
|
542
|
+
const uniformScale = Math.max(Math.max(scale[0], scale[1]), scale[2]);
|
|
543
|
+
const radius = sphere[3] * uniformScale;
|
|
544
|
+
if (defined(result)) {
|
|
545
|
+
result.center = center;
|
|
546
|
+
result.radius = radius;
|
|
547
|
+
return result;
|
|
548
|
+
}
|
|
549
|
+
return new import_culling3.BoundingSphere(center, radius);
|
|
550
|
+
}
|
|
551
|
+
function createObbFromRegion(region) {
|
|
552
|
+
const [west, south, east, north, minHeight, maxHeight] = region;
|
|
553
|
+
const northWest = import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian(
|
|
554
|
+
[(0, import_core4.degrees)(west), (0, import_core4.degrees)(north), minHeight],
|
|
555
|
+
scratchNorthWest
|
|
556
|
+
);
|
|
557
|
+
const southEast = import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian(
|
|
558
|
+
[(0, import_core4.degrees)(east), (0, import_core4.degrees)(south), maxHeight],
|
|
559
|
+
scratchSouthEast
|
|
560
|
+
);
|
|
561
|
+
const centerInCartesian = new import_core4.Vector3().addVectors(northWest, southEast).multiplyByScalar(0.5);
|
|
562
|
+
import_geospatial4.Ellipsoid.WGS84.cartesianToCartographic(centerInCartesian, scratchCenter);
|
|
563
|
+
import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian(
|
|
564
|
+
[(0, import_core4.degrees)(east), scratchCenter[1], scratchCenter[2]],
|
|
565
|
+
scratchXAxis
|
|
566
|
+
);
|
|
567
|
+
import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian(
|
|
568
|
+
[scratchCenter[0], (0, import_core4.degrees)(north), scratchCenter[2]],
|
|
569
|
+
scratchYAxis
|
|
570
|
+
);
|
|
571
|
+
import_geospatial4.Ellipsoid.WGS84.cartographicToCartesian(
|
|
572
|
+
[scratchCenter[0], scratchCenter[1], maxHeight],
|
|
573
|
+
scratchZAxis
|
|
574
|
+
);
|
|
575
|
+
return createBox(
|
|
576
|
+
[
|
|
577
|
+
...centerInCartesian,
|
|
578
|
+
...scratchXAxis.subtract(centerInCartesian),
|
|
579
|
+
...scratchYAxis.subtract(centerInCartesian),
|
|
580
|
+
...scratchZAxis.subtract(centerInCartesian)
|
|
581
|
+
],
|
|
582
|
+
new import_core4.Matrix4()
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
function orientedBoundingBoxToCartographicBounds(boundingVolume) {
|
|
586
|
+
const result = emptyCartographicBounds();
|
|
587
|
+
const { halfAxes } = boundingVolume;
|
|
588
|
+
const xAxis = new import_core4.Vector3(halfAxes.getColumn(0));
|
|
589
|
+
const yAxis = new import_core4.Vector3(halfAxes.getColumn(1));
|
|
590
|
+
const zAxis = new import_core4.Vector3(halfAxes.getColumn(2));
|
|
591
|
+
for (let x = 0; x < 2; x++) {
|
|
592
|
+
for (let y = 0; y < 2; y++) {
|
|
593
|
+
for (let z = 0; z < 2; z++) {
|
|
594
|
+
scratchPoint.copy(boundingVolume.center);
|
|
595
|
+
scratchPoint.add(xAxis);
|
|
596
|
+
scratchPoint.add(yAxis);
|
|
597
|
+
scratchPoint.add(zAxis);
|
|
598
|
+
addToCartographicBounds(result, scratchPoint);
|
|
599
|
+
zAxis.negate();
|
|
600
|
+
}
|
|
601
|
+
yAxis.negate();
|
|
602
|
+
}
|
|
603
|
+
xAxis.negate();
|
|
604
|
+
}
|
|
605
|
+
return result;
|
|
606
|
+
}
|
|
607
|
+
function boundingSphereToCartographicBounds(boundingVolume) {
|
|
608
|
+
const result = emptyCartographicBounds();
|
|
609
|
+
const { center, radius } = boundingVolume;
|
|
610
|
+
const point = import_geospatial4.Ellipsoid.WGS84.scaleToGeodeticSurface(center, scratchPoint);
|
|
611
|
+
let zAxis;
|
|
612
|
+
if (point) {
|
|
613
|
+
zAxis = import_geospatial4.Ellipsoid.WGS84.geodeticSurfaceNormal(point);
|
|
614
|
+
} else {
|
|
615
|
+
zAxis = new import_core4.Vector3(0, 0, 1);
|
|
616
|
+
}
|
|
617
|
+
let xAxis = new import_core4.Vector3(zAxis[2], -zAxis[1], 0);
|
|
618
|
+
if (xAxis.len() > 0) {
|
|
619
|
+
xAxis.normalize();
|
|
620
|
+
} else {
|
|
621
|
+
xAxis = new import_core4.Vector3(0, 1, 0);
|
|
622
|
+
}
|
|
623
|
+
const yAxis = xAxis.clone().cross(zAxis);
|
|
624
|
+
for (const axis of [xAxis, yAxis, zAxis]) {
|
|
625
|
+
scratchScale.copy(axis).scale(radius);
|
|
626
|
+
for (let dir = 0; dir < 2; dir++) {
|
|
627
|
+
scratchPoint.copy(center);
|
|
628
|
+
scratchPoint.add(scratchScale);
|
|
629
|
+
addToCartographicBounds(result, scratchPoint);
|
|
630
|
+
scratchScale.negate();
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return result;
|
|
634
|
+
}
|
|
635
|
+
function emptyCartographicBounds() {
|
|
636
|
+
return [
|
|
637
|
+
[Infinity, Infinity, Infinity],
|
|
638
|
+
[-Infinity, -Infinity, -Infinity]
|
|
639
|
+
];
|
|
640
|
+
}
|
|
641
|
+
function addToCartographicBounds(target, cartesian) {
|
|
642
|
+
import_geospatial4.Ellipsoid.WGS84.cartesianToCartographic(cartesian, scratchPoint);
|
|
643
|
+
target[0][0] = Math.min(target[0][0], scratchPoint[0]);
|
|
644
|
+
target[0][1] = Math.min(target[0][1], scratchPoint[1]);
|
|
645
|
+
target[0][2] = Math.min(target[0][2], scratchPoint[2]);
|
|
646
|
+
target[1][0] = Math.max(target[1][0], scratchPoint[0]);
|
|
647
|
+
target[1][1] = Math.max(target[1][1], scratchPoint[1]);
|
|
648
|
+
target[1][2] = Math.max(target[1][2], scratchPoint[2]);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// src/tileset/helpers/tiles-3d-lod.ts
|
|
652
|
+
var import_core5 = require("@math.gl/core");
|
|
653
|
+
var scratchPositionNormal = new import_core5.Vector3();
|
|
654
|
+
var scratchCartographic = new import_core5.Vector3();
|
|
655
|
+
var scratchMatrix = new import_core5.Matrix4();
|
|
656
|
+
var scratchCenter2 = new import_core5.Vector3();
|
|
657
|
+
var scratchPosition2 = new import_core5.Vector3();
|
|
658
|
+
var scratchDirection = new import_core5.Vector3();
|
|
659
|
+
function fog(distanceToCamera, density) {
|
|
660
|
+
const scalar = distanceToCamera * density;
|
|
661
|
+
return 1 - Math.exp(-(scalar * scalar));
|
|
662
|
+
}
|
|
663
|
+
function getDynamicScreenSpaceError(tileset, distanceToCamera) {
|
|
664
|
+
if (tileset.dynamicScreenSpaceError && tileset.dynamicScreenSpaceErrorComputedDensity) {
|
|
665
|
+
const density = tileset.dynamicScreenSpaceErrorComputedDensity;
|
|
666
|
+
const factor = tileset.dynamicScreenSpaceErrorFactor;
|
|
667
|
+
const dynamicError = fog(distanceToCamera, density) * factor;
|
|
668
|
+
return dynamicError;
|
|
669
|
+
}
|
|
670
|
+
return 0;
|
|
671
|
+
}
|
|
672
|
+
function getTiles3DScreenSpaceError(tile, frameState, useParentLodMetric) {
|
|
673
|
+
const tileset = tile.tileset;
|
|
674
|
+
const parentLodMetricValue = tile.parent && tile.parent.lodMetricValue || tile.lodMetricValue;
|
|
675
|
+
const lodMetricValue = useParentLodMetric ? parentLodMetricValue : tile.lodMetricValue;
|
|
676
|
+
if (lodMetricValue === 0) {
|
|
677
|
+
return 0;
|
|
678
|
+
}
|
|
679
|
+
const distance = Math.max(tile._distanceToCamera, 1e-7);
|
|
680
|
+
const { height, sseDenominator } = frameState;
|
|
681
|
+
const { viewDistanceScale } = tileset.options;
|
|
682
|
+
let error = lodMetricValue * height * (viewDistanceScale || 1) / (distance * sseDenominator);
|
|
683
|
+
error -= getDynamicScreenSpaceError(tileset, distance);
|
|
684
|
+
return error;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// src/tileset/helpers/i3s-lod.ts
|
|
688
|
+
var import_core6 = require("@math.gl/core");
|
|
689
|
+
var import_geospatial5 = require("@math.gl/geospatial");
|
|
690
|
+
var cameraPositionCartesian = new import_core6.Vector3();
|
|
691
|
+
var toEye = new import_core6.Vector3();
|
|
692
|
+
var cameraPositionEnu = new import_core6.Vector3();
|
|
693
|
+
var extraVertexEnu = new import_core6.Vector3();
|
|
694
|
+
var projectedOriginVector = new import_core6.Vector3();
|
|
695
|
+
var enuToCartesianMatrix = new import_core6.Matrix4();
|
|
696
|
+
var cartesianToEnuMatrix = new import_core6.Matrix4();
|
|
697
|
+
function getLodStatus(tile, frameState) {
|
|
698
|
+
if (tile.lodMetricValue === 0 || isNaN(tile.lodMetricValue)) {
|
|
699
|
+
return "DIG";
|
|
700
|
+
}
|
|
701
|
+
const screenSize = 2 * getProjectedRadius(tile, frameState);
|
|
702
|
+
if (screenSize < 2) {
|
|
703
|
+
return "OUT";
|
|
704
|
+
}
|
|
705
|
+
if (!tile.header.children || screenSize <= tile.lodMetricValue) {
|
|
706
|
+
return "DRAW";
|
|
707
|
+
} else if (tile.header.children) {
|
|
708
|
+
return "DIG";
|
|
709
|
+
}
|
|
710
|
+
return "OUT";
|
|
711
|
+
}
|
|
712
|
+
function getProjectedRadius(tile, frameState) {
|
|
713
|
+
const { topDownViewport: viewport } = frameState;
|
|
714
|
+
const mbsLat = tile.header.mbs[1];
|
|
715
|
+
const mbsLon = tile.header.mbs[0];
|
|
716
|
+
const mbsZ = tile.header.mbs[2];
|
|
717
|
+
const mbsR = tile.header.mbs[3];
|
|
718
|
+
const mbsCenterCartesian = [...tile.boundingVolume.center];
|
|
719
|
+
const cameraPositionCartographic = viewport.unprojectPosition(viewport.cameraPosition);
|
|
720
|
+
import_geospatial5.Ellipsoid.WGS84.cartographicToCartesian(cameraPositionCartographic, cameraPositionCartesian);
|
|
721
|
+
toEye.copy(cameraPositionCartesian).subtract(mbsCenterCartesian).normalize();
|
|
722
|
+
import_geospatial5.Ellipsoid.WGS84.eastNorthUpToFixedFrame(mbsCenterCartesian, enuToCartesianMatrix);
|
|
723
|
+
cartesianToEnuMatrix.copy(enuToCartesianMatrix).invert();
|
|
724
|
+
cameraPositionEnu.copy(cameraPositionCartesian).transform(cartesianToEnuMatrix);
|
|
725
|
+
const projection = Math.sqrt(
|
|
726
|
+
cameraPositionEnu[0] * cameraPositionEnu[0] + cameraPositionEnu[1] * cameraPositionEnu[1]
|
|
727
|
+
);
|
|
728
|
+
const extraZ = projection * projection / cameraPositionEnu[2];
|
|
729
|
+
extraVertexEnu.copy([cameraPositionEnu[0], cameraPositionEnu[1], extraZ]);
|
|
730
|
+
const extraVertexCartesian = extraVertexEnu.transform(enuToCartesianMatrix);
|
|
731
|
+
const extraVectorCartesian = extraVertexCartesian.subtract(mbsCenterCartesian).normalize();
|
|
732
|
+
const radiusVector = toEye.cross(extraVectorCartesian).normalize().scale(mbsR);
|
|
733
|
+
const sphereMbsBorderVertexCartesian = radiusVector.add(mbsCenterCartesian);
|
|
734
|
+
const sphereMbsBorderVertexCartographic = import_geospatial5.Ellipsoid.WGS84.cartesianToCartographic(
|
|
735
|
+
sphereMbsBorderVertexCartesian
|
|
736
|
+
);
|
|
737
|
+
const projectedOrigin = viewport.project([mbsLon, mbsLat, mbsZ]);
|
|
738
|
+
const projectedMbsBorderVertex = viewport.project(
|
|
739
|
+
sphereMbsBorderVertexCartographic
|
|
740
|
+
);
|
|
741
|
+
const projectedRadius = projectedOriginVector.copy(projectedOrigin).subtract(projectedMbsBorderVertex).magnitude();
|
|
742
|
+
return projectedRadius;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// src/tileset/helpers/3d-tiles-options.ts
|
|
746
|
+
function get3dTilesOptions(tileset) {
|
|
747
|
+
return {
|
|
748
|
+
assetGltfUpAxis: tileset.asset && tileset.asset.gltfUpAxis || "Y"
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// src/utils/managed-array.ts
|
|
753
|
+
var import_loader_utils3 = require("@loaders.gl/loader-utils");
|
|
754
|
+
var ManagedArray = class {
|
|
755
|
+
constructor(length = 0) {
|
|
756
|
+
this._map = /* @__PURE__ */ new Map();
|
|
757
|
+
this._array = new Array(length);
|
|
758
|
+
this._length = length;
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Gets or sets the length of the array.
|
|
762
|
+
* If the set length is greater than the length of the internal array, the internal array is resized.
|
|
763
|
+
*
|
|
764
|
+
* @memberof ManagedArray.prototype
|
|
765
|
+
* @type Number
|
|
766
|
+
*/
|
|
767
|
+
get length() {
|
|
768
|
+
return this._length;
|
|
769
|
+
}
|
|
770
|
+
set length(length) {
|
|
771
|
+
this._length = length;
|
|
772
|
+
if (length > this._array.length) {
|
|
773
|
+
this._array.length = length;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Gets the internal array.
|
|
778
|
+
*
|
|
779
|
+
* @memberof ManagedArray.prototype
|
|
780
|
+
* @type Array
|
|
781
|
+
* @readonly
|
|
782
|
+
*/
|
|
783
|
+
get values() {
|
|
784
|
+
return this._array;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Gets the element at an index.
|
|
788
|
+
*
|
|
789
|
+
* @param {Number} index The index to get.
|
|
790
|
+
*/
|
|
791
|
+
get(index) {
|
|
792
|
+
(0, import_loader_utils3.assert)(index < this._array.length);
|
|
793
|
+
return this._array[index];
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Sets the element at an index. Resizes the array if index is greater than the length of the array.
|
|
797
|
+
*
|
|
798
|
+
* @param {Number} index The index to set.
|
|
799
|
+
* @param {*} element The element to set at index.
|
|
800
|
+
*/
|
|
801
|
+
set(index, element) {
|
|
802
|
+
(0, import_loader_utils3.assert)(index >= 0);
|
|
803
|
+
if (index >= this.length) {
|
|
804
|
+
this.length = index + 1;
|
|
805
|
+
}
|
|
806
|
+
if (this._map.has(this._array[index])) {
|
|
807
|
+
this._map.delete(this._array[index]);
|
|
808
|
+
}
|
|
809
|
+
this._array[index] = element;
|
|
810
|
+
this._map.set(element, index);
|
|
811
|
+
}
|
|
812
|
+
delete(element) {
|
|
813
|
+
const index = this._map.get(element);
|
|
814
|
+
if (index >= 0) {
|
|
815
|
+
this._array.splice(index, 1);
|
|
816
|
+
this._map.delete(element);
|
|
817
|
+
this.length--;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Returns the last element in the array without modifying the array.
|
|
822
|
+
*
|
|
823
|
+
* @returns {*} The last element in the array.
|
|
824
|
+
*/
|
|
825
|
+
peek() {
|
|
826
|
+
return this._array[this._length - 1];
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Push an element into the array.
|
|
830
|
+
*
|
|
831
|
+
* @param {*} element The element to push.
|
|
832
|
+
*/
|
|
833
|
+
push(element) {
|
|
834
|
+
if (!this._map.has(element)) {
|
|
835
|
+
const index = this.length++;
|
|
836
|
+
this._array[index] = element;
|
|
837
|
+
this._map.set(element, index);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Pop an element from the array.
|
|
842
|
+
*
|
|
843
|
+
* @returns {*} The last element in the array.
|
|
844
|
+
*/
|
|
845
|
+
pop() {
|
|
846
|
+
const element = this._array[--this.length];
|
|
847
|
+
this._map.delete(element);
|
|
848
|
+
return element;
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* Resize the internal array if length > _array.length.
|
|
852
|
+
*
|
|
853
|
+
* @param {Number} length The length.
|
|
854
|
+
*/
|
|
855
|
+
reserve(length) {
|
|
856
|
+
(0, import_loader_utils3.assert)(length >= 0);
|
|
857
|
+
if (length > this._array.length) {
|
|
858
|
+
this._array.length = length;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Resize the array.
|
|
863
|
+
*
|
|
864
|
+
* @param {Number} length The length.
|
|
865
|
+
*/
|
|
866
|
+
resize(length) {
|
|
867
|
+
(0, import_loader_utils3.assert)(length >= 0);
|
|
868
|
+
this.length = length;
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Trim the internal array to the specified length. Defaults to the current length.
|
|
872
|
+
*
|
|
873
|
+
* @param {Number} [length] The length.
|
|
874
|
+
*/
|
|
875
|
+
trim(length) {
|
|
876
|
+
if (length === null || length === void 0) {
|
|
877
|
+
length = this.length;
|
|
878
|
+
}
|
|
879
|
+
this._array.length = length;
|
|
880
|
+
}
|
|
881
|
+
reset() {
|
|
882
|
+
this._array = [];
|
|
883
|
+
this._map = /* @__PURE__ */ new Map();
|
|
884
|
+
this._length = 0;
|
|
885
|
+
}
|
|
886
|
+
find(target) {
|
|
887
|
+
return this._map.has(target);
|
|
888
|
+
}
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
// src/tileset/tileset-traverser.ts
|
|
892
|
+
var DEFAULT_PROPS = {
|
|
893
|
+
loadSiblings: false,
|
|
894
|
+
skipLevelOfDetail: false,
|
|
895
|
+
maximumScreenSpaceError: 2,
|
|
896
|
+
updateTransforms: true,
|
|
897
|
+
onTraversalEnd: () => {
|
|
898
|
+
},
|
|
899
|
+
viewportTraversersMap: {},
|
|
900
|
+
basePath: ""
|
|
901
|
+
};
|
|
902
|
+
var TilesetTraverser = class {
|
|
903
|
+
// TODO nested props
|
|
904
|
+
constructor(options) {
|
|
905
|
+
// fulfill in traverse call
|
|
906
|
+
this.root = null;
|
|
907
|
+
// tiles should be rendered
|
|
908
|
+
this.selectedTiles = {};
|
|
909
|
+
// tiles should be loaded from server
|
|
910
|
+
this.requestedTiles = {};
|
|
911
|
+
// tiles does not have render content
|
|
912
|
+
this.emptyTiles = {};
|
|
913
|
+
this.lastUpdate = new Date().getTime();
|
|
914
|
+
this.updateDebounceTime = 1e3;
|
|
915
|
+
/** temporary storage to hold the traversed tiles during a traversal */
|
|
916
|
+
this._traversalStack = new ManagedArray();
|
|
917
|
+
this._emptyTraversalStack = new ManagedArray();
|
|
918
|
+
/** set in every traverse cycle */
|
|
919
|
+
this._frameNumber = null;
|
|
920
|
+
this.options = { ...DEFAULT_PROPS, ...options };
|
|
921
|
+
}
|
|
922
|
+
// RESULT
|
|
923
|
+
traversalFinished(frameState) {
|
|
924
|
+
return true;
|
|
925
|
+
}
|
|
926
|
+
// tiles should be visible
|
|
927
|
+
traverse(root, frameState, options) {
|
|
928
|
+
this.root = root;
|
|
929
|
+
this.options = { ...this.options, ...options };
|
|
930
|
+
this.reset();
|
|
931
|
+
this.updateTile(root, frameState);
|
|
932
|
+
this._frameNumber = frameState.frameNumber;
|
|
933
|
+
this.executeTraversal(root, frameState);
|
|
934
|
+
}
|
|
935
|
+
reset() {
|
|
936
|
+
this.requestedTiles = {};
|
|
937
|
+
this.selectedTiles = {};
|
|
938
|
+
this.emptyTiles = {};
|
|
939
|
+
this._traversalStack.reset();
|
|
940
|
+
this._emptyTraversalStack.reset();
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Execute traverse
|
|
944
|
+
* Depth-first traversal that traverses all visible tiles and marks tiles for selection.
|
|
945
|
+
* If skipLevelOfDetail is off then a tile does not refine until all children are loaded.
|
|
946
|
+
* This is the traditional replacement refinement approach and is called the base traversal.
|
|
947
|
+
* Tiles that have a greater screen space error than the base screen space error are part of the base traversal,
|
|
948
|
+
* all other tiles are part of the skip traversal. The skip traversal allows for skipping levels of the tree
|
|
949
|
+
* and rendering children and parent tiles simultaneously.
|
|
950
|
+
*/
|
|
951
|
+
/* eslint-disable-next-line complexity, max-statements */
|
|
952
|
+
executeTraversal(root, frameState) {
|
|
953
|
+
const stack = this._traversalStack;
|
|
954
|
+
root._selectionDepth = 1;
|
|
955
|
+
stack.push(root);
|
|
956
|
+
while (stack.length > 0) {
|
|
957
|
+
const tile = stack.pop();
|
|
958
|
+
let shouldRefine = false;
|
|
959
|
+
if (this.canTraverse(tile, frameState)) {
|
|
960
|
+
this.updateChildTiles(tile, frameState);
|
|
961
|
+
shouldRefine = this.updateAndPushChildren(
|
|
962
|
+
tile,
|
|
963
|
+
frameState,
|
|
964
|
+
stack,
|
|
965
|
+
tile.hasRenderContent ? tile._selectionDepth + 1 : tile._selectionDepth
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
const parent = tile.parent;
|
|
969
|
+
const parentRefines = Boolean(!parent || parent._shouldRefine);
|
|
970
|
+
const stoppedRefining = !shouldRefine;
|
|
971
|
+
if (!tile.hasRenderContent) {
|
|
972
|
+
this.emptyTiles[tile.id] = tile;
|
|
973
|
+
this.loadTile(tile, frameState);
|
|
974
|
+
if (stoppedRefining) {
|
|
975
|
+
this.selectTile(tile, frameState);
|
|
976
|
+
}
|
|
977
|
+
} else if (tile.refine === 1 /* ADD */) {
|
|
978
|
+
this.loadTile(tile, frameState);
|
|
979
|
+
this.selectTile(tile, frameState);
|
|
980
|
+
} else if (tile.refine === 2 /* REPLACE */) {
|
|
981
|
+
this.loadTile(tile, frameState);
|
|
982
|
+
if (stoppedRefining) {
|
|
983
|
+
this.selectTile(tile, frameState);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
this.touchTile(tile, frameState);
|
|
987
|
+
tile._shouldRefine = shouldRefine && parentRefines;
|
|
988
|
+
}
|
|
989
|
+
const newTime = new Date().getTime();
|
|
990
|
+
if (this.traversalFinished(frameState) || newTime - this.lastUpdate > this.updateDebounceTime) {
|
|
991
|
+
this.lastUpdate = newTime;
|
|
992
|
+
this.options.onTraversalEnd(frameState);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
updateChildTiles(tile, frameState) {
|
|
996
|
+
const children = tile.children;
|
|
997
|
+
for (const child of children) {
|
|
998
|
+
this.updateTile(child, frameState);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
/* eslint-disable complexity, max-statements */
|
|
1002
|
+
updateAndPushChildren(tile, frameState, stack, depth) {
|
|
1003
|
+
const { loadSiblings, skipLevelOfDetail } = this.options;
|
|
1004
|
+
const children = tile.children;
|
|
1005
|
+
children.sort(this.compareDistanceToCamera.bind(this));
|
|
1006
|
+
const checkRefines = tile.refine === 2 /* REPLACE */ && tile.hasRenderContent && !skipLevelOfDetail;
|
|
1007
|
+
let hasVisibleChild = false;
|
|
1008
|
+
let refines = true;
|
|
1009
|
+
for (const child of children) {
|
|
1010
|
+
child._selectionDepth = depth;
|
|
1011
|
+
if (child.isVisibleAndInRequestVolume) {
|
|
1012
|
+
if (stack.find(child)) {
|
|
1013
|
+
stack.delete(child);
|
|
1014
|
+
}
|
|
1015
|
+
stack.push(child);
|
|
1016
|
+
hasVisibleChild = true;
|
|
1017
|
+
} else if (checkRefines || loadSiblings) {
|
|
1018
|
+
this.loadTile(child, frameState);
|
|
1019
|
+
this.touchTile(child, frameState);
|
|
1020
|
+
}
|
|
1021
|
+
if (checkRefines) {
|
|
1022
|
+
let childRefines;
|
|
1023
|
+
if (!child._inRequestVolume) {
|
|
1024
|
+
childRefines = false;
|
|
1025
|
+
} else if (!child.hasRenderContent) {
|
|
1026
|
+
childRefines = this.executeEmptyTraversal(child, frameState);
|
|
1027
|
+
} else {
|
|
1028
|
+
childRefines = child.contentAvailable;
|
|
1029
|
+
}
|
|
1030
|
+
refines = refines && childRefines;
|
|
1031
|
+
if (!refines) {
|
|
1032
|
+
return false;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
if (!hasVisibleChild) {
|
|
1037
|
+
refines = false;
|
|
1038
|
+
}
|
|
1039
|
+
return refines;
|
|
1040
|
+
}
|
|
1041
|
+
/* eslint-enable complexity, max-statements */
|
|
1042
|
+
updateTile(tile, frameState) {
|
|
1043
|
+
this.updateTileVisibility(tile, frameState);
|
|
1044
|
+
}
|
|
1045
|
+
// tile to render in the browser
|
|
1046
|
+
selectTile(tile, frameState) {
|
|
1047
|
+
if (this.shouldSelectTile(tile)) {
|
|
1048
|
+
tile._selectedFrame = frameState.frameNumber;
|
|
1049
|
+
this.selectedTiles[tile.id] = tile;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
// tile to load from server
|
|
1053
|
+
loadTile(tile, frameState) {
|
|
1054
|
+
if (this.shouldLoadTile(tile)) {
|
|
1055
|
+
tile._requestedFrame = frameState.frameNumber;
|
|
1056
|
+
tile._priority = tile._getPriority();
|
|
1057
|
+
this.requestedTiles[tile.id] = tile;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
// cache tile
|
|
1061
|
+
touchTile(tile, frameState) {
|
|
1062
|
+
tile.tileset._cache.touch(tile);
|
|
1063
|
+
tile._touchedFrame = frameState.frameNumber;
|
|
1064
|
+
}
|
|
1065
|
+
// tile should be visible
|
|
1066
|
+
// tile should have children
|
|
1067
|
+
// tile LoD (level of detail) is not sufficient under current viewport
|
|
1068
|
+
canTraverse(tile, frameState, useParentMetric = false, ignoreVisibility = false) {
|
|
1069
|
+
if (!tile.hasChildren) {
|
|
1070
|
+
return false;
|
|
1071
|
+
}
|
|
1072
|
+
if (tile.hasTilesetContent) {
|
|
1073
|
+
return !tile.contentExpired;
|
|
1074
|
+
}
|
|
1075
|
+
if (!ignoreVisibility && !tile.isVisibleAndInRequestVolume) {
|
|
1076
|
+
return false;
|
|
1077
|
+
}
|
|
1078
|
+
return this.shouldRefine(tile, frameState, useParentMetric);
|
|
1079
|
+
}
|
|
1080
|
+
shouldLoadTile(tile) {
|
|
1081
|
+
return tile.hasUnloadedContent || tile.contentExpired;
|
|
1082
|
+
}
|
|
1083
|
+
shouldSelectTile(tile) {
|
|
1084
|
+
return tile.contentAvailable && !this.options.skipLevelOfDetail;
|
|
1085
|
+
}
|
|
1086
|
+
/** Decide if tile LoD (level of detail) is not sufficient under current viewport */
|
|
1087
|
+
shouldRefine(tile, frameState, useParentMetric = false) {
|
|
1088
|
+
let screenSpaceError = tile._screenSpaceError;
|
|
1089
|
+
if (useParentMetric) {
|
|
1090
|
+
screenSpaceError = tile.getScreenSpaceError(frameState, true);
|
|
1091
|
+
}
|
|
1092
|
+
return screenSpaceError > this.options.maximumScreenSpaceError;
|
|
1093
|
+
}
|
|
1094
|
+
updateTileVisibility(tile, frameState) {
|
|
1095
|
+
const viewportIds = [];
|
|
1096
|
+
if (this.options.viewportTraversersMap) {
|
|
1097
|
+
for (const key in this.options.viewportTraversersMap) {
|
|
1098
|
+
const value = this.options.viewportTraversersMap[key];
|
|
1099
|
+
if (value === frameState.viewport.id) {
|
|
1100
|
+
viewportIds.push(key);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
} else {
|
|
1104
|
+
viewportIds.push(frameState.viewport.id);
|
|
1105
|
+
}
|
|
1106
|
+
tile.updateVisibility(frameState, viewportIds);
|
|
1107
|
+
}
|
|
1108
|
+
// UTILITIES
|
|
1109
|
+
compareDistanceToCamera(b, a) {
|
|
1110
|
+
return b._distanceToCamera - a._distanceToCamera;
|
|
1111
|
+
}
|
|
1112
|
+
anyChildrenVisible(tile, frameState) {
|
|
1113
|
+
let anyVisible = false;
|
|
1114
|
+
for (const child of tile.children) {
|
|
1115
|
+
child.updateVisibility(frameState);
|
|
1116
|
+
anyVisible = anyVisible || child.isVisibleAndInRequestVolume;
|
|
1117
|
+
}
|
|
1118
|
+
return anyVisible;
|
|
1119
|
+
}
|
|
1120
|
+
// Depth-first traversal that checks if all nearest descendants with content are loaded.
|
|
1121
|
+
// Ignores visibility.
|
|
1122
|
+
executeEmptyTraversal(root, frameState) {
|
|
1123
|
+
let allDescendantsLoaded = true;
|
|
1124
|
+
const stack = this._emptyTraversalStack;
|
|
1125
|
+
stack.push(root);
|
|
1126
|
+
while (stack.length > 0 && allDescendantsLoaded) {
|
|
1127
|
+
const tile = stack.pop();
|
|
1128
|
+
this.updateTile(tile, frameState);
|
|
1129
|
+
if (!tile.isVisibleAndInRequestVolume) {
|
|
1130
|
+
this.loadTile(tile, frameState);
|
|
1131
|
+
}
|
|
1132
|
+
this.touchTile(tile, frameState);
|
|
1133
|
+
const traverse = !tile.hasRenderContent && this.canTraverse(tile, frameState, false, true);
|
|
1134
|
+
if (traverse) {
|
|
1135
|
+
const children = tile.children;
|
|
1136
|
+
for (const child of children) {
|
|
1137
|
+
if (stack.find(child)) {
|
|
1138
|
+
stack.delete(child);
|
|
1139
|
+
}
|
|
1140
|
+
stack.push(child);
|
|
1141
|
+
}
|
|
1142
|
+
} else if (!tile.contentAvailable && !tile.hasEmptyContent) {
|
|
1143
|
+
allDescendantsLoaded = false;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return allDescendantsLoaded;
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1149
|
+
|
|
1150
|
+
// src/tileset/tile-3d.ts
|
|
1151
|
+
var scratchVector3 = new import_core7.Vector3();
|
|
1152
|
+
function defined2(x) {
|
|
1153
|
+
return x !== void 0 && x !== null;
|
|
1154
|
+
}
|
|
1155
|
+
var Tile3D = class {
|
|
1156
|
+
// TODO i3s specific, needs to remove
|
|
1157
|
+
/**
|
|
1158
|
+
* @constructs
|
|
1159
|
+
* Create a Tile3D instance
|
|
1160
|
+
* @param tileset - Tileset3D instance
|
|
1161
|
+
* @param header - tile header - JSON loaded from a dataset
|
|
1162
|
+
* @param parentHeader - parent Tile3D instance
|
|
1163
|
+
* @param extendedId - optional ID to separate copies of a tile for different viewports.
|
|
1164
|
+
* const extendedId = `${tile.id}-${frameState.viewport.id}`;
|
|
1165
|
+
*/
|
|
1166
|
+
// eslint-disable-next-line max-statements
|
|
1167
|
+
constructor(tileset, header, parentHeader, extendedId = "") {
|
|
1168
|
+
/** Different refinement algorithms used by I3S and 3D tiles */
|
|
1169
|
+
this.lodMetricType = "geometricError";
|
|
1170
|
+
/** The error, in meters, introduced if this tile is rendered and its children are not. */
|
|
1171
|
+
this.lodMetricValue = 0;
|
|
1172
|
+
/** @todo math.gl is not exporting BoundingVolume base type? */
|
|
1173
|
+
this.boundingVolume = null;
|
|
1174
|
+
/**
|
|
1175
|
+
* The tile's content. This represents the actual tile's payload,
|
|
1176
|
+
* not the content's metadata in the tileset JSON file.
|
|
1177
|
+
*/
|
|
1178
|
+
this.content = null;
|
|
1179
|
+
this.contentState = TILE_CONTENT_STATE.UNLOADED;
|
|
1180
|
+
this.gpuMemoryUsageInBytes = 0;
|
|
1181
|
+
/** The tile's children - an array of Tile3D objects. */
|
|
1182
|
+
this.children = [];
|
|
1183
|
+
this.depth = 0;
|
|
1184
|
+
this.viewportIds = [];
|
|
1185
|
+
this.transform = new import_core7.Matrix4();
|
|
1186
|
+
this.extensions = null;
|
|
1187
|
+
/** TODO Cesium 3d tiles specific */
|
|
1188
|
+
this.implicitTiling = null;
|
|
1189
|
+
/** Container to store application specific data */
|
|
1190
|
+
this.userData = {};
|
|
1191
|
+
this.hasEmptyContent = false;
|
|
1192
|
+
this.hasTilesetContent = false;
|
|
1193
|
+
this.traverser = new TilesetTraverser({});
|
|
1194
|
+
/** Used by TilesetCache */
|
|
1195
|
+
this._cacheNode = null;
|
|
1196
|
+
this._frameNumber = null;
|
|
1197
|
+
// TODO Cesium 3d tiles specific
|
|
1198
|
+
this._expireDate = null;
|
|
1199
|
+
this._expiredContent = null;
|
|
1200
|
+
this._boundingBox = void 0;
|
|
1201
|
+
/** updated every frame for tree traversal and rendering optimizations: */
|
|
1202
|
+
this._distanceToCamera = 0;
|
|
1203
|
+
this._screenSpaceError = 0;
|
|
1204
|
+
this._visible = void 0;
|
|
1205
|
+
this._initialTransform = new import_core7.Matrix4();
|
|
1206
|
+
// Used by traverser, cannot be marked private
|
|
1207
|
+
this._priority = 0;
|
|
1208
|
+
this._selectedFrame = 0;
|
|
1209
|
+
this._requestedFrame = 0;
|
|
1210
|
+
this._selectionDepth = 0;
|
|
1211
|
+
this._touchedFrame = 0;
|
|
1212
|
+
this._centerZDepth = 0;
|
|
1213
|
+
this._shouldRefine = false;
|
|
1214
|
+
this._stackLength = 0;
|
|
1215
|
+
this._visitedFrame = 0;
|
|
1216
|
+
this._inRequestVolume = false;
|
|
1217
|
+
this._lodJudge = null;
|
|
1218
|
+
this.header = header;
|
|
1219
|
+
this.tileset = tileset;
|
|
1220
|
+
this.id = extendedId || header.id;
|
|
1221
|
+
this.url = header.url;
|
|
1222
|
+
this.parent = parentHeader;
|
|
1223
|
+
this.refine = this._getRefine(header.refine);
|
|
1224
|
+
this.type = header.type;
|
|
1225
|
+
this.contentUrl = header.contentUrl;
|
|
1226
|
+
this._initializeLodMetric(header);
|
|
1227
|
+
this._initializeTransforms(header);
|
|
1228
|
+
this._initializeBoundingVolumes(header);
|
|
1229
|
+
this._initializeContent(header);
|
|
1230
|
+
this._initializeRenderingState(header);
|
|
1231
|
+
Object.seal(this);
|
|
1232
|
+
}
|
|
1233
|
+
destroy() {
|
|
1234
|
+
this.header = null;
|
|
1235
|
+
}
|
|
1236
|
+
isDestroyed() {
|
|
1237
|
+
return this.header === null;
|
|
1238
|
+
}
|
|
1239
|
+
get selected() {
|
|
1240
|
+
return this._selectedFrame === this.tileset._frameNumber;
|
|
1241
|
+
}
|
|
1242
|
+
get isVisible() {
|
|
1243
|
+
return this._visible;
|
|
1244
|
+
}
|
|
1245
|
+
get isVisibleAndInRequestVolume() {
|
|
1246
|
+
return this._visible && this._inRequestVolume;
|
|
1247
|
+
}
|
|
1248
|
+
/** Returns true if tile is not an empty tile and not an external tileset */
|
|
1249
|
+
get hasRenderContent() {
|
|
1250
|
+
return !this.hasEmptyContent && !this.hasTilesetContent;
|
|
1251
|
+
}
|
|
1252
|
+
/** Returns true if tile has children */
|
|
1253
|
+
get hasChildren() {
|
|
1254
|
+
return this.children.length > 0 || this.header.children && this.header.children.length > 0;
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Determines if the tile's content is ready. This is automatically `true` for
|
|
1258
|
+
* tiles with empty content.
|
|
1259
|
+
*/
|
|
1260
|
+
get contentReady() {
|
|
1261
|
+
return this.contentState === TILE_CONTENT_STATE.READY || this.hasEmptyContent;
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Determines if the tile has available content to render. `true` if the tile's
|
|
1265
|
+
* content is ready or if it has expired content this renders while new content loads; otherwise,
|
|
1266
|
+
*/
|
|
1267
|
+
get contentAvailable() {
|
|
1268
|
+
return Boolean(
|
|
1269
|
+
this.contentReady && this.hasRenderContent || this._expiredContent && !this.contentFailed
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
/** Returns true if tile has renderable content but it's unloaded */
|
|
1273
|
+
get hasUnloadedContent() {
|
|
1274
|
+
return this.hasRenderContent && this.contentUnloaded;
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Determines if the tile's content has not be requested. `true` if tile's
|
|
1278
|
+
* content has not be requested; otherwise, `false`.
|
|
1279
|
+
*/
|
|
1280
|
+
get contentUnloaded() {
|
|
1281
|
+
return this.contentState === TILE_CONTENT_STATE.UNLOADED;
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Determines if the tile's content is expired. `true` if tile's
|
|
1285
|
+
* content is expired; otherwise, `false`.
|
|
1286
|
+
*/
|
|
1287
|
+
get contentExpired() {
|
|
1288
|
+
return this.contentState === TILE_CONTENT_STATE.EXPIRED;
|
|
1289
|
+
}
|
|
1290
|
+
// Determines if the tile's content failed to load. `true` if the tile's
|
|
1291
|
+
// content failed to load; otherwise, `false`.
|
|
1292
|
+
get contentFailed() {
|
|
1293
|
+
return this.contentState === TILE_CONTENT_STATE.FAILED;
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Distance from the tile's bounding volume center to the camera
|
|
1297
|
+
*/
|
|
1298
|
+
get distanceToCamera() {
|
|
1299
|
+
return this._distanceToCamera;
|
|
1300
|
+
}
|
|
1301
|
+
/**
|
|
1302
|
+
* Screen space error for LOD selection
|
|
1303
|
+
*/
|
|
1304
|
+
get screenSpaceError() {
|
|
1305
|
+
return this._screenSpaceError;
|
|
1306
|
+
}
|
|
1307
|
+
/**
|
|
1308
|
+
* Get bounding box in cartographic coordinates
|
|
1309
|
+
* @returns [min, max] each in [longitude, latitude, altitude]
|
|
1310
|
+
*/
|
|
1311
|
+
get boundingBox() {
|
|
1312
|
+
if (!this._boundingBox) {
|
|
1313
|
+
this._boundingBox = getCartographicBounds(this.header.boundingVolume, this.boundingVolume);
|
|
1314
|
+
}
|
|
1315
|
+
return this._boundingBox;
|
|
1316
|
+
}
|
|
1317
|
+
/** Get the tile's screen space error. */
|
|
1318
|
+
getScreenSpaceError(frameState, useParentLodMetric) {
|
|
1319
|
+
switch (this.tileset.type) {
|
|
1320
|
+
case "I3S" /* I3S */:
|
|
1321
|
+
return getProjectedRadius(this, frameState);
|
|
1322
|
+
case "TILES3D" /* TILES3D */:
|
|
1323
|
+
return getTiles3DScreenSpaceError(this, frameState, useParentLodMetric);
|
|
1324
|
+
default:
|
|
1325
|
+
throw new Error("Unsupported tileset type");
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
/**
|
|
1329
|
+
* Make tile unselected than means it won't be shown
|
|
1330
|
+
* but it can be still loaded in memory
|
|
1331
|
+
*/
|
|
1332
|
+
unselect() {
|
|
1333
|
+
this._selectedFrame = 0;
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Memory usage of tile on GPU
|
|
1337
|
+
*/
|
|
1338
|
+
_getGpuMemoryUsageInBytes() {
|
|
1339
|
+
return this.content.gpuMemoryUsageInBytes || this.content.byteLength || 0;
|
|
1340
|
+
}
|
|
1341
|
+
/*
|
|
1342
|
+
* If skipLevelOfDetail is off try to load child tiles as soon as possible so that their parent can refine sooner.
|
|
1343
|
+
* Tiles are prioritized by screen space error.
|
|
1344
|
+
*/
|
|
1345
|
+
// eslint-disable-next-line complexity
|
|
1346
|
+
_getPriority() {
|
|
1347
|
+
const traverser = this.tileset._traverser;
|
|
1348
|
+
const { skipLevelOfDetail } = traverser.options;
|
|
1349
|
+
const maySkipTile = this.refine === 1 /* ADD */ || skipLevelOfDetail;
|
|
1350
|
+
if (maySkipTile && !this.isVisible && this._visible !== void 0) {
|
|
1351
|
+
return -1;
|
|
1352
|
+
}
|
|
1353
|
+
if (this.tileset._frameNumber - this._touchedFrame >= 1) {
|
|
1354
|
+
return -1;
|
|
1355
|
+
}
|
|
1356
|
+
if (this.contentState === TILE_CONTENT_STATE.UNLOADED) {
|
|
1357
|
+
return -1;
|
|
1358
|
+
}
|
|
1359
|
+
const parent = this.parent;
|
|
1360
|
+
const useParentScreenSpaceError = parent && (!maySkipTile || this._screenSpaceError === 0 || parent.hasTilesetContent);
|
|
1361
|
+
const screenSpaceError = useParentScreenSpaceError ? parent._screenSpaceError : this._screenSpaceError;
|
|
1362
|
+
const rootScreenSpaceError = traverser.root ? traverser.root._screenSpaceError : 0;
|
|
1363
|
+
return Math.max(rootScreenSpaceError - screenSpaceError, 0);
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Requests the tile's content.
|
|
1367
|
+
* The request may not be made if the Request Scheduler can't prioritize it.
|
|
1368
|
+
*/
|
|
1369
|
+
// eslint-disable-next-line max-statements, complexity
|
|
1370
|
+
async loadContent() {
|
|
1371
|
+
if (this.hasEmptyContent) {
|
|
1372
|
+
return false;
|
|
1373
|
+
}
|
|
1374
|
+
if (this.content) {
|
|
1375
|
+
return true;
|
|
1376
|
+
}
|
|
1377
|
+
const expired = this.contentExpired;
|
|
1378
|
+
if (expired) {
|
|
1379
|
+
this._expireDate = null;
|
|
1380
|
+
}
|
|
1381
|
+
this.contentState = TILE_CONTENT_STATE.LOADING;
|
|
1382
|
+
const requestToken = await this.tileset._requestScheduler.scheduleRequest(
|
|
1383
|
+
this.id,
|
|
1384
|
+
this._getPriority.bind(this)
|
|
1385
|
+
);
|
|
1386
|
+
if (!requestToken) {
|
|
1387
|
+
this.contentState = TILE_CONTENT_STATE.UNLOADED;
|
|
1388
|
+
return false;
|
|
1389
|
+
}
|
|
1390
|
+
try {
|
|
1391
|
+
const contentUrl = this.tileset.getTileUrl(this.contentUrl);
|
|
1392
|
+
const loader = this.tileset.loader;
|
|
1393
|
+
const options = {
|
|
1394
|
+
...this.tileset.loadOptions,
|
|
1395
|
+
[loader.id]: {
|
|
1396
|
+
// @ts-expect-error
|
|
1397
|
+
...this.tileset.loadOptions[loader.id],
|
|
1398
|
+
isTileset: this.type === "json",
|
|
1399
|
+
...this._getLoaderSpecificOptions(loader.id)
|
|
1400
|
+
}
|
|
1401
|
+
};
|
|
1402
|
+
this.content = await (0, import_core8.load)(contentUrl, loader, options);
|
|
1403
|
+
if (this.tileset.options.contentLoader) {
|
|
1404
|
+
await this.tileset.options.contentLoader(this);
|
|
1405
|
+
}
|
|
1406
|
+
if (this._isTileset()) {
|
|
1407
|
+
this.tileset._initializeTileHeaders(this.content, this);
|
|
1408
|
+
}
|
|
1409
|
+
this.contentState = TILE_CONTENT_STATE.READY;
|
|
1410
|
+
this._onContentLoaded();
|
|
1411
|
+
return true;
|
|
1412
|
+
} catch (error) {
|
|
1413
|
+
this.contentState = TILE_CONTENT_STATE.FAILED;
|
|
1414
|
+
throw error;
|
|
1415
|
+
} finally {
|
|
1416
|
+
requestToken.done();
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
// Unloads the tile's content.
|
|
1420
|
+
unloadContent() {
|
|
1421
|
+
if (this.content && this.content.destroy) {
|
|
1422
|
+
this.content.destroy();
|
|
1423
|
+
}
|
|
1424
|
+
this.content = null;
|
|
1425
|
+
if (this.header.content && this.header.content.destroy) {
|
|
1426
|
+
this.header.content.destroy();
|
|
1427
|
+
}
|
|
1428
|
+
this.header.content = null;
|
|
1429
|
+
this.contentState = TILE_CONTENT_STATE.UNLOADED;
|
|
1430
|
+
return true;
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* Update the tile's visibility
|
|
1434
|
+
* @param {Object} frameState - frame state for tile culling
|
|
1435
|
+
* @param {string[]} viewportIds - a list of viewport ids that show this tile
|
|
1436
|
+
* @return {void}
|
|
1437
|
+
*/
|
|
1438
|
+
updateVisibility(frameState, viewportIds) {
|
|
1439
|
+
if (this._frameNumber === frameState.frameNumber) {
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
const parent = this.parent;
|
|
1443
|
+
const parentVisibilityPlaneMask = parent ? parent._visibilityPlaneMask : import_culling4.CullingVolume.MASK_INDETERMINATE;
|
|
1444
|
+
if (this.tileset._traverser.options.updateTransforms) {
|
|
1445
|
+
const parentTransform = parent ? parent.computedTransform : this.tileset.modelMatrix;
|
|
1446
|
+
this._updateTransform(parentTransform);
|
|
1447
|
+
}
|
|
1448
|
+
this._distanceToCamera = this.distanceToTile(frameState);
|
|
1449
|
+
this._screenSpaceError = this.getScreenSpaceError(frameState, false);
|
|
1450
|
+
this._visibilityPlaneMask = this.visibility(frameState, parentVisibilityPlaneMask);
|
|
1451
|
+
this._visible = this._visibilityPlaneMask !== import_culling4.CullingVolume.MASK_OUTSIDE;
|
|
1452
|
+
this._inRequestVolume = this.insideViewerRequestVolume(frameState);
|
|
1453
|
+
this._frameNumber = frameState.frameNumber;
|
|
1454
|
+
this.viewportIds = viewportIds;
|
|
1455
|
+
}
|
|
1456
|
+
// Determines whether the tile's bounding volume intersects the culling volume.
|
|
1457
|
+
// @param {FrameState} frameState The frame state.
|
|
1458
|
+
// @param {Number} parentVisibilityPlaneMask The parent's plane mask to speed up the visibility check.
|
|
1459
|
+
// @returns {Number} A plane mask as described above in {@link CullingVolume#computeVisibilityWithPlaneMask}.
|
|
1460
|
+
visibility(frameState, parentVisibilityPlaneMask) {
|
|
1461
|
+
const { cullingVolume: cullingVolume2 } = frameState;
|
|
1462
|
+
const { boundingVolume } = this;
|
|
1463
|
+
return cullingVolume2.computeVisibilityWithPlaneMask(boundingVolume, parentVisibilityPlaneMask);
|
|
1464
|
+
}
|
|
1465
|
+
// Assuming the tile's bounding volume intersects the culling volume, determines
|
|
1466
|
+
// whether the tile's content's bounding volume intersects the culling volume.
|
|
1467
|
+
// @param {FrameState} frameState The frame state.
|
|
1468
|
+
// @returns {Intersect} The result of the intersection: the tile's content is completely outside, completely inside, or intersecting the culling volume.
|
|
1469
|
+
contentVisibility() {
|
|
1470
|
+
return true;
|
|
1471
|
+
}
|
|
1472
|
+
/**
|
|
1473
|
+
* Computes the (potentially approximate) distance from the closest point of the tile's bounding volume to the camera.
|
|
1474
|
+
* @param frameState The frame state.
|
|
1475
|
+
* @returns {Number} The distance, in meters, or zero if the camera is inside the bounding volume.
|
|
1476
|
+
*/
|
|
1477
|
+
distanceToTile(frameState) {
|
|
1478
|
+
const boundingVolume = this.boundingVolume;
|
|
1479
|
+
return Math.sqrt(Math.max(boundingVolume.distanceSquaredTo(frameState.camera.position), 0));
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Computes the tile's camera-space z-depth.
|
|
1483
|
+
* @param frameState The frame state.
|
|
1484
|
+
* @returns The distance, in meters.
|
|
1485
|
+
*/
|
|
1486
|
+
cameraSpaceZDepth({ camera }) {
|
|
1487
|
+
const boundingVolume = this.boundingVolume;
|
|
1488
|
+
scratchVector3.subVectors(boundingVolume.center, camera.position);
|
|
1489
|
+
return camera.direction.dot(scratchVector3);
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Checks if the camera is inside the viewer request volume.
|
|
1493
|
+
* @param {FrameState} frameState The frame state.
|
|
1494
|
+
* @returns {Boolean} Whether the camera is inside the volume.
|
|
1495
|
+
*/
|
|
1496
|
+
insideViewerRequestVolume(frameState) {
|
|
1497
|
+
const viewerRequestVolume = this._viewerRequestVolume;
|
|
1498
|
+
return !viewerRequestVolume || viewerRequestVolume.distanceSquaredTo(frameState.camera.position) <= 0;
|
|
1499
|
+
}
|
|
1500
|
+
// TODO Cesium specific
|
|
1501
|
+
// Update whether the tile has expired.
|
|
1502
|
+
updateExpiration() {
|
|
1503
|
+
if (defined2(this._expireDate) && this.contentReady && !this.hasEmptyContent) {
|
|
1504
|
+
const now = Date.now();
|
|
1505
|
+
if (Date.lessThan(this._expireDate, now)) {
|
|
1506
|
+
this.contentState = TILE_CONTENT_STATE.EXPIRED;
|
|
1507
|
+
this._expiredContent = this.content;
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
get extras() {
|
|
1512
|
+
return this.header.extras;
|
|
1513
|
+
}
|
|
1514
|
+
// INTERNAL METHODS
|
|
1515
|
+
_initializeLodMetric(header) {
|
|
1516
|
+
if ("lodMetricType" in header) {
|
|
1517
|
+
this.lodMetricType = header.lodMetricType;
|
|
1518
|
+
} else {
|
|
1519
|
+
this.lodMetricType = this.parent && this.parent.lodMetricType || this.tileset.lodMetricType;
|
|
1520
|
+
console.warn(`3D Tile: Required prop lodMetricType is undefined. Using parent lodMetricType`);
|
|
1521
|
+
}
|
|
1522
|
+
if ("lodMetricValue" in header) {
|
|
1523
|
+
this.lodMetricValue = header.lodMetricValue;
|
|
1524
|
+
} else {
|
|
1525
|
+
this.lodMetricValue = this.parent && this.parent.lodMetricValue || this.tileset.lodMetricValue;
|
|
1526
|
+
console.warn(
|
|
1527
|
+
"3D Tile: Required prop lodMetricValue is undefined. Using parent lodMetricValue"
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
_initializeTransforms(tileHeader) {
|
|
1532
|
+
this.transform = tileHeader.transform ? new import_core7.Matrix4(tileHeader.transform) : new import_core7.Matrix4();
|
|
1533
|
+
const parent = this.parent;
|
|
1534
|
+
const tileset = this.tileset;
|
|
1535
|
+
const parentTransform = parent && parent.computedTransform ? parent.computedTransform.clone() : tileset.modelMatrix.clone();
|
|
1536
|
+
this.computedTransform = new import_core7.Matrix4(parentTransform).multiplyRight(this.transform);
|
|
1537
|
+
const parentInitialTransform = parent && parent._initialTransform ? parent._initialTransform.clone() : new import_core7.Matrix4();
|
|
1538
|
+
this._initialTransform = new import_core7.Matrix4(parentInitialTransform).multiplyRight(this.transform);
|
|
1539
|
+
}
|
|
1540
|
+
_initializeBoundingVolumes(tileHeader) {
|
|
1541
|
+
this._contentBoundingVolume = null;
|
|
1542
|
+
this._viewerRequestVolume = null;
|
|
1543
|
+
this._updateBoundingVolume(tileHeader);
|
|
1544
|
+
}
|
|
1545
|
+
_initializeContent(tileHeader) {
|
|
1546
|
+
this.content = { _tileset: this.tileset, _tile: this };
|
|
1547
|
+
this.hasEmptyContent = true;
|
|
1548
|
+
this.contentState = TILE_CONTENT_STATE.UNLOADED;
|
|
1549
|
+
this.hasTilesetContent = false;
|
|
1550
|
+
if (tileHeader.contentUrl) {
|
|
1551
|
+
this.content = null;
|
|
1552
|
+
this.hasEmptyContent = false;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
// TODO - remove anything not related to basic visibility detection
|
|
1556
|
+
_initializeRenderingState(header) {
|
|
1557
|
+
this.depth = header.level || (this.parent ? this.parent.depth + 1 : 0);
|
|
1558
|
+
this._shouldRefine = false;
|
|
1559
|
+
this._distanceToCamera = 0;
|
|
1560
|
+
this._centerZDepth = 0;
|
|
1561
|
+
this._screenSpaceError = 0;
|
|
1562
|
+
this._visibilityPlaneMask = import_culling4.CullingVolume.MASK_INDETERMINATE;
|
|
1563
|
+
this._visible = void 0;
|
|
1564
|
+
this._inRequestVolume = false;
|
|
1565
|
+
this._stackLength = 0;
|
|
1566
|
+
this._selectionDepth = 0;
|
|
1567
|
+
this._frameNumber = 0;
|
|
1568
|
+
this._touchedFrame = 0;
|
|
1569
|
+
this._visitedFrame = 0;
|
|
1570
|
+
this._selectedFrame = 0;
|
|
1571
|
+
this._requestedFrame = 0;
|
|
1572
|
+
this._priority = 0;
|
|
1573
|
+
}
|
|
1574
|
+
_getRefine(refine) {
|
|
1575
|
+
return refine || this.parent && this.parent.refine || 2 /* REPLACE */;
|
|
1576
|
+
}
|
|
1577
|
+
_isTileset() {
|
|
1578
|
+
return this.contentUrl.indexOf(".json") !== -1;
|
|
1579
|
+
}
|
|
1580
|
+
_onContentLoaded() {
|
|
1581
|
+
switch (this.content && this.content.type) {
|
|
1582
|
+
case "vctr":
|
|
1583
|
+
case "geom":
|
|
1584
|
+
this.tileset._traverser.disableSkipLevelOfDetail = true;
|
|
1585
|
+
break;
|
|
1586
|
+
default:
|
|
1587
|
+
}
|
|
1588
|
+
if (this._isTileset()) {
|
|
1589
|
+
this.hasTilesetContent = true;
|
|
1590
|
+
} else {
|
|
1591
|
+
this.gpuMemoryUsageInBytes = this._getGpuMemoryUsageInBytes();
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
_updateBoundingVolume(header) {
|
|
1595
|
+
this.boundingVolume = createBoundingVolume(
|
|
1596
|
+
header.boundingVolume,
|
|
1597
|
+
this.computedTransform,
|
|
1598
|
+
this.boundingVolume
|
|
1599
|
+
);
|
|
1600
|
+
const content = header.content;
|
|
1601
|
+
if (!content) {
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
if (content.boundingVolume) {
|
|
1605
|
+
this._contentBoundingVolume = createBoundingVolume(
|
|
1606
|
+
content.boundingVolume,
|
|
1607
|
+
this.computedTransform,
|
|
1608
|
+
this._contentBoundingVolume
|
|
1609
|
+
);
|
|
1610
|
+
}
|
|
1611
|
+
if (header.viewerRequestVolume) {
|
|
1612
|
+
this._viewerRequestVolume = createBoundingVolume(
|
|
1613
|
+
header.viewerRequestVolume,
|
|
1614
|
+
this.computedTransform,
|
|
1615
|
+
this._viewerRequestVolume
|
|
1616
|
+
);
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
// Update the tile's transform. The transform is applied to the tile's bounding volumes.
|
|
1620
|
+
_updateTransform(parentTransform = new import_core7.Matrix4()) {
|
|
1621
|
+
const computedTransform = parentTransform.clone().multiplyRight(this.transform);
|
|
1622
|
+
const didTransformChange = !computedTransform.equals(this.computedTransform);
|
|
1623
|
+
if (!didTransformChange) {
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
this.computedTransform = computedTransform;
|
|
1627
|
+
this._updateBoundingVolume(this.header);
|
|
1628
|
+
}
|
|
1629
|
+
// Get options which are applicable only for the particular loader
|
|
1630
|
+
_getLoaderSpecificOptions(loaderId) {
|
|
1631
|
+
switch (loaderId) {
|
|
1632
|
+
case "i3s":
|
|
1633
|
+
return {
|
|
1634
|
+
...this.tileset.options.i3s,
|
|
1635
|
+
_tileOptions: {
|
|
1636
|
+
attributeUrls: this.header.attributeUrls,
|
|
1637
|
+
textureUrl: this.header.textureUrl,
|
|
1638
|
+
textureFormat: this.header.textureFormat,
|
|
1639
|
+
textureLoaderOptions: this.header.textureLoaderOptions,
|
|
1640
|
+
materialDefinition: this.header.materialDefinition,
|
|
1641
|
+
isDracoGeometry: this.header.isDracoGeometry,
|
|
1642
|
+
mbs: this.header.mbs
|
|
1643
|
+
},
|
|
1644
|
+
_tilesetOptions: {
|
|
1645
|
+
store: this.tileset.tileset.store,
|
|
1646
|
+
attributeStorageInfo: this.tileset.tileset.attributeStorageInfo,
|
|
1647
|
+
fields: this.tileset.tileset.fields
|
|
1648
|
+
},
|
|
1649
|
+
isTileHeader: false
|
|
1650
|
+
};
|
|
1651
|
+
case "3d-tiles":
|
|
1652
|
+
case "cesium-ion":
|
|
1653
|
+
default:
|
|
1654
|
+
return get3dTilesOptions(this.tileset.tileset);
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
|
|
1659
|
+
// src/tileset/format-3d-tiles/tileset-3d-traverser.ts
|
|
1660
|
+
var Tileset3DTraverser = class extends TilesetTraverser {
|
|
1661
|
+
compareDistanceToCamera(a, b) {
|
|
1662
|
+
return b._distanceToCamera === 0 && a._distanceToCamera === 0 ? b._centerZDepth - a._centerZDepth : b._distanceToCamera - a._distanceToCamera;
|
|
1663
|
+
}
|
|
1664
|
+
updateTileVisibility(tile, frameState) {
|
|
1665
|
+
super.updateTileVisibility(tile, frameState);
|
|
1666
|
+
if (!tile.isVisibleAndInRequestVolume) {
|
|
1667
|
+
return;
|
|
1668
|
+
}
|
|
1669
|
+
const hasChildren = tile.children.length > 0;
|
|
1670
|
+
if (tile.hasTilesetContent && hasChildren) {
|
|
1671
|
+
const firstChild = tile.children[0];
|
|
1672
|
+
this.updateTileVisibility(firstChild, frameState);
|
|
1673
|
+
tile._visible = firstChild._visible;
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
if (this.meetsScreenSpaceErrorEarly(tile, frameState)) {
|
|
1677
|
+
tile._visible = false;
|
|
1678
|
+
return;
|
|
1679
|
+
}
|
|
1680
|
+
const replace = tile.refine === 2 /* REPLACE */;
|
|
1681
|
+
const useOptimization = tile._optimChildrenWithinParent === TILE3D_OPTIMIZATION_HINT.USE_OPTIMIZATION;
|
|
1682
|
+
if (replace && useOptimization && hasChildren) {
|
|
1683
|
+
if (!this.anyChildrenVisible(tile, frameState)) {
|
|
1684
|
+
tile._visible = false;
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
meetsScreenSpaceErrorEarly(tile, frameState) {
|
|
1690
|
+
const { parent } = tile;
|
|
1691
|
+
if (!parent || parent.hasTilesetContent || parent.refine !== 1 /* ADD */) {
|
|
1692
|
+
return false;
|
|
1693
|
+
}
|
|
1694
|
+
return !this.shouldRefine(tile, frameState, true);
|
|
1695
|
+
}
|
|
1696
|
+
};
|
|
1697
|
+
|
|
1698
|
+
// src/tileset/format-i3s/i3s-tileset-traverser.ts
|
|
1699
|
+
var import_core9 = require("@loaders.gl/core");
|
|
1700
|
+
|
|
1701
|
+
// src/tileset/format-i3s/i3s-pending-tiles-register.ts
|
|
1702
|
+
var I3SPendingTilesRegister = class {
|
|
1703
|
+
constructor() {
|
|
1704
|
+
this.frameNumberMap = /* @__PURE__ */ new Map();
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Register a new pending tile header for the particular frameNumber
|
|
1708
|
+
* @param viewportId
|
|
1709
|
+
* @param frameNumber
|
|
1710
|
+
*/
|
|
1711
|
+
register(viewportId, frameNumber) {
|
|
1712
|
+
const viewportMap = this.frameNumberMap.get(viewportId) || /* @__PURE__ */ new Map();
|
|
1713
|
+
const oldCount = viewportMap.get(frameNumber) || 0;
|
|
1714
|
+
viewportMap.set(frameNumber, oldCount + 1);
|
|
1715
|
+
this.frameNumberMap.set(viewportId, viewportMap);
|
|
1716
|
+
}
|
|
1717
|
+
/**
|
|
1718
|
+
* Deregister a pending tile header for the particular frameNumber
|
|
1719
|
+
* @param viewportId
|
|
1720
|
+
* @param frameNumber
|
|
1721
|
+
*/
|
|
1722
|
+
deregister(viewportId, frameNumber) {
|
|
1723
|
+
const viewportMap = this.frameNumberMap.get(viewportId);
|
|
1724
|
+
if (!viewportMap) {
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
const oldCount = viewportMap.get(frameNumber) || 1;
|
|
1728
|
+
viewportMap.set(frameNumber, oldCount - 1);
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* Check is there are no pending tile headers registered for the particular frameNumber
|
|
1732
|
+
* @param viewportId
|
|
1733
|
+
* @param frameNumber
|
|
1734
|
+
* @returns
|
|
1735
|
+
*/
|
|
1736
|
+
isZero(viewportId, frameNumber) {
|
|
1737
|
+
var _a;
|
|
1738
|
+
const count = ((_a = this.frameNumberMap.get(viewportId)) == null ? void 0 : _a.get(frameNumber)) || 0;
|
|
1739
|
+
return count === 0;
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1742
|
+
|
|
1743
|
+
// src/tileset/format-i3s/i3s-tile-manager.ts
|
|
1744
|
+
var STATUS = {
|
|
1745
|
+
REQUESTED: "REQUESTED",
|
|
1746
|
+
COMPLETED: "COMPLETED",
|
|
1747
|
+
ERROR: "ERROR"
|
|
1748
|
+
};
|
|
1749
|
+
var I3STileManager = class {
|
|
1750
|
+
constructor() {
|
|
1751
|
+
this.pendingTilesRegister = new I3SPendingTilesRegister();
|
|
1752
|
+
this._statusMap = {};
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Add request to map
|
|
1756
|
+
* @param request - node metadata request
|
|
1757
|
+
* @param key - unique key
|
|
1758
|
+
* @param callback - callback after request completed
|
|
1759
|
+
* @param frameState - frameState data
|
|
1760
|
+
*/
|
|
1761
|
+
add(request, key, callback, frameState) {
|
|
1762
|
+
if (!this._statusMap[key]) {
|
|
1763
|
+
const {
|
|
1764
|
+
frameNumber,
|
|
1765
|
+
viewport: { id }
|
|
1766
|
+
} = frameState;
|
|
1767
|
+
this._statusMap[key] = { request, callback, key, frameState, status: STATUS.REQUESTED };
|
|
1768
|
+
this.pendingTilesRegister.register(id, frameNumber);
|
|
1769
|
+
request().then((data) => {
|
|
1770
|
+
this._statusMap[key].status = STATUS.COMPLETED;
|
|
1771
|
+
const {
|
|
1772
|
+
frameNumber: actualFrameNumber,
|
|
1773
|
+
viewport: { id: id2 }
|
|
1774
|
+
} = this._statusMap[key].frameState;
|
|
1775
|
+
this.pendingTilesRegister.deregister(id2, actualFrameNumber);
|
|
1776
|
+
this._statusMap[key].callback(data, frameState);
|
|
1777
|
+
}).catch((error) => {
|
|
1778
|
+
this._statusMap[key].status = STATUS.ERROR;
|
|
1779
|
+
const {
|
|
1780
|
+
frameNumber: actualFrameNumber,
|
|
1781
|
+
viewport: { id: id2 }
|
|
1782
|
+
} = this._statusMap[key].frameState;
|
|
1783
|
+
this.pendingTilesRegister.deregister(id2, actualFrameNumber);
|
|
1784
|
+
callback(error);
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
/**
|
|
1789
|
+
* Update request if it is still actual for the new frameState
|
|
1790
|
+
* @param key - unique key
|
|
1791
|
+
* @param frameState - frameState data
|
|
1792
|
+
*/
|
|
1793
|
+
update(key, frameState) {
|
|
1794
|
+
if (this._statusMap[key]) {
|
|
1795
|
+
const {
|
|
1796
|
+
frameNumber,
|
|
1797
|
+
viewport: { id }
|
|
1798
|
+
} = this._statusMap[key].frameState;
|
|
1799
|
+
this.pendingTilesRegister.deregister(id, frameNumber);
|
|
1800
|
+
const {
|
|
1801
|
+
frameNumber: newFrameNumber,
|
|
1802
|
+
viewport: { id: newViewportId }
|
|
1803
|
+
} = frameState;
|
|
1804
|
+
this.pendingTilesRegister.register(newViewportId, newFrameNumber);
|
|
1805
|
+
this._statusMap[key].frameState = frameState;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* Find request in the map
|
|
1810
|
+
* @param key - unique key
|
|
1811
|
+
* @returns
|
|
1812
|
+
*/
|
|
1813
|
+
find(key) {
|
|
1814
|
+
return this._statusMap[key];
|
|
1815
|
+
}
|
|
1816
|
+
/**
|
|
1817
|
+
* Check it there are pending tile headers for the particular frameNumber
|
|
1818
|
+
* @param viewportId
|
|
1819
|
+
* @param frameNumber
|
|
1820
|
+
* @returns
|
|
1821
|
+
*/
|
|
1822
|
+
hasPendingTiles(viewportId, frameNumber) {
|
|
1823
|
+
return !this.pendingTilesRegister.isZero(viewportId, frameNumber);
|
|
1824
|
+
}
|
|
1825
|
+
};
|
|
1826
|
+
|
|
1827
|
+
// src/tileset/format-i3s/i3s-tileset-traverser.ts
|
|
1828
|
+
var I3STilesetTraverser = class extends TilesetTraverser {
|
|
1829
|
+
constructor(options) {
|
|
1830
|
+
super(options);
|
|
1831
|
+
this._tileManager = new I3STileManager();
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Check if there are no penging tile header requests,
|
|
1835
|
+
* that means the traversal is finished and we can call
|
|
1836
|
+
* following-up callbacks.
|
|
1837
|
+
*/
|
|
1838
|
+
traversalFinished(frameState) {
|
|
1839
|
+
return !this._tileManager.hasPendingTiles(frameState.viewport.id, this._frameNumber || 0);
|
|
1840
|
+
}
|
|
1841
|
+
shouldRefine(tile, frameState) {
|
|
1842
|
+
tile._lodJudge = getLodStatus(tile, frameState);
|
|
1843
|
+
return tile._lodJudge === "DIG";
|
|
1844
|
+
}
|
|
1845
|
+
updateChildTiles(tile, frameState) {
|
|
1846
|
+
const children = tile.header.children || [];
|
|
1847
|
+
const childTiles = tile.children;
|
|
1848
|
+
const tileset = tile.tileset;
|
|
1849
|
+
for (const child of children) {
|
|
1850
|
+
const extendedId = `${child.id}-${frameState.viewport.id}`;
|
|
1851
|
+
const childTile = childTiles && childTiles.find((t) => t.id === extendedId);
|
|
1852
|
+
if (!childTile) {
|
|
1853
|
+
let request = () => this._loadTile(child.id, tileset);
|
|
1854
|
+
const cachedRequest = this._tileManager.find(extendedId);
|
|
1855
|
+
if (!cachedRequest) {
|
|
1856
|
+
if (tileset.tileset.nodePages) {
|
|
1857
|
+
request = () => tileset.tileset.nodePagesTile.formTileFromNodePages(child.id);
|
|
1858
|
+
}
|
|
1859
|
+
this._tileManager.add(
|
|
1860
|
+
request,
|
|
1861
|
+
extendedId,
|
|
1862
|
+
(header) => this._onTileLoad(header, tile, extendedId),
|
|
1863
|
+
frameState
|
|
1864
|
+
);
|
|
1865
|
+
} else {
|
|
1866
|
+
this._tileManager.update(extendedId, frameState);
|
|
1867
|
+
}
|
|
1868
|
+
} else if (childTile) {
|
|
1869
|
+
this.updateTile(childTile, frameState);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
return false;
|
|
1873
|
+
}
|
|
1874
|
+
async _loadTile(nodeId, tileset) {
|
|
1875
|
+
const { loader } = tileset;
|
|
1876
|
+
const nodeUrl = tileset.getTileUrl(`${tileset.url}/nodes/${nodeId}`);
|
|
1877
|
+
const options = {
|
|
1878
|
+
...tileset.loadOptions,
|
|
1879
|
+
i3s: {
|
|
1880
|
+
...tileset.loadOptions.i3s,
|
|
1881
|
+
isTileHeader: true
|
|
1882
|
+
}
|
|
1883
|
+
};
|
|
1884
|
+
return await (0, import_core9.load)(nodeUrl, loader, options);
|
|
1885
|
+
}
|
|
1886
|
+
/**
|
|
1887
|
+
* The callback to init Tile3D instance after loading the tile JSON
|
|
1888
|
+
* @param {Object} header - the tile JSON from a dataset
|
|
1889
|
+
* @param {Tile3D} tile - the parent Tile3D instance
|
|
1890
|
+
* @param {string} extendedId - optional ID to separate copies of a tile for different viewports.
|
|
1891
|
+
* const extendedId = `${tile.id}-${frameState.viewport.id}`;
|
|
1892
|
+
* @return {void}
|
|
1893
|
+
*/
|
|
1894
|
+
_onTileLoad(header, tile, extendedId) {
|
|
1895
|
+
const childTile = new Tile3D(tile.tileset, header, tile, extendedId);
|
|
1896
|
+
tile.children.push(childTile);
|
|
1897
|
+
const frameState = this._tileManager.find(childTile.id).frameState;
|
|
1898
|
+
this.updateTile(childTile, frameState);
|
|
1899
|
+
if (this._frameNumber === frameState.frameNumber && (this.traversalFinished(frameState) || new Date().getTime() - this.lastUpdate > this.updateDebounceTime)) {
|
|
1900
|
+
this.executeTraversal(childTile, frameState);
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
};
|
|
1904
|
+
|
|
1905
|
+
// src/tileset/tileset-3d.ts
|
|
1906
|
+
var DEFAULT_PROPS2 = {
|
|
1907
|
+
description: "",
|
|
1908
|
+
ellipsoid: import_geospatial6.Ellipsoid.WGS84,
|
|
1909
|
+
modelMatrix: new import_core10.Matrix4(),
|
|
1910
|
+
throttleRequests: true,
|
|
1911
|
+
maxRequests: 64,
|
|
1912
|
+
maximumMemoryUsage: 32,
|
|
1913
|
+
maximumTilesSelected: 0,
|
|
1914
|
+
debounceTime: 0,
|
|
1915
|
+
onTileLoad: () => {
|
|
1916
|
+
},
|
|
1917
|
+
onTileUnload: () => {
|
|
1918
|
+
},
|
|
1919
|
+
onTileError: () => {
|
|
1920
|
+
},
|
|
1921
|
+
onTraversalComplete: (selectedTiles) => selectedTiles,
|
|
1922
|
+
contentLoader: void 0,
|
|
1923
|
+
viewDistanceScale: 1,
|
|
1924
|
+
maximumScreenSpaceError: 8,
|
|
1925
|
+
loadTiles: true,
|
|
1926
|
+
updateTransforms: true,
|
|
1927
|
+
viewportTraversersMap: null,
|
|
1928
|
+
loadOptions: { fetch: {} },
|
|
1929
|
+
attributions: [],
|
|
1930
|
+
basePath: "",
|
|
1931
|
+
i3s: {}
|
|
1932
|
+
};
|
|
1933
|
+
var TILES_TOTAL = "Tiles In Tileset(s)";
|
|
1934
|
+
var TILES_IN_MEMORY = "Tiles In Memory";
|
|
1935
|
+
var TILES_IN_VIEW = "Tiles In View";
|
|
1936
|
+
var TILES_RENDERABLE = "Tiles To Render";
|
|
1937
|
+
var TILES_LOADED = "Tiles Loaded";
|
|
1938
|
+
var TILES_LOADING = "Tiles Loading";
|
|
1939
|
+
var TILES_UNLOADED = "Tiles Unloaded";
|
|
1940
|
+
var TILES_LOAD_FAILED = "Failed Tile Loads";
|
|
1941
|
+
var POINTS_COUNT = "Points/Vertices";
|
|
1942
|
+
var TILES_GPU_MEMORY = "Tile Memory Use";
|
|
1943
|
+
var Tileset3D = class {
|
|
1944
|
+
/**
|
|
1945
|
+
* Create a new Tileset3D
|
|
1946
|
+
* @param json
|
|
1947
|
+
* @param props
|
|
1948
|
+
*/
|
|
1949
|
+
// eslint-disable-next-line max-statements
|
|
1950
|
+
constructor(tileset, options) {
|
|
1951
|
+
this.root = null;
|
|
1952
|
+
this.roots = {};
|
|
1953
|
+
/** @todo any->unknown */
|
|
1954
|
+
this.asset = {};
|
|
1955
|
+
// Metadata for the entire tileset
|
|
1956
|
+
this.description = "";
|
|
1957
|
+
this.extras = null;
|
|
1958
|
+
this.attributions = {};
|
|
1959
|
+
this.credits = {};
|
|
1960
|
+
/** flags that contain information about data types in nested tiles */
|
|
1961
|
+
this.contentFormats = { draco: false, meshopt: false, dds: false, ktx2: false };
|
|
1962
|
+
// view props
|
|
1963
|
+
this.cartographicCenter = null;
|
|
1964
|
+
this.cartesianCenter = null;
|
|
1965
|
+
this.zoom = 1;
|
|
1966
|
+
this.boundingVolume = null;
|
|
1967
|
+
/** Updated based on the camera position and direction */
|
|
1968
|
+
this.dynamicScreenSpaceErrorComputedDensity = 0;
|
|
1969
|
+
// METRICS
|
|
1970
|
+
/**
|
|
1971
|
+
* The maximum amount of GPU memory (in MB) that may be used to cache tiles
|
|
1972
|
+
* Tiles not in view are unloaded to enforce private
|
|
1973
|
+
*/
|
|
1974
|
+
this.maximumMemoryUsage = 32;
|
|
1975
|
+
/** The total amount of GPU memory in bytes used by the tileset. */
|
|
1976
|
+
this.gpuMemoryUsageInBytes = 0;
|
|
1977
|
+
/** Update tracker. increase in each update cycle. */
|
|
1978
|
+
this._frameNumber = 0;
|
|
1979
|
+
this._queryParams = {};
|
|
1980
|
+
this._extensionsUsed = [];
|
|
1981
|
+
this._tiles = {};
|
|
1982
|
+
/** counter for tracking tiles requests */
|
|
1983
|
+
this._pendingCount = 0;
|
|
1984
|
+
/** Hold traversal results */
|
|
1985
|
+
this.selectedTiles = [];
|
|
1986
|
+
// TRAVERSAL
|
|
1987
|
+
this.traverseCounter = 0;
|
|
1988
|
+
this.geometricError = 0;
|
|
1989
|
+
this.lastUpdatedVieports = null;
|
|
1990
|
+
this._requestedTiles = [];
|
|
1991
|
+
this._emptyTiles = [];
|
|
1992
|
+
this.frameStateData = {};
|
|
1993
|
+
this._cache = new TilesetCache();
|
|
1994
|
+
// Promise tracking
|
|
1995
|
+
this.updatePromise = null;
|
|
1996
|
+
this.options = { ...DEFAULT_PROPS2, ...options };
|
|
1997
|
+
this.tileset = tileset;
|
|
1998
|
+
this.loader = tileset.loader;
|
|
1999
|
+
this.type = tileset.type;
|
|
2000
|
+
this.url = tileset.url;
|
|
2001
|
+
this.basePath = tileset.basePath || import_loader_utils4.path.dirname(this.url);
|
|
2002
|
+
this.modelMatrix = this.options.modelMatrix;
|
|
2003
|
+
this.ellipsoid = this.options.ellipsoid;
|
|
2004
|
+
this.lodMetricType = tileset.lodMetricType;
|
|
2005
|
+
this.lodMetricValue = tileset.lodMetricValue;
|
|
2006
|
+
this.refine = tileset.root.refine;
|
|
2007
|
+
this.loadOptions = this.options.loadOptions || {};
|
|
2008
|
+
this._traverser = this._initializeTraverser();
|
|
2009
|
+
this._requestScheduler = new import_loader_utils4.RequestScheduler({
|
|
2010
|
+
throttleRequests: this.options.throttleRequests,
|
|
2011
|
+
maxRequests: this.options.maxRequests
|
|
2012
|
+
});
|
|
2013
|
+
this.stats = new import_stats.Stats({ id: this.url });
|
|
2014
|
+
this._initializeStats();
|
|
2015
|
+
this.tilesetInitializationPromise = this._initializeTileSet(tileset);
|
|
2016
|
+
}
|
|
2017
|
+
/** Release resources */
|
|
2018
|
+
destroy() {
|
|
2019
|
+
this._destroy();
|
|
2020
|
+
}
|
|
2021
|
+
/** Is the tileset loaded (update needs to have been called at least once) */
|
|
2022
|
+
isLoaded() {
|
|
2023
|
+
return this._pendingCount === 0 && this._frameNumber !== 0 && this._requestedTiles.length === 0;
|
|
2024
|
+
}
|
|
2025
|
+
get tiles() {
|
|
2026
|
+
return Object.values(this._tiles);
|
|
2027
|
+
}
|
|
2028
|
+
get frameNumber() {
|
|
2029
|
+
return this._frameNumber;
|
|
2030
|
+
}
|
|
2031
|
+
get queryParams() {
|
|
2032
|
+
return new URLSearchParams(this._queryParams).toString();
|
|
2033
|
+
}
|
|
2034
|
+
setProps(props) {
|
|
2035
|
+
this.options = { ...this.options, ...props };
|
|
2036
|
+
}
|
|
2037
|
+
/** @deprecated */
|
|
2038
|
+
setOptions(options) {
|
|
2039
|
+
this.options = { ...this.options, ...options };
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* Return a loadable tile url for a specific tile subpath
|
|
2043
|
+
* @param tilePath a tile subpath
|
|
2044
|
+
*/
|
|
2045
|
+
getTileUrl(tilePath) {
|
|
2046
|
+
const isDataUrl = tilePath.startsWith("data:");
|
|
2047
|
+
if (isDataUrl) {
|
|
2048
|
+
return tilePath;
|
|
2049
|
+
}
|
|
2050
|
+
let tileUrl = tilePath;
|
|
2051
|
+
if (this.queryParams.length) {
|
|
2052
|
+
tileUrl = `${tilePath}${tilePath.includes("?") ? "&" : "?"}${this.queryParams}`;
|
|
2053
|
+
}
|
|
2054
|
+
return tileUrl;
|
|
2055
|
+
}
|
|
2056
|
+
// TODO CESIUM specific
|
|
2057
|
+
hasExtension(extensionName) {
|
|
2058
|
+
return Boolean(this._extensionsUsed.indexOf(extensionName) > -1);
|
|
2059
|
+
}
|
|
2060
|
+
/**
|
|
2061
|
+
* Update visible tiles relying on a list of viewports
|
|
2062
|
+
* @param viewports - list of viewports
|
|
2063
|
+
* @deprecated
|
|
2064
|
+
*/
|
|
2065
|
+
update(viewports = null) {
|
|
2066
|
+
this.tilesetInitializationPromise.then(() => {
|
|
2067
|
+
if (!viewports && this.lastUpdatedVieports) {
|
|
2068
|
+
viewports = this.lastUpdatedVieports;
|
|
2069
|
+
} else {
|
|
2070
|
+
this.lastUpdatedVieports = viewports;
|
|
2071
|
+
}
|
|
2072
|
+
if (viewports) {
|
|
2073
|
+
this.doUpdate(viewports);
|
|
2074
|
+
}
|
|
2075
|
+
});
|
|
2076
|
+
}
|
|
2077
|
+
/**
|
|
2078
|
+
* Update visible tiles relying on a list of viewports.
|
|
2079
|
+
* Do it with debounce delay to prevent update spam
|
|
2080
|
+
* @param viewports viewports
|
|
2081
|
+
* @returns Promise of new frameNumber
|
|
2082
|
+
*/
|
|
2083
|
+
async selectTiles(viewports = null) {
|
|
2084
|
+
await this.tilesetInitializationPromise;
|
|
2085
|
+
if (viewports) {
|
|
2086
|
+
this.lastUpdatedVieports = viewports;
|
|
2087
|
+
}
|
|
2088
|
+
if (!this.updatePromise) {
|
|
2089
|
+
this.updatePromise = new Promise((resolve) => {
|
|
2090
|
+
setTimeout(() => {
|
|
2091
|
+
if (this.lastUpdatedVieports) {
|
|
2092
|
+
this.doUpdate(this.lastUpdatedVieports);
|
|
2093
|
+
}
|
|
2094
|
+
resolve(this._frameNumber);
|
|
2095
|
+
this.updatePromise = null;
|
|
2096
|
+
}, this.options.debounceTime);
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
return this.updatePromise;
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Update visible tiles relying on a list of viewports
|
|
2103
|
+
* @param viewports viewports
|
|
2104
|
+
*/
|
|
2105
|
+
// eslint-disable-next-line max-statements, complexity
|
|
2106
|
+
doUpdate(viewports) {
|
|
2107
|
+
if ("loadTiles" in this.options && !this.options.loadTiles) {
|
|
2108
|
+
return;
|
|
2109
|
+
}
|
|
2110
|
+
if (this.traverseCounter > 0) {
|
|
2111
|
+
return;
|
|
2112
|
+
}
|
|
2113
|
+
const preparedViewports = viewports instanceof Array ? viewports : [viewports];
|
|
2114
|
+
this._cache.reset();
|
|
2115
|
+
this._frameNumber++;
|
|
2116
|
+
this.traverseCounter = preparedViewports.length;
|
|
2117
|
+
const viewportsToTraverse = [];
|
|
2118
|
+
for (const viewport of preparedViewports) {
|
|
2119
|
+
const id = viewport.id;
|
|
2120
|
+
if (this._needTraverse(id)) {
|
|
2121
|
+
viewportsToTraverse.push(id);
|
|
2122
|
+
} else {
|
|
2123
|
+
this.traverseCounter--;
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
for (const viewport of preparedViewports) {
|
|
2127
|
+
const id = viewport.id;
|
|
2128
|
+
if (!this.roots[id]) {
|
|
2129
|
+
this.roots[id] = this._initializeTileHeaders(this.tileset, null);
|
|
2130
|
+
}
|
|
2131
|
+
if (!viewportsToTraverse.includes(id)) {
|
|
2132
|
+
continue;
|
|
2133
|
+
}
|
|
2134
|
+
const frameState = getFrameState(viewport, this._frameNumber);
|
|
2135
|
+
this._traverser.traverse(this.roots[id], frameState, this.options);
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Check if traversal is needed for particular viewport
|
|
2140
|
+
* @param {string} viewportId - id of a viewport
|
|
2141
|
+
* @return {boolean}
|
|
2142
|
+
*/
|
|
2143
|
+
_needTraverse(viewportId) {
|
|
2144
|
+
let traverserId = viewportId;
|
|
2145
|
+
if (this.options.viewportTraversersMap) {
|
|
2146
|
+
traverserId = this.options.viewportTraversersMap[viewportId];
|
|
2147
|
+
}
|
|
2148
|
+
if (traverserId !== viewportId) {
|
|
2149
|
+
return false;
|
|
2150
|
+
}
|
|
2151
|
+
return true;
|
|
2152
|
+
}
|
|
2153
|
+
/**
|
|
2154
|
+
* The callback to post-process tiles after traversal procedure
|
|
2155
|
+
* @param frameState - frame state for tile culling
|
|
2156
|
+
*/
|
|
2157
|
+
_onTraversalEnd(frameState) {
|
|
2158
|
+
const id = frameState.viewport.id;
|
|
2159
|
+
if (!this.frameStateData[id]) {
|
|
2160
|
+
this.frameStateData[id] = { selectedTiles: [], _requestedTiles: [], _emptyTiles: [] };
|
|
2161
|
+
}
|
|
2162
|
+
const currentFrameStateData = this.frameStateData[id];
|
|
2163
|
+
const selectedTiles = Object.values(this._traverser.selectedTiles);
|
|
2164
|
+
const [filteredSelectedTiles, unselectedTiles] = limitSelectedTiles(
|
|
2165
|
+
selectedTiles,
|
|
2166
|
+
frameState,
|
|
2167
|
+
this.options.maximumTilesSelected
|
|
2168
|
+
);
|
|
2169
|
+
currentFrameStateData.selectedTiles = filteredSelectedTiles;
|
|
2170
|
+
for (const tile of unselectedTiles) {
|
|
2171
|
+
tile.unselect();
|
|
2172
|
+
}
|
|
2173
|
+
currentFrameStateData._requestedTiles = Object.values(this._traverser.requestedTiles);
|
|
2174
|
+
currentFrameStateData._emptyTiles = Object.values(this._traverser.emptyTiles);
|
|
2175
|
+
this.traverseCounter--;
|
|
2176
|
+
if (this.traverseCounter > 0) {
|
|
2177
|
+
return;
|
|
2178
|
+
}
|
|
2179
|
+
this._updateTiles();
|
|
2180
|
+
}
|
|
2181
|
+
/**
|
|
2182
|
+
* Update tiles relying on data from all traversers
|
|
2183
|
+
*/
|
|
2184
|
+
_updateTiles() {
|
|
2185
|
+
this.selectedTiles = [];
|
|
2186
|
+
this._requestedTiles = [];
|
|
2187
|
+
this._emptyTiles = [];
|
|
2188
|
+
for (const frameStateKey in this.frameStateData) {
|
|
2189
|
+
const frameStateDataValue = this.frameStateData[frameStateKey];
|
|
2190
|
+
this.selectedTiles = this.selectedTiles.concat(frameStateDataValue.selectedTiles);
|
|
2191
|
+
this._requestedTiles = this._requestedTiles.concat(frameStateDataValue._requestedTiles);
|
|
2192
|
+
this._emptyTiles = this._emptyTiles.concat(frameStateDataValue._emptyTiles);
|
|
2193
|
+
}
|
|
2194
|
+
this.selectedTiles = this.options.onTraversalComplete(this.selectedTiles);
|
|
2195
|
+
for (const tile of this.selectedTiles) {
|
|
2196
|
+
this._tiles[tile.id] = tile;
|
|
2197
|
+
}
|
|
2198
|
+
this._loadTiles();
|
|
2199
|
+
this._unloadTiles();
|
|
2200
|
+
this._updateStats();
|
|
2201
|
+
}
|
|
2202
|
+
_tilesChanged(oldSelectedTiles, selectedTiles) {
|
|
2203
|
+
if (oldSelectedTiles.length !== selectedTiles.length) {
|
|
2204
|
+
return true;
|
|
2205
|
+
}
|
|
2206
|
+
const set1 = new Set(oldSelectedTiles.map((t) => t.id));
|
|
2207
|
+
const set2 = new Set(selectedTiles.map((t) => t.id));
|
|
2208
|
+
let changed = oldSelectedTiles.filter((x) => !set2.has(x.id)).length > 0;
|
|
2209
|
+
changed = changed || selectedTiles.filter((x) => !set1.has(x.id)).length > 0;
|
|
2210
|
+
return changed;
|
|
2211
|
+
}
|
|
2212
|
+
_loadTiles() {
|
|
2213
|
+
for (const tile of this._requestedTiles) {
|
|
2214
|
+
if (tile.contentUnloaded) {
|
|
2215
|
+
this._loadTile(tile);
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
_unloadTiles() {
|
|
2220
|
+
this._cache.unloadTiles(this, (tileset, tile) => tileset._unloadTile(tile));
|
|
2221
|
+
}
|
|
2222
|
+
_updateStats() {
|
|
2223
|
+
let tilesRenderable = 0;
|
|
2224
|
+
let pointsRenderable = 0;
|
|
2225
|
+
for (const tile of this.selectedTiles) {
|
|
2226
|
+
if (tile.contentAvailable && tile.content) {
|
|
2227
|
+
tilesRenderable++;
|
|
2228
|
+
if (tile.content.pointCount) {
|
|
2229
|
+
pointsRenderable += tile.content.pointCount;
|
|
2230
|
+
} else {
|
|
2231
|
+
pointsRenderable += tile.content.vertexCount;
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
this.stats.get(TILES_IN_VIEW).count = this.selectedTiles.length;
|
|
2236
|
+
this.stats.get(TILES_RENDERABLE).count = tilesRenderable;
|
|
2237
|
+
this.stats.get(POINTS_COUNT).count = pointsRenderable;
|
|
2238
|
+
}
|
|
2239
|
+
async _initializeTileSet(tilesetJson) {
|
|
2240
|
+
if (this.type === "I3S" /* I3S */) {
|
|
2241
|
+
this.calculateViewPropsI3S();
|
|
2242
|
+
tilesetJson.root = await tilesetJson.root;
|
|
2243
|
+
}
|
|
2244
|
+
this.root = this._initializeTileHeaders(tilesetJson, null);
|
|
2245
|
+
if (this.type === "TILES3D" /* TILES3D */) {
|
|
2246
|
+
this._initializeTiles3DTileset(tilesetJson);
|
|
2247
|
+
this.calculateViewPropsTiles3D();
|
|
2248
|
+
}
|
|
2249
|
+
if (this.type === "I3S" /* I3S */) {
|
|
2250
|
+
this._initializeI3STileset();
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
/**
|
|
2254
|
+
* Called during initialize Tileset to initialize the tileset's cartographic center (longitude, latitude) and zoom.
|
|
2255
|
+
* These metrics help apps center view on tileset
|
|
2256
|
+
* For I3S there is extent (<1.8 version) or fullExtent (>=1.8 version) to calculate view props
|
|
2257
|
+
* @returns
|
|
2258
|
+
*/
|
|
2259
|
+
calculateViewPropsI3S() {
|
|
2260
|
+
var _a;
|
|
2261
|
+
const fullExtent = this.tileset.fullExtent;
|
|
2262
|
+
if (fullExtent) {
|
|
2263
|
+
const { xmin, xmax, ymin, ymax, zmin, zmax } = fullExtent;
|
|
2264
|
+
this.cartographicCenter = new import_core10.Vector3(
|
|
2265
|
+
xmin + (xmax - xmin) / 2,
|
|
2266
|
+
ymin + (ymax - ymin) / 2,
|
|
2267
|
+
zmin + (zmax - zmin) / 2
|
|
2268
|
+
);
|
|
2269
|
+
this.cartesianCenter = new import_core10.Vector3();
|
|
2270
|
+
import_geospatial6.Ellipsoid.WGS84.cartographicToCartesian(this.cartographicCenter, this.cartesianCenter);
|
|
2271
|
+
this.zoom = getZoomFromFullExtent(fullExtent, this.cartographicCenter, this.cartesianCenter);
|
|
2272
|
+
return;
|
|
2273
|
+
}
|
|
2274
|
+
const extent = (_a = this.tileset.store) == null ? void 0 : _a.extent;
|
|
2275
|
+
if (extent) {
|
|
2276
|
+
const [xmin, ymin, xmax, ymax] = extent;
|
|
2277
|
+
this.cartographicCenter = new import_core10.Vector3(xmin + (xmax - xmin) / 2, ymin + (ymax - ymin) / 2, 0);
|
|
2278
|
+
this.cartesianCenter = new import_core10.Vector3();
|
|
2279
|
+
import_geospatial6.Ellipsoid.WGS84.cartographicToCartesian(this.cartographicCenter, this.cartesianCenter);
|
|
2280
|
+
this.zoom = getZoomFromExtent(extent, this.cartographicCenter, this.cartesianCenter);
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
2283
|
+
console.warn("Extent is not defined in the tileset header");
|
|
2284
|
+
this.cartographicCenter = new import_core10.Vector3();
|
|
2285
|
+
this.zoom = 1;
|
|
2286
|
+
return;
|
|
2287
|
+
}
|
|
2288
|
+
/**
|
|
2289
|
+
* Called during initialize Tileset to initialize the tileset's cartographic center (longitude, latitude) and zoom.
|
|
2290
|
+
* These metrics help apps center view on tileset.
|
|
2291
|
+
* For 3DTiles the root tile data is used to calculate view props.
|
|
2292
|
+
* @returns
|
|
2293
|
+
*/
|
|
2294
|
+
calculateViewPropsTiles3D() {
|
|
2295
|
+
const root = this.root;
|
|
2296
|
+
const { center } = root.boundingVolume;
|
|
2297
|
+
if (!center) {
|
|
2298
|
+
console.warn("center was not pre-calculated for the root tile");
|
|
2299
|
+
this.cartographicCenter = new import_core10.Vector3();
|
|
2300
|
+
this.zoom = 1;
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
if (center[0] !== 0 || center[1] !== 0 || center[2] !== 0) {
|
|
2304
|
+
this.cartographicCenter = new import_core10.Vector3();
|
|
2305
|
+
import_geospatial6.Ellipsoid.WGS84.cartesianToCartographic(center, this.cartographicCenter);
|
|
2306
|
+
} else {
|
|
2307
|
+
this.cartographicCenter = new import_core10.Vector3(0, 0, -import_geospatial6.Ellipsoid.WGS84.radii[0]);
|
|
2308
|
+
}
|
|
2309
|
+
this.cartesianCenter = center;
|
|
2310
|
+
this.zoom = getZoomFromBoundingVolume(root.boundingVolume, this.cartographicCenter);
|
|
2311
|
+
}
|
|
2312
|
+
_initializeStats() {
|
|
2313
|
+
this.stats.get(TILES_TOTAL);
|
|
2314
|
+
this.stats.get(TILES_LOADING);
|
|
2315
|
+
this.stats.get(TILES_IN_MEMORY);
|
|
2316
|
+
this.stats.get(TILES_IN_VIEW);
|
|
2317
|
+
this.stats.get(TILES_RENDERABLE);
|
|
2318
|
+
this.stats.get(TILES_LOADED);
|
|
2319
|
+
this.stats.get(TILES_UNLOADED);
|
|
2320
|
+
this.stats.get(TILES_LOAD_FAILED);
|
|
2321
|
+
this.stats.get(POINTS_COUNT);
|
|
2322
|
+
this.stats.get(TILES_GPU_MEMORY, "memory");
|
|
2323
|
+
}
|
|
2324
|
+
// Installs the main tileset JSON file or a tileset JSON file referenced from a tile.
|
|
2325
|
+
// eslint-disable-next-line max-statements
|
|
2326
|
+
_initializeTileHeaders(tilesetJson, parentTileHeader) {
|
|
2327
|
+
var _a;
|
|
2328
|
+
const rootTile = new Tile3D(this, tilesetJson.root, parentTileHeader);
|
|
2329
|
+
if (parentTileHeader) {
|
|
2330
|
+
parentTileHeader.children.push(rootTile);
|
|
2331
|
+
rootTile.depth = parentTileHeader.depth + 1;
|
|
2332
|
+
}
|
|
2333
|
+
if (this.type === "TILES3D" /* TILES3D */) {
|
|
2334
|
+
const stack = [];
|
|
2335
|
+
stack.push(rootTile);
|
|
2336
|
+
while (stack.length > 0) {
|
|
2337
|
+
const tile = stack.pop();
|
|
2338
|
+
this.stats.get(TILES_TOTAL).incrementCount();
|
|
2339
|
+
const children = tile.header.children || [];
|
|
2340
|
+
for (const childHeader of children) {
|
|
2341
|
+
const childTile = new Tile3D(this, childHeader, tile);
|
|
2342
|
+
if ((_a = childTile.contentUrl) == null ? void 0 : _a.includes("?session=")) {
|
|
2343
|
+
const url = new URL(childTile.contentUrl);
|
|
2344
|
+
const session = url.searchParams.get("session");
|
|
2345
|
+
if (session) {
|
|
2346
|
+
this._queryParams.session = session;
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
tile.children.push(childTile);
|
|
2350
|
+
childTile.depth = tile.depth + 1;
|
|
2351
|
+
stack.push(childTile);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
return rootTile;
|
|
2356
|
+
}
|
|
2357
|
+
_initializeTraverser() {
|
|
2358
|
+
let TraverserClass;
|
|
2359
|
+
const type = this.type;
|
|
2360
|
+
switch (type) {
|
|
2361
|
+
case "TILES3D" /* TILES3D */:
|
|
2362
|
+
TraverserClass = Tileset3DTraverser;
|
|
2363
|
+
break;
|
|
2364
|
+
case "I3S" /* I3S */:
|
|
2365
|
+
TraverserClass = I3STilesetTraverser;
|
|
2366
|
+
break;
|
|
2367
|
+
default:
|
|
2368
|
+
TraverserClass = TilesetTraverser;
|
|
2369
|
+
}
|
|
2370
|
+
return new TraverserClass({
|
|
2371
|
+
basePath: this.basePath,
|
|
2372
|
+
onTraversalEnd: this._onTraversalEnd.bind(this)
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2375
|
+
_destroyTileHeaders(parentTile) {
|
|
2376
|
+
this._destroySubtree(parentTile);
|
|
2377
|
+
}
|
|
2378
|
+
async _loadTile(tile) {
|
|
2379
|
+
let loaded;
|
|
2380
|
+
try {
|
|
2381
|
+
this._onStartTileLoading();
|
|
2382
|
+
loaded = await tile.loadContent();
|
|
2383
|
+
} catch (error) {
|
|
2384
|
+
this._onTileLoadError(tile, error instanceof Error ? error : new Error("load failed"));
|
|
2385
|
+
} finally {
|
|
2386
|
+
this._onEndTileLoading();
|
|
2387
|
+
this._onTileLoad(tile, loaded);
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
_onTileLoadError(tile, error) {
|
|
2391
|
+
this.stats.get(TILES_LOAD_FAILED).incrementCount();
|
|
2392
|
+
const message = error.message || error.toString();
|
|
2393
|
+
const url = tile.url;
|
|
2394
|
+
console.error(`A 3D tile failed to load: ${tile.url} ${message}`);
|
|
2395
|
+
this.options.onTileError(tile, message, url);
|
|
2396
|
+
}
|
|
2397
|
+
_onTileLoad(tile, loaded) {
|
|
2398
|
+
var _a, _b;
|
|
2399
|
+
if (!loaded) {
|
|
2400
|
+
return;
|
|
2401
|
+
}
|
|
2402
|
+
if (this.type === "I3S" /* I3S */) {
|
|
2403
|
+
const nodesInNodePages = ((_b = (_a = this.tileset) == null ? void 0 : _a.nodePagesTile) == null ? void 0 : _b.nodesInNodePages) || 0;
|
|
2404
|
+
this.stats.get(TILES_TOTAL).reset();
|
|
2405
|
+
this.stats.get(TILES_TOTAL).addCount(nodesInNodePages);
|
|
2406
|
+
}
|
|
2407
|
+
if (tile && tile.content) {
|
|
2408
|
+
calculateTransformProps(tile, tile.content);
|
|
2409
|
+
}
|
|
2410
|
+
this.updateContentTypes(tile);
|
|
2411
|
+
this._addTileToCache(tile);
|
|
2412
|
+
this.options.onTileLoad(tile);
|
|
2413
|
+
}
|
|
2414
|
+
/**
|
|
2415
|
+
* Update information about data types in nested tiles
|
|
2416
|
+
* @param tile instance of a nested Tile3D
|
|
2417
|
+
*/
|
|
2418
|
+
updateContentTypes(tile) {
|
|
2419
|
+
var _a;
|
|
2420
|
+
if (this.type === "I3S" /* I3S */) {
|
|
2421
|
+
if (tile.header.isDracoGeometry) {
|
|
2422
|
+
this.contentFormats.draco = true;
|
|
2423
|
+
}
|
|
2424
|
+
switch (tile.header.textureFormat) {
|
|
2425
|
+
case "dds":
|
|
2426
|
+
this.contentFormats.dds = true;
|
|
2427
|
+
break;
|
|
2428
|
+
case "ktx2":
|
|
2429
|
+
this.contentFormats.ktx2 = true;
|
|
2430
|
+
break;
|
|
2431
|
+
default:
|
|
2432
|
+
}
|
|
2433
|
+
} else if (this.type === "TILES3D" /* TILES3D */) {
|
|
2434
|
+
const { extensionsRemoved = [] } = ((_a = tile.content) == null ? void 0 : _a.gltf) || {};
|
|
2435
|
+
if (extensionsRemoved.includes("KHR_draco_mesh_compression")) {
|
|
2436
|
+
this.contentFormats.draco = true;
|
|
2437
|
+
}
|
|
2438
|
+
if (extensionsRemoved.includes("EXT_meshopt_compression")) {
|
|
2439
|
+
this.contentFormats.meshopt = true;
|
|
2440
|
+
}
|
|
2441
|
+
if (extensionsRemoved.includes("KHR_texture_basisu")) {
|
|
2442
|
+
this.contentFormats.ktx2 = true;
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
_onStartTileLoading() {
|
|
2447
|
+
this._pendingCount++;
|
|
2448
|
+
this.stats.get(TILES_LOADING).incrementCount();
|
|
2449
|
+
}
|
|
2450
|
+
_onEndTileLoading() {
|
|
2451
|
+
this._pendingCount--;
|
|
2452
|
+
this.stats.get(TILES_LOADING).decrementCount();
|
|
2453
|
+
}
|
|
2454
|
+
_addTileToCache(tile) {
|
|
2455
|
+
this._cache.add(this, tile, (tileset) => tileset._updateCacheStats(tile));
|
|
2456
|
+
}
|
|
2457
|
+
_updateCacheStats(tile) {
|
|
2458
|
+
this.stats.get(TILES_LOADED).incrementCount();
|
|
2459
|
+
this.stats.get(TILES_IN_MEMORY).incrementCount();
|
|
2460
|
+
this.gpuMemoryUsageInBytes += tile.gpuMemoryUsageInBytes || 0;
|
|
2461
|
+
this.stats.get(TILES_GPU_MEMORY).count = this.gpuMemoryUsageInBytes;
|
|
2462
|
+
}
|
|
2463
|
+
_unloadTile(tile) {
|
|
2464
|
+
this.gpuMemoryUsageInBytes -= tile.gpuMemoryUsageInBytes || 0;
|
|
2465
|
+
this.stats.get(TILES_IN_MEMORY).decrementCount();
|
|
2466
|
+
this.stats.get(TILES_UNLOADED).incrementCount();
|
|
2467
|
+
this.stats.get(TILES_GPU_MEMORY).count = this.gpuMemoryUsageInBytes;
|
|
2468
|
+
this.options.onTileUnload(tile);
|
|
2469
|
+
tile.unloadContent();
|
|
2470
|
+
}
|
|
2471
|
+
// Traverse the tree and destroy all tiles
|
|
2472
|
+
_destroy() {
|
|
2473
|
+
const stack = [];
|
|
2474
|
+
if (this.root) {
|
|
2475
|
+
stack.push(this.root);
|
|
2476
|
+
}
|
|
2477
|
+
while (stack.length > 0) {
|
|
2478
|
+
const tile = stack.pop();
|
|
2479
|
+
for (const child of tile.children) {
|
|
2480
|
+
stack.push(child);
|
|
2481
|
+
}
|
|
2482
|
+
this._destroyTile(tile);
|
|
2483
|
+
}
|
|
2484
|
+
this.root = null;
|
|
2485
|
+
}
|
|
2486
|
+
// Traverse the tree and destroy all sub tiles
|
|
2487
|
+
_destroySubtree(tile) {
|
|
2488
|
+
const root = tile;
|
|
2489
|
+
const stack = [];
|
|
2490
|
+
stack.push(root);
|
|
2491
|
+
while (stack.length > 0) {
|
|
2492
|
+
tile = stack.pop();
|
|
2493
|
+
for (const child of tile.children) {
|
|
2494
|
+
stack.push(child);
|
|
2495
|
+
}
|
|
2496
|
+
if (tile !== root) {
|
|
2497
|
+
this._destroyTile(tile);
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
root.children = [];
|
|
2501
|
+
}
|
|
2502
|
+
_destroyTile(tile) {
|
|
2503
|
+
this._cache.unloadTile(this, tile);
|
|
2504
|
+
this._unloadTile(tile);
|
|
2505
|
+
tile.destroy();
|
|
2506
|
+
}
|
|
2507
|
+
_initializeTiles3DTileset(tilesetJson) {
|
|
2508
|
+
if (tilesetJson.queryString) {
|
|
2509
|
+
const searchParams = new URLSearchParams(tilesetJson.queryString);
|
|
2510
|
+
const queryParams = Object.fromEntries(searchParams.entries());
|
|
2511
|
+
this._queryParams = { ...this._queryParams, ...queryParams };
|
|
2512
|
+
}
|
|
2513
|
+
this.asset = tilesetJson.asset;
|
|
2514
|
+
if (!this.asset) {
|
|
2515
|
+
throw new Error("Tileset must have an asset property.");
|
|
2516
|
+
}
|
|
2517
|
+
if (this.asset.version !== "0.0" && this.asset.version !== "1.0" && this.asset.version !== "1.1") {
|
|
2518
|
+
throw new Error("The tileset must be 3D Tiles version either 0.0 or 1.0 or 1.1.");
|
|
2519
|
+
}
|
|
2520
|
+
if ("tilesetVersion" in this.asset) {
|
|
2521
|
+
this._queryParams.v = this.asset.tilesetVersion;
|
|
2522
|
+
}
|
|
2523
|
+
this.credits = {
|
|
2524
|
+
attributions: this.options.attributions || []
|
|
2525
|
+
};
|
|
2526
|
+
this.description = this.options.description || "";
|
|
2527
|
+
this.properties = tilesetJson.properties;
|
|
2528
|
+
this.geometricError = tilesetJson.geometricError;
|
|
2529
|
+
this._extensionsUsed = tilesetJson.extensionsUsed || [];
|
|
2530
|
+
this.extras = tilesetJson.extras;
|
|
2531
|
+
}
|
|
2532
|
+
_initializeI3STileset() {
|
|
2533
|
+
if (this.loadOptions.i3s && "token" in this.loadOptions.i3s) {
|
|
2534
|
+
this._queryParams.token = this.loadOptions.i3s.token;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
};
|