@inweb/viewer-three 26.9.1 → 26.9.3

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 (62) hide show
  1. package/dist/plugins/components/AxesHelperComponent.js +8 -6
  2. package/dist/plugins/components/AxesHelperComponent.js.map +1 -1
  3. package/dist/plugins/components/AxesHelperComponent.min.js +1 -1
  4. package/dist/plugins/components/AxesHelperComponent.module.js +8 -6
  5. package/dist/plugins/components/AxesHelperComponent.module.js.map +1 -1
  6. package/dist/plugins/components/ExtentsHelperComponent.js.map +1 -1
  7. package/dist/plugins/components/ExtentsHelperComponent.min.js +1 -1
  8. package/dist/plugins/components/ExtentsHelperComponent.module.js +1 -1
  9. package/dist/plugins/components/ExtentsHelperComponent.module.js.map +1 -1
  10. package/dist/plugins/components/LightHelperComponent.js.map +1 -1
  11. package/dist/plugins/components/LightHelperComponent.min.js +1 -1
  12. package/dist/plugins/components/LightHelperComponent.module.js +7 -7
  13. package/dist/plugins/components/LightHelperComponent.module.js.map +1 -1
  14. package/dist/plugins/components/RoomEnvironmentComponent.js.map +1 -1
  15. package/dist/plugins/components/RoomEnvironmentComponent.min.js +1 -1
  16. package/dist/plugins/components/RoomEnvironmentComponent.module.js +1 -1
  17. package/dist/plugins/components/RoomEnvironmentComponent.module.js.map +1 -1
  18. package/dist/plugins/components/StatsPanelComponent.js.map +1 -1
  19. package/dist/plugins/components/StatsPanelComponent.min.js +1 -1
  20. package/dist/plugins/components/StatsPanelComponent.module.js +1 -1
  21. package/dist/plugins/components/StatsPanelComponent.module.js.map +1 -1
  22. package/dist/plugins/loaders/GLTFCloudLoader.js.map +1 -1
  23. package/dist/plugins/loaders/GLTFCloudLoader.min.js +1 -1
  24. package/dist/plugins/loaders/GLTFCloudLoader.module.js +1 -1
  25. package/dist/plugins/loaders/GLTFCloudLoader.module.js.map +1 -1
  26. package/dist/plugins/loaders/IFCXLoader.js +4 -4
  27. package/dist/plugins/loaders/IFCXLoader.js.map +1 -1
  28. package/dist/plugins/loaders/IFCXLoader.min.js +1 -1
  29. package/dist/plugins/loaders/IFCXLoader.module.js +92 -92
  30. package/dist/plugins/loaders/IFCXLoader.module.js.map +1 -1
  31. package/dist/plugins/loaders/PotreeLoader.js +160 -0
  32. package/dist/plugins/loaders/PotreeLoader.js.map +1 -0
  33. package/dist/plugins/loaders/PotreeLoader.min.js +1 -0
  34. package/dist/plugins/loaders/PotreeLoader.module.js +68 -0
  35. package/dist/plugins/loaders/PotreeLoader.module.js.map +1 -0
  36. package/dist/viewer-three.js +1180 -795
  37. package/dist/viewer-three.js.map +1 -1
  38. package/dist/viewer-three.min.js +3 -3
  39. package/dist/viewer-three.module.js +608 -301
  40. package/dist/viewer-three.module.js.map +1 -1
  41. package/lib/Viewer/Viewer.d.ts +3 -2
  42. package/lib/Viewer/controls/FlyControls.d.ts +34 -0
  43. package/lib/Viewer/controls/WalkControls.d.ts +19 -3
  44. package/lib/Viewer/draggers/FlyDragger.d.ts +14 -0
  45. package/package.json +6 -5
  46. package/plugins/components/AxesHelperComponent.ts +10 -6
  47. package/plugins/loaders/{IFCXCloudLoader.ts → IFCX/IFCXCloudLoader.ts} +1 -1
  48. package/plugins/loaders/{IFCXFileLoader.ts → IFCX/IFCXFileLoader.ts} +1 -1
  49. package/plugins/loaders/Potree/PotreeFileLoader.ts +106 -0
  50. package/plugins/loaders/Potree/PotreeModelImpl.ts +36 -0
  51. package/plugins/loaders/Potree/index.ts +28 -0
  52. package/src/Viewer/Viewer.ts +34 -10
  53. package/src/Viewer/components/ExtentsComponent.ts +1 -1
  54. package/src/Viewer/components/ResizeCanvasComponent.ts +1 -18
  55. package/src/Viewer/controls/FlyControls.ts +205 -0
  56. package/src/Viewer/controls/WalkControls.ts +129 -20
  57. package/src/Viewer/draggers/FlyDragger.ts +73 -0
  58. package/src/Viewer/draggers/OrbitDragger.ts +9 -0
  59. package/src/Viewer/draggers/WalkDragger.ts +11 -2
  60. package/src/Viewer/draggers/index.ts +2 -0
  61. package/src/Viewer/helpers/WCSHelper.ts +3 -3
  62. /package/plugins/loaders/{IFCXLoader.ts → IFCX/index.ts} +0 -0
@@ -0,0 +1,205 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
3
+ // All rights reserved.
4
+ //
5
+ // This software and its documentation and related materials are owned by
6
+ // the Alliance. The software may only be incorporated into application
7
+ // programs owned by members of the Alliance, subject to a signed
8
+ // Membership Agreement and Supplemental Software License Agreement with the
9
+ // Alliance. The structure and organization of this software are the valuable
10
+ // trade secrets of the Alliance and its suppliers. The software is also
11
+ // protected by copyright law and international treaty provisions. Application
12
+ // programs incorporating this software must include the following statement
13
+ // with their copyright notices:
14
+ //
15
+ // This application incorporates Open Design Alliance software pursuant to a
16
+ // license agreement with Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
18
+ // All rights reserved.
19
+ //
20
+ // By use of this software, its documentation or related materials, you
21
+ // acknowledge and accept the above terms.
22
+ ///////////////////////////////////////////////////////////////////////////////
23
+
24
+ import { Clock, Camera, Controls, Quaternion, Vector2, Vector3 } from "three";
25
+
26
+ interface FlyControlsEventMap {
27
+ change: { type: "change" };
28
+ flyspeedchange: { type: "flyspeedchange"; data: number };
29
+ }
30
+
31
+ export class FlyControls extends Controls<FlyControlsEventMap> {
32
+ public movementSpeed = 0.2;
33
+ public lookSpeed = 5;
34
+ public multiplier = 5;
35
+
36
+ private moveKeys: Set<string>;
37
+ private moveWheel = 0;
38
+ private moveClock: Clock;
39
+
40
+ private quaternion: Quaternion;
41
+ private downPosition: Vector2;
42
+ private mouseDragOn = false;
43
+ public rotateDelta: Vector2;
44
+
45
+ constructor(camera: Camera, canvas: HTMLElement) {
46
+ super(camera, canvas);
47
+
48
+ this.moveKeys = new Set();
49
+ this.moveClock = new Clock();
50
+
51
+ this.quaternion = camera.quaternion.clone();
52
+ this.downPosition = new Vector2(0, 0);
53
+ this.rotateDelta = new Vector2(0, 0);
54
+
55
+ this.domElement.addEventListener("pointerdown", this.onPointerDown);
56
+ this.domElement.addEventListener("pointermove", this.onPointerMove);
57
+ this.domElement.addEventListener("pointerup", this.onPointerUp);
58
+ this.domElement.addEventListener("pointercancel", this.onPointerCancel);
59
+ this.domElement.addEventListener("wheel", this.onWheel);
60
+
61
+ window.addEventListener("keydown", this.onKeyDown);
62
+ window.addEventListener("keyup", this.onKeyUp);
63
+ }
64
+
65
+ override dispose() {
66
+ this.domElement.removeEventListener("pointerdown", this.onPointerDown);
67
+ this.domElement.removeEventListener("pointermove", this.onPointerMove);
68
+ this.domElement.removeEventListener("pointerup", this.onPointerUp);
69
+ this.domElement.removeEventListener("pointercancel", this.onPointerCancel);
70
+ this.domElement.removeEventListener("wheel", this.onWheel);
71
+
72
+ window.removeEventListener("keydown", this.onKeyDown);
73
+ window.removeEventListener("keyup", this.onKeyUp);
74
+
75
+ super.dispose();
76
+ }
77
+
78
+ onPointerDown = (event: PointerEvent) => {
79
+ if (event.button !== 0) return;
80
+
81
+ this.domElement.setPointerCapture(event.pointerId);
82
+ this.downPosition.set(event.clientX, event.clientY);
83
+ this.quaternion.copy(this.object.quaternion);
84
+ this.mouseDragOn = true;
85
+ };
86
+
87
+ onPointerMove = (event: PointerEvent) => {
88
+ if (!this.mouseDragOn) return;
89
+
90
+ const movePosition = new Vector2(event.clientX, event.clientY);
91
+ if (this.downPosition.distanceTo(movePosition) === 0) return;
92
+
93
+ this.rotateDelta.copy(this.downPosition).sub(movePosition);
94
+ this.rotateCamera(this.rotateDelta);
95
+ this.dispatchEvent({ type: "change" });
96
+ };
97
+
98
+ onPointerUp = (event: PointerEvent) => {
99
+ this.domElement.releasePointerCapture(event.pointerId);
100
+ this.mouseDragOn = false;
101
+ };
102
+
103
+ onPointerCancel = (event: PointerEvent) => {
104
+ this.domElement.dispatchEvent(new PointerEvent("pointerup", event));
105
+ };
106
+
107
+ onWheel = (event: WheelEvent) => {
108
+ this.moveWheel = event.deltaY;
109
+ this.update();
110
+ };
111
+
112
+ onKeyDown = (event: KeyboardEvent) => {
113
+ switch (event.code) {
114
+ case "NumpadSubtract":
115
+ case "Minus":
116
+ if (this.multiplier > 1) {
117
+ this.multiplier = this.multiplier - 1;
118
+ this.dispatchEvent({ type: "flyspeedchange", data: this.multiplier });
119
+ }
120
+ break;
121
+
122
+ case "NumpadAdd":
123
+ case "Equal":
124
+ if (this.multiplier < 10) {
125
+ this.multiplier = this.multiplier + 1;
126
+ this.dispatchEvent({ type: "flyspeedchange", data: this.multiplier });
127
+ }
128
+ break;
129
+
130
+ case "ArrowLeft":
131
+ case "ArrowRight":
132
+ case "ArrowUp":
133
+ case "ArrowDown":
134
+ case "KeyW":
135
+ case "KeyS":
136
+ case "KeyA":
137
+ case "KeyD":
138
+ case "KeyQ":
139
+ case "KeyE":
140
+ this.moveKeys.add(event.code);
141
+ this.update();
142
+ break;
143
+ }
144
+ };
145
+
146
+ onKeyUp = (event: KeyboardEvent) => {
147
+ if (this.moveKeys.delete(event.code)) this.update();
148
+ };
149
+
150
+ override update() {
151
+ if (this.moveKeys.size > 0) {
152
+ const timeDelta = this.moveClock.getDelta();
153
+ const moveDelta = timeDelta * this.movementSpeed * this.multiplier;
154
+
155
+ if (this.moveKeys.has("KeyW")) this.object.translateZ(-moveDelta);
156
+ if (this.moveKeys.has("KeyS")) this.object.translateZ(moveDelta);
157
+
158
+ if (this.moveKeys.has("KeyA")) this.object.translateX(-moveDelta);
159
+ if (this.moveKeys.has("KeyD")) this.object.translateX(moveDelta);
160
+
161
+ if (this.moveKeys.has("KeyQ")) this.object.translateY(moveDelta);
162
+ if (this.moveKeys.has("KeyE")) this.object.translateY(-moveDelta);
163
+
164
+ const lookDelta = this.lookSpeed + (this.multiplier - 1);
165
+
166
+ if (this.moveKeys.has("ArrowUp")) this.rotateCamera(this.rotateDelta.add(new Vector2(0, -lookDelta / 2)));
167
+ if (this.moveKeys.has("ArrowDown")) this.rotateCamera(this.rotateDelta.add(new Vector2(0, lookDelta / 2)));
168
+
169
+ if (this.moveKeys.has("ArrowLeft")) this.rotateCamera(this.rotateDelta.add(new Vector2(lookDelta, 0)));
170
+ if (this.moveKeys.has("ArrowRight")) this.rotateCamera(this.rotateDelta.add(new Vector2(-lookDelta, 0)));
171
+
172
+ this.moveWheel = 0;
173
+ this.dispatchEvent({ type: "change" });
174
+ }
175
+
176
+ if (this.moveWheel !== 0) {
177
+ const moveDelta = this.moveWheel * 0.0001 * this.movementSpeed * this.multiplier;
178
+
179
+ this.object.translateZ(-moveDelta);
180
+ this.moveWheel += -1 * Math.sign(this.moveWheel);
181
+ this.dispatchEvent({ type: "change" });
182
+ }
183
+
184
+ if (this.moveKeys.size === 0 && this.moveWheel === 0) {
185
+ this.moveClock.stop();
186
+ this.moveClock.autoStart = true;
187
+ }
188
+ }
189
+
190
+ rotateCamera(delta: Vector2) {
191
+ const rotateX = (Math.PI * delta.x) / this.domElement.clientWidth;
192
+ const rotateY = (Math.PI * delta.y) / this.domElement.clientHeight;
193
+
194
+ const xRotation = new Quaternion();
195
+ xRotation.setFromAxisAngle(this.object.up, rotateX);
196
+
197
+ const yRotation = new Quaternion();
198
+ yRotation.setFromAxisAngle(new Vector3(1, 0, 0), rotateY);
199
+
200
+ const quaternion = this.quaternion.clone();
201
+ quaternion.premultiply(xRotation).multiply(yRotation).normalize();
202
+
203
+ this.object.setRotationFromQuaternion(quaternion);
204
+ }
205
+ }
@@ -21,7 +21,10 @@
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Clock, Camera, Controls, Quaternion, Vector2, Vector3 } from "three";
24
+ import { Clock, Camera, Controls, Quaternion, Vector2, Vector3, Raycaster, Object3D, MathUtils } from "three";
25
+ import { Viewer } from "../Viewer";
26
+ import { IModelImpl } from "../models/IModelImpl";
27
+ import { HighlighterComponent } from "../components/HighlighterComponent";
25
28
 
26
29
  interface WalkControlsEventMap {
27
30
  change: { type: "change" };
@@ -29,9 +32,18 @@ interface WalkControlsEventMap {
29
32
  }
30
33
 
31
34
  export class WalkControls extends Controls<WalkControlsEventMap> {
32
- public movementSpeed = 0.2;
33
- public lookSpeed = 5;
34
- public multiplier = 5;
35
+ readonly EYE_HEIGHT = 1.7;
36
+ readonly FAILING_DISTANCE = 2;
37
+ readonly GROUND_FOLLOWING_SPEED = 0.05;
38
+ readonly LOOK_SPEED = 0.1;
39
+ readonly WALK_SPEED_DELIMITER = 4;
40
+ readonly WHEEL_SPEED_DELIMITER = 15000;
41
+
42
+ public movementSpeed = 0.1;
43
+ public multiplier = 3;
44
+
45
+ private raycaster: Raycaster;
46
+ private groundObjects: Object3D[];
35
47
 
36
48
  private moveKeys: Set<string>;
37
49
  private moveWheel = 0;
@@ -42,8 +54,19 @@ export class WalkControls extends Controls<WalkControlsEventMap> {
42
54
  private mouseDragOn = false;
43
55
  public rotateDelta: Vector2;
44
56
 
45
- constructor(camera: Camera, canvas: HTMLElement) {
57
+ private camera: Camera;
58
+ private viewer: Viewer;
59
+ protected highlighter: HighlighterComponent;
60
+
61
+ constructor(camera: Camera, canvas: HTMLElement, groundObjects: Object3D[], viewer: Viewer) {
46
62
  super(camera, canvas);
63
+ this.camera = camera;
64
+ this.viewer = viewer;
65
+
66
+ this.groundObjects = groundObjects;
67
+ this.raycaster = new Raycaster();
68
+ this.raycaster.near = 0;
69
+ this.raycaster.far = this.EYE_HEIGHT + this.FAILING_DISTANCE;
47
70
 
48
71
  this.moveKeys = new Set();
49
72
  this.moveClock = new Clock();
@@ -147,37 +170,123 @@ export class WalkControls extends Controls<WalkControlsEventMap> {
147
170
  if (this.moveKeys.delete(event.code)) this.update();
148
171
  };
149
172
 
150
- override update() {
151
- if (this.moveKeys.size > 0) {
152
- const timeDelta = this.moveClock.getDelta();
153
- const moveDelta = timeDelta * this.movementSpeed * this.multiplier;
173
+ private updateGroundFollowing() {
174
+ this.raycaster.set(this.object.position, new Vector3(0, -1, 0));
175
+
176
+ this.raycaster.params = this.raycaster.params = {
177
+ Mesh: {},
178
+ Line: { threshold: 0 },
179
+ Line2: { threshold: 0 },
180
+ LOD: { threshold: 0 },
181
+ Points: { threshold: 0 },
182
+ Sprite: { threshold: 0 },
183
+ };
184
+
185
+ let intersects = this.raycaster.intersectObjects(this.groundObjects, false);
186
+ if (intersects.length > 0) {
187
+ const groundY = intersects[0].point.y;
188
+ const targetY = groundY + this.EYE_HEIGHT;
189
+
190
+ // Smoothly interpolate the camera's y position to the target height
191
+ this.object.position.y = MathUtils.lerp(this.object.position.y, targetY, this.GROUND_FOLLOWING_SPEED);
192
+
193
+ // Only for debug
194
+ // const model = this.viewer.models[0];
195
+ // const handles = model.getHandlesByObjects(intersects[0].object);
196
+ // const objects = model.getObjectsByHandles(handles);
197
+ // this.viewer.clearSelected();
198
+ // this.select(objects, model);
199
+ }
200
+ }
201
+
202
+ select(objects: Object3D | Object3D[], model?: IModelImpl) {
203
+ if (!model) {
204
+ this.viewer.models.forEach((model) => this.select(objects, model));
205
+ return;
206
+ }
207
+
208
+ if (!Array.isArray(objects)) objects = [objects];
209
+ if (!objects.length) return;
154
210
 
155
- if (this.moveKeys.has("KeyW")) this.object.translateZ(-moveDelta);
156
- if (this.moveKeys.has("KeyS")) this.object.translateZ(moveDelta);
211
+ model.showOriginalObjects(objects);
212
+ this.highlighter.highlight(objects);
157
213
 
158
- if (this.moveKeys.has("KeyA")) this.object.translateX(-moveDelta);
159
- if (this.moveKeys.has("KeyD")) this.object.translateX(moveDelta);
214
+ objects.forEach((object: any) => this.viewer.selected.push(object));
215
+ objects.forEach((object: any) => (object.isSelected = true));
216
+ }
217
+
218
+ initHighlighter = () => {
219
+ this.highlighter = this.viewer.getComponent("HighlighterComponent") as HighlighterComponent;
220
+ };
160
221
 
161
- if (this.moveKeys.has("KeyQ")) this.object.translateY(moveDelta);
162
- if (this.moveKeys.has("KeyE")) this.object.translateY(-moveDelta);
222
+ override update() {
223
+ let moved = false;
224
+ let upgradeGroundFollowing = false;
225
+ const forward = new Vector3();
226
+ const sideways = new Vector3();
163
227
 
164
- const lookDelta = this.lookSpeed + (this.multiplier - 1);
228
+ if (this.moveKeys.size > 0) {
229
+ upgradeGroundFollowing = true;
230
+ const timeDelta = this.moveClock.getDelta();
231
+ const moveDelta = (timeDelta * this.multiplier * this.movementSpeed) / this.WALK_SPEED_DELIMITER;
232
+
233
+ this.object.getWorldDirection(forward);
234
+ forward.y = 0;
235
+ forward.normalize();
236
+
237
+ sideways.setFromMatrixColumn(this.object.matrix, 0);
238
+ sideways.y = 0;
239
+ sideways.normalize();
240
+
241
+ if (this.moveKeys.has("KeyW")) {
242
+ this.object.position.addScaledVector(forward, moveDelta);
243
+ }
244
+ if (this.moveKeys.has("KeyS")) {
245
+ this.object.position.addScaledVector(forward, -moveDelta);
246
+ }
247
+
248
+ if (this.moveKeys.has("KeyA")) {
249
+ this.object.position.addScaledVector(sideways, -moveDelta);
250
+ }
251
+ if (this.moveKeys.has("KeyD")) {
252
+ this.object.position.addScaledVector(sideways, moveDelta);
253
+ }
254
+
255
+ if (this.moveKeys.has("KeyQ")) {
256
+ this.object.translateY(moveDelta);
257
+ upgradeGroundFollowing = false;
258
+ }
259
+ if (this.moveKeys.has("KeyE")) {
260
+ this.object.translateY(-moveDelta);
261
+ upgradeGroundFollowing = false;
262
+ }
263
+
264
+ const lookDelta = this.LOOK_SPEED + (this.multiplier - 1);
165
265
 
166
266
  if (this.moveKeys.has("ArrowUp")) this.rotateCamera(this.rotateDelta.add(new Vector2(0, -lookDelta / 2)));
167
267
  if (this.moveKeys.has("ArrowDown")) this.rotateCamera(this.rotateDelta.add(new Vector2(0, lookDelta / 2)));
168
-
169
268
  if (this.moveKeys.has("ArrowLeft")) this.rotateCamera(this.rotateDelta.add(new Vector2(lookDelta, 0)));
170
269
  if (this.moveKeys.has("ArrowRight")) this.rotateCamera(this.rotateDelta.add(new Vector2(-lookDelta, 0)));
171
270
 
172
271
  this.moveWheel = 0;
173
- this.dispatchEvent({ type: "change" });
272
+ moved = true;
174
273
  }
175
274
 
176
275
  if (this.moveWheel !== 0) {
177
- const moveDelta = this.moveWheel * 0.0001 * this.movementSpeed * this.multiplier;
276
+ const moveDelta = (this.moveWheel * this.multiplier * this.movementSpeed) / this.WHEEL_SPEED_DELIMITER;
277
+
278
+ this.object.getWorldDirection(forward);
279
+ forward.y = 0;
280
+ forward.normalize();
281
+ this.object.position.addScaledVector(forward, -moveDelta);
178
282
 
179
- this.object.translateZ(-moveDelta);
180
283
  this.moveWheel += -1 * Math.sign(this.moveWheel);
284
+ moved = true;
285
+ }
286
+
287
+ if (upgradeGroundFollowing) this.updateGroundFollowing();
288
+
289
+ if (moved) {
181
290
  this.dispatchEvent({ type: "change" });
182
291
  }
183
292
 
@@ -0,0 +1,73 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance").
3
+ // All rights reserved.
4
+ //
5
+ // This software and its documentation and related materials are owned by
6
+ // the Alliance. The software may only be incorporated into application
7
+ // programs owned by members of the Alliance, subject to a signed
8
+ // Membership Agreement and Supplemental Software License Agreement with the
9
+ // Alliance. The structure and organization of this software are the valuable
10
+ // trade secrets of the Alliance and its suppliers. The software is also
11
+ // protected by copyright law and international treaty provisions. Application
12
+ // programs incorporating this software must include the following statement
13
+ // with their copyright notices:
14
+ //
15
+ // This application incorporates Open Design Alliance software pursuant to a
16
+ // license agreement with Open Design Alliance.
17
+ // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance.
18
+ // All rights reserved.
19
+ //
20
+ // By use of this software, its documentation or related materials, you
21
+ // acknowledge and accept the above terms.
22
+ ///////////////////////////////////////////////////////////////////////////////
23
+
24
+ import { Vector3 } from "three";
25
+ import { type IDragger } from "@inweb/viewer-core";
26
+
27
+ import type { Viewer } from "../Viewer";
28
+ import { FlyControls } from "../controls/FlyControls";
29
+
30
+ export class FlyDragger implements IDragger {
31
+ protected viewer: Viewer;
32
+ public controls: FlyControls;
33
+
34
+ constructor(viewer: Viewer) {
35
+ this.controls = new FlyControls(viewer.camera, viewer.canvas);
36
+ this.controls.addEventListener("change", this.controlsChange);
37
+ this.controls.addEventListener("flyspeedchange", this.flyspeedChange);
38
+ this.viewer = viewer;
39
+ this.viewer.on("render", this.viewerRender);
40
+ this.viewer.on("zoom", this.viewerZoom);
41
+ this.updateControls();
42
+ }
43
+
44
+ dispose() {
45
+ this.viewer.off("render", this.viewerRender);
46
+ this.viewer.off("zoom", this.viewerZoom);
47
+ this.controls.removeEventListener("flyspeedchange", this.flyspeedChange);
48
+ this.controls.removeEventListener("change", this.controlsChange);
49
+ this.controls.dispose();
50
+ }
51
+
52
+ updateControls = () => {
53
+ const size = this.viewer.extents.getSize(new Vector3());
54
+ this.controls.movementSpeed = Math.min(size.x, size.y, size.z) / 2;
55
+ };
56
+
57
+ controlsChange = () => {
58
+ this.viewer.update();
59
+ this.viewer.emitEvent({ type: "changecamera" });
60
+ };
61
+
62
+ flyspeedChange = (event: any) => {
63
+ this.viewer.emitEvent(event);
64
+ };
65
+
66
+ viewerRender = () => {
67
+ this.controls.update();
68
+ };
69
+
70
+ viewerZoom = () => {
71
+ this.controls.rotateDelta.set(0, 0);
72
+ };
73
+ }
@@ -81,6 +81,13 @@ export class OrbitDragger implements IDragger {
81
81
  this.viewer.update();
82
82
 
83
83
  switch (this.orbit.state) {
84
+ case STATE.ROTATE:
85
+ case STATE.TOUCH_ROTATE:
86
+ this.viewer.emitEvent({
87
+ type: "orbit",
88
+ });
89
+ break;
90
+
84
91
  case STATE.PAN:
85
92
  case STATE.TOUCH_PAN:
86
93
  this.viewer.emitEvent({
@@ -102,6 +109,8 @@ export class OrbitDragger implements IDragger {
102
109
  break;
103
110
  }
104
111
 
112
+ this.viewer.emitEvent({ type: "changecamera" });
113
+
105
114
  this.changed = true;
106
115
  };
107
116
 
@@ -21,7 +21,7 @@
21
21
  // acknowledge and accept the above terms.
22
22
  ///////////////////////////////////////////////////////////////////////////////
23
23
 
24
- import { Vector3 } from "three";
24
+ import { Mesh, Vector3 } from "three";
25
25
  import { type IDragger } from "@inweb/viewer-core";
26
26
 
27
27
  import type { Viewer } from "../Viewer";
@@ -32,7 +32,15 @@ export class WalkDragger implements IDragger {
32
32
  public controls: WalkControls;
33
33
 
34
34
  constructor(viewer: Viewer) {
35
- this.controls = new WalkControls(viewer.camera, viewer.canvas);
35
+ const meshOnlyGround: Mesh[] = [];
36
+ viewer.models[0].getObjects().forEach((obj) => {
37
+ obj.traverse((child) => {
38
+ if (child instanceof Mesh) {
39
+ meshOnlyGround.push(child);
40
+ }
41
+ });
42
+ });
43
+ this.controls = new WalkControls(viewer.camera, viewer.canvas, meshOnlyGround, viewer);
36
44
  this.controls.addEventListener("change", this.controlsChange);
37
45
  this.controls.addEventListener("walkspeedchange", this.walkspeedChange);
38
46
  this.viewer = viewer;
@@ -56,6 +64,7 @@ export class WalkDragger implements IDragger {
56
64
 
57
65
  controlsChange = () => {
58
66
  this.viewer.update();
67
+ this.viewer.emitEvent({ type: "changecamera" });
59
68
  };
60
69
 
61
70
  walkspeedChange = (event: any) => {
@@ -30,6 +30,7 @@ import { MeasureLineDragger } from "./MeasureLineDragger";
30
30
  import { OrbitDragger } from "./OrbitDragger";
31
31
  import { PanDragger } from "./PanDragger";
32
32
  import { WalkDragger } from "./WalkDragger";
33
+ import { FlyDragger } from "./FlyDragger";
33
34
  import { ZoomDragger } from "./ZoomDragger";
34
35
 
35
36
  /**
@@ -87,3 +88,4 @@ draggers.registerDragger("CuttingPlaneXAxis", (viewer) => new CuttingPlaneXAxisD
87
88
  draggers.registerDragger("CuttingPlaneYAxis", (viewer) => new CuttingPlaneYAxisDragger(viewer));
88
89
  draggers.registerDragger("CuttingPlaneZAxis", (viewer) => new CuttingPlaneZAxisDragger(viewer));
89
90
  draggers.registerDragger("Walk", (viewer) => new WalkDragger(viewer));
91
+ draggers.registerDragger("Fly", (viewer) => new FlyDragger(viewer));
@@ -28,9 +28,9 @@ export class WCSHelper extends Object3D {
28
28
  this.orthoCamera = new OrthographicCamera(-2, 2, 2, -2, 0, 4);
29
29
  this.orthoCamera.position.set(0, 0, 2);
30
30
 
31
- const matRed = new MeshBasicMaterial({ toneMapped: false, color: "#aa0000" });
32
- const matGreen = new MeshBasicMaterial({ toneMapped: false, color: "#00aa00" });
33
- const matBlue = new MeshBasicMaterial({ toneMapped: false, color: "#0000aa" });
31
+ const matRed = new MeshBasicMaterial({ toneMapped: false, color: "#dd0000" });
32
+ const matGreen = new MeshBasicMaterial({ toneMapped: false, color: "#00dd00" });
33
+ const matBlue = new MeshBasicMaterial({ toneMapped: false, color: "#0000dd" });
34
34
 
35
35
  const spriteRed = this.getSpriteMaterial(matRed.color, "X");
36
36
  const spriteGreen = this.getSpriteMaterial(matGreen.color, "Y");