@loaders.gl/tile-converter 3.1.0 → 3.1.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.
- package/dist/converter.min.js +18 -18
- package/dist/{bundle.js → dist.min.js} +1113 -403
- package/dist/es5/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
- package/dist/es5/i3s-converter/helpers/geometry-attributes.js +11 -18
- package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
- package/dist/es5/i3s-converter/helpers/geometry-converter.js +29 -4
- package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
- package/dist/es5/i3s-converter/helpers/node-debug.js +9 -3
- package/dist/es5/i3s-converter/helpers/node-debug.js.map +1 -1
- package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
- package/dist/es5/pgm-loader.js +1 -1
- package/dist/esm/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
- package/dist/esm/i3s-converter/helpers/geometry-attributes.js +10 -18
- package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
- package/dist/esm/i3s-converter/helpers/geometry-converter.js +31 -4
- package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
- package/dist/esm/i3s-converter/helpers/node-debug.js +9 -3
- package/dist/esm/i3s-converter/helpers/node-debug.js.map +1 -1
- package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
- package/dist/esm/pgm-loader.js +1 -1
- package/package.json +16 -16
- package/src/i3s-converter/helpers/create-scene-server-path.ts +9 -5
- package/src/i3s-converter/helpers/geometry-attributes.ts +52 -30
- package/src/i3s-converter/helpers/geometry-converter.js +39 -4
- package/src/i3s-converter/helpers/node-debug.ts +58 -12
- package/src/i3s-converter/i3s-converter.ts +1 -1
- 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
|
|
9
|
-
* @returns
|
|
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
|
|
27
|
-
const attributeObjects = makeAttributeObjects({
|
|
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
|
|
34
|
+
return groupedAttributes;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/**
|
|
36
38
|
* Calculates face Ranges and feature count based on featureIndices.
|
|
37
|
-
* @param
|
|
38
|
-
* @returns
|
|
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
|
|
78
|
-
* @returns
|
|
83
|
+
* @param attributes
|
|
84
|
+
* @returns sorted list of attribute objects.
|
|
79
85
|
*/
|
|
80
|
-
function makeAttributeObjects(attributes) {
|
|
81
|
-
const {
|
|
82
|
-
|
|
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
|
|
122
|
-
* @param
|
|
123
|
-
* @param
|
|
124
|
-
* @returns
|
|
134
|
+
* @param attributeName
|
|
135
|
+
* @param startIndex
|
|
136
|
+
* @param endIndex
|
|
137
|
+
* @returns sliced count
|
|
125
138
|
*/
|
|
126
|
-
function getSliceAttributeCount(
|
|
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
|
|
149
|
-
* @returns
|
|
165
|
+
* @param sortedData
|
|
166
|
+
* @returns unique list of objects
|
|
150
167
|
*/
|
|
151
|
-
function unifyObjectsByFeatureId(
|
|
152
|
-
|
|
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
|
|
180
|
-
* @returns
|
|
198
|
+
* @param unifiedObjects
|
|
199
|
+
* @returns generated attributes with new faceRange.
|
|
181
200
|
*/
|
|
182
|
-
function groupAttributesAndRangesByFeatureId(
|
|
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
|
|
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,
|
|
296
|
+
convertMesh(mesh, tileContent, attributesMap, useCartesianPositions, transformationMatrix);
|
|
268
297
|
}
|
|
269
298
|
|
|
270
|
-
convertNodes(
|
|
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
|
-
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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
|
|
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);
|
|
@@ -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
|
+
};
|