@loaders.gl/tile-converter 5.0.0-alpha.7 → 5.0.0-alpha.8
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/README.md +155 -0
- package/dist/converter.min.cjs +194 -175
- package/dist/i3s-server/bin/i3s-server.min.cjs +84 -84
- package/dist/index.cjs +35865 -0
- package/dist/index.js +35837 -0
- package/dist/v5/browser-sink.d.ts +37 -0
- package/dist/v5/browser-source.d.ts +38 -0
- package/dist/v5/browser-tileset-source.d.ts +70 -0
- package/dist/v5/browser.cjs +1962 -0
- package/dist/v5/browser.d.ts +18 -0
- package/dist/v5/browser.js +1927 -0
- package/dist/v5/conversion-api.d.ts +122 -0
- package/dist/v5/feature-arrow.d.ts +36 -0
- package/dist/v5/index.cjs +3975 -0
- package/dist/v5/index.d.ts +18 -0
- package/dist/v5/index.js +3928 -0
- package/dist/v5/point-cloud-conversion.d.ts +31 -0
- package/dist/v5/point-cloud-source-encoder.d.ts +49 -0
- package/dist/v5/point-cloud-source.d.ts +25 -0
- package/dist/v5/point-cloud.d.ts +24 -0
- package/dist/v5/resource-manifest.d.ts +58 -0
- package/dist/v5/spatial-conversion.d.ts +59 -0
- package/dist/v5/tileset-source.d.ts +21 -0
- package/package.json +41 -26
- package/src/common/README.md +5 -0
- package/src/index.ts +1 -2
- package/src/{3d-tiles-converter → v4/3d-tiles-converter}/3d-tiles-converter.ts +13 -2
- package/src/v4/3d-tiles-converter/helpers/validate-i3s-spatial-reference.ts +124 -0
- package/src/{deps-installer → v4/deps-installer}/deps-installer.ts +10 -7
- package/src/v4/i3s-converter/helpers/encode-string-attribute.ts +23 -0
- package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-converter.ts +15 -42
- package/src/{i3s-converter → v4/i3s-converter}/helpers/gltf-attributes.ts +5 -4
- package/src/{i3s-converter → v4/i3s-converter}/helpers/load-3d-tiles.ts +5 -9
- package/src/{i3s-converter → v4/i3s-converter}/i3s-converter.ts +6 -7
- package/src/{i3s-server → v4/i3s-server}/README.md +2 -2
- package/src/{i3s-server → v4/i3s-server}/routes/slpk-router.ts +1 -0
- package/src/v4/index.ts +2 -0
- package/src/v5/browser-sink.ts +129 -0
- package/src/v5/browser-source.ts +155 -0
- package/src/v5/browser-tileset-source.ts +328 -0
- package/src/v5/browser.ts +54 -0
- package/src/v5/conversion-api.ts +287 -0
- package/src/v5/feature-arrow.ts +427 -0
- package/src/v5/index.ts +47 -0
- package/src/v5/point-cloud-conversion.ts +80 -0
- package/src/v5/point-cloud-source-encoder.ts +102 -0
- package/src/v5/point-cloud-source.ts +84 -0
- package/src/v5/point-cloud.ts +271 -0
- package/src/v5/resource-manifest.ts +213 -0
- package/src/v5/spatial-conversion.ts +305 -0
- package/src/v5/tileset-source.ts +54 -0
- /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/3d-tiles-content-converter.ts +0 -0
- /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/i3s-obb-to-3d-tiles-obb.ts +0 -0
- /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/load-i3s.ts +0 -0
- /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/texture-atlas.ts +0 -0
- /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/json-templates/tileset.ts +0 -0
- /package/src/{constants.ts → v4/constants.ts} +0 -0
- /package/src/{converter-cli.ts → v4/converter-cli.ts} +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/attribute-metadata-info.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/batch-ids-extensions.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/coordinate-converter.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/create-scene-server-path.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/feature-attributes.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-attributes.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-debug.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-index-document.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-pages.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/preprocess-3d-tiles.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/progress.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/helpers/tileset-traversal.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/json-templates/geometry-definitions.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/json-templates/layers.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/json-templates/metadata.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/json-templates/node.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/json-templates/scene-server.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/json-templates/shared-resources.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/json-templates/store.ts +0 -0
- /package/src/{i3s-converter → v4/i3s-converter}/types.ts +0 -0
- /package/src/{i3s-server → v4/i3s-server}/app.ts +0 -0
- /package/src/{i3s-server → v4/i3s-server}/bin/www.ts +0 -0
- /package/src/{i3s-server → v4/i3s-server}/certs/cert.pem +0 -0
- /package/src/{i3s-server → v4/i3s-server}/certs/key.pem +0 -0
- /package/src/{i3s-server → v4/i3s-server}/controllers/slpk-controller.ts +0 -0
- /package/src/{i3s-server → v4/i3s-server}/utils/create-scene-server.ts +0 -0
- /package/src/{i3s-server → v4/i3s-server}/utils/server-utils.ts +0 -0
- /package/src/{lib → v4/lib}/json-schemas/conversion-dump-json-schema.ts +0 -0
- /package/src/{lib → v4/lib}/utils/cli-utils.ts +0 -0
- /package/src/{lib → v4/lib}/utils/compress-util.ts +0 -0
- /package/src/{lib → v4/lib}/utils/conversion-dump.ts +0 -0
- /package/src/{lib → v4/lib}/utils/file-utils.ts +0 -0
- /package/src/{lib → v4/lib}/utils/geometry-utils.ts +0 -0
- /package/src/{lib → v4/lib}/utils/lod-conversion-utils.ts +0 -0
- /package/src/{lib → v4/lib}/utils/queue.ts +0 -0
- /package/src/{lib → v4/lib}/utils/statistic-utils.ts +0 -0
- /package/src/{lib → v4/lib}/utils/write-queue.ts +0 -0
- /package/src/{pgm-loader.ts → v4/pgm-loader.ts} +0 -0
|
@@ -0,0 +1,1927 @@
|
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __esm = (fn, res, err) => function __init() {
|
|
3
|
+
if (err) throw err[0];
|
|
4
|
+
try {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
} catch (e) {
|
|
7
|
+
throw err = [e], e;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// ../../modules/loader-utils/src/lib/env-utils/assert.ts
|
|
12
|
+
function assert(condition, message) {
|
|
13
|
+
if (!condition) {
|
|
14
|
+
throw new Error(message || "loader assertion failed.");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
var init_assert = __esm({
|
|
18
|
+
"../../modules/loader-utils/src/lib/env-utils/assert.ts"() {
|
|
19
|
+
"use strict";
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// ../../modules/loader-utils/src/lib/binary-utils/memory-copy-utils.ts
|
|
24
|
+
function padToNBytes(byteLength, padding) {
|
|
25
|
+
assert(byteLength >= 0);
|
|
26
|
+
assert(padding > 0);
|
|
27
|
+
return byteLength + (padding - 1) & ~(padding - 1);
|
|
28
|
+
}
|
|
29
|
+
var init_memory_copy_utils = __esm({
|
|
30
|
+
"../../modules/loader-utils/src/lib/binary-utils/memory-copy-utils.ts"() {
|
|
31
|
+
"use strict";
|
|
32
|
+
init_assert();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// ../../modules/loader-utils/src/lib/binary-utils/dataview-copy-utils.ts
|
|
37
|
+
function padStringToByteAlignment(string, byteAlignment) {
|
|
38
|
+
const length = string.length;
|
|
39
|
+
const paddedLength = Math.ceil(length / byteAlignment) * byteAlignment;
|
|
40
|
+
const padding = paddedLength - length;
|
|
41
|
+
let whitespace = "";
|
|
42
|
+
for (let i = 0; i < padding; ++i) {
|
|
43
|
+
whitespace += " ";
|
|
44
|
+
}
|
|
45
|
+
return string + whitespace;
|
|
46
|
+
}
|
|
47
|
+
function copyStringToDataView(dataView, byteOffset, string, byteLength) {
|
|
48
|
+
if (dataView) {
|
|
49
|
+
for (let i = 0; i < byteLength; i++) {
|
|
50
|
+
dataView.setUint8(byteOffset + i, string.charCodeAt(i));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return byteOffset + byteLength;
|
|
54
|
+
}
|
|
55
|
+
function copyBinaryToDataView(dataView, byteOffset, binary, byteLength) {
|
|
56
|
+
if (dataView) {
|
|
57
|
+
for (let i = 0; i < byteLength; i++) {
|
|
58
|
+
dataView.setUint8(byteOffset + i, binary[i]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return byteOffset + byteLength;
|
|
62
|
+
}
|
|
63
|
+
function copyPaddedArrayBufferToDataView(dataView, byteOffset, sourceBuffer, padding) {
|
|
64
|
+
const paddedLength = padToNBytes(sourceBuffer.byteLength, padding);
|
|
65
|
+
const padLength = paddedLength - sourceBuffer.byteLength;
|
|
66
|
+
if (dataView) {
|
|
67
|
+
const targetArray = new Uint8Array(
|
|
68
|
+
dataView.buffer,
|
|
69
|
+
dataView.byteOffset + byteOffset,
|
|
70
|
+
sourceBuffer.byteLength
|
|
71
|
+
);
|
|
72
|
+
const sourceArray = new Uint8Array(sourceBuffer);
|
|
73
|
+
targetArray.set(sourceArray);
|
|
74
|
+
for (let i = 0; i < padLength; ++i) {
|
|
75
|
+
dataView.setUint8(byteOffset + sourceBuffer.byteLength + i, 32);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
byteOffset += paddedLength;
|
|
79
|
+
return byteOffset;
|
|
80
|
+
}
|
|
81
|
+
function copyPaddedStringToDataView(dataView, byteOffset, string, padding) {
|
|
82
|
+
const textEncoder = new TextEncoder();
|
|
83
|
+
const stringBuffer = textEncoder.encode(string);
|
|
84
|
+
byteOffset = copyPaddedArrayBufferToDataView(dataView, byteOffset, stringBuffer, padding);
|
|
85
|
+
return byteOffset;
|
|
86
|
+
}
|
|
87
|
+
var init_dataview_copy_utils = __esm({
|
|
88
|
+
"../../modules/loader-utils/src/lib/binary-utils/dataview-copy-utils.ts"() {
|
|
89
|
+
"use strict";
|
|
90
|
+
init_memory_copy_utils();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// ../../modules/loader-utils/src/index.ts
|
|
95
|
+
var init_src = __esm({
|
|
96
|
+
"../../modules/loader-utils/src/index.ts"() {
|
|
97
|
+
"use strict";
|
|
98
|
+
init_assert();
|
|
99
|
+
init_memory_copy_utils();
|
|
100
|
+
init_dataview_copy_utils();
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// ../../modules/tiles/src/tileset-3d/common/tileset-content-traversal.ts
|
|
105
|
+
async function* traverseTilesetContents(tileset, options = {}) {
|
|
106
|
+
await tileset.tilesetInitializationPromise;
|
|
107
|
+
throwIfAborted2(options.signal);
|
|
108
|
+
if (!tileset.root) {
|
|
109
|
+
throw new Error("Tileset initialization completed without a root tile");
|
|
110
|
+
}
|
|
111
|
+
const stack = [tileset.root];
|
|
112
|
+
const visitedTiles = /* @__PURE__ */ new Set();
|
|
113
|
+
while (stack.length > 0) {
|
|
114
|
+
throwIfAborted2(options.signal);
|
|
115
|
+
const tile = stack.pop();
|
|
116
|
+
if (visitedTiles.has(tile)) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
visitedTiles.add(tile);
|
|
120
|
+
if (tile.header.implicitSubtree && tile.childrenState !== "ready") {
|
|
121
|
+
const loadChildren = tileset.source.loadTileChildrenForTraversal;
|
|
122
|
+
if (!loadChildren) {
|
|
123
|
+
throw new Error("Tileset source does not support camera-independent subtree loading");
|
|
124
|
+
}
|
|
125
|
+
const result = await loadChildren.call(tileset.source, tile, options.signal);
|
|
126
|
+
if (!result.loaded) {
|
|
127
|
+
throw new Error(`Unable to load implicit subtree for tile ${tile.id}`);
|
|
128
|
+
}
|
|
129
|
+
tile.childrenState = "ready";
|
|
130
|
+
}
|
|
131
|
+
if (tileset.type === "I3S" /* I3S */ && tileset.source.loadTileChildrenForTraversal) {
|
|
132
|
+
const result = await tileset.source.loadTileChildrenForTraversal(tile, options.signal);
|
|
133
|
+
if (!result.loaded) {
|
|
134
|
+
throw new Error(`Unable to load I3S child nodes for tile ${tile.id}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
throwIfAborted2(options.signal);
|
|
138
|
+
const loadsContent = tile.contentUrls.length > 0 && !tile.content;
|
|
139
|
+
try {
|
|
140
|
+
if (loadsContent) {
|
|
141
|
+
const loadResult = await tile.loadContentForTraversal();
|
|
142
|
+
throwIfAborted2(options.signal);
|
|
143
|
+
if (!loadResult.loaded) {
|
|
144
|
+
throw new Error(`Unable to load tile content for tile ${tile.id}`);
|
|
145
|
+
}
|
|
146
|
+
tileset.source.onTileLoaded?.(tileset, tile, loadResult);
|
|
147
|
+
}
|
|
148
|
+
yield { tile, contents: tile.contentEntries };
|
|
149
|
+
} finally {
|
|
150
|
+
if (options.unloadContent && loadsContent) {
|
|
151
|
+
tile.unloadContent();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
for (let childIndex = tile.children.length - 1; childIndex >= 0; childIndex--) {
|
|
155
|
+
stack.push(tile.children[childIndex]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function throwIfAborted2(signal) {
|
|
160
|
+
if (signal?.aborted) {
|
|
161
|
+
throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
var init_tileset_content_traversal = __esm({
|
|
165
|
+
"../../modules/tiles/src/tileset-3d/common/tileset-content-traversal.ts"() {
|
|
166
|
+
"use strict";
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// ../../modules/tiles/src/index.ts
|
|
171
|
+
var init_src2 = __esm({
|
|
172
|
+
"../../modules/tiles/src/index.ts"() {
|
|
173
|
+
"use strict";
|
|
174
|
+
init_tileset_content_traversal();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// ../../modules/3d-tiles/src/lib/utils/version.ts
|
|
179
|
+
var VERSION;
|
|
180
|
+
var init_version = __esm({
|
|
181
|
+
"../../modules/3d-tiles/src/lib/utils/version.ts"() {
|
|
182
|
+
"use strict";
|
|
183
|
+
VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// ../../modules/3d-tiles/src/lib/constants.ts
|
|
188
|
+
var TILE3D_TYPE, TILE3D_TYPES, MAGIC_ARRAY;
|
|
189
|
+
var init_constants = __esm({
|
|
190
|
+
"../../modules/3d-tiles/src/lib/constants.ts"() {
|
|
191
|
+
"use strict";
|
|
192
|
+
TILE3D_TYPE = {
|
|
193
|
+
COMPOSITE: "cmpt",
|
|
194
|
+
POINT_CLOUD: "pnts",
|
|
195
|
+
BATCHED_3D_MODEL: "b3dm",
|
|
196
|
+
INSTANCED_3D_MODEL: "i3dm",
|
|
197
|
+
GEOMETRY: "geom",
|
|
198
|
+
VECTOR: "vect",
|
|
199
|
+
GLTF: "glTF"
|
|
200
|
+
};
|
|
201
|
+
TILE3D_TYPES = Object.keys(TILE3D_TYPE);
|
|
202
|
+
MAGIC_ARRAY = {
|
|
203
|
+
BATCHED_MODEL: [98, 51, 100, 109],
|
|
204
|
+
INSTANCED_MODEL: [105, 51, 100, 109],
|
|
205
|
+
POINT_CLOUD: [112, 110, 116, 115],
|
|
206
|
+
COMPOSITE: [99, 109, 112, 116]
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// ../../modules/schema-utils/src/lib/schema/convert-arrow-schema.ts
|
|
212
|
+
import * as arrow from "apache-arrow";
|
|
213
|
+
function serializeArrowSchema(arrowSchema) {
|
|
214
|
+
return {
|
|
215
|
+
fields: arrowSchema.fields.map((arrowField) => serializeArrowField(arrowField)),
|
|
216
|
+
metadata: serializeArrowMetadata(arrowSchema.metadata)
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function serializeArrowMetadata(arrowMetadata) {
|
|
220
|
+
return Object.fromEntries(arrowMetadata);
|
|
221
|
+
}
|
|
222
|
+
function serializeArrowField(field) {
|
|
223
|
+
return {
|
|
224
|
+
name: field.name,
|
|
225
|
+
type: serializeArrowType(field.type),
|
|
226
|
+
nullable: field.nullable,
|
|
227
|
+
metadata: serializeArrowMetadata(field.metadata)
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function serializeArrowType(arrowType) {
|
|
231
|
+
if (isArrowViewType(arrowType, "BinaryView")) {
|
|
232
|
+
return "binary-view";
|
|
233
|
+
}
|
|
234
|
+
if (isArrowViewType(arrowType, "Utf8View")) {
|
|
235
|
+
return "utf8-view";
|
|
236
|
+
}
|
|
237
|
+
if (isOptionalArrowType(arrowType, "LargeList")) {
|
|
238
|
+
const largeListType = arrowType;
|
|
239
|
+
return {
|
|
240
|
+
type: "large-list",
|
|
241
|
+
children: [serializeArrowField(largeListType.valueField)]
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
switch (arrowType.constructor) {
|
|
245
|
+
case arrow.Null:
|
|
246
|
+
return "null";
|
|
247
|
+
case arrow.Binary:
|
|
248
|
+
return "binary";
|
|
249
|
+
case arrow.FixedSizeBinary:
|
|
250
|
+
return {
|
|
251
|
+
type: "fixed-size-binary",
|
|
252
|
+
byteWidth: arrowType.byteWidth
|
|
253
|
+
};
|
|
254
|
+
case arrow.Bool:
|
|
255
|
+
return "bool";
|
|
256
|
+
case arrow.Int:
|
|
257
|
+
const intType = arrowType;
|
|
258
|
+
return `${intType.isSigned ? "" : "u"}int${intType.bitWidth}`;
|
|
259
|
+
case arrow.Int8:
|
|
260
|
+
return "int8";
|
|
261
|
+
case arrow.Int16:
|
|
262
|
+
return "int16";
|
|
263
|
+
case arrow.Int32:
|
|
264
|
+
return "int32";
|
|
265
|
+
case arrow.Int64:
|
|
266
|
+
return "int64";
|
|
267
|
+
case arrow.Uint8:
|
|
268
|
+
return "uint8";
|
|
269
|
+
case arrow.Uint16:
|
|
270
|
+
return "uint16";
|
|
271
|
+
case arrow.Uint32:
|
|
272
|
+
return "uint32";
|
|
273
|
+
case arrow.Uint64:
|
|
274
|
+
return "uint64";
|
|
275
|
+
case arrow.Float:
|
|
276
|
+
const precision = arrowType.precision;
|
|
277
|
+
switch (precision) {
|
|
278
|
+
case arrow.Precision.HALF:
|
|
279
|
+
return "float16";
|
|
280
|
+
case arrow.Precision.SINGLE:
|
|
281
|
+
return "float32";
|
|
282
|
+
case arrow.Precision.DOUBLE:
|
|
283
|
+
return "float64";
|
|
284
|
+
default:
|
|
285
|
+
return "float16";
|
|
286
|
+
}
|
|
287
|
+
case arrow.Float16:
|
|
288
|
+
return "float16";
|
|
289
|
+
case arrow.Float32:
|
|
290
|
+
return "float32";
|
|
291
|
+
case arrow.Float64:
|
|
292
|
+
return "float64";
|
|
293
|
+
case arrow.Utf8:
|
|
294
|
+
return "utf8";
|
|
295
|
+
case arrow.Decimal:
|
|
296
|
+
const decimal = arrowType;
|
|
297
|
+
return {
|
|
298
|
+
type: "decimal",
|
|
299
|
+
bitWidth: decimal.bitWidth,
|
|
300
|
+
precision: decimal.precision,
|
|
301
|
+
scale: decimal.scale
|
|
302
|
+
};
|
|
303
|
+
case arrow.Date_:
|
|
304
|
+
const dateUnit = arrowType.unit;
|
|
305
|
+
return dateUnit === arrow.DateUnit.DAY ? "date-day" : "date-millisecond";
|
|
306
|
+
case arrow.DateDay:
|
|
307
|
+
return "date-day";
|
|
308
|
+
case arrow.DateMillisecond:
|
|
309
|
+
return "date-millisecond";
|
|
310
|
+
case arrow.Time:
|
|
311
|
+
const timeUnit = arrowType.unit;
|
|
312
|
+
switch (timeUnit) {
|
|
313
|
+
case arrow.TimeUnit.SECOND:
|
|
314
|
+
return "time-second";
|
|
315
|
+
case arrow.TimeUnit.MILLISECOND:
|
|
316
|
+
return "time-millisecond";
|
|
317
|
+
case arrow.TimeUnit.MICROSECOND:
|
|
318
|
+
return "time-microsecond";
|
|
319
|
+
case arrow.TimeUnit.NANOSECOND:
|
|
320
|
+
return "time-nanosecond";
|
|
321
|
+
default:
|
|
322
|
+
return "time-second";
|
|
323
|
+
}
|
|
324
|
+
case arrow.TimeMillisecond:
|
|
325
|
+
return "time-millisecond";
|
|
326
|
+
case arrow.TimeSecond:
|
|
327
|
+
return "time-second";
|
|
328
|
+
case arrow.TimeMicrosecond:
|
|
329
|
+
return "time-microsecond";
|
|
330
|
+
case arrow.TimeNanosecond:
|
|
331
|
+
return "time-nanosecond";
|
|
332
|
+
case arrow.Timestamp:
|
|
333
|
+
const timeStampUnit = arrowType.unit;
|
|
334
|
+
switch (timeStampUnit) {
|
|
335
|
+
case arrow.TimeUnit.SECOND:
|
|
336
|
+
return "timestamp-second";
|
|
337
|
+
case arrow.TimeUnit.MILLISECOND:
|
|
338
|
+
return "timestamp-millisecond";
|
|
339
|
+
case arrow.TimeUnit.MICROSECOND:
|
|
340
|
+
return "timestamp-microsecond";
|
|
341
|
+
case arrow.TimeUnit.NANOSECOND:
|
|
342
|
+
return "timestamp-nanosecond";
|
|
343
|
+
default:
|
|
344
|
+
return "timestamp-second";
|
|
345
|
+
}
|
|
346
|
+
case arrow.TimestampSecond:
|
|
347
|
+
return "timestamp-second";
|
|
348
|
+
case arrow.TimestampMillisecond:
|
|
349
|
+
return "timestamp-millisecond";
|
|
350
|
+
case arrow.TimestampMicrosecond:
|
|
351
|
+
return "timestamp-microsecond";
|
|
352
|
+
case arrow.TimestampNanosecond:
|
|
353
|
+
return "timestamp-nanosecond";
|
|
354
|
+
case arrow.Interval:
|
|
355
|
+
const intervalUnit = arrowType.unit;
|
|
356
|
+
switch (intervalUnit) {
|
|
357
|
+
case arrow.IntervalUnit.DAY_TIME:
|
|
358
|
+
return "interval-daytime";
|
|
359
|
+
case arrow.IntervalUnit.YEAR_MONTH:
|
|
360
|
+
return "interval-yearmonth";
|
|
361
|
+
default:
|
|
362
|
+
return "interval-daytime";
|
|
363
|
+
}
|
|
364
|
+
case arrow.IntervalDayTime:
|
|
365
|
+
return "interval-daytime";
|
|
366
|
+
case arrow.IntervalYearMonth:
|
|
367
|
+
return "interval-yearmonth";
|
|
368
|
+
case arrow.Map_:
|
|
369
|
+
const mapType = arrowType;
|
|
370
|
+
return {
|
|
371
|
+
type: "map",
|
|
372
|
+
keysSorted: mapType.keysSorted,
|
|
373
|
+
children: mapType.children.map((arrowField) => serializeArrowField(arrowField))
|
|
374
|
+
};
|
|
375
|
+
case arrow.List:
|
|
376
|
+
const listType = arrowType;
|
|
377
|
+
const listField = listType.valueField;
|
|
378
|
+
return {
|
|
379
|
+
type: "list",
|
|
380
|
+
children: [serializeArrowField(listField)]
|
|
381
|
+
};
|
|
382
|
+
case arrow.FixedSizeList:
|
|
383
|
+
const fixedSizeList = arrowType;
|
|
384
|
+
return {
|
|
385
|
+
type: "fixed-size-list",
|
|
386
|
+
listSize: fixedSizeList.listSize,
|
|
387
|
+
children: [serializeArrowField(fixedSizeList.children[0])]
|
|
388
|
+
};
|
|
389
|
+
case arrow.Struct:
|
|
390
|
+
const structType = arrowType;
|
|
391
|
+
return {
|
|
392
|
+
type: "struct",
|
|
393
|
+
children: structType.children.map((arrowField) => serializeArrowField(arrowField))
|
|
394
|
+
};
|
|
395
|
+
case arrow.SparseUnion:
|
|
396
|
+
case arrow.DenseUnion:
|
|
397
|
+
const unionType = arrowType;
|
|
398
|
+
return {
|
|
399
|
+
type: unionType instanceof arrow.DenseUnion ? "dense-union" : "sparse-union",
|
|
400
|
+
typeIds: unionType.typeIds,
|
|
401
|
+
children: unionType.children.map((arrowField) => serializeArrowField(arrowField)),
|
|
402
|
+
typeIdToChildIndex: { ...unionType.typeIdToChildIndex }
|
|
403
|
+
};
|
|
404
|
+
case arrow.Dictionary:
|
|
405
|
+
const dictionaryType = arrowType;
|
|
406
|
+
return {
|
|
407
|
+
type: "dictionary",
|
|
408
|
+
id: dictionaryType.id,
|
|
409
|
+
indices: serializeArrowDictionaryKeyType(dictionaryType.indices),
|
|
410
|
+
dictionary: serializeArrowType(dictionaryType.dictionary),
|
|
411
|
+
isOrdered: dictionaryType.isOrdered
|
|
412
|
+
};
|
|
413
|
+
default:
|
|
414
|
+
throw new Error(`arrow type not supported: ${arrowType.constructor.name}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
function getOptionalArrowConstructor(typeName) {
|
|
418
|
+
return arrow[typeName];
|
|
419
|
+
}
|
|
420
|
+
function isArrowViewType(arrowType, viewTypeName) {
|
|
421
|
+
const constructor = getOptionalArrowConstructor(viewTypeName);
|
|
422
|
+
if (constructor && arrowType instanceof constructor) {
|
|
423
|
+
return true;
|
|
424
|
+
}
|
|
425
|
+
const guards = arrow.DataType;
|
|
426
|
+
const guard = viewTypeName === "BinaryView" ? guards.isBinaryView : guards.isUtf8View;
|
|
427
|
+
return Boolean(guard?.(arrowType));
|
|
428
|
+
}
|
|
429
|
+
function isOptionalArrowType(arrowType, typeName) {
|
|
430
|
+
const constructor = getOptionalArrowConstructor(typeName);
|
|
431
|
+
return Boolean(constructor && arrowType instanceof constructor);
|
|
432
|
+
}
|
|
433
|
+
function serializeArrowDictionaryKeyType(arrowType) {
|
|
434
|
+
if (arrowType instanceof arrow.Int) {
|
|
435
|
+
const prefix = arrowType.isSigned ? "int" : "uint";
|
|
436
|
+
const keyType = `${prefix}${arrowType.bitWidth}`;
|
|
437
|
+
if (isSchemaDictionaryKeyType(keyType)) {
|
|
438
|
+
return keyType;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
switch (arrowType.constructor) {
|
|
442
|
+
case arrow.Int8:
|
|
443
|
+
return "int8";
|
|
444
|
+
case arrow.Int16:
|
|
445
|
+
return "int16";
|
|
446
|
+
case arrow.Int32:
|
|
447
|
+
return "int32";
|
|
448
|
+
case arrow.Uint8:
|
|
449
|
+
return "uint8";
|
|
450
|
+
case arrow.Uint16:
|
|
451
|
+
return "uint16";
|
|
452
|
+
case arrow.Uint32:
|
|
453
|
+
return "uint32";
|
|
454
|
+
default:
|
|
455
|
+
throw new Error(`arrow dictionary index type not supported: ${arrowType.constructor.name}`);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
function isSchemaDictionaryKeyType(keyType) {
|
|
459
|
+
return ["int8", "int16", "int32", "uint8", "uint16", "uint32"].includes(keyType);
|
|
460
|
+
}
|
|
461
|
+
var init_convert_arrow_schema = __esm({
|
|
462
|
+
"../../modules/schema-utils/src/lib/schema/convert-arrow-schema.ts"() {
|
|
463
|
+
"use strict";
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// ../../modules/schema-utils/src/lib/mesh/mesh-utils.ts
|
|
468
|
+
function getMeshBoundingBox(attributes) {
|
|
469
|
+
let minX = Infinity;
|
|
470
|
+
let minY = Infinity;
|
|
471
|
+
let minZ = Infinity;
|
|
472
|
+
let maxX = -Infinity;
|
|
473
|
+
let maxY = -Infinity;
|
|
474
|
+
let maxZ = -Infinity;
|
|
475
|
+
const positions = attributes.POSITION ? attributes.POSITION.value : [];
|
|
476
|
+
const len = positions && positions.length;
|
|
477
|
+
for (let i = 0; i < len; i += 3) {
|
|
478
|
+
const x = positions[i];
|
|
479
|
+
const y = positions[i + 1];
|
|
480
|
+
const z = positions[i + 2];
|
|
481
|
+
minX = x < minX ? x : minX;
|
|
482
|
+
minY = y < minY ? y : minY;
|
|
483
|
+
minZ = z < minZ ? z : minZ;
|
|
484
|
+
maxX = x > maxX ? x : maxX;
|
|
485
|
+
maxY = y > maxY ? y : maxY;
|
|
486
|
+
maxZ = z > maxZ ? z : maxZ;
|
|
487
|
+
}
|
|
488
|
+
return [
|
|
489
|
+
[minX, minY, minZ],
|
|
490
|
+
[maxX, maxY, maxZ]
|
|
491
|
+
];
|
|
492
|
+
}
|
|
493
|
+
var init_mesh_utils = __esm({
|
|
494
|
+
"../../modules/schema-utils/src/lib/mesh/mesh-utils.ts"() {
|
|
495
|
+
"use strict";
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
// ../../modules/schema/src/float16.ts
|
|
500
|
+
import { getFloat16ArrayConstructor, NativeFloat16ArrayConstructor } from "@math.gl/types";
|
|
501
|
+
function createFloat16Array(length) {
|
|
502
|
+
const ArrayConstructor = getFloat16ArrayConstructor();
|
|
503
|
+
return new ArrayConstructor(length);
|
|
504
|
+
}
|
|
505
|
+
function isNativeFloat16Array(value) {
|
|
506
|
+
return Boolean(NativeFloat16ArrayConstructor && value instanceof NativeFloat16ArrayConstructor);
|
|
507
|
+
}
|
|
508
|
+
function setFloat16Value(array, index, value) {
|
|
509
|
+
if (isNativeFloat16Array(array)) {
|
|
510
|
+
array[index] = value;
|
|
511
|
+
} else {
|
|
512
|
+
array[index] = encodeFloat16(value);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
function getFloat16Value(array, index) {
|
|
516
|
+
if (isNativeFloat16Array(array)) {
|
|
517
|
+
return array[index];
|
|
518
|
+
}
|
|
519
|
+
return decodeFloat16(array[index]);
|
|
520
|
+
}
|
|
521
|
+
function encodeFloat16(value) {
|
|
522
|
+
if (!Number.isFinite(value)) {
|
|
523
|
+
return value === Infinity ? 31744 : value === -Infinity ? 64512 : 32256;
|
|
524
|
+
}
|
|
525
|
+
const sign = value < 0 || Object.is(value, -0) ? 32768 : 0;
|
|
526
|
+
const absoluteValue = Math.abs(value);
|
|
527
|
+
if (absoluteValue === 0) {
|
|
528
|
+
return sign;
|
|
529
|
+
}
|
|
530
|
+
if (absoluteValue >= 65520) {
|
|
531
|
+
return sign | 31744;
|
|
532
|
+
}
|
|
533
|
+
if (absoluteValue >= 65504) {
|
|
534
|
+
return sign | 31743;
|
|
535
|
+
}
|
|
536
|
+
const exponent = Math.floor(Math.log2(absoluteValue));
|
|
537
|
+
if (exponent < -14) {
|
|
538
|
+
return sign | Math.round(absoluteValue / 2 ** -24);
|
|
539
|
+
}
|
|
540
|
+
const normalizedExponent = exponent + 15;
|
|
541
|
+
const mantissa = Math.round((absoluteValue / 2 ** exponent - 1) * 1024);
|
|
542
|
+
if (mantissa === 1024) {
|
|
543
|
+
return sign | normalizedExponent + 1 << 10;
|
|
544
|
+
}
|
|
545
|
+
return sign | normalizedExponent << 10 | mantissa;
|
|
546
|
+
}
|
|
547
|
+
function decodeFloat16(value) {
|
|
548
|
+
const sign = value & 32768 ? -1 : 1;
|
|
549
|
+
const exponent = value >> 10 & 31;
|
|
550
|
+
const mantissa = value & 1023;
|
|
551
|
+
if (exponent === 0) {
|
|
552
|
+
return sign * mantissa * 2 ** -24;
|
|
553
|
+
}
|
|
554
|
+
if (exponent === 31) {
|
|
555
|
+
return mantissa ? NaN : sign * Infinity;
|
|
556
|
+
}
|
|
557
|
+
return sign * (1 + mantissa / 1024) * 2 ** (exponent - 15);
|
|
558
|
+
}
|
|
559
|
+
var init_float16 = __esm({
|
|
560
|
+
"../../modules/schema/src/float16.ts"() {
|
|
561
|
+
"use strict";
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// ../../modules/schema/src/index.ts
|
|
566
|
+
var init_src3 = __esm({
|
|
567
|
+
"../../modules/schema/src/index.ts"() {
|
|
568
|
+
"use strict";
|
|
569
|
+
init_float16();
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// ../../modules/schema-utils/src/lib/arrow-utils/arrow-fixed-size-list-utils.ts
|
|
574
|
+
import * as arrow2 from "apache-arrow";
|
|
575
|
+
function getFixedSizeListSize(vector) {
|
|
576
|
+
return vector.type instanceof arrow2.FixedSizeList ? vector.type.listSize : 1;
|
|
577
|
+
}
|
|
578
|
+
var init_arrow_fixed_size_list_utils = __esm({
|
|
579
|
+
"../../modules/schema-utils/src/lib/arrow-utils/arrow-fixed-size-list-utils.ts"() {
|
|
580
|
+
"use strict";
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
// ../../modules/schema-utils/src/lib/mesh/convert-table-to-mesh.ts
|
|
585
|
+
import * as arrow3 from "apache-arrow";
|
|
586
|
+
function convertTableToMesh(table) {
|
|
587
|
+
switch (table.shape) {
|
|
588
|
+
// case 'columnar-table':
|
|
589
|
+
// return convertColumnarTableToMesh(table);
|
|
590
|
+
case "arrow-table":
|
|
591
|
+
return convertArrowTableToMesh(table);
|
|
592
|
+
default:
|
|
593
|
+
throw new Error(table.shape);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
function convertArrowTableToMesh(table) {
|
|
597
|
+
const arrowTable = table.data;
|
|
598
|
+
const schema = serializeArrowSchema(arrowTable.schema);
|
|
599
|
+
const fields = schema.fields;
|
|
600
|
+
const attributes = {};
|
|
601
|
+
for (const field of fields) {
|
|
602
|
+
const { name } = field;
|
|
603
|
+
if (name === "indices") {
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
const attributeData = arrowTable.getChild(name);
|
|
607
|
+
const size = getFixedSizeListSize(attributeData);
|
|
608
|
+
const typedArray = getAttributeTypedArray(attributeData, size);
|
|
609
|
+
const metadata = getMeshAttributeMetadata(field.metadata);
|
|
610
|
+
attributes[name] = {
|
|
611
|
+
value: metadata.componentType === "float16" ? restoreFloat16Array(typedArray) : typedArray,
|
|
612
|
+
size,
|
|
613
|
+
...metadata
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
fixMetadata(schema);
|
|
617
|
+
const topology = schema.metadata.topology;
|
|
618
|
+
const mode = getMeshMode(schema);
|
|
619
|
+
const indices = getIndices(arrowTable);
|
|
620
|
+
const boundingBox = attributes.POSITION?.transform?.type === "quantization" ? getMeshBoundingBoxFromSchema(schema) || getMeshBoundingBox(attributes) : getMeshBoundingBox(attributes);
|
|
621
|
+
return {
|
|
622
|
+
schema,
|
|
623
|
+
attributes,
|
|
624
|
+
topology,
|
|
625
|
+
mode,
|
|
626
|
+
indices,
|
|
627
|
+
header: {
|
|
628
|
+
vertexCount: arrowTable.numRows,
|
|
629
|
+
boundingBox
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
function getMeshBoundingBoxFromSchema(schema) {
|
|
634
|
+
const serializedBoundingBox = schema.metadata?.boundingBox;
|
|
635
|
+
if (!serializedBoundingBox) {
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
try {
|
|
639
|
+
const boundingBox = JSON.parse(serializedBoundingBox);
|
|
640
|
+
if (Array.isArray(boundingBox) && boundingBox.length === 2 && boundingBox.every(
|
|
641
|
+
(corner) => Array.isArray(corner) && corner.length === 3 && corner.every((value) => typeof value === "number")
|
|
642
|
+
)) {
|
|
643
|
+
return boundingBox;
|
|
644
|
+
}
|
|
645
|
+
} catch {
|
|
646
|
+
}
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
function getMeshAttributeMetadata(metadata = {}) {
|
|
650
|
+
const result = {};
|
|
651
|
+
if (metadata.byteOffset !== void 0) {
|
|
652
|
+
result.byteOffset = Number(metadata.byteOffset);
|
|
653
|
+
}
|
|
654
|
+
if (metadata.byteStride !== void 0) {
|
|
655
|
+
result.byteStride = Number(metadata.byteStride);
|
|
656
|
+
}
|
|
657
|
+
if (metadata.normalized !== void 0) {
|
|
658
|
+
result.normalized = metadata.normalized === "true";
|
|
659
|
+
}
|
|
660
|
+
if (metadata.componentType === "float16") {
|
|
661
|
+
result.componentType = "float16";
|
|
662
|
+
}
|
|
663
|
+
if (metadata["loaders.gl.transform"]) {
|
|
664
|
+
try {
|
|
665
|
+
const transform = JSON.parse(metadata["loaders.gl.transform"]);
|
|
666
|
+
if (isMeshAttributeTransform(transform)) {
|
|
667
|
+
result.transform = transform;
|
|
668
|
+
}
|
|
669
|
+
} catch {
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return result;
|
|
673
|
+
}
|
|
674
|
+
function isMeshAttributeTransform(value) {
|
|
675
|
+
if (!value || typeof value !== "object" || !("type" in value)) {
|
|
676
|
+
return false;
|
|
677
|
+
}
|
|
678
|
+
const transform = value;
|
|
679
|
+
if (transform.type === "octahedron") {
|
|
680
|
+
return Number.isInteger(transform.bits) && transform.bits >= 1 && transform.bits <= 30;
|
|
681
|
+
}
|
|
682
|
+
return transform.type === "quantization" && Number.isInteger(transform.bits) && transform.bits >= 1 && transform.bits <= 30 && Array.isArray(transform.origin) && transform.origin.every((component) => typeof component === "number") && typeof transform.range === "number";
|
|
683
|
+
}
|
|
684
|
+
function fixMetadata(schema) {
|
|
685
|
+
schema.metadata ||= {};
|
|
686
|
+
schema.metadata.topology ||= "point-list";
|
|
687
|
+
schema.metadata.mode ||= "0";
|
|
688
|
+
}
|
|
689
|
+
function getAttributeTypedArray(attributeData, size) {
|
|
690
|
+
if (!(attributeData.type instanceof arrow3.FixedSizeList)) {
|
|
691
|
+
return attributeData.toArray();
|
|
692
|
+
}
|
|
693
|
+
const values = attributeData.data[0].children[0].values;
|
|
694
|
+
const TypedArrayConstructor = values.constructor;
|
|
695
|
+
const typedArray = new TypedArrayConstructor(attributeData.length * size);
|
|
696
|
+
let targetOffset = 0;
|
|
697
|
+
for (const data of attributeData.data) {
|
|
698
|
+
const child = data.children[0];
|
|
699
|
+
const sourceLength = data.length * size;
|
|
700
|
+
const sourceOffset = child.offset || data.offset * size;
|
|
701
|
+
const sourceStart = sourceOffset + sourceLength <= child.values.length ? sourceOffset : 0;
|
|
702
|
+
const source = child.values.subarray(sourceStart, sourceStart + sourceLength);
|
|
703
|
+
typedArray.set(source, targetOffset);
|
|
704
|
+
targetOffset += sourceLength;
|
|
705
|
+
}
|
|
706
|
+
return typedArray;
|
|
707
|
+
}
|
|
708
|
+
function restoreFloat16Array(typedArray) {
|
|
709
|
+
const result = createFloat16Array(typedArray.length);
|
|
710
|
+
for (let index = 0; index < typedArray.length; index++) {
|
|
711
|
+
setFloat16Value(result, index, getFloat16Value(typedArray, index));
|
|
712
|
+
}
|
|
713
|
+
return result;
|
|
714
|
+
}
|
|
715
|
+
function getMeshMode(schema) {
|
|
716
|
+
const mode = Number(schema.metadata?.mode);
|
|
717
|
+
return Number.isFinite(mode) ? mode : 0;
|
|
718
|
+
}
|
|
719
|
+
function getIndices(arrowTable) {
|
|
720
|
+
const indicesColumn = arrowTable.getChild("indices");
|
|
721
|
+
if (!indicesColumn?.isValid(0)) {
|
|
722
|
+
return void 0;
|
|
723
|
+
}
|
|
724
|
+
const indicesData = indicesColumn.data[0];
|
|
725
|
+
const valueOffsets = indicesData.valueOffsets;
|
|
726
|
+
const start = valueOffsets[indicesData.offset];
|
|
727
|
+
const end = valueOffsets[indicesData.offset + 1];
|
|
728
|
+
const values = indicesData.children[0].values.subarray(start, end);
|
|
729
|
+
return { value: values, size: 1 };
|
|
730
|
+
}
|
|
731
|
+
var init_convert_table_to_mesh = __esm({
|
|
732
|
+
"../../modules/schema-utils/src/lib/mesh/convert-table-to-mesh.ts"() {
|
|
733
|
+
"use strict";
|
|
734
|
+
init_src3();
|
|
735
|
+
init_arrow_fixed_size_list_utils();
|
|
736
|
+
init_convert_arrow_schema();
|
|
737
|
+
init_mesh_utils();
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
// ../../modules/schema-utils/src/index.ts
|
|
742
|
+
var init_src4 = __esm({
|
|
743
|
+
"../../modules/schema-utils/src/index.ts"() {
|
|
744
|
+
"use strict";
|
|
745
|
+
init_convert_table_to_mesh();
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
// src/v5/conversion-api.ts
|
|
750
|
+
var TileConversionError = class extends Error {
|
|
751
|
+
/** Stable machine-readable failure code. */
|
|
752
|
+
code;
|
|
753
|
+
/** Diagnostics associated with this failure. */
|
|
754
|
+
diagnostics;
|
|
755
|
+
/** Creates a typed conversion failure. */
|
|
756
|
+
constructor(code, message, diagnostics = []) {
|
|
757
|
+
super(message);
|
|
758
|
+
this.name = "TileConversionError";
|
|
759
|
+
this.code = code;
|
|
760
|
+
this.diagnostics = diagnostics;
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
async function inspectTileset(source, signal) {
|
|
764
|
+
throwIfAborted(signal);
|
|
765
|
+
const inspection = await source.inspect(signal);
|
|
766
|
+
throwIfAborted(signal);
|
|
767
|
+
return inspection;
|
|
768
|
+
}
|
|
769
|
+
async function convertTileset(options) {
|
|
770
|
+
const {
|
|
771
|
+
source,
|
|
772
|
+
codec,
|
|
773
|
+
sink,
|
|
774
|
+
measureInputBytes,
|
|
775
|
+
measureOutputBytes,
|
|
776
|
+
maxInputResourceBytes = Number.POSITIVE_INFINITY,
|
|
777
|
+
maxOutputResourceBytes = Number.POSITIVE_INFINITY,
|
|
778
|
+
signal,
|
|
779
|
+
onProgress
|
|
780
|
+
} = options;
|
|
781
|
+
let inputResources = 0;
|
|
782
|
+
let outputResources = 0;
|
|
783
|
+
let inputBytes = 0;
|
|
784
|
+
let outputBytes = 0;
|
|
785
|
+
let largestOutputResourceBytes = 0;
|
|
786
|
+
const diagnostics = [];
|
|
787
|
+
const reportProgress = (phase) => {
|
|
788
|
+
onProgress?.({ phase, inputResources, outputResources, inputBytes, outputBytes });
|
|
789
|
+
};
|
|
790
|
+
try {
|
|
791
|
+
if (maxInputResourceBytes !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(maxInputResourceBytes) || maxInputResourceBytes < 0)) {
|
|
792
|
+
throw new TileConversionError(
|
|
793
|
+
"INVALID_INPUT_RESOURCE_LIMIT",
|
|
794
|
+
"maxInputResourceBytes must be a nonnegative safe integer or Infinity"
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
reportProgress("inspect");
|
|
798
|
+
const inspection = await inspectTileset(source, signal);
|
|
799
|
+
for await (const inputResource of source.read(inspection, signal)) {
|
|
800
|
+
throwIfAborted(signal);
|
|
801
|
+
const inputResourceBytes = measureInputBytes(inputResource);
|
|
802
|
+
if (!Number.isSafeInteger(inputResourceBytes) || inputResourceBytes < 0) {
|
|
803
|
+
throw new TileConversionError(
|
|
804
|
+
"INVALID_INPUT_RESOURCE_SIZE",
|
|
805
|
+
"measureInputBytes must return a nonnegative safe integer"
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
if (inputResourceBytes > maxInputResourceBytes) {
|
|
809
|
+
throw new TileConversionError(
|
|
810
|
+
"INPUT_RESOURCE_TOO_LARGE",
|
|
811
|
+
`Input resource is ${inputResourceBytes} bytes, exceeding the configured limit of ${maxInputResourceBytes} bytes`
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
inputResources++;
|
|
815
|
+
inputBytes += inputResourceBytes;
|
|
816
|
+
reportProgress("convert");
|
|
817
|
+
const convertedResources = await codec.convert(inputResource, inspection, signal);
|
|
818
|
+
for await (const outputResource of convertedResources) {
|
|
819
|
+
throwIfAborted(signal);
|
|
820
|
+
reportProgress("validate");
|
|
821
|
+
const resourceDiagnostics = await codec.validateOutput?.(outputResource, signal) || [];
|
|
822
|
+
diagnostics.push(...resourceDiagnostics);
|
|
823
|
+
const outputResourceBytes = measureOutputBytes(outputResource);
|
|
824
|
+
largestOutputResourceBytes = Math.max(largestOutputResourceBytes, outputResourceBytes);
|
|
825
|
+
if (outputResourceBytes > maxOutputResourceBytes) {
|
|
826
|
+
throw new TileConversionError(
|
|
827
|
+
"OUTPUT_RESOURCE_TOO_LARGE",
|
|
828
|
+
`Output resource is ${outputResourceBytes} bytes, exceeding the configured limit of ${maxOutputResourceBytes} bytes`
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
if (resourceDiagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
832
|
+
throw new TileConversionError(
|
|
833
|
+
"OUTPUT_VALIDATION_FAILED",
|
|
834
|
+
"Output resource validation failed",
|
|
835
|
+
resourceDiagnostics
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
throwIfAborted(signal);
|
|
839
|
+
await sink.write(outputResource, signal);
|
|
840
|
+
throwIfAborted(signal);
|
|
841
|
+
outputResources++;
|
|
842
|
+
outputBytes += outputResourceBytes;
|
|
843
|
+
reportProgress("convert");
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
const report = {
|
|
847
|
+
state: "completed",
|
|
848
|
+
inputResources,
|
|
849
|
+
outputResources,
|
|
850
|
+
inputBytes,
|
|
851
|
+
outputBytes,
|
|
852
|
+
largestOutputResourceBytes,
|
|
853
|
+
diagnostics
|
|
854
|
+
};
|
|
855
|
+
throwIfAborted(signal);
|
|
856
|
+
reportProgress("finalize");
|
|
857
|
+
await sink.finalize(report);
|
|
858
|
+
return report;
|
|
859
|
+
} catch (error) {
|
|
860
|
+
try {
|
|
861
|
+
await sink.abort(error);
|
|
862
|
+
} catch (abortError) {
|
|
863
|
+
throw new AggregateError(
|
|
864
|
+
[error, abortError],
|
|
865
|
+
"Conversion failed and the destination could not abort"
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
throw error;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
async function validateTileset(options) {
|
|
872
|
+
throwIfAborted(options.signal);
|
|
873
|
+
const diagnostics = await options.validate(options.tileset, options.signal);
|
|
874
|
+
throwIfAborted(options.signal);
|
|
875
|
+
return {
|
|
876
|
+
valid: !diagnostics.some((diagnostic) => diagnostic.severity === "error"),
|
|
877
|
+
diagnostics
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
function throwIfAborted(signal) {
|
|
881
|
+
if (signal?.aborted) {
|
|
882
|
+
throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// src/v5/tileset-source.ts
|
|
887
|
+
init_src2();
|
|
888
|
+
function createTilesetConversionSource(tileset, options = {}) {
|
|
889
|
+
return {
|
|
890
|
+
async inspect(signal) {
|
|
891
|
+
signal?.throwIfAborted();
|
|
892
|
+
await tileset.tilesetInitializationPromise;
|
|
893
|
+
signal?.throwIfAborted();
|
|
894
|
+
if (!tileset.root) {
|
|
895
|
+
throw new TileConversionError(
|
|
896
|
+
"TILESET_ROOT_REQUIRED",
|
|
897
|
+
"Tileset initialization completed without a root tile"
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
return tileset.source.getMetadata();
|
|
901
|
+
},
|
|
902
|
+
read: (_inspection, signal) => traverseTilesetContents(tileset, { unloadContent: options.unloadContent, signal })
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// src/v5/browser-sink.ts
|
|
907
|
+
var BLOB_SIZE_GETTER = Object.getOwnPropertyDescriptor(Blob.prototype, "size")?.get;
|
|
908
|
+
function createBoundedMemoryTileConversionSink(options) {
|
|
909
|
+
if (!Number.isSafeInteger(options.maxTotalBytes) || options.maxTotalBytes < 0) {
|
|
910
|
+
throw new TileConversionError(
|
|
911
|
+
"INVALID_OUTPUT_MEMORY_LIMIT",
|
|
912
|
+
"The browser output memory limit must be a non-negative safe integer"
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
const files = /* @__PURE__ */ new Map();
|
|
916
|
+
let totalBytes = 0;
|
|
917
|
+
let closed = false;
|
|
918
|
+
return {
|
|
919
|
+
getFiles() {
|
|
920
|
+
return [...files.values()].sort(
|
|
921
|
+
(left, right) => left.resourceId < right.resourceId ? -1 : left.resourceId > right.resourceId ? 1 : 0
|
|
922
|
+
);
|
|
923
|
+
},
|
|
924
|
+
async write(resource, signal) {
|
|
925
|
+
if (signal?.aborted) {
|
|
926
|
+
throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
927
|
+
}
|
|
928
|
+
if (closed) {
|
|
929
|
+
throw new TileConversionError(
|
|
930
|
+
"RESOURCE_SINK_CLOSED",
|
|
931
|
+
"Cannot write after sink finalization"
|
|
932
|
+
);
|
|
933
|
+
}
|
|
934
|
+
if (!resource.resourceId || files.has(resource.resourceId)) {
|
|
935
|
+
throw new TileConversionError(
|
|
936
|
+
"INVALID_BROWSER_RESOURCE_ID",
|
|
937
|
+
"Browser output resource IDs must be non-empty and unique"
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
const byteLength = resource.parts.reduce((total, part) => total + measureBlobPart(part), 0);
|
|
941
|
+
if (!Number.isSafeInteger(byteLength) || totalBytes + byteLength > options.maxTotalBytes) {
|
|
942
|
+
throw new TileConversionError(
|
|
943
|
+
"OUTPUT_MEMORY_LIMIT_EXCEEDED",
|
|
944
|
+
`Browser output exceeds the configured ${options.maxTotalBytes} byte memory limit`
|
|
945
|
+
);
|
|
946
|
+
}
|
|
947
|
+
const blob = new Blob([...resource.parts], { type: resource.contentType });
|
|
948
|
+
files.set(resource.resourceId, { resourceId: resource.resourceId, blob });
|
|
949
|
+
totalBytes += blob.size;
|
|
950
|
+
},
|
|
951
|
+
async finalize(_report) {
|
|
952
|
+
if (closed) {
|
|
953
|
+
throw new TileConversionError("RESOURCE_SINK_CLOSED", "Sink has already been finalized");
|
|
954
|
+
}
|
|
955
|
+
closed = true;
|
|
956
|
+
},
|
|
957
|
+
async abort() {
|
|
958
|
+
files.clear();
|
|
959
|
+
totalBytes = 0;
|
|
960
|
+
closed = true;
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
function measureBlobPart(part) {
|
|
965
|
+
if (typeof part === "string") {
|
|
966
|
+
return new TextEncoder().encode(part).byteLength;
|
|
967
|
+
}
|
|
968
|
+
if (BLOB_SIZE_GETTER) {
|
|
969
|
+
try {
|
|
970
|
+
return BLOB_SIZE_GETTER.call(part);
|
|
971
|
+
} catch {
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
if (part instanceof ArrayBuffer || ArrayBuffer.isView(part)) {
|
|
975
|
+
return part.byteLength;
|
|
976
|
+
}
|
|
977
|
+
throw new TileConversionError("UNSUPPORTED_BROWSER_RESOURCE", "Unsupported browser Blob part");
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// src/v5/browser-source.ts
|
|
981
|
+
function createBrowserTileConversionSource(options) {
|
|
982
|
+
if (!options.resourceId || !Number.isSafeInteger(options.maxInputBytes) || options.maxInputBytes < 0) {
|
|
983
|
+
throw new TileConversionError(
|
|
984
|
+
"INVALID_BROWSER_SOURCE_OPTIONS",
|
|
985
|
+
"Browser sources require a resource ID and a non-negative safe input byte limit"
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
return {
|
|
989
|
+
async inspect(signal) {
|
|
990
|
+
throwIfAborted3(signal);
|
|
991
|
+
const contentType = options.contentType ?? getBlobContentType(options.input);
|
|
992
|
+
return {
|
|
993
|
+
resourceId: options.resourceId,
|
|
994
|
+
...contentType ? { contentType } : {}
|
|
995
|
+
};
|
|
996
|
+
},
|
|
997
|
+
async *read(inspection, signal) {
|
|
998
|
+
throwIfAborted3(signal);
|
|
999
|
+
const input = options.input;
|
|
1000
|
+
let data;
|
|
1001
|
+
let contentType = inspection.contentType;
|
|
1002
|
+
if (typeof input === "string") {
|
|
1003
|
+
const response = await fetch(input, { signal });
|
|
1004
|
+
if (!response.ok) {
|
|
1005
|
+
throw new TileConversionError(
|
|
1006
|
+
"BROWSER_SOURCE_FETCH_FAILED",
|
|
1007
|
+
`Could not fetch browser input (${response.status} ${response.statusText})`
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
contentType = contentType ?? response.headers.get("content-type") ?? void 0;
|
|
1011
|
+
data = await readResponseBytes(response, options.maxInputBytes, signal);
|
|
1012
|
+
} else {
|
|
1013
|
+
if (input.size > options.maxInputBytes) {
|
|
1014
|
+
throw createInputLimitError(options.maxInputBytes);
|
|
1015
|
+
}
|
|
1016
|
+
data = new Uint8Array(await input.arrayBuffer());
|
|
1017
|
+
}
|
|
1018
|
+
throwIfAborted3(signal);
|
|
1019
|
+
yield {
|
|
1020
|
+
resourceId: inspection.resourceId,
|
|
1021
|
+
data,
|
|
1022
|
+
...contentType ? { contentType } : {}
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
async function readResponseBytes(response, maxInputBytes, signal) {
|
|
1028
|
+
const reader = response.body?.getReader();
|
|
1029
|
+
if (!reader) {
|
|
1030
|
+
throw new TileConversionError(
|
|
1031
|
+
"BROWSER_SOURCE_STREAM_UNAVAILABLE",
|
|
1032
|
+
"Browser URL inputs must provide a readable response stream"
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
const data = new Uint8Array(maxInputBytes);
|
|
1036
|
+
let totalBytes = 0;
|
|
1037
|
+
try {
|
|
1038
|
+
while (true) {
|
|
1039
|
+
throwIfAborted3(signal);
|
|
1040
|
+
const { done, value } = await reader.read();
|
|
1041
|
+
if (done) break;
|
|
1042
|
+
if (value.byteLength > maxInputBytes - totalBytes) {
|
|
1043
|
+
await reader.cancel();
|
|
1044
|
+
throw createInputLimitError(maxInputBytes);
|
|
1045
|
+
}
|
|
1046
|
+
data.set(value, totalBytes);
|
|
1047
|
+
totalBytes += value.byteLength;
|
|
1048
|
+
}
|
|
1049
|
+
} finally {
|
|
1050
|
+
reader.releaseLock();
|
|
1051
|
+
}
|
|
1052
|
+
return data.subarray(0, totalBytes);
|
|
1053
|
+
}
|
|
1054
|
+
function getBlobContentType(input) {
|
|
1055
|
+
return typeof input === "string" ? void 0 : input.type || void 0;
|
|
1056
|
+
}
|
|
1057
|
+
function createInputLimitError(maxInputBytes) {
|
|
1058
|
+
return new TileConversionError(
|
|
1059
|
+
"INPUT_RESOURCE_TOO_LARGE",
|
|
1060
|
+
`Browser input exceeds the configured ${maxInputBytes} byte memory limit`
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
function throwIfAborted3(signal) {
|
|
1064
|
+
if (signal?.aborted) {
|
|
1065
|
+
throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
// src/v5/browser-tileset-source.ts
|
|
1070
|
+
function createBrowserTilesetConversionSource(options) {
|
|
1071
|
+
if (!Number.isSafeInteger(options.maxInputBytes) || options.maxInputBytes < 1 || !Number.isSafeInteger(options.maxInputResources) || options.maxInputResources < 1) {
|
|
1072
|
+
throw new TileConversionError(
|
|
1073
|
+
"INVALID_BROWSER_SOURCE_OPTIONS",
|
|
1074
|
+
"Browser tileset sources require positive byte and resource limits"
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
const fetcher = options.fetcher ?? fetch;
|
|
1078
|
+
return {
|
|
1079
|
+
async inspect(signal) {
|
|
1080
|
+
throwIfAborted4(signal);
|
|
1081
|
+
const rootUrl = new URL(options.input).href;
|
|
1082
|
+
const response = await fetcher(rootUrl, { signal });
|
|
1083
|
+
if (!response.ok) {
|
|
1084
|
+
throw new TileConversionError(
|
|
1085
|
+
"BROWSER_SOURCE_FETCH_FAILED",
|
|
1086
|
+
`Could not fetch browser tileset (${response.status} ${response.statusText})`
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
const data = await readResponseBytes2(response, options.maxInputBytes, signal);
|
|
1090
|
+
let tileset;
|
|
1091
|
+
try {
|
|
1092
|
+
tileset = JSON.parse(new TextDecoder().decode(data));
|
|
1093
|
+
} catch {
|
|
1094
|
+
throw new TileConversionError("INVALID_BROWSER_TILESET", "Tileset input is not valid JSON");
|
|
1095
|
+
}
|
|
1096
|
+
if (!isRecord(tileset) || !["1.0", "1.1"].includes(tileset.asset?.version || "") || !isRecord(tileset.root)) {
|
|
1097
|
+
throw new TileConversionError(
|
|
1098
|
+
"UNSUPPORTED_BROWSER_TILESET",
|
|
1099
|
+
"Browser tileset traversal supports explicit 3D Tiles 1.0 and 1.1 documents"
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
const resources = collectResources(tileset.root, options.maxInputResources);
|
|
1103
|
+
return { rootUrl, tileset, resources, tilesetBytes: data.byteLength };
|
|
1104
|
+
},
|
|
1105
|
+
async *read(inspection, signal) {
|
|
1106
|
+
let inputBytes = inspection.tilesetBytes;
|
|
1107
|
+
for (const descriptor of inspection.resources) {
|
|
1108
|
+
throwIfAborted4(signal);
|
|
1109
|
+
const resourceUrl = resolveResourceUrl(descriptor.uri, inspection.rootUrl);
|
|
1110
|
+
const response = await fetcher(resourceUrl, { signal });
|
|
1111
|
+
if (!response.ok) {
|
|
1112
|
+
throw new TileConversionError(
|
|
1113
|
+
"BROWSER_SOURCE_FETCH_FAILED",
|
|
1114
|
+
`Could not fetch browser tile content (${response.status} ${response.statusText})`,
|
|
1115
|
+
[
|
|
1116
|
+
{
|
|
1117
|
+
code: "BROWSER_SOURCE_FETCH_FAILED",
|
|
1118
|
+
message: resourceUrl,
|
|
1119
|
+
severity: "error",
|
|
1120
|
+
resourceId: descriptor.resourceId
|
|
1121
|
+
}
|
|
1122
|
+
]
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
const remainingBytes = options.maxInputBytes - inputBytes;
|
|
1126
|
+
const data = await readResponseBytes2(response, remainingBytes, signal);
|
|
1127
|
+
inputBytes += data.byteLength;
|
|
1128
|
+
const contentType = response.headers.get("content-type") ?? void 0;
|
|
1129
|
+
if (isJsonContent(data, contentType)) {
|
|
1130
|
+
throw new TileConversionError(
|
|
1131
|
+
"UNSUPPORTED_BROWSER_TILESET_CONTENT",
|
|
1132
|
+
`Nested tilesets and JSON tile content are not supported: ${descriptor.uri}`
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
yield { ...descriptor, data, ...contentType ? { contentType } : {} };
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
function collectResources(root, maxInputResources) {
|
|
1141
|
+
const resources = [];
|
|
1142
|
+
const stack = [
|
|
1143
|
+
{ tile: root, path: [], transform: identityMatrix() }
|
|
1144
|
+
];
|
|
1145
|
+
while (stack.length > 0) {
|
|
1146
|
+
const { tile, path, transform: parentTransform } = stack.pop();
|
|
1147
|
+
if (!isRecord(tile)) {
|
|
1148
|
+
throw new TileConversionError("INVALID_BROWSER_TILESET", "Tile entries must be objects");
|
|
1149
|
+
}
|
|
1150
|
+
if (tile.implicitTiling !== void 0 || tile.extensions?.["3DTILES_implicit_tiling"] !== void 0) {
|
|
1151
|
+
throw new TileConversionError(
|
|
1152
|
+
"UNSUPPORTED_BROWSER_TILESET",
|
|
1153
|
+
"Browser tileset traversal does not yet support implicit tiling"
|
|
1154
|
+
);
|
|
1155
|
+
}
|
|
1156
|
+
if (tile.contents !== void 0 && !Array.isArray(tile.contents)) {
|
|
1157
|
+
throw new TileConversionError("INVALID_BROWSER_TILESET", "Tile contents must be an array");
|
|
1158
|
+
}
|
|
1159
|
+
if (tile.children !== void 0 && !Array.isArray(tile.children)) {
|
|
1160
|
+
throw new TileConversionError("INVALID_BROWSER_TILESET", "Tile children must be an array");
|
|
1161
|
+
}
|
|
1162
|
+
const transform = multiplyMatrices(parentTransform, normalizeMatrix(tile.transform));
|
|
1163
|
+
const contents = tile.contents ?? (tile.content ? [tile.content] : []);
|
|
1164
|
+
for (let contentIndex = 0; contentIndex < contents.length; contentIndex++) {
|
|
1165
|
+
const content = contents[contentIndex];
|
|
1166
|
+
if (!isRecord(content)) {
|
|
1167
|
+
throw new TileConversionError(
|
|
1168
|
+
"INVALID_BROWSER_TILESET",
|
|
1169
|
+
"Tile content entries must be objects"
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1172
|
+
const uri = content.uri ?? content.url;
|
|
1173
|
+
if (typeof uri !== "string" || !uri) {
|
|
1174
|
+
throw new TileConversionError(
|
|
1175
|
+
"INVALID_BROWSER_TILESET",
|
|
1176
|
+
`Tile content at ${path.join("/")} has no URI`
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
if (resources.length >= maxInputResources) {
|
|
1180
|
+
throw new TileConversionError(
|
|
1181
|
+
"INPUT_RESOURCE_COUNT_EXCEEDED",
|
|
1182
|
+
`Browser tileset exceeds the configured ${maxInputResources} resource limit`
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
resources.push({
|
|
1186
|
+
resourceId: `tile-${path.length ? path.join("-") : "root"}-content-${contentIndex}`,
|
|
1187
|
+
uri,
|
|
1188
|
+
tilePath: path,
|
|
1189
|
+
transform
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
const children = tile.children ?? [];
|
|
1193
|
+
for (let childIndex = children.length - 1; childIndex >= 0; childIndex--) {
|
|
1194
|
+
stack.push({
|
|
1195
|
+
tile: children[childIndex],
|
|
1196
|
+
path: [...path, childIndex],
|
|
1197
|
+
transform
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
return resources;
|
|
1202
|
+
}
|
|
1203
|
+
async function readResponseBytes2(response, maximumBytes, signal) {
|
|
1204
|
+
const reader = response.body?.getReader();
|
|
1205
|
+
if (!reader) {
|
|
1206
|
+
throw new TileConversionError(
|
|
1207
|
+
"BROWSER_SOURCE_STREAM_UNAVAILABLE",
|
|
1208
|
+
"Browser inputs must provide a readable response stream"
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
const data = new Uint8Array(maximumBytes);
|
|
1212
|
+
let byteLength = 0;
|
|
1213
|
+
try {
|
|
1214
|
+
while (true) {
|
|
1215
|
+
throwIfAborted4(signal);
|
|
1216
|
+
const { done, value } = await reader.read();
|
|
1217
|
+
if (done) break;
|
|
1218
|
+
if (value.byteLength > maximumBytes - byteLength) {
|
|
1219
|
+
await reader.cancel();
|
|
1220
|
+
throw new TileConversionError(
|
|
1221
|
+
"INPUT_RESOURCE_TOO_LARGE",
|
|
1222
|
+
`Browser tileset input exceeds the configured ${maximumBytes} byte remaining limit`
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
data.set(value, byteLength);
|
|
1226
|
+
byteLength += value.byteLength;
|
|
1227
|
+
}
|
|
1228
|
+
} finally {
|
|
1229
|
+
reader.releaseLock();
|
|
1230
|
+
}
|
|
1231
|
+
return data.subarray(0, byteLength);
|
|
1232
|
+
}
|
|
1233
|
+
function isJsonContent(data, contentType) {
|
|
1234
|
+
if (contentType?.includes("json")) return true;
|
|
1235
|
+
let byteOffset = data[0] === 239 && data[1] === 187 && data[2] === 191 ? 3 : 0;
|
|
1236
|
+
while ([9, 10, 13, 32].includes(data[byteOffset])) byteOffset++;
|
|
1237
|
+
return data[byteOffset] === 123;
|
|
1238
|
+
}
|
|
1239
|
+
function resolveResourceUrl(uri, rootUrl) {
|
|
1240
|
+
const root = new URL(rootUrl);
|
|
1241
|
+
const resource = new URL(uri, root);
|
|
1242
|
+
if (resource.origin === root.origin) {
|
|
1243
|
+
for (const [name, value] of root.searchParams) {
|
|
1244
|
+
if (!resource.searchParams.has(name)) resource.searchParams.append(name, value);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return resource.href;
|
|
1248
|
+
}
|
|
1249
|
+
function isRecord(value) {
|
|
1250
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
1251
|
+
}
|
|
1252
|
+
function identityMatrix() {
|
|
1253
|
+
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
|
1254
|
+
}
|
|
1255
|
+
function normalizeMatrix(matrix) {
|
|
1256
|
+
if (matrix === void 0) return identityMatrix();
|
|
1257
|
+
if (!Array.isArray(matrix) || matrix.length !== 16 || matrix.some((value) => !Number.isFinite(value))) {
|
|
1258
|
+
throw new TileConversionError(
|
|
1259
|
+
"INVALID_BROWSER_TILESET",
|
|
1260
|
+
"Tile transform must contain 16 finite numbers"
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
return matrix;
|
|
1264
|
+
}
|
|
1265
|
+
function multiplyMatrices(left, right) {
|
|
1266
|
+
const result = new Array(16);
|
|
1267
|
+
for (let column = 0; column < 4; column++) {
|
|
1268
|
+
for (let row = 0; row < 4; row++) {
|
|
1269
|
+
result[column * 4 + row] = left[row] * right[column * 4] + left[4 + row] * right[column * 4 + 1] + left[8 + row] * right[column * 4 + 2] + left[12 + row] * right[column * 4 + 3];
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
return result;
|
|
1273
|
+
}
|
|
1274
|
+
function throwIfAborted4(signal) {
|
|
1275
|
+
if (signal?.aborted) {
|
|
1276
|
+
throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// ../../modules/3d-tiles/src/tile-3d-writer.ts
|
|
1281
|
+
init_version();
|
|
1282
|
+
|
|
1283
|
+
// ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile.ts
|
|
1284
|
+
init_constants();
|
|
1285
|
+
init_src();
|
|
1286
|
+
|
|
1287
|
+
// ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-composite.ts
|
|
1288
|
+
init_constants();
|
|
1289
|
+
|
|
1290
|
+
// ../../modules/3d-tiles/src/lib/encoders/helpers/encode-3d-tile-header.ts
|
|
1291
|
+
init_src();
|
|
1292
|
+
function encode3DTileHeader(tile, dataView, byteOffset) {
|
|
1293
|
+
const HEADER_SIZE = 12;
|
|
1294
|
+
if (!dataView) {
|
|
1295
|
+
return byteOffset + HEADER_SIZE;
|
|
1296
|
+
}
|
|
1297
|
+
const { magic, version = 1, byteLength = 12 } = tile;
|
|
1298
|
+
assert(Array.isArray(magic) && Number.isFinite(version) && Number.isFinite(byteLength));
|
|
1299
|
+
dataView.setUint8(byteOffset + 0, magic[0]);
|
|
1300
|
+
dataView.setUint8(byteOffset + 1, magic[1]);
|
|
1301
|
+
dataView.setUint8(byteOffset + 2, magic[2]);
|
|
1302
|
+
dataView.setUint8(byteOffset + 3, magic[3]);
|
|
1303
|
+
dataView.setUint32(byteOffset + 4, version, true);
|
|
1304
|
+
dataView.setUint32(byteOffset + 8, byteLength, true);
|
|
1305
|
+
byteOffset += HEADER_SIZE;
|
|
1306
|
+
return byteOffset;
|
|
1307
|
+
}
|
|
1308
|
+
function encode3DTileByteLength(dataView, byteOffsetTileStart, byteLength) {
|
|
1309
|
+
if (!dataView) {
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
dataView.setUint32(byteOffsetTileStart + 8, byteLength, true);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-composite.ts
|
|
1316
|
+
function encodeComposite3DTile(tile, dataView, byteOffset, options, encode3DTile2) {
|
|
1317
|
+
tile = { magic: MAGIC_ARRAY.COMPOSITE, tiles: [], ...tile };
|
|
1318
|
+
const byteOffsetStart = byteOffset;
|
|
1319
|
+
byteOffset += encode3DTileHeader(tile, dataView, byteOffset);
|
|
1320
|
+
if (dataView) {
|
|
1321
|
+
dataView.setUint32(byteOffset, tile.tiles.length, true);
|
|
1322
|
+
}
|
|
1323
|
+
byteOffset += 4;
|
|
1324
|
+
for (let i = 0; i < tile.tiles.length; ++i) {
|
|
1325
|
+
byteOffset += encode3DTile2(tile.tiles[i], dataView, byteOffset, options);
|
|
1326
|
+
}
|
|
1327
|
+
encode3DTileByteLength(dataView, byteOffsetStart, byteOffset - byteOffsetStart);
|
|
1328
|
+
return byteOffset;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
// ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-batched-model.ts
|
|
1332
|
+
init_src();
|
|
1333
|
+
init_constants();
|
|
1334
|
+
function encodeBatchedModel3DTile(tile, dataView, byteOffset, options) {
|
|
1335
|
+
const { featuresLength = 0, batchTable } = tile;
|
|
1336
|
+
const featureTableJson = {
|
|
1337
|
+
BATCH_LENGTH: featuresLength
|
|
1338
|
+
};
|
|
1339
|
+
const featureTableJsonString = JSON.stringify(featureTableJson);
|
|
1340
|
+
const batchTableJsonString = batchTable ? JSON.stringify(batchTable) : "";
|
|
1341
|
+
const featureTableJsonByteLength = padToNBytes(featureTableJsonString.length, 8);
|
|
1342
|
+
const batchTableJsonByteLength = batchTableJsonString ? padToNBytes(batchTableJsonString.length, 8) : 0;
|
|
1343
|
+
tile = { magic: MAGIC_ARRAY.BATCHED_MODEL, ...tile };
|
|
1344
|
+
const byteOffsetStart = byteOffset;
|
|
1345
|
+
byteOffset = encode3DTileHeader(tile, dataView, byteOffset);
|
|
1346
|
+
if (dataView) {
|
|
1347
|
+
dataView.setUint32(12, featureTableJsonByteLength, true);
|
|
1348
|
+
dataView.setUint32(16, 0, true);
|
|
1349
|
+
dataView.setUint32(20, batchTableJsonByteLength, true);
|
|
1350
|
+
dataView.setUint32(24, 0, true);
|
|
1351
|
+
}
|
|
1352
|
+
byteOffset += 16;
|
|
1353
|
+
byteOffset = copyPaddedStringToDataView(dataView, byteOffset, featureTableJsonString, 8);
|
|
1354
|
+
if (batchTable) {
|
|
1355
|
+
byteOffset = copyPaddedStringToDataView(dataView, byteOffset, batchTableJsonString, 8);
|
|
1356
|
+
}
|
|
1357
|
+
const gltfEncoded = tile.gltfEncoded;
|
|
1358
|
+
if (gltfEncoded) {
|
|
1359
|
+
byteOffset = copyBinaryToDataView(dataView, byteOffset, gltfEncoded, gltfEncoded.byteLength);
|
|
1360
|
+
}
|
|
1361
|
+
encode3DTileByteLength(dataView, byteOffsetStart, byteOffset - byteOffsetStart);
|
|
1362
|
+
return byteOffset;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
// ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-instanced-model.ts
|
|
1366
|
+
init_src();
|
|
1367
|
+
init_constants();
|
|
1368
|
+
function encodeInstancedModel3DTile(tile, dataView, byteOffset, options) {
|
|
1369
|
+
const { featuresLength = 1, gltfFormat = 1, gltfUri = "" } = tile;
|
|
1370
|
+
const gltfUriByteLength = gltfUri.length;
|
|
1371
|
+
const featureTableJson = {
|
|
1372
|
+
INSTANCES_LENGTH: featuresLength,
|
|
1373
|
+
POSITION: new Array(featuresLength * 3).fill(0)
|
|
1374
|
+
};
|
|
1375
|
+
const featureTableJsonString = JSON.stringify(featureTableJson);
|
|
1376
|
+
const featureTableJsonByteLength = featureTableJsonString.length;
|
|
1377
|
+
tile = { magic: MAGIC_ARRAY.INSTANCED_MODEL, ...tile };
|
|
1378
|
+
const byteOffsetStart = byteOffset;
|
|
1379
|
+
byteOffset = encode3DTileHeader(tile, dataView, 0);
|
|
1380
|
+
if (dataView) {
|
|
1381
|
+
dataView.setUint32(12, featureTableJsonByteLength, true);
|
|
1382
|
+
dataView.setUint32(16, 0, true);
|
|
1383
|
+
dataView.setUint32(20, 0, true);
|
|
1384
|
+
dataView.setUint32(24, 0, true);
|
|
1385
|
+
dataView.setUint32(28, gltfFormat, true);
|
|
1386
|
+
}
|
|
1387
|
+
byteOffset += 20;
|
|
1388
|
+
byteOffset += copyStringToDataView(
|
|
1389
|
+
dataView,
|
|
1390
|
+
byteOffset,
|
|
1391
|
+
featureTableJsonString,
|
|
1392
|
+
featureTableJsonByteLength
|
|
1393
|
+
);
|
|
1394
|
+
byteOffset += copyStringToDataView(dataView, byteOffset, gltfUri, gltfUriByteLength);
|
|
1395
|
+
encode3DTileByteLength(dataView, byteOffsetStart, byteOffset - byteOffsetStart);
|
|
1396
|
+
return byteOffset;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
// ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-point-cloud.ts
|
|
1400
|
+
init_constants();
|
|
1401
|
+
init_src();
|
|
1402
|
+
var DEFAULT_FEATURE_TABLE_JSON = {
|
|
1403
|
+
POINTS_LENGTH: 1,
|
|
1404
|
+
POSITIONS: {
|
|
1405
|
+
byteOffset: 0
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
function encodePointCloud3DTile(tile, dataView, byteOffset, options) {
|
|
1409
|
+
const pointData = getPointCloudFeatureTable(tile);
|
|
1410
|
+
const featureTableJsonString = padStringToByteAlignment(JSON.stringify(pointData.json), 4);
|
|
1411
|
+
const featureTableJsonByteLength = tile.featureTableJsonByteLength ?? featureTableJsonString.length;
|
|
1412
|
+
const featureTableBinary = pointData.binary;
|
|
1413
|
+
const featureTableBinaryByteLength = featureTableBinary.byteLength;
|
|
1414
|
+
const batchTableJsonString = tile.batchTableJson ? JSON.stringify(tile.batchTableJson) : "";
|
|
1415
|
+
const batchTableJsonByteLength = batchTableJsonString ? padStringToByteAlignment(batchTableJsonString, 4).length : 0;
|
|
1416
|
+
const paddedBatchTableJsonString = batchTableJsonByteLength ? padStringToByteAlignment(batchTableJsonString, 4) : "";
|
|
1417
|
+
const batchTableBinary = tile.batchTableBinary || new Uint8Array();
|
|
1418
|
+
tile = { magic: MAGIC_ARRAY.POINT_CLOUD, ...tile };
|
|
1419
|
+
const byteOffsetStart = byteOffset;
|
|
1420
|
+
byteOffset = encode3DTileHeader(tile, dataView, byteOffset);
|
|
1421
|
+
if (dataView) {
|
|
1422
|
+
dataView.setUint32(byteOffset + 0, featureTableJsonByteLength, true);
|
|
1423
|
+
dataView.setUint32(byteOffset + 4, featureTableBinaryByteLength, true);
|
|
1424
|
+
dataView.setUint32(byteOffset + 8, batchTableJsonByteLength, true);
|
|
1425
|
+
dataView.setUint32(byteOffset + 12, batchTableBinary.byteLength, true);
|
|
1426
|
+
}
|
|
1427
|
+
byteOffset += 16;
|
|
1428
|
+
byteOffset = copyStringToDataView(
|
|
1429
|
+
dataView,
|
|
1430
|
+
byteOffset,
|
|
1431
|
+
featureTableJsonString,
|
|
1432
|
+
featureTableJsonByteLength
|
|
1433
|
+
);
|
|
1434
|
+
byteOffset = copyBinaryToDataView(
|
|
1435
|
+
dataView,
|
|
1436
|
+
byteOffset,
|
|
1437
|
+
featureTableBinary,
|
|
1438
|
+
featureTableBinaryByteLength
|
|
1439
|
+
);
|
|
1440
|
+
if (batchTableJsonByteLength > 0) {
|
|
1441
|
+
byteOffset = copyStringToDataView(
|
|
1442
|
+
dataView,
|
|
1443
|
+
byteOffset,
|
|
1444
|
+
paddedBatchTableJsonString,
|
|
1445
|
+
batchTableJsonByteLength
|
|
1446
|
+
);
|
|
1447
|
+
}
|
|
1448
|
+
byteOffset = copyBinaryToDataView(
|
|
1449
|
+
dataView,
|
|
1450
|
+
byteOffset,
|
|
1451
|
+
batchTableBinary,
|
|
1452
|
+
batchTableBinary.byteLength
|
|
1453
|
+
);
|
|
1454
|
+
encode3DTileByteLength(dataView, byteOffsetStart, byteOffset - byteOffsetStart);
|
|
1455
|
+
return byteOffset;
|
|
1456
|
+
}
|
|
1457
|
+
function getPointCloudFeatureTable(tile) {
|
|
1458
|
+
const positions = tile.attributes?.positions;
|
|
1459
|
+
if (!positions) {
|
|
1460
|
+
const json2 = tile.featureTableJson || DEFAULT_FEATURE_TABLE_JSON;
|
|
1461
|
+
return { json: json2, binary: new Uint8Array(12) };
|
|
1462
|
+
}
|
|
1463
|
+
if (positions.length === 0 || positions.length % 3 !== 0) {
|
|
1464
|
+
throw new Error("3D Tiles point cloud positions must contain one or more xyz triples");
|
|
1465
|
+
}
|
|
1466
|
+
const pointCount = positions.length / 3;
|
|
1467
|
+
const properties = [];
|
|
1468
|
+
properties.push({ name: "POSITION", alignment: 4, bytes: encodeFloat32Array(positions) });
|
|
1469
|
+
const colors = tile.attributes?.colors;
|
|
1470
|
+
if (colors) {
|
|
1471
|
+
const colorValues = Array.isArray(colors) ? colors : colors.value;
|
|
1472
|
+
const colorSize = Array.isArray(colors) ? colorValues.length / pointCount : colors.size;
|
|
1473
|
+
if (colorSize !== 3 && colorSize !== 4) {
|
|
1474
|
+
throw new Error("3D Tiles point cloud colors must contain RGB or RGBA values");
|
|
1475
|
+
}
|
|
1476
|
+
const colorBytes = encodeColorBytes(
|
|
1477
|
+
colorValues,
|
|
1478
|
+
!Array.isArray(colors) && colors.normalized,
|
|
1479
|
+
pointCount,
|
|
1480
|
+
colorSize
|
|
1481
|
+
);
|
|
1482
|
+
properties.push({ name: colorSize === 4 ? "RGBA" : "RGB", alignment: 1, bytes: colorBytes });
|
|
1483
|
+
}
|
|
1484
|
+
const normals = tile.attributes?.normals;
|
|
1485
|
+
if (normals) {
|
|
1486
|
+
const normalValues = Array.isArray(normals) ? normals : normals.value;
|
|
1487
|
+
if (normalValues.length !== pointCount * 3) {
|
|
1488
|
+
throw new Error("3D Tiles point cloud normal count does not match the position count");
|
|
1489
|
+
}
|
|
1490
|
+
properties.push({ name: "NORMAL", alignment: 4, bytes: encodeFloat32Array(normalValues) });
|
|
1491
|
+
}
|
|
1492
|
+
const batchIds = tile.attributes?.batchIds;
|
|
1493
|
+
let batchLength = 0;
|
|
1494
|
+
if (batchIds) {
|
|
1495
|
+
if (batchIds.length !== pointCount) {
|
|
1496
|
+
throw new Error("3D Tiles point cloud batch ID count does not match the position count");
|
|
1497
|
+
}
|
|
1498
|
+
const batchIdValues = new Uint16Array(batchIds.length);
|
|
1499
|
+
for (let index = 0; index < batchIds.length; index++) {
|
|
1500
|
+
const batchId = batchIds[index];
|
|
1501
|
+
if (!Number.isInteger(batchId) || batchId < 0 || batchId > 65535) {
|
|
1502
|
+
throw new Error("3D Tiles point cloud batch IDs must be unsigned 16-bit integers");
|
|
1503
|
+
}
|
|
1504
|
+
batchIdValues[index] = batchId;
|
|
1505
|
+
batchLength = Math.max(batchLength, batchId + 1);
|
|
1506
|
+
}
|
|
1507
|
+
const batchIdBytes = new Uint8Array(batchIdValues.length * 2);
|
|
1508
|
+
const dataView = new DataView(batchIdBytes.buffer);
|
|
1509
|
+
for (let index = 0; index < batchIdValues.length; index++) {
|
|
1510
|
+
dataView.setUint16(index * 2, batchIdValues[index], true);
|
|
1511
|
+
}
|
|
1512
|
+
properties.push({ name: "BATCH_ID", alignment: 2, bytes: batchIdBytes });
|
|
1513
|
+
}
|
|
1514
|
+
const json = {
|
|
1515
|
+
...tile.featureTableJson || {},
|
|
1516
|
+
POINTS_LENGTH: pointCount
|
|
1517
|
+
};
|
|
1518
|
+
if (batchIds) {
|
|
1519
|
+
json.BATCH_LENGTH = batchLength;
|
|
1520
|
+
}
|
|
1521
|
+
const binaryByteLength = getPointCloudFeatureTableByteLength(properties);
|
|
1522
|
+
const binary = new Uint8Array(binaryByteLength);
|
|
1523
|
+
let byteOffset = 0;
|
|
1524
|
+
for (const property of properties) {
|
|
1525
|
+
byteOffset = align(byteOffset, property.alignment);
|
|
1526
|
+
json[property.name] = { byteOffset };
|
|
1527
|
+
binary.set(property.bytes, byteOffset);
|
|
1528
|
+
byteOffset += property.bytes.byteLength;
|
|
1529
|
+
}
|
|
1530
|
+
return { json, binary };
|
|
1531
|
+
}
|
|
1532
|
+
function getPointCloudFeatureTableByteLength(properties) {
|
|
1533
|
+
let byteLength = 0;
|
|
1534
|
+
for (const property of properties) {
|
|
1535
|
+
byteLength = align(byteLength, property.alignment) + property.bytes.byteLength;
|
|
1536
|
+
}
|
|
1537
|
+
return byteLength;
|
|
1538
|
+
}
|
|
1539
|
+
function align(byteOffset, alignment) {
|
|
1540
|
+
return Math.ceil(byteOffset / alignment) * alignment;
|
|
1541
|
+
}
|
|
1542
|
+
function encodeFloat32Array(values) {
|
|
1543
|
+
const bytes = new Uint8Array(values.length * 4);
|
|
1544
|
+
const dataView = new DataView(bytes.buffer);
|
|
1545
|
+
for (let index = 0; index < values.length; index++) {
|
|
1546
|
+
const value = values[index];
|
|
1547
|
+
if (!Number.isFinite(value)) {
|
|
1548
|
+
throw new Error("3D Tiles point cloud attributes must contain finite values");
|
|
1549
|
+
}
|
|
1550
|
+
dataView.setFloat32(index * 4, value, true);
|
|
1551
|
+
}
|
|
1552
|
+
return bytes;
|
|
1553
|
+
}
|
|
1554
|
+
function encodeColorBytes(colors, normalized, pointCount, colorSize) {
|
|
1555
|
+
if (colors.length !== pointCount * colorSize) {
|
|
1556
|
+
throw new Error("3D Tiles point cloud color count does not match the position count");
|
|
1557
|
+
}
|
|
1558
|
+
const bytes = new Uint8Array(colors.length);
|
|
1559
|
+
for (let index = 0; index < colors.length; index++) {
|
|
1560
|
+
const value = colors[index];
|
|
1561
|
+
const scaledValue = normalized ? value * 255 : value;
|
|
1562
|
+
if (!Number.isFinite(scaledValue) || scaledValue < 0 || scaledValue > 255) {
|
|
1563
|
+
throw new Error("3D Tiles point cloud color components must be between 0 and 255");
|
|
1564
|
+
}
|
|
1565
|
+
bytes[index] = Math.round(scaledValue);
|
|
1566
|
+
}
|
|
1567
|
+
return bytes;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
// ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile.ts
|
|
1571
|
+
function encode3DTile(tile, options) {
|
|
1572
|
+
const byteLength = encode3DTileToDataView(tile, null, 0, options);
|
|
1573
|
+
const arrayBuffer = new ArrayBuffer(byteLength);
|
|
1574
|
+
const dataView = new DataView(arrayBuffer);
|
|
1575
|
+
encode3DTileToDataView(tile, dataView, 0, options);
|
|
1576
|
+
return arrayBuffer;
|
|
1577
|
+
}
|
|
1578
|
+
function encode3DTileToDataView(tile, dataView, byteOffset, options) {
|
|
1579
|
+
assert(typeof tile.type === "string");
|
|
1580
|
+
switch (tile.type) {
|
|
1581
|
+
case TILE3D_TYPE.COMPOSITE:
|
|
1582
|
+
return encodeComposite3DTile(tile, dataView, byteOffset, options, encode3DTileToDataView);
|
|
1583
|
+
case TILE3D_TYPE.POINT_CLOUD:
|
|
1584
|
+
return encodePointCloud3DTile(tile, dataView, byteOffset, options);
|
|
1585
|
+
case TILE3D_TYPE.BATCHED_3D_MODEL:
|
|
1586
|
+
return encodeBatchedModel3DTile(tile, dataView, byteOffset, options);
|
|
1587
|
+
case TILE3D_TYPE.INSTANCED_3D_MODEL:
|
|
1588
|
+
return encodeInstancedModel3DTile(tile, dataView, byteOffset, options);
|
|
1589
|
+
default:
|
|
1590
|
+
throw new Error("3D Tiles: unknown tile type");
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
// ../../modules/3d-tiles/src/tile-3d-writer.ts
|
|
1595
|
+
var Tile3DWriter = {
|
|
1596
|
+
name: "3D Tile",
|
|
1597
|
+
id: "3d-tiles",
|
|
1598
|
+
module: "3d-tiles",
|
|
1599
|
+
version: VERSION,
|
|
1600
|
+
extensions: ["cmpt", "pnts", "b3dm", "i3dm"],
|
|
1601
|
+
mimeTypes: ["application/octet-stream"],
|
|
1602
|
+
binary: true,
|
|
1603
|
+
options: {
|
|
1604
|
+
["3d-tiles"]: {}
|
|
1605
|
+
},
|
|
1606
|
+
encode: async (tile, options) => encodeSync(tile, options),
|
|
1607
|
+
encodeSync
|
|
1608
|
+
};
|
|
1609
|
+
function encodeSync(tile, options) {
|
|
1610
|
+
return encode3DTile(tile, options);
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
// ../../modules/3d-tiles/src/index.ts
|
|
1614
|
+
init_constants();
|
|
1615
|
+
|
|
1616
|
+
// src/v5/point-cloud.ts
|
|
1617
|
+
init_src4();
|
|
1618
|
+
function encodePointCloudTile(pointBatch, options = {}) {
|
|
1619
|
+
const mesh = "attributes" in pointBatch ? pointBatch : convertTableToMesh(pointBatch);
|
|
1620
|
+
validatePointAttributes(mesh.attributes);
|
|
1621
|
+
const positionAttribute = mesh.attributes.POSITION;
|
|
1622
|
+
if (!positionAttribute || positionAttribute.size !== 3) {
|
|
1623
|
+
throw new TileConversionError(
|
|
1624
|
+
"POINT_CLOUD_POSITION_REQUIRED",
|
|
1625
|
+
"Point cloud batches must contain a three-component POSITION attribute"
|
|
1626
|
+
);
|
|
1627
|
+
}
|
|
1628
|
+
const positions = getPositionValues(positionAttribute, options.rtcCenter);
|
|
1629
|
+
const pointCount = positions.length / 3;
|
|
1630
|
+
if (pointCount === 0 || !Number.isInteger(pointCount)) {
|
|
1631
|
+
throw new TileConversionError(
|
|
1632
|
+
"POINT_CLOUD_POSITION_COUNT_INVALID",
|
|
1633
|
+
"Point cloud POSITION must contain one or more xyz triples"
|
|
1634
|
+
);
|
|
1635
|
+
}
|
|
1636
|
+
const colors = getColorAttribute(mesh.attributes.COLOR_0 || mesh.attributes.COLOR, pointCount);
|
|
1637
|
+
const constantRGBA = colors ? null : getConstantRgba(options.constantRGBA);
|
|
1638
|
+
const normals = getNormalAttribute(mesh.attributes.NORMAL, pointCount);
|
|
1639
|
+
const batchIds = getBatchIds(mesh.attributes.BATCH_ID, pointCount);
|
|
1640
|
+
const batchTableJson = validateBatchTable(options.batchTableJson, batchIds);
|
|
1641
|
+
return Tile3DWriter.encodeSync(
|
|
1642
|
+
{
|
|
1643
|
+
type: TILE3D_TYPE.POINT_CLOUD,
|
|
1644
|
+
featureTableJson: options.rtcCenter || constantRGBA ? {
|
|
1645
|
+
...options.rtcCenter ? { RTC_CENTER: [...options.rtcCenter] } : {},
|
|
1646
|
+
...constantRGBA ? { CONSTANT_RGBA: constantRGBA } : {}
|
|
1647
|
+
} : void 0,
|
|
1648
|
+
batchTableJson,
|
|
1649
|
+
attributes: { positions, colors, normals, batchIds }
|
|
1650
|
+
},
|
|
1651
|
+
{}
|
|
1652
|
+
);
|
|
1653
|
+
}
|
|
1654
|
+
function validatePointAttributes(attributes) {
|
|
1655
|
+
const supportedAttributes = /* @__PURE__ */ new Set([
|
|
1656
|
+
"POSITION",
|
|
1657
|
+
"NORMAL",
|
|
1658
|
+
"BATCH_ID",
|
|
1659
|
+
attributes.COLOR_0 ? "COLOR_0" : "COLOR"
|
|
1660
|
+
]);
|
|
1661
|
+
const unsupportedAttributes = Object.keys(attributes).filter(
|
|
1662
|
+
(name) => !supportedAttributes.has(name)
|
|
1663
|
+
);
|
|
1664
|
+
if (unsupportedAttributes.length > 0) {
|
|
1665
|
+
throw new TileConversionError(
|
|
1666
|
+
"POINT_CLOUD_ATTRIBUTE_UNSUPPORTED",
|
|
1667
|
+
`PNTS encoding does not support these point attributes: ${unsupportedAttributes.join(", ")}`
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
function getConstantRgba(constantRGBA) {
|
|
1672
|
+
if (!constantRGBA) {
|
|
1673
|
+
return null;
|
|
1674
|
+
}
|
|
1675
|
+
if (constantRGBA.length !== 4 || constantRGBA.some((value) => !Number.isInteger(value) || value < 0 || value > 255)) {
|
|
1676
|
+
throw new TileConversionError(
|
|
1677
|
+
"POINT_CLOUD_CONSTANT_RGBA_INVALID",
|
|
1678
|
+
"Point cloud constantRGBA must contain four unsigned byte values"
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
return [constantRGBA[0], constantRGBA[1], constantRGBA[2], constantRGBA[3]];
|
|
1682
|
+
}
|
|
1683
|
+
function getPositionValues(attribute, rtcCenter) {
|
|
1684
|
+
if (rtcCenter && (rtcCenter.length !== 3 || rtcCenter.some((value) => !Number.isFinite(value)))) {
|
|
1685
|
+
throw new TileConversionError(
|
|
1686
|
+
"POINT_CLOUD_RTC_CENTER_INVALID",
|
|
1687
|
+
"Point cloud RTC_CENTER must contain three finite values"
|
|
1688
|
+
);
|
|
1689
|
+
}
|
|
1690
|
+
const values = attribute.value;
|
|
1691
|
+
const result = new Float32Array(values.length);
|
|
1692
|
+
const transform = attribute.transform;
|
|
1693
|
+
for (let index = 0; index < values.length; index++) {
|
|
1694
|
+
const component = index % 3;
|
|
1695
|
+
const value = values[index];
|
|
1696
|
+
const absoluteValue = transform?.type === "quantization" ? transform.origin[component] + value / (2 ** transform.bits - 1) * transform.range : value;
|
|
1697
|
+
result[index] = absoluteValue - (rtcCenter?.[component] ?? 0);
|
|
1698
|
+
}
|
|
1699
|
+
return result;
|
|
1700
|
+
}
|
|
1701
|
+
function getColorAttribute(attribute, pointCount) {
|
|
1702
|
+
if (!attribute) {
|
|
1703
|
+
return null;
|
|
1704
|
+
}
|
|
1705
|
+
if (attribute.size !== 3 && attribute.size !== 4) {
|
|
1706
|
+
throw new TileConversionError(
|
|
1707
|
+
"POINT_CLOUD_COLOR_SIZE_UNSUPPORTED",
|
|
1708
|
+
"Point cloud color attributes must contain three or four components"
|
|
1709
|
+
);
|
|
1710
|
+
}
|
|
1711
|
+
if (attribute.value.length !== pointCount * attribute.size) {
|
|
1712
|
+
throw new TileConversionError(
|
|
1713
|
+
"POINT_CLOUD_COLOR_COUNT_MISMATCH",
|
|
1714
|
+
"Point cloud color count does not match the POSITION count"
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
const colors = new Uint8Array(attribute.value.length);
|
|
1718
|
+
const maximum = getIntegerColorMaximum(attribute.value);
|
|
1719
|
+
for (let index = 0; index < attribute.value.length; index++) {
|
|
1720
|
+
const value = attribute.value[index];
|
|
1721
|
+
const scaledValue = maximum ? value / maximum * 255 : value <= 1 ? value * 255 : value;
|
|
1722
|
+
if (!Number.isFinite(scaledValue) || scaledValue < 0 || scaledValue > 255) {
|
|
1723
|
+
throw new TileConversionError(
|
|
1724
|
+
"POINT_CLOUD_COLOR_VALUE_INVALID",
|
|
1725
|
+
"Point cloud color components must be finite values from 0 through 255"
|
|
1726
|
+
);
|
|
1727
|
+
}
|
|
1728
|
+
colors[index] = Math.round(scaledValue);
|
|
1729
|
+
}
|
|
1730
|
+
return { type: 5121, value: colors, size: attribute.size, normalized: false };
|
|
1731
|
+
}
|
|
1732
|
+
function getIntegerColorMaximum(values) {
|
|
1733
|
+
if (values instanceof Uint8Array || values instanceof Uint8ClampedArray) {
|
|
1734
|
+
return 255;
|
|
1735
|
+
}
|
|
1736
|
+
if (values instanceof Uint16Array) {
|
|
1737
|
+
return 65535;
|
|
1738
|
+
}
|
|
1739
|
+
if (values instanceof Uint32Array) {
|
|
1740
|
+
return 4294967295;
|
|
1741
|
+
}
|
|
1742
|
+
return null;
|
|
1743
|
+
}
|
|
1744
|
+
function getNormalAttribute(attribute, pointCount) {
|
|
1745
|
+
if (!attribute) {
|
|
1746
|
+
return null;
|
|
1747
|
+
}
|
|
1748
|
+
if (attribute.size !== 3 || attribute.value.length !== pointCount * 3) {
|
|
1749
|
+
throw new TileConversionError(
|
|
1750
|
+
"POINT_CLOUD_NORMAL_COUNT_MISMATCH",
|
|
1751
|
+
"Point cloud normals must contain one xyz triple per position"
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
return { type: 5126, value: Float32Array.from(attribute.value), size: 3 };
|
|
1755
|
+
}
|
|
1756
|
+
function getBatchIds(attribute, pointCount) {
|
|
1757
|
+
if (!attribute) {
|
|
1758
|
+
return null;
|
|
1759
|
+
}
|
|
1760
|
+
if (attribute.size !== 1 || attribute.value.length !== pointCount) {
|
|
1761
|
+
throw new TileConversionError(
|
|
1762
|
+
"POINT_CLOUD_BATCH_ID_COUNT_MISMATCH",
|
|
1763
|
+
"Point cloud BATCH_ID must contain one value per position"
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
const batchIds = new Uint16Array(pointCount);
|
|
1767
|
+
for (let index = 0; index < pointCount; index++) {
|
|
1768
|
+
const batchId = attribute.value[index];
|
|
1769
|
+
if (!Number.isInteger(batchId) || batchId < 0 || batchId > 65535) {
|
|
1770
|
+
throw new TileConversionError(
|
|
1771
|
+
"POINT_CLOUD_BATCH_ID_OUT_OF_RANGE",
|
|
1772
|
+
"Point cloud BATCH_ID values must be unsigned 16-bit integers"
|
|
1773
|
+
);
|
|
1774
|
+
}
|
|
1775
|
+
batchIds[index] = batchId;
|
|
1776
|
+
}
|
|
1777
|
+
return batchIds;
|
|
1778
|
+
}
|
|
1779
|
+
function validateBatchTable(batchTableJson, batchIds) {
|
|
1780
|
+
if (!batchTableJson) {
|
|
1781
|
+
if (batchIds) {
|
|
1782
|
+
throw new TileConversionError(
|
|
1783
|
+
"POINT_CLOUD_BATCH_TABLE_REQUIRED",
|
|
1784
|
+
"BATCH_ID values require matching batchTableJson properties"
|
|
1785
|
+
);
|
|
1786
|
+
}
|
|
1787
|
+
return void 0;
|
|
1788
|
+
}
|
|
1789
|
+
if (!batchIds) {
|
|
1790
|
+
throw new TileConversionError(
|
|
1791
|
+
"POINT_CLOUD_BATCH_ID_REQUIRED",
|
|
1792
|
+
"batchTableJson requires a BATCH_ID attribute"
|
|
1793
|
+
);
|
|
1794
|
+
}
|
|
1795
|
+
let batchLength = 0;
|
|
1796
|
+
for (const batchId of batchIds) {
|
|
1797
|
+
batchLength = Math.max(batchLength, batchId + 1);
|
|
1798
|
+
}
|
|
1799
|
+
const normalizedBatchTable = {};
|
|
1800
|
+
for (const [name, values] of Object.entries(batchTableJson)) {
|
|
1801
|
+
if (values.length !== batchLength) {
|
|
1802
|
+
throw new TileConversionError(
|
|
1803
|
+
"POINT_CLOUD_BATCH_TABLE_LENGTH_MISMATCH",
|
|
1804
|
+
`Batch table property "${name}" must contain ${batchLength} values`
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1807
|
+
normalizedBatchTable[name] = [...values];
|
|
1808
|
+
}
|
|
1809
|
+
return normalizedBatchTable;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
// src/v5/point-cloud-source.ts
|
|
1813
|
+
async function* traversePointCloudSource(source, options = {}) {
|
|
1814
|
+
const { maxDepth = Number.POSITIVE_INFINITY, signal } = options;
|
|
1815
|
+
if (maxDepth !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(maxDepth) || maxDepth < 0)) {
|
|
1816
|
+
throw new RangeError("Point-cloud source maxDepth must be a non-negative integer");
|
|
1817
|
+
}
|
|
1818
|
+
throwIfAborted5(signal);
|
|
1819
|
+
if (!source.isReady) {
|
|
1820
|
+
await source.initialize();
|
|
1821
|
+
}
|
|
1822
|
+
throwIfAborted5(signal);
|
|
1823
|
+
const root = await source.getRootTile();
|
|
1824
|
+
const pendingTiles = [root];
|
|
1825
|
+
const visitedTileIds = /* @__PURE__ */ new Set();
|
|
1826
|
+
while (pendingTiles.length > 0) {
|
|
1827
|
+
throwIfAborted5(signal);
|
|
1828
|
+
const header = pendingTiles.pop();
|
|
1829
|
+
if (visitedTileIds.has(header.id)) {
|
|
1830
|
+
continue;
|
|
1831
|
+
}
|
|
1832
|
+
visitedTileIds.add(header.id);
|
|
1833
|
+
const content = await source.loadTileContent(header);
|
|
1834
|
+
throwIfAborted5(signal);
|
|
1835
|
+
yield { header, content };
|
|
1836
|
+
throwIfAborted5(signal);
|
|
1837
|
+
if (header.level >= maxDepth) {
|
|
1838
|
+
continue;
|
|
1839
|
+
}
|
|
1840
|
+
const children = await source.getChildren(header);
|
|
1841
|
+
throwIfAborted5(signal);
|
|
1842
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
1843
|
+
pendingTiles.push(children[index]);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
function throwIfAborted5(signal) {
|
|
1848
|
+
if (signal?.aborted) {
|
|
1849
|
+
throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
// src/v5/point-cloud-source-encoder.ts
|
|
1854
|
+
async function* encodePointCloudSource(source, options = {}) {
|
|
1855
|
+
for await (const sourceTile of traversePointCloudSource(source, options)) {
|
|
1856
|
+
const encodingOptions = sourceTile.content ? options.getTileEncodingOptions?.(sourceTile) : void 0;
|
|
1857
|
+
const encodedTile = encodePointCloudSourceTile(sourceTile, encodingOptions);
|
|
1858
|
+
if (encodedTile) {
|
|
1859
|
+
yield encodedTile;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
function encodePointCloudSourceTile(sourceTile, options = {}) {
|
|
1864
|
+
const { header, content } = sourceTile;
|
|
1865
|
+
if (!content) {
|
|
1866
|
+
return null;
|
|
1867
|
+
}
|
|
1868
|
+
return {
|
|
1869
|
+
id: header.id,
|
|
1870
|
+
header,
|
|
1871
|
+
pnts: encodePointCloudTile(content.data, {
|
|
1872
|
+
...options,
|
|
1873
|
+
constantRGBA: options.constantRGBA ?? content.constantRGBA
|
|
1874
|
+
}),
|
|
1875
|
+
pointCount: content.pointCount,
|
|
1876
|
+
coordinateSystem: content.coordinateSystem,
|
|
1877
|
+
cartographicOrigin: [...content.cartographicOrigin],
|
|
1878
|
+
modelMatrix: content.modelMatrix ? Array.from(content.modelMatrix) : void 0,
|
|
1879
|
+
spatialReference: content.spatialReference,
|
|
1880
|
+
spatialBoundingVolume: content.spatialBoundingVolume || header.spatialBoundingVolume
|
|
1881
|
+
};
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
// src/v5/point-cloud-conversion.ts
|
|
1885
|
+
function convertPointCloudSource(source, options) {
|
|
1886
|
+
return convertTileset({
|
|
1887
|
+
source: {
|
|
1888
|
+
async inspect() {
|
|
1889
|
+
if (!source.isReady) {
|
|
1890
|
+
await source.initialize();
|
|
1891
|
+
}
|
|
1892
|
+
},
|
|
1893
|
+
read: (_inspection, signal) => traversePointCloudSource(source, { maxDepth: options.maxDepth, signal })
|
|
1894
|
+
},
|
|
1895
|
+
codec: {
|
|
1896
|
+
async *convert(sourceTile) {
|
|
1897
|
+
const encodingOptions = sourceTile.content ? options.getTileEncodingOptions?.(sourceTile) : void 0;
|
|
1898
|
+
const encodedTile = encodePointCloudSourceTile(sourceTile, encodingOptions);
|
|
1899
|
+
if (encodedTile) {
|
|
1900
|
+
yield encodedTile;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
},
|
|
1904
|
+
sink: options.sink,
|
|
1905
|
+
measureInputBytes: options.measureInputBytes,
|
|
1906
|
+
measureOutputBytes: (resource) => resource.pnts.byteLength,
|
|
1907
|
+
maxInputResourceBytes: options.maxInputResourceBytes,
|
|
1908
|
+
maxOutputResourceBytes: options.maxOutputResourceBytes,
|
|
1909
|
+
signal: options.signal,
|
|
1910
|
+
onProgress: options.onProgress
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
export {
|
|
1914
|
+
TileConversionError,
|
|
1915
|
+
convertPointCloudSource,
|
|
1916
|
+
convertTileset,
|
|
1917
|
+
createBoundedMemoryTileConversionSink,
|
|
1918
|
+
createBrowserTileConversionSource,
|
|
1919
|
+
createBrowserTilesetConversionSource,
|
|
1920
|
+
createTilesetConversionSource,
|
|
1921
|
+
encodePointCloudSource,
|
|
1922
|
+
encodePointCloudSourceTile,
|
|
1923
|
+
encodePointCloudTile,
|
|
1924
|
+
inspectTileset,
|
|
1925
|
+
traversePointCloudSource,
|
|
1926
|
+
validateTileset
|
|
1927
|
+
};
|