@2112-lab/central-plant 0.1.77 → 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 +438 -43
- package/dist/cjs/src/core/centralPlant.js +1 -1
- 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/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()
|
|
@@ -35051,7 +35446,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
35051
35446
|
* Initialize the CentralPlant manager
|
|
35052
35447
|
*
|
|
35053
35448
|
* @constructor
|
|
35054
|
-
* @version 0.1.
|
|
35449
|
+
* @version 0.1.78
|
|
35055
35450
|
* @updated 2025-10-22
|
|
35056
35451
|
*
|
|
35057
35452
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -19,7 +19,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
19
19
|
* Initialize the CentralPlant manager
|
|
20
20
|
*
|
|
21
21
|
* @constructor
|
|
22
|
-
* @version 0.1.
|
|
22
|
+
* @version 0.1.78
|
|
23
23
|
* @updated 2025-10-22
|
|
24
24
|
*
|
|
25
25
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -6,6 +6,7 @@ var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHel
|
|
|
6
6
|
var THREE = require('three');
|
|
7
7
|
var transformControls = require('./transformControls.js');
|
|
8
8
|
var objectTypes = require('../../utils/objectTypes.js');
|
|
9
|
+
var boundingBoxUtils = require('../../utils/boundingBoxUtils.js');
|
|
9
10
|
|
|
10
11
|
function _interopNamespace(e) {
|
|
11
12
|
if (e && e.__esModule) return e;
|
|
@@ -942,23 +943,16 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
942
943
|
return;
|
|
943
944
|
}
|
|
944
945
|
try {
|
|
945
|
-
// Create
|
|
946
|
+
// Create bounding box helpers for each selected object
|
|
947
|
+
// Smart components get filtered helpers (component body + individual io-device boxes)
|
|
946
948
|
this.selectedObjects.forEach(function (obj) {
|
|
947
|
-
var
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
isBoundingBox: true
|
|
953
|
-
};
|
|
954
|
-
|
|
955
|
-
// Add to scene
|
|
956
|
-
_this5.scene.add(boundingBoxHelper);
|
|
957
|
-
|
|
958
|
-
// Store in array for later cleanup
|
|
959
|
-
_this5.boundingBoxHelpers.push(boundingBoxHelper);
|
|
949
|
+
var helpers = boundingBoxUtils.createSelectionBoxHelpers(obj, _this5.config.boundingBoxColor);
|
|
950
|
+
helpers.forEach(function (helper) {
|
|
951
|
+
_this5.scene.add(helper);
|
|
952
|
+
_this5.boundingBoxHelpers.push(helper);
|
|
953
|
+
});
|
|
960
954
|
});
|
|
961
|
-
console.log("\uD83D\uDCE6 Bounding boxes created for ".concat(this.selectedObjects.length, " object(s)"));
|
|
955
|
+
console.log("\uD83D\uDCE6 Bounding boxes created for ".concat(this.selectedObjects.length, " object(s) (").concat(this.boundingBoxHelpers.length, " helpers)"));
|
|
962
956
|
} catch (error) {
|
|
963
957
|
console.warn('⚠️ Failed to create bounding boxes:', error);
|
|
964
958
|
}
|
|
@@ -1089,21 +1083,19 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1089
1083
|
// Update bounding boxes for all selected objects
|
|
1090
1084
|
if (this.selectedObjects.length > 0 && this.boundingBoxHelpers.length > 0) {
|
|
1091
1085
|
try {
|
|
1092
|
-
//
|
|
1093
|
-
this.
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
_this6.boundingBoxCache.set(obj, updatedBoundingBox);
|
|
1106
|
-
}
|
|
1086
|
+
// Ensure all selected objects have up-to-date matrices
|
|
1087
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1088
|
+
return obj.updateMatrixWorld(true);
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
// Use the centralized update function which handles filtered, io-device, and standard helpers
|
|
1092
|
+
boundingBoxUtils.updateSelectionBoxHelpers(this.boundingBoxHelpers, this.selectedObjects, this.scene);
|
|
1093
|
+
|
|
1094
|
+
// Also update the cached bounding box if it exists
|
|
1095
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1096
|
+
if (_this6.boundingBoxCache.has(obj)) {
|
|
1097
|
+
var updatedBoundingBox = new THREE__namespace.Box3().setFromObject(obj);
|
|
1098
|
+
_this6.boundingBoxCache.set(obj, updatedBoundingBox);
|
|
1107
1099
|
}
|
|
1108
1100
|
});
|
|
1109
1101
|
} catch (error) {
|