@inweb/viewer-three 26.10.5 → 26.11.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/README.md +7 -4
- package/dist/{plugins → extensions}/components/AxesHelperComponent.js +23 -1
- package/dist/extensions/components/AxesHelperComponent.js.map +1 -0
- package/dist/extensions/components/AxesHelperComponent.min.js +24 -0
- package/dist/{plugins → extensions}/components/AxesHelperComponent.module.js +24 -2
- package/dist/extensions/components/AxesHelperComponent.module.js.map +1 -0
- package/dist/{plugins → extensions}/components/ExtentsHelperComponent.js +18 -0
- package/dist/extensions/components/ExtentsHelperComponent.js.map +1 -0
- package/dist/{plugins/components/AxesHelperComponent.min.js → extensions/components/ExtentsHelperComponent.min.js} +1 -1
- package/dist/{plugins → extensions}/components/ExtentsHelperComponent.module.js +19 -1
- package/dist/extensions/components/ExtentsHelperComponent.module.js.map +1 -0
- package/dist/extensions/components/GridHelperComponent.js.map +1 -0
- package/dist/extensions/components/GridHelperComponent.module.js.map +1 -0
- package/dist/extensions/components/LightHelperComponent.js.map +1 -0
- package/dist/extensions/components/LightHelperComponent.module.js.map +1 -0
- package/dist/extensions/components/RoomEnvironmentComponent.js.map +1 -0
- package/dist/extensions/components/RoomEnvironmentComponent.module.js.map +1 -0
- package/dist/extensions/components/StatsPanelComponent.js.map +1 -0
- package/dist/extensions/components/StatsPanelComponent.module.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/GLTFCloudLoader.js +2 -3
- package/dist/extensions/loaders/GLTFCloudLoader.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/GLTFCloudLoader.min.js +1 -1
- package/dist/{plugins → extensions}/loaders/GLTFCloudLoader.module.js +2 -3
- package/dist/extensions/loaders/GLTFCloudLoader.module.js.map +1 -0
- package/dist/extensions/loaders/GLTFFileLoader.js +2499 -0
- package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -0
- package/dist/extensions/loaders/GLTFFileLoader.min.js +24 -0
- package/dist/extensions/loaders/GLTFFileLoader.module.js +74 -0
- package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/IFCXLoader.js +5 -7
- package/dist/extensions/loaders/IFCXLoader.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/IFCXLoader.min.js +1 -1
- package/dist/{plugins → extensions}/loaders/IFCXLoader.module.js +5 -7
- package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/PotreeLoader.js +1 -2
- package/dist/extensions/loaders/PotreeLoader.js.map +1 -0
- package/dist/{plugins → extensions}/loaders/PotreeLoader.min.js +1 -1
- package/dist/{plugins → extensions}/loaders/PotreeLoader.module.js +1 -2
- package/dist/extensions/loaders/PotreeLoader.module.js.map +1 -0
- package/dist/viewer-three.js +1023 -2928
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +856 -359
- package/dist/viewer-three.module.js.map +1 -1
- package/{plugins → extensions}/components/AxesHelperComponent.ts +31 -2
- package/{plugins → extensions}/components/ExtentsHelperComponent.ts +25 -0
- package/{plugins → extensions}/loaders/GLTFCloudLoader.ts +2 -3
- package/{src/Viewer → extensions}/loaders/GLTFFileLoader.ts +21 -12
- package/{plugins → extensions}/loaders/IFCX/IFCXCloudLoader.ts +5 -5
- package/{plugins → extensions}/loaders/IFCX/IFCXFileLoader.ts +3 -4
- package/{plugins → extensions}/loaders/Potree/PotreeFileLoader.ts +3 -4
- package/lib/Viewer/Viewer.d.ts +27 -20
- package/lib/Viewer/commands/GetSelected2.d.ts +2 -0
- package/lib/Viewer/commands/SelectModel.d.ts +1 -1
- package/lib/Viewer/commands/SetSelected2.d.ts +2 -0
- package/lib/Viewer/components/SelectionComponent.d.ts +1 -3
- package/lib/Viewer/components/index.d.ts +6 -6
- package/lib/Viewer/draggers/MeasureLineDragger.d.ts +7 -1
- package/lib/Viewer/draggers/OrbitDragger.d.ts +3 -0
- package/lib/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.d.ts +0 -1
- package/lib/Viewer/loaders/GLTFBinaryExtension.d.ts +5 -0
- package/lib/Viewer/loaders/GLTFCloudDynamicLoader.d.ts +2 -2
- package/lib/Viewer/loaders/{GLTFFileLoader.d.ts → GLTFFileDynamicLoader.d.ts} +7 -1
- package/lib/Viewer/loaders/GLTFLoadingManager.d.ts +4 -3
- package/lib/Viewer/loaders/RangesLoader.d.ts +15 -0
- package/lib/Viewer/loaders/index.d.ts +22 -14
- package/lib/Viewer/measurement/Snapper.d.ts +15 -0
- package/lib/Viewer/measurement/UnitConverter.d.ts +63 -0
- package/lib/Viewer/measurement/UnitFormatter.d.ts +4 -0
- package/lib/Viewer/models/IModelImpl.d.ts +10 -8
- package/lib/Viewer/models/ModelImpl.d.ts +7 -5
- package/package.json +11 -11
- package/src/Viewer/Viewer.ts +120 -88
- package/src/Viewer/commands/ClearSelected.ts +3 -1
- package/src/Viewer/commands/GetModels.ts +1 -1
- package/src/Viewer/commands/GetSelected.ts +2 -2
- package/src/Viewer/commands/GetSelected2.ts +34 -0
- package/src/Viewer/commands/HideSelected.ts +3 -1
- package/src/Viewer/commands/SelectModel.ts +5 -5
- package/src/Viewer/commands/SetSelected.ts +9 -10
- package/src/Viewer/commands/SetSelected2.ts +42 -0
- package/src/Viewer/commands/ZoomToObjects.ts +5 -6
- package/src/Viewer/commands/ZoomToSelected.ts +3 -1
- package/src/Viewer/commands/index.ts +4 -0
- package/src/Viewer/components/CameraComponent.ts +6 -1
- package/src/Viewer/components/ExtentsComponent.ts +4 -1
- package/src/Viewer/components/HighlighterComponent.ts +5 -3
- package/src/Viewer/components/SelectionComponent.ts +7 -30
- package/src/Viewer/components/index.ts +6 -6
- package/src/Viewer/draggers/MeasureLineDragger.ts +84 -226
- package/src/Viewer/draggers/OrbitDragger.ts +6 -0
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +263 -34
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +20 -10
- package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +4 -1
- package/src/Viewer/loaders/GLTFBinaryExtension.ts +91 -0
- package/src/Viewer/loaders/GLTFCloudDynamicLoader.ts +13 -19
- package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +145 -0
- package/src/Viewer/loaders/GLTFLoadingManager.ts +5 -4
- package/src/Viewer/loaders/RangesLoader.ts +95 -0
- package/src/Viewer/loaders/index.ts +24 -16
- package/src/Viewer/measurement/Snapper.ts +208 -0
- package/src/Viewer/measurement/UnitConverter.ts +47 -0
- package/src/Viewer/measurement/UnitFormatter.ts +95 -0
- package/src/Viewer/models/IModelImpl.ts +15 -8
- package/src/Viewer/models/ModelImpl.ts +48 -17
- package/src/index-umd.ts +1 -1
- package/dist/plugins/components/AxesHelperComponent.js.map +0 -1
- package/dist/plugins/components/AxesHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/ExtentsHelperComponent.js.map +0 -1
- package/dist/plugins/components/ExtentsHelperComponent.min.js +0 -24
- package/dist/plugins/components/ExtentsHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/GridHelperComponent.js.map +0 -1
- package/dist/plugins/components/GridHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/LightHelperComponent.js.map +0 -1
- package/dist/plugins/components/LightHelperComponent.module.js.map +0 -1
- package/dist/plugins/components/RoomEnvironmentComponent.js.map +0 -1
- package/dist/plugins/components/RoomEnvironmentComponent.module.js.map +0 -1
- package/dist/plugins/components/StatsPanelComponent.js.map +0 -1
- package/dist/plugins/components/StatsPanelComponent.module.js.map +0 -1
- package/dist/plugins/loaders/GLTFCloudLoader.js.map +0 -1
- package/dist/plugins/loaders/GLTFCloudLoader.module.js.map +0 -1
- package/dist/plugins/loaders/IFCXLoader.js.map +0 -1
- package/dist/plugins/loaders/IFCXLoader.module.js.map +0 -1
- package/dist/plugins/loaders/PotreeLoader.js.map +0 -1
- package/dist/plugins/loaders/PotreeLoader.module.js.map +0 -1
- /package/dist/{plugins → extensions}/components/GridHelperComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/GridHelperComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/GridHelperComponent.module.js +0 -0
- /package/dist/{plugins → extensions}/components/LightHelperComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/LightHelperComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/LightHelperComponent.module.js +0 -0
- /package/dist/{plugins → extensions}/components/RoomEnvironmentComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/RoomEnvironmentComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/RoomEnvironmentComponent.module.js +0 -0
- /package/dist/{plugins → extensions}/components/StatsPanelComponent.js +0 -0
- /package/dist/{plugins → extensions}/components/StatsPanelComponent.min.js +0 -0
- /package/dist/{plugins → extensions}/components/StatsPanelComponent.module.js +0 -0
- /package/{plugins → extensions}/components/GridHelperComponent.ts +0 -0
- /package/{plugins → extensions}/components/LightHelperComponent.ts +0 -0
- /package/{plugins → extensions}/components/RoomEnvironmentComponent.ts +0 -0
- /package/{plugins → extensions}/components/StatsPanelComponent.ts +0 -0
- /package/{plugins → extensions}/loaders/IFCX/IFCXLoader.ts +0 -0
- /package/{plugins → extensions}/loaders/IFCX/index.ts +0 -0
- /package/{plugins → extensions}/loaders/IFCX/render.js +0 -0
- /package/{plugins → extensions}/loaders/Potree/PotreeModelImpl.ts +0 -0
- /package/{plugins → extensions}/loaders/Potree/index.ts +0 -0
|
@@ -21,14 +21,13 @@
|
|
|
21
21
|
// acknowledge and accept the above terms.
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
|
-
import { draggersRegistry, commandsRegistry, componentsRegistry, Loader, loadersRegistry,
|
|
24
|
+
import { draggersRegistry, commandsRegistry, Options, componentsRegistry, Loader, loadersRegistry, CANVAS_EVENTS } from '@inweb/viewer-core';
|
|
25
25
|
export * from '@inweb/viewer-core';
|
|
26
|
-
import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Line3,
|
|
26
|
+
import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Line3, Raycaster, MathUtils, EdgesGeometry, Matrix4, Vector4, Controls, Clock, Sphere, Box3, Color, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, HemisphereLight, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, TextureLoader, BufferAttribute, PointsMaterial, Points, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, LoadingManager, LoaderUtils, FileLoader, UniformsUtils, ShaderMaterial, AdditiveBlending, HalfFloatType, Scene, WebGLRenderer, LinearSRGBColorSpace } from 'three';
|
|
27
27
|
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
|
|
28
28
|
import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry.js';
|
|
29
29
|
import { Wireframe } from 'three/examples/jsm/lines/Wireframe.js';
|
|
30
30
|
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js';
|
|
31
|
-
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
32
31
|
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
33
32
|
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
|
|
34
33
|
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
|
|
@@ -752,6 +751,9 @@ class OrbitDragger {
|
|
|
752
751
|
this.orbit.object = this.viewer.camera;
|
|
753
752
|
this.orbit.update();
|
|
754
753
|
};
|
|
754
|
+
this.optionsChange = ({ data: options }) => {
|
|
755
|
+
this.orbit.zoomSpeed = Math.abs(this.orbit.zoomSpeed) * (options.reverseZoomWheel ? -1 : 1);
|
|
756
|
+
};
|
|
755
757
|
this.controlsStart = () => {
|
|
756
758
|
this.changed = false;
|
|
757
759
|
};
|
|
@@ -807,6 +809,7 @@ class OrbitDragger {
|
|
|
807
809
|
this.viewer.addEventListener("zoom", this.updateControls);
|
|
808
810
|
this.viewer.addEventListener("drawviewpoint", this.updateControls);
|
|
809
811
|
this.viewer.addEventListener("changecameramode", this.updateControlsCamera);
|
|
812
|
+
this.viewer.addEventListener("optionschange", this.optionsChange);
|
|
810
813
|
this.viewer.addEventListener("contextmenu", this.stopContextMenu);
|
|
811
814
|
this.updateControls();
|
|
812
815
|
}
|
|
@@ -817,6 +820,7 @@ class OrbitDragger {
|
|
|
817
820
|
this.viewer.removeEventListener("zoom", this.updateControls);
|
|
818
821
|
this.viewer.removeEventListener("drawviewpoint", this.updateControls);
|
|
819
822
|
this.viewer.removeEventListener("changecameramode", this.updateControlsCamera);
|
|
823
|
+
this.viewer.removeEventListener("optionschange", this.optionsChange);
|
|
820
824
|
this.viewer.removeEventListener("contextmenu", this.stopContextMenu);
|
|
821
825
|
this.orbit.removeEventListener("start", this.controlsStart);
|
|
822
826
|
this.orbit.removeEventListener("change", this.controlsChange);
|
|
@@ -909,116 +913,91 @@ class CuttingPlaneZAxisDragger extends CuttingPlaneDragger {
|
|
|
909
913
|
}
|
|
910
914
|
}
|
|
911
915
|
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
this.viewer.canvas.addEventListener("pointerleave", this.onPointerLeave);
|
|
978
|
-
this.viewer.addEventListener("render", this.renderOverlay);
|
|
979
|
-
this.viewer.addEventListener("hide", this.updateSnapper);
|
|
980
|
-
this.viewer.addEventListener("isolate", this.updateSnapper);
|
|
981
|
-
this.viewer.addEventListener("show", this.updateSnapper);
|
|
982
|
-
this.viewer.addEventListener("showall", this.updateSnapper);
|
|
983
|
-
this.viewer.addEventListener("changecameramode", this.updateSnapperCamera);
|
|
984
|
-
}
|
|
985
|
-
dispose() {
|
|
986
|
-
this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown);
|
|
987
|
-
this.viewer.canvas.removeEventListener("pointermove", this.onPointerMove);
|
|
988
|
-
this.viewer.canvas.removeEventListener("pointerup", this.onPointerUp);
|
|
989
|
-
this.viewer.canvas.removeEventListener("pointercancel", this.onPointerCancel);
|
|
990
|
-
this.viewer.canvas.removeEventListener("pointerleave", this.onPointerLeave);
|
|
991
|
-
this.viewer.removeEventListener("render", this.renderOverlay);
|
|
992
|
-
this.viewer.removeEventListener("hide", this.updateSnapper);
|
|
993
|
-
this.viewer.removeEventListener("isolate", this.updateSnapper);
|
|
994
|
-
this.viewer.removeEventListener("show", this.updateSnapper);
|
|
995
|
-
this.viewer.removeEventListener("showall", this.updateSnapper);
|
|
996
|
-
this.viewer.removeEventListener("changecameramode", this.updateSnapperCamera);
|
|
997
|
-
this.snapper.dispose();
|
|
998
|
-
this.overlay.detach();
|
|
999
|
-
this.overlay.dispose();
|
|
1000
|
-
super.dispose();
|
|
916
|
+
const ModelUnits = {
|
|
917
|
+
Meters: { name: "Meters", type: "m", scale: 1.0 },
|
|
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 },
|
|
929
|
+
};
|
|
930
|
+
function convertUnits(fromUnits, toUnits, distance) {
|
|
931
|
+
const fromFactor = 1 / (ModelUnits[fromUnits] || ModelUnits.Default).scale;
|
|
932
|
+
const toFactor = (ModelUnits[toUnits] || ModelUnits.Default).scale || 1;
|
|
933
|
+
return distance * fromFactor * toFactor;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
function getDisplayUnit(units) {
|
|
937
|
+
return (ModelUnits[units] || ModelUnits.Default).type;
|
|
938
|
+
}
|
|
939
|
+
function calculatePrecision(value) {
|
|
940
|
+
const distance = Math.abs(value);
|
|
941
|
+
if (distance >= 1000)
|
|
942
|
+
return 0;
|
|
943
|
+
if (distance >= 10)
|
|
944
|
+
return 1;
|
|
945
|
+
if (distance >= 0.1)
|
|
946
|
+
return 2;
|
|
947
|
+
if (distance >= 0.001)
|
|
948
|
+
return 3;
|
|
949
|
+
return distance > 0 ? Math.floor(-Math.log10(distance)) + 1 : 2;
|
|
950
|
+
}
|
|
951
|
+
function formatNumber(distance, digits, precision) {
|
|
952
|
+
let result = distance.toFixed(digits);
|
|
953
|
+
if (precision === "Auto")
|
|
954
|
+
result = result.replace(/\.0+$/, "").replace(/\.$/, "");
|
|
955
|
+
if (+result !== distance)
|
|
956
|
+
result = "~ " + result;
|
|
957
|
+
return result;
|
|
958
|
+
}
|
|
959
|
+
function formatDistance(distance, units, precision = 2) {
|
|
960
|
+
let digits;
|
|
961
|
+
if (precision === "Auto")
|
|
962
|
+
digits = calculatePrecision(distance);
|
|
963
|
+
else if (Number.isFinite(precision))
|
|
964
|
+
digits = precision;
|
|
965
|
+
else
|
|
966
|
+
digits = parseFloat(precision);
|
|
967
|
+
if (!Number.isFinite(digits))
|
|
968
|
+
digits = 2;
|
|
969
|
+
else if (digits < 0)
|
|
970
|
+
digits = 0;
|
|
971
|
+
else if (digits > 10)
|
|
972
|
+
digits = 10;
|
|
973
|
+
if (ModelUnits[units]) {
|
|
974
|
+
return formatNumber(distance, digits, precision) + " " + ModelUnits[units].type;
|
|
975
|
+
}
|
|
976
|
+
else if (units) {
|
|
977
|
+
return formatNumber(distance, digits, precision) + " " + units;
|
|
978
|
+
}
|
|
979
|
+
else {
|
|
980
|
+
return formatNumber(distance, digits, precision);
|
|
1001
981
|
}
|
|
1002
982
|
}
|
|
983
|
+
|
|
984
|
+
const DESKTOP_SNAP_DISTANCE = 10;
|
|
985
|
+
const MOBILE_SNAP_DISTANCE = 50;
|
|
1003
986
|
const _vertex = new Vector3();
|
|
1004
987
|
const _start = new Vector3();
|
|
1005
988
|
const _end = new Vector3();
|
|
1006
989
|
const _line = new Line3();
|
|
1007
990
|
const _center = new Vector3();
|
|
1008
991
|
const _projection = new Vector3();
|
|
1009
|
-
class
|
|
1010
|
-
constructor(camera, canvas) {
|
|
992
|
+
class Snapper {
|
|
993
|
+
constructor(camera, renderer, canvas) {
|
|
1011
994
|
this.camera = camera;
|
|
995
|
+
this.renderer = renderer;
|
|
1012
996
|
this.canvas = canvas;
|
|
1013
|
-
this.objects = [];
|
|
1014
|
-
this.clippingPlanes = [];
|
|
1015
997
|
this.raycaster = new Raycaster();
|
|
1016
998
|
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
1017
999
|
this.edgesCache = new WeakMap();
|
|
1018
1000
|
}
|
|
1019
|
-
dispose() {
|
|
1020
|
-
this.objects = [];
|
|
1021
|
-
}
|
|
1022
1001
|
isMobile() {
|
|
1023
1002
|
if (typeof navigator === "undefined")
|
|
1024
1003
|
return false;
|
|
@@ -1027,7 +1006,7 @@ class MeasureSnapper {
|
|
|
1027
1006
|
getMousePosition(event, target) {
|
|
1028
1007
|
return target.set(event.clientX, event.clientY);
|
|
1029
1008
|
}
|
|
1030
|
-
getPointerIntersects(mouse) {
|
|
1009
|
+
getPointerIntersects(mouse, objects) {
|
|
1031
1010
|
const rect = this.canvas.getBoundingClientRect();
|
|
1032
1011
|
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
1033
1012
|
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
@@ -1041,8 +1020,8 @@ class MeasureSnapper {
|
|
|
1041
1020
|
Points: { threshold: 0.01 },
|
|
1042
1021
|
Sprite: {},
|
|
1043
1022
|
};
|
|
1044
|
-
let intersects = this.raycaster.intersectObjects(
|
|
1045
|
-
this.clippingPlanes.forEach((plane) => {
|
|
1023
|
+
let intersects = this.raycaster.intersectObjects(objects, false);
|
|
1024
|
+
(this.renderer.clippingPlanes || []).forEach((plane) => {
|
|
1046
1025
|
intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
|
|
1047
1026
|
});
|
|
1048
1027
|
return intersects;
|
|
@@ -1064,9 +1043,8 @@ class MeasureSnapper {
|
|
|
1064
1043
|
}
|
|
1065
1044
|
return 0.1;
|
|
1066
1045
|
}
|
|
1067
|
-
getSnapPoint(
|
|
1068
|
-
const
|
|
1069
|
-
const intersections = this.getPointerIntersects(mouse);
|
|
1046
|
+
getSnapPoint(mouse, objects) {
|
|
1047
|
+
const intersections = this.getPointerIntersects(mouse, objects);
|
|
1070
1048
|
if (intersections.length === 0)
|
|
1071
1049
|
return undefined;
|
|
1072
1050
|
const object = intersections[0].object;
|
|
@@ -1114,13 +1092,133 @@ class MeasureSnapper {
|
|
|
1114
1092
|
return object.localToWorld(snapPoint);
|
|
1115
1093
|
return intersectionPoint.clone();
|
|
1116
1094
|
}
|
|
1117
|
-
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
const _downPoint = new Vector2();
|
|
1098
|
+
class MeasureLineDragger extends OrbitDragger {
|
|
1099
|
+
constructor(viewer) {
|
|
1100
|
+
super(viewer);
|
|
1101
|
+
this.scale = 1.0;
|
|
1102
|
+
this.units = "";
|
|
1103
|
+
this.precision = 2;
|
|
1104
|
+
this.onPointerDown = (event) => {
|
|
1105
|
+
if (event.button !== 0)
|
|
1106
|
+
return;
|
|
1107
|
+
const mouse = this.snapper.getMousePosition(event, _downPoint);
|
|
1108
|
+
this.line.startPoint = this.snapper.getSnapPoint(mouse, this.objects);
|
|
1109
|
+
this.line.render();
|
|
1110
|
+
this.viewer.canvas.setPointerCapture(event.pointerId);
|
|
1111
|
+
this.orbit.enabled = !this.line.startPoint;
|
|
1112
|
+
};
|
|
1113
|
+
this.onPointerMove = (event) => {
|
|
1114
|
+
if (this.orbit.enabled && this.orbit.state !== -1)
|
|
1115
|
+
return;
|
|
1116
|
+
const mouse = this.snapper.getMousePosition(event, _downPoint);
|
|
1117
|
+
const snapPoint = this.snapper.getSnapPoint(mouse, this.objects);
|
|
1118
|
+
if (snapPoint && this.line.endPoint && snapPoint.equals(this.line.endPoint))
|
|
1119
|
+
return;
|
|
1120
|
+
this.line.endPoint = snapPoint;
|
|
1121
|
+
this.line.render();
|
|
1122
|
+
if (this.line.startPoint)
|
|
1123
|
+
this.changed = true;
|
|
1124
|
+
};
|
|
1125
|
+
this.onPointerUp = (event) => {
|
|
1126
|
+
if (this.line.startPoint && this.line.endPoint && this.line.getDistance() > 0) {
|
|
1127
|
+
this.line = new MeasureLine(this.overlay, this.scale, this.units, this.precision);
|
|
1128
|
+
this.overlay.addLine(this.line);
|
|
1129
|
+
}
|
|
1130
|
+
else {
|
|
1131
|
+
this.line.startPoint = undefined;
|
|
1132
|
+
this.line.endPoint = undefined;
|
|
1133
|
+
this.line.render();
|
|
1134
|
+
}
|
|
1135
|
+
this.viewer.canvas.releasePointerCapture(event.pointerId);
|
|
1136
|
+
this.orbit.enabled = true;
|
|
1137
|
+
};
|
|
1138
|
+
this.onPointerCancel = (event) => {
|
|
1139
|
+
this.viewer.canvas.dispatchEvent(new PointerEvent("pointerup", event));
|
|
1140
|
+
};
|
|
1141
|
+
this.onPointerLeave = () => {
|
|
1142
|
+
this.line.endPoint = undefined;
|
|
1143
|
+
this.line.render();
|
|
1144
|
+
};
|
|
1145
|
+
this.clearOverlay = () => {
|
|
1146
|
+
this.overlay.clear();
|
|
1147
|
+
this.line = new MeasureLine(this.overlay, this.scale, this.units, this.precision);
|
|
1148
|
+
this.overlay.addLine(this.line);
|
|
1149
|
+
};
|
|
1150
|
+
this.renderOverlay = () => {
|
|
1151
|
+
this.overlay.render();
|
|
1152
|
+
};
|
|
1153
|
+
this.updateObjects = () => {
|
|
1154
|
+
this.objects.length = 0;
|
|
1155
|
+
this.viewer.models.forEach((model) => {
|
|
1156
|
+
model.getVisibleObjects().forEach((object) => this.objects.push(object));
|
|
1157
|
+
});
|
|
1158
|
+
};
|
|
1159
|
+
this.updateSnapperCamera = () => {
|
|
1160
|
+
this.snapper.camera = this.viewer.camera;
|
|
1161
|
+
this.overlay.camera = this.viewer.camera;
|
|
1162
|
+
};
|
|
1163
|
+
this.updateUnits = () => {
|
|
1164
|
+
var _a, _b;
|
|
1165
|
+
const model = this.viewer.models[0];
|
|
1166
|
+
const units = (_a = this.viewer.options.rulerUnit) !== null && _a !== void 0 ? _a : "Default";
|
|
1167
|
+
const precision = (_b = this.viewer.options.rulerPrecision) !== null && _b !== void 0 ? _b : "Default";
|
|
1168
|
+
if (units === "Default") {
|
|
1169
|
+
this.scale = model.getUnitScale();
|
|
1170
|
+
this.units = model.getUnitString();
|
|
1171
|
+
}
|
|
1172
|
+
else {
|
|
1173
|
+
this.scale = convertUnits(model.getUnits(), units, 1);
|
|
1174
|
+
this.units = units;
|
|
1175
|
+
}
|
|
1176
|
+
if (precision === "Default") {
|
|
1177
|
+
this.precision = model.getPrecision();
|
|
1178
|
+
}
|
|
1179
|
+
else {
|
|
1180
|
+
this.precision = precision;
|
|
1181
|
+
}
|
|
1182
|
+
this.overlay.updateLineUnits(this.scale, this.units, this.precision);
|
|
1183
|
+
};
|
|
1184
|
+
this.overlay = new MeasureOverlay(viewer.camera, viewer.canvas);
|
|
1185
|
+
this.overlay.attach();
|
|
1186
|
+
this.line = new MeasureLine(this.overlay, this.scale, this.units, this.precision);
|
|
1187
|
+
this.overlay.addLine(this.line);
|
|
1188
|
+
this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
|
|
1189
|
+
this.objects = [];
|
|
1190
|
+
this.updateObjects();
|
|
1191
|
+
this.updateUnits();
|
|
1192
|
+
this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown);
|
|
1193
|
+
this.viewer.canvas.addEventListener("pointermove", this.onPointerMove);
|
|
1194
|
+
this.viewer.canvas.addEventListener("pointerup", this.onPointerUp);
|
|
1195
|
+
this.viewer.canvas.addEventListener("pointercancel", this.onPointerCancel);
|
|
1196
|
+
this.viewer.canvas.addEventListener("pointerleave", this.onPointerLeave);
|
|
1197
|
+
this.viewer.addEventListener("render", this.renderOverlay);
|
|
1198
|
+
this.viewer.addEventListener("hide", this.updateObjects);
|
|
1199
|
+
this.viewer.addEventListener("isolate", this.updateObjects);
|
|
1200
|
+
this.viewer.addEventListener("show", this.updateObjects);
|
|
1201
|
+
this.viewer.addEventListener("showall", this.updateObjects);
|
|
1202
|
+
this.viewer.addEventListener("changecameramode", this.updateSnapperCamera);
|
|
1203
|
+
this.viewer.addEventListener("optionschange", this.updateUnits);
|
|
1204
|
+
}
|
|
1205
|
+
dispose() {
|
|
1206
|
+
this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown);
|
|
1207
|
+
this.viewer.canvas.removeEventListener("pointermove", this.onPointerMove);
|
|
1208
|
+
this.viewer.canvas.removeEventListener("pointerup", this.onPointerUp);
|
|
1209
|
+
this.viewer.canvas.removeEventListener("pointercancel", this.onPointerCancel);
|
|
1210
|
+
this.viewer.canvas.removeEventListener("pointerleave", this.onPointerLeave);
|
|
1211
|
+
this.viewer.removeEventListener("render", this.renderOverlay);
|
|
1212
|
+
this.viewer.removeEventListener("hide", this.updateObjects);
|
|
1213
|
+
this.viewer.removeEventListener("isolate", this.updateObjects);
|
|
1214
|
+
this.viewer.removeEventListener("show", this.updateObjects);
|
|
1215
|
+
this.viewer.removeEventListener("showall", this.updateObjects);
|
|
1216
|
+
this.viewer.removeEventListener("changecameramode", this.updateSnapperCamera);
|
|
1217
|
+
this.viewer.removeEventListener("optionschange", this.updateUnits);
|
|
1118
1218
|
this.objects.length = 0;
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
this.camera = viewer.camera;
|
|
1123
|
-
this.clippingPlanes = viewer.renderer.clippingPlanes || [];
|
|
1219
|
+
this.overlay.detach();
|
|
1220
|
+
this.overlay.dispose();
|
|
1221
|
+
super.dispose();
|
|
1124
1222
|
}
|
|
1125
1223
|
}
|
|
1126
1224
|
class MeasureOverlay {
|
|
@@ -1140,6 +1238,9 @@ class MeasureOverlay {
|
|
|
1140
1238
|
this.projector = new MeasureProjector(camera, canvas);
|
|
1141
1239
|
this.resizeObserver = new ResizeObserver(this.resizeContainer);
|
|
1142
1240
|
}
|
|
1241
|
+
dispose() {
|
|
1242
|
+
this.clear();
|
|
1243
|
+
}
|
|
1143
1244
|
attach() {
|
|
1144
1245
|
this.container = document.createElement("div");
|
|
1145
1246
|
this.container.id = "measure-container";
|
|
@@ -1152,9 +1253,6 @@ class MeasureOverlay {
|
|
|
1152
1253
|
this.canvas.parentElement.appendChild(this.container);
|
|
1153
1254
|
this.resizeObserver.observe(this.canvas);
|
|
1154
1255
|
}
|
|
1155
|
-
dispose() {
|
|
1156
|
-
this.clear();
|
|
1157
|
-
}
|
|
1158
1256
|
detach() {
|
|
1159
1257
|
this.resizeObserver.disconnect();
|
|
1160
1258
|
this.container.remove();
|
|
@@ -1162,7 +1260,7 @@ class MeasureOverlay {
|
|
|
1162
1260
|
}
|
|
1163
1261
|
clear() {
|
|
1164
1262
|
this.lines.forEach((line) => line.dispose());
|
|
1165
|
-
this.lines =
|
|
1263
|
+
this.lines.length = 0;
|
|
1166
1264
|
}
|
|
1167
1265
|
render() {
|
|
1168
1266
|
this.projector.setFromCamera(this.camera);
|
|
@@ -1177,13 +1275,18 @@ class MeasureOverlay {
|
|
|
1177
1275
|
removeLine(line) {
|
|
1178
1276
|
this.lines = this.lines.filter((x) => x !== line);
|
|
1179
1277
|
}
|
|
1278
|
+
updateLineUnits(scale, units, precision) {
|
|
1279
|
+
this.lines.forEach((line) => {
|
|
1280
|
+
line.scale = scale;
|
|
1281
|
+
line.units = units;
|
|
1282
|
+
line.precision = precision;
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1180
1285
|
}
|
|
1181
1286
|
const _middlePoint = new Vector3();
|
|
1182
1287
|
class MeasureLine {
|
|
1183
|
-
constructor(overlay) {
|
|
1288
|
+
constructor(overlay, scale, units, precision) {
|
|
1184
1289
|
this.id = MathUtils.generateUUID();
|
|
1185
|
-
this.unit = "";
|
|
1186
|
-
this.scale = 1.0;
|
|
1187
1290
|
this.size = 10.0;
|
|
1188
1291
|
this.lineWidth = 2;
|
|
1189
1292
|
this.style = {
|
|
@@ -1194,6 +1297,9 @@ class MeasureLine {
|
|
|
1194
1297
|
font: "1rem system-ui",
|
|
1195
1298
|
};
|
|
1196
1299
|
this.overlay = overlay;
|
|
1300
|
+
this.scale = scale;
|
|
1301
|
+
this.units = units;
|
|
1302
|
+
this.precision = precision;
|
|
1197
1303
|
this.elementStartPoint = overlay.container.appendChild(document.createElement("div"));
|
|
1198
1304
|
this.elementEndPoint = overlay.container.appendChild(document.createElement("div"));
|
|
1199
1305
|
this.elementLine = overlay.container.appendChild(document.createElement("div"));
|
|
@@ -1248,10 +1354,10 @@ class MeasureLine {
|
|
|
1248
1354
|
_middlePoint.lerpVectors(this.startPoint, this.endPoint, 0.5);
|
|
1249
1355
|
const { point, visible } = projector.projectPoint(_middlePoint);
|
|
1250
1356
|
const distance = this.getDistance();
|
|
1251
|
-
this.elementLabel.style.display = visible && distance
|
|
1357
|
+
this.elementLabel.style.display = visible && distance > 0 ? "block" : "none";
|
|
1252
1358
|
this.elementLabel.style.left = `${point.x}px`;
|
|
1253
1359
|
this.elementLabel.style.top = `${point.y}px`;
|
|
1254
|
-
this.elementLabel.innerHTML =
|
|
1360
|
+
this.elementLabel.innerHTML = formatDistance(distance, this.units, this.precision);
|
|
1255
1361
|
}
|
|
1256
1362
|
else {
|
|
1257
1363
|
this.elementLabel.style.display = "none";
|
|
@@ -2055,7 +2161,8 @@ function clearSelected(viewer) {
|
|
|
2055
2161
|
const selection = viewer.getComponent("SelectionComponent");
|
|
2056
2162
|
selection.clearSelection();
|
|
2057
2163
|
viewer.update();
|
|
2058
|
-
viewer.emitEvent({ type: "select",
|
|
2164
|
+
viewer.emitEvent({ type: "select", handles: [] });
|
|
2165
|
+
viewer.emitEvent({ type: "select2", handles: [] });
|
|
2059
2166
|
}
|
|
2060
2167
|
|
|
2061
2168
|
function clearSlices(viewer) {
|
|
@@ -2144,22 +2251,31 @@ function getDefaultViewPositions() {
|
|
|
2144
2251
|
}
|
|
2145
2252
|
|
|
2146
2253
|
function getModels(viewer) {
|
|
2147
|
-
return viewer.models.map((model) => model.
|
|
2254
|
+
return viewer.models.map((model) => model.id);
|
|
2148
2255
|
}
|
|
2149
2256
|
|
|
2150
2257
|
function getSelected(viewer) {
|
|
2151
|
-
const
|
|
2152
|
-
|
|
2258
|
+
const handles2 = viewer.executeCommand("getSelected2");
|
|
2259
|
+
const handles = handles2.map((handle) => handle.slice(handle.indexOf(":") + 1));
|
|
2153
2260
|
return handles;
|
|
2154
2261
|
}
|
|
2155
2262
|
|
|
2263
|
+
function getSelected2(viewer) {
|
|
2264
|
+
const handles2 = [];
|
|
2265
|
+
viewer.models.forEach((model) => {
|
|
2266
|
+
handles2.push(...model.getHandlesByObjects(viewer.selected));
|
|
2267
|
+
});
|
|
2268
|
+
return handles2;
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2156
2271
|
function hideSelected(viewer) {
|
|
2157
2272
|
viewer.models.forEach((model) => model.hideObjects(viewer.selected));
|
|
2158
2273
|
const selection = viewer.getComponent("SelectionComponent");
|
|
2159
2274
|
selection.clearSelection();
|
|
2160
2275
|
viewer.update();
|
|
2161
2276
|
viewer.emitEvent({ type: "hide" });
|
|
2162
|
-
viewer.emitEvent({ type: "select",
|
|
2277
|
+
viewer.emitEvent({ type: "select", handles: [] });
|
|
2278
|
+
viewer.emitEvent({ type: "select2", handles: [] });
|
|
2163
2279
|
}
|
|
2164
2280
|
|
|
2165
2281
|
function isolateSelected(viewer) {
|
|
@@ -2186,14 +2302,13 @@ function resetView(viewer) {
|
|
|
2186
2302
|
viewer.emit({ type: "resetview" });
|
|
2187
2303
|
}
|
|
2188
2304
|
|
|
2189
|
-
function selectModel(viewer,
|
|
2305
|
+
function selectModel(viewer, id) {
|
|
2190
2306
|
const selection = viewer.getComponent("SelectionComponent");
|
|
2191
2307
|
selection.clearSelection();
|
|
2192
|
-
viewer.models
|
|
2193
|
-
.filter((model) => model.handle === handle)
|
|
2194
|
-
.forEach((model) => selection.select(model.getObjects(), model));
|
|
2308
|
+
viewer.models.filter((model) => model.id === id).forEach((model) => selection.select(model.getObjects(), model));
|
|
2195
2309
|
viewer.update();
|
|
2196
|
-
viewer.
|
|
2310
|
+
viewer.emitEvent({ type: "select", handles: viewer.getSelected() });
|
|
2311
|
+
viewer.emitEvent({ type: "select2", handles: viewer.getSelected2() });
|
|
2197
2312
|
}
|
|
2198
2313
|
|
|
2199
2314
|
function setActiveDragger(viewer, dragger = "") {
|
|
@@ -2205,16 +2320,31 @@ function setMarkupColor(viewer, r = 255, g = 0, b = 0) {
|
|
|
2205
2320
|
}
|
|
2206
2321
|
|
|
2207
2322
|
function setSelected(viewer, handles = []) {
|
|
2208
|
-
const
|
|
2209
|
-
|
|
2323
|
+
const handles2 = [];
|
|
2324
|
+
handles.forEach((handle) => {
|
|
2325
|
+
if (handle.includes(":")) {
|
|
2326
|
+
handles2.push(handle);
|
|
2327
|
+
}
|
|
2328
|
+
else
|
|
2329
|
+
viewer.models.forEach((model) => {
|
|
2330
|
+
handles2.push(`${model.id}:${handle}`);
|
|
2331
|
+
});
|
|
2332
|
+
});
|
|
2333
|
+
viewer.executeCommand("setSelected2", handles2);
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
function setSelected2(viewer, handles = []) {
|
|
2337
|
+
const selectionComponent = viewer.getComponent("SelectionComponent");
|
|
2338
|
+
selectionComponent.clearSelection();
|
|
2210
2339
|
viewer.models.forEach((model) => {
|
|
2211
2340
|
const objects = model.getObjectsByHandles(handles);
|
|
2212
2341
|
model.showObjects(objects);
|
|
2213
|
-
|
|
2342
|
+
selectionComponent.select(objects, model);
|
|
2214
2343
|
});
|
|
2215
2344
|
viewer.update();
|
|
2216
2345
|
viewer.emitEvent({ type: "show" });
|
|
2217
|
-
viewer.emitEvent({ type: "select", data: undefined, handles });
|
|
2346
|
+
viewer.emitEvent({ type: "select", data: undefined, handles: viewer.getSelected() });
|
|
2347
|
+
viewer.emitEvent({ type: "select2", data: undefined, handles });
|
|
2218
2348
|
}
|
|
2219
2349
|
|
|
2220
2350
|
function showAll(viewer) {
|
|
@@ -2228,21 +2358,19 @@ function zoomToExtents(viewer) {
|
|
|
2228
2358
|
}
|
|
2229
2359
|
|
|
2230
2360
|
function zoomToObjects(viewer, handles = []) {
|
|
2231
|
-
const
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
if (handleSet.has((_a = child.userData) === null || _a === void 0 ? void 0 : _a.handle))
|
|
2236
|
-
objects.push(child);
|
|
2361
|
+
const extents = new Box3();
|
|
2362
|
+
viewer.models.forEach((model) => {
|
|
2363
|
+
const objects = model.getObjectsByHandles(handles);
|
|
2364
|
+
objects.forEach((object) => extents.expandByObject(object));
|
|
2237
2365
|
});
|
|
2238
|
-
const extents = objects.reduce((result, object) => result.expandByObject(object), new Box3());
|
|
2239
2366
|
if (extents.isEmpty())
|
|
2240
2367
|
extents.copy(viewer.extents);
|
|
2241
2368
|
zoomTo(viewer, extents);
|
|
2242
2369
|
}
|
|
2243
2370
|
|
|
2244
2371
|
function zoomToSelected(viewer) {
|
|
2245
|
-
const extents =
|
|
2372
|
+
const extents = new Box3();
|
|
2373
|
+
viewer.selected.forEach((object) => extents.expandByObject(object));
|
|
2246
2374
|
if (extents.isEmpty())
|
|
2247
2375
|
extents.copy(viewer.extents);
|
|
2248
2376
|
zoomTo(viewer, extents);
|
|
@@ -2259,6 +2387,7 @@ commands.registerCommand("explode", explode);
|
|
|
2259
2387
|
commands.registerCommand("getDefaultViewPositions", getDefaultViewPositions);
|
|
2260
2388
|
commands.registerCommand("getModels", getModels);
|
|
2261
2389
|
commands.registerCommand("getSelected", getSelected);
|
|
2390
|
+
commands.registerCommand("getSelected2", getSelected2);
|
|
2262
2391
|
commands.registerCommand("hideSelected", hideSelected);
|
|
2263
2392
|
commands.registerCommand("isolateSelected", isolateSelected);
|
|
2264
2393
|
commands.registerCommand("regenerateAll", regenerateAll);
|
|
@@ -2268,6 +2397,7 @@ commands.registerCommand("setActiveDragger", setActiveDragger);
|
|
|
2268
2397
|
commands.registerCommand("setDefaultViewPosition", setDefaultViewPosition);
|
|
2269
2398
|
commands.registerCommand("setMarkupColor", setMarkupColor);
|
|
2270
2399
|
commands.registerCommand("setSelected", setSelected);
|
|
2400
|
+
commands.registerCommand("setSelected2", setSelected2);
|
|
2271
2401
|
commands.registerCommand("showAll", showAll);
|
|
2272
2402
|
commands.registerCommand("zoomToExtents", zoomToExtents);
|
|
2273
2403
|
commands.registerCommand("zoomToObjects", zoomToObjects);
|
|
@@ -2320,6 +2450,10 @@ class CameraComponent {
|
|
|
2320
2450
|
this.switchCameraMode(this.viewer.options.cameraMode);
|
|
2321
2451
|
};
|
|
2322
2452
|
this.geometryEnd = () => {
|
|
2453
|
+
if (this.viewer.models.length > 1) {
|
|
2454
|
+
this.switchCamera(this.viewer.camera);
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2323
2457
|
let camera;
|
|
2324
2458
|
this.viewer.scene.traverse((object) => {
|
|
2325
2459
|
if (object.isCamera)
|
|
@@ -2417,6 +2551,8 @@ class ExtentsComponent {
|
|
|
2417
2551
|
const extents = new Box3();
|
|
2418
2552
|
this.viewer.models.forEach((model) => model.getExtents(extents));
|
|
2419
2553
|
this.viewer.extents.copy(extents);
|
|
2554
|
+
if (this.viewer.models.length > 1)
|
|
2555
|
+
return;
|
|
2420
2556
|
this.viewer.extents.getCenter(this.viewer.target);
|
|
2421
2557
|
};
|
|
2422
2558
|
this.viewer = viewer;
|
|
@@ -2703,8 +2839,9 @@ class HighlighterComponent {
|
|
|
2703
2839
|
});
|
|
2704
2840
|
}
|
|
2705
2841
|
syncHighlightColors() {
|
|
2706
|
-
const
|
|
2707
|
-
const {
|
|
2842
|
+
const options = this.viewer.options.enableCustomHighlight ? this.viewer.options : Options.defaults();
|
|
2843
|
+
const { facesColor, facesTransparancy, facesOverlap } = options;
|
|
2844
|
+
const { edgesColor, edgesVisibility, edgesOverlap } = options;
|
|
2708
2845
|
this.facesMaterial.color.setRGB(facesColor.r / 255, facesColor.g / 255, facesColor.b / 255);
|
|
2709
2846
|
this.facesMaterial.opacity = (255 - facesTransparancy) / 255;
|
|
2710
2847
|
this.facesMaterial.depthTest = !facesOverlap;
|
|
@@ -2743,10 +2880,11 @@ class SelectionComponent {
|
|
|
2743
2880
|
const upPosition = this.getMousePosition(event, new Vector2());
|
|
2744
2881
|
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
2745
2882
|
return;
|
|
2883
|
+
const snapper = new Snapper(this.viewer.camera, this.viewer.renderer, this.viewer.canvas);
|
|
2746
2884
|
let intersections = [];
|
|
2747
2885
|
this.viewer.models.forEach((model) => {
|
|
2748
2886
|
const objects = model.getVisibleObjects();
|
|
2749
|
-
const intersects =
|
|
2887
|
+
const intersects = snapper.getPointerIntersects(upPosition, objects);
|
|
2750
2888
|
if (intersects.length > 0)
|
|
2751
2889
|
intersections.push({ ...intersects[0], model });
|
|
2752
2890
|
});
|
|
@@ -2764,6 +2902,7 @@ class SelectionComponent {
|
|
|
2764
2902
|
}
|
|
2765
2903
|
this.viewer.update();
|
|
2766
2904
|
this.viewer.emitEvent({ type: "select", data: undefined, handles: this.viewer.getSelected() });
|
|
2905
|
+
this.viewer.emitEvent({ type: "select2", data: undefined, handles: this.viewer.getSelected2() });
|
|
2767
2906
|
};
|
|
2768
2907
|
this.onDoubleClick = (event) => {
|
|
2769
2908
|
if (event.button !== 0)
|
|
@@ -2774,7 +2913,6 @@ class SelectionComponent {
|
|
|
2774
2913
|
this.highlighter = this.viewer.getComponent("HighlighterComponent");
|
|
2775
2914
|
};
|
|
2776
2915
|
this.viewer = viewer;
|
|
2777
|
-
this.raycaster = new Raycaster();
|
|
2778
2916
|
this.downPosition = new Vector2();
|
|
2779
2917
|
this.viewer.addEventListener("pointerdown", this.onPointerDown);
|
|
2780
2918
|
this.viewer.addEventListener("pointerup", this.onPointerUp);
|
|
@@ -2790,26 +2928,6 @@ class SelectionComponent {
|
|
|
2790
2928
|
getMousePosition(event, target) {
|
|
2791
2929
|
return target.set(event.clientX, event.clientY);
|
|
2792
2930
|
}
|
|
2793
|
-
getPointerIntersects(mouse, objects) {
|
|
2794
|
-
const rect = this.viewer.canvas.getBoundingClientRect();
|
|
2795
|
-
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
2796
|
-
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
2797
|
-
const coords = new Vector2(x, y);
|
|
2798
|
-
this.raycaster.setFromCamera(coords, this.viewer.camera);
|
|
2799
|
-
this.raycaster.params = {
|
|
2800
|
-
Mesh: {},
|
|
2801
|
-
Line: { threshold: 0.05 },
|
|
2802
|
-
Line2: { threshold: 0.05 },
|
|
2803
|
-
LOD: {},
|
|
2804
|
-
Points: { threshold: 0.01 },
|
|
2805
|
-
Sprite: {},
|
|
2806
|
-
};
|
|
2807
|
-
let intersects = this.raycaster.intersectObjects(objects, false);
|
|
2808
|
-
(this.viewer.renderer.clippingPlanes || []).forEach((plane) => {
|
|
2809
|
-
intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
|
|
2810
|
-
});
|
|
2811
|
-
return intersects;
|
|
2812
|
-
}
|
|
2813
2931
|
select(objects, model) {
|
|
2814
2932
|
if (!model) {
|
|
2815
2933
|
this.viewer.models.forEach((model) => this.select(objects, model));
|
|
@@ -3008,48 +3126,8 @@ components.registerComponent("SelectionComponent", (viewer) => new SelectionComp
|
|
|
3008
3126
|
components.registerComponent("WCSHelperComponent", (viewer) => new WCSHelperComponent(viewer));
|
|
3009
3127
|
components.registerComponent("ResetComponent", (viewer) => new ResetComponent(viewer));
|
|
3010
3128
|
|
|
3011
|
-
class GLTFLoadingManager extends LoadingManager {
|
|
3012
|
-
constructor(file, params = {}) {
|
|
3013
|
-
super();
|
|
3014
|
-
this.path = "";
|
|
3015
|
-
this.resourcePath = "";
|
|
3016
|
-
this.fileURL = "";
|
|
3017
|
-
this.dataURLs = new Map();
|
|
3018
|
-
this.path = params.path || "";
|
|
3019
|
-
const externalFiles = params.externalFiles || new Map();
|
|
3020
|
-
if (typeof file === "string") {
|
|
3021
|
-
this.fileURL = file;
|
|
3022
|
-
this.resourcePath = LoaderUtils.extractUrlBase(file);
|
|
3023
|
-
}
|
|
3024
|
-
else {
|
|
3025
|
-
externalFiles.forEach((value, key) => (this.fileURL = value === file ? key : this.fileURL));
|
|
3026
|
-
externalFiles.set(this.fileURL, file);
|
|
3027
|
-
}
|
|
3028
|
-
externalFiles.forEach((value, key) => {
|
|
3029
|
-
let dataURL;
|
|
3030
|
-
if (typeof value === "string")
|
|
3031
|
-
dataURL = value;
|
|
3032
|
-
else
|
|
3033
|
-
dataURL = URL.createObjectURL(new Blob([value]));
|
|
3034
|
-
this.dataURLs.set(key, dataURL);
|
|
3035
|
-
});
|
|
3036
|
-
this.setURLModifier((url) => {
|
|
3037
|
-
const key = decodeURI(url)
|
|
3038
|
-
.replace(this.path, "")
|
|
3039
|
-
.replace(this.resourcePath, "")
|
|
3040
|
-
.replace(/^(\.?\/)/, "");
|
|
3041
|
-
const dataURL = this.dataURLs.get(key);
|
|
3042
|
-
return dataURL !== null && dataURL !== void 0 ? dataURL : url;
|
|
3043
|
-
});
|
|
3044
|
-
}
|
|
3045
|
-
dispose() {
|
|
3046
|
-
this.dataURLs.forEach(URL.revokeObjectURL);
|
|
3047
|
-
}
|
|
3048
|
-
}
|
|
3049
|
-
|
|
3050
3129
|
class ModelImpl {
|
|
3051
3130
|
constructor(scene) {
|
|
3052
|
-
this.handle = "1";
|
|
3053
3131
|
this.scene = scene;
|
|
3054
3132
|
}
|
|
3055
3133
|
dispose() {
|
|
@@ -3069,6 +3147,18 @@ class ModelImpl {
|
|
|
3069
3147
|
this.scene.traverse(disposeObject);
|
|
3070
3148
|
this.scene.clear();
|
|
3071
3149
|
}
|
|
3150
|
+
getUnits() {
|
|
3151
|
+
return "Meters";
|
|
3152
|
+
}
|
|
3153
|
+
getUnitScale() {
|
|
3154
|
+
return convertUnits(this.getUnits(), "Meters", 1);
|
|
3155
|
+
}
|
|
3156
|
+
getUnitString() {
|
|
3157
|
+
return getDisplayUnit(this.getUnits());
|
|
3158
|
+
}
|
|
3159
|
+
getPrecision() {
|
|
3160
|
+
return 2;
|
|
3161
|
+
}
|
|
3072
3162
|
getExtents(target) {
|
|
3073
3163
|
this.scene.traverseVisible((object) => !object.children.length && target.expandByObject(object));
|
|
3074
3164
|
return target;
|
|
@@ -3091,27 +3181,45 @@ class ModelImpl {
|
|
|
3091
3181
|
}
|
|
3092
3182
|
return false;
|
|
3093
3183
|
}
|
|
3184
|
+
hasHandle(handle) {
|
|
3185
|
+
return !handle.includes(":") || handle.split(":", 1)[0] === this.id + "";
|
|
3186
|
+
}
|
|
3094
3187
|
getOwnObjects(objects) {
|
|
3095
3188
|
if (!Array.isArray(objects))
|
|
3096
3189
|
objects = [objects];
|
|
3097
3190
|
return objects.filter((object) => this.hasObject(object));
|
|
3098
3191
|
}
|
|
3192
|
+
getOwnHandles(handles) {
|
|
3193
|
+
if (!Array.isArray(handles))
|
|
3194
|
+
handles = [handles];
|
|
3195
|
+
return handles.filter((handle) => this.hasHandle(handle));
|
|
3196
|
+
}
|
|
3099
3197
|
getObjectsByHandles(handles) {
|
|
3100
|
-
const
|
|
3198
|
+
const ownHandles = this.getOwnHandles(handles);
|
|
3199
|
+
if (ownHandles.length === 0)
|
|
3200
|
+
return [];
|
|
3201
|
+
const handleSet = new Set(ownHandles.map((handle) => handle.slice(handle.indexOf(":") + 1)));
|
|
3101
3202
|
const objects = [];
|
|
3102
|
-
this.scene.traverse((object) =>
|
|
3203
|
+
this.scene.traverse((object) => {
|
|
3204
|
+
const handle = object.userData.handle;
|
|
3205
|
+
if (handle && handleSet.has(handle))
|
|
3206
|
+
objects.push(object);
|
|
3207
|
+
});
|
|
3103
3208
|
return objects;
|
|
3104
3209
|
}
|
|
3105
3210
|
getHandlesByObjects(objects) {
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3211
|
+
const ownObjects = this.getOwnObjects(objects);
|
|
3212
|
+
if (ownObjects.length === 0)
|
|
3213
|
+
return [];
|
|
3214
|
+
const handleSet = new Set();
|
|
3215
|
+
ownObjects.forEach((object) => {
|
|
3216
|
+
const handle = object.userData.handle;
|
|
3217
|
+
if (handle)
|
|
3218
|
+
handleSet.add(`${this.id}:${handle}`);
|
|
3219
|
+
});
|
|
3220
|
+
return Array.from(handleSet);
|
|
3111
3221
|
}
|
|
3112
3222
|
hideObjects(objects) {
|
|
3113
|
-
if (!Array.isArray(objects))
|
|
3114
|
-
objects = [objects];
|
|
3115
3223
|
this.getOwnObjects(objects).forEach((object) => (object.visible = false));
|
|
3116
3224
|
return this;
|
|
3117
3225
|
}
|
|
@@ -3127,8 +3235,6 @@ class ModelImpl {
|
|
|
3127
3235
|
return this;
|
|
3128
3236
|
}
|
|
3129
3237
|
showObjects(objects) {
|
|
3130
|
-
if (!Array.isArray(objects))
|
|
3131
|
-
objects = [objects];
|
|
3132
3238
|
this.getOwnObjects(objects).forEach((object) => {
|
|
3133
3239
|
object.visible = true;
|
|
3134
3240
|
object.traverseAncestors((parent) => (parent.visible = true));
|
|
@@ -3184,42 +3290,6 @@ class ModelImpl {
|
|
|
3184
3290
|
}
|
|
3185
3291
|
}
|
|
3186
3292
|
|
|
3187
|
-
class GLTFFileLoader extends Loader {
|
|
3188
|
-
constructor(viewer) {
|
|
3189
|
-
super();
|
|
3190
|
-
this.viewer = viewer;
|
|
3191
|
-
}
|
|
3192
|
-
isSupport(file, format) {
|
|
3193
|
-
return ((typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
|
|
3194
|
-
/(gltf|glb)$/i.test(format));
|
|
3195
|
-
}
|
|
3196
|
-
async load(file, format, params) {
|
|
3197
|
-
const manager = new GLTFLoadingManager(file, params);
|
|
3198
|
-
const loader = new GLTFLoader(manager);
|
|
3199
|
-
loader.setPath(manager.path);
|
|
3200
|
-
loader.setCrossOrigin(params.crossOrigin || loader.crossOrigin);
|
|
3201
|
-
loader.setWithCredentials(params.withCredentials || loader.withCredentials);
|
|
3202
|
-
const progress = (event) => {
|
|
3203
|
-
const { lengthComputable, loaded, total } = event;
|
|
3204
|
-
const progress = lengthComputable ? loaded / total : 1;
|
|
3205
|
-
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
|
|
3206
|
-
};
|
|
3207
|
-
const gltf = await loader.loadAsync(manager.fileURL, progress);
|
|
3208
|
-
if (!this.viewer.scene)
|
|
3209
|
-
return this;
|
|
3210
|
-
const modelImpl = new ModelImpl(gltf.scene);
|
|
3211
|
-
modelImpl.loader = this;
|
|
3212
|
-
modelImpl.viewer = this.viewer;
|
|
3213
|
-
this.viewer.scene.add(gltf.scene);
|
|
3214
|
-
this.viewer.models.push(modelImpl);
|
|
3215
|
-
this.viewer.syncOptions();
|
|
3216
|
-
this.viewer.syncOverlay();
|
|
3217
|
-
this.viewer.update();
|
|
3218
|
-
this.viewer.emitEvent({ type: "databasechunk", data: gltf.scene, file });
|
|
3219
|
-
return this;
|
|
3220
|
-
}
|
|
3221
|
-
}
|
|
3222
|
-
|
|
3223
3293
|
class DynamicModelImpl extends ModelImpl {
|
|
3224
3294
|
getExtents(target) {
|
|
3225
3295
|
return target.union(this.gltfLoader.getTotalGeometryExtent());
|
|
@@ -3238,31 +3308,40 @@ class DynamicModelImpl extends ModelImpl {
|
|
|
3238
3308
|
return this.gltfLoader.originalObjects.has(object);
|
|
3239
3309
|
}
|
|
3240
3310
|
getObjectsByHandles(handles) {
|
|
3241
|
-
const
|
|
3311
|
+
const ownHandles = this.getOwnHandles(handles);
|
|
3312
|
+
if (ownHandles.length === 0)
|
|
3313
|
+
return [];
|
|
3314
|
+
const handlesSet = new Set(ownHandles);
|
|
3242
3315
|
const objects = [];
|
|
3243
3316
|
handlesSet.forEach((handle) => {
|
|
3244
|
-
|
|
3245
|
-
const handles = this.gltfLoader.handleToObjects.get(handle2) || [];
|
|
3246
|
-
objects.push(...Array.from(handles));
|
|
3317
|
+
objects.push(...this.gltfLoader.getObjectsByHandle(handle));
|
|
3247
3318
|
});
|
|
3248
3319
|
return objects;
|
|
3249
3320
|
}
|
|
3250
3321
|
getHandlesByObjects(objects) {
|
|
3251
|
-
const
|
|
3252
|
-
|
|
3322
|
+
const ownObjects = this.getOwnObjects(objects);
|
|
3323
|
+
if (ownObjects.length === 0)
|
|
3324
|
+
return [];
|
|
3325
|
+
const handleSet = new Set();
|
|
3326
|
+
ownObjects.forEach((object) => {
|
|
3327
|
+
const handle = object.userData.handle;
|
|
3328
|
+
if (handle)
|
|
3329
|
+
handleSet.add(handle);
|
|
3330
|
+
});
|
|
3331
|
+
return Array.from(handleSet);
|
|
3253
3332
|
}
|
|
3254
3333
|
hideObjects(objects) {
|
|
3255
|
-
const handles =
|
|
3334
|
+
const handles = this.getHandlesByObjects(objects);
|
|
3256
3335
|
this.gltfLoader.hideObjects(handles);
|
|
3257
3336
|
return this;
|
|
3258
3337
|
}
|
|
3259
3338
|
isolateObjects(objects) {
|
|
3260
|
-
const handles =
|
|
3339
|
+
const handles = this.getHandlesByObjects(objects);
|
|
3261
3340
|
this.gltfLoader.isolateObjects(new Set(handles));
|
|
3262
3341
|
return this;
|
|
3263
3342
|
}
|
|
3264
3343
|
showObjects(objects) {
|
|
3265
|
-
const handles =
|
|
3344
|
+
const handles = this.getHandlesByObjects(objects);
|
|
3266
3345
|
this.gltfLoader.showObjects(handles);
|
|
3267
3346
|
return this;
|
|
3268
3347
|
}
|
|
@@ -3326,11 +3405,14 @@ class GltfStructure {
|
|
|
3326
3405
|
this.materials = new Map();
|
|
3327
3406
|
this.textureCache = new Map();
|
|
3328
3407
|
this.materialCache = new Map();
|
|
3408
|
+
this.uri = "";
|
|
3409
|
+
this._nextObjectId = 0;
|
|
3329
3410
|
}
|
|
3330
3411
|
async initialize(loader) {
|
|
3331
3412
|
this.json = await this.loadController.loadJson();
|
|
3332
3413
|
this.baseUrl = await this.loadController.baseUrl();
|
|
3333
3414
|
this.loader = loader;
|
|
3415
|
+
this.uri = this.json.buffers[0].uri || "";
|
|
3334
3416
|
}
|
|
3335
3417
|
clear() {
|
|
3336
3418
|
this.json = null;
|
|
@@ -3424,7 +3506,7 @@ class GltfStructure {
|
|
|
3424
3506
|
await this.loader.waitForChunkSlot();
|
|
3425
3507
|
try {
|
|
3426
3508
|
const length = range.end - range.start;
|
|
3427
|
-
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }]);
|
|
3509
|
+
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }], this.uri);
|
|
3428
3510
|
for (const req of range.requests) {
|
|
3429
3511
|
const relOffset = req.offset - range.start;
|
|
3430
3512
|
try {
|
|
@@ -3741,6 +3823,7 @@ class GltfStructure {
|
|
|
3741
3823
|
}
|
|
3742
3824
|
}
|
|
3743
3825
|
|
|
3826
|
+
const STRUCTURE_ID_SEPARATOR = ":";
|
|
3744
3827
|
class DynamicGltfLoader {
|
|
3745
3828
|
constructor(camera, scene, renderer) {
|
|
3746
3829
|
this.camera = camera;
|
|
@@ -3753,6 +3836,7 @@ class DynamicGltfLoader {
|
|
|
3753
3836
|
geometryerror: [],
|
|
3754
3837
|
update: [],
|
|
3755
3838
|
geometrymemory: [],
|
|
3839
|
+
optimizationprogress: [],
|
|
3756
3840
|
};
|
|
3757
3841
|
this.loadDistance = 100;
|
|
3758
3842
|
this.unloadDistance = 150;
|
|
@@ -3794,7 +3878,6 @@ class DynamicGltfLoader {
|
|
|
3794
3878
|
this.hiddenHandles = new Set();
|
|
3795
3879
|
this.newOptimizedObjects = new Set();
|
|
3796
3880
|
this.oldOptimizeObjects = new Set();
|
|
3797
|
-
this.maxConcurrentChunks = 8;
|
|
3798
3881
|
this.activeChunkLoads = 0;
|
|
3799
3882
|
this.chunkQueue = [];
|
|
3800
3883
|
this.objectIdToIndex = new Map();
|
|
@@ -3803,6 +3886,7 @@ class DynamicGltfLoader {
|
|
|
3803
3886
|
this.maxConcurrentChunks = 6;
|
|
3804
3887
|
this.mergedObjectMap = new Map();
|
|
3805
3888
|
this.mergedGeometryVisibility = new Map();
|
|
3889
|
+
this._webglInfoCache = null;
|
|
3806
3890
|
}
|
|
3807
3891
|
setVisibleEdges(visible) {
|
|
3808
3892
|
this.visibleEdges = visible;
|
|
@@ -3906,6 +3990,123 @@ class DynamicGltfLoader {
|
|
|
3906
3990
|
this.updateMemoryIndicator();
|
|
3907
3991
|
console.log(`Final memory usage: ${Math.round(currentMemoryUsage / (1024 * 1024))}MB`);
|
|
3908
3992
|
}
|
|
3993
|
+
getStats() {
|
|
3994
|
+
let totalObjects = 0;
|
|
3995
|
+
let renderedObjects = 0;
|
|
3996
|
+
let totalTriangles = 0;
|
|
3997
|
+
let renderedTriangles = 0;
|
|
3998
|
+
let totalLines = 0;
|
|
3999
|
+
let renderedLines = 0;
|
|
4000
|
+
let totalEdges = 0;
|
|
4001
|
+
let renderedEdges = 0;
|
|
4002
|
+
this.scene.traverse((object) => {
|
|
4003
|
+
totalObjects++;
|
|
4004
|
+
const geometry = object.geometry;
|
|
4005
|
+
if (!geometry) return;
|
|
4006
|
+
let triCount = 0;
|
|
4007
|
+
if (geometry.index) {
|
|
4008
|
+
triCount = Math.floor(geometry.index.count / 3);
|
|
4009
|
+
} else if (geometry.attributes && geometry.attributes.position) {
|
|
4010
|
+
triCount = Math.floor(geometry.attributes.position.count / 3);
|
|
4011
|
+
}
|
|
4012
|
+
totalTriangles += triCount;
|
|
4013
|
+
let lineCount = 0;
|
|
4014
|
+
if (geometry.index) {
|
|
4015
|
+
lineCount = Math.floor(geometry.index.count / 2);
|
|
4016
|
+
} else if (geometry.attributes && geometry.attributes.position) {
|
|
4017
|
+
lineCount = Math.floor(geometry.attributes.position.count / 2);
|
|
4018
|
+
}
|
|
4019
|
+
if (object.type === "Line" || object.type === "LineSegments" || object.type === "LineLoop") {
|
|
4020
|
+
if (object.userData.isEdge) {
|
|
4021
|
+
totalEdges += lineCount;
|
|
4022
|
+
} else {
|
|
4023
|
+
totalLines += lineCount;
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
4026
|
+
if (object.visible !== false) {
|
|
4027
|
+
if (object.isMesh || object.isLine || object.isPoints) {
|
|
4028
|
+
renderedObjects++;
|
|
4029
|
+
if (object.isMesh) {
|
|
4030
|
+
renderedTriangles += triCount;
|
|
4031
|
+
} else if (object.type === "Line" || object.type === "LineSegments" || object.type === "LineLoop") {
|
|
4032
|
+
if (object.userData.isEdge) {
|
|
4033
|
+
renderedEdges += lineCount;
|
|
4034
|
+
} else {
|
|
4035
|
+
renderedLines += lineCount;
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
4040
|
+
});
|
|
4041
|
+
const geometryCount = this.geometryCache ? this.geometryCache.size : 0;
|
|
4042
|
+
const geometryMemoryBytes = Array.from(this.geometryCache?.values?.() || []).reduce((a, b) => a + b, 0);
|
|
4043
|
+
const uniqueMaterialIds = new Set();
|
|
4044
|
+
const uniqueTextureIds = new Set();
|
|
4045
|
+
if (Array.isArray(this.structures)) {
|
|
4046
|
+
for (const structure of this.structures) {
|
|
4047
|
+
console.log(structure.materialCache.values());
|
|
4048
|
+
try {
|
|
4049
|
+
for (const entry of structure.materialCache.values()) {
|
|
4050
|
+
if (entry?.mesh?.uuid) uniqueMaterialIds.add(entry.mesh.uuid);
|
|
4051
|
+
if (entry?.points?.uuid) uniqueMaterialIds.add(entry.points.uuid);
|
|
4052
|
+
if (entry?.lines?.uuid) uniqueMaterialIds.add(entry.lines.uuid);
|
|
4053
|
+
}
|
|
4054
|
+
} catch (exp) {
|
|
4055
|
+
console.error("Error adding material to uniqueMaterialIds", exp);
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
const materialCount = uniqueMaterialIds.size;
|
|
4060
|
+
const textureCount = uniqueTextureIds.size;
|
|
4061
|
+
const estimatedGpuMemoryBytes = geometryMemoryBytes;
|
|
4062
|
+
if (!this._webglInfoCache) {
|
|
4063
|
+
try {
|
|
4064
|
+
const gl = this.renderer.getContext();
|
|
4065
|
+
const dbgInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
4066
|
+
if (dbgInfo) {
|
|
4067
|
+
const rendererStr = gl.getParameter(dbgInfo.UNMASKED_RENDERER_WEBGL);
|
|
4068
|
+
const vendorStr = gl.getParameter(dbgInfo.UNMASKED_VENDOR_WEBGL);
|
|
4069
|
+
this._webglInfoCache = { renderer: rendererStr, vendor: vendorStr };
|
|
4070
|
+
} else {
|
|
4071
|
+
this._webglInfoCache = { renderer: null, vendor: null };
|
|
4072
|
+
}
|
|
4073
|
+
} catch (e) {
|
|
4074
|
+
console.error("Error getting webgl info", e);
|
|
4075
|
+
this._webglInfoCache = { renderer: null, vendor: null };
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
4078
|
+
const size = new Vector2();
|
|
4079
|
+
if (this.renderer && this.renderer.getSize) {
|
|
4080
|
+
this.renderer.getSize(size);
|
|
4081
|
+
}
|
|
4082
|
+
return {
|
|
4083
|
+
scene: {
|
|
4084
|
+
beforeOptimization: {
|
|
4085
|
+
objects: totalObjects - renderedObjects,
|
|
4086
|
+
triangles: totalTriangles - renderedTriangles,
|
|
4087
|
+
lines: totalLines - renderedLines,
|
|
4088
|
+
edges: totalEdges - renderedEdges,
|
|
4089
|
+
},
|
|
4090
|
+
afterOptimization: {
|
|
4091
|
+
objects: renderedObjects,
|
|
4092
|
+
triangles: renderedTriangles,
|
|
4093
|
+
lines: renderedLines,
|
|
4094
|
+
edges: renderedEdges,
|
|
4095
|
+
},
|
|
4096
|
+
},
|
|
4097
|
+
memory: {
|
|
4098
|
+
geometries: { count: geometryCount, bytes: geometryMemoryBytes },
|
|
4099
|
+
textures: { count: textureCount },
|
|
4100
|
+
materials: { count: materialCount },
|
|
4101
|
+
totalEstimatedGpuBytes: estimatedGpuMemoryBytes,
|
|
4102
|
+
},
|
|
4103
|
+
system: {
|
|
4104
|
+
webglRenderer: this._webglInfoCache?.renderer || "",
|
|
4105
|
+
webglVendor: this._webglInfoCache?.vendor || "",
|
|
4106
|
+
viewport: { width: size.x || 0, height: size.y || 0 },
|
|
4107
|
+
},
|
|
4108
|
+
};
|
|
4109
|
+
}
|
|
3909
4110
|
async loadNode(nodeId, onLoadFinishCb) {
|
|
3910
4111
|
const node = this.nodes.get(nodeId);
|
|
3911
4112
|
if (!node || node.loaded || node.loading) return;
|
|
@@ -4076,7 +4277,7 @@ class DynamicGltfLoader {
|
|
|
4076
4277
|
if (node.handle) {
|
|
4077
4278
|
mesh.userData.handle = node.handle;
|
|
4078
4279
|
} else {
|
|
4079
|
-
mesh.userData.handle =
|
|
4280
|
+
mesh.userData.handle = this.getFullHandle(node.structure.id, mesh.userData.handle);
|
|
4080
4281
|
}
|
|
4081
4282
|
if (mesh.material.name === "edges") {
|
|
4082
4283
|
mesh.userData.isEdge = true;
|
|
@@ -4217,12 +4418,15 @@ class DynamicGltfLoader {
|
|
|
4217
4418
|
})),
|
|
4218
4419
|
});
|
|
4219
4420
|
}
|
|
4421
|
+
getFullHandle(structureId, originalHandle) {
|
|
4422
|
+
return `${structureId}${STRUCTURE_ID_SEPARATOR}${originalHandle}`;
|
|
4423
|
+
}
|
|
4220
4424
|
async processNodeHierarchy(structure, nodeId, parentGroup) {
|
|
4221
4425
|
const nodeDef = structure.json.nodes[nodeId];
|
|
4222
4426
|
let nodeGroup = null;
|
|
4223
4427
|
let handle = null;
|
|
4224
4428
|
if (nodeDef.extras?.handle) {
|
|
4225
|
-
handle =
|
|
4429
|
+
handle = this.getFullHandle(structure.id, nodeDef.extras.handle);
|
|
4226
4430
|
}
|
|
4227
4431
|
if (nodeDef.camera !== undefined) {
|
|
4228
4432
|
const camera = this.loadCamera(structure, nodeDef.camera, nodeDef);
|
|
@@ -4239,7 +4443,7 @@ class DynamicGltfLoader {
|
|
|
4239
4443
|
if (nodeDef.extras) {
|
|
4240
4444
|
nodeGroup.userData = { ...nodeDef.extras };
|
|
4241
4445
|
if (nodeGroup.userData.handle) {
|
|
4242
|
-
nodeGroup.userData.handle =
|
|
4446
|
+
nodeGroup.userData.handle = this.getFullHandle(structure.id, nodeGroup.userData.handle);
|
|
4243
4447
|
}
|
|
4244
4448
|
}
|
|
4245
4449
|
if (nodeDef.matrix) {
|
|
@@ -4284,7 +4488,7 @@ class DynamicGltfLoader {
|
|
|
4284
4488
|
this.edgeNodes.push(uniqueNodeId);
|
|
4285
4489
|
}
|
|
4286
4490
|
if (meshDef.extras && meshDef.extras.handle) {
|
|
4287
|
-
handle =
|
|
4491
|
+
handle = this.getFullHandle(structure.id, meshDef.extras.handle);
|
|
4288
4492
|
}
|
|
4289
4493
|
this.nodes.set(uniqueNodeId, {
|
|
4290
4494
|
position: nodeGroup ? nodeGroup.position.clone() : new Vector3().setFromMatrixPosition(nodeMatrix),
|
|
@@ -4297,7 +4501,7 @@ class DynamicGltfLoader {
|
|
|
4297
4501
|
structure,
|
|
4298
4502
|
extras: nodeDef.extras,
|
|
4299
4503
|
geometryExtents,
|
|
4300
|
-
handle,
|
|
4504
|
+
handle: handle || this.getFullHandle(structure.id, structure._nextObjectId++),
|
|
4301
4505
|
});
|
|
4302
4506
|
}
|
|
4303
4507
|
if (nodeDef.children) {
|
|
@@ -4370,12 +4574,12 @@ class DynamicGltfLoader {
|
|
|
4370
4574
|
}
|
|
4371
4575
|
}
|
|
4372
4576
|
async loadNodes() {
|
|
4373
|
-
console.time("
|
|
4577
|
+
console.time("Process nodes");
|
|
4374
4578
|
await this.processNodes();
|
|
4375
|
-
console.timeEnd("
|
|
4376
|
-
console.time("
|
|
4579
|
+
console.timeEnd("Process nodes");
|
|
4580
|
+
console.time("Optimize scene");
|
|
4377
4581
|
await this.optimizeScene();
|
|
4378
|
-
console.timeEnd("
|
|
4582
|
+
console.timeEnd("Optimize scene");
|
|
4379
4583
|
}
|
|
4380
4584
|
cleanupPartialLoad() {
|
|
4381
4585
|
this.nodesToLoad.forEach((nodeId) => {
|
|
@@ -4696,7 +4900,7 @@ class DynamicGltfLoader {
|
|
|
4696
4900
|
this.handleToObjects.set(fullHandle, new Set());
|
|
4697
4901
|
}
|
|
4698
4902
|
this.handleToObjects.get(fullHandle).add(object);
|
|
4699
|
-
object.userData.structureId = object.userData.handle.split(
|
|
4903
|
+
object.userData.structureId = object.userData.handle.split(STRUCTURE_ID_SEPARATOR)[0];
|
|
4700
4904
|
}
|
|
4701
4905
|
getObjectsByHandle(handle) {
|
|
4702
4906
|
if (!handle) return [];
|
|
@@ -4762,10 +4966,28 @@ class DynamicGltfLoader {
|
|
|
4762
4966
|
}
|
|
4763
4967
|
this.originalObjects.add(object);
|
|
4764
4968
|
}
|
|
4765
|
-
|
|
4969
|
+
yieldToUI() {
|
|
4970
|
+
return new Promise((resolve) => {
|
|
4971
|
+
requestAnimationFrame(() => {
|
|
4972
|
+
setTimeout(resolve, 0);
|
|
4973
|
+
});
|
|
4974
|
+
});
|
|
4975
|
+
}
|
|
4976
|
+
async optimizeScene() {
|
|
4977
|
+
console.log("Starting scene optimization...");
|
|
4978
|
+
this.dispatchEvent("optimizationprogress", {
|
|
4979
|
+
phase: "start",
|
|
4980
|
+
progress: 0,
|
|
4981
|
+
message: "Starting optimization...",
|
|
4982
|
+
});
|
|
4766
4983
|
this.originalObjects.clear();
|
|
4767
4984
|
this.originalObjectsToSelection.clear();
|
|
4768
4985
|
const structureGroups = new Map();
|
|
4986
|
+
this.dispatchEvent("optimizationprogress", {
|
|
4987
|
+
phase: "collecting",
|
|
4988
|
+
progress: 5,
|
|
4989
|
+
message: "Collecting scene objects...",
|
|
4990
|
+
});
|
|
4769
4991
|
this.scene.traverse((object) => {
|
|
4770
4992
|
if (object.userData.structureId) {
|
|
4771
4993
|
const structureId = object.userData.structureId;
|
|
@@ -4794,16 +5016,44 @@ class DynamicGltfLoader {
|
|
|
4794
5016
|
}
|
|
4795
5017
|
}
|
|
4796
5018
|
});
|
|
5019
|
+
let processedGroups = 0;
|
|
5020
|
+
const totalGroups = structureGroups.size;
|
|
5021
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5022
|
+
phase: "merging",
|
|
5023
|
+
progress: 10,
|
|
5024
|
+
message: `Merging ${totalGroups} structure groups...`,
|
|
5025
|
+
current: 0,
|
|
5026
|
+
total: totalGroups,
|
|
5027
|
+
});
|
|
4797
5028
|
for (const group of structureGroups.values()) {
|
|
4798
5029
|
group.mapMeshes.clear();
|
|
4799
5030
|
group.mapLines.clear();
|
|
4800
5031
|
group.mapLineSegments.clear();
|
|
4801
5032
|
group.mapPoints.clear();
|
|
4802
|
-
this.mergeMeshGroups(group.meshes, group.rootGroup);
|
|
4803
|
-
this.
|
|
4804
|
-
this.
|
|
4805
|
-
this.
|
|
5033
|
+
await this.mergeMeshGroups(group.meshes, group.rootGroup);
|
|
5034
|
+
await this.yieldToUI();
|
|
5035
|
+
await this.mergeLineGroups(group.lines, group.rootGroup);
|
|
5036
|
+
await this.yieldToUI();
|
|
5037
|
+
await this.mergeLineSegmentGroups(group.lineSegments, group.rootGroup);
|
|
5038
|
+
await this.yieldToUI();
|
|
5039
|
+
await this.mergePointsGroups(group.points, group.rootGroup);
|
|
5040
|
+
processedGroups++;
|
|
5041
|
+
const progress = 10 + Math.round((processedGroups / totalGroups) * 80);
|
|
5042
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5043
|
+
phase: "merging",
|
|
5044
|
+
progress,
|
|
5045
|
+
message: `Processing structure ${processedGroups}/${totalGroups}...`,
|
|
5046
|
+
current: processedGroups,
|
|
5047
|
+
total: totalGroups,
|
|
5048
|
+
});
|
|
5049
|
+
console.log(`Optimization progress: ${processedGroups}/${totalGroups} structure groups processed (${progress}%)`);
|
|
5050
|
+
await this.yieldToUI();
|
|
4806
5051
|
}
|
|
5052
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5053
|
+
phase: "finalizing",
|
|
5054
|
+
progress: 95,
|
|
5055
|
+
message: "Finalizing optimization...",
|
|
5056
|
+
});
|
|
4807
5057
|
this.originalObjects.forEach((obj) => {
|
|
4808
5058
|
obj.visible = false;
|
|
4809
5059
|
if (!(obj instanceof Points) && !obj.userData.isEdge) {
|
|
@@ -4812,9 +5062,15 @@ class DynamicGltfLoader {
|
|
|
4812
5062
|
});
|
|
4813
5063
|
this.initializeObjectVisibility();
|
|
4814
5064
|
console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
|
|
5065
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5066
|
+
phase: "complete",
|
|
5067
|
+
progress: 100,
|
|
5068
|
+
message: `Optimization complete! ${this.maxObjectId} objects processed.`,
|
|
5069
|
+
});
|
|
4815
5070
|
this.dispatchEvent("update");
|
|
4816
5071
|
}
|
|
4817
|
-
mergeMeshGroups(materialGroups, rootGroup) {
|
|
5072
|
+
async mergeMeshGroups(materialGroups, rootGroup) {
|
|
5073
|
+
let processedGroups = 0;
|
|
4818
5074
|
for (const group of materialGroups) {
|
|
4819
5075
|
if (!group.material) {
|
|
4820
5076
|
console.warn("Skipping mesh group with null material");
|
|
@@ -4828,8 +5084,6 @@ class DynamicGltfLoader {
|
|
|
4828
5084
|
let currentVertexOffset = 0;
|
|
4829
5085
|
for (const mesh of group.objects) {
|
|
4830
5086
|
const geometry = mesh.geometry.clone();
|
|
4831
|
-
mesh.updateWorldMatrix(true, false);
|
|
4832
|
-
geometry.applyMatrix4(mesh.matrixWorld);
|
|
4833
5087
|
const handle = mesh.userData.handle;
|
|
4834
5088
|
if (!this.objectIdToIndex.has(handle)) {
|
|
4835
5089
|
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
@@ -4888,6 +5142,10 @@ class DynamicGltfLoader {
|
|
|
4888
5142
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
4889
5143
|
}
|
|
4890
5144
|
});
|
|
5145
|
+
processedGroups++;
|
|
5146
|
+
if (processedGroups % 5 === 0) {
|
|
5147
|
+
await this.yieldToUI();
|
|
5148
|
+
}
|
|
4891
5149
|
} catch (error) {
|
|
4892
5150
|
console.error("Failed to merge meshes for material:", error);
|
|
4893
5151
|
group.objects.forEach((mesh) => {
|
|
@@ -4896,7 +5154,8 @@ class DynamicGltfLoader {
|
|
|
4896
5154
|
}
|
|
4897
5155
|
}
|
|
4898
5156
|
}
|
|
4899
|
-
mergeLineGroups(materialGroups, rootGroup) {
|
|
5157
|
+
async mergeLineGroups(materialGroups, rootGroup) {
|
|
5158
|
+
let processedGroups = 0;
|
|
4900
5159
|
for (const group of materialGroups) {
|
|
4901
5160
|
if (group.objects.length === 0) continue;
|
|
4902
5161
|
if (!group.material) {
|
|
@@ -4915,7 +5174,9 @@ class DynamicGltfLoader {
|
|
|
4915
5174
|
let posOffset = 0;
|
|
4916
5175
|
const indices = [];
|
|
4917
5176
|
let vertexOffset = 0;
|
|
5177
|
+
let isEdge = false;
|
|
4918
5178
|
group.objects.forEach((line) => {
|
|
5179
|
+
isEdge = line.userData.isEdge;
|
|
4919
5180
|
const geometry = line.geometry;
|
|
4920
5181
|
const positionAttr = geometry.attributes.position;
|
|
4921
5182
|
const vertexCount = positionAttr.count;
|
|
@@ -4928,12 +5189,9 @@ class DynamicGltfLoader {
|
|
|
4928
5189
|
vertexCount,
|
|
4929
5190
|
});
|
|
4930
5191
|
currentVertexOffset += vertexCount;
|
|
4931
|
-
line.updateWorldMatrix(true, false);
|
|
4932
|
-
const matrix = line.matrixWorld;
|
|
4933
5192
|
const vector = new Vector3();
|
|
4934
5193
|
for (let i = 0; i < vertexCount; i++) {
|
|
4935
5194
|
vector.fromBufferAttribute(positionAttr, i);
|
|
4936
|
-
vector.applyMatrix4(matrix);
|
|
4937
5195
|
positions[posOffset++] = vector.x;
|
|
4938
5196
|
positions[posOffset++] = vector.y;
|
|
4939
5197
|
positions[posOffset++] = vector.z;
|
|
@@ -4966,6 +5224,7 @@ class DynamicGltfLoader {
|
|
|
4966
5224
|
geometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
4967
5225
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
4968
5226
|
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
5227
|
+
mergedLine.userData.isEdge = isEdge;
|
|
4969
5228
|
const mergedObjects = [mergedLine];
|
|
4970
5229
|
if (this.useVAO) {
|
|
4971
5230
|
this.createVAO(mergedLine);
|
|
@@ -4988,9 +5247,14 @@ class DynamicGltfLoader {
|
|
|
4988
5247
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
4989
5248
|
}
|
|
4990
5249
|
});
|
|
5250
|
+
processedGroups++;
|
|
5251
|
+
if (processedGroups % 5 === 0) {
|
|
5252
|
+
await this.yieldToUI();
|
|
5253
|
+
}
|
|
4991
5254
|
}
|
|
4992
5255
|
}
|
|
4993
|
-
mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
5256
|
+
async mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
5257
|
+
let processedGroups = 0;
|
|
4994
5258
|
for (const group of materialGroups) {
|
|
4995
5259
|
if (!group.material) {
|
|
4996
5260
|
console.warn("Skipping line segment group with null material");
|
|
@@ -5002,10 +5266,10 @@ class DynamicGltfLoader {
|
|
|
5002
5266
|
const handles = new Set();
|
|
5003
5267
|
const objectMapping = new Map();
|
|
5004
5268
|
let currentVertexOffset = 0;
|
|
5269
|
+
let isEdge = false;
|
|
5005
5270
|
for (const line of group.objects) {
|
|
5271
|
+
isEdge = line.userData.isEdge;
|
|
5006
5272
|
const geometry = line.geometry.clone();
|
|
5007
|
-
line.updateWorldMatrix(true, false);
|
|
5008
|
-
geometry.applyMatrix4(line.matrixWorld);
|
|
5009
5273
|
const handle = line.userData.handle;
|
|
5010
5274
|
if (!this.objectIdToIndex.has(handle)) {
|
|
5011
5275
|
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
@@ -5038,6 +5302,7 @@ class DynamicGltfLoader {
|
|
|
5038
5302
|
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
5039
5303
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
5040
5304
|
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
5305
|
+
mergedLine.userData.isEdge = isEdge;
|
|
5041
5306
|
if (this.useVAO) {
|
|
5042
5307
|
this.createVAO(mergedLine);
|
|
5043
5308
|
}
|
|
@@ -5064,6 +5329,10 @@ class DynamicGltfLoader {
|
|
|
5064
5329
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
5065
5330
|
}
|
|
5066
5331
|
});
|
|
5332
|
+
processedGroups++;
|
|
5333
|
+
if (processedGroups % 5 === 0) {
|
|
5334
|
+
await this.yieldToUI();
|
|
5335
|
+
}
|
|
5067
5336
|
} catch (error) {
|
|
5068
5337
|
console.warn("Failed to merge line segments for material:", error);
|
|
5069
5338
|
group.objects.forEach((line) => {
|
|
@@ -5072,7 +5341,8 @@ class DynamicGltfLoader {
|
|
|
5072
5341
|
}
|
|
5073
5342
|
}
|
|
5074
5343
|
}
|
|
5075
|
-
mergePointsGroups(materialGroups, rootGroup) {
|
|
5344
|
+
async mergePointsGroups(materialGroups, rootGroup) {
|
|
5345
|
+
let processedGroups = 0;
|
|
5076
5346
|
for (const group of materialGroups) {
|
|
5077
5347
|
if (!group.material) {
|
|
5078
5348
|
console.warn("Skipping points group with null material");
|
|
@@ -5084,8 +5354,6 @@ class DynamicGltfLoader {
|
|
|
5084
5354
|
const handles = new Set();
|
|
5085
5355
|
for (const points of group.objects) {
|
|
5086
5356
|
const geometry = points.geometry.clone();
|
|
5087
|
-
points.updateWorldMatrix(true, false);
|
|
5088
|
-
geometry.applyMatrix4(points.matrixWorld);
|
|
5089
5357
|
geometries.push(geometry);
|
|
5090
5358
|
optimizedObjects.push(points);
|
|
5091
5359
|
handles.add(points.userData.handle);
|
|
@@ -5114,6 +5382,10 @@ class DynamicGltfLoader {
|
|
|
5114
5382
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
5115
5383
|
}
|
|
5116
5384
|
});
|
|
5385
|
+
processedGroups++;
|
|
5386
|
+
if (processedGroups % 5 === 0) {
|
|
5387
|
+
await this.yieldToUI();
|
|
5388
|
+
}
|
|
5117
5389
|
} catch (error) {
|
|
5118
5390
|
console.warn("Failed to merge points for material:", error);
|
|
5119
5391
|
group.objects.forEach((points) => {
|
|
@@ -5132,7 +5404,6 @@ class DynamicGltfLoader {
|
|
|
5132
5404
|
const hasNormals = lineSegmentsArray.some((segment) => segment.geometry.attributes.normal !== undefined);
|
|
5133
5405
|
lineSegmentsArray.forEach((segment) => {
|
|
5134
5406
|
const clonedGeometry = segment.geometry.clone();
|
|
5135
|
-
segment.updateWorldMatrix(true, false);
|
|
5136
5407
|
clonedGeometry.applyMatrix4(segment.matrixWorld);
|
|
5137
5408
|
if (hasNormals && !clonedGeometry.attributes.normal) {
|
|
5138
5409
|
clonedGeometry.computeVertexNormals();
|
|
@@ -5349,8 +5620,225 @@ class DynamicGltfLoader {
|
|
|
5349
5620
|
}
|
|
5350
5621
|
}
|
|
5351
5622
|
|
|
5352
|
-
class
|
|
5623
|
+
class GLTFLoadingManager extends LoadingManager {
|
|
5624
|
+
constructor(file, params = {}) {
|
|
5625
|
+
super();
|
|
5626
|
+
this.path = "";
|
|
5627
|
+
this.resourcePath = "";
|
|
5628
|
+
this.fileURL = "";
|
|
5629
|
+
this.dataURLs = new Map();
|
|
5630
|
+
this.path = params.path || "";
|
|
5631
|
+
const externalFiles = params.externalFiles || new Map();
|
|
5632
|
+
if (typeof file === "string") {
|
|
5633
|
+
this.fileURL = file;
|
|
5634
|
+
this.resourcePath = LoaderUtils.extractUrlBase(file);
|
|
5635
|
+
}
|
|
5636
|
+
else {
|
|
5637
|
+
externalFiles.forEach((value, key) => (this.fileURL = value === file ? key : this.fileURL));
|
|
5638
|
+
externalFiles.set(this.fileURL, file);
|
|
5639
|
+
}
|
|
5640
|
+
externalFiles.forEach((value, key) => {
|
|
5641
|
+
let dataURL;
|
|
5642
|
+
if (typeof value === "string")
|
|
5643
|
+
dataURL = value;
|
|
5644
|
+
else
|
|
5645
|
+
dataURL = URL.createObjectURL(new Blob([value]));
|
|
5646
|
+
this.dataURLs.set(key, dataURL);
|
|
5647
|
+
});
|
|
5648
|
+
this.setURLModifier((url) => {
|
|
5649
|
+
const key = decodeURI(url)
|
|
5650
|
+
.replace(this.path, "")
|
|
5651
|
+
.replace(this.resourcePath, "")
|
|
5652
|
+
.replace(/^(\.?\/)/, "");
|
|
5653
|
+
const dataURL = this.dataURLs.get(key);
|
|
5654
|
+
return dataURL !== null && dataURL !== void 0 ? dataURL : url;
|
|
5655
|
+
});
|
|
5656
|
+
}
|
|
5657
|
+
dispose() {
|
|
5658
|
+
this.dataURLs.forEach((dataURL) => URL.revokeObjectURL(dataURL));
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
|
|
5662
|
+
const BINARY_EXTENSION_HEADER_MAGIC = "glTF";
|
|
5663
|
+
const BINARY_EXTENSION_HEADER_LENGTH = 12;
|
|
5664
|
+
const BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4e4f534a, BIN: 0x004e4042 };
|
|
5665
|
+
class GLTFBinaryExtension {
|
|
5666
|
+
constructor(data) {
|
|
5667
|
+
const headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH);
|
|
5668
|
+
const textDecoder = new TextDecoder();
|
|
5669
|
+
const magic = textDecoder.decode(new Uint8Array(data.slice(0, 4)));
|
|
5670
|
+
if (magic !== BINARY_EXTENSION_HEADER_MAGIC) {
|
|
5671
|
+
this.content = textDecoder.decode(data);
|
|
5672
|
+
return;
|
|
5673
|
+
}
|
|
5674
|
+
const header = {
|
|
5675
|
+
magic,
|
|
5676
|
+
version: headerView.getUint32(4, true),
|
|
5677
|
+
length: headerView.getUint32(8, true),
|
|
5678
|
+
};
|
|
5679
|
+
if (header.magic !== BINARY_EXTENSION_HEADER_MAGIC) {
|
|
5680
|
+
throw new Error("Unsupported glTF-Binary header.");
|
|
5681
|
+
}
|
|
5682
|
+
if (header.version < 2.0) {
|
|
5683
|
+
throw new Error("Legacy binary file detected.");
|
|
5684
|
+
}
|
|
5685
|
+
const chunkContentsLength = header.length - BINARY_EXTENSION_HEADER_LENGTH;
|
|
5686
|
+
const chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH);
|
|
5687
|
+
let chunkIndex = 0;
|
|
5688
|
+
while (chunkIndex < chunkContentsLength) {
|
|
5689
|
+
const chunkLength = chunkView.getUint32(chunkIndex, true);
|
|
5690
|
+
chunkIndex += 4;
|
|
5691
|
+
const chunkType = chunkView.getUint32(chunkIndex, true);
|
|
5692
|
+
chunkIndex += 4;
|
|
5693
|
+
if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) {
|
|
5694
|
+
const contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength);
|
|
5695
|
+
this.content = textDecoder.decode(contentArray);
|
|
5696
|
+
}
|
|
5697
|
+
else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) {
|
|
5698
|
+
const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
|
|
5699
|
+
this.body = data.slice(byteOffset, byteOffset + chunkLength);
|
|
5700
|
+
}
|
|
5701
|
+
chunkIndex += chunkLength;
|
|
5702
|
+
}
|
|
5703
|
+
if (typeof this.content === "undefined") {
|
|
5704
|
+
throw new Error("JSON content not found.");
|
|
5705
|
+
}
|
|
5706
|
+
}
|
|
5707
|
+
}
|
|
5708
|
+
|
|
5709
|
+
class RangesLoader {
|
|
5710
|
+
constructor() {
|
|
5711
|
+
this.requestHeader = {};
|
|
5712
|
+
this.withCredentials = false;
|
|
5713
|
+
this.abortSignal = undefined;
|
|
5714
|
+
}
|
|
5715
|
+
setRequestHeader(requestHeader) {
|
|
5716
|
+
this.requestHeader = requestHeader;
|
|
5717
|
+
}
|
|
5718
|
+
setWithCredentials(withCredentials) {
|
|
5719
|
+
this.withCredentials = withCredentials;
|
|
5720
|
+
}
|
|
5721
|
+
setAbortSignal(abortSignal) {
|
|
5722
|
+
this.abortSignal = abortSignal;
|
|
5723
|
+
}
|
|
5724
|
+
async load(url, ranges) {
|
|
5725
|
+
const init = {
|
|
5726
|
+
headers: {
|
|
5727
|
+
...this.requestHeader,
|
|
5728
|
+
Range: "bytes=" + ranges.map((x) => `${x.offset}-${x.offset + x.length - 1}`).join(","),
|
|
5729
|
+
},
|
|
5730
|
+
credentials: this.withCredentials ? "include" : "same-origin",
|
|
5731
|
+
signal: this.abortSignal,
|
|
5732
|
+
};
|
|
5733
|
+
const response = await fetch(url, init);
|
|
5734
|
+
if (!response.ok) {
|
|
5735
|
+
throw new Error(`Failed to fetch "${url}", status ${response.status}`);
|
|
5736
|
+
}
|
|
5737
|
+
if (response.status !== 206) {
|
|
5738
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
5739
|
+
return this.extractRanges(arrayBuffer, ranges);
|
|
5740
|
+
}
|
|
5741
|
+
return response.arrayBuffer();
|
|
5742
|
+
}
|
|
5743
|
+
extractRanges(arrayBuffer, ranges) {
|
|
5744
|
+
const totalLength = ranges.reduce((sum, range) => sum + range.length, 0);
|
|
5745
|
+
const result = new Uint8Array(totalLength);
|
|
5746
|
+
let offset = 0;
|
|
5747
|
+
for (const range of ranges) {
|
|
5748
|
+
const chunk = new Uint8Array(arrayBuffer, range.offset, range.length);
|
|
5749
|
+
result.set(chunk, offset);
|
|
5750
|
+
offset += range.length;
|
|
5751
|
+
}
|
|
5752
|
+
return result.buffer;
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
|
|
5756
|
+
class GLTFFileDynamicLoader extends Loader {
|
|
5757
|
+
constructor(viewer) {
|
|
5758
|
+
super();
|
|
5759
|
+
this.viewer = viewer;
|
|
5760
|
+
}
|
|
5761
|
+
dispose() {
|
|
5762
|
+
if (this.gltfLoader)
|
|
5763
|
+
this.gltfLoader.clear();
|
|
5764
|
+
if (this.manager)
|
|
5765
|
+
this.manager.dispose();
|
|
5766
|
+
}
|
|
5767
|
+
isSupport(file, format) {
|
|
5768
|
+
return ((typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
|
|
5769
|
+
/(gltf|glb)$/i.test(format));
|
|
5770
|
+
}
|
|
5771
|
+
async load(file, format, params) {
|
|
5772
|
+
this.manager = new GLTFLoadingManager(file, params);
|
|
5773
|
+
const scene = new Group();
|
|
5774
|
+
this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
|
|
5775
|
+
this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
|
|
5776
|
+
this.gltfLoader.visibleEdges = this.viewer.options.edgeModel;
|
|
5777
|
+
const modelImpl = new DynamicModelImpl(scene);
|
|
5778
|
+
modelImpl.id = params.modelId || this.extractFileName(file);
|
|
5779
|
+
modelImpl.gltfLoader = this.gltfLoader;
|
|
5780
|
+
this.gltfLoader.addEventListener("databasechunk", () => {
|
|
5781
|
+
this.viewer.scene.add(scene);
|
|
5782
|
+
this.viewer.models.push(modelImpl);
|
|
5783
|
+
this.viewer.syncOptions();
|
|
5784
|
+
this.viewer.syncOverlay();
|
|
5785
|
+
this.viewer.update();
|
|
5786
|
+
this.viewer.emitEvent({ type: "databasechunk", data: scene, file });
|
|
5787
|
+
});
|
|
5788
|
+
this.gltfLoader.addEventListener("geometryerror", (data) => {
|
|
5789
|
+
this.viewer.emitEvent({ type: "geometryerror", data, file });
|
|
5790
|
+
});
|
|
5791
|
+
this.gltfLoader.addEventListener("update", (data) => {
|
|
5792
|
+
this.viewer.update();
|
|
5793
|
+
});
|
|
5794
|
+
const loadController = {
|
|
5795
|
+
loadJson: async () => {
|
|
5796
|
+
const loader = new FileLoader(this.manager);
|
|
5797
|
+
loader.setPath(this.manager.path);
|
|
5798
|
+
loader.setRequestHeader(params.requestHeader || {});
|
|
5799
|
+
loader.setWithCredentials(params.withCredentials || loader.withCredentials);
|
|
5800
|
+
loader.setResponseType("arraybuffer");
|
|
5801
|
+
const progress = (event) => {
|
|
5802
|
+
const { lengthComputable, loaded, total } = event;
|
|
5803
|
+
const progress = lengthComputable ? loaded / total : 1;
|
|
5804
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
|
|
5805
|
+
};
|
|
5806
|
+
const data = await loader.loadAsync(this.manager.fileURL, progress);
|
|
5807
|
+
const extension = new GLTFBinaryExtension(data);
|
|
5808
|
+
this.gltf = JSON.parse(extension.content);
|
|
5809
|
+
this.bin = extension.body;
|
|
5810
|
+
return this.gltf;
|
|
5811
|
+
},
|
|
5812
|
+
loadBinaryData: (ranges, uri = "") => {
|
|
5813
|
+
const loader = new RangesLoader();
|
|
5814
|
+
loader.setRequestHeader(params.requestHeader || {});
|
|
5815
|
+
loader.setWithCredentials(params.withCredentials || false);
|
|
5816
|
+
loader.setAbortSignal(this.gltfLoader.abortController.signal);
|
|
5817
|
+
if (this.bin)
|
|
5818
|
+
return loader.extractRanges(this.bin, ranges);
|
|
5819
|
+
const path = this.manager.path || this.manager.resourcePath;
|
|
5820
|
+
const url = LoaderUtils.resolveURL(uri, path);
|
|
5821
|
+
return loader.load(this.manager.resolveURL(url), ranges);
|
|
5822
|
+
},
|
|
5823
|
+
baseUrl: () => {
|
|
5824
|
+
const path = this.manager.path || this.manager.resourcePath;
|
|
5825
|
+
return Promise.resolve(path);
|
|
5826
|
+
},
|
|
5827
|
+
};
|
|
5828
|
+
const structure = new GltfStructure(modelImpl.id, loadController);
|
|
5829
|
+
await this.gltfLoader.loadStructure(structure);
|
|
5830
|
+
await this.gltfLoader.loadNodes();
|
|
5831
|
+
return this;
|
|
5832
|
+
}
|
|
5833
|
+
cancel() {
|
|
5834
|
+
if (this.gltfLoader)
|
|
5835
|
+
this.gltfLoader.abortLoading();
|
|
5836
|
+
}
|
|
5837
|
+
}
|
|
5838
|
+
|
|
5839
|
+
class GLTFCloudDynamicLoader extends Loader {
|
|
5353
5840
|
constructor(viewer) {
|
|
5841
|
+
super();
|
|
5354
5842
|
this.requestId = 0;
|
|
5355
5843
|
this.viewer = viewer;
|
|
5356
5844
|
}
|
|
@@ -5365,17 +5853,15 @@ class GLTFCloudDynamicLoader {
|
|
|
5365
5853
|
typeof file.downloadResourceRange === "function" &&
|
|
5366
5854
|
/.gltf$/i.test(file.database));
|
|
5367
5855
|
}
|
|
5368
|
-
async load(model, format, params) {
|
|
5856
|
+
async load(model, format, params = {}) {
|
|
5369
5857
|
const scene = new Group();
|
|
5370
5858
|
this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
|
|
5371
5859
|
this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
|
|
5372
5860
|
this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
|
|
5861
|
+
const modelImpl = new DynamicModelImpl(scene);
|
|
5862
|
+
modelImpl.id = model.file.id;
|
|
5863
|
+
modelImpl.gltfLoader = this.gltfLoader;
|
|
5373
5864
|
this.gltfLoader.addEventListener("databasechunk", (data) => {
|
|
5374
|
-
const modelImpl = new DynamicModelImpl(scene);
|
|
5375
|
-
modelImpl.loader = this;
|
|
5376
|
-
modelImpl.viewer = this.viewer;
|
|
5377
|
-
modelImpl.gltfLoader = this.gltfLoader;
|
|
5378
|
-
modelImpl.modelId = model.id;
|
|
5379
5865
|
this.viewer.scene.add(scene);
|
|
5380
5866
|
this.viewer.models.push(modelImpl);
|
|
5381
5867
|
this.viewer.syncOptions();
|
|
@@ -5383,10 +5869,6 @@ class GLTFCloudDynamicLoader {
|
|
|
5383
5869
|
this.viewer.update();
|
|
5384
5870
|
this.viewer.emitEvent({ type: "databasechunk", data: scene, file: model.file, model });
|
|
5385
5871
|
});
|
|
5386
|
-
this.gltfLoader.addEventListener("geometryprogress", (data) => {
|
|
5387
|
-
const progress = data.loaded / data.total;
|
|
5388
|
-
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model.file, model });
|
|
5389
|
-
});
|
|
5390
5872
|
this.gltfLoader.addEventListener("geometryerror", (data) => {
|
|
5391
5873
|
this.viewer.emitEvent({ type: "geometryerror", data, file: model.file, model });
|
|
5392
5874
|
});
|
|
@@ -5396,7 +5878,7 @@ class GLTFCloudDynamicLoader {
|
|
|
5396
5878
|
const loadController = {
|
|
5397
5879
|
loadJson: async () => {
|
|
5398
5880
|
const progress = (progress) => {
|
|
5399
|
-
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model });
|
|
5881
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model.file, model });
|
|
5400
5882
|
};
|
|
5401
5883
|
const arrayBuffer = await model.downloadResource(model.database, progress, this.gltfLoader.getAbortController().signal);
|
|
5402
5884
|
const text = new TextDecoder().decode(arrayBuffer);
|
|
@@ -5413,7 +5895,7 @@ class GLTFCloudDynamicLoader {
|
|
|
5413
5895
|
},
|
|
5414
5896
|
baseUrl: () => Promise.resolve(`${model.httpClient.serverUrl}${model.path}/`),
|
|
5415
5897
|
};
|
|
5416
|
-
const structure = new GltfStructure(
|
|
5898
|
+
const structure = new GltfStructure(modelImpl.id, loadController);
|
|
5417
5899
|
await this.gltfLoader.loadStructure(structure);
|
|
5418
5900
|
await this.gltfLoader.loadNodes();
|
|
5419
5901
|
return this;
|
|
@@ -5425,7 +5907,7 @@ class GLTFCloudDynamicLoader {
|
|
|
5425
5907
|
}
|
|
5426
5908
|
|
|
5427
5909
|
const loaders = loadersRegistry("threejs");
|
|
5428
|
-
loaders.registerLoader("gltf-file", (viewer) => new
|
|
5910
|
+
loaders.registerLoader("gltf-file", (viewer) => new GLTFFileDynamicLoader(viewer));
|
|
5429
5911
|
loaders.registerLoader("gltf-cloud", (viewer) => new GLTFCloudDynamicLoader(viewer));
|
|
5430
5912
|
|
|
5431
5913
|
class SSAARenderPass extends Pass {
|
|
@@ -5632,24 +6114,25 @@ class Helpers extends Scene {
|
|
|
5632
6114
|
class Viewer extends EventEmitter2 {
|
|
5633
6115
|
constructor(client) {
|
|
5634
6116
|
super();
|
|
5635
|
-
this._options = new Options(this);
|
|
5636
6117
|
this.client = client;
|
|
5637
|
-
this.
|
|
5638
|
-
this.canvaseventlistener = (event) => this.emit(event);
|
|
6118
|
+
this.options = new Options(this);
|
|
5639
6119
|
this.loaders = [];
|
|
5640
6120
|
this.models = [];
|
|
6121
|
+
this.canvasEvents = CANVAS_EVENTS.slice();
|
|
6122
|
+
this.canvaseventlistener = (event) => this.emit(event);
|
|
5641
6123
|
this.selected = [];
|
|
5642
6124
|
this.extents = new Box3();
|
|
5643
|
-
this.target = new Vector3();
|
|
6125
|
+
this.target = new Vector3(0, 0, 0);
|
|
5644
6126
|
this._activeDragger = null;
|
|
5645
6127
|
this._components = [];
|
|
6128
|
+
this._renderNeeded = false;
|
|
5646
6129
|
this._renderTime = 0;
|
|
5647
6130
|
this.render = this.render.bind(this);
|
|
5648
6131
|
this.update = this.update.bind(this);
|
|
5649
6132
|
this._markup = new Markup();
|
|
5650
6133
|
}
|
|
5651
|
-
get
|
|
5652
|
-
return this.
|
|
6134
|
+
get markup() {
|
|
6135
|
+
return this._markup;
|
|
5653
6136
|
}
|
|
5654
6137
|
get draggers() {
|
|
5655
6138
|
return [...draggers.getDraggers().keys()];
|
|
@@ -5657,14 +6140,10 @@ class Viewer extends EventEmitter2 {
|
|
|
5657
6140
|
get components() {
|
|
5658
6141
|
return [...components.getComponents().keys()];
|
|
5659
6142
|
}
|
|
5660
|
-
get markup() {
|
|
5661
|
-
return this._markup;
|
|
5662
|
-
}
|
|
5663
6143
|
initialize(canvas, onProgress) {
|
|
5664
6144
|
this.addEventListener("optionschange", (event) => this.syncOptions(event.data));
|
|
5665
6145
|
this.scene = new Scene();
|
|
5666
6146
|
this.helpers = new Helpers();
|
|
5667
|
-
this.target = new Vector3(0, 0, 0);
|
|
5668
6147
|
const pixelRatio = window.devicePixelRatio;
|
|
5669
6148
|
const rect = canvas.parentElement.getBoundingClientRect();
|
|
5670
6149
|
const width = rect.width || 1;
|
|
@@ -5815,21 +6294,25 @@ class Viewer extends EventEmitter2 {
|
|
|
5815
6294
|
async open(file, params = {}) {
|
|
5816
6295
|
if (!this.renderer)
|
|
5817
6296
|
return this;
|
|
5818
|
-
|
|
6297
|
+
const mode = params.mode || "file";
|
|
6298
|
+
if (mode !== "assembly" && mode !== "a" && mode !== "append") {
|
|
5819
6299
|
this.cancel();
|
|
5820
6300
|
this.clear();
|
|
5821
6301
|
}
|
|
5822
|
-
this.emitEvent({ type: "open", file });
|
|
6302
|
+
this.emitEvent({ type: "open", mode, file });
|
|
5823
6303
|
let model = file;
|
|
5824
6304
|
if (model && typeof model.getModels === "function") {
|
|
5825
6305
|
const models = await model.getModels();
|
|
5826
6306
|
model = models.find((model) => model.default) || models[0] || file;
|
|
5827
6307
|
}
|
|
6308
|
+
if (model && typeof model.database === "string") {
|
|
6309
|
+
file = model.file;
|
|
6310
|
+
}
|
|
5828
6311
|
if (!model)
|
|
5829
6312
|
throw new Error(`Format not supported`);
|
|
5830
6313
|
let format = params.format;
|
|
5831
|
-
if (!format && typeof
|
|
5832
|
-
format =
|
|
6314
|
+
if (!format && typeof file["type"] === "string")
|
|
6315
|
+
format = file["type"].split(".").pop();
|
|
5833
6316
|
if (!format && typeof file === "string")
|
|
5834
6317
|
format = file.split(".").pop();
|
|
5835
6318
|
if (!format && file instanceof globalThis.File)
|
|
@@ -5856,7 +6339,7 @@ class Viewer extends EventEmitter2 {
|
|
|
5856
6339
|
}
|
|
5857
6340
|
loadGltfFile(file, externalFiles, params = {}) {
|
|
5858
6341
|
console.warn("Viewer.loadGltfFile() has been deprecated since 26.4 and will be removed in a future release, use Viewer.open() instead.");
|
|
5859
|
-
return this.open(file, { ...params, format: "gltf", externalFiles, mode: "
|
|
6342
|
+
return this.open(file, { ...params, format: "gltf", externalFiles, mode: "assembly" });
|
|
5860
6343
|
}
|
|
5861
6344
|
cancel() {
|
|
5862
6345
|
this.loaders.forEach((loader) => loader.cancel());
|
|
@@ -5876,12 +6359,17 @@ class Viewer extends EventEmitter2 {
|
|
|
5876
6359
|
this.models = [];
|
|
5877
6360
|
this.scene.clear();
|
|
5878
6361
|
this.helpers.clear();
|
|
6362
|
+
this.extents.makeEmpty();
|
|
6363
|
+
this.target.set(0, 0, 0);
|
|
5879
6364
|
this.syncOptions();
|
|
5880
6365
|
this.syncOverlay();
|
|
5881
6366
|
this.update(true);
|
|
5882
6367
|
this.emitEvent({ type: "clear" });
|
|
5883
6368
|
return this;
|
|
5884
6369
|
}
|
|
6370
|
+
is3D() {
|
|
6371
|
+
return true;
|
|
6372
|
+
}
|
|
5885
6373
|
syncOptions(options = this.options) {
|
|
5886
6374
|
if (!this.renderer)
|
|
5887
6375
|
return;
|
|
@@ -5913,9 +6401,15 @@ class Viewer extends EventEmitter2 {
|
|
|
5913
6401
|
getSelected() {
|
|
5914
6402
|
return this.executeCommand("getSelected");
|
|
5915
6403
|
}
|
|
6404
|
+
getSelected2() {
|
|
6405
|
+
return this.executeCommand("getSelected2");
|
|
6406
|
+
}
|
|
5916
6407
|
setSelected(handles) {
|
|
5917
6408
|
this.executeCommand("setSelected", handles);
|
|
5918
6409
|
}
|
|
6410
|
+
setSelected2(handles) {
|
|
6411
|
+
this.executeCommand("setSelected2", handles);
|
|
6412
|
+
}
|
|
5919
6413
|
clearSelected() {
|
|
5920
6414
|
this.executeCommand("clearSelected");
|
|
5921
6415
|
}
|
|
@@ -5975,37 +6469,8 @@ class Viewer extends EventEmitter2 {
|
|
|
5975
6469
|
getComponent(name) {
|
|
5976
6470
|
return this._components.find((component) => component.name === name);
|
|
5977
6471
|
}
|
|
5978
|
-
is3D() {
|
|
5979
|
-
return true;
|
|
5980
|
-
}
|
|
5981
|
-
screenToWorld(position) {
|
|
5982
|
-
if (!this.renderer)
|
|
5983
|
-
return { x: position.x, y: position.y, z: 0 };
|
|
5984
|
-
const rect = this.canvas.getBoundingClientRect();
|
|
5985
|
-
const x = position.x / (rect.width / 2) - 1;
|
|
5986
|
-
const y = -position.y / (rect.height / 2) + 1;
|
|
5987
|
-
const point = new Vector3(x, y, -1);
|
|
5988
|
-
point.unproject(this.camera);
|
|
5989
|
-
return { x: point.x, y: point.y, z: point.z };
|
|
5990
|
-
}
|
|
5991
|
-
worldToScreen(position) {
|
|
5992
|
-
if (!this.renderer)
|
|
5993
|
-
return { x: position.x, y: position.y };
|
|
5994
|
-
const point = new Vector3(position.x, position.y, position.z);
|
|
5995
|
-
point.project(this.camera);
|
|
5996
|
-
const rect = this.canvas.getBoundingClientRect();
|
|
5997
|
-
const x = (point.x + 1) * (rect.width / 2);
|
|
5998
|
-
const y = (-point.y + 1) * (rect.height / 2);
|
|
5999
|
-
return { x, y };
|
|
6000
|
-
}
|
|
6001
|
-
getScale() {
|
|
6002
|
-
return { x: 1, y: 1, z: 1 };
|
|
6003
|
-
}
|
|
6004
|
-
executeCommand(id, ...args) {
|
|
6005
|
-
return commands.executeCommand(id, this, ...args);
|
|
6006
|
-
}
|
|
6007
6472
|
drawViewpoint(viewpoint) {
|
|
6008
|
-
var _a, _b, _c;
|
|
6473
|
+
var _a, _b, _c, _d;
|
|
6009
6474
|
if (!this.renderer)
|
|
6010
6475
|
return;
|
|
6011
6476
|
const getVector3FromPoint3d = ({ x, y, z }) => new Vector3(x, y, z);
|
|
@@ -6057,11 +6522,13 @@ class Viewer extends EventEmitter2 {
|
|
|
6057
6522
|
}
|
|
6058
6523
|
};
|
|
6059
6524
|
const setClippingPlanes = (clipping_planes) => {
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6525
|
+
if (clipping_planes) {
|
|
6526
|
+
clipping_planes.forEach((clipping_plane) => {
|
|
6527
|
+
const plane = new Plane();
|
|
6528
|
+
plane.setFromNormalAndCoplanarPoint(getVector3FromPoint3d(clipping_plane.direction), getVector3FromPoint3d(clipping_plane.location));
|
|
6529
|
+
this.renderer.clippingPlanes.push(plane);
|
|
6530
|
+
});
|
|
6531
|
+
}
|
|
6065
6532
|
};
|
|
6066
6533
|
const setSelection = (selection) => {
|
|
6067
6534
|
if (selection)
|
|
@@ -6077,9 +6544,9 @@ class Viewer extends EventEmitter2 {
|
|
|
6077
6544
|
setOrthogonalCamera(viewpoint.orthogonal_camera);
|
|
6078
6545
|
setPerspectiveCamera(viewpoint.perspective_camera);
|
|
6079
6546
|
setClippingPlanes(viewpoint.clipping_planes);
|
|
6080
|
-
setSelection(viewpoint.selection);
|
|
6547
|
+
setSelection(((_b = viewpoint.custom_fields) === null || _b === void 0 ? void 0 : _b.selection2) || viewpoint.selection);
|
|
6081
6548
|
this._markup.setViewpoint(viewpoint);
|
|
6082
|
-
this.target
|
|
6549
|
+
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));
|
|
6083
6550
|
this.setActiveDragger(draggerName);
|
|
6084
6551
|
this.emitEvent({ type: "drawviewpoint", data: viewpoint });
|
|
6085
6552
|
this.update();
|
|
@@ -6126,6 +6593,9 @@ class Viewer extends EventEmitter2 {
|
|
|
6126
6593
|
const getSelection = () => {
|
|
6127
6594
|
return this.getSelected().map((handle) => ({ handle }));
|
|
6128
6595
|
};
|
|
6596
|
+
const getSelection2 = () => {
|
|
6597
|
+
return this.getSelected2().map((handle) => ({ handle }));
|
|
6598
|
+
};
|
|
6129
6599
|
const viewpoint = { custom_fields: {} };
|
|
6130
6600
|
viewpoint.orthogonal_camera = getOrthogonalCamera();
|
|
6131
6601
|
viewpoint.perspective_camera = getPerspectiveCamera();
|
|
@@ -6134,9 +6604,36 @@ class Viewer extends EventEmitter2 {
|
|
|
6134
6604
|
viewpoint.description = new Date().toDateString();
|
|
6135
6605
|
this._markup.getViewpoint(viewpoint);
|
|
6136
6606
|
viewpoint.custom_fields.camera_target = getPoint3dFromVector3(this.target);
|
|
6607
|
+
viewpoint.custom_fields.selection2 = getSelection2();
|
|
6137
6608
|
this.emitEvent({ type: "createviewpoint", data: viewpoint });
|
|
6138
6609
|
return viewpoint;
|
|
6139
6610
|
}
|
|
6611
|
+
screenToWorld(position) {
|
|
6612
|
+
if (!this.renderer)
|
|
6613
|
+
return { x: position.x, y: position.y, z: 0 };
|
|
6614
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
6615
|
+
const x = position.x / (rect.width / 2) - 1;
|
|
6616
|
+
const y = -position.y / (rect.height / 2) + 1;
|
|
6617
|
+
const point = new Vector3(x, y, -1);
|
|
6618
|
+
point.unproject(this.camera);
|
|
6619
|
+
return { x: point.x, y: point.y, z: point.z };
|
|
6620
|
+
}
|
|
6621
|
+
worldToScreen(position) {
|
|
6622
|
+
if (!this.renderer)
|
|
6623
|
+
return { x: position.x, y: position.y };
|
|
6624
|
+
const point = new Vector3(position.x, position.y, position.z);
|
|
6625
|
+
point.project(this.camera);
|
|
6626
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
6627
|
+
const x = (point.x + 1) * (rect.width / 2);
|
|
6628
|
+
const y = (-point.y + 1) * (rect.height / 2);
|
|
6629
|
+
return { x, y };
|
|
6630
|
+
}
|
|
6631
|
+
getScale() {
|
|
6632
|
+
return { x: 1, y: 1, z: 1 };
|
|
6633
|
+
}
|
|
6634
|
+
executeCommand(id, ...args) {
|
|
6635
|
+
return commands.executeCommand(id, this, ...args);
|
|
6636
|
+
}
|
|
6140
6637
|
}
|
|
6141
6638
|
|
|
6142
6639
|
export { GLTFLoadingManager, ModelImpl, Viewer, commands, components, draggers, loaders };
|