@loaders.gl/i3s 3.1.0-alpha.3 → 4.0.0-alpha.4

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 (39) hide show
  1. package/dist/i3s-attribute-loader.js +44 -14
  2. package/dist/i3s-attribute-loader.js.map +1 -1
  3. package/dist/i3s-building-scene-layer-loader.js +21 -0
  4. package/dist/i3s-building-scene-layer-loader.js.map +1 -0
  5. package/dist/i3s-content-loader.js +1 -1
  6. package/dist/i3s-content-worker.js +7549 -2
  7. package/dist/i3s-loader.js +5 -2
  8. package/dist/i3s-loader.js.map +1 -1
  9. package/dist/i3s-node-page-loader.js +1 -1
  10. package/dist/index.js +2 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/lib/helpers/i3s-nodepages-tiles.js +27 -20
  13. package/dist/lib/helpers/i3s-nodepages-tiles.js.map +1 -1
  14. package/dist/lib/parsers/constants.js +8 -0
  15. package/dist/lib/parsers/constants.js.map +1 -1
  16. package/dist/lib/parsers/parse-i3s-attribute.js +9 -1
  17. package/dist/lib/parsers/parse-i3s-attribute.js.map +1 -1
  18. package/dist/lib/parsers/parse-i3s-building-scene-layer.js +43 -0
  19. package/dist/lib/parsers/parse-i3s-building-scene-layer.js.map +1 -0
  20. package/dist/lib/parsers/parse-i3s-tile-content.js +49 -32
  21. package/dist/lib/parsers/parse-i3s-tile-content.js.map +1 -1
  22. package/dist/lib/parsers/parse-i3s.js +4 -4
  23. package/dist/lib/parsers/parse-i3s.js.map +1 -1
  24. package/dist/lib/utils/url-utils.js +3 -3
  25. package/dist/lib/utils/url-utils.js.map +1 -1
  26. package/package.json +13 -11
  27. package/src/i3s-attribute-loader.ts +56 -19
  28. package/src/i3s-building-scene-layer-loader.ts +34 -0
  29. package/src/i3s-loader.ts +4 -1
  30. package/src/index.ts +2 -0
  31. package/src/lib/helpers/i3s-nodepages-tiles.ts +28 -12
  32. package/src/lib/parsers/constants.ts +22 -0
  33. package/src/lib/parsers/parse-i3s-attribute.ts +19 -1
  34. package/src/lib/parsers/parse-i3s-building-scene-layer.ts +57 -0
  35. package/src/lib/parsers/parse-i3s-tile-content.ts +51 -31
  36. package/src/types.ts +102 -6
  37. package/dist/dist.min.js +0 -2
  38. package/dist/dist.min.js.map +0 -1
  39. package/dist/i3s-content-worker.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import {load} from '@loaders.gl/core';
2
- import {getSupportedGPUTextureFormats} from '@loaders.gl/textures';
2
+ import {getSupportedGPUTextureFormats, selectSupportedBasisFormat} from '@loaders.gl/textures';
3
3
  import {Tileset, NodePage} from '../../types';
4
4
  import {I3SNodePageLoader} from '../../i3s-node-page-loader';
5
5
  import {normalizeTileNonUrlData} from '../parsers/parse-i3s';
@@ -16,6 +16,7 @@ export default class I3SNodePagesTiles {
16
16
  options: {[key: string]: any};
17
17
  lodSelectionMetricType: any;
18
18
  textureDefinitionsSelectedFormats: any[] = [];
19
+ private textureLoaderOptions: {[key: string]: any} = {};
19
20
 
20
21
  /**
21
22
  * @constructs
@@ -29,7 +30,7 @@ export default class I3SNodePagesTiles {
29
30
  this.lodSelectionMetricType = tileset.nodePages.lodSelectionMetricType;
30
31
  this.options = options;
31
32
 
32
- this._initSelectedFormatsForTextureDefinitions(tileset);
33
+ this.initSelectedFormatsForTextureDefinitions(tileset);
33
34
  }
34
35
 
35
36
  /**
@@ -83,11 +84,11 @@ export default class I3SNodePagesTiles {
83
84
  if (node && node.mesh) {
84
85
  // Get geometry resource URL and type (compressed / non-compressed)
85
86
  const {url, isDracoGeometry: isDracoGeometryResult} = (node.mesh.geometry &&
86
- this._getContentUrl(node.mesh.geometry)) || {url: null, isDracoGeometry: null};
87
+ this.getContentUrl(node.mesh.geometry)) || {url: null, isDracoGeometry: null};
87
88
  contentUrl = url;
88
89
  isDracoGeometry = isDracoGeometryResult;
89
90
 
90
- const [textureData, nodeMaterialDefinition] = this._getInformationFromMaterial(
91
+ const [textureData, nodeMaterialDefinition] = this.getInformationFromMaterial(
91
92
  node.mesh.material
92
93
  );
93
94
  materialDefinition = nodeMaterialDefinition;
@@ -101,7 +102,7 @@ export default class I3SNodePagesTiles {
101
102
  }
102
103
  }
103
104
 
104
- const lodSelection = this._getLodSelection(node);
105
+ const lodSelection = this.getLodSelection(node);
105
106
 
106
107
  return normalizeTileNonUrlData({
107
108
  id,
@@ -112,6 +113,7 @@ export default class I3SNodePagesTiles {
112
113
  attributeUrls,
113
114
  materialDefinition,
114
115
  textureFormat,
116
+ textureLoaderOptions: this.textureLoaderOptions,
115
117
  children,
116
118
  isDracoGeometry
117
119
  });
@@ -124,7 +126,7 @@ export default class I3SNodePagesTiles {
124
126
  * {string} url - url to the geometry resource
125
127
  * {boolean} isDracoGeometry - whether the geometry resource contain DRACO compressed geometry
126
128
  */
127
- _getContentUrl(meshGeometryData) {
129
+ private getContentUrl(meshGeometryData) {
128
130
  let result = {};
129
131
  const geometryDefinition = this.tileset.geometryDefinitions[meshGeometryData.definition];
130
132
  let geometryIndex = -1;
@@ -159,7 +161,7 @@ export default class I3SNodePagesTiles {
159
161
  * {string} metricType - the label of the LOD metric
160
162
  * {number} maxError - the value of the metric
161
163
  */
162
- _getLodSelection(node): object[] {
164
+ private getLodSelection(node): object[] {
163
165
  const lodSelection: object[] = [];
164
166
  if (this.lodSelectionMetricType === 'maxScreenThresholdSQ') {
165
167
  lodSelection.push({
@@ -182,7 +184,7 @@ export default class I3SNodePagesTiles {
182
184
  * {string} textureData.format - format of the texture
183
185
  * materialDefinition - PBR-like material definition from `materialDefinitions`
184
186
  */
185
- _getInformationFromMaterial(material) {
187
+ private getInformationFromMaterial(material) {
186
188
  const textureDataDefault = {name: null, format: null};
187
189
  if (material) {
188
190
  const materialDefinition = this.tileset.materialDefinitions[material.definition];
@@ -206,13 +208,13 @@ export default class I3SNodePagesTiles {
206
208
  * @param {Object} tileset - I3S layer data
207
209
  * @returns {void}
208
210
  */
209
- _initSelectedFormatsForTextureDefinitions(tileset) {
211
+ private initSelectedFormatsForTextureDefinitions(tileset) {
210
212
  this.textureDefinitionsSelectedFormats = [];
211
- const possibleI3sFormats = this._getSupportedTextureFormats();
213
+ const possibleI3sFormats = this.getSupportedTextureFormats();
212
214
  const textureSetDefinitions = tileset.textureSetDefinitions || [];
213
215
  for (const textureSetDefinition of textureSetDefinitions) {
214
216
  const formats = (textureSetDefinition && textureSetDefinition.formats) || [];
215
- let selectedFormat = null;
217
+ let selectedFormat: {format: string; name: string} | null = null;
216
218
  for (const i3sFormat of possibleI3sFormats) {
217
219
  const format = formats.find((value) => value.format === i3sFormat);
218
220
  if (format) {
@@ -220,6 +222,15 @@ export default class I3SNodePagesTiles {
220
222
  break;
221
223
  }
222
224
  }
225
+ // For I3S 1.8 need to define basis target format to decode
226
+ if (selectedFormat && selectedFormat.format === 'ktx2') {
227
+ this.textureLoaderOptions.basis = {
228
+ format: selectSupportedBasisFormat(),
229
+ containerFormat: 'ktx2',
230
+ module: 'encoder'
231
+ };
232
+ }
233
+
223
234
  this.textureDefinitionsSelectedFormats.push(selectedFormat);
224
235
  }
225
236
  }
@@ -228,9 +239,10 @@ export default class I3SNodePagesTiles {
228
239
  * Returns the array of supported texture format
229
240
  * @returns list of format strings
230
241
  */
231
- _getSupportedTextureFormats(): string[] {
242
+ private getSupportedTextureFormats(): string[] {
232
243
  const formats: string[] = [];
233
244
  if (!this.options.i3s || this.options.i3s.useCompressedTextures) {
245
+ // I3S 1.7 selection
234
246
  const supportedCompressedFormats = getSupportedGPUTextureFormats();
235
247
  // List of possible in i3s formats:
236
248
  // https://github.com/Esri/i3s-spec/blob/master/docs/1.7/textureSetDefinitionFormat.cmn.md
@@ -240,6 +252,10 @@ export default class I3SNodePagesTiles {
240
252
  if (supportedCompressedFormats.has('dxt')) {
241
253
  formats.push('dds');
242
254
  }
255
+
256
+ // I3S 1.8 selection
257
+ // ktx2 wraps basis texture which at the edge case can be decoded as uncompressed image
258
+ formats.push('ktx2');
243
259
  }
244
260
 
245
261
  formats.push('jpg');
@@ -47,3 +47,25 @@ export const SIZEOF = {
47
47
  export const STRING_ATTRIBUTE_TYPE = 'String';
48
48
  export const OBJECT_ID_ATTRIBUTE_TYPE = 'Oid32';
49
49
  export const FLOAT_64_TYPE = 'Float64';
50
+ export const INT_16_ATTRIBUTE_TYPE = 'Int16';
51
+
52
+ // https://github.com/visgl/deck.gl/blob/9548f43cba2234a1f4877b6b17f6c88eb35b2e08/modules/core/src/lib/constants.js#L27
53
+ // Describes the format of positions
54
+ export const COORDINATE_SYSTEM = {
55
+ // `LNGLAT` if rendering into a geospatial viewport, `CARTESIAN` otherwise
56
+ DEFAULT: -1,
57
+ // Positions are interpreted as [lng, lat, elevation]
58
+ // lng lat are degrees, elevation is meters. distances as meters.
59
+ LNGLAT: 1,
60
+
61
+ // Positions are interpreted as meter offsets, distances as meters
62
+ METER_OFFSETS: 2,
63
+
64
+ // Positions are interpreted as lng lat offsets: [deltaLng, deltaLat, elevation]
65
+ // deltaLng, deltaLat are delta degrees, elevation is meters.
66
+ // distances as meters.
67
+ LNGLAT_OFFSETS: 3,
68
+
69
+ // Non-geospatial
70
+ CARTESIAN: 0
71
+ };
@@ -1,4 +1,9 @@
1
- import {STRING_ATTRIBUTE_TYPE, OBJECT_ID_ATTRIBUTE_TYPE, FLOAT_64_TYPE} from './constants';
1
+ import {
2
+ STRING_ATTRIBUTE_TYPE,
3
+ OBJECT_ID_ATTRIBUTE_TYPE,
4
+ FLOAT_64_TYPE,
5
+ INT_16_ATTRIBUTE_TYPE
6
+ } from './constants';
2
7
 
3
8
  /**
4
9
  * Get particular tile and creates attribute object inside.
@@ -31,6 +36,8 @@ function parseAttribute(attributeType, arrayBuffer) {
31
36
  return parseShortNumberAttribute(arrayBuffer);
32
37
  case FLOAT_64_TYPE:
33
38
  return parseFloatAttribute(arrayBuffer);
39
+ case INT_16_ATTRIBUTE_TYPE:
40
+ return parseInt16ShortNumberAttribute(arrayBuffer);
34
41
  default:
35
42
  return parseShortNumberAttribute(arrayBuffer);
36
43
  }
@@ -47,6 +54,17 @@ function parseShortNumberAttribute(arrayBuffer) {
47
54
  return new Uint32Array(arrayBuffer, countOffset);
48
55
  }
49
56
 
57
+ /**
58
+ * Parse Int16 short number attribute.
59
+ * Parsing of such data is not documented. Added to handle Building Scene Layer Tileset attributes data.
60
+ * @param {ArrayBuffer} arrayBuffer
61
+ * @returns {Int16Array}
62
+ */
63
+ function parseInt16ShortNumberAttribute(arrayBuffer) {
64
+ const countOffset = 4;
65
+ return new Int16Array(arrayBuffer, countOffset);
66
+ }
67
+
50
68
  /**
51
69
  * Parse float attribute.
52
70
  * Double Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/attributeStorageInfo.cmn.md
@@ -0,0 +1,57 @@
1
+ import type {BuildingSceneLayerTileset, BuildingSceneSublayer} from '../../types';
2
+
3
+ const OBJECT_3D_LAYER_TYPE = '3DObject';
4
+
5
+ /**
6
+ * Parses Builiding Scene Layer and creates tileset
7
+ * @param data
8
+ * @param options
9
+ * @param context
10
+ */
11
+ export async function parseBuildingSceneLayer(
12
+ data: ArrayBuffer,
13
+ url: string
14
+ ): Promise<BuildingSceneLayerTileset> {
15
+ const layer0 = JSON.parse(new TextDecoder().decode(data));
16
+ const {sublayers} = layer0;
17
+
18
+ return {
19
+ header: layer0,
20
+ sublayers: parseSublayersTree(sublayers, url)
21
+ };
22
+ }
23
+
24
+ /**
25
+ * Recursively parses Building Scene Layer sublayers.
26
+ * @param sublayers
27
+ * @param url
28
+ */
29
+ function parseSublayersTree(
30
+ sublayers: BuildingSceneSublayer[],
31
+ url: string
32
+ ): BuildingSceneSublayer[] {
33
+ let layers: BuildingSceneSublayer[] = [];
34
+
35
+ for (let index = 0; index < sublayers.length; index++) {
36
+ const subLayer = sublayers[index];
37
+ const {id, layerType, ...rest} = subLayer;
38
+
39
+ // Add support only for 3DObject layer type for I3S purposes.
40
+ if (layerType === OBJECT_3D_LAYER_TYPE) {
41
+ const sublayerUrl = `${url}/sublayers/${id}`;
42
+
43
+ layers.push({
44
+ url: sublayerUrl,
45
+ id,
46
+ layerType,
47
+ ...rest
48
+ });
49
+ }
50
+
51
+ if (subLayer?.sublayers?.length) {
52
+ layers = [...layers, ...parseSublayersTree(subLayer.sublayers, url)];
53
+ }
54
+ }
55
+
56
+ return layers;
57
+ }
@@ -17,7 +17,8 @@ import {
17
17
  SIZEOF,
18
18
  I3S_NAMED_HEADER_ATTRIBUTES,
19
19
  I3S_NAMED_VERTEX_ATTRIBUTES,
20
- I3S_NAMED_GEOMETRY_ATTRIBUTES
20
+ I3S_NAMED_GEOMETRY_ATTRIBUTES,
21
+ COORDINATE_SYSTEM
21
22
  } from './constants';
22
23
 
23
24
  const scratchVector = new Vector3([0, 0, 0]);
@@ -53,22 +54,26 @@ export async function parseI3STileContent(
53
54
  const response = await fetch(url);
54
55
  const arrayBuffer = await response.arrayBuffer();
55
56
 
56
- if (loader === ImageLoader) {
57
- const options = {...tile.textureLoaderOptions, image: {type: 'data'}};
58
- // @ts-ignore context must be defined
59
- // Image constructor is not supported in worker thread.
60
- // Do parsing image data on the main thread by using context to avoid worker issues.
61
- tile.content.texture = await context.parse(arrayBuffer, options);
62
- } else if (loader === CompressedTextureLoader || loader === BasisLoader) {
63
- // @ts-ignore context must be defined
64
- const texture = await load(arrayBuffer, loader, tile.textureLoaderOptions);
65
- tile.content.texture = {
66
- compressed: true,
67
- mipmaps: false,
68
- width: texture[0].width,
69
- height: texture[0].height,
70
- data: texture
71
- };
57
+ if (options?.i3s.decodeTextures) {
58
+ if (loader === ImageLoader) {
59
+ const options = {...tile.textureLoaderOptions, image: {type: 'data'}};
60
+ // @ts-ignore context must be defined
61
+ // Image constructor is not supported in worker thread.
62
+ // Do parsing image data on the main thread by using context to avoid worker issues.
63
+ tile.content.texture = await context.parse(arrayBuffer, options);
64
+ } else if (loader === CompressedTextureLoader || loader === BasisLoader) {
65
+ // @ts-ignore context must be defined
66
+ const texture = await load(arrayBuffer, loader, tile.textureLoaderOptions);
67
+ tile.content.texture = {
68
+ compressed: true,
69
+ mipmaps: false,
70
+ width: texture[0].width,
71
+ height: texture[0].height,
72
+ data: texture
73
+ };
74
+ }
75
+ } else {
76
+ tile.content.texture = arrayBuffer;
72
77
  }
73
78
  }
74
79
 
@@ -77,13 +82,14 @@ export async function parseI3STileContent(
77
82
  tile.content.texture = null;
78
83
  }
79
84
 
80
- return await parseI3SNodeGeometry(arrayBuffer, tile, context);
85
+ return await parseI3SNodeGeometry(arrayBuffer, tile, options, context);
81
86
  }
82
87
 
83
88
  /* eslint-disable max-statements */
84
89
  async function parseI3SNodeGeometry(
85
90
  arrayBuffer: ArrayBuffer,
86
91
  tile: Tile = {},
92
+ options?: LoaderOptions,
87
93
  context?: LoaderContext
88
94
  ) {
89
95
  if (!tile.content) {
@@ -161,12 +167,17 @@ async function parseI3SNodeGeometry(
161
167
  attributes = concatAttributes(normalizedVertexAttributes, normalizedFeatureAttributes);
162
168
  }
163
169
 
164
- const {enuMatrix, cartographicOrigin, cartesianOrigin} = parsePositions(
165
- attributes.position,
166
- tile
167
- );
168
-
169
- const matrix = new Matrix4().multiplyRight(enuMatrix);
170
+ if (
171
+ !options?.i3s?.coordinateSystem ||
172
+ options.i3s.coordinateSystem === COORDINATE_SYSTEM.METER_OFFSETS
173
+ ) {
174
+ const {enuMatrix} = parsePositions(attributes.position, tile);
175
+ content.modelMatrix = enuMatrix.invert();
176
+ content.coordinateSystem = COORDINATE_SYSTEM.METER_OFFSETS;
177
+ } else {
178
+ content.modelMatrix = getModelMatrix(attributes.position);
179
+ content.coordinateSystem = COORDINATE_SYSTEM.LNGLAT_OFFSETS;
180
+ }
170
181
 
171
182
  content.attributes = {
172
183
  positions: attributes.position,
@@ -189,9 +200,6 @@ async function parseI3SNodeGeometry(
189
200
  }
190
201
 
191
202
  content.vertexCount = vertexCount;
192
- content.cartographicCenter = cartographicOrigin;
193
- content.cartesianOrigin = cartesianOrigin;
194
- content.modelMatrix = matrix.invert();
195
203
  content.byteLength = arrayBuffer.byteLength;
196
204
 
197
205
  return tile;
@@ -395,10 +403,7 @@ function parsePositions(attribute, tile) {
395
403
  attribute.value = offsetsToCartesians(value, metadata, cartographicOrigin);
396
404
 
397
405
  return {
398
- enuMatrix,
399
- fixedFrameToENUMatrix: enuMatrix.invert(),
400
- cartographicOrigin,
401
- cartesianOrigin
406
+ enuMatrix
402
407
  };
403
408
  }
404
409
 
@@ -431,6 +436,21 @@ function offsetsToCartesians(vertices, metadata = {}, cartographicOrigin) {
431
436
  return positions;
432
437
  }
433
438
 
439
+ /**
440
+ * Get model matrix for loaded vertices
441
+ * @param positions positions attribute
442
+ * @returns Matrix4 - model matrix for geometry transformation
443
+ */
444
+ function getModelMatrix(positions) {
445
+ const metadata = positions.metadata;
446
+ const scaleX = metadata?.['i3s-scale_x']?.double || 1;
447
+ const scaleY = metadata?.['i3s-scale_y']?.double || 1;
448
+ const modelMatrix = new Matrix4();
449
+ modelMatrix[0] = scaleX;
450
+ modelMatrix[5] = scaleY;
451
+ return modelMatrix;
452
+ }
453
+
434
454
  /**
435
455
  * Makes a glTF-compatible PBR material from an I3S material definition
436
456
  * @param {object} materialDefinition - i3s material definition
package/src/types.ts CHANGED
@@ -26,12 +26,7 @@ export type SceneLayer3D = {
26
26
  id: number;
27
27
  href?: string;
28
28
  layerType: string;
29
- spatialReference?: {
30
- wkid: number;
31
- latestWkid: number;
32
- vcsWkid: number;
33
- latestVcsWkid: number;
34
- };
29
+ spatialReference?: SpatialReference;
35
30
  heightModelInfo?: HeightModelInfo;
36
31
  version: string;
37
32
  name?: string;
@@ -180,6 +175,106 @@ export type Extent = [number, number, number, number];
180
175
 
181
176
  export type FeatureAttribute = {[key: string]: any};
182
177
 
178
+ export type BuildingSceneLayerTileset = {
179
+ header: BuildingSceneLayer;
180
+ sublayers: BuildingSceneSublayer[];
181
+ };
182
+
183
+ export type BuildingSceneLayer = {
184
+ id: number;
185
+ name: string;
186
+ version: string;
187
+ alias?: string;
188
+ layerType: 'Building';
189
+ description?: string;
190
+ copyrightText?: string;
191
+ fullExtent: FullExtent;
192
+ spatialReference: SpatialReference;
193
+ heightModelInfo?: HeightModelInfo;
194
+ sublayers: BuildingSceneSublayer[];
195
+ filters?: Filter[];
196
+ activeFilterID?: string;
197
+ statisticsHRef?: string;
198
+ };
199
+
200
+ export type BuildingSceneSublayer = {
201
+ id: number;
202
+ name: string;
203
+ alias?: string;
204
+ discipline?: 'Mechanical' | 'Architectural' | 'Piping' | 'Electrical' | 'Structural';
205
+ modelName?: string;
206
+ layerType: 'group' | '3DObject' | 'Point';
207
+ visibility?: boolean;
208
+ sublayers?: BuildingSceneSublayer[];
209
+ isEmpty?: boolean;
210
+ url?: string;
211
+ };
212
+
213
+ type Filter = {
214
+ id: string;
215
+ name: string;
216
+ description: string;
217
+ isDefaultFilter?: boolean;
218
+ isVisible?: boolean;
219
+ filterBlocks: FilterBlock[];
220
+ filterAuthoringInfo?: FilterAuthoringInfo;
221
+ };
222
+
223
+ type FilterAuthoringInfo = {
224
+ type: string;
225
+ filterBlocks: FilterBlockAuthoringInfo[];
226
+ };
227
+
228
+ type FilterBlockAuthoringInfo = {
229
+ filterTypes: FilterType[];
230
+ };
231
+
232
+ type FilterType = {
233
+ filterType: string;
234
+ filterValues: string[];
235
+ };
236
+
237
+ type FilterBlock = {
238
+ title: string;
239
+ filterMode: FilterModeSolid | FilterModeWireFrame;
240
+ filterExpression: string;
241
+ };
242
+
243
+ type Edges = {
244
+ type: string;
245
+ color: number[];
246
+ size: number;
247
+ transparency: number;
248
+ extensionLength: number;
249
+ };
250
+
251
+ type FilterModeSolid = {
252
+ type: 'solid';
253
+ };
254
+
255
+ type FilterModeWireFrame = {
256
+ type: 'wireFrame';
257
+ edges: Edges;
258
+ };
259
+
260
+ type SpatialReference = {
261
+ wkid: number;
262
+ latestWkid: number;
263
+ vcsWkid: number;
264
+ latestVcsWkid: number;
265
+ wkt?: string;
266
+ };
267
+
268
+ type FullExtent = {
269
+ xmin: number; // left
270
+ xmax: number; // right
271
+ ymin: number; // bottom
272
+ ymax: number; // top
273
+ zmin: number; // lowest elevation
274
+ zmax: number; // highest elevation
275
+ spatialReference?: SpatialReference;
276
+ };
277
+
183
278
  type TextureDefinitionInfo = {
184
279
  encoding: string[];
185
280
  wrap?: string[];
@@ -229,6 +324,7 @@ type DefaultGeometrySchema = {
229
324
  region: Uint16Array;
230
325
  };
231
326
 
327
+ // TODO change string to possible values from https://github.com/Esri/i3s-spec/blob/master/docs/1.8/heightModelInfo.cmn.md
232
328
  type HeightModelInfo = {
233
329
  heightModel: string;
234
330
  vertCRS: string;