@inweb/viewer-three 26.10.6 → 26.12.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/InfoPanelComponent.js +170 -0
- package/dist/extensions/components/InfoPanelComponent.js.map +1 -0
- package/dist/extensions/components/InfoPanelComponent.min.js +24 -0
- package/dist/extensions/components/InfoPanelComponent.module.js +164 -0
- package/dist/extensions/components/InfoPanelComponent.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/{plugins → extensions}/components/StatsPanelComponent.js +9 -3
- package/dist/extensions/components/StatsPanelComponent.js.map +1 -0
- package/dist/extensions/components/StatsPanelComponent.min.js +24 -0
- package/dist/{plugins → extensions}/components/StatsPanelComponent.module.js +9 -3
- 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 +56 -6
- package/dist/extensions/loaders/PotreeLoader.js.map +1 -0
- package/dist/extensions/loaders/PotreeLoader.min.js +24 -0
- package/dist/{plugins → extensions}/loaders/PotreeLoader.module.js +53 -2
- package/dist/extensions/loaders/PotreeLoader.module.js.map +1 -0
- package/dist/viewer-three.js +1416 -2930
- package/dist/viewer-three.js.map +1 -1
- package/dist/viewer-three.min.js +8 -3
- package/dist/viewer-three.module.js +1205 -363
- 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/extensions/components/InfoPanelComponent.ts +197 -0
- package/{plugins → extensions}/components/StatsPanelComponent.ts +10 -3
- 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/extensions/loaders/Potree/PotreeModelImpl.ts +108 -0
- package/lib/Viewer/Viewer.d.ts +28 -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/InfoComponent.d.ts +22 -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 +2 -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 +11 -8
- package/lib/Viewer/models/ModelImpl.d.ts +9 -5
- package/package.json +11 -11
- package/src/Viewer/Viewer.ts +127 -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/{plugins/loaders/Potree/PotreeModelImpl.ts → src/Viewer/commands/GetSelected2.ts} +7 -9
- 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/InfoComponent.ts +187 -0
- package/src/Viewer/components/SelectionComponent.ts +7 -30
- package/src/Viewer/components/index.ts +8 -6
- package/src/Viewer/draggers/MeasureLineDragger.ts +84 -226
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +276 -39
- package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +45 -10
- package/src/Viewer/loaders/DynamicGltfLoader/GltfStructure.js +71 -2
- 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 +105 -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 +17 -8
- package/src/Viewer/models/ModelImpl.ts +205 -16
- 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.min.js +0 -24
- 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.min.js +0 -24
- 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/{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}/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/index.ts +0 -0
|
@@ -21,14 +21,13 @@
|
|
|
21
21
|
// acknowledge and accept the above terms.
|
|
22
22
|
///////////////////////////////////////////////////////////////////////////////
|
|
23
23
|
|
|
24
|
-
import { draggersRegistry, commandsRegistry, Options, componentsRegistry, Loader, loadersRegistry, CANVAS_EVENTS } from '@inweb/viewer-core';
|
|
24
|
+
import { draggersRegistry, commandsRegistry, Options, componentsRegistry, Info, 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, REVISION, 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;
|
|
@@ -2502,6 +2633,140 @@ class LightComponent {
|
|
|
2502
2633
|
}
|
|
2503
2634
|
}
|
|
2504
2635
|
|
|
2636
|
+
class InfoComponent {
|
|
2637
|
+
constructor(viewer) {
|
|
2638
|
+
this.initialize = () => {
|
|
2639
|
+
try {
|
|
2640
|
+
const gl = this.viewer.renderer.getContext();
|
|
2641
|
+
const dbgInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
2642
|
+
if (dbgInfo) {
|
|
2643
|
+
this.viewer.info.system.webglRenderer = gl.getParameter(dbgInfo.UNMASKED_RENDERER_WEBGL);
|
|
2644
|
+
this.viewer.info.system.webglVendor = gl.getParameter(dbgInfo.UNMASKED_VENDOR_WEBGL);
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
catch (error) {
|
|
2648
|
+
console.error("Error reading WebGL info.", error);
|
|
2649
|
+
}
|
|
2650
|
+
console.log("THREE.WebGLRenderer:", REVISION);
|
|
2651
|
+
console.log("WebGL Renderer:", this.viewer.info.system.webglRenderer);
|
|
2652
|
+
console.log("WebGL Vendor:", this.viewer.info.system.webglVendor);
|
|
2653
|
+
this.resize();
|
|
2654
|
+
this.optionsChange({ data: this.viewer.options });
|
|
2655
|
+
};
|
|
2656
|
+
this.clear = () => {
|
|
2657
|
+
this.viewer.info.performance.timeToFirstRender = 0;
|
|
2658
|
+
this.viewer.info.performance.loadTime = 0;
|
|
2659
|
+
this.viewer.info.scene.objects = 0;
|
|
2660
|
+
this.viewer.info.scene.triangles = 0;
|
|
2661
|
+
this.viewer.info.scene.points = 0;
|
|
2662
|
+
this.viewer.info.scene.lines = 0;
|
|
2663
|
+
this.viewer.info.scene.edges = 0;
|
|
2664
|
+
this.viewer.info.optimizedScene.objects = 0;
|
|
2665
|
+
this.viewer.info.optimizedScene.triangles = 0;
|
|
2666
|
+
this.viewer.info.optimizedScene.points = 0;
|
|
2667
|
+
this.viewer.info.optimizedScene.lines = 0;
|
|
2668
|
+
this.viewer.info.optimizedScene.edges = 0;
|
|
2669
|
+
this.viewer.info.memory.geometries = 0;
|
|
2670
|
+
this.viewer.info.memory.geometryBytes = 0;
|
|
2671
|
+
this.viewer.info.memory.textures = 0;
|
|
2672
|
+
this.viewer.info.memory.textureBytes = 0;
|
|
2673
|
+
this.viewer.info.memory.materials = 0;
|
|
2674
|
+
this.viewer.info.memory.totalEstimatedGpuBytes = 0;
|
|
2675
|
+
this.viewer.info.memory.usedJSHeapSize = 0;
|
|
2676
|
+
};
|
|
2677
|
+
this.optionsChange = ({ data: options }) => {
|
|
2678
|
+
if (options.antialiasing === false)
|
|
2679
|
+
this.viewer.info.render.antialiasing = "";
|
|
2680
|
+
else if (options.antialiasing === true)
|
|
2681
|
+
this.viewer.info.render.antialiasing = "mxaa";
|
|
2682
|
+
else
|
|
2683
|
+
this.viewer.info.render.antialiasing = options.antialiasing;
|
|
2684
|
+
};
|
|
2685
|
+
this.geometryStart = () => {
|
|
2686
|
+
this.startTime = performance.now();
|
|
2687
|
+
};
|
|
2688
|
+
this.databaseChunk = () => {
|
|
2689
|
+
this.viewer.info.performance.timeToFirstRender += performance.now() - this.startTime;
|
|
2690
|
+
console.log("Time to first render:", this.viewer.info.performance.timeToFirstRender, "ms");
|
|
2691
|
+
};
|
|
2692
|
+
this.geometryEnd = () => {
|
|
2693
|
+
const model = this.viewer.models[this.viewer.models.length - 1];
|
|
2694
|
+
const info = model.getInfo();
|
|
2695
|
+
this.viewer.info.scene.objects += info.scene.objects;
|
|
2696
|
+
this.viewer.info.scene.triangles += info.scene.triangles;
|
|
2697
|
+
this.viewer.info.scene.points += info.scene.points;
|
|
2698
|
+
this.viewer.info.scene.lines += info.scene.lines;
|
|
2699
|
+
this.viewer.info.scene.edges += info.scene.edges;
|
|
2700
|
+
this.viewer.info.optimizedScene.objects += info.optimizedScene.objects;
|
|
2701
|
+
this.viewer.info.optimizedScene.triangles += info.optimizedScene.triangles;
|
|
2702
|
+
this.viewer.info.optimizedScene.points += info.optimizedScene.points;
|
|
2703
|
+
this.viewer.info.optimizedScene.lines += info.optimizedScene.lines;
|
|
2704
|
+
this.viewer.info.optimizedScene.edges += info.optimizedScene.edges;
|
|
2705
|
+
this.viewer.info.memory.geometries += info.memory.geometries;
|
|
2706
|
+
this.viewer.info.memory.geometryBytes += info.memory.geometryBytes;
|
|
2707
|
+
this.viewer.info.memory.textures += info.memory.textures;
|
|
2708
|
+
this.viewer.info.memory.textureBytes += info.memory.textureBytes;
|
|
2709
|
+
this.viewer.info.memory.materials += info.memory.materials;
|
|
2710
|
+
this.viewer.info.memory.totalEstimatedGpuBytes += info.memory.totalEstimatedGpuBytes;
|
|
2711
|
+
const memory = performance["memory"];
|
|
2712
|
+
if (memory)
|
|
2713
|
+
this.viewer.info.memory.usedJSHeapSize = memory.usedJSHeapSize;
|
|
2714
|
+
this.viewer.info.performance.loadTime += performance.now() - this.startTime;
|
|
2715
|
+
console.log("Number of objects:", info.scene.objects);
|
|
2716
|
+
console.log("Number of objects after optimization:", info.optimizedScene.objects);
|
|
2717
|
+
console.log("Total geometry size:", info.memory.totalEstimatedGpuBytes / (1024 * 1024), "MB");
|
|
2718
|
+
console.log("File load time:", this.viewer.info.performance.loadTime, "ms");
|
|
2719
|
+
};
|
|
2720
|
+
this.resize = () => {
|
|
2721
|
+
const rendererSize = this.viewer.renderer.getSize(new Vector2());
|
|
2722
|
+
this.viewer.info.render.viewport.width = rendererSize.x;
|
|
2723
|
+
this.viewer.info.render.viewport.height = rendererSize.y;
|
|
2724
|
+
};
|
|
2725
|
+
this.render = () => {
|
|
2726
|
+
this.viewer.info.render.drawCalls = this.viewer.renderer.info.render.calls;
|
|
2727
|
+
this.viewer.info.render.triangles = this.viewer.renderer.info.render.triangles;
|
|
2728
|
+
this.viewer.info.render.points = this.viewer.renderer.info.render.points;
|
|
2729
|
+
this.viewer.info.render.lines = this.viewer.renderer.info.render.lines;
|
|
2730
|
+
};
|
|
2731
|
+
this.animate = () => {
|
|
2732
|
+
const time = performance.now();
|
|
2733
|
+
this.viewer.info.performance.frameTime = Math.round(time - this.beginTime);
|
|
2734
|
+
this.beginTime = time;
|
|
2735
|
+
this.frames++;
|
|
2736
|
+
if (time - this.prevTime >= 1000) {
|
|
2737
|
+
this.viewer.info.performance.fps = Math.round((this.frames * 1000) / (time - this.prevTime));
|
|
2738
|
+
this.prevTime = time;
|
|
2739
|
+
this.frames = 0;
|
|
2740
|
+
}
|
|
2741
|
+
};
|
|
2742
|
+
this.viewer = viewer;
|
|
2743
|
+
this.startTime = 0;
|
|
2744
|
+
this.beginTime = performance.now();
|
|
2745
|
+
this.prevTime = performance.now();
|
|
2746
|
+
this.frames = 0;
|
|
2747
|
+
this.viewer.addEventListener("initialize", this.initialize);
|
|
2748
|
+
this.viewer.addEventListener("clear", this.clear);
|
|
2749
|
+
this.viewer.addEventListener("optionschange", this.optionsChange);
|
|
2750
|
+
this.viewer.addEventListener("geometrystart", this.geometryStart);
|
|
2751
|
+
this.viewer.addEventListener("databasechunk", this.databaseChunk);
|
|
2752
|
+
this.viewer.addEventListener("geometryend", this.geometryEnd);
|
|
2753
|
+
this.viewer.addEventListener("resize", this.resize);
|
|
2754
|
+
this.viewer.addEventListener("render", this.render);
|
|
2755
|
+
this.viewer.addEventListener("animate", this.animate);
|
|
2756
|
+
}
|
|
2757
|
+
dispose() {
|
|
2758
|
+
this.viewer.removeEventListener("initialize", this.initialize);
|
|
2759
|
+
this.viewer.removeEventListener("clear", this.clear);
|
|
2760
|
+
this.viewer.removeEventListener("optionschange", this.optionsChange);
|
|
2761
|
+
this.viewer.removeEventListener("geometrystart", this.geometryStart);
|
|
2762
|
+
this.viewer.removeEventListener("databasechunk", this.databaseChunk);
|
|
2763
|
+
this.viewer.removeEventListener("geometryend", this.geometryEnd);
|
|
2764
|
+
this.viewer.removeEventListener("resize", this.resize);
|
|
2765
|
+
this.viewer.removeEventListener("render", this.render);
|
|
2766
|
+
this.viewer.addEventListener("animate", this.animate);
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2505
2770
|
class RenderLoopComponent {
|
|
2506
2771
|
constructor(viewer) {
|
|
2507
2772
|
this.animate = (time = 0) => {
|
|
@@ -2749,10 +3014,11 @@ class SelectionComponent {
|
|
|
2749
3014
|
const upPosition = this.getMousePosition(event, new Vector2());
|
|
2750
3015
|
if (upPosition.distanceTo(this.downPosition) !== 0)
|
|
2751
3016
|
return;
|
|
3017
|
+
const snapper = new Snapper(this.viewer.camera, this.viewer.renderer, this.viewer.canvas);
|
|
2752
3018
|
let intersections = [];
|
|
2753
3019
|
this.viewer.models.forEach((model) => {
|
|
2754
3020
|
const objects = model.getVisibleObjects();
|
|
2755
|
-
const intersects =
|
|
3021
|
+
const intersects = snapper.getPointerIntersects(upPosition, objects);
|
|
2756
3022
|
if (intersects.length > 0)
|
|
2757
3023
|
intersections.push({ ...intersects[0], model });
|
|
2758
3024
|
});
|
|
@@ -2770,6 +3036,7 @@ class SelectionComponent {
|
|
|
2770
3036
|
}
|
|
2771
3037
|
this.viewer.update();
|
|
2772
3038
|
this.viewer.emitEvent({ type: "select", data: undefined, handles: this.viewer.getSelected() });
|
|
3039
|
+
this.viewer.emitEvent({ type: "select2", data: undefined, handles: this.viewer.getSelected2() });
|
|
2773
3040
|
};
|
|
2774
3041
|
this.onDoubleClick = (event) => {
|
|
2775
3042
|
if (event.button !== 0)
|
|
@@ -2780,7 +3047,6 @@ class SelectionComponent {
|
|
|
2780
3047
|
this.highlighter = this.viewer.getComponent("HighlighterComponent");
|
|
2781
3048
|
};
|
|
2782
3049
|
this.viewer = viewer;
|
|
2783
|
-
this.raycaster = new Raycaster();
|
|
2784
3050
|
this.downPosition = new Vector2();
|
|
2785
3051
|
this.viewer.addEventListener("pointerdown", this.onPointerDown);
|
|
2786
3052
|
this.viewer.addEventListener("pointerup", this.onPointerUp);
|
|
@@ -2796,26 +3062,6 @@ class SelectionComponent {
|
|
|
2796
3062
|
getMousePosition(event, target) {
|
|
2797
3063
|
return target.set(event.clientX, event.clientY);
|
|
2798
3064
|
}
|
|
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
3065
|
select(objects, model) {
|
|
2820
3066
|
if (!model) {
|
|
2821
3067
|
this.viewer.models.forEach((model) => this.select(objects, model));
|
|
@@ -3007,6 +3253,7 @@ components.registerComponent("ExtentsComponent", (viewer) => new ExtentsComponen
|
|
|
3007
3253
|
components.registerComponent("CameraComponent", (viewer) => new CameraComponent(viewer));
|
|
3008
3254
|
components.registerComponent("BackgroundComponent", (viewer) => new BackgroundComponent(viewer));
|
|
3009
3255
|
components.registerComponent("LightComponent", (viewer) => new LightComponent(viewer));
|
|
3256
|
+
components.registerComponent("InfoComponent", (viewer) => new InfoComponent(viewer));
|
|
3010
3257
|
components.registerComponent("ResizeCanvasComponent", (viewer) => new ResizeCanvasComponent(viewer));
|
|
3011
3258
|
components.registerComponent("RenderLoopComponent", (viewer) => new RenderLoopComponent(viewer));
|
|
3012
3259
|
components.registerComponent("HighlighterComponent", (viewer) => new HighlighterComponent(viewer));
|
|
@@ -3014,48 +3261,8 @@ components.registerComponent("SelectionComponent", (viewer) => new SelectionComp
|
|
|
3014
3261
|
components.registerComponent("WCSHelperComponent", (viewer) => new WCSHelperComponent(viewer));
|
|
3015
3262
|
components.registerComponent("ResetComponent", (viewer) => new ResetComponent(viewer));
|
|
3016
3263
|
|
|
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
3264
|
class ModelImpl {
|
|
3057
3265
|
constructor(scene) {
|
|
3058
|
-
this.handle = "1";
|
|
3059
3266
|
this.scene = scene;
|
|
3060
3267
|
}
|
|
3061
3268
|
dispose() {
|
|
@@ -3075,6 +3282,144 @@ class ModelImpl {
|
|
|
3075
3282
|
this.scene.traverse(disposeObject);
|
|
3076
3283
|
this.scene.clear();
|
|
3077
3284
|
}
|
|
3285
|
+
getUnits() {
|
|
3286
|
+
return "Meters";
|
|
3287
|
+
}
|
|
3288
|
+
getUnitScale() {
|
|
3289
|
+
return convertUnits(this.getUnits(), "Meters", 1);
|
|
3290
|
+
}
|
|
3291
|
+
getUnitString() {
|
|
3292
|
+
return getDisplayUnit(this.getUnits());
|
|
3293
|
+
}
|
|
3294
|
+
getPrecision() {
|
|
3295
|
+
return 2;
|
|
3296
|
+
}
|
|
3297
|
+
getInfo() {
|
|
3298
|
+
const geometries = new Set();
|
|
3299
|
+
const materials = new Set();
|
|
3300
|
+
const textures = new Set();
|
|
3301
|
+
let totalObjects = 0;
|
|
3302
|
+
let totalTriangles = 0;
|
|
3303
|
+
let totalPoints = 0;
|
|
3304
|
+
let totalLines = 0;
|
|
3305
|
+
let totalEdges = 0;
|
|
3306
|
+
let geometryBytes = 0;
|
|
3307
|
+
let textureBytes = 0;
|
|
3308
|
+
this.scene.traverse((object) => {
|
|
3309
|
+
totalObjects++;
|
|
3310
|
+
if (object.geometry) {
|
|
3311
|
+
const geometry = object.geometry;
|
|
3312
|
+
if (!geometries.has(geometry)) {
|
|
3313
|
+
geometries.add(geometry);
|
|
3314
|
+
if (geometry.attributes) {
|
|
3315
|
+
for (const name in geometry.attributes) {
|
|
3316
|
+
const attribute = geometry.attributes[name];
|
|
3317
|
+
if (attribute && attribute.array) {
|
|
3318
|
+
geometryBytes += attribute.array.byteLength;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
if (geometry.index && geometry.index.array) {
|
|
3323
|
+
geometryBytes += geometry.index.array.byteLength;
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
if (geometry.index) {
|
|
3327
|
+
const indexCount = geometry.index.count;
|
|
3328
|
+
if (object.isLine || object.isLineSegments) {
|
|
3329
|
+
totalLines += indexCount / 2;
|
|
3330
|
+
}
|
|
3331
|
+
else if (object.isPoints) {
|
|
3332
|
+
totalPoints += indexCount;
|
|
3333
|
+
}
|
|
3334
|
+
else {
|
|
3335
|
+
totalTriangles += indexCount / 3;
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
else if (geometry.attributes && geometry.attributes.position) {
|
|
3339
|
+
const positionCount = geometry.attributes.position.count;
|
|
3340
|
+
if (object.isLine || object.isLineSegments) {
|
|
3341
|
+
totalLines += positionCount / 2;
|
|
3342
|
+
}
|
|
3343
|
+
else if (object.isPoints) {
|
|
3344
|
+
totalPoints += positionCount;
|
|
3345
|
+
}
|
|
3346
|
+
else {
|
|
3347
|
+
totalTriangles += positionCount / 3;
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
if (object.isLineSegments && geometry.attributes.position) {
|
|
3351
|
+
totalEdges += geometry.attributes.position.count / 2;
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
if (object.material) {
|
|
3355
|
+
const materialsArray = Array.isArray(object.material) ? object.material : [object.material];
|
|
3356
|
+
materialsArray.forEach((material) => {
|
|
3357
|
+
materials.add(material);
|
|
3358
|
+
if (material.map && !textures.has(material.map)) {
|
|
3359
|
+
textures.add(material.map);
|
|
3360
|
+
textureBytes += estimateTextureSize(material.map);
|
|
3361
|
+
}
|
|
3362
|
+
const textureProps = [
|
|
3363
|
+
"alphaMap",
|
|
3364
|
+
"aoMap",
|
|
3365
|
+
"bumpMap",
|
|
3366
|
+
"displacementMap",
|
|
3367
|
+
"emissiveMap",
|
|
3368
|
+
"envMap",
|
|
3369
|
+
"lightMap",
|
|
3370
|
+
"metalnessMap",
|
|
3371
|
+
"normalMap",
|
|
3372
|
+
"roughnessMap",
|
|
3373
|
+
"specularMap",
|
|
3374
|
+
"clearcoatMap",
|
|
3375
|
+
"clearcoatNormalMap",
|
|
3376
|
+
"clearcoatRoughnessMap",
|
|
3377
|
+
"iridescenceMap",
|
|
3378
|
+
"sheenColorMap",
|
|
3379
|
+
"sheenRoughnessMap",
|
|
3380
|
+
"thicknessMap",
|
|
3381
|
+
"transmissionMap",
|
|
3382
|
+
"anisotropyMap",
|
|
3383
|
+
"gradientMap",
|
|
3384
|
+
];
|
|
3385
|
+
textureProps.forEach((prop) => {
|
|
3386
|
+
const texture = material[prop];
|
|
3387
|
+
if (texture && !textures.has(texture)) {
|
|
3388
|
+
textures.add(texture);
|
|
3389
|
+
textureBytes += estimateTextureSize(texture);
|
|
3390
|
+
}
|
|
3391
|
+
});
|
|
3392
|
+
});
|
|
3393
|
+
}
|
|
3394
|
+
});
|
|
3395
|
+
function estimateTextureSize(texture) {
|
|
3396
|
+
if (!texture.image)
|
|
3397
|
+
return 0;
|
|
3398
|
+
const width = texture.image.width || 0;
|
|
3399
|
+
const height = texture.image.height || 0;
|
|
3400
|
+
const bytesPerPixel = 4;
|
|
3401
|
+
const mipmapMultiplier = texture.generateMipmaps ? 1.33 : 1;
|
|
3402
|
+
return width * height * bytesPerPixel * mipmapMultiplier;
|
|
3403
|
+
}
|
|
3404
|
+
const info = new Info();
|
|
3405
|
+
info.scene.objects = totalObjects;
|
|
3406
|
+
info.scene.triangles = Math.floor(totalTriangles);
|
|
3407
|
+
info.scene.points = Math.floor(totalPoints);
|
|
3408
|
+
info.scene.lines = Math.floor(totalLines);
|
|
3409
|
+
info.scene.edges = Math.floor(totalEdges);
|
|
3410
|
+
info.memory.geometries = geometries.size;
|
|
3411
|
+
info.memory.geometryBytes = geometryBytes;
|
|
3412
|
+
info.memory.textures = textures.size;
|
|
3413
|
+
info.memory.textureBytes = Math.floor(textureBytes);
|
|
3414
|
+
info.memory.materials = materials.size;
|
|
3415
|
+
info.memory.totalEstimatedGpuBytes = geometryBytes + Math.floor(textureBytes);
|
|
3416
|
+
info.optimizedScene.objects = info.scene.objects;
|
|
3417
|
+
info.optimizedScene.triangles = info.scene.triangles;
|
|
3418
|
+
info.optimizedScene.points = info.scene.points;
|
|
3419
|
+
info.optimizedScene.lines = info.scene.lines;
|
|
3420
|
+
info.optimizedScene.edges = info.scene.edges;
|
|
3421
|
+
return info;
|
|
3422
|
+
}
|
|
3078
3423
|
getExtents(target) {
|
|
3079
3424
|
this.scene.traverseVisible((object) => !object.children.length && target.expandByObject(object));
|
|
3080
3425
|
return target;
|
|
@@ -3097,27 +3442,45 @@ class ModelImpl {
|
|
|
3097
3442
|
}
|
|
3098
3443
|
return false;
|
|
3099
3444
|
}
|
|
3445
|
+
hasHandle(handle) {
|
|
3446
|
+
return !handle.includes(":") || handle.split(":", 1)[0] === this.id + "";
|
|
3447
|
+
}
|
|
3100
3448
|
getOwnObjects(objects) {
|
|
3101
3449
|
if (!Array.isArray(objects))
|
|
3102
3450
|
objects = [objects];
|
|
3103
3451
|
return objects.filter((object) => this.hasObject(object));
|
|
3104
3452
|
}
|
|
3453
|
+
getOwnHandles(handles) {
|
|
3454
|
+
if (!Array.isArray(handles))
|
|
3455
|
+
handles = [handles];
|
|
3456
|
+
return handles.filter((handle) => this.hasHandle(handle));
|
|
3457
|
+
}
|
|
3105
3458
|
getObjectsByHandles(handles) {
|
|
3106
|
-
const
|
|
3459
|
+
const ownHandles = this.getOwnHandles(handles);
|
|
3460
|
+
if (ownHandles.length === 0)
|
|
3461
|
+
return [];
|
|
3462
|
+
const handleSet = new Set(ownHandles.map((handle) => handle.slice(handle.indexOf(":") + 1)));
|
|
3107
3463
|
const objects = [];
|
|
3108
|
-
this.scene.traverse((object) =>
|
|
3464
|
+
this.scene.traverse((object) => {
|
|
3465
|
+
const handle = object.userData.handle;
|
|
3466
|
+
if (handle && handleSet.has(handle))
|
|
3467
|
+
objects.push(object);
|
|
3468
|
+
});
|
|
3109
3469
|
return objects;
|
|
3110
3470
|
}
|
|
3111
3471
|
getHandlesByObjects(objects) {
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3472
|
+
const ownObjects = this.getOwnObjects(objects);
|
|
3473
|
+
if (ownObjects.length === 0)
|
|
3474
|
+
return [];
|
|
3475
|
+
const handleSet = new Set();
|
|
3476
|
+
ownObjects.forEach((object) => {
|
|
3477
|
+
const handle = object.userData.handle;
|
|
3478
|
+
if (handle)
|
|
3479
|
+
handleSet.add(`${this.id}:${handle}`);
|
|
3480
|
+
});
|
|
3481
|
+
return Array.from(handleSet);
|
|
3117
3482
|
}
|
|
3118
3483
|
hideObjects(objects) {
|
|
3119
|
-
if (!Array.isArray(objects))
|
|
3120
|
-
objects = [objects];
|
|
3121
3484
|
this.getOwnObjects(objects).forEach((object) => (object.visible = false));
|
|
3122
3485
|
return this;
|
|
3123
3486
|
}
|
|
@@ -3133,8 +3496,6 @@ class ModelImpl {
|
|
|
3133
3496
|
return this;
|
|
3134
3497
|
}
|
|
3135
3498
|
showObjects(objects) {
|
|
3136
|
-
if (!Array.isArray(objects))
|
|
3137
|
-
objects = [objects];
|
|
3138
3499
|
this.getOwnObjects(objects).forEach((object) => {
|
|
3139
3500
|
object.visible = true;
|
|
3140
3501
|
object.traverseAncestors((parent) => (parent.visible = true));
|
|
@@ -3184,49 +3545,31 @@ class ModelImpl {
|
|
|
3184
3545
|
}
|
|
3185
3546
|
object.children.forEach((x) => explodeObject(x, depth + 1));
|
|
3186
3547
|
}
|
|
3187
|
-
explodeObject(this.scene, 0);
|
|
3188
|
-
this.scene.updateMatrixWorld();
|
|
3189
|
-
return this;
|
|
3190
|
-
}
|
|
3191
|
-
}
|
|
3192
|
-
|
|
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 });
|
|
3548
|
+
explodeObject(this.scene, 0);
|
|
3549
|
+
this.scene.updateMatrixWorld();
|
|
3225
3550
|
return this;
|
|
3226
3551
|
}
|
|
3227
3552
|
}
|
|
3228
3553
|
|
|
3229
3554
|
class DynamicModelImpl extends ModelImpl {
|
|
3555
|
+
getInfo() {
|
|
3556
|
+
const stats = this.gltfLoader.getStats();
|
|
3557
|
+
const info = new Info();
|
|
3558
|
+
info.scene.objects = stats.scene.beforeOptimization.objects;
|
|
3559
|
+
info.scene.triangles = stats.scene.beforeOptimization.triangles;
|
|
3560
|
+
info.scene.lines = stats.scene.beforeOptimization.lines;
|
|
3561
|
+
info.scene.edges = stats.scene.beforeOptimization.edges;
|
|
3562
|
+
info.optimizedScene.objects = stats.scene.afterOptimization.objects;
|
|
3563
|
+
info.optimizedScene.triangles = stats.scene.afterOptimization.triangles;
|
|
3564
|
+
info.optimizedScene.lines = stats.scene.afterOptimization.lines;
|
|
3565
|
+
info.optimizedScene.edges = stats.scene.afterOptimization.edges;
|
|
3566
|
+
info.memory.geometries = stats.memory.geometries.count;
|
|
3567
|
+
info.memory.geometryBytes = stats.memory.geometries.bytes;
|
|
3568
|
+
info.memory.textures = stats.memory.textures.count;
|
|
3569
|
+
info.memory.materials = stats.memory.materials.count;
|
|
3570
|
+
info.memory.totalEstimatedGpuBytes = stats.memory.totalEstimatedGpuBytes;
|
|
3571
|
+
return info;
|
|
3572
|
+
}
|
|
3230
3573
|
getExtents(target) {
|
|
3231
3574
|
return target.union(this.gltfLoader.getTotalGeometryExtent());
|
|
3232
3575
|
}
|
|
@@ -3244,31 +3587,40 @@ class DynamicModelImpl extends ModelImpl {
|
|
|
3244
3587
|
return this.gltfLoader.originalObjects.has(object);
|
|
3245
3588
|
}
|
|
3246
3589
|
getObjectsByHandles(handles) {
|
|
3247
|
-
const
|
|
3590
|
+
const ownHandles = this.getOwnHandles(handles);
|
|
3591
|
+
if (ownHandles.length === 0)
|
|
3592
|
+
return [];
|
|
3593
|
+
const handlesSet = new Set(ownHandles);
|
|
3248
3594
|
const objects = [];
|
|
3249
3595
|
handlesSet.forEach((handle) => {
|
|
3250
|
-
|
|
3251
|
-
const handles = this.gltfLoader.handleToObjects.get(handle2) || [];
|
|
3252
|
-
objects.push(...Array.from(handles));
|
|
3596
|
+
objects.push(...this.gltfLoader.getObjectsByHandle(handle));
|
|
3253
3597
|
});
|
|
3254
3598
|
return objects;
|
|
3255
3599
|
}
|
|
3256
3600
|
getHandlesByObjects(objects) {
|
|
3257
|
-
const
|
|
3258
|
-
|
|
3601
|
+
const ownObjects = this.getOwnObjects(objects);
|
|
3602
|
+
if (ownObjects.length === 0)
|
|
3603
|
+
return [];
|
|
3604
|
+
const handleSet = new Set();
|
|
3605
|
+
ownObjects.forEach((object) => {
|
|
3606
|
+
const handle = object.userData.handle;
|
|
3607
|
+
if (handle)
|
|
3608
|
+
handleSet.add(handle);
|
|
3609
|
+
});
|
|
3610
|
+
return Array.from(handleSet);
|
|
3259
3611
|
}
|
|
3260
3612
|
hideObjects(objects) {
|
|
3261
|
-
const handles =
|
|
3613
|
+
const handles = this.getHandlesByObjects(objects);
|
|
3262
3614
|
this.gltfLoader.hideObjects(handles);
|
|
3263
3615
|
return this;
|
|
3264
3616
|
}
|
|
3265
3617
|
isolateObjects(objects) {
|
|
3266
|
-
const handles =
|
|
3618
|
+
const handles = this.getHandlesByObjects(objects);
|
|
3267
3619
|
this.gltfLoader.isolateObjects(new Set(handles));
|
|
3268
3620
|
return this;
|
|
3269
3621
|
}
|
|
3270
3622
|
showObjects(objects) {
|
|
3271
|
-
const handles =
|
|
3623
|
+
const handles = this.getHandlesByObjects(objects);
|
|
3272
3624
|
this.gltfLoader.showObjects(handles);
|
|
3273
3625
|
return this;
|
|
3274
3626
|
}
|
|
@@ -3332,11 +3684,16 @@ class GltfStructure {
|
|
|
3332
3684
|
this.materials = new Map();
|
|
3333
3685
|
this.textureCache = new Map();
|
|
3334
3686
|
this.materialCache = new Map();
|
|
3687
|
+
this.uri = "";
|
|
3688
|
+
this._nextObjectId = 0;
|
|
3689
|
+
this.loadingAborted = false;
|
|
3690
|
+
this.criticalError = null;
|
|
3335
3691
|
}
|
|
3336
3692
|
async initialize(loader) {
|
|
3337
3693
|
this.json = await this.loadController.loadJson();
|
|
3338
3694
|
this.baseUrl = await this.loadController.baseUrl();
|
|
3339
3695
|
this.loader = loader;
|
|
3696
|
+
this.uri = this.json.buffers[0].uri || "";
|
|
3340
3697
|
}
|
|
3341
3698
|
clear() {
|
|
3342
3699
|
this.json = null;
|
|
@@ -3352,12 +3709,18 @@ class GltfStructure {
|
|
|
3352
3709
|
this.materials.clear();
|
|
3353
3710
|
this.activeChunkLoads = 0;
|
|
3354
3711
|
this.chunkQueue = [];
|
|
3712
|
+
this.loadingAborted = false;
|
|
3713
|
+
this.criticalError = null;
|
|
3355
3714
|
}
|
|
3356
3715
|
getJson() {
|
|
3357
3716
|
return this.json;
|
|
3358
3717
|
}
|
|
3359
3718
|
scheduleRequest(request) {
|
|
3360
3719
|
return new Promise((resolve, reject) => {
|
|
3720
|
+
if (this.loadingAborted) {
|
|
3721
|
+
reject(this.criticalError || new Error("Structure loading has been aborted due to critical error"));
|
|
3722
|
+
return;
|
|
3723
|
+
}
|
|
3361
3724
|
this.pendingRequests.push({
|
|
3362
3725
|
...request,
|
|
3363
3726
|
_resolve: resolve,
|
|
@@ -3365,6 +3728,41 @@ class GltfStructure {
|
|
|
3365
3728
|
});
|
|
3366
3729
|
});
|
|
3367
3730
|
}
|
|
3731
|
+
isCriticalHttpError(error) {
|
|
3732
|
+
if (!error) return false;
|
|
3733
|
+
const status = error.status || error.statusCode || error.code;
|
|
3734
|
+
if (typeof status === "number") {
|
|
3735
|
+
return status >= 400 && status < 600;
|
|
3736
|
+
}
|
|
3737
|
+
if (error.message) {
|
|
3738
|
+
const match = error.message.match(/HTTP\s+(\d{3})/i);
|
|
3739
|
+
if (match) {
|
|
3740
|
+
const code = parseInt(match[1], 10);
|
|
3741
|
+
return code >= 400 && code < 600;
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
return false;
|
|
3745
|
+
}
|
|
3746
|
+
abortLoading(error) {
|
|
3747
|
+
if (this.loadingAborted) {
|
|
3748
|
+
return;
|
|
3749
|
+
}
|
|
3750
|
+
this.loadingAborted = true;
|
|
3751
|
+
this.criticalError = error;
|
|
3752
|
+
const requests = [...this.pendingRequests];
|
|
3753
|
+
this.pendingRequests = [];
|
|
3754
|
+
for (const req of requests) {
|
|
3755
|
+
if (req._reject) {
|
|
3756
|
+
req._reject(error);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
console.error(
|
|
3760
|
+
`❌ Critical error for structure "${this.id}". All further loading aborted.`,
|
|
3761
|
+
`\n Error: ${error.message || error}`,
|
|
3762
|
+
`\n Rejected ${requests.length} pending chunk requests.`
|
|
3763
|
+
);
|
|
3764
|
+
throw error;
|
|
3765
|
+
}
|
|
3368
3766
|
async flushBufferRequests() {
|
|
3369
3767
|
if (!this.pendingRequests || this.pendingRequests.length === 0) return;
|
|
3370
3768
|
const requests = [...this.pendingRequests];
|
|
@@ -3427,10 +3825,16 @@ class GltfStructure {
|
|
|
3427
3825
|
}
|
|
3428
3826
|
}
|
|
3429
3827
|
const promises = finalRanges.map(async (range, index) => {
|
|
3828
|
+
if (this.loadingAborted) {
|
|
3829
|
+
for (const req of range.requests) {
|
|
3830
|
+
req._reject(this.criticalError || new Error("Structure loading aborted"));
|
|
3831
|
+
}
|
|
3832
|
+
return;
|
|
3833
|
+
}
|
|
3430
3834
|
await this.loader.waitForChunkSlot();
|
|
3431
3835
|
try {
|
|
3432
3836
|
const length = range.end - range.start;
|
|
3433
|
-
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }]);
|
|
3837
|
+
const buffer = await this.loadController.loadBinaryData([{ offset: range.start, length }], this.uri);
|
|
3434
3838
|
for (const req of range.requests) {
|
|
3435
3839
|
const relOffset = req.offset - range.start;
|
|
3436
3840
|
try {
|
|
@@ -3443,7 +3847,11 @@ class GltfStructure {
|
|
|
3443
3847
|
for (const req of range.requests) {
|
|
3444
3848
|
req._reject(error);
|
|
3445
3849
|
}
|
|
3446
|
-
|
|
3850
|
+
if (this.isCriticalHttpError(error)) {
|
|
3851
|
+
this.abortLoading(error);
|
|
3852
|
+
} else {
|
|
3853
|
+
console.warn(`Failed to load chunk ${index + 1}/${finalRanges.length} (${range.start}-${range.end}):`, error);
|
|
3854
|
+
}
|
|
3447
3855
|
} finally {
|
|
3448
3856
|
this.loader.releaseChunkSlot();
|
|
3449
3857
|
}
|
|
@@ -3747,6 +4155,7 @@ class GltfStructure {
|
|
|
3747
4155
|
}
|
|
3748
4156
|
}
|
|
3749
4157
|
|
|
4158
|
+
const STRUCTURE_ID_SEPARATOR = ":";
|
|
3750
4159
|
class DynamicGltfLoader {
|
|
3751
4160
|
constructor(camera, scene, renderer) {
|
|
3752
4161
|
this.camera = camera;
|
|
@@ -3759,6 +4168,7 @@ class DynamicGltfLoader {
|
|
|
3759
4168
|
geometryerror: [],
|
|
3760
4169
|
update: [],
|
|
3761
4170
|
geometrymemory: [],
|
|
4171
|
+
optimizationprogress: [],
|
|
3762
4172
|
};
|
|
3763
4173
|
this.loadDistance = 100;
|
|
3764
4174
|
this.unloadDistance = 150;
|
|
@@ -3800,7 +4210,6 @@ class DynamicGltfLoader {
|
|
|
3800
4210
|
this.hiddenHandles = new Set();
|
|
3801
4211
|
this.newOptimizedObjects = new Set();
|
|
3802
4212
|
this.oldOptimizeObjects = new Set();
|
|
3803
|
-
this.maxConcurrentChunks = 8;
|
|
3804
4213
|
this.activeChunkLoads = 0;
|
|
3805
4214
|
this.chunkQueue = [];
|
|
3806
4215
|
this.objectIdToIndex = new Map();
|
|
@@ -3809,6 +4218,7 @@ class DynamicGltfLoader {
|
|
|
3809
4218
|
this.maxConcurrentChunks = 6;
|
|
3810
4219
|
this.mergedObjectMap = new Map();
|
|
3811
4220
|
this.mergedGeometryVisibility = new Map();
|
|
4221
|
+
this._webglInfoCache = null;
|
|
3812
4222
|
}
|
|
3813
4223
|
setVisibleEdges(visible) {
|
|
3814
4224
|
this.visibleEdges = visible;
|
|
@@ -3912,6 +4322,123 @@ class DynamicGltfLoader {
|
|
|
3912
4322
|
this.updateMemoryIndicator();
|
|
3913
4323
|
console.log(`Final memory usage: ${Math.round(currentMemoryUsage / (1024 * 1024))}MB`);
|
|
3914
4324
|
}
|
|
4325
|
+
getStats() {
|
|
4326
|
+
let totalObjects = 0;
|
|
4327
|
+
let renderedObjects = 0;
|
|
4328
|
+
let totalTriangles = 0;
|
|
4329
|
+
let renderedTriangles = 0;
|
|
4330
|
+
let totalLines = 0;
|
|
4331
|
+
let renderedLines = 0;
|
|
4332
|
+
let totalEdges = 0;
|
|
4333
|
+
let renderedEdges = 0;
|
|
4334
|
+
this.scene.traverse((object) => {
|
|
4335
|
+
totalObjects++;
|
|
4336
|
+
const geometry = object.geometry;
|
|
4337
|
+
if (!geometry) return;
|
|
4338
|
+
let triCount = 0;
|
|
4339
|
+
if (geometry.index) {
|
|
4340
|
+
triCount = Math.floor(geometry.index.count / 3);
|
|
4341
|
+
} else if (geometry.attributes && geometry.attributes.position) {
|
|
4342
|
+
triCount = Math.floor(geometry.attributes.position.count / 3);
|
|
4343
|
+
}
|
|
4344
|
+
totalTriangles += triCount;
|
|
4345
|
+
let lineCount = 0;
|
|
4346
|
+
if (geometry.index) {
|
|
4347
|
+
lineCount = Math.floor(geometry.index.count / 2);
|
|
4348
|
+
} else if (geometry.attributes && geometry.attributes.position) {
|
|
4349
|
+
lineCount = Math.floor(geometry.attributes.position.count / 2);
|
|
4350
|
+
}
|
|
4351
|
+
if (object.type === "Line" || object.type === "LineSegments" || object.type === "LineLoop") {
|
|
4352
|
+
if (object.userData.isEdge) {
|
|
4353
|
+
totalEdges += lineCount;
|
|
4354
|
+
} else {
|
|
4355
|
+
totalLines += lineCount;
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
if (object.visible !== false) {
|
|
4359
|
+
if (object.isMesh || object.isLine || object.isPoints) {
|
|
4360
|
+
renderedObjects++;
|
|
4361
|
+
if (object.isMesh) {
|
|
4362
|
+
renderedTriangles += triCount;
|
|
4363
|
+
} else if (object.type === "Line" || object.type === "LineSegments" || object.type === "LineLoop") {
|
|
4364
|
+
if (object.userData.isEdge) {
|
|
4365
|
+
renderedEdges += lineCount;
|
|
4366
|
+
} else {
|
|
4367
|
+
renderedLines += lineCount;
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
});
|
|
4373
|
+
const geometryCount = this.geometryCache ? this.geometryCache.size : 0;
|
|
4374
|
+
const geometryMemoryBytes = Array.from(this.geometryCache?.values?.() || []).reduce((a, b) => a + b, 0);
|
|
4375
|
+
const uniqueMaterialIds = new Set();
|
|
4376
|
+
const uniqueTextureIds = new Set();
|
|
4377
|
+
if (Array.isArray(this.structures)) {
|
|
4378
|
+
for (const structure of this.structures) {
|
|
4379
|
+
console.log(structure.materialCache.values());
|
|
4380
|
+
try {
|
|
4381
|
+
for (const entry of structure.materialCache.values()) {
|
|
4382
|
+
if (entry?.mesh?.uuid) uniqueMaterialIds.add(entry.mesh.uuid);
|
|
4383
|
+
if (entry?.points?.uuid) uniqueMaterialIds.add(entry.points.uuid);
|
|
4384
|
+
if (entry?.lines?.uuid) uniqueMaterialIds.add(entry.lines.uuid);
|
|
4385
|
+
}
|
|
4386
|
+
} catch (exp) {
|
|
4387
|
+
console.error("Error adding material to uniqueMaterialIds", exp);
|
|
4388
|
+
}
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
const materialCount = uniqueMaterialIds.size;
|
|
4392
|
+
const textureCount = uniqueTextureIds.size;
|
|
4393
|
+
const estimatedGpuMemoryBytes = geometryMemoryBytes;
|
|
4394
|
+
if (!this._webglInfoCache) {
|
|
4395
|
+
try {
|
|
4396
|
+
const gl = this.renderer.getContext();
|
|
4397
|
+
const dbgInfo = gl.getExtension("WEBGL_debug_renderer_info");
|
|
4398
|
+
if (dbgInfo) {
|
|
4399
|
+
const rendererStr = gl.getParameter(dbgInfo.UNMASKED_RENDERER_WEBGL);
|
|
4400
|
+
const vendorStr = gl.getParameter(dbgInfo.UNMASKED_VENDOR_WEBGL);
|
|
4401
|
+
this._webglInfoCache = { renderer: rendererStr, vendor: vendorStr };
|
|
4402
|
+
} else {
|
|
4403
|
+
this._webglInfoCache = { renderer: null, vendor: null };
|
|
4404
|
+
}
|
|
4405
|
+
} catch (e) {
|
|
4406
|
+
console.error("Error getting webgl info", e);
|
|
4407
|
+
this._webglInfoCache = { renderer: null, vendor: null };
|
|
4408
|
+
}
|
|
4409
|
+
}
|
|
4410
|
+
const size = new Vector2();
|
|
4411
|
+
if (this.renderer && this.renderer.getSize) {
|
|
4412
|
+
this.renderer.getSize(size);
|
|
4413
|
+
}
|
|
4414
|
+
return {
|
|
4415
|
+
scene: {
|
|
4416
|
+
beforeOptimization: {
|
|
4417
|
+
objects: totalObjects - renderedObjects,
|
|
4418
|
+
triangles: totalTriangles - renderedTriangles,
|
|
4419
|
+
lines: totalLines - renderedLines,
|
|
4420
|
+
edges: totalEdges - renderedEdges,
|
|
4421
|
+
},
|
|
4422
|
+
afterOptimization: {
|
|
4423
|
+
objects: renderedObjects,
|
|
4424
|
+
triangles: renderedTriangles,
|
|
4425
|
+
lines: renderedLines,
|
|
4426
|
+
edges: renderedEdges,
|
|
4427
|
+
},
|
|
4428
|
+
},
|
|
4429
|
+
memory: {
|
|
4430
|
+
geometries: { count: geometryCount, bytes: geometryMemoryBytes },
|
|
4431
|
+
textures: { count: textureCount },
|
|
4432
|
+
materials: { count: materialCount },
|
|
4433
|
+
totalEstimatedGpuBytes: estimatedGpuMemoryBytes,
|
|
4434
|
+
},
|
|
4435
|
+
system: {
|
|
4436
|
+
webglRenderer: this._webglInfoCache?.renderer || "",
|
|
4437
|
+
webglVendor: this._webglInfoCache?.vendor || "",
|
|
4438
|
+
viewport: { width: size.x || 0, height: size.y || 0 },
|
|
4439
|
+
},
|
|
4440
|
+
};
|
|
4441
|
+
}
|
|
3915
4442
|
async loadNode(nodeId, onLoadFinishCb) {
|
|
3916
4443
|
const node = this.nodes.get(nodeId);
|
|
3917
4444
|
if (!node || node.loaded || node.loading) return;
|
|
@@ -4082,7 +4609,7 @@ class DynamicGltfLoader {
|
|
|
4082
4609
|
if (node.handle) {
|
|
4083
4610
|
mesh.userData.handle = node.handle;
|
|
4084
4611
|
} else {
|
|
4085
|
-
mesh.userData.handle =
|
|
4612
|
+
mesh.userData.handle = this.getFullHandle(node.structure.id, mesh.userData.handle);
|
|
4086
4613
|
}
|
|
4087
4614
|
if (mesh.material.name === "edges") {
|
|
4088
4615
|
mesh.userData.isEdge = true;
|
|
@@ -4115,10 +4642,14 @@ class DynamicGltfLoader {
|
|
|
4115
4642
|
onLoadFinishCb();
|
|
4116
4643
|
}
|
|
4117
4644
|
} catch (error) {
|
|
4118
|
-
if (error.name !== "AbortError") {
|
|
4119
|
-
console.error(`Error loading node ${nodeId}:`, error);
|
|
4120
|
-
}
|
|
4121
4645
|
node.loading = false;
|
|
4646
|
+
if (error.name === "AbortError") {
|
|
4647
|
+
return;
|
|
4648
|
+
}
|
|
4649
|
+
if (node.structure && node.structure.loadingAborted) {
|
|
4650
|
+
return;
|
|
4651
|
+
}
|
|
4652
|
+
console.error(`Error loading node ${nodeId}:`, error);
|
|
4122
4653
|
}
|
|
4123
4654
|
}
|
|
4124
4655
|
unloadNode(nodeId) {
|
|
@@ -4223,12 +4754,15 @@ class DynamicGltfLoader {
|
|
|
4223
4754
|
})),
|
|
4224
4755
|
});
|
|
4225
4756
|
}
|
|
4757
|
+
getFullHandle(structureId, originalHandle) {
|
|
4758
|
+
return `${structureId}${STRUCTURE_ID_SEPARATOR}${originalHandle}`;
|
|
4759
|
+
}
|
|
4226
4760
|
async processNodeHierarchy(structure, nodeId, parentGroup) {
|
|
4227
4761
|
const nodeDef = structure.json.nodes[nodeId];
|
|
4228
4762
|
let nodeGroup = null;
|
|
4229
4763
|
let handle = null;
|
|
4230
4764
|
if (nodeDef.extras?.handle) {
|
|
4231
|
-
handle =
|
|
4765
|
+
handle = this.getFullHandle(structure.id, nodeDef.extras.handle);
|
|
4232
4766
|
}
|
|
4233
4767
|
if (nodeDef.camera !== undefined) {
|
|
4234
4768
|
const camera = this.loadCamera(structure, nodeDef.camera, nodeDef);
|
|
@@ -4245,7 +4779,7 @@ class DynamicGltfLoader {
|
|
|
4245
4779
|
if (nodeDef.extras) {
|
|
4246
4780
|
nodeGroup.userData = { ...nodeDef.extras };
|
|
4247
4781
|
if (nodeGroup.userData.handle) {
|
|
4248
|
-
nodeGroup.userData.handle =
|
|
4782
|
+
nodeGroup.userData.handle = this.getFullHandle(structure.id, nodeGroup.userData.handle);
|
|
4249
4783
|
}
|
|
4250
4784
|
}
|
|
4251
4785
|
if (nodeDef.matrix) {
|
|
@@ -4290,7 +4824,7 @@ class DynamicGltfLoader {
|
|
|
4290
4824
|
this.edgeNodes.push(uniqueNodeId);
|
|
4291
4825
|
}
|
|
4292
4826
|
if (meshDef.extras && meshDef.extras.handle) {
|
|
4293
|
-
handle =
|
|
4827
|
+
handle = this.getFullHandle(structure.id, meshDef.extras.handle);
|
|
4294
4828
|
}
|
|
4295
4829
|
this.nodes.set(uniqueNodeId, {
|
|
4296
4830
|
position: nodeGroup ? nodeGroup.position.clone() : new Vector3().setFromMatrixPosition(nodeMatrix),
|
|
@@ -4303,7 +4837,7 @@ class DynamicGltfLoader {
|
|
|
4303
4837
|
structure,
|
|
4304
4838
|
extras: nodeDef.extras,
|
|
4305
4839
|
geometryExtents,
|
|
4306
|
-
handle,
|
|
4840
|
+
handle: handle || this.getFullHandle(structure.id, structure._nextObjectId++),
|
|
4307
4841
|
});
|
|
4308
4842
|
}
|
|
4309
4843
|
if (nodeDef.children) {
|
|
@@ -4376,12 +4910,12 @@ class DynamicGltfLoader {
|
|
|
4376
4910
|
}
|
|
4377
4911
|
}
|
|
4378
4912
|
async loadNodes() {
|
|
4379
|
-
console.time("
|
|
4913
|
+
console.time("Process nodes");
|
|
4380
4914
|
await this.processNodes();
|
|
4381
|
-
console.timeEnd("
|
|
4382
|
-
console.time("
|
|
4915
|
+
console.timeEnd("Process nodes");
|
|
4916
|
+
console.time("Optimize scene");
|
|
4383
4917
|
await this.optimizeScene();
|
|
4384
|
-
console.timeEnd("
|
|
4918
|
+
console.timeEnd("Optimize scene");
|
|
4385
4919
|
}
|
|
4386
4920
|
cleanupPartialLoad() {
|
|
4387
4921
|
this.nodesToLoad.forEach((nodeId) => {
|
|
@@ -4702,7 +5236,7 @@ class DynamicGltfLoader {
|
|
|
4702
5236
|
this.handleToObjects.set(fullHandle, new Set());
|
|
4703
5237
|
}
|
|
4704
5238
|
this.handleToObjects.get(fullHandle).add(object);
|
|
4705
|
-
object.userData.structureId = object.userData.handle.split(
|
|
5239
|
+
object.userData.structureId = object.userData.handle.split(STRUCTURE_ID_SEPARATOR)[0];
|
|
4706
5240
|
}
|
|
4707
5241
|
getObjectsByHandle(handle) {
|
|
4708
5242
|
if (!handle) return [];
|
|
@@ -4768,10 +5302,28 @@ class DynamicGltfLoader {
|
|
|
4768
5302
|
}
|
|
4769
5303
|
this.originalObjects.add(object);
|
|
4770
5304
|
}
|
|
4771
|
-
|
|
5305
|
+
yieldToUI() {
|
|
5306
|
+
return new Promise((resolve) => {
|
|
5307
|
+
requestAnimationFrame(() => {
|
|
5308
|
+
setTimeout(resolve, 0);
|
|
5309
|
+
});
|
|
5310
|
+
});
|
|
5311
|
+
}
|
|
5312
|
+
async optimizeScene() {
|
|
5313
|
+
console.log("Starting scene optimization...");
|
|
5314
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5315
|
+
phase: "start",
|
|
5316
|
+
progress: 0,
|
|
5317
|
+
message: "Starting optimization...",
|
|
5318
|
+
});
|
|
4772
5319
|
this.originalObjects.clear();
|
|
4773
5320
|
this.originalObjectsToSelection.clear();
|
|
4774
5321
|
const structureGroups = new Map();
|
|
5322
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5323
|
+
phase: "collecting",
|
|
5324
|
+
progress: 5,
|
|
5325
|
+
message: "Collecting scene objects...",
|
|
5326
|
+
});
|
|
4775
5327
|
this.scene.traverse((object) => {
|
|
4776
5328
|
if (object.userData.structureId) {
|
|
4777
5329
|
const structureId = object.userData.structureId;
|
|
@@ -4800,16 +5352,44 @@ class DynamicGltfLoader {
|
|
|
4800
5352
|
}
|
|
4801
5353
|
}
|
|
4802
5354
|
});
|
|
5355
|
+
let processedGroups = 0;
|
|
5356
|
+
const totalGroups = structureGroups.size;
|
|
5357
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5358
|
+
phase: "merging",
|
|
5359
|
+
progress: 10,
|
|
5360
|
+
message: `Merging ${totalGroups} structure groups...`,
|
|
5361
|
+
current: 0,
|
|
5362
|
+
total: totalGroups,
|
|
5363
|
+
});
|
|
4803
5364
|
for (const group of structureGroups.values()) {
|
|
4804
5365
|
group.mapMeshes.clear();
|
|
4805
5366
|
group.mapLines.clear();
|
|
4806
5367
|
group.mapLineSegments.clear();
|
|
4807
5368
|
group.mapPoints.clear();
|
|
4808
|
-
this.mergeMeshGroups(group.meshes, group.rootGroup);
|
|
4809
|
-
this.
|
|
4810
|
-
this.
|
|
4811
|
-
this.
|
|
5369
|
+
await this.mergeMeshGroups(group.meshes, group.rootGroup);
|
|
5370
|
+
await this.yieldToUI();
|
|
5371
|
+
await this.mergeLineGroups(group.lines, group.rootGroup);
|
|
5372
|
+
await this.yieldToUI();
|
|
5373
|
+
await this.mergeLineSegmentGroups(group.lineSegments, group.rootGroup);
|
|
5374
|
+
await this.yieldToUI();
|
|
5375
|
+
await this.mergePointsGroups(group.points, group.rootGroup);
|
|
5376
|
+
processedGroups++;
|
|
5377
|
+
const progress = 10 + Math.round((processedGroups / totalGroups) * 80);
|
|
5378
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5379
|
+
phase: "merging",
|
|
5380
|
+
progress,
|
|
5381
|
+
message: `Processing structure ${processedGroups}/${totalGroups}...`,
|
|
5382
|
+
current: processedGroups,
|
|
5383
|
+
total: totalGroups,
|
|
5384
|
+
});
|
|
5385
|
+
console.log(`Optimization progress: ${processedGroups}/${totalGroups} structure groups processed (${progress}%)`);
|
|
5386
|
+
await this.yieldToUI();
|
|
4812
5387
|
}
|
|
5388
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5389
|
+
phase: "finalizing",
|
|
5390
|
+
progress: 95,
|
|
5391
|
+
message: "Finalizing optimization...",
|
|
5392
|
+
});
|
|
4813
5393
|
this.originalObjects.forEach((obj) => {
|
|
4814
5394
|
obj.visible = false;
|
|
4815
5395
|
if (!(obj instanceof Points) && !obj.userData.isEdge) {
|
|
@@ -4818,9 +5398,15 @@ class DynamicGltfLoader {
|
|
|
4818
5398
|
});
|
|
4819
5399
|
this.initializeObjectVisibility();
|
|
4820
5400
|
console.log(`Optimization complete. Total objects: ${this.maxObjectId}`);
|
|
5401
|
+
this.dispatchEvent("optimizationprogress", {
|
|
5402
|
+
phase: "complete",
|
|
5403
|
+
progress: 100,
|
|
5404
|
+
message: `Optimization complete! ${this.maxObjectId} objects processed.`,
|
|
5405
|
+
});
|
|
4821
5406
|
this.dispatchEvent("update");
|
|
4822
5407
|
}
|
|
4823
|
-
mergeMeshGroups(materialGroups, rootGroup) {
|
|
5408
|
+
async mergeMeshGroups(materialGroups, rootGroup) {
|
|
5409
|
+
let processedGroups = 0;
|
|
4824
5410
|
for (const group of materialGroups) {
|
|
4825
5411
|
if (!group.material) {
|
|
4826
5412
|
console.warn("Skipping mesh group with null material");
|
|
@@ -4834,8 +5420,6 @@ class DynamicGltfLoader {
|
|
|
4834
5420
|
let currentVertexOffset = 0;
|
|
4835
5421
|
for (const mesh of group.objects) {
|
|
4836
5422
|
const geometry = mesh.geometry.clone();
|
|
4837
|
-
mesh.updateWorldMatrix(true, false);
|
|
4838
|
-
geometry.applyMatrix4(mesh.matrixWorld);
|
|
4839
5423
|
const handle = mesh.userData.handle;
|
|
4840
5424
|
if (!this.objectIdToIndex.has(handle)) {
|
|
4841
5425
|
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
@@ -4871,6 +5455,7 @@ class DynamicGltfLoader {
|
|
|
4871
5455
|
}
|
|
4872
5456
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
4873
5457
|
const mergedMesh = new Mesh(mergedGeometry, visibilityMaterial);
|
|
5458
|
+
mergedMesh.userData.isOptimized = true;
|
|
4874
5459
|
rootGroup.add(mergedMesh);
|
|
4875
5460
|
this.mergedMesh.add(mergedMesh);
|
|
4876
5461
|
this.optimizedOriginalMap.set(mergedMesh, optimizedObjects);
|
|
@@ -4894,6 +5479,10 @@ class DynamicGltfLoader {
|
|
|
4894
5479
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
4895
5480
|
}
|
|
4896
5481
|
});
|
|
5482
|
+
processedGroups++;
|
|
5483
|
+
if (processedGroups % 5 === 0) {
|
|
5484
|
+
await this.yieldToUI();
|
|
5485
|
+
}
|
|
4897
5486
|
} catch (error) {
|
|
4898
5487
|
console.error("Failed to merge meshes for material:", error);
|
|
4899
5488
|
group.objects.forEach((mesh) => {
|
|
@@ -4902,7 +5491,8 @@ class DynamicGltfLoader {
|
|
|
4902
5491
|
}
|
|
4903
5492
|
}
|
|
4904
5493
|
}
|
|
4905
|
-
mergeLineGroups(materialGroups, rootGroup) {
|
|
5494
|
+
async mergeLineGroups(materialGroups, rootGroup) {
|
|
5495
|
+
let processedGroups = 0;
|
|
4906
5496
|
for (const group of materialGroups) {
|
|
4907
5497
|
if (group.objects.length === 0) continue;
|
|
4908
5498
|
if (!group.material) {
|
|
@@ -4921,7 +5511,9 @@ class DynamicGltfLoader {
|
|
|
4921
5511
|
let posOffset = 0;
|
|
4922
5512
|
const indices = [];
|
|
4923
5513
|
let vertexOffset = 0;
|
|
5514
|
+
let isEdge = false;
|
|
4924
5515
|
group.objects.forEach((line) => {
|
|
5516
|
+
isEdge = line.userData.isEdge;
|
|
4925
5517
|
const geometry = line.geometry;
|
|
4926
5518
|
const positionAttr = geometry.attributes.position;
|
|
4927
5519
|
const vertexCount = positionAttr.count;
|
|
@@ -4934,12 +5526,9 @@ class DynamicGltfLoader {
|
|
|
4934
5526
|
vertexCount,
|
|
4935
5527
|
});
|
|
4936
5528
|
currentVertexOffset += vertexCount;
|
|
4937
|
-
line.updateWorldMatrix(true, false);
|
|
4938
|
-
const matrix = line.matrixWorld;
|
|
4939
5529
|
const vector = new Vector3();
|
|
4940
5530
|
for (let i = 0; i < vertexCount; i++) {
|
|
4941
5531
|
vector.fromBufferAttribute(positionAttr, i);
|
|
4942
|
-
vector.applyMatrix4(matrix);
|
|
4943
5532
|
positions[posOffset++] = vector.x;
|
|
4944
5533
|
positions[posOffset++] = vector.y;
|
|
4945
5534
|
positions[posOffset++] = vector.z;
|
|
@@ -4972,6 +5561,8 @@ class DynamicGltfLoader {
|
|
|
4972
5561
|
geometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
4973
5562
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
4974
5563
|
const mergedLine = new LineSegments(geometry, visibilityMaterial);
|
|
5564
|
+
mergedLine.userData.isEdge = isEdge;
|
|
5565
|
+
mergedLine.userData.isOptimized = true;
|
|
4975
5566
|
const mergedObjects = [mergedLine];
|
|
4976
5567
|
if (this.useVAO) {
|
|
4977
5568
|
this.createVAO(mergedLine);
|
|
@@ -4994,9 +5585,14 @@ class DynamicGltfLoader {
|
|
|
4994
5585
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
4995
5586
|
}
|
|
4996
5587
|
});
|
|
5588
|
+
processedGroups++;
|
|
5589
|
+
if (processedGroups % 5 === 0) {
|
|
5590
|
+
await this.yieldToUI();
|
|
5591
|
+
}
|
|
4997
5592
|
}
|
|
4998
5593
|
}
|
|
4999
|
-
mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
5594
|
+
async mergeLineSegmentGroups(materialGroups, rootGroup) {
|
|
5595
|
+
let processedGroups = 0;
|
|
5000
5596
|
for (const group of materialGroups) {
|
|
5001
5597
|
if (!group.material) {
|
|
5002
5598
|
console.warn("Skipping line segment group with null material");
|
|
@@ -5008,10 +5604,10 @@ class DynamicGltfLoader {
|
|
|
5008
5604
|
const handles = new Set();
|
|
5009
5605
|
const objectMapping = new Map();
|
|
5010
5606
|
let currentVertexOffset = 0;
|
|
5607
|
+
let isEdge = false;
|
|
5011
5608
|
for (const line of group.objects) {
|
|
5609
|
+
isEdge = line.userData.isEdge;
|
|
5012
5610
|
const geometry = line.geometry.clone();
|
|
5013
|
-
line.updateWorldMatrix(true, false);
|
|
5014
|
-
geometry.applyMatrix4(line.matrixWorld);
|
|
5015
5611
|
const handle = line.userData.handle;
|
|
5016
5612
|
if (!this.objectIdToIndex.has(handle)) {
|
|
5017
5613
|
this.objectIdToIndex.set(handle, this.maxObjectId++);
|
|
@@ -5044,6 +5640,8 @@ class DynamicGltfLoader {
|
|
|
5044
5640
|
mergedGeometry.setAttribute("visibility", new BufferAttribute(visibilityArray, 1));
|
|
5045
5641
|
const visibilityMaterial = this.createVisibilityMaterial(group.material);
|
|
5046
5642
|
const mergedLine = new LineSegments(mergedGeometry, visibilityMaterial);
|
|
5643
|
+
mergedLine.userData.isEdge = isEdge;
|
|
5644
|
+
mergedLine.userData.isOptimized = true;
|
|
5047
5645
|
if (this.useVAO) {
|
|
5048
5646
|
this.createVAO(mergedLine);
|
|
5049
5647
|
}
|
|
@@ -5070,6 +5668,10 @@ class DynamicGltfLoader {
|
|
|
5070
5668
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
5071
5669
|
}
|
|
5072
5670
|
});
|
|
5671
|
+
processedGroups++;
|
|
5672
|
+
if (processedGroups % 5 === 0) {
|
|
5673
|
+
await this.yieldToUI();
|
|
5674
|
+
}
|
|
5073
5675
|
} catch (error) {
|
|
5074
5676
|
console.warn("Failed to merge line segments for material:", error);
|
|
5075
5677
|
group.objects.forEach((line) => {
|
|
@@ -5078,7 +5680,8 @@ class DynamicGltfLoader {
|
|
|
5078
5680
|
}
|
|
5079
5681
|
}
|
|
5080
5682
|
}
|
|
5081
|
-
mergePointsGroups(materialGroups, rootGroup) {
|
|
5683
|
+
async mergePointsGroups(materialGroups, rootGroup) {
|
|
5684
|
+
let processedGroups = 0;
|
|
5082
5685
|
for (const group of materialGroups) {
|
|
5083
5686
|
if (!group.material) {
|
|
5084
5687
|
console.warn("Skipping points group with null material");
|
|
@@ -5090,8 +5693,6 @@ class DynamicGltfLoader {
|
|
|
5090
5693
|
const handles = new Set();
|
|
5091
5694
|
for (const points of group.objects) {
|
|
5092
5695
|
const geometry = points.geometry.clone();
|
|
5093
|
-
points.updateWorldMatrix(true, false);
|
|
5094
|
-
geometry.applyMatrix4(points.matrixWorld);
|
|
5095
5696
|
geometries.push(geometry);
|
|
5096
5697
|
optimizedObjects.push(points);
|
|
5097
5698
|
handles.add(points.userData.handle);
|
|
@@ -5100,6 +5701,7 @@ class DynamicGltfLoader {
|
|
|
5100
5701
|
if (geometries.length > 0) {
|
|
5101
5702
|
const mergedGeometry = mergeGeometries(geometries, false);
|
|
5102
5703
|
const mergedPoints = new Points(mergedGeometry, group.material);
|
|
5704
|
+
mergedPoints.userData.isOptimized = true;
|
|
5103
5705
|
if (this.useVAO) {
|
|
5104
5706
|
this.createVAO(mergedPoints);
|
|
5105
5707
|
}
|
|
@@ -5120,6 +5722,10 @@ class DynamicGltfLoader {
|
|
|
5120
5722
|
this.handleToOptimizedObjects.set(handle, mergedObjects);
|
|
5121
5723
|
}
|
|
5122
5724
|
});
|
|
5725
|
+
processedGroups++;
|
|
5726
|
+
if (processedGroups % 5 === 0) {
|
|
5727
|
+
await this.yieldToUI();
|
|
5728
|
+
}
|
|
5123
5729
|
} catch (error) {
|
|
5124
5730
|
console.warn("Failed to merge points for material:", error);
|
|
5125
5731
|
group.objects.forEach((points) => {
|
|
@@ -5138,7 +5744,6 @@ class DynamicGltfLoader {
|
|
|
5138
5744
|
const hasNormals = lineSegmentsArray.some((segment) => segment.geometry.attributes.normal !== undefined);
|
|
5139
5745
|
lineSegmentsArray.forEach((segment) => {
|
|
5140
5746
|
const clonedGeometry = segment.geometry.clone();
|
|
5141
|
-
segment.updateWorldMatrix(true, false);
|
|
5142
5747
|
clonedGeometry.applyMatrix4(segment.matrixWorld);
|
|
5143
5748
|
if (hasNormals && !clonedGeometry.attributes.normal) {
|
|
5144
5749
|
clonedGeometry.computeVertexNormals();
|
|
@@ -5172,6 +5777,7 @@ class DynamicGltfLoader {
|
|
|
5172
5777
|
}
|
|
5173
5778
|
const mergedLine = new LineSegments(finalGeometry, material);
|
|
5174
5779
|
mergedLine.userData.structureId = structureId;
|
|
5780
|
+
mergedLine.userData.isOptimized = true;
|
|
5175
5781
|
rootGroup.add(mergedLine);
|
|
5176
5782
|
this.mergedLineSegments.add(mergedLine);
|
|
5177
5783
|
lineSegmentsArray.forEach((obj) => {
|
|
@@ -5355,8 +5961,232 @@ class DynamicGltfLoader {
|
|
|
5355
5961
|
}
|
|
5356
5962
|
}
|
|
5357
5963
|
|
|
5358
|
-
class
|
|
5964
|
+
class GLTFLoadingManager extends LoadingManager {
|
|
5965
|
+
constructor(file, params = {}) {
|
|
5966
|
+
super();
|
|
5967
|
+
this.path = "";
|
|
5968
|
+
this.resourcePath = "";
|
|
5969
|
+
this.fileURL = "";
|
|
5970
|
+
this.dataURLs = new Map();
|
|
5971
|
+
this.path = params.path || "";
|
|
5972
|
+
const externalFiles = params.externalFiles || new Map();
|
|
5973
|
+
if (typeof file === "string") {
|
|
5974
|
+
this.fileURL = file;
|
|
5975
|
+
this.resourcePath = LoaderUtils.extractUrlBase(file);
|
|
5976
|
+
}
|
|
5977
|
+
else {
|
|
5978
|
+
externalFiles.forEach((value, key) => (this.fileURL = value === file ? key : this.fileURL));
|
|
5979
|
+
externalFiles.set(this.fileURL, file);
|
|
5980
|
+
}
|
|
5981
|
+
externalFiles.forEach((value, key) => {
|
|
5982
|
+
let dataURL;
|
|
5983
|
+
if (typeof value === "string")
|
|
5984
|
+
dataURL = value;
|
|
5985
|
+
else
|
|
5986
|
+
dataURL = URL.createObjectURL(new Blob([value]));
|
|
5987
|
+
this.dataURLs.set(key, dataURL);
|
|
5988
|
+
});
|
|
5989
|
+
this.setURLModifier((url) => {
|
|
5990
|
+
const key = decodeURI(url)
|
|
5991
|
+
.replace(this.path, "")
|
|
5992
|
+
.replace(this.resourcePath, "")
|
|
5993
|
+
.replace(/^(\.?\/)/, "");
|
|
5994
|
+
const dataURL = this.dataURLs.get(key);
|
|
5995
|
+
return dataURL !== null && dataURL !== void 0 ? dataURL : url;
|
|
5996
|
+
});
|
|
5997
|
+
}
|
|
5998
|
+
dispose() {
|
|
5999
|
+
this.dataURLs.forEach((dataURL) => URL.revokeObjectURL(dataURL));
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
|
|
6003
|
+
const BINARY_EXTENSION_HEADER_MAGIC = "glTF";
|
|
6004
|
+
const BINARY_EXTENSION_HEADER_LENGTH = 12;
|
|
6005
|
+
const BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4e4f534a, BIN: 0x004e4042 };
|
|
6006
|
+
class GLTFBinaryExtension {
|
|
6007
|
+
constructor(data) {
|
|
6008
|
+
const headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH);
|
|
6009
|
+
const textDecoder = new TextDecoder();
|
|
6010
|
+
const magic = textDecoder.decode(new Uint8Array(data.slice(0, 4)));
|
|
6011
|
+
if (magic !== BINARY_EXTENSION_HEADER_MAGIC) {
|
|
6012
|
+
this.content = textDecoder.decode(data);
|
|
6013
|
+
return;
|
|
6014
|
+
}
|
|
6015
|
+
const header = {
|
|
6016
|
+
magic,
|
|
6017
|
+
version: headerView.getUint32(4, true),
|
|
6018
|
+
length: headerView.getUint32(8, true),
|
|
6019
|
+
};
|
|
6020
|
+
if (header.magic !== BINARY_EXTENSION_HEADER_MAGIC) {
|
|
6021
|
+
throw new Error("Unsupported glTF-Binary header.");
|
|
6022
|
+
}
|
|
6023
|
+
if (header.version < 2.0) {
|
|
6024
|
+
throw new Error("Legacy binary file detected.");
|
|
6025
|
+
}
|
|
6026
|
+
const chunkContentsLength = header.length - BINARY_EXTENSION_HEADER_LENGTH;
|
|
6027
|
+
const chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH);
|
|
6028
|
+
let chunkIndex = 0;
|
|
6029
|
+
while (chunkIndex < chunkContentsLength) {
|
|
6030
|
+
const chunkLength = chunkView.getUint32(chunkIndex, true);
|
|
6031
|
+
chunkIndex += 4;
|
|
6032
|
+
const chunkType = chunkView.getUint32(chunkIndex, true);
|
|
6033
|
+
chunkIndex += 4;
|
|
6034
|
+
if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) {
|
|
6035
|
+
const contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength);
|
|
6036
|
+
this.content = textDecoder.decode(contentArray);
|
|
6037
|
+
}
|
|
6038
|
+
else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) {
|
|
6039
|
+
const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
|
|
6040
|
+
this.body = data.slice(byteOffset, byteOffset + chunkLength);
|
|
6041
|
+
}
|
|
6042
|
+
chunkIndex += chunkLength;
|
|
6043
|
+
}
|
|
6044
|
+
if (typeof this.content === "undefined") {
|
|
6045
|
+
throw new Error("JSON content not found.");
|
|
6046
|
+
}
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
|
|
6050
|
+
class FetchError extends Error {
|
|
6051
|
+
constructor(status, message) {
|
|
6052
|
+
super(message);
|
|
6053
|
+
this.name = "FetchError";
|
|
6054
|
+
this.status = status;
|
|
6055
|
+
}
|
|
6056
|
+
}
|
|
6057
|
+
class RangesLoader {
|
|
6058
|
+
constructor() {
|
|
6059
|
+
this.requestHeader = {};
|
|
6060
|
+
this.withCredentials = false;
|
|
6061
|
+
this.abortSignal = undefined;
|
|
6062
|
+
}
|
|
6063
|
+
setRequestHeader(requestHeader) {
|
|
6064
|
+
this.requestHeader = requestHeader;
|
|
6065
|
+
}
|
|
6066
|
+
setWithCredentials(withCredentials) {
|
|
6067
|
+
this.withCredentials = withCredentials;
|
|
6068
|
+
}
|
|
6069
|
+
setAbortSignal(abortSignal) {
|
|
6070
|
+
this.abortSignal = abortSignal;
|
|
6071
|
+
}
|
|
6072
|
+
async load(url, ranges) {
|
|
6073
|
+
const init = {
|
|
6074
|
+
headers: {
|
|
6075
|
+
...this.requestHeader,
|
|
6076
|
+
Range: "bytes=" + ranges.map((x) => `${x.offset}-${x.offset + x.length - 1}`).join(","),
|
|
6077
|
+
},
|
|
6078
|
+
credentials: this.withCredentials ? "include" : "same-origin",
|
|
6079
|
+
signal: this.abortSignal,
|
|
6080
|
+
};
|
|
6081
|
+
const response = await fetch(url, init);
|
|
6082
|
+
if (!response.ok) {
|
|
6083
|
+
throw new FetchError(response.status, `Failed to fetch "${url}", status ${response.status}`);
|
|
6084
|
+
}
|
|
6085
|
+
if (response.status !== 206) {
|
|
6086
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
6087
|
+
return this.extractRanges(arrayBuffer, ranges);
|
|
6088
|
+
}
|
|
6089
|
+
return response.arrayBuffer();
|
|
6090
|
+
}
|
|
6091
|
+
extractRanges(arrayBuffer, ranges) {
|
|
6092
|
+
const totalLength = ranges.reduce((sum, range) => sum + range.length, 0);
|
|
6093
|
+
const result = new Uint8Array(totalLength);
|
|
6094
|
+
let offset = 0;
|
|
6095
|
+
for (const range of ranges) {
|
|
6096
|
+
const chunk = new Uint8Array(arrayBuffer, range.offset, range.length);
|
|
6097
|
+
result.set(chunk, offset);
|
|
6098
|
+
offset += range.length;
|
|
6099
|
+
}
|
|
6100
|
+
return result.buffer;
|
|
6101
|
+
}
|
|
6102
|
+
}
|
|
6103
|
+
|
|
6104
|
+
class GLTFFileDynamicLoader extends Loader {
|
|
6105
|
+
constructor(viewer) {
|
|
6106
|
+
super();
|
|
6107
|
+
this.viewer = viewer;
|
|
6108
|
+
}
|
|
6109
|
+
dispose() {
|
|
6110
|
+
if (this.gltfLoader)
|
|
6111
|
+
this.gltfLoader.clear();
|
|
6112
|
+
if (this.manager)
|
|
6113
|
+
this.manager.dispose();
|
|
6114
|
+
}
|
|
6115
|
+
isSupport(file, format) {
|
|
6116
|
+
return ((typeof file === "string" || file instanceof globalThis.File || file instanceof ArrayBuffer) &&
|
|
6117
|
+
/(gltf|glb)$/i.test(format));
|
|
6118
|
+
}
|
|
6119
|
+
async load(file, format, params) {
|
|
6120
|
+
this.manager = new GLTFLoadingManager(file, params);
|
|
6121
|
+
const scene = new Group();
|
|
6122
|
+
this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
|
|
6123
|
+
this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
|
|
6124
|
+
this.gltfLoader.visibleEdges = this.viewer.options.edgeModel;
|
|
6125
|
+
const modelImpl = new DynamicModelImpl(scene);
|
|
6126
|
+
modelImpl.id = params.modelId || this.extractFileName(file);
|
|
6127
|
+
modelImpl.gltfLoader = this.gltfLoader;
|
|
6128
|
+
this.gltfLoader.addEventListener("databasechunk", () => {
|
|
6129
|
+
this.viewer.scene.add(scene);
|
|
6130
|
+
this.viewer.models.push(modelImpl);
|
|
6131
|
+
this.viewer.syncOptions();
|
|
6132
|
+
this.viewer.syncOverlay();
|
|
6133
|
+
this.viewer.update();
|
|
6134
|
+
this.viewer.emitEvent({ type: "databasechunk", data: scene, file });
|
|
6135
|
+
});
|
|
6136
|
+
this.gltfLoader.addEventListener("geometryerror", (data) => {
|
|
6137
|
+
this.viewer.emitEvent({ type: "geometryerror", data, file });
|
|
6138
|
+
});
|
|
6139
|
+
this.gltfLoader.addEventListener("update", (data) => {
|
|
6140
|
+
this.viewer.update();
|
|
6141
|
+
});
|
|
6142
|
+
const loadController = {
|
|
6143
|
+
loadJson: async () => {
|
|
6144
|
+
const loader = new FileLoader(this.manager);
|
|
6145
|
+
loader.setPath(this.manager.path);
|
|
6146
|
+
loader.setRequestHeader(params.requestHeader || {});
|
|
6147
|
+
loader.setWithCredentials(params.withCredentials || loader.withCredentials);
|
|
6148
|
+
loader.setResponseType("arraybuffer");
|
|
6149
|
+
const progress = (event) => {
|
|
6150
|
+
const { lengthComputable, loaded, total } = event;
|
|
6151
|
+
const progress = lengthComputable ? loaded / total : 1;
|
|
6152
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file });
|
|
6153
|
+
};
|
|
6154
|
+
const data = await loader.loadAsync(this.manager.fileURL, progress);
|
|
6155
|
+
const extension = new GLTFBinaryExtension(data);
|
|
6156
|
+
this.gltf = JSON.parse(extension.content);
|
|
6157
|
+
this.bin = extension.body;
|
|
6158
|
+
return this.gltf;
|
|
6159
|
+
},
|
|
6160
|
+
loadBinaryData: (ranges, uri = "") => {
|
|
6161
|
+
const loader = new RangesLoader();
|
|
6162
|
+
loader.setRequestHeader(params.requestHeader || {});
|
|
6163
|
+
loader.setWithCredentials(params.withCredentials || false);
|
|
6164
|
+
loader.setAbortSignal(this.gltfLoader.abortController.signal);
|
|
6165
|
+
if (this.bin)
|
|
6166
|
+
return loader.extractRanges(this.bin, ranges);
|
|
6167
|
+
const path = this.manager.path || this.manager.resourcePath;
|
|
6168
|
+
const url = LoaderUtils.resolveURL(uri, path);
|
|
6169
|
+
return loader.load(this.manager.resolveURL(url), ranges);
|
|
6170
|
+
},
|
|
6171
|
+
baseUrl: () => {
|
|
6172
|
+
const path = this.manager.path || this.manager.resourcePath;
|
|
6173
|
+
return Promise.resolve(path);
|
|
6174
|
+
},
|
|
6175
|
+
};
|
|
6176
|
+
const structure = new GltfStructure(modelImpl.id, loadController);
|
|
6177
|
+
await this.gltfLoader.loadStructure(structure);
|
|
6178
|
+
await this.gltfLoader.loadNodes();
|
|
6179
|
+
return this;
|
|
6180
|
+
}
|
|
6181
|
+
cancel() {
|
|
6182
|
+
if (this.gltfLoader)
|
|
6183
|
+
this.gltfLoader.abortLoading();
|
|
6184
|
+
}
|
|
6185
|
+
}
|
|
6186
|
+
|
|
6187
|
+
class GLTFCloudDynamicLoader extends Loader {
|
|
5359
6188
|
constructor(viewer) {
|
|
6189
|
+
super();
|
|
5360
6190
|
this.requestId = 0;
|
|
5361
6191
|
this.viewer = viewer;
|
|
5362
6192
|
}
|
|
@@ -5371,17 +6201,15 @@ class GLTFCloudDynamicLoader {
|
|
|
5371
6201
|
typeof file.downloadResourceRange === "function" &&
|
|
5372
6202
|
/.gltf$/i.test(file.database));
|
|
5373
6203
|
}
|
|
5374
|
-
async load(model, format, params) {
|
|
6204
|
+
async load(model, format, params = {}) {
|
|
5375
6205
|
const scene = new Group();
|
|
5376
6206
|
this.gltfLoader = new DynamicGltfLoader(this.viewer.camera, scene, this.viewer.renderer);
|
|
5377
6207
|
this.gltfLoader.memoryLimit = this.viewer.options.memoryLimit;
|
|
5378
6208
|
this.gltfLoader.setVisibleEdges(this.viewer.options.edgeModel);
|
|
6209
|
+
const modelImpl = new DynamicModelImpl(scene);
|
|
6210
|
+
modelImpl.id = model.file.id;
|
|
6211
|
+
modelImpl.gltfLoader = this.gltfLoader;
|
|
5379
6212
|
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
6213
|
this.viewer.scene.add(scene);
|
|
5386
6214
|
this.viewer.models.push(modelImpl);
|
|
5387
6215
|
this.viewer.syncOptions();
|
|
@@ -5389,10 +6217,6 @@ class GLTFCloudDynamicLoader {
|
|
|
5389
6217
|
this.viewer.update();
|
|
5390
6218
|
this.viewer.emitEvent({ type: "databasechunk", data: scene, file: model.file, model });
|
|
5391
6219
|
});
|
|
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
6220
|
this.gltfLoader.addEventListener("geometryerror", (data) => {
|
|
5397
6221
|
this.viewer.emitEvent({ type: "geometryerror", data, file: model.file, model });
|
|
5398
6222
|
});
|
|
@@ -5402,7 +6226,7 @@ class GLTFCloudDynamicLoader {
|
|
|
5402
6226
|
const loadController = {
|
|
5403
6227
|
loadJson: async () => {
|
|
5404
6228
|
const progress = (progress) => {
|
|
5405
|
-
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model });
|
|
6229
|
+
this.viewer.emitEvent({ type: "geometryprogress", data: progress, file: model.file, model });
|
|
5406
6230
|
};
|
|
5407
6231
|
const arrayBuffer = await model.downloadResource(model.database, progress, this.gltfLoader.getAbortController().signal);
|
|
5408
6232
|
const text = new TextDecoder().decode(arrayBuffer);
|
|
@@ -5419,7 +6243,7 @@ class GLTFCloudDynamicLoader {
|
|
|
5419
6243
|
},
|
|
5420
6244
|
baseUrl: () => Promise.resolve(`${model.httpClient.serverUrl}${model.path}/`),
|
|
5421
6245
|
};
|
|
5422
|
-
const structure = new GltfStructure(
|
|
6246
|
+
const structure = new GltfStructure(modelImpl.id, loadController);
|
|
5423
6247
|
await this.gltfLoader.loadStructure(structure);
|
|
5424
6248
|
await this.gltfLoader.loadNodes();
|
|
5425
6249
|
return this;
|
|
@@ -5431,7 +6255,7 @@ class GLTFCloudDynamicLoader {
|
|
|
5431
6255
|
}
|
|
5432
6256
|
|
|
5433
6257
|
const loaders = loadersRegistry("threejs");
|
|
5434
|
-
loaders.registerLoader("gltf-file", (viewer) => new
|
|
6258
|
+
loaders.registerLoader("gltf-file", (viewer) => new GLTFFileDynamicLoader(viewer));
|
|
5435
6259
|
loaders.registerLoader("gltf-cloud", (viewer) => new GLTFCloudDynamicLoader(viewer));
|
|
5436
6260
|
|
|
5437
6261
|
class SSAARenderPass extends Pass {
|
|
@@ -5638,24 +6462,26 @@ class Helpers extends Scene {
|
|
|
5638
6462
|
class Viewer extends EventEmitter2 {
|
|
5639
6463
|
constructor(client) {
|
|
5640
6464
|
super();
|
|
5641
|
-
this._options = new Options(this);
|
|
5642
6465
|
this.client = client;
|
|
5643
|
-
this.
|
|
5644
|
-
this.canvaseventlistener = (event) => this.emit(event);
|
|
6466
|
+
this.options = new Options(this);
|
|
5645
6467
|
this.loaders = [];
|
|
5646
6468
|
this.models = [];
|
|
6469
|
+
this.info = new Info();
|
|
6470
|
+
this.canvasEvents = CANVAS_EVENTS.slice();
|
|
6471
|
+
this.canvaseventlistener = (event) => this.emit(event);
|
|
5647
6472
|
this.selected = [];
|
|
5648
6473
|
this.extents = new Box3();
|
|
5649
|
-
this.target = new Vector3();
|
|
6474
|
+
this.target = new Vector3(0, 0, 0);
|
|
5650
6475
|
this._activeDragger = null;
|
|
5651
6476
|
this._components = [];
|
|
6477
|
+
this._renderNeeded = false;
|
|
5652
6478
|
this._renderTime = 0;
|
|
5653
6479
|
this.render = this.render.bind(this);
|
|
5654
6480
|
this.update = this.update.bind(this);
|
|
5655
6481
|
this._markup = new Markup();
|
|
5656
6482
|
}
|
|
5657
|
-
get
|
|
5658
|
-
return this.
|
|
6483
|
+
get markup() {
|
|
6484
|
+
return this._markup;
|
|
5659
6485
|
}
|
|
5660
6486
|
get draggers() {
|
|
5661
6487
|
return [...draggers.getDraggers().keys()];
|
|
@@ -5663,14 +6489,10 @@ class Viewer extends EventEmitter2 {
|
|
|
5663
6489
|
get components() {
|
|
5664
6490
|
return [...components.getComponents().keys()];
|
|
5665
6491
|
}
|
|
5666
|
-
get markup() {
|
|
5667
|
-
return this._markup;
|
|
5668
|
-
}
|
|
5669
6492
|
initialize(canvas, onProgress) {
|
|
5670
6493
|
this.addEventListener("optionschange", (event) => this.syncOptions(event.data));
|
|
5671
6494
|
this.scene = new Scene();
|
|
5672
6495
|
this.helpers = new Helpers();
|
|
5673
|
-
this.target = new Vector3(0, 0, 0);
|
|
5674
6496
|
const pixelRatio = window.devicePixelRatio;
|
|
5675
6497
|
const rect = canvas.parentElement.getBoundingClientRect();
|
|
5676
6498
|
const width = rect.width || 1;
|
|
@@ -5805,6 +6627,8 @@ class Viewer extends EventEmitter2 {
|
|
|
5805
6627
|
const deltaTime = (time - this._renderTime) / 1000;
|
|
5806
6628
|
this._renderTime = time;
|
|
5807
6629
|
this._renderNeeded = false;
|
|
6630
|
+
this.renderer.info.autoReset = false;
|
|
6631
|
+
this.renderer.info.reset();
|
|
5808
6632
|
if (this.options.antialiasing === true || this.options.antialiasing === "msaa") {
|
|
5809
6633
|
this.renderer.render(this.scene, this.camera);
|
|
5810
6634
|
this.renderer.render(this.helpers, this.camera);
|
|
@@ -5821,21 +6645,25 @@ class Viewer extends EventEmitter2 {
|
|
|
5821
6645
|
async open(file, params = {}) {
|
|
5822
6646
|
if (!this.renderer)
|
|
5823
6647
|
return this;
|
|
5824
|
-
|
|
6648
|
+
const mode = params.mode || "file";
|
|
6649
|
+
if (mode !== "assembly" && mode !== "a" && mode !== "append") {
|
|
5825
6650
|
this.cancel();
|
|
5826
6651
|
this.clear();
|
|
5827
6652
|
}
|
|
5828
|
-
this.emitEvent({ type: "open", file });
|
|
6653
|
+
this.emitEvent({ type: "open", mode, file });
|
|
5829
6654
|
let model = file;
|
|
5830
6655
|
if (model && typeof model.getModels === "function") {
|
|
5831
6656
|
const models = await model.getModels();
|
|
5832
6657
|
model = models.find((model) => model.default) || models[0] || file;
|
|
5833
6658
|
}
|
|
6659
|
+
if (model && typeof model.database === "string") {
|
|
6660
|
+
file = model.file;
|
|
6661
|
+
}
|
|
5834
6662
|
if (!model)
|
|
5835
6663
|
throw new Error(`Format not supported`);
|
|
5836
6664
|
let format = params.format;
|
|
5837
|
-
if (!format && typeof
|
|
5838
|
-
format =
|
|
6665
|
+
if (!format && typeof file["type"] === "string")
|
|
6666
|
+
format = file["type"].split(".").pop();
|
|
5839
6667
|
if (!format && typeof file === "string")
|
|
5840
6668
|
format = file.split(".").pop();
|
|
5841
6669
|
if (!format && file instanceof globalThis.File)
|
|
@@ -5862,7 +6690,7 @@ class Viewer extends EventEmitter2 {
|
|
|
5862
6690
|
}
|
|
5863
6691
|
loadGltfFile(file, externalFiles, params = {}) {
|
|
5864
6692
|
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: "
|
|
6693
|
+
return this.open(file, { ...params, format: "gltf", externalFiles, mode: "assembly" });
|
|
5866
6694
|
}
|
|
5867
6695
|
cancel() {
|
|
5868
6696
|
this.loaders.forEach((loader) => loader.cancel());
|
|
@@ -5882,12 +6710,17 @@ class Viewer extends EventEmitter2 {
|
|
|
5882
6710
|
this.models = [];
|
|
5883
6711
|
this.scene.clear();
|
|
5884
6712
|
this.helpers.clear();
|
|
6713
|
+
this.extents.makeEmpty();
|
|
6714
|
+
this.target.set(0, 0, 0);
|
|
5885
6715
|
this.syncOptions();
|
|
5886
6716
|
this.syncOverlay();
|
|
5887
6717
|
this.update(true);
|
|
5888
6718
|
this.emitEvent({ type: "clear" });
|
|
5889
6719
|
return this;
|
|
5890
6720
|
}
|
|
6721
|
+
is3D() {
|
|
6722
|
+
return true;
|
|
6723
|
+
}
|
|
5891
6724
|
syncOptions(options = this.options) {
|
|
5892
6725
|
if (!this.renderer)
|
|
5893
6726
|
return;
|
|
@@ -5919,9 +6752,15 @@ class Viewer extends EventEmitter2 {
|
|
|
5919
6752
|
getSelected() {
|
|
5920
6753
|
return this.executeCommand("getSelected");
|
|
5921
6754
|
}
|
|
6755
|
+
getSelected2() {
|
|
6756
|
+
return this.executeCommand("getSelected2");
|
|
6757
|
+
}
|
|
5922
6758
|
setSelected(handles) {
|
|
5923
6759
|
this.executeCommand("setSelected", handles);
|
|
5924
6760
|
}
|
|
6761
|
+
setSelected2(handles) {
|
|
6762
|
+
this.executeCommand("setSelected2", handles);
|
|
6763
|
+
}
|
|
5925
6764
|
clearSelected() {
|
|
5926
6765
|
this.executeCommand("clearSelected");
|
|
5927
6766
|
}
|
|
@@ -5981,37 +6820,8 @@ class Viewer extends EventEmitter2 {
|
|
|
5981
6820
|
getComponent(name) {
|
|
5982
6821
|
return this._components.find((component) => component.name === name);
|
|
5983
6822
|
}
|
|
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
6823
|
drawViewpoint(viewpoint) {
|
|
6014
|
-
var _a, _b, _c;
|
|
6824
|
+
var _a, _b, _c, _d;
|
|
6015
6825
|
if (!this.renderer)
|
|
6016
6826
|
return;
|
|
6017
6827
|
const getVector3FromPoint3d = ({ x, y, z }) => new Vector3(x, y, z);
|
|
@@ -6063,11 +6873,13 @@ class Viewer extends EventEmitter2 {
|
|
|
6063
6873
|
}
|
|
6064
6874
|
};
|
|
6065
6875
|
const setClippingPlanes = (clipping_planes) => {
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6876
|
+
if (clipping_planes) {
|
|
6877
|
+
clipping_planes.forEach((clipping_plane) => {
|
|
6878
|
+
const plane = new Plane();
|
|
6879
|
+
plane.setFromNormalAndCoplanarPoint(getVector3FromPoint3d(clipping_plane.direction), getVector3FromPoint3d(clipping_plane.location));
|
|
6880
|
+
this.renderer.clippingPlanes.push(plane);
|
|
6881
|
+
});
|
|
6882
|
+
}
|
|
6071
6883
|
};
|
|
6072
6884
|
const setSelection = (selection) => {
|
|
6073
6885
|
if (selection)
|
|
@@ -6083,9 +6895,9 @@ class Viewer extends EventEmitter2 {
|
|
|
6083
6895
|
setOrthogonalCamera(viewpoint.orthogonal_camera);
|
|
6084
6896
|
setPerspectiveCamera(viewpoint.perspective_camera);
|
|
6085
6897
|
setClippingPlanes(viewpoint.clipping_planes);
|
|
6086
|
-
setSelection(viewpoint.selection);
|
|
6898
|
+
setSelection(((_b = viewpoint.custom_fields) === null || _b === void 0 ? void 0 : _b.selection2) || viewpoint.selection);
|
|
6087
6899
|
this._markup.setViewpoint(viewpoint);
|
|
6088
|
-
this.target
|
|
6900
|
+
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
6901
|
this.setActiveDragger(draggerName);
|
|
6090
6902
|
this.emitEvent({ type: "drawviewpoint", data: viewpoint });
|
|
6091
6903
|
this.update();
|
|
@@ -6132,6 +6944,9 @@ class Viewer extends EventEmitter2 {
|
|
|
6132
6944
|
const getSelection = () => {
|
|
6133
6945
|
return this.getSelected().map((handle) => ({ handle }));
|
|
6134
6946
|
};
|
|
6947
|
+
const getSelection2 = () => {
|
|
6948
|
+
return this.getSelected2().map((handle) => ({ handle }));
|
|
6949
|
+
};
|
|
6135
6950
|
const viewpoint = { custom_fields: {} };
|
|
6136
6951
|
viewpoint.orthogonal_camera = getOrthogonalCamera();
|
|
6137
6952
|
viewpoint.perspective_camera = getPerspectiveCamera();
|
|
@@ -6140,9 +6955,36 @@ class Viewer extends EventEmitter2 {
|
|
|
6140
6955
|
viewpoint.description = new Date().toDateString();
|
|
6141
6956
|
this._markup.getViewpoint(viewpoint);
|
|
6142
6957
|
viewpoint.custom_fields.camera_target = getPoint3dFromVector3(this.target);
|
|
6958
|
+
viewpoint.custom_fields.selection2 = getSelection2();
|
|
6143
6959
|
this.emitEvent({ type: "createviewpoint", data: viewpoint });
|
|
6144
6960
|
return viewpoint;
|
|
6145
6961
|
}
|
|
6962
|
+
screenToWorld(position) {
|
|
6963
|
+
if (!this.renderer)
|
|
6964
|
+
return { x: position.x, y: position.y, z: 0 };
|
|
6965
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
6966
|
+
const x = position.x / (rect.width / 2) - 1;
|
|
6967
|
+
const y = -position.y / (rect.height / 2) + 1;
|
|
6968
|
+
const point = new Vector3(x, y, -1);
|
|
6969
|
+
point.unproject(this.camera);
|
|
6970
|
+
return { x: point.x, y: point.y, z: point.z };
|
|
6971
|
+
}
|
|
6972
|
+
worldToScreen(position) {
|
|
6973
|
+
if (!this.renderer)
|
|
6974
|
+
return { x: position.x, y: position.y };
|
|
6975
|
+
const point = new Vector3(position.x, position.y, position.z);
|
|
6976
|
+
point.project(this.camera);
|
|
6977
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
6978
|
+
const x = (point.x + 1) * (rect.width / 2);
|
|
6979
|
+
const y = (-point.y + 1) * (rect.height / 2);
|
|
6980
|
+
return { x, y };
|
|
6981
|
+
}
|
|
6982
|
+
getScale() {
|
|
6983
|
+
return { x: 1, y: 1, z: 1 };
|
|
6984
|
+
}
|
|
6985
|
+
executeCommand(id, ...args) {
|
|
6986
|
+
return commands.executeCommand(id, this, ...args);
|
|
6987
|
+
}
|
|
6146
6988
|
}
|
|
6147
6989
|
|
|
6148
6990
|
export { GLTFLoadingManager, ModelImpl, Viewer, commands, components, draggers, loaders };
|