@inweb/viewer-three 26.10.0 → 26.10.2

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.
@@ -23,7 +23,7 @@
23
23
 
24
24
  import { draggersRegistry, commandsRegistry, componentsRegistry, Loader, loadersRegistry, Options, 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, Matrix4, Vector4, MathUtils, Raycaster, EdgesGeometry, Controls, Clock, Sphere, Box3, Color, AmbientLight, DirectionalLight, HemisphereLight, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, OrthographicCamera, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, LoadingManager, LoaderUtils, TextureLoader, BufferAttribute, PointsMaterial, Points, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, PerspectiveCamera, UniformsUtils, ShaderMaterial, AdditiveBlending, HalfFloatType, Scene, WebGLRenderer, LinearSRGBColorSpace } from 'three';
26
+ import { Line, Vector3, BufferGeometry, Float32BufferAttribute, LineBasicMaterial, Mesh, MeshBasicMaterial, DoubleSide, EventDispatcher, MOUSE, TOUCH, Spherical, Quaternion, Vector2, Plane, Object3D, Line3, Matrix4, Vector4, MathUtils, Raycaster, EdgesGeometry, Controls, Clock, Sphere, Box3, Color, PerspectiveCamera, OrthographicCamera, AmbientLight, DirectionalLight, HemisphereLight, MeshPhongMaterial, WebGLRenderTarget, UnsignedByteType, RGBAFormat, CylinderGeometry, Sprite, CanvasTexture, SRGBColorSpace, SpriteMaterial, LoadingManager, LoaderUtils, TextureLoader, BufferAttribute, PointsMaterial, Points, TriangleStripDrawMode, TriangleFanDrawMode, LineSegments, LineLoop, Group, NormalBlending, 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';
@@ -743,10 +743,13 @@ class OrbitControls extends EventDispatcher {
743
743
  class OrbitDragger {
744
744
  constructor(viewer) {
745
745
  this.updateControls = () => {
746
+ this.orbit.target.copy(this.viewer.target);
747
+ this.orbit.update();
748
+ };
749
+ this.updateControlsCamera = () => {
746
750
  this.orbit.maxDistance = this.viewer.camera.far;
747
751
  this.orbit.minDistance = this.viewer.camera.near;
748
752
  this.orbit.object = this.viewer.camera;
749
- this.orbit.target.copy(this.viewer.target);
750
753
  this.orbit.update();
751
754
  };
752
755
  this.controlsStart = () => {
@@ -803,6 +806,7 @@ class OrbitDragger {
803
806
  this.viewer.on("viewposition", this.updateControls);
804
807
  this.viewer.addEventListener("zoom", this.updateControls);
805
808
  this.viewer.addEventListener("drawviewpoint", this.updateControls);
809
+ this.viewer.addEventListener("changecameramode", this.updateControlsCamera);
806
810
  this.viewer.addEventListener("contextmenu", this.stopContextMenu);
807
811
  this.updateControls();
808
812
  }
@@ -812,6 +816,7 @@ class OrbitDragger {
812
816
  this.viewer.off("viewposition", this.updateControls);
813
817
  this.viewer.removeEventListener("zoom", this.updateControls);
814
818
  this.viewer.removeEventListener("drawviewpoint", this.updateControls);
819
+ this.viewer.removeEventListener("changecameramode", this.updateControlsCamera);
815
820
  this.viewer.removeEventListener("contextmenu", this.stopContextMenu);
816
821
  this.orbit.removeEventListener("start", this.controlsStart);
817
822
  this.orbit.removeEventListener("change", this.controlsChange);
@@ -833,6 +838,9 @@ class CuttingPlaneDragger extends OrbitDragger {
833
838
  this.planeHelper.size = this.viewer.extents.getSize(new Vector3()).length();
834
839
  this.viewer.update();
835
840
  };
841
+ this.updateTransformCamera = () => {
842
+ this.transform.camera = this.viewer.camera;
843
+ };
836
844
  this.onDoubleClick = (event) => {
837
845
  event.stopPropagation();
838
846
  this.plane.negate();
@@ -858,16 +866,18 @@ class CuttingPlaneDragger extends OrbitDragger {
858
866
  this.transform.addEventListener("change", this.transformChange);
859
867
  this.transform.addEventListener("dragging-changed", this.transformDrag);
860
868
  this.viewer.helpers.add(this.transform.getHelper());
861
- this.viewer.on("explode", this.updatePlaneSize);
862
- this.viewer.on("show", this.updatePlaneSize);
863
- this.viewer.on("showall", this.updatePlaneSize);
869
+ this.viewer.addEventListener("explode", this.updatePlaneSize);
870
+ this.viewer.addEventListener("show", this.updatePlaneSize);
871
+ this.viewer.addEventListener("showall", this.updatePlaneSize);
872
+ this.viewer.addEventListener("changecameramode", this.updateTransformCamera);
864
873
  this.viewer.canvas.addEventListener("dblclick", this.onDoubleClick, true);
865
874
  this.viewer.update();
866
875
  }
867
876
  dispose() {
868
- this.viewer.off("explode", this.updatePlaneSize);
869
- this.viewer.off("show", this.updatePlaneSize);
870
- this.viewer.off("showAll", this.updatePlaneSize);
877
+ this.viewer.removeEventListener("explode", this.updatePlaneSize);
878
+ this.viewer.removeEventListener("show", this.updatePlaneSize);
879
+ this.viewer.removeEventListener("showall", this.updatePlaneSize);
880
+ this.viewer.removeEventListener("changecameramode", this.updateTransformCamera);
871
881
  this.viewer.canvas.removeEventListener("dblclick", this.onDoubleClick, true);
872
882
  this.transform.removeEventListener("change", this.transformChange);
873
883
  this.transform.removeEventListener("dragging-changed", this.transformDrag);
@@ -950,6 +960,10 @@ class MeasureLineDragger extends OrbitDragger {
950
960
  this.updateSnapper = () => {
951
961
  this.snapper.update(this.viewer);
952
962
  };
963
+ this.updateSnapperCamera = () => {
964
+ this.snapper.camera = this.viewer.camera;
965
+ this.overlay.camera = this.viewer.camera;
966
+ };
953
967
  this.overlay = new MeasureOverlay(viewer.camera, viewer.canvas);
954
968
  this.overlay.attach();
955
969
  this.line = new MeasureLine(this.overlay);
@@ -966,6 +980,7 @@ class MeasureLineDragger extends OrbitDragger {
966
980
  this.viewer.addEventListener("isolate", this.updateSnapper);
967
981
  this.viewer.addEventListener("show", this.updateSnapper);
968
982
  this.viewer.addEventListener("showall", this.updateSnapper);
983
+ this.viewer.addEventListener("changecameramode", this.updateSnapperCamera);
969
984
  }
970
985
  dispose() {
971
986
  this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown);
@@ -978,6 +993,8 @@ class MeasureLineDragger extends OrbitDragger {
978
993
  this.viewer.removeEventListener("isolate", this.updateSnapper);
979
994
  this.viewer.removeEventListener("show", this.updateSnapper);
980
995
  this.viewer.removeEventListener("showall", this.updateSnapper);
996
+ this.viewer.removeEventListener("changecameramode", this.updateSnapperCamera);
997
+ this.snapper.dispose();
981
998
  this.snapper.dispose();
982
999
  this.overlay.detach();
983
1000
  this.overlay.dispose();
@@ -1029,16 +1046,16 @@ class MeasureSnapper {
1029
1046
  getDetectRadius(point) {
1030
1047
  const camera = this.camera;
1031
1048
  if (camera.isOrthographicCamera) {
1032
- const worldHeight = camera.top - camera.bottom;
1049
+ const fieldHeight = (camera.top - camera.bottom) / camera.zoom;
1033
1050
  const canvasHeight = this.canvas.height;
1034
- const worldUnitsPerPixel = worldHeight / canvasHeight;
1051
+ const worldUnitsPerPixel = fieldHeight / canvasHeight;
1035
1052
  return this.detectRadiusInPixels * worldUnitsPerPixel;
1036
1053
  }
1037
1054
  if (camera.isPerspectiveCamera) {
1038
1055
  const distance = camera.position.distanceTo(point);
1039
- const worldHeight = 2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5)) * distance;
1056
+ const fieldHeight = 2 * Math.tan(MathUtils.degToRad(camera.fov * 0.5)) * distance;
1040
1057
  const canvasHeight = this.canvas.height;
1041
- const worldUnitsPerPixel = worldHeight / canvasHeight;
1058
+ const worldUnitsPerPixel = fieldHeight / canvasHeight;
1042
1059
  return this.detectRadiusInPixels * worldUnitsPerPixel;
1043
1060
  }
1044
1061
  return 0.1;
@@ -1135,7 +1152,7 @@ class MeasureOverlay {
1135
1152
  this.lines = [];
1136
1153
  }
1137
1154
  render() {
1138
- this.projector.updateProjectionMatrix();
1155
+ this.projector.setFromCamera(this.camera);
1139
1156
  this.lines.forEach((line) => line.render());
1140
1157
  }
1141
1158
  update() {
@@ -1286,6 +1303,10 @@ class MeasureProjector {
1286
1303
  this.camera = camera;
1287
1304
  this.canvas = canvas;
1288
1305
  }
1306
+ setFromCamera(camera) {
1307
+ this.camera = camera;
1308
+ this.updateProjectionMatrix();
1309
+ }
1289
1310
  updateProjectionMatrix() {
1290
1311
  const rect = this.canvas.getBoundingClientRect();
1291
1312
  _widthHalf = rect.width / 2;
@@ -1462,7 +1483,7 @@ class WalkControls extends Controls {
1462
1483
  Points: { threshold: 0 },
1463
1484
  Sprite: { threshold: 0 },
1464
1485
  };
1465
- let intersects = this.raycaster.intersectObjects(this.groundObjects, false);
1486
+ const intersects = this.raycaster.intersectObjects(this.groundObjects, false);
1466
1487
  if (intersects.length > 0) {
1467
1488
  const groundY = intersects[0].point.y;
1468
1489
  const targetY = groundY + this.EYE_HEIGHT;
@@ -1554,6 +1575,9 @@ class WalkDragger {
1554
1575
  const size = this.viewer.extents.getSize(new Vector3());
1555
1576
  this.controls.movementSpeed = Math.min(size.x, size.y, size.z) / 2;
1556
1577
  };
1578
+ this.updateControlsCamera = () => {
1579
+ this.controls.object = this.viewer.camera;
1580
+ };
1557
1581
  this.controlsChange = () => {
1558
1582
  this.viewer.update();
1559
1583
  this.viewer.emitEvent({ type: "changecamera" });
@@ -1577,13 +1601,15 @@ class WalkDragger {
1577
1601
  this.controls.addEventListener("change", this.controlsChange);
1578
1602
  this.controls.addEventListener("walkspeedchange", this.walkspeedChange);
1579
1603
  this.viewer = viewer;
1580
- this.viewer.on("render", this.viewerRender);
1581
- this.viewer.on("zoom", this.viewerZoom);
1604
+ this.viewer.addEventListener("render", this.viewerRender);
1605
+ this.viewer.addEventListener("zoom", this.viewerZoom);
1606
+ this.viewer.addEventListener("changecameramode", this.updateControlsCamera);
1582
1607
  this.updateControls();
1583
1608
  }
1584
1609
  dispose() {
1585
- this.viewer.off("render", this.viewerRender);
1586
- this.viewer.off("zoom", this.viewerZoom);
1610
+ this.viewer.removeEventListener("render", this.viewerRender);
1611
+ this.viewer.removeEventListener("zoom", this.viewerZoom);
1612
+ this.viewer.removeEventListener("changecameramode", this.updateControlsCamera);
1587
1613
  this.controls.removeEventListener("walkspeedchange", this.walkspeedChange);
1588
1614
  this.controls.removeEventListener("change", this.controlsChange);
1589
1615
  this.controls.dispose();
@@ -1743,6 +1769,9 @@ class FlyDragger {
1743
1769
  const size = this.viewer.extents.getSize(new Vector3());
1744
1770
  this.controls.movementSpeed = Math.min(size.x, size.y, size.z) / 2;
1745
1771
  };
1772
+ this.updateControlsCamera = () => {
1773
+ this.controls.object = this.viewer.camera;
1774
+ };
1746
1775
  this.controlsChange = () => {
1747
1776
  this.viewer.update();
1748
1777
  this.viewer.emitEvent({ type: "changecamera" });
@@ -1760,13 +1789,15 @@ class FlyDragger {
1760
1789
  this.controls.addEventListener("change", this.controlsChange);
1761
1790
  this.controls.addEventListener("flyspeedchange", this.flyspeedChange);
1762
1791
  this.viewer = viewer;
1763
- this.viewer.on("render", this.viewerRender);
1764
- this.viewer.on("zoom", this.viewerZoom);
1792
+ this.viewer.addEventListener("render", this.viewerRender);
1793
+ this.viewer.addEventListener("zoom", this.viewerZoom);
1794
+ this.viewer.addEventListener("changecameramode", this.updateControlsCamera);
1765
1795
  this.updateControls();
1766
1796
  }
1767
1797
  dispose() {
1768
- this.viewer.off("render", this.viewerRender);
1769
- this.viewer.off("zoom", this.viewerZoom);
1798
+ this.viewer.removeEventListener("render", this.viewerRender);
1799
+ this.viewer.removeEventListener("zoom", this.viewerZoom);
1800
+ this.viewer.removeEventListener("changecameramode", this.updateControlsCamera);
1770
1801
  this.controls.removeEventListener("flyspeedchange", this.flyspeedChange);
1771
1802
  this.controls.removeEventListener("change", this.controlsChange);
1772
1803
  this.controls.dispose();
@@ -2064,10 +2095,10 @@ class BackgroundComponent {
2064
2095
 
2065
2096
  class CameraComponent {
2066
2097
  constructor(viewer) {
2098
+ this.optionsChange = () => {
2099
+ this.switchCameraMode(this.viewer.options.cameraMode);
2100
+ };
2067
2101
  this.geometryEnd = () => {
2068
- const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius * 2;
2069
- const rendererSize = this.viewer.renderer.getSize(new Vector2());
2070
- const aspect = rendererSize.x / rendererSize.y;
2071
2102
  let camera;
2072
2103
  this.viewer.scene.traverse((object) => {
2073
2104
  if (object.isCamera)
@@ -2079,36 +2110,83 @@ class CameraComponent {
2079
2110
  if (camera) {
2080
2111
  camera.isDefaultCamera = true;
2081
2112
  camera.scale.set(1, 1, 1);
2082
- this.viewer.camera = camera;
2083
- this.viewer.renderPass.camera = camera;
2084
- this.viewer.helpersPass.camera = camera;
2085
- this.viewer.ssaaRenderPass.camera = camera;
2113
+ this.switchCamera(camera);
2114
+ const mode = this.getCameraMode(camera);
2115
+ this.viewer.options.cameraMode = mode;
2116
+ this.viewer.emitEvent({ type: "changecameramode", mode });
2086
2117
  }
2087
2118
  else {
2088
- camera = this.viewer.camera;
2089
- }
2090
- if (camera.isPerspectiveCamera) {
2091
- camera.aspect = aspect;
2092
- camera.near = extentsSize / 1000;
2093
- camera.far = extentsSize * 1000;
2094
- camera.updateProjectionMatrix();
2095
- }
2096
- if (camera.isOrthographicCamera) {
2097
- camera.left = camera.bottom * aspect;
2098
- camera.right = camera.top * aspect;
2099
- camera.near = 0;
2100
- camera.far = extentsSize * 1000;
2101
- camera.updateProjectionMatrix();
2102
- }
2103
- if (!camera.isDefaultCamera) {
2119
+ this.switchCamera(this.viewer.camera);
2104
2120
  this.viewer.executeCommand("setDefaultViewPosition");
2105
2121
  }
2106
2122
  };
2107
2123
  this.viewer = viewer;
2108
2124
  this.viewer.addEventListener("databasechunk", this.geometryEnd);
2125
+ this.viewer.addEventListener("optionschange", this.optionsChange);
2126
+ this.viewer.addEventListener("initialize", this.optionsChange);
2109
2127
  }
2110
2128
  dispose() {
2111
2129
  this.viewer.removeEventListener("databasechunk", this.geometryEnd);
2130
+ this.viewer.removeEventListener("optionschange", this.optionsChange);
2131
+ this.viewer.removeEventListener("initialize", this.optionsChange);
2132
+ }
2133
+ getCameraMode(camera) {
2134
+ return camera.isOrthographicCamera ? "orthographic" : "perspective";
2135
+ }
2136
+ switchCamera(camera) {
2137
+ const extentsSize = this.viewer.extents.getBoundingSphere(new Sphere()).radius * 2 || 1;
2138
+ const rendererSize = this.viewer.renderer.getSize(new Vector2());
2139
+ const aspect = rendererSize.x / rendererSize.y;
2140
+ if (camera.isPerspectiveCamera) {
2141
+ camera.aspect = aspect;
2142
+ camera.near = extentsSize / 1000;
2143
+ camera.far = extentsSize * 1000;
2144
+ }
2145
+ if (camera.isOrthographicCamera) {
2146
+ camera.left = camera.bottom * aspect;
2147
+ camera.right = camera.top * aspect;
2148
+ camera.near = 0;
2149
+ camera.far = extentsSize * 1000;
2150
+ }
2151
+ camera.updateProjectionMatrix();
2152
+ this.viewer.camera = camera;
2153
+ this.viewer.renderPass.camera = camera;
2154
+ this.viewer.helpersPass.camera = camera;
2155
+ this.viewer.ssaaRenderPass.camera = camera;
2156
+ this.viewer.update();
2157
+ }
2158
+ switchCameraMode(mode) {
2159
+ if (!mode)
2160
+ return;
2161
+ const currentCamera = this.viewer.camera;
2162
+ if (mode === this.getCameraMode(currentCamera))
2163
+ return;
2164
+ const target = this.viewer.target.clone();
2165
+ let camera;
2166
+ if (currentCamera.isOrthographicCamera) {
2167
+ const fov = currentCamera.userData.fov || 45;
2168
+ const fieldHeight = (currentCamera.top - currentCamera.bottom) / currentCamera.zoom;
2169
+ const distance = fieldHeight / (2 * Math.tan(MathUtils.degToRad(fov) / 2));
2170
+ const direction = new Vector3().subVectors(currentCamera.position, target).normalize();
2171
+ camera = new PerspectiveCamera(fov);
2172
+ camera.position.copy(direction).multiplyScalar(distance).add(target);
2173
+ }
2174
+ if (currentCamera.isPerspectiveCamera) {
2175
+ const fov = currentCamera.fov;
2176
+ const distance = currentCamera.position.distanceTo(target);
2177
+ const fieldHeight = 2 * Math.tan(MathUtils.degToRad(fov) / 2) * distance;
2178
+ camera = new OrthographicCamera();
2179
+ camera.top = fieldHeight / 2;
2180
+ camera.bottom = -fieldHeight / 2;
2181
+ camera.position.copy(currentCamera.position);
2182
+ camera.userData.fov = fov;
2183
+ }
2184
+ if (!camera)
2185
+ return;
2186
+ camera.up.copy(currentCamera.up);
2187
+ camera.quaternion.copy(currentCamera.quaternion);
2188
+ this.switchCamera(camera);
2189
+ this.viewer.emitEvent({ type: "changecameramode", mode });
2112
2190
  }
2113
2191
  }
2114
2192
 
@@ -5728,6 +5806,7 @@ class Viewer extends EventEmitter2 {
5728
5806
  this.renderPass.camera = camera;
5729
5807
  this.helpersPass.camera = camera;
5730
5808
  this.ssaaRenderPass.camera = camera;
5809
+ this.emitEvent({ type: "changecameramode", mode: "orthographic" });
5731
5810
  }
5732
5811
  };
5733
5812
  const setPerspectiveCamera = (perspective_camera) => {
@@ -5749,6 +5828,7 @@ class Viewer extends EventEmitter2 {
5749
5828
  this.renderPass.camera = camera;
5750
5829
  this.helpersPass.camera = camera;
5751
5830
  this.ssaaRenderPass.camera = camera;
5831
+ this.emitEvent({ type: "changecameramode", mode: "perspective" });
5752
5832
  }
5753
5833
  };
5754
5834
  const setClippingPlanes = (clipping_planes) => {