@inweb/viewer-three 26.10.6 → 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 +1015 -2926
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +3 -3
- package/dist/viewer-three.module.js +847 -356
- 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/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/SelectionComponent.ts +7 -30
- package/src/Viewer/components/index.ts +6 -6
- package/src/Viewer/draggers/MeasureLineDragger.ts +84 -226
- 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
|
@@ -23,12 +23,11 @@
|
|
|
23
23
|
|
|
24
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';
|
|
@@ -914,116 +913,91 @@ class CuttingPlaneZAxisDragger extends CuttingPlaneDragger {
|
|
|
914
913
|
}
|
|
915
914
|
}
|
|
916
915
|
|
|
917
|
-
const
|
|
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
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
this.viewer.canvas.addEventListener("pointerleave", this.onPointerLeave);
|
|
983
|
-
this.viewer.addEventListener("render", this.renderOverlay);
|
|
984
|
-
this.viewer.addEventListener("hide", this.updateSnapper);
|
|
985
|
-
this.viewer.addEventListener("isolate", this.updateSnapper);
|
|
986
|
-
this.viewer.addEventListener("show", this.updateSnapper);
|
|
987
|
-
this.viewer.addEventListener("showall", this.updateSnapper);
|
|
988
|
-
this.viewer.addEventListener("changecameramode", this.updateSnapperCamera);
|
|
989
|
-
}
|
|
990
|
-
dispose() {
|
|
991
|
-
this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown);
|
|
992
|
-
this.viewer.canvas.removeEventListener("pointermove", this.onPointerMove);
|
|
993
|
-
this.viewer.canvas.removeEventListener("pointerup", this.onPointerUp);
|
|
994
|
-
this.viewer.canvas.removeEventListener("pointercancel", this.onPointerCancel);
|
|
995
|
-
this.viewer.canvas.removeEventListener("pointerleave", this.onPointerLeave);
|
|
996
|
-
this.viewer.removeEventListener("render", this.renderOverlay);
|
|
997
|
-
this.viewer.removeEventListener("hide", this.updateSnapper);
|
|
998
|
-
this.viewer.removeEventListener("isolate", this.updateSnapper);
|
|
999
|
-
this.viewer.removeEventListener("show", this.updateSnapper);
|
|
1000
|
-
this.viewer.removeEventListener("showall", this.updateSnapper);
|
|
1001
|
-
this.viewer.removeEventListener("changecameramode", this.updateSnapperCamera);
|
|
1002
|
-
this.snapper.dispose();
|
|
1003
|
-
this.overlay.detach();
|
|
1004
|
-
this.overlay.dispose();
|
|
1005
|
-
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);
|
|
1006
981
|
}
|
|
1007
982
|
}
|
|
983
|
+
|
|
984
|
+
const DESKTOP_SNAP_DISTANCE = 10;
|
|
985
|
+
const MOBILE_SNAP_DISTANCE = 50;
|
|
1008
986
|
const _vertex = new Vector3();
|
|
1009
987
|
const _start = new Vector3();
|
|
1010
988
|
const _end = new Vector3();
|
|
1011
989
|
const _line = new Line3();
|
|
1012
990
|
const _center = new Vector3();
|
|
1013
991
|
const _projection = new Vector3();
|
|
1014
|
-
class
|
|
1015
|
-
constructor(camera, canvas) {
|
|
992
|
+
class Snapper {
|
|
993
|
+
constructor(camera, renderer, canvas) {
|
|
1016
994
|
this.camera = camera;
|
|
995
|
+
this.renderer = renderer;
|
|
1017
996
|
this.canvas = canvas;
|
|
1018
|
-
this.objects = [];
|
|
1019
|
-
this.clippingPlanes = [];
|
|
1020
997
|
this.raycaster = new Raycaster();
|
|
1021
998
|
this.detectRadiusInPixels = this.isMobile() ? MOBILE_SNAP_DISTANCE : DESKTOP_SNAP_DISTANCE;
|
|
1022
999
|
this.edgesCache = new WeakMap();
|
|
1023
1000
|
}
|
|
1024
|
-
dispose() {
|
|
1025
|
-
this.objects = [];
|
|
1026
|
-
}
|
|
1027
1001
|
isMobile() {
|
|
1028
1002
|
if (typeof navigator === "undefined")
|
|
1029
1003
|
return false;
|
|
@@ -1032,7 +1006,7 @@ class MeasureSnapper {
|
|
|
1032
1006
|
getMousePosition(event, target) {
|
|
1033
1007
|
return target.set(event.clientX, event.clientY);
|
|
1034
1008
|
}
|
|
1035
|
-
getPointerIntersects(mouse) {
|
|
1009
|
+
getPointerIntersects(mouse, objects) {
|
|
1036
1010
|
const rect = this.canvas.getBoundingClientRect();
|
|
1037
1011
|
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
1038
1012
|
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
@@ -1046,8 +1020,8 @@ class MeasureSnapper {
|
|
|
1046
1020
|
Points: { threshold: 0.01 },
|
|
1047
1021
|
Sprite: {},
|
|
1048
1022
|
};
|
|
1049
|
-
let intersects = this.raycaster.intersectObjects(
|
|
1050
|
-
this.clippingPlanes.forEach((plane) => {
|
|
1023
|
+
let intersects = this.raycaster.intersectObjects(objects, false);
|
|
1024
|
+
(this.renderer.clippingPlanes || []).forEach((plane) => {
|
|
1051
1025
|
intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
|
|
1052
1026
|
});
|
|
1053
1027
|
return intersects;
|
|
@@ -1069,9 +1043,8 @@ class MeasureSnapper {
|
|
|
1069
1043
|
}
|
|
1070
1044
|
return 0.1;
|
|
1071
1045
|
}
|
|
1072
|
-
getSnapPoint(
|
|
1073
|
-
const
|
|
1074
|
-
const intersections = this.getPointerIntersects(mouse);
|
|
1046
|
+
getSnapPoint(mouse, objects) {
|
|
1047
|
+
const intersections = this.getPointerIntersects(mouse, objects);
|
|
1075
1048
|
if (intersections.length === 0)
|
|
1076
1049
|
return undefined;
|
|
1077
1050
|
const object = intersections[0].object;
|
|
@@ -1119,13 +1092,133 @@ class MeasureSnapper {
|
|
|
1119
1092
|
return object.localToWorld(snapPoint);
|
|
1120
1093
|
return intersectionPoint.clone();
|
|
1121
1094
|
}
|
|
1122
|
-
|
|
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);
|
|
1123
1218
|
this.objects.length = 0;
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
this.camera = viewer.camera;
|
|
1128
|
-
this.clippingPlanes = viewer.renderer.clippingPlanes || [];
|
|
1219
|
+
this.overlay.detach();
|
|
1220
|
+
this.overlay.dispose();
|
|
1221
|
+
super.dispose();
|
|
1129
1222
|
}
|
|
1130
1223
|
}
|
|
1131
1224
|
class MeasureOverlay {
|
|
@@ -1145,6 +1238,9 @@ class MeasureOverlay {
|
|
|
1145
1238
|
this.projector = new MeasureProjector(camera, canvas);
|
|
1146
1239
|
this.resizeObserver = new ResizeObserver(this.resizeContainer);
|
|
1147
1240
|
}
|
|
1241
|
+
dispose() {
|
|
1242
|
+
this.clear();
|
|
1243
|
+
}
|
|
1148
1244
|
attach() {
|
|
1149
1245
|
this.container = document.createElement("div");
|
|
1150
1246
|
this.container.id = "measure-container";
|
|
@@ -1157,9 +1253,6 @@ class MeasureOverlay {
|
|
|
1157
1253
|
this.canvas.parentElement.appendChild(this.container);
|
|
1158
1254
|
this.resizeObserver.observe(this.canvas);
|
|
1159
1255
|
}
|
|
1160
|
-
dispose() {
|
|
1161
|
-
this.clear();
|
|
1162
|
-
}
|
|
1163
1256
|
detach() {
|
|
1164
1257
|
this.resizeObserver.disconnect();
|
|
1165
1258
|
this.container.remove();
|
|
@@ -1167,7 +1260,7 @@ class MeasureOverlay {
|
|
|
1167
1260
|
}
|
|
1168
1261
|
clear() {
|
|
1169
1262
|
this.lines.forEach((line) => line.dispose());
|
|
1170
|
-
this.lines =
|
|
1263
|
+
this.lines.length = 0;
|
|
1171
1264
|
}
|
|
1172
1265
|
render() {
|
|
1173
1266
|
this.projector.setFromCamera(this.camera);
|
|
@@ -1182,13 +1275,18 @@ class MeasureOverlay {
|
|
|
1182
1275
|
removeLine(line) {
|
|
1183
1276
|
this.lines = this.lines.filter((x) => x !== line);
|
|
1184
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
|
+
}
|
|
1185
1285
|
}
|
|
1186
1286
|
const _middlePoint = new Vector3();
|
|
1187
1287
|
class MeasureLine {
|
|
1188
|
-
constructor(overlay) {
|
|
1288
|
+
constructor(overlay, scale, units, precision) {
|
|
1189
1289
|
this.id = MathUtils.generateUUID();
|
|
1190
|
-
this.unit = "";
|
|
1191
|
-
this.scale = 1.0;
|
|
1192
1290
|
this.size = 10.0;
|
|
1193
1291
|
this.lineWidth = 2;
|
|
1194
1292
|
this.style = {
|
|
@@ -1199,6 +1297,9 @@ class MeasureLine {
|
|
|
1199
1297
|
font: "1rem system-ui",
|
|
1200
1298
|
};
|
|
1201
1299
|
this.overlay = overlay;
|
|
1300
|
+
this.scale = scale;
|
|
1301
|
+
this.units = units;
|
|
1302
|
+
this.precision = precision;
|
|
1202
1303
|
this.elementStartPoint = overlay.container.appendChild(document.createElement("div"));
|
|
1203
1304
|
this.elementEndPoint = overlay.container.appendChild(document.createElement("div"));
|
|
1204
1305
|
this.elementLine = overlay.container.appendChild(document.createElement("div"));
|
|
@@ -1253,10 +1354,10 @@ class MeasureLine {
|
|
|
1253
1354
|
_middlePoint.lerpVectors(this.startPoint, this.endPoint, 0.5);
|
|
1254
1355
|
const { point, visible } = projector.projectPoint(_middlePoint);
|
|
1255
1356
|
const distance = this.getDistance();
|
|
1256
|
-
this.elementLabel.style.display = visible && distance
|
|
1357
|
+
this.elementLabel.style.display = visible && distance > 0 ? "block" : "none";
|
|
1257
1358
|
this.elementLabel.style.left = `${point.x}px`;
|
|
1258
1359
|
this.elementLabel.style.top = `${point.y}px`;
|
|
1259
|
-
this.elementLabel.innerHTML =
|
|
1360
|
+
this.elementLabel.innerHTML = formatDistance(distance, this.units, this.precision);
|
|
1260
1361
|
}
|
|
1261
1362
|
else {
|
|
1262
1363
|
this.elementLabel.style.display = "none";
|
|
@@ -2060,7 +2161,8 @@ function clearSelected(viewer) {
|
|
|
2060
2161
|
const selection = viewer.getComponent("SelectionComponent");
|
|
2061
2162
|
selection.clearSelection();
|
|
2062
2163
|
viewer.update();
|
|
2063
|
-
viewer.emitEvent({ type: "select",
|
|
2164
|
+
viewer.emitEvent({ type: "select", handles: [] });
|
|
2165
|
+
viewer.emitEvent({ type: "select2", handles: [] });
|
|
2064
2166
|
}
|
|
2065
2167
|
|
|
2066
2168
|
function clearSlices(viewer) {
|
|
@@ -2149,22 +2251,31 @@ function getDefaultViewPositions() {
|
|
|
2149
2251
|
}
|
|
2150
2252
|
|
|
2151
2253
|
function getModels(viewer) {
|
|
2152
|
-
return viewer.models.map((model) => model.
|
|
2254
|
+
return viewer.models.map((model) => model.id);
|
|
2153
2255
|
}
|
|
2154
2256
|
|
|
2155
2257
|
function getSelected(viewer) {
|
|
2156
|
-
const
|
|
2157
|
-
|
|
2258
|
+
const handles2 = viewer.executeCommand("getSelected2");
|
|
2259
|
+
const handles = handles2.map((handle) => handle.slice(handle.indexOf(":") + 1));
|
|
2158
2260
|
return handles;
|
|
2159
2261
|
}
|
|
2160
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
|
+
|
|
2161
2271
|
function hideSelected(viewer) {
|
|
2162
2272
|
viewer.models.forEach((model) => model.hideObjects(viewer.selected));
|
|
2163
2273
|
const selection = viewer.getComponent("SelectionComponent");
|
|
2164
2274
|
selection.clearSelection();
|
|
2165
2275
|
viewer.update();
|
|
2166
2276
|
viewer.emitEvent({ type: "hide" });
|
|
2167
|
-
viewer.emitEvent({ type: "select",
|
|
2277
|
+
viewer.emitEvent({ type: "select", handles: [] });
|
|
2278
|
+
viewer.emitEvent({ type: "select2", handles: [] });
|
|
2168
2279
|
}
|
|
2169
2280
|
|
|
2170
2281
|
function isolateSelected(viewer) {
|
|
@@ -2191,14 +2302,13 @@ function resetView(viewer) {
|
|
|
2191
2302
|
viewer.emit({ type: "resetview" });
|
|
2192
2303
|
}
|
|
2193
2304
|
|
|
2194
|
-
function selectModel(viewer,
|
|
2305
|
+
function selectModel(viewer, id) {
|
|
2195
2306
|
const selection = viewer.getComponent("SelectionComponent");
|
|
2196
2307
|
selection.clearSelection();
|
|
2197
|
-
viewer.models
|
|
2198
|
-
.filter((model) => model.handle === handle)
|
|
2199
|
-
.forEach((model) => selection.select(model.getObjects(), model));
|
|
2308
|
+
viewer.models.filter((model) => model.id === id).forEach((model) => selection.select(model.getObjects(), model));
|
|
2200
2309
|
viewer.update();
|
|
2201
|
-
viewer.
|
|
2310
|
+
viewer.emitEvent({ type: "select", handles: viewer.getSelected() });
|
|
2311
|
+
viewer.emitEvent({ type: "select2", handles: viewer.getSelected2() });
|
|
2202
2312
|
}
|
|
2203
2313
|
|
|
2204
2314
|
function setActiveDragger(viewer, dragger = "") {
|
|
@@ -2210,16 +2320,31 @@ function setMarkupColor(viewer, r = 255, g = 0, b = 0) {
|
|
|
2210
2320
|
}
|
|
2211
2321
|
|
|
2212
2322
|
function setSelected(viewer, handles = []) {
|
|
2213
|
-
const
|
|
2214
|
-
|
|
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();
|
|
2215
2339
|
viewer.models.forEach((model) => {
|
|
2216
2340
|
const objects = model.getObjectsByHandles(handles);
|
|
2217
2341
|
model.showObjects(objects);
|
|
2218
|
-
|
|
2342
|
+
selectionComponent.select(objects, model);
|
|
2219
2343
|
});
|
|
2220
2344
|
viewer.update();
|
|
2221
2345
|
viewer.emitEvent({ type: "show" });
|
|
2222
|
-
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 });
|
|
2223
2348
|
}
|
|
2224
2349
|
|
|
2225
2350
|
function showAll(viewer) {
|
|
@@ -2233,21 +2358,19 @@ function zoomToExtents(viewer) {
|
|
|
2233
2358
|
}
|
|
2234
2359
|
|
|
2235
2360
|
function zoomToObjects(viewer, handles = []) {
|
|
2236
|
-
const
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
if (handleSet.has((_a = child.userData) === null || _a === void 0 ? void 0 : _a.handle))
|
|
2241
|
-
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));
|
|
2242
2365
|
});
|
|
2243
|
-
const extents = objects.reduce((result, object) => result.expandByObject(object), new Box3());
|
|
2244
2366
|
if (extents.isEmpty())
|
|
2245
2367
|
extents.copy(viewer.extents);
|
|
2246
2368
|
zoomTo(viewer, extents);
|
|
2247
2369
|
}
|
|
2248
2370
|
|
|
2249
2371
|
function zoomToSelected(viewer) {
|
|
2250
|
-
const extents =
|
|
2372
|
+
const extents = new Box3();
|
|
2373
|
+
viewer.selected.forEach((object) => extents.expandByObject(object));
|
|
2251
2374
|
if (extents.isEmpty())
|
|
2252
2375
|
extents.copy(viewer.extents);
|
|
2253
2376
|
zoomTo(viewer, extents);
|
|
@@ -2264,6 +2387,7 @@ commands.registerCommand("explode", explode);
|
|
|
2264
2387
|
commands.registerCommand("getDefaultViewPositions", getDefaultViewPositions);
|
|
2265
2388
|
commands.registerCommand("getModels", getModels);
|
|
2266
2389
|
commands.registerCommand("getSelected", getSelected);
|
|
2390
|
+
commands.registerCommand("getSelected2", getSelected2);
|
|
2267
2391
|
commands.registerCommand("hideSelected", hideSelected);
|
|
2268
2392
|
commands.registerCommand("isolateSelected", isolateSelected);
|
|
2269
2393
|
commands.registerCommand("regenerateAll", regenerateAll);
|
|
@@ -2273,6 +2397,7 @@ commands.registerCommand("setActiveDragger", setActiveDragger);
|
|
|
2273
2397
|
commands.registerCommand("setDefaultViewPosition", setDefaultViewPosition);
|
|
2274
2398
|
commands.registerCommand("setMarkupColor", setMarkupColor);
|
|
2275
2399
|
commands.registerCommand("setSelected", setSelected);
|
|
2400
|
+
commands.registerCommand("setSelected2", setSelected2);
|
|
2276
2401
|
commands.registerCommand("showAll", showAll);
|
|
2277
2402
|
commands.registerCommand("zoomToExtents", zoomToExtents);
|
|
2278
2403
|
commands.registerCommand("zoomToObjects", zoomToObjects);
|
|
@@ -2325,6 +2450,10 @@ class CameraComponent {
|
|
|
2325
2450
|
this.switchCameraMode(this.viewer.options.cameraMode);
|
|
2326
2451
|
};
|
|
2327
2452
|
this.geometryEnd = () => {
|
|
2453
|
+
if (this.viewer.models.length > 1) {
|
|
2454
|
+
this.switchCamera(this.viewer.camera);
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2328
2457
|
let camera;
|
|
2329
2458
|
this.viewer.scene.traverse((object) => {
|
|
2330
2459
|
if (object.isCamera)
|
|
@@ -2422,6 +2551,8 @@ class ExtentsComponent {
|
|
|
2422
2551
|
const extents = new Box3();
|
|
2423
2552
|
this.viewer.models.forEach((model) => model.getExtents(extents));
|
|
2424
2553
|
this.viewer.extents.copy(extents);
|
|
2554
|
+
if (this.viewer.models.length > 1)
|
|
2555
|
+
return;
|
|
2425
2556
|
this.viewer.extents.getCenter(this.viewer.target);
|
|
2426
2557
|
};
|
|
2427
2558
|
this.viewer = viewer;
|
|
@@ -2749,10 +2880,11 @@ class SelectionComponent {
|
|
|
2749
2880
|
const upPosition = this.getMousePosition(event, new Vector2());
|
|
2750
2881
|
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
2751
2882
|
return;
|
|
2883
|
+
const snapper = new Snapper(this.viewer.camera, this.viewer.renderer, this.viewer.canvas);
|
|
2752
2884
|
let intersections = [];
|
|
2753
2885
|
this.viewer.models.forEach((model) => {
|
|
2754
2886
|
const objects = model.getVisibleObjects();
|
|
2755
|
-
const intersects =
|
|
2887
|
+
const intersects = snapper.getPointerIntersects(upPosition, objects);
|
|
2756
2888
|
if (intersects.length > 0)
|
|
2757
2889
|
intersections.push({ ...intersects[0], model });
|
|
2758
2890
|
});
|
|
@@ -2770,6 +2902,7 @@ class SelectionComponent {
|
|
|
2770
2902
|
}
|
|
2771
2903
|
this.viewer.update();
|
|
2772
2904
|
this.viewer.emitEvent({ type: "select", data: undefined, handles: this.viewer.getSelected() });
|
|
2905
|
+
this.viewer.emitEvent({ type: "select2", data: undefined, handles: this.viewer.getSelected2() });
|
|
2773
2906
|
};
|
|
2774
2907
|
this.onDoubleClick = (event) => {
|
|
2775
2908
|
if (event.button !== 0)
|
|
@@ -2780,7 +2913,6 @@ class SelectionComponent {
|
|
|
2780
2913
|
this.highlighter = this.viewer.getComponent("HighlighterComponent");
|
|
2781
2914
|
};
|
|
2782
2915
|
this.viewer = viewer;
|
|
2783
|
-
this.raycaster = new Raycaster();
|
|
2784
2916
|
this.downPosition = new Vector2();
|
|
2785
2917
|
this.viewer.addEventListener("pointerdown", this.onPointerDown);
|
|
2786
2918
|
this.viewer.addEventListener("pointerup", this.onPointerUp);
|
|
@@ -2796,26 +2928,6 @@ class SelectionComponent {
|
|
|
2796
2928
|
getMousePosition(event, target) {
|
|
2797
2929
|
return target.set(event.clientX, event.clientY);
|
|
2798
2930
|
}
|
|
2799
|
-
getPointerIntersects(mouse, objects) {
|
|
2800
|
-
const rect = this.viewer.canvas.getBoundingClientRect();
|
|
2801
|
-
const x = ((mouse.x - rect.left) / rect.width) * 2 - 1;
|
|
2802
|
-
const y = (-(mouse.y - rect.top) / rect.height) * 2 + 1;
|
|
2803
|
-
const coords = new Vector2(x, y);
|
|
2804
|
-
this.raycaster.setFromCamera(coords, this.viewer.camera);
|
|
2805
|
-
this.raycaster.params = {
|
|
2806
|
-
Mesh: {},
|
|
2807
|
-
Line: { threshold: 0.05 },
|
|
2808
|
-
Line2: { threshold: 0.05 },
|
|
2809
|
-
LOD: {},
|
|
2810
|
-
Points: { threshold: 0.01 },
|
|
2811
|
-
Sprite: {},
|
|
2812
|
-
};
|
|
2813
|
-
let intersects = this.raycaster.intersectObjects(objects, false);
|
|
2814
|
-
(this.viewer.renderer.clippingPlanes || []).forEach((plane) => {
|
|
2815
|
-
intersects = intersects.filter((intersect) => plane.distanceToPoint(intersect.point) >= 0);
|
|
2816
|
-
});
|
|
2817
|
-
return intersects;
|
|
2818
|
-
}
|
|
2819
2931
|
select(objects, model) {
|
|
2820
2932
|
if (!model) {
|
|
2821
2933
|
this.viewer.models.forEach((model) => this.select(objects, model));
|
|
@@ -3014,48 +3126,8 @@ components.registerComponent("SelectionComponent", (viewer) => new SelectionComp
|
|
|
3014
3126
|
components.registerComponent("WCSHelperComponent", (viewer) => new WCSHelperComponent(viewer));
|
|
3015
3127
|
components.registerComponent("ResetComponent", (viewer) => new ResetComponent(viewer));
|
|
3016
3128
|
|
|
3017
|
-
class GLTFLoadingManager extends LoadingManager {
|
|
3018
|
-
constructor(file, params = {}) {
|
|
3019
|
-
super();
|
|
3020
|
-
this.path = "";
|
|
3021
|
-
this.resourcePath = "";
|
|
3022
|
-
this.fileURL = "";
|
|
3023
|
-
this.dataURLs = new Map();
|
|
3024
|
-
this.path = params.path || "";
|
|
3025
|
-
const externalFiles = params.externalFiles || new Map();
|
|
3026
|
-
if (typeof file === "string") {
|
|
3027
|
-
this.fileURL = file;
|
|
3028
|
-
this.resourcePath = LoaderUtils.extractUrlBase(file);
|
|
3029
|
-
}
|
|
3030
|
-
else {
|
|
3031
|
-
externalFiles.forEach((value, key) => (this.fileURL = value === file ? key : this.fileURL));
|
|
3032
|
-
externalFiles.set(this.fileURL, file);
|
|
3033
|
-
}
|
|
3034
|
-
externalFiles.forEach((value, key) => {
|
|
3035
|
-
let dataURL;
|
|
3036
|
-
if (typeof value === "string")
|
|
3037
|
-
dataURL = value;
|
|
3038
|
-
else
|
|
3039
|
-
dataURL = URL.createObjectURL(new Blob([value]));
|
|
3040
|
-
this.dataURLs.set(key, dataURL);
|
|
3041
|
-
});
|
|
3042
|
-
this.setURLModifier((url) => {
|
|
3043
|
-
const key = decodeURI(url)
|
|
3044
|
-
.replace(this.path, "")
|
|
3045
|
-
.replace(this.resourcePath, "")
|
|
3046
|
-
.replace(/^(\.?\/)/, "");
|
|
3047
|
-
const dataURL = this.dataURLs.get(key);
|
|
3048
|
-
return dataURL !== null && dataURL !== void 0 ? dataURL : url;
|
|
3049
|
-
});
|
|
3050
|
-
}
|
|
3051
|
-
dispose() {
|
|
3052
|
-
this.dataURLs.forEach(URL.revokeObjectURL);
|
|
3053
|
-
}
|
|
3054
|
-
}
|
|
3055
|
-
|
|
3056
3129
|
class ModelImpl {
|
|
3057
3130
|
constructor(scene) {
|
|
3058
|
-
this.handle = "1";
|
|
3059
3131
|
this.scene = scene;
|
|
3060
3132
|
}
|
|
3061
3133
|
dispose() {
|
|
@@ -3075,6 +3147,18 @@ class ModelImpl {
|
|
|
3075
3147
|
this.scene.traverse(disposeObject);
|
|
3076
3148
|
this.scene.clear();
|
|
3077
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
|
+
}
|
|
3078
3162
|
getExtents(target) {
|
|
3079
3163
|
this.scene.traverseVisible((object) => !object.children.length && target.expandByObject(object));
|
|
3080
3164
|
return target;
|
|
@@ -3097,27 +3181,45 @@ class ModelImpl {
|
|
|
3097
3181
|
}
|
|
3098
3182
|
return false;
|
|
3099
3183
|
}
|
|
3184
|
+
hasHandle(handle) {
|
|
3185
|
+
return !handle.includes(":") || handle.split(":", 1)[0] === this.id + "";
|
|
3186
|
+
}
|
|
3100
3187
|
getOwnObjects(objects) {
|
|
3101
3188
|
if (!Array.isArray(objects))
|
|
3102
3189
|
objects = [objects];
|
|
3103
3190
|
return objects.filter((object) => this.hasObject(object));
|
|
3104
3191
|
}
|
|
3192
|
+
getOwnHandles(handles) {
|
|
3193
|
+
if (!Array.isArray(handles))
|
|
3194
|
+
handles = [handles];
|
|
3195
|
+
return handles.filter((handle) => this.hasHandle(handle));
|
|
3196
|
+
}
|
|
3105
3197
|
getObjectsByHandles(handles) {
|
|
3106
|
-
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)));
|
|
3107
3202
|
const objects = [];
|
|
3108
|
-
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
|
+
});
|
|
3109
3208
|
return objects;
|
|
3110
3209
|
}
|
|
3111
3210
|
getHandlesByObjects(objects) {
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
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);
|
|
3117
3221
|
}
|
|
3118
3222
|
hideObjects(objects) {
|
|
3119
|
-
if (!Array.isArray(objects))
|
|
3120
|
-
objects = [objects];
|
|
3121
3223
|
this.getOwnObjects(objects).forEach((object) => (object.visible = false));
|
|
3122
3224
|
return this;
|
|
3123
3225
|
}
|
|
@@ -3133,8 +3235,6 @@ class ModelImpl {
|
|
|
3133
3235
|
return this;
|
|
3134
3236
|
}
|
|
3135
3237
|
showObjects(objects) {
|
|
3136
|
-
if (!Array.isArray(objects))
|
|
3137
|
-
objects = [objects];
|
|
3138
3238
|
this.getOwnObjects(objects).forEach((object) => {
|
|
3139
3239
|
object.visible = true;
|
|
3140
3240
|
object.traverseAncestors((parent) => (parent.visible = true));
|
|
@@ -3190,42 +3290,6 @@ class ModelImpl {
|
|
|
3190
3290
|
}
|
|
3191
3291
|
}
|
|
3192
3292
|
|
|
3193
|
-
class GLTFFileLoader extends Loader {
|
|
3194
|
-
constructor(viewer) {
|
|
3195
|
-
super();
|
|
3196
|
-
this.viewer = viewer;
|
|
3197
|
-
}
|
|
3198
|
-
isSupport(file, format) {
|
|
3199
|
-
return ((typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
|
|
3200
|
-
/(gltf|glb)$/i.test(format));
|
|
3201
|
-
}
|
|
3202
|
-
async load(file, format, params) {
|
|
3203
|
-
const manager = new GLTFLoadingManager(file, params);
|
|
3204
|
-
const loader = new GLTFLoader(manager);
|
|
3205
|
-
loader.setPath(manager.path);
|
|
3206
|
-
loader.setCrossOrigin(params.crossOrigin || loader.crossOrigin);
|
|
3207
|
-
loader.setWithCredentials(params.withCredentials || loader.withCredentials);
|
|
3208
|
-
const progress = (event) => {
|
|
3209
|
-
const { lengthComputable, loaded, total } = event;
|
|
3210
|
-
const progress = lengthComputable ? loaded / total : 1;
|
|
3211
|
-
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
|
|
3212
|
-
};
|
|
3213
|
-
const gltf = await loader.loadAsync(manager.fileURL, progress);
|
|
3214
|
-
if (!this.viewer.scene)
|
|
3215
|
-
return this;
|
|
3216
|
-
const modelImpl = new ModelImpl(gltf.scene);
|
|
3217
|
-
modelImpl.loader = this;
|
|
3218
|
-
modelImpl.viewer = this.viewer;
|
|
3219
|
-
this.viewer.scene.add(gltf.scene);
|
|
3220
|
-
this.viewer.models.push(modelImpl);
|
|
3221
|
-
this.viewer.syncOptions();
|
|
3222
|
-
this.viewer.syncOverlay();
|
|
3223
|
-
this.viewer.update();
|
|
3224
|
-
this.viewer.emitEvent({ type: "databasechunk", data: gltf.scene, file });
|
|
3225
|
-
return this;
|
|
3226
|
-
}
|
|
3227
|
-
}
|
|
3228
|
-
|
|
3229
3293
|
class DynamicModelImpl extends ModelImpl {
|
|
3230
3294
|
getExtents(target) {
|
|
3231
3295
|
return target.union(this.gltfLoader.getTotalGeometryExtent());
|
|
@@ -3244,31 +3308,40 @@ class DynamicModelImpl extends ModelImpl {
|
|
|
3244
3308
|
return this.gltfLoader.originalObjects.has(object);
|
|
3245
3309
|
}
|
|
3246
3310
|
getObjectsByHandles(handles) {
|
|
3247
|
-
const
|
|
3311
|
+
const ownHandles = this.getOwnHandles(handles);
|
|
3312
|
+
if (ownHandles.length === 0)
|
|
3313
|
+
return [];
|
|
3314
|
+
const handlesSet = new Set(ownHandles);
|
|
3248
3315
|
const objects = [];
|
|
3249
3316
|
handlesSet.forEach((handle) => {
|
|
3250
|
-
|
|
3251
|
-
const handles = this.gltfLoader.handleToObjects.get(handle2) || [];
|
|
3252
|
-
objects.push(...Array.from(handles));
|
|
3317
|
+
objects.push(...this.gltfLoader.getObjectsByHandle(handle));
|
|
3253
3318
|
});
|
|
3254
3319
|
return objects;
|
|
3255
3320
|
}
|
|
3256
3321
|
getHandlesByObjects(objects) {
|
|
3257
|
-
const
|
|
3258
|
-
|
|
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);
|
|
3259
3332
|
}
|
|
3260
3333
|
hideObjects(objects) {
|
|
3261
|
-
const handles =
|
|
3334
|
+
const handles = this.getHandlesByObjects(objects);
|
|
3262
3335
|
this.gltfLoader.hideObjects(handles);
|
|
3263
3336
|
return this;
|
|
3264
3337
|
}
|
|
3265
3338
|
isolateObjects(objects) {
|
|
3266
|
-
const handles =
|
|
3339
|
+
const handles = this.getHandlesByObjects(objects);
|
|
3267
3340
|
this.gltfLoader.isolateObjects(new Set(handles));
|
|
3268
3341
|
return this;
|
|
3269
3342
|
}
|
|
3270
3343
|
showObjects(objects) {
|
|
3271
|
-
const handles =
|
|
3344
|
+
const handles = this.getHandlesByObjects(objects);
|
|
3272
3345
|
this.gltfLoader.showObjects(handles);
|
|
3273
3346
|
return this;
|
|
3274
3347
|
}
|
|
@@ -3332,11 +3405,14 @@ class GltfStructure {
|
|
|
3332
3405
|
this.materials = new Map();
|
|
3333
3406
|
this.textureCache = new Map();
|
|
3334
3407
|
this.materialCache = new Map();
|
|
3408
|
+
this.uri = "";
|
|
3409
|
+
this._nextObjectId = 0;
|
|
3335
3410
|
}
|
|
3336
3411
|
async initialize(loader) {
|
|
3337
3412
|
this.json = await this.loadController.loadJson();
|
|
3338
3413
|
this.baseUrl = await this.loadController.baseUrl();
|
|
3339
3414
|
this.loader = loader;
|
|
3415
|
+
this.uri = this.json.buffers[0].uri || "";
|
|
3340
3416
|
}
|
|
3341
3417
|
clear() {
|
|
3342
3418
|
this.json = null;
|
|
@@ -3430,7 +3506,7 @@ class GltfStructure {
|
|
|
3430
3506
|
await this.loader.waitForChunkSlot();
|
|
3431
3507
|
try {
|
|
3432
3508
|
const length = range.end - range.start;
|
|
3433
|
-
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }]);
|
|
3509
|
+
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }], this.uri);
|
|
3434
3510
|
for (const req of range.requests) {
|
|
3435
3511
|
const relOffset = req.offset - range.start;
|
|
3436
3512
|
try {
|
|
@@ -3747,6 +3823,7 @@ class GltfStructure {
|
|
|
3747
3823
|
}
|
|
3748
3824
|
}
|
|
3749
3825
|
|
|
3826
|
+
const STRUCTURE_ID_SEPARATOR = ":";
|
|
3750
3827
|
class DynamicGltfLoader {
|
|
3751
3828
|
constructor(camera, scene, renderer) {
|
|
3752
3829
|
this.camera = camera;
|
|
@@ -3759,6 +3836,7 @@ class DynamicGltfLoader {
|
|
|
3759
3836
|
geometryerror: [],
|
|
3760
3837
|
update: [],
|
|
3761
3838
|
geometrymemory: [],
|
|
3839
|
+
optimizationprogress: [],
|
|
3762
3840
|
};
|
|
3763
3841
|
this.loadDistance = 100;
|
|
3764
3842
|
this.unloadDistance = 150;
|
|
@@ -3800,7 +3878,6 @@ class DynamicGltfLoader {
|
|
|
3800
3878
|
this.hiddenHandles = new Set();
|
|
3801
3879
|
this.newOptimizedObjects = new Set();
|
|
3802
3880
|
this.oldOptimizeObjects = new Set();
|
|
3803
|
-
this.maxConcurrentChunks = 8;
|
|
3804
3881
|
this.activeChunkLoads = 0;
|
|
3805
3882
|
this.chunkQueue = [];
|
|
3806
3883
|
this.objectIdToIndex = new Map();
|
|
@@ -3809,6 +3886,7 @@ class DynamicGltfLoader {
|
|
|
3809
3886
|
this.maxConcurrentChunks = 6;
|
|
3810
3887
|
this.mergedObjectMap = new Map();
|
|
3811
3888
|
this.mergedGeometryVisibility = new Map();
|
|
3889
|
+
this._webglInfoCache = null;
|
|
3812
3890
|
}
|
|
3813
3891
|
setVisibleEdges(visible) {
|
|
3814
3892
|
this.visibleEdges = visible;
|
|
@@ -3912,6 +3990,123 @@ class DynamicGltfLoader {
|
|
|
3912
3990
|
this.updateMemoryIndicator();
|
|
3913
3991
|
console.log(`Final memory usage: ${Math.round(currentMemoryUsage / (1024 * 1024))}MB`);
|
|
3914
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
|
+
}
|
|
3915
4110
|
async loadNode(nodeId, onLoadFinishCb) {
|
|
3916
4111
|
const node = this.nodes.get(nodeId);
|
|
3917
4112
|
if (!node || node.loaded || node.loading) return;
|
|
@@ -4082,7 +4277,7 @@ class DynamicGltfLoader {
|
|
|
4082
4277
|
if (node.handle) {
|
|
4083
4278
|
mesh.userData.handle = node.handle;
|
|
4084
4279
|
} else {
|
|
4085
|
-
mesh.userData.handle =
|
|
4280
|
+
mesh.userData.handle = this.getFullHandle(node.structure.id, mesh.userData.handle);
|
|
4086
4281
|
}
|
|
4087
4282
|
if (mesh.material.name === "edges") {
|
|
4088
4283
|
mesh.userData.isEdge = true;
|
|
@@ -4223,12 +4418,15 @@ class DynamicGltfLoader {
|
|
|
4223
4418
|
})),
|
|
4224
4419
|
});
|
|
4225
4420
|
}
|
|
4421
|
+
getFullHandle(structureId, originalHandle) {
|
|
4422
|
+
return `${structureId}${STRUCTURE_ID_SEPARATOR}${originalHandle}`;
|
|
4423
|
+
}
|
|
4226
4424
|
async processNodeHierarchy(structure, nodeId, parentGroup) {
|
|
4227
4425
|
const nodeDef = structure.json.nodes[nodeId];
|
|
4228
4426
|
let nodeGroup = null;
|
|
4229
4427
|
let handle = null;
|
|
4230
4428
|
if (nodeDef.extras?.handle) {
|
|
4231
|
-
handle =
|
|
4429
|
+
handle = this.getFullHandle(structure.id, nodeDef.extras.handle);
|
|
4232
4430
|
}
|
|
4233
4431
|
if (nodeDef.camera !== undefined) {
|
|
4234
4432
|
const camera = this.loadCamera(structure, nodeDef.camera, nodeDef);
|
|
@@ -4245,7 +4443,7 @@ class DynamicGltfLoader {
|
|
|
4245
4443
|
if (nodeDef.extras) {
|
|
4246
4444
|
nodeGroup.userData = { ...nodeDef.extras };
|
|
4247
4445
|
if (nodeGroup.userData.handle) {
|
|
4248
|
-
nodeGroup.userData.handle =
|
|
4446
|
+
nodeGroup.userData.handle = this.getFullHandle(structure.id, nodeGroup.userData.handle);
|
|
4249
4447
|
}
|
|
4250
4448
|
}
|
|
4251
4449
|
if (nodeDef.matrix) {
|
|
@@ -4290,7 +4488,7 @@ class DynamicGltfLoader {
|
|
|
4290
4488
|
this.edgeNodes.push(uniqueNodeId);
|
|
4291
4489
|
}
|
|
4292
4490
|
if (meshDef.extras && meshDef.extras.handle) {
|
|
4293
|
-
handle =
|
|
4491
|
+
handle = this.getFullHandle(structure.id, meshDef.extras.handle);
|
|
4294
4492
|
}
|
|
4295
4493
|
this.nodes.set(uniqueNodeId, {
|
|
4296
4494
|
position: nodeGroup ? nodeGroup.position.clone() : new Vector3().setFromMatrixPosition(nodeMatrix),
|
|
@@ -4303,7 +4501,7 @@ class DynamicGltfLoader {
|
|
|
4303
4501
|
structure,
|
|
4304
4502
|
extras: nodeDef.extras,
|
|
4305
4503
|
geometryExtents,
|
|
4306
|
-
handle,
|
|
4504
|
+
handle: handle || this.getFullHandle(structure.id, structure._nextObjectId++),
|
|
4307
4505
|
});
|
|
4308
4506
|
}
|
|
4309
4507
|
if (nodeDef.children) {
|
|
@@ -4376,12 +4574,12 @@ class DynamicGltfLoader {
|
|
|
4376
4574
|
}
|
|
4377
4575
|
}
|
|
4378
4576
|
async loadNodes() {
|
|
4379
|
-
console.time("
|
|
4577
|
+
console.time("Process nodes");
|
|
4380
4578
|
await this.processNodes();
|
|
4381
|
-
console.timeEnd("
|
|
4382
|
-
console.time("
|
|
4579
|
+
console.timeEnd("Process nodes");
|
|
4580
|
+
console.time("Optimize scene");
|
|
4383
4581
|
await this.optimizeScene();
|
|
4384
|
-
console.timeEnd("
|
|
4582
|
+
console.timeEnd("Optimize scene");
|
|
4385
4583
|
}
|
|
4386
4584
|
cleanupPartialLoad() {
|
|
4387
4585
|
this.nodesToLoad.forEach((nodeId) => {
|
|
@@ -4702,7 +4900,7 @@ class DynamicGltfLoader {
|
|
|
4702
4900
|
this.handleToObjects.set(fullHandle, new Set());
|
|
4703
4901
|
}
|
|
4704
4902
|
this.handleToObjects.get(fullHandle).add(object);
|
|
4705
|
-
object.userData.structureId = object.userData.handle.split(
|
|
4903
|
+
object.userData.structureId = object.userData.handle.split(STRUCTURE_ID_SEPARATOR)[0];
|
|
4706
4904
|
}
|
|
4707
4905
|
getObjectsByHandle(handle) {
|
|
4708
4906
|
if (!handle) return [];
|
|
@@ -4768,10 +4966,28 @@ class DynamicGltfLoader {
|
|
|
4768
4966
|
}
|
|
4769
4967
|
this.originalObjects.add(object);
|
|
4770
4968
|
}
|
|
4771
|
-
|
|
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
|
+
});
|
|
4772
4983
|
this.originalObjects.clear();
|
|
4773
4984
|
this.originalObjectsToSelection.clear();
|
|
4774
4985
|
const structureGroups = new Map();
|
|
4986
|
+
this.dispatchEvent("optimizationprogress", {
|
|
4987
|
+
phase: "collecting",
|
|
4988
|
+
progress: 5,
|
|
4989
|
+
message: "Collecting scene objects...",
|
|
4990
|
+
});
|
|
4775
4991
|
this.scene.traverse((object) => {
|
|
4776
4992
|
if (object.userData.structureId) {
|
|
4777
4993
|
const structureId = object.userData.structureId;
|
|
@@ -4800,16 +5016,44 @@ class DynamicGltfLoader {
|
|
|
4800
5016
|
}
|
|
4801
5017
|
}
|
|
4802
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
|
+
});
|
|
4803
5028
|
for (const group of structureGroups.values()) {
|
|
4804
5029
|
group.mapMeshes.clear();
|
|
4805
5030
|
group.mapLines.clear();
|
|
4806
5031
|
group.mapLineSegments.clear();
|
|
4807
5032
|
group.mapPoints.clear();
|
|
4808
|
-
this.mergeMeshGroups(group.meshes, group.rootGroup);
|
|
4809
|
-
this.
|
|
4810
|
-
this.
|
|
4811
|
-
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();
|
|
4812
5051
|
}
|
|
5052
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5053
|
+
phase: "finalizing",
|
|
5054
|
+
progress: 95,
|
|
5055
|
+
message: "Finalizing optimization...",
|
|
5056
|
+
});
|
|
4813
5057
|
this.originalObjects.forEach((obj) => {
|
|
4814
5058
|
obj.visible = false;
|
|
4815
5059
|
if (!(obj instanceof Points) && !obj.userData.isEdge) {
|
|
@@ -4818,9 +5062,15 @@ class DynamicGltfLoader {
|
|
|
4818
5062
|
});
|
|
4819
5063
|
this.initializeObjectVisibility();
|
|
4820
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
|
+
});
|
|
4821
5070
|
this.dispatchEvent("update");
|
|
4822
5071
|
}
|
|
4823
|
-
mergeMeshGroups(materialGroups, rootGroup) {
|
|
5072
|
+
async mergeMeshGroups(materialGroups, rootGroup) {
|
|
5073
|
+
let processedGroups = 0;
|
|
4824
5074
|
for (const group of materialGroups) {
|
|
4825
5075
|
if (!group.material) {
|
|
4826
5076
|
console.warn("Skipping mesh group with null material");
|
|
@@ -4834,8 +5084,6 @@ class DynamicGltfLoader {
|
|
|
4834
5084
|
let currentVertexOffset = 0;
|
|
4835
5085
|
for (const mesh of group.objects) {
|
|
4836
5086
|
const geometry = mesh.geometry.clone();
|
|
4837
|
-
mesh.updateWorldMatrix(true, false);
|
|
4838
|
-
geometry.applyMatrix4(mesh.matrixWorld);
|
|
4839
5087
|
const handle = mesh.userData.handle;
|
|
4840
5088
|
if (!this.objectIdToIndex.has(handle)) {
|
|
4841
5089
|
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
@@ -4894,6 +5142,10 @@ class DynamicGltfLoader {
|
|
|
4894
5142
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
4895
5143
|
}
|
|
4896
5144
|
});
|
|
5145
|
+
processedGroups++;
|
|
5146
|
+
if (processedGroups % 5 === 0) {
|
|
5147
|
+
await this.yieldToUI();
|
|
5148
|
+
}
|
|
4897
5149
|
} catch (error) {
|
|
4898
5150
|
console.error("Failed to merge meshes for material:", error);
|
|
4899
5151
|
group.objects.forEach((mesh) => {
|
|
@@ -4902,7 +5154,8 @@ class DynamicGltfLoader {
|
|
|
4902
5154
|
}
|
|
4903
5155
|
}
|
|
4904
5156
|
}
|
|
4905
|
-
mergeLineGroups(materialGroups, rootGroup) {
|
|
5157
|
+
async mergeLineGroups(materialGroups, rootGroup) {
|
|
5158
|
+
let processedGroups = 0;
|
|
4906
5159
|
for (const group of materialGroups) {
|
|
4907
5160
|
if (group.objects.length === 0) continue;
|
|
4908
5161
|
if (!group.material) {
|
|
@@ -4921,7 +5174,9 @@ class DynamicGltfLoader {
|
|
|
4921
5174
|
let posOffset = 0;
|
|
4922
5175
|
const indices = [];
|
|
4923
5176
|
let vertexOffset = 0;
|
|
5177
|
+
let isEdge = false;
|
|
4924
5178
|
group.objects.forEach((line) => {
|
|
5179
|
+
isEdge = line.userData.isEdge;
|
|
4925
5180
|
const geometry = line.geometry;
|
|
4926
5181
|
const positionAttr = geometry.attributes.position;
|
|
4927
5182
|
const vertexCount = positionAttr.count;
|
|
@@ -4934,12 +5189,9 @@ class DynamicGltfLoader {
|
|
|
4934
5189
|
vertexCount,
|
|
4935
5190
|
});
|
|
4936
5191
|
currentVertexOffset += vertexCount;
|
|
4937
|
-
line.updateWorldMatrix(true, false);
|
|
4938
|
-
const matrix = line.matrixWorld;
|
|
4939
5192
|
const vector = new Vector3();
|
|
4940
5193
|
for (let i = 0; i < vertexCount; i++) {
|
|
4941
5194
|
vector.fromBufferAttribute(positionAttr, i);
|
|
4942
|
-
vector.applyMatrix4(matrix);
|
|
4943
5195
|
positions[posOffset++] = vector.x;
|
|
4944
5196
|
positions[posOffset++] = vector.y;
|
|
4945
5197
|
positions[posOffset++] = vector.z;
|
|
@@ -4972,6 +5224,7 @@ class DynamicGltfLoader {
|
|
|
4972
5224
|
geometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
4973
5225
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
4974
5226
|
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
5227
|
+
mergedLine.userData.isEdge = isEdge;
|
|
4975
5228
|
const mergedObjects = [mergedLine];
|
|
4976
5229
|
if (this.useVAO) {
|
|
4977
5230
|
this.createVAO(mergedLine);
|
|
@@ -4994,9 +5247,14 @@ class DynamicGltfLoader {
|
|
|
4994
5247
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
4995
5248
|
}
|
|
4996
5249
|
});
|
|
5250
|
+
processedGroups++;
|
|
5251
|
+
if (processedGroups % 5 === 0) {
|
|
5252
|
+
await this.yieldToUI();
|
|
5253
|
+
}
|
|
4997
5254
|
}
|
|
4998
5255
|
}
|
|
4999
|
-
mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
5256
|
+
async mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
5257
|
+
let processedGroups = 0;
|
|
5000
5258
|
for (const group of materialGroups) {
|
|
5001
5259
|
if (!group.material) {
|
|
5002
5260
|
console.warn("Skipping line segment group with null material");
|
|
@@ -5008,10 +5266,10 @@ class DynamicGltfLoader {
|
|
|
5008
5266
|
const handles = new Set();
|
|
5009
5267
|
const objectMapping = new Map();
|
|
5010
5268
|
let currentVertexOffset = 0;
|
|
5269
|
+
let isEdge = false;
|
|
5011
5270
|
for (const line of group.objects) {
|
|
5271
|
+
isEdge = line.userData.isEdge;
|
|
5012
5272
|
const geometry = line.geometry.clone();
|
|
5013
|
-
line.updateWorldMatrix(true, false);
|
|
5014
|
-
geometry.applyMatrix4(line.matrixWorld);
|
|
5015
5273
|
const handle = line.userData.handle;
|
|
5016
5274
|
if (!this.objectIdToIndex.has(handle)) {
|
|
5017
5275
|
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
@@ -5044,6 +5302,7 @@ class DynamicGltfLoader {
|
|
|
5044
5302
|
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
5045
5303
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
5046
5304
|
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
5305
|
+
mergedLine.userData.isEdge = isEdge;
|
|
5047
5306
|
if (this.useVAO) {
|
|
5048
5307
|
this.createVAO(mergedLine);
|
|
5049
5308
|
}
|
|
@@ -5070,6 +5329,10 @@ class DynamicGltfLoader {
|
|
|
5070
5329
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
5071
5330
|
}
|
|
5072
5331
|
});
|
|
5332
|
+
processedGroups++;
|
|
5333
|
+
if (processedGroups % 5 === 0) {
|
|
5334
|
+
await this.yieldToUI();
|
|
5335
|
+
}
|
|
5073
5336
|
} catch (error) {
|
|
5074
5337
|
console.warn("Failed to merge line segments for material:", error);
|
|
5075
5338
|
group.objects.forEach((line) => {
|
|
@@ -5078,7 +5341,8 @@ class DynamicGltfLoader {
|
|
|
5078
5341
|
}
|
|
5079
5342
|
}
|
|
5080
5343
|
}
|
|
5081
|
-
mergePointsGroups(materialGroups, rootGroup) {
|
|
5344
|
+
async mergePointsGroups(materialGroups, rootGroup) {
|
|
5345
|
+
let processedGroups = 0;
|
|
5082
5346
|
for (const group of materialGroups) {
|
|
5083
5347
|
if (!group.material) {
|
|
5084
5348
|
console.warn("Skipping points group with null material");
|
|
@@ -5090,8 +5354,6 @@ class DynamicGltfLoader {
|
|
|
5090
5354
|
const handles = new Set();
|
|
5091
5355
|
for (const points of group.objects) {
|
|
5092
5356
|
const geometry = points.geometry.clone();
|
|
5093
|
-
points.updateWorldMatrix(true, false);
|
|
5094
|
-
geometry.applyMatrix4(points.matrixWorld);
|
|
5095
5357
|
geometries.push(geometry);
|
|
5096
5358
|
optimizedObjects.push(points);
|
|
5097
5359
|
handles.add(points.userData.handle);
|
|
@@ -5120,6 +5382,10 @@ class DynamicGltfLoader {
|
|
|
5120
5382
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
5121
5383
|
}
|
|
5122
5384
|
});
|
|
5385
|
+
processedGroups++;
|
|
5386
|
+
if (processedGroups % 5 === 0) {
|
|
5387
|
+
await this.yieldToUI();
|
|
5388
|
+
}
|
|
5123
5389
|
} catch (error) {
|
|
5124
5390
|
console.warn("Failed to merge points for material:", error);
|
|
5125
5391
|
group.objects.forEach((points) => {
|
|
@@ -5138,7 +5404,6 @@ class DynamicGltfLoader {
|
|
|
5138
5404
|
const hasNormals = lineSegmentsArray.some((segment) => segment.geometry.attributes.normal !== undefined);
|
|
5139
5405
|
lineSegmentsArray.forEach((segment) => {
|
|
5140
5406
|
const clonedGeometry = segment.geometry.clone();
|
|
5141
|
-
segment.updateWorldMatrix(true, false);
|
|
5142
5407
|
clonedGeometry.applyMatrix4(segment.matrixWorld);
|
|
5143
5408
|
if (hasNormals && !clonedGeometry.attributes.normal) {
|
|
5144
5409
|
clonedGeometry.computeVertexNormals();
|
|
@@ -5355,8 +5620,225 @@ class DynamicGltfLoader {
|
|
|
5355
5620
|
}
|
|
5356
5621
|
}
|
|
5357
5622
|
|
|
5358
|
-
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 {
|
|
5359
5840
|
constructor(viewer) {
|
|
5841
|
+
super();
|
|
5360
5842
|
this.requestId = 0;
|
|
5361
5843
|
this.viewer = viewer;
|
|
5362
5844
|
}
|
|
@@ -5371,17 +5853,15 @@ class GLTFCloudDynamicLoader {
|
|
|
5371
5853
|
typeof file.downloadResourceRange === "function" &&
|
|
5372
5854
|
/.gltf$/i.test(file.database));
|
|
5373
5855
|
}
|
|
5374
|
-
async load(model, format, params) {
|
|
5856
|
+
async load(model, format, params = {}) {
|
|
5375
5857
|
const scene = new Group();
|
|
5376
5858
|
this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
|
|
5377
5859
|
this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
|
|
5378
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;
|
|
5379
5864
|
this.gltfLoader.addEventListener("databasechunk", (data) => {
|
|
5380
|
-
const modelImpl = new DynamicModelImpl(scene);
|
|
5381
|
-
modelImpl.loader = this;
|
|
5382
|
-
modelImpl.viewer = this.viewer;
|
|
5383
|
-
modelImpl.gltfLoader = this.gltfLoader;
|
|
5384
|
-
modelImpl.modelId = model.id;
|
|
5385
5865
|
this.viewer.scene.add(scene);
|
|
5386
5866
|
this.viewer.models.push(modelImpl);
|
|
5387
5867
|
this.viewer.syncOptions();
|
|
@@ -5389,10 +5869,6 @@ class GLTFCloudDynamicLoader {
|
|
|
5389
5869
|
this.viewer.update();
|
|
5390
5870
|
this.viewer.emitEvent({ type: "databasechunk", data: scene, file: model.file, model });
|
|
5391
5871
|
});
|
|
5392
|
-
this.gltfLoader.addEventListener("geometryprogress", (data) => {
|
|
5393
|
-
const progress = data.loaded / data.total;
|
|
5394
|
-
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model.file, model });
|
|
5395
|
-
});
|
|
5396
5872
|
this.gltfLoader.addEventListener("geometryerror", (data) => {
|
|
5397
5873
|
this.viewer.emitEvent({ type: "geometryerror", data, file: model.file, model });
|
|
5398
5874
|
});
|
|
@@ -5402,7 +5878,7 @@ class GLTFCloudDynamicLoader {
|
|
|
5402
5878
|
const loadController = {
|
|
5403
5879
|
loadJson: async () => {
|
|
5404
5880
|
const progress = (progress) => {
|
|
5405
|
-
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model });
|
|
5881
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model.file, model });
|
|
5406
5882
|
};
|
|
5407
5883
|
const arrayBuffer = await model.downloadResource(model.database, progress, this.gltfLoader.getAbortController().signal);
|
|
5408
5884
|
const text = new TextDecoder().decode(arrayBuffer);
|
|
@@ -5419,7 +5895,7 @@ class GLTFCloudDynamicLoader {
|
|
|
5419
5895
|
},
|
|
5420
5896
|
baseUrl: () => Promise.resolve(`${model.httpClient.serverUrl}${model.path}/`),
|
|
5421
5897
|
};
|
|
5422
|
-
const structure = new GltfStructure(
|
|
5898
|
+
const structure = new GltfStructure(modelImpl.id, loadController);
|
|
5423
5899
|
await this.gltfLoader.loadStructure(structure);
|
|
5424
5900
|
await this.gltfLoader.loadNodes();
|
|
5425
5901
|
return this;
|
|
@@ -5431,7 +5907,7 @@ class GLTFCloudDynamicLoader {
|
|
|
5431
5907
|
}
|
|
5432
5908
|
|
|
5433
5909
|
const loaders = loadersRegistry("threejs");
|
|
5434
|
-
loaders.registerLoader("gltf-file", (viewer) => new
|
|
5910
|
+
loaders.registerLoader("gltf-file", (viewer) => new GLTFFileDynamicLoader(viewer));
|
|
5435
5911
|
loaders.registerLoader("gltf-cloud", (viewer) => new GLTFCloudDynamicLoader(viewer));
|
|
5436
5912
|
|
|
5437
5913
|
class SSAARenderPass extends Pass {
|
|
@@ -5638,24 +6114,25 @@ class Helpers extends Scene {
|
|
|
5638
6114
|
class Viewer extends EventEmitter2 {
|
|
5639
6115
|
constructor(client) {
|
|
5640
6116
|
super();
|
|
5641
|
-
this._options = new Options(this);
|
|
5642
6117
|
this.client = client;
|
|
5643
|
-
this.
|
|
5644
|
-
this.canvaseventlistener = (event) => this.emit(event);
|
|
6118
|
+
this.options = new Options(this);
|
|
5645
6119
|
this.loaders = [];
|
|
5646
6120
|
this.models = [];
|
|
6121
|
+
this.canvasEvents = CANVAS_EVENTS.slice();
|
|
6122
|
+
this.canvaseventlistener = (event) => this.emit(event);
|
|
5647
6123
|
this.selected = [];
|
|
5648
6124
|
this.extents = new Box3();
|
|
5649
|
-
this.target = new Vector3();
|
|
6125
|
+
this.target = new Vector3(0, 0, 0);
|
|
5650
6126
|
this._activeDragger = null;
|
|
5651
6127
|
this._components = [];
|
|
6128
|
+
this._renderNeeded = false;
|
|
5652
6129
|
this._renderTime = 0;
|
|
5653
6130
|
this.render = this.render.bind(this);
|
|
5654
6131
|
this.update = this.update.bind(this);
|
|
5655
6132
|
this._markup = new Markup();
|
|
5656
6133
|
}
|
|
5657
|
-
get
|
|
5658
|
-
return this.
|
|
6134
|
+
get markup() {
|
|
6135
|
+
return this._markup;
|
|
5659
6136
|
}
|
|
5660
6137
|
get draggers() {
|
|
5661
6138
|
return [...draggers.getDraggers().keys()];
|
|
@@ -5663,14 +6140,10 @@ class Viewer extends EventEmitter2 {
|
|
|
5663
6140
|
get components() {
|
|
5664
6141
|
return [...components.getComponents().keys()];
|
|
5665
6142
|
}
|
|
5666
|
-
get markup() {
|
|
5667
|
-
return this._markup;
|
|
5668
|
-
}
|
|
5669
6143
|
initialize(canvas, onProgress) {
|
|
5670
6144
|
this.addEventListener("optionschange", (event) => this.syncOptions(event.data));
|
|
5671
6145
|
this.scene = new Scene();
|
|
5672
6146
|
this.helpers = new Helpers();
|
|
5673
|
-
this.target = new Vector3(0, 0, 0);
|
|
5674
6147
|
const pixelRatio = window.devicePixelRatio;
|
|
5675
6148
|
const rect = canvas.parentElement.getBoundingClientRect();
|
|
5676
6149
|
const width = rect.width || 1;
|
|
@@ -5821,21 +6294,25 @@ class Viewer extends EventEmitter2 {
|
|
|
5821
6294
|
async open(file, params = {}) {
|
|
5822
6295
|
if (!this.renderer)
|
|
5823
6296
|
return this;
|
|
5824
|
-
|
|
6297
|
+
const mode = params.mode || "file";
|
|
6298
|
+
if (mode !== "assembly" && mode !== "a" && mode !== "append") {
|
|
5825
6299
|
this.cancel();
|
|
5826
6300
|
this.clear();
|
|
5827
6301
|
}
|
|
5828
|
-
this.emitEvent({ type: "open", file });
|
|
6302
|
+
this.emitEvent({ type: "open", mode, file });
|
|
5829
6303
|
let model = file;
|
|
5830
6304
|
if (model && typeof model.getModels === "function") {
|
|
5831
6305
|
const models = await model.getModels();
|
|
5832
6306
|
model = models.find((model) => model.default) || models[0] || file;
|
|
5833
6307
|
}
|
|
6308
|
+
if (model && typeof model.database === "string") {
|
|
6309
|
+
file = model.file;
|
|
6310
|
+
}
|
|
5834
6311
|
if (!model)
|
|
5835
6312
|
throw new Error(`Format not supported`);
|
|
5836
6313
|
let format = params.format;
|
|
5837
|
-
if (!format && typeof
|
|
5838
|
-
format =
|
|
6314
|
+
if (!format && typeof file["type"] === "string")
|
|
6315
|
+
format = file["type"].split(".").pop();
|
|
5839
6316
|
if (!format && typeof file === "string")
|
|
5840
6317
|
format = file.split(".").pop();
|
|
5841
6318
|
if (!format && file instanceof globalThis.File)
|
|
@@ -5862,7 +6339,7 @@ class Viewer extends EventEmitter2 {
|
|
|
5862
6339
|
}
|
|
5863
6340
|
loadGltfFile(file, externalFiles, params = {}) {
|
|
5864
6341
|
console.warn("Viewer.loadGltfFile() has been deprecated since 26.4 and will be removed in a future release, use Viewer.open() instead.");
|
|
5865
|
-
return this.open(file, { ...params, format: "gltf", externalFiles, mode: "
|
|
6342
|
+
return this.open(file, { ...params, format: "gltf", externalFiles, mode: "assembly" });
|
|
5866
6343
|
}
|
|
5867
6344
|
cancel() {
|
|
5868
6345
|
this.loaders.forEach((loader) => loader.cancel());
|
|
@@ -5882,12 +6359,17 @@ class Viewer extends EventEmitter2 {
|
|
|
5882
6359
|
this.models = [];
|
|
5883
6360
|
this.scene.clear();
|
|
5884
6361
|
this.helpers.clear();
|
|
6362
|
+
this.extents.makeEmpty();
|
|
6363
|
+
this.target.set(0, 0, 0);
|
|
5885
6364
|
this.syncOptions();
|
|
5886
6365
|
this.syncOverlay();
|
|
5887
6366
|
this.update(true);
|
|
5888
6367
|
this.emitEvent({ type: "clear" });
|
|
5889
6368
|
return this;
|
|
5890
6369
|
}
|
|
6370
|
+
is3D() {
|
|
6371
|
+
return true;
|
|
6372
|
+
}
|
|
5891
6373
|
syncOptions(options = this.options) {
|
|
5892
6374
|
if (!this.renderer)
|
|
5893
6375
|
return;
|
|
@@ -5919,9 +6401,15 @@ class Viewer extends EventEmitter2 {
|
|
|
5919
6401
|
getSelected() {
|
|
5920
6402
|
return this.executeCommand("getSelected");
|
|
5921
6403
|
}
|
|
6404
|
+
getSelected2() {
|
|
6405
|
+
return this.executeCommand("getSelected2");
|
|
6406
|
+
}
|
|
5922
6407
|
setSelected(handles) {
|
|
5923
6408
|
this.executeCommand("setSelected", handles);
|
|
5924
6409
|
}
|
|
6410
|
+
setSelected2(handles) {
|
|
6411
|
+
this.executeCommand("setSelected2", handles);
|
|
6412
|
+
}
|
|
5925
6413
|
clearSelected() {
|
|
5926
6414
|
this.executeCommand("clearSelected");
|
|
5927
6415
|
}
|
|
@@ -5981,37 +6469,8 @@ class Viewer extends EventEmitter2 {
|
|
|
5981
6469
|
getComponent(name) {
|
|
5982
6470
|
return this._components.find((component) => component.name === name);
|
|
5983
6471
|
}
|
|
5984
|
-
is3D() {
|
|
5985
|
-
return true;
|
|
5986
|
-
}
|
|
5987
|
-
screenToWorld(position) {
|
|
5988
|
-
if (!this.renderer)
|
|
5989
|
-
return { x: position.x, y: position.y, z: 0 };
|
|
5990
|
-
const rect = this.canvas.getBoundingClientRect();
|
|
5991
|
-
const x = position.x / (rect.width / 2) - 1;
|
|
5992
|
-
const y = -position.y / (rect.height / 2) + 1;
|
|
5993
|
-
const point = new Vector3(x, y, -1);
|
|
5994
|
-
point.unproject(this.camera);
|
|
5995
|
-
return { x: point.x, y: point.y, z: point.z };
|
|
5996
|
-
}
|
|
5997
|
-
worldToScreen(position) {
|
|
5998
|
-
if (!this.renderer)
|
|
5999
|
-
return { x: position.x, y: position.y };
|
|
6000
|
-
const point = new Vector3(position.x, position.y, position.z);
|
|
6001
|
-
point.project(this.camera);
|
|
6002
|
-
const rect = this.canvas.getBoundingClientRect();
|
|
6003
|
-
const x = (point.x + 1) * (rect.width / 2);
|
|
6004
|
-
const y = (-point.y + 1) * (rect.height / 2);
|
|
6005
|
-
return { x, y };
|
|
6006
|
-
}
|
|
6007
|
-
getScale() {
|
|
6008
|
-
return { x: 1, y: 1, z: 1 };
|
|
6009
|
-
}
|
|
6010
|
-
executeCommand(id, ...args) {
|
|
6011
|
-
return commands.executeCommand(id, this, ...args);
|
|
6012
|
-
}
|
|
6013
6472
|
drawViewpoint(viewpoint) {
|
|
6014
|
-
var _a, _b, _c;
|
|
6473
|
+
var _a, _b, _c, _d;
|
|
6015
6474
|
if (!this.renderer)
|
|
6016
6475
|
return;
|
|
6017
6476
|
const getVector3FromPoint3d = ({ x, y, z }) => new Vector3(x, y, z);
|
|
@@ -6063,11 +6522,13 @@ class Viewer extends EventEmitter2 {
|
|
|
6063
6522
|
}
|
|
6064
6523
|
};
|
|
6065
6524
|
const setClippingPlanes = (clipping_planes) => {
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
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
|
+
}
|
|
6071
6532
|
};
|
|
6072
6533
|
const setSelection = (selection) => {
|
|
6073
6534
|
if (selection)
|
|
@@ -6083,9 +6544,9 @@ class Viewer extends EventEmitter2 {
|
|
|
6083
6544
|
setOrthogonalCamera(viewpoint.orthogonal_camera);
|
|
6084
6545
|
setPerspectiveCamera(viewpoint.perspective_camera);
|
|
6085
6546
|
setClippingPlanes(viewpoint.clipping_planes);
|
|
6086
|
-
setSelection(viewpoint.selection);
|
|
6547
|
+
setSelection(((_b = viewpoint.custom_fields) === null || _b === void 0 ? void 0 : _b.selection2) || viewpoint.selection);
|
|
6087
6548
|
this._markup.setViewpoint(viewpoint);
|
|
6088
|
-
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));
|
|
6089
6550
|
this.setActiveDragger(draggerName);
|
|
6090
6551
|
this.emitEvent({ type: "drawviewpoint", data: viewpoint });
|
|
6091
6552
|
this.update();
|
|
@@ -6132,6 +6593,9 @@ class Viewer extends EventEmitter2 {
|
|
|
6132
6593
|
const getSelection = () => {
|
|
6133
6594
|
return this.getSelected().map((handle) => ({ handle }));
|
|
6134
6595
|
};
|
|
6596
|
+
const getSelection2 = () => {
|
|
6597
|
+
return this.getSelected2().map((handle) => ({ handle }));
|
|
6598
|
+
};
|
|
6135
6599
|
const viewpoint = { custom_fields: {} };
|
|
6136
6600
|
viewpoint.orthogonal_camera = getOrthogonalCamera();
|
|
6137
6601
|
viewpoint.perspective_camera = getPerspectiveCamera();
|
|
@@ -6140,9 +6604,36 @@ class Viewer extends EventEmitter2 {
|
|
|
6140
6604
|
viewpoint.description = new Date().toDateString();
|
|
6141
6605
|
this._markup.getViewpoint(viewpoint);
|
|
6142
6606
|
viewpoint.custom_fields.camera_target = getPoint3dFromVector3(this.target);
|
|
6607
|
+
viewpoint.custom_fields.selection2 = getSelection2();
|
|
6143
6608
|
this.emitEvent({ type: "createviewpoint", data: viewpoint });
|
|
6144
6609
|
return viewpoint;
|
|
6145
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
|
+
}
|
|
6146
6637
|
}
|
|
6147
6638
|
|
|
6148
6639
|
export { GLTFLoadingManager, ModelImpl, Viewer, commands, components, draggers, loaders };
|