@loaders.gl/tile-converter 5.0.0-alpha.1 → 5.0.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/LICENSE +14 -3
  2. package/README.md +497 -0
  3. package/dist/converter.min.cjs +210 -282
  4. package/dist/i3s-server/bin/i3s-server.min.cjs +106 -341
  5. package/dist/index.cjs +38586 -0
  6. package/dist/index.js +38557 -0
  7. package/dist/v5/adapters.cjs +3548 -0
  8. package/dist/v5/adapters.d.ts +33 -0
  9. package/dist/v5/adapters.js +3537 -0
  10. package/dist/v5/browser-sink.d.ts +37 -0
  11. package/dist/v5/browser-source.d.ts +38 -0
  12. package/dist/v5/browser-tileset-source.d.ts +70 -0
  13. package/dist/v5/browser.cjs +76 -0
  14. package/dist/v5/browser.d.ts +44 -0
  15. package/dist/v5/browser.js +75 -0
  16. package/dist/v5/conversion-api.d.ts +122 -0
  17. package/dist/v5/conversion-archive.d.ts +32 -0
  18. package/dist/v5/core.cjs +917 -0
  19. package/dist/v5/core.d.ts +16 -0
  20. package/dist/v5/core.js +899 -0
  21. package/dist/v5/feature-arrow.d.ts +36 -0
  22. package/dist/v5/i3s-mesh-conversion.d.ts +32 -0
  23. package/dist/v5/i3s-mesh-sink.d.ts +25 -0
  24. package/dist/v5/i3s-mesh-source-features.d.ts +13 -0
  25. package/dist/v5/i3s-mesh-source-material.d.ts +5 -0
  26. package/dist/v5/i3s-mesh-source.d.ts +30 -0
  27. package/dist/v5/index.cjs +73 -0
  28. package/dist/v5/index.d.ts +40 -0
  29. package/dist/v5/index.js +75 -0
  30. package/dist/v5/mesh-conversion.d.ts +71 -0
  31. package/dist/v5/mesh-draco.d.ts +8 -0
  32. package/dist/v5/mesh-features.d.ts +9 -0
  33. package/dist/v5/mesh-source-features.d.ts +21 -0
  34. package/dist/v5/mesh-source-texture.d.ts +6 -0
  35. package/dist/v5/mesh-source.d.ts +41 -0
  36. package/dist/v5/mesh-tileset-archive.d.ts +18 -0
  37. package/dist/v5/mesh-tileset-sink.d.ts +51 -0
  38. package/dist/v5/mesh.d.ts +86 -0
  39. package/dist/v5/point-cloud-conversion.d.ts +31 -0
  40. package/dist/v5/point-cloud-source-encoder.d.ts +46 -0
  41. package/dist/v5/point-cloud-source.d.ts +25 -0
  42. package/dist/v5/point-cloud-spatial.d.ts +22 -0
  43. package/dist/v5/point-cloud-tileset-sink.d.ts +28 -0
  44. package/dist/v5/point-cloud.d.ts +49 -0
  45. package/dist/v5/resource-fetcher.d.ts +18 -0
  46. package/dist/v5/resource-manifest.d.ts +58 -0
  47. package/dist/v5/spatial-conversion.d.ts +61 -0
  48. package/dist/v5/tileset-source.d.ts +21 -0
  49. package/package.json +52 -26
  50. package/src/common/README.md +5 -0
  51. package/src/index.ts +1 -2
  52. package/src/{3d-tiles-converter → v4/3d-tiles-converter}/3d-tiles-converter.ts +13 -2
  53. package/src/v4/3d-tiles-converter/helpers/validate-i3s-spatial-reference.ts +124 -0
  54. package/src/{deps-installer → v4/deps-installer}/deps-installer.ts +10 -7
  55. package/src/{i3s-converter → v4/i3s-converter}/helpers/batch-ids-extensions.ts +1 -1
  56. package/src/v4/i3s-converter/helpers/encode-string-attribute.ts +23 -0
  57. package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-converter.ts +30 -55
  58. package/src/{i3s-converter → v4/i3s-converter}/helpers/gltf-attributes.ts +5 -4
  59. package/src/{i3s-converter → v4/i3s-converter}/helpers/load-3d-tiles.ts +5 -9
  60. package/src/{i3s-converter → v4/i3s-converter}/i3s-converter.ts +6 -7
  61. package/src/{i3s-server → v4/i3s-server}/README.md +2 -2
  62. package/src/{i3s-server → v4/i3s-server}/routes/slpk-router.ts +1 -0
  63. package/src/v4/index.ts +2 -0
  64. package/src/{lib → v4/lib}/utils/compress-util.ts +8 -7
  65. package/src/v5/adapters.ts +75 -0
  66. package/src/v5/browser-sink.ts +130 -0
  67. package/src/v5/browser-source.ts +155 -0
  68. package/src/v5/browser-tileset-source.ts +328 -0
  69. package/src/v5/browser.ts +139 -0
  70. package/src/v5/conversion-api.ts +287 -0
  71. package/src/v5/conversion-archive.ts +85 -0
  72. package/src/v5/core.ts +61 -0
  73. package/src/v5/feature-arrow.ts +429 -0
  74. package/src/v5/i3s-mesh-conversion.ts +192 -0
  75. package/src/v5/i3s-mesh-sink.ts +351 -0
  76. package/src/v5/i3s-mesh-source-features.ts +279 -0
  77. package/src/v5/i3s-mesh-source-material.ts +157 -0
  78. package/src/v5/i3s-mesh-source.ts +227 -0
  79. package/src/v5/index.ts +131 -0
  80. package/src/v5/mesh-conversion.ts +230 -0
  81. package/src/v5/mesh-draco.ts +182 -0
  82. package/src/v5/mesh-features.ts +319 -0
  83. package/src/v5/mesh-source-features.ts +263 -0
  84. package/src/v5/mesh-source-texture.ts +169 -0
  85. package/src/v5/mesh-source.ts +422 -0
  86. package/src/v5/mesh-tileset-archive.ts +50 -0
  87. package/src/v5/mesh-tileset-sink.ts +324 -0
  88. package/src/v5/mesh.ts +526 -0
  89. package/src/v5/point-cloud-conversion.ts +88 -0
  90. package/src/v5/point-cloud-source-encoder.ts +116 -0
  91. package/src/v5/point-cloud-source.ts +84 -0
  92. package/src/v5/point-cloud-spatial.ts +280 -0
  93. package/src/v5/point-cloud-tileset-sink.ts +234 -0
  94. package/src/v5/point-cloud.ts +398 -0
  95. package/src/v5/resource-fetcher.ts +110 -0
  96. package/src/v5/resource-manifest.ts +213 -0
  97. package/src/v5/spatial-conversion.ts +389 -0
  98. package/src/v5/tileset-source.ts +54 -0
  99. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/3d-tiles-content-converter.ts +0 -0
  100. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/i3s-obb-to-3d-tiles-obb.ts +0 -0
  101. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/load-i3s.ts +0 -0
  102. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/helpers/texture-atlas.ts +0 -0
  103. /package/src/{3d-tiles-converter → v4/3d-tiles-converter}/json-templates/tileset.ts +0 -0
  104. /package/src/{constants.ts → v4/constants.ts} +0 -0
  105. /package/src/{converter-cli.ts → v4/converter-cli.ts} +0 -0
  106. /package/src/{i3s-converter → v4/i3s-converter}/helpers/attribute-metadata-info.ts +0 -0
  107. /package/src/{i3s-converter → v4/i3s-converter}/helpers/coordinate-converter.ts +0 -0
  108. /package/src/{i3s-converter → v4/i3s-converter}/helpers/create-scene-server-path.ts +0 -0
  109. /package/src/{i3s-converter → v4/i3s-converter}/helpers/feature-attributes.ts +0 -0
  110. /package/src/{i3s-converter → v4/i3s-converter}/helpers/geometry-attributes.ts +0 -0
  111. /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-debug.ts +0 -0
  112. /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-index-document.ts +0 -0
  113. /package/src/{i3s-converter → v4/i3s-converter}/helpers/node-pages.ts +0 -0
  114. /package/src/{i3s-converter → v4/i3s-converter}/helpers/preprocess-3d-tiles.ts +0 -0
  115. /package/src/{i3s-converter → v4/i3s-converter}/helpers/progress.ts +0 -0
  116. /package/src/{i3s-converter → v4/i3s-converter}/helpers/tileset-traversal.ts +0 -0
  117. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/geometry-definitions.ts +0 -0
  118. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/layers.ts +0 -0
  119. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/metadata.ts +0 -0
  120. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/node.ts +0 -0
  121. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/scene-server.ts +0 -0
  122. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/shared-resources.ts +0 -0
  123. /package/src/{i3s-converter → v4/i3s-converter}/json-templates/store.ts +0 -0
  124. /package/src/{i3s-converter → v4/i3s-converter}/types.ts +0 -0
  125. /package/src/{i3s-server → v4/i3s-server}/app.ts +0 -0
  126. /package/src/{i3s-server → v4/i3s-server}/bin/www.ts +0 -0
  127. /package/src/{i3s-server → v4/i3s-server}/certs/cert.pem +0 -0
  128. /package/src/{i3s-server → v4/i3s-server}/certs/key.pem +0 -0
  129. /package/src/{i3s-server → v4/i3s-server}/controllers/slpk-controller.ts +0 -0
  130. /package/src/{i3s-server → v4/i3s-server}/utils/create-scene-server.ts +0 -0
  131. /package/src/{i3s-server → v4/i3s-server}/utils/server-utils.ts +0 -0
  132. /package/src/{lib → v4/lib}/json-schemas/conversion-dump-json-schema.ts +0 -0
  133. /package/src/{lib → v4/lib}/utils/cli-utils.ts +0 -0
  134. /package/src/{lib → v4/lib}/utils/conversion-dump.ts +0 -0
  135. /package/src/{lib → v4/lib}/utils/file-utils.ts +0 -0
  136. /package/src/{lib → v4/lib}/utils/geometry-utils.ts +0 -0
  137. /package/src/{lib → v4/lib}/utils/lod-conversion-utils.ts +0 -0
  138. /package/src/{lib → v4/lib}/utils/queue.ts +0 -0
  139. /package/src/{lib → v4/lib}/utils/statistic-utils.ts +0 -0
  140. /package/src/{lib → v4/lib}/utils/write-queue.ts +0 -0
  141. /package/src/{pgm-loader.ts → v4/pgm-loader.ts} +0 -0
@@ -0,0 +1,389 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {
6
+ createTilesetSpatialReference,
7
+ I3SSpatialTransformer,
8
+ markTilesetSpatialReferenceTransformed,
9
+ Tiles3DSpatialTransformer
10
+ } from '@loaders.gl/tiles';
11
+ import {Matrix4} from '@math.gl/core';
12
+ import type {
13
+ CreateTilesetSpatialReferenceOptions,
14
+ I3SSpatialBounds,
15
+ I3STransformedPositions,
16
+ I3STransformedGeometry,
17
+ Tiles3DSpatialBoundingVolume,
18
+ TilesetSpatialOptions,
19
+ TilesetSpatialReference
20
+ } from '@loaders.gl/tiles';
21
+ import {TileConversionError} from './conversion-api.js';
22
+ import type {TileConversionDiagnostic} from './conversion-api.js';
23
+
24
+ /** Portable coordinate operations and output metadata for a 3D Tiles conversion. */
25
+ export interface Tiles3DConversionSpatialContext {
26
+ /** Source and selected target CRS, height reference, units, and transformation state. */
27
+ readonly spatialReference: TilesetSpatialReference;
28
+ /** Transform packed absolute xyz positions using double precision output. */
29
+ transformPositions(positions: ArrayLike<number>): Float64Array;
30
+ /** Transform packed normals using the corresponding source positions. */
31
+ transformNormals(normals: ArrayLike<number>, positions: ArrayLike<number>): Float32Array;
32
+ /** Rebuild a conservative bound in the selected target coordinate frame. */
33
+ transformBoundingVolume(
34
+ volume: Tiles3DSpatialBoundingVolume,
35
+ sourceTransform?: ArrayLike<number>
36
+ ): Tiles3DSpatialBoundingVolume;
37
+ }
38
+
39
+ /** Portable coordinate operations and output metadata for an I3S conversion. */
40
+ export interface I3SConversionSpatialContext {
41
+ /** Source and selected target CRS, height reference, units, and transformation state. */
42
+ readonly spatialReference: TilesetSpatialReference;
43
+ /** Transform absolute I3S positions after applying declared height units and placement. */
44
+ transformPositions(
45
+ positions: ArrayLike<number>,
46
+ sourceOrigin: ArrayLike<number>
47
+ ): I3STransformedPositions;
48
+ /** Transform absolute conversion geometry without intermediate float32 rounding. */
49
+ transformGeometryAsync(
50
+ positions: ArrayLike<number>,
51
+ normals?: ArrayLike<number>,
52
+ normalReferenceFrame?: string
53
+ ): Promise<I3STransformedGeometry>;
54
+ /** Transform absolute I3S positions when terrain or scene sampling is asynchronous. */
55
+ transformPositionsAsync(
56
+ positions: ArrayLike<number>,
57
+ sourceOrigin: ArrayLike<number>
58
+ ): Promise<I3STransformedPositions>;
59
+ /** Transform packed normals using the corresponding source positions. */
60
+ transformNormals(
61
+ normals: ArrayLike<number>,
62
+ positions: ArrayLike<number>,
63
+ normalReferenceFrame?: string
64
+ ): Float32Array;
65
+ /** Rebuild a conservative I3S bound in the selected target frame. */
66
+ transformBoundingVolume(
67
+ bounds: I3SSpatialBounds
68
+ ): I3SSpatialBounds | {box?: number[]; region?: number[]};
69
+ /** Rebuild a bound when terrain or scene sampling is asynchronous. */
70
+ transformBoundingVolumeAsync(
71
+ bounds: I3SSpatialBounds
72
+ ): Promise<I3SSpatialBounds | {box?: number[]; region?: number[]}>;
73
+ }
74
+
75
+ /**
76
+ * Creates the shared spatial operations used to write 3D Tiles in a selected CRS and height frame.
77
+ *
78
+ * Source discovery remains format-specific and should use `get3DTilesSpatialReference` or the
79
+ * initialized source's spatial metadata. Target choices on a normalized, transformable reference
80
+ * are retained unless overridden in `options`. Do not reuse a reference already marked
81
+ * `transformed`; that would apply the operation twice. The returned reference is the metadata to
82
+ * publish with transformed output; unresolved requests fail instead of guessing a CRS or height datum.
83
+ *
84
+ * @param discovered - Source CRS, units, coordinate epoch, and height metadata.
85
+ * @param options - Target CRS, height reference, and explicitly supplied geoid resources.
86
+ * @returns Shared position, normal, and bound operations with matching output metadata.
87
+ */
88
+ export function createTiles3DConversionSpatialContext(
89
+ discovered: CreateTilesetSpatialReferenceOptions | TilesetSpatialReference,
90
+ options: TilesetSpatialOptions = {}
91
+ ): Tiles3DConversionSpatialContext {
92
+ const spatialReference = createConversionSpatialReference(discovered, options);
93
+ if (spatialReference.status === 'unresolved') {
94
+ throw createSpatialConversionError(spatialReference);
95
+ }
96
+
97
+ if (spatialReference.status !== 'native' && spatialReference.coordinateEpoch !== undefined) {
98
+ throw new TileConversionError(
99
+ 'SPATIAL_EPOCH_UNSUPPORTED',
100
+ 'Epoch-tagged coordinates require an epoch-aware datum operation before conversion'
101
+ );
102
+ }
103
+
104
+ const transformer =
105
+ spatialReference.status === 'native'
106
+ ? undefined
107
+ : createSpatialTransformer(
108
+ spatialReference,
109
+ () => new Tiles3DSpatialTransformer(spatialReference, options)
110
+ );
111
+ const outputSpatialReference = transformer
112
+ ? markTilesetSpatialReferenceTransformed(spatialReference)
113
+ : spatialReference;
114
+
115
+ return {
116
+ spatialReference: outputSpatialReference,
117
+ transformPositions: positions =>
118
+ transformer ? transformer.transformPositions(positions) : Float64Array.from(positions),
119
+ transformNormals: (normals, positions) =>
120
+ transformer ? transformer.transformNormals(normals, positions) : Float32Array.from(normals),
121
+ transformBoundingVolume: (volume, sourceTransform) =>
122
+ transformer
123
+ ? transformer.transformBoundingVolume(volume, sourceTransform)
124
+ : cloneBoundingVolume(volume)
125
+ };
126
+ }
127
+
128
+ /**
129
+ * Creates the shared spatial operations used to write I3S in a selected CRS and height frame.
130
+ *
131
+ * I3S height units, vertical datum, elevation placement, and bounds use the same transformer as
132
+ * the source-backed tile runtime. Terrain or scene elevation providers are explicit application
133
+ * inputs and may make position and bound operations asynchronous.
134
+ *
135
+ * @param discovered - Source CRS, vertical units, height reference, and elevation mode.
136
+ * @param options - Target CRS, height reference, geoid, or explicit elevation providers.
137
+ * @returns Shared position, normal, bound, and output-metadata operations.
138
+ */
139
+ export function createI3SConversionSpatialContext(
140
+ discovered: CreateTilesetSpatialReferenceOptions | TilesetSpatialReference,
141
+ options: TilesetSpatialOptions = {}
142
+ ): I3SConversionSpatialContext {
143
+ const spatialReference = createConversionSpatialReference(discovered, options);
144
+ if (spatialReference.status === 'unresolved') {
145
+ throw createSpatialConversionError(spatialReference);
146
+ }
147
+
148
+ if (spatialReference.status !== 'native' && spatialReference.coordinateEpoch !== undefined) {
149
+ throw new TileConversionError(
150
+ 'SPATIAL_EPOCH_UNSUPPORTED',
151
+ 'Epoch-tagged coordinates require an epoch-aware datum operation before conversion'
152
+ );
153
+ }
154
+
155
+ const transformer =
156
+ spatialReference.status === 'native'
157
+ ? undefined
158
+ : createSpatialTransformer(
159
+ spatialReference,
160
+ () => new I3SSpatialTransformer(spatialReference, options)
161
+ );
162
+ const outputSpatialReference = transformer ? transformer.spatialReference : spatialReference;
163
+ // I3S vector bases can differ from the coordinate basis even when positions retain their CRS.
164
+ let nativeNormalTransformer: I3SSpatialTransformer | undefined;
165
+ /** Maps native I3S vectors into the writer basis without reprojecting its positions. */
166
+ const transformNativeNormals = (
167
+ normals: ArrayLike<number>,
168
+ positions: ArrayLike<number>,
169
+ normalReferenceFrame?: string
170
+ ): Float32Array => {
171
+ if (
172
+ !spatialReference.sourceCrs ||
173
+ ['local', 'cartesian'].includes(spatialReference.coordinateFrame)
174
+ ) {
175
+ // Unreferenced/native local vectors already use the retained position basis.
176
+ const targetNormals = Float32Array.from(normals);
177
+ for (let index = 0; index < normals.length; index += 3) {
178
+ const length = Math.hypot(normals[index], normals[index + 1], normals[index + 2]);
179
+ if (length) {
180
+ for (let axis = 0; axis < 3; axis++) {
181
+ targetNormals[index + axis] = normals[index + axis] / length;
182
+ }
183
+ }
184
+ }
185
+ return targetNormals;
186
+ }
187
+ nativeNormalTransformer ||= createSpatialTransformer(
188
+ spatialReference,
189
+ () =>
190
+ new I3SSpatialTransformer(
191
+ {
192
+ ...spatialReference,
193
+ status: 'transformable',
194
+ targetCrs: spatialReference.sourceCrs
195
+ },
196
+ options
197
+ )
198
+ );
199
+ return nativeNormalTransformer.transformNormals(normals, positions, normalReferenceFrame);
200
+ };
201
+
202
+ return {
203
+ spatialReference: outputSpatialReference,
204
+ transformPositions: (positions, sourceOrigin) =>
205
+ transformer
206
+ ? transformer.transformPositions(positions, sourceOrigin)
207
+ : createNativeI3SPositions(positions, sourceOrigin, spatialReference),
208
+ transformGeometryAsync: async (positions, normals, normalReferenceFrame) => {
209
+ if (transformer)
210
+ return transformer.transformGeometryAsync(positions, normals, normalReferenceFrame);
211
+ const targetPositions = Float64Array.from(positions);
212
+ if (
213
+ targetPositions.length % 3 ||
214
+ targetPositions.some(value => !Number.isFinite(value)) ||
215
+ (normals &&
216
+ (normals.length !== positions.length ||
217
+ Array.from(normals).some(value => !Number.isFinite(value)))) ||
218
+ (normalReferenceFrame !== undefined &&
219
+ !['earth-centered', 'vertex-reference-frame'].includes(normalReferenceFrame))
220
+ ) {
221
+ throw new TileConversionError(
222
+ 'SPATIAL_INPUT_INVALID',
223
+ 'Conversion geometry requires finite matching xyz arrays and a supported I3S vector frame'
224
+ );
225
+ }
226
+ return {
227
+ positions: targetPositions,
228
+ normals: normals
229
+ ? transformNativeNormals(normals, positions, normalReferenceFrame)
230
+ : undefined
231
+ };
232
+ },
233
+ transformPositionsAsync: (positions, sourceOrigin) =>
234
+ transformer
235
+ ? transformer.transformPositionsAsync(positions, sourceOrigin)
236
+ : Promise.resolve(createNativeI3SPositions(positions, sourceOrigin, spatialReference)),
237
+ transformNormals: (normals, positions, normalReferenceFrame) =>
238
+ transformer
239
+ ? transformer.transformNormals(normals, positions, normalReferenceFrame)
240
+ : Float32Array.from(normals),
241
+ transformBoundingVolume: bounds =>
242
+ transformer ? transformer.transformBoundingVolume(bounds) : cloneI3SBounds(bounds),
243
+ transformBoundingVolumeAsync: bounds =>
244
+ transformer
245
+ ? transformer.transformBoundingVolumeAsync(bounds)
246
+ : Promise.resolve(cloneI3SBounds(bounds))
247
+ };
248
+ }
249
+
250
+ /** Raises a typed error and preserves discovery warnings for unresolved spatial operations. */
251
+ function createSpatialConversionError(
252
+ spatialReference: TilesetSpatialReference,
253
+ cause?: unknown
254
+ ): TileConversionError {
255
+ const diagnostics: TileConversionDiagnostic[] = spatialReference.warnings.map(message => ({
256
+ code: 'SPATIAL_REFERENCE_WARNING',
257
+ message,
258
+ severity: 'warning' as const
259
+ }));
260
+ const causeMessage = cause instanceof Error ? `: ${cause.message}` : '';
261
+ const message = causeMessage
262
+ ? `Spatial conversion could not be initialized${causeMessage}`
263
+ : 'The requested spatial conversion cannot be resolved from the available metadata';
264
+ diagnostics.push({
265
+ code: 'SPATIAL_REFERENCE_UNRESOLVED',
266
+ message,
267
+ severity: 'error'
268
+ });
269
+ return new TileConversionError('SPATIAL_REFERENCE_UNRESOLVED', message, diagnostics);
270
+ }
271
+
272
+ /** Creates a conversion reference while retaining target choices from normalized source metadata. */
273
+ function createConversionSpatialReference(
274
+ discovered: CreateTilesetSpatialReferenceOptions | TilesetSpatialReference,
275
+ options: TilesetSpatialOptions
276
+ ): TilesetSpatialReference {
277
+ if (!('status' in discovered)) {
278
+ return createTilesetSpatialReference(discovered, options);
279
+ }
280
+ if (discovered.status === 'transformed') {
281
+ throw createSpatialConversionError(
282
+ discovered,
283
+ new Error('coordinates are already transformed')
284
+ );
285
+ }
286
+
287
+ const sourceMetadata: CreateTilesetSpatialReferenceOptions = {
288
+ sourceCrs: discovered.sourceCrs,
289
+ sourceCrsState: discovered.crs.state,
290
+ sourceCrsRepresentation:
291
+ discovered.crs.state === 'explicit' || discovered.crs.state === 'default'
292
+ ? discovered.crs.representation
293
+ : undefined,
294
+ sourceCrsAlternatives:
295
+ discovered.crs.state === 'explicit' || discovered.crs.state === 'default'
296
+ ? discovered.crs.alternatives
297
+ : undefined,
298
+ verticalCrs: discovered.verticalCrs,
299
+ units: discovered.units,
300
+ verticalUnitScale: discovered.verticalUnitScale,
301
+ coordinateEpoch: discovered.coordinateEpoch,
302
+ heightReference: discovered.heightReference,
303
+ elevationMode: discovered.elevationMode,
304
+ elevationOffset: discovered.elevationOffset,
305
+ elevationUnit: discovered.elevationUnit,
306
+ elevationUnitScale: discovered.elevationUnitScale,
307
+ coordinateFrame: discovered.coordinateFrame,
308
+ axisOrder: discovered.axisOrder,
309
+ provenance: discovered.provenance,
310
+ warnings: discovered.warnings
311
+ };
312
+ const retainedOptions: TilesetSpatialOptions = {
313
+ ...options,
314
+ targetCrs: options.targetCrs ?? discovered.targetCrs,
315
+ targetHeightReference: options.targetHeightReference ?? discovered.targetHeightReference,
316
+ outputCoordinates: options.outputCoordinates ?? discovered.outputCoordinates
317
+ };
318
+ return createTilesetSpatialReference(sourceMetadata, retainedOptions);
319
+ }
320
+
321
+ /** Converts transformer initialization failures into the public typed diagnostic contract. */
322
+ function createSpatialTransformer<T>(
323
+ spatialReference: TilesetSpatialReference,
324
+ createTransformer: () => T
325
+ ): T {
326
+ try {
327
+ return createTransformer();
328
+ } catch (error) {
329
+ throw createSpatialConversionError(spatialReference, error);
330
+ }
331
+ }
332
+
333
+ /** Clones bounds for native-coordinate output without changing caller-owned arrays. */
334
+ function cloneBoundingVolume(volume: Tiles3DSpatialBoundingVolume): Tiles3DSpatialBoundingVolume {
335
+ return {
336
+ ...volume,
337
+ box: volume.box ? [...volume.box] : undefined,
338
+ sphere: volume.sphere ? [...volume.sphere] : undefined,
339
+ region: volume.region ? [...volume.region] : undefined
340
+ };
341
+ }
342
+
343
+ /** Clones I3S bounds for native-coordinate output without changing caller-owned arrays. */
344
+ function cloneI3SBounds(bounds: I3SSpatialBounds): I3SSpatialBounds {
345
+ return {
346
+ ...bounds,
347
+ mbs: bounds.mbs ? Array.from(bounds.mbs) : undefined,
348
+ obb: bounds.obb
349
+ ? {
350
+ center: Array.from(bounds.obb.center),
351
+ halfSize: Array.from(bounds.obb.halfSize),
352
+ quaternion: Array.from(bounds.obb.quaternion)
353
+ }
354
+ : undefined
355
+ };
356
+ }
357
+
358
+ /** Build stable local offsets for native I3S coordinates without changing their frame. */
359
+ function createNativeI3SPositions(
360
+ sourcePositions: ArrayLike<number>,
361
+ sourceOrigin: ArrayLike<number>,
362
+ spatialReference: TilesetSpatialReference
363
+ ): I3STransformedPositions {
364
+ if (sourcePositions.length % 3 !== 0 || sourceOrigin.length < 3) {
365
+ throw new Error('I3S positions and origin must contain complete xyz coordinates');
366
+ }
367
+ const origin: [number, number, number] = [
368
+ Number(sourceOrigin[0]),
369
+ Number(sourceOrigin[1]),
370
+ Number(sourceOrigin[2])
371
+ ];
372
+ const sourcePositions64 = Float64Array.from(sourcePositions);
373
+ const positions = new Float32Array(sourcePositions.length);
374
+ for (let index = 0; index < sourcePositions.length; index += 3) {
375
+ positions[index] = Number(sourcePositions[index]) - origin[0];
376
+ positions[index + 1] = Number(sourcePositions[index + 1]) - origin[1];
377
+ positions[index + 2] = Number(sourcePositions[index + 2]) - origin[2];
378
+ }
379
+ const isGeographic = spatialReference.coordinateFrame === 'geographic';
380
+ const modelMatrix = isGeographic ? new Matrix4() : new Matrix4().translate(origin);
381
+ return {
382
+ positions,
383
+ sourcePositions: sourcePositions64,
384
+ origin,
385
+ cartographicOrigin: isGeographic ? origin : [0, 0, 0],
386
+ coordinateSystem: isGeographic ? 'lnglat-offsets' : 'cartesian',
387
+ modelMatrix
388
+ };
389
+ }
@@ -0,0 +1,54 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {traverseTilesetContents} from '@loaders.gl/tiles';
6
+ import type {
7
+ Tileset3D,
8
+ TilesetContentTraversalItem,
9
+ TilesetSourceMetadata,
10
+ TraverseTilesetContentsOptions
11
+ } from '@loaders.gl/tiles';
12
+ import {TileConversionError} from './conversion-api.js';
13
+ import type {TileConversionSource} from './conversion-api.js';
14
+
15
+ /** Decoded-content lifetime options for source-backed conversion. */
16
+ export type TilesetConversionSourceOptions = Pick<TraverseTilesetContentsOptions, 'unloadContent'>;
17
+
18
+ /**
19
+ * Adapts a source-backed tileset to the portable v5 conversion source contract.
20
+ *
21
+ * Inspection waits for initialization and returns the source's normalized metadata. Reading uses
22
+ * camera-independent shared traversal, retaining each placement and its ordered decoded contents.
23
+ * Source adapters own content, subtree, node-page, nested tileset, and archive resolution.
24
+ *
25
+ * Enable `unloadContent` on a dedicated runtime to release newly loaded payloads after the codec
26
+ * and awaited writes finish, or iteration closes on failure. Preloaded payloads remain attached.
27
+ * Applications own tileset destruction, format codecs, byte accounting, and output packaging.
28
+ * This adapter does not impose an aggregate input memory limit or transform coordinates.
29
+ *
30
+ * @param tileset - An initializing or initialized runtime backed by a 3D Tiles or I3S source.
31
+ * @param options - Optional cleanup of content loaded during conversion.
32
+ * @returns A source accepted by `inspectTileset` and `convertTileset`.
33
+ */
34
+ export function createTilesetConversionSource(
35
+ tileset: Tileset3D,
36
+ options: TilesetConversionSourceOptions = {}
37
+ ): TileConversionSource<TilesetSourceMetadata, TilesetContentTraversalItem> {
38
+ return {
39
+ async inspect(signal) {
40
+ signal?.throwIfAborted();
41
+ await tileset.tilesetInitializationPromise;
42
+ signal?.throwIfAborted();
43
+ if (!tileset.root) {
44
+ throw new TileConversionError(
45
+ 'TILESET_ROOT_REQUIRED',
46
+ 'Tileset initialization completed without a root tile'
47
+ );
48
+ }
49
+ return tileset.source.getMetadata();
50
+ },
51
+ read: (_inspection, signal) =>
52
+ traverseTilesetContents(tileset, {unloadContent: options.unloadContent, signal})
53
+ };
54
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes