@loaders.gl/tile-converter 5.0.0-alpha.6 → 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.
Files changed (96) hide show
  1. package/README.md +155 -0
  2. package/dist/converter.min.cjs +194 -194
  3. package/dist/i3s-server/bin/i3s-server.min.cjs +84 -84
  4. package/dist/index.cjs +35865 -0
  5. package/dist/index.js +35837 -0
  6. package/dist/v5/browser-sink.d.ts +37 -0
  7. package/dist/v5/browser-source.d.ts +38 -0
  8. package/dist/v5/browser-tileset-source.d.ts +70 -0
  9. package/dist/v5/browser.cjs +1962 -0
  10. package/dist/v5/browser.d.ts +18 -0
  11. package/dist/v5/browser.js +1927 -0
  12. package/dist/v5/conversion-api.d.ts +122 -0
  13. package/dist/v5/feature-arrow.d.ts +36 -0
  14. package/dist/v5/index.cjs +3975 -0
  15. package/dist/v5/index.d.ts +18 -0
  16. package/dist/v5/index.js +3928 -0
  17. package/dist/v5/point-cloud-conversion.d.ts +31 -0
  18. package/dist/v5/point-cloud-source-encoder.d.ts +49 -0
  19. package/dist/v5/point-cloud-source.d.ts +25 -0
  20. package/dist/v5/point-cloud.d.ts +24 -0
  21. package/dist/v5/resource-manifest.d.ts +58 -0
  22. package/dist/v5/spatial-conversion.d.ts +59 -0
  23. package/dist/v5/tileset-source.d.ts +21 -0
  24. package/package.json +41 -26
  25. package/src/common/README.md +5 -0
  26. package/src/index.ts +1 -2
  27. package/src/{3d-tiles-converter → v4/3d-tiles-converter}/3d-tiles-converter.ts +13 -2
  28. package/src/v4/3d-tiles-converter/helpers/validate-i3s-spatial-reference.ts +124 -0
  29. package/src/{deps-installer → v4/deps-installer}/deps-installer.ts +10 -7
  30. package/src/v4/i3s-converter/helpers/encode-string-attribute.ts +23 -0
  31. package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-converter.ts +15 -42
  32. package/src/{i3s-converter → v4/i3s-converter}/helpers/gltf-attributes.ts +5 -4
  33. package/src/{i3s-converter → v4/i3s-converter}/helpers/load-3d-tiles.ts +5 -9
  34. package/src/{i3s-converter → v4/i3s-converter}/i3s-converter.ts +6 -7
  35. package/src/{i3s-server → v4/i3s-server}/README.md +2 -2
  36. package/src/{i3s-server → v4/i3s-server}/routes/slpk-router.ts +1 -0
  37. package/src/v4/index.ts +2 -0
  38. package/src/v5/browser-sink.ts +129 -0
  39. package/src/v5/browser-source.ts +155 -0
  40. package/src/v5/browser-tileset-source.ts +328 -0
  41. package/src/v5/browser.ts +54 -0
  42. package/src/v5/conversion-api.ts +287 -0
  43. package/src/v5/feature-arrow.ts +427 -0
  44. package/src/v5/index.ts +47 -0
  45. package/src/v5/point-cloud-conversion.ts +80 -0
  46. package/src/v5/point-cloud-source-encoder.ts +102 -0
  47. package/src/v5/point-cloud-source.ts +84 -0
  48. package/src/v5/point-cloud.ts +271 -0
  49. package/src/v5/resource-manifest.ts +213 -0
  50. package/src/v5/spatial-conversion.ts +305 -0
  51. package/src/v5/tileset-source.ts +54 -0
  52. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/3d-tiles-content-converter.ts +0 -0
  53. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/i3s-obb-to-3d-tiles-obb.ts +0 -0
  54. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/load-i3s.ts +0 -0
  55. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/texture-atlas.ts +0 -0
  56. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/json-templates/tileset.ts +0 -0
  57. /package/src/{constants.ts → v4/constants.ts} +0 -0
  58. /package/src/{converter-cli.ts → v4/converter-cli.ts} +0 -0
  59. /package/src/{i3s-converter → v4/i3s-converter}/helpers/attribute-metadata-info.ts +0 -0
  60. /package/src/{i3s-converter → v4/i3s-converter}/helpers/batch-ids-extensions.ts +0 -0
  61. /package/src/{i3s-converter → v4/i3s-converter}/helpers/coordinate-converter.ts +0 -0
  62. /package/src/{i3s-converter → v4/i3s-converter}/helpers/create-scene-server-path.ts +0 -0
  63. /package/src/{i3s-converter → v4/i3s-converter}/helpers/feature-attributes.ts +0 -0
  64. /package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-attributes.ts +0 -0
  65. /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-debug.ts +0 -0
  66. /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-index-document.ts +0 -0
  67. /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-pages.ts +0 -0
  68. /package/src/{i3s-converter → v4/i3s-converter}/helpers/preprocess-3d-tiles.ts +0 -0
  69. /package/src/{i3s-converter → v4/i3s-converter}/helpers/progress.ts +0 -0
  70. /package/src/{i3s-converter → v4/i3s-converter}/helpers/tileset-traversal.ts +0 -0
  71. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/geometry-definitions.ts +0 -0
  72. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/layers.ts +0 -0
  73. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/metadata.ts +0 -0
  74. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/node.ts +0 -0
  75. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/scene-server.ts +0 -0
  76. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/shared-resources.ts +0 -0
  77. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/store.ts +0 -0
  78. /package/src/{i3s-converter → v4/i3s-converter}/types.ts +0 -0
  79. /package/src/{i3s-server → v4/i3s-server}/app.ts +0 -0
  80. /package/src/{i3s-server → v4/i3s-server}/bin/www.ts +0 -0
  81. /package/src/{i3s-server → v4/i3s-server}/certs/cert.pem +0 -0
  82. /package/src/{i3s-server → v4/i3s-server}/certs/key.pem +0 -0
  83. /package/src/{i3s-server → v4/i3s-server}/controllers/slpk-controller.ts +0 -0
  84. /package/src/{i3s-server → v4/i3s-server}/utils/create-scene-server.ts +0 -0
  85. /package/src/{i3s-server → v4/i3s-server}/utils/server-utils.ts +0 -0
  86. /package/src/{lib → v4/lib}/json-schemas/conversion-dump-json-schema.ts +0 -0
  87. /package/src/{lib → v4/lib}/utils/cli-utils.ts +0 -0
  88. /package/src/{lib → v4/lib}/utils/compress-util.ts +0 -0
  89. /package/src/{lib → v4/lib}/utils/conversion-dump.ts +0 -0
  90. /package/src/{lib → v4/lib}/utils/file-utils.ts +0 -0
  91. /package/src/{lib → v4/lib}/utils/geometry-utils.ts +0 -0
  92. /package/src/{lib → v4/lib}/utils/lod-conversion-utils.ts +0 -0
  93. /package/src/{lib → v4/lib}/utils/queue.ts +0 -0
  94. /package/src/{lib → v4/lib}/utils/statistic-utils.ts +0 -0
  95. /package/src/{lib → v4/lib}/utils/write-queue.ts +0 -0
  96. /package/src/{pgm-loader.ts → v4/pgm-loader.ts} +0 -0
@@ -0,0 +1,3928 @@
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/spatial/normalize-crs-identifier.ts
105
+ function normalizeCrsIdentifier(identifier) {
106
+ const normalizedIdentifier = identifier.trim().toUpperCase();
107
+ const ogcMatch = normalizedIdentifier.match(
108
+ /(?:\/DEF\/CRS\/|URN:OGC:DEF:CRS:)([A-Z0-9_-]+)(?:\/|::)(?:[^/:]*[/:])?([A-Z0-9_.-]+)$/
109
+ );
110
+ return ogcMatch ? `${ogcMatch[1]}:${ogcMatch[2]}` : normalizedIdentifier;
111
+ }
112
+ var WGS84_GEOGRAPHIC_CRS, WGS84_GEOCENTRIC_CRS;
113
+ var init_normalize_crs_identifier = __esm({
114
+ "../../modules/tiles/src/spatial/normalize-crs-identifier.ts"() {
115
+ "use strict";
116
+ WGS84_GEOGRAPHIC_CRS = "EPSG:4326";
117
+ WGS84_GEOCENTRIC_CRS = "EPSG:4978";
118
+ }
119
+ });
120
+
121
+ // ../../modules/tiles/src/spatial/get-spatial-coordinate-frame.ts
122
+ import {
123
+ inferCRSRepresentation,
124
+ parsePROJString,
125
+ parseWKTCRS
126
+ } from "@math.gl/crs";
127
+ function getSpatialCoordinateFrame(definition) {
128
+ if (typeof definition === "string") {
129
+ const representation = inferCRSRepresentation(definition);
130
+ if (representation === "wkt") {
131
+ return getWktCoordinateFrame(definition);
132
+ }
133
+ if (representation === "proj-string") {
134
+ return getProjStringCoordinateFrame(definition);
135
+ }
136
+ return getKnownCrsIdentifierCoordinateFrame(definition) || "projected";
137
+ }
138
+ const projJsonDefinition = definition;
139
+ if (projJsonDefinition.type === "BoundCRS" && projJsonDefinition.source_crs) {
140
+ return getSpatialCoordinateFrame(projJsonDefinition.source_crs);
141
+ }
142
+ if (projJsonDefinition.type === "CompoundCRS" && projJsonDefinition.components?.[0]) {
143
+ return getSpatialCoordinateFrame(projJsonDefinition.components[0]);
144
+ }
145
+ if (String(projJsonDefinition.type).includes("Projected")) {
146
+ return "projected";
147
+ }
148
+ if (String(projJsonDefinition.type).includes("Geographic")) {
149
+ return "geographic";
150
+ }
151
+ if (String(projJsonDefinition.type).includes("Geodetic")) {
152
+ return projJsonDefinition.coordinate_system?.subtype === "Cartesian" ? "geocentric" : "geographic";
153
+ }
154
+ return "unknown";
155
+ }
156
+ function getKnownCrsIdentifierCoordinateFrame(definition) {
157
+ if (typeof definition !== "string") {
158
+ return void 0;
159
+ }
160
+ const normalized = normalizeCrsIdentifier(definition);
161
+ if (normalized === WGS84_GEOCENTRIC_CRS) {
162
+ return "geocentric";
163
+ }
164
+ if (normalized === WGS84_GEOGRAPHIC_CRS || normalized === "OGC:CRS84") {
165
+ return "geographic";
166
+ }
167
+ const epsgMatch = /^EPSG:(\d+)$/.exec(normalized);
168
+ if (!epsgMatch) {
169
+ return void 0;
170
+ }
171
+ const identifier = Number(epsgMatch[1]);
172
+ if (identifier === 7789) {
173
+ return "geocentric";
174
+ }
175
+ if (identifier === 4490 || identifier === 4979) {
176
+ return "geographic";
177
+ }
178
+ if (identifier === 3857 || identifier >= 32601 && identifier <= 32660 || identifier >= 32701 && identifier <= 32760) {
179
+ return "projected";
180
+ }
181
+ return void 0;
182
+ }
183
+ function getWktCoordinateFrame(definition) {
184
+ let root;
185
+ try {
186
+ root = parseWKTCRS(definition).root;
187
+ } catch {
188
+ return "unknown";
189
+ }
190
+ switch (root.keyword.toUpperCase()) {
191
+ case "GEOCCS":
192
+ return "geocentric";
193
+ case "GEOGCS":
194
+ case "GEOGCRS":
195
+ case "GEOGRAPHICCRS":
196
+ case "GEOGRAPHIC2DCRS":
197
+ case "GEOGRAPHIC3DCRS":
198
+ return "geographic";
199
+ case "PROJCS":
200
+ case "PROJCRS":
201
+ case "PROJECTEDCRS":
202
+ return "projected";
203
+ case "GEODCRS":
204
+ case "GEODETICCRS": {
205
+ const coordinateSystem = root.values.find(
206
+ (value) => value.type === "node" && value.keyword.toUpperCase() === "CS"
207
+ );
208
+ const subtype = coordinateSystem?.values[0];
209
+ if (subtype?.type !== "enumeration" && subtype?.type !== "string") {
210
+ return "unknown";
211
+ }
212
+ return subtype.value.toUpperCase() === "CARTESIAN" ? "geocentric" : subtype.value.toUpperCase() === "ELLIPSOIDAL" ? "geographic" : "unknown";
213
+ }
214
+ default:
215
+ return "unknown";
216
+ }
217
+ }
218
+ function getProjStringCoordinateFrame(definition) {
219
+ try {
220
+ const projection = parsePROJString(definition).parameters.find(
221
+ (parameter) => parameter.name.toLowerCase() === "proj"
222
+ )?.value;
223
+ switch (projection?.toLowerCase()) {
224
+ case "longlat":
225
+ case "latlong":
226
+ return "geographic";
227
+ case "geocent":
228
+ return "geocentric";
229
+ default:
230
+ return projection ? "projected" : "unknown";
231
+ }
232
+ } catch {
233
+ return "unknown";
234
+ }
235
+ }
236
+ var init_get_spatial_coordinate_frame = __esm({
237
+ "../../modules/tiles/src/spatial/get-spatial-coordinate-frame.ts"() {
238
+ "use strict";
239
+ init_normalize_crs_identifier();
240
+ }
241
+ });
242
+
243
+ // ../../modules/tiles/src/spatial/spatial-types.ts
244
+ import {
245
+ createSpatialReference,
246
+ inferCRSRepresentation as inferCRSRepresentation2
247
+ } from "@math.gl/crs";
248
+ function createTilesetSpatialReference(discovered, options = {}) {
249
+ const hasSourceCrsOverride = options.sourceCrs !== void 0;
250
+ const sourceCrs = options.sourceCrs || discovered.sourceCrs;
251
+ const outputCoordinates = options.outputCoordinates || "auto";
252
+ const targetCrs = options.targetCrs || (outputCoordinates === "ecef" ? "EPSG:4978" : void 0);
253
+ const targetHeightReference = options.targetHeightReference || "native";
254
+ const verticalUnitScale = discovered.verticalUnitScale ?? 1;
255
+ const elevationUnitScale = discovered.elevationUnitScale ?? 1;
256
+ const elevationOffset = discovered.elevationOffset || 0;
257
+ const requiresSurface = discovered.elevationMode === "onTheGround" || discovered.elevationMode === "relativeToGround" || discovered.elevationMode === "relativeToScene";
258
+ const hasElevationProvider = discovered.elevationMode === "relativeToScene" ? Boolean(options.sceneElevationProvider) : !requiresSurface || Boolean(options.terrainElevationProvider);
259
+ const hasFormatVerticalOperation = verticalUnitScale !== 1 || elevationUnitScale !== 1 || discovered.elevationMode !== void 0 && (requiresSurface || discovered.elevationMode === "absoluteHeight" && elevationOffset !== 0);
260
+ const needsHeightTransform = targetHeightReference !== "native" && targetHeightReference !== discovered.heightReference;
261
+ const hasRequestedTransform = Boolean(targetCrs) || targetHeightReference !== "native" || outputCoordinates !== "auto" || hasFormatVerticalOperation;
262
+ const hasRequiredTarget = outputCoordinates !== "target-crs" || Boolean(targetCrs);
263
+ const hasHeightMetadata = !needsHeightTransform || (discovered.heightReference || "unknown") !== "unknown";
264
+ const hasVerticalUnits = Number.isFinite(verticalUnitScale) && verticalUnitScale > 0 && Number.isFinite(elevationUnitScale) && elevationUnitScale > 0;
265
+ const canTransform = Boolean(sourceCrs) && hasRequestedTransform && hasRequiredTarget && hasHeightMetadata && hasVerticalUnits && hasElevationProvider && outputCoordinates !== "local-enu";
266
+ const provenance = hasSourceCrsOverride ? "caller-override" : discovered.provenance || "unknown";
267
+ const coordinateFrame = hasSourceCrsOverride && sourceCrs ? getSpatialCoordinateFrame(sourceCrs) : discovered.coordinateFrame;
268
+ const sourceCrsState = hasSourceCrsOverride ? "explicit" : discovered.sourceCrsState || (sourceCrs ? provenance === "format-default" ? "default" : "explicit" : "absent");
269
+ const spatialReference = createSpatialReference({
270
+ crs: sourceCrs ? {
271
+ state: sourceCrsState === "default" ? "default" : "explicit",
272
+ definition: sourceCrs,
273
+ representation: !hasSourceCrsOverride && discovered.sourceCrsRepresentation || inferCRSRepresentation2(sourceCrs),
274
+ provenance,
275
+ alternatives: hasSourceCrsOverride ? void 0 : discovered.sourceCrsAlternatives
276
+ } : {
277
+ state: sourceCrsState === "unknown" ? "unknown" : "absent",
278
+ provenance
279
+ },
280
+ vertical: discovered.verticalCrs ? {
281
+ state: "explicit",
282
+ definition: discovered.verticalCrs,
283
+ representation: inferCRSRepresentation2(discovered.verticalCrs),
284
+ provenance: discovered.provenance || "metadata"
285
+ } : void 0,
286
+ coordinateEpoch: options.coordinateEpoch ?? discovered.coordinateEpoch,
287
+ coordinateFrame,
288
+ coordinateOrder: getCoordinateOrder(discovered.axisOrder),
289
+ units: hasSourceCrsOverride ? void 0 : discovered.units
290
+ });
291
+ const normalizedSourceCrs = getKnownCRSDefinition(spatialReference.crs);
292
+ const normalizedVerticalCrs = spatialReference.vertical ? getKnownCRSDefinition(spatialReference.vertical) : void 0;
293
+ const normalizedTargetCrs = targetCrs ? cloneReadonlyCRSDefinition(targetCrs) : void 0;
294
+ return Object.freeze({
295
+ ...spatialReference,
296
+ sourceCrs: normalizedSourceCrs,
297
+ verticalCrs: normalizedVerticalCrs,
298
+ verticalUnitScale,
299
+ coordinateEpoch: options.coordinateEpoch ?? discovered.coordinateEpoch,
300
+ heightReference: discovered.heightReference || "unknown",
301
+ elevationMode: discovered.elevationMode,
302
+ elevationOffset: discovered.elevationOffset,
303
+ elevationUnit: discovered.elevationUnit,
304
+ elevationUnitScale,
305
+ coordinateFrame: coordinateFrame || "unknown",
306
+ axisOrder: discovered.axisOrder || "unknown",
307
+ provenance,
308
+ targetCrs: normalizedTargetCrs,
309
+ targetHeightReference,
310
+ outputCoordinates,
311
+ status: hasRequestedTransform ? canTransform ? "transformable" : "unresolved" : "native",
312
+ warnings: Object.freeze([...discovered.warnings || []])
313
+ });
314
+ }
315
+ function getKnownCRSDefinition(reference) {
316
+ return reference.state === "explicit" || reference.state === "default" ? reference.definition : void 0;
317
+ }
318
+ function cloneReadonlyCRSDefinition(definition) {
319
+ const spatialReference = createSpatialReference({
320
+ crs: {
321
+ state: "explicit",
322
+ definition,
323
+ representation: inferCRSRepresentation2(definition),
324
+ provenance: "caller-override"
325
+ }
326
+ });
327
+ const clonedDefinition = getKnownCRSDefinition(spatialReference.crs);
328
+ if (!clonedDefinition) {
329
+ throw new Error("Failed to normalize a known target CRS definition");
330
+ }
331
+ return clonedDefinition;
332
+ }
333
+ function getCoordinateOrder(axisOrder) {
334
+ switch (axisOrder) {
335
+ case "xy":
336
+ return ["x", "y"];
337
+ case "yx":
338
+ return ["y", "x"];
339
+ case "xyz":
340
+ return ["x", "y", "z"];
341
+ default:
342
+ return [];
343
+ }
344
+ }
345
+ function markTilesetSpatialReferenceTransformed(spatialReference) {
346
+ if (spatialReference.status !== "transformable" && spatialReference.status !== "transformed") {
347
+ throw new Error("Only a transformable spatial reference can be marked as transformed");
348
+ }
349
+ return Object.freeze({ ...spatialReference, status: "transformed" });
350
+ }
351
+ var init_spatial_types = __esm({
352
+ "../../modules/tiles/src/spatial/spatial-types.ts"() {
353
+ "use strict";
354
+ init_get_spatial_coordinate_frame();
355
+ }
356
+ });
357
+
358
+ // ../../modules/tiles/src/tileset-3d/common/tileset-content-traversal.ts
359
+ async function* traverseTilesetContents(tileset, options = {}) {
360
+ await tileset.tilesetInitializationPromise;
361
+ throwIfAborted2(options.signal);
362
+ if (!tileset.root) {
363
+ throw new Error("Tileset initialization completed without a root tile");
364
+ }
365
+ const stack = [tileset.root];
366
+ const visitedTiles = /* @__PURE__ */ new Set();
367
+ while (stack.length > 0) {
368
+ throwIfAborted2(options.signal);
369
+ const tile = stack.pop();
370
+ if (visitedTiles.has(tile)) {
371
+ continue;
372
+ }
373
+ visitedTiles.add(tile);
374
+ if (tile.header.implicitSubtree && tile.childrenState !== "ready") {
375
+ const loadChildren = tileset.source.loadTileChildrenForTraversal;
376
+ if (!loadChildren) {
377
+ throw new Error("Tileset source does not support camera-independent subtree loading");
378
+ }
379
+ const result = await loadChildren.call(tileset.source, tile, options.signal);
380
+ if (!result.loaded) {
381
+ throw new Error(`Unable to load implicit subtree for tile ${tile.id}`);
382
+ }
383
+ tile.childrenState = "ready";
384
+ }
385
+ if (tileset.type === "I3S" /* I3S */ && tileset.source.loadTileChildrenForTraversal) {
386
+ const result = await tileset.source.loadTileChildrenForTraversal(tile, options.signal);
387
+ if (!result.loaded) {
388
+ throw new Error(`Unable to load I3S child nodes for tile ${tile.id}`);
389
+ }
390
+ }
391
+ throwIfAborted2(options.signal);
392
+ const loadsContent = tile.contentUrls.length > 0 && !tile.content;
393
+ try {
394
+ if (loadsContent) {
395
+ const loadResult = await tile.loadContentForTraversal();
396
+ throwIfAborted2(options.signal);
397
+ if (!loadResult.loaded) {
398
+ throw new Error(`Unable to load tile content for tile ${tile.id}`);
399
+ }
400
+ tileset.source.onTileLoaded?.(tileset, tile, loadResult);
401
+ }
402
+ yield { tile, contents: tile.contentEntries };
403
+ } finally {
404
+ if (options.unloadContent && loadsContent) {
405
+ tile.unloadContent();
406
+ }
407
+ }
408
+ for (let childIndex = tile.children.length - 1; childIndex >= 0; childIndex--) {
409
+ stack.push(tile.children[childIndex]);
410
+ }
411
+ }
412
+ }
413
+ function throwIfAborted2(signal) {
414
+ if (signal?.aborted) {
415
+ throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
416
+ }
417
+ }
418
+ var init_tileset_content_traversal = __esm({
419
+ "../../modules/tiles/src/tileset-3d/common/tileset-content-traversal.ts"() {
420
+ "use strict";
421
+ }
422
+ });
423
+
424
+ // ../../modules/tiles/src/spatial/i3s-elevation.ts
425
+ function getI3SLinearUnitScale(unit) {
426
+ if (!unit) {
427
+ return void 0;
428
+ }
429
+ const normalized = unit.trim().toLowerCase().replaceAll("_", "-");
430
+ const canonical = LINEAR_UNIT_ALIASES[normalized] || normalized;
431
+ return LINEAR_UNIT_TO_METERS[canonical];
432
+ }
433
+ var LINEAR_UNIT_TO_METERS, LINEAR_UNIT_ALIASES;
434
+ var init_i3s_elevation = __esm({
435
+ "../../modules/tiles/src/spatial/i3s-elevation.ts"() {
436
+ "use strict";
437
+ LINEAR_UNIT_TO_METERS = Object.freeze({
438
+ meter: 1,
439
+ millimeter: 1e-3,
440
+ centimeter: 0.01,
441
+ decimeter: 0.1,
442
+ kilometer: 1e3,
443
+ foot: 0.3048,
444
+ yard: 0.9144,
445
+ mile: 1609.344,
446
+ "us-foot": 1200 / 3937,
447
+ "us-inch": 0.0254000508001016,
448
+ "us-yard": 3600 / 3937,
449
+ "us-mile": 6336e3 / 3937,
450
+ "clarke-foot": 0.3047972654,
451
+ "clarke-yard": 0.9143917962,
452
+ "clarke-link": 0.201166195164,
453
+ "sears-yard": 0.914398414616,
454
+ "sears-foot": 0.304799471539,
455
+ "sears-chain": 20.1167651216,
456
+ "sears-1922-truncated-chain": 20.116756,
457
+ "benoit-1895-b-chain": 20.1167824944,
458
+ "indian-yard": 0.914398530744,
459
+ "indian-1937-yard": 0.91439523,
460
+ "gold-coast-foot": 0.304799710181
461
+ });
462
+ LINEAR_UNIT_ALIASES = Object.freeze({
463
+ m: "meter",
464
+ metre: "meter",
465
+ meters: "meter",
466
+ metres: "meter",
467
+ mm: "millimeter",
468
+ millimetre: "millimeter",
469
+ millimeters: "millimeter",
470
+ millimetres: "millimeter",
471
+ cm: "centimeter",
472
+ centimetre: "centimeter",
473
+ centimeters: "centimeter",
474
+ centimetres: "centimeter",
475
+ dm: "decimeter",
476
+ decimetre: "decimeter",
477
+ decimeters: "decimeter",
478
+ decimetres: "decimeter",
479
+ km: "kilometer",
480
+ kilometre: "kilometer",
481
+ kilometers: "kilometer",
482
+ kilometres: "kilometer",
483
+ ft: "foot",
484
+ feet: "foot",
485
+ "us-survey-foot": "us-foot",
486
+ "us-survey-feet": "us-foot",
487
+ yd: "yard",
488
+ yards: "yard",
489
+ mi: "mile",
490
+ miles: "mile"
491
+ });
492
+ }
493
+ });
494
+
495
+ // ../../modules/tiles/src/spatial/spatial-resource-registry.ts
496
+ import { parsePGM } from "@math.gl/geoid";
497
+ import { Projection } from "@math.gl/proj4";
498
+ function getGeoidModel(name) {
499
+ return geoidModels.get(name);
500
+ }
501
+ var geoidModels;
502
+ var init_spatial_resource_registry = __esm({
503
+ "../../modules/tiles/src/spatial/spatial-resource-registry.ts"() {
504
+ "use strict";
505
+ geoidModels = /* @__PURE__ */ new Map();
506
+ }
507
+ });
508
+
509
+ // ../../modules/tiles/src/spatial/spatial-coordinate-transformer.ts
510
+ import { Vector3 } from "@math.gl/core";
511
+ import { Ellipsoid } from "@math.gl/geospatial";
512
+ import { Projection as Projection2 } from "@math.gl/proj4";
513
+ function getFiniteDifferenceJacobian(transformer, position, epsilon) {
514
+ const columns = [];
515
+ for (let axis = 0; axis < 3; axis++) {
516
+ const plus = position.slice();
517
+ const minus = position.slice();
518
+ plus[axis] += epsilon;
519
+ minus[axis] -= epsilon;
520
+ const plusPosition = transformer.transformPosition(plus);
521
+ const minusPosition = transformer.transformPosition(minus);
522
+ columns.push([
523
+ (plusPosition[0] - minusPosition[0]) / (2 * epsilon),
524
+ (plusPosition[1] - minusPosition[1]) / (2 * epsilon),
525
+ (plusPosition[2] - minusPosition[2]) / (2 * epsilon)
526
+ ]);
527
+ }
528
+ return columns;
529
+ }
530
+ function inverseTransposeMultiply(jacobianColumns, vector) {
531
+ const [a, b, c] = jacobianColumns;
532
+ const determinant = a[0] * (b[1] * c[2] - b[2] * c[1]) - b[0] * (a[1] * c[2] - a[2] * c[1]) + c[0] * (a[1] * b[2] - a[2] * b[1]);
533
+ if (!Number.isFinite(determinant) || Math.abs(determinant) < 1e-15) {
534
+ return vector;
535
+ }
536
+ const inverseTranspose = [
537
+ [b[1] * c[2] - b[2] * c[1], a[2] * c[1] - a[1] * c[2], a[1] * b[2] - a[2] * b[1]],
538
+ [b[2] * c[0] - b[0] * c[2], a[0] * c[2] - a[2] * c[0], a[2] * b[0] - a[0] * b[2]],
539
+ [b[0] * c[1] - b[1] * c[0], a[1] * c[0] - a[0] * c[1], a[0] * b[1] - a[1] * b[0]]
540
+ ];
541
+ return inverseTranspose.map(
542
+ (row) => (row[0] * vector[0] + row[1] * vector[1] + row[2] * vector[2]) / determinant
543
+ );
544
+ }
545
+ function getHorizontalProj4Definition(definition) {
546
+ if (!definition) {
547
+ throw new Error("Cannot construct a projection because the CRS is unknown");
548
+ }
549
+ if (typeof definition !== "string" && definition.type === "CompoundCRS") {
550
+ const horizontalComponents = definition.components.filter(
551
+ (component) => component.type !== "VerticalCRS"
552
+ );
553
+ if (horizontalComponents.length !== 1) {
554
+ throw new Error("CompoundCRS requires exactly one horizontal component");
555
+ }
556
+ return getHorizontalProj4Definition(horizontalComponents[0]);
557
+ }
558
+ return definition;
559
+ }
560
+ function validateTransformRequest(spatialReference) {
561
+ if (spatialReference.outputCoordinates === "local-enu") {
562
+ throw new Error(
563
+ "local-enu output requires a dataset-derived local origin and must be created by a tileset source"
564
+ );
565
+ }
566
+ if (spatialReference.outputCoordinates === "target-crs" && !spatialReference.targetCrs) {
567
+ throw new Error("target-crs output requires targetCrs");
568
+ }
569
+ if (!spatialReference.sourceCrs && spatialReference.status === "unresolved") {
570
+ throw new Error("Cannot transform coordinates because the source CRS is unknown");
571
+ }
572
+ if (requiresHeightTransformation(spatialReference) && spatialReference.heightReference === "unknown") {
573
+ throw new Error("Cannot convert heights because the source height reference is unknown");
574
+ }
575
+ if (spatialReference.coordinateFrame === "geocentric" && !isWgs84Geocentric(spatialReference.sourceCrs)) {
576
+ throw new Error(
577
+ "Only EPSG:4978 geocentric coordinates are supported by the current spatial transformer"
578
+ );
579
+ }
580
+ if (spatialReference.status === "unresolved") {
581
+ throw new Error("The requested spatial output cannot be resolved from the available metadata");
582
+ }
583
+ }
584
+ function isWgs84Geocentric(definition) {
585
+ return typeof definition === "string" && normalizeCrsIdentifier(definition) === WGS84_GEOCENTRIC_CRS;
586
+ }
587
+ function isWgs84Geographic(definition) {
588
+ if (typeof definition !== "string") {
589
+ return false;
590
+ }
591
+ const identifier = normalizeCrsIdentifier(definition);
592
+ return identifier === WGS84_GEOGRAPHIC_CRS || identifier === "EPSG:4979" || identifier === "OGC:CRS84";
593
+ }
594
+ function requiresHeightTransformation(spatialReference) {
595
+ const target = spatialReference.targetHeightReference;
596
+ return target !== "native" && target !== spatialReference.heightReference;
597
+ }
598
+ function resolveGeoid(model) {
599
+ return typeof model === "string" ? getGeoidModel(model) : model;
600
+ }
601
+ function transformHeight(height, geoidUndulation, source, target) {
602
+ if (source === target || target === "native") {
603
+ return height;
604
+ }
605
+ if (source === "orthometric" && target === "ellipsoidal") {
606
+ return height + geoidUndulation;
607
+ }
608
+ if (source === "ellipsoidal" && target === "orthometric") {
609
+ return height - geoidUndulation;
610
+ }
611
+ throw new Error(`Unsupported height conversion from ${source} to ${target}`);
612
+ }
613
+ var SpatialCoordinateTransformer;
614
+ var init_spatial_coordinate_transformer = __esm({
615
+ "../../modules/tiles/src/spatial/spatial-coordinate-transformer.ts"() {
616
+ "use strict";
617
+ init_spatial_resource_registry();
618
+ init_normalize_crs_identifier();
619
+ init_get_spatial_coordinate_frame();
620
+ SpatialCoordinateTransformer = class {
621
+ /** Normalized spatial metadata describing this transformation. */
622
+ spatialReference;
623
+ /** Projection from the source CRS directly to the requested horizontal target CRS. */
624
+ horizontalProjection;
625
+ /** Projection from the source CRS to geographic longitude, latitude, and ellipsoidal height. */
626
+ geographicProjection;
627
+ /** Projection from adjusted geographic coordinates to the requested output CRS. */
628
+ heightOutputProjection;
629
+ /** Whether source coordinates use the WGS84 geocentric frame handled by math.gl. */
630
+ sourceIsGeocentric;
631
+ /** Whether output coordinates use the WGS84 geocentric frame handled by math.gl. */
632
+ outputIsGeocentric;
633
+ /** Whether source coordinates already use conventional WGS84 longitude/latitude order. */
634
+ sourceIsGeographic;
635
+ /** Whether output coordinates use conventional WGS84 longitude/latitude order. */
636
+ outputIsGeographic;
637
+ /** Geoid model used to convert between ellipsoidal and orthometric heights. */
638
+ geoid;
639
+ /**
640
+ * Creates a coordinate transformer.
641
+ *
642
+ * @param spatialReference - Format-discovered and option-normalized spatial metadata.
643
+ * @param options - Application options containing an optional geoid model.
644
+ */
645
+ constructor(spatialReference, options = {}) {
646
+ this.spatialReference = spatialReference;
647
+ validateTransformRequest(spatialReference);
648
+ const outputCrs = spatialReference.targetCrs || spatialReference.sourceCrs;
649
+ this.sourceIsGeocentric = isWgs84Geocentric(spatialReference.sourceCrs);
650
+ this.outputIsGeocentric = isWgs84Geocentric(outputCrs);
651
+ this.sourceIsGeographic = isWgs84Geographic(spatialReference.sourceCrs);
652
+ this.outputIsGeographic = isWgs84Geographic(outputCrs);
653
+ if (spatialReference.sourceCrs && spatialReference.targetCrs && !this.sourceIsGeocentric && !this.outputIsGeocentric) {
654
+ this.horizontalProjection = new Projection2({
655
+ from: getHorizontalProj4Definition(spatialReference.sourceCrs),
656
+ to: getHorizontalProj4Definition(spatialReference.targetCrs),
657
+ enforceAxis: false
658
+ });
659
+ }
660
+ if (requiresHeightTransformation(spatialReference) || this.sourceIsGeocentric || this.outputIsGeocentric) {
661
+ if (!this.sourceIsGeographic && !this.sourceIsGeocentric) {
662
+ this.geographicProjection = new Projection2({
663
+ from: getHorizontalProj4Definition(spatialReference.sourceCrs),
664
+ to: WGS84_GEOGRAPHIC_CRS,
665
+ enforceAxis: false
666
+ });
667
+ }
668
+ if (!this.outputIsGeographic && !this.outputIsGeocentric) {
669
+ this.heightOutputProjection = new Projection2({
670
+ from: WGS84_GEOGRAPHIC_CRS,
671
+ to: getHorizontalProj4Definition(outputCrs),
672
+ enforceAxis: false
673
+ });
674
+ }
675
+ }
676
+ if (requiresHeightTransformation(spatialReference)) {
677
+ this.geoid = resolveGeoid(options.geoidModel);
678
+ if (!this.geoid) {
679
+ const modelName = typeof options.geoidModel === "string" ? ` "${options.geoidModel}"` : "";
680
+ throw new Error(
681
+ `Height conversion requires a registered geoid model${modelName}; call registerGeoidModel() or pass a parsed Geoid instance`
682
+ );
683
+ }
684
+ }
685
+ }
686
+ /**
687
+ * Transforms one `[x, y, z?]` coordinate while retaining additional components.
688
+ *
689
+ * @param coordinate - Source coordinate in the format adapter's normalized `x/y/z` order.
690
+ * @returns A new transformed coordinate array.
691
+ */
692
+ transformPosition(coordinate) {
693
+ if (coordinate.length < 2) {
694
+ throw new Error("A spatial coordinate must contain at least x and y components");
695
+ }
696
+ const result = [...coordinate];
697
+ if (requiresHeightTransformation(this.spatialReference) || this.sourceIsGeocentric || this.outputIsGeocentric) {
698
+ if (result.length < 3 || !Number.isFinite(result[2])) {
699
+ throw new Error("Three-dimensional CRS conversion requires a finite z coordinate");
700
+ }
701
+ const geographic = this.toGeographic(result);
702
+ if (requiresHeightTransformation(this.spatialReference)) {
703
+ const geoidUndulation = this.geoid.getHeight(geographic[1], geographic[0]);
704
+ geographic[2] = transformHeight(
705
+ geographic[2],
706
+ geoidUndulation,
707
+ this.spatialReference.heightReference,
708
+ this.spatialReference.targetHeightReference
709
+ );
710
+ }
711
+ const projected = this.fromGeographic(geographic);
712
+ result.splice(0, projected.length, ...projected);
713
+ return result;
714
+ }
715
+ if (this.horizontalProjection) {
716
+ const projected = this.horizontalProjection.project(result.slice(0, 3));
717
+ result.splice(0, projected.length, ...projected);
718
+ }
719
+ return result;
720
+ }
721
+ /** Transform a packed sequence of xyz positions, preserving the input array type only when safe. */
722
+ transformPositions(positions) {
723
+ if (positions.length % 3 !== 0) {
724
+ throw new Error("Packed spatial positions must contain a multiple of three components");
725
+ }
726
+ const transformedPositions = new Float64Array(positions.length);
727
+ for (let index = 0; index < positions.length; index += 3) {
728
+ const transformed = this.transformPosition([
729
+ Number(positions[index]),
730
+ Number(positions[index + 1]),
731
+ Number(positions[index + 2])
732
+ ]);
733
+ transformedPositions[index] = transformed[0];
734
+ transformedPositions[index + 1] = transformed[1];
735
+ transformedPositions[index + 2] = transformed[2];
736
+ }
737
+ return transformedPositions;
738
+ }
739
+ /** Transform packed xyz normals using a local finite-difference tangent approximation. */
740
+ transformNormals(normals, positions) {
741
+ if (normals.length !== positions.length || normals.length % 3 !== 0) {
742
+ throw new Error("Spatial normals and positions must have matching xyz component counts");
743
+ }
744
+ const transformedNormals = new Float32Array(normals.length);
745
+ const epsilon = 1e-5;
746
+ for (let index = 0; index < normals.length; index += 3) {
747
+ const position = [
748
+ Number(positions[index]),
749
+ Number(positions[index + 1]),
750
+ Number(positions[index + 2])
751
+ ];
752
+ const normal = [
753
+ Number(normals[index]),
754
+ Number(normals[index + 1]),
755
+ Number(normals[index + 2])
756
+ ];
757
+ const jacobian = getFiniteDifferenceJacobian(this, position, epsilon);
758
+ const transformedNormal = inverseTransposeMultiply(jacobian, normal);
759
+ const length = Math.hypot(...transformedNormal);
760
+ if (length > 0 && Number.isFinite(length)) {
761
+ transformedNormals[index] = transformedNormal[0] / length;
762
+ transformedNormals[index + 1] = transformedNormal[1] / length;
763
+ transformedNormals[index + 2] = transformedNormal[2] / length;
764
+ } else {
765
+ transformedNormals[index] = normal[0];
766
+ transformedNormals[index + 1] = normal[1];
767
+ transformedNormals[index + 2] = normal[2];
768
+ }
769
+ }
770
+ return transformedNormals;
771
+ }
772
+ /** Convert one source coordinate to conventional WGS84 longitude, latitude, and height. */
773
+ toGeographic(coordinate) {
774
+ if (this.sourceIsGeocentric) {
775
+ return Array.from(Ellipsoid.WGS84.cartesianToCartographic(new Vector3(coordinate)));
776
+ }
777
+ if (this.sourceIsGeographic) {
778
+ return coordinate.slice(0, 3);
779
+ }
780
+ return this.geographicProjection.project(coordinate.slice(0, 3));
781
+ }
782
+ /** Convert one conventional WGS84 geographic coordinate to the selected output CRS. */
783
+ fromGeographic(coordinate) {
784
+ if (this.outputIsGeocentric) {
785
+ return Array.from(Ellipsoid.WGS84.cartographicToCartesian(new Vector3(coordinate)));
786
+ }
787
+ if (this.outputIsGeographic) {
788
+ return coordinate.slice(0, 3);
789
+ }
790
+ return this.heightOutputProjection.project(coordinate.slice(0, 3));
791
+ }
792
+ };
793
+ }
794
+ });
795
+
796
+ // ../../modules/tiles/src/spatial/tiles-3d-spatial-transformer.ts
797
+ import { Matrix4 } from "@math.gl/core";
798
+ import { Ellipsoid as Ellipsoid2 } from "@math.gl/geospatial";
799
+ function getRegionSamples(region) {
800
+ if (region.length < 6 || region.some((value) => !Number.isFinite(value))) {
801
+ return [];
802
+ }
803
+ const [west, south, east, north, minimumHeight, maximumHeight] = region;
804
+ const longitudeEnd = east < west ? east + Math.PI * 2 : east;
805
+ const longitudes = getIntervalSamples(west, longitudeEnd);
806
+ const latitudes = getIntervalSamples(south, north);
807
+ const samples = [];
808
+ for (const longitude of longitudes) {
809
+ for (const latitude of latitudes) {
810
+ for (const height of [minimumHeight, maximumHeight]) {
811
+ samples.push([longitude * 180 / Math.PI, latitude * 180 / Math.PI, height]);
812
+ }
813
+ }
814
+ }
815
+ return samples;
816
+ }
817
+ function getIntervalSamples(start, end) {
818
+ const samples = [start, (start + end) / 2, end];
819
+ const angularStep = Math.PI / 2;
820
+ const firstCriticalIndex = Math.ceil(start / angularStep);
821
+ const lastCriticalIndex = Math.floor(end / angularStep);
822
+ for (let criticalIndex = firstCriticalIndex; criticalIndex <= lastCriticalIndex; criticalIndex++) {
823
+ samples.push(criticalIndex * angularStep);
824
+ }
825
+ return samples;
826
+ }
827
+ function getVolumeSamples(volume) {
828
+ if (volume.box && volume.box.length >= 12) {
829
+ const center = volume.box.slice(0, 3);
830
+ const axes = [volume.box.slice(3, 6), volume.box.slice(6, 9), volume.box.slice(9, 12)];
831
+ const samples = [];
832
+ for (let firstIndex = 0; firstIndex <= 4; firstIndex++) {
833
+ for (let secondIndex = 0; secondIndex <= 4; secondIndex++) {
834
+ for (let thirdIndex = 0; thirdIndex <= 4; thirdIndex++) {
835
+ const first = firstIndex / 2 - 1;
836
+ const second = secondIndex / 2 - 1;
837
+ const third = thirdIndex / 2 - 1;
838
+ samples.push([
839
+ center[0] + first * axes[0][0] + second * axes[1][0] + third * axes[2][0],
840
+ center[1] + first * axes[0][1] + second * axes[1][1] + third * axes[2][1],
841
+ center[2] + first * axes[0][2] + second * axes[1][2] + third * axes[2][2]
842
+ ]);
843
+ }
844
+ }
845
+ }
846
+ return samples;
847
+ }
848
+ if (volume.sphere && volume.sphere.length >= 4) {
849
+ const [x, y, z, radius] = volume.sphere;
850
+ const samples = [
851
+ [x - radius, y, z],
852
+ [x + radius, y, z],
853
+ [x, y - radius, z],
854
+ [x, y + radius, z],
855
+ [x, y, z - radius],
856
+ [x, y, z + radius]
857
+ ];
858
+ for (let longitudeIndex = 0; longitudeIndex < 16; longitudeIndex++) {
859
+ const longitude = longitudeIndex * Math.PI * 2 / 16;
860
+ samples.push([x + radius * Math.cos(longitude), y + radius * Math.sin(longitude), z]);
861
+ }
862
+ return samples;
863
+ }
864
+ return [];
865
+ }
866
+ function createAxisAlignedBox(samples) {
867
+ const minimum = [Infinity, Infinity, Infinity];
868
+ const maximum = [-Infinity, -Infinity, -Infinity];
869
+ for (const sample of samples) {
870
+ for (let axis = 0; axis < 3; axis++) {
871
+ minimum[axis] = Math.min(minimum[axis], sample[axis]);
872
+ maximum[axis] = Math.max(maximum[axis], sample[axis]);
873
+ }
874
+ }
875
+ const padding = [
876
+ Math.max((maximum[0] - minimum[0]) * 0.01, 1e-9),
877
+ Math.max((maximum[1] - minimum[1]) * 0.01, 1e-9),
878
+ Math.max((maximum[2] - minimum[2]) * 0.01, 1e-9)
879
+ ];
880
+ const center = [
881
+ (minimum[0] + maximum[0]) / 2,
882
+ (minimum[1] + maximum[1]) / 2,
883
+ (minimum[2] + maximum[2]) / 2
884
+ ];
885
+ return [
886
+ ...center,
887
+ (maximum[0] - minimum[0]) / 2 + padding[0],
888
+ 0,
889
+ 0,
890
+ 0,
891
+ (maximum[1] - minimum[1]) / 2 + padding[1],
892
+ 0,
893
+ 0,
894
+ 0,
895
+ (maximum[2] - minimum[2]) / 2 + padding[2]
896
+ ];
897
+ }
898
+ var Tiles3DSpatialTransformer;
899
+ var init_tiles_3d_spatial_transformer = __esm({
900
+ "../../modules/tiles/src/spatial/tiles-3d-spatial-transformer.ts"() {
901
+ "use strict";
902
+ init_spatial_coordinate_transformer();
903
+ init_get_spatial_coordinate_frame();
904
+ Tiles3DSpatialTransformer = class {
905
+ /** Normalized reference describing the completed operation. */
906
+ spatialReference;
907
+ coordinateTransformer;
908
+ geographicCoordinateTransformer;
909
+ /** Creates a 3D Tiles transformer for a requested target CRS. */
910
+ constructor(spatialReference, options = {}) {
911
+ this.coordinateTransformer = new SpatialCoordinateTransformer(spatialReference, options);
912
+ const geographicSpatialReference = {
913
+ ...spatialReference,
914
+ sourceCrs: "EPSG:4326",
915
+ targetCrs: spatialReference.targetCrs || spatialReference.sourceCrs,
916
+ coordinateFrame: "geographic",
917
+ axisOrder: "xy"
918
+ };
919
+ this.geographicCoordinateTransformer = new SpatialCoordinateTransformer(
920
+ geographicSpatialReference,
921
+ options
922
+ );
923
+ this.spatialReference = spatialReference;
924
+ }
925
+ /** Transform packed POSITION values into the target CRS. */
926
+ transformPositions(positions) {
927
+ return this.coordinateTransformer.transformPositions(positions);
928
+ }
929
+ /** Transform packed NORMAL values using the corresponding source positions. */
930
+ transformNormals(normals, positions) {
931
+ return this.coordinateTransformer.transformNormals(normals, positions);
932
+ }
933
+ /** Rebuild a conservative target-frame volume from a source volume. */
934
+ transformBoundingVolume(volume, sourceTransform) {
935
+ const transform = sourceTransform ? new Matrix4(Array.from(sourceTransform)) : void 0;
936
+ const samples = volume.region ? getRegionSamples(volume.region) : getVolumeSamples(volume).map(
937
+ (sample) => transform ? Array.from(transform.transformAsPoint(sample)) : sample
938
+ );
939
+ if (!samples.length) {
940
+ return volume;
941
+ }
942
+ const transformed = volume.region ? samples.map((sample) => this.transformRegionSample(sample)) : samples.map((sample) => this.coordinateTransformer.transformPosition(sample));
943
+ return { box: createAxisAlignedBox(transformed) };
944
+ }
945
+ /** Transforms one WGS84 region sample into the selected output frame. */
946
+ transformRegionSample(sample) {
947
+ const [longitudeDegrees, latitudeDegrees, height] = sample;
948
+ const targetCrs = this.spatialReference.targetCrs || this.spatialReference.sourceCrs;
949
+ if (targetCrs && getSpatialCoordinateFrame(targetCrs) === "geocentric") {
950
+ const cartesian = Ellipsoid2.WGS84.cartographicToCartesian([
951
+ longitudeDegrees,
952
+ latitudeDegrees,
953
+ height
954
+ ]);
955
+ return Array.from(cartesian);
956
+ }
957
+ return this.geographicCoordinateTransformer.transformPosition(sample);
958
+ }
959
+ };
960
+ }
961
+ });
962
+
963
+ // ../../modules/tiles/src/spatial/i3s-spatial-transformer.ts
964
+ import { Matrix3, Matrix4 as Matrix42, Quaternion, Vector3 as Vector32 } from "@math.gl/core";
965
+ import { Ellipsoid as Ellipsoid3 } from "@math.gl/geospatial";
966
+ function getElevationProvider(mode, options) {
967
+ return mode === "relativeToScene" ? options.sceneElevationProvider : requiresElevationSurface(mode) ? options.terrainElevationProvider : void 0;
968
+ }
969
+ function requiresElevationSurface(mode) {
970
+ return mode === "onTheGround" || mode === "relativeToGround" || mode === "relativeToScene";
971
+ }
972
+ function toPositionArrays(positions) {
973
+ if (positions.length % 3 !== 0) {
974
+ throw new Error("I3S position arrays must contain complete XYZ tuples");
975
+ }
976
+ const result = [];
977
+ for (let index = 0; index < positions.length; index += 3) {
978
+ result.push([positions[index], positions[index + 1], positions[index + 2]]);
979
+ }
980
+ return result;
981
+ }
982
+ function getElevationBounds(geographicSamples) {
983
+ const region = getGeographicRegion(geographicSamples);
984
+ return {
985
+ west: region[0] * 180 / Math.PI,
986
+ south: region[1] * 180 / Math.PI,
987
+ east: region[2] * 180 / Math.PI,
988
+ north: region[3] * 180 / Math.PI
989
+ };
990
+ }
991
+ function getGeographicBoundingSphere(geographicSamples) {
992
+ if (!geographicSamples.length) {
993
+ throw new Error("I3S spatial transformation requires at least one bound sample");
994
+ }
995
+ const cartesianSamples = geographicSamples.map(
996
+ (position) => Ellipsoid3.WGS84.cartographicToCartesian(new Vector32(position))
997
+ );
998
+ const cartesianCenter = new Vector32();
999
+ for (const sample of cartesianSamples) {
1000
+ cartesianCenter.add(sample);
1001
+ }
1002
+ cartesianCenter.scale(1 / cartesianSamples.length);
1003
+ let radius = 0;
1004
+ for (const sample of cartesianSamples) {
1005
+ radius = Math.max(radius, new Vector32(sample).subtract(cartesianCenter).magnitude());
1006
+ }
1007
+ const geographicCenter = Ellipsoid3.WGS84.cartesianToCartographic(cartesianCenter);
1008
+ return [geographicCenter[0], geographicCenter[1], geographicCenter[2], radius];
1009
+ }
1010
+ function getSourceBoundSamples(bounds, sourceFrame, sourceToGeographicTransformer, sourceVerticalUnitScale) {
1011
+ const obb = bounds.obb;
1012
+ if (obb) {
1013
+ const center2 = Array.from(obb.center).slice(0, 3);
1014
+ center2[2] *= sourceVerticalUnitScale;
1015
+ const halfSize = Array.from(obb.halfSize).slice(0, 3);
1016
+ const quaternion = new Quaternion().fromArray(Array.from(obb.quaternion));
1017
+ const axes = [
1018
+ new Vector32([halfSize[0], 0, 0]).transformByQuaternion(quaternion),
1019
+ new Vector32([0, halfSize[1], 0]).transformByQuaternion(quaternion),
1020
+ new Vector32([0, 0, halfSize[2]]).transformByQuaternion(quaternion)
1021
+ ];
1022
+ if (sourceFrame === "geographic") {
1023
+ const geographicCenter = sourceToGeographicTransformer.transformPosition(center2);
1024
+ const cartesianCenter = Ellipsoid3.WGS84.cartographicToCartesian(
1025
+ new Vector32(geographicCenter)
1026
+ );
1027
+ const cartesianAxes = bounds.normalReferenceFrame === "vertex-reference-frame" ? axes.map((axis) => localEnuVectorToEcef(axis, geographicCenter)) : axes;
1028
+ return getBoxSigns().map((signs) => {
1029
+ const corner = new Vector32(cartesianCenter);
1030
+ for (let axisIndex = 0; axisIndex < 3; axisIndex++) {
1031
+ corner.add(new Vector32(cartesianAxes[axisIndex]).scale(signs[axisIndex]));
1032
+ }
1033
+ return Array.from(Ellipsoid3.WGS84.cartesianToCartographic(corner));
1034
+ });
1035
+ }
1036
+ return getBoxSigns().map((signs) => {
1037
+ const corner = new Vector32(center2);
1038
+ for (let axisIndex = 0; axisIndex < 3; axisIndex++) {
1039
+ corner.add(new Vector32(axes[axisIndex]).scale(signs[axisIndex]));
1040
+ }
1041
+ return Array.from(corner);
1042
+ });
1043
+ }
1044
+ const mbs = bounds.mbs ? Array.from(bounds.mbs) : [];
1045
+ if (mbs.length < 4) {
1046
+ return [];
1047
+ }
1048
+ const center = mbs.slice(0, 3);
1049
+ center[2] *= sourceVerticalUnitScale;
1050
+ const radius = mbs[3];
1051
+ if (sourceFrame === "geographic") {
1052
+ const geographicCenter = sourceToGeographicTransformer.transformPosition(center);
1053
+ const cartesianCenter = Ellipsoid3.WGS84.cartographicToCartesian(new Vector32(geographicCenter));
1054
+ return getAxisDirections().map(
1055
+ (direction) => Array.from(
1056
+ Ellipsoid3.WGS84.cartesianToCartographic(
1057
+ new Vector32(cartesianCenter).add(new Vector32(direction).scale(radius))
1058
+ )
1059
+ )
1060
+ );
1061
+ }
1062
+ return getAxisDirections().map(
1063
+ (direction) => Array.from(new Vector32(center).add(new Vector32(direction).scale(radius)))
1064
+ );
1065
+ }
1066
+ function getBoxSigns() {
1067
+ return [-1, 1].flatMap((x) => [-1, 1].flatMap((y) => [-1, 1].map((z) => [x, y, z])));
1068
+ }
1069
+ function getAxisDirections() {
1070
+ return [
1071
+ [1, 0, 0],
1072
+ [-1, 0, 0],
1073
+ [0, 1, 0],
1074
+ [0, -1, 0],
1075
+ [0, 0, 1],
1076
+ [0, 0, -1]
1077
+ ];
1078
+ }
1079
+ function getPositiveAxisDirections() {
1080
+ return [new Vector32([1, 0, 0]), new Vector32([0, 1, 0]), new Vector32([0, 0, 1])];
1081
+ }
1082
+ function localEnuVectorToEcef(vector, geographic) {
1083
+ const longitude = geographic[0] * Math.PI / 180;
1084
+ const latitude = geographic[1] * Math.PI / 180;
1085
+ const east = new Vector32([-Math.sin(longitude), Math.cos(longitude), 0]);
1086
+ const north = new Vector32([
1087
+ -Math.sin(latitude) * Math.cos(longitude),
1088
+ -Math.sin(latitude) * Math.sin(longitude),
1089
+ Math.cos(latitude)
1090
+ ]);
1091
+ const up = new Vector32([
1092
+ Math.cos(latitude) * Math.cos(longitude),
1093
+ Math.cos(latitude) * Math.sin(longitude),
1094
+ Math.sin(latitude)
1095
+ ]);
1096
+ return east.scale(vector[0]).add(north.scale(vector[1])).add(up.scale(vector[2]));
1097
+ }
1098
+ function ecefVectorToLocalEnu(vector, geographic) {
1099
+ const longitude = geographic[0] * Math.PI / 180;
1100
+ const latitude = geographic[1] * Math.PI / 180;
1101
+ const east = new Vector32([-Math.sin(longitude), Math.cos(longitude), 0]);
1102
+ const north = new Vector32([
1103
+ -Math.sin(latitude) * Math.cos(longitude),
1104
+ -Math.sin(latitude) * Math.sin(longitude),
1105
+ Math.cos(latitude)
1106
+ ]);
1107
+ const up = new Vector32([
1108
+ Math.cos(latitude) * Math.cos(longitude),
1109
+ Math.cos(latitude) * Math.sin(longitude),
1110
+ Math.sin(latitude)
1111
+ ]);
1112
+ return new Vector32([east.dot(vector), north.dot(vector), up.dot(vector)]);
1113
+ }
1114
+ function getAxisAlignedBox(positions) {
1115
+ const minimum = [Infinity, Infinity, Infinity];
1116
+ const maximum = [-Infinity, -Infinity, -Infinity];
1117
+ for (const position of positions) {
1118
+ for (let component = 0; component < 3; component++) {
1119
+ minimum[component] = Math.min(minimum[component], position[component]);
1120
+ maximum[component] = Math.max(maximum[component], position[component]);
1121
+ }
1122
+ }
1123
+ const center = minimum.map((value, index) => (value + maximum[index]) / 2);
1124
+ const halfSize = minimum.map((value, index) => (maximum[index] - value) / 2);
1125
+ return [center[0], center[1], center[2], halfSize[0], 0, 0, 0, halfSize[1], 0, 0, 0, halfSize[2]];
1126
+ }
1127
+ function getGeographicRegion(positions) {
1128
+ const referenceLongitude = positions[0][0];
1129
+ let minimumLongitude = Infinity;
1130
+ let maximumLongitude = -Infinity;
1131
+ let minimumLatitude = Infinity;
1132
+ let maximumLatitude = -Infinity;
1133
+ let minimumHeight = Infinity;
1134
+ let maximumHeight = -Infinity;
1135
+ for (const position of positions) {
1136
+ const longitude = referenceLongitude + normalizeLongitude(position[0] - referenceLongitude);
1137
+ minimumLongitude = Math.min(minimumLongitude, longitude);
1138
+ maximumLongitude = Math.max(maximumLongitude, longitude);
1139
+ minimumLatitude = Math.min(minimumLatitude, position[1]);
1140
+ maximumLatitude = Math.max(maximumLatitude, position[1]);
1141
+ minimumHeight = Math.min(minimumHeight, position[2]);
1142
+ maximumHeight = Math.max(maximumHeight, position[2]);
1143
+ }
1144
+ return [
1145
+ normalizeLongitude(minimumLongitude) * Math.PI / 180,
1146
+ minimumLatitude * Math.PI / 180,
1147
+ normalizeLongitude(maximumLongitude) * Math.PI / 180,
1148
+ maximumLatitude * Math.PI / 180,
1149
+ minimumHeight,
1150
+ maximumHeight
1151
+ ];
1152
+ }
1153
+ function normalizeLongitude(longitude) {
1154
+ return ((longitude + 180) % 360 + 360) % 360 - 180;
1155
+ }
1156
+ var I3SSpatialTransformer;
1157
+ var init_i3s_spatial_transformer = __esm({
1158
+ "../../modules/tiles/src/spatial/i3s-spatial-transformer.ts"() {
1159
+ "use strict";
1160
+ init_spatial_coordinate_transformer();
1161
+ init_spatial_types();
1162
+ init_i3s_elevation();
1163
+ I3SSpatialTransformer = class {
1164
+ /** Descriptor attached to output after all adapter-owned spatial values have been transformed. */
1165
+ spatialReference;
1166
+ /** Broad coordinate frame of the selected output CRS. */
1167
+ targetCoordinateFrame;
1168
+ /** Source-to-target position operation. */
1169
+ positionTransformer;
1170
+ /** Source-to-WGS84 geographic operation used for vector-frame conversion. */
1171
+ sourceToGeographicTransformer;
1172
+ /** WGS84-geographic-to-target operation used for normal finite differences. */
1173
+ geographicToTargetTransformer;
1174
+ /** Source frame recorded by I3S metadata. */
1175
+ sourceCoordinateFrame;
1176
+ /** Source Z multiplier that normalizes stored elevation values to meters. */
1177
+ sourceVerticalUnitScale;
1178
+ /** I3S elevation placement mode. */
1179
+ elevationMode;
1180
+ /** I3S elevation offset normalized to meters. */
1181
+ elevationOffset;
1182
+ /** Terrain or scene provider selected for the declared placement mode. */
1183
+ elevationProvider;
1184
+ /** Provider height multiplier that normalizes returned values to meters. */
1185
+ providerUnitScale;
1186
+ /** Optional provider-height to layer-height datum operation. */
1187
+ providerHeightTransformer;
1188
+ /**
1189
+ * Creates an I3S spatial adapter.
1190
+ *
1191
+ * @param spatialReference - Transformable I3S spatial descriptor.
1192
+ * @param options - Registered geoid and custom resource options used by the shared transformer.
1193
+ */
1194
+ constructor(spatialReference, options = {}) {
1195
+ if (spatialReference.status !== "transformable" && spatialReference.status !== "transformed") {
1196
+ throw new Error("I3SSpatialTransformer requires a requested, transformable spatial output");
1197
+ }
1198
+ const targetCrs = spatialReference.targetCrs || spatialReference.sourceCrs;
1199
+ if (!targetCrs) {
1200
+ throw new Error("I3S spatial transformation requires a target CRS");
1201
+ }
1202
+ this.positionTransformer = new SpatialCoordinateTransformer(spatialReference, options);
1203
+ this.sourceCoordinateFrame = spatialReference.coordinateFrame;
1204
+ this.sourceVerticalUnitScale = spatialReference.verticalUnitScale;
1205
+ this.elevationMode = spatialReference.elevationMode;
1206
+ this.elevationOffset = (spatialReference.elevationOffset || 0) * spatialReference.elevationUnitScale;
1207
+ this.elevationProvider = getElevationProvider(this.elevationMode, options);
1208
+ if (this.elevationProvider && (typeof this.elevationProvider.sampleElevations !== "function" || typeof this.elevationProvider.getElevationRange !== "function")) {
1209
+ throw new Error(
1210
+ "An I3S elevation provider must implement sampleElevations() and getElevationRange()"
1211
+ );
1212
+ }
1213
+ const providerUnitScale = getI3SLinearUnitScale(this.elevationProvider?.unit || "meter");
1214
+ if (this.elevationProvider && providerUnitScale === void 0) {
1215
+ throw new Error(`Unsupported elevation-provider unit ${this.elevationProvider.unit}`);
1216
+ }
1217
+ this.providerUnitScale = providerUnitScale || 1;
1218
+ this.targetCoordinateFrame = getSpatialCoordinateFrame(targetCrs);
1219
+ this.spatialReference = markTilesetSpatialReferenceTransformed(spatialReference);
1220
+ const sourceToGeographicReference = createTilesetSpatialReference(
1221
+ {
1222
+ sourceCrs: spatialReference.sourceCrs,
1223
+ heightReference: spatialReference.heightReference,
1224
+ coordinateFrame: spatialReference.coordinateFrame,
1225
+ axisOrder: spatialReference.axisOrder,
1226
+ provenance: spatialReference.provenance
1227
+ },
1228
+ { targetCrs: "EPSG:4326" }
1229
+ );
1230
+ this.sourceToGeographicTransformer = new SpatialCoordinateTransformer(
1231
+ sourceToGeographicReference
1232
+ );
1233
+ if (requiresElevationSurface(this.elevationMode)) {
1234
+ if (!this.elevationProvider) {
1235
+ const providerName = this.elevationMode === "relativeToScene" ? "scene" : "terrain";
1236
+ throw new Error(
1237
+ `I3S elevation mode ${this.elevationMode} requires a ${providerName} elevation provider`
1238
+ );
1239
+ }
1240
+ if (spatialReference.heightReference === "unknown") {
1241
+ throw new Error(
1242
+ `I3S elevation mode ${this.elevationMode} requires a known source height reference`
1243
+ );
1244
+ }
1245
+ const providerHeightReference = this.elevationProvider.heightReference || spatialReference.heightReference;
1246
+ if (providerHeightReference !== spatialReference.heightReference) {
1247
+ if (spatialReference.heightReference !== "ellipsoidal" && spatialReference.heightReference !== "orthometric") {
1248
+ throw new Error(
1249
+ "Converting elevation-provider heights requires an ellipsoidal or orthometric source height reference"
1250
+ );
1251
+ }
1252
+ const providerHeightSpatialReference = createTilesetSpatialReference(
1253
+ {
1254
+ sourceCrs: "EPSG:4326",
1255
+ heightReference: providerHeightReference,
1256
+ coordinateFrame: "geographic",
1257
+ axisOrder: "xyz",
1258
+ provenance: "caller-override"
1259
+ },
1260
+ {
1261
+ targetCrs: "EPSG:4326",
1262
+ targetHeightReference: spatialReference.heightReference,
1263
+ geoidModel: options.geoidModel
1264
+ }
1265
+ );
1266
+ this.providerHeightTransformer = new SpatialCoordinateTransformer(
1267
+ providerHeightSpatialReference,
1268
+ options
1269
+ );
1270
+ }
1271
+ }
1272
+ const geographicToTargetReference = createTilesetSpatialReference(
1273
+ {
1274
+ sourceCrs: "EPSG:4326",
1275
+ heightReference: spatialReference.heightReference,
1276
+ coordinateFrame: "geographic",
1277
+ axisOrder: "xyz",
1278
+ provenance: "format-default"
1279
+ },
1280
+ {
1281
+ targetCrs,
1282
+ targetHeightReference: spatialReference.targetHeightReference,
1283
+ geoidModel: options.geoidModel
1284
+ }
1285
+ );
1286
+ this.geographicToTargetTransformer = new SpatialCoordinateTransformer(
1287
+ geographicToTargetReference,
1288
+ options
1289
+ );
1290
+ }
1291
+ /** Transform one absolute I3S source position. */
1292
+ transformPosition(position) {
1293
+ const placedPosition = this.placeSourcePositionsSync(position);
1294
+ const transformed = this.positionTransformer.transformPosition([
1295
+ placedPosition[0],
1296
+ placedPosition[1],
1297
+ placedPosition[2]
1298
+ ]);
1299
+ return [transformed[0], transformed[1], transformed[2]];
1300
+ }
1301
+ /** Transform one absolute I3S source position after asynchronous surface placement. */
1302
+ async transformPositionAsync(position) {
1303
+ const placedPosition = await this.placeSourcePositions(position);
1304
+ const transformed = this.positionTransformer.transformPosition([
1305
+ placedPosition[0],
1306
+ placedPosition[1],
1307
+ placedPosition[2]
1308
+ ]);
1309
+ return [transformed[0], transformed[1], transformed[2]];
1310
+ }
1311
+ /** Transform an already placed, meter-normalized position to the requested target. */
1312
+ transformPlacedPosition(position) {
1313
+ const transformed = this.positionTransformer.transformPosition([
1314
+ position[0],
1315
+ position[1],
1316
+ position[2]
1317
+ ]);
1318
+ return [transformed[0], transformed[1], transformed[2]];
1319
+ }
1320
+ /** Transform one absolute I3S source position to WGS84 longitude, latitude, and height. */
1321
+ transformSourcePositionToGeographic(position) {
1322
+ const placedPosition = this.placeSourcePositionsSync(position);
1323
+ const transformed = this.sourceToGeographicTransformer.transformPosition([
1324
+ placedPosition[0],
1325
+ placedPosition[1],
1326
+ placedPosition[2]
1327
+ ]);
1328
+ return [transformed[0], transformed[1], transformed[2]];
1329
+ }
1330
+ /** Transform one source position to WGS84 after asynchronous elevation placement. */
1331
+ async transformSourcePositionToGeographicAsync(position) {
1332
+ const placedPosition = await this.placeSourcePositions(position);
1333
+ const transformed = this.sourceToGeographicTransformer.transformPosition([
1334
+ placedPosition[0],
1335
+ placedPosition[1],
1336
+ placedPosition[2]
1337
+ ]);
1338
+ return [transformed[0], transformed[1], transformed[2]];
1339
+ }
1340
+ /**
1341
+ * Transform absolute Float64 positions and return stable Float32 offsets around a target origin.
1342
+ *
1343
+ * @param sourcePositions - Absolute positions in source CRS order.
1344
+ * @param sourceOrigin - Stable source origin, normally the node MBS or OBB center.
1345
+ */
1346
+ transformPositions(sourcePositions, sourceOrigin) {
1347
+ const placedSourcePositions = this.placeSourcePositionsSync(sourcePositions);
1348
+ const placedSourceOrigin = this.placeSourcePositionsSync(sourceOrigin);
1349
+ return this.transformPlacedPositions(placedSourcePositions, placedSourceOrigin);
1350
+ }
1351
+ /**
1352
+ * Transform positions after asynchronously sampling any requested terrain or scene surface.
1353
+ *
1354
+ * @param sourcePositions - Absolute positions in source CRS order.
1355
+ * @param sourceOrigin - Stable source origin, normally the node MBS or OBB center.
1356
+ * @returns Renderer-ready target-frame offsets and stable origin metadata.
1357
+ */
1358
+ async transformPositionsAsync(sourcePositions, sourceOrigin) {
1359
+ const combinedPositions = new Float64Array(sourcePositions.length + 3);
1360
+ combinedPositions.set(Array.from(sourcePositions), 0);
1361
+ combinedPositions.set(Array.from(sourceOrigin).slice(0, 3), sourcePositions.length);
1362
+ const placedPositions = await this.placeSourcePositions(combinedPositions);
1363
+ return this.transformPlacedPositions(
1364
+ placedPositions.subarray(0, sourcePositions.length),
1365
+ placedPositions.subarray(sourcePositions.length)
1366
+ );
1367
+ }
1368
+ /** Transform already placed positions into renderer-relative target coordinates. */
1369
+ transformPlacedPositions(sourcePositions, sourceOrigin) {
1370
+ const origin = this.transformPlacedPosition(sourceOrigin);
1371
+ const positions = new Float32Array(sourcePositions.length);
1372
+ const absoluteSourcePositions = Float64Array.from(sourcePositions);
1373
+ for (let index = 0; index < sourcePositions.length; index += 3) {
1374
+ const transformed = this.transformPlacedPosition([
1375
+ sourcePositions[index],
1376
+ sourcePositions[index + 1],
1377
+ sourcePositions[index + 2]
1378
+ ]);
1379
+ positions[index] = transformed[0] - origin[0];
1380
+ positions[index + 1] = transformed[1] - origin[1];
1381
+ positions[index + 2] = transformed[2] - origin[2];
1382
+ }
1383
+ const isGeographic = this.targetCoordinateFrame === "geographic";
1384
+ const modelMatrix = isGeographic ? new Matrix42() : new Matrix42().translate(origin);
1385
+ return {
1386
+ positions,
1387
+ sourcePositions: absoluteSourcePositions,
1388
+ origin,
1389
+ cartographicOrigin: isGeographic ? origin : [0, 0, 0],
1390
+ coordinateSystem: isGeographic ? "lnglat-offsets" : "cartesian",
1391
+ modelMatrix
1392
+ };
1393
+ }
1394
+ /**
1395
+ * Transform I3S normals into the selected target basis.
1396
+ *
1397
+ * Earth-centered normals are rotated directly. Vertex-reference-frame normals are first mapped
1398
+ * through the local east/north/up basis at each source position.
1399
+ *
1400
+ * @param normals - Three-component normal vectors.
1401
+ * @param sourcePositions - Absolute source position paired with each normal.
1402
+ * @param normalReferenceFrame - I3S normal frame declaration.
1403
+ */
1404
+ transformNormals(normals, sourcePositions, normalReferenceFrame = "earth-centered") {
1405
+ const transformedNormals = new Float32Array(normals.length);
1406
+ for (let index = 0; index < normals.length; index += 3) {
1407
+ const geographic = this.sourceToGeographicTransformer.transformPosition([
1408
+ sourcePositions[index],
1409
+ sourcePositions[index + 1],
1410
+ sourcePositions[index + 2]
1411
+ ]);
1412
+ const inputNormal = new Vector32([
1413
+ normals[index],
1414
+ normals[index + 1],
1415
+ normals[index + 2]
1416
+ ]).normalize();
1417
+ const ecefNormal = normalReferenceFrame === "earth-centered" ? inputNormal : localEnuVectorToEcef(inputNormal, geographic);
1418
+ const outputNormal = this.transformEcefNormal(ecefNormal, geographic);
1419
+ transformedNormals.set(outputNormal, index);
1420
+ }
1421
+ return transformedNormals;
1422
+ }
1423
+ /**
1424
+ * Rebuild an I3S node bound from transformed corner or sphere-axis samples.
1425
+ *
1426
+ * @param bounds - Source MBS/OBB fields.
1427
+ * @returns A generic tile `region` for geographic output or axis-aligned `box` otherwise.
1428
+ */
1429
+ transformBoundingVolume(bounds) {
1430
+ const geographicSamples = this.getGeographicBoundSamples(bounds);
1431
+ const targetSamples = geographicSamples.map(
1432
+ (position) => this.geographicToTargetTransformer.transformPosition(position)
1433
+ );
1434
+ return this.targetCoordinateFrame === "geographic" ? { region: getGeographicRegion(targetSamples) } : { box: getAxisAlignedBox(targetSamples) };
1435
+ }
1436
+ /** Rebuild an I3S bound in the target frame after asynchronous elevation placement. */
1437
+ async transformBoundingVolumeAsync(bounds) {
1438
+ const geographicSamples = await this.getGeographicBoundSamplesAsync(bounds);
1439
+ const targetSamples = geographicSamples.map(
1440
+ (position) => this.geographicToTargetTransformer.transformPosition(position)
1441
+ );
1442
+ return this.targetCoordinateFrame === "geographic" ? { region: getGeographicRegion(targetSamples) } : { box: getAxisAlignedBox(targetSamples) };
1443
+ }
1444
+ /** Rebuild an I3S bound as a WGS84 geographic region for geographic traversal algorithms. */
1445
+ transformBoundingVolumeToGeographic(bounds) {
1446
+ return { region: getGeographicRegion(this.getGeographicBoundSamples(bounds)) };
1447
+ }
1448
+ /** Rebuild an I3S bound as WGS84 geographic after asynchronous elevation placement. */
1449
+ async transformBoundingVolumeToGeographicAsync(bounds) {
1450
+ return { region: getGeographicRegion(await this.getGeographicBoundSamplesAsync(bounds)) };
1451
+ }
1452
+ /** Rebuild an I3S bound as a WGS84 ECEF box for generic `Tileset3D` traversal. */
1453
+ transformBoundingVolumeToGeocentric(bounds) {
1454
+ const cartesianSamples = this.getGeographicBoundSamples(bounds).map(
1455
+ (position) => Array.from(Ellipsoid3.WGS84.cartographicToCartesian(new Vector32(position)))
1456
+ );
1457
+ return { box: getAxisAlignedBox(cartesianSamples) };
1458
+ }
1459
+ /** Rebuild an I3S bound as WGS84 ECEF after asynchronous elevation placement. */
1460
+ async transformBoundingVolumeToGeocentricAsync(bounds) {
1461
+ const cartesianSamples = (await this.getGeographicBoundSamplesAsync(bounds)).map(
1462
+ (position) => Array.from(Ellipsoid3.WGS84.cartographicToCartesian(new Vector32(position)))
1463
+ );
1464
+ return { box: getAxisAlignedBox(cartesianSamples) };
1465
+ }
1466
+ /** Return a WGS84 geographic MBS used by the I3S screen-threshold calculation. */
1467
+ transformBoundingSphereToGeographic(bounds) {
1468
+ const sourceCenter = bounds.mbs?.length ? Array.from(bounds.mbs).slice(0, 3) : bounds.obb ? Array.from(bounds.obb.center).slice(0, 3) : null;
1469
+ if (!sourceCenter) {
1470
+ throw new Error("I3S spatial transformation requires an MBS or OBB bound");
1471
+ }
1472
+ const placedCenter = this.placeSourcePositionsSync(sourceCenter);
1473
+ const geographicCenter = this.sourceToGeographicTransformer.transformPosition(
1474
+ Array.from(placedCenter)
1475
+ );
1476
+ const radius = bounds.mbs?.length ? bounds.mbs[3] : Math.hypot(...Array.from(bounds.obb.halfSize).slice(0, 3));
1477
+ return [geographicCenter[0], geographicCenter[1], geographicCenter[2], radius];
1478
+ }
1479
+ /** Return a placed WGS84 MBS used by the I3S screen-threshold calculation. */
1480
+ async transformBoundingSphereToGeographicAsync(bounds) {
1481
+ return getGeographicBoundingSphere(await this.getGeographicBoundSamplesAsync(bounds));
1482
+ }
1483
+ /**
1484
+ * Rebuild traversal, target-output, and I3S LOD bounds from one elevation-sampling batch.
1485
+ *
1486
+ * @param bounds - Source MBS/OBB fields.
1487
+ * @returns Parallel bounds in WGS84 ECEF, the selected output frame, and WGS84 geographic.
1488
+ */
1489
+ async transformBoundsAsync(bounds) {
1490
+ const geographicSamples = await this.getGeographicBoundSamplesAsync(bounds);
1491
+ const cartesianSamples = geographicSamples.map(
1492
+ (position) => Array.from(Ellipsoid3.WGS84.cartographicToCartesian(new Vector32(position)))
1493
+ );
1494
+ const targetSamples = geographicSamples.map(
1495
+ (position) => this.geographicToTargetTransformer.transformPosition(position)
1496
+ );
1497
+ return {
1498
+ boundingVolume: { box: getAxisAlignedBox(cartesianSamples) },
1499
+ spatialBoundingVolume: this.targetCoordinateFrame === "geographic" ? { region: getGeographicRegion(targetSamples) } : { box: getAxisAlignedBox(targetSamples) },
1500
+ i3sLodMbs: requiresElevationSurface(this.elevationMode) ? getGeographicBoundingSphere(geographicSamples) : this.transformBoundingSphereToGeographic(bounds)
1501
+ };
1502
+ }
1503
+ /**
1504
+ * Rebuild Point Cloud traversal and target-output bounds from one elevation-sampling batch.
1505
+ *
1506
+ * @param bounds - Source OBB fields.
1507
+ * @returns WGS84 geographic traversal bound plus the selected output-frame bound.
1508
+ */
1509
+ async transformPointCloudBoundsAsync(bounds) {
1510
+ const geographicSamples = await this.getGeographicBoundSamplesAsync(bounds);
1511
+ const targetSamples = geographicSamples.map(
1512
+ (position) => this.geographicToTargetTransformer.transformPosition(position)
1513
+ );
1514
+ return {
1515
+ boundingVolume: { region: getGeographicRegion(geographicSamples) },
1516
+ spatialBoundingVolume: this.targetCoordinateFrame === "geographic" ? { region: getGeographicRegion(targetSamples) } : { box: getAxisAlignedBox(targetSamples) }
1517
+ };
1518
+ }
1519
+ /** Sample a source I3S bound and normalize every sample to WGS84 geographic coordinates. */
1520
+ getGeographicBoundSamples(bounds) {
1521
+ const sourceSamples = getSourceBoundSamples(
1522
+ bounds,
1523
+ this.sourceCoordinateFrame,
1524
+ this.sourceToGeographicTransformer,
1525
+ this.sourceVerticalUnitScale
1526
+ );
1527
+ if (!sourceSamples.length) {
1528
+ throw new Error("I3S spatial transformation requires an MBS or OBB bound");
1529
+ }
1530
+ const placedSourceSamples = this.placeSourcePositionsSync(sourceSamples.flat(), true);
1531
+ const placedSamples = toPositionArrays(placedSourceSamples);
1532
+ return this.sourceCoordinateFrame === "geographic" ? placedSamples : placedSamples.map(
1533
+ (position) => this.sourceToGeographicTransformer.transformPosition(position)
1534
+ );
1535
+ }
1536
+ /** Sample, place, and normalize one source bound to WGS84 geographic coordinates. */
1537
+ async getGeographicBoundSamplesAsync(bounds) {
1538
+ const sourceSamples = getSourceBoundSamples(
1539
+ bounds,
1540
+ this.sourceCoordinateFrame,
1541
+ this.sourceToGeographicTransformer,
1542
+ this.sourceVerticalUnitScale
1543
+ );
1544
+ if (!sourceSamples.length) {
1545
+ throw new Error("I3S spatial transformation requires an MBS or OBB bound");
1546
+ }
1547
+ if (requiresElevationSurface(this.elevationMode)) {
1548
+ const geographicSamples = this.sourceCoordinateFrame === "geographic" ? sourceSamples : sourceSamples.map(
1549
+ (position) => this.sourceToGeographicTransformer.transformPosition(position)
1550
+ );
1551
+ return await this.placeGeographicBoundSamples(geographicSamples);
1552
+ }
1553
+ const placedSamples = toPositionArrays(
1554
+ await this.placeSourcePositions(sourceSamples.flat(), true)
1555
+ );
1556
+ return this.sourceCoordinateFrame === "geographic" ? placedSamples : placedSamples.map(
1557
+ (position) => this.sourceToGeographicTransformer.transformPosition(position)
1558
+ );
1559
+ }
1560
+ /** Apply a provider's conservative surface range to an entire geographic bound footprint. */
1561
+ async placeGeographicBoundSamples(geographicSamples) {
1562
+ const elevationProvider = this.elevationProvider;
1563
+ const elevationRange = await elevationProvider.getElevationRange(
1564
+ getElevationBounds(geographicSamples)
1565
+ );
1566
+ const minimumProviderHeight = elevationRange.minimum * this.providerUnitScale;
1567
+ const maximumProviderHeight = elevationRange.maximum * this.providerUnitScale;
1568
+ if (!Number.isFinite(minimumProviderHeight) || !Number.isFinite(maximumProviderHeight) || minimumProviderHeight > maximumProviderHeight) {
1569
+ throw new Error(
1570
+ "Elevation provider returned an invalid range; minimum and maximum must be finite and ordered"
1571
+ );
1572
+ }
1573
+ const sourceHeights = geographicSamples.map((position) => position[2]);
1574
+ const minimumSourceHeight = Math.min(...sourceHeights);
1575
+ const maximumSourceHeight = Math.max(...sourceHeights);
1576
+ const placedSamples = [];
1577
+ for (const [longitude, latitude] of geographicSamples) {
1578
+ const convertedMinimum = this.providerHeightTransformer ? this.providerHeightTransformer.transformPosition([
1579
+ longitude,
1580
+ latitude,
1581
+ minimumProviderHeight
1582
+ ])[2] : minimumProviderHeight;
1583
+ const convertedMaximum = this.providerHeightTransformer ? this.providerHeightTransformer.transformPosition([
1584
+ longitude,
1585
+ latitude,
1586
+ maximumProviderHeight
1587
+ ])[2] : maximumProviderHeight;
1588
+ const minimumSurfaceHeight = Math.min(convertedMinimum, convertedMaximum);
1589
+ const maximumSurfaceHeight = Math.max(convertedMinimum, convertedMaximum);
1590
+ const minimumHeight = this.elevationMode === "onTheGround" ? minimumSurfaceHeight : minimumSurfaceHeight + minimumSourceHeight + this.elevationOffset;
1591
+ const maximumHeight = this.elevationMode === "onTheGround" ? maximumSurfaceHeight : maximumSurfaceHeight + maximumSourceHeight + this.elevationOffset;
1592
+ placedSamples.push(
1593
+ [longitude, latitude, minimumHeight],
1594
+ [longitude, latitude, maximumHeight]
1595
+ );
1596
+ }
1597
+ return placedSamples;
1598
+ }
1599
+ /** Apply source units and non-surface placement without awaiting external resources. */
1600
+ placeSourcePositionsSync(sourcePositions, sourceHeightsAreMeters = false) {
1601
+ if (requiresElevationSurface(this.elevationMode)) {
1602
+ throw new Error(
1603
+ `I3S elevation mode ${this.elevationMode} requires asynchronous surface placement`
1604
+ );
1605
+ }
1606
+ const positions = Float64Array.from(sourcePositions);
1607
+ const offset = this.elevationMode === "absoluteHeight" ? this.elevationOffset : 0;
1608
+ for (let index = 2; index < positions.length; index += 3) {
1609
+ positions[index] = positions[index] * (sourceHeightsAreMeters ? 1 : this.sourceVerticalUnitScale) + offset;
1610
+ }
1611
+ return positions;
1612
+ }
1613
+ /** Apply source units and all I3S elevation-placement modes. */
1614
+ async placeSourcePositions(sourcePositions, sourceHeightsAreMeters = false) {
1615
+ if (!requiresElevationSurface(this.elevationMode)) {
1616
+ return this.placeSourcePositionsSync(sourcePositions, sourceHeightsAreMeters);
1617
+ }
1618
+ const positions = Float64Array.from(sourcePositions);
1619
+ const geographicLocations = toPositionArrays(positions).map((position) => {
1620
+ const geographic = this.sourceToGeographicTransformer.transformPosition(position);
1621
+ return [geographic[0], geographic[1]];
1622
+ });
1623
+ const sampledHeights = await this.elevationProvider.sampleElevations(geographicLocations);
1624
+ if (sampledHeights.length !== geographicLocations.length) {
1625
+ throw new Error(
1626
+ `Elevation provider returned ${sampledHeights.length} heights for ${geographicLocations.length} positions`
1627
+ );
1628
+ }
1629
+ for (let positionIndex = 0; positionIndex < geographicLocations.length; positionIndex++) {
1630
+ const sampledHeight = sampledHeights[positionIndex] * this.providerUnitScale;
1631
+ if (!Number.isFinite(sampledHeight)) {
1632
+ throw new Error(
1633
+ `Elevation provider returned a non-finite height at index ${positionIndex}`
1634
+ );
1635
+ }
1636
+ const [longitude, latitude] = geographicLocations[positionIndex];
1637
+ const surfaceHeight = this.providerHeightTransformer ? this.providerHeightTransformer.transformPosition([longitude, latitude, sampledHeight])[2] : sampledHeight;
1638
+ const sourceHeight = positions[positionIndex * 3 + 2] * (sourceHeightsAreMeters ? 1 : this.sourceVerticalUnitScale);
1639
+ positions[positionIndex * 3 + 2] = this.elevationMode === "onTheGround" ? surfaceHeight : surfaceHeight + sourceHeight + this.elevationOffset;
1640
+ }
1641
+ return positions;
1642
+ }
1643
+ /** Transform one earth-centered normal to the selected target basis. */
1644
+ transformEcefNormal(ecefNormal, geographic) {
1645
+ if (this.targetCoordinateFrame === "geocentric") {
1646
+ return ecefNormal.normalize();
1647
+ }
1648
+ if (this.targetCoordinateFrame === "geographic") {
1649
+ return ecefVectorToLocalEnu(ecefNormal, geographic).normalize();
1650
+ }
1651
+ const cartesian = Ellipsoid3.WGS84.cartographicToCartesian(new Vector32(geographic));
1652
+ const jacobianColumns = [];
1653
+ for (const direction of getPositiveAxisDirections()) {
1654
+ const positiveGeographic = Ellipsoid3.WGS84.cartesianToCartographic(
1655
+ new Vector32(cartesian).add(direction)
1656
+ );
1657
+ const negativeGeographic = Ellipsoid3.WGS84.cartesianToCartographic(
1658
+ new Vector32(cartesian).subtract(direction)
1659
+ );
1660
+ const positiveTarget = this.geographicToTargetTransformer.transformPosition(positiveGeographic);
1661
+ const negativeTarget = this.geographicToTargetTransformer.transformPosition(negativeGeographic);
1662
+ jacobianColumns.push(
1663
+ (positiveTarget[0] - negativeTarget[0]) / 2,
1664
+ (positiveTarget[1] - negativeTarget[1]) / 2,
1665
+ (positiveTarget[2] - negativeTarget[2]) / 2
1666
+ );
1667
+ }
1668
+ const normalMatrix = new Matrix3(jacobianColumns);
1669
+ if (Math.abs(normalMatrix.determinant()) < 1e-12) {
1670
+ throw new Error("Cannot transform an I3S normal through a singular local projection");
1671
+ }
1672
+ normalMatrix.invert().transpose();
1673
+ return new Vector32(ecefNormal).transformByMatrix3(normalMatrix).normalize();
1674
+ }
1675
+ };
1676
+ }
1677
+ });
1678
+
1679
+ // ../../modules/tiles/src/index.ts
1680
+ var init_src2 = __esm({
1681
+ "../../modules/tiles/src/index.ts"() {
1682
+ "use strict";
1683
+ init_tileset_content_traversal();
1684
+ init_spatial_types();
1685
+ init_tiles_3d_spatial_transformer();
1686
+ init_i3s_spatial_transformer();
1687
+ }
1688
+ });
1689
+
1690
+ // ../../modules/schema-utils/src/lib/schema/convert-arrow-schema.ts
1691
+ import * as arrow from "apache-arrow";
1692
+ function convertArrowToSchema(arrowSchema) {
1693
+ return serializeArrowSchema(arrowSchema);
1694
+ }
1695
+ function convertSchemaToArrow(schema, options) {
1696
+ return deserializeArrowSchema(schema, options);
1697
+ }
1698
+ function serializeArrowSchema(arrowSchema) {
1699
+ return {
1700
+ fields: arrowSchema.fields.map((arrowField) => serializeArrowField(arrowField)),
1701
+ metadata: serializeArrowMetadata(arrowSchema.metadata)
1702
+ };
1703
+ }
1704
+ function deserializeArrowSchema(schema, options) {
1705
+ return new arrow.Schema(
1706
+ schema.fields.map((field) => deserializeArrowField(field, options)),
1707
+ deserializeArrowMetadata(schema.metadata)
1708
+ );
1709
+ }
1710
+ function serializeArrowMetadata(arrowMetadata) {
1711
+ return Object.fromEntries(arrowMetadata);
1712
+ }
1713
+ function deserializeArrowMetadata(metadata) {
1714
+ return metadata ? new Map(Object.entries(metadata)) : /* @__PURE__ */ new Map();
1715
+ }
1716
+ function serializeArrowField(field) {
1717
+ return {
1718
+ name: field.name,
1719
+ type: serializeArrowType(field.type),
1720
+ nullable: field.nullable,
1721
+ metadata: serializeArrowMetadata(field.metadata)
1722
+ };
1723
+ }
1724
+ function deserializeArrowField(field, options) {
1725
+ return new arrow.Field(
1726
+ field.name,
1727
+ deserializeArrowType(field.type, options),
1728
+ field.nullable,
1729
+ deserializeArrowMetadata(field.metadata)
1730
+ );
1731
+ }
1732
+ function serializeArrowType(arrowType) {
1733
+ if (isArrowViewType(arrowType, "BinaryView")) {
1734
+ return "binary-view";
1735
+ }
1736
+ if (isArrowViewType(arrowType, "Utf8View")) {
1737
+ return "utf8-view";
1738
+ }
1739
+ if (isOptionalArrowType(arrowType, "LargeList")) {
1740
+ const largeListType = arrowType;
1741
+ return {
1742
+ type: "large-list",
1743
+ children: [serializeArrowField(largeListType.valueField)]
1744
+ };
1745
+ }
1746
+ switch (arrowType.constructor) {
1747
+ case arrow.Null:
1748
+ return "null";
1749
+ case arrow.Binary:
1750
+ return "binary";
1751
+ case arrow.FixedSizeBinary:
1752
+ return {
1753
+ type: "fixed-size-binary",
1754
+ byteWidth: arrowType.byteWidth
1755
+ };
1756
+ case arrow.Bool:
1757
+ return "bool";
1758
+ case arrow.Int:
1759
+ const intType = arrowType;
1760
+ return `${intType.isSigned ? "" : "u"}int${intType.bitWidth}`;
1761
+ case arrow.Int8:
1762
+ return "int8";
1763
+ case arrow.Int16:
1764
+ return "int16";
1765
+ case arrow.Int32:
1766
+ return "int32";
1767
+ case arrow.Int64:
1768
+ return "int64";
1769
+ case arrow.Uint8:
1770
+ return "uint8";
1771
+ case arrow.Uint16:
1772
+ return "uint16";
1773
+ case arrow.Uint32:
1774
+ return "uint32";
1775
+ case arrow.Uint64:
1776
+ return "uint64";
1777
+ case arrow.Float:
1778
+ const precision = arrowType.precision;
1779
+ switch (precision) {
1780
+ case arrow.Precision.HALF:
1781
+ return "float16";
1782
+ case arrow.Precision.SINGLE:
1783
+ return "float32";
1784
+ case arrow.Precision.DOUBLE:
1785
+ return "float64";
1786
+ default:
1787
+ return "float16";
1788
+ }
1789
+ case arrow.Float16:
1790
+ return "float16";
1791
+ case arrow.Float32:
1792
+ return "float32";
1793
+ case arrow.Float64:
1794
+ return "float64";
1795
+ case arrow.Utf8:
1796
+ return "utf8";
1797
+ case arrow.Decimal:
1798
+ const decimal = arrowType;
1799
+ return {
1800
+ type: "decimal",
1801
+ bitWidth: decimal.bitWidth,
1802
+ precision: decimal.precision,
1803
+ scale: decimal.scale
1804
+ };
1805
+ case arrow.Date_:
1806
+ const dateUnit = arrowType.unit;
1807
+ return dateUnit === arrow.DateUnit.DAY ? "date-day" : "date-millisecond";
1808
+ case arrow.DateDay:
1809
+ return "date-day";
1810
+ case arrow.DateMillisecond:
1811
+ return "date-millisecond";
1812
+ case arrow.Time:
1813
+ const timeUnit = arrowType.unit;
1814
+ switch (timeUnit) {
1815
+ case arrow.TimeUnit.SECOND:
1816
+ return "time-second";
1817
+ case arrow.TimeUnit.MILLISECOND:
1818
+ return "time-millisecond";
1819
+ case arrow.TimeUnit.MICROSECOND:
1820
+ return "time-microsecond";
1821
+ case arrow.TimeUnit.NANOSECOND:
1822
+ return "time-nanosecond";
1823
+ default:
1824
+ return "time-second";
1825
+ }
1826
+ case arrow.TimeMillisecond:
1827
+ return "time-millisecond";
1828
+ case arrow.TimeSecond:
1829
+ return "time-second";
1830
+ case arrow.TimeMicrosecond:
1831
+ return "time-microsecond";
1832
+ case arrow.TimeNanosecond:
1833
+ return "time-nanosecond";
1834
+ case arrow.Timestamp:
1835
+ const timeStampUnit = arrowType.unit;
1836
+ switch (timeStampUnit) {
1837
+ case arrow.TimeUnit.SECOND:
1838
+ return "timestamp-second";
1839
+ case arrow.TimeUnit.MILLISECOND:
1840
+ return "timestamp-millisecond";
1841
+ case arrow.TimeUnit.MICROSECOND:
1842
+ return "timestamp-microsecond";
1843
+ case arrow.TimeUnit.NANOSECOND:
1844
+ return "timestamp-nanosecond";
1845
+ default:
1846
+ return "timestamp-second";
1847
+ }
1848
+ case arrow.TimestampSecond:
1849
+ return "timestamp-second";
1850
+ case arrow.TimestampMillisecond:
1851
+ return "timestamp-millisecond";
1852
+ case arrow.TimestampMicrosecond:
1853
+ return "timestamp-microsecond";
1854
+ case arrow.TimestampNanosecond:
1855
+ return "timestamp-nanosecond";
1856
+ case arrow.Interval:
1857
+ const intervalUnit = arrowType.unit;
1858
+ switch (intervalUnit) {
1859
+ case arrow.IntervalUnit.DAY_TIME:
1860
+ return "interval-daytime";
1861
+ case arrow.IntervalUnit.YEAR_MONTH:
1862
+ return "interval-yearmonth";
1863
+ default:
1864
+ return "interval-daytime";
1865
+ }
1866
+ case arrow.IntervalDayTime:
1867
+ return "interval-daytime";
1868
+ case arrow.IntervalYearMonth:
1869
+ return "interval-yearmonth";
1870
+ case arrow.Map_:
1871
+ const mapType = arrowType;
1872
+ return {
1873
+ type: "map",
1874
+ keysSorted: mapType.keysSorted,
1875
+ children: mapType.children.map((arrowField) => serializeArrowField(arrowField))
1876
+ };
1877
+ case arrow.List:
1878
+ const listType = arrowType;
1879
+ const listField = listType.valueField;
1880
+ return {
1881
+ type: "list",
1882
+ children: [serializeArrowField(listField)]
1883
+ };
1884
+ case arrow.FixedSizeList:
1885
+ const fixedSizeList = arrowType;
1886
+ return {
1887
+ type: "fixed-size-list",
1888
+ listSize: fixedSizeList.listSize,
1889
+ children: [serializeArrowField(fixedSizeList.children[0])]
1890
+ };
1891
+ case arrow.Struct:
1892
+ const structType = arrowType;
1893
+ return {
1894
+ type: "struct",
1895
+ children: structType.children.map((arrowField) => serializeArrowField(arrowField))
1896
+ };
1897
+ case arrow.SparseUnion:
1898
+ case arrow.DenseUnion:
1899
+ const unionType = arrowType;
1900
+ return {
1901
+ type: unionType instanceof arrow.DenseUnion ? "dense-union" : "sparse-union",
1902
+ typeIds: unionType.typeIds,
1903
+ children: unionType.children.map((arrowField) => serializeArrowField(arrowField)),
1904
+ typeIdToChildIndex: { ...unionType.typeIdToChildIndex }
1905
+ };
1906
+ case arrow.Dictionary:
1907
+ const dictionaryType = arrowType;
1908
+ return {
1909
+ type: "dictionary",
1910
+ id: dictionaryType.id,
1911
+ indices: serializeArrowDictionaryKeyType(dictionaryType.indices),
1912
+ dictionary: serializeArrowType(dictionaryType.dictionary),
1913
+ isOrdered: dictionaryType.isOrdered
1914
+ };
1915
+ default:
1916
+ throw new Error(`arrow type not supported: ${arrowType.constructor.name}`);
1917
+ }
1918
+ }
1919
+ function deserializeArrowType(dataType, options) {
1920
+ if (typeof dataType === "object") {
1921
+ switch (dataType.type) {
1922
+ case "decimal":
1923
+ return new arrow.Decimal(dataType.scale, dataType.precision, dataType.bitWidth);
1924
+ case "map": {
1925
+ const children = dataType.children.map(
1926
+ (arrowField) => deserializeArrowField(arrowField, options)
1927
+ );
1928
+ return new arrow.Map_(children[0], dataType.keysSorted);
1929
+ }
1930
+ case "list": {
1931
+ const field = deserializeArrowField(dataType.children[0], options);
1932
+ return new arrow.List(field);
1933
+ }
1934
+ case "large-list": {
1935
+ const field = deserializeArrowField(dataType.children[0], options);
1936
+ const LargeList = getOptionalArrowConstructor("LargeList");
1937
+ if (!LargeList) {
1938
+ throw new Error(
1939
+ "LargeList requires an Apache Arrow runtime that exports the LargeList constructor"
1940
+ );
1941
+ }
1942
+ return new LargeList(field);
1943
+ }
1944
+ case "fixed-size-list": {
1945
+ const child = deserializeArrowField(dataType.children[0], options);
1946
+ return new arrow.FixedSizeList(dataType.listSize, child);
1947
+ }
1948
+ case "fixed-size-binary":
1949
+ return new arrow.FixedSizeBinary(dataType.byteWidth);
1950
+ case "struct": {
1951
+ const children = dataType.children.map(
1952
+ (arrowField) => deserializeArrowField(arrowField, options)
1953
+ );
1954
+ return new arrow.Struct(children);
1955
+ }
1956
+ case "sparse-union":
1957
+ case "dense-union": {
1958
+ const children = dataType.children.map(
1959
+ (arrowField) => deserializeArrowField(arrowField, options)
1960
+ );
1961
+ return dataType.type === "dense-union" ? new arrow.DenseUnion(dataType.typeIds, children) : new arrow.SparseUnion(dataType.typeIds, children);
1962
+ }
1963
+ case "dictionary": {
1964
+ return new arrow.Dictionary(
1965
+ deserializeArrowType(dataType.dictionary, options),
1966
+ deserializeArrowDictionaryKeyType(dataType.indices),
1967
+ dataType.id,
1968
+ dataType.isOrdered
1969
+ );
1970
+ }
1971
+ default:
1972
+ throw new Error("array type not supported");
1973
+ }
1974
+ }
1975
+ switch (dataType) {
1976
+ case "null":
1977
+ return new arrow.Null();
1978
+ case "binary":
1979
+ return makeVariableWidthArrowType("BinaryView", new arrow.Binary(), options);
1980
+ case "binary-view":
1981
+ return makeRequiredArrowViewType("BinaryView");
1982
+ case "bool":
1983
+ return new arrow.Bool();
1984
+ case "int8":
1985
+ return new arrow.Int8();
1986
+ case "int16":
1987
+ return new arrow.Int16();
1988
+ case "int32":
1989
+ return new arrow.Int32();
1990
+ case "int64":
1991
+ return new arrow.Int64();
1992
+ case "uint8":
1993
+ return new arrow.Uint8();
1994
+ case "uint16":
1995
+ return new arrow.Uint16();
1996
+ case "uint32":
1997
+ return new arrow.Uint32();
1998
+ case "uint64":
1999
+ return new arrow.Uint64();
2000
+ case "float16":
2001
+ return new arrow.Float16();
2002
+ case "float32":
2003
+ return new arrow.Float32();
2004
+ case "float64":
2005
+ return new arrow.Float64();
2006
+ case "utf8":
2007
+ return makeVariableWidthArrowType("Utf8View", new arrow.Utf8(), options);
2008
+ case "utf8-view":
2009
+ return makeRequiredArrowViewType("Utf8View");
2010
+ case "date-day":
2011
+ return new arrow.DateDay();
2012
+ case "date-millisecond":
2013
+ return new arrow.DateMillisecond();
2014
+ case "time-second":
2015
+ return new arrow.TimeSecond();
2016
+ case "time-millisecond":
2017
+ return new arrow.TimeMillisecond();
2018
+ case "time-microsecond":
2019
+ return new arrow.TimeMicrosecond();
2020
+ case "time-nanosecond":
2021
+ return new arrow.TimeNanosecond();
2022
+ case "timestamp-second":
2023
+ return new arrow.TimestampSecond();
2024
+ case "timestamp-millisecond":
2025
+ return new arrow.TimestampMillisecond();
2026
+ case "timestamp-microsecond":
2027
+ return new arrow.TimestampMicrosecond();
2028
+ case "timestamp-nanosecond":
2029
+ return new arrow.TimestampNanosecond();
2030
+ case "interval-daytime":
2031
+ return new arrow.IntervalDayTime();
2032
+ case "interval-yearmonth":
2033
+ return new arrow.IntervalYearMonth();
2034
+ default:
2035
+ throw new Error("array type not supported");
2036
+ }
2037
+ }
2038
+ function getOptionalArrowConstructor(typeName) {
2039
+ return arrow[typeName];
2040
+ }
2041
+ function isArrowViewType(arrowType, viewTypeName) {
2042
+ const constructor = getOptionalArrowConstructor(viewTypeName);
2043
+ if (constructor && arrowType instanceof constructor) {
2044
+ return true;
2045
+ }
2046
+ const guards = arrow.DataType;
2047
+ const guard = viewTypeName === "BinaryView" ? guards.isBinaryView : guards.isUtf8View;
2048
+ return Boolean(guard?.(arrowType));
2049
+ }
2050
+ function isOptionalArrowType(arrowType, typeName) {
2051
+ const constructor = getOptionalArrowConstructor(typeName);
2052
+ return Boolean(constructor && arrowType instanceof constructor);
2053
+ }
2054
+ function makeVariableWidthArrowType(viewTypeName, fallbackType, options) {
2055
+ const viewTypeMode = options?.viewTypes || "never";
2056
+ if (viewTypeMode === "never") {
2057
+ return fallbackType;
2058
+ }
2059
+ const constructor = getOptionalArrowConstructor(viewTypeName);
2060
+ if (constructor) {
2061
+ return new constructor();
2062
+ }
2063
+ if (viewTypeMode === "require") {
2064
+ throw new Error(
2065
+ `${viewTypeName} requires apache-arrow 21.2.0 or later; the installed runtime does not support it`
2066
+ );
2067
+ }
2068
+ return fallbackType;
2069
+ }
2070
+ function makeRequiredArrowViewType(viewTypeName) {
2071
+ const constructor = getOptionalArrowConstructor(viewTypeName);
2072
+ if (!constructor) {
2073
+ throw new Error(
2074
+ `${viewTypeName} requires apache-arrow 21.2.0 or later; the installed runtime does not support it`
2075
+ );
2076
+ }
2077
+ return new constructor();
2078
+ }
2079
+ function serializeArrowDictionaryKeyType(arrowType) {
2080
+ if (arrowType instanceof arrow.Int) {
2081
+ const prefix = arrowType.isSigned ? "int" : "uint";
2082
+ const keyType = `${prefix}${arrowType.bitWidth}`;
2083
+ if (isSchemaDictionaryKeyType(keyType)) {
2084
+ return keyType;
2085
+ }
2086
+ }
2087
+ switch (arrowType.constructor) {
2088
+ case arrow.Int8:
2089
+ return "int8";
2090
+ case arrow.Int16:
2091
+ return "int16";
2092
+ case arrow.Int32:
2093
+ return "int32";
2094
+ case arrow.Uint8:
2095
+ return "uint8";
2096
+ case arrow.Uint16:
2097
+ return "uint16";
2098
+ case arrow.Uint32:
2099
+ return "uint32";
2100
+ default:
2101
+ throw new Error(`arrow dictionary index type not supported: ${arrowType.constructor.name}`);
2102
+ }
2103
+ }
2104
+ function isSchemaDictionaryKeyType(keyType) {
2105
+ return ["int8", "int16", "int32", "uint8", "uint16", "uint32"].includes(keyType);
2106
+ }
2107
+ function deserializeArrowDictionaryKeyType(keyType) {
2108
+ switch (keyType) {
2109
+ case "int8":
2110
+ return new arrow.Int8();
2111
+ case "int16":
2112
+ return new arrow.Int16();
2113
+ case "int32":
2114
+ return new arrow.Int32();
2115
+ case "uint8":
2116
+ return new arrow.Uint8();
2117
+ case "uint16":
2118
+ return new arrow.Uint16();
2119
+ case "uint32":
2120
+ return new arrow.Uint32();
2121
+ default:
2122
+ throw new Error(`schema dictionary index type not supported: ${keyType}`);
2123
+ }
2124
+ }
2125
+ var init_convert_arrow_schema = __esm({
2126
+ "../../modules/schema-utils/src/lib/schema/convert-arrow-schema.ts"() {
2127
+ "use strict";
2128
+ }
2129
+ });
2130
+
2131
+ // ../../modules/schema-utils/src/lib/mesh/mesh-utils.ts
2132
+ function getMeshBoundingBox(attributes) {
2133
+ let minX = Infinity;
2134
+ let minY = Infinity;
2135
+ let minZ = Infinity;
2136
+ let maxX = -Infinity;
2137
+ let maxY = -Infinity;
2138
+ let maxZ = -Infinity;
2139
+ const positions = attributes.POSITION ? attributes.POSITION.value : [];
2140
+ const len = positions && positions.length;
2141
+ for (let i = 0; i < len; i += 3) {
2142
+ const x = positions[i];
2143
+ const y = positions[i + 1];
2144
+ const z = positions[i + 2];
2145
+ minX = x < minX ? x : minX;
2146
+ minY = y < minY ? y : minY;
2147
+ minZ = z < minZ ? z : minZ;
2148
+ maxX = x > maxX ? x : maxX;
2149
+ maxY = y > maxY ? y : maxY;
2150
+ maxZ = z > maxZ ? z : maxZ;
2151
+ }
2152
+ return [
2153
+ [minX, minY, minZ],
2154
+ [maxX, maxY, maxZ]
2155
+ ];
2156
+ }
2157
+ var init_mesh_utils = __esm({
2158
+ "../../modules/schema-utils/src/lib/mesh/mesh-utils.ts"() {
2159
+ "use strict";
2160
+ }
2161
+ });
2162
+
2163
+ // ../../modules/schema/src/float16.ts
2164
+ import { getFloat16ArrayConstructor, NativeFloat16ArrayConstructor } from "@math.gl/types";
2165
+ function createFloat16Array(length) {
2166
+ const ArrayConstructor = getFloat16ArrayConstructor();
2167
+ return new ArrayConstructor(length);
2168
+ }
2169
+ function isNativeFloat16Array(value) {
2170
+ return Boolean(NativeFloat16ArrayConstructor && value instanceof NativeFloat16ArrayConstructor);
2171
+ }
2172
+ function setFloat16Value(array, index, value) {
2173
+ if (isNativeFloat16Array(array)) {
2174
+ array[index] = value;
2175
+ } else {
2176
+ array[index] = encodeFloat16(value);
2177
+ }
2178
+ }
2179
+ function getFloat16Value(array, index) {
2180
+ if (isNativeFloat16Array(array)) {
2181
+ return array[index];
2182
+ }
2183
+ return decodeFloat16(array[index]);
2184
+ }
2185
+ function encodeFloat16(value) {
2186
+ if (!Number.isFinite(value)) {
2187
+ return value === Infinity ? 31744 : value === -Infinity ? 64512 : 32256;
2188
+ }
2189
+ const sign = value < 0 || Object.is(value, -0) ? 32768 : 0;
2190
+ const absoluteValue = Math.abs(value);
2191
+ if (absoluteValue === 0) {
2192
+ return sign;
2193
+ }
2194
+ if (absoluteValue >= 65520) {
2195
+ return sign | 31744;
2196
+ }
2197
+ if (absoluteValue >= 65504) {
2198
+ return sign | 31743;
2199
+ }
2200
+ const exponent = Math.floor(Math.log2(absoluteValue));
2201
+ if (exponent < -14) {
2202
+ return sign | Math.round(absoluteValue / 2 ** -24);
2203
+ }
2204
+ const normalizedExponent = exponent + 15;
2205
+ const mantissa = Math.round((absoluteValue / 2 ** exponent - 1) * 1024);
2206
+ if (mantissa === 1024) {
2207
+ return sign | normalizedExponent + 1 << 10;
2208
+ }
2209
+ return sign | normalizedExponent << 10 | mantissa;
2210
+ }
2211
+ function decodeFloat16(value) {
2212
+ const sign = value & 32768 ? -1 : 1;
2213
+ const exponent = value >> 10 & 31;
2214
+ const mantissa = value & 1023;
2215
+ if (exponent === 0) {
2216
+ return sign * mantissa * 2 ** -24;
2217
+ }
2218
+ if (exponent === 31) {
2219
+ return mantissa ? NaN : sign * Infinity;
2220
+ }
2221
+ return sign * (1 + mantissa / 1024) * 2 ** (exponent - 15);
2222
+ }
2223
+ var init_float16 = __esm({
2224
+ "../../modules/schema/src/float16.ts"() {
2225
+ "use strict";
2226
+ }
2227
+ });
2228
+
2229
+ // ../../modules/schema/src/index.ts
2230
+ var init_src3 = __esm({
2231
+ "../../modules/schema/src/index.ts"() {
2232
+ "use strict";
2233
+ init_float16();
2234
+ }
2235
+ });
2236
+
2237
+ // ../../modules/schema-utils/src/lib/arrow-utils/arrow-fixed-size-list-utils.ts
2238
+ import * as arrow2 from "apache-arrow";
2239
+ function getFixedSizeListSize(vector) {
2240
+ return vector.type instanceof arrow2.FixedSizeList ? vector.type.listSize : 1;
2241
+ }
2242
+ var init_arrow_fixed_size_list_utils = __esm({
2243
+ "../../modules/schema-utils/src/lib/arrow-utils/arrow-fixed-size-list-utils.ts"() {
2244
+ "use strict";
2245
+ }
2246
+ });
2247
+
2248
+ // ../../modules/schema-utils/src/lib/mesh/convert-table-to-mesh.ts
2249
+ import * as arrow3 from "apache-arrow";
2250
+ function convertTableToMesh(table) {
2251
+ switch (table.shape) {
2252
+ // case 'columnar-table':
2253
+ // return convertColumnarTableToMesh(table);
2254
+ case "arrow-table":
2255
+ return convertArrowTableToMesh(table);
2256
+ default:
2257
+ throw new Error(table.shape);
2258
+ }
2259
+ }
2260
+ function convertArrowTableToMesh(table) {
2261
+ const arrowTable = table.data;
2262
+ const schema = serializeArrowSchema(arrowTable.schema);
2263
+ const fields = schema.fields;
2264
+ const attributes = {};
2265
+ for (const field of fields) {
2266
+ const { name } = field;
2267
+ if (name === "indices") {
2268
+ continue;
2269
+ }
2270
+ const attributeData = arrowTable.getChild(name);
2271
+ const size = getFixedSizeListSize(attributeData);
2272
+ const typedArray = getAttributeTypedArray(attributeData, size);
2273
+ const metadata = getMeshAttributeMetadata(field.metadata);
2274
+ attributes[name] = {
2275
+ value: metadata.componentType === "float16" ? restoreFloat16Array(typedArray) : typedArray,
2276
+ size,
2277
+ ...metadata
2278
+ };
2279
+ }
2280
+ fixMetadata(schema);
2281
+ const topology = schema.metadata.topology;
2282
+ const mode = getMeshMode(schema);
2283
+ const indices = getIndices(arrowTable);
2284
+ const boundingBox = attributes.POSITION?.transform?.type === "quantization" ? getMeshBoundingBoxFromSchema(schema) || getMeshBoundingBox(attributes) : getMeshBoundingBox(attributes);
2285
+ return {
2286
+ schema,
2287
+ attributes,
2288
+ topology,
2289
+ mode,
2290
+ indices,
2291
+ header: {
2292
+ vertexCount: arrowTable.numRows,
2293
+ boundingBox
2294
+ }
2295
+ };
2296
+ }
2297
+ function getMeshBoundingBoxFromSchema(schema) {
2298
+ const serializedBoundingBox = schema.metadata?.boundingBox;
2299
+ if (!serializedBoundingBox) {
2300
+ return null;
2301
+ }
2302
+ try {
2303
+ const boundingBox = JSON.parse(serializedBoundingBox);
2304
+ if (Array.isArray(boundingBox) && boundingBox.length === 2 && boundingBox.every(
2305
+ (corner) => Array.isArray(corner) && corner.length === 3 && corner.every((value) => typeof value === "number")
2306
+ )) {
2307
+ return boundingBox;
2308
+ }
2309
+ } catch {
2310
+ }
2311
+ return null;
2312
+ }
2313
+ function getMeshAttributeMetadata(metadata = {}) {
2314
+ const result = {};
2315
+ if (metadata.byteOffset !== void 0) {
2316
+ result.byteOffset = Number(metadata.byteOffset);
2317
+ }
2318
+ if (metadata.byteStride !== void 0) {
2319
+ result.byteStride = Number(metadata.byteStride);
2320
+ }
2321
+ if (metadata.normalized !== void 0) {
2322
+ result.normalized = metadata.normalized === "true";
2323
+ }
2324
+ if (metadata.componentType === "float16") {
2325
+ result.componentType = "float16";
2326
+ }
2327
+ if (metadata["loaders.gl.transform"]) {
2328
+ try {
2329
+ const transform = JSON.parse(metadata["loaders.gl.transform"]);
2330
+ if (isMeshAttributeTransform(transform)) {
2331
+ result.transform = transform;
2332
+ }
2333
+ } catch {
2334
+ }
2335
+ }
2336
+ return result;
2337
+ }
2338
+ function isMeshAttributeTransform(value) {
2339
+ if (!value || typeof value !== "object" || !("type" in value)) {
2340
+ return false;
2341
+ }
2342
+ const transform = value;
2343
+ if (transform.type === "octahedron") {
2344
+ return Number.isInteger(transform.bits) && transform.bits >= 1 && transform.bits <= 30;
2345
+ }
2346
+ 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";
2347
+ }
2348
+ function fixMetadata(schema) {
2349
+ schema.metadata ||= {};
2350
+ schema.metadata.topology ||= "point-list";
2351
+ schema.metadata.mode ||= "0";
2352
+ }
2353
+ function getAttributeTypedArray(attributeData, size) {
2354
+ if (!(attributeData.type instanceof arrow3.FixedSizeList)) {
2355
+ return attributeData.toArray();
2356
+ }
2357
+ const values = attributeData.data[0].children[0].values;
2358
+ const TypedArrayConstructor = values.constructor;
2359
+ const typedArray = new TypedArrayConstructor(attributeData.length * size);
2360
+ let targetOffset = 0;
2361
+ for (const data of attributeData.data) {
2362
+ const child = data.children[0];
2363
+ const sourceLength = data.length * size;
2364
+ const sourceOffset = child.offset || data.offset * size;
2365
+ const sourceStart = sourceOffset + sourceLength <= child.values.length ? sourceOffset : 0;
2366
+ const source = child.values.subarray(sourceStart, sourceStart + sourceLength);
2367
+ typedArray.set(source, targetOffset);
2368
+ targetOffset += sourceLength;
2369
+ }
2370
+ return typedArray;
2371
+ }
2372
+ function restoreFloat16Array(typedArray) {
2373
+ const result = createFloat16Array(typedArray.length);
2374
+ for (let index = 0; index < typedArray.length; index++) {
2375
+ setFloat16Value(result, index, getFloat16Value(typedArray, index));
2376
+ }
2377
+ return result;
2378
+ }
2379
+ function getMeshMode(schema) {
2380
+ const mode = Number(schema.metadata?.mode);
2381
+ return Number.isFinite(mode) ? mode : 0;
2382
+ }
2383
+ function getIndices(arrowTable) {
2384
+ const indicesColumn = arrowTable.getChild("indices");
2385
+ if (!indicesColumn?.isValid(0)) {
2386
+ return void 0;
2387
+ }
2388
+ const indicesData = indicesColumn.data[0];
2389
+ const valueOffsets = indicesData.valueOffsets;
2390
+ const start = valueOffsets[indicesData.offset];
2391
+ const end = valueOffsets[indicesData.offset + 1];
2392
+ const values = indicesData.children[0].values.subarray(start, end);
2393
+ return { value: values, size: 1 };
2394
+ }
2395
+ var init_convert_table_to_mesh = __esm({
2396
+ "../../modules/schema-utils/src/lib/mesh/convert-table-to-mesh.ts"() {
2397
+ "use strict";
2398
+ init_src3();
2399
+ init_arrow_fixed_size_list_utils();
2400
+ init_convert_arrow_schema();
2401
+ init_mesh_utils();
2402
+ }
2403
+ });
2404
+
2405
+ // ../../modules/schema-utils/src/lib/table/batch-builder/arrow-table-builder.ts
2406
+ import * as arrow4 from "apache-arrow";
2407
+ var ArrowTableBuilder;
2408
+ var init_arrow_table_builder = __esm({
2409
+ "../../modules/schema-utils/src/lib/table/batch-builder/arrow-table-builder.ts"() {
2410
+ "use strict";
2411
+ init_src4();
2412
+ ArrowTableBuilder = class {
2413
+ schema;
2414
+ arrowSchema;
2415
+ arrowBuilders;
2416
+ length;
2417
+ constructor(schema, options) {
2418
+ this.arrowSchema = convertSchemaToArrow(schema, options);
2419
+ this.schema = options?.viewTypes && options.viewTypes !== "never" ? convertArrowToSchema(this.arrowSchema) : schema;
2420
+ this.arrowBuilders = this.arrowSchema.fields.map(
2421
+ (field) => arrow4.makeBuilder({ type: field.type, nullValues: [null] })
2422
+ );
2423
+ this.length = 0;
2424
+ }
2425
+ addObjectRow(row) {
2426
+ for (let i = 0; i < this.arrowBuilders.length; i++) {
2427
+ const columnName = this.schema.fields[i].name;
2428
+ const value = row[columnName];
2429
+ this.arrowBuilders[i].append(value);
2430
+ }
2431
+ this.length++;
2432
+ }
2433
+ addArrayRow(row) {
2434
+ for (let i = 0; i < this.arrowBuilders.length; i++) {
2435
+ this.arrowBuilders[i].append(row[i]);
2436
+ }
2437
+ this.length++;
2438
+ }
2439
+ /** Makes sure that a first batch with schema is sent even if no rows */
2440
+ firstBatch() {
2441
+ const arrowRecordBatch = this._getArrowRecordBatch();
2442
+ if (arrowRecordBatch.numCols !== 0) {
2443
+ return null;
2444
+ }
2445
+ return {
2446
+ shape: "arrow-table",
2447
+ batchType: "data",
2448
+ length: arrowRecordBatch.numRows,
2449
+ schema: this.schema,
2450
+ data: new arrow4.Table(arrowRecordBatch)
2451
+ };
2452
+ }
2453
+ /** Flush the current batch if conditions are right */
2454
+ flushBatch() {
2455
+ const arrowRecordBatch = this._getArrowRecordBatch();
2456
+ if (arrowRecordBatch.numCols === 0) {
2457
+ return null;
2458
+ }
2459
+ return {
2460
+ shape: "arrow-table",
2461
+ batchType: "data",
2462
+ length: arrowRecordBatch.numRows,
2463
+ schema: this.schema,
2464
+ data: new arrow4.Table(arrowRecordBatch)
2465
+ };
2466
+ }
2467
+ /** Get a last batch if any data is left */
2468
+ finishBatch() {
2469
+ const arrowRecordBatch = this._getArrowRecordBatch();
2470
+ this.arrowBuilders.forEach((builder) => builder.finish());
2471
+ if (arrowRecordBatch.numCols === 0 && arrowRecordBatch.numRows === 0) {
2472
+ return null;
2473
+ }
2474
+ return {
2475
+ shape: "arrow-table",
2476
+ batchType: "data",
2477
+ length: arrowRecordBatch.numRows,
2478
+ schema: this.schema,
2479
+ data: new arrow4.Table(arrowRecordBatch)
2480
+ };
2481
+ }
2482
+ /** Return a table with all the accumulated data */
2483
+ finishTable() {
2484
+ const arrowRecordBatch = this._getArrowRecordBatch();
2485
+ this.arrowBuilders.forEach((builder) => builder.finish());
2486
+ return {
2487
+ shape: "arrow-table",
2488
+ schema: this.schema,
2489
+ data: new arrow4.Table(arrowRecordBatch)
2490
+ };
2491
+ }
2492
+ /** Extract a record batch flushing the currently accumulated data in the builders */
2493
+ _getArrowRecordBatch() {
2494
+ const { arrowBuilders, arrowSchema } = this;
2495
+ const arrowDatas = arrowBuilders.map((builder) => builder.flush());
2496
+ const length = arrowDatas[0]?.length || this.length;
2497
+ this.length = 0;
2498
+ const structField = new arrow4.Struct(arrowSchema.fields);
2499
+ const arrowStructData = new arrow4.Data(structField, 0, length, 0, void 0, arrowDatas);
2500
+ const arrowRecordBatch = new arrow4.RecordBatch(arrowSchema, arrowStructData);
2501
+ return arrowRecordBatch;
2502
+ }
2503
+ };
2504
+ }
2505
+ });
2506
+
2507
+ // ../../modules/schema-utils/src/index.ts
2508
+ var init_src4 = __esm({
2509
+ "../../modules/schema-utils/src/index.ts"() {
2510
+ "use strict";
2511
+ init_convert_arrow_schema();
2512
+ init_convert_table_to_mesh();
2513
+ init_arrow_table_builder();
2514
+ }
2515
+ });
2516
+
2517
+ // ../../modules/3d-tiles/src/lib/utils/version.ts
2518
+ var VERSION;
2519
+ var init_version = __esm({
2520
+ "../../modules/3d-tiles/src/lib/utils/version.ts"() {
2521
+ "use strict";
2522
+ VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "latest";
2523
+ }
2524
+ });
2525
+
2526
+ // ../../modules/3d-tiles/src/lib/constants.ts
2527
+ var TILE3D_TYPE, TILE3D_TYPES, MAGIC_ARRAY;
2528
+ var init_constants = __esm({
2529
+ "../../modules/3d-tiles/src/lib/constants.ts"() {
2530
+ "use strict";
2531
+ TILE3D_TYPE = {
2532
+ COMPOSITE: "cmpt",
2533
+ POINT_CLOUD: "pnts",
2534
+ BATCHED_3D_MODEL: "b3dm",
2535
+ INSTANCED_3D_MODEL: "i3dm",
2536
+ GEOMETRY: "geom",
2537
+ VECTOR: "vect",
2538
+ GLTF: "glTF"
2539
+ };
2540
+ TILE3D_TYPES = Object.keys(TILE3D_TYPE);
2541
+ MAGIC_ARRAY = {
2542
+ BATCHED_MODEL: [98, 51, 100, 109],
2543
+ INSTANCED_MODEL: [105, 51, 100, 109],
2544
+ POINT_CLOUD: [112, 110, 116, 115],
2545
+ COMPOSITE: [99, 109, 112, 116]
2546
+ };
2547
+ }
2548
+ });
2549
+
2550
+ // src/v5/conversion-api.ts
2551
+ var TileConversionError = class extends Error {
2552
+ /** Stable machine-readable failure code. */
2553
+ code;
2554
+ /** Diagnostics associated with this failure. */
2555
+ diagnostics;
2556
+ /** Creates a typed conversion failure. */
2557
+ constructor(code, message, diagnostics = []) {
2558
+ super(message);
2559
+ this.name = "TileConversionError";
2560
+ this.code = code;
2561
+ this.diagnostics = diagnostics;
2562
+ }
2563
+ };
2564
+ async function inspectTileset(source, signal) {
2565
+ throwIfAborted(signal);
2566
+ const inspection = await source.inspect(signal);
2567
+ throwIfAborted(signal);
2568
+ return inspection;
2569
+ }
2570
+ async function convertTileset(options) {
2571
+ const {
2572
+ source,
2573
+ codec,
2574
+ sink,
2575
+ measureInputBytes,
2576
+ measureOutputBytes,
2577
+ maxInputResourceBytes = Number.POSITIVE_INFINITY,
2578
+ maxOutputResourceBytes = Number.POSITIVE_INFINITY,
2579
+ signal,
2580
+ onProgress
2581
+ } = options;
2582
+ let inputResources = 0;
2583
+ let outputResources = 0;
2584
+ let inputBytes = 0;
2585
+ let outputBytes = 0;
2586
+ let largestOutputResourceBytes = 0;
2587
+ const diagnostics = [];
2588
+ const reportProgress = (phase) => {
2589
+ onProgress?.({ phase, inputResources, outputResources, inputBytes, outputBytes });
2590
+ };
2591
+ try {
2592
+ if (maxInputResourceBytes !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(maxInputResourceBytes) || maxInputResourceBytes < 0)) {
2593
+ throw new TileConversionError(
2594
+ "INVALID_INPUT_RESOURCE_LIMIT",
2595
+ "maxInputResourceBytes must be a nonnegative safe integer or Infinity"
2596
+ );
2597
+ }
2598
+ reportProgress("inspect");
2599
+ const inspection = await inspectTileset(source, signal);
2600
+ for await (const inputResource of source.read(inspection, signal)) {
2601
+ throwIfAborted(signal);
2602
+ const inputResourceBytes = measureInputBytes(inputResource);
2603
+ if (!Number.isSafeInteger(inputResourceBytes) || inputResourceBytes < 0) {
2604
+ throw new TileConversionError(
2605
+ "INVALID_INPUT_RESOURCE_SIZE",
2606
+ "measureInputBytes must return a nonnegative safe integer"
2607
+ );
2608
+ }
2609
+ if (inputResourceBytes > maxInputResourceBytes) {
2610
+ throw new TileConversionError(
2611
+ "INPUT_RESOURCE_TOO_LARGE",
2612
+ `Input resource is ${inputResourceBytes} bytes, exceeding the configured limit of ${maxInputResourceBytes} bytes`
2613
+ );
2614
+ }
2615
+ inputResources++;
2616
+ inputBytes += inputResourceBytes;
2617
+ reportProgress("convert");
2618
+ const convertedResources = await codec.convert(inputResource, inspection, signal);
2619
+ for await (const outputResource of convertedResources) {
2620
+ throwIfAborted(signal);
2621
+ reportProgress("validate");
2622
+ const resourceDiagnostics = await codec.validateOutput?.(outputResource, signal) || [];
2623
+ diagnostics.push(...resourceDiagnostics);
2624
+ const outputResourceBytes = measureOutputBytes(outputResource);
2625
+ largestOutputResourceBytes = Math.max(largestOutputResourceBytes, outputResourceBytes);
2626
+ if (outputResourceBytes > maxOutputResourceBytes) {
2627
+ throw new TileConversionError(
2628
+ "OUTPUT_RESOURCE_TOO_LARGE",
2629
+ `Output resource is ${outputResourceBytes} bytes, exceeding the configured limit of ${maxOutputResourceBytes} bytes`
2630
+ );
2631
+ }
2632
+ if (resourceDiagnostics.some((diagnostic) => diagnostic.severity === "error")) {
2633
+ throw new TileConversionError(
2634
+ "OUTPUT_VALIDATION_FAILED",
2635
+ "Output resource validation failed",
2636
+ resourceDiagnostics
2637
+ );
2638
+ }
2639
+ throwIfAborted(signal);
2640
+ await sink.write(outputResource, signal);
2641
+ throwIfAborted(signal);
2642
+ outputResources++;
2643
+ outputBytes += outputResourceBytes;
2644
+ reportProgress("convert");
2645
+ }
2646
+ }
2647
+ const report = {
2648
+ state: "completed",
2649
+ inputResources,
2650
+ outputResources,
2651
+ inputBytes,
2652
+ outputBytes,
2653
+ largestOutputResourceBytes,
2654
+ diagnostics
2655
+ };
2656
+ throwIfAborted(signal);
2657
+ reportProgress("finalize");
2658
+ await sink.finalize(report);
2659
+ return report;
2660
+ } catch (error) {
2661
+ try {
2662
+ await sink.abort(error);
2663
+ } catch (abortError) {
2664
+ throw new AggregateError(
2665
+ [error, abortError],
2666
+ "Conversion failed and the destination could not abort"
2667
+ );
2668
+ }
2669
+ throw error;
2670
+ }
2671
+ }
2672
+ async function validateTileset(options) {
2673
+ throwIfAborted(options.signal);
2674
+ const diagnostics = await options.validate(options.tileset, options.signal);
2675
+ throwIfAborted(options.signal);
2676
+ return {
2677
+ valid: !diagnostics.some((diagnostic) => diagnostic.severity === "error"),
2678
+ diagnostics
2679
+ };
2680
+ }
2681
+ function throwIfAborted(signal) {
2682
+ if (signal?.aborted) {
2683
+ throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
2684
+ }
2685
+ }
2686
+
2687
+ // src/v5/tileset-source.ts
2688
+ init_src2();
2689
+ function createTilesetConversionSource(tileset, options = {}) {
2690
+ return {
2691
+ async inspect(signal) {
2692
+ signal?.throwIfAborted();
2693
+ await tileset.tilesetInitializationPromise;
2694
+ signal?.throwIfAborted();
2695
+ if (!tileset.root) {
2696
+ throw new TileConversionError(
2697
+ "TILESET_ROOT_REQUIRED",
2698
+ "Tileset initialization completed without a root tile"
2699
+ );
2700
+ }
2701
+ return tileset.source.getMetadata();
2702
+ },
2703
+ read: (_inspection, signal) => traverseTilesetContents(tileset, { unloadContent: options.unloadContent, signal })
2704
+ };
2705
+ }
2706
+
2707
+ // src/v5/spatial-conversion.ts
2708
+ init_src2();
2709
+ import { Matrix4 as Matrix43 } from "@math.gl/core";
2710
+ function createTiles3DConversionSpatialContext(discovered, options = {}) {
2711
+ const spatialReference = createConversionSpatialReference(discovered, options);
2712
+ if (spatialReference.status === "unresolved") {
2713
+ throw createSpatialConversionError(spatialReference);
2714
+ }
2715
+ const transformer = spatialReference.status === "native" ? void 0 : createSpatialTransformer(
2716
+ spatialReference,
2717
+ () => new Tiles3DSpatialTransformer(spatialReference, options)
2718
+ );
2719
+ const outputSpatialReference = transformer ? markTilesetSpatialReferenceTransformed(spatialReference) : spatialReference;
2720
+ return {
2721
+ spatialReference: outputSpatialReference,
2722
+ transformPositions: (positions) => transformer ? transformer.transformPositions(positions) : Float64Array.from(positions),
2723
+ transformNormals: (normals, positions) => transformer ? transformer.transformNormals(normals, positions) : Float32Array.from(normals),
2724
+ transformBoundingVolume: (volume, sourceTransform) => transformer ? transformer.transformBoundingVolume(volume, sourceTransform) : cloneBoundingVolume(volume)
2725
+ };
2726
+ }
2727
+ function createI3SConversionSpatialContext(discovered, options = {}) {
2728
+ const spatialReference = createConversionSpatialReference(discovered, options);
2729
+ if (spatialReference.status === "unresolved") {
2730
+ throw createSpatialConversionError(spatialReference);
2731
+ }
2732
+ const transformer = spatialReference.status === "native" ? void 0 : createSpatialTransformer(
2733
+ spatialReference,
2734
+ () => new I3SSpatialTransformer(spatialReference, options)
2735
+ );
2736
+ const outputSpatialReference = transformer ? transformer.spatialReference : spatialReference;
2737
+ return {
2738
+ spatialReference: outputSpatialReference,
2739
+ transformPositions: (positions, sourceOrigin) => transformer ? transformer.transformPositions(positions, sourceOrigin) : createNativeI3SPositions(positions, sourceOrigin, spatialReference),
2740
+ transformPositionsAsync: (positions, sourceOrigin) => transformer ? transformer.transformPositionsAsync(positions, sourceOrigin) : Promise.resolve(createNativeI3SPositions(positions, sourceOrigin, spatialReference)),
2741
+ transformNormals: (normals, positions, normalReferenceFrame) => transformer ? transformer.transformNormals(normals, positions, normalReferenceFrame) : Float32Array.from(normals),
2742
+ transformBoundingVolume: (bounds) => transformer ? transformer.transformBoundingVolume(bounds) : cloneI3SBounds(bounds),
2743
+ transformBoundingVolumeAsync: (bounds) => transformer ? transformer.transformBoundingVolumeAsync(bounds) : Promise.resolve(cloneI3SBounds(bounds))
2744
+ };
2745
+ }
2746
+ function createSpatialConversionError(spatialReference, cause) {
2747
+ const diagnostics = spatialReference.warnings.map((message2) => ({
2748
+ code: "SPATIAL_REFERENCE_WARNING",
2749
+ message: message2,
2750
+ severity: "warning"
2751
+ }));
2752
+ const causeMessage = cause instanceof Error ? `: ${cause.message}` : "";
2753
+ const message = causeMessage ? `Spatial conversion could not be initialized${causeMessage}` : "The requested spatial conversion cannot be resolved from the available metadata";
2754
+ diagnostics.push({
2755
+ code: "SPATIAL_REFERENCE_UNRESOLVED",
2756
+ message,
2757
+ severity: "error"
2758
+ });
2759
+ return new TileConversionError("SPATIAL_REFERENCE_UNRESOLVED", message, diagnostics);
2760
+ }
2761
+ function createConversionSpatialReference(discovered, options) {
2762
+ if (!("status" in discovered)) {
2763
+ return createTilesetSpatialReference(discovered, options);
2764
+ }
2765
+ if (discovered.status === "transformed") {
2766
+ throw createSpatialConversionError(
2767
+ discovered,
2768
+ new Error("coordinates are already transformed")
2769
+ );
2770
+ }
2771
+ const sourceMetadata = {
2772
+ sourceCrs: discovered.sourceCrs,
2773
+ sourceCrsState: discovered.crs.state,
2774
+ sourceCrsRepresentation: discovered.crs.state === "explicit" || discovered.crs.state === "default" ? discovered.crs.representation : void 0,
2775
+ sourceCrsAlternatives: discovered.crs.state === "explicit" || discovered.crs.state === "default" ? discovered.crs.alternatives : void 0,
2776
+ verticalCrs: discovered.verticalCrs,
2777
+ units: discovered.units,
2778
+ verticalUnitScale: discovered.verticalUnitScale,
2779
+ coordinateEpoch: discovered.coordinateEpoch,
2780
+ heightReference: discovered.heightReference,
2781
+ elevationMode: discovered.elevationMode,
2782
+ elevationOffset: discovered.elevationOffset,
2783
+ elevationUnit: discovered.elevationUnit,
2784
+ elevationUnitScale: discovered.elevationUnitScale,
2785
+ coordinateFrame: discovered.coordinateFrame,
2786
+ axisOrder: discovered.axisOrder,
2787
+ provenance: discovered.provenance,
2788
+ warnings: discovered.warnings
2789
+ };
2790
+ const retainedOptions = {
2791
+ ...options,
2792
+ targetCrs: options.targetCrs ?? discovered.targetCrs,
2793
+ targetHeightReference: options.targetHeightReference ?? discovered.targetHeightReference,
2794
+ outputCoordinates: options.outputCoordinates ?? discovered.outputCoordinates
2795
+ };
2796
+ return createTilesetSpatialReference(sourceMetadata, retainedOptions);
2797
+ }
2798
+ function createSpatialTransformer(spatialReference, createTransformer) {
2799
+ try {
2800
+ return createTransformer();
2801
+ } catch (error) {
2802
+ throw createSpatialConversionError(spatialReference, error);
2803
+ }
2804
+ }
2805
+ function cloneBoundingVolume(volume) {
2806
+ return {
2807
+ ...volume,
2808
+ box: volume.box ? [...volume.box] : void 0,
2809
+ sphere: volume.sphere ? [...volume.sphere] : void 0,
2810
+ region: volume.region ? [...volume.region] : void 0
2811
+ };
2812
+ }
2813
+ function cloneI3SBounds(bounds) {
2814
+ return {
2815
+ ...bounds,
2816
+ mbs: bounds.mbs ? Array.from(bounds.mbs) : void 0,
2817
+ obb: bounds.obb ? {
2818
+ center: Array.from(bounds.obb.center),
2819
+ halfSize: Array.from(bounds.obb.halfSize),
2820
+ quaternion: Array.from(bounds.obb.quaternion)
2821
+ } : void 0
2822
+ };
2823
+ }
2824
+ function createNativeI3SPositions(sourcePositions, sourceOrigin, spatialReference) {
2825
+ if (sourcePositions.length % 3 !== 0 || sourceOrigin.length < 3) {
2826
+ throw new Error("I3S positions and origin must contain complete xyz coordinates");
2827
+ }
2828
+ const origin = [
2829
+ Number(sourceOrigin[0]),
2830
+ Number(sourceOrigin[1]),
2831
+ Number(sourceOrigin[2])
2832
+ ];
2833
+ const sourcePositions64 = Float64Array.from(sourcePositions);
2834
+ const positions = new Float32Array(sourcePositions.length);
2835
+ for (let index = 0; index < sourcePositions.length; index += 3) {
2836
+ positions[index] = Number(sourcePositions[index]) - origin[0];
2837
+ positions[index + 1] = Number(sourcePositions[index + 1]) - origin[1];
2838
+ positions[index + 2] = Number(sourcePositions[index + 2]) - origin[2];
2839
+ }
2840
+ const isGeographic = spatialReference.coordinateFrame === "geographic";
2841
+ const modelMatrix = isGeographic ? new Matrix43() : new Matrix43().translate(origin);
2842
+ return {
2843
+ positions,
2844
+ sourcePositions: sourcePositions64,
2845
+ origin,
2846
+ cartographicOrigin: isGeographic ? origin : [0, 0, 0],
2847
+ coordinateSystem: isGeographic ? "lnglat-offsets" : "cartesian",
2848
+ modelMatrix
2849
+ };
2850
+ }
2851
+
2852
+ // src/v5/feature-arrow.ts
2853
+ init_src4();
2854
+ var DEFAULT_FEATURE_ID_FIELD = "feature_id";
2855
+ var FEATURE_CLASS_METADATA_KEY = "loaders.gl:feature-class";
2856
+ function convertFeatureAttributesToArrowBatches(features, options) {
2857
+ const featureIdField = options.featureIdField || DEFAULT_FEATURE_ID_FIELD;
2858
+ const batchSize = options.batchSize ?? 65536;
2859
+ if (!Number.isInteger(batchSize) || batchSize <= 0) {
2860
+ throw new TileConversionError(
2861
+ "INVALID_FEATURE_BATCH_SIZE",
2862
+ "Feature Arrow batch size must be a positive integer"
2863
+ );
2864
+ }
2865
+ const featureClasses = new Set(features.map((feature) => feature.metadataClass));
2866
+ if (featureClasses.size > 1) {
2867
+ throw new TileConversionError(
2868
+ "MULTIPLE_FEATURE_CLASSES",
2869
+ "Build separate Arrow batches for each source metadata class"
2870
+ );
2871
+ }
2872
+ const metadataClass = features[0]?.metadataClass;
2873
+ const schema = makeFeatureSchema(
2874
+ options.schema,
2875
+ featureIdField,
2876
+ options.rawMetadataField,
2877
+ metadataClass
2878
+ );
2879
+ const fieldsByName = new Map(schema.fields.map((field) => [field.name, field]));
2880
+ const propertyFieldNames = new Set(
2881
+ schema.fields.filter((field) => field.name !== featureIdField && field.name !== options.rawMetadataField).map((field) => field.name)
2882
+ );
2883
+ for (const feature of features) {
2884
+ validateFeatureIdentifier(feature.featureId, fieldsByName.get(featureIdField)?.type);
2885
+ if (feature.rawMetadata && !options.rawMetadataField) {
2886
+ throw new TileConversionError(
2887
+ "RAW_METADATA_FIELD_REQUIRED",
2888
+ "A rawMetadataField must be declared to preserve encoded source metadata"
2889
+ );
2890
+ }
2891
+ for (const propertyName of Object.keys(feature.properties)) {
2892
+ if (!propertyFieldNames.has(propertyName)) {
2893
+ throw new TileConversionError(
2894
+ "FEATURE_PROPERTY_NOT_MAPPED",
2895
+ `Feature property "${propertyName}" is not declared in the Arrow schema`
2896
+ );
2897
+ }
2898
+ }
2899
+ }
2900
+ const batches = [];
2901
+ for (let batchStart = 0; batchStart < features.length; batchStart += batchSize) {
2902
+ const tableBuilder = new ArrowTableBuilder(schema);
2903
+ const batchFeatures = features.slice(batchStart, batchStart + batchSize);
2904
+ for (const feature of batchFeatures) {
2905
+ const row = {
2906
+ ...feature.properties,
2907
+ [featureIdField]: feature.featureId
2908
+ };
2909
+ if (options.rawMetadataField) {
2910
+ row[options.rawMetadataField] = feature.rawMetadata || null;
2911
+ }
2912
+ for (const field of schema.fields) {
2913
+ if (row[field.name] === void 0) {
2914
+ row[field.name] = null;
2915
+ }
2916
+ validateFeatureValue(field, row[field.name], field.name);
2917
+ }
2918
+ tableBuilder.addObjectRow(row);
2919
+ }
2920
+ const batch = tableBuilder.finishBatch();
2921
+ if (batch) {
2922
+ batches.push(batch);
2923
+ }
2924
+ }
2925
+ return batches;
2926
+ }
2927
+ function makeFeatureSchema(sourceSchema, featureIdField, rawMetadataField, metadataClass) {
2928
+ const fieldsByName = new Map(sourceSchema.fields.map((field) => [field.name, field]));
2929
+ if (fieldsByName.size !== sourceSchema.fields.length) {
2930
+ throw new TileConversionError(
2931
+ "DUPLICATE_FEATURE_FIELDS",
2932
+ "Arrow schema fields must have unique names"
2933
+ );
2934
+ }
2935
+ for (const field of sourceSchema.fields) {
2936
+ validateFeatureSchemaType(field);
2937
+ }
2938
+ const featureIdType = fieldsByName.get(featureIdField)?.type;
2939
+ if (!featureIdType) {
2940
+ throw new TileConversionError(
2941
+ "FEATURE_ID_FIELD_REQUIRED",
2942
+ `Arrow schema must declare the feature identifier field "${featureIdField}"`
2943
+ );
2944
+ }
2945
+ if (rawMetadataField && !fieldsByName.has(rawMetadataField)) {
2946
+ throw new TileConversionError(
2947
+ "RAW_METADATA_FIELD_NOT_DECLARED",
2948
+ `Arrow schema does not declare the raw metadata field "${rawMetadataField}"`
2949
+ );
2950
+ }
2951
+ if (rawMetadataField === featureIdField) {
2952
+ throw new TileConversionError(
2953
+ "FEATURE_FIELDS_COLLIDE",
2954
+ "The feature identifier and raw metadata require separate Arrow fields"
2955
+ );
2956
+ }
2957
+ if (rawMetadataField && !isBinaryType(fieldsByName.get(rawMetadataField)?.type)) {
2958
+ throw new TileConversionError(
2959
+ "RAW_METADATA_FIELD_NOT_BINARY",
2960
+ `Arrow schema field "${rawMetadataField}" must use binary or fixed-size-binary type`
2961
+ );
2962
+ }
2963
+ return {
2964
+ ...sourceSchema,
2965
+ metadata: {
2966
+ ...sourceSchema.metadata || {},
2967
+ ...metadataClass ? { [FEATURE_CLASS_METADATA_KEY]: metadataClass } : {}
2968
+ }
2969
+ };
2970
+ }
2971
+ function validateFeatureIdentifier(featureId, dataType) {
2972
+ const isStringIdentifier = typeof featureId === "string";
2973
+ const isIntegerIdentifier2 = typeof featureId === "bigint" || Number.isSafeInteger(featureId);
2974
+ const isStringType = dataType === "utf8" || dataType === "utf8-view";
2975
+ if (isStringIdentifier && isStringType || isIntegerIdentifier2 && isIntegerDataType(dataType)) {
2976
+ return;
2977
+ }
2978
+ throw new TileConversionError(
2979
+ "FEATURE_ID_TYPE_MISMATCH",
2980
+ `Feature identifier ${String(featureId)} is not compatible with the declared Arrow type`
2981
+ );
2982
+ }
2983
+ function validateFeatureValue(field, value, fieldPath) {
2984
+ if (value === null || value === void 0) {
2985
+ if (field.nullable !== true) {
2986
+ throw new TileConversionError(
2987
+ "FEATURE_VALUE_REQUIRED",
2988
+ `Required Arrow field "${fieldPath}" has no value`
2989
+ );
2990
+ }
2991
+ return;
2992
+ }
2993
+ const dataType = field.type;
2994
+ if (typeof dataType === "object") {
2995
+ if (dataType.type === "dictionary") {
2996
+ validateFeatureValue({ ...field, type: dataType.dictionary }, value, fieldPath);
2997
+ return;
2998
+ }
2999
+ if (dataType.type === "list" || dataType.type === "large-list") {
3000
+ if (!Array.isArray(value)) {
3001
+ throw createFeatureValueTypeError(fieldPath, "an array");
3002
+ }
3003
+ const childField = dataType.children[0];
3004
+ for (let index = 0; index < value.length; index++) {
3005
+ validateFeatureValue(childField, value[index], `${fieldPath}[${index}]`);
3006
+ }
3007
+ return;
3008
+ }
3009
+ if (dataType.type === "fixed-size-list") {
3010
+ if (!Array.isArray(value) || value.length !== dataType.listSize) {
3011
+ throw createFeatureValueTypeError(fieldPath, `an array of length ${dataType.listSize}`);
3012
+ }
3013
+ const childField = dataType.children[0];
3014
+ for (let index = 0; index < value.length; index++) {
3015
+ validateFeatureValue(childField, value[index], `${fieldPath}[${index}]`);
3016
+ }
3017
+ return;
3018
+ }
3019
+ if (dataType.type === "struct") {
3020
+ if (!isRecord(value)) {
3021
+ throw createFeatureValueTypeError(fieldPath, "an object");
3022
+ }
3023
+ const childNames = new Set(dataType.children.map((childField) => childField.name));
3024
+ const unknownNames = Object.keys(value).filter((name) => !childNames.has(name));
3025
+ if (unknownNames.length > 0) {
3026
+ throw new TileConversionError(
3027
+ "FEATURE_PROPERTY_NOT_MAPPED",
3028
+ `Nested feature properties "${unknownNames.join(", ")}" are not declared under "${fieldPath}"`
3029
+ );
3030
+ }
3031
+ for (const childField of dataType.children) {
3032
+ validateFeatureValue(childField, value[childField.name], `${fieldPath}.${childField.name}`);
3033
+ }
3034
+ return;
3035
+ }
3036
+ if (dataType.type === "decimal") {
3037
+ if (typeof value !== "bigint") {
3038
+ throw createFeatureValueTypeError(fieldPath, "an unscaled bigint decimal value");
3039
+ }
3040
+ if (value <= -(10n ** BigInt(dataType.precision)) || value >= 10n ** BigInt(dataType.precision)) {
3041
+ throw new TileConversionError(
3042
+ "FEATURE_VALUE_OUT_OF_RANGE",
3043
+ `Value for Arrow decimal field "${fieldPath}" exceeds precision ${dataType.precision}`
3044
+ );
3045
+ }
3046
+ return;
3047
+ }
3048
+ if (dataType.type === "fixed-size-binary") {
3049
+ const byteLength = getByteLength(value);
3050
+ if (byteLength !== dataType.byteWidth) {
3051
+ throw createFeatureValueTypeError(fieldPath, `exactly ${dataType.byteWidth} bytes`);
3052
+ }
3053
+ return;
3054
+ }
3055
+ throw new TileConversionError(
3056
+ "FEATURE_VALUE_MAPPING_UNSUPPORTED",
3057
+ `Arrow schema type "${dataType.type}" has no feature value mapping for "${fieldPath}"`
3058
+ );
3059
+ }
3060
+ if (isIntegerDataType(dataType)) {
3061
+ if (!isIntegerIdentifier(value)) {
3062
+ throw createFeatureValueTypeError(fieldPath, "an integer");
3063
+ }
3064
+ const [minimum, maximum] = getIntegerBounds(dataType);
3065
+ const integerValue = typeof value === "bigint" ? value : BigInt(value);
3066
+ if (integerValue < minimum || integerValue > maximum) {
3067
+ throw new TileConversionError(
3068
+ "FEATURE_VALUE_OUT_OF_RANGE",
3069
+ `Value for Arrow field "${fieldPath}" is outside the range of ${dataType}`
3070
+ );
3071
+ }
3072
+ return;
3073
+ }
3074
+ if (dataType === "utf8" || dataType === "utf8-view") {
3075
+ if (typeof value !== "string") throw createFeatureValueTypeError(fieldPath, "a string");
3076
+ return;
3077
+ }
3078
+ if (dataType === "bool") {
3079
+ if (typeof value !== "boolean") throw createFeatureValueTypeError(fieldPath, "a boolean");
3080
+ return;
3081
+ }
3082
+ if (dataType === "binary" || dataType === "binary-view") {
3083
+ if (getByteLength(value) < 0) throw createFeatureValueTypeError(fieldPath, "binary data");
3084
+ return;
3085
+ }
3086
+ if (dataType === "float" || dataType === "float16" || dataType === "float32" || dataType === "float64") {
3087
+ if (typeof value !== "number") throw createFeatureValueTypeError(fieldPath, "a number");
3088
+ return;
3089
+ }
3090
+ if (dataType === "null") {
3091
+ throw createFeatureValueTypeError(fieldPath, "null");
3092
+ }
3093
+ if (dataType === "date-day" || dataType === "date-millisecond" || dataType.startsWith("timestamp-")) {
3094
+ if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {
3095
+ throw createFeatureValueTypeError(fieldPath, "a valid Date");
3096
+ }
3097
+ return;
3098
+ }
3099
+ throw new TileConversionError(
3100
+ "FEATURE_VALUE_MAPPING_UNSUPPORTED",
3101
+ `Arrow schema type "${dataType}" has no feature value mapping for "${fieldPath}"`
3102
+ );
3103
+ }
3104
+ function isIntegerIdentifier(value) {
3105
+ return typeof value === "bigint" || typeof value === "number" && Number.isSafeInteger(value);
3106
+ }
3107
+ function isIntegerDataType(dataType) {
3108
+ return dataType === "int8" || dataType === "int16" || dataType === "int32" || dataType === "int64" || dataType === "uint8" || dataType === "uint16" || dataType === "uint32" || dataType === "uint64";
3109
+ }
3110
+ function validateFeatureSchemaType(field) {
3111
+ const dataType = field.type;
3112
+ if (dataType === "int") {
3113
+ throw new TileConversionError(
3114
+ "FEATURE_INTEGER_TYPE_UNSUPPORTED",
3115
+ `Arrow field "${field.name}" must declare an explicit integer width and signedness`
3116
+ );
3117
+ }
3118
+ if (typeof dataType !== "object") {
3119
+ return;
3120
+ }
3121
+ let childFields = [];
3122
+ if (dataType.type === "dictionary" && dataType.indices) {
3123
+ childFields = [{ name: `${field.name} index`, type: dataType.indices, nullable: false }];
3124
+ } else if ("children" in dataType) {
3125
+ childFields = dataType.children;
3126
+ }
3127
+ for (const childField of childFields) {
3128
+ validateFeatureSchemaType(childField);
3129
+ }
3130
+ }
3131
+ function getIntegerBounds(dataType) {
3132
+ switch (dataType) {
3133
+ case "int8":
3134
+ return [-128n, 127n];
3135
+ case "uint8":
3136
+ return [0n, 255n];
3137
+ case "int16":
3138
+ return [-32768n, 32767n];
3139
+ case "uint16":
3140
+ return [0n, 65535n];
3141
+ case "int32":
3142
+ return [-2147483648n, 2147483647n];
3143
+ case "uint32":
3144
+ return [0n, 4294967295n];
3145
+ case "int64":
3146
+ return [-(2n ** 63n), 2n ** 63n - 1n];
3147
+ case "uint64":
3148
+ return [0n, 2n ** 64n - 1n];
3149
+ default:
3150
+ return [-(2n ** 31n), 2n ** 31n - 1n];
3151
+ }
3152
+ }
3153
+ function createFeatureValueTypeError(fieldPath, expected) {
3154
+ return new TileConversionError(
3155
+ "FEATURE_VALUE_TYPE_MISMATCH",
3156
+ `Arrow field "${fieldPath}" requires ${expected}`
3157
+ );
3158
+ }
3159
+ function isRecord(value) {
3160
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3161
+ }
3162
+ function getByteLength(value) {
3163
+ if (value instanceof Uint8Array) return value.byteLength;
3164
+ if (value instanceof ArrayBuffer) return value.byteLength;
3165
+ return -1;
3166
+ }
3167
+ function isBinaryType(dataType) {
3168
+ return dataType === "binary" || dataType === "binary-view" || typeof dataType === "object" && dataType.type === "fixed-size-binary";
3169
+ }
3170
+
3171
+ // ../../modules/3d-tiles/src/tile-3d-writer.ts
3172
+ init_version();
3173
+
3174
+ // ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile.ts
3175
+ init_constants();
3176
+ init_src();
3177
+
3178
+ // ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-composite.ts
3179
+ init_constants();
3180
+
3181
+ // ../../modules/3d-tiles/src/lib/encoders/helpers/encode-3d-tile-header.ts
3182
+ init_src();
3183
+ function encode3DTileHeader(tile, dataView, byteOffset) {
3184
+ const HEADER_SIZE = 12;
3185
+ if (!dataView) {
3186
+ return byteOffset + HEADER_SIZE;
3187
+ }
3188
+ const { magic, version = 1, byteLength = 12 } = tile;
3189
+ assert(Array.isArray(magic) && Number.isFinite(version) && Number.isFinite(byteLength));
3190
+ dataView.setUint8(byteOffset + 0, magic[0]);
3191
+ dataView.setUint8(byteOffset + 1, magic[1]);
3192
+ dataView.setUint8(byteOffset + 2, magic[2]);
3193
+ dataView.setUint8(byteOffset + 3, magic[3]);
3194
+ dataView.setUint32(byteOffset + 4, version, true);
3195
+ dataView.setUint32(byteOffset + 8, byteLength, true);
3196
+ byteOffset += HEADER_SIZE;
3197
+ return byteOffset;
3198
+ }
3199
+ function encode3DTileByteLength(dataView, byteOffsetTileStart, byteLength) {
3200
+ if (!dataView) {
3201
+ return;
3202
+ }
3203
+ dataView.setUint32(byteOffsetTileStart + 8, byteLength, true);
3204
+ }
3205
+
3206
+ // ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-composite.ts
3207
+ function encodeComposite3DTile(tile, dataView, byteOffset, options, encode3DTile2) {
3208
+ tile = { magic: MAGIC_ARRAY.COMPOSITE, tiles: [], ...tile };
3209
+ const byteOffsetStart = byteOffset;
3210
+ byteOffset += encode3DTileHeader(tile, dataView, byteOffset);
3211
+ if (dataView) {
3212
+ dataView.setUint32(byteOffset, tile.tiles.length, true);
3213
+ }
3214
+ byteOffset += 4;
3215
+ for (let i = 0; i < tile.tiles.length; ++i) {
3216
+ byteOffset += encode3DTile2(tile.tiles[i], dataView, byteOffset, options);
3217
+ }
3218
+ encode3DTileByteLength(dataView, byteOffsetStart, byteOffset - byteOffsetStart);
3219
+ return byteOffset;
3220
+ }
3221
+
3222
+ // ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-batched-model.ts
3223
+ init_src();
3224
+ init_constants();
3225
+ function encodeBatchedModel3DTile(tile, dataView, byteOffset, options) {
3226
+ const { featuresLength = 0, batchTable } = tile;
3227
+ const featureTableJson = {
3228
+ BATCH_LENGTH: featuresLength
3229
+ };
3230
+ const featureTableJsonString = JSON.stringify(featureTableJson);
3231
+ const batchTableJsonString = batchTable ? JSON.stringify(batchTable) : "";
3232
+ const featureTableJsonByteLength = padToNBytes(featureTableJsonString.length, 8);
3233
+ const batchTableJsonByteLength = batchTableJsonString ? padToNBytes(batchTableJsonString.length, 8) : 0;
3234
+ tile = { magic: MAGIC_ARRAY.BATCHED_MODEL, ...tile };
3235
+ const byteOffsetStart = byteOffset;
3236
+ byteOffset = encode3DTileHeader(tile, dataView, byteOffset);
3237
+ if (dataView) {
3238
+ dataView.setUint32(12, featureTableJsonByteLength, true);
3239
+ dataView.setUint32(16, 0, true);
3240
+ dataView.setUint32(20, batchTableJsonByteLength, true);
3241
+ dataView.setUint32(24, 0, true);
3242
+ }
3243
+ byteOffset += 16;
3244
+ byteOffset = copyPaddedStringToDataView(dataView, byteOffset, featureTableJsonString, 8);
3245
+ if (batchTable) {
3246
+ byteOffset = copyPaddedStringToDataView(dataView, byteOffset, batchTableJsonString, 8);
3247
+ }
3248
+ const gltfEncoded = tile.gltfEncoded;
3249
+ if (gltfEncoded) {
3250
+ byteOffset = copyBinaryToDataView(dataView, byteOffset, gltfEncoded, gltfEncoded.byteLength);
3251
+ }
3252
+ encode3DTileByteLength(dataView, byteOffsetStart, byteOffset - byteOffsetStart);
3253
+ return byteOffset;
3254
+ }
3255
+
3256
+ // ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-instanced-model.ts
3257
+ init_src();
3258
+ init_constants();
3259
+ function encodeInstancedModel3DTile(tile, dataView, byteOffset, options) {
3260
+ const { featuresLength = 1, gltfFormat = 1, gltfUri = "" } = tile;
3261
+ const gltfUriByteLength = gltfUri.length;
3262
+ const featureTableJson = {
3263
+ INSTANCES_LENGTH: featuresLength,
3264
+ POSITION: new Array(featuresLength * 3).fill(0)
3265
+ };
3266
+ const featureTableJsonString = JSON.stringify(featureTableJson);
3267
+ const featureTableJsonByteLength = featureTableJsonString.length;
3268
+ tile = { magic: MAGIC_ARRAY.INSTANCED_MODEL, ...tile };
3269
+ const byteOffsetStart = byteOffset;
3270
+ byteOffset = encode3DTileHeader(tile, dataView, 0);
3271
+ if (dataView) {
3272
+ dataView.setUint32(12, featureTableJsonByteLength, true);
3273
+ dataView.setUint32(16, 0, true);
3274
+ dataView.setUint32(20, 0, true);
3275
+ dataView.setUint32(24, 0, true);
3276
+ dataView.setUint32(28, gltfFormat, true);
3277
+ }
3278
+ byteOffset += 20;
3279
+ byteOffset += copyStringToDataView(
3280
+ dataView,
3281
+ byteOffset,
3282
+ featureTableJsonString,
3283
+ featureTableJsonByteLength
3284
+ );
3285
+ byteOffset += copyStringToDataView(dataView, byteOffset, gltfUri, gltfUriByteLength);
3286
+ encode3DTileByteLength(dataView, byteOffsetStart, byteOffset - byteOffsetStart);
3287
+ return byteOffset;
3288
+ }
3289
+
3290
+ // ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile-point-cloud.ts
3291
+ init_constants();
3292
+ init_src();
3293
+ var DEFAULT_FEATURE_TABLE_JSON = {
3294
+ POINTS_LENGTH: 1,
3295
+ POSITIONS: {
3296
+ byteOffset: 0
3297
+ }
3298
+ };
3299
+ function encodePointCloud3DTile(tile, dataView, byteOffset, options) {
3300
+ const pointData = getPointCloudFeatureTable(tile);
3301
+ const featureTableJsonString = padStringToByteAlignment(JSON.stringify(pointData.json), 4);
3302
+ const featureTableJsonByteLength = tile.featureTableJsonByteLength ?? featureTableJsonString.length;
3303
+ const featureTableBinary = pointData.binary;
3304
+ const featureTableBinaryByteLength = featureTableBinary.byteLength;
3305
+ const batchTableJsonString = tile.batchTableJson ? JSON.stringify(tile.batchTableJson) : "";
3306
+ const batchTableJsonByteLength = batchTableJsonString ? padStringToByteAlignment(batchTableJsonString, 4).length : 0;
3307
+ const paddedBatchTableJsonString = batchTableJsonByteLength ? padStringToByteAlignment(batchTableJsonString, 4) : "";
3308
+ const batchTableBinary = tile.batchTableBinary || new Uint8Array();
3309
+ tile = { magic: MAGIC_ARRAY.POINT_CLOUD, ...tile };
3310
+ const byteOffsetStart = byteOffset;
3311
+ byteOffset = encode3DTileHeader(tile, dataView, byteOffset);
3312
+ if (dataView) {
3313
+ dataView.setUint32(byteOffset + 0, featureTableJsonByteLength, true);
3314
+ dataView.setUint32(byteOffset + 4, featureTableBinaryByteLength, true);
3315
+ dataView.setUint32(byteOffset + 8, batchTableJsonByteLength, true);
3316
+ dataView.setUint32(byteOffset + 12, batchTableBinary.byteLength, true);
3317
+ }
3318
+ byteOffset += 16;
3319
+ byteOffset = copyStringToDataView(
3320
+ dataView,
3321
+ byteOffset,
3322
+ featureTableJsonString,
3323
+ featureTableJsonByteLength
3324
+ );
3325
+ byteOffset = copyBinaryToDataView(
3326
+ dataView,
3327
+ byteOffset,
3328
+ featureTableBinary,
3329
+ featureTableBinaryByteLength
3330
+ );
3331
+ if (batchTableJsonByteLength > 0) {
3332
+ byteOffset = copyStringToDataView(
3333
+ dataView,
3334
+ byteOffset,
3335
+ paddedBatchTableJsonString,
3336
+ batchTableJsonByteLength
3337
+ );
3338
+ }
3339
+ byteOffset = copyBinaryToDataView(
3340
+ dataView,
3341
+ byteOffset,
3342
+ batchTableBinary,
3343
+ batchTableBinary.byteLength
3344
+ );
3345
+ encode3DTileByteLength(dataView, byteOffsetStart, byteOffset - byteOffsetStart);
3346
+ return byteOffset;
3347
+ }
3348
+ function getPointCloudFeatureTable(tile) {
3349
+ const positions = tile.attributes?.positions;
3350
+ if (!positions) {
3351
+ const json2 = tile.featureTableJson || DEFAULT_FEATURE_TABLE_JSON;
3352
+ return { json: json2, binary: new Uint8Array(12) };
3353
+ }
3354
+ if (positions.length === 0 || positions.length % 3 !== 0) {
3355
+ throw new Error("3D Tiles point cloud positions must contain one or more xyz triples");
3356
+ }
3357
+ const pointCount = positions.length / 3;
3358
+ const properties = [];
3359
+ properties.push({ name: "POSITION", alignment: 4, bytes: encodeFloat32Array(positions) });
3360
+ const colors = tile.attributes?.colors;
3361
+ if (colors) {
3362
+ const colorValues = Array.isArray(colors) ? colors : colors.value;
3363
+ const colorSize = Array.isArray(colors) ? colorValues.length / pointCount : colors.size;
3364
+ if (colorSize !== 3 && colorSize !== 4) {
3365
+ throw new Error("3D Tiles point cloud colors must contain RGB or RGBA values");
3366
+ }
3367
+ const colorBytes = encodeColorBytes(
3368
+ colorValues,
3369
+ !Array.isArray(colors) && colors.normalized,
3370
+ pointCount,
3371
+ colorSize
3372
+ );
3373
+ properties.push({ name: colorSize === 4 ? "RGBA" : "RGB", alignment: 1, bytes: colorBytes });
3374
+ }
3375
+ const normals = tile.attributes?.normals;
3376
+ if (normals) {
3377
+ const normalValues = Array.isArray(normals) ? normals : normals.value;
3378
+ if (normalValues.length !== pointCount * 3) {
3379
+ throw new Error("3D Tiles point cloud normal count does not match the position count");
3380
+ }
3381
+ properties.push({ name: "NORMAL", alignment: 4, bytes: encodeFloat32Array(normalValues) });
3382
+ }
3383
+ const batchIds = tile.attributes?.batchIds;
3384
+ let batchLength = 0;
3385
+ if (batchIds) {
3386
+ if (batchIds.length !== pointCount) {
3387
+ throw new Error("3D Tiles point cloud batch ID count does not match the position count");
3388
+ }
3389
+ const batchIdValues = new Uint16Array(batchIds.length);
3390
+ for (let index = 0; index < batchIds.length; index++) {
3391
+ const batchId = batchIds[index];
3392
+ if (!Number.isInteger(batchId) || batchId < 0 || batchId > 65535) {
3393
+ throw new Error("3D Tiles point cloud batch IDs must be unsigned 16-bit integers");
3394
+ }
3395
+ batchIdValues[index] = batchId;
3396
+ batchLength = Math.max(batchLength, batchId + 1);
3397
+ }
3398
+ const batchIdBytes = new Uint8Array(batchIdValues.length * 2);
3399
+ const dataView = new DataView(batchIdBytes.buffer);
3400
+ for (let index = 0; index < batchIdValues.length; index++) {
3401
+ dataView.setUint16(index * 2, batchIdValues[index], true);
3402
+ }
3403
+ properties.push({ name: "BATCH_ID", alignment: 2, bytes: batchIdBytes });
3404
+ }
3405
+ const json = {
3406
+ ...tile.featureTableJson || {},
3407
+ POINTS_LENGTH: pointCount
3408
+ };
3409
+ if (batchIds) {
3410
+ json.BATCH_LENGTH = batchLength;
3411
+ }
3412
+ const binaryByteLength = getPointCloudFeatureTableByteLength(properties);
3413
+ const binary = new Uint8Array(binaryByteLength);
3414
+ let byteOffset = 0;
3415
+ for (const property of properties) {
3416
+ byteOffset = align(byteOffset, property.alignment);
3417
+ json[property.name] = { byteOffset };
3418
+ binary.set(property.bytes, byteOffset);
3419
+ byteOffset += property.bytes.byteLength;
3420
+ }
3421
+ return { json, binary };
3422
+ }
3423
+ function getPointCloudFeatureTableByteLength(properties) {
3424
+ let byteLength = 0;
3425
+ for (const property of properties) {
3426
+ byteLength = align(byteLength, property.alignment) + property.bytes.byteLength;
3427
+ }
3428
+ return byteLength;
3429
+ }
3430
+ function align(byteOffset, alignment) {
3431
+ return Math.ceil(byteOffset / alignment) * alignment;
3432
+ }
3433
+ function encodeFloat32Array(values) {
3434
+ const bytes = new Uint8Array(values.length * 4);
3435
+ const dataView = new DataView(bytes.buffer);
3436
+ for (let index = 0; index < values.length; index++) {
3437
+ const value = values[index];
3438
+ if (!Number.isFinite(value)) {
3439
+ throw new Error("3D Tiles point cloud attributes must contain finite values");
3440
+ }
3441
+ dataView.setFloat32(index * 4, value, true);
3442
+ }
3443
+ return bytes;
3444
+ }
3445
+ function encodeColorBytes(colors, normalized, pointCount, colorSize) {
3446
+ if (colors.length !== pointCount * colorSize) {
3447
+ throw new Error("3D Tiles point cloud color count does not match the position count");
3448
+ }
3449
+ const bytes = new Uint8Array(colors.length);
3450
+ for (let index = 0; index < colors.length; index++) {
3451
+ const value = colors[index];
3452
+ const scaledValue = normalized ? value * 255 : value;
3453
+ if (!Number.isFinite(scaledValue) || scaledValue < 0 || scaledValue > 255) {
3454
+ throw new Error("3D Tiles point cloud color components must be between 0 and 255");
3455
+ }
3456
+ bytes[index] = Math.round(scaledValue);
3457
+ }
3458
+ return bytes;
3459
+ }
3460
+
3461
+ // ../../modules/3d-tiles/src/lib/encoders/encode-3d-tile.ts
3462
+ function encode3DTile(tile, options) {
3463
+ const byteLength = encode3DTileToDataView(tile, null, 0, options);
3464
+ const arrayBuffer = new ArrayBuffer(byteLength);
3465
+ const dataView = new DataView(arrayBuffer);
3466
+ encode3DTileToDataView(tile, dataView, 0, options);
3467
+ return arrayBuffer;
3468
+ }
3469
+ function encode3DTileToDataView(tile, dataView, byteOffset, options) {
3470
+ assert(typeof tile.type === "string");
3471
+ switch (tile.type) {
3472
+ case TILE3D_TYPE.COMPOSITE:
3473
+ return encodeComposite3DTile(tile, dataView, byteOffset, options, encode3DTileToDataView);
3474
+ case TILE3D_TYPE.POINT_CLOUD:
3475
+ return encodePointCloud3DTile(tile, dataView, byteOffset, options);
3476
+ case TILE3D_TYPE.BATCHED_3D_MODEL:
3477
+ return encodeBatchedModel3DTile(tile, dataView, byteOffset, options);
3478
+ case TILE3D_TYPE.INSTANCED_3D_MODEL:
3479
+ return encodeInstancedModel3DTile(tile, dataView, byteOffset, options);
3480
+ default:
3481
+ throw new Error("3D Tiles: unknown tile type");
3482
+ }
3483
+ }
3484
+
3485
+ // ../../modules/3d-tiles/src/tile-3d-writer.ts
3486
+ var Tile3DWriter = {
3487
+ name: "3D Tile",
3488
+ id: "3d-tiles",
3489
+ module: "3d-tiles",
3490
+ version: VERSION,
3491
+ extensions: ["cmpt", "pnts", "b3dm", "i3dm"],
3492
+ mimeTypes: ["application/octet-stream"],
3493
+ binary: true,
3494
+ options: {
3495
+ ["3d-tiles"]: {}
3496
+ },
3497
+ encode: async (tile, options) => encodeSync(tile, options),
3498
+ encodeSync
3499
+ };
3500
+ function encodeSync(tile, options) {
3501
+ return encode3DTile(tile, options);
3502
+ }
3503
+
3504
+ // ../../modules/3d-tiles/src/index.ts
3505
+ init_constants();
3506
+
3507
+ // src/v5/point-cloud.ts
3508
+ init_src4();
3509
+ function encodePointCloudTile(pointBatch, options = {}) {
3510
+ const mesh = "attributes" in pointBatch ? pointBatch : convertTableToMesh(pointBatch);
3511
+ validatePointAttributes(mesh.attributes);
3512
+ const positionAttribute = mesh.attributes.POSITION;
3513
+ if (!positionAttribute || positionAttribute.size !== 3) {
3514
+ throw new TileConversionError(
3515
+ "POINT_CLOUD_POSITION_REQUIRED",
3516
+ "Point cloud batches must contain a three-component POSITION attribute"
3517
+ );
3518
+ }
3519
+ const positions = getPositionValues(positionAttribute, options.rtcCenter);
3520
+ const pointCount = positions.length / 3;
3521
+ if (pointCount === 0 || !Number.isInteger(pointCount)) {
3522
+ throw new TileConversionError(
3523
+ "POINT_CLOUD_POSITION_COUNT_INVALID",
3524
+ "Point cloud POSITION must contain one or more xyz triples"
3525
+ );
3526
+ }
3527
+ const colors = getColorAttribute(mesh.attributes.COLOR_0 || mesh.attributes.COLOR, pointCount);
3528
+ const constantRGBA = colors ? null : getConstantRgba(options.constantRGBA);
3529
+ const normals = getNormalAttribute(mesh.attributes.NORMAL, pointCount);
3530
+ const batchIds = getBatchIds(mesh.attributes.BATCH_ID, pointCount);
3531
+ const batchTableJson = validateBatchTable(options.batchTableJson, batchIds);
3532
+ return Tile3DWriter.encodeSync(
3533
+ {
3534
+ type: TILE3D_TYPE.POINT_CLOUD,
3535
+ featureTableJson: options.rtcCenter || constantRGBA ? {
3536
+ ...options.rtcCenter ? { RTC_CENTER: [...options.rtcCenter] } : {},
3537
+ ...constantRGBA ? { CONSTANT_RGBA: constantRGBA } : {}
3538
+ } : void 0,
3539
+ batchTableJson,
3540
+ attributes: { positions, colors, normals, batchIds }
3541
+ },
3542
+ {}
3543
+ );
3544
+ }
3545
+ function validatePointAttributes(attributes) {
3546
+ const supportedAttributes = /* @__PURE__ */ new Set([
3547
+ "POSITION",
3548
+ "NORMAL",
3549
+ "BATCH_ID",
3550
+ attributes.COLOR_0 ? "COLOR_0" : "COLOR"
3551
+ ]);
3552
+ const unsupportedAttributes = Object.keys(attributes).filter(
3553
+ (name) => !supportedAttributes.has(name)
3554
+ );
3555
+ if (unsupportedAttributes.length > 0) {
3556
+ throw new TileConversionError(
3557
+ "POINT_CLOUD_ATTRIBUTE_UNSUPPORTED",
3558
+ `PNTS encoding does not support these point attributes: ${unsupportedAttributes.join(", ")}`
3559
+ );
3560
+ }
3561
+ }
3562
+ function getConstantRgba(constantRGBA) {
3563
+ if (!constantRGBA) {
3564
+ return null;
3565
+ }
3566
+ if (constantRGBA.length !== 4 || constantRGBA.some((value) => !Number.isInteger(value) || value < 0 || value > 255)) {
3567
+ throw new TileConversionError(
3568
+ "POINT_CLOUD_CONSTANT_RGBA_INVALID",
3569
+ "Point cloud constantRGBA must contain four unsigned byte values"
3570
+ );
3571
+ }
3572
+ return [constantRGBA[0], constantRGBA[1], constantRGBA[2], constantRGBA[3]];
3573
+ }
3574
+ function getPositionValues(attribute, rtcCenter) {
3575
+ if (rtcCenter && (rtcCenter.length !== 3 || rtcCenter.some((value) => !Number.isFinite(value)))) {
3576
+ throw new TileConversionError(
3577
+ "POINT_CLOUD_RTC_CENTER_INVALID",
3578
+ "Point cloud RTC_CENTER must contain three finite values"
3579
+ );
3580
+ }
3581
+ const values = attribute.value;
3582
+ const result = new Float32Array(values.length);
3583
+ const transform = attribute.transform;
3584
+ for (let index = 0; index < values.length; index++) {
3585
+ const component = index % 3;
3586
+ const value = values[index];
3587
+ const absoluteValue = transform?.type === "quantization" ? transform.origin[component] + value / (2 ** transform.bits - 1) * transform.range : value;
3588
+ result[index] = absoluteValue - (rtcCenter?.[component] ?? 0);
3589
+ }
3590
+ return result;
3591
+ }
3592
+ function getColorAttribute(attribute, pointCount) {
3593
+ if (!attribute) {
3594
+ return null;
3595
+ }
3596
+ if (attribute.size !== 3 && attribute.size !== 4) {
3597
+ throw new TileConversionError(
3598
+ "POINT_CLOUD_COLOR_SIZE_UNSUPPORTED",
3599
+ "Point cloud color attributes must contain three or four components"
3600
+ );
3601
+ }
3602
+ if (attribute.value.length !== pointCount * attribute.size) {
3603
+ throw new TileConversionError(
3604
+ "POINT_CLOUD_COLOR_COUNT_MISMATCH",
3605
+ "Point cloud color count does not match the POSITION count"
3606
+ );
3607
+ }
3608
+ const colors = new Uint8Array(attribute.value.length);
3609
+ const maximum = getIntegerColorMaximum(attribute.value);
3610
+ for (let index = 0; index < attribute.value.length; index++) {
3611
+ const value = attribute.value[index];
3612
+ const scaledValue = maximum ? value / maximum * 255 : value <= 1 ? value * 255 : value;
3613
+ if (!Number.isFinite(scaledValue) || scaledValue < 0 || scaledValue > 255) {
3614
+ throw new TileConversionError(
3615
+ "POINT_CLOUD_COLOR_VALUE_INVALID",
3616
+ "Point cloud color components must be finite values from 0 through 255"
3617
+ );
3618
+ }
3619
+ colors[index] = Math.round(scaledValue);
3620
+ }
3621
+ return { type: 5121, value: colors, size: attribute.size, normalized: false };
3622
+ }
3623
+ function getIntegerColorMaximum(values) {
3624
+ if (values instanceof Uint8Array || values instanceof Uint8ClampedArray) {
3625
+ return 255;
3626
+ }
3627
+ if (values instanceof Uint16Array) {
3628
+ return 65535;
3629
+ }
3630
+ if (values instanceof Uint32Array) {
3631
+ return 4294967295;
3632
+ }
3633
+ return null;
3634
+ }
3635
+ function getNormalAttribute(attribute, pointCount) {
3636
+ if (!attribute) {
3637
+ return null;
3638
+ }
3639
+ if (attribute.size !== 3 || attribute.value.length !== pointCount * 3) {
3640
+ throw new TileConversionError(
3641
+ "POINT_CLOUD_NORMAL_COUNT_MISMATCH",
3642
+ "Point cloud normals must contain one xyz triple per position"
3643
+ );
3644
+ }
3645
+ return { type: 5126, value: Float32Array.from(attribute.value), size: 3 };
3646
+ }
3647
+ function getBatchIds(attribute, pointCount) {
3648
+ if (!attribute) {
3649
+ return null;
3650
+ }
3651
+ if (attribute.size !== 1 || attribute.value.length !== pointCount) {
3652
+ throw new TileConversionError(
3653
+ "POINT_CLOUD_BATCH_ID_COUNT_MISMATCH",
3654
+ "Point cloud BATCH_ID must contain one value per position"
3655
+ );
3656
+ }
3657
+ const batchIds = new Uint16Array(pointCount);
3658
+ for (let index = 0; index < pointCount; index++) {
3659
+ const batchId = attribute.value[index];
3660
+ if (!Number.isInteger(batchId) || batchId < 0 || batchId > 65535) {
3661
+ throw new TileConversionError(
3662
+ "POINT_CLOUD_BATCH_ID_OUT_OF_RANGE",
3663
+ "Point cloud BATCH_ID values must be unsigned 16-bit integers"
3664
+ );
3665
+ }
3666
+ batchIds[index] = batchId;
3667
+ }
3668
+ return batchIds;
3669
+ }
3670
+ function validateBatchTable(batchTableJson, batchIds) {
3671
+ if (!batchTableJson) {
3672
+ if (batchIds) {
3673
+ throw new TileConversionError(
3674
+ "POINT_CLOUD_BATCH_TABLE_REQUIRED",
3675
+ "BATCH_ID values require matching batchTableJson properties"
3676
+ );
3677
+ }
3678
+ return void 0;
3679
+ }
3680
+ if (!batchIds) {
3681
+ throw new TileConversionError(
3682
+ "POINT_CLOUD_BATCH_ID_REQUIRED",
3683
+ "batchTableJson requires a BATCH_ID attribute"
3684
+ );
3685
+ }
3686
+ let batchLength = 0;
3687
+ for (const batchId of batchIds) {
3688
+ batchLength = Math.max(batchLength, batchId + 1);
3689
+ }
3690
+ const normalizedBatchTable = {};
3691
+ for (const [name, values] of Object.entries(batchTableJson)) {
3692
+ if (values.length !== batchLength) {
3693
+ throw new TileConversionError(
3694
+ "POINT_CLOUD_BATCH_TABLE_LENGTH_MISMATCH",
3695
+ `Batch table property "${name}" must contain ${batchLength} values`
3696
+ );
3697
+ }
3698
+ normalizedBatchTable[name] = [...values];
3699
+ }
3700
+ return normalizedBatchTable;
3701
+ }
3702
+
3703
+ // src/v5/point-cloud-source.ts
3704
+ async function* traversePointCloudSource(source, options = {}) {
3705
+ const { maxDepth = Number.POSITIVE_INFINITY, signal } = options;
3706
+ if (maxDepth !== Number.POSITIVE_INFINITY && (!Number.isSafeInteger(maxDepth) || maxDepth < 0)) {
3707
+ throw new RangeError("Point-cloud source maxDepth must be a non-negative integer");
3708
+ }
3709
+ throwIfAborted3(signal);
3710
+ if (!source.isReady) {
3711
+ await source.initialize();
3712
+ }
3713
+ throwIfAborted3(signal);
3714
+ const root = await source.getRootTile();
3715
+ const pendingTiles = [root];
3716
+ const visitedTileIds = /* @__PURE__ */ new Set();
3717
+ while (pendingTiles.length > 0) {
3718
+ throwIfAborted3(signal);
3719
+ const header = pendingTiles.pop();
3720
+ if (visitedTileIds.has(header.id)) {
3721
+ continue;
3722
+ }
3723
+ visitedTileIds.add(header.id);
3724
+ const content = await source.loadTileContent(header);
3725
+ throwIfAborted3(signal);
3726
+ yield { header, content };
3727
+ throwIfAborted3(signal);
3728
+ if (header.level >= maxDepth) {
3729
+ continue;
3730
+ }
3731
+ const children = await source.getChildren(header);
3732
+ throwIfAborted3(signal);
3733
+ for (let index = children.length - 1; index >= 0; index--) {
3734
+ pendingTiles.push(children[index]);
3735
+ }
3736
+ }
3737
+ }
3738
+ function throwIfAborted3(signal) {
3739
+ if (signal?.aborted) {
3740
+ throw signal.reason ?? new DOMException("The operation was aborted", "AbortError");
3741
+ }
3742
+ }
3743
+
3744
+ // src/v5/point-cloud-source-encoder.ts
3745
+ async function* encodePointCloudSource(source, options = {}) {
3746
+ for await (const sourceTile of traversePointCloudSource(source, options)) {
3747
+ const encodingOptions = sourceTile.content ? options.getTileEncodingOptions?.(sourceTile) : void 0;
3748
+ const encodedTile = encodePointCloudSourceTile(sourceTile, encodingOptions);
3749
+ if (encodedTile) {
3750
+ yield encodedTile;
3751
+ }
3752
+ }
3753
+ }
3754
+ function encodePointCloudSourceTile(sourceTile, options = {}) {
3755
+ const { header, content } = sourceTile;
3756
+ if (!content) {
3757
+ return null;
3758
+ }
3759
+ return {
3760
+ id: header.id,
3761
+ header,
3762
+ pnts: encodePointCloudTile(content.data, {
3763
+ ...options,
3764
+ constantRGBA: options.constantRGBA ?? content.constantRGBA
3765
+ }),
3766
+ pointCount: content.pointCount,
3767
+ coordinateSystem: content.coordinateSystem,
3768
+ cartographicOrigin: [...content.cartographicOrigin],
3769
+ modelMatrix: content.modelMatrix ? Array.from(content.modelMatrix) : void 0,
3770
+ spatialReference: content.spatialReference,
3771
+ spatialBoundingVolume: content.spatialBoundingVolume || header.spatialBoundingVolume
3772
+ };
3773
+ }
3774
+
3775
+ // src/v5/point-cloud-conversion.ts
3776
+ function convertPointCloudSource(source, options) {
3777
+ return convertTileset({
3778
+ source: {
3779
+ async inspect() {
3780
+ if (!source.isReady) {
3781
+ await source.initialize();
3782
+ }
3783
+ },
3784
+ read: (_inspection, signal) => traversePointCloudSource(source, { maxDepth: options.maxDepth, signal })
3785
+ },
3786
+ codec: {
3787
+ async *convert(sourceTile) {
3788
+ const encodingOptions = sourceTile.content ? options.getTileEncodingOptions?.(sourceTile) : void 0;
3789
+ const encodedTile = encodePointCloudSourceTile(sourceTile, encodingOptions);
3790
+ if (encodedTile) {
3791
+ yield encodedTile;
3792
+ }
3793
+ }
3794
+ },
3795
+ sink: options.sink,
3796
+ measureInputBytes: options.measureInputBytes,
3797
+ measureOutputBytes: (resource) => resource.pnts.byteLength,
3798
+ maxInputResourceBytes: options.maxInputResourceBytes,
3799
+ maxOutputResourceBytes: options.maxOutputResourceBytes,
3800
+ signal: options.signal,
3801
+ onProgress: options.onProgress
3802
+ });
3803
+ }
3804
+
3805
+ // src/v5/resource-manifest.ts
3806
+ var TILE_RESOURCE_MANIFEST_VERSION = 1;
3807
+ async function createManifestBackedTileConversionSink(options) {
3808
+ const priorManifest = await options.manifestStore.load();
3809
+ const resources = /* @__PURE__ */ new Map();
3810
+ if (priorManifest) {
3811
+ validateManifest(priorManifest);
3812
+ for (const entry of priorManifest.resources) {
3813
+ resources.set(entry.resourceId, entry);
3814
+ }
3815
+ }
3816
+ let writeChain = Promise.resolve();
3817
+ let writeFailed = false;
3818
+ let writeFailure;
3819
+ let closed = false;
3820
+ const persistManifest = async (complete, report) => {
3821
+ await options.manifestStore.save({
3822
+ version: TILE_RESOURCE_MANIFEST_VERSION,
3823
+ complete,
3824
+ resources: [...resources.values()].sort(
3825
+ (left, right) => left.resourceId < right.resourceId ? -1 : left.resourceId > right.resourceId ? 1 : 0
3826
+ ),
3827
+ ...report ? { report } : {}
3828
+ });
3829
+ };
3830
+ const writeResource = async (resource, signal) => {
3831
+ if (closed) {
3832
+ throw new TileConversionError("RESOURCE_SINK_CLOSED", "Cannot write after sink finalization");
3833
+ }
3834
+ if (writeFailed) {
3835
+ throw writeFailure;
3836
+ }
3837
+ const entry = createManifestEntry(options, resource);
3838
+ const priorEntry = resources.get(entry.resourceId);
3839
+ if (priorEntry) {
3840
+ if (priorEntry.byteLength !== entry.byteLength || priorEntry.fingerprint !== entry.fingerprint) {
3841
+ throw new TileConversionError(
3842
+ "RESOURCE_RESUME_MISMATCH",
3843
+ `Resource "${entry.resourceId}" changed since the saved manifest`
3844
+ );
3845
+ }
3846
+ return;
3847
+ }
3848
+ await options.sink.write(resource, signal);
3849
+ resources.set(entry.resourceId, entry);
3850
+ await persistManifest(false);
3851
+ };
3852
+ return {
3853
+ write(resource, signal) {
3854
+ const operation = writeChain.then(() => writeResource(resource, signal));
3855
+ writeChain = operation.catch((error) => {
3856
+ writeFailed = true;
3857
+ writeFailure = error;
3858
+ });
3859
+ return operation;
3860
+ },
3861
+ async finalize(report) {
3862
+ await writeChain;
3863
+ if (writeFailed) {
3864
+ throw writeFailure;
3865
+ }
3866
+ if (closed) {
3867
+ throw new TileConversionError("RESOURCE_SINK_CLOSED", "Sink has already been finalized");
3868
+ }
3869
+ await options.sink.finalize(report);
3870
+ await persistManifest(true, report);
3871
+ closed = true;
3872
+ },
3873
+ async abort(reason) {
3874
+ await writeChain;
3875
+ if (closed) return;
3876
+ closed = true;
3877
+ resources.clear();
3878
+ await persistManifest(false);
3879
+ await options.sink.abort(reason);
3880
+ }
3881
+ };
3882
+ }
3883
+ function createManifestEntry(options, resource) {
3884
+ const resourceId = options.getResourceId(resource);
3885
+ const byteLength = options.measureResourceBytes(resource);
3886
+ const fingerprint = options.fingerprintResource(resource);
3887
+ if (typeof resourceId !== "string" || resourceId.length === 0 || typeof fingerprint !== "string" || fingerprint.length === 0 || !Number.isSafeInteger(byteLength) || byteLength < 0) {
3888
+ throw new TileConversionError(
3889
+ "INVALID_RESOURCE_MANIFEST_ENTRY",
3890
+ "Resource manifest entries require an ID, a fingerprint, and a non-negative safe byte length"
3891
+ );
3892
+ }
3893
+ return { resourceId, byteLength, fingerprint };
3894
+ }
3895
+ function validateManifest(manifest) {
3896
+ if (typeof manifest !== "object" || manifest === null || manifest.version !== TILE_RESOURCE_MANIFEST_VERSION || typeof manifest.complete !== "boolean" || !Array.isArray(manifest.resources)) {
3897
+ throw new TileConversionError(
3898
+ "UNSUPPORTED_RESOURCE_MANIFEST",
3899
+ `Unsupported or malformed resource manifest version: ${String(manifest.version)}`
3900
+ );
3901
+ }
3902
+ const resourceIds = /* @__PURE__ */ new Set();
3903
+ for (const entry of manifest.resources) {
3904
+ if (typeof entry?.resourceId !== "string" || entry.resourceId.length === 0 || typeof entry?.fingerprint !== "string" || entry.fingerprint.length === 0 || !Number.isSafeInteger(entry.byteLength) || entry.byteLength < 0 || resourceIds.has(entry.resourceId)) {
3905
+ throw new TileConversionError(
3906
+ "INVALID_RESOURCE_MANIFEST",
3907
+ "Resource manifest contains an invalid or duplicate entry"
3908
+ );
3909
+ }
3910
+ resourceIds.add(entry.resourceId);
3911
+ }
3912
+ }
3913
+ export {
3914
+ TileConversionError,
3915
+ convertFeatureAttributesToArrowBatches,
3916
+ convertPointCloudSource,
3917
+ convertTileset,
3918
+ createI3SConversionSpatialContext,
3919
+ createManifestBackedTileConversionSink,
3920
+ createTiles3DConversionSpatialContext,
3921
+ createTilesetConversionSource,
3922
+ encodePointCloudSource,
3923
+ encodePointCloudSourceTile,
3924
+ encodePointCloudTile,
3925
+ inspectTileset,
3926
+ traversePointCloudSource,
3927
+ validateTileset
3928
+ };