@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
|
@@ -805,6 +805,7 @@ class OrbitDragger {
|
|
|
805
805
|
this.changed = false;
|
|
806
806
|
this.viewer = viewer;
|
|
807
807
|
this.viewer.addEventListener("databasechunk", this.updateControls);
|
|
808
|
+
this.viewer.addEventListener("clear", this.updateControls);
|
|
808
809
|
this.viewer.on("viewposition", this.updateControls);
|
|
809
810
|
this.viewer.addEventListener("zoom", this.updateControls);
|
|
810
811
|
this.viewer.addEventListener("drawviewpoint", this.updateControls);
|
|
@@ -816,6 +817,7 @@ class OrbitDragger {
|
|
|
816
817
|
initialize() { }
|
|
817
818
|
dispose() {
|
|
818
819
|
this.viewer.removeEventListener("databasechunk", this.updateControls);
|
|
820
|
+
this.viewer.removeEventListener("clear", this.updateControls);
|
|
819
821
|
this.viewer.off("viewposition", this.updateControls);
|
|
820
822
|
this.viewer.removeEventListener("zoom", this.updateControls);
|
|
821
823
|
this.viewer.removeEventListener("drawviewpoint", this.updateControls);
|
|
@@ -913,20 +915,25 @@ class CuttingPlaneZAxisDragger extends CuttingPlaneDragger {
|
|
|
913
915
|
}
|
|
914
916
|
}
|
|
915
917
|
|
|
918
|
+
const DisplayUnits = {
|
|
919
|
+
Meters: { name: "Meters", symbol: "m", scale: 1.0 },
|
|
920
|
+
Centimeters: { name: "Centimeters", symbol: "cm", scale: 0.01 },
|
|
921
|
+
Millimeters: { name: "Millimeters", symbol: "mm", scale: 0.001 },
|
|
922
|
+
Feet: { name: "Feet", symbol: "ft", scale: 0.3048 },
|
|
923
|
+
Inches: { name: "Inches", symbol: "in", scale: 0.0254 },
|
|
924
|
+
Yards: { name: "Yards", symbol: "yd", scale: 0.9144 },
|
|
925
|
+
Kilometers: { name: "Kilometers", symbol: "km", scale: 1000.0 },
|
|
926
|
+
Miles: { name: "Miles", symbol: "mi", scale: 1609.344 },
|
|
927
|
+
Micrometers: { name: "Micrometers", symbol: "µm", scale: 0.000001 },
|
|
928
|
+
Mils: { name: "Mils", symbol: "mil", scale: 0.0000254 },
|
|
929
|
+
MicroInches: { name: "Micro-inches", symbol: "µin", scale: 0.0000000254 },
|
|
930
|
+
Default: { name: "File units", symbol: "", scale: 1.0 },
|
|
931
|
+
};
|
|
916
932
|
const ModelUnits = {
|
|
917
|
-
|
|
918
|
-
Centimeters: { name: "Centimeters", type: "cm", scale: 0.01 },
|
|
919
|
-
Millimeters: { name: "Millimeters", type: "mm", scale: 0.001 },
|
|
920
|
-
Feet: { name: "Feet", type: "ft", scale: 0.3048 },
|
|
921
|
-
Inches: { name: "Inches", type: "in", scale: 0.0254 },
|
|
922
|
-
Yards: { name: "Yards", type: "yd", scale: 0.9144 },
|
|
923
|
-
Kilometers: { name: "Kilometers", type: "km", scale: 1000.0 },
|
|
924
|
-
Miles: { name: "Miles", type: "mi", scale: 1609.344 },
|
|
925
|
-
Micrometers: { name: "Micrometers", type: "µm", scale: 0.000001 },
|
|
926
|
-
Mils: { name: "Mils", type: "mil", scale: 0.0000254 },
|
|
927
|
-
MicroInches: { name: "Micro-inches", type: "µin", scale: 0.0000000254 },
|
|
928
|
-
Default: { name: "File units", type: "unit", scale: 1.0 },
|
|
933
|
+
Default: { name: "", symbol: "", scale: 1.0 },
|
|
929
934
|
};
|
|
935
|
+
Object.keys(DisplayUnits).forEach((key) => (ModelUnits[key] = DisplayUnits[key]));
|
|
936
|
+
Object.keys(DisplayUnits).forEach((key) => (ModelUnits[DisplayUnits[key].symbol] = DisplayUnits[key]));
|
|
930
937
|
function convertUnits(fromUnits, toUnits, distance) {
|
|
931
938
|
const fromFactor = 1 / (ModelUnits[fromUnits] || ModelUnits.Default).scale;
|
|
932
939
|
const toFactor = (ModelUnits[toUnits] || ModelUnits.Default).scale || 1;
|
|
@@ -934,7 +941,7 @@ function convertUnits(fromUnits, toUnits, distance) {
|
|
|
934
941
|
}
|
|
935
942
|
|
|
936
943
|
function getDisplayUnit(units) {
|
|
937
|
-
return (ModelUnits[units] || ModelUnits.Default).
|
|
944
|
+
return (ModelUnits[units] || ModelUnits.Default).symbol;
|
|
938
945
|
}
|
|
939
946
|
function calculatePrecision(value) {
|
|
940
947
|
const distance = Math.abs(value);
|
|
@@ -971,7 +978,7 @@ function formatDistance(distance, units, precision = 2) {
|
|
|
971
978
|
else if (digits > 10)
|
|
972
979
|
digits = 10;
|
|
973
980
|
if (ModelUnits[units]) {
|
|
974
|
-
return formatNumber(distance, digits, precision) + " " + ModelUnits[units].
|
|
981
|
+
return formatNumber(distance, digits, precision) + " " + ModelUnits[units].symbol;
|
|
975
982
|
}
|
|
976
983
|
else if (units) {
|
|
977
984
|
return formatNumber(distance, digits, precision) + " " + units;
|
|
@@ -994,6 +1001,7 @@ class Snapper {
|
|
|
994
1001
|
this.camera = camera;
|
|
995
1002
|
this.renderer = renderer;
|
|
996
1003
|
this.canvas = canvas;
|
|
1004
|
+
this.threshold = 0.0001;
|
|
997
1005
|
this.raycaster = new Raycaster();
|
|
998
1006
|
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
999
1007
|
this.edgesCache = new WeakMap();
|
|
@@ -1014,10 +1022,10 @@ class Snapper {
|
|
|
1014
1022
|
this.raycaster.setFromCamera(coords, this.camera);
|
|
1015
1023
|
this.raycaster.params = {
|
|
1016
1024
|
Mesh: {},
|
|
1017
|
-
Line: { threshold:
|
|
1018
|
-
Line2: { threshold:
|
|
1025
|
+
Line: { threshold: this.threshold },
|
|
1026
|
+
Line2: { threshold: this.threshold },
|
|
1019
1027
|
LOD: {},
|
|
1020
|
-
Points: { threshold:
|
|
1028
|
+
Points: { threshold: this.threshold },
|
|
1021
1029
|
Sprite: {},
|
|
1022
1030
|
};
|
|
1023
1031
|
let intersects = this.raycaster.intersectObjects(objects, false);
|
|
@@ -1186,6 +1194,7 @@ class MeasureLineDragger extends OrbitDragger {
|
|
|
1186
1194
|
this.line = new MeasureLine(this.overlay, this.scale, this.units, this.precision);
|
|
1187
1195
|
this.overlay.addLine(this.line);
|
|
1188
1196
|
this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
|
|
1197
|
+
this.snapper.threshold = viewer.extents.getSize(new Vector3()).length() / 10000;
|
|
1189
1198
|
this.objects = [];
|
|
1190
1199
|
this.updateObjects();
|
|
1191
1200
|
this.updateUnits();
|
|
@@ -2189,7 +2198,7 @@ function zoomTo(viewer, box) {
|
|
|
2189
2198
|
const boxCenter = box.getCenter(new Vector3());
|
|
2190
2199
|
const boxSize = box.getBoundingSphere(new Sphere()).radius;
|
|
2191
2200
|
const rendererSize = viewer.renderer.getSize(new Vector2());
|
|
2192
|
-
const
|
|
2201
|
+
const aspectRatio = rendererSize.x / rendererSize.y;
|
|
2193
2202
|
const camera = viewer.camera;
|
|
2194
2203
|
if (camera.isPerspectiveCamera) {
|
|
2195
2204
|
const offset = new Vector3(0, 0, 1)
|
|
@@ -2201,8 +2210,8 @@ function zoomTo(viewer, box) {
|
|
|
2201
2210
|
if (camera.isOrthographicCamera) {
|
|
2202
2211
|
camera.top = boxSize;
|
|
2203
2212
|
camera.bottom = -boxSize;
|
|
2204
|
-
camera.left = camera.bottom *
|
|
2205
|
-
camera.right = camera.top *
|
|
2213
|
+
camera.left = camera.bottom * aspectRatio;
|
|
2214
|
+
camera.right = camera.top * aspectRatio;
|
|
2206
2215
|
camera.zoom = 1;
|
|
2207
2216
|
camera.updateProjectionMatrix();
|
|
2208
2217
|
const offset = new Vector3(0, 0, 1)
|
|
@@ -2263,9 +2272,9 @@ function getSelected(viewer) {
|
|
|
2263
2272
|
function getSelected2(viewer) {
|
|
2264
2273
|
const handles2 = [];
|
|
2265
2274
|
viewer.models.forEach((model) => {
|
|
2266
|
-
handles2.push(
|
|
2275
|
+
handles2.push(model.getHandlesByObjects(viewer.selected));
|
|
2267
2276
|
});
|
|
2268
|
-
return handles2;
|
|
2277
|
+
return handles2.flat();
|
|
2269
2278
|
}
|
|
2270
2279
|
|
|
2271
2280
|
function hideSelected(viewer) {
|
|
@@ -2489,15 +2498,15 @@ class CameraComponent {
|
|
|
2489
2498
|
switchCamera(camera) {
|
|
2490
2499
|
const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius * 2 || 1;
|
|
2491
2500
|
const rendererSize = this.viewer.renderer.getSize(new Vector2());
|
|
2492
|
-
const
|
|
2501
|
+
const aspectRatio = rendererSize.x / rendererSize.y;
|
|
2493
2502
|
if (camera.isPerspectiveCamera) {
|
|
2494
|
-
camera.aspect =
|
|
2503
|
+
camera.aspect = aspectRatio;
|
|
2495
2504
|
camera.near = extentsSize / 1000;
|
|
2496
2505
|
camera.far = extentsSize * 1000;
|
|
2497
2506
|
}
|
|
2498
2507
|
if (camera.isOrthographicCamera) {
|
|
2499
|
-
camera.left = camera.bottom *
|
|
2500
|
-
camera.right = camera.top *
|
|
2508
|
+
camera.left = camera.bottom * aspectRatio;
|
|
2509
|
+
camera.right = camera.top * aspectRatio;
|
|
2501
2510
|
camera.near = 0;
|
|
2502
2511
|
camera.far = extentsSize * 1000;
|
|
2503
2512
|
}
|
|
@@ -2545,10 +2554,12 @@ class CameraComponent {
|
|
|
2545
2554
|
|
|
2546
2555
|
class ExtentsComponent {
|
|
2547
2556
|
constructor(viewer) {
|
|
2548
|
-
this.syncExtents = () => {
|
|
2557
|
+
this.syncExtents = (event) => {
|
|
2549
2558
|
const extents = new Box3();
|
|
2550
2559
|
this.viewer.models.forEach((model) => model.getExtents(extents));
|
|
2551
2560
|
this.viewer.extents.copy(extents);
|
|
2561
|
+
if (event.type !== "databasechunk" && event.target !== "clear")
|
|
2562
|
+
return;
|
|
2552
2563
|
if (this.viewer.models.length > 1)
|
|
2553
2564
|
return;
|
|
2554
2565
|
this.viewer.extents.getCenter(this.viewer.target);
|
|
@@ -2915,12 +2926,12 @@ class HighlighterComponent {
|
|
|
2915
2926
|
const { edgesVisibility } = this.viewer.options;
|
|
2916
2927
|
if (!Array.isArray(objects))
|
|
2917
2928
|
objects = [objects];
|
|
2918
|
-
if (
|
|
2929
|
+
if (objects.length === 0)
|
|
2919
2930
|
return;
|
|
2920
2931
|
objects
|
|
2921
2932
|
.filter((object) => !object.userData.isEdge)
|
|
2922
2933
|
.forEach((object) => {
|
|
2923
|
-
if (object.isHighlighted)
|
|
2934
|
+
if (object.userData.isHighlighted)
|
|
2924
2935
|
return;
|
|
2925
2936
|
if (object.isLine || object.isLineSegments) {
|
|
2926
2937
|
const positions = object.geometry.attributes.position.array;
|
|
@@ -2929,43 +2940,39 @@ class HighlighterComponent {
|
|
|
2929
2940
|
? HighlighterUtils.fromIndexedLine(positions, indices)
|
|
2930
2941
|
: HighlighterUtils.fromNonIndexedLine(positions, object.isLineSegments);
|
|
2931
2942
|
const wireframe = new Wireframe(lineGeometry, this.lineGlowMaterial);
|
|
2932
|
-
wireframe.position.copy(object.position);
|
|
2933
|
-
wireframe.rotation.copy(object.rotation);
|
|
2934
|
-
wireframe.scale.copy(object.scale);
|
|
2935
2943
|
wireframe.visible = edgesVisibility;
|
|
2936
|
-
|
|
2944
|
+
wireframe.userData.isHighlightWireframe = true;
|
|
2945
|
+
object.add(wireframe);
|
|
2937
2946
|
object.userData.highlightWireframe = wireframe;
|
|
2938
2947
|
object.userData.originalMaterial = object.material;
|
|
2939
2948
|
object.material = this.lineMaterial;
|
|
2940
|
-
object.isHighlighted = true;
|
|
2949
|
+
object.userData.isHighlighted = true;
|
|
2941
2950
|
}
|
|
2942
2951
|
else if (object.isMesh) {
|
|
2943
2952
|
const edgesGeometry = new EdgesGeometry(object.geometry, 89);
|
|
2944
2953
|
const lineGeometry = new LineSegmentsGeometry().fromEdgesGeometry(edgesGeometry);
|
|
2945
2954
|
const wireframe = new Wireframe(lineGeometry, this.edgesMaterial);
|
|
2946
|
-
wireframe.position.copy(object.position);
|
|
2947
|
-
wireframe.rotation.copy(object.rotation);
|
|
2948
|
-
wireframe.scale.copy(object.scale);
|
|
2949
2955
|
wireframe.visible = edgesVisibility;
|
|
2950
|
-
|
|
2956
|
+
wireframe.userData.isHighlightWireframe = true;
|
|
2957
|
+
object.add(wireframe);
|
|
2951
2958
|
object.userData.highlightWireframe = wireframe;
|
|
2952
2959
|
object.userData.originalMaterial = object.material;
|
|
2953
2960
|
object.material = this.facesMaterial;
|
|
2954
|
-
object.isHighlighted = true;
|
|
2961
|
+
object.userData.isHighlighted = true;
|
|
2955
2962
|
}
|
|
2956
2963
|
});
|
|
2957
2964
|
}
|
|
2958
2965
|
unhighlight(objects) {
|
|
2959
2966
|
if (!Array.isArray(objects))
|
|
2960
2967
|
objects = [objects];
|
|
2961
|
-
if (
|
|
2968
|
+
if (objects.length === 0)
|
|
2962
2969
|
return;
|
|
2963
2970
|
objects.forEach((object) => {
|
|
2964
|
-
if (!object.isHighlighted)
|
|
2971
|
+
if (!object.userData.isHighlighted)
|
|
2965
2972
|
return;
|
|
2966
|
-
object.isHighlighted = false;
|
|
2967
2973
|
object.material = object.userData.originalMaterial;
|
|
2968
2974
|
object.userData.highlightWireframe.removeFromParent();
|
|
2975
|
+
delete object.userData.isHighlighted;
|
|
2969
2976
|
delete object.userData.originalMaterial;
|
|
2970
2977
|
delete object.userData.highlightWireframe;
|
|
2971
2978
|
});
|
|
@@ -3013,6 +3020,7 @@ class SelectionComponent {
|
|
|
3013
3020
|
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
3014
3021
|
return;
|
|
3015
3022
|
const snapper = new Snapper(this.viewer.camera, this.viewer.renderer, this.viewer.canvas);
|
|
3023
|
+
snapper.threshold = this.viewer.extents.getSize(new Vector3()).length() / 10000;
|
|
3016
3024
|
let intersections = [];
|
|
3017
3025
|
this.viewer.models.forEach((model) => {
|
|
3018
3026
|
const objects = model.getVisibleObjects();
|
|
@@ -3067,12 +3075,12 @@ class SelectionComponent {
|
|
|
3067
3075
|
}
|
|
3068
3076
|
if (!Array.isArray(objects))
|
|
3069
3077
|
objects = [objects];
|
|
3070
|
-
if (
|
|
3078
|
+
if (objects.length === 0)
|
|
3071
3079
|
return;
|
|
3072
|
-
model.
|
|
3080
|
+
model.highlightObjects(objects);
|
|
3073
3081
|
this.highlighter.highlight(objects);
|
|
3074
3082
|
objects.forEach((object) => this.viewer.selected.push(object));
|
|
3075
|
-
objects.forEach((object) => (object.isSelected = true));
|
|
3083
|
+
objects.forEach((object) => (object.userData.isSelected = true));
|
|
3076
3084
|
}
|
|
3077
3085
|
deselect(objects, model) {
|
|
3078
3086
|
if (!model) {
|
|
@@ -3081,29 +3089,29 @@ class SelectionComponent {
|
|
|
3081
3089
|
}
|
|
3082
3090
|
if (!Array.isArray(objects))
|
|
3083
3091
|
objects = [objects];
|
|
3084
|
-
if (
|
|
3092
|
+
if (objects.length === 0)
|
|
3085
3093
|
return;
|
|
3094
|
+
model.unhighlightObjects(objects);
|
|
3086
3095
|
this.highlighter.unhighlight(objects);
|
|
3087
|
-
model.hideOriginalObjects(objects);
|
|
3088
3096
|
this.viewer.selected = this.viewer.selected.filter((x) => !objects.includes(x));
|
|
3089
|
-
objects.forEach((object) => (object.isSelected = false));
|
|
3097
|
+
objects.forEach((object) => (object.userData.isSelected = false));
|
|
3090
3098
|
}
|
|
3091
3099
|
toggleSelection(objects, model) {
|
|
3092
3100
|
if (!Array.isArray(objects))
|
|
3093
3101
|
objects = [objects];
|
|
3094
|
-
if (
|
|
3102
|
+
if (objects.length === 0)
|
|
3095
3103
|
return;
|
|
3096
|
-
if (objects[0].isSelected)
|
|
3104
|
+
if (objects[0].userData.isSelected)
|
|
3097
3105
|
this.deselect(objects, model);
|
|
3098
3106
|
else
|
|
3099
3107
|
this.select(objects, model);
|
|
3100
3108
|
}
|
|
3101
3109
|
clearSelection() {
|
|
3102
|
-
if (
|
|
3110
|
+
if (this.viewer.selected.length === 0)
|
|
3103
3111
|
return;
|
|
3112
|
+
this.viewer.models.forEach((model) => model.unhighlightObjects(this.viewer.selected));
|
|
3104
3113
|
this.highlighter.unhighlight(this.viewer.selected);
|
|
3105
|
-
this.viewer.
|
|
3106
|
-
this.viewer.selected.forEach((object) => (object.isSelected = false));
|
|
3114
|
+
this.viewer.selected.forEach((object) => (object.userData.isSelected = false));
|
|
3107
3115
|
this.viewer.selected.length = 0;
|
|
3108
3116
|
}
|
|
3109
3117
|
}
|
|
@@ -3265,6 +3273,20 @@ components.registerComponent("ResetComponent", (viewer) => new ResetComponent(vi
|
|
|
3265
3273
|
class ModelImpl {
|
|
3266
3274
|
constructor(scene) {
|
|
3267
3275
|
this.scene = scene;
|
|
3276
|
+
this.handleToObjects = new Map();
|
|
3277
|
+
this.originalObjects = new Set();
|
|
3278
|
+
this.scene.traverse((object) => {
|
|
3279
|
+
this.originalObjects.add(object);
|
|
3280
|
+
const handle = object.userData.handle;
|
|
3281
|
+
if (!handle)
|
|
3282
|
+
return;
|
|
3283
|
+
let objects = this.handleToObjects.get(handle);
|
|
3284
|
+
if (!objects) {
|
|
3285
|
+
objects = new Set();
|
|
3286
|
+
this.handleToObjects.set(handle, objects);
|
|
3287
|
+
}
|
|
3288
|
+
objects.add(object);
|
|
3289
|
+
});
|
|
3268
3290
|
}
|
|
3269
3291
|
dispose() {
|
|
3270
3292
|
function disposeMaterial(material) {
|
|
@@ -3280,6 +3302,8 @@ class ModelImpl {
|
|
|
3280
3302
|
if (object.material)
|
|
3281
3303
|
disposeMaterials(object.material);
|
|
3282
3304
|
}
|
|
3305
|
+
this.handleToObjects = undefined;
|
|
3306
|
+
this.originalObjects = undefined;
|
|
3283
3307
|
this.scene.traverse(disposeObject);
|
|
3284
3308
|
this.scene.clear();
|
|
3285
3309
|
}
|
|
@@ -3422,67 +3446,56 @@ class ModelImpl {
|
|
|
3422
3446
|
return info;
|
|
3423
3447
|
}
|
|
3424
3448
|
getExtents(target) {
|
|
3425
|
-
this.scene.traverseVisible((object) =>
|
|
3449
|
+
this.scene.traverseVisible((object) => target.expandByObject(object));
|
|
3426
3450
|
return target;
|
|
3427
3451
|
}
|
|
3428
3452
|
getObjects() {
|
|
3429
|
-
|
|
3430
|
-
this.scene.traverse((object) => objects.push(object));
|
|
3431
|
-
return objects;
|
|
3453
|
+
return Array.from(this.originalObjects);
|
|
3432
3454
|
}
|
|
3433
3455
|
getVisibleObjects() {
|
|
3434
3456
|
const objects = [];
|
|
3435
3457
|
this.scene.traverseVisible((object) => objects.push(object));
|
|
3436
|
-
return objects;
|
|
3437
|
-
}
|
|
3438
|
-
hasObject(object) {
|
|
3439
|
-
while (object) {
|
|
3440
|
-
if (object === this.scene)
|
|
3441
|
-
return true;
|
|
3442
|
-
object = object.parent;
|
|
3443
|
-
}
|
|
3444
|
-
return false;
|
|
3445
|
-
}
|
|
3446
|
-
hasHandle(handle) {
|
|
3447
|
-
return !handle.includes(":") || handle.split(":", 1)[0] === this.id + "";
|
|
3458
|
+
return objects.filter((object) => object.userData.handle);
|
|
3448
3459
|
}
|
|
3449
|
-
|
|
3450
|
-
if (!Array.isArray(objects))
|
|
3451
|
-
objects = [objects];
|
|
3452
|
-
return objects.filter((object) => this.hasObject(object));
|
|
3453
|
-
}
|
|
3454
|
-
getOwnHandles(handles) {
|
|
3460
|
+
getObjectsByHandles(handles) {
|
|
3455
3461
|
if (!Array.isArray(handles))
|
|
3456
3462
|
handles = [handles];
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3463
|
+
const ownHandles = [];
|
|
3464
|
+
handles.forEach((handle) => {
|
|
3465
|
+
const index = handle.indexOf(":");
|
|
3466
|
+
if (index !== -1) {
|
|
3467
|
+
if (handle.slice(0, index) !== this.id)
|
|
3468
|
+
return;
|
|
3469
|
+
handle = handle.slice(index + 1);
|
|
3470
|
+
}
|
|
3471
|
+
ownHandles.push(handle);
|
|
3472
|
+
});
|
|
3473
|
+
const handlesSet = new Set(ownHandles);
|
|
3464
3474
|
const objects = [];
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
if (handle && handleSet.has(handle))
|
|
3468
|
-
objects.push(object);
|
|
3475
|
+
handlesSet.forEach((handle) => {
|
|
3476
|
+
objects.push(Array.from(this.handleToObjects.get(handle) || []));
|
|
3469
3477
|
});
|
|
3470
|
-
return objects;
|
|
3478
|
+
return objects.flat();
|
|
3471
3479
|
}
|
|
3472
3480
|
getHandlesByObjects(objects) {
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
return [];
|
|
3481
|
+
if (!Array.isArray(objects))
|
|
3482
|
+
objects = [objects];
|
|
3476
3483
|
const handleSet = new Set();
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3484
|
+
objects
|
|
3485
|
+
.filter((object) => this.originalObjects.has(object))
|
|
3486
|
+
.forEach((object) => {
|
|
3487
|
+
handleSet.add(`${this.id}:${object.userData.handle}`);
|
|
3481
3488
|
});
|
|
3482
3489
|
return Array.from(handleSet);
|
|
3483
3490
|
}
|
|
3484
3491
|
hideObjects(objects) {
|
|
3485
|
-
|
|
3492
|
+
if (!Array.isArray(objects))
|
|
3493
|
+
objects = [objects];
|
|
3494
|
+
objects
|
|
3495
|
+
.filter((object) => this.originalObjects.has(object))
|
|
3496
|
+
.forEach((object) => {
|
|
3497
|
+
object.visible = false;
|
|
3498
|
+
});
|
|
3486
3499
|
return this;
|
|
3487
3500
|
}
|
|
3488
3501
|
hideAllObjects() {
|
|
@@ -3492,12 +3505,20 @@ class ModelImpl {
|
|
|
3492
3505
|
if (!Array.isArray(objects))
|
|
3493
3506
|
objects = [objects];
|
|
3494
3507
|
const visibleSet = new Set(objects);
|
|
3495
|
-
|
|
3508
|
+
objects
|
|
3509
|
+
.filter((object) => this.originalObjects.has(object))
|
|
3510
|
+
.forEach((object) => {
|
|
3511
|
+
object.traverseAncestors((parent) => visibleSet.add(parent));
|
|
3512
|
+
});
|
|
3496
3513
|
this.scene.traverse((object) => (object.visible = visibleSet.has(object)));
|
|
3497
3514
|
return this;
|
|
3498
3515
|
}
|
|
3499
3516
|
showObjects(objects) {
|
|
3500
|
-
|
|
3517
|
+
if (!Array.isArray(objects))
|
|
3518
|
+
objects = [objects];
|
|
3519
|
+
objects
|
|
3520
|
+
.filter((object) => this.originalObjects.has(object))
|
|
3521
|
+
.forEach((object) => {
|
|
3501
3522
|
object.visible = true;
|
|
3502
3523
|
object.traverseAncestors((parent) => (parent.visible = true));
|
|
3503
3524
|
});
|
|
@@ -3507,36 +3528,55 @@ class ModelImpl {
|
|
|
3507
3528
|
this.scene.traverse((object) => (object.visible = true));
|
|
3508
3529
|
return this;
|
|
3509
3530
|
}
|
|
3510
|
-
|
|
3531
|
+
highlightObjects(objects) {
|
|
3511
3532
|
return this;
|
|
3512
3533
|
}
|
|
3513
|
-
|
|
3534
|
+
unhighlightObjects(objects) {
|
|
3514
3535
|
return this;
|
|
3515
3536
|
}
|
|
3516
3537
|
explode(scale = 0, coeff = 4) {
|
|
3538
|
+
const centers = new Map();
|
|
3539
|
+
const getObjectCenter = (object, target) => {
|
|
3540
|
+
const extents = new Box3().setFromObject(object);
|
|
3541
|
+
const handle = object.userData.handle;
|
|
3542
|
+
if (!handle)
|
|
3543
|
+
return extents.getCenter(target);
|
|
3544
|
+
const center = centers.get(handle);
|
|
3545
|
+
if (center)
|
|
3546
|
+
return target.copy(center);
|
|
3547
|
+
const objects = this.getObjectsByHandles(handle);
|
|
3548
|
+
objects.forEach((x) => extents.expandByObject(x));
|
|
3549
|
+
extents.getCenter(target);
|
|
3550
|
+
centers.set(handle, target.clone());
|
|
3551
|
+
return target;
|
|
3552
|
+
};
|
|
3517
3553
|
function calcExplodeDepth(object, depth) {
|
|
3518
|
-
let
|
|
3554
|
+
let result = depth;
|
|
3519
3555
|
object.children.forEach((x) => {
|
|
3520
3556
|
const objectDepth = calcExplodeDepth(x, depth + 1);
|
|
3521
|
-
if (
|
|
3522
|
-
|
|
3557
|
+
if (result < objectDepth)
|
|
3558
|
+
result = objectDepth;
|
|
3523
3559
|
});
|
|
3524
3560
|
object.userData.originalPosition = object.position.clone();
|
|
3525
|
-
object.userData.originalCenter =
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
if (!
|
|
3531
|
-
|
|
3532
|
-
const maxDepth =
|
|
3533
|
-
const scaledExplodeDepth =
|
|
3561
|
+
object.userData.originalCenter = getObjectCenter(object, new Vector3());
|
|
3562
|
+
return result;
|
|
3563
|
+
}
|
|
3564
|
+
const explodeScale = scale / 100;
|
|
3565
|
+
const explodeRoot = this.scene;
|
|
3566
|
+
if (!explodeRoot.userData.explodeDepth)
|
|
3567
|
+
explodeRoot.userData.explodeDepth = calcExplodeDepth(explodeRoot, 1);
|
|
3568
|
+
const maxDepth = explodeRoot.userData.explodeDepth;
|
|
3569
|
+
const scaledExplodeDepth = explodeScale * maxDepth + 1;
|
|
3534
3570
|
const explodeDepth = 0 | scaledExplodeDepth;
|
|
3535
3571
|
const currentSegmentFraction = scaledExplodeDepth - explodeDepth;
|
|
3536
3572
|
function explodeObject(object, depth) {
|
|
3573
|
+
if (object.isCamera)
|
|
3574
|
+
return;
|
|
3575
|
+
if (object.userData.isHighlightWireframe)
|
|
3576
|
+
return;
|
|
3537
3577
|
object.position.copy(object.userData.originalPosition);
|
|
3538
|
-
if (depth > 0 && depth <= explodeDepth
|
|
3539
|
-
let objectScale =
|
|
3578
|
+
if (depth > 0 && depth <= explodeDepth) {
|
|
3579
|
+
let objectScale = explodeScale * coeff;
|
|
3540
3580
|
if (depth === explodeDepth)
|
|
3541
3581
|
objectScale *= currentSegmentFraction;
|
|
3542
3582
|
const parentCenter = object.parent.userData.originalCenter;
|
|
@@ -3546,7 +3586,7 @@ class ModelImpl {
|
|
|
3546
3586
|
}
|
|
3547
3587
|
object.children.forEach((x) => explodeObject(x, depth + 1));
|
|
3548
3588
|
}
|
|
3549
|
-
explodeObject(
|
|
3589
|
+
explodeObject(explodeRoot, 0);
|
|
3550
3590
|
this.scene.updateMatrixWorld();
|
|
3551
3591
|
return this;
|
|
3552
3592
|
}
|
|
@@ -3584,29 +3624,24 @@ class DynamicModelImpl extends ModelImpl {
|
|
|
3584
3624
|
getVisibleObjects() {
|
|
3585
3625
|
return this.gltfLoader.getOriginalObjectForSelect();
|
|
3586
3626
|
}
|
|
3587
|
-
hasObject(object) {
|
|
3588
|
-
return this.gltfLoader.originalObjects.has(object);
|
|
3589
|
-
}
|
|
3590
3627
|
getObjectsByHandles(handles) {
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
const handlesSet = new Set(ownHandles);
|
|
3628
|
+
if (!Array.isArray(handles))
|
|
3629
|
+
handles = [handles];
|
|
3630
|
+
const handlesSet = new Set(handles);
|
|
3595
3631
|
const objects = [];
|
|
3596
3632
|
handlesSet.forEach((handle) => {
|
|
3597
|
-
objects.push(
|
|
3633
|
+
objects.push(this.gltfLoader.getObjectsByHandle(handle));
|
|
3598
3634
|
});
|
|
3599
|
-
return objects;
|
|
3635
|
+
return objects.flat();
|
|
3600
3636
|
}
|
|
3601
3637
|
getHandlesByObjects(objects) {
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
return [];
|
|
3638
|
+
if (!Array.isArray(objects))
|
|
3639
|
+
objects = [objects];
|
|
3605
3640
|
const handleSet = new Set();
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3641
|
+
objects
|
|
3642
|
+
.filter((object) => this.gltfLoader.originalObjects.has(object))
|
|
3643
|
+
.forEach((object) => {
|
|
3644
|
+
handleSet.add(object.userData.handle);
|
|
3610
3645
|
});
|
|
3611
3646
|
return Array.from(handleSet);
|
|
3612
3647
|
}
|
|
@@ -3629,14 +3664,78 @@ class DynamicModelImpl extends ModelImpl {
|
|
|
3629
3664
|
this.gltfLoader.showAllHiddenObjects();
|
|
3630
3665
|
return this;
|
|
3631
3666
|
}
|
|
3632
|
-
|
|
3667
|
+
highlightObjects(objects) {
|
|
3633
3668
|
this.gltfLoader.showOriginalObjects(objects);
|
|
3634
3669
|
return this;
|
|
3635
3670
|
}
|
|
3636
|
-
|
|
3671
|
+
unhighlightObjects(objects) {
|
|
3637
3672
|
this.gltfLoader.hideOriginalObjects(objects);
|
|
3638
3673
|
return this;
|
|
3639
3674
|
}
|
|
3675
|
+
explode(scale = 0, coeff = 4) {
|
|
3676
|
+
const centers = new Map();
|
|
3677
|
+
const calcObjectCenter = (object, target) => {
|
|
3678
|
+
const extents = new Box3().setFromObject(object);
|
|
3679
|
+
const handle = object.userData.handle;
|
|
3680
|
+
if (!handle)
|
|
3681
|
+
return extents.getCenter(target);
|
|
3682
|
+
const center = centers.get(handle);
|
|
3683
|
+
if (center)
|
|
3684
|
+
return target.copy(center);
|
|
3685
|
+
const objects = this.getObjectsByHandles(handle);
|
|
3686
|
+
objects.forEach((x) => extents.expandByObject(x));
|
|
3687
|
+
extents.getCenter(target);
|
|
3688
|
+
centers.set(handle, target.clone());
|
|
3689
|
+
return target;
|
|
3690
|
+
};
|
|
3691
|
+
function calcExplodeDepth(object, depth) {
|
|
3692
|
+
let result = depth;
|
|
3693
|
+
object.children
|
|
3694
|
+
.filter((x) => !x.userData.isOptimized)
|
|
3695
|
+
.forEach((x) => {
|
|
3696
|
+
const objectDepth = calcExplodeDepth(x, depth + 1);
|
|
3697
|
+
if (result < objectDepth)
|
|
3698
|
+
result = objectDepth;
|
|
3699
|
+
});
|
|
3700
|
+
object.userData.originalPosition = object.position.clone();
|
|
3701
|
+
object.userData.originalCenter = calcObjectCenter(object, new Vector3());
|
|
3702
|
+
return result;
|
|
3703
|
+
}
|
|
3704
|
+
const explodeScale = scale / 100;
|
|
3705
|
+
const explodeRoot = this.scene.children[0];
|
|
3706
|
+
if (!explodeRoot.userData.explodeDepth)
|
|
3707
|
+
explodeRoot.userData.explodeDepth = calcExplodeDepth(explodeRoot, 1);
|
|
3708
|
+
const maxDepth = explodeRoot.userData.explodeDepth;
|
|
3709
|
+
const scaledExplodeDepth = explodeScale * maxDepth + 1;
|
|
3710
|
+
const explodeDepth = 0 | scaledExplodeDepth;
|
|
3711
|
+
const currentSegmentFraction = scaledExplodeDepth - explodeDepth;
|
|
3712
|
+
const transformMap = new Map();
|
|
3713
|
+
function explodeObject(object, depth) {
|
|
3714
|
+
if (object.isCamera)
|
|
3715
|
+
return;
|
|
3716
|
+
if (object.userData.isHighlightWireframe)
|
|
3717
|
+
return;
|
|
3718
|
+
object.position.copy(object.userData.originalPosition);
|
|
3719
|
+
if (depth > 0 && depth <= explodeDepth && !object.userData.isExplodeLocked) {
|
|
3720
|
+
let objectScale = explodeScale * coeff;
|
|
3721
|
+
if (depth === explodeDepth)
|
|
3722
|
+
objectScale *= currentSegmentFraction;
|
|
3723
|
+
const parentCenter = object.parent.userData.originalCenter;
|
|
3724
|
+
const objectCenter = object.userData.originalCenter;
|
|
3725
|
+
const objectOffset = objectCenter.clone().sub(parentCenter).multiplyScalar(objectScale);
|
|
3726
|
+
object.position.add(objectOffset);
|
|
3727
|
+
const matrix = new Matrix4().makeTranslation(objectOffset.x, objectOffset.y, objectOffset.z);
|
|
3728
|
+
transformMap.set(object, matrix);
|
|
3729
|
+
}
|
|
3730
|
+
object.children
|
|
3731
|
+
.filter((x) => !x.userData.isOptimized)
|
|
3732
|
+
.forEach((x) => explodeObject(x, depth + 1));
|
|
3733
|
+
}
|
|
3734
|
+
explodeObject(explodeRoot, 0);
|
|
3735
|
+
this.scene.updateMatrixWorld();
|
|
3736
|
+
this.gltfLoader.applyObjectTransforms(transformMap);
|
|
3737
|
+
return this;
|
|
3738
|
+
}
|
|
3640
3739
|
}
|
|
3641
3740
|
|
|
3642
3741
|
const GL_COMPONENT_TYPES = {
|
|
@@ -3685,7 +3784,7 @@ class GltfStructure {
|
|
|
3685
3784
|
this.textureCache = new Map();
|
|
3686
3785
|
this.materialCache = new Map();
|
|
3687
3786
|
this.uri = "";
|
|
3688
|
-
this._nextObjectId =
|
|
3787
|
+
this._nextObjectId = 1;
|
|
3689
3788
|
this.loadingAborted = false;
|
|
3690
3789
|
this.criticalError = null;
|
|
3691
3790
|
}
|
|
@@ -4186,8 +4285,6 @@ class DynamicGltfLoader {
|
|
|
4186
4285
|
this.frameDelay = 0;
|
|
4187
4286
|
this.graphicsObjectLimit = 10000;
|
|
4188
4287
|
this.totalLoadedObjects = 0;
|
|
4189
|
-
this.lastUpdateTime = 0;
|
|
4190
|
-
this.updateInterval = 1000;
|
|
4191
4288
|
this.handleToObjects = new Map();
|
|
4192
4289
|
this.originalObjects = new Set();
|
|
4193
4290
|
this.originalObjectsToSelection = new Set();
|
|
@@ -4204,6 +4301,8 @@ class DynamicGltfLoader {
|
|
|
4204
4301
|
this.hiddenHandles = new Set();
|
|
4205
4302
|
this.newOptimizedObjects = new Set();
|
|
4206
4303
|
this.oldOptimizeObjects = new Set();
|
|
4304
|
+
this.objectTransforms = new Map();
|
|
4305
|
+
this.transformedGeometries = new Map();
|
|
4207
4306
|
this.activeChunkLoads = 0;
|
|
4208
4307
|
this.chunkQueue = [];
|
|
4209
4308
|
this.objectIdToIndex = new Map();
|
|
@@ -4861,11 +4960,7 @@ class DynamicGltfLoader {
|
|
|
4861
4960
|
loaded: loadedCount,
|
|
4862
4961
|
total: totalNodes,
|
|
4863
4962
|
});
|
|
4864
|
-
|
|
4865
|
-
if (currentTime - this.lastUpdateTime >= this.updateInterval) {
|
|
4866
|
-
this.dispatchEvent("update");
|
|
4867
|
-
this.lastUpdateTime = currentTime;
|
|
4868
|
-
}
|
|
4963
|
+
this.dispatchEvent("update");
|
|
4869
4964
|
await new Promise((resolve) => {
|
|
4870
4965
|
setTimeout(resolve, 0);
|
|
4871
4966
|
});
|
|
@@ -4965,14 +5060,32 @@ class DynamicGltfLoader {
|
|
|
4965
5060
|
if (!node.geometryExtents) continue;
|
|
4966
5061
|
if (node.object && this.hiddenHandles.has(node.object.userData.handle)) continue;
|
|
4967
5062
|
const transformedBox = node.geometryExtents.clone();
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
5063
|
+
const structureRoot = node.structure ? this.structureRoots.get(node.structure.id) : null;
|
|
5064
|
+
if (node.group) {
|
|
5065
|
+
const matrices = [];
|
|
5066
|
+
let currentGroup = node.group;
|
|
5067
|
+
while (currentGroup && currentGroup !== structureRoot) {
|
|
5068
|
+
if (currentGroup.matrix && currentGroup.matrixAutoUpdate === false) {
|
|
5069
|
+
matrices.unshift(currentGroup.matrix);
|
|
5070
|
+
}
|
|
5071
|
+
currentGroup = currentGroup.parent;
|
|
4972
5072
|
}
|
|
5073
|
+
for (const matrix of matrices) {
|
|
5074
|
+
transformedBox.applyMatrix4(matrix);
|
|
5075
|
+
}
|
|
5076
|
+
}
|
|
5077
|
+
if (structureRoot && structureRoot.matrix) {
|
|
5078
|
+
transformedBox.applyMatrix4(structureRoot.matrix);
|
|
5079
|
+
}
|
|
5080
|
+
const transform = this.objectTransforms.get(node.object);
|
|
5081
|
+
if (transform) {
|
|
5082
|
+
transformedBox.applyMatrix4(transform);
|
|
4973
5083
|
}
|
|
4974
5084
|
totalExtent.union(transformedBox);
|
|
4975
5085
|
}
|
|
5086
|
+
if (this.scene && this.scene.matrix && !totalExtent.isEmpty()) {
|
|
5087
|
+
totalExtent.applyMatrix4(this.scene.matrix);
|
|
5088
|
+
}
|
|
4976
5089
|
return totalExtent;
|
|
4977
5090
|
}
|
|
4978
5091
|
loadCamera(structure, cameraIndex, nodeDef) {
|
|
@@ -5048,7 +5161,6 @@ class DynamicGltfLoader {
|
|
|
5048
5161
|
for (let i = 0; i < this.maxObjectId; i++) {
|
|
5049
5162
|
this.objectVisibility[i] = 1.0;
|
|
5050
5163
|
}
|
|
5051
|
-
console.log(`Initialized object visibility array: ${this.maxObjectId} objects`);
|
|
5052
5164
|
}
|
|
5053
5165
|
}
|
|
5054
5166
|
createVisibilityMaterial(material) {
|
|
@@ -5185,8 +5297,9 @@ class DynamicGltfLoader {
|
|
|
5185
5297
|
this.newOptimizedObjects.clear();
|
|
5186
5298
|
this.oldOptimizeObjects.clear();
|
|
5187
5299
|
this.isolatedObjects = [];
|
|
5300
|
+
this.objectTransforms.clear();
|
|
5301
|
+
this.transformedGeometries.clear();
|
|
5188
5302
|
this.totalLoadedObjects = 0;
|
|
5189
|
-
this.lastUpdateTime = 0;
|
|
5190
5303
|
this.currentMemoryUsage = 0;
|
|
5191
5304
|
this.loadedGeometrySize = 0;
|
|
5192
5305
|
this.abortController = new AbortController();
|
|
@@ -5297,9 +5410,7 @@ class DynamicGltfLoader {
|
|
|
5297
5410
|
}
|
|
5298
5411
|
yieldToUI() {
|
|
5299
5412
|
return new Promise((resolve) => {
|
|
5300
|
-
|
|
5301
|
-
setTimeout(resolve, 0);
|
|
5302
|
-
});
|
|
5413
|
+
setTimeout(resolve, 0);
|
|
5303
5414
|
});
|
|
5304
5415
|
}
|
|
5305
5416
|
async optimizeScene() {
|
|
@@ -5882,6 +5993,171 @@ class DynamicGltfLoader {
|
|
|
5882
5993
|
mergedObject.geometry.attributes.visibility.needsUpdate = true;
|
|
5883
5994
|
}
|
|
5884
5995
|
}
|
|
5996
|
+
applyObjectTransforms(objectTransformMap) {
|
|
5997
|
+
if (this.mergedObjectMap.size === 0) {
|
|
5998
|
+
console.warn("No merged objects to transform");
|
|
5999
|
+
return;
|
|
6000
|
+
}
|
|
6001
|
+
this.objectTransforms = new Map(objectTransformMap);
|
|
6002
|
+
for (const mesh of this.mergedMesh) {
|
|
6003
|
+
this._applyTransformToMergedObject(mesh);
|
|
6004
|
+
}
|
|
6005
|
+
for (const line of this.mergedLines) {
|
|
6006
|
+
this._applyTransformToMergedObject(line);
|
|
6007
|
+
}
|
|
6008
|
+
for (const lineSegment of this.mergedLineSegments) {
|
|
6009
|
+
this._applyTransformToMergedObject(lineSegment);
|
|
6010
|
+
}
|
|
6011
|
+
for (const point of this.mergedPoints) {
|
|
6012
|
+
this._applyTransformToMergedObject(point);
|
|
6013
|
+
}
|
|
6014
|
+
}
|
|
6015
|
+
createExplodeTransforms(objects = null, explodeCenter = null, explodeFactor = 1.5) {
|
|
6016
|
+
const transformMap = new Map();
|
|
6017
|
+
if (!explodeCenter) {
|
|
6018
|
+
explodeCenter = new Vector3();
|
|
6019
|
+
const extent = this.getTotalGeometryExtent();
|
|
6020
|
+
if (!extent.isEmpty()) {
|
|
6021
|
+
extent.getCenter(explodeCenter);
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
const objectsArray = objects
|
|
6025
|
+
? Array.isArray(objects)
|
|
6026
|
+
? objects
|
|
6027
|
+
: Array.from(objects)
|
|
6028
|
+
: Array.from(this.originalObjects);
|
|
6029
|
+
for (const obj of objectsArray) {
|
|
6030
|
+
if (!obj.geometry || !obj.geometry.attributes.position) continue;
|
|
6031
|
+
const boundingBox = new Box3().setFromBufferAttribute(obj.geometry.attributes.position);
|
|
6032
|
+
if (obj.matrixWorld) {
|
|
6033
|
+
boundingBox.applyMatrix4(obj.matrixWorld);
|
|
6034
|
+
}
|
|
6035
|
+
if (boundingBox.isEmpty()) continue;
|
|
6036
|
+
const objectCenter = new Vector3();
|
|
6037
|
+
boundingBox.getCenter(objectCenter);
|
|
6038
|
+
const direction = objectCenter.clone().sub(explodeCenter);
|
|
6039
|
+
const distance = direction.length();
|
|
6040
|
+
if (distance > 0) {
|
|
6041
|
+
direction.normalize();
|
|
6042
|
+
const offset = direction.multiplyScalar(distance * (explodeFactor - 1.0));
|
|
6043
|
+
const matrix = new Matrix4().makeTranslation(offset.x, offset.y, offset.z);
|
|
6044
|
+
transformMap.set(obj, matrix);
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
return transformMap;
|
|
6048
|
+
}
|
|
6049
|
+
clearTransforms() {
|
|
6050
|
+
this.objectTransforms.clear();
|
|
6051
|
+
for (const mesh of this.mergedMesh) {
|
|
6052
|
+
this._restoreOriginalGeometry(mesh);
|
|
6053
|
+
}
|
|
6054
|
+
for (const line of this.mergedLines) {
|
|
6055
|
+
this._restoreOriginalGeometry(line);
|
|
6056
|
+
}
|
|
6057
|
+
for (const lineSegment of this.mergedLineSegments) {
|
|
6058
|
+
this._restoreOriginalGeometry(lineSegment);
|
|
6059
|
+
}
|
|
6060
|
+
for (const point of this.mergedPoints) {
|
|
6061
|
+
this._restoreOriginalGeometry(point);
|
|
6062
|
+
}
|
|
6063
|
+
}
|
|
6064
|
+
clearHandleTransforms() {
|
|
6065
|
+
this.clearTransforms();
|
|
6066
|
+
}
|
|
6067
|
+
_applyTransformToMergedObject(mergedObject) {
|
|
6068
|
+
const objectData = this.mergedObjectMap.get(mergedObject.uuid);
|
|
6069
|
+
if (!objectData || !objectData.objectMapping) return;
|
|
6070
|
+
const geometry = mergedObject.geometry;
|
|
6071
|
+
if (!geometry || !geometry.attributes.position) return;
|
|
6072
|
+
const positionAttr = geometry.attributes.position;
|
|
6073
|
+
const positions = positionAttr.array;
|
|
6074
|
+
if (!this.transformedGeometries.has(mergedObject.uuid)) {
|
|
6075
|
+
this.transformedGeometries.set(mergedObject.uuid, new Float32Array(positions));
|
|
6076
|
+
}
|
|
6077
|
+
const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
|
|
6078
|
+
const tempVector = new Vector3();
|
|
6079
|
+
for (const [originalMesh, mappingData] of objectData.objectMapping) {
|
|
6080
|
+
const transform = this.objectTransforms.get(originalMesh);
|
|
6081
|
+
if (!transform) {
|
|
6082
|
+
const startIdx = mappingData.startVertexIndex * 3;
|
|
6083
|
+
const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
|
|
6084
|
+
for (let i = startIdx; i < endIdx; i++) {
|
|
6085
|
+
positions[i] = originalPositions[i];
|
|
6086
|
+
}
|
|
6087
|
+
continue;
|
|
6088
|
+
}
|
|
6089
|
+
const startVertex = mappingData.startVertexIndex;
|
|
6090
|
+
const vertexCount = mappingData.vertexCount;
|
|
6091
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
6092
|
+
const idx = (startVertex + i) * 3;
|
|
6093
|
+
tempVector.set(originalPositions[idx], originalPositions[idx + 1], originalPositions[idx + 2]);
|
|
6094
|
+
tempVector.applyMatrix4(transform);
|
|
6095
|
+
positions[idx] = tempVector.x;
|
|
6096
|
+
positions[idx + 1] = tempVector.y;
|
|
6097
|
+
positions[idx + 2] = tempVector.z;
|
|
6098
|
+
}
|
|
6099
|
+
}
|
|
6100
|
+
if (geometry.attributes.normal) {
|
|
6101
|
+
this._updateNormalsForTransform(geometry, objectData, originalPositions);
|
|
6102
|
+
}
|
|
6103
|
+
positionAttr.needsUpdate = true;
|
|
6104
|
+
geometry.computeBoundingSphere();
|
|
6105
|
+
geometry.computeBoundingBox();
|
|
6106
|
+
}
|
|
6107
|
+
_updateNormalsForTransform(geometry, objectData, originalPositions) {
|
|
6108
|
+
const normalAttr = geometry.attributes.normal;
|
|
6109
|
+
if (!normalAttr) return;
|
|
6110
|
+
const normals = normalAttr.array;
|
|
6111
|
+
const tempVector = new Vector3();
|
|
6112
|
+
const normalMatrix = new Matrix4();
|
|
6113
|
+
const normalsKey = `${geometry.uuid}_normals`;
|
|
6114
|
+
if (!this.transformedGeometries.has(normalsKey)) {
|
|
6115
|
+
this.transformedGeometries.set(normalsKey, new Float32Array(normals));
|
|
6116
|
+
}
|
|
6117
|
+
const originalNormals = this.transformedGeometries.get(normalsKey);
|
|
6118
|
+
for (const [originalMesh, mappingData] of objectData.objectMapping) {
|
|
6119
|
+
const transform = this.objectTransforms.get(originalMesh);
|
|
6120
|
+
if (!transform) {
|
|
6121
|
+
const startIdx = mappingData.startVertexIndex * 3;
|
|
6122
|
+
const endIdx = (mappingData.startVertexIndex + mappingData.vertexCount) * 3;
|
|
6123
|
+
for (let i = startIdx; i < endIdx; i++) {
|
|
6124
|
+
normals[i] = originalNormals[i];
|
|
6125
|
+
}
|
|
6126
|
+
continue;
|
|
6127
|
+
}
|
|
6128
|
+
normalMatrix.copy(transform).invert().transpose();
|
|
6129
|
+
const startVertex = mappingData.startVertexIndex;
|
|
6130
|
+
const vertexCount = mappingData.vertexCount;
|
|
6131
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
6132
|
+
const idx = (startVertex + i) * 3;
|
|
6133
|
+
tempVector.set(originalNormals[idx], originalNormals[idx + 1], originalNormals[idx + 2]);
|
|
6134
|
+
tempVector.applyMatrix4(normalMatrix).normalize();
|
|
6135
|
+
normals[idx] = tempVector.x;
|
|
6136
|
+
normals[idx + 1] = tempVector.y;
|
|
6137
|
+
normals[idx + 2] = tempVector.z;
|
|
6138
|
+
}
|
|
6139
|
+
}
|
|
6140
|
+
normalAttr.needsUpdate = true;
|
|
6141
|
+
}
|
|
6142
|
+
_restoreOriginalGeometry(mergedObject) {
|
|
6143
|
+
const geometry = mergedObject.geometry;
|
|
6144
|
+
if (!geometry || !geometry.attributes.position) return;
|
|
6145
|
+
const originalPositions = this.transformedGeometries.get(mergedObject.uuid);
|
|
6146
|
+
if (originalPositions) {
|
|
6147
|
+
const positions = geometry.attributes.position.array;
|
|
6148
|
+
positions.set(originalPositions);
|
|
6149
|
+
geometry.attributes.position.needsUpdate = true;
|
|
6150
|
+
}
|
|
6151
|
+
const normalsKey = `${geometry.uuid}_normals`;
|
|
6152
|
+
const originalNormals = this.transformedGeometries.get(normalsKey);
|
|
6153
|
+
if (originalNormals && geometry.attributes.normal) {
|
|
6154
|
+
const normals = geometry.attributes.normal.array;
|
|
6155
|
+
normals.set(originalNormals);
|
|
6156
|
+
geometry.attributes.normal.needsUpdate = true;
|
|
6157
|
+
}
|
|
6158
|
+
geometry.computeBoundingSphere();
|
|
6159
|
+
geometry.computeBoundingBox();
|
|
6160
|
+
}
|
|
5885
6161
|
syncHiddenObjects() {
|
|
5886
6162
|
if (this.mergedObjectMap.size === 0) {
|
|
5887
6163
|
console.log("No merged objects to sync");
|
|
@@ -5913,19 +6189,33 @@ class DynamicGltfLoader {
|
|
|
5913
6189
|
}
|
|
5914
6190
|
getStructureGeometryExtent(structureId) {
|
|
5915
6191
|
const extent = new Box3();
|
|
6192
|
+
const structureRoot = this.structureRoots.get(structureId);
|
|
5916
6193
|
for (const [nodeId, node] of this.nodes.entries()) {
|
|
5917
6194
|
if (!node.geometryExtents) continue;
|
|
5918
6195
|
if (!nodeId.startsWith(structureId + "_")) continue;
|
|
5919
6196
|
if (node.object && this.hiddenHandles && this.hiddenHandles.has(node.object.userData.handle)) continue;
|
|
5920
6197
|
const transformedBox = node.geometryExtents.clone();
|
|
5921
|
-
if (node.group
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
6198
|
+
if (node.group) {
|
|
6199
|
+
const matrices = [];
|
|
6200
|
+
let currentGroup = node.group;
|
|
6201
|
+
while (currentGroup && currentGroup !== structureRoot) {
|
|
6202
|
+
if (currentGroup.matrix && currentGroup.matrixAutoUpdate === false) {
|
|
6203
|
+
matrices.unshift(currentGroup.matrix);
|
|
6204
|
+
}
|
|
6205
|
+
currentGroup = currentGroup.parent;
|
|
5925
6206
|
}
|
|
6207
|
+
for (const matrix of matrices) {
|
|
6208
|
+
transformedBox.applyMatrix4(matrix);
|
|
6209
|
+
}
|
|
6210
|
+
}
|
|
6211
|
+
if (structureRoot && structureRoot.matrix) {
|
|
6212
|
+
transformedBox.applyMatrix4(structureRoot.matrix);
|
|
5926
6213
|
}
|
|
5927
6214
|
extent.union(transformedBox);
|
|
5928
6215
|
}
|
|
6216
|
+
if (this.scene && this.scene.matrix && !extent.isEmpty()) {
|
|
6217
|
+
extent.applyMatrix4(this.scene.matrix);
|
|
6218
|
+
}
|
|
5929
6219
|
return extent;
|
|
5930
6220
|
}
|
|
5931
6221
|
setMaxConcurrentChunks(maxChunks) {
|
|
@@ -6475,6 +6765,7 @@ class Viewer extends EventEmitter2 {
|
|
|
6475
6765
|
this.target = new Vector3(0, 0, 0);
|
|
6476
6766
|
this._activeDragger = null;
|
|
6477
6767
|
this._components = [];
|
|
6768
|
+
this._updateDelay = 1000;
|
|
6478
6769
|
this._renderNeeded = false;
|
|
6479
6770
|
this._renderTime = 0;
|
|
6480
6771
|
this.render = this.render.bind(this);
|
|
@@ -6498,8 +6789,8 @@ class Viewer extends EventEmitter2 {
|
|
|
6498
6789
|
const rect = canvas.parentElement.getBoundingClientRect();
|
|
6499
6790
|
const width = rect.width || 1;
|
|
6500
6791
|
const height = rect.height || 1;
|
|
6501
|
-
const
|
|
6502
|
-
this.camera = new PerspectiveCamera(45,
|
|
6792
|
+
const aspectRatio = width / height;
|
|
6793
|
+
this.camera = new PerspectiveCamera(45, aspectRatio, 0.001, 1000);
|
|
6503
6794
|
this.camera.up.set(0, 1, 0);
|
|
6504
6795
|
this.camera.position.set(0, 0, 1);
|
|
6505
6796
|
this.camera.lookAt(this.target);
|
|
@@ -6596,14 +6887,14 @@ class Viewer extends EventEmitter2 {
|
|
|
6596
6887
|
if (!this.renderer)
|
|
6597
6888
|
return;
|
|
6598
6889
|
const camera = this.camera;
|
|
6599
|
-
const
|
|
6890
|
+
const aspectRatio = width / height;
|
|
6600
6891
|
if (camera.isPerspectiveCamera) {
|
|
6601
|
-
camera.aspect =
|
|
6892
|
+
camera.aspect = aspectRatio;
|
|
6602
6893
|
camera.updateProjectionMatrix();
|
|
6603
6894
|
}
|
|
6604
6895
|
if (camera.isOrthographicCamera) {
|
|
6605
|
-
camera.left = camera.bottom *
|
|
6606
|
-
camera.right = camera.top *
|
|
6896
|
+
camera.left = camera.bottom * aspectRatio;
|
|
6897
|
+
camera.right = camera.top * aspectRatio;
|
|
6607
6898
|
camera.updateProjectionMatrix();
|
|
6608
6899
|
}
|
|
6609
6900
|
this.renderer.setSize(width, height, updateStyle);
|
|
@@ -6612,16 +6903,18 @@ class Viewer extends EventEmitter2 {
|
|
|
6612
6903
|
this.emitEvent({ type: "resize", width, height });
|
|
6613
6904
|
}
|
|
6614
6905
|
update(force = false) {
|
|
6906
|
+
const time = performance.now();
|
|
6907
|
+
force = force || time - this._renderTime >= this._updateDelay;
|
|
6615
6908
|
this._renderNeeded = true;
|
|
6616
6909
|
if (force)
|
|
6617
|
-
this.render();
|
|
6618
|
-
this.emitEvent({ type: "update",
|
|
6910
|
+
this.render(time);
|
|
6911
|
+
this.emitEvent({ type: "update", force });
|
|
6619
6912
|
}
|
|
6620
|
-
render(time
|
|
6913
|
+
render(time) {
|
|
6621
6914
|
var _a, _b;
|
|
6622
6915
|
if (!this.renderer)
|
|
6623
6916
|
return;
|
|
6624
|
-
if (!this._renderNeeded
|
|
6917
|
+
if (!this._renderNeeded)
|
|
6625
6918
|
return;
|
|
6626
6919
|
if (!time)
|
|
6627
6920
|
time = performance.now();
|
|
@@ -6830,12 +7123,12 @@ class Viewer extends EventEmitter2 {
|
|
|
6830
7123
|
if (orthogonal_camera) {
|
|
6831
7124
|
const extentsSize = this.extents.getBoundingSphere(new Sphere()).radius * 2;
|
|
6832
7125
|
const rendererSize = this.renderer.getSize(new Vector2());
|
|
6833
|
-
const
|
|
7126
|
+
const aspectRatio = rendererSize.x / rendererSize.y;
|
|
6834
7127
|
const camera = new OrthographicCamera();
|
|
6835
7128
|
camera.top = orthogonal_camera.field_height / 2;
|
|
6836
7129
|
camera.bottom = -orthogonal_camera.field_height / 2;
|
|
6837
|
-
camera.left = camera.bottom *
|
|
6838
|
-
camera.right = camera.top *
|
|
7130
|
+
camera.left = camera.bottom * aspectRatio;
|
|
7131
|
+
camera.right = camera.top * aspectRatio;
|
|
6839
7132
|
camera.near = 0;
|
|
6840
7133
|
camera.far = extentsSize * 1000;
|
|
6841
7134
|
camera.zoom = orthogonal_camera.view_to_world_scale;
|
|
@@ -6848,6 +7141,7 @@ class Viewer extends EventEmitter2 {
|
|
|
6848
7141
|
this.renderPass.camera = camera;
|
|
6849
7142
|
this.helpersPass.camera = camera;
|
|
6850
7143
|
this.ssaaRenderPass.camera = camera;
|
|
7144
|
+
this.options.cameraMode = "orthographic";
|
|
6851
7145
|
this.emitEvent({ type: "changecameramode", mode: "orthographic" });
|
|
6852
7146
|
}
|
|
6853
7147
|
};
|
|
@@ -6855,10 +7149,10 @@ class Viewer extends EventEmitter2 {
|
|
|
6855
7149
|
if (perspective_camera) {
|
|
6856
7150
|
const extentsSize = this.extents.getBoundingSphere(new Sphere()).radius * 2;
|
|
6857
7151
|
const rendererSize = this.renderer.getSize(new Vector2());
|
|
6858
|
-
const
|
|
7152
|
+
const aspectRatio = rendererSize.x / rendererSize.y;
|
|
6859
7153
|
const camera = new PerspectiveCamera();
|
|
6860
7154
|
camera.fov = perspective_camera.field_of_view;
|
|
6861
|
-
camera.aspect =
|
|
7155
|
+
camera.aspect = aspectRatio;
|
|
6862
7156
|
camera.near = extentsSize / 1000;
|
|
6863
7157
|
camera.far = extentsSize * 1000;
|
|
6864
7158
|
camera.updateProjectionMatrix();
|
|
@@ -6870,6 +7164,7 @@ class Viewer extends EventEmitter2 {
|
|
|
6870
7164
|
this.renderPass.camera = camera;
|
|
6871
7165
|
this.helpersPass.camera = camera;
|
|
6872
7166
|
this.ssaaRenderPass.camera = camera;
|
|
7167
|
+
this.options.cameraMode = "perspective";
|
|
6873
7168
|
this.emitEvent({ type: "changecameramode", mode: "perspective" });
|
|
6874
7169
|
}
|
|
6875
7170
|
};
|
|
@@ -6899,6 +7194,7 @@ class Viewer extends EventEmitter2 {
|
|
|
6899
7194
|
setSelection(((_b = viewpoint.custom_fields) === null || _b === void 0 ? void 0 : _b.selection2) || viewpoint.selection);
|
|
6900
7195
|
this._markup.setViewpoint(viewpoint);
|
|
6901
7196
|
this.target.copy(getVector3FromPoint3d((_d = (_c = viewpoint.custom_fields) === null || _c === void 0 ? void 0 : _c.camera_target) !== null && _d !== void 0 ? _d : this.target));
|
|
7197
|
+
this.syncOverlay();
|
|
6902
7198
|
this.setActiveDragger(draggerName);
|
|
6903
7199
|
this.emitEvent({ type: "drawviewpoint", data: viewpoint });
|
|
6904
7200
|
this.update();
|