three-cad-viewer 4.3.4 → 4.3.6

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 (59) hide show
  1. package/dist/scene/clipping.d.ts +6 -0
  2. package/dist/three-cad-viewer.esm.js +20 -5
  3. package/dist/three-cad-viewer.esm.js.map +1 -1
  4. package/dist/three-cad-viewer.esm.min.js +1 -1
  5. package/dist/three-cad-viewer.js +20 -5
  6. package/dist/three-cad-viewer.min.js +1 -1
  7. package/package.json +2 -3
  8. package/src/_version.ts +0 -1
  9. package/src/camera/camera.ts +0 -445
  10. package/src/camera/controls/CADOrbitControls.ts +0 -241
  11. package/src/camera/controls/CADTrackballControls.ts +0 -598
  12. package/src/camera/controls.ts +0 -380
  13. package/src/core/patches.ts +0 -16
  14. package/src/core/studio-manager.ts +0 -652
  15. package/src/core/types.ts +0 -892
  16. package/src/core/viewer-state.ts +0 -784
  17. package/src/core/viewer.ts +0 -4821
  18. package/src/index.ts +0 -151
  19. package/src/rendering/environment.ts +0 -840
  20. package/src/rendering/light-detection.ts +0 -327
  21. package/src/rendering/material-factory.ts +0 -735
  22. package/src/rendering/material-presets.ts +0 -289
  23. package/src/rendering/raycast.ts +0 -291
  24. package/src/rendering/room-environment.ts +0 -192
  25. package/src/rendering/studio-composer.ts +0 -577
  26. package/src/rendering/studio-floor.ts +0 -108
  27. package/src/rendering/texture-cache.ts +0 -324
  28. package/src/rendering/tree-model.ts +0 -542
  29. package/src/rendering/triplanar.ts +0 -329
  30. package/src/scene/animation.ts +0 -343
  31. package/src/scene/axes.ts +0 -108
  32. package/src/scene/bbox.ts +0 -223
  33. package/src/scene/clipping.ts +0 -640
  34. package/src/scene/grid.ts +0 -864
  35. package/src/scene/nestedgroup.ts +0 -1444
  36. package/src/scene/objectgroup.ts +0 -866
  37. package/src/scene/orientation.ts +0 -259
  38. package/src/scene/render-shape.ts +0 -634
  39. package/src/tools/cad_tools/measure.ts +0 -811
  40. package/src/tools/cad_tools/select.ts +0 -100
  41. package/src/tools/cad_tools/tools.ts +0 -231
  42. package/src/tools/cad_tools/ui.ts +0 -454
  43. package/src/tools/cad_tools/zebra.ts +0 -369
  44. package/src/types/html.d.ts +0 -5
  45. package/src/types/n8ao.d.ts +0 -28
  46. package/src/types/three-augmentation.d.ts +0 -60
  47. package/src/ui/display.ts +0 -3295
  48. package/src/ui/index.html +0 -505
  49. package/src/ui/info.ts +0 -177
  50. package/src/ui/slider.ts +0 -206
  51. package/src/ui/toolbar.ts +0 -347
  52. package/src/ui/treeview.ts +0 -945
  53. package/src/utils/decode-instances.ts +0 -233
  54. package/src/utils/font.ts +0 -60
  55. package/src/utils/gpu-tracker.ts +0 -265
  56. package/src/utils/logger.ts +0 -92
  57. package/src/utils/sizeof.ts +0 -116
  58. package/src/utils/timer.ts +0 -69
  59. 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.4",
3
+ "version": "4.3.6",
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.4";
@@ -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 };