@2112-lab/central-plant 0.1.76 → 0.1.78
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 +656 -75
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/core/centralPlantInternals.js +73 -0
- package/dist/cjs/src/managers/controls/componentDragManager.js +145 -32
- package/dist/cjs/src/managers/controls/transformControlsManager.js +22 -30
- package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +52 -8
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +41 -4
- package/dist/cjs/src/utils/boundingBoxUtils.js +356 -0
- package/dist/esm/src/core/centralPlant.js +1 -1
- package/dist/esm/src/core/centralPlantInternals.js +74 -1
- package/dist/esm/src/managers/controls/componentDragManager.js +146 -33
- package/dist/esm/src/managers/controls/transformControlsManager.js +22 -30
- package/dist/esm/src/managers/pathfinding/pathfindingManager.js +52 -8
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +41 -4
- package/dist/esm/src/utils/boundingBoxUtils.js +329 -0
- package/package.json +1 -1
package/dist/bundle/index.js
CHANGED
|
@@ -3403,6 +3403,331 @@ function getObjectsByType(scene, typePredicate) {
|
|
|
3403
3403
|
return results;
|
|
3404
3404
|
}
|
|
3405
3405
|
|
|
3406
|
+
/**
|
|
3407
|
+
* Creates a wireframe box helper (LineSegments) from a Box3, visually identical
|
|
3408
|
+
* to THREE.BoxHelper but driven by an explicit Box3 instead of setFromObject().
|
|
3409
|
+
*
|
|
3410
|
+
* @param {THREE.Box3} box3 - The bounding box to visualize
|
|
3411
|
+
* @param {number} color - Line color (hex)
|
|
3412
|
+
* @returns {THREE.LineSegments} A wireframe box matching BoxHelper's visual style
|
|
3413
|
+
* @private
|
|
3414
|
+
*/
|
|
3415
|
+
function _createBoxHelperFromBox3(box3, color) {
|
|
3416
|
+
var indices = new Uint16Array([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7]);
|
|
3417
|
+
var positions = new Float32Array(8 * 3);
|
|
3418
|
+
var geometry = new THREE__namespace.BufferGeometry();
|
|
3419
|
+
geometry.setIndex(new THREE__namespace.BufferAttribute(indices, 1));
|
|
3420
|
+
geometry.setAttribute('position', new THREE__namespace.BufferAttribute(positions, 3));
|
|
3421
|
+
var helper = new THREE__namespace.LineSegments(geometry, new THREE__namespace.LineBasicMaterial({
|
|
3422
|
+
color: color,
|
|
3423
|
+
toneMapped: false
|
|
3424
|
+
}));
|
|
3425
|
+
helper.matrixAutoUpdate = false;
|
|
3426
|
+
|
|
3427
|
+
// Populate positions from box3
|
|
3428
|
+
_updateBoxHelperPositions(helper, box3);
|
|
3429
|
+
return helper;
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
/**
|
|
3433
|
+
* Updates a box helper's geometry positions from a Box3.
|
|
3434
|
+
* Matches the vertex layout used by THREE.BoxHelper.
|
|
3435
|
+
*
|
|
3436
|
+
* @param {THREE.LineSegments} helper - The wireframe helper to update
|
|
3437
|
+
* @param {THREE.Box3} box3 - The bounding box
|
|
3438
|
+
* @private
|
|
3439
|
+
*/
|
|
3440
|
+
function _updateBoxHelperPositions(helper, box3) {
|
|
3441
|
+
if (box3.isEmpty()) return;
|
|
3442
|
+
var min = box3.min;
|
|
3443
|
+
var max = box3.max;
|
|
3444
|
+
var position = helper.geometry.attributes.position;
|
|
3445
|
+
var array = position.array;
|
|
3446
|
+
|
|
3447
|
+
// Same vertex layout as THREE.BoxHelper
|
|
3448
|
+
array[0] = max.x;
|
|
3449
|
+
array[1] = max.y;
|
|
3450
|
+
array[2] = max.z;
|
|
3451
|
+
array[3] = min.x;
|
|
3452
|
+
array[4] = max.y;
|
|
3453
|
+
array[5] = max.z;
|
|
3454
|
+
array[6] = min.x;
|
|
3455
|
+
array[7] = min.y;
|
|
3456
|
+
array[8] = max.z;
|
|
3457
|
+
array[9] = max.x;
|
|
3458
|
+
array[10] = min.y;
|
|
3459
|
+
array[11] = max.z;
|
|
3460
|
+
array[12] = max.x;
|
|
3461
|
+
array[13] = max.y;
|
|
3462
|
+
array[14] = min.z;
|
|
3463
|
+
array[15] = min.x;
|
|
3464
|
+
array[16] = max.y;
|
|
3465
|
+
array[17] = min.z;
|
|
3466
|
+
array[18] = min.x;
|
|
3467
|
+
array[19] = min.y;
|
|
3468
|
+
array[20] = min.z;
|
|
3469
|
+
array[21] = max.x;
|
|
3470
|
+
array[22] = min.y;
|
|
3471
|
+
array[23] = min.z;
|
|
3472
|
+
position.needsUpdate = true;
|
|
3473
|
+
helper.geometry.computeBoundingSphere();
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
/**
|
|
3477
|
+
* Computes a bounding box for a Three.js object, excluding descendant meshes
|
|
3478
|
+
* that belong to subtrees rooted at objects with excluded objectTypes.
|
|
3479
|
+
*
|
|
3480
|
+
* This mirrors what THREE.Box3.expandByObject() does internally, but with a
|
|
3481
|
+
* filter predicate that skips meshes whose ancestry (up to the root object)
|
|
3482
|
+
* includes any excluded objectType.
|
|
3483
|
+
*
|
|
3484
|
+
* @param {THREE.Object3D} object - The root object to compute bbox for
|
|
3485
|
+
* @param {string[]} excludeTypes - userData.objectType values to exclude (e.g., ['io-device', 'connector'])
|
|
3486
|
+
* @returns {THREE.Box3} The filtered bounding box in world space
|
|
3487
|
+
*
|
|
3488
|
+
* @example
|
|
3489
|
+
* // Compute bbox for pump body only, excluding io-devices and connectors
|
|
3490
|
+
* const pumpBodyBBox = computeFilteredBoundingBox(pumpModel, ['io-device', 'connector'])
|
|
3491
|
+
*/
|
|
3492
|
+
function computeFilteredBoundingBox(object) {
|
|
3493
|
+
var excludeTypes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
|
|
3494
|
+
var box = new THREE__namespace.Box3();
|
|
3495
|
+
var tempBox = new THREE__namespace.Box3();
|
|
3496
|
+
var hasGeometry = false;
|
|
3497
|
+
|
|
3498
|
+
// Build a Set for O(1) lookups
|
|
3499
|
+
var excludeSet = new Set(excludeTypes);
|
|
3500
|
+
object.updateWorldMatrix(false, true);
|
|
3501
|
+
object.traverse(function (child) {
|
|
3502
|
+
// Only process nodes with geometry (Mesh, SkinnedMesh, etc.)
|
|
3503
|
+
if (!child.geometry) return;
|
|
3504
|
+
|
|
3505
|
+
// Walk up the ancestry from child to root object, checking for excluded types.
|
|
3506
|
+
// If any ancestor (excluding the root object itself) has an excluded objectType,
|
|
3507
|
+
// this mesh belongs to an excluded subtree — skip it.
|
|
3508
|
+
var ancestor = child;
|
|
3509
|
+
while (ancestor && ancestor !== object) {
|
|
3510
|
+
var _ancestor$userData;
|
|
3511
|
+
if ((_ancestor$userData = ancestor.userData) !== null && _ancestor$userData !== void 0 && _ancestor$userData.objectType && excludeSet.has(ancestor.userData.objectType)) {
|
|
3512
|
+
return; // Skip — this mesh belongs to an excluded subtree
|
|
3513
|
+
}
|
|
3514
|
+
ancestor = ancestor.parent;
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3517
|
+
// Include this mesh's geometry in the bounding box
|
|
3518
|
+
child.geometry.computeBoundingBox();
|
|
3519
|
+
if (child.geometry.boundingBox) {
|
|
3520
|
+
tempBox.copy(child.geometry.boundingBox);
|
|
3521
|
+
tempBox.applyMatrix4(child.matrixWorld);
|
|
3522
|
+
if (!hasGeometry) {
|
|
3523
|
+
box.copy(tempBox);
|
|
3524
|
+
hasGeometry = true;
|
|
3525
|
+
} else {
|
|
3526
|
+
box.union(tempBox);
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
});
|
|
3530
|
+
if (!hasGeometry) {
|
|
3531
|
+
// Fallback: return a zero-size box at the object's world position
|
|
3532
|
+
var position = new THREE__namespace.Vector3();
|
|
3533
|
+
object.getWorldPosition(position);
|
|
3534
|
+
box.setFromCenterAndSize(position, new THREE__namespace.Vector3(0, 0, 0));
|
|
3535
|
+
console.warn("[boundingBoxUtils] computeFilteredBoundingBox: No geometry found for ".concat(object.uuid, ", returning empty box"));
|
|
3536
|
+
}
|
|
3537
|
+
return box;
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
/**
|
|
3541
|
+
* Computes individual world-space bounding boxes for each io-device child
|
|
3542
|
+
* of a component. Uses standard THREE.Box3.setFromObject() on each io-device
|
|
3543
|
+
* since io-devices don't have their own sub-devices that need filtering.
|
|
3544
|
+
*
|
|
3545
|
+
* @param {THREE.Object3D} componentObject - The component's Three.js object
|
|
3546
|
+
* @returns {Array<{uuid: string, userData: Object, worldBoundingBox: {min: number[], max: number[]}}>}
|
|
3547
|
+
* Array of io-device bounding box descriptors ready for injection into scene data
|
|
3548
|
+
*
|
|
3549
|
+
* @example
|
|
3550
|
+
* const ioDeviceBBoxes = computeIODeviceBoundingBoxes(pumpModel)
|
|
3551
|
+
* // Returns: [{ uuid: 'signal-light-1', userData: {...}, worldBoundingBox: { min: [...], max: [...] } }]
|
|
3552
|
+
*/
|
|
3553
|
+
function computeIODeviceBoundingBoxes(componentObject) {
|
|
3554
|
+
var results = [];
|
|
3555
|
+
var _iterator = _createForOfIteratorHelper(componentObject.children),
|
|
3556
|
+
_step;
|
|
3557
|
+
try {
|
|
3558
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
3559
|
+
var _child$userData;
|
|
3560
|
+
var child = _step.value;
|
|
3561
|
+
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) !== 'io-device') continue;
|
|
3562
|
+
var bbox = new THREE__namespace.Box3().setFromObject(child);
|
|
3563
|
+
if (!bbox.isEmpty()) {
|
|
3564
|
+
results.push({
|
|
3565
|
+
uuid: child.uuid,
|
|
3566
|
+
userData: {
|
|
3567
|
+
objectType: 'io-device',
|
|
3568
|
+
deviceId: child.userData.deviceId || null,
|
|
3569
|
+
attachmentId: child.userData.attachmentId || null,
|
|
3570
|
+
parentComponentId: child.userData.parentComponentId || componentObject.uuid
|
|
3571
|
+
},
|
|
3572
|
+
worldBoundingBox: {
|
|
3573
|
+
min: [bbox.min.x, bbox.min.y, bbox.min.z],
|
|
3574
|
+
max: [bbox.max.x, bbox.max.y, bbox.max.z]
|
|
3575
|
+
}
|
|
3576
|
+
});
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
} catch (err) {
|
|
3580
|
+
_iterator.e(err);
|
|
3581
|
+
} finally {
|
|
3582
|
+
_iterator.f();
|
|
3583
|
+
}
|
|
3584
|
+
return results;
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3587
|
+
/**
|
|
3588
|
+
* Creates bounding box helpers for a selected object. For smart components
|
|
3589
|
+
* (components with io-device children), this produces:
|
|
3590
|
+
* - One filtered helper for the component body (excluding io-devices and connectors)
|
|
3591
|
+
* - One helper per io-device child
|
|
3592
|
+
*
|
|
3593
|
+
* For non-smart components and other objects, produces a single standard BoxHelper.
|
|
3594
|
+
*
|
|
3595
|
+
* Each helper is tagged with metadata in userData for update tracking:
|
|
3596
|
+
* - `isBoundingBox: true`
|
|
3597
|
+
* - `sourceObjectUuid: string` — the object this helper represents
|
|
3598
|
+
* - `isFiltered: boolean` — whether filtered computation was used
|
|
3599
|
+
* - `excludeTypes: string[]` — types excluded (for recomputation)
|
|
3600
|
+
*
|
|
3601
|
+
* @param {THREE.Object3D} object - The selected scene object
|
|
3602
|
+
* @param {number} color - Line color (hex), default green
|
|
3603
|
+
* @returns {THREE.LineSegments[]} Array of box helpers to add to the scene
|
|
3604
|
+
*
|
|
3605
|
+
* @example
|
|
3606
|
+
* const helpers = createSelectionBoxHelpers(pumpModel, 0x00ff00)
|
|
3607
|
+
* helpers.forEach(h => scene.add(h))
|
|
3608
|
+
*/
|
|
3609
|
+
function createSelectionBoxHelpers(object) {
|
|
3610
|
+
var _object$children;
|
|
3611
|
+
var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0x00ff00;
|
|
3612
|
+
var helpers = [];
|
|
3613
|
+
var excludeTypes = ['io-device', 'connector'];
|
|
3614
|
+
|
|
3615
|
+
// Check if this object has io-device children (smart component)
|
|
3616
|
+
var hasIODevices = (_object$children = object.children) === null || _object$children === void 0 ? void 0 : _object$children.some(function (child) {
|
|
3617
|
+
var _child$userData2;
|
|
3618
|
+
return ((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'io-device';
|
|
3619
|
+
});
|
|
3620
|
+
if (hasIODevices) {
|
|
3621
|
+
// 1. Create filtered helper for the component body
|
|
3622
|
+
var filteredBox = computeFilteredBoundingBox(object, excludeTypes);
|
|
3623
|
+
var componentHelper = _createBoxHelperFromBox3(filteredBox, color);
|
|
3624
|
+
componentHelper.isHelper = true;
|
|
3625
|
+
componentHelper.userData = {
|
|
3626
|
+
isBoundingBox: true,
|
|
3627
|
+
sourceObjectUuid: object.uuid,
|
|
3628
|
+
isFiltered: true,
|
|
3629
|
+
excludeTypes: excludeTypes
|
|
3630
|
+
};
|
|
3631
|
+
helpers.push(componentHelper);
|
|
3632
|
+
|
|
3633
|
+
// 2. Create individual helpers for each io-device
|
|
3634
|
+
var _iterator2 = _createForOfIteratorHelper(object.children),
|
|
3635
|
+
_step2;
|
|
3636
|
+
try {
|
|
3637
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
3638
|
+
var _child$userData3;
|
|
3639
|
+
var child = _step2.value;
|
|
3640
|
+
if (((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) !== 'io-device') continue;
|
|
3641
|
+
var deviceBox = new THREE__namespace.Box3().setFromObject(child);
|
|
3642
|
+
if (deviceBox.isEmpty()) continue;
|
|
3643
|
+
var deviceHelper = _createBoxHelperFromBox3(deviceBox, color);
|
|
3644
|
+
deviceHelper.isHelper = true;
|
|
3645
|
+
deviceHelper.userData = {
|
|
3646
|
+
isBoundingBox: true,
|
|
3647
|
+
sourceObjectUuid: child.uuid,
|
|
3648
|
+
isFiltered: false,
|
|
3649
|
+
isIODevice: true,
|
|
3650
|
+
parentComponentUuid: object.uuid
|
|
3651
|
+
};
|
|
3652
|
+
helpers.push(deviceHelper);
|
|
3653
|
+
}
|
|
3654
|
+
} catch (err) {
|
|
3655
|
+
_iterator2.e(err);
|
|
3656
|
+
} finally {
|
|
3657
|
+
_iterator2.f();
|
|
3658
|
+
}
|
|
3659
|
+
} else {
|
|
3660
|
+
// Standard BoxHelper for non-smart objects
|
|
3661
|
+
var boxHelper = new THREE__namespace.BoxHelper(object, color);
|
|
3662
|
+
boxHelper.isHelper = true;
|
|
3663
|
+
boxHelper.userData = {
|
|
3664
|
+
isBoundingBox: true,
|
|
3665
|
+
sourceObjectUuid: object.uuid,
|
|
3666
|
+
isFiltered: false
|
|
3667
|
+
};
|
|
3668
|
+
helpers.push(boxHelper);
|
|
3669
|
+
}
|
|
3670
|
+
return helpers;
|
|
3671
|
+
}
|
|
3672
|
+
|
|
3673
|
+
/**
|
|
3674
|
+
* Updates a set of bounding box helpers to reflect current object transforms.
|
|
3675
|
+
* Handles both standard BoxHelpers and filtered/io-device helpers.
|
|
3676
|
+
*
|
|
3677
|
+
* @param {THREE.LineSegments[]} helpers - Array of box helpers
|
|
3678
|
+
* @param {THREE.Object3D[]} selectedObjects - The selected scene objects
|
|
3679
|
+
* @param {THREE.Scene} scene - The scene (for finding objects by uuid)
|
|
3680
|
+
*/
|
|
3681
|
+
function updateSelectionBoxHelpers(helpers, selectedObjects, scene) {
|
|
3682
|
+
var _iterator3 = _createForOfIteratorHelper(helpers),
|
|
3683
|
+
_step3;
|
|
3684
|
+
try {
|
|
3685
|
+
var _loop = function _loop() {
|
|
3686
|
+
var helper = _step3.value;
|
|
3687
|
+
var _helper$userData = helper.userData,
|
|
3688
|
+
sourceObjectUuid = _helper$userData.sourceObjectUuid,
|
|
3689
|
+
isFiltered = _helper$userData.isFiltered,
|
|
3690
|
+
excludeTypes = _helper$userData.excludeTypes,
|
|
3691
|
+
isIODevice = _helper$userData.isIODevice,
|
|
3692
|
+
parentComponentUuid = _helper$userData.parentComponentUuid;
|
|
3693
|
+
var sourceObject;
|
|
3694
|
+
if (isIODevice && parentComponentUuid) {
|
|
3695
|
+
var _parent$children;
|
|
3696
|
+
// Find the parent component first, then the io-device child
|
|
3697
|
+
var parent = scene.getObjectByProperty('uuid', parentComponentUuid);
|
|
3698
|
+
sourceObject = parent === null || parent === void 0 || (_parent$children = parent.children) === null || _parent$children === void 0 ? void 0 : _parent$children.find(function (c) {
|
|
3699
|
+
return c.uuid === sourceObjectUuid;
|
|
3700
|
+
});
|
|
3701
|
+
} else {
|
|
3702
|
+
sourceObject = selectedObjects.find(function (obj) {
|
|
3703
|
+
return obj.uuid === sourceObjectUuid;
|
|
3704
|
+
}) || scene.getObjectByProperty('uuid', sourceObjectUuid);
|
|
3705
|
+
}
|
|
3706
|
+
if (!sourceObject) return 1; // continue
|
|
3707
|
+
sourceObject.updateMatrixWorld(true);
|
|
3708
|
+
if (isFiltered && excludeTypes) {
|
|
3709
|
+
// Recompute filtered bbox
|
|
3710
|
+
var box = computeFilteredBoundingBox(sourceObject, excludeTypes);
|
|
3711
|
+
_updateBoxHelperPositions(helper, box);
|
|
3712
|
+
} else if (isIODevice) {
|
|
3713
|
+
// Recompute io-device bbox
|
|
3714
|
+
var _box = new THREE__namespace.Box3().setFromObject(sourceObject);
|
|
3715
|
+
_updateBoxHelperPositions(helper, _box);
|
|
3716
|
+
} else if (helper.update) {
|
|
3717
|
+
// Standard BoxHelper — use built-in update
|
|
3718
|
+
helper.update();
|
|
3719
|
+
}
|
|
3720
|
+
};
|
|
3721
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
3722
|
+
if (_loop()) continue;
|
|
3723
|
+
}
|
|
3724
|
+
} catch (err) {
|
|
3725
|
+
_iterator3.e(err);
|
|
3726
|
+
} finally {
|
|
3727
|
+
_iterator3.f();
|
|
3728
|
+
}
|
|
3729
|
+
}
|
|
3730
|
+
|
|
3406
3731
|
var TransformControlsManager = /*#__PURE__*/function () {
|
|
3407
3732
|
function TransformControlsManager(scene, camera, renderer) {
|
|
3408
3733
|
var orbitControls = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
@@ -4318,23 +4643,16 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4318
4643
|
return;
|
|
4319
4644
|
}
|
|
4320
4645
|
try {
|
|
4321
|
-
// Create
|
|
4646
|
+
// Create bounding box helpers for each selected object
|
|
4647
|
+
// Smart components get filtered helpers (component body + individual io-device boxes)
|
|
4322
4648
|
this.selectedObjects.forEach(function (obj) {
|
|
4323
|
-
var
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
isBoundingBox: true
|
|
4329
|
-
};
|
|
4330
|
-
|
|
4331
|
-
// Add to scene
|
|
4332
|
-
_this5.scene.add(boundingBoxHelper);
|
|
4333
|
-
|
|
4334
|
-
// Store in array for later cleanup
|
|
4335
|
-
_this5.boundingBoxHelpers.push(boundingBoxHelper);
|
|
4649
|
+
var helpers = createSelectionBoxHelpers(obj, _this5.config.boundingBoxColor);
|
|
4650
|
+
helpers.forEach(function (helper) {
|
|
4651
|
+
_this5.scene.add(helper);
|
|
4652
|
+
_this5.boundingBoxHelpers.push(helper);
|
|
4653
|
+
});
|
|
4336
4654
|
});
|
|
4337
|
-
console.log("\uD83D\uDCE6 Bounding boxes created for ".concat(this.selectedObjects.length, " object(s)"));
|
|
4655
|
+
console.log("\uD83D\uDCE6 Bounding boxes created for ".concat(this.selectedObjects.length, " object(s) (").concat(this.boundingBoxHelpers.length, " helpers)"));
|
|
4338
4656
|
} catch (error) {
|
|
4339
4657
|
console.warn('⚠️ Failed to create bounding boxes:', error);
|
|
4340
4658
|
}
|
|
@@ -4465,21 +4783,19 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4465
4783
|
// Update bounding boxes for all selected objects
|
|
4466
4784
|
if (this.selectedObjects.length > 0 && this.boundingBoxHelpers.length > 0) {
|
|
4467
4785
|
try {
|
|
4468
|
-
//
|
|
4469
|
-
this.
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
_this6.boundingBoxCache.set(obj, updatedBoundingBox);
|
|
4482
|
-
}
|
|
4786
|
+
// Ensure all selected objects have up-to-date matrices
|
|
4787
|
+
this.selectedObjects.forEach(function (obj) {
|
|
4788
|
+
return obj.updateMatrixWorld(true);
|
|
4789
|
+
});
|
|
4790
|
+
|
|
4791
|
+
// Use the centralized update function which handles filtered, io-device, and standard helpers
|
|
4792
|
+
updateSelectionBoxHelpers(this.boundingBoxHelpers, this.selectedObjects, this.scene);
|
|
4793
|
+
|
|
4794
|
+
// Also update the cached bounding box if it exists
|
|
4795
|
+
this.selectedObjects.forEach(function (obj) {
|
|
4796
|
+
if (_this6.boundingBoxCache.has(obj)) {
|
|
4797
|
+
var updatedBoundingBox = new THREE__namespace.Box3().setFromObject(obj);
|
|
4798
|
+
_this6.boundingBoxCache.set(obj, updatedBoundingBox);
|
|
4483
4799
|
}
|
|
4484
4800
|
});
|
|
4485
4801
|
} catch (error) {
|
|
@@ -27401,20 +27717,63 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
27401
27717
|
// Find the actual component object in the scene
|
|
27402
27718
|
var componentObject = _this3.sceneViewer.scene.getObjectByProperty('uuid', child.uuid);
|
|
27403
27719
|
if (componentObject) {
|
|
27404
|
-
// Compute
|
|
27405
|
-
|
|
27406
|
-
|
|
27720
|
+
// Compute FILTERED bounding box — excludes io-device and connector subtrees
|
|
27721
|
+
// so the component body bbox is tight-fitting and doesn't envelop attached devices
|
|
27722
|
+
var filteredBBox = computeFilteredBoundingBox(componentObject, ['io-device', 'connector']);
|
|
27723
|
+
console.log("\uD83D\uDD04 Updated worldBoundingBox for component ".concat(child.uuid, " (filtered): min=[").concat(filteredBBox.min.x.toFixed(2), ", ").concat(filteredBBox.min.y.toFixed(2), ", ").concat(filteredBBox.min.z.toFixed(2), "], max=[").concat(filteredBBox.max.x.toFixed(2), ", ").concat(filteredBBox.max.y.toFixed(2), ", ").concat(filteredBBox.max.z.toFixed(2), "]"));
|
|
27407
27724
|
|
|
27408
|
-
//
|
|
27409
|
-
|
|
27410
|
-
return _objectSpread2(_objectSpread2({}, child), {}, {
|
|
27725
|
+
// Build the enriched component entry
|
|
27726
|
+
var enrichedChild = _objectSpread2(_objectSpread2({}, child), {}, {
|
|
27411
27727
|
userData: _objectSpread2(_objectSpread2({}, child.userData), {}, {
|
|
27412
27728
|
worldBoundingBox: {
|
|
27413
|
-
min: [
|
|
27414
|
-
max: [
|
|
27729
|
+
min: [filteredBBox.min.x, filteredBBox.min.y, filteredBBox.min.z],
|
|
27730
|
+
max: [filteredBBox.max.x, filteredBBox.max.y, filteredBBox.max.z]
|
|
27415
27731
|
}
|
|
27416
27732
|
})
|
|
27417
27733
|
});
|
|
27734
|
+
|
|
27735
|
+
// Compute separate bounding boxes for each attached io-device
|
|
27736
|
+
// These are injected as children so the pathfinder treats each as an independent obstacle
|
|
27737
|
+
var ioDeviceBBoxes = computeIODeviceBoundingBoxes(componentObject);
|
|
27738
|
+
if (ioDeviceBBoxes.length > 0) {
|
|
27739
|
+
// Ensure children array exists (may already contain connectors)
|
|
27740
|
+
if (!enrichedChild.children) {
|
|
27741
|
+
enrichedChild.children = [];
|
|
27742
|
+
}
|
|
27743
|
+
|
|
27744
|
+
// Inject io-device entries with their own worldBoundingBox
|
|
27745
|
+
ioDeviceBBoxes.forEach(function (deviceBBox) {
|
|
27746
|
+
// Check if this io-device already exists in scene data children
|
|
27747
|
+
var existingIndex = enrichedChild.children.findIndex(function (c) {
|
|
27748
|
+
return c.uuid === deviceBBox.uuid;
|
|
27749
|
+
});
|
|
27750
|
+
if (existingIndex >= 0) {
|
|
27751
|
+
// Update existing entry with bounding box
|
|
27752
|
+
enrichedChild.children[existingIndex] = _objectSpread2(_objectSpread2({}, enrichedChild.children[existingIndex]), {}, {
|
|
27753
|
+
userData: _objectSpread2(_objectSpread2({}, enrichedChild.children[existingIndex].userData), {}, {
|
|
27754
|
+
objectType: 'io-device',
|
|
27755
|
+
worldBoundingBox: deviceBBox.worldBoundingBox
|
|
27756
|
+
})
|
|
27757
|
+
});
|
|
27758
|
+
} else {
|
|
27759
|
+
// Create new entry for the io-device
|
|
27760
|
+
enrichedChild.children.push({
|
|
27761
|
+
uuid: deviceBBox.uuid,
|
|
27762
|
+
userData: _objectSpread2(_objectSpread2({}, deviceBBox.userData), {}, {
|
|
27763
|
+
worldBoundingBox: deviceBBox.worldBoundingBox
|
|
27764
|
+
}),
|
|
27765
|
+
children: []
|
|
27766
|
+
});
|
|
27767
|
+
}
|
|
27768
|
+
console.log("\uD83D\uDCE6 Injected io-device bbox for ".concat(deviceBBox.uuid, ": min=[").concat(deviceBBox.worldBoundingBox.min.map(function (v) {
|
|
27769
|
+
return v.toFixed(2);
|
|
27770
|
+
}).join(', '), "], max=[").concat(deviceBBox.worldBoundingBox.max.map(function (v) {
|
|
27771
|
+
return v.toFixed(2);
|
|
27772
|
+
}).join(', '), "]"));
|
|
27773
|
+
});
|
|
27774
|
+
console.log("\uD83D\uDCE6 Injected ".concat(ioDeviceBBoxes.length, " io-device bounding box(es) for component ").concat(child.uuid));
|
|
27775
|
+
}
|
|
27776
|
+
return enrichedChild;
|
|
27418
27777
|
} else {
|
|
27419
27778
|
console.warn("\u26A0\uFE0F Could not find component object in scene: ".concat(child.uuid));
|
|
27420
27779
|
}
|
|
@@ -29477,6 +29836,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
29477
29836
|
|
|
29478
29837
|
/**
|
|
29479
29838
|
* Helper function to compute world bounding boxes
|
|
29839
|
+
* For components: uses filtered bbox (excludes io-device and connector subtrees)
|
|
29840
|
+
* For io-devices: computes separate bounding boxes and injects them as children
|
|
29480
29841
|
*/
|
|
29481
29842
|
}, {
|
|
29482
29843
|
key: "computeWorldBoundingBoxes",
|
|
@@ -29515,12 +29876,46 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
29515
29876
|
};
|
|
29516
29877
|
jsonObject = _findJsonObject(data.scene.children);
|
|
29517
29878
|
if (jsonObject) {
|
|
29518
|
-
// Compute world bounding box
|
|
29519
|
-
var boundingBox = new THREE__namespace.Box3().setFromObject(object);
|
|
29520
|
-
|
|
29521
29879
|
// Store in JSON userData for pathfinder (skip for gateways - they're just routing points)
|
|
29522
29880
|
if (!jsonObject.userData) jsonObject.userData = {};
|
|
29523
|
-
if (jsonObject.userData.objectType
|
|
29881
|
+
if (jsonObject.userData.objectType === 'component') {
|
|
29882
|
+
// For components: compute filtered bounding box (excludes io-device and connector subtrees)
|
|
29883
|
+
var filteredBBox = computeFilteredBoundingBox(object, ['io-device', 'connector']);
|
|
29884
|
+
jsonObject.userData.worldBoundingBox = {
|
|
29885
|
+
min: filteredBBox.min.toArray(),
|
|
29886
|
+
max: filteredBBox.max.toArray()
|
|
29887
|
+
};
|
|
29888
|
+
console.log("Added filtered world bounding box for component:", jsonObject.userData.worldBoundingBox);
|
|
29889
|
+
|
|
29890
|
+
// Compute and inject separate io-device bounding boxes as children
|
|
29891
|
+
var ioDeviceBBoxes = computeIODeviceBoundingBoxes(object);
|
|
29892
|
+
if (ioDeviceBBoxes.length > 0) {
|
|
29893
|
+
if (!jsonObject.children) jsonObject.children = [];
|
|
29894
|
+
ioDeviceBBoxes.forEach(function (deviceBBox) {
|
|
29895
|
+
var existingIndex = jsonObject.children.findIndex(function (c) {
|
|
29896
|
+
return c.uuid === deviceBBox.uuid;
|
|
29897
|
+
});
|
|
29898
|
+
if (existingIndex >= 0) {
|
|
29899
|
+
// Update existing entry
|
|
29900
|
+
if (!jsonObject.children[existingIndex].userData) jsonObject.children[existingIndex].userData = {};
|
|
29901
|
+
jsonObject.children[existingIndex].userData.objectType = 'io-device';
|
|
29902
|
+
jsonObject.children[existingIndex].userData.worldBoundingBox = deviceBBox.worldBoundingBox;
|
|
29903
|
+
} else {
|
|
29904
|
+
// Create new entry
|
|
29905
|
+
jsonObject.children.push({
|
|
29906
|
+
uuid: deviceBBox.uuid,
|
|
29907
|
+
userData: _objectSpread2(_objectSpread2({}, deviceBBox.userData), {}, {
|
|
29908
|
+
worldBoundingBox: deviceBBox.worldBoundingBox
|
|
29909
|
+
}),
|
|
29910
|
+
children: []
|
|
29911
|
+
});
|
|
29912
|
+
}
|
|
29913
|
+
});
|
|
29914
|
+
console.log("\uD83D\uDCE6 Injected ".concat(ioDeviceBBoxes.length, " io-device bbox(es) for component ").concat(jsonObject.uuid));
|
|
29915
|
+
}
|
|
29916
|
+
} else if (jsonObject.userData.objectType !== 'gateway') {
|
|
29917
|
+
// For non-component, non-gateway objects: standard bounding box
|
|
29918
|
+
var boundingBox = new THREE__namespace.Box3().setFromObject(object);
|
|
29524
29919
|
jsonObject.userData.worldBoundingBox = {
|
|
29525
29920
|
min: boundingBox.min.toArray(),
|
|
29526
29921
|
max: boundingBox.max.toArray()
|
|
@@ -30938,7 +31333,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
30938
31333
|
console.log("\uD83D\uDD0D ModelPreloader available:", !!modelPreloader);
|
|
30939
31334
|
console.log("\uD83D\uDD0D ComponentDictionary available:", !!(modelPreloader !== null && modelPreloader !== void 0 && modelPreloader.componentDictionary));
|
|
30940
31335
|
if (!(modelPreloader && modelPreloader.componentDictionary)) {
|
|
30941
|
-
_context2.n =
|
|
31336
|
+
_context2.n = 14;
|
|
30942
31337
|
break;
|
|
30943
31338
|
}
|
|
30944
31339
|
console.log("\uD83D\uDCDA Available dictionary keys:", Object.keys(modelPreloader.componentDictionary));
|
|
@@ -30954,7 +31349,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
30954
31349
|
});
|
|
30955
31350
|
}
|
|
30956
31351
|
if (!(componentData && componentData.modelKey)) {
|
|
30957
|
-
_context2.n =
|
|
31352
|
+
_context2.n = 12;
|
|
30958
31353
|
break;
|
|
30959
31354
|
}
|
|
30960
31355
|
// Try to get cached model first
|
|
@@ -30994,7 +31389,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
30994
31389
|
console.warn("\u26A0\uFE0F Failed to preload model ".concat(componentData.modelKey, ":"), _t2);
|
|
30995
31390
|
case 8:
|
|
30996
31391
|
if (!cachedModel) {
|
|
30997
|
-
_context2.n =
|
|
31392
|
+
_context2.n = 10;
|
|
30998
31393
|
break;
|
|
30999
31394
|
}
|
|
31000
31395
|
this.dragData.previewObject = cachedModel.clone();
|
|
@@ -31005,6 +31400,14 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31005
31400
|
// Store original colors BEFORE making transparent
|
|
31006
31401
|
this._storeOriginalColors(this.dragData.previewObject);
|
|
31007
31402
|
|
|
31403
|
+
// For smart components, load and attach IO device models to the preview
|
|
31404
|
+
if (!(componentData.isSmart && componentData.attachedDevices)) {
|
|
31405
|
+
_context2.n = 9;
|
|
31406
|
+
break;
|
|
31407
|
+
}
|
|
31408
|
+
_context2.n = 9;
|
|
31409
|
+
return this._attachIODeviceModelsToPreview(this.dragData.previewObject, componentData, modelPreloader);
|
|
31410
|
+
case 9:
|
|
31008
31411
|
// Make the preview semi-transparent
|
|
31009
31412
|
this._setPreviewTransparency(this.dragData.previewObject, 0.5);
|
|
31010
31413
|
this.dragData.previewObject.userData = {
|
|
@@ -31018,19 +31421,19 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31018
31421
|
this.sceneViewer.scene.add(this.dragData.previewObject);
|
|
31019
31422
|
console.log("\u2705 Created ".concat(componentData.isS3Component ? 'S3' : 'static', " GLB preview object for: ").concat(componentId));
|
|
31020
31423
|
return _context2.a(2);
|
|
31021
|
-
case 9:
|
|
31022
|
-
console.warn("\u26A0\uFE0F Failed to load model for ".concat(componentId, ", will use fallback"));
|
|
31023
31424
|
case 10:
|
|
31024
|
-
|
|
31025
|
-
break;
|
|
31425
|
+
console.warn("\u26A0\uFE0F Failed to load model for ".concat(componentId, ", will use fallback"));
|
|
31026
31426
|
case 11:
|
|
31027
|
-
|
|
31028
|
-
case 12:
|
|
31029
|
-
_context2.n = 14;
|
|
31427
|
+
_context2.n = 13;
|
|
31030
31428
|
break;
|
|
31429
|
+
case 12:
|
|
31430
|
+
console.warn("\u26A0\uFE0F No modelKey found for component ".concat(componentId));
|
|
31031
31431
|
case 13:
|
|
31032
|
-
|
|
31432
|
+
_context2.n = 15;
|
|
31433
|
+
break;
|
|
31033
31434
|
case 14:
|
|
31435
|
+
console.warn("\u26A0\uFE0F ModelPreloader or component dictionary not available");
|
|
31436
|
+
case 15:
|
|
31034
31437
|
// Fallback: Create a simple preview mesh if model not available
|
|
31035
31438
|
geometry = new THREE__namespace.BoxGeometry(1, 1, 1);
|
|
31036
31439
|
material = new THREE__namespace.MeshPhysicalMaterial({
|
|
@@ -31053,7 +31456,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31053
31456
|
this.dragData.previewObject.position.set(1000, 1000, 1000);
|
|
31054
31457
|
this.sceneViewer.scene.add(this.dragData.previewObject);
|
|
31055
31458
|
console.log("\u26A0\uFE0F Created fallback wireframe preview for: ".concat(componentId));
|
|
31056
|
-
case
|
|
31459
|
+
case 16:
|
|
31057
31460
|
return _context2.a(2);
|
|
31058
31461
|
}
|
|
31059
31462
|
}, _callee2, this, [[5, 7], [1, 3]]);
|
|
@@ -31063,6 +31466,111 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31063
31466
|
}
|
|
31064
31467
|
return _createPreviewObject;
|
|
31065
31468
|
}()
|
|
31469
|
+
/**
|
|
31470
|
+
* Load and attach IO device models to a smart component preview
|
|
31471
|
+
* @param {THREE.Object3D} parentObject - The parent preview object
|
|
31472
|
+
* @param {Object} componentData - Component dictionary entry (must have attachedDevices)
|
|
31473
|
+
* @param {Object} modelPreloader - ModelPreloader instance
|
|
31474
|
+
* @private
|
|
31475
|
+
*/
|
|
31476
|
+
)
|
|
31477
|
+
}, {
|
|
31478
|
+
key: "_attachIODeviceModelsToPreview",
|
|
31479
|
+
value: (function () {
|
|
31480
|
+
var _attachIODeviceModelsToPreview2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(parentObject, componentData, modelPreloader) {
|
|
31481
|
+
var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _attachment$attachmen, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, _t3;
|
|
31482
|
+
return _regenerator().w(function (_context3) {
|
|
31483
|
+
while (1) switch (_context3.n) {
|
|
31484
|
+
case 0:
|
|
31485
|
+
if (componentData.attachedDevices) {
|
|
31486
|
+
_context3.n = 1;
|
|
31487
|
+
break;
|
|
31488
|
+
}
|
|
31489
|
+
return _context3.a(2);
|
|
31490
|
+
case 1:
|
|
31491
|
+
_i = 0, _Object$entries = Object.entries(componentData.attachedDevices);
|
|
31492
|
+
case 2:
|
|
31493
|
+
if (!(_i < _Object$entries.length)) {
|
|
31494
|
+
_context3.n = 12;
|
|
31495
|
+
break;
|
|
31496
|
+
}
|
|
31497
|
+
_Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), attachmentId = _Object$entries$_i[0], attachment = _Object$entries$_i[1];
|
|
31498
|
+
_context3.p = 3;
|
|
31499
|
+
deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
|
|
31500
|
+
if (!(!deviceData || !deviceData.modelKey)) {
|
|
31501
|
+
_context3.n = 4;
|
|
31502
|
+
break;
|
|
31503
|
+
}
|
|
31504
|
+
console.warn("\u26A0\uFE0F IO device ".concat(attachment.deviceId, " not found in dictionary for preview"));
|
|
31505
|
+
return _context3.a(3, 11);
|
|
31506
|
+
case 4:
|
|
31507
|
+
// Ensure device model is loaded
|
|
31508
|
+
cachedDevice = modelPreloader.getCachedModelWithDimensions(deviceData.modelKey, attachment.deviceId);
|
|
31509
|
+
if (cachedDevice) {
|
|
31510
|
+
_context3.n = 8;
|
|
31511
|
+
break;
|
|
31512
|
+
}
|
|
31513
|
+
if (!((_modelPreloader$loadi = modelPreloader.loadingPromises) !== null && _modelPreloader$loadi !== void 0 && _modelPreloader$loadi.has(deviceData.modelKey))) {
|
|
31514
|
+
_context3.n = 6;
|
|
31515
|
+
break;
|
|
31516
|
+
}
|
|
31517
|
+
_context3.n = 5;
|
|
31518
|
+
return modelPreloader.loadingPromises.get(deviceData.modelKey);
|
|
31519
|
+
case 5:
|
|
31520
|
+
_context3.n = 7;
|
|
31521
|
+
break;
|
|
31522
|
+
case 6:
|
|
31523
|
+
_context3.n = 7;
|
|
31524
|
+
return modelPreloader.preloadSingleModel(deviceData.modelKey);
|
|
31525
|
+
case 7:
|
|
31526
|
+
cachedDevice = modelPreloader.getCachedModelWithDimensions(deviceData.modelKey, attachment.deviceId);
|
|
31527
|
+
case 8:
|
|
31528
|
+
if (cachedDevice) {
|
|
31529
|
+
_context3.n = 9;
|
|
31530
|
+
break;
|
|
31531
|
+
}
|
|
31532
|
+
console.warn("\u26A0\uFE0F Could not load IO device model: ".concat(deviceData.modelKey));
|
|
31533
|
+
return _context3.a(3, 11);
|
|
31534
|
+
case 9:
|
|
31535
|
+
deviceModel = cachedDevice.clone();
|
|
31536
|
+
this._cloneMaterials(deviceModel);
|
|
31537
|
+
this._storeOriginalColors(deviceModel);
|
|
31538
|
+
deviceModel.userData = {
|
|
31539
|
+
objectType: 'io-device',
|
|
31540
|
+
deviceId: attachment.deviceId,
|
|
31541
|
+
attachmentId: attachmentId,
|
|
31542
|
+
attachmentLabel: attachment.attachmentLabel
|
|
31543
|
+
};
|
|
31544
|
+
if ((_attachment$attachmen = attachment.attachmentPoint) !== null && _attachment$attachmen !== void 0 && _attachment$attachmen.position) {
|
|
31545
|
+
pos = attachment.attachmentPoint.position;
|
|
31546
|
+
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
31547
|
+
}
|
|
31548
|
+
|
|
31549
|
+
// IO device models use their natural (1:1) scale — the stored
|
|
31550
|
+
// attachmentPoint.scale value is for the connector marker sphere.
|
|
31551
|
+
deviceModel.scale.setScalar(1);
|
|
31552
|
+
parentObject.add(deviceModel);
|
|
31553
|
+
console.log("\u2705 Attached IO device preview: ".concat(attachment.attachmentLabel || attachment.deviceId));
|
|
31554
|
+
_context3.n = 11;
|
|
31555
|
+
break;
|
|
31556
|
+
case 10:
|
|
31557
|
+
_context3.p = 10;
|
|
31558
|
+
_t3 = _context3.v;
|
|
31559
|
+
console.warn("\u26A0\uFE0F Could not attach IO device model ".concat(attachment.deviceId, " to preview:"), _t3);
|
|
31560
|
+
case 11:
|
|
31561
|
+
_i++;
|
|
31562
|
+
_context3.n = 2;
|
|
31563
|
+
break;
|
|
31564
|
+
case 12:
|
|
31565
|
+
return _context3.a(2);
|
|
31566
|
+
}
|
|
31567
|
+
}, _callee3, this, [[3, 10]]);
|
|
31568
|
+
}));
|
|
31569
|
+
function _attachIODeviceModelsToPreview(_x5, _x6, _x7) {
|
|
31570
|
+
return _attachIODeviceModelsToPreview2.apply(this, arguments);
|
|
31571
|
+
}
|
|
31572
|
+
return _attachIODeviceModelsToPreview;
|
|
31573
|
+
}()
|
|
31066
31574
|
/**
|
|
31067
31575
|
* Clone all materials in an object hierarchy to avoid shared material issues
|
|
31068
31576
|
* @param {THREE.Object3D} object - The object to clone materials for
|
|
@@ -31210,8 +31718,8 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31210
31718
|
});
|
|
31211
31719
|
|
|
31212
31720
|
// Check for overlaps
|
|
31213
|
-
for (var
|
|
31214
|
-
var mesh = _sceneMeshes[
|
|
31721
|
+
for (var _i2 = 0, _sceneMeshes = sceneMeshes; _i2 < _sceneMeshes.length; _i2++) {
|
|
31722
|
+
var mesh = _sceneMeshes[_i2];
|
|
31215
31723
|
var meshBBox = new THREE__namespace.Box3().setFromObject(mesh);
|
|
31216
31724
|
if (previewBBox.intersectsBox(meshBBox)) {
|
|
31217
31725
|
console.log('⚠️ ComponentDragManager: Overlap detected with:', mesh.userData.objectType || mesh.name || mesh.uuid);
|
|
@@ -31525,50 +32033,50 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31525
32033
|
var _this3 = this;
|
|
31526
32034
|
if (!element || !componentId) return;
|
|
31527
32035
|
var handleMouseDown = /*#__PURE__*/function () {
|
|
31528
|
-
var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
31529
|
-
return _regenerator().w(function (
|
|
31530
|
-
while (1) switch (
|
|
32036
|
+
var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(event) {
|
|
32037
|
+
return _regenerator().w(function (_context4) {
|
|
32038
|
+
while (1) switch (_context4.n) {
|
|
31531
32039
|
case 0:
|
|
31532
32040
|
if (!(event.button !== 0)) {
|
|
31533
|
-
|
|
32041
|
+
_context4.n = 1;
|
|
31534
32042
|
break;
|
|
31535
32043
|
}
|
|
31536
|
-
return
|
|
32044
|
+
return _context4.a(2);
|
|
31537
32045
|
case 1:
|
|
31538
32046
|
// Only left mouse button
|
|
31539
32047
|
event.preventDefault();
|
|
31540
|
-
|
|
32048
|
+
_context4.n = 2;
|
|
31541
32049
|
return _this3.startComponentDrag(componentId, element, event);
|
|
31542
32050
|
case 2:
|
|
31543
|
-
return
|
|
32051
|
+
return _context4.a(2);
|
|
31544
32052
|
}
|
|
31545
|
-
},
|
|
32053
|
+
}, _callee4);
|
|
31546
32054
|
}));
|
|
31547
|
-
return function handleMouseDown(
|
|
32055
|
+
return function handleMouseDown(_x8) {
|
|
31548
32056
|
return _ref.apply(this, arguments);
|
|
31549
32057
|
};
|
|
31550
32058
|
}();
|
|
31551
32059
|
var handleTouchStart = /*#__PURE__*/function () {
|
|
31552
|
-
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
31553
|
-
return _regenerator().w(function (
|
|
31554
|
-
while (1) switch (
|
|
32060
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(event) {
|
|
32061
|
+
return _regenerator().w(function (_context5) {
|
|
32062
|
+
while (1) switch (_context5.n) {
|
|
31555
32063
|
case 0:
|
|
31556
32064
|
if (!(event.touches.length !== 1)) {
|
|
31557
|
-
|
|
32065
|
+
_context5.n = 1;
|
|
31558
32066
|
break;
|
|
31559
32067
|
}
|
|
31560
|
-
return
|
|
32068
|
+
return _context5.a(2);
|
|
31561
32069
|
case 1:
|
|
31562
32070
|
// Only single touch
|
|
31563
32071
|
event.preventDefault();
|
|
31564
|
-
|
|
32072
|
+
_context5.n = 2;
|
|
31565
32073
|
return _this3.startComponentDrag(componentId, element, event);
|
|
31566
32074
|
case 2:
|
|
31567
|
-
return
|
|
32075
|
+
return _context5.a(2);
|
|
31568
32076
|
}
|
|
31569
|
-
},
|
|
32077
|
+
}, _callee5);
|
|
31570
32078
|
}));
|
|
31571
|
-
return function handleTouchStart(
|
|
32079
|
+
return function handleTouchStart(_x9) {
|
|
31572
32080
|
return _ref2.apply(this, arguments);
|
|
31573
32081
|
};
|
|
31574
32082
|
}();
|
|
@@ -34710,6 +35218,11 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
34710
35218
|
});
|
|
34711
35219
|
}
|
|
34712
35220
|
|
|
35221
|
+
// Add attached IO device models for smart components
|
|
35222
|
+
if (componentData.isSmart && componentData.attachedDevices) {
|
|
35223
|
+
this._attachIODevicesToComponent(componentModel, componentData, modelPreloader, componentId);
|
|
35224
|
+
}
|
|
35225
|
+
|
|
34713
35226
|
// Notify the component manager about the new component
|
|
34714
35227
|
if (componentManager.registerComponent) {
|
|
34715
35228
|
componentManager.registerComponent(componentModel);
|
|
@@ -34760,6 +35273,74 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
34760
35273
|
}
|
|
34761
35274
|
}
|
|
34762
35275
|
|
|
35276
|
+
/**
|
|
35277
|
+
* Attach IO device models to a smart component from cached models.
|
|
35278
|
+
* Each device referenced in componentData.attachedDevices is looked up
|
|
35279
|
+
* in the model preloader cache, cloned, positioned, and added as a child.
|
|
35280
|
+
* @param {THREE.Object3D} componentModel - The parent component model
|
|
35281
|
+
* @param {Object} componentData - Component dictionary entry (has attachedDevices)
|
|
35282
|
+
* @param {Object} modelPreloader - ModelPreloader instance
|
|
35283
|
+
* @param {string} parentComponentId - The parent component's UUID
|
|
35284
|
+
* @private
|
|
35285
|
+
*/
|
|
35286
|
+
}, {
|
|
35287
|
+
key: "_attachIODevicesToComponent",
|
|
35288
|
+
value: function _attachIODevicesToComponent(componentModel, componentData, modelPreloader, parentComponentId) {
|
|
35289
|
+
var attachedDevices = componentData.attachedDevices;
|
|
35290
|
+
console.log("\uD83D\uDD0C addComponent(): Attaching ".concat(Object.keys(attachedDevices).length, " IO devices to smart component"));
|
|
35291
|
+
for (var _i = 0, _Object$entries = Object.entries(attachedDevices); _i < _Object$entries.length; _i++) {
|
|
35292
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
35293
|
+
attachmentId = _Object$entries$_i[0],
|
|
35294
|
+
attachment = _Object$entries$_i[1];
|
|
35295
|
+
try {
|
|
35296
|
+
var _modelPreloader$compo, _attachment$attachmen;
|
|
35297
|
+
var deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
|
|
35298
|
+
if (!deviceData || !deviceData.modelKey) {
|
|
35299
|
+
console.warn("\u26A0\uFE0F IO device ".concat(attachment.deviceId, " not found in dictionary, skipping"));
|
|
35300
|
+
continue;
|
|
35301
|
+
}
|
|
35302
|
+
var deviceModel = modelPreloader.getCachedModelWithDimensions(deviceData.modelKey, attachment.deviceId);
|
|
35303
|
+
if (!deviceModel) {
|
|
35304
|
+
console.warn("\u26A0\uFE0F IO device model not in cache: ".concat(deviceData.modelKey, ", skipping"));
|
|
35305
|
+
continue;
|
|
35306
|
+
}
|
|
35307
|
+
|
|
35308
|
+
// Name the device model
|
|
35309
|
+
deviceModel.name = "".concat(attachment.attachmentLabel || 'IO Device', " (").concat(attachmentId, ")");
|
|
35310
|
+
|
|
35311
|
+
// Set user data for identification
|
|
35312
|
+
deviceModel.userData = {
|
|
35313
|
+
objectType: 'io-device',
|
|
35314
|
+
deviceId: attachment.deviceId,
|
|
35315
|
+
attachmentId: attachmentId,
|
|
35316
|
+
attachmentLabel: attachment.attachmentLabel,
|
|
35317
|
+
parentComponentId: parentComponentId
|
|
35318
|
+
};
|
|
35319
|
+
|
|
35320
|
+
// Position at the attachment point
|
|
35321
|
+
if ((_attachment$attachmen = attachment.attachmentPoint) !== null && _attachment$attachmen !== void 0 && _attachment$attachmen.position) {
|
|
35322
|
+
var pos = attachment.attachmentPoint.position;
|
|
35323
|
+
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
35324
|
+
}
|
|
35325
|
+
|
|
35326
|
+
// IO device models are authored at the same real-world unit scale
|
|
35327
|
+
// as the host component, so keep them at their natural (1:1) size.
|
|
35328
|
+
// Note: attachmentPoint.scale is the connector marker sphere size,
|
|
35329
|
+
// NOT a desired device model scale.
|
|
35330
|
+
deviceModel.scale.setScalar(1);
|
|
35331
|
+
|
|
35332
|
+
// Add as child of the component
|
|
35333
|
+
componentModel.add(deviceModel);
|
|
35334
|
+
console.log("\u2705 Attached IO device: ".concat(attachment.attachmentLabel || attachment.deviceId, " at"), {
|
|
35335
|
+
position: deviceModel.position,
|
|
35336
|
+
scale: deviceModel.scale
|
|
35337
|
+
});
|
|
35338
|
+
} catch (err) {
|
|
35339
|
+
console.error("\u274C Error attaching IO device ".concat(attachment.deviceId, ":"), err);
|
|
35340
|
+
}
|
|
35341
|
+
}
|
|
35342
|
+
}
|
|
35343
|
+
|
|
34763
35344
|
/**
|
|
34764
35345
|
* Delete a component from the scene by componentId (internal implementation)
|
|
34765
35346
|
* @param {string} componentId - The UUID of the component to delete
|
|
@@ -34865,7 +35446,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34865
35446
|
* Initialize the CentralPlant manager
|
|
34866
35447
|
*
|
|
34867
35448
|
* @constructor
|
|
34868
|
-
* @version 0.1.
|
|
35449
|
+
* @version 0.1.78
|
|
34869
35450
|
* @updated 2025-10-22
|
|
34870
35451
|
*
|
|
34871
35452
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|