@loaders.gl/tiles 5.0.0-alpha.2 → 5.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +1 -1
  2. package/dist/dist.dev.js +17325 -5650
  3. package/dist/dist.min.js +4 -1
  4. package/dist/index.cjs +1924 -178
  5. package/dist/index.cjs.map +3 -3
  6. package/dist/index.d.ts +9 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +6 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/point-cloud/point-cloud-tileset.d.ts +4 -0
  11. package/dist/point-cloud/point-cloud-tileset.d.ts.map +1 -1
  12. package/dist/point-cloud/point-cloud-tileset.js +51 -12
  13. package/dist/point-cloud/point-cloud-tileset.js.map +1 -1
  14. package/dist/point-cloud/types.d.ts +17 -0
  15. package/dist/point-cloud/types.d.ts.map +1 -1
  16. package/dist/raster-set.d.ts +10 -8
  17. package/dist/raster-set.d.ts.map +1 -1
  18. package/dist/raster-set.js +18 -1
  19. package/dist/raster-set.js.map +1 -1
  20. package/dist/spatial/format-spatial-reference.d.ts +67 -0
  21. package/dist/spatial/format-spatial-reference.d.ts.map +1 -0
  22. package/dist/spatial/format-spatial-reference.js +233 -0
  23. package/dist/spatial/format-spatial-reference.js.map +1 -0
  24. package/dist/spatial/get-spatial-coordinate-frame.d.ts +9 -0
  25. package/dist/spatial/get-spatial-coordinate-frame.d.ts.map +1 -0
  26. package/dist/spatial/get-spatial-coordinate-frame.js +58 -0
  27. package/dist/spatial/get-spatial-coordinate-frame.js.map +1 -0
  28. package/dist/spatial/i3s-elevation.d.ts +20 -0
  29. package/dist/spatial/i3s-elevation.d.ts.map +1 -0
  30. package/dist/spatial/i3s-elevation.js +90 -0
  31. package/dist/spatial/i3s-elevation.js.map +1 -0
  32. package/dist/spatial/i3s-spatial-transformer.d.ts +189 -0
  33. package/dist/spatial/i3s-spatial-transformer.d.ts.map +1 -0
  34. package/dist/spatial/i3s-spatial-transformer.js +686 -0
  35. package/dist/spatial/i3s-spatial-transformer.js.map +1 -0
  36. package/dist/spatial/spatial-coordinate-transformer.d.ts +48 -0
  37. package/dist/spatial/spatial-coordinate-transformer.d.ts.map +1 -0
  38. package/dist/spatial/spatial-coordinate-transformer.js +211 -0
  39. package/dist/spatial/spatial-coordinate-transformer.js.map +1 -0
  40. package/dist/spatial/spatial-resource-registry.d.ts +44 -0
  41. package/dist/spatial/spatial-resource-registry.d.ts.map +1 -0
  42. package/dist/spatial/spatial-resource-registry.js +67 -0
  43. package/dist/spatial/spatial-resource-registry.js.map +1 -0
  44. package/dist/spatial/spatial-types.d.ts +190 -0
  45. package/dist/spatial/spatial-types.d.ts.map +1 -0
  46. package/dist/spatial/spatial-types.js +192 -0
  47. package/dist/spatial/spatial-types.js.map +1 -0
  48. package/dist/tileset-3d/common/tile-3d.d.ts +49 -1
  49. package/dist/tileset-3d/common/tile-3d.d.ts.map +1 -1
  50. package/dist/tileset-3d/common/tile-3d.js +132 -64
  51. package/dist/tileset-3d/common/tile-3d.js.map +1 -1
  52. package/dist/tileset-3d/common/tileset-3d.d.ts +25 -0
  53. package/dist/tileset-3d/common/tileset-3d.d.ts.map +1 -1
  54. package/dist/tileset-3d/common/tileset-3d.js +49 -7
  55. package/dist/tileset-3d/common/tileset-3d.js.map +1 -1
  56. package/dist/tileset-3d/common/tileset-source.d.ts +14 -0
  57. package/dist/tileset-3d/common/tileset-source.d.ts.map +1 -1
  58. package/dist/tileset-3d/common/tileset-source.js.map +1 -1
  59. package/dist/tileset-3d/common/tileset-traverser.d.ts +6 -1
  60. package/dist/tileset-3d/common/tileset-traverser.d.ts.map +1 -1
  61. package/dist/tileset-3d/common/tileset-traverser.js +11 -6
  62. package/dist/tileset-3d/common/tileset-traverser.js.map +1 -1
  63. package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts +26 -1
  64. package/dist/tileset-3d/format-3d-tiles/implicit-tiling.d.ts.map +1 -1
  65. package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js +62 -18
  66. package/dist/tileset-3d/format-3d-tiles/implicit-tiling.js.map +1 -1
  67. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts +1 -7
  68. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.d.ts.map +1 -1
  69. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js +32 -55
  70. package/dist/tileset-3d/format-3d-tiles/tiles-3d-source.js.map +1 -1
  71. package/dist/tileset-3d/format-i3s/i3s-source.d.ts +14 -1
  72. package/dist/tileset-3d/format-i3s/i3s-source.d.ts.map +1 -1
  73. package/dist/tileset-3d/format-i3s/i3s-source.js +107 -17
  74. package/dist/tileset-3d/format-i3s/i3s-source.js.map +1 -1
  75. package/dist/tileset-3d/helpers/bounding-volume.d.ts.map +1 -1
  76. package/dist/tileset-3d/helpers/bounding-volume.js +3 -33
  77. package/dist/tileset-3d/helpers/bounding-volume.js.map +1 -1
  78. package/dist/tileset-3d/helpers/frame-state.d.ts +3 -1
  79. package/dist/tileset-3d/helpers/frame-state.d.ts.map +1 -1
  80. package/dist/tileset-3d/helpers/frame-state.js +1 -0
  81. package/dist/tileset-3d/helpers/frame-state.js.map +1 -1
  82. package/dist/tileset-3d/helpers/i3s-lod.d.ts.map +1 -1
  83. package/dist/tileset-3d/helpers/i3s-lod.js +20 -8
  84. package/dist/tileset-3d/helpers/i3s-lod.js.map +1 -1
  85. package/dist/types.d.ts +3 -0
  86. package/dist/types.d.ts.map +1 -1
  87. package/package.json +12 -9
  88. package/src/index.ts +42 -1
  89. package/src/point-cloud/point-cloud-tileset.ts +66 -12
  90. package/src/point-cloud/types.ts +17 -0
  91. package/src/raster-set.ts +46 -11
  92. package/src/spatial/format-spatial-reference.ts +311 -0
  93. package/src/spatial/get-spatial-coordinate-frame.ts +74 -0
  94. package/src/spatial/i3s-elevation.ts +96 -0
  95. package/src/spatial/i3s-spatial-transformer.ts +957 -0
  96. package/src/spatial/spatial-coordinate-transformer.ts +276 -0
  97. package/src/spatial/spatial-resource-registry.ts +79 -0
  98. package/src/spatial/spatial-types.ts +422 -0
  99. package/src/tileset-3d/common/tile-3d.ts +156 -69
  100. package/src/tileset-3d/common/tileset-3d.ts +77 -6
  101. package/src/tileset-3d/common/tileset-source.ts +15 -0
  102. package/src/tileset-3d/common/tileset-traverser.ts +11 -6
  103. package/src/tileset-3d/format-3d-tiles/implicit-tiling.ts +100 -22
  104. package/src/tileset-3d/format-3d-tiles/tiles-3d-source.ts +36 -56
  105. package/src/tileset-3d/format-i3s/i3s-source.ts +119 -18
  106. package/src/tileset-3d/helpers/bounding-volume.ts +3 -55
  107. package/src/tileset-3d/helpers/frame-state.ts +3 -0
  108. package/src/tileset-3d/helpers/i3s-lod.ts +22 -8
  109. package/src/types.ts +3 -0
@@ -0,0 +1,276 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {Geoid} from '@math.gl/geoid';
6
+ import {Vector3} from '@math.gl/core';
7
+ import {Ellipsoid} from '@math.gl/geospatial';
8
+ import type {ReadonlyCRSDefinition} from '@math.gl/crs';
9
+ import {Proj4Projection, toProj4CRSDefinition, type Proj4CRSDefinition} from '@math.gl/proj4';
10
+ import {getGeoidModel} from './spatial-resource-registry';
11
+ import type {
12
+ TilesetHeightReference,
13
+ TilesetSpatialOptions,
14
+ TilesetSpatialReference,
15
+ TilesetTargetHeightReference
16
+ } from './spatial-types';
17
+ export {getSpatialCoordinateFrame} from './get-spatial-coordinate-frame';
18
+
19
+ const GEOGRAPHIC_CRS = 'EPSG:4326';
20
+ const GEOCENTRIC_CRS = 'EPSG:4978';
21
+
22
+ /**
23
+ * Deterministic coordinate transformer used by 3D tile format adapters.
24
+ *
25
+ * The transformer uses conventional `[x, y, z]` array order at its boundary. Format adapters are
26
+ * responsible for mapping authority-axis order into their documented wire order. Requested
27
+ * transformations fail when required definitions or geoid resources are unavailable.
28
+ */
29
+ export class SpatialCoordinateTransformer {
30
+ /** Normalized spatial metadata describing this transformation. */
31
+ readonly spatialReference: TilesetSpatialReference;
32
+
33
+ /** Projection from the source CRS directly to the requested horizontal target CRS. */
34
+ private readonly horizontalProjection?: Proj4Projection;
35
+
36
+ /** Projection from the source CRS to geographic longitude, latitude, and ellipsoidal height. */
37
+ private readonly geographicProjection?: Proj4Projection;
38
+
39
+ /** Projection from adjusted geographic coordinates to the requested output CRS. */
40
+ private readonly heightOutputProjection?: Proj4Projection;
41
+
42
+ /** Whether source coordinates use the WGS84 geocentric frame handled by math.gl. */
43
+ private readonly sourceIsGeocentric: boolean;
44
+
45
+ /** Whether output coordinates use the WGS84 geocentric frame handled by math.gl. */
46
+ private readonly outputIsGeocentric: boolean;
47
+
48
+ /** Whether source coordinates already use conventional WGS84 longitude/latitude order. */
49
+ private readonly sourceIsGeographic: boolean;
50
+
51
+ /** Whether output coordinates use conventional WGS84 longitude/latitude order. */
52
+ private readonly outputIsGeographic: boolean;
53
+
54
+ /** Geoid model used to convert between ellipsoidal and orthometric heights. */
55
+ private readonly geoid?: Geoid;
56
+
57
+ /**
58
+ * Creates a coordinate transformer.
59
+ *
60
+ * @param spatialReference - Format-discovered and option-normalized spatial metadata.
61
+ * @param options - Application options containing an optional geoid model.
62
+ */
63
+ constructor(spatialReference: TilesetSpatialReference, options: TilesetSpatialOptions = {}) {
64
+ this.spatialReference = spatialReference;
65
+ validateTransformRequest(spatialReference);
66
+ const outputCrs = spatialReference.targetCrs || spatialReference.sourceCrs;
67
+ this.sourceIsGeocentric = isWgs84Geocentric(spatialReference.sourceCrs);
68
+ this.outputIsGeocentric = isWgs84Geocentric(outputCrs);
69
+ this.sourceIsGeographic = isWgs84Geographic(spatialReference.sourceCrs);
70
+ this.outputIsGeographic = isWgs84Geographic(outputCrs);
71
+
72
+ if (
73
+ spatialReference.sourceCrs &&
74
+ spatialReference.targetCrs &&
75
+ !this.sourceIsGeocentric &&
76
+ !this.outputIsGeocentric
77
+ ) {
78
+ this.horizontalProjection = new Proj4Projection({
79
+ from: getHorizontalProj4Definition(spatialReference.sourceCrs),
80
+ to: getHorizontalProj4Definition(spatialReference.targetCrs),
81
+ enforceAxis: false
82
+ });
83
+ }
84
+
85
+ if (
86
+ requiresHeightTransformation(spatialReference) ||
87
+ this.sourceIsGeocentric ||
88
+ this.outputIsGeocentric
89
+ ) {
90
+ if (!this.sourceIsGeographic && !this.sourceIsGeocentric) {
91
+ this.geographicProjection = new Proj4Projection({
92
+ from: getHorizontalProj4Definition(spatialReference.sourceCrs),
93
+ to: GEOGRAPHIC_CRS,
94
+ enforceAxis: false
95
+ });
96
+ }
97
+ if (!this.outputIsGeographic && !this.outputIsGeocentric) {
98
+ this.heightOutputProjection = new Proj4Projection({
99
+ from: GEOGRAPHIC_CRS,
100
+ to: getHorizontalProj4Definition(outputCrs),
101
+ enforceAxis: false
102
+ });
103
+ }
104
+ }
105
+
106
+ if (requiresHeightTransformation(spatialReference)) {
107
+ this.geoid = resolveGeoid(options.geoidModel);
108
+ if (!this.geoid) {
109
+ const modelName = typeof options.geoidModel === 'string' ? ` "${options.geoidModel}"` : '';
110
+ throw new Error(
111
+ `Height conversion requires a registered geoid model${modelName}; ` +
112
+ 'call registerGeoidModel() or pass a parsed Geoid instance'
113
+ );
114
+ }
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Transforms one `[x, y, z?]` coordinate while retaining additional components.
120
+ *
121
+ * @param coordinate - Source coordinate in the format adapter's normalized `x/y/z` order.
122
+ * @returns A new transformed coordinate array.
123
+ */
124
+ transformPosition(coordinate: readonly number[]): number[] {
125
+ if (coordinate.length < 2) {
126
+ throw new Error('A spatial coordinate must contain at least x and y components');
127
+ }
128
+
129
+ const result = [...coordinate];
130
+ if (
131
+ requiresHeightTransformation(this.spatialReference) ||
132
+ this.sourceIsGeocentric ||
133
+ this.outputIsGeocentric
134
+ ) {
135
+ if (result.length < 3 || !Number.isFinite(result[2])) {
136
+ throw new Error('Three-dimensional CRS conversion requires a finite z coordinate');
137
+ }
138
+ const geographic = this.toGeographic(result);
139
+ if (requiresHeightTransformation(this.spatialReference)) {
140
+ const geoidUndulation = this.geoid!.getHeight(geographic[1], geographic[0]);
141
+ geographic[2] = transformHeight(
142
+ geographic[2],
143
+ geoidUndulation,
144
+ this.spatialReference.heightReference,
145
+ this.spatialReference.targetHeightReference
146
+ );
147
+ }
148
+ const projected = this.fromGeographic(geographic);
149
+ result.splice(0, projected.length, ...projected);
150
+ return result;
151
+ }
152
+
153
+ if (this.horizontalProjection) {
154
+ const projected = this.horizontalProjection.project(result.slice(0, 3));
155
+ result.splice(0, projected.length, ...projected);
156
+ }
157
+ return result;
158
+ }
159
+
160
+ /** Convert one source coordinate to conventional WGS84 longitude, latitude, and height. */
161
+ private toGeographic(coordinate: number[]): number[] {
162
+ if (this.sourceIsGeocentric) {
163
+ return Array.from(Ellipsoid.WGS84.cartesianToCartographic(new Vector3(coordinate)));
164
+ }
165
+ if (this.sourceIsGeographic) {
166
+ return coordinate.slice(0, 3);
167
+ }
168
+ return this.geographicProjection!.project(coordinate.slice(0, 3));
169
+ }
170
+
171
+ /** Convert one conventional WGS84 geographic coordinate to the selected output CRS. */
172
+ private fromGeographic(coordinate: number[]): number[] {
173
+ if (this.outputIsGeocentric) {
174
+ return Array.from(Ellipsoid.WGS84.cartographicToCartesian(new Vector3(coordinate)));
175
+ }
176
+ if (this.outputIsGeographic) {
177
+ return coordinate.slice(0, 3);
178
+ }
179
+ return this.heightOutputProjection!.project(coordinate.slice(0, 3));
180
+ }
181
+ }
182
+
183
+ /** Select the horizontal component that the proj4js runtime can execute. */
184
+ function getHorizontalProj4Definition(
185
+ definition: ReadonlyCRSDefinition | undefined
186
+ ): Proj4CRSDefinition {
187
+ if (!definition) {
188
+ throw new Error('Cannot construct a projection because the CRS is unknown');
189
+ }
190
+ return toProj4CRSDefinition(definition, {mode: 'horizontal'});
191
+ }
192
+
193
+ /** Validate that all requested operations can be represented by the current runtime. */
194
+ function validateTransformRequest(spatialReference: TilesetSpatialReference): void {
195
+ if (spatialReference.outputCoordinates === 'local-enu') {
196
+ throw new Error(
197
+ 'local-enu output requires a dataset-derived local origin and must be created by a tileset source'
198
+ );
199
+ }
200
+ if (spatialReference.outputCoordinates === 'target-crs' && !spatialReference.targetCrs) {
201
+ throw new Error('target-crs output requires targetCrs');
202
+ }
203
+ if (!spatialReference.sourceCrs && spatialReference.status === 'unresolved') {
204
+ throw new Error('Cannot transform coordinates because the source CRS is unknown');
205
+ }
206
+ if (
207
+ requiresHeightTransformation(spatialReference) &&
208
+ spatialReference.heightReference === 'unknown'
209
+ ) {
210
+ throw new Error('Cannot convert heights because the source height reference is unknown');
211
+ }
212
+ if (
213
+ spatialReference.coordinateFrame === 'geocentric' &&
214
+ !isWgs84Geocentric(spatialReference.sourceCrs)
215
+ ) {
216
+ throw new Error(
217
+ 'Only EPSG:4978 geocentric coordinates are supported by the current spatial transformer'
218
+ );
219
+ }
220
+ if (spatialReference.status === 'unresolved') {
221
+ throw new Error('The requested spatial output cannot be resolved from the available metadata');
222
+ }
223
+ }
224
+
225
+ /** Return whether a CRS definition identifies the WGS84 geocentric frame. */
226
+ function isWgs84Geocentric(definition: unknown): boolean {
227
+ return typeof definition === 'string' && normalizeCrsIdentifier(definition) === GEOCENTRIC_CRS;
228
+ }
229
+
230
+ /** Return whether a CRS definition uses conventional WGS84 longitude/latitude coordinates. */
231
+ function isWgs84Geographic(definition: unknown): boolean {
232
+ if (typeof definition !== 'string') {
233
+ return false;
234
+ }
235
+ const identifier = normalizeCrsIdentifier(definition);
236
+ return identifier === GEOGRAPHIC_CRS || identifier === 'EPSG:4979' || identifier === 'OGC:CRS84';
237
+ }
238
+
239
+ /** Normalize common OGC URL and URN CRS spellings to authority identifiers. */
240
+ function normalizeCrsIdentifier(identifier: string): string {
241
+ const normalizedIdentifier = identifier.trim().toUpperCase();
242
+ const ogcMatch = normalizedIdentifier.match(
243
+ /(?:\/DEF\/CRS\/|URN:OGC:DEF:CRS:)([A-Z0-9_-]+)(?:\/|::)(?:[^/:]*[/:])?([A-Z0-9_.-]+)$/
244
+ );
245
+ return ogcMatch ? `${ogcMatch[1]}:${ogcMatch[2]}` : normalizedIdentifier;
246
+ }
247
+
248
+ /** Return whether source and target height interpretations differ. */
249
+ function requiresHeightTransformation(spatialReference: TilesetSpatialReference): boolean {
250
+ const target = spatialReference.targetHeightReference;
251
+ return target !== 'native' && target !== spatialReference.heightReference;
252
+ }
253
+
254
+ /** Resolve an inline or registered geoid model. */
255
+ function resolveGeoid(model: string | Geoid | undefined): Geoid | undefined {
256
+ return typeof model === 'string' ? getGeoidModel(model) : model;
257
+ }
258
+
259
+ /** Apply the GeographicLib geoid undulation convention, h = H + N. */
260
+ function transformHeight(
261
+ height: number,
262
+ geoidUndulation: number,
263
+ source: TilesetHeightReference,
264
+ target: TilesetTargetHeightReference
265
+ ): number {
266
+ if (source === target || target === 'native') {
267
+ return height;
268
+ }
269
+ if (source === 'orthometric' && target === 'ellipsoidal') {
270
+ return height + geoidUndulation;
271
+ }
272
+ if (source === 'ellipsoidal' && target === 'orthometric') {
273
+ return height - geoidUndulation;
274
+ }
275
+ throw new Error(`Unsupported height conversion from ${source} to ${target}`);
276
+ }
@@ -0,0 +1,79 @@
1
+ // loaders.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Geoid, parsePGM} from '@math.gl/geoid';
6
+ import {Proj4Projection} from '@math.gl/proj4';
7
+ import type {Proj4CRSDefinition} from '@math.gl/proj4';
8
+
9
+ const geoidModels = new Map<string, Geoid>();
10
+
11
+ /**
12
+ * Registers an application-supplied CRS alias for deterministic Proj4 transformations.
13
+ *
14
+ * loaders.gl never downloads registry definitions implicitly.
15
+ *
16
+ * @param name - Identifier used by dataset metadata or application options.
17
+ * @param definition - CRS definition understood by `@math.gl/proj4`.
18
+ */
19
+ export function registerSpatialCrs(name: string, definition: Proj4CRSDefinition): void {
20
+ validateResourceName(name, 'CRS');
21
+ Proj4Projection.defineProjectionAliases({[name]: definition});
22
+ }
23
+
24
+ /**
25
+ * Registers an NTv2 datum grid used by a previously or subsequently registered CRS definition.
26
+ *
27
+ * @param name - Grid name referenced by the Proj4 definition.
28
+ * @param data - Complete NTv2 grid bytes.
29
+ */
30
+ export function registerSpatialDatumGrid(name: string, data: ArrayBuffer): void {
31
+ validateResourceName(name, 'datum grid');
32
+ Proj4Projection.registerDatumGrid(name, data);
33
+ }
34
+
35
+ /**
36
+ * Registers an already parsed geoid model.
37
+ *
38
+ * @param name - Stable application-local model name.
39
+ * @param geoid - Parsed `@math.gl/geoid` model.
40
+ */
41
+ export function registerGeoidModel(name: string, geoid: Geoid): void {
42
+ validateResourceName(name, 'geoid model');
43
+ geoidModels.set(name, geoid);
44
+ }
45
+
46
+ /**
47
+ * Parses and registers a GeographicLib PGM geoid model.
48
+ *
49
+ * @param name - Stable application-local model name.
50
+ * @param data - Complete PGM model bytes.
51
+ * @param options - Interpolation options forwarded to `@math.gl/geoid`.
52
+ * @returns The parsed and registered geoid model.
53
+ */
54
+ export function registerGeoidModelFromPgm(
55
+ name: string,
56
+ data: Uint8Array,
57
+ options: {cubic?: boolean} = {}
58
+ ): Geoid {
59
+ const geoid = parsePGM(data, options);
60
+ registerGeoidModel(name, geoid);
61
+ return geoid;
62
+ }
63
+
64
+ /**
65
+ * Returns a registered geoid model without initiating network access.
66
+ *
67
+ * @param name - Application-local model name.
68
+ * @returns Registered model, or `undefined` when the application has not supplied it.
69
+ */
70
+ export function getGeoidModel(name: string): Geoid | undefined {
71
+ return geoidModels.get(name);
72
+ }
73
+
74
+ /** Validate a caller-controlled spatial resource name. */
75
+ function validateResourceName(name: string, resourceType: string): void {
76
+ if (!name.trim()) {
77
+ throw new Error(`${resourceType} name must not be empty`);
78
+ }
79
+ }