@loaders.gl/tile-converter 3.1.1 → 3.1.5

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 (29) hide show
  1. package/dist/converter.min.js +1 -1
  2. package/dist/{bundle.js → dist.min.js} +88 -24
  3. package/dist/es5/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
  4. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +11 -18
  5. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  6. package/dist/es5/i3s-converter/helpers/geometry-converter.js +29 -4
  7. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  8. package/dist/es5/i3s-converter/helpers/node-debug.js +9 -3
  9. package/dist/es5/i3s-converter/helpers/node-debug.js.map +1 -1
  10. package/dist/es5/i3s-converter/i3s-converter.js +12 -10
  11. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  12. package/dist/es5/pgm-loader.js +1 -1
  13. package/dist/esm/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
  14. package/dist/esm/i3s-converter/helpers/geometry-attributes.js +10 -18
  15. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  16. package/dist/esm/i3s-converter/helpers/geometry-converter.js +31 -4
  17. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  18. package/dist/esm/i3s-converter/helpers/node-debug.js +9 -3
  19. package/dist/esm/i3s-converter/helpers/node-debug.js.map +1 -1
  20. package/dist/esm/i3s-converter/i3s-converter.js +3 -3
  21. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  22. package/dist/esm/pgm-loader.js +1 -1
  23. package/package.json +15 -15
  24. package/src/i3s-converter/helpers/create-scene-server-path.ts +9 -5
  25. package/src/i3s-converter/helpers/geometry-attributes.ts +52 -30
  26. package/src/i3s-converter/helpers/geometry-converter.js +39 -4
  27. package/src/i3s-converter/helpers/node-debug.ts +58 -12
  28. package/src/i3s-converter/i3s-converter.ts +4 -4
  29. package/src/i3s-converter/types.ts +28 -0
@@ -1,3 +1,4 @@
1
+ import type {GeometryAttributes, AttributesData, GroupedByFeatureIdAttributes} from '../types';
1
2
  import {concatenateTypedArrays} from '@loaders.gl/loader-utils';
2
3
 
3
4
  const VALUES_PER_VERTEX = 3;
@@ -5,10 +6,10 @@ const POSITIONS_AND_NORMALS_PER_TRIANGLE = 9;
5
6
 
6
7
  /**
7
8
  * Generate geometry attributes with faceRange and featureCount
8
- * @param {Object} attributes
9
- * @returns {Object} Object with featureCount, reordered attributes and changed faceRange.
9
+ * @param attributes
10
+ * @returns attirbutes with featureCount, featureIds and changed faceRange.
10
11
  */
11
- export function generateAttributes(attributes) {
12
+ export function generateAttributes(attributes: AttributesData): GeometryAttributes {
12
13
  const {positions, normals, texCoords, colors, featureIndices, triangleCount} = attributes;
13
14
 
14
15
  if (!featureIndices.length) {
@@ -23,21 +24,26 @@ export function generateAttributes(attributes) {
23
24
  };
24
25
  }
25
26
 
26
- const {faceRange, featureCount, featureIds} = calculateFaceRangesAndFeaturesCount(featureIndices);
27
- const attributeObjects = makeAttributeObjects({faceRange, featureIds, ...attributes});
27
+ const data = calculateFaceRangesAndFeaturesCount(featureIndices);
28
+ const attributeObjects = makeAttributeObjects({...data, ...attributes});
28
29
  const unifiedAttributeObjectsByFeatureIds = unifyObjectsByFeatureId(attributeObjects);
29
30
  const groupedAttributes = groupAttributesAndRangesByFeatureId(
30
- unifiedAttributeObjectsByFeatureIds
31
+ unifiedAttributeObjectsByFeatureIds,
32
+ data.featureCount
31
33
  );
32
- return {featureCount, ...groupedAttributes};
34
+ return groupedAttributes;
33
35
  }
34
36
 
35
37
  /**
36
38
  * Calculates face Ranges and feature count based on featureIndices.
37
- * @param {Object} featureIndices
38
- * @returns {Object} Object with featureCount, reordered attributes and changed faceRange.
39
+ * @param featureIndices
40
+ * @returns Object with featureCount, reordered attributes and changed faceRange.
39
41
  */
40
- function calculateFaceRangesAndFeaturesCount(featureIndices) {
42
+ function calculateFaceRangesAndFeaturesCount(featureIndices: number[]): {
43
+ faceRange: Uint32Array;
44
+ featureCount: number;
45
+ featureIds: number[];
46
+ } {
41
47
  let rangeIndex = 1;
42
48
  let featureIndex = 1;
43
49
  let currentFeatureId = featureIndices[0];
@@ -74,12 +80,19 @@ function calculateFaceRangesAndFeaturesCount(featureIndices) {
74
80
 
75
81
  /**
76
82
  * Generate list of attribute object grouped by feature ids.
77
- * @param {Object} attributes
78
- * @returns {Array} sorted list of attribute objects.
83
+ * @param attributes
84
+ * @returns sorted list of attribute objects.
79
85
  */
80
- function makeAttributeObjects(attributes) {
81
- const {featureIds, positions, normals, colors, texCoords, faceRange} = attributes;
82
- const groupedData: any[] = [];
86
+ function makeAttributeObjects(attributes: GeometryAttributes): GroupedByFeatureIdAttributes[] {
87
+ const {
88
+ featureIds,
89
+ positions,
90
+ normals,
91
+ colors,
92
+ texCoords,
93
+ faceRange = new Uint32Array(0)
94
+ } = attributes;
95
+ const groupedData: GroupedByFeatureIdAttributes[] = [];
83
96
 
84
97
  let positionsList = new Float32Array(positions);
85
98
  let normalsList = new Float32Array(normals);
@@ -118,12 +131,16 @@ function makeAttributeObjects(attributes) {
118
131
 
119
132
  /**
120
133
  * Generate sliced count for generating attribute objects depends on attribute name and range.
121
- * @param {String} attributeName
122
- * @param {Number} startIndex
123
- * @param {Number} endIndex
124
- * @returns {Number} - sliced count
134
+ * @param attributeName
135
+ * @param startIndex
136
+ * @param endIndex
137
+ * @returns sliced count
125
138
  */
126
- function getSliceAttributeCount(attributeName, startIndex, endIndex) {
139
+ function getSliceAttributeCount(
140
+ attributeName: string,
141
+ startIndex: number,
142
+ endIndex: number
143
+ ): number {
127
144
  const colorsPerVertex = 4;
128
145
  const texCoordsPerVertex = 2;
129
146
 
@@ -145,11 +162,13 @@ function getSliceAttributeCount(attributeName, startIndex, endIndex) {
145
162
 
146
163
  /**
147
164
  * Generates unique object list depends on feature ids and concantenate their attributes.
148
- * @param {Array} sortedData
149
- * @returns {Array} - unique list of objects
165
+ * @param sortedData
166
+ * @returns unique list of objects
150
167
  */
151
- function unifyObjectsByFeatureId(sortedData) {
152
- const uniqueObjects: any[] = [];
168
+ function unifyObjectsByFeatureId(
169
+ sortedData: GroupedByFeatureIdAttributes[]
170
+ ): GroupedByFeatureIdAttributes[] {
171
+ const uniqueObjects: GroupedByFeatureIdAttributes[] = [];
153
172
 
154
173
  for (let index = 0; index < sortedData.length; index++) {
155
174
  const currentObject = sortedData[index];
@@ -176,12 +195,15 @@ function unifyObjectsByFeatureId(sortedData) {
176
195
 
177
196
  /**
178
197
  * Generates attribute objects with new faceRange and reordered attributes.
179
- * @param {Array} unifiedObjects
180
- * @returns {Object} - ugenerated attributes with new faceRange.
198
+ * @param unifiedObjects
199
+ * @returns generated attributes with new faceRange.
181
200
  */
182
- function groupAttributesAndRangesByFeatureId(unifiedObjects) {
201
+ function groupAttributesAndRangesByFeatureId(
202
+ unifiedObjects: GroupedByFeatureIdAttributes[],
203
+ featureCount: number
204
+ ): GeometryAttributes {
183
205
  const firstAttributeObject = unifiedObjects[0];
184
- const featureIds = [firstAttributeObject.featureId];
206
+ const featureIds = [firstAttributeObject.featureId || 0];
185
207
 
186
208
  let positions = new Float32Array(firstAttributeObject.positions);
187
209
  let normals = new Float32Array(firstAttributeObject.normals);
@@ -194,7 +216,7 @@ function groupAttributesAndRangesByFeatureId(unifiedObjects) {
194
216
 
195
217
  for (let index = 1; index < unifiedObjects.length; index++) {
196
218
  const currentAttributesObject = unifiedObjects[index];
197
- featureIds.push(currentAttributesObject.featureId);
219
+ featureIds.push(currentAttributesObject.featureId || 0);
198
220
 
199
221
  positions = concatenateTypedArrays(positions, currentAttributesObject.positions);
200
222
  normals = concatenateTypedArrays(normals, currentAttributesObject.normals);
@@ -212,5 +234,5 @@ function groupAttributesAndRangesByFeatureId(unifiedObjects) {
212
234
  range.push(positions.length / POSITIONS_AND_NORMALS_PER_TRIANGLE - 1);
213
235
 
214
236
  const faceRange = new Uint32Array(range);
215
- return {faceRange, featureIds, positions, normals, colors, texCoords};
237
+ return {faceRange, featureIds, positions, normals, colors, texCoords, featureCount};
216
238
  }
@@ -243,6 +243,36 @@ function convertNodes(
243
243
  }
244
244
  }
245
245
 
246
+ /**
247
+ * Generate transformation matrix for node
248
+ * Aapply all gltf transformations to initial transformation matrix.
249
+ * @param node
250
+ * @param matrix
251
+ */
252
+ function getCompositeTransformationMatrix(node, matrix) {
253
+ let transformationMatrix = matrix;
254
+
255
+ const {matrix: nodeMatrix, rotation, scale, translation} = node;
256
+
257
+ if (nodeMatrix) {
258
+ transformationMatrix = matrix.multiplyRight(nodeMatrix);
259
+ }
260
+
261
+ if (rotation) {
262
+ transformationMatrix = transformationMatrix.rotateXYZ(rotation);
263
+ }
264
+
265
+ if (scale) {
266
+ transformationMatrix = transformationMatrix.scale(scale);
267
+ }
268
+
269
+ if (translation) {
270
+ transformationMatrix = transformationMatrix.translate(translation);
271
+ }
272
+
273
+ return transformationMatrix;
274
+ }
275
+
246
276
  /**
247
277
  * Convert all primitives of node and all children nodes
248
278
  * @param {Object} node - gltf node
@@ -259,15 +289,20 @@ function convertNode(
259
289
  useCartesianPositions,
260
290
  matrix = new Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
261
291
  ) {
262
- const nodeMatrix = node.matrix;
263
- const compositeMatrix = nodeMatrix ? matrix.multiplyRight(nodeMatrix) : matrix;
292
+ const transformationMatrix = getCompositeTransformationMatrix(node, matrix);
264
293
 
265
294
  const mesh = node.mesh;
266
295
  if (mesh) {
267
- convertMesh(mesh, tileContent, attributesMap, useCartesianPositions, compositeMatrix);
296
+ convertMesh(mesh, tileContent, attributesMap, useCartesianPositions, transformationMatrix);
268
297
  }
269
298
 
270
- convertNodes(node.children, tileContent, attributesMap, useCartesianPositions, compositeMatrix);
299
+ convertNodes(
300
+ node.children,
301
+ tileContent,
302
+ attributesMap,
303
+ useCartesianPositions,
304
+ transformationMatrix
305
+ );
271
306
  }
272
307
 
273
308
  /**
@@ -1,14 +1,23 @@
1
+ import type {Mbs, Node3DIndexDocument, Obb} from '@loaders.gl/i3s';
2
+
1
3
  import {OrientedBoundingBox, BoundingSphere} from '@math.gl/culling';
2
4
  import {CubeGeometry} from '@luma.gl/engine';
3
5
  import {Vector3} from '@math.gl/core';
4
6
  import {Ellipsoid} from '@math.gl/geospatial';
5
7
 
6
8
  // TODO Unite Tile validation logic in i3s-17-and-debug with this code.
7
- export function validateNodeBoundingVolumes(node) {
8
- if (!node.parentNode.obb || !node.parentNode.mbs) {
9
+
10
+ /**
11
+ * Do validation of bounding volumes for particular node.
12
+ * Generates special warnings if there are some issues.
13
+ * @param node
14
+ */
15
+ export function validateNodeBoundingVolumes(node: Node3DIndexDocument): string[] {
16
+ if (!node?.parentNode?.obb || !node?.parentNode?.mbs) {
9
17
  return [];
10
18
  }
11
- const tileWarnings = [];
19
+
20
+ const tileWarnings: string[] = [];
12
21
 
13
22
  validateObb(tileWarnings, node);
14
23
  validateMbs(tileWarnings, node);
@@ -16,7 +25,13 @@ export function validateNodeBoundingVolumes(node) {
16
25
  return tileWarnings;
17
26
  }
18
27
 
19
- function validateObb(tileWarnings, node) {
28
+ /**
29
+ * Check if child Obb fit into parent Obb.
30
+ * @param tileWarnings
31
+ * @param node
32
+ */
33
+ function validateObb(tileWarnings: string[], node: Node3DIndexDocument): void {
34
+ // @ts-expect-error
20
35
  const parentObb = createBoundingBoxFromTileObb(node.parentNode.obb);
21
36
  const tileVertices = getTileObbVertices(node);
22
37
  const isTileObbInsideParentObb = isAllVerticesInsideBoundingVolume(parentObb, tileVertices);
@@ -25,36 +40,58 @@ function validateObb(tileWarnings, node) {
25
40
  return;
26
41
  }
27
42
 
28
- const title = `OBB of Tile (${node.id}) doesn't fit into Parent (${node.parentNode.id}) tile OBB`;
43
+ const title = `OBB of Tile (${node.id}) doesn't fit into Parent (${node.parentNode?.id}) tile OBB`;
29
44
  tileWarnings.push(title);
30
45
  }
31
46
 
32
- function validateMbs(tileWarnings, node) {
47
+ /**
48
+ * Check if child Mbs fit into parent Mbs.
49
+ * @param tileWarnings
50
+ * @param node
51
+ */
52
+ function validateMbs(tileWarnings: string[], node: Node3DIndexDocument): void {
53
+ // @ts-expect-error
33
54
  const tileMbs = createBoundingSphereFromTileMbs(node.mbs);
55
+ // @ts-expect-error
34
56
  const parentMbs = createBoundingSphereFromTileMbs(node.parentNode.mbs);
35
57
  const distanceBetweenCenters = tileMbs.center.distanceTo(parentMbs.center);
36
58
 
37
59
  if (distanceBetweenCenters + tileMbs.radius > parentMbs.radius) {
38
- const title = `MBS of Tile (${node.id}) doesn't fit into Parent (${node.parentNode.id}) tile MBS`;
60
+ const title = `MBS of Tile (${node.id}) doesn't fit into Parent (${node.parentNode?.id}) tile MBS`;
39
61
  tileWarnings.push(title);
40
62
  }
41
63
  }
42
64
 
43
- function createBoundingSphereFromTileMbs(mbs) {
65
+ /**
66
+ * Generates bounding sphere from mbs
67
+ * @param mbs
68
+ */
69
+ function createBoundingSphereFromTileMbs(mbs: Mbs): BoundingSphere {
44
70
  return new BoundingSphere([mbs[0], mbs[1], mbs[2]], mbs[3]);
45
71
  }
46
72
 
47
- function createBoundingBoxFromTileObb(obb) {
73
+ /**
74
+ * Generates oriented bounding box from tile obb
75
+ * @param obb
76
+ * @returns
77
+ */
78
+ function createBoundingBoxFromTileObb(obb: Obb): OrientedBoundingBox {
48
79
  const {center, halfSize, quaternion} = obb;
49
80
  return new OrientedBoundingBox().fromCenterHalfSizeQuaternion(center, halfSize, quaternion);
50
81
  }
51
82
 
52
- // TODO check if Obb generates properly
53
- function getTileObbVertices(node) {
83
+ /**
84
+ * Get vertices fromnode obb
85
+ * TODO check if Obb generates properly
86
+ * @param node
87
+ */
88
+ function getTileObbVertices(node: Node3DIndexDocument): number[] {
54
89
  const geometry = new CubeGeometry();
90
+ // @ts-expect-error
55
91
  const halfSize = node.obb.halfSize;
56
92
  const attributes = geometry.getAttributes();
57
93
  const positions = new Float32Array(attributes.POSITION.value);
94
+ // @ts-expect-error
58
95
  const obbCenterCartesian = Ellipsoid.WGS84.cartographicToCartesian(node.obb.center);
59
96
 
60
97
  let vertices = [];
@@ -66,6 +103,7 @@ function getTileObbVertices(node) {
66
103
  (positions[i + 2] *= halfSize[2])
67
104
  );
68
105
  const rotatedPositions = positionsVector
106
+ // @ts-expect-error
69
107
  .transformByQuaternion(node.obb.quaternion)
70
108
  .add(obbCenterCartesian);
71
109
  // @ts-expect-error
@@ -75,7 +113,15 @@ function getTileObbVertices(node) {
75
113
  return vertices;
76
114
  }
77
115
 
78
- function isAllVerticesInsideBoundingVolume(boundingVolume, positions) {
116
+ /**
117
+ * Check if all vertices inside bounding volume
118
+ * @param boundingVolume
119
+ * @param positions
120
+ */
121
+ function isAllVerticesInsideBoundingVolume(
122
+ boundingVolume: OrientedBoundingBox,
123
+ positions: number[]
124
+ ): boolean {
79
125
  let isVerticesInsideObb = true;
80
126
 
81
127
  for (let index = 0; index < positions.length / 3; index += 3) {
@@ -227,7 +227,7 @@ export default class I3SConverter {
227
227
 
228
228
  this.layers0!.materialDefinitions = this.materialDefinitions;
229
229
  await this._writeLayers0();
230
- createSceneServerPath(tilesetName, this.layers0, tilesetPath);
230
+ createSceneServerPath(tilesetName, this.layers0!, tilesetPath);
231
231
  await this._writeNodeIndexDocument(root0, 'root', join(this.layers0Path, 'nodes', 'root'));
232
232
  await this.nodePages.save(this.layers0Path, this.fileMap, isCreateSlpk);
233
233
  await this._createSlpk(tilesetPath);
@@ -942,9 +942,6 @@ export default class I3SConverter {
942
942
  childPath: string,
943
943
  slpkChildPath: string
944
944
  ): Promise<void> {
945
- const texturePath = join(childPath, `textures/${name}/`);
946
- await writeFile(texturePath, textureData, `index.${format}`);
947
-
948
945
  if (this.options.slpk) {
949
946
  const slpkTexturePath = join(childPath, 'textures');
950
947
  const compress = false;
@@ -955,6 +952,9 @@ export default class I3SConverter {
955
952
  `${name}.${format}`,
956
953
  compress
957
954
  );
955
+ } else {
956
+ const texturePath = join(childPath, `textures/${name}/`);
957
+ await writeFile(texturePath, textureData, `index.${format}`);
958
958
  }
959
959
  }
960
960
 
@@ -12,3 +12,31 @@ export type I3SConvertedResources = {
12
12
  geometryBuffer?: ArrayBuffer;
13
13
  boundingVolumes: BoundingVolumes | null;
14
14
  };
15
+
16
+ export type AttributesData = {
17
+ positions: Float32Array;
18
+ normals: Float32Array;
19
+ texCoords: Float32Array;
20
+ colors: Uint8Array;
21
+ featureIndices: number[];
22
+ triangleCount: number;
23
+ boundingVolumes?: BoundingVolumes | null;
24
+ };
25
+
26
+ export type GeometryAttributes = {
27
+ positions: Float32Array;
28
+ normals: Float32Array;
29
+ texCoords: Float32Array;
30
+ colors: Uint8Array;
31
+ faceRange: Uint32Array;
32
+ featureIds: number[];
33
+ featureCount: number;
34
+ };
35
+
36
+ export type GroupedByFeatureIdAttributes = {
37
+ featureId: number;
38
+ positions: Float32Array;
39
+ normals: Float32Array;
40
+ colors: Uint8Array;
41
+ texCoords: Float32Array;
42
+ };