@inweb/viewer-three 27.2.4 → 27.3.1

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.
Files changed (159) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +1 -1
  3. package/dist/extensions/components/AxesHelperComponent.js +2 -2
  4. package/dist/extensions/components/AxesHelperComponent.js.map +1 -1
  5. package/dist/extensions/components/AxesHelperComponent.min.js +2 -2
  6. package/dist/extensions/components/AxesHelperComponent.module.js +2 -2
  7. package/dist/extensions/components/AxesHelperComponent.module.js.map +1 -1
  8. package/dist/extensions/components/ExtentsHelperComponent.js +2 -2
  9. package/dist/extensions/components/ExtentsHelperComponent.js.map +1 -1
  10. package/dist/extensions/components/ExtentsHelperComponent.min.js +2 -2
  11. package/dist/extensions/components/ExtentsHelperComponent.module.js +2 -2
  12. package/dist/extensions/components/ExtentsHelperComponent.module.js.map +1 -1
  13. package/dist/extensions/components/GridHelperComponent.js +2 -2
  14. package/dist/extensions/components/GridHelperComponent.js.map +1 -1
  15. package/dist/extensions/components/GridHelperComponent.min.js +2 -2
  16. package/dist/extensions/components/GridHelperComponent.module.js +2 -2
  17. package/dist/extensions/components/GridHelperComponent.module.js.map +1 -1
  18. package/dist/extensions/components/InfoPanelComponent.js +2 -2
  19. package/dist/extensions/components/InfoPanelComponent.js.map +1 -1
  20. package/dist/extensions/components/InfoPanelComponent.min.js +2 -2
  21. package/dist/extensions/components/InfoPanelComponent.module.js +2 -2
  22. package/dist/extensions/components/InfoPanelComponent.module.js.map +1 -1
  23. package/dist/extensions/components/LightHelperComponent.js +2 -2
  24. package/dist/extensions/components/LightHelperComponent.js.map +1 -1
  25. package/dist/extensions/components/LightHelperComponent.min.js +2 -2
  26. package/dist/extensions/components/LightHelperComponent.module.js +2 -2
  27. package/dist/extensions/components/LightHelperComponent.module.js.map +1 -1
  28. package/dist/extensions/components/RoomEnvironmentComponent.js +2 -2
  29. package/dist/extensions/components/RoomEnvironmentComponent.js.map +1 -1
  30. package/dist/extensions/components/RoomEnvironmentComponent.min.js +2 -2
  31. package/dist/extensions/components/RoomEnvironmentComponent.module.js +2 -2
  32. package/dist/extensions/components/RoomEnvironmentComponent.module.js.map +1 -1
  33. package/dist/extensions/components/StatsPanelComponent.js +2 -2
  34. package/dist/extensions/components/StatsPanelComponent.js.map +1 -1
  35. package/dist/extensions/components/StatsPanelComponent.min.js +2 -2
  36. package/dist/extensions/components/StatsPanelComponent.module.js +2 -2
  37. package/dist/extensions/components/StatsPanelComponent.module.js.map +1 -1
  38. package/dist/extensions/loaders/GLTFCloudLoader.js +2 -2
  39. package/dist/extensions/loaders/GLTFCloudLoader.js.map +1 -1
  40. package/dist/extensions/loaders/GLTFCloudLoader.min.js +2 -2
  41. package/dist/extensions/loaders/GLTFCloudLoader.module.js +2 -2
  42. package/dist/extensions/loaders/GLTFCloudLoader.module.js.map +1 -1
  43. package/dist/extensions/loaders/GLTFFileLoader.js +2 -2
  44. package/dist/extensions/loaders/GLTFFileLoader.js.map +1 -1
  45. package/dist/extensions/loaders/GLTFFileLoader.min.js +2 -2
  46. package/dist/extensions/loaders/GLTFFileLoader.module.js +2 -2
  47. package/dist/extensions/loaders/GLTFFileLoader.module.js.map +1 -1
  48. package/dist/extensions/loaders/IFCXLoader.js +2 -2
  49. package/dist/extensions/loaders/IFCXLoader.js.map +1 -1
  50. package/dist/extensions/loaders/IFCXLoader.min.js +2 -2
  51. package/dist/extensions/loaders/IFCXLoader.module.js +2 -2
  52. package/dist/extensions/loaders/IFCXLoader.module.js.map +1 -1
  53. package/dist/extensions/loaders/PotreeLoader.js +2 -2
  54. package/dist/extensions/loaders/PotreeLoader.js.map +1 -1
  55. package/dist/extensions/loaders/PotreeLoader.min.js +2 -2
  56. package/dist/extensions/loaders/PotreeLoader.module.js +2 -2
  57. package/dist/extensions/loaders/PotreeLoader.module.js.map +1 -1
  58. package/dist/viewer-three.js +755 -362
  59. package/dist/viewer-three.js.map +1 -1
  60. package/dist/viewer-three.min.js +5 -5
  61. package/dist/viewer-three.module.js +756 -363
  62. package/dist/viewer-three.module.js.map +1 -1
  63. package/extensions/components/AxesHelperComponent.ts +2 -2
  64. package/extensions/components/ExtentsHelperComponent.ts +2 -2
  65. package/extensions/components/GridHelperComponent.ts +2 -2
  66. package/extensions/components/InfoPanelComponent.ts +2 -2
  67. package/extensions/components/LightHelperComponent.ts +2 -2
  68. package/extensions/components/RoomEnvironmentComponent.ts +2 -2
  69. package/extensions/components/StatsPanelComponent.ts +2 -2
  70. package/extensions/loaders/GLTFCloudLoader.ts +2 -2
  71. package/extensions/loaders/GLTFFileLoader.ts +2 -2
  72. package/extensions/loaders/IFCX/IFCXCloudLoader.ts +2 -2
  73. package/extensions/loaders/IFCX/IFCXFileLoader.ts +2 -2
  74. package/extensions/loaders/IFCX/IFCXLoader.ts +2 -2
  75. package/extensions/loaders/IFCX/index.ts +2 -2
  76. package/extensions/loaders/IFCX/render.js +2 -2
  77. package/extensions/loaders/Potree/PotreeFileLoader.ts +2 -2
  78. package/extensions/loaders/Potree/PotreeModelImpl.ts +2 -2
  79. package/extensions/loaders/Potree/index.ts +2 -2
  80. package/lib/Viewer/controls/WalkControls.d.ts +8 -0
  81. package/lib/Viewer/draggers/CuttingPlaneDragger.d.ts +23 -5
  82. package/lib/Viewer/helpers/PlaneHelper2.d.ts +8 -4
  83. package/lib/Viewer/measurement/Snapper.d.ts +1 -1
  84. package/package.json +5 -5
  85. package/src/Viewer/Viewer.ts +2 -2
  86. package/src/Viewer/commands/ApplyModelTransform.ts +2 -2
  87. package/src/Viewer/commands/ClearMarkup.ts +2 -2
  88. package/src/Viewer/commands/ClearSelected.ts +2 -2
  89. package/src/Viewer/commands/ClearSlices.ts +2 -2
  90. package/src/Viewer/commands/Explode.ts +2 -2
  91. package/src/Viewer/commands/GetDefaultViewPositions.ts +2 -2
  92. package/src/Viewer/commands/GetModels.ts +2 -2
  93. package/src/Viewer/commands/GetSelected.ts +2 -2
  94. package/src/Viewer/commands/GetSelected2.ts +2 -2
  95. package/src/Viewer/commands/GetSnapshot.ts +2 -2
  96. package/src/Viewer/commands/HideSelected.ts +2 -2
  97. package/src/Viewer/commands/IsolateSelected.ts +2 -2
  98. package/src/Viewer/commands/RegenerateAll.ts +2 -2
  99. package/src/Viewer/commands/ResetView.ts +2 -2
  100. package/src/Viewer/commands/SelectModel.ts +2 -2
  101. package/src/Viewer/commands/SetActiveDragger.ts +2 -2
  102. package/src/Viewer/commands/SetDefaultViewPosition.ts +2 -2
  103. package/src/Viewer/commands/SetMarkupColor.ts +2 -2
  104. package/src/Viewer/commands/SetSelected.ts +2 -2
  105. package/src/Viewer/commands/SetSelected2.ts +2 -2
  106. package/src/Viewer/commands/ShowAll.ts +2 -2
  107. package/src/Viewer/commands/ZoomTo.ts +2 -2
  108. package/src/Viewer/commands/ZoomToExtents.ts +2 -2
  109. package/src/Viewer/commands/ZoomToObjects.ts +2 -2
  110. package/src/Viewer/commands/ZoomToSelected.ts +2 -2
  111. package/src/Viewer/commands/index.ts +2 -2
  112. package/src/Viewer/components/BackgroundComponent.ts +2 -2
  113. package/src/Viewer/components/CameraComponent.ts +2 -2
  114. package/src/Viewer/components/CanvasRemoveComponent.ts +2 -2
  115. package/src/Viewer/components/CanvasResizeComponent.ts +2 -2
  116. package/src/Viewer/components/ExtentsComponent.ts +2 -2
  117. package/src/Viewer/components/HighlighterComponent.ts +2 -2
  118. package/src/Viewer/components/HighlighterUtils.ts +2 -2
  119. package/src/Viewer/components/InfoComponent.ts +2 -2
  120. package/src/Viewer/components/LightComponent.ts +2 -2
  121. package/src/Viewer/components/RenderLoopComponent.ts +2 -2
  122. package/src/Viewer/components/ResetComponent.ts +2 -2
  123. package/src/Viewer/components/SelectionComponent.ts +3 -3
  124. package/src/Viewer/components/ViewPositionComponent.ts +2 -2
  125. package/src/Viewer/components/WCSHelperComponent.ts +2 -2
  126. package/src/Viewer/components/index.ts +2 -2
  127. package/src/Viewer/controls/FlyControls.ts +2 -2
  128. package/src/Viewer/controls/JoyStickControls.ts +2 -2
  129. package/src/Viewer/controls/WalkControls.ts +52 -6
  130. package/src/Viewer/draggers/CuttingPlaneDragger.ts +193 -33
  131. package/src/Viewer/draggers/CuttingPlaneXAxis.ts +4 -5
  132. package/src/Viewer/draggers/CuttingPlaneYAxis.ts +4 -5
  133. package/src/Viewer/draggers/CuttingPlaneZAxis.ts +4 -5
  134. package/src/Viewer/draggers/FlyDragger.ts +2 -2
  135. package/src/Viewer/draggers/MeasureLineDragger.ts +2 -2
  136. package/src/Viewer/draggers/OrbitDragger.ts +2 -2
  137. package/src/Viewer/draggers/PanDragger.ts +2 -2
  138. package/src/Viewer/draggers/WalkDragger.ts +2 -2
  139. package/src/Viewer/draggers/ZoomDragger.ts +2 -2
  140. package/src/Viewer/draggers/index.ts +4 -2
  141. package/src/Viewer/helpers/PlaneHelper2.ts +32 -19
  142. package/src/Viewer/loaders/DynamicGltfLoader/DynamicGltfLoader.js +495 -182
  143. package/src/Viewer/loaders/DynamicGltfLoader/DynamicModelImpl.ts +46 -35
  144. package/src/Viewer/loaders/GLTFBinaryParser.ts +2 -2
  145. package/src/Viewer/loaders/GLTFCloudDynamicLoader.ts +2 -2
  146. package/src/Viewer/loaders/GLTFFileDynamicLoader.ts +2 -2
  147. package/src/Viewer/loaders/GLTFLoadingManager.ts +2 -2
  148. package/src/Viewer/loaders/JSONStreamParser.ts +2 -2
  149. package/src/Viewer/loaders/RangesLoader.ts +2 -2
  150. package/src/Viewer/loaders/index.ts +2 -2
  151. package/src/Viewer/measurement/Snapper.ts +15 -7
  152. package/src/Viewer/measurement/UnitConverter.ts +2 -2
  153. package/src/Viewer/measurement/UnitFormatter.ts +2 -2
  154. package/src/Viewer/models/IModelImpl.ts +2 -2
  155. package/src/Viewer/models/ModelImpl.ts +15 -12
  156. package/src/Viewer/postprocessing/SSAARenderPass.js +2 -2
  157. package/src/Viewer/scenes/Helpers.ts +2 -2
  158. package/src/index-umd.ts +2 -2
  159. package/src/index.ts +2 -2
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,14 +14,14 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Clock, Camera, Controls, Quaternion, Vector2, Vector3, Raycaster, Object3D, MathUtils } from "three";
24
+ import { Box3, Clock, Camera, Controls, Quaternion, Vector2, Vector3, Raycaster, Object3D, MathUtils } from "three";
25
25
 
26
26
  interface WalkControlsEventMap {
27
27
  change: { type: "change" };
@@ -41,8 +41,15 @@ export class WalkControls extends Controls<WalkControlsEventMap> {
41
41
  public multiplier = 3;
42
42
  private groundFollowingSkippedFrames = 0;
43
43
 
44
+ readonly GROUND_BOX_HALF_SIZE = 20;
45
+ readonly GROUND_BOX_REFRESH_THRESHOLD = 0.3;
46
+
44
47
  private raycaster: Raycaster;
45
48
  private groundObjects: Object3D[];
49
+ private _groundObjectBoxes = new Map<Object3D, Box3>();
50
+ private _activeGroundObjects: Object3D[] = [];
51
+ private _groundBox = new Box3();
52
+ private _groundBoxCenter = new Vector3();
46
53
 
47
54
  private moveKeys: Set<string>;
48
55
  private moveWheel = 0;
@@ -64,6 +71,12 @@ export class WalkControls extends Controls<WalkControlsEventMap> {
64
71
  this.camera = camera;
65
72
 
66
73
  this.groundObjects = groundObjects;
74
+ for (const obj of groundObjects) {
75
+ this._groundObjectBoxes.set(obj, new Box3().setFromObject(obj));
76
+ }
77
+ const pos = this.object.position;
78
+ this._rebuildGroundBox(pos);
79
+
67
80
  this.raycaster = new Raycaster();
68
81
  this.raycaster.near = 0;
69
82
  this.raycaster.far = this.EYE_HEIGHT + this.FAILING_DISTANCE;
@@ -175,14 +188,47 @@ export class WalkControls extends Controls<WalkControlsEventMap> {
175
188
  };
176
189
 
177
190
  onKeyUp = (event: KeyboardEvent) => {
178
- if (this.moveKeys.delete(event.code)) this.update();
191
+ if (this.moveKeys.delete(event.code)) {
192
+ if (this.moveKeys.size === 0) {
193
+ this._rebuildGroundBox(this.object.position);
194
+ }
195
+ this.update();
196
+ }
179
197
  };
180
198
 
199
+ private _rebuildGroundBox(center: Vector3) {
200
+ const h = this.GROUND_BOX_HALF_SIZE;
201
+ this._groundBoxCenter.copy(center);
202
+ this._groundBox.set(
203
+ new Vector3(center.x - h, center.y - h * 4, center.z - h),
204
+ new Vector3(center.x + h, center.y + h * 4, center.z + h)
205
+ );
206
+
207
+ this._activeGroundObjects = this.groundObjects.filter((obj) => {
208
+ const objectBox = this._groundObjectBoxes.get(obj);
209
+ return objectBox !== undefined && this._groundBox.intersectsBox(objectBox);
210
+ });
211
+ }
212
+
213
+ private _needsGroundBoxRebuild(pos: Vector3): boolean {
214
+ if (this._activeGroundObjects.length === 0 && this.groundObjects.length > 0) return true;
215
+ const threshold = this.GROUND_BOX_HALF_SIZE * this.GROUND_BOX_REFRESH_THRESHOLD;
216
+ return (
217
+ Math.abs(pos.x - this._groundBoxCenter.x) > threshold || Math.abs(pos.z - this._groundBoxCenter.z) > threshold
218
+ );
219
+ }
220
+
181
221
  private updateGroundFollowing() {
222
+ const pos = this.object.position;
223
+
224
+ if (this._needsGroundBoxRebuild(pos)) {
225
+ this._rebuildGroundBox(pos);
226
+ }
227
+
182
228
  this._up.copy(this.camera.up).negate();
183
- this.raycaster.set(this.object.position, this._up);
229
+ this.raycaster.set(pos, this._up);
184
230
 
185
- const intersects = this.raycaster.intersectObjects(this.groundObjects, false);
231
+ const intersects = this.raycaster.intersectObjects(this._activeGroundObjects, false);
186
232
  if (intersects.length > 0) {
187
233
  const groundY = intersects[0].point.y;
188
234
  const targetY = groundY + this.EYE_HEIGHT;
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,53 +14,56 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Object3D, Plane, Vector3 } from "three";
24
+ import { Plane, Quaternion, Vector2, Vector3 } from "three";
25
25
  import { TransformControls } from "three/examples/jsm/controls/TransformControls.js";
26
26
 
27
27
  import type { Viewer } from "../Viewer";
28
+ import { STATE } from "../controls/OrbitControls.js";
28
29
  import { PlaneHelper2 } from "../helpers/PlaneHelper2";
30
+ import { Snapper } from "../measurement/Snapper";
29
31
  import { OrbitDragger } from "./OrbitDragger";
30
32
 
31
33
  export class CuttingPlaneDragger extends OrbitDragger {
32
- protected plane: Plane;
33
- protected planeCenter: Object3D;
34
- protected planeHelper: PlaneHelper2;
34
+ protected clippingPlanes: Plane[];
35
+ protected helpers: PlaneHelper2[] = [];
36
+ protected activeHelper: PlaneHelper2 = null;
37
+ protected snapper: Snapper;
38
+ protected downPosition: Vector2;
39
+ protected position0: Vector3;
40
+ protected quaternion0: Quaternion;
35
41
  protected translate: TransformControls;
36
42
  protected rotate: TransformControls;
37
43
 
38
- constructor(viewer: Viewer, normal: Vector3) {
44
+ constructor(viewer: Viewer) {
39
45
  super(viewer);
40
46
 
41
- const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
42
- const extentsCenter = viewer.extents.getCenter(new Vector3());
43
- const constant = -extentsCenter.dot(normal);
47
+ if (!viewer.renderer.clippingPlanes) viewer.renderer.clippingPlanes = [];
44
48
 
45
- this.plane = new Plane(normal, constant);
49
+ this.clippingPlanes = viewer.renderer.clippingPlanes;
50
+ this.clippingPlanes.forEach((plane) => this.addHelper(plane));
46
51
 
47
- if (!viewer.renderer.clippingPlanes) viewer.renderer.clippingPlanes = [];
48
- viewer.renderer.clippingPlanes.push(this.plane);
52
+ const extentsSize = viewer.extents.getSize(new Vector3()).length() || 1;
49
53
 
50
- this.planeCenter = new Object3D();
51
- this.planeCenter.position.copy(extentsCenter);
52
- this.planeCenter.quaternion.setFromUnitVectors(new Vector3(0, 0, -1), normal);
53
- this.viewer.helpers.add(this.planeCenter);
54
+ this.snapper = new Snapper(viewer.camera, viewer.renderer, viewer.canvas);
55
+ this.snapper.threshold = extentsSize / 10000;
54
56
 
55
- this.planeHelper = new PlaneHelper2(extentsSize);
56
- this.planeCenter.add(this.planeHelper);
57
+ this.downPosition = new Vector2();
58
+ this.position0 = new Vector3();
59
+ this.quaternion0 = new Quaternion();
57
60
 
58
61
  this.translate = new TransformControls(viewer.camera, viewer.canvas);
62
+ this.translate.setMode("translate");
59
63
  this.translate.setSpace("local");
60
64
  this.translate.showX = false;
61
65
  this.translate.showY = false;
62
66
  this.translate.showZ = true;
63
- this.translate.attach(this.planeCenter);
64
67
  this.translate.addEventListener("change", this.transformChange);
65
68
  this.translate.addEventListener("dragging-changed", this.translateDrag);
66
69
  this.viewer.helpers.add(this.translate.getHelper());
@@ -71,15 +74,20 @@ export class CuttingPlaneDragger extends OrbitDragger {
71
74
  this.rotate.showX = true;
72
75
  this.rotate.showY = true;
73
76
  this.rotate.showZ = false;
74
- this.rotate.attach(this.planeCenter);
75
77
  this.rotate.addEventListener("change", this.transformChange);
76
78
  this.rotate.addEventListener("dragging-changed", this.rotateDrag);
77
79
  this.viewer.helpers.add(this.rotate.getHelper());
78
80
 
81
+ this.setActiveHelper(this.helpers[this.helpers.length - 1]);
82
+
79
83
  this.viewer.addEventListener("explode", this.updatePlaneSize);
80
84
  this.viewer.addEventListener("show", this.updatePlaneSize);
81
85
  this.viewer.addEventListener("showall", this.updatePlaneSize);
82
86
  this.viewer.addEventListener("changecameramode", this.updateTransformCamera);
87
+ this.viewer.addEventListener("clearslices", this.clearHelpers);
88
+ this.viewer.canvas.addEventListener("pointerdown", this.onPointerDown, true);
89
+ this.viewer.canvas.addEventListener("pointerup", this.onPointerUp, true);
90
+ this.viewer.canvas.addEventListener("pointercancel", this.onPointerCancel, true);
83
91
  this.viewer.canvas.addEventListener("dblclick", this.onDoubleClick, true);
84
92
  window.addEventListener("keydown", this.onKeyDown);
85
93
  window.addEventListener("keyup", this.onKeyUp);
@@ -92,6 +100,10 @@ export class CuttingPlaneDragger extends OrbitDragger {
92
100
  this.viewer.removeEventListener("show", this.updatePlaneSize);
93
101
  this.viewer.removeEventListener("showall", this.updatePlaneSize);
94
102
  this.viewer.removeEventListener("changecameramode", this.updateTransformCamera);
103
+ this.viewer.removeEventListener("clearslices", this.clearHelpers);
104
+ this.viewer.canvas.removeEventListener("pointerdown", this.onPointerDown, true);
105
+ this.viewer.canvas.removeEventListener("pointerup", this.onPointerUp, true);
106
+ this.viewer.canvas.removeEventListener("pointercancel", this.onPointerCancel, true);
95
107
  this.viewer.canvas.removeEventListener("dblclick", this.onDoubleClick, true);
96
108
  window.removeEventListener("keydown", this.onKeyDown);
97
109
  window.removeEventListener("keyup", this.onKeyUp);
@@ -108,21 +120,26 @@ export class CuttingPlaneDragger extends OrbitDragger {
108
120
  this.rotate.detach();
109
121
  this.rotate.dispose();
110
122
 
111
- this.planeHelper.removeFromParent();
112
- this.planeHelper.dispose();
113
-
114
- this.planeCenter.removeFromParent();
115
-
116
- // this.viewer.renderer.clippingPlanes = this.viewer.renderer.clippingPlanes.filter((plane) => plane !== this.plane);
117
- // this.viewer.update();
123
+ this.helpers.forEach((helper) => {
124
+ helper.removeFromParent();
125
+ helper.dispose();
126
+ });
127
+ this.helpers = [];
128
+ this.activeHelper = null;
118
129
 
119
130
  super.dispose();
120
131
  }
121
132
 
122
133
  transformChange = () => {
123
- this.plane.normal.copy(new Vector3(0, 0, -1)).applyQuaternion(this.planeCenter.quaternion);
124
- this.plane.constant = -this.planeCenter.position.dot(this.plane.normal);
134
+ if (!this.activeHelper) return;
135
+
136
+ const plane = this.activeHelper.plane;
137
+ plane.normal.copy(new Vector3(0, 0, -1)).applyQuaternion(this.activeHelper.quaternion);
138
+ plane.constant = -this.activeHelper.position.dot(plane.normal);
139
+
125
140
  this.viewer.update();
141
+
142
+ this.changed = true; // <- cancel context menu
126
143
  };
127
144
 
128
145
  translateDrag = (event) => {
@@ -136,27 +153,170 @@ export class CuttingPlaneDragger extends OrbitDragger {
136
153
  };
137
154
 
138
155
  updatePlaneSize = () => {
139
- this.planeHelper.size = this.viewer.extents.getSize(new Vector3()).length() || 1;
156
+ const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
157
+ this.helpers.forEach((planeHelper) => (planeHelper.size = extentsSize));
140
158
  this.viewer.update();
141
159
  };
142
160
 
143
161
  updateTransformCamera = () => {
144
162
  this.translate.camera = this.viewer.camera;
145
163
  this.rotate.camera = this.viewer.camera;
164
+ this.snapper.camera = this.viewer.camera;
165
+ };
166
+
167
+ clearHelpers = () => {
168
+ this.setActiveHelper();
169
+
170
+ this.helpers.forEach((helper) => {
171
+ helper.removeFromParent();
172
+ helper.dispose();
173
+ });
174
+ this.helpers = [];
175
+
176
+ this.viewer.update();
146
177
  };
147
178
 
148
179
  onKeyDown = (event: KeyboardEvent) => {
149
180
  if (event.key === "Shift") this.rotate.setRotationSnap(Math.PI / 4);
181
+ if (event.key === "Delete" || event.key === "Backspace") this.deleteActivePlane();
182
+ if (event.key === "Escape" && (this.translate.dragging || this.rotate.dragging)) this.reset();
150
183
  };
151
184
 
152
185
  onKeyUp = (event: KeyboardEvent) => {
153
186
  if (event.key === "Shift") this.rotate.setRotationSnap(null);
154
187
  };
155
188
 
189
+ onPointerDown = (event: PointerEvent) => {
190
+ if (event.button !== 0 || !event.isPrimary) return;
191
+
192
+ this.snapper.getMousePosition(event, this.downPosition);
193
+ this.saveState();
194
+ };
195
+
196
+ onPointerUp = (event: PointerEvent) => {
197
+ if (event.button !== 0) return;
198
+
199
+ const upPosition = this.snapper.getMousePosition(event, new Vector2());
200
+ if (upPosition.distanceTo(this.downPosition) !== 0) return;
201
+
202
+ const intersects = this.snapper.getPointerIntersects(upPosition, this.helpers, true, false);
203
+ if (intersects.length === 0) return;
204
+
205
+ this.setActiveHelper(intersects[0].object.parent as PlaneHelper2);
206
+ };
207
+
208
+ onPointerCancel = (event: PointerEvent) => {
209
+ this.viewer.canvas.dispatchEvent(new PointerEvent("pointerup", event));
210
+ };
211
+
156
212
  onDoubleClick = (event: PointerEvent) => {
157
- event.stopPropagation();
213
+ if (!this.activeHelper) return;
158
214
 
159
- this.planeCenter.rotateOnAxis(new Vector3(0, 1, 0), Math.PI);
215
+ const mousePosition = this.snapper.getMousePosition(event, new Vector2());
216
+
217
+ const intersects = this.snapper.getPointerIntersects(mousePosition, [this.activeHelper], true, false);
218
+ if (intersects.length === 0) return;
219
+
220
+ this.activeHelper.rotateOnAxis(new Vector3(0, 1, 0), Math.PI);
160
221
  this.transformChange();
222
+
223
+ event.stopPropagation();
161
224
  };
225
+
226
+ private addHelper(plane: Plane): PlaneHelper2 {
227
+ const extentsSize = this.viewer.extents.getSize(new Vector3()).length() || 1;
228
+ const extentsCenter = this.viewer.extents.getCenter(new Vector3());
229
+
230
+ const helper = new PlaneHelper2(extentsSize);
231
+ helper.plane = plane;
232
+ helper.position.copy(plane.projectPoint(extentsCenter, new Vector3()));
233
+ helper.quaternion.setFromUnitVectors(new Vector3(0, 0, -1), plane.normal);
234
+
235
+ this.helpers.push(helper);
236
+ this.viewer.helpers.add(helper);
237
+
238
+ return helper;
239
+ }
240
+
241
+ private setActiveHelper(helper?: PlaneHelper2) {
242
+ if (helper === this.activeHelper) return;
243
+
244
+ if (this.activeHelper) {
245
+ this.activeHelper.getLineMaterial().color.setHex(0xf0f0f0);
246
+ this.activeHelper.getMeshMaterial().opacity = 0.15;
247
+
248
+ this.translate.detach();
249
+ this.rotate.detach();
250
+ }
251
+
252
+ this.activeHelper = helper;
253
+
254
+ if (this.activeHelper) {
255
+ this.activeHelper.getLineMaterial().color.setHex(0xd0d0d0);
256
+ this.activeHelper.getMeshMaterial().opacity = 0.3;
257
+
258
+ this.translate.attach(this.activeHelper);
259
+ this.rotate.attach(this.activeHelper);
260
+ }
261
+
262
+ this.viewer.update();
263
+ }
264
+
265
+ private saveState() {
266
+ if (!this.activeHelper) return;
267
+
268
+ this.position0.copy(this.activeHelper.position);
269
+ this.quaternion0.copy(this.activeHelper.quaternion);
270
+ }
271
+
272
+ private reset() {
273
+ if (!this.activeHelper) return;
274
+
275
+ this.translate.dragging = false;
276
+ this.rotate.dragging = false;
277
+ this.orbit.state = STATE.NONE;
278
+
279
+ this.activeHelper.position.copy(this.position0);
280
+ this.activeHelper.quaternion.copy(this.quaternion0);
281
+
282
+ this.transformChange();
283
+ }
284
+
285
+ addPlane(normal: Vector3) {
286
+ const extentsCenter = this.viewer.extents.getCenter(new Vector3());
287
+ const constant = -extentsCenter.dot(normal);
288
+
289
+ const plane = new Plane(normal, constant);
290
+ this.clippingPlanes.push(plane);
291
+
292
+ const helper = this.addHelper(plane);
293
+ this.setActiveHelper(helper);
294
+ }
295
+
296
+ addPlaneX() {
297
+ this.addPlane(new Vector3(-1, 0, 0));
298
+ }
299
+
300
+ addPlaneY() {
301
+ this.addPlane(new Vector3(0, -1, 0));
302
+ }
303
+
304
+ addPlaneZ() {
305
+ this.addPlane(new Vector3(0, 0, -1));
306
+ }
307
+
308
+ deleteActivePlane() {
309
+ if (!this.activeHelper) return;
310
+
311
+ const helper = this.activeHelper;
312
+
313
+ const index = this.clippingPlanes.indexOf(helper.plane);
314
+ if (index !== -1) this.clippingPlanes.splice(index, 1);
315
+
316
+ this.helpers = this.helpers.filter((x) => x !== helper);
317
+ helper.removeFromParent();
318
+ helper.dispose();
319
+
320
+ this.setActiveHelper(this.helpers[this.helpers.length - 1]);
321
+ }
162
322
  }
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,20 +14,19 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Vector3 } from "three";
25
-
26
24
  import type { Viewer } from "../Viewer";
27
25
  import { CuttingPlaneDragger } from "./CuttingPlaneDragger";
28
26
 
29
27
  export class CuttingPlaneXAxisDragger extends CuttingPlaneDragger {
30
28
  constructor(viewer: Viewer) {
31
- super(viewer, new Vector3(-1, 0, 0));
29
+ super(viewer);
30
+ this.addPlaneX();
32
31
  }
33
32
  }
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,20 +14,19 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Vector3 } from "three";
25
-
26
24
  import type { Viewer } from "../Viewer";
27
25
  import { CuttingPlaneDragger } from "./CuttingPlaneDragger";
28
26
 
29
27
  export class CuttingPlaneYAxisDragger extends CuttingPlaneDragger {
30
28
  constructor(viewer: Viewer) {
31
- super(viewer, new Vector3(0, -1, 0));
29
+ super(viewer);
30
+ this.addPlaneY();
32
31
  }
33
32
  }
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,20 +14,19 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Vector3 } from "three";
25
-
26
24
  import type { Viewer } from "../Viewer";
27
25
  import { CuttingPlaneDragger } from "./CuttingPlaneDragger";
28
26
 
29
27
  export class CuttingPlaneZAxisDragger extends CuttingPlaneDragger {
30
28
  constructor(viewer: Viewer) {
31
- super(viewer, new Vector3(0, 0, -1));
29
+ super(viewer);
30
+ this.addPlaneZ();
32
31
  }
33
32
  }
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
@@ -1,5 +1,5 @@
1
1
  ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
2
+ // Copyright (C) 2002-2026, Open Design Alliance (the "Alliance").
3
3
  // All rights reserved.
4
4
  //
5
5
  // This software and its documentation and related materials are owned by
@@ -14,7 +14,7 @@
14
14
  //
15
15
  // This application incorporates Open Design Alliance software pursuant to a
16
16
  // license agreement with Open Design Alliance.
17
- // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2026 by Open Design Alliance.
18
18
  // All rights reserved.
19
19
  //
20
20
  // By use of this software, its documentation or related materials, you
@@ -23,6 +23,7 @@
23
23
 
24
24
  import { IDraggersRegistry, draggersRegistry } from "@inweb/viewer-core";
25
25
 
26
+ import { CuttingPlaneDragger } from "./CuttingPlaneDragger";
26
27
  import { CuttingPlaneXAxisDragger } from "./CuttingPlaneXAxis";
27
28
  import { CuttingPlaneYAxisDragger } from "./CuttingPlaneYAxis";
28
29
  import { CuttingPlaneZAxisDragger } from "./CuttingPlaneZAxis";
@@ -84,6 +85,7 @@ draggers.registerDragger("Pan", (viewer) => new PanDragger(viewer));
84
85
  draggers.registerDragger("Orbit", (viewer) => new OrbitDragger(viewer));
85
86
  draggers.registerDragger("Zoom", (viewer) => new ZoomDragger(viewer));
86
87
  draggers.registerDragger("MeasureLine", (viewer) => new MeasureLineDragger(viewer));
88
+ draggers.registerDragger("CuttingPlane", (viewer) => new CuttingPlaneDragger(viewer));
87
89
  draggers.registerDragger("CuttingPlaneXAxis", (viewer) => new CuttingPlaneXAxisDragger(viewer));
88
90
  draggers.registerDragger("CuttingPlaneYAxis", (viewer) => new CuttingPlaneYAxisDragger(viewer));
89
91
  draggers.registerDragger("CuttingPlaneZAxis", (viewer) => new CuttingPlaneZAxisDragger(viewer));