@inweb/viewer-three 26.12.5 → 26.12.7

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 (45) hide show
  1. package/dist/extensions/loaders/GLTFFileLoader.js +1 -1
  2. package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -1
  3. package/dist/extensions/loaders/GLTFFileLoader.min.js +1 -1
  4. package/dist/extensions/loaders/GLTFFileLoader.module.js +1 -1
  5. package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -1
  6. package/dist/extensions/loaders/IFCXLoader.js +2 -2
  7. package/dist/extensions/loaders/IFCXLoader.js.map +1 -1
  8. package/dist/extensions/loaders/IFCXLoader.min.js +1 -1
  9. package/dist/extensions/loaders/IFCXLoader.module.js +2 -2
  10. package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -1
  11. package/dist/viewer-three.js +467 -164
  12. package/dist/viewer-three.js.map +1 -1
  13. package/dist/viewer-three.min.js +3 -3
  14. package/dist/viewer-three.module.js +465 -162
  15. package/dist/viewer-three.module.js.map +1 -1
  16. package/extensions/loaders/GLTFFileLoader.ts +1 -1
  17. package/extensions/loaders/IFCX/IFCXCloudLoader.ts +1 -1
  18. package/extensions/loaders/IFCX/IFCXFileLoader.ts +1 -1
  19. package/lib/Viewer/components/ExtentsComponent.d.ts +1 -1
  20. package/lib/Viewer/components/ResetComponent.d.ts +1 -1
  21. package/lib/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.d.ts +3 -3
  22. package/lib/Viewer/measurement/Snapper.d.ts +1 -0
  23. package/lib/Viewer/measurement/UnitConverter.d.ts +20 -13
  24. package/lib/Viewer/models/IModelImpl.d.ts +2 -6
  25. package/lib/Viewer/models/ModelImpl.d.ts +4 -6
  26. package/package.json +5 -5
  27. package/src/Viewer/Viewer.ts +15 -11
  28. package/src/Viewer/commands/GetSelected2.ts +2 -2
  29. package/src/Viewer/commands/ResetView.ts +0 -5
  30. package/src/Viewer/commands/ZoomTo.ts +3 -3
  31. package/src/Viewer/components/CameraComponent.ts +4 -4
  32. package/src/Viewer/components/ExtentsComponent.ts +3 -3
  33. package/src/Viewer/components/HighlighterComponent.ts +11 -17
  34. package/src/Viewer/components/ResetComponent.ts +5 -2
  35. package/src/Viewer/components/SelectionComponent.ts +14 -13
  36. package/src/Viewer/draggers/MeasureLineDragger.ts +1 -0
  37. package/src/Viewer/draggers/OrbitDragger.ts +2 -0
  38. package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +285 -10
  39. package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +94 -18
  40. package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +1 -1
  41. package/src/Viewer/measurement/Snapper.ts +6 -3
  42. package/src/Viewer/measurement/UnitConverter.ts +19 -12
  43. package/src/Viewer/measurement/UnitFormatter.ts +2 -2
  44. package/src/Viewer/models/IModelImpl.ts +2 -10
  45. package/src/Viewer/models/ModelImpl.ts +111 -61
@@ -102,6 +102,10 @@ export class DynamicGltfLoader {
102
102
  this.newOptimizedObjects = new Set();
103
103
  this.oldOptimizeObjects = new Set();
104
104
 
105
+ // Transform system for exploded view - works directly with original objects
106
+ this.objectTransforms = new Map(); // originalObject -> Matrix4
107
+ this.transformedGeometries = new Map(); // mergedObject.uuid -> original position data
108
+
105
109
  this.activeChunkLoads = 0;
106
110
  this.chunkQueue = [];
107
111
 
@@ -311,7 +315,6 @@ export class DynamicGltfLoader {
311
315
  const uniqueTextureIds = new Set();
312
316
  if (Array.isArray(this.structures)) {
313
317
  for (const structure of this.structures) {
314
- // console.log(structure.materialCache.values());
315
318
  try {
316
319
  for (const entry of structure.materialCache.values()) {
317
320
  if (entry?.mesh?.uuid) uniqueMaterialIds.add(entry.mesh.uuid);
@@ -1006,17 +1009,40 @@ export class DynamicGltfLoader {
1006
1009
  if (node.object && this.hiddenHandles.has(node.object.userData.handle)) continue;
1007
1010
 
1008
1011
  const transformedBox = node.geometryExtents.clone();
1012
+ const structureRoot = node.structure ? this.structureRoots.get(node.structure.id) : null;
1013
+
1014
+ if (node.group) {
1015
+ const matrices = [];
1016
+ let currentGroup = node.group;
1009
1017
 
1010
- if (node.group && node.group.matrix) {
1011
- transformedBox.applyMatrix4(node.group.matrix);
1018
+ while (currentGroup && currentGroup !== structureRoot) {
1019
+ if (currentGroup.matrix && currentGroup.matrixAutoUpdate === false) {
1020
+ matrices.unshift(currentGroup.matrix);
1021
+ }
1022
+ currentGroup = currentGroup.parent;
1023
+ }
1012
1024
 
1013
- if (node.group.parent && node.group.parent.matrix) {
1014
- transformedBox.applyMatrix4(node.group.parent.matrix);
1025
+ for (const matrix of matrices) {
1026
+ transformedBox.applyMatrix4(matrix);
1015
1027
  }
1016
1028
  }
1029
+
1030
+ if (structureRoot && structureRoot.matrix) {
1031
+ transformedBox.applyMatrix4(structureRoot.matrix);
1032
+ }
1033
+
1034
+ const transform = this.objectTransforms.get(node.object);
1035
+ if (transform) {
1036
+ transformedBox.applyMatrix4(transform);
1037
+ }
1038
+
1017
1039
  totalExtent.union(transformedBox);
1018
1040
  }
1019
1041
 
1042
+ if (this.scene && this.scene.matrix && !totalExtent.isEmpty()) {
1043
+ totalExtent.applyMatrix4(this.scene.matrix);
1044
+ }
1045
+
1020
1046
  return totalExtent;
1021
1047
  }
1022
1048
 
@@ -1101,7 +1127,6 @@ export class DynamicGltfLoader {
1101
1127
  for (let i = 0; i < this.maxObjectId; i++) {
1102
1128
  this.objectVisibility[i] = 1.0;
1103
1129
  }
1104
- console.log(`Initialized object visibility array: ${this.maxObjectId} objects`);
1105
1130
  }
1106
1131
  }
1107
1132
 
@@ -1255,6 +1280,9 @@ export class DynamicGltfLoader {
1255
1280
  this.oldOptimizeObjects.clear();
1256
1281
  this.isolatedObjects = [];
1257
1282
 
1283
+ this.objectTransforms.clear();
1284
+ this.transformedGeometries.clear();
1285
+
1258
1286
  this.totalLoadedObjects = 0;
1259
1287
  this.lastUpdateTime = 0;
1260
1288
  this.currentMemoryUsage = 0;
@@ -2114,6 +2142,231 @@ export class DynamicGltfLoader {
2114
2142
  }
2115
2143
  }
2116
2144
 
2145
+ applyObjectTransforms(objectTransformMap) {
2146
+ if (this.mergedObjectMap.size === 0) {
2147
+ console.warn("No merged objects to transform");
2148
+ return;
2149
+ }
2150
+
2151
+ // Store transform map directly
2152
+ this.objectTransforms = new Map(objectTransformMap);
2153
+
2154
+ // Apply transforms to all merged meshes
2155
+ for (const mesh of this.mergedMesh) {
2156
+ this._applyTransformToMergedObject(mesh);
2157
+ }
2158
+ for (const line of this.mergedLines) {
2159
+ this._applyTransformToMergedObject(line);
2160
+ }
2161
+ for (const lineSegment of this.mergedLineSegments) {
2162
+ this._applyTransformToMergedObject(lineSegment);
2163
+ }
2164
+ for (const point of this.mergedPoints) {
2165
+ this._applyTransformToMergedObject(point);
2166
+ }
2167
+ }
2168
+
2169
+ createExplodeTransforms(objects = null, explodeCenter = null, explodeFactor = 1.5) {
2170
+ const transformMap = new Map();
2171
+
2172
+ if (!explodeCenter) {
2173
+ explodeCenter = new Vector3();
2174
+ const extent = this.getTotalGeometryExtent();
2175
+ if (!extent.isEmpty()) {
2176
+ extent.getCenter(explodeCenter);
2177
+ }
2178
+ }
2179
+
2180
+ const objectsArray = objects
2181
+ ? Array.isArray(objects)
2182
+ ? objects
2183
+ : Array.from(objects)
2184
+ : Array.from(this.originalObjects);
2185
+
2186
+ for (const obj of objectsArray) {
2187
+ if (!obj.geometry || !obj.geometry.attributes.position) continue;
2188
+
2189
+ const boundingBox = new Box3().setFromBufferAttribute(obj.geometry.attributes.position);
2190
+
2191
+ if (obj.matrixWorld) {
2192
+ boundingBox.applyMatrix4(obj.matrixWorld);
2193
+ }
2194
+
2195
+ if (boundingBox.isEmpty()) continue;
2196
+
2197
+ const objectCenter = new Vector3();
2198
+ boundingBox.getCenter(objectCenter);
2199
+
2200
+ const direction = objectCenter.clone().sub(explodeCenter);
2201
+ const distance = direction.length();
2202
+
2203
+ if (distance > 0) {
2204
+ direction.normalize();
2205
+ const offset = direction.multiplyScalar(distance * (explodeFactor - 1.0));
2206
+
2207
+ const matrix = new Matrix4().makeTranslation(offset.x, offset.y, offset.z);
2208
+ transformMap.set(obj, matrix);
2209
+ }
2210
+ }
2211
+
2212
+ return transformMap;
2213
+ }
2214
+
2215
+ clearTransforms() {
2216
+ this.objectTransforms.clear();
2217
+
2218
+ for (const mesh of this.mergedMesh) {
2219
+ this._restoreOriginalGeometry(mesh);
2220
+ }
2221
+ for (const line of this.mergedLines) {
2222
+ this._restoreOriginalGeometry(line);
2223
+ }
2224
+ for (const lineSegment of this.mergedLineSegments) {
2225
+ this._restoreOriginalGeometry(lineSegment);
2226
+ }
2227
+ for (const point of this.mergedPoints) {
2228
+ this._restoreOriginalGeometry(point);
2229
+ }
2230
+ }
2231
+
2232
+ clearHandleTransforms() {
2233
+ this.clearTransforms();
2234
+ }
2235
+
2236
+ _applyTransformToMergedObject(mergedObject) {
2237
+ const objectData = this.mergedObjectMap.get(mergedObject.uuid);
2238
+ if (!objectData || !objectData.objectMapping) return;
2239
+
2240
+ const geometry = mergedObject.geometry;
2241
+ if (!geometry || !geometry.attributes.position) return;
2242
+
2243
+ const positionAttr = geometry.attributes.position;
2244
+ const positions = positionAttr.array;
2245
+
2246
+ if (!this.transformedGeometries.has(mergedObject.uuid)) {
2247
+ this.transformedGeometries.set(mergedObject.uuid, new Float32Array(positions));
2248
+ }
2249
+
2250
+ const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
2251
+ const tempVector = new Vector3();
2252
+
2253
+ for (const [originalMesh, mappingData] of objectData.objectMapping) {
2254
+ const transform = this.objectTransforms.get(originalMesh);
2255
+
2256
+ if (!transform) {
2257
+ const startIdx = mappingData.startVertexIndex * 3;
2258
+ const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
2259
+ for (let i = startIdx; i < endIdx; i++) {
2260
+ positions[i] = originalPositions[i];
2261
+ }
2262
+ continue;
2263
+ }
2264
+
2265
+ const startVertex = mappingData.startVertexIndex;
2266
+ const vertexCount = mappingData.vertexCount;
2267
+
2268
+ for (let i = 0; i < vertexCount; i++) {
2269
+ const idx = (startVertex + i) * 3;
2270
+
2271
+ tempVector.set(originalPositions[idx], originalPositions[idx + 1], originalPositions[idx + 2]);
2272
+
2273
+ tempVector.applyMatrix4(transform);
2274
+
2275
+ positions[idx] = tempVector.x;
2276
+ positions[idx + 1] = tempVector.y;
2277
+ positions[idx + 2] = tempVector.z;
2278
+ }
2279
+ }
2280
+
2281
+ if (geometry.attributes.normal) {
2282
+ this._updateNormalsForTransform(geometry, objectData, originalPositions);
2283
+ }
2284
+
2285
+ positionAttr.needsUpdate = true;
2286
+ geometry.computeBoundingSphere();
2287
+ geometry.computeBoundingBox();
2288
+ }
2289
+
2290
+ _updateNormalsForTransform(geometry, objectData, originalPositions) {
2291
+ const normalAttr = geometry.attributes.normal;
2292
+ if (!normalAttr) return;
2293
+
2294
+ const normals = normalAttr.array;
2295
+ const tempVector = new Vector3();
2296
+ const normalMatrix = new Matrix4();
2297
+
2298
+ // Store original normals if not already stored
2299
+ const normalsKey = `${geometry.uuid}_normals`;
2300
+ if (!this.transformedGeometries.has(normalsKey)) {
2301
+ this.transformedGeometries.set(normalsKey, new Float32Array(normals));
2302
+ }
2303
+
2304
+ const originalNormals = this.transformedGeometries.get(normalsKey);
2305
+
2306
+ for (const [originalMesh, mappingData] of objectData.objectMapping) {
2307
+ // Direct lookup by object reference - NO HANDLE LOOKUP!
2308
+ const transform = this.objectTransforms.get(originalMesh);
2309
+
2310
+ if (!transform) {
2311
+ // Restore original normals
2312
+ const startIdx = mappingData.startVertexIndex * 3;
2313
+ const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
2314
+ for (let i = startIdx; i < endIdx; i++) {
2315
+ normals[i] = originalNormals[i];
2316
+ }
2317
+ continue;
2318
+ }
2319
+
2320
+ // Create normal matrix (inverse transpose of transform)
2321
+ normalMatrix.copy(transform).invert().transpose();
2322
+
2323
+ const startVertex = mappingData.startVertexIndex;
2324
+ const vertexCount = mappingData.vertexCount;
2325
+
2326
+ for (let i = 0; i < vertexCount; i++) {
2327
+ const idx = (startVertex + i) * 3;
2328
+
2329
+ // Get original normal
2330
+ tempVector.set(originalNormals[idx], originalNormals[idx + 1], originalNormals[idx + 2]);
2331
+
2332
+ // Apply normal transformation
2333
+ tempVector.applyMatrix4(normalMatrix).normalize();
2334
+
2335
+ // Write back transformed normal
2336
+ normals[idx] = tempVector.x;
2337
+ normals[idx + 1] = tempVector.y;
2338
+ normals[idx + 2] = tempVector.z;
2339
+ }
2340
+ }
2341
+
2342
+ normalAttr.needsUpdate = true;
2343
+ }
2344
+
2345
+ _restoreOriginalGeometry(mergedObject) {
2346
+ const geometry = mergedObject.geometry;
2347
+ if (!geometry || !geometry.attributes.position) return;
2348
+
2349
+ // Restore original positions
2350
+ const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
2351
+ if (originalPositions) {
2352
+ const positions = geometry.attributes.position.array;
2353
+ positions.set(originalPositions);
2354
+ geometry.attributes.position.needsUpdate = true;
2355
+ }
2356
+
2357
+ // Restore original normals
2358
+ const normalsKey = `${geometry.uuid}_normals`;
2359
+ const originalNormals = this.transformedGeometries.get(normalsKey);
2360
+ if (originalNormals && geometry.attributes.normal) {
2361
+ const normals = geometry.attributes.normal.array;
2362
+ normals.set(originalNormals);
2363
+ geometry.attributes.normal.needsUpdate = true;
2364
+ }
2365
+
2366
+ geometry.computeBoundingSphere();
2367
+ geometry.computeBoundingBox();
2368
+ }
2369
+
2117
2370
  syncHiddenObjects() {
2118
2371
  if (this.mergedObjectMap.size === 0) {
2119
2372
  console.log("No merged objects to sync");
@@ -2149,19 +2402,41 @@ export class DynamicGltfLoader {
2149
2402
 
2150
2403
  getStructureGeometryExtent(structureId) {
2151
2404
  const extent = new Box3();
2405
+ const structureRoot = this.structureRoots.get(structureId);
2406
+
2152
2407
  for (const [nodeId, node] of this.nodes.entries()) {
2153
2408
  if (!node.geometryExtents) continue;
2154
2409
  if (!nodeId.startsWith(structureId + "_")) continue;
2155
2410
  if (node.object && this.hiddenHandles && this.hiddenHandles.has(node.object.userData.handle)) continue;
2156
2411
  const transformedBox = node.geometryExtents.clone();
2157
- if (node.group && node.group.matrix) {
2158
- transformedBox.applyMatrix4(node.group.matrix);
2159
- if (node.group.parent && node.group.parent.matrix) {
2160
- transformedBox.applyMatrix4(node.group.parent.matrix);
2412
+
2413
+ if (node.group) {
2414
+ const matrices = [];
2415
+ let currentGroup = node.group;
2416
+
2417
+ while (currentGroup && currentGroup !== structureRoot) {
2418
+ if (currentGroup.matrix && currentGroup.matrixAutoUpdate === false) {
2419
+ matrices.unshift(currentGroup.matrix);
2420
+ }
2421
+ currentGroup = currentGroup.parent;
2422
+ }
2423
+
2424
+ for (const matrix of matrices) {
2425
+ transformedBox.applyMatrix4(matrix);
2161
2426
  }
2162
2427
  }
2428
+
2429
+ if (structureRoot && structureRoot.matrix) {
2430
+ transformedBox.applyMatrix4(structureRoot.matrix);
2431
+ }
2432
+
2163
2433
  extent.union(transformedBox);
2164
2434
  }
2435
+
2436
+ if (this.scene && this.scene.matrix && !extent.isEmpty()) {
2437
+ extent.applyMatrix4(this.scene.matrix);
2438
+ }
2439
+
2165
2440
  return extent;
2166
2441
  }
2167
2442
 
@@ -21,7 +21,7 @@
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Box3, Object3D } from "three";
24
+ import { Box3, Matrix4, Object3D, Vector3 } from "three";
25
25
  import { IInfo, Info } from "@inweb/viewer-core";
26
26
 
27
27
  import { ModelImpl } from "../../models/ModelImpl";
@@ -72,33 +72,28 @@ export class DynamicModelImpl extends ModelImpl {
72
72
  return this.gltfLoader.getOriginalObjectForSelect();
73
73
  }
74
74
 
75
- override hasObject(object: any): boolean {
76
- return this.gltfLoader.originalObjects.has(object);
77
- }
78
-
79
75
  override getObjectsByHandles(handles: string | string[]): Object3D[] {
80
- const ownHandles = this.getOwnHandles(handles);
81
- if (ownHandles.length === 0) return [];
76
+ if (!Array.isArray(handles)) handles = [handles];
82
77
 
83
- const handlesSet = new Set(ownHandles);
78
+ const handlesSet = new Set(handles);
84
79
 
85
80
  const objects = [];
86
81
  handlesSet.forEach((handle) => {
87
- objects.push(...this.gltfLoader.getObjectsByHandle(handle));
82
+ objects.push(this.gltfLoader.getObjectsByHandle(handle));
88
83
  });
89
84
 
90
- return objects;
85
+ return objects.flat();
91
86
  }
92
87
 
93
88
  override getHandlesByObjects(objects: Object3D | Object3D[]): string[] {
94
- const ownObjects = this.getOwnObjects(objects);
95
- if (ownObjects.length === 0) return [];
89
+ if (!Array.isArray(objects)) objects = [objects];
96
90
 
97
91
  const handleSet = new Set<string>();
98
- ownObjects.forEach((object) => {
99
- const handle = object.userData.handle;
100
- if (handle) handleSet.add(handle);
101
- });
92
+ objects
93
+ .filter((object) => this.gltfLoader.originalObjects.has(object))
94
+ .forEach((object) => {
95
+ handleSet.add(object.userData.handle);
96
+ });
102
97
 
103
98
  return Array.from(handleSet);
104
99
  }
@@ -126,13 +121,94 @@ export class DynamicModelImpl extends ModelImpl {
126
121
  return this;
127
122
  }
128
123
 
129
- override showOriginalObjects(objects: Object3D | Object3D[]): this {
124
+ override highlightObjects(objects: Object3D | Object3D[]): this {
130
125
  this.gltfLoader.showOriginalObjects(objects);
131
126
  return this;
132
127
  }
133
128
 
134
- override hideOriginalObjects(objects: Object3D | Object3D[]): this {
129
+ override unhighlightObjects(objects: Object3D | Object3D[]): this {
135
130
  this.gltfLoader.hideOriginalObjects(objects);
136
131
  return this;
137
132
  }
133
+
134
+ override explode(scale = 0, coeff = 4): this {
135
+ const centers = new Map();
136
+
137
+ const calcObjectCenter = (object: Object3D, target: Vector3): Vector3 => {
138
+ const extents = new Box3().setFromObject(object);
139
+
140
+ const handle = object.userData.handle;
141
+ if (!handle) return extents.getCenter(target);
142
+
143
+ const center = centers.get(handle);
144
+ if (center) return target.copy(center);
145
+
146
+ const objects = this.getObjectsByHandles(handle);
147
+ objects.forEach((x: Object3D) => extents.expandByObject(x));
148
+ extents.getCenter(target);
149
+
150
+ centers.set(handle, target.clone());
151
+
152
+ return target;
153
+ };
154
+
155
+ function calcExplodeDepth(object: Object3D, depth: number): number {
156
+ let result = depth;
157
+ object.children
158
+ .filter((x: Object3D) => !x.userData.isOptimized)
159
+ .forEach((x: Object3D) => {
160
+ const objectDepth = calcExplodeDepth(x, depth + 1);
161
+ if (result < objectDepth) result = objectDepth;
162
+ });
163
+
164
+ object.userData.originalPosition = object.position.clone();
165
+ object.userData.originalCenter = calcObjectCenter(object, new Vector3());
166
+
167
+ return result;
168
+ }
169
+
170
+ const explodeScale = scale / 100;
171
+ const explodeRoot = this.scene.children[0];
172
+
173
+ if (!explodeRoot.userData.explodeDepth) explodeRoot.userData.explodeDepth = calcExplodeDepth(explodeRoot, 1);
174
+ const maxDepth = explodeRoot.userData.explodeDepth;
175
+
176
+ const scaledExplodeDepth = explodeScale * maxDepth + 1;
177
+ const explodeDepth = 0 | scaledExplodeDepth;
178
+ const currentSegmentFraction = scaledExplodeDepth - explodeDepth;
179
+
180
+ const transformMap = new Map();
181
+
182
+ function explodeObject(object, depth: number) {
183
+ if (object.isCamera) return;
184
+ if (object.userData.isHighlightWireframe) return;
185
+
186
+ object.position.copy(object.userData.originalPosition);
187
+
188
+ if (depth > 0 && depth <= explodeDepth && !object.userData.isExplodeLocked) {
189
+ let objectScale = explodeScale * coeff;
190
+ if (depth === explodeDepth) objectScale *= currentSegmentFraction;
191
+
192
+ const parentCenter = object.parent.userData.originalCenter;
193
+ const objectCenter = object.userData.originalCenter;
194
+ const objectOffset = objectCenter.clone().sub(parentCenter).multiplyScalar(objectScale);
195
+
196
+ object.position.add(objectOffset);
197
+
198
+ const matrix = new Matrix4().makeTranslation(objectOffset.x, objectOffset.y, objectOffset.z);
199
+ transformMap.set(object, matrix);
200
+ }
201
+
202
+ object.children
203
+ .filter((x: Object3D) => !x.userData.isOptimized)
204
+ .forEach((x: Object3D) => explodeObject(x, depth + 1));
205
+ }
206
+
207
+ explodeObject(explodeRoot, 0);
208
+ this.scene.updateMatrixWorld();
209
+
210
+ this.gltfLoader.applyObjectTransforms(transformMap);
211
+
212
+ return this;
213
+ }
138
214
  }
@@ -58,7 +58,7 @@ export class GltfStructure {
58
58
  this.textureCache = new Map();
59
59
  this.materialCache = new Map();
60
60
  this.uri = "";
61
- this._nextObjectId = 0;
61
+ this._nextObjectId = 1;
62
62
  this.loadingAborted = false;
63
63
  this.criticalError = null;
64
64
  }
@@ -49,6 +49,7 @@ export class Snapper {
49
49
  public camera: Camera;
50
50
  public renderer: WebGLRenderer;
51
51
  public canvas: HTMLCanvasElement;
52
+ public threshold: number;
52
53
  private raycaster: Raycaster;
53
54
  private detectRadiusInPixels: number;
54
55
  private edgesCache: WeakMap<any, EdgesGeometry>;
@@ -58,6 +59,8 @@ export class Snapper {
58
59
  this.renderer = renderer;
59
60
  this.canvas = canvas;
60
61
 
62
+ this.threshold = 0.0001;
63
+
61
64
  this.raycaster = new Raycaster();
62
65
  this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
63
66
  this.edgesCache = new WeakMap();
@@ -91,10 +94,10 @@ export class Snapper {
91
94
 
92
95
  this.raycaster.params = {
93
96
  Mesh: {},
94
- Line: { threshold: 0.05 },
95
- Line2: { threshold: 0.05 },
97
+ Line: { threshold: this.threshold },
98
+ Line2: { threshold: this.threshold },
96
99
  LOD: {},
97
- Points: { threshold: 0.01 },
100
+ Points: { threshold: this.threshold },
98
101
  Sprite: {},
99
102
  };
100
103
 
@@ -23,21 +23,28 @@
23
23
 
24
24
  // Model units for the user to choose from.
25
25
 
26
+ export const DisplayUnits = {
27
+ Meters: { name: "Meters", symbol: "m", scale: 1.0 },
28
+ Centimeters: { name: "Centimeters", symbol: "cm", scale: 0.01 },
29
+ Millimeters: { name: "Millimeters", symbol: "mm", scale: 0.001 },
30
+ Feet: { name: "Feet", symbol: "ft", scale: 0.3048 },
31
+ Inches: { name: "Inches", symbol: "in", scale: 0.0254 },
32
+ Yards: { name: "Yards", symbol: "yd", scale: 0.9144 },
33
+ Kilometers: { name: "Kilometers", symbol: "km", scale: 1000.0 },
34
+ Miles: { name: "Miles", symbol: "mi", scale: 1609.344 },
35
+ Micrometers: { name: "Micrometers", symbol: "µm", scale: 0.000001 },
36
+ Mils: { name: "Mils", symbol: "mil", scale: 0.0000254 },
37
+ MicroInches: { name: "Micro-inches", symbol: "µin", scale: 0.0000000254 },
38
+ Default: { name: "File units", symbol: "", scale: 1.0 },
39
+ };
40
+
26
41
  export const ModelUnits = {
27
- Meters: { name: "Meters", type: "m", scale: 1.0 },
28
- Centimeters: { name: "Centimeters", type: "cm", scale: 0.01 },
29
- Millimeters: { name: "Millimeters", type: "mm", scale: 0.001 },
30
- Feet: { name: "Feet", type: "ft", scale: 0.3048 },
31
- Inches: { name: "Inches", type: "in", scale: 0.0254 },
32
- Yards: { name: "Yards", type: "yd", scale: 0.9144 },
33
- Kilometers: { name: "Kilometers", type: "km", scale: 1000.0 },
34
- Miles: { name: "Miles", type: "mi", scale: 1609.344 },
35
- Micrometers: { name: "Micrometers", type: "µm", scale: 0.000001 },
36
- Mils: { name: "Mils", type: "mil", scale: 0.0000254 },
37
- MicroInches: { name: "Micro-inches", type: "µin", scale: 0.0000000254 },
38
- Default: { name: "File units", type: "unit", scale: 1.0 },
42
+ Default: { name: "", symbol: "", scale: 1.0 },
39
43
  };
40
44
 
45
+ Object.keys(DisplayUnits).forEach((key) => (ModelUnits[key] = DisplayUnits[key]));
46
+ Object.keys(DisplayUnits).forEach((key) => (ModelUnits[DisplayUnits[key].symbol] = DisplayUnits[key]));
47
+
41
48
  // Convert distance from unit to unit.
42
49
 
43
50
  export function convertUnits(fromUnits: string, toUnits: string, distance: number) {
@@ -26,7 +26,7 @@ import { ModelUnits } from "./UnitConverter";
26
26
  // Returns a standard string representation of the display unit.
27
27
 
28
28
  export function getDisplayUnit(units: string) {
29
- return (ModelUnits[units] || ModelUnits.Default).type;
29
+ return (ModelUnits[units] || ModelUnits.Default).symbol;
30
30
  }
31
31
 
32
32
  // ===================== AI-CODE-START ======================
@@ -86,7 +86,7 @@ export function formatDistance(distance: number, units: string, precision: any =
86
86
  else if (digits > 10) digits = 10;
87
87
 
88
88
  if (ModelUnits[units]) {
89
- return formatNumber(distance, digits, precision) + " " + ModelUnits[units].type;
89
+ return formatNumber(distance, digits, precision) + " " + ModelUnits[units].symbol;
90
90
  } else if (units) {
91
91
  return formatNumber(distance, digits, precision) + " " + units;
92
92
  } else {
@@ -46,14 +46,6 @@ export interface IModelImpl extends IModel {
46
46
 
47
47
  getVisibleObjects(): Object3D[];
48
48
 
49
- hasObject(object: Object3D): boolean;
50
-
51
- hasHandle(handle: string): boolean;
52
-
53
- getOwnObjects(objects: Object3D | Object3D[]): Object3D[];
54
-
55
- getOwnHandles(handles: string | string[]): string[];
56
-
57
49
  getObjectsByHandles(handles: string | string[]): Object3D[];
58
50
 
59
51
  getHandlesByObjects(objects: Object3D | Object3D[]): string[];
@@ -68,9 +60,9 @@ export interface IModelImpl extends IModel {
68
60
 
69
61
  showAllObjects(): this;
70
62
 
71
- showOriginalObjects(objects: Object3D | Object3D[]): this;
63
+ highlightObjects(objects: Object3D | Object3D[]): this;
72
64
 
73
- hideOriginalObjects(objects: Object3D | Object3D[]): this;
65
+ unhighlightObjects(objects: Object3D | Object3D[]): this;
74
66
 
75
67
  explode(scale: number, coeff?: number): this;
76
68
  }