@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
|
@@ -40,14 +40,18 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
40
40
|
|
|
41
41
|
// Transform control instance
|
|
42
42
|
this.transformControls = null;
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
|
|
44
|
+
// Array of bounding box helpers (one per selected object)
|
|
45
|
+
this.boundingBoxHelpers = [];
|
|
45
46
|
|
|
46
47
|
// Cache for object bounding boxes to improve performance
|
|
47
48
|
this.boundingBoxCache = new WeakMap();
|
|
48
49
|
|
|
49
|
-
//
|
|
50
|
-
this.
|
|
50
|
+
// Array of all selected objects (supports single or multi-selection)
|
|
51
|
+
this.selectedObjects = [];
|
|
52
|
+
|
|
53
|
+
// Group to hold selected objects for transform controls
|
|
54
|
+
this.multiSelectionGroup = null;
|
|
51
55
|
|
|
52
56
|
// Transform mode: 'translate', 'rotate', 'scale'
|
|
53
57
|
this.currentMode = 'translate';
|
|
@@ -145,9 +149,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
145
149
|
this._objectTransformedListener = function (eventData) {
|
|
146
150
|
console.log('๐ฒ TransformControlsManager detected object transformation');
|
|
147
151
|
|
|
148
|
-
//
|
|
149
|
-
if (_this.
|
|
150
|
-
console.log('๐ฒ Updating bounding
|
|
152
|
+
// Update bounding box if the transformed object is in current selection
|
|
153
|
+
if (_this.selectedObjects.includes(eventData.object)) {
|
|
154
|
+
console.log('๐ฒ Updating bounding boxes for selected objects after transform');
|
|
151
155
|
_this.updateBoundingBox();
|
|
152
156
|
}
|
|
153
157
|
};
|
|
@@ -236,13 +240,14 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
236
240
|
this.eventHandlers.transformStart = function () {
|
|
237
241
|
console.log("transformControls transformStart");
|
|
238
242
|
_this2.transformState.isTransforming = true;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
243
|
+
|
|
244
|
+
// Store initial transforms for all selected objects
|
|
245
|
+
if (_this2.selectedObjects.length > 0 && _this2.multiSelectionGroup) {
|
|
246
|
+
_this2.selectedObjects.forEach(function (obj) {
|
|
247
|
+
obj.userData._multiSelectOriginalPosition = obj.position.clone();
|
|
248
|
+
obj.userData._multiSelectOriginalRotation = obj.rotation.clone();
|
|
249
|
+
obj.userData._multiSelectOriginalScale = obj.scale.clone();
|
|
250
|
+
});
|
|
246
251
|
}
|
|
247
252
|
|
|
248
253
|
// Disable orbit controls during transformation
|
|
@@ -252,7 +257,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
252
257
|
|
|
253
258
|
// Execute callback
|
|
254
259
|
if (_this2.callbacks.onTransformStart) {
|
|
255
|
-
_this2.callbacks.onTransformStart(_this2.
|
|
260
|
+
_this2.callbacks.onTransformStart(_this2.selectedObjects[0] || null, _this2.currentMode);
|
|
256
261
|
}
|
|
257
262
|
console.log("\uD83D\uDD27 Transform started: ".concat(_this2.currentMode, " mode"));
|
|
258
263
|
};
|
|
@@ -266,54 +271,31 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
266
271
|
_this2.orbitControls.enabled = true;
|
|
267
272
|
}
|
|
268
273
|
|
|
269
|
-
//
|
|
270
|
-
if (_this2.
|
|
271
|
-
_this2.
|
|
272
|
-
|
|
273
|
-
rotation: _this2.selectedObject.rotation.clone(),
|
|
274
|
-
scale: _this2.selectedObject.scale.clone()
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
// If centralPlant API is available and we're in translate mode,
|
|
278
|
-
// use the API to apply the translation properly
|
|
279
|
-
// BUT skip API-based translation for pipe segments - they should stay where dragged
|
|
280
|
-
if (_this2.centralPlant && _this2.currentMode === 'translate' && !objectTypes.isSegment(_this2.selectedObject)) {
|
|
281
|
-
_this2.handleTranslateWithAPI();
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Clear bounding box cache for the transformed object to ensure selection uses updated position
|
|
285
|
-
if (_this2.boundingBoxCache.has(_this2.selectedObject)) {
|
|
286
|
-
_this2.boundingBoxCache.delete(_this2.selectedObject);
|
|
287
|
-
}
|
|
274
|
+
// Apply multi-selection transforms (works for single or multiple objects)
|
|
275
|
+
if (_this2.selectedObjects.length > 0 && _this2.multiSelectionGroup) {
|
|
276
|
+
_this2.applyMultiSelectionTransform();
|
|
277
|
+
}
|
|
288
278
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
279
|
+
// Update paths after translation is complete
|
|
280
|
+
// Only if we translated components (not segments/gateways - they handle paths internally)
|
|
281
|
+
if (_this2.currentMode === 'translate' && _this2.sceneViewer && typeof _this2.sceneViewer.updatePaths === 'function') {
|
|
282
|
+
// Check if any of the selected objects are components (not segments or gateways)
|
|
283
|
+
var hasComponents = _this2.selectedObjects.some(function (obj) {
|
|
284
|
+
return !objectTypes.isSegment(obj) && !objectTypes.isGateway(obj);
|
|
285
|
+
});
|
|
286
|
+
if (hasComponents) {
|
|
287
|
+
console.log('๐ Updating paths after component translation...');
|
|
293
288
|
try {
|
|
294
289
|
_this2.sceneViewer.updatePaths();
|
|
295
|
-
console.log('โ
Paths
|
|
290
|
+
console.log('โ
Paths updated successfully after translation');
|
|
296
291
|
} catch (error) {
|
|
297
|
-
console.error('โ Error
|
|
292
|
+
console.error('โ Error updating paths after translation:', error);
|
|
298
293
|
}
|
|
294
|
+
} else {
|
|
295
|
+
console.log('โน๏ธ Skipping updatePaths - segments/gateways handle their own path updates');
|
|
299
296
|
}
|
|
300
297
|
}
|
|
301
298
|
|
|
302
|
-
// Execute callback
|
|
303
|
-
if (_this2.callbacks.onTransformEnd) {
|
|
304
|
-
_this2.callbacks.onTransformEnd(_this2.selectedObject, _this2.transformState.initialTransform, _this2.transformState.currentTransform, _this2.currentMode);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Handle pipe segment transformations (only in translate mode)
|
|
308
|
-
if (_this2.currentMode === 'translate' && objectTypes.isSegment(_this2.selectedObject)) {
|
|
309
|
-
_this2.handlePipeSegmentTransform(_this2.selectedObject);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Handle gateway transformations (only in translate mode)
|
|
313
|
-
if (_this2.currentMode === 'translate' && objectTypes.isGateway(_this2.selectedObject)) {
|
|
314
|
-
_this2.handleGatewayTransform(_this2.selectedObject);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
299
|
// Dispatch custom scene update event after transform completes
|
|
318
300
|
if (typeof window !== 'undefined') {
|
|
319
301
|
var _this2$selectedObject;
|
|
@@ -322,7 +304,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
322
304
|
detail: {
|
|
323
305
|
timestamp: Date.now(),
|
|
324
306
|
transformType: _this2.currentMode,
|
|
325
|
-
objectName: ((_this2$selectedObject = _this2.
|
|
307
|
+
objectName: ((_this2$selectedObject = _this2.selectedObjects[0]) === null || _this2$selectedObject === void 0 ? void 0 : _this2$selectedObject.name) || 'unknown',
|
|
308
|
+
objectCount: _this2.selectedObjects.length
|
|
326
309
|
}
|
|
327
310
|
});
|
|
328
311
|
window.dispatchEvent(sceneCompleteEvent);
|
|
@@ -331,11 +314,18 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
331
314
|
};
|
|
332
315
|
// Transform changing event
|
|
333
316
|
this.eventHandlers.transforming = function () {
|
|
334
|
-
//
|
|
335
|
-
if (_this2.
|
|
336
|
-
_this2.
|
|
317
|
+
// Apply real-time visual transformation to objects during drag
|
|
318
|
+
if (_this2.selectedObjects.length > 0 && _this2.multiSelectionGroup) {
|
|
319
|
+
_this2.applyRealtimeTransform();
|
|
337
320
|
}
|
|
338
321
|
|
|
322
|
+
// Clear the bounding box cache for all selected objects during transformation
|
|
323
|
+
_this2.selectedObjects.forEach(function (obj) {
|
|
324
|
+
if (_this2.boundingBoxCache.has(obj)) {
|
|
325
|
+
_this2.boundingBoxCache.delete(obj);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
339
329
|
// Update bounding box during transformation
|
|
340
330
|
_this2.updateBoundingBox();
|
|
341
331
|
|
|
@@ -346,7 +336,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
346
336
|
detail: {
|
|
347
337
|
timestamp: Date.now(),
|
|
348
338
|
transformType: _this2.currentMode,
|
|
349
|
-
objectName: ((_this2$selectedObject2 = _this2.
|
|
339
|
+
objectName: ((_this2$selectedObject2 = _this2.selectedObjects[0]) === null || _this2$selectedObject2 === void 0 ? void 0 : _this2$selectedObject2.name) || 'unknown',
|
|
350
340
|
isTransforming: true
|
|
351
341
|
}
|
|
352
342
|
});
|
|
@@ -416,6 +406,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
416
406
|
|
|
417
407
|
// Single click handler with double-click detection
|
|
418
408
|
this.eventHandlers.click = function (event) {
|
|
409
|
+
var _targetObject$userDat;
|
|
419
410
|
// Skip if currently transforming
|
|
420
411
|
if (_this4.transformState.isTransforming) {
|
|
421
412
|
return;
|
|
@@ -430,6 +421,36 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
430
421
|
// Find target object using appropriate selection method
|
|
431
422
|
var targetObject = _this4._findTargetObject(raycaster, objectFilter);
|
|
432
423
|
|
|
424
|
+
// Check if shift key is pressed for multi-selection
|
|
425
|
+
var isShiftPressed = event.shiftKey;
|
|
426
|
+
|
|
427
|
+
// Skip selection if no target object found
|
|
428
|
+
if (!targetObject) {
|
|
429
|
+
// Deselect if clicking on empty space (and not holding shift)
|
|
430
|
+
if (!isShiftPressed) {
|
|
431
|
+
_this4.deselectObject();
|
|
432
|
+
}
|
|
433
|
+
_this4.clickTiming.lastClickTime = 0;
|
|
434
|
+
_this4.clickTiming.lastClickedObject = null;
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Skip selection if not a component, gateway, or segment
|
|
439
|
+
var objectType = (_targetObject$userDat = targetObject.userData) === null || _targetObject$userDat === void 0 ? void 0 : _targetObject$userDat.objectType;
|
|
440
|
+
var isValidType = objectType === 'component' || objectType === 'gateway' || objectType === 'segment';
|
|
441
|
+
if (!isValidType) {
|
|
442
|
+
console.log('โ Object excluded from selection:', targetObject.name || targetObject.uuid, 'objectType:', objectType);
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Handle multi-selection with shift key
|
|
447
|
+
if (isShiftPressed) {
|
|
448
|
+
_this4.toggleObjectSelection(targetObject);
|
|
449
|
+
_this4.clickTiming.lastClickTime = currentTime;
|
|
450
|
+
_this4.clickTiming.lastClickedObject = targetObject;
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
|
|
433
454
|
// Check if this is a double-click: same object clicked within delay time
|
|
434
455
|
var isSameObject = targetObject === _this4.clickTiming.lastClickedObject;
|
|
435
456
|
var isWithinDelay = timeSinceLastClick < _this4.clickTiming.doubleClickDelay;
|
|
@@ -522,6 +543,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
522
543
|
}, {
|
|
523
544
|
key: "_isValidSelectableObject",
|
|
524
545
|
value: function _isValidSelectableObject(object) {
|
|
546
|
+
var _object$userData;
|
|
525
547
|
// Safety check: ensure object is still valid and in the scene
|
|
526
548
|
if (!object || !object.parent) {
|
|
527
549
|
console.warn('โ ๏ธ Selected object is no longer valid or in scene');
|
|
@@ -533,6 +555,12 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
533
555
|
console.warn('โ Object missing required Three.js properties for transform controls');
|
|
534
556
|
return false;
|
|
535
557
|
}
|
|
558
|
+
|
|
559
|
+
// Check if object has explicit selectable flag set to false
|
|
560
|
+
if (((_object$userData = object.userData) === null || _object$userData === void 0 ? void 0 : _object$userData.selectable) === false) {
|
|
561
|
+
console.warn('โ ๏ธ Object is marked as non-selectable (stub segment)');
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
536
564
|
return true;
|
|
537
565
|
}
|
|
538
566
|
|
|
@@ -572,48 +600,41 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
572
600
|
}, {
|
|
573
601
|
key: "isSelectableObject",
|
|
574
602
|
value: function isSelectableObject(object) {
|
|
575
|
-
var _object$
|
|
603
|
+
var _object$userData2, _object$userData3, _object$userData4, _object$userData5, _object$userData6, _object$userData7, _object$userData8;
|
|
576
604
|
// Basic safety checks
|
|
577
605
|
if (!object || !object.isObject3D) {
|
|
578
606
|
return false;
|
|
579
607
|
}
|
|
580
608
|
|
|
581
|
-
// Debug logging for pipe segments
|
|
582
|
-
if (objectTypes.isSegment(object)) {
|
|
583
|
-
console.log('๐ Found pipe segment in selection check:', object.name, object.userData);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
609
|
// Skip transform controls and their children
|
|
587
610
|
if (object.isTransformControls || object.isTransformControlsPlane || object.isTransformControlsGizmo) {
|
|
588
611
|
return false;
|
|
589
612
|
}
|
|
590
613
|
|
|
591
614
|
// Skip helpers and special objects
|
|
592
|
-
var isHelper = object.isHelper || ((_object$
|
|
593
|
-
var isBaseGround = (_object$
|
|
594
|
-
var isBrickWall = (_object$
|
|
615
|
+
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);
|
|
616
|
+
var isBaseGround = (_object$userData4 = object.userData) === null || _object$userData4 === void 0 ? void 0 : _object$userData4.isBaseGround;
|
|
617
|
+
var isBrickWall = (_object$userData5 = object.userData) === null || _object$userData5 === void 0 ? void 0 : _object$userData5.isBrickWall;
|
|
595
618
|
if (isHelper || isBaseGround || isBrickWall || !object.visible) {
|
|
596
619
|
return false;
|
|
597
620
|
}
|
|
598
621
|
|
|
599
|
-
//
|
|
600
|
-
if (
|
|
601
|
-
console.log('โ Polyline parent object excluded from selection:', object.name);
|
|
622
|
+
// Skip segment connectors - they should not be selectable for transformation
|
|
623
|
+
if (((_object$userData6 = object.userData) === null || _object$userData6 === void 0 ? void 0 : _object$userData6.objectType) === 'segment-connector') {
|
|
602
624
|
return false;
|
|
603
625
|
}
|
|
604
626
|
|
|
605
|
-
// Check
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
var isGLBModel = object.name && object.name.includes(' Component');
|
|
627
|
+
// Check if object has explicit selectable flag set to false
|
|
628
|
+
if (((_object$userData7 = object.userData) === null || _object$userData7 === void 0 ? void 0 : _object$userData7.selectable) === false) {
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
610
631
|
|
|
611
|
-
//
|
|
612
|
-
var
|
|
613
|
-
return
|
|
632
|
+
// Allow components, gateways, and segments to be selected
|
|
633
|
+
var objectType = (_object$userData8 = object.userData) === null || _object$userData8 === void 0 ? void 0 : _object$userData8.objectType;
|
|
634
|
+
return objectType === 'component' || objectType === 'gateway' || objectTypes.isSegment(object);
|
|
614
635
|
}
|
|
615
636
|
/**
|
|
616
|
-
* Select an object for transformation
|
|
637
|
+
* Select an object for transformation (with full callbacks including tooltips)
|
|
617
638
|
* @param {THREE.Object3D} object - The object to select
|
|
618
639
|
*/
|
|
619
640
|
}, {
|
|
@@ -623,37 +644,14 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
623
644
|
console.warn('โ ๏ธ Invalid object provided for selection');
|
|
624
645
|
return false;
|
|
625
646
|
}
|
|
626
|
-
this.selectedObject = object;
|
|
627
|
-
|
|
628
|
-
// Force object matrix update to ensure correct transforms
|
|
629
|
-
object.updateMatrixWorld(true);
|
|
630
|
-
|
|
631
|
-
// Refresh bounding box cache for this object
|
|
632
|
-
var updatedBoundingBox = new THREE__namespace.Box3().setFromObject(object);
|
|
633
|
-
this.boundingBoxCache.set(object, updatedBoundingBox);
|
|
634
|
-
|
|
635
|
-
// Attach transform controls
|
|
636
|
-
this.transformControls.attach(object);
|
|
637
|
-
|
|
638
|
-
// Update interaction time to reset delay
|
|
639
|
-
if (this.transformControls.updateInteractionTime) {
|
|
640
|
-
this.transformControls.updateInteractionTime();
|
|
641
|
-
}
|
|
642
647
|
|
|
643
|
-
//
|
|
644
|
-
this.
|
|
648
|
+
// Clear existing selection and select this object
|
|
649
|
+
this.selectedObjects = [object];
|
|
645
650
|
|
|
646
|
-
//
|
|
647
|
-
|
|
648
|
-
this.transformControls.enabled = this.config.enabled;
|
|
649
|
-
this._showTransformControls();
|
|
650
|
-
} else {
|
|
651
|
-
console.log('๐ Transform controls kept invisible despite object selection');
|
|
652
|
-
this.transformControls.enabled = false;
|
|
653
|
-
this._hideTransformControls();
|
|
654
|
-
}
|
|
651
|
+
// Update the multi-selection display (works for single object too)
|
|
652
|
+
this.updateMultiSelection();
|
|
655
653
|
|
|
656
|
-
// Execute callback
|
|
654
|
+
// Execute callback for tooltips and other UI updates
|
|
657
655
|
if (this.callbacks.onObjectSelect) {
|
|
658
656
|
this.callbacks.onObjectSelect(object);
|
|
659
657
|
}
|
|
@@ -673,56 +671,198 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
673
671
|
console.warn('โ ๏ธ Invalid object provided for selection');
|
|
674
672
|
return false;
|
|
675
673
|
}
|
|
676
|
-
this.selectedObject = object;
|
|
677
674
|
|
|
678
|
-
//
|
|
679
|
-
object
|
|
675
|
+
// Clear existing selection and select this object
|
|
676
|
+
this.selectedObjects = [object];
|
|
680
677
|
|
|
681
|
-
//
|
|
682
|
-
|
|
683
|
-
this.boundingBoxCache.set(object, updatedBoundingBox);
|
|
678
|
+
// Update the multi-selection display (works for single object too)
|
|
679
|
+
this.updateMultiSelection();
|
|
684
680
|
|
|
685
|
-
//
|
|
686
|
-
|
|
681
|
+
// NOTE: We deliberately do NOT call any callback here
|
|
682
|
+
// This allows transform controls and bounding box to show without triggering tooltips
|
|
683
|
+
|
|
684
|
+
console.log("\uD83C\uDFAF Object selected for transform only: ".concat(object.name || object.uuid));
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Toggle object selection for multi-selection (shift+click)
|
|
690
|
+
* @param {THREE.Object3D} object - The object to toggle
|
|
691
|
+
*/
|
|
692
|
+
}, {
|
|
693
|
+
key: "toggleObjectSelection",
|
|
694
|
+
value: function toggleObjectSelection(object) {
|
|
695
|
+
if (!object || !object.isObject3D) {
|
|
696
|
+
console.warn('โ ๏ธ Invalid object provided for multi-selection');
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Check if object is already in selection
|
|
701
|
+
var index = this.selectedObjects.findIndex(function (obj) {
|
|
702
|
+
return obj === object;
|
|
703
|
+
});
|
|
704
|
+
if (index !== -1) {
|
|
705
|
+
// Object is already selected, remove it
|
|
706
|
+
this.selectedObjects.splice(index, 1);
|
|
707
|
+
console.log("\u2796 Removed from selection: ".concat(object.name || object.uuid));
|
|
708
|
+
} else {
|
|
709
|
+
// Object is not selected, add it
|
|
710
|
+
this.selectedObjects.push(object);
|
|
711
|
+
console.log("\u2795 Added to selection: ".concat(object.name || object.uuid));
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Update the multi-selection display
|
|
715
|
+
this.updateMultiSelection();
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Update the multi-selection group and transform controls
|
|
720
|
+
* Works for both single and multiple object selection
|
|
721
|
+
*/
|
|
722
|
+
}, {
|
|
723
|
+
key: "updateMultiSelection",
|
|
724
|
+
value: function updateMultiSelection() {
|
|
725
|
+
if (this.selectedObjects.length === 0) {
|
|
726
|
+
// No objects selected, deselect everything
|
|
727
|
+
this.deselectObject();
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Create/update group for selected objects (even if just one)
|
|
732
|
+
this.createMultiSelectionGroup();
|
|
733
|
+
|
|
734
|
+
// Attach transform controls to the group
|
|
735
|
+
this.transformControls.attach(this.multiSelectionGroup);
|
|
687
736
|
|
|
688
737
|
// Update interaction time to reset delay
|
|
689
738
|
if (this.transformControls.updateInteractionTime) {
|
|
690
739
|
this.transformControls.updateInteractionTime();
|
|
691
740
|
}
|
|
692
741
|
|
|
693
|
-
// Create
|
|
694
|
-
this.
|
|
742
|
+
// Create bounding boxes for all selected objects
|
|
743
|
+
this.createMultiBoundingBox();
|
|
695
744
|
|
|
696
|
-
//
|
|
745
|
+
// Enable transform controls if not forcing invisibility
|
|
697
746
|
if (!this.forceInvisible) {
|
|
698
747
|
this.transformControls.enabled = true;
|
|
699
748
|
this._showTransformControls();
|
|
700
|
-
} else {
|
|
701
|
-
console.log('๐ Transform controls kept invisible despite object selection');
|
|
702
|
-
this.transformControls.enabled = false;
|
|
703
|
-
this._hideTransformControls();
|
|
704
749
|
}
|
|
750
|
+
console.log("\uD83C\uDFAF Selection active: ".concat(this.selectedObjects.length, " object(s)"));
|
|
751
|
+
}
|
|
705
752
|
|
|
706
|
-
|
|
707
|
-
|
|
753
|
+
/**
|
|
754
|
+
* Create or update the multi-selection group
|
|
755
|
+
*/
|
|
756
|
+
}, {
|
|
757
|
+
key: "createMultiSelectionGroup",
|
|
758
|
+
value: function createMultiSelectionGroup() {
|
|
759
|
+
// Remove existing group if it exists
|
|
760
|
+
if (this.multiSelectionGroup) {
|
|
761
|
+
this.scene.remove(this.multiSelectionGroup);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Create new group
|
|
765
|
+
this.multiSelectionGroup = new THREE__namespace.Group();
|
|
766
|
+
this.multiSelectionGroup.name = 'MultiSelectionGroup';
|
|
767
|
+
this.multiSelectionGroup.userData = {
|
|
768
|
+
isMultiSelectionGroup: true
|
|
769
|
+
};
|
|
708
770
|
|
|
709
|
-
|
|
710
|
-
|
|
771
|
+
// Calculate the centroid of all selected objects
|
|
772
|
+
var centroid = new THREE__namespace.Vector3();
|
|
773
|
+
this.selectedObjects.forEach(function (obj) {
|
|
774
|
+
var worldPos = new THREE__namespace.Vector3();
|
|
775
|
+
obj.getWorldPosition(worldPos);
|
|
776
|
+
centroid.add(worldPos);
|
|
777
|
+
});
|
|
778
|
+
centroid.divideScalar(this.selectedObjects.length);
|
|
779
|
+
|
|
780
|
+
// Position the group at the centroid
|
|
781
|
+
this.multiSelectionGroup.position.copy(centroid);
|
|
782
|
+
|
|
783
|
+
// Add group to scene
|
|
784
|
+
this.scene.add(this.multiSelectionGroup);
|
|
785
|
+
|
|
786
|
+
// Store original position, rotation, and scale for each object
|
|
787
|
+
// Note: We don't store the parent reference to avoid circular JSON issues
|
|
788
|
+
this.selectedObjects.forEach(function (obj) {
|
|
789
|
+
// Store local transforms (for final API calls)
|
|
790
|
+
obj.userData._multiSelectOriginalPosition = obj.position.clone();
|
|
791
|
+
obj.userData._multiSelectOriginalRotation = obj.rotation.clone();
|
|
792
|
+
obj.userData._multiSelectOriginalScale = obj.scale.clone();
|
|
793
|
+
|
|
794
|
+
// Store world position (for real-time visual updates)
|
|
795
|
+
var worldPos = new THREE__namespace.Vector3();
|
|
796
|
+
obj.getWorldPosition(worldPos);
|
|
797
|
+
obj.userData._multiSelectOriginalWorldPosition = worldPos;
|
|
798
|
+
});
|
|
799
|
+
console.log("\uD83D\uDCE6 Multi-selection group created at centroid:", centroid.toArray());
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Create a bounding box that encompasses all selected objects
|
|
804
|
+
*/
|
|
805
|
+
}, {
|
|
806
|
+
key: "createMultiBoundingBox",
|
|
807
|
+
value:
|
|
808
|
+
/**
|
|
809
|
+
* Create bounding boxes for all selected objects
|
|
810
|
+
*/
|
|
811
|
+
function createMultiBoundingBox() {
|
|
812
|
+
var _this5 = this;
|
|
813
|
+
// Skip if bounding box is disabled
|
|
814
|
+
if (!this.config.showBoundingBox) {
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Remove any existing bounding boxes first
|
|
819
|
+
this.removeBoundingBox();
|
|
820
|
+
if (this.selectedObjects.length === 0) {
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
try {
|
|
824
|
+
// Create individual bounding boxes for each selected object
|
|
825
|
+
this.selectedObjects.forEach(function (obj) {
|
|
826
|
+
var boundingBoxHelper = new THREE__namespace.BoxHelper(obj, _this5.config.boundingBoxColor);
|
|
827
|
+
|
|
828
|
+
// Mark it as a helper to avoid selection
|
|
829
|
+
boundingBoxHelper.isHelper = true;
|
|
830
|
+
boundingBoxHelper.userData = {
|
|
831
|
+
isBoundingBox: true
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
// Add to scene
|
|
835
|
+
_this5.scene.add(boundingBoxHelper);
|
|
836
|
+
|
|
837
|
+
// Store in array for later cleanup
|
|
838
|
+
_this5.boundingBoxHelpers.push(boundingBoxHelper);
|
|
839
|
+
});
|
|
840
|
+
console.log("\uD83D\uDCE6 Bounding boxes created for ".concat(this.selectedObjects.length, " object(s)"));
|
|
841
|
+
} catch (error) {
|
|
842
|
+
console.warn('โ ๏ธ Failed to create bounding boxes:', error);
|
|
843
|
+
}
|
|
711
844
|
}
|
|
712
845
|
|
|
713
846
|
/**
|
|
714
|
-
*
|
|
847
|
+
* Remove all bounding box helpers
|
|
715
848
|
*/
|
|
716
849
|
}, {
|
|
717
850
|
key: "deselectObject",
|
|
718
|
-
value:
|
|
719
|
-
|
|
720
|
-
|
|
851
|
+
value:
|
|
852
|
+
/**
|
|
853
|
+
* Deselect all currently selected objects
|
|
854
|
+
*/
|
|
855
|
+
function deselectObject() {
|
|
856
|
+
if (this.selectedObjects.length > 0) {
|
|
857
|
+
console.log("\uD83D\uDD04 Objects deselected: ".concat(this.selectedObjects.length));
|
|
721
858
|
}
|
|
722
859
|
|
|
723
|
-
//
|
|
860
|
+
// Clear multi-selection
|
|
861
|
+
this.clearMultiSelection();
|
|
862
|
+
|
|
863
|
+
// Remove bounding boxes
|
|
724
864
|
this.removeBoundingBox();
|
|
725
|
-
|
|
865
|
+
|
|
726
866
|
// Detach and hide transform controls
|
|
727
867
|
if (this.transformControls) {
|
|
728
868
|
// First detach from object
|
|
@@ -741,94 +881,97 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
741
881
|
}
|
|
742
882
|
|
|
743
883
|
/**
|
|
744
|
-
*
|
|
745
|
-
* @param {THREE.Object3D} object - The object to create a bounding box for
|
|
884
|
+
* Clear selection and restore original object states
|
|
746
885
|
*/
|
|
747
886
|
}, {
|
|
748
|
-
key: "
|
|
749
|
-
value: function
|
|
750
|
-
//
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
887
|
+
key: "clearMultiSelection",
|
|
888
|
+
value: function clearMultiSelection() {
|
|
889
|
+
// Clean up userData for selected objects
|
|
890
|
+
this.selectedObjects.forEach(function (obj) {
|
|
891
|
+
if (obj.userData._multiSelectOriginalPosition) {
|
|
892
|
+
delete obj.userData._multiSelectOriginalPosition;
|
|
893
|
+
delete obj.userData._multiSelectOriginalRotation;
|
|
894
|
+
delete obj.userData._multiSelectOriginalScale;
|
|
895
|
+
delete obj.userData._multiSelectOriginalWorldPosition;
|
|
896
|
+
}
|
|
897
|
+
});
|
|
754
898
|
|
|
755
|
-
// Remove
|
|
756
|
-
this.
|
|
757
|
-
|
|
758
|
-
|
|
899
|
+
// Remove selection group from scene
|
|
900
|
+
if (this.multiSelectionGroup) {
|
|
901
|
+
this.scene.remove(this.multiSelectionGroup);
|
|
902
|
+
this.multiSelectionGroup = null;
|
|
759
903
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
this.boundingBoxHelper.userData = {
|
|
767
|
-
isBoundingBox: true
|
|
768
|
-
};
|
|
769
|
-
console.log("this.boundingBoxHelper object:", object);
|
|
770
|
-
|
|
771
|
-
// Add to scene
|
|
772
|
-
this.scene.add(this.boundingBoxHelper);
|
|
773
|
-
console.log("\uD83D\uDCE6 Bounding box created for: ".concat(object.name || object.uuid));
|
|
774
|
-
} catch (error) {
|
|
775
|
-
console.warn('โ ๏ธ Failed to create bounding box:', error);
|
|
904
|
+
|
|
905
|
+
// Clear selection array
|
|
906
|
+
var count = this.selectedObjects.length;
|
|
907
|
+
this.selectedObjects = [];
|
|
908
|
+
if (count > 0) {
|
|
909
|
+
console.log("\uD83E\uDDF9 Cleared selection (".concat(count, " object(s))"));
|
|
776
910
|
}
|
|
777
911
|
}
|
|
778
|
-
|
|
779
|
-
/**
|
|
780
|
-
* Remove the current bounding box helper
|
|
781
|
-
*/
|
|
782
912
|
}, {
|
|
783
913
|
key: "removeBoundingBox",
|
|
784
914
|
value: function removeBoundingBox() {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
915
|
+
// Remove all bounding box helpers
|
|
916
|
+
if (this.boundingBoxHelpers.length > 0) {
|
|
917
|
+
this.boundingBoxHelpers.forEach(function (helper) {
|
|
918
|
+
try {
|
|
919
|
+
// Remove from scene
|
|
920
|
+
if (helper.parent) {
|
|
921
|
+
helper.parent.remove(helper);
|
|
922
|
+
}
|
|
791
923
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
924
|
+
// Dispose geometry and material if they exist
|
|
925
|
+
if (helper.geometry) {
|
|
926
|
+
helper.geometry.dispose();
|
|
927
|
+
}
|
|
928
|
+
if (helper.material) {
|
|
929
|
+
helper.material.dispose();
|
|
930
|
+
}
|
|
931
|
+
} catch (error) {
|
|
932
|
+
console.warn('โ ๏ธ Error removing bounding box helper:', error);
|
|
798
933
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
934
|
+
});
|
|
935
|
+
var count = this.boundingBoxHelpers.length;
|
|
936
|
+
this.boundingBoxHelpers = [];
|
|
937
|
+
if (count > 0) {
|
|
938
|
+
console.log("\uD83D\uDCE6 Removed ".concat(count, " bounding box(es)"));
|
|
804
939
|
}
|
|
805
940
|
}
|
|
806
941
|
}
|
|
807
942
|
|
|
808
943
|
/**
|
|
809
|
-
* Update the bounding
|
|
810
|
-
* Call this after any transformation to keep the bounding
|
|
944
|
+
* Update the bounding boxes to match the current object states
|
|
945
|
+
* Call this after any transformation to keep the bounding boxes in sync
|
|
811
946
|
*/
|
|
812
947
|
}, {
|
|
813
948
|
key: "updateBoundingBox",
|
|
814
949
|
value: function updateBoundingBox() {
|
|
815
|
-
|
|
950
|
+
var _this6 = this;
|
|
951
|
+
// Update bounding boxes for all selected objects
|
|
952
|
+
if (this.selectedObjects.length > 0 && this.boundingBoxHelpers.length > 0) {
|
|
816
953
|
try {
|
|
817
|
-
//
|
|
818
|
-
this.
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
954
|
+
// Update each bounding box helper
|
|
955
|
+
this.boundingBoxHelpers.forEach(function (helper, index) {
|
|
956
|
+
var obj = _this6.selectedObjects[index];
|
|
957
|
+
if (obj) {
|
|
958
|
+
// Force object matrix update to ensure correct bounding box
|
|
959
|
+
obj.updateMatrixWorld(true);
|
|
960
|
+
|
|
961
|
+
// Update bounding box
|
|
962
|
+
helper.update();
|
|
963
|
+
|
|
964
|
+
// Also update the cached bounding box if it exists
|
|
965
|
+
if (_this6.boundingBoxCache.has(obj)) {
|
|
966
|
+
var updatedBoundingBox = new THREE__namespace.Box3().setFromObject(obj);
|
|
967
|
+
_this6.boundingBoxCache.set(obj, updatedBoundingBox);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
});
|
|
828
971
|
} catch (error) {
|
|
829
|
-
console.warn('โ ๏ธ Error updating bounding
|
|
830
|
-
// If update fails, recreate the bounding
|
|
831
|
-
this.
|
|
972
|
+
console.warn('โ ๏ธ Error updating bounding boxes:', error);
|
|
973
|
+
// If update fails, recreate the bounding boxes
|
|
974
|
+
this.createMultiBoundingBox();
|
|
832
975
|
}
|
|
833
976
|
}
|
|
834
977
|
}
|
|
@@ -930,33 +1073,34 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
930
1073
|
key: "setEnabled",
|
|
931
1074
|
value: function setEnabled(enabled) {
|
|
932
1075
|
this.config.enabled = enabled;
|
|
933
|
-
if (this.
|
|
1076
|
+
if (this.selectedObjects.length > 0) {
|
|
934
1077
|
this.transformControls.enabled = enabled;
|
|
935
1078
|
}
|
|
936
1079
|
console.log("\uD83D\uDD04 Transform controls ".concat(enabled ? 'enabled' : 'disabled'));
|
|
937
1080
|
}
|
|
938
1081
|
|
|
939
1082
|
/**
|
|
940
|
-
* Get world transformation data for the selected object
|
|
1083
|
+
* Get world transformation data for the first selected object
|
|
941
1084
|
* @returns {Object} World transformation data
|
|
942
1085
|
*/
|
|
943
1086
|
}, {
|
|
944
1087
|
key: "getWorldTransformData",
|
|
945
1088
|
value: function getWorldTransformData() {
|
|
946
|
-
if (
|
|
1089
|
+
if (this.selectedObjects.length === 0) {
|
|
947
1090
|
return null;
|
|
948
1091
|
}
|
|
1092
|
+
var selectedObject = this.selectedObjects[0];
|
|
949
1093
|
|
|
950
1094
|
// Ensure the object's world matrix is up to date
|
|
951
|
-
|
|
1095
|
+
selectedObject.updateMatrixWorld(true);
|
|
952
1096
|
|
|
953
1097
|
// Get world position
|
|
954
1098
|
var worldPosition = new THREE__namespace.Vector3();
|
|
955
|
-
|
|
1099
|
+
selectedObject.getWorldPosition(worldPosition);
|
|
956
1100
|
|
|
957
1101
|
// Get world quaternion
|
|
958
1102
|
var worldQuaternion = new THREE__namespace.Quaternion();
|
|
959
|
-
|
|
1103
|
+
selectedObject.getWorldQuaternion(worldQuaternion);
|
|
960
1104
|
|
|
961
1105
|
// Convert quaternion to Euler rotation
|
|
962
1106
|
var worldRotation = new THREE__namespace.Euler();
|
|
@@ -964,7 +1108,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
964
1108
|
|
|
965
1109
|
// Get world scale
|
|
966
1110
|
var worldScale = new THREE__namespace.Vector3();
|
|
967
|
-
|
|
1111
|
+
selectedObject.getWorldScale(worldScale);
|
|
968
1112
|
return {
|
|
969
1113
|
position: worldPosition,
|
|
970
1114
|
rotation: worldRotation,
|
|
@@ -983,11 +1127,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
983
1127
|
key: "updateObjectTransform",
|
|
984
1128
|
value: function updateObjectTransform(type, axis, value) {
|
|
985
1129
|
var useWorldCoords = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
986
|
-
if (
|
|
1130
|
+
if (this.selectedObjects.length === 0) {
|
|
987
1131
|
console.warn('โ ๏ธ No object selected for transformation');
|
|
988
1132
|
return;
|
|
989
1133
|
}
|
|
990
|
-
var object = this.
|
|
1134
|
+
var object = this.selectedObjects[0];
|
|
991
1135
|
var numericValue = parseFloat(value);
|
|
992
1136
|
if (isNaN(numericValue)) {
|
|
993
1137
|
console.warn('โ ๏ธ Invalid numeric value for transform:', value);
|
|
@@ -1013,7 +1157,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1013
1157
|
console.warn("\u26A0\uFE0F Unknown transform type: ".concat(type));
|
|
1014
1158
|
return;
|
|
1015
1159
|
}
|
|
1016
|
-
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// Update transform controls to reflect the change
|
|
1017
1163
|
if (this.transformControls) {
|
|
1018
1164
|
this.transformControls.updateMatrixWorld();
|
|
1019
1165
|
}
|
|
@@ -1141,13 +1287,13 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1141
1287
|
}, {
|
|
1142
1288
|
key: "getSelectableObjectsWithBounds",
|
|
1143
1289
|
value: function getSelectableObjectsWithBounds() {
|
|
1144
|
-
var
|
|
1290
|
+
var _this7 = this;
|
|
1145
1291
|
var objectFilter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
1146
1292
|
var objectsWithBounds = [];
|
|
1147
1293
|
|
|
1148
1294
|
// Traverse scene to find selectable objects
|
|
1149
1295
|
this.scene.traverse(function (object) {
|
|
1150
|
-
var _object$
|
|
1296
|
+
var _object$userData9, _object$userData0;
|
|
1151
1297
|
// Skip invalid objects and helpers early
|
|
1152
1298
|
if (!object || !object.isObject3D) {
|
|
1153
1299
|
return;
|
|
@@ -1159,25 +1305,25 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1159
1305
|
}
|
|
1160
1306
|
|
|
1161
1307
|
// Skip other helpers and special objects
|
|
1162
|
-
if (object.isHelper || (_object$
|
|
1308
|
+
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) {
|
|
1163
1309
|
return;
|
|
1164
1310
|
}
|
|
1165
1311
|
try {
|
|
1166
1312
|
// Apply filter (use provided filter or default isSelectableObject method)
|
|
1167
|
-
var isSelectable = objectFilter ? objectFilter(object) :
|
|
1313
|
+
var isSelectable = objectFilter ? objectFilter(object) : _this7.isSelectableObject(object);
|
|
1168
1314
|
if (isSelectable) {
|
|
1169
1315
|
// Force object matrix update to ensure correct bounding box
|
|
1170
1316
|
object.updateMatrixWorld(true);
|
|
1171
1317
|
|
|
1172
1318
|
// Get or compute bounding box
|
|
1173
|
-
var boundingBox =
|
|
1319
|
+
var boundingBox = _this7.boundingBoxCache.get(object);
|
|
1174
1320
|
|
|
1175
1321
|
// Always recompute bounding box for recently transformed objects
|
|
1176
1322
|
// or if no cached bounding box exists
|
|
1177
|
-
if (!boundingBox || object
|
|
1323
|
+
if (!boundingBox || _this7.selectedObjects.includes(object)) {
|
|
1178
1324
|
// Compute and cache bounding box
|
|
1179
1325
|
boundingBox = new THREE__namespace.Box3().setFromObject(object);
|
|
1180
|
-
|
|
1326
|
+
_this7.boundingBoxCache.set(object, boundingBox);
|
|
1181
1327
|
}
|
|
1182
1328
|
objectsWithBounds.push({
|
|
1183
1329
|
object: object,
|
|
@@ -1239,60 +1385,216 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1239
1385
|
}
|
|
1240
1386
|
|
|
1241
1387
|
/**
|
|
1242
|
-
*
|
|
1243
|
-
* This
|
|
1244
|
-
* then uses the centralPlant.translate() API to apply the change properly
|
|
1388
|
+
* Apply real-time visual transformation during drag (no API calls)
|
|
1389
|
+
* This updates the object positions/rotations visually while the user is dragging
|
|
1245
1390
|
*/
|
|
1246
1391
|
}, {
|
|
1247
|
-
key: "
|
|
1248
|
-
value: function
|
|
1249
|
-
var
|
|
1250
|
-
if (!this.
|
|
1251
|
-
console.warn('โ ๏ธ Cannot handle translate with API: missing required state');
|
|
1392
|
+
key: "applyRealtimeTransform",
|
|
1393
|
+
value: function applyRealtimeTransform() {
|
|
1394
|
+
var _this8 = this;
|
|
1395
|
+
if (!this.multiSelectionGroup || this.selectedObjects.length === 0) {
|
|
1252
1396
|
return;
|
|
1253
1397
|
}
|
|
1254
1398
|
|
|
1255
|
-
// Calculate the
|
|
1256
|
-
var
|
|
1257
|
-
var
|
|
1258
|
-
var deltaZ = this.transformState.currentTransform.position.z - this.transformState.initialTransform.position.z;
|
|
1399
|
+
// Calculate the transformation delta from the group
|
|
1400
|
+
var groupPosition = this.multiSelectionGroup.position.clone();
|
|
1401
|
+
var groupRotation = this.multiSelectionGroup.rotation.clone();
|
|
1259
1402
|
|
|
1260
|
-
//
|
|
1261
|
-
|
|
1262
|
-
this.
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1403
|
+
// Get the original centroid position (from when group was created)
|
|
1404
|
+
var originalCentroid = new THREE__namespace.Vector3();
|
|
1405
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1406
|
+
var originalWorldPos = obj.userData._multiSelectOriginalWorldPosition;
|
|
1407
|
+
if (originalWorldPos) {
|
|
1408
|
+
originalCentroid.add(originalWorldPos);
|
|
1409
|
+
}
|
|
1410
|
+
});
|
|
1411
|
+
originalCentroid.divideScalar(this.selectedObjects.length);
|
|
1412
|
+
|
|
1413
|
+
// Calculate deltas
|
|
1414
|
+
var positionDelta = groupPosition.clone().sub(originalCentroid);
|
|
1415
|
+
var rotationDelta = groupRotation.clone();
|
|
1416
|
+
|
|
1417
|
+
// Apply transformation to each selected object visually
|
|
1418
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1419
|
+
var originalWorldPos = obj.userData._multiSelectOriginalWorldPosition;
|
|
1420
|
+
var originalRot = obj.userData._multiSelectOriginalRotation;
|
|
1421
|
+
if (!originalWorldPos || !originalRot) {
|
|
1422
|
+
return;
|
|
1423
|
+
}
|
|
1424
|
+
if (_this8.currentMode === 'translate') {
|
|
1425
|
+
// Simple translation: original world position + delta
|
|
1426
|
+
var newWorldPos = originalWorldPos.clone().add(positionDelta);
|
|
1427
|
+
|
|
1428
|
+
// Convert to local position if object has a parent
|
|
1429
|
+
if (obj.parent && obj.parent !== _this8.scene) {
|
|
1430
|
+
// Update parent matrix if parent is also being transformed
|
|
1431
|
+
obj.parent.updateMatrixWorld(true);
|
|
1432
|
+
var parentMatrixInverse = new THREE__namespace.Matrix4();
|
|
1433
|
+
parentMatrixInverse.copy(obj.parent.matrixWorld).invert();
|
|
1434
|
+
newWorldPos.applyMatrix4(parentMatrixInverse);
|
|
1435
|
+
}
|
|
1436
|
+
obj.position.copy(newWorldPos);
|
|
1437
|
+
obj.updateMatrix();
|
|
1438
|
+
} else if (_this8.currentMode === 'rotate') {
|
|
1439
|
+
// Calculate offset from centroid
|
|
1440
|
+
var offsetFromCentroid = originalWorldPos.clone().sub(originalCentroid);
|
|
1441
|
+
|
|
1442
|
+
// Rotate the offset vector
|
|
1443
|
+
var rotatedOffset = offsetFromCentroid.clone();
|
|
1444
|
+
var rotationQuat = new THREE__namespace.Quaternion().setFromEuler(rotationDelta);
|
|
1445
|
+
rotatedOffset.applyQuaternion(rotationQuat);
|
|
1446
|
+
|
|
1447
|
+
// Calculate new world position
|
|
1448
|
+
var _newWorldPos = originalCentroid.clone().add(rotatedOffset).add(positionDelta);
|
|
1449
|
+
|
|
1450
|
+
// Convert to local position
|
|
1451
|
+
if (obj.parent && obj.parent !== _this8.scene) {
|
|
1452
|
+
// Update parent matrix if parent is also being transformed
|
|
1453
|
+
obj.parent.updateMatrixWorld(true);
|
|
1454
|
+
var _parentMatrixInverse = new THREE__namespace.Matrix4();
|
|
1455
|
+
_parentMatrixInverse.copy(obj.parent.matrixWorld).invert();
|
|
1456
|
+
_newWorldPos.applyMatrix4(_parentMatrixInverse);
|
|
1457
|
+
}
|
|
1458
|
+
obj.position.copy(_newWorldPos);
|
|
1459
|
+
|
|
1460
|
+
// Apply rotation to the object itself
|
|
1461
|
+
obj.rotation.x = originalRot.x + rotationDelta.x;
|
|
1462
|
+
obj.rotation.y = originalRot.y + rotationDelta.y;
|
|
1463
|
+
obj.rotation.z = originalRot.z + rotationDelta.z;
|
|
1464
|
+
obj.updateMatrix();
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
// Mark world matrix as needing update (will propagate to children)
|
|
1468
|
+
obj.matrixWorldNeedsUpdate = true;
|
|
1268
1469
|
});
|
|
1470
|
+
}
|
|
1269
1471
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1472
|
+
/**
|
|
1473
|
+
* Apply transformation from multi-selection group to all selected objects
|
|
1474
|
+
* Simple approach: calculate delta once, apply to each object via API
|
|
1475
|
+
*/
|
|
1476
|
+
}, {
|
|
1477
|
+
key: "applyMultiSelectionTransform",
|
|
1478
|
+
value: function applyMultiSelectionTransform() {
|
|
1479
|
+
var _this9 = this;
|
|
1480
|
+
if (!this.multiSelectionGroup || this.selectedObjects.length === 0) {
|
|
1274
1481
|
return;
|
|
1275
1482
|
}
|
|
1483
|
+
console.log("\uD83D\uDD27 Applying multi-selection transform to ".concat(this.selectedObjects.length, " objects"));
|
|
1276
1484
|
|
|
1277
|
-
//
|
|
1278
|
-
|
|
1485
|
+
// Calculate the transformation delta from the group
|
|
1486
|
+
var groupPosition = this.multiSelectionGroup.position.clone();
|
|
1487
|
+
|
|
1488
|
+
// Get the original centroid position (from when group was created)
|
|
1489
|
+
var originalCentroid = new THREE__namespace.Vector3();
|
|
1490
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1491
|
+
var originalWorldPos = obj.userData._multiSelectOriginalWorldPosition;
|
|
1492
|
+
if (originalWorldPos) {
|
|
1493
|
+
originalCentroid.add(originalWorldPos);
|
|
1494
|
+
}
|
|
1495
|
+
});
|
|
1496
|
+
originalCentroid.divideScalar(this.selectedObjects.length);
|
|
1497
|
+
|
|
1498
|
+
// Calculate position delta - this is the same for ALL objects
|
|
1499
|
+
var positionDelta = groupPosition.clone().sub(originalCentroid);
|
|
1500
|
+
|
|
1501
|
+
// Round deltas to avoid floating point precision issues
|
|
1502
|
+
var deltaX = Math.round(positionDelta.x * 2) / 2;
|
|
1503
|
+
var deltaY = Math.round(positionDelta.y * 2) / 2;
|
|
1504
|
+
var deltaZ = Math.round(positionDelta.z * 2) / 2;
|
|
1505
|
+
console.log('๐ง Transform delta:', {
|
|
1506
|
+
deltaX: deltaX,
|
|
1507
|
+
deltaY: deltaY,
|
|
1508
|
+
deltaZ: deltaZ
|
|
1509
|
+
});
|
|
1510
|
+
|
|
1511
|
+
// Only process if there's a meaningful translation
|
|
1279
1512
|
var threshold = 0.001;
|
|
1280
|
-
if (
|
|
1281
|
-
//
|
|
1282
|
-
|
|
1283
|
-
this.
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
this.
|
|
1513
|
+
if (this.currentMode === 'translate' && positionDelta.length() > threshold) {
|
|
1514
|
+
// FIRST: Reset all objects to their original positions
|
|
1515
|
+
// This undoes the visual transform applied during drag
|
|
1516
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1517
|
+
var originalPos = obj.userData._multiSelectOriginalPosition;
|
|
1518
|
+
if (originalPos) {
|
|
1519
|
+
obj.position.copy(originalPos);
|
|
1520
|
+
obj.updateMatrixWorld(true);
|
|
1521
|
+
}
|
|
1522
|
+
});
|
|
1523
|
+
console.log('๐ Reset objects to original positions before API calls');
|
|
1524
|
+
|
|
1525
|
+
// THEN: Apply the delta to each object using the appropriate API
|
|
1526
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1527
|
+
var _obj$userData;
|
|
1528
|
+
if (!_this9.centralPlant) {
|
|
1529
|
+
console.warn('โ ๏ธ CentralPlant API not available');
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
var componentId = obj.uuid || ((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.originalUuid);
|
|
1533
|
+
if (objectTypes.isSegment(obj)) {
|
|
1534
|
+
// Use translateSegment API
|
|
1535
|
+
if (Math.abs(deltaX) > threshold) {
|
|
1536
|
+
_this9.centralPlant.translateSegment(componentId, 'x', deltaX);
|
|
1537
|
+
}
|
|
1538
|
+
if (Math.abs(deltaY) > threshold) {
|
|
1539
|
+
_this9.centralPlant.translateSegment(componentId, 'y', deltaY);
|
|
1540
|
+
}
|
|
1541
|
+
if (Math.abs(deltaZ) > threshold) {
|
|
1542
|
+
_this9.centralPlant.translateSegment(componentId, 'z', deltaZ);
|
|
1543
|
+
}
|
|
1544
|
+
console.log("\uD83D\uDCE6 Segment ".concat(obj.name, " translated:"), {
|
|
1545
|
+
deltaX: deltaX,
|
|
1546
|
+
deltaY: deltaY,
|
|
1547
|
+
deltaZ: deltaZ
|
|
1548
|
+
});
|
|
1549
|
+
} else if (objectTypes.isGateway(obj)) {
|
|
1550
|
+
// Use translateGateway API
|
|
1551
|
+
if (Math.abs(deltaX) > threshold) {
|
|
1552
|
+
_this9.centralPlant.translateGateway(componentId, 'x', deltaX);
|
|
1553
|
+
}
|
|
1554
|
+
if (Math.abs(deltaY) > threshold) {
|
|
1555
|
+
_this9.centralPlant.translateGateway(componentId, 'y', deltaY);
|
|
1556
|
+
}
|
|
1557
|
+
if (Math.abs(deltaZ) > threshold) {
|
|
1558
|
+
_this9.centralPlant.translateGateway(componentId, 'z', deltaZ);
|
|
1559
|
+
}
|
|
1560
|
+
console.log("\uD83D\uDEAA Gateway ".concat(obj.name, " translated:"), {
|
|
1561
|
+
deltaX: deltaX,
|
|
1562
|
+
deltaY: deltaY,
|
|
1563
|
+
deltaZ: deltaZ
|
|
1564
|
+
});
|
|
1565
|
+
} else {
|
|
1566
|
+
// Use standard translate API for components
|
|
1567
|
+
if (Math.abs(deltaX) > threshold) {
|
|
1568
|
+
_this9.centralPlant.translate(componentId, 'x', deltaX);
|
|
1569
|
+
}
|
|
1570
|
+
if (Math.abs(deltaY) > threshold) {
|
|
1571
|
+
_this9.centralPlant.translate(componentId, 'y', deltaY);
|
|
1572
|
+
}
|
|
1573
|
+
if (Math.abs(deltaZ) > threshold) {
|
|
1574
|
+
_this9.centralPlant.translate(componentId, 'z', deltaZ);
|
|
1575
|
+
}
|
|
1576
|
+
console.log("\uD83D\uDD27 Component ".concat(obj.name, " translated:"), {
|
|
1577
|
+
deltaX: deltaX,
|
|
1578
|
+
deltaY: deltaY,
|
|
1579
|
+
deltaZ: deltaZ
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
});
|
|
1583
|
+
console.log("\u2705 All ".concat(this.selectedObjects.length, " objects translated with delta:"), {
|
|
1584
|
+
deltaX: deltaX,
|
|
1585
|
+
deltaY: deltaY,
|
|
1586
|
+
deltaZ: deltaZ
|
|
1587
|
+
});
|
|
1294
1588
|
}
|
|
1295
|
-
|
|
1589
|
+
|
|
1590
|
+
// Reset the multi-selection group transform
|
|
1591
|
+
this.multiSelectionGroup.position.set(0, 0, 0);
|
|
1592
|
+
this.multiSelectionGroup.rotation.set(0, 0, 0);
|
|
1593
|
+
this.multiSelectionGroup.scale.set(1, 1, 1);
|
|
1594
|
+
|
|
1595
|
+
// Update the multi-selection display with new positions
|
|
1596
|
+
this.updateMultiSelection();
|
|
1597
|
+
console.log("\u2705 Multi-selection transform applied");
|
|
1296
1598
|
}
|
|
1297
1599
|
|
|
1298
1600
|
/**
|
|
@@ -1486,10 +1788,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1486
1788
|
// Remove bounding box helper
|
|
1487
1789
|
this.removeBoundingBox();
|
|
1488
1790
|
|
|
1489
|
-
//
|
|
1490
|
-
|
|
1491
|
-
this.deselectObject();
|
|
1492
|
-
}
|
|
1791
|
+
// Clear multi-selection
|
|
1792
|
+
this.clearMultiSelection();
|
|
1493
1793
|
|
|
1494
1794
|
// Dispose transform controls
|
|
1495
1795
|
if (this.transformControls) {
|
|
@@ -1518,7 +1818,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1518
1818
|
}
|
|
1519
1819
|
|
|
1520
1820
|
// Clear references - but keep scene, camera, and renderer references for reuse
|
|
1521
|
-
this.
|
|
1821
|
+
this.selectedObjects = [];
|
|
1522
1822
|
// Don't null these out: this.scene, this.camera, this.renderer
|
|
1523
1823
|
this.orbitControls = null;
|
|
1524
1824
|
console.log('๐งน Transform controls disposed');
|