@inweb/viewer-three 26.12.6 → 27.1.0
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/extensions/loaders/GLTFFileLoader.js +1 -1
- package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -1
- package/dist/extensions/loaders/GLTFFileLoader.min.js +1 -1
- package/dist/extensions/loaders/GLTFFileLoader.module.js +1 -1
- package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -1
- package/dist/extensions/loaders/IFCXLoader.js +2 -2
- package/dist/extensions/loaders/IFCXLoader.js.map +1 -1
- package/dist/extensions/loaders/IFCXLoader.min.js +1 -1
- package/dist/extensions/loaders/IFCXLoader.module.js +2 -2
- package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -1
- package/dist/viewer-three.js +466 -170
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +2 -2
- package/dist/viewer-three.module.js +464 -168
- package/dist/viewer-three.module.js.map +1 -1
- package/extensions/loaders/GLTFFileLoader.ts +1 -1
- package/extensions/loaders/IFCX/IFCXCloudLoader.ts +1 -1
- package/extensions/loaders/IFCX/IFCXFileLoader.ts +1 -1
- package/lib/Viewer/Viewer.d.ts +2 -1
- package/lib/Viewer/components/ExtentsComponent.d.ts +1 -1
- package/lib/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.d.ts +3 -3
- package/lib/Viewer/measurement/Snapper.d.ts +1 -0
- package/lib/Viewer/measurement/UnitConverter.d.ts +20 -13
- package/lib/Viewer/models/IModelImpl.d.ts +2 -6
- package/lib/Viewer/models/ModelImpl.d.ts +4 -6
- package/package.json +5 -5
- package/src/Viewer/Viewer.ts +25 -15
- package/src/Viewer/commands/GetSelected2.ts +2 -2
- package/src/Viewer/commands/ZoomTo.ts +3 -3
- package/src/Viewer/components/CameraComponent.ts +4 -4
- package/src/Viewer/components/ExtentsComponent.ts +3 -3
- package/src/Viewer/components/HighlighterComponent.ts +11 -17
- package/src/Viewer/components/SelectionComponent.ts +14 -13
- package/src/Viewer/draggers/MeasureLineDragger.ts +1 -0
- package/src/Viewer/draggers/OrbitDragger.ts +2 -0
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +287 -22
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +94 -18
- package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +1 -1
- package/src/Viewer/measurement/Snapper.ts +6 -3
- package/src/Viewer/measurement/UnitConverter.ts +19 -12
- package/src/Viewer/measurement/UnitFormatter.ts +2 -2
- package/src/Viewer/models/IModelImpl.ts +2 -10
- package/src/Viewer/models/ModelImpl.ts +111 -61
|
@@ -77,9 +77,6 @@ export class DynamicGltfLoader {
|
|
|
77
77
|
this.graphicsObjectLimit = 10000;
|
|
78
78
|
this.totalLoadedObjects = 0;
|
|
79
79
|
|
|
80
|
-
this.lastUpdateTime = 0;
|
|
81
|
-
this.updateInterval = 1000;
|
|
82
|
-
|
|
83
80
|
this.handleToObjects = new Map();
|
|
84
81
|
|
|
85
82
|
this.originalObjects = new Set();
|
|
@@ -102,6 +99,10 @@ export class DynamicGltfLoader {
|
|
|
102
99
|
this.newOptimizedObjects = new Set();
|
|
103
100
|
this.oldOptimizeObjects = new Set();
|
|
104
101
|
|
|
102
|
+
// Transform system for exploded view - works directly with original objects
|
|
103
|
+
this.objectTransforms = new Map(); // originalObject -> Matrix4
|
|
104
|
+
this.transformedGeometries = new Map(); // mergedObject.uuid -> original position data
|
|
105
|
+
|
|
105
106
|
this.activeChunkLoads = 0;
|
|
106
107
|
this.chunkQueue = [];
|
|
107
108
|
|
|
@@ -311,7 +312,6 @@ export class DynamicGltfLoader {
|
|
|
311
312
|
const uniqueTextureIds = new Set();
|
|
312
313
|
if (Array.isArray(this.structures)) {
|
|
313
314
|
for (const structure of this.structures) {
|
|
314
|
-
// console.log(structure.materialCache.values());
|
|
315
315
|
try {
|
|
316
316
|
for (const entry of structure.materialCache.values()) {
|
|
317
317
|
if (entry?.mesh?.uuid) uniqueMaterialIds.add(entry.mesh.uuid);
|
|
@@ -884,11 +884,7 @@ export class DynamicGltfLoader {
|
|
|
884
884
|
total: totalNodes,
|
|
885
885
|
});
|
|
886
886
|
|
|
887
|
-
|
|
888
|
-
if (currentTime - this.lastUpdateTime >= this.updateInterval) {
|
|
889
|
-
this.dispatchEvent("update");
|
|
890
|
-
this.lastUpdateTime = currentTime;
|
|
891
|
-
}
|
|
887
|
+
this.dispatchEvent("update");
|
|
892
888
|
|
|
893
889
|
await new Promise((resolve) => {
|
|
894
890
|
setTimeout(resolve, 0);
|
|
@@ -1006,17 +1002,40 @@ export class DynamicGltfLoader {
|
|
|
1006
1002
|
if (node.object && this.hiddenHandles.has(node.object.userData.handle)) continue;
|
|
1007
1003
|
|
|
1008
1004
|
const transformedBox = node.geometryExtents.clone();
|
|
1005
|
+
const structureRoot = node.structure ? this.structureRoots.get(node.structure.id) : null;
|
|
1009
1006
|
|
|
1010
|
-
if (node.group
|
|
1011
|
-
|
|
1007
|
+
if (node.group) {
|
|
1008
|
+
const matrices = [];
|
|
1009
|
+
let currentGroup = node.group;
|
|
1012
1010
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1011
|
+
while (currentGroup && currentGroup !== structureRoot) {
|
|
1012
|
+
if (currentGroup.matrix && currentGroup.matrixAutoUpdate === false) {
|
|
1013
|
+
matrices.unshift(currentGroup.matrix);
|
|
1014
|
+
}
|
|
1015
|
+
currentGroup = currentGroup.parent;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
for (const matrix of matrices) {
|
|
1019
|
+
transformedBox.applyMatrix4(matrix);
|
|
1015
1020
|
}
|
|
1016
1021
|
}
|
|
1022
|
+
|
|
1023
|
+
if (structureRoot && structureRoot.matrix) {
|
|
1024
|
+
transformedBox.applyMatrix4(structureRoot.matrix);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
const transform = this.objectTransforms.get(node.object);
|
|
1028
|
+
if (transform) {
|
|
1029
|
+
transformedBox.applyMatrix4(transform);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1017
1032
|
totalExtent.union(transformedBox);
|
|
1018
1033
|
}
|
|
1019
1034
|
|
|
1035
|
+
if (this.scene && this.scene.matrix && !totalExtent.isEmpty()) {
|
|
1036
|
+
totalExtent.applyMatrix4(this.scene.matrix);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1020
1039
|
return totalExtent;
|
|
1021
1040
|
}
|
|
1022
1041
|
|
|
@@ -1101,7 +1120,6 @@ export class DynamicGltfLoader {
|
|
|
1101
1120
|
for (let i = 0; i < this.maxObjectId; i++) {
|
|
1102
1121
|
this.objectVisibility[i] = 1.0;
|
|
1103
1122
|
}
|
|
1104
|
-
console.log(`Initialized object visibility array: ${this.maxObjectId} objects`);
|
|
1105
1123
|
}
|
|
1106
1124
|
}
|
|
1107
1125
|
|
|
@@ -1255,8 +1273,10 @@ export class DynamicGltfLoader {
|
|
|
1255
1273
|
this.oldOptimizeObjects.clear();
|
|
1256
1274
|
this.isolatedObjects = [];
|
|
1257
1275
|
|
|
1276
|
+
this.objectTransforms.clear();
|
|
1277
|
+
this.transformedGeometries.clear();
|
|
1278
|
+
|
|
1258
1279
|
this.totalLoadedObjects = 0;
|
|
1259
|
-
this.lastUpdateTime = 0;
|
|
1260
1280
|
this.currentMemoryUsage = 0;
|
|
1261
1281
|
this.loadedGeometrySize = 0;
|
|
1262
1282
|
|
|
@@ -1386,9 +1406,7 @@ export class DynamicGltfLoader {
|
|
|
1386
1406
|
|
|
1387
1407
|
yieldToUI() {
|
|
1388
1408
|
return new Promise((resolve) => {
|
|
1389
|
-
|
|
1390
|
-
setTimeout(resolve, 0);
|
|
1391
|
-
});
|
|
1409
|
+
setTimeout(resolve, 0);
|
|
1392
1410
|
});
|
|
1393
1411
|
}
|
|
1394
1412
|
|
|
@@ -2114,6 +2132,231 @@ export class DynamicGltfLoader {
|
|
|
2114
2132
|
}
|
|
2115
2133
|
}
|
|
2116
2134
|
|
|
2135
|
+
applyObjectTransforms(objectTransformMap) {
|
|
2136
|
+
if (this.mergedObjectMap.size === 0) {
|
|
2137
|
+
console.warn("No merged objects to transform");
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
// Store transform map directly
|
|
2142
|
+
this.objectTransforms = new Map(objectTransformMap);
|
|
2143
|
+
|
|
2144
|
+
// Apply transforms to all merged meshes
|
|
2145
|
+
for (const mesh of this.mergedMesh) {
|
|
2146
|
+
this._applyTransformToMergedObject(mesh);
|
|
2147
|
+
}
|
|
2148
|
+
for (const line of this.mergedLines) {
|
|
2149
|
+
this._applyTransformToMergedObject(line);
|
|
2150
|
+
}
|
|
2151
|
+
for (const lineSegment of this.mergedLineSegments) {
|
|
2152
|
+
this._applyTransformToMergedObject(lineSegment);
|
|
2153
|
+
}
|
|
2154
|
+
for (const point of this.mergedPoints) {
|
|
2155
|
+
this._applyTransformToMergedObject(point);
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
createExplodeTransforms(objects = null, explodeCenter = null, explodeFactor = 1.5) {
|
|
2160
|
+
const transformMap = new Map();
|
|
2161
|
+
|
|
2162
|
+
if (!explodeCenter) {
|
|
2163
|
+
explodeCenter = new Vector3();
|
|
2164
|
+
const extent = this.getTotalGeometryExtent();
|
|
2165
|
+
if (!extent.isEmpty()) {
|
|
2166
|
+
extent.getCenter(explodeCenter);
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
const objectsArray = objects
|
|
2171
|
+
? Array.isArray(objects)
|
|
2172
|
+
? objects
|
|
2173
|
+
: Array.from(objects)
|
|
2174
|
+
: Array.from(this.originalObjects);
|
|
2175
|
+
|
|
2176
|
+
for (const obj of objectsArray) {
|
|
2177
|
+
if (!obj.geometry || !obj.geometry.attributes.position) continue;
|
|
2178
|
+
|
|
2179
|
+
const boundingBox = new Box3().setFromBufferAttribute(obj.geometry.attributes.position);
|
|
2180
|
+
|
|
2181
|
+
if (obj.matrixWorld) {
|
|
2182
|
+
boundingBox.applyMatrix4(obj.matrixWorld);
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
if (boundingBox.isEmpty()) continue;
|
|
2186
|
+
|
|
2187
|
+
const objectCenter = new Vector3();
|
|
2188
|
+
boundingBox.getCenter(objectCenter);
|
|
2189
|
+
|
|
2190
|
+
const direction = objectCenter.clone().sub(explodeCenter);
|
|
2191
|
+
const distance = direction.length();
|
|
2192
|
+
|
|
2193
|
+
if (distance > 0) {
|
|
2194
|
+
direction.normalize();
|
|
2195
|
+
const offset = direction.multiplyScalar(distance * (explodeFactor - 1.0));
|
|
2196
|
+
|
|
2197
|
+
const matrix = new Matrix4().makeTranslation(offset.x, offset.y, offset.z);
|
|
2198
|
+
transformMap.set(obj, matrix);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
return transformMap;
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
clearTransforms() {
|
|
2206
|
+
this.objectTransforms.clear();
|
|
2207
|
+
|
|
2208
|
+
for (const mesh of this.mergedMesh) {
|
|
2209
|
+
this._restoreOriginalGeometry(mesh);
|
|
2210
|
+
}
|
|
2211
|
+
for (const line of this.mergedLines) {
|
|
2212
|
+
this._restoreOriginalGeometry(line);
|
|
2213
|
+
}
|
|
2214
|
+
for (const lineSegment of this.mergedLineSegments) {
|
|
2215
|
+
this._restoreOriginalGeometry(lineSegment);
|
|
2216
|
+
}
|
|
2217
|
+
for (const point of this.mergedPoints) {
|
|
2218
|
+
this._restoreOriginalGeometry(point);
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
clearHandleTransforms() {
|
|
2223
|
+
this.clearTransforms();
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
_applyTransformToMergedObject(mergedObject) {
|
|
2227
|
+
const objectData = this.mergedObjectMap.get(mergedObject.uuid);
|
|
2228
|
+
if (!objectData || !objectData.objectMapping) return;
|
|
2229
|
+
|
|
2230
|
+
const geometry = mergedObject.geometry;
|
|
2231
|
+
if (!geometry || !geometry.attributes.position) return;
|
|
2232
|
+
|
|
2233
|
+
const positionAttr = geometry.attributes.position;
|
|
2234
|
+
const positions = positionAttr.array;
|
|
2235
|
+
|
|
2236
|
+
if (!this.transformedGeometries.has(mergedObject.uuid)) {
|
|
2237
|
+
this.transformedGeometries.set(mergedObject.uuid, new Float32Array(positions));
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
|
|
2241
|
+
const tempVector = new Vector3();
|
|
2242
|
+
|
|
2243
|
+
for (const [originalMesh, mappingData] of objectData.objectMapping) {
|
|
2244
|
+
const transform = this.objectTransforms.get(originalMesh);
|
|
2245
|
+
|
|
2246
|
+
if (!transform) {
|
|
2247
|
+
const startIdx = mappingData.startVertexIndex * 3;
|
|
2248
|
+
const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
|
|
2249
|
+
for (let i = startIdx; i < endIdx; i++) {
|
|
2250
|
+
positions[i] = originalPositions[i];
|
|
2251
|
+
}
|
|
2252
|
+
continue;
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
const startVertex = mappingData.startVertexIndex;
|
|
2256
|
+
const vertexCount = mappingData.vertexCount;
|
|
2257
|
+
|
|
2258
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
2259
|
+
const idx = (startVertex + i) * 3;
|
|
2260
|
+
|
|
2261
|
+
tempVector.set(originalPositions[idx], originalPositions[idx + 1], originalPositions[idx + 2]);
|
|
2262
|
+
|
|
2263
|
+
tempVector.applyMatrix4(transform);
|
|
2264
|
+
|
|
2265
|
+
positions[idx] = tempVector.x;
|
|
2266
|
+
positions[idx + 1] = tempVector.y;
|
|
2267
|
+
positions[idx + 2] = tempVector.z;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
if (geometry.attributes.normal) {
|
|
2272
|
+
this._updateNormalsForTransform(geometry, objectData, originalPositions);
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
positionAttr.needsUpdate = true;
|
|
2276
|
+
geometry.computeBoundingSphere();
|
|
2277
|
+
geometry.computeBoundingBox();
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
_updateNormalsForTransform(geometry, objectData, originalPositions) {
|
|
2281
|
+
const normalAttr = geometry.attributes.normal;
|
|
2282
|
+
if (!normalAttr) return;
|
|
2283
|
+
|
|
2284
|
+
const normals = normalAttr.array;
|
|
2285
|
+
const tempVector = new Vector3();
|
|
2286
|
+
const normalMatrix = new Matrix4();
|
|
2287
|
+
|
|
2288
|
+
// Store original normals if not already stored
|
|
2289
|
+
const normalsKey = `${geometry.uuid}_normals`;
|
|
2290
|
+
if (!this.transformedGeometries.has(normalsKey)) {
|
|
2291
|
+
this.transformedGeometries.set(normalsKey, new Float32Array(normals));
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
const originalNormals = this.transformedGeometries.get(normalsKey);
|
|
2295
|
+
|
|
2296
|
+
for (const [originalMesh, mappingData] of objectData.objectMapping) {
|
|
2297
|
+
// Direct lookup by object reference - NO HANDLE LOOKUP!
|
|
2298
|
+
const transform = this.objectTransforms.get(originalMesh);
|
|
2299
|
+
|
|
2300
|
+
if (!transform) {
|
|
2301
|
+
// Restore original normals
|
|
2302
|
+
const startIdx = mappingData.startVertexIndex * 3;
|
|
2303
|
+
const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
|
|
2304
|
+
for (let i = startIdx; i < endIdx; i++) {
|
|
2305
|
+
normals[i] = originalNormals[i];
|
|
2306
|
+
}
|
|
2307
|
+
continue;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
// Create normal matrix (inverse transpose of transform)
|
|
2311
|
+
normalMatrix.copy(transform).invert().transpose();
|
|
2312
|
+
|
|
2313
|
+
const startVertex = mappingData.startVertexIndex;
|
|
2314
|
+
const vertexCount = mappingData.vertexCount;
|
|
2315
|
+
|
|
2316
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
2317
|
+
const idx = (startVertex + i) * 3;
|
|
2318
|
+
|
|
2319
|
+
// Get original normal
|
|
2320
|
+
tempVector.set(originalNormals[idx], originalNormals[idx + 1], originalNormals[idx + 2]);
|
|
2321
|
+
|
|
2322
|
+
// Apply normal transformation
|
|
2323
|
+
tempVector.applyMatrix4(normalMatrix).normalize();
|
|
2324
|
+
|
|
2325
|
+
// Write back transformed normal
|
|
2326
|
+
normals[idx] = tempVector.x;
|
|
2327
|
+
normals[idx + 1] = tempVector.y;
|
|
2328
|
+
normals[idx + 2] = tempVector.z;
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
normalAttr.needsUpdate = true;
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
_restoreOriginalGeometry(mergedObject) {
|
|
2336
|
+
const geometry = mergedObject.geometry;
|
|
2337
|
+
if (!geometry || !geometry.attributes.position) return;
|
|
2338
|
+
|
|
2339
|
+
// Restore original positions
|
|
2340
|
+
const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
|
|
2341
|
+
if (originalPositions) {
|
|
2342
|
+
const positions = geometry.attributes.position.array;
|
|
2343
|
+
positions.set(originalPositions);
|
|
2344
|
+
geometry.attributes.position.needsUpdate = true;
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2347
|
+
// Restore original normals
|
|
2348
|
+
const normalsKey = `${geometry.uuid}_normals`;
|
|
2349
|
+
const originalNormals = this.transformedGeometries.get(normalsKey);
|
|
2350
|
+
if (originalNormals && geometry.attributes.normal) {
|
|
2351
|
+
const normals = geometry.attributes.normal.array;
|
|
2352
|
+
normals.set(originalNormals);
|
|
2353
|
+
geometry.attributes.normal.needsUpdate = true;
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
geometry.computeBoundingSphere();
|
|
2357
|
+
geometry.computeBoundingBox();
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2117
2360
|
syncHiddenObjects() {
|
|
2118
2361
|
if (this.mergedObjectMap.size === 0) {
|
|
2119
2362
|
console.log("No merged objects to sync");
|
|
@@ -2149,19 +2392,41 @@ export class DynamicGltfLoader {
|
|
|
2149
2392
|
|
|
2150
2393
|
getStructureGeometryExtent(structureId) {
|
|
2151
2394
|
const extent = new Box3();
|
|
2395
|
+
const structureRoot = this.structureRoots.get(structureId);
|
|
2396
|
+
|
|
2152
2397
|
for (const [nodeId, node] of this.nodes.entries()) {
|
|
2153
2398
|
if (!node.geometryExtents) continue;
|
|
2154
2399
|
if (!nodeId.startsWith(structureId + "_")) continue;
|
|
2155
2400
|
if (node.object && this.hiddenHandles && this.hiddenHandles.has(node.object.userData.handle)) continue;
|
|
2156
2401
|
const transformedBox = node.geometryExtents.clone();
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2402
|
+
|
|
2403
|
+
if (node.group) {
|
|
2404
|
+
const matrices = [];
|
|
2405
|
+
let currentGroup = node.group;
|
|
2406
|
+
|
|
2407
|
+
while (currentGroup && currentGroup !== structureRoot) {
|
|
2408
|
+
if (currentGroup.matrix && currentGroup.matrixAutoUpdate === false) {
|
|
2409
|
+
matrices.unshift(currentGroup.matrix);
|
|
2410
|
+
}
|
|
2411
|
+
currentGroup = currentGroup.parent;
|
|
2161
2412
|
}
|
|
2413
|
+
|
|
2414
|
+
for (const matrix of matrices) {
|
|
2415
|
+
transformedBox.applyMatrix4(matrix);
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
if (structureRoot && structureRoot.matrix) {
|
|
2420
|
+
transformedBox.applyMatrix4(structureRoot.matrix);
|
|
2162
2421
|
}
|
|
2422
|
+
|
|
2163
2423
|
extent.union(transformedBox);
|
|
2164
2424
|
}
|
|
2425
|
+
|
|
2426
|
+
if (this.scene && this.scene.matrix && !extent.isEmpty()) {
|
|
2427
|
+
extent.applyMatrix4(this.scene.matrix);
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2165
2430
|
return extent;
|
|
2166
2431
|
}
|
|
2167
2432
|
|
|
@@ -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
|
-
|
|
81
|
-
if (ownHandles.length === 0) return [];
|
|
76
|
+
if (!Array.isArray(handles)) handles = [handles];
|
|
82
77
|
|
|
83
|
-
const handlesSet = new Set(
|
|
78
|
+
const handlesSet = new Set(handles);
|
|
84
79
|
|
|
85
80
|
const objects = [];
|
|
86
81
|
handlesSet.forEach((handle) => {
|
|
87
|
-
objects.push(
|
|
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
|
-
|
|
95
|
-
if (ownObjects.length === 0) return [];
|
|
89
|
+
if (!Array.isArray(objects)) objects = [objects];
|
|
96
90
|
|
|
97
91
|
const handleSet = new Set<string>();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
124
|
+
override highlightObjects(objects: Object3D | Object3D[]): this {
|
|
130
125
|
this.gltfLoader.showOriginalObjects(objects);
|
|
131
126
|
return this;
|
|
132
127
|
}
|
|
133
128
|
|
|
134
|
-
override
|
|
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
|
}
|
|
@@ -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:
|
|
95
|
-
Line2: { threshold:
|
|
97
|
+
Line: { threshold: this.threshold },
|
|
98
|
+
Line2: { threshold: this.threshold },
|
|
96
99
|
LOD: {},
|
|
97
|
-
Points: { threshold:
|
|
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
|
-
|
|
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).
|
|
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].
|
|
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
|
-
|
|
63
|
+
highlightObjects(objects: Object3D | Object3D[]): this;
|
|
72
64
|
|
|
73
|
-
|
|
65
|
+
unhighlightObjects(objects: Object3D | Object3D[]): this;
|
|
74
66
|
|
|
75
67
|
explode(scale: number, coeff?: number): this;
|
|
76
68
|
}
|