three-cad-viewer 4.3.5 → 4.3.7

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 (58) hide show
  1. package/dist/three-cad-viewer.esm.js +8 -5
  2. package/dist/three-cad-viewer.esm.js.map +1 -1
  3. package/dist/three-cad-viewer.esm.min.js +1 -1
  4. package/dist/three-cad-viewer.js +8 -5
  5. package/dist/three-cad-viewer.min.js +1 -1
  6. package/package.json +2 -3
  7. package/src/_version.ts +0 -1
  8. package/src/camera/camera.ts +0 -445
  9. package/src/camera/controls/CADOrbitControls.ts +0 -241
  10. package/src/camera/controls/CADTrackballControls.ts +0 -598
  11. package/src/camera/controls.ts +0 -380
  12. package/src/core/patches.ts +0 -16
  13. package/src/core/studio-manager.ts +0 -652
  14. package/src/core/types.ts +0 -892
  15. package/src/core/viewer-state.ts +0 -784
  16. package/src/core/viewer.ts +0 -4821
  17. package/src/index.ts +0 -151
  18. package/src/rendering/environment.ts +0 -840
  19. package/src/rendering/light-detection.ts +0 -327
  20. package/src/rendering/material-factory.ts +0 -735
  21. package/src/rendering/material-presets.ts +0 -289
  22. package/src/rendering/raycast.ts +0 -291
  23. package/src/rendering/room-environment.ts +0 -192
  24. package/src/rendering/studio-composer.ts +0 -577
  25. package/src/rendering/studio-floor.ts +0 -108
  26. package/src/rendering/texture-cache.ts +0 -324
  27. package/src/rendering/tree-model.ts +0 -542
  28. package/src/rendering/triplanar.ts +0 -329
  29. package/src/scene/animation.ts +0 -343
  30. package/src/scene/axes.ts +0 -108
  31. package/src/scene/bbox.ts +0 -223
  32. package/src/scene/clipping.ts +0 -650
  33. package/src/scene/grid.ts +0 -864
  34. package/src/scene/nestedgroup.ts +0 -1448
  35. package/src/scene/objectgroup.ts +0 -866
  36. package/src/scene/orientation.ts +0 -259
  37. package/src/scene/render-shape.ts +0 -634
  38. package/src/tools/cad_tools/measure.ts +0 -811
  39. package/src/tools/cad_tools/select.ts +0 -100
  40. package/src/tools/cad_tools/tools.ts +0 -231
  41. package/src/tools/cad_tools/ui.ts +0 -454
  42. package/src/tools/cad_tools/zebra.ts +0 -369
  43. package/src/types/html.d.ts +0 -5
  44. package/src/types/n8ao.d.ts +0 -28
  45. package/src/types/three-augmentation.d.ts +0 -60
  46. package/src/ui/display.ts +0 -3295
  47. package/src/ui/index.html +0 -505
  48. package/src/ui/info.ts +0 -177
  49. package/src/ui/slider.ts +0 -206
  50. package/src/ui/toolbar.ts +0 -347
  51. package/src/ui/treeview.ts +0 -945
  52. package/src/utils/decode-instances.ts +0 -233
  53. package/src/utils/font.ts +0 -60
  54. package/src/utils/gpu-tracker.ts +0 -265
  55. package/src/utils/logger.ts +0 -92
  56. package/src/utils/sizeof.ts +0 -116
  57. package/src/utils/timer.ts +0 -69
  58. package/src/utils/utils.ts +0 -446
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-cad-viewer",
3
- "version": "4.3.5",
3
+ "version": "4.3.7",
4
4
  "type": "module",
5
5
  "description": "WebGL-based CAD viewer built on Three.js with clipping planes, measurement tools, and tree navigation",
6
6
  "repository": {
@@ -15,8 +15,7 @@
15
15
  "dist/three-cad-viewer.esm.js.map",
16
16
  "dist/three-cad-viewer.esm.min.js",
17
17
  "dist/three-cad-viewer.js",
18
- "dist/three-cad-viewer.min.js",
19
- "src"
18
+ "dist/three-cad-viewer.min.js"
20
19
  ],
21
20
  "main": "dist/three-cad-viewer.js",
22
21
  "module": "dist/three-cad-viewer.esm.js",
package/src/_version.ts DELETED
@@ -1 +0,0 @@
1
- export const version: string = "4.3.5";
@@ -1,445 +0,0 @@
1
- import * as THREE from "three";
2
- import type { Vector3Tuple, QuaternionTuple } from "three";
3
- import type { UpDirection } from "../core/types";
4
- import { logger } from "../utils/logger.js";
5
-
6
- type CameraDirection = "iso" | "front" | "rear" | "left" | "right" | "top" | "bottom";
7
-
8
- interface DirectionConfig {
9
- pos: THREE.Vector3;
10
- quat: THREE.Quaternion | null;
11
- }
12
-
13
- type DirectionMap = Record<CameraDirection, DirectionConfig>;
14
-
15
- type UpMode = "y_up" | "z_up" | "legacy";
16
-
17
- const defaultDirections: Record<UpMode, DirectionMap> = {
18
- y_up: {
19
- // compatible to fusion 360
20
- iso: { pos: new THREE.Vector3(1, 1, 1), quat: null },
21
- front: { pos: new THREE.Vector3(0, 0, 1), quat: null },
22
- rear: { pos: new THREE.Vector3(0, 0, -1), quat: null },
23
- left: { pos: new THREE.Vector3(-1, 0, 0), quat: null },
24
- right: { pos: new THREE.Vector3(1, 0, 0), quat: null },
25
- top: { pos: new THREE.Vector3(0, 1, 0), quat: null },
26
- bottom: { pos: new THREE.Vector3(0, -1, 0), quat: null },
27
- },
28
- z_up: {
29
- // compatible to FreeCAD, OnShape
30
- iso: { pos: new THREE.Vector3(1, -1, 1), quat: null },
31
- front: { pos: new THREE.Vector3(0, -1, 0), quat: null },
32
- rear: { pos: new THREE.Vector3(0, 1, 0), quat: null },
33
- left: { pos: new THREE.Vector3(-1, 0, 0), quat: null },
34
- right: { pos: new THREE.Vector3(1, 0, 0), quat: null },
35
- top: { pos: new THREE.Vector3(0, 0, 1), quat: new THREE.Quaternion(0, 0, 0, 1) },
36
- bottom: { pos: new THREE.Vector3(0, 0, -1), quat: new THREE.Quaternion(1, 0, 0, 0) },
37
- },
38
- legacy: {
39
- // legacy Z up
40
- iso: { pos: new THREE.Vector3(1, 1, 1), quat: null },
41
- front: { pos: new THREE.Vector3(1, 0, 0), quat: null },
42
- rear: { pos: new THREE.Vector3(-1, 0, 0), quat: null },
43
- left: { pos: new THREE.Vector3(0, 1, 0), quat: null },
44
- right: { pos: new THREE.Vector3(0, -1, 0), quat: null },
45
- top: { pos: new THREE.Vector3(0, 0, 1), quat: null },
46
- bottom: { pos: new THREE.Vector3(0, 0, -1), quat: null },
47
- },
48
- };
49
-
50
- const cameraUp: Record<UpMode, [number, number, number]> = {
51
- y_up: [0, 1, 0],
52
- z_up: [0, 0, 1],
53
- legacy: [0, 0, 1],
54
- };
55
-
56
- /**
57
- * Manages orthographic and perspective cameras for the viewer.
58
- *
59
- * Camera wraps both camera types and provides:
60
- * - Seamless switching between orthographic and perspective
61
- * - Preset positions (iso, front, top, etc.)
62
- * - Support for Y-up and Z-up coordinate systems
63
- * - Synchronized position/zoom across camera types
64
- *
65
- * ## Coordinate Systems
66
- * Supports three modes via `up` parameter:
67
- * - `"Y"`: Y-up (Fusion 360 compatible)
68
- * - `"Z"`: Z-up (FreeCAD, OnShape compatible)
69
- * - Legacy Z-up mode
70
- *
71
- * @internal - This is an internal class used by Viewer
72
- */
73
- class Camera {
74
- private static readonly DISTANCE_FACTOR = 5;
75
-
76
- /**
77
- * Near plane factor: near = max(0.1, NEAR_FACTOR * distance).
78
- * With far = 100 * distance, this gives a far/near ratio of 10,000:1,
79
- * which is comfortable for 24-bit depth buffers and avoids z-fighting
80
- * on large models (e.g. toycar at ~1100 unit bounding radius).
81
- */
82
- private static readonly NEAR_FACTOR = 0.01;
83
-
84
- target: THREE.Vector3;
85
- ortho: boolean;
86
- up: UpMode;
87
- yaxis: THREE.Vector3;
88
- zaxis: THREE.Vector3;
89
- camera_distance: number;
90
- pCamera!: THREE.PerspectiveCamera; // Initialized in constructor
91
- oCamera!: THREE.OrthographicCamera; // Initialized in constructor
92
- camera!: THREE.PerspectiveCamera | THREE.OrthographicCamera; // Set in constructor
93
-
94
- /**
95
- * Compute the near clipping plane from the bounding radius.
96
- * Keeps the far/near ratio bounded for depth buffer precision.
97
- */
98
- private static _computeNear(distance: number): number {
99
- return Math.max(0.1, Camera.NEAR_FACTOR * distance);
100
- }
101
-
102
- /**
103
- * Create a combined camera (orthographic and perspective).
104
- * @param width - canvas width.
105
- * @param height - canvas height.
106
- * @param distance - distance from the lookAt point.
107
- * @param target - target (Vector3) to look at.
108
- * @param ortho - flag whether the initial camera should be orthographic.
109
- * @param up - Z or Y to define whether Z or Y direction is camera up.
110
- */
111
- constructor(
112
- width: number,
113
- height: number,
114
- distance: number,
115
- target: Vector3Tuple,
116
- ortho: boolean,
117
- up: UpDirection
118
- ) {
119
- const mapping: Record<string, UpMode> = {
120
- Y: "y_up",
121
- Z: "z_up",
122
- L: "legacy",
123
- };
124
- this.target = new THREE.Vector3(...target);
125
- this.ortho = ortho;
126
- this.up = mapping[up] || "z_up";
127
- this.yaxis = new THREE.Vector3(0, 1, 0);
128
- this.zaxis = new THREE.Vector3(0, 0, 1);
129
-
130
- // define the perspective camera
131
-
132
- const aspect = width / height;
133
-
134
- // 22 is a good compromise
135
- const fov = 22;
136
-
137
- this.camera_distance = Camera.DISTANCE_FACTOR * distance;
138
-
139
- const near = Camera._computeNear(distance);
140
- const far = 100 * distance;
141
-
142
- this.pCamera = new THREE.PerspectiveCamera(fov, aspect, near, far);
143
- this.pCamera.up.set(...cameraUp[this.up]);
144
- this.pCamera.lookAt(this.target);
145
-
146
- // define the orthographic camera
147
- const pSize = this.projectSize(distance, aspect);
148
-
149
- this.oCamera = new THREE.OrthographicCamera(
150
- -pSize[0],
151
- pSize[0],
152
- pSize[1],
153
- -pSize[1],
154
- near,
155
- far,
156
- );
157
- this.oCamera.up.set(...cameraUp[this.up]);
158
- this.oCamera.lookAt(this.target);
159
-
160
- this.camera = ortho ? this.oCamera! : this.pCamera!;
161
- this.camera.up.set(...cameraUp[this.up]);
162
- }
163
-
164
- /**
165
- * Update the near/far clipping planes for both cameras.
166
- * @param distance - The new bounding radius to base the clipping planes on.
167
- */
168
- updateFarPlane(distance: number): void {
169
- const near = Camera._computeNear(distance);
170
- const far = 100 * distance;
171
- this.pCamera.near = near;
172
- this.pCamera.far = far;
173
- this.oCamera.near = near;
174
- this.oCamera.far = far;
175
- this.camera.updateProjectionMatrix();
176
- }
177
-
178
- /**
179
- * Recalculate camera_distance from a new bounding radius.
180
- * Uses the same factor as the constructor so that zoom 1.0 frames the scene.
181
- * @param distance - The new bounding radius (bb_radius).
182
- */
183
- updateCameraDistance(distance: number): void {
184
- this.camera_distance = Camera.DISTANCE_FACTOR * distance;
185
- }
186
-
187
- /**
188
- * Remove assets.
189
- */
190
- dispose(): void {
191
- // Cameras are simple objects; no explicit cleanup needed.
192
- // The Camera instance itself will be garbage collected.
193
- }
194
-
195
- /**
196
- * Get the current camera.
197
- * @returns Camera object.
198
- */
199
- getCamera(): THREE.PerspectiveCamera | THREE.OrthographicCamera {
200
- return this.camera;
201
- }
202
-
203
- /**
204
- * Set the lookAt point for the camera to the provided target.
205
- */
206
- lookAtTarget(): void {
207
- this.camera.lookAt(this.target);
208
- }
209
-
210
- /**
211
- * Update current camera's projection matrix.
212
- */
213
- updateProjectionMatrix(): void {
214
- this.camera.updateProjectionMatrix();
215
- }
216
-
217
- /**
218
- * Switch between orthographic and perspective camera.
219
- * @param ortho_flag - true for orthographic camera, else perspective camera.
220
- */
221
- switchCamera(ortho_flag: boolean): void {
222
- const p0 = this.getPosition().clone();
223
- const z0 = this.getZoom();
224
- const q0 = this.getQuaternion().clone();
225
-
226
- if (ortho_flag) {
227
- this.camera = this.oCamera;
228
- this.ortho = true;
229
- } else {
230
- this.camera = this.pCamera;
231
- this.ortho = false;
232
- }
233
-
234
- this.setPosition(p0, false);
235
- this.setZoom(z0);
236
- this.setQuaternion(q0);
237
-
238
- this.updateProjectionMatrix();
239
- }
240
-
241
- /**
242
- * Calculate projected size for orthographic camera.
243
- * @param frustum - View frustum size.
244
- * @param aspect - Viewer aspect ratio (width / height).
245
- * @returns Width and height [w, h] for the orthographic camera.
246
- */
247
- projectSize(frustum: number, aspect: number): [number, number] {
248
- let w: number, h: number;
249
- if (aspect < 1) {
250
- w = frustum;
251
- h = w / aspect;
252
- } else {
253
- h = frustum;
254
- w = h * aspect;
255
- }
256
- return [w, h];
257
- }
258
-
259
- /**
260
- * Setup the current camera.
261
- * @param relative - flag whether the position is a relative (e.g. [1,1,1] for iso) or absolute point.
262
- * @param position - the camera position (relative or absolute).
263
- * @param quaternion - the camera rotation expressed by a quaternion.
264
- * @param zoom - zoom value.
265
- */
266
- setupCamera(
267
- relative: boolean,
268
- position: THREE.Vector3 | null = null,
269
- quaternion: THREE.Quaternion | null = null,
270
- zoom: number | null = null
271
- ): void {
272
- if (position != null) {
273
- const cameraPosition = relative
274
- ? position
275
- .clone()
276
- .normalize()
277
- .multiplyScalar(this.camera_distance)
278
- .add(this.target)
279
- : position;
280
-
281
- this.camera.position.set(...cameraPosition.toArray());
282
- }
283
-
284
- if (quaternion != null) {
285
- this.camera.quaternion.set(...quaternion.toArray());
286
- }
287
-
288
- if (zoom != null) {
289
- this.setZoom(zoom);
290
- }
291
-
292
- this.updateProjectionMatrix();
293
- }
294
-
295
- /**
296
- * Move the camera to a given preset.
297
- * @param dir - can be "iso", "top", "bottom", "front", "rear", "left", "right"
298
- */
299
- presetCamera(dir: CameraDirection, zoom: number | null = null): void {
300
- if (zoom == null) {
301
- zoom = this.camera.zoom;
302
- }
303
- // For the default directions quaternion can be ignored, it will be reset automatically
304
- this.setupCamera(true, defaultDirections[this.up][dir].pos, null, zoom);
305
- this.lookAtTarget();
306
-
307
- const quat = defaultDirections[this.up][dir].quat;
308
- if (quat != null) {
309
- this.setQuaternion(quat);
310
- }
311
- }
312
-
313
- /**
314
- * Return current zoom value.
315
- * @returns zoom value.
316
- */
317
- getZoom(): number {
318
- if (this.ortho) {
319
- return this.camera.zoom;
320
- } else {
321
- const p = this.camera.position.clone().sub(this.target);
322
- return this.camera_distance / p.length();
323
- }
324
- }
325
-
326
- /**
327
- * Set zoom value.
328
- * @param val - float zoom value.
329
- */
330
- setZoom(val: number): void {
331
- if (this.ortho) {
332
- this.camera.zoom = val;
333
- } else {
334
- this.camera.position
335
- .sub(this.target)
336
- .setLength(this.camera_distance / val)
337
- .add(this.target);
338
- }
339
-
340
- this.updateProjectionMatrix();
341
- }
342
-
343
- /**
344
- * Get the current camera position.
345
- * @returns camera position.
346
- */
347
- getPosition(): THREE.Vector3 {
348
- return this.camera.position;
349
- }
350
-
351
- /**
352
- * Set camera position.
353
- * @param position - position as 3 dim Array [x,y,z] or as Vector3.
354
- * @param relative - flag whether the position is a relative (e.g. [1,1,1] for iso) or absolute point.
355
- */
356
- setPosition(position: Vector3Tuple | THREE.Vector3, relative: boolean): void {
357
- if (Array.isArray(position) && position.length === 3) {
358
- this.setupCamera(relative, new THREE.Vector3(...position));
359
- } else if (position instanceof THREE.Vector3) {
360
- this.setupCamera(relative, position);
361
- } else {
362
- logger.error("wrong type for position", position);
363
- }
364
- }
365
-
366
- /**
367
- * Get the current camera quaternion.
368
- * @returns camera quaternion.
369
- */
370
- getQuaternion(): THREE.Quaternion {
371
- return this.camera.quaternion;
372
- }
373
-
374
- /**
375
- * Set camera quaternion.
376
- * @param quaternion - quaternion as 4 dim Array or as Quaternion.
377
- */
378
- setQuaternion(quaternion: QuaternionTuple | THREE.Quaternion): void {
379
- if (Array.isArray(quaternion) && quaternion.length === 4) {
380
- this.setupCamera(false, null, new THREE.Quaternion(...quaternion));
381
- } else if (quaternion instanceof THREE.Quaternion) {
382
- this.setupCamera(false, null, quaternion);
383
- } else {
384
- logger.error("wrong type for quaternion", quaternion);
385
- }
386
-
387
- this.updateProjectionMatrix();
388
- }
389
-
390
- /**
391
- * Get the current camera rotation.
392
- * @returns camera rotation.
393
- */
394
- getRotation(): THREE.Euler {
395
- return this.camera.rotation;
396
- }
397
-
398
- /**
399
- * Get the visible area dimensions at the target plane.
400
- * @returns The visible width and height.
401
- */
402
- getVisibleArea(): { width: number; height: number } {
403
- if (this.ortho && this.oCamera) {
404
- const height = (this.oCamera.top - this.oCamera.bottom) / this.oCamera.zoom;
405
- const width = (this.oCamera.right - this.oCamera.left) / this.oCamera.zoom;
406
- return { width, height };
407
- } else if (this.pCamera) {
408
- const distance = this.pCamera.position.distanceTo(this.target);
409
- const vFOV = (this.pCamera.fov * Math.PI) / 180;
410
- const height = 2 * Math.tan(vFOV / 2) * distance;
411
- const width = height * this.pCamera.aspect;
412
- return { width, height };
413
- }
414
- return { width: 0, height: 0 };
415
- }
416
-
417
- /**
418
- * Update camera dimensions when viewport size changes.
419
- * @param distance - Distance used for orthographic frustum calculation.
420
- * @param width - New viewport width in pixels.
421
- * @param height - New viewport height in pixels.
422
- */
423
- changeDimensions(distance: number, width: number, height: number): void {
424
- const aspect = width / height;
425
- const pSize = this.projectSize(distance, aspect);
426
-
427
- if (this.oCamera) {
428
- this.oCamera.left = -pSize[0];
429
- this.oCamera.right = pSize[0];
430
- this.oCamera.top = pSize[1];
431
- this.oCamera.bottom = -pSize[1];
432
- }
433
-
434
- if (this.pCamera) {
435
- this.pCamera.aspect = aspect;
436
- }
437
-
438
- if (this.camera) {
439
- this.camera.updateProjectionMatrix();
440
- }
441
- }
442
- }
443
-
444
- export { Camera };
445
- export type { CameraDirection, UpMode };
@@ -1,241 +0,0 @@
1
- /**
2
- * CADOrbitControls - Extended OrbitControls for CAD applications
3
- *
4
- * Adds:
5
- * - Public rotateLeft/rotateUp methods for programmatic rotation
6
- * - Quaternion-based saveState/reset
7
- * - Modifier key rotation restrictions (ctrl: vertical only, meta: horizontal only)
8
- *
9
- * Internal OrbitControls methods/properties used (see three-augmentation.d.ts):
10
- * - _onMouseDown: Replaced to customize modifier key behavior (shift=pan, ctrl/meta=rotate with axis lock)
11
- * - _handleMouseDownRotate: Called to initialize rotation state
12
- * - _handleMouseDownDolly: Called to initialize dolly/zoom state
13
- * - _handleMouseDownPan: Called to initialize pan state
14
- * - _sphericalDelta: Modified in _rotateLeft/_rotateUp overrides to implement axis locking
15
- * - state: Set to track current interaction mode (ROTATE/DOLLY/PAN/NONE)
16
- */
17
-
18
- import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
19
- import { MOUSE, Quaternion, Vector3, Camera } from "three";
20
- import { KeyMapper, isOrthographicCamera, isPerspectiveCamera } from "../../utils/utils.js";
21
-
22
- // State constants matching OrbitControls internal state
23
- const STATE = {
24
- NONE: -1,
25
- ROTATE: 0,
26
- DOLLY: 1,
27
- PAN: 2,
28
- };
29
-
30
- class CADOrbitControls extends OrbitControls {
31
- quaternion0: Quaternion;
32
- private _horizontalRotate: boolean;
33
- private _verticalRotate: boolean;
34
- private _onCADPointerDown?: (event: PointerEvent) => void;
35
- private _onCADPointerUp?: () => void;
36
-
37
- // Expose internal properties for type safety
38
- declare state: number;
39
- declare _sphericalDelta: { theta: number; phi: number };
40
- declare zoom0: number;
41
- declare target0: Vector3;
42
- declare position0: Vector3;
43
- declare _onMouseDown: (event: MouseEvent) => void;
44
- declare _handleMouseDownRotate: (event: MouseEvent) => void;
45
- declare _handleMouseDownDolly: (event: MouseEvent) => void;
46
- declare _handleMouseDownPan: (event: MouseEvent) => void;
47
-
48
- /**
49
- * Constructs CAD-enhanced orbit controls.
50
- *
51
- * @param object - The camera to control.
52
- * @param domElement - The HTML element for event listeners.
53
- */
54
- constructor(object: Camera, domElement: HTMLElement | null = null) {
55
- super(object, domElement!);
56
-
57
- /**
58
- * Saved quaternion for reset (in addition to position/target/zoom).
59
- */
60
- this.quaternion0 = this.object.quaternion.clone();
61
-
62
- // Rotation axis restriction flags (set via modifier keys)
63
- this._horizontalRotate = true; // meta key restricts to horizontal only
64
- this._verticalRotate = true; // ctrl key restricts to vertical only
65
-
66
- // Add pointer event listeners for modifier key detection
67
- if (domElement) {
68
- this._onCADPointerDown = this._handleCADPointerDown.bind(this);
69
- this._onCADPointerUp = this._handleCADPointerUp.bind(this);
70
- domElement.addEventListener("pointerdown", this._onCADPointerDown);
71
- domElement.addEventListener("pointerup", this._onCADPointerUp);
72
- domElement.addEventListener("pointercancel", this._onCADPointerUp);
73
- }
74
-
75
- // Override the parent's _onMouseDown which was bound in parent constructor
76
- this._onMouseDown = this._handleMouseDown.bind(this);
77
- }
78
-
79
- /**
80
- * Handle pointer down to check modifier keys for rotation restriction.
81
- */
82
- private _handleCADPointerDown(event: PointerEvent): void {
83
- // Check modifier keys for rotation restriction
84
- // ctrl: restrict to vertical rotation only (horizontalRotate = false)
85
- // meta: restrict to horizontal rotation only (verticalRotate = false)
86
- this._horizontalRotate = !KeyMapper.get(event, "ctrl");
87
- this._verticalRotate = !KeyMapper.get(event, "meta");
88
- }
89
-
90
- /**
91
- * Handle pointer up to reset rotation restrictions.
92
- */
93
- private _handleCADPointerUp(): void {
94
- this._horizontalRotate = true;
95
- this._verticalRotate = true;
96
- }
97
-
98
- /**
99
- * Override dispose to clean up our event listeners.
100
- */
101
- dispose(): void {
102
- if (this.domElement && this._onCADPointerDown && this._onCADPointerUp) {
103
- this.domElement.removeEventListener("pointerdown", this._onCADPointerDown);
104
- this.domElement.removeEventListener("pointerup", this._onCADPointerUp);
105
- this.domElement.removeEventListener("pointercancel", this._onCADPointerUp);
106
- }
107
- super.dispose();
108
- }
109
-
110
- /**
111
- * Custom mouse down handler for rotation restriction via modifier keys.
112
- *
113
- * Original OrbitControls: ctrl/meta/shift + left mouse = pan
114
- * CADOrbitControls: ctrl = vertical rotate only, meta = horizontal rotate only,
115
- * shift = pan (via KeyMapper)
116
- */
117
- private _handleMouseDown(event: MouseEvent): void {
118
- let mouseAction: number;
119
-
120
- switch (event.button) {
121
- case 0:
122
- mouseAction = this.mouseButtons.LEFT!;
123
- break;
124
- case 1:
125
- mouseAction = this.mouseButtons.MIDDLE!;
126
- break;
127
- case 2:
128
- mouseAction = this.mouseButtons.RIGHT!;
129
- break;
130
- default:
131
- mouseAction = -1;
132
- }
133
-
134
- switch (mouseAction) {
135
- case MOUSE.DOLLY:
136
- if (this.enableZoom === false) return;
137
- this._handleMouseDownDolly(event);
138
- this.state = STATE.DOLLY;
139
- break;
140
-
141
- case MOUSE.ROTATE:
142
- // Check if shift key (via KeyMapper) is pressed for pan
143
- if (KeyMapper.get(event, "shift")) {
144
- if (this.enablePan === false) return;
145
- this._handleMouseDownPan(event);
146
- this.state = STATE.PAN;
147
- } else {
148
- // ctrl and meta are handled for rotation restriction in _handleCADPointerDown
149
- if (this.enableRotate === false) return;
150
- this._handleMouseDownRotate(event);
151
- this.state = STATE.ROTATE;
152
- }
153
- break;
154
-
155
- case MOUSE.PAN:
156
- // For right mouse button, check if any modifier for rotate
157
- if (
158
- KeyMapper.get(event, "ctrl") ||
159
- KeyMapper.get(event, "meta") ||
160
- KeyMapper.get(event, "shift")
161
- ) {
162
- if (this.enableRotate === false) return;
163
- this._handleMouseDownRotate(event);
164
- this.state = STATE.ROTATE;
165
- } else {
166
- if (this.enablePan === false) return;
167
- this._handleMouseDownPan(event);
168
- this.state = STATE.PAN;
169
- }
170
- break;
171
-
172
- default:
173
- this.state = STATE.NONE;
174
- }
175
- }
176
-
177
- /**
178
- * Override _rotateLeft to respect horizontal rotation restriction.
179
- */
180
- _rotateLeft(angle: number): void {
181
- if (this._horizontalRotate) {
182
- this._sphericalDelta.theta -= angle;
183
- }
184
- }
185
-
186
- /**
187
- * Override _rotateUp to respect vertical rotation restriction.
188
- */
189
- _rotateUp(angle: number): void {
190
- if (this._verticalRotate) {
191
- this._sphericalDelta.phi -= angle;
192
- }
193
- }
194
-
195
- /**
196
- * Save the current state including quaternion.
197
- */
198
- saveState(): void {
199
- super.saveState();
200
- this.quaternion0.copy(this.object.quaternion);
201
- }
202
-
203
- /**
204
- * Reset to saved state including quaternion.
205
- */
206
- reset(): void {
207
- this.target.copy(this.target0);
208
- this.object.position.copy(this.position0);
209
- this.object.quaternion.copy(this.quaternion0);
210
-
211
- if (isPerspectiveCamera(this.object) || isOrthographicCamera(this.object)) {
212
- this.object.zoom = this.zoom0;
213
- this.object.updateProjectionMatrix();
214
- }
215
- this.dispatchEvent({ type: "change" });
216
-
217
- this.update();
218
-
219
- this.state = -1; // STATE.NONE
220
- }
221
-
222
- /**
223
- * Rotate camera left (around the up axis).
224
- * Programmatic rotation bypasses modifier key restrictions.
225
- */
226
- rotateLeft(angle: number): void {
227
- // Bypass restriction for programmatic rotation
228
- this._sphericalDelta.theta -= angle;
229
- }
230
-
231
- /**
232
- * Rotate camera up (around the right axis).
233
- * Programmatic rotation bypasses modifier key restrictions.
234
- */
235
- rotateUp(angle: number): void {
236
- // Bypass restriction for programmatic rotation
237
- this._sphericalDelta.phi -= angle;
238
- }
239
- }
240
-
241
- export { CADOrbitControls };