@shapediver/viewer.features.drawing-tools 3.13.20 → 3.14.0

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 (55) hide show
  1. package/dist/api/implementation/DrawingToolsApi.d.ts +5 -2
  2. package/dist/api/implementation/DrawingToolsApi.d.ts.map +1 -1
  3. package/dist/api/implementation/DrawingToolsApi.js.map +1 -1
  4. package/dist/api/interfaces/IDrawingToolsApi.d.ts +5 -2
  5. package/dist/api/interfaces/IDrawingToolsApi.d.ts.map +1 -1
  6. package/dist/business/implementation/DrawingToolsManager.d.ts +12 -9
  7. package/dist/business/implementation/DrawingToolsManager.d.ts.map +1 -1
  8. package/dist/business/implementation/DrawingToolsManager.js +20 -14
  9. package/dist/business/implementation/DrawingToolsManager.js.map +1 -1
  10. package/dist/business/implementation/managers/HistoryManager.d.ts +2 -0
  11. package/dist/business/implementation/managers/HistoryManager.d.ts.map +1 -1
  12. package/dist/business/implementation/managers/HistoryManager.js +3 -1
  13. package/dist/business/implementation/managers/HistoryManager.js.map +1 -1
  14. package/dist/business/implementation/managers/geometry/GeometryManager.d.ts +3 -2
  15. package/dist/business/implementation/managers/geometry/GeometryManager.d.ts.map +1 -1
  16. package/dist/business/implementation/managers/geometry/GeometryManager.js +4 -4
  17. package/dist/business/implementation/managers/geometry/GeometryManager.js.map +1 -1
  18. package/dist/business/implementation/managers/geometry/GeometryState.d.ts +4 -2
  19. package/dist/business/implementation/managers/geometry/GeometryState.d.ts.map +1 -1
  20. package/dist/business/implementation/managers/geometry/GeometryState.js +15 -7
  21. package/dist/business/implementation/managers/geometry/GeometryState.js.map +1 -1
  22. package/dist/business/implementation/managers/geometry/helpers/GeometryManagerHelper.d.ts +3 -2
  23. package/dist/business/implementation/managers/geometry/helpers/GeometryManagerHelper.d.ts.map +1 -1
  24. package/dist/business/implementation/managers/geometry/helpers/GeometryManagerHelper.js +20 -6
  25. package/dist/business/implementation/managers/geometry/helpers/GeometryManagerHelper.js.map +1 -1
  26. package/dist/business/implementation/managers/interaction/InteractionManager.d.ts +1 -1
  27. package/dist/business/implementation/managers/interaction/InteractionManager.d.ts.map +1 -1
  28. package/dist/business/implementation/managers/interaction/InteractionManager.js +2 -2
  29. package/dist/business/implementation/managers/interaction/InteractionManager.js.map +1 -1
  30. package/dist/business/implementation/managers/interaction/handlers/InsertionInteractionHandler.d.ts.map +1 -1
  31. package/dist/business/implementation/managers/interaction/handlers/InsertionInteractionHandler.js +10 -10
  32. package/dist/business/implementation/managers/interaction/handlers/InsertionInteractionHandler.js.map +1 -1
  33. package/dist/business/implementation/managers/interaction/helpers/InteractionManagerHelper.d.ts +1 -0
  34. package/dist/business/implementation/managers/interaction/helpers/InteractionManagerHelper.d.ts.map +1 -1
  35. package/dist/business/implementation/managers/interaction/helpers/InteractionManagerHelper.js +24 -8
  36. package/dist/business/implementation/managers/interaction/helpers/InteractionManagerHelper.js.map +1 -1
  37. package/dist/business/implementation/managers/interaction/interfaces/IStrategy.d.ts +1 -1
  38. package/dist/business/implementation/managers/interaction/interfaces/IStrategy.d.ts.map +1 -1
  39. package/dist/business/implementation/managers/interaction/strategies/DesktopStrategy.d.ts +349 -6
  40. package/dist/business/implementation/managers/interaction/strategies/DesktopStrategy.d.ts.map +1 -1
  41. package/dist/business/implementation/managers/interaction/strategies/DesktopStrategy.js +631 -147
  42. package/dist/business/implementation/managers/interaction/strategies/DesktopStrategy.js.map +1 -1
  43. package/dist/business/implementation/managers/interaction/strategies/MobileStategy.d.ts +1 -1
  44. package/dist/business/implementation/managers/interaction/strategies/MobileStategy.d.ts.map +1 -1
  45. package/dist/business/implementation/managers/interaction/strategies/MobileStategy.js +7 -5
  46. package/dist/business/implementation/managers/interaction/strategies/MobileStategy.js.map +1 -1
  47. package/dist/business/interfaces/IDrawingToolsManager.d.ts +8 -5
  48. package/dist/business/interfaces/IDrawingToolsManager.d.ts.map +1 -1
  49. package/dist/business/interfaces/IDrawingToolsManager.js.map +1 -1
  50. package/dist/business/interfaces/events/IDrawingToolsEvent.d.ts +2 -0
  51. package/dist/business/interfaces/events/IDrawingToolsEvent.d.ts.map +1 -1
  52. package/dist/index.d.ts +2 -2
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js.map +1 -1
  55. package/package.json +11 -10
@@ -10,12 +10,71 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _DesktopStrategy_drawingToolsManager, _DesktopStrategy_geometryMathManager, _DesktopStrategy_insertionInteractionHandler, _DesktopStrategy_interactionManager, _DesktopStrategy_interactionManagerHelper, _DesktopStrategy_midPointInteractionHandler, _DesktopStrategy_restrictionManager, _DesktopStrategy_viewport, _DesktopStrategy_cameraFreezeFlag, _DesktopStrategy_lastEvent, _DesktopStrategy_onDownPointer;
13
+ var _DesktopStrategy_instances, _DesktopStrategy_drawingToolsManager, _DesktopStrategy_geometryMathManager, _DesktopStrategy_insertionInteractionHandler, _DesktopStrategy_interactionManager, _DesktopStrategy_interactionManagerHelper, _DesktopStrategy_midPointInteractionHandler, _DesktopStrategy_restrictionManager, _DesktopStrategy_selectionBox, _DesktopStrategy_viewport, _DesktopStrategy_boxHoveredPoints, _DesktopStrategy_cameraFreezeFlag, _DesktopStrategy_isBoxSelecting, _DesktopStrategy_lastEvent, _DesktopStrategy_lastMoveEvent, _DesktopStrategy_onDownPointer, _DesktopStrategy_updateAllPointMaterials;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.DesktopStrategy = void 0;
16
+ const viewer_rendering_engine_intersection_engine_1 = require("@shapediver/viewer.rendering-engine.intersection-engine");
16
17
  const viewer_shared_types_1 = require("@shapediver/viewer.shared.types");
18
+ const gl_matrix_1 = require("gl-matrix");
19
+ const IDrawingToolsManager_1 = require("../../../../interfaces/IDrawingToolsManager");
20
+ /**
21
+ * ## Quick Reference - Main Event Flow:
22
+ *
23
+ * **Mouse Down** → Initiate interaction (box selection, insertion, point selection)
24
+ * **Mouse Move** → Update previews, handle dragging, provide feedback
25
+ * **Mouse Up** → Finalize operations, apply changes, cleanup state
26
+ * **Mouse Out** → Pause operations, cleanup visual feedback
27
+ * **Key Down** → Execute commands (insert, confirm, cancel, delete)
28
+ *
29
+ * ## Interaction State Priority:
30
+ * 1. **Box Selection** (Alt + drag) - Highest priority, blocks other interactions
31
+ * 2. **Active Insertion** - Continuous point placement mode
32
+ * 3. **Point Dragging** - Moving selected points
33
+ * 4. **Point Selection** - Single/multi-point selection
34
+ * 5. **Mid-point Insertion** - Insert between existing points
35
+ * 6. **Hover Detection** - Visual feedback only
36
+ *
37
+ * See DesktopStrategy.md for detailed workflow documentation.
38
+ */
39
+ /**
40
+ * DesktopStrategy - Handles desktop mouse and keyboard interactions for drawing tools
41
+ *
42
+ * This class implements the Strategy pattern to provide desktop-specific interaction handling
43
+ * for drawing tools. It manages various interaction modes including point insertion, selection,
44
+ * dragging, and box selection.
45
+ *
46
+ * ## Main Interaction Workflows:
47
+ *
48
+ * ### 1. Point Insertion Workflow:
49
+ * - User clicks to start insertion mode
50
+ * - Mouse movements update the insertion preview
51
+ * - Click again to finalize point placement
52
+ * - Supports auto-start for empty drawings
53
+ *
54
+ * ### 2. Point Selection & Dragging Workflow:
55
+ * - Click on existing points to select them
56
+ * - Drag selected points to move them
57
+ * - Multiple selection support with modifier keys
58
+ *
59
+ * ### 3. Box Selection Workflow:
60
+ * - Alt + drag to create selection box
61
+ * - Shift = additive selection, Ctrl = removal selection
62
+ * - All points within box are selected/deselected
63
+ *
64
+ * ### 4. Mid-point Insertion Workflow:
65
+ * - Hover over line segments to show mid-point preview
66
+ * - Click to insert point between existing points
67
+ *
68
+ * ## Key Features:
69
+ * - Camera freeze during interactions
70
+ * - Visual feedback through cursor changes
71
+ * - Material updates for hover/selection states
72
+ * - Keyboard shortcuts for common operations
73
+ * - Restriction-based point placement
74
+ */
17
75
  class DesktopStrategy {
18
76
  constructor(drawingToolsManager, interactionManager) {
77
+ _DesktopStrategy_instances.add(this);
19
78
  _DesktopStrategy_drawingToolsManager.set(this, void 0);
20
79
  _DesktopStrategy_geometryMathManager.set(this, void 0);
21
80
  _DesktopStrategy_insertionInteractionHandler.set(this, void 0);
@@ -23,9 +82,13 @@ class DesktopStrategy {
23
82
  _DesktopStrategy_interactionManagerHelper.set(this, void 0);
24
83
  _DesktopStrategy_midPointInteractionHandler.set(this, void 0);
25
84
  _DesktopStrategy_restrictionManager.set(this, void 0);
85
+ _DesktopStrategy_selectionBox.set(this, void 0);
26
86
  _DesktopStrategy_viewport.set(this, void 0);
87
+ _DesktopStrategy_boxHoveredPoints.set(this, []);
27
88
  _DesktopStrategy_cameraFreezeFlag.set(this, "");
89
+ _DesktopStrategy_isBoxSelecting.set(this, false);
28
90
  _DesktopStrategy_lastEvent.set(this, void 0);
91
+ _DesktopStrategy_lastMoveEvent.set(this, void 0);
29
92
  _DesktopStrategy_onDownPointer.set(this, void 0);
30
93
  __classPrivateFieldSet(this, _DesktopStrategy_drawingToolsManager, drawingToolsManager, "f");
31
94
  __classPrivateFieldSet(this, _DesktopStrategy_interactionManager, interactionManager, "f");
@@ -35,142 +98,202 @@ class DesktopStrategy {
35
98
  __classPrivateFieldSet(this, _DesktopStrategy_insertionInteractionHandler, __classPrivateFieldGet(this, _DesktopStrategy_interactionManager, "f").insertionInteractionHandler, "f");
36
99
  __classPrivateFieldSet(this, _DesktopStrategy_midPointInteractionHandler, __classPrivateFieldGet(this, _DesktopStrategy_interactionManager, "f").midPointInteractionHandler, "f");
37
100
  __classPrivateFieldSet(this, _DesktopStrategy_interactionManagerHelper, __classPrivateFieldGet(this, _DesktopStrategy_interactionManager, "f").interactionManagerHelper, "f");
101
+ __classPrivateFieldSet(this, _DesktopStrategy_selectionBox, new viewer_rendering_engine_intersection_engine_1.SelectionBox(__classPrivateFieldGet(this, _DesktopStrategy_viewport, "f").canvas), "f");
38
102
  }
39
103
  get cameraFreezeFlag() {
40
104
  return __classPrivateFieldGet(this, _DesktopStrategy_cameraFreezeFlag, "f");
41
105
  }
106
+ /**
107
+ * Handles mouse/pointer down events - Entry point for most interaction workflows
108
+ *
109
+ * ## Workflow Priority:
110
+ * 1. **Box Selection** (Alt + Click): Initiates rectangular selection mode
111
+ * 2. **Insertion Finalization**: If insertion is active, finalizes current point and starts new insertion
112
+ * 3. **Point Interaction**: Handles hover detection, selection, and dragging initiation
113
+ * 4. **Right Click**: Cancels current operation
114
+ *
115
+ * ## State Changes:
116
+ * - Sets camera freeze flag for dragging/box selection
117
+ * - Updates selection state
118
+ * - Triggers mid-point insertion completion
119
+ * - Starts dragging mode for selected points
120
+ *
121
+ * @param event - Pointer event containing mouse button and modifier key information
122
+ * @param ray - 3D ray from camera through mouse position for intersection testing
123
+ */
42
124
  onDown(event, ray) {
43
125
  if (event.button === 0) {
44
126
  __classPrivateFieldSet(this, _DesktopStrategy_onDownPointer, event, "f");
45
127
  __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").moving = false;
46
- /**
47
- * IF INSERT KEY IS PRESSED
48
- * FINALIZE INSERTION AND START A NEW ONE
49
- */
50
- if (__classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionActive === true) {
51
- const result = __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").finalizeInsertion();
52
- const distances = __classPrivateFieldGet(this, _DesktopStrategy_geometryMathManager, "f").checkPointDistances(ray, __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray);
53
- __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").checkHover(distances, ray);
54
- if (result) {
55
- __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").update();
56
- return;
57
- }
58
- else {
59
- __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").startInsertion(event);
60
- return;
61
- }
128
+ // Handle box selection initiation
129
+ if (this.handleBoxSelectionStart(event)) {
130
+ return;
62
131
  }
63
- const distances = __classPrivateFieldGet(this, _DesktopStrategy_geometryMathManager, "f").checkPointDistances(ray, __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray);
64
- /**
65
- * IF MID POINT INSERTION IS ACTIVE
66
- * FINISH MID POINT INSERTION IF THE CURRENT INDEX IS THE MID POINT INSERTION INDEX
67
- */
68
- if (__classPrivateFieldGet(this, _DesktopStrategy_midPointInteractionHandler, "f").midPointInsertionActive ===
69
- true) {
70
- __classPrivateFieldGet(this, _DesktopStrategy_midPointInteractionHandler, "f").finishMidPointInsertion(distances);
71
- __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").midPointInserted = true;
132
+ // Handle insertion finalization and restart
133
+ if (this.handleInsertionFinalization(event, ray)) {
134
+ return;
72
135
  }
73
- /**
74
- * CHECK HOVERED POINT
75
- */
136
+ // Calculate point distances for hover and selection logic
137
+ const distances = __classPrivateFieldGet(this, _DesktopStrategy_geometryMathManager, "f").checkPointDistances(ray, __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray);
138
+ // Handle mid-point insertion
139
+ this.handleMidPointInsertion(distances);
140
+ // Check hover state
76
141
  __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").checkHover(distances, ray);
77
- /**
78
- * IF THERE IS A POINT CLOSE TO THE RAY
79
- */
80
- __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").selectPoint(distances);
81
- /**
82
- * IF THE CURRENTLY HOVERED POINT IS SELECTED
83
- * START DRAGGING
84
- */
85
- const draggingStarted = __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").startDragging();
86
- if (draggingStarted && !__classPrivateFieldGet(this, _DesktopStrategy_cameraFreezeFlag, "f"))
87
- __classPrivateFieldSet(this, _DesktopStrategy_cameraFreezeFlag, __classPrivateFieldGet(this, _DesktopStrategy_viewport, "f").addFlag(viewer_shared_types_1.FLAG_TYPE.CAMERA_FREEZE), "f");
142
+ // Handle point selection and dragging
143
+ this.handlePointSelection(distances);
88
144
  }
89
145
  else if (event.button === 2) {
90
- /**
91
- * WHEN RIGHT MOUSE BUTTON IS PRESSED
92
- */
146
+ // Right mouse button - cancel current operation
93
147
  this.onOut();
94
148
  }
95
149
  }
96
150
  /**
97
- * On mouse move, move the selected point if there is one
151
+ * Handles keyboard input for drawing tool controls
98
152
  *
99
- * @param event
100
- * @param ray
153
+ * ## Supported Operations:
154
+ *
155
+ * ### Confirm Key (typically Enter):
156
+ * - **During Insertion**: Finalizes insertion and updates drawing
157
+ * - **Normal Mode**: Updates/commits current drawing state
158
+ *
159
+ * ### Cancel Key (typically Escape):
160
+ * - **During Insertion**: Stops insertion mode
161
+ * - **Normal Mode**: Cancels entire drawing operation
162
+ *
163
+ * ### Insert Key (typically Space):
164
+ * - Starts insertion mode at current mouse position
165
+ * - Shows restriction visualization
166
+ *
167
+ * ### Delete Key (typically Delete/Backspace):
168
+ * - Removes currently selected points from drawing
169
+ *
170
+ * ## Workflow Integration:
171
+ * These keyboard shortcuts provide alternative ways to control the drawing workflow
172
+ * without relying solely on mouse interactions.
101
173
  */
102
- onMove(event, ray) {
103
- let currentRestrictedPoint;
104
- // if there are no points, start with the insertion right away
105
- if (__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.general.autoStart &&
106
- __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionActive === false &&
107
- __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").getPointsData().length === 0) {
108
- __classPrivateFieldSet(this, _DesktopStrategy_lastEvent, event, "f");
109
- currentRestrictedPoint =
110
- this.startInsertion() || currentRestrictedPoint;
174
+ onKeyDown() {
175
+ const keys = this.getKeyStates();
176
+ // Handle confirm key
177
+ if (keys.confirm) {
178
+ if (__classPrivateFieldGet(this, _DesktopStrategy_interactionManager, "f").insertionInteractionHandler
179
+ .insertionActive) {
180
+ this.stopInsertion();
181
+ __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").update();
182
+ }
183
+ else {
184
+ __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").update();
185
+ }
111
186
  }
112
- // if the insertion was paused, try to start it again
113
- // it might not start if the ray is not intersecting with the restriction
114
- if (__classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionPaused) {
115
- __classPrivateFieldSet(this, _DesktopStrategy_lastEvent, event, "f");
116
- currentRestrictedPoint =
117
- this.startInsertion() || currentRestrictedPoint;
187
+ // Handle cancel key
188
+ if (keys.cancel) {
189
+ if (__classPrivateFieldGet(this, _DesktopStrategy_interactionManager, "f").insertionInteractionHandler
190
+ .insertionActive) {
191
+ this.stopInsertion();
192
+ }
193
+ else {
194
+ __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").cancel();
195
+ }
118
196
  }
119
- const distanceSquared = __classPrivateFieldGet(this, _DesktopStrategy_onDownPointer, "f")
120
- ? Math.pow(event.clientX - __classPrivateFieldGet(this, _DesktopStrategy_onDownPointer, "f").clientX, 2) +
121
- Math.pow(event.clientY - __classPrivateFieldGet(this, _DesktopStrategy_onDownPointer, "f").clientY, 2)
122
- : Infinity;
123
- const clickThresholdSquared = 25;
124
- const pointerMoved = distanceSquared > clickThresholdSquared;
197
+ // Handle insert key
198
+ if (keys.insert) {
199
+ this.startInsertion();
200
+ }
201
+ // Handle delete key
202
+ if (keys.delete) {
203
+ __classPrivateFieldGet(this, _DesktopStrategy_interactionManager, "f").deleteSelection();
204
+ }
205
+ }
206
+ /**
207
+ * Handles mouse/pointer movement - Core interaction processing for all movement-based workflows
208
+ *
209
+ * ## Primary Workflows:
210
+ *
211
+ * ### 1. Box Selection Mode (when #isBoxSelecting = true):
212
+ * - Updates selection rectangle bounds
213
+ * - Provides real-time hover feedback for points within selection
214
+ * - Respects modifier keys (Shift=add, Ctrl=remove)
215
+ *
216
+ * ### 2. Insertion Workflows:
217
+ * - **Auto-start**: Automatically begins insertion for empty drawings
218
+ * - **Resume**: Restarts paused insertions when mouse re-enters valid area
219
+ * - **Active insertion**: Updates insertion preview position
220
+ * - **Pause**: Pauses insertion when mouse leaves restricted area
221
+ *
222
+ * ### 3. Point Manipulation:
223
+ * - **Dragging**: Moves selected points when dragging is active
224
+ * - **Hover detection**: Updates hover state for visual feedback
225
+ * - **Mid-point insertion**: Shows preview for inserting points between existing ones
226
+ *
227
+ * ### 4. Visual Feedback:
228
+ * - **Cursor updates**: Changes cursor based on interaction state (grab, pointer, default)
229
+ * - **Material updates**: Updates point colors for hover/selection states
230
+ * - **Text visualization**: Updates position indicator text
231
+ *
232
+ * ## Movement Detection:
233
+ * Uses CLICK_THRESHOLD_SQUARED to distinguish between clicks and drags,
234
+ * preventing accidental dragging on small mouse movements.
235
+ *
236
+ * @param event - Pointer event with current mouse position and modifier keys
237
+ * @param ray - 3D ray for intersection testing and point placement
238
+ */
239
+ onMove(event, ray) {
240
+ // Track the last move event for modifier key states
241
+ __classPrivateFieldSet(this, _DesktopStrategy_lastMoveEvent, event, "f");
242
+ // Handle box selection movement
243
+ if (__classPrivateFieldGet(this, _DesktopStrategy_isBoxSelecting, "f")) {
244
+ // Pass the current shift/ctrl state to determine selection behavior
245
+ const isAdditive = event.shiftKey;
246
+ const isRemoval = event.ctrlKey;
247
+ __classPrivateFieldGet(this, _DesktopStrategy_selectionBox, "f").onMove(event, isAdditive, isRemoval);
248
+ // Update hover effects for points inside the selection box
249
+ this.updateBoxSelectionHover();
250
+ return;
251
+ }
252
+ let currentRestrictedPoint;
253
+ // Handle automatic start and insertion resume
254
+ currentRestrictedPoint =
255
+ this.handleAutoStart(event) || currentRestrictedPoint;
256
+ currentRestrictedPoint =
257
+ this.handleInsertionResume(event) || currentRestrictedPoint;
258
+ const pointerMoved = this.hasPointerMoved(event);
125
259
  __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").moving = pointerMoved;
126
260
  if (pointerMoved) {
127
261
  __classPrivateFieldSet(this, _DesktopStrategy_lastEvent, event, "f");
128
- /**
129
- * IF WE ARE DRAGGING A POINT
130
- * MOVE THE SELECTED POINTS
131
- */
262
+ // Handle point dragging
132
263
  currentRestrictedPoint =
133
264
  __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").moveSelectedPoints(ray) ||
134
265
  currentRestrictedPoint;
135
266
  }
267
+ // Check point distances and hover state
136
268
  const distances = __classPrivateFieldGet(this, _DesktopStrategy_geometryMathManager, "f").checkPointDistances(ray, __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray);
137
269
  __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").checkHover(distances, ray);
138
270
  if (pointerMoved) {
139
- /**
140
- * IF INSERT KEY IS PRESSED
141
- * ADD POINT AT RAY INTERSECTION IF THERE IS NONE WAS ADDED
142
- * MOVE LAST ADDED POINT IF THERE IS ONE
143
- */
271
+ // Handle insertion movement
144
272
  currentRestrictedPoint =
145
- __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").onMove(ray) ||
146
- currentRestrictedPoint;
147
- /**
148
- * IF INSERT KEY IS NOT PRESSED AND DRAGGING IS NOT ACTIVE
149
- * CHECK IF THERE IS A LINE CLOSE TO THE RAY AND ADD A MID POINT TO IT
150
- */
151
- if (__classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionActive === false &&
152
- __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").dragging === false &&
153
- __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").selectedPointIndices.length === 0) {
154
- __classPrivateFieldGet(this, _DesktopStrategy_midPointInteractionHandler, "f").onMove(ray, __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").hoveredPoint);
155
- }
156
- }
157
- if (__classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").dragging) {
158
- document.body.style.cursor = "grabbing";
159
- }
160
- else if (__classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").hoveredPoint !== undefined) {
161
- document.body.style.cursor = "pointer";
162
- }
163
- else {
164
- document.body.style.cursor = "default";
273
+ this.handleInsertionMove(ray) || currentRestrictedPoint;
274
+ // Handle mid-point insertion
275
+ this.handleMidPointMove(ray);
165
276
  }
166
- // if the insertion is active, but the current point is not restricted, pause the insertion
167
- if (!currentRestrictedPoint &&
168
- __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionActive)
169
- __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").pauseInsertion();
277
+ // Update cursor and handle insertion pause
278
+ this.updateCursor();
279
+ this.handleInsertionPause(currentRestrictedPoint);
170
280
  __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").textVisualizationManager.updatePointerPosition(currentRestrictedPoint);
171
281
  }
172
282
  /**
173
- * On mouse out, deselect the hovered point and remove the stop dragging
283
+ * Handles mouse leave/out events - Cleanup and state reset
284
+ *
285
+ * ## Cleanup Operations:
286
+ * - **Restriction visualization**: Hides visual guides for point placement restrictions
287
+ * - **Insertion pause**: Temporarily stops insertion mode (can be resumed on mouse re-enter)
288
+ * - **Hover state**: Clears any hovered point indicators
289
+ * - **General reset**: Calls reset() to clean up interaction state
290
+ *
291
+ * ## Use Cases:
292
+ * - Mouse leaves the drawing area/viewport
293
+ * - Right-click cancellation
294
+ * - Focus loss events
295
+ *
296
+ * This ensures the UI returns to a clean state when interaction is interrupted.
174
297
  */
175
298
  onOut() {
176
299
  __classPrivateFieldGet(this, _DesktopStrategy_restrictionManager, "f").showRestrictionVisualization = false;
@@ -178,11 +301,304 @@ class DesktopStrategy {
178
301
  __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").onOut();
179
302
  this.reset();
180
303
  }
181
- onUp() {
304
+ /**
305
+ * Handles mouse/pointer up events - Finalization of click/drag operations
306
+ *
307
+ * ## Primary Operations:
308
+ *
309
+ * ### Box Selection Completion:
310
+ * When box selection is active (#isBoxSelecting = true):
311
+ * 1. **Finalize selection**: Ends the selection rectangle operation
312
+ * 2. **Process intersections**: Determines which points are within the selection box
313
+ * 3. **Apply selection logic**: Handles modifier keys for add/remove/toggle selection
314
+ * 4. **Visual cleanup**: Updates material indices and resets hover states
315
+ * 5. **State reset**: Clears box selection flags and data
316
+ *
317
+ * ### General Cleanup:
318
+ * For all other operations:
319
+ * - **End dragging**: Stops any active point dragging operations
320
+ * - **Camera unfreeze**: Removes camera movement restrictions
321
+ * - **State reset**: Returns to default interaction state
322
+ *
323
+ * ## Workflow Integration:
324
+ * This method completes the interaction cycle started by onDown(),
325
+ * ensuring proper cleanup and state transitions for all operation types.
326
+ *
327
+ * @param event - Pointer event with final mouse position and modifier key states
328
+ */
329
+ onUp(event) {
330
+ // Handle box selection completion
331
+ if (__classPrivateFieldGet(this, _DesktopStrategy_isBoxSelecting, "f")) {
332
+ __classPrivateFieldGet(this, _DesktopStrategy_selectionBox, "f").onEnd(event);
333
+ this.handleBoxSelection(event);
334
+ // Clear box hovered points, last move event, and update material indices for all points
335
+ __classPrivateFieldSet(this, _DesktopStrategy_boxHoveredPoints, [], "f");
336
+ __classPrivateFieldGet(this, _DesktopStrategy_instances, "m", _DesktopStrategy_updateAllPointMaterials).call(this);
337
+ __classPrivateFieldSet(this, _DesktopStrategy_lastMoveEvent, undefined, "f");
338
+ __classPrivateFieldSet(this, _DesktopStrategy_isBoxSelecting, false, "f");
339
+ __classPrivateFieldGet(this, _DesktopStrategy_selectionBox, "f").reset();
340
+ }
182
341
  __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").onUp();
183
342
  this.reset();
184
343
  }
344
+ /**
345
+ * Convert position array to array of vec3 points
346
+ */
347
+ convertPositionArrayToPoints() {
348
+ if (!__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray ||
349
+ __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray.length === 0) {
350
+ return [];
351
+ }
352
+ const points = [];
353
+ for (let i = 0; i < __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray.length; i += DesktopStrategy.COORDINATE_STEP) {
354
+ points.push(gl_matrix_1.vec3.fromValues(__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray[i], __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray[i + 1], __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray[i + 2]));
355
+ }
356
+ return points;
357
+ }
358
+ /**
359
+ * Get the current state of control keys
360
+ */
361
+ getKeyStates() {
362
+ return {
363
+ insert: __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").keyPressed(__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.controls.insert),
364
+ cancel: __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").keyPressed(__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.controls.cancel),
365
+ confirm: __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").keyPressed(__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.controls.confirm),
366
+ delete: __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").keyPressed(__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.controls.delete),
367
+ };
368
+ }
369
+ /**
370
+ * Enables automatic insertion start for empty drawings to improve user experience
371
+ *
372
+ * ## Auto-start Conditions:
373
+ * 1. **Setting enabled**: `autoStart` setting must be enabled
374
+ * 2. **No active insertion**: Insertion mode is not currently active
375
+ * 3. **Empty drawing**: No points exist in the current drawing
376
+ *
377
+ * ## Workflow Benefits:
378
+ * - Eliminates need to press insert key for first point
379
+ * - Creates smoother initial user experience
380
+ * - Reduces friction for starting new drawings
381
+ *
382
+ * @param event - Pointer event to cache for insertion start
383
+ * @returns Restricted point position if insertion started, undefined otherwise
384
+ */
385
+ handleAutoStart(event) {
386
+ if (__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.general.autoStart &&
387
+ __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionActive === false &&
388
+ __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").getPointsData().length === 0) {
389
+ __classPrivateFieldSet(this, _DesktopStrategy_lastEvent, event, "f");
390
+ return this.startInsertion();
391
+ }
392
+ return undefined;
393
+ }
394
+ /**
395
+ * Processes box selection completion and applies selection logic based on modifier keys
396
+ *
397
+ * ## Selection Logic Workflow:
398
+ * 1. **Point conversion**: Converts position array to 3D points for intersection testing
399
+ * 2. **Intersection calculation**: Determines which points are within the selection box
400
+ * 3. **Modifier key handling**:
401
+ * - **Shift**: Additive selection (adds points to existing selection)
402
+ * - **Ctrl**: Removal selection (removes points from existing selection)
403
+ * - **None**: Toggle selection (default behavior - toggles each point's selection state)
404
+ *
405
+ * ## Integration with Selection System:
406
+ * - Uses InteractionManagerHelper methods for consistent selection behavior
407
+ * - Maintains selection state across different interaction modes
408
+ * - Respects existing selection when using modifier keys
409
+ *
410
+ * @param event - Optional pointer event for modifier key state (fallback to last move event)
411
+ */
412
+ handleBoxSelection(event) {
413
+ const points = this.convertPositionArrayToPoints();
414
+ if (points.length === 0) {
415
+ return;
416
+ }
417
+ // Get intersected point indices
418
+ const intersectedIndices = __classPrivateFieldGet(this, _DesktopStrategy_selectionBox, "f").intersectPoints(points);
419
+ // Use the last move event for modifier key state, fallback to provided event
420
+ const currentEvent = __classPrivateFieldGet(this, _DesktopStrategy_lastMoveEvent, "f") || event;
421
+ // Handle selection based on modifier keys from the last move event
422
+ if (currentEvent === null || currentEvent === void 0 ? void 0 : currentEvent.shiftKey) {
423
+ // Shift key: add to selection
424
+ intersectedIndices.forEach((index) => {
425
+ __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").selectPoint([
426
+ { index, distance: 0 },
427
+ ]);
428
+ });
429
+ }
430
+ else if (currentEvent === null || currentEvent === void 0 ? void 0 : currentEvent.ctrlKey) {
431
+ // Ctrl key: remove from selection
432
+ intersectedIndices.forEach((index) => {
433
+ __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").deselectPoint(index);
434
+ });
435
+ }
436
+ else {
437
+ // No modifier key: replace selection (default behavior)
438
+ intersectedIndices.forEach((index) => {
439
+ __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").toggleSelection(index);
440
+ });
441
+ }
442
+ }
443
+ /**
444
+ * Initiates box selection mode when Alt key is pressed during mouse down
445
+ *
446
+ * ## Workflow:
447
+ * 1. **Validation**: Checks if Alt key is pressed
448
+ * 2. **State setup**: Sets box selection flag and initializes selection box
449
+ * 3. **Camera control**: Freezes camera to prevent viewport movement during selection
450
+ * 4. **Event binding**: Connects selection box to camera projection for accurate 3D selection
451
+ *
452
+ * ## Visual Feedback:
453
+ * - Selection rectangle appears on screen
454
+ * - Camera movement is disabled
455
+ * - Cursor indicates selection mode
456
+ *
457
+ * @param event - Pointer event to check for Alt key modifier
458
+ * @returns true if box selection was initiated, false otherwise
459
+ */
460
+ handleBoxSelectionStart(event) {
461
+ if (!event.altKey)
462
+ return false;
463
+ __classPrivateFieldSet(this, _DesktopStrategy_isBoxSelecting, true, "f");
464
+ if (__classPrivateFieldGet(this, _DesktopStrategy_viewport, "f").camera) {
465
+ __classPrivateFieldGet(this, _DesktopStrategy_selectionBox, "f").onDown(event, __classPrivateFieldGet(this, _DesktopStrategy_viewport, "f").camera.project.bind(__classPrivateFieldGet(this, _DesktopStrategy_viewport, "f").camera));
466
+ }
467
+ if (!__classPrivateFieldGet(this, _DesktopStrategy_cameraFreezeFlag, "f")) {
468
+ __classPrivateFieldSet(this, _DesktopStrategy_cameraFreezeFlag, __classPrivateFieldGet(this, _DesktopStrategy_viewport, "f").addFlag(viewer_shared_types_1.FLAG_TYPE.CAMERA_FREEZE), "f");
469
+ }
470
+ return true;
471
+ }
472
+ /**
473
+ * Manages the insertion workflow when insertion mode is already active
474
+ *
475
+ * ## Insertion Finalization Workflow:
476
+ * 1. **Completion attempt**: Tries to finalize the current insertion point
477
+ * 2. **Success path**: If successful, updates the drawing and exits
478
+ * 3. **Continuation path**: If not finalized, starts a new insertion at click location
479
+ * 4. **Hover management**: Updates hover state after point distance calculations
480
+ *
481
+ * ## Use Cases:
482
+ * - User clicks while in insertion mode to place a point
483
+ * - Handles both successful point placement and insertion continuation
484
+ * - Maintains smooth insertion workflow for multiple point placement
485
+ *
486
+ * @param event - Pointer event for the new insertion location
487
+ * @param ray - 3D ray for intersection testing and point placement
488
+ * @returns true if insertion was processed, false if insertion mode is not active
489
+ */
490
+ handleInsertionFinalization(event, ray) {
491
+ if (!__classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionActive)
492
+ return false;
493
+ const result = __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").finalizeInsertion();
494
+ const distances = __classPrivateFieldGet(this, _DesktopStrategy_geometryMathManager, "f").checkPointDistances(ray, __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray);
495
+ __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").checkHover(distances, ray);
496
+ if (result) {
497
+ __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").update();
498
+ return true;
499
+ }
500
+ else {
501
+ __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").startInsertion(event);
502
+ return true;
503
+ }
504
+ }
505
+ /**
506
+ * Handle mouse move during insertion mode
507
+ */
508
+ handleInsertionMove(ray) {
509
+ return __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").onMove(ray);
510
+ }
511
+ /**
512
+ * Handle insertion pause when point is not restricted
513
+ */
514
+ handleInsertionPause(currentRestrictedPoint) {
515
+ if (!currentRestrictedPoint &&
516
+ __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionActive) {
517
+ __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").pauseInsertion();
518
+ }
519
+ }
520
+ /**
521
+ * Handle resuming paused insertion
522
+ */
523
+ handleInsertionResume(event) {
524
+ if (__classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionPaused) {
525
+ __classPrivateFieldSet(this, _DesktopStrategy_lastEvent, event, "f");
526
+ return this.startInsertion();
527
+ }
528
+ return undefined;
529
+ }
530
+ /**
531
+ * Handle mid-point insertion completion
532
+ */
533
+ handleMidPointInsertion(distances) {
534
+ if (__classPrivateFieldGet(this, _DesktopStrategy_midPointInteractionHandler, "f").midPointInsertionActive &&
535
+ distances) {
536
+ __classPrivateFieldGet(this, _DesktopStrategy_midPointInteractionHandler, "f").finishMidPointInsertion(distances);
537
+ __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").midPointInserted = true;
538
+ }
539
+ }
540
+ /**
541
+ * Handle mid-point insertion logic during movement
542
+ */
543
+ handleMidPointMove(ray) {
544
+ if (__classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionActive === false &&
545
+ __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").dragging === false &&
546
+ __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").selectedPointIndices.length === 0) {
547
+ __classPrivateFieldGet(this, _DesktopStrategy_midPointInteractionHandler, "f").onMove(ray, __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").hoveredPoint);
548
+ }
549
+ }
550
+ /**
551
+ * Handle point selection and dragging initiation
552
+ */
553
+ handlePointSelection(distances) {
554
+ if (!distances)
555
+ return;
556
+ __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").selectPoint(distances);
557
+ const draggingStarted = __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").startDragging();
558
+ if (draggingStarted && !__classPrivateFieldGet(this, _DesktopStrategy_cameraFreezeFlag, "f")) {
559
+ __classPrivateFieldSet(this, _DesktopStrategy_cameraFreezeFlag, __classPrivateFieldGet(this, _DesktopStrategy_viewport, "f").addFlag(viewer_shared_types_1.FLAG_TYPE.CAMERA_FREEZE), "f");
560
+ }
561
+ }
562
+ /**
563
+ * Check if pointer has moved beyond the click threshold
564
+ */
565
+ hasPointerMoved(event) {
566
+ const distanceSquared = __classPrivateFieldGet(this, _DesktopStrategy_onDownPointer, "f")
567
+ ? Math.pow(event.clientX - __classPrivateFieldGet(this, _DesktopStrategy_onDownPointer, "f").clientX, 2) +
568
+ Math.pow(event.clientY - __classPrivateFieldGet(this, _DesktopStrategy_onDownPointer, "f").clientY, 2)
569
+ : Infinity;
570
+ return distanceSquared > DesktopStrategy.CLICK_THRESHOLD_SQUARED;
571
+ }
572
+ /**
573
+ * Comprehensive state reset for interaction cleanup
574
+ *
575
+ * ## Reset Workflow:
576
+ * ```
577
+ * Box Selection Reset → Insertion State Check → Camera Unfreeze → Helper Reset
578
+ * ↓ ↓ ↓ ↓
579
+ * Clear box flags Check if insertion Remove freeze Reset selection
580
+ * Reset hover states is still active flag if safe and drag states
581
+ * Clear tracking Keep freeze if Restore camera Clean temp data
582
+ * ```
583
+ *
584
+ * ## Safety Measures:
585
+ * - Only unfreezes camera if insertion is not active
586
+ * - Properly cleans up visual states for all tracked points
587
+ * - Ensures no orphaned state remains after interactions
588
+ */
185
589
  reset() {
590
+ // Reset box selection if active
591
+ if (__classPrivateFieldGet(this, _DesktopStrategy_isBoxSelecting, "f")) {
592
+ __classPrivateFieldSet(this, _DesktopStrategy_isBoxSelecting, false, "f");
593
+ __classPrivateFieldGet(this, _DesktopStrategy_selectionBox, "f").reset();
594
+ __classPrivateFieldSet(this, _DesktopStrategy_lastMoveEvent, undefined, "f");
595
+ // Clear hover effects from box hovered points
596
+ __classPrivateFieldGet(this, _DesktopStrategy_boxHoveredPoints, "f").forEach((index) => {
597
+ const isSelected = __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").selectedPointIndices.includes(index);
598
+ this.updatePointMaterial(index, isSelected, false);
599
+ });
600
+ __classPrivateFieldSet(this, _DesktopStrategy_boxHoveredPoints, [], "f");
601
+ }
186
602
  if (__classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").insertionActive === false) {
187
603
  __classPrivateFieldGet(this, _DesktopStrategy_restrictionManager, "f").showRestrictionVisualization = false;
188
604
  __classPrivateFieldGet(this, _DesktopStrategy_viewport, "f").removeFlag(__classPrivateFieldGet(this, _DesktopStrategy_cameraFreezeFlag, "f"));
@@ -190,67 +606,135 @@ class DesktopStrategy {
190
606
  }
191
607
  __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").reset();
192
608
  }
609
+ /**
610
+ * Initiates insertion mode with proper state setup
611
+ *
612
+ * ## Insertion Start Workflow:
613
+ * ```
614
+ * Enable Restrictions → Stop Mid-point → Start Insertion → Return Position
615
+ * ↓ ↓ ↓ ↓
616
+ * Show visual Clear any existing Begin insertion Validate and
617
+ * guides for mid-point preview at cached event return position
618
+ * valid placement operations location or undefined
619
+ * ```
620
+ *
621
+ * @returns Restricted point position if insertion started successfully, undefined if restricted
622
+ */
193
623
  startInsertion() {
194
624
  __classPrivateFieldGet(this, _DesktopStrategy_restrictionManager, "f").showRestrictionVisualization = true;
195
625
  __classPrivateFieldGet(this, _DesktopStrategy_midPointInteractionHandler, "f").stopMidPointInsertion();
196
626
  return __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").startInsertion(__classPrivateFieldGet(this, _DesktopStrategy_lastEvent, "f"));
197
627
  }
628
+ /**
629
+ * Cleanly exits insertion mode with proper cleanup
630
+ *
631
+ * ## Insertion Stop Workflow:
632
+ * ```
633
+ * Hide Restrictions → Stop Insertion → Unfreeze Camera → Clear Flags
634
+ * ↓ ↓ ↓ ↓
635
+ * Remove visual End insertion Restore camera Reset freeze
636
+ * guides and handler state movement flag state
637
+ * feedback capability
638
+ * ```
639
+ */
198
640
  stopInsertion() {
199
641
  __classPrivateFieldGet(this, _DesktopStrategy_restrictionManager, "f").showRestrictionVisualization = false;
200
642
  __classPrivateFieldGet(this, _DesktopStrategy_insertionInteractionHandler, "f").stopInsertion();
201
643
  __classPrivateFieldGet(this, _DesktopStrategy_viewport, "f").removeFlag(__classPrivateFieldGet(this, _DesktopStrategy_cameraFreezeFlag, "f"));
202
644
  __classPrivateFieldSet(this, _DesktopStrategy_cameraFreezeFlag, "", "f");
203
645
  }
204
- onKeyDown() {
205
- const insertKeyPressed = __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").keyPressed(__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.controls.insert);
206
- const cancelKeyPressed = __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").keyPressed(__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.controls.cancel);
207
- const confirmKeyPressed = __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").keyPressed(__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.controls.confirm);
208
- const deleteKeyPressed = __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").keyPressed(__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").settings.controls.delete);
209
- /**
210
- * IF CONFIRM KEY IS PRESSED
211
- * - IF INSERTION IS ACTIVE, STOP INSERTION
212
- * - IF INSERTION IS NOT ACTIVE, UPDATE DRAWING TOOL
213
- */
214
- if (confirmKeyPressed) {
215
- if (__classPrivateFieldGet(this, _DesktopStrategy_interactionManager, "f").insertionInteractionHandler
216
- .insertionActive) {
217
- this.stopInsertion();
218
- __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").update();
219
- }
220
- else {
221
- __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").update();
222
- }
646
+ /**
647
+ * Provides real-time visual feedback during box selection by updating hover states
648
+ *
649
+ * ## Dynamic Hover Management:
650
+ * 1. **Current intersection**: Calculates which points are currently in the selection box
651
+ * 2. **Hover removal**: Points that left the box lose their hover effect
652
+ * 3. **Hover addition**: Points that entered the box gain hover effect
653
+ * 4. **State preservation**: Maintains existing selection states while adding hover effects
654
+ *
655
+ * ## Visual Feedback:
656
+ * - Points inside selection box show hover material (different color/highlight)
657
+ * - Selected + hovered points show combined visual state
658
+ * - Provides immediate feedback during box drag operation
659
+ *
660
+ * ## Performance Optimization:
661
+ * - Only updates materials for points that changed state
662
+ * - Tracks previous hover state to minimize unnecessary updates
663
+ */
664
+ updateBoxSelectionHover() {
665
+ const points = this.convertPositionArrayToPoints();
666
+ if (points.length === 0) {
667
+ return;
223
668
  }
224
- /**
225
- * IF CANCEL KEY IS PRESSED
226
- * - IF INSERTION IS ACTIVE, STOP INSERTION
227
- * - IF INSERTION IS NOT ACTIVE, CANCEL DRAWING TOOL
228
- */
229
- if (cancelKeyPressed) {
230
- if (__classPrivateFieldGet(this, _DesktopStrategy_interactionManager, "f").insertionInteractionHandler
231
- .insertionActive) {
232
- this.stopInsertion();
233
- }
234
- else {
235
- __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").cancel();
236
- }
669
+ // Get current intersected point indices
670
+ const currentBoxIntersectedIndices = __classPrivateFieldGet(this, _DesktopStrategy_selectionBox, "f").intersectPoints(points);
671
+ // Find points that were previously hovered but are no longer in the box
672
+ const pointsToUnhover = __classPrivateFieldGet(this, _DesktopStrategy_boxHoveredPoints, "f").filter((index) => !currentBoxIntersectedIndices.includes(index));
673
+ // Find points that are newly in the box
674
+ const pointsToHover = currentBoxIntersectedIndices.filter((index) => !__classPrivateFieldGet(this, _DesktopStrategy_boxHoveredPoints, "f").includes(index));
675
+ // Remove hover effect from points no longer in the box
676
+ pointsToUnhover.forEach((index) => {
677
+ const isSelected = __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").selectedPointIndices.includes(index);
678
+ this.updatePointMaterial(index, isSelected, false);
679
+ });
680
+ // Add hover effect to points newly in the box
681
+ pointsToHover.forEach((index) => {
682
+ const isSelected = __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").selectedPointIndices.includes(index);
683
+ this.updatePointMaterial(index, isSelected, true);
684
+ });
685
+ // Update the tracked hovered points
686
+ __classPrivateFieldSet(this, _DesktopStrategy_boxHoveredPoints, currentBoxIntersectedIndices, "f");
687
+ }
688
+ /**
689
+ * Update cursor based on current interaction state
690
+ */
691
+ updateCursor() {
692
+ if (__classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").dragging) {
693
+ document.body.style.cursor = "grabbing";
237
694
  }
238
- /**
239
- * IF INSERT KEY IS PRESSED
240
- * - START INSERTION
241
- */
242
- if (insertKeyPressed) {
243
- this.startInsertion();
695
+ else if (__classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").hoveredPoint !== undefined) {
696
+ document.body.style.cursor = "pointer";
244
697
  }
245
- /**
246
- * IF DELETE KEY IS PRESSED
247
- * - DELETE SELECTION
248
- */
249
- if (deleteKeyPressed) {
250
- __classPrivateFieldGet(this, _DesktopStrategy_interactionManager, "f").deleteSelection();
698
+ else {
699
+ document.body.style.cursor = "default";
251
700
  }
252
701
  }
702
+ /**
703
+ * Update material index for a single point based on its state
704
+ */
705
+ updatePointMaterial(index, isSelected, isHovered) {
706
+ let materialIndex;
707
+ if (isSelected && isHovered) {
708
+ materialIndex = IDrawingToolsManager_1.MATERIAL_INDEX.SELECTED_HOVERED;
709
+ }
710
+ else if (isSelected) {
711
+ materialIndex = IDrawingToolsManager_1.MATERIAL_INDEX.SELECTED;
712
+ }
713
+ else if (isHovered) {
714
+ materialIndex = IDrawingToolsManager_1.MATERIAL_INDEX.HOVERED;
715
+ }
716
+ else {
717
+ materialIndex = IDrawingToolsManager_1.MATERIAL_INDEX.DEFAULT;
718
+ }
719
+ __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").updateMaterialIndex(index, materialIndex);
720
+ }
253
721
  }
254
722
  exports.DesktopStrategy = DesktopStrategy;
255
- _DesktopStrategy_drawingToolsManager = new WeakMap(), _DesktopStrategy_geometryMathManager = new WeakMap(), _DesktopStrategy_insertionInteractionHandler = new WeakMap(), _DesktopStrategy_interactionManager = new WeakMap(), _DesktopStrategy_interactionManagerHelper = new WeakMap(), _DesktopStrategy_midPointInteractionHandler = new WeakMap(), _DesktopStrategy_restrictionManager = new WeakMap(), _DesktopStrategy_viewport = new WeakMap(), _DesktopStrategy_cameraFreezeFlag = new WeakMap(), _DesktopStrategy_lastEvent = new WeakMap(), _DesktopStrategy_onDownPointer = new WeakMap();
723
+ _DesktopStrategy_drawingToolsManager = new WeakMap(), _DesktopStrategy_geometryMathManager = new WeakMap(), _DesktopStrategy_insertionInteractionHandler = new WeakMap(), _DesktopStrategy_interactionManager = new WeakMap(), _DesktopStrategy_interactionManagerHelper = new WeakMap(), _DesktopStrategy_midPointInteractionHandler = new WeakMap(), _DesktopStrategy_restrictionManager = new WeakMap(), _DesktopStrategy_selectionBox = new WeakMap(), _DesktopStrategy_viewport = new WeakMap(), _DesktopStrategy_boxHoveredPoints = new WeakMap(), _DesktopStrategy_cameraFreezeFlag = new WeakMap(), _DesktopStrategy_isBoxSelecting = new WeakMap(), _DesktopStrategy_lastEvent = new WeakMap(), _DesktopStrategy_lastMoveEvent = new WeakMap(), _DesktopStrategy_onDownPointer = new WeakMap(), _DesktopStrategy_instances = new WeakSet(), _DesktopStrategy_updateAllPointMaterials = function _DesktopStrategy_updateAllPointMaterials() {
724
+ if (!__classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray ||
725
+ __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray.length === 0) {
726
+ return;
727
+ }
728
+ const pointCount = __classPrivateFieldGet(this, _DesktopStrategy_drawingToolsManager, "f").positionArray.length /
729
+ DesktopStrategy.COORDINATE_STEP;
730
+ const selectedIndices = __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").selectedPointIndices;
731
+ const hoveredPoint = __classPrivateFieldGet(this, _DesktopStrategy_interactionManagerHelper, "f").hoveredPoint;
732
+ for (let i = 0; i < pointCount; i++) {
733
+ const isSelected = selectedIndices.includes(i);
734
+ const isHovered = hoveredPoint === i;
735
+ this.updatePointMaterial(i, isSelected, isHovered);
736
+ }
737
+ };
738
+ DesktopStrategy.CLICK_THRESHOLD_SQUARED = 25; // 5px threshold squared
739
+ DesktopStrategy.COORDINATE_STEP = 3; // Number of coordinates per point (x, y, z)
256
740
  //# sourceMappingURL=DesktopStrategy.js.map