@2112-lab/central-plant 0.1.39 โ 0.1.41
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.
- package/dist/bundle/index.js +7991 -7054
- package/dist/cjs/src/core/centralPlant.js +48 -3
- package/dist/cjs/src/core/centralPlantInternals.js +75 -566
- package/dist/cjs/src/core/sceneViewer.js +38 -13
- package/dist/cjs/src/index.js +6 -4
- package/dist/cjs/src/managers/components/pathfindingManager.js +75 -60
- package/dist/cjs/src/managers/components/transformOperationsManager.js +929 -0
- package/dist/cjs/src/managers/controls/keyboardControlsManager.js +57 -1
- package/dist/cjs/src/managers/controls/transformControls.js +11 -3
- package/dist/cjs/src/managers/controls/transformControlsManager.js +563 -263
- package/dist/cjs/src/managers/pathfinding/ConnectorManager.js +385 -0
- package/dist/cjs/src/managers/pathfinding/PathIntersectionDetector.js +387 -0
- package/dist/cjs/src/managers/pathfinding/PathRenderingManager.js +401 -0
- package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +378 -0
- package/dist/cjs/src/managers/pathfinding/sceneDataManager.js +256 -0
- package/dist/cjs/src/managers/scene/animationManager.js +145 -0
- package/dist/cjs/src/managers/scene/sceneExportManager.js +14 -13
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +516 -21
- package/dist/cjs/src/managers/scene/sceneTooltipsManager.js +1 -8
- package/dist/cjs/src/managers/system/operationHistoryManager.js +414 -0
- package/dist/cjs/src/managers/system/settingsManager.js +2 -1
- package/dist/cjs/src/utils/objectTypes.js +5 -7
- package/dist/esm/src/core/centralPlant.js +48 -3
- package/dist/esm/src/core/centralPlantInternals.js +76 -567
- package/dist/esm/src/core/sceneViewer.js +38 -13
- package/dist/esm/src/index.js +4 -3
- package/dist/esm/src/managers/components/pathfindingManager.js +75 -60
- package/dist/esm/src/managers/components/transformOperationsManager.js +904 -0
- package/dist/esm/src/managers/controls/keyboardControlsManager.js +57 -1
- package/dist/esm/src/managers/controls/transformControls.js +11 -3
- package/dist/esm/src/managers/controls/transformControlsManager.js +564 -264
- package/dist/esm/src/managers/pathfinding/ConnectorManager.js +361 -0
- package/dist/esm/src/managers/pathfinding/PathIntersectionDetector.js +363 -0
- package/dist/esm/src/managers/pathfinding/PathRenderingManager.js +377 -0
- package/dist/esm/src/managers/pathfinding/pathfindingManager.js +374 -0
- package/dist/esm/src/managers/pathfinding/sceneDataManager.js +232 -0
- package/dist/esm/src/managers/scene/animationManager.js +141 -0
- package/dist/esm/src/managers/scene/sceneExportManager.js +14 -13
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +516 -21
- package/dist/esm/src/managers/scene/sceneTooltipsManager.js +1 -8
- package/dist/esm/src/managers/system/operationHistoryManager.js +409 -0
- package/dist/esm/src/managers/system/settingsManager.js +2 -1
- package/dist/esm/src/utils/objectTypes.js +5 -7
- package/dist/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -16,14 +16,18 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
16
16
|
|
|
17
17
|
// Transform control instance
|
|
18
18
|
this.transformControls = null;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
|
|
20
|
+
// Array of bounding box helpers (one per selected object)
|
|
21
|
+
this.boundingBoxHelpers = [];
|
|
21
22
|
|
|
22
23
|
// Cache for object bounding boxes to improve performance
|
|
23
24
|
this.boundingBoxCache = new WeakMap();
|
|
24
25
|
|
|
25
|
-
//
|
|
26
|
-
this.
|
|
26
|
+
// Array of all selected objects (supports single or multi-selection)
|
|
27
|
+
this.selectedObjects = [];
|
|
28
|
+
|
|
29
|
+
// Group to hold selected objects for transform controls
|
|
30
|
+
this.multiSelectionGroup = null;
|
|
27
31
|
|
|
28
32
|
// Transform mode: 'translate', 'rotate', 'scale'
|
|
29
33
|
this.currentMode = 'translate';
|
|
@@ -121,9 +125,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
121
125
|
this._objectTransformedListener = function (eventData) {
|
|
122
126
|
console.log('๐ฒ TransformControlsManager detected object transformation');
|
|
123
127
|
|
|
124
|
-
//
|
|
125
|
-
if (_this.
|
|
126
|
-
console.log('๐ฒ Updating bounding
|
|
128
|
+
// Update bounding box if the transformed object is in current selection
|
|
129
|
+
if (_this.selectedObjects.includes(eventData.object)) {
|
|
130
|
+
console.log('๐ฒ Updating bounding boxes for selected objects after transform');
|
|
127
131
|
_this.updateBoundingBox();
|
|
128
132
|
}
|
|
129
133
|
};
|
|
@@ -212,13 +216,14 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
212
216
|
this.eventHandlers.transformStart = function () {
|
|
213
217
|
console.log("transformControls transformStart");
|
|
214
218
|
_this2.transformState.isTransforming = true;
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
219
|
+
|
|
220
|
+
// Store initial transforms for all selected objects
|
|
221
|
+
if (_this2.selectedObjects.length > 0 && _this2.multiSelectionGroup) {
|
|
222
|
+
_this2.selectedObjects.forEach(function (obj) {
|
|
223
|
+
obj.userData._multiSelectOriginalPosition = obj.position.clone();
|
|
224
|
+
obj.userData._multiSelectOriginalRotation = obj.rotation.clone();
|
|
225
|
+
obj.userData._multiSelectOriginalScale = obj.scale.clone();
|
|
226
|
+
});
|
|
222
227
|
}
|
|
223
228
|
|
|
224
229
|
// Disable orbit controls during transformation
|
|
@@ -228,7 +233,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
228
233
|
|
|
229
234
|
// Execute callback
|
|
230
235
|
if (_this2.callbacks.onTransformStart) {
|
|
231
|
-
_this2.callbacks.onTransformStart(_this2.
|
|
236
|
+
_this2.callbacks.onTransformStart(_this2.selectedObjects[0] || null, _this2.currentMode);
|
|
232
237
|
}
|
|
233
238
|
console.log("\uD83D\uDD27 Transform started: ".concat(_this2.currentMode, " mode"));
|
|
234
239
|
};
|
|
@@ -242,54 +247,31 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
242
247
|
_this2.orbitControls.enabled = true;
|
|
243
248
|
}
|
|
244
249
|
|
|
245
|
-
//
|
|
246
|
-
if (_this2.
|
|
247
|
-
_this2.
|
|
248
|
-
|
|
249
|
-
rotation: _this2.selectedObject.rotation.clone(),
|
|
250
|
-
scale: _this2.selectedObject.scale.clone()
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
// If centralPlant API is available and we're in translate mode,
|
|
254
|
-
// use the API to apply the translation properly
|
|
255
|
-
// BUT skip API-based translation for pipe segments - they should stay where dragged
|
|
256
|
-
if (_this2.centralPlant && _this2.currentMode === 'translate' && !isSegment(_this2.selectedObject)) {
|
|
257
|
-
_this2.handleTranslateWithAPI();
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Clear bounding box cache for the transformed object to ensure selection uses updated position
|
|
261
|
-
if (_this2.boundingBoxCache.has(_this2.selectedObject)) {
|
|
262
|
-
_this2.boundingBoxCache.delete(_this2.selectedObject);
|
|
263
|
-
}
|
|
250
|
+
// Apply multi-selection transforms (works for single or multiple objects)
|
|
251
|
+
if (_this2.selectedObjects.length > 0 && _this2.multiSelectionGroup) {
|
|
252
|
+
_this2.applyMultiSelectionTransform();
|
|
253
|
+
}
|
|
264
254
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
255
|
+
// Update paths after translation is complete
|
|
256
|
+
// Only if we translated components (not segments/gateways - they handle paths internally)
|
|
257
|
+
if (_this2.currentMode === 'translate' && _this2.sceneViewer && typeof _this2.sceneViewer.updatePaths === 'function') {
|
|
258
|
+
// Check if any of the selected objects are components (not segments or gateways)
|
|
259
|
+
var hasComponents = _this2.selectedObjects.some(function (obj) {
|
|
260
|
+
return !isSegment(obj) && !isGateway(obj);
|
|
261
|
+
});
|
|
262
|
+
if (hasComponents) {
|
|
263
|
+
console.log('๐ Updating paths after component translation...');
|
|
269
264
|
try {
|
|
270
265
|
_this2.sceneViewer.updatePaths();
|
|
271
|
-
console.log('โ
Paths
|
|
266
|
+
console.log('โ
Paths updated successfully after translation');
|
|
272
267
|
} catch (error) {
|
|
273
|
-
console.error('โ Error
|
|
268
|
+
console.error('โ Error updating paths after translation:', error);
|
|
274
269
|
}
|
|
270
|
+
} else {
|
|
271
|
+
console.log('โน๏ธ Skipping updatePaths - segments/gateways handle their own path updates');
|
|
275
272
|
}
|
|
276
273
|
}
|
|
277
274
|
|
|
278
|
-
// Execute callback
|
|
279
|
-
if (_this2.callbacks.onTransformEnd) {
|
|
280
|
-
_this2.callbacks.onTransformEnd(_this2.selectedObject, _this2.transformState.initialTransform, _this2.transformState.currentTransform, _this2.currentMode);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Handle pipe segment transformations (only in translate mode)
|
|
284
|
-
if (_this2.currentMode === 'translate' && isSegment(_this2.selectedObject)) {
|
|
285
|
-
_this2.handlePipeSegmentTransform(_this2.selectedObject);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Handle gateway transformations (only in translate mode)
|
|
289
|
-
if (_this2.currentMode === 'translate' && isGateway(_this2.selectedObject)) {
|
|
290
|
-
_this2.handleGatewayTransform(_this2.selectedObject);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
275
|
// Dispatch custom scene update event after transform completes
|
|
294
276
|
if (typeof window !== 'undefined') {
|
|
295
277
|
var _this2$selectedObject;
|
|
@@ -298,7 +280,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
298
280
|
detail: {
|
|
299
281
|
timestamp: Date.now(),
|
|
300
282
|
transformType: _this2.currentMode,
|
|
301
|
-
objectName: ((_this2$selectedObject = _this2.
|
|
283
|
+
objectName: ((_this2$selectedObject = _this2.selectedObjects[0]) === null || _this2$selectedObject === void 0 ? void 0 : _this2$selectedObject.name) || 'unknown',
|
|
284
|
+
objectCount: _this2.selectedObjects.length
|
|
302
285
|
}
|
|
303
286
|
});
|
|
304
287
|
window.dispatchEvent(sceneCompleteEvent);
|
|
@@ -307,11 +290,18 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
307
290
|
};
|
|
308
291
|
// Transform changing event
|
|
309
292
|
this.eventHandlers.transforming = function () {
|
|
310
|
-
//
|
|
311
|
-
if (_this2.
|
|
312
|
-
_this2.
|
|
293
|
+
// Apply real-time visual transformation to objects during drag
|
|
294
|
+
if (_this2.selectedObjects.length > 0 && _this2.multiSelectionGroup) {
|
|
295
|
+
_this2.applyRealtimeTransform();
|
|
313
296
|
}
|
|
314
297
|
|
|
298
|
+
// Clear the bounding box cache for all selected objects during transformation
|
|
299
|
+
_this2.selectedObjects.forEach(function (obj) {
|
|
300
|
+
if (_this2.boundingBoxCache.has(obj)) {
|
|
301
|
+
_this2.boundingBoxCache.delete(obj);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
315
305
|
// Update bounding box during transformation
|
|
316
306
|
_this2.updateBoundingBox();
|
|
317
307
|
|
|
@@ -322,7 +312,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
322
312
|
detail: {
|
|
323
313
|
timestamp: Date.now(),
|
|
324
314
|
transformType: _this2.currentMode,
|
|
325
|
-
objectName: ((_this2$selectedObject2 = _this2.
|
|
315
|
+
objectName: ((_this2$selectedObject2 = _this2.selectedObjects[0]) === null || _this2$selectedObject2 === void 0 ? void 0 : _this2$selectedObject2.name) || 'unknown',
|
|
326
316
|
isTransforming: true
|
|
327
317
|
}
|
|
328
318
|
});
|
|
@@ -392,6 +382,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
392
382
|
|
|
393
383
|
// Single click handler with double-click detection
|
|
394
384
|
this.eventHandlers.click = function (event) {
|
|
385
|
+
var _targetObject$userDat;
|
|
395
386
|
// Skip if currently transforming
|
|
396
387
|
if (_this4.transformState.isTransforming) {
|
|
397
388
|
return;
|
|
@@ -406,6 +397,36 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
406
397
|
// Find target object using appropriate selection method
|
|
407
398
|
var targetObject = _this4._findTargetObject(raycaster, objectFilter);
|
|
408
399
|
|
|
400
|
+
// Check if shift key is pressed for multi-selection
|
|
401
|
+
var isShiftPressed = event.shiftKey;
|
|
402
|
+
|
|
403
|
+
// Skip selection if no target object found
|
|
404
|
+
if (!targetObject) {
|
|
405
|
+
// Deselect if clicking on empty space (and not holding shift)
|
|
406
|
+
if (!isShiftPressed) {
|
|
407
|
+
_this4.deselectObject();
|
|
408
|
+
}
|
|
409
|
+
_this4.clickTiming.lastClickTime = 0;
|
|
410
|
+
_this4.clickTiming.lastClickedObject = null;
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Skip selection if not a component, gateway, or segment
|
|
415
|
+
var objectType = (_targetObject$userDat = targetObject.userData) === null || _targetObject$userDat === void 0 ? void 0 : _targetObject$userDat.objectType;
|
|
416
|
+
var isValidType = objectType === 'component' || objectType === 'gateway' || objectType === 'segment';
|
|
417
|
+
if (!isValidType) {
|
|
418
|
+
console.log('โ Object excluded from selection:', targetObject.name || targetObject.uuid, 'objectType:', objectType);
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Handle multi-selection with shift key
|
|
423
|
+
if (isShiftPressed) {
|
|
424
|
+
_this4.toggleObjectSelection(targetObject);
|
|
425
|
+
_this4.clickTiming.lastClickTime = currentTime;
|
|
426
|
+
_this4.clickTiming.lastClickedObject = targetObject;
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
409
430
|
// Check if this is a double-click: same object clicked within delay time
|
|
410
431
|
var isSameObject = targetObject === _this4.clickTiming.lastClickedObject;
|
|
411
432
|
var isWithinDelay = timeSinceLastClick < _this4.clickTiming.doubleClickDelay;
|
|
@@ -498,6 +519,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
498
519
|
}, {
|
|
499
520
|
key: "_isValidSelectableObject",
|
|
500
521
|
value: function _isValidSelectableObject(object) {
|
|
522
|
+
var _object$userData;
|
|
501
523
|
// Safety check: ensure object is still valid and in the scene
|
|
502
524
|
if (!object || !object.parent) {
|
|
503
525
|
console.warn('โ ๏ธ Selected object is no longer valid or in scene');
|
|
@@ -509,6 +531,12 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
509
531
|
console.warn('โ Object missing required Three.js properties for transform controls');
|
|
510
532
|
return false;
|
|
511
533
|
}
|
|
534
|
+
|
|
535
|
+
// Check if object has explicit selectable flag set to false
|
|
536
|
+
if (((_object$userData = object.userData) === null || _object$userData === void 0 ? void 0 : _object$userData.selectable) === false) {
|
|
537
|
+
console.warn('โ ๏ธ Object is marked as non-selectable (stub segment)');
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
512
540
|
return true;
|
|
513
541
|
}
|
|
514
542
|
|
|
@@ -548,48 +576,41 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
548
576
|
}, {
|
|
549
577
|
key: "isSelectableObject",
|
|
550
578
|
value: function isSelectableObject(object) {
|
|
551
|
-
var _object$
|
|
579
|
+
var _object$userData2, _object$userData3, _object$userData4, _object$userData5, _object$userData6, _object$userData7, _object$userData8;
|
|
552
580
|
// Basic safety checks
|
|
553
581
|
if (!object || !object.isObject3D) {
|
|
554
582
|
return false;
|
|
555
583
|
}
|
|
556
584
|
|
|
557
|
-
// Debug logging for pipe segments
|
|
558
|
-
if (isSegment(object)) {
|
|
559
|
-
console.log('๐ Found pipe segment in selection check:', object.name, object.userData);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
585
|
// Skip transform controls and their children
|
|
563
586
|
if (object.isTransformControls || object.isTransformControlsPlane || object.isTransformControlsGizmo) {
|
|
564
587
|
return false;
|
|
565
588
|
}
|
|
566
589
|
|
|
567
590
|
// Skip helpers and special objects
|
|
568
|
-
var isHelper = object.isHelper || ((_object$
|
|
569
|
-
var isBaseGround = (_object$
|
|
570
|
-
var isBrickWall = (_object$
|
|
591
|
+
var isHelper = object.isHelper || ((_object$userData2 = object.userData) === null || _object$userData2 === void 0 ? void 0 : _object$userData2.isHelper) || ((_object$userData3 = object.userData) === null || _object$userData3 === void 0 ? void 0 : _object$userData3.isBoundingBox);
|
|
592
|
+
var isBaseGround = (_object$userData4 = object.userData) === null || _object$userData4 === void 0 ? void 0 : _object$userData4.isBaseGround;
|
|
593
|
+
var isBrickWall = (_object$userData5 = object.userData) === null || _object$userData5 === void 0 ? void 0 : _object$userData5.isBrickWall;
|
|
571
594
|
if (isHelper || isBaseGround || isBrickWall || !object.visible) {
|
|
572
595
|
return false;
|
|
573
596
|
}
|
|
574
597
|
|
|
575
|
-
//
|
|
576
|
-
if (
|
|
577
|
-
console.log('โ Polyline parent object excluded from selection:', object.name);
|
|
598
|
+
// Skip segment connectors - they should not be selectable for transformation
|
|
599
|
+
if (((_object$userData6 = object.userData) === null || _object$userData6 === void 0 ? void 0 : _object$userData6.objectType) === 'segment-connector') {
|
|
578
600
|
return false;
|
|
579
601
|
}
|
|
580
602
|
|
|
581
|
-
// Check
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
var isGLBModel = object.name && object.name.includes(' Component');
|
|
603
|
+
// Check if object has explicit selectable flag set to false
|
|
604
|
+
if (((_object$userData7 = object.userData) === null || _object$userData7 === void 0 ? void 0 : _object$userData7.selectable) === false) {
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
586
607
|
|
|
587
|
-
//
|
|
588
|
-
var
|
|
589
|
-
return
|
|
608
|
+
// Allow components, gateways, and segments to be selected
|
|
609
|
+
var objectType = (_object$userData8 = object.userData) === null || _object$userData8 === void 0 ? void 0 : _object$userData8.objectType;
|
|
610
|
+
return objectType === 'component' || objectType === 'gateway' || isSegment(object);
|
|
590
611
|
}
|
|
591
612
|
/**
|
|
592
|
-
* Select an object for transformation
|
|
613
|
+
* Select an object for transformation (with full callbacks including tooltips)
|
|
593
614
|
* @param {THREE.Object3D} object - The object to select
|
|
594
615
|
*/
|
|
595
616
|
}, {
|
|
@@ -599,37 +620,14 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
599
620
|
console.warn('โ ๏ธ Invalid object provided for selection');
|
|
600
621
|
return false;
|
|
601
622
|
}
|
|
602
|
-
this.selectedObject = object;
|
|
603
|
-
|
|
604
|
-
// Force object matrix update to ensure correct transforms
|
|
605
|
-
object.updateMatrixWorld(true);
|
|
606
|
-
|
|
607
|
-
// Refresh bounding box cache for this object
|
|
608
|
-
var updatedBoundingBox = new THREE.Box3().setFromObject(object);
|
|
609
|
-
this.boundingBoxCache.set(object, updatedBoundingBox);
|
|
610
623
|
|
|
611
|
-
//
|
|
612
|
-
this.
|
|
624
|
+
// Clear existing selection and select this object
|
|
625
|
+
this.selectedObjects = [object];
|
|
613
626
|
|
|
614
|
-
// Update
|
|
615
|
-
|
|
616
|
-
this.transformControls.updateInteractionTime();
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// Create and show bounding box if enabled
|
|
620
|
-
this.createBoundingBox(object);
|
|
621
|
-
|
|
622
|
-
// Only enable if not forcing invisibility
|
|
623
|
-
if (!this.forceInvisible) {
|
|
624
|
-
this.transformControls.enabled = this.config.enabled;
|
|
625
|
-
this._showTransformControls();
|
|
626
|
-
} else {
|
|
627
|
-
console.log('๐ Transform controls kept invisible despite object selection');
|
|
628
|
-
this.transformControls.enabled = false;
|
|
629
|
-
this._hideTransformControls();
|
|
630
|
-
}
|
|
627
|
+
// Update the multi-selection display (works for single object too)
|
|
628
|
+
this.updateMultiSelection();
|
|
631
629
|
|
|
632
|
-
// Execute callback
|
|
630
|
+
// Execute callback for tooltips and other UI updates
|
|
633
631
|
if (this.callbacks.onObjectSelect) {
|
|
634
632
|
this.callbacks.onObjectSelect(object);
|
|
635
633
|
}
|
|
@@ -649,56 +647,198 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
649
647
|
console.warn('โ ๏ธ Invalid object provided for selection');
|
|
650
648
|
return false;
|
|
651
649
|
}
|
|
652
|
-
this.selectedObject = object;
|
|
653
650
|
|
|
654
|
-
//
|
|
655
|
-
object
|
|
651
|
+
// Clear existing selection and select this object
|
|
652
|
+
this.selectedObjects = [object];
|
|
653
|
+
|
|
654
|
+
// Update the multi-selection display (works for single object too)
|
|
655
|
+
this.updateMultiSelection();
|
|
656
|
+
|
|
657
|
+
// NOTE: We deliberately do NOT call any callback here
|
|
658
|
+
// This allows transform controls and bounding box to show without triggering tooltips
|
|
659
|
+
|
|
660
|
+
console.log("\uD83C\uDFAF Object selected for transform only: ".concat(object.name || object.uuid));
|
|
661
|
+
return true;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Toggle object selection for multi-selection (shift+click)
|
|
666
|
+
* @param {THREE.Object3D} object - The object to toggle
|
|
667
|
+
*/
|
|
668
|
+
}, {
|
|
669
|
+
key: "toggleObjectSelection",
|
|
670
|
+
value: function toggleObjectSelection(object) {
|
|
671
|
+
if (!object || !object.isObject3D) {
|
|
672
|
+
console.warn('โ ๏ธ Invalid object provided for multi-selection');
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
656
675
|
|
|
657
|
-
//
|
|
658
|
-
var
|
|
659
|
-
|
|
676
|
+
// Check if object is already in selection
|
|
677
|
+
var index = this.selectedObjects.findIndex(function (obj) {
|
|
678
|
+
return obj === object;
|
|
679
|
+
});
|
|
680
|
+
if (index !== -1) {
|
|
681
|
+
// Object is already selected, remove it
|
|
682
|
+
this.selectedObjects.splice(index, 1);
|
|
683
|
+
console.log("\u2796 Removed from selection: ".concat(object.name || object.uuid));
|
|
684
|
+
} else {
|
|
685
|
+
// Object is not selected, add it
|
|
686
|
+
this.selectedObjects.push(object);
|
|
687
|
+
console.log("\u2795 Added to selection: ".concat(object.name || object.uuid));
|
|
688
|
+
}
|
|
660
689
|
|
|
661
|
-
//
|
|
662
|
-
this.
|
|
690
|
+
// Update the multi-selection display
|
|
691
|
+
this.updateMultiSelection();
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Update the multi-selection group and transform controls
|
|
696
|
+
* Works for both single and multiple object selection
|
|
697
|
+
*/
|
|
698
|
+
}, {
|
|
699
|
+
key: "updateMultiSelection",
|
|
700
|
+
value: function updateMultiSelection() {
|
|
701
|
+
if (this.selectedObjects.length === 0) {
|
|
702
|
+
// No objects selected, deselect everything
|
|
703
|
+
this.deselectObject();
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Create/update group for selected objects (even if just one)
|
|
708
|
+
this.createMultiSelectionGroup();
|
|
709
|
+
|
|
710
|
+
// Attach transform controls to the group
|
|
711
|
+
this.transformControls.attach(this.multiSelectionGroup);
|
|
663
712
|
|
|
664
713
|
// Update interaction time to reset delay
|
|
665
714
|
if (this.transformControls.updateInteractionTime) {
|
|
666
715
|
this.transformControls.updateInteractionTime();
|
|
667
716
|
}
|
|
668
717
|
|
|
669
|
-
// Create
|
|
670
|
-
this.
|
|
718
|
+
// Create bounding boxes for all selected objects
|
|
719
|
+
this.createMultiBoundingBox();
|
|
671
720
|
|
|
672
|
-
//
|
|
721
|
+
// Enable transform controls if not forcing invisibility
|
|
673
722
|
if (!this.forceInvisible) {
|
|
674
723
|
this.transformControls.enabled = true;
|
|
675
724
|
this._showTransformControls();
|
|
676
|
-
} else {
|
|
677
|
-
console.log('๐ Transform controls kept invisible despite object selection');
|
|
678
|
-
this.transformControls.enabled = false;
|
|
679
|
-
this._hideTransformControls();
|
|
680
725
|
}
|
|
726
|
+
console.log("\uD83C\uDFAF Selection active: ".concat(this.selectedObjects.length, " object(s)"));
|
|
727
|
+
}
|
|
681
728
|
|
|
682
|
-
|
|
683
|
-
|
|
729
|
+
/**
|
|
730
|
+
* Create or update the multi-selection group
|
|
731
|
+
*/
|
|
732
|
+
}, {
|
|
733
|
+
key: "createMultiSelectionGroup",
|
|
734
|
+
value: function createMultiSelectionGroup() {
|
|
735
|
+
// Remove existing group if it exists
|
|
736
|
+
if (this.multiSelectionGroup) {
|
|
737
|
+
this.scene.remove(this.multiSelectionGroup);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// Create new group
|
|
741
|
+
this.multiSelectionGroup = new THREE.Group();
|
|
742
|
+
this.multiSelectionGroup.name = 'MultiSelectionGroup';
|
|
743
|
+
this.multiSelectionGroup.userData = {
|
|
744
|
+
isMultiSelectionGroup: true
|
|
745
|
+
};
|
|
684
746
|
|
|
685
|
-
|
|
686
|
-
|
|
747
|
+
// Calculate the centroid of all selected objects
|
|
748
|
+
var centroid = new THREE.Vector3();
|
|
749
|
+
this.selectedObjects.forEach(function (obj) {
|
|
750
|
+
var worldPos = new THREE.Vector3();
|
|
751
|
+
obj.getWorldPosition(worldPos);
|
|
752
|
+
centroid.add(worldPos);
|
|
753
|
+
});
|
|
754
|
+
centroid.divideScalar(this.selectedObjects.length);
|
|
755
|
+
|
|
756
|
+
// Position the group at the centroid
|
|
757
|
+
this.multiSelectionGroup.position.copy(centroid);
|
|
758
|
+
|
|
759
|
+
// Add group to scene
|
|
760
|
+
this.scene.add(this.multiSelectionGroup);
|
|
761
|
+
|
|
762
|
+
// Store original position, rotation, and scale for each object
|
|
763
|
+
// Note: We don't store the parent reference to avoid circular JSON issues
|
|
764
|
+
this.selectedObjects.forEach(function (obj) {
|
|
765
|
+
// Store local transforms (for final API calls)
|
|
766
|
+
obj.userData._multiSelectOriginalPosition = obj.position.clone();
|
|
767
|
+
obj.userData._multiSelectOriginalRotation = obj.rotation.clone();
|
|
768
|
+
obj.userData._multiSelectOriginalScale = obj.scale.clone();
|
|
769
|
+
|
|
770
|
+
// Store world position (for real-time visual updates)
|
|
771
|
+
var worldPos = new THREE.Vector3();
|
|
772
|
+
obj.getWorldPosition(worldPos);
|
|
773
|
+
obj.userData._multiSelectOriginalWorldPosition = worldPos;
|
|
774
|
+
});
|
|
775
|
+
console.log("\uD83D\uDCE6 Multi-selection group created at centroid:", centroid.toArray());
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Create a bounding box that encompasses all selected objects
|
|
780
|
+
*/
|
|
781
|
+
}, {
|
|
782
|
+
key: "createMultiBoundingBox",
|
|
783
|
+
value:
|
|
784
|
+
/**
|
|
785
|
+
* Create bounding boxes for all selected objects
|
|
786
|
+
*/
|
|
787
|
+
function createMultiBoundingBox() {
|
|
788
|
+
var _this5 = this;
|
|
789
|
+
// Skip if bounding box is disabled
|
|
790
|
+
if (!this.config.showBoundingBox) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Remove any existing bounding boxes first
|
|
795
|
+
this.removeBoundingBox();
|
|
796
|
+
if (this.selectedObjects.length === 0) {
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
try {
|
|
800
|
+
// Create individual bounding boxes for each selected object
|
|
801
|
+
this.selectedObjects.forEach(function (obj) {
|
|
802
|
+
var boundingBoxHelper = new THREE.BoxHelper(obj, _this5.config.boundingBoxColor);
|
|
803
|
+
|
|
804
|
+
// Mark it as a helper to avoid selection
|
|
805
|
+
boundingBoxHelper.isHelper = true;
|
|
806
|
+
boundingBoxHelper.userData = {
|
|
807
|
+
isBoundingBox: true
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
// Add to scene
|
|
811
|
+
_this5.scene.add(boundingBoxHelper);
|
|
812
|
+
|
|
813
|
+
// Store in array for later cleanup
|
|
814
|
+
_this5.boundingBoxHelpers.push(boundingBoxHelper);
|
|
815
|
+
});
|
|
816
|
+
console.log("\uD83D\uDCE6 Bounding boxes created for ".concat(this.selectedObjects.length, " object(s)"));
|
|
817
|
+
} catch (error) {
|
|
818
|
+
console.warn('โ ๏ธ Failed to create bounding boxes:', error);
|
|
819
|
+
}
|
|
687
820
|
}
|
|
688
821
|
|
|
689
822
|
/**
|
|
690
|
-
*
|
|
823
|
+
* Remove all bounding box helpers
|
|
691
824
|
*/
|
|
692
825
|
}, {
|
|
693
826
|
key: "deselectObject",
|
|
694
|
-
value:
|
|
695
|
-
|
|
696
|
-
|
|
827
|
+
value:
|
|
828
|
+
/**
|
|
829
|
+
* Deselect all currently selected objects
|
|
830
|
+
*/
|
|
831
|
+
function deselectObject() {
|
|
832
|
+
if (this.selectedObjects.length > 0) {
|
|
833
|
+
console.log("\uD83D\uDD04 Objects deselected: ".concat(this.selectedObjects.length));
|
|
697
834
|
}
|
|
698
835
|
|
|
699
|
-
//
|
|
836
|
+
// Clear multi-selection
|
|
837
|
+
this.clearMultiSelection();
|
|
838
|
+
|
|
839
|
+
// Remove bounding boxes
|
|
700
840
|
this.removeBoundingBox();
|
|
701
|
-
|
|
841
|
+
|
|
702
842
|
// Detach and hide transform controls
|
|
703
843
|
if (this.transformControls) {
|
|
704
844
|
// First detach from object
|
|
@@ -717,94 +857,97 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
717
857
|
}
|
|
718
858
|
|
|
719
859
|
/**
|
|
720
|
-
*
|
|
721
|
-
* @param {THREE.Object3D} object - The object to create a bounding box for
|
|
860
|
+
* Clear selection and restore original object states
|
|
722
861
|
*/
|
|
723
862
|
}, {
|
|
724
|
-
key: "
|
|
725
|
-
value: function
|
|
726
|
-
//
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
863
|
+
key: "clearMultiSelection",
|
|
864
|
+
value: function clearMultiSelection() {
|
|
865
|
+
// Clean up userData for selected objects
|
|
866
|
+
this.selectedObjects.forEach(function (obj) {
|
|
867
|
+
if (obj.userData._multiSelectOriginalPosition) {
|
|
868
|
+
delete obj.userData._multiSelectOriginalPosition;
|
|
869
|
+
delete obj.userData._multiSelectOriginalRotation;
|
|
870
|
+
delete obj.userData._multiSelectOriginalScale;
|
|
871
|
+
delete obj.userData._multiSelectOriginalWorldPosition;
|
|
872
|
+
}
|
|
873
|
+
});
|
|
730
874
|
|
|
731
|
-
// Remove
|
|
732
|
-
this.
|
|
733
|
-
|
|
734
|
-
|
|
875
|
+
// Remove selection group from scene
|
|
876
|
+
if (this.multiSelectionGroup) {
|
|
877
|
+
this.scene.remove(this.multiSelectionGroup);
|
|
878
|
+
this.multiSelectionGroup = null;
|
|
735
879
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
this.boundingBoxHelper.userData = {
|
|
743
|
-
isBoundingBox: true
|
|
744
|
-
};
|
|
745
|
-
console.log("this.boundingBoxHelper object:", object);
|
|
746
|
-
|
|
747
|
-
// Add to scene
|
|
748
|
-
this.scene.add(this.boundingBoxHelper);
|
|
749
|
-
console.log("\uD83D\uDCE6 Bounding box created for: ".concat(object.name || object.uuid));
|
|
750
|
-
} catch (error) {
|
|
751
|
-
console.warn('โ ๏ธ Failed to create bounding box:', error);
|
|
880
|
+
|
|
881
|
+
// Clear selection array
|
|
882
|
+
var count = this.selectedObjects.length;
|
|
883
|
+
this.selectedObjects = [];
|
|
884
|
+
if (count > 0) {
|
|
885
|
+
console.log("\uD83E\uDDF9 Cleared selection (".concat(count, " object(s))"));
|
|
752
886
|
}
|
|
753
887
|
}
|
|
754
|
-
|
|
755
|
-
/**
|
|
756
|
-
* Remove the current bounding box helper
|
|
757
|
-
*/
|
|
758
888
|
}, {
|
|
759
889
|
key: "removeBoundingBox",
|
|
760
890
|
value: function removeBoundingBox() {
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
891
|
+
// Remove all bounding box helpers
|
|
892
|
+
if (this.boundingBoxHelpers.length > 0) {
|
|
893
|
+
this.boundingBoxHelpers.forEach(function (helper) {
|
|
894
|
+
try {
|
|
895
|
+
// Remove from scene
|
|
896
|
+
if (helper.parent) {
|
|
897
|
+
helper.parent.remove(helper);
|
|
898
|
+
}
|
|
767
899
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
900
|
+
// Dispose geometry and material if they exist
|
|
901
|
+
if (helper.geometry) {
|
|
902
|
+
helper.geometry.dispose();
|
|
903
|
+
}
|
|
904
|
+
if (helper.material) {
|
|
905
|
+
helper.material.dispose();
|
|
906
|
+
}
|
|
907
|
+
} catch (error) {
|
|
908
|
+
console.warn('โ ๏ธ Error removing bounding box helper:', error);
|
|
774
909
|
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
910
|
+
});
|
|
911
|
+
var count = this.boundingBoxHelpers.length;
|
|
912
|
+
this.boundingBoxHelpers = [];
|
|
913
|
+
if (count > 0) {
|
|
914
|
+
console.log("\uD83D\uDCE6 Removed ".concat(count, " bounding box(es)"));
|
|
780
915
|
}
|
|
781
916
|
}
|
|
782
917
|
}
|
|
783
918
|
|
|
784
919
|
/**
|
|
785
|
-
* Update the bounding
|
|
786
|
-
* Call this after any transformation to keep the bounding
|
|
920
|
+
* Update the bounding boxes to match the current object states
|
|
921
|
+
* Call this after any transformation to keep the bounding boxes in sync
|
|
787
922
|
*/
|
|
788
923
|
}, {
|
|
789
924
|
key: "updateBoundingBox",
|
|
790
925
|
value: function updateBoundingBox() {
|
|
791
|
-
|
|
926
|
+
var _this6 = this;
|
|
927
|
+
// Update bounding boxes for all selected objects
|
|
928
|
+
if (this.selectedObjects.length > 0 && this.boundingBoxHelpers.length > 0) {
|
|
792
929
|
try {
|
|
793
|
-
//
|
|
794
|
-
this.
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
930
|
+
// Update each bounding box helper
|
|
931
|
+
this.boundingBoxHelpers.forEach(function (helper, index) {
|
|
932
|
+
var obj = _this6.selectedObjects[index];
|
|
933
|
+
if (obj) {
|
|
934
|
+
// Force object matrix update to ensure correct bounding box
|
|
935
|
+
obj.updateMatrixWorld(true);
|
|
936
|
+
|
|
937
|
+
// Update bounding box
|
|
938
|
+
helper.update();
|
|
939
|
+
|
|
940
|
+
// Also update the cached bounding box if it exists
|
|
941
|
+
if (_this6.boundingBoxCache.has(obj)) {
|
|
942
|
+
var updatedBoundingBox = new THREE.Box3().setFromObject(obj);
|
|
943
|
+
_this6.boundingBoxCache.set(obj, updatedBoundingBox);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
});
|
|
804
947
|
} catch (error) {
|
|
805
|
-
console.warn('โ ๏ธ Error updating bounding
|
|
806
|
-
// If update fails, recreate the bounding
|
|
807
|
-
this.
|
|
948
|
+
console.warn('โ ๏ธ Error updating bounding boxes:', error);
|
|
949
|
+
// If update fails, recreate the bounding boxes
|
|
950
|
+
this.createMultiBoundingBox();
|
|
808
951
|
}
|
|
809
952
|
}
|
|
810
953
|
}
|
|
@@ -906,33 +1049,34 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
906
1049
|
key: "setEnabled",
|
|
907
1050
|
value: function setEnabled(enabled) {
|
|
908
1051
|
this.config.enabled = enabled;
|
|
909
|
-
if (this.
|
|
1052
|
+
if (this.selectedObjects.length > 0) {
|
|
910
1053
|
this.transformControls.enabled = enabled;
|
|
911
1054
|
}
|
|
912
1055
|
console.log("\uD83D\uDD04 Transform controls ".concat(enabled ? 'enabled' : 'disabled'));
|
|
913
1056
|
}
|
|
914
1057
|
|
|
915
1058
|
/**
|
|
916
|
-
* Get world transformation data for the selected object
|
|
1059
|
+
* Get world transformation data for the first selected object
|
|
917
1060
|
* @returns {Object} World transformation data
|
|
918
1061
|
*/
|
|
919
1062
|
}, {
|
|
920
1063
|
key: "getWorldTransformData",
|
|
921
1064
|
value: function getWorldTransformData() {
|
|
922
|
-
if (
|
|
1065
|
+
if (this.selectedObjects.length === 0) {
|
|
923
1066
|
return null;
|
|
924
1067
|
}
|
|
1068
|
+
var selectedObject = this.selectedObjects[0];
|
|
925
1069
|
|
|
926
1070
|
// Ensure the object's world matrix is up to date
|
|
927
|
-
|
|
1071
|
+
selectedObject.updateMatrixWorld(true);
|
|
928
1072
|
|
|
929
1073
|
// Get world position
|
|
930
1074
|
var worldPosition = new THREE.Vector3();
|
|
931
|
-
|
|
1075
|
+
selectedObject.getWorldPosition(worldPosition);
|
|
932
1076
|
|
|
933
1077
|
// Get world quaternion
|
|
934
1078
|
var worldQuaternion = new THREE.Quaternion();
|
|
935
|
-
|
|
1079
|
+
selectedObject.getWorldQuaternion(worldQuaternion);
|
|
936
1080
|
|
|
937
1081
|
// Convert quaternion to Euler rotation
|
|
938
1082
|
var worldRotation = new THREE.Euler();
|
|
@@ -940,7 +1084,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
940
1084
|
|
|
941
1085
|
// Get world scale
|
|
942
1086
|
var worldScale = new THREE.Vector3();
|
|
943
|
-
|
|
1087
|
+
selectedObject.getWorldScale(worldScale);
|
|
944
1088
|
return {
|
|
945
1089
|
position: worldPosition,
|
|
946
1090
|
rotation: worldRotation,
|
|
@@ -959,11 +1103,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
959
1103
|
key: "updateObjectTransform",
|
|
960
1104
|
value: function updateObjectTransform(type, axis, value) {
|
|
961
1105
|
var useWorldCoords = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
962
|
-
if (
|
|
1106
|
+
if (this.selectedObjects.length === 0) {
|
|
963
1107
|
console.warn('โ ๏ธ No object selected for transformation');
|
|
964
1108
|
return;
|
|
965
1109
|
}
|
|
966
|
-
var object = this.
|
|
1110
|
+
var object = this.selectedObjects[0];
|
|
967
1111
|
var numericValue = parseFloat(value);
|
|
968
1112
|
if (isNaN(numericValue)) {
|
|
969
1113
|
console.warn('โ ๏ธ Invalid numeric value for transform:', value);
|
|
@@ -989,7 +1133,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
989
1133
|
console.warn("\u26A0\uFE0F Unknown transform type: ".concat(type));
|
|
990
1134
|
return;
|
|
991
1135
|
}
|
|
992
|
-
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// Update transform controls to reflect the change
|
|
993
1139
|
if (this.transformControls) {
|
|
994
1140
|
this.transformControls.updateMatrixWorld();
|
|
995
1141
|
}
|
|
@@ -1117,13 +1263,13 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1117
1263
|
}, {
|
|
1118
1264
|
key: "getSelectableObjectsWithBounds",
|
|
1119
1265
|
value: function getSelectableObjectsWithBounds() {
|
|
1120
|
-
var
|
|
1266
|
+
var _this7 = this;
|
|
1121
1267
|
var objectFilter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
1122
1268
|
var objectsWithBounds = [];
|
|
1123
1269
|
|
|
1124
1270
|
// Traverse scene to find selectable objects
|
|
1125
1271
|
this.scene.traverse(function (object) {
|
|
1126
|
-
var _object$
|
|
1272
|
+
var _object$userData9, _object$userData0;
|
|
1127
1273
|
// Skip invalid objects and helpers early
|
|
1128
1274
|
if (!object || !object.isObject3D) {
|
|
1129
1275
|
return;
|
|
@@ -1135,25 +1281,25 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1135
1281
|
}
|
|
1136
1282
|
|
|
1137
1283
|
// Skip other helpers and special objects
|
|
1138
|
-
if (object.isHelper || (_object$
|
|
1284
|
+
if (object.isHelper || (_object$userData9 = object.userData) !== null && _object$userData9 !== void 0 && _object$userData9.isHelper || (_object$userData0 = object.userData) !== null && _object$userData0 !== void 0 && _object$userData0.isBoundingBox) {
|
|
1139
1285
|
return;
|
|
1140
1286
|
}
|
|
1141
1287
|
try {
|
|
1142
1288
|
// Apply filter (use provided filter or default isSelectableObject method)
|
|
1143
|
-
var isSelectable = objectFilter ? objectFilter(object) :
|
|
1289
|
+
var isSelectable = objectFilter ? objectFilter(object) : _this7.isSelectableObject(object);
|
|
1144
1290
|
if (isSelectable) {
|
|
1145
1291
|
// Force object matrix update to ensure correct bounding box
|
|
1146
1292
|
object.updateMatrixWorld(true);
|
|
1147
1293
|
|
|
1148
1294
|
// Get or compute bounding box
|
|
1149
|
-
var boundingBox =
|
|
1295
|
+
var boundingBox = _this7.boundingBoxCache.get(object);
|
|
1150
1296
|
|
|
1151
1297
|
// Always recompute bounding box for recently transformed objects
|
|
1152
1298
|
// or if no cached bounding box exists
|
|
1153
|
-
if (!boundingBox || object
|
|
1299
|
+
if (!boundingBox || _this7.selectedObjects.includes(object)) {
|
|
1154
1300
|
// Compute and cache bounding box
|
|
1155
1301
|
boundingBox = new THREE.Box3().setFromObject(object);
|
|
1156
|
-
|
|
1302
|
+
_this7.boundingBoxCache.set(object, boundingBox);
|
|
1157
1303
|
}
|
|
1158
1304
|
objectsWithBounds.push({
|
|
1159
1305
|
object: object,
|
|
@@ -1215,60 +1361,216 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1215
1361
|
}
|
|
1216
1362
|
|
|
1217
1363
|
/**
|
|
1218
|
-
*
|
|
1219
|
-
* This
|
|
1220
|
-
* then uses the centralPlant.translate() API to apply the change properly
|
|
1364
|
+
* Apply real-time visual transformation during drag (no API calls)
|
|
1365
|
+
* This updates the object positions/rotations visually while the user is dragging
|
|
1221
1366
|
*/
|
|
1222
1367
|
}, {
|
|
1223
|
-
key: "
|
|
1224
|
-
value: function
|
|
1225
|
-
var
|
|
1226
|
-
if (!this.
|
|
1227
|
-
console.warn('โ ๏ธ Cannot handle translate with API: missing required state');
|
|
1368
|
+
key: "applyRealtimeTransform",
|
|
1369
|
+
value: function applyRealtimeTransform() {
|
|
1370
|
+
var _this8 = this;
|
|
1371
|
+
if (!this.multiSelectionGroup || this.selectedObjects.length === 0) {
|
|
1228
1372
|
return;
|
|
1229
1373
|
}
|
|
1230
1374
|
|
|
1231
|
-
// Calculate the
|
|
1232
|
-
var
|
|
1233
|
-
var
|
|
1234
|
-
var deltaZ = this.transformState.currentTransform.position.z - this.transformState.initialTransform.position.z;
|
|
1375
|
+
// Calculate the transformation delta from the group
|
|
1376
|
+
var groupPosition = this.multiSelectionGroup.position.clone();
|
|
1377
|
+
var groupRotation = this.multiSelectionGroup.rotation.clone();
|
|
1235
1378
|
|
|
1236
|
-
//
|
|
1237
|
-
|
|
1238
|
-
this.
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
deltaZ: deltaZ
|
|
1379
|
+
// Get the original centroid position (from when group was created)
|
|
1380
|
+
var originalCentroid = new THREE.Vector3();
|
|
1381
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1382
|
+
var originalWorldPos = obj.userData._multiSelectOriginalWorldPosition;
|
|
1383
|
+
if (originalWorldPos) {
|
|
1384
|
+
originalCentroid.add(originalWorldPos);
|
|
1385
|
+
}
|
|
1244
1386
|
});
|
|
1387
|
+
originalCentroid.divideScalar(this.selectedObjects.length);
|
|
1245
1388
|
|
|
1246
|
-
//
|
|
1247
|
-
var
|
|
1248
|
-
|
|
1249
|
-
|
|
1389
|
+
// Calculate deltas
|
|
1390
|
+
var positionDelta = groupPosition.clone().sub(originalCentroid);
|
|
1391
|
+
var rotationDelta = groupRotation.clone();
|
|
1392
|
+
|
|
1393
|
+
// Apply transformation to each selected object visually
|
|
1394
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1395
|
+
var originalWorldPos = obj.userData._multiSelectOriginalWorldPosition;
|
|
1396
|
+
var originalRot = obj.userData._multiSelectOriginalRotation;
|
|
1397
|
+
if (!originalWorldPos || !originalRot) {
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
if (_this8.currentMode === 'translate') {
|
|
1401
|
+
// Simple translation: original world position + delta
|
|
1402
|
+
var newWorldPos = originalWorldPos.clone().add(positionDelta);
|
|
1403
|
+
|
|
1404
|
+
// Convert to local position if object has a parent
|
|
1405
|
+
if (obj.parent && obj.parent !== _this8.scene) {
|
|
1406
|
+
// Update parent matrix if parent is also being transformed
|
|
1407
|
+
obj.parent.updateMatrixWorld(true);
|
|
1408
|
+
var parentMatrixInverse = new THREE.Matrix4();
|
|
1409
|
+
parentMatrixInverse.copy(obj.parent.matrixWorld).invert();
|
|
1410
|
+
newWorldPos.applyMatrix4(parentMatrixInverse);
|
|
1411
|
+
}
|
|
1412
|
+
obj.position.copy(newWorldPos);
|
|
1413
|
+
obj.updateMatrix();
|
|
1414
|
+
} else if (_this8.currentMode === 'rotate') {
|
|
1415
|
+
// Calculate offset from centroid
|
|
1416
|
+
var offsetFromCentroid = originalWorldPos.clone().sub(originalCentroid);
|
|
1417
|
+
|
|
1418
|
+
// Rotate the offset vector
|
|
1419
|
+
var rotatedOffset = offsetFromCentroid.clone();
|
|
1420
|
+
var rotationQuat = new THREE.Quaternion().setFromEuler(rotationDelta);
|
|
1421
|
+
rotatedOffset.applyQuaternion(rotationQuat);
|
|
1422
|
+
|
|
1423
|
+
// Calculate new world position
|
|
1424
|
+
var _newWorldPos = originalCentroid.clone().add(rotatedOffset).add(positionDelta);
|
|
1425
|
+
|
|
1426
|
+
// Convert to local position
|
|
1427
|
+
if (obj.parent && obj.parent !== _this8.scene) {
|
|
1428
|
+
// Update parent matrix if parent is also being transformed
|
|
1429
|
+
obj.parent.updateMatrixWorld(true);
|
|
1430
|
+
var _parentMatrixInverse = new THREE.Matrix4();
|
|
1431
|
+
_parentMatrixInverse.copy(obj.parent.matrixWorld).invert();
|
|
1432
|
+
_newWorldPos.applyMatrix4(_parentMatrixInverse);
|
|
1433
|
+
}
|
|
1434
|
+
obj.position.copy(_newWorldPos);
|
|
1435
|
+
|
|
1436
|
+
// Apply rotation to the object itself
|
|
1437
|
+
obj.rotation.x = originalRot.x + rotationDelta.x;
|
|
1438
|
+
obj.rotation.y = originalRot.y + rotationDelta.y;
|
|
1439
|
+
obj.rotation.z = originalRot.z + rotationDelta.z;
|
|
1440
|
+
obj.updateMatrix();
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// Mark world matrix as needing update (will propagate to children)
|
|
1444
|
+
obj.matrixWorldNeedsUpdate = true;
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
/**
|
|
1449
|
+
* Apply transformation from multi-selection group to all selected objects
|
|
1450
|
+
* Simple approach: calculate delta once, apply to each object via API
|
|
1451
|
+
*/
|
|
1452
|
+
}, {
|
|
1453
|
+
key: "applyMultiSelectionTransform",
|
|
1454
|
+
value: function applyMultiSelectionTransform() {
|
|
1455
|
+
var _this9 = this;
|
|
1456
|
+
if (!this.multiSelectionGroup || this.selectedObjects.length === 0) {
|
|
1250
1457
|
return;
|
|
1251
1458
|
}
|
|
1459
|
+
console.log("\uD83D\uDD27 Applying multi-selection transform to ".concat(this.selectedObjects.length, " objects"));
|
|
1252
1460
|
|
|
1253
|
-
//
|
|
1254
|
-
|
|
1461
|
+
// Calculate the transformation delta from the group
|
|
1462
|
+
var groupPosition = this.multiSelectionGroup.position.clone();
|
|
1463
|
+
|
|
1464
|
+
// Get the original centroid position (from when group was created)
|
|
1465
|
+
var originalCentroid = new THREE.Vector3();
|
|
1466
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1467
|
+
var originalWorldPos = obj.userData._multiSelectOriginalWorldPosition;
|
|
1468
|
+
if (originalWorldPos) {
|
|
1469
|
+
originalCentroid.add(originalWorldPos);
|
|
1470
|
+
}
|
|
1471
|
+
});
|
|
1472
|
+
originalCentroid.divideScalar(this.selectedObjects.length);
|
|
1473
|
+
|
|
1474
|
+
// Calculate position delta - this is the same for ALL objects
|
|
1475
|
+
var positionDelta = groupPosition.clone().sub(originalCentroid);
|
|
1476
|
+
|
|
1477
|
+
// Round deltas to avoid floating point precision issues
|
|
1478
|
+
var deltaX = Math.round(positionDelta.x * 2) / 2;
|
|
1479
|
+
var deltaY = Math.round(positionDelta.y * 2) / 2;
|
|
1480
|
+
var deltaZ = Math.round(positionDelta.z * 2) / 2;
|
|
1481
|
+
console.log('๐ง Transform delta:', {
|
|
1482
|
+
deltaX: deltaX,
|
|
1483
|
+
deltaY: deltaY,
|
|
1484
|
+
deltaZ: deltaZ
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
// Only process if there's a meaningful translation
|
|
1255
1488
|
var threshold = 0.001;
|
|
1256
|
-
if (
|
|
1257
|
-
//
|
|
1258
|
-
|
|
1259
|
-
this.
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
this.
|
|
1270
|
-
|
|
1271
|
-
|
|
1489
|
+
if (this.currentMode === 'translate' && positionDelta.length() > threshold) {
|
|
1490
|
+
// FIRST: Reset all objects to their original positions
|
|
1491
|
+
// This undoes the visual transform applied during drag
|
|
1492
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1493
|
+
var originalPos = obj.userData._multiSelectOriginalPosition;
|
|
1494
|
+
if (originalPos) {
|
|
1495
|
+
obj.position.copy(originalPos);
|
|
1496
|
+
obj.updateMatrixWorld(true);
|
|
1497
|
+
}
|
|
1498
|
+
});
|
|
1499
|
+
console.log('๐ Reset objects to original positions before API calls');
|
|
1500
|
+
|
|
1501
|
+
// THEN: Apply the delta to each object using the appropriate API
|
|
1502
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1503
|
+
var _obj$userData;
|
|
1504
|
+
if (!_this9.centralPlant) {
|
|
1505
|
+
console.warn('โ ๏ธ CentralPlant API not available');
|
|
1506
|
+
return;
|
|
1507
|
+
}
|
|
1508
|
+
var componentId = obj.uuid || ((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.originalUuid);
|
|
1509
|
+
if (isSegment(obj)) {
|
|
1510
|
+
// Use translateSegment API
|
|
1511
|
+
if (Math.abs(deltaX) > threshold) {
|
|
1512
|
+
_this9.centralPlant.translateSegment(componentId, 'x', deltaX);
|
|
1513
|
+
}
|
|
1514
|
+
if (Math.abs(deltaY) > threshold) {
|
|
1515
|
+
_this9.centralPlant.translateSegment(componentId, 'y', deltaY);
|
|
1516
|
+
}
|
|
1517
|
+
if (Math.abs(deltaZ) > threshold) {
|
|
1518
|
+
_this9.centralPlant.translateSegment(componentId, 'z', deltaZ);
|
|
1519
|
+
}
|
|
1520
|
+
console.log("\uD83D\uDCE6 Segment ".concat(obj.name, " translated:"), {
|
|
1521
|
+
deltaX: deltaX,
|
|
1522
|
+
deltaY: deltaY,
|
|
1523
|
+
deltaZ: deltaZ
|
|
1524
|
+
});
|
|
1525
|
+
} else if (isGateway(obj)) {
|
|
1526
|
+
// Use translateGateway API
|
|
1527
|
+
if (Math.abs(deltaX) > threshold) {
|
|
1528
|
+
_this9.centralPlant.translateGateway(componentId, 'x', deltaX);
|
|
1529
|
+
}
|
|
1530
|
+
if (Math.abs(deltaY) > threshold) {
|
|
1531
|
+
_this9.centralPlant.translateGateway(componentId, 'y', deltaY);
|
|
1532
|
+
}
|
|
1533
|
+
if (Math.abs(deltaZ) > threshold) {
|
|
1534
|
+
_this9.centralPlant.translateGateway(componentId, 'z', deltaZ);
|
|
1535
|
+
}
|
|
1536
|
+
console.log("\uD83D\uDEAA Gateway ".concat(obj.name, " translated:"), {
|
|
1537
|
+
deltaX: deltaX,
|
|
1538
|
+
deltaY: deltaY,
|
|
1539
|
+
deltaZ: deltaZ
|
|
1540
|
+
});
|
|
1541
|
+
} else {
|
|
1542
|
+
// Use standard translate API for components
|
|
1543
|
+
if (Math.abs(deltaX) > threshold) {
|
|
1544
|
+
_this9.centralPlant.translate(componentId, 'x', deltaX);
|
|
1545
|
+
}
|
|
1546
|
+
if (Math.abs(deltaY) > threshold) {
|
|
1547
|
+
_this9.centralPlant.translate(componentId, 'y', deltaY);
|
|
1548
|
+
}
|
|
1549
|
+
if (Math.abs(deltaZ) > threshold) {
|
|
1550
|
+
_this9.centralPlant.translate(componentId, 'z', deltaZ);
|
|
1551
|
+
}
|
|
1552
|
+
console.log("\uD83D\uDD27 Component ".concat(obj.name, " translated:"), {
|
|
1553
|
+
deltaX: deltaX,
|
|
1554
|
+
deltaY: deltaY,
|
|
1555
|
+
deltaZ: deltaZ
|
|
1556
|
+
});
|
|
1557
|
+
}
|
|
1558
|
+
});
|
|
1559
|
+
console.log("\u2705 All ".concat(this.selectedObjects.length, " objects translated with delta:"), {
|
|
1560
|
+
deltaX: deltaX,
|
|
1561
|
+
deltaY: deltaY,
|
|
1562
|
+
deltaZ: deltaZ
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
// Reset the multi-selection group transform
|
|
1567
|
+
this.multiSelectionGroup.position.set(0, 0, 0);
|
|
1568
|
+
this.multiSelectionGroup.rotation.set(0, 0, 0);
|
|
1569
|
+
this.multiSelectionGroup.scale.set(1, 1, 1);
|
|
1570
|
+
|
|
1571
|
+
// Update the multi-selection display with new positions
|
|
1572
|
+
this.updateMultiSelection();
|
|
1573
|
+
console.log("\u2705 Multi-selection transform applied");
|
|
1272
1574
|
}
|
|
1273
1575
|
|
|
1274
1576
|
/**
|
|
@@ -1462,10 +1764,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1462
1764
|
// Remove bounding box helper
|
|
1463
1765
|
this.removeBoundingBox();
|
|
1464
1766
|
|
|
1465
|
-
//
|
|
1466
|
-
|
|
1467
|
-
this.deselectObject();
|
|
1468
|
-
}
|
|
1767
|
+
// Clear multi-selection
|
|
1768
|
+
this.clearMultiSelection();
|
|
1469
1769
|
|
|
1470
1770
|
// Dispose transform controls
|
|
1471
1771
|
if (this.transformControls) {
|
|
@@ -1494,7 +1794,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1494
1794
|
}
|
|
1495
1795
|
|
|
1496
1796
|
// Clear references - but keep scene, camera, and renderer references for reuse
|
|
1497
|
-
this.
|
|
1797
|
+
this.selectedObjects = [];
|
|
1498
1798
|
// Don't null these out: this.scene, this.camera, this.renderer
|
|
1499
1799
|
this.orbitControls = null;
|
|
1500
1800
|
console.log('๐งน Transform controls disposed');
|