@2112-lab/central-plant 0.3.5 → 0.3.6
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 +162 -176
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/managers/scene/modelManager.js +7 -0
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +62 -132
- package/dist/cjs/src/managers/scene/viewport2DManager.js +88 -40
- package/dist/cjs/src/utils/sceneClearingUtility.js +2 -2
- package/dist/esm/src/core/centralPlant.js +1 -1
- package/dist/esm/src/managers/scene/modelManager.js +7 -0
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +63 -133
- package/dist/esm/src/managers/scene/viewport2DManager.js +88 -40
- package/dist/esm/src/utils/sceneClearingUtility.js +2 -2
- package/package.json +1 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { createClass as _createClass, objectSpread2 as _objectSpread2, construct as _construct, toConsumableArray as _toConsumableArray, objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, classCallCheck as _classCallCheck,
|
|
1
|
+
import { createClass as _createClass, objectSpread2 as _objectSpread2, construct as _construct, toConsumableArray as _toConsumableArray, objectWithoutProperties as _objectWithoutProperties, slicedToArray as _slicedToArray, classCallCheck as _classCallCheck, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, typeof as _typeof } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
import { loadTextureSet } from '../environment/textureConfig.js';
|
|
4
4
|
import { ModelManager } from './modelManager.js';
|
|
5
5
|
import { SceneClearingUtility } from '../../utils/sceneClearingUtility.js';
|
|
6
|
-
import { computeFilteredBoundingBox, computeIODeviceBoundingBoxes } from '../../utils/boundingBoxUtils.js';
|
|
7
6
|
|
|
8
7
|
var _excluded = ["direction"],
|
|
9
8
|
_excluded2 = ["direction"];
|
|
@@ -623,123 +622,52 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
623
622
|
}
|
|
624
623
|
|
|
625
624
|
/**
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
*
|
|
625
|
+
* Sync world-space positions and isDeclared flags for gateways and connectors
|
|
626
|
+
* into the scene JSON data so the pathfinder can read them.
|
|
627
|
+
*
|
|
628
|
+
* Bounding boxes for components and segments are intentionally NOT computed here.
|
|
629
|
+
* They are computed (with matrix-hash caching) by
|
|
630
|
+
* PathfindingManager._enrichSceneDataWithBoundingBoxes(), which runs after GLB
|
|
631
|
+
* models are fully loaded and therefore produces correct values.
|
|
629
632
|
*/
|
|
630
633
|
}, {
|
|
631
|
-
key: "
|
|
632
|
-
value: function
|
|
633
|
-
var
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
// Recursively search children
|
|
653
|
-
if (child.children) {
|
|
654
|
-
var found = _findJsonObject(child.children);
|
|
655
|
-
if (found) return found;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
} catch (err) {
|
|
659
|
-
_iterator.e(err);
|
|
660
|
-
} finally {
|
|
661
|
-
_iterator.f();
|
|
662
|
-
}
|
|
663
|
-
return null;
|
|
664
|
-
};
|
|
665
|
-
jsonObject = _findJsonObject(data.scene.children);
|
|
666
|
-
if (jsonObject) {
|
|
667
|
-
// Store in JSON userData for pathfinder (skip for gateways - they're just routing points)
|
|
668
|
-
if (!jsonObject.userData) jsonObject.userData = {};
|
|
669
|
-
if (jsonObject.userData.objectType === 'component') {
|
|
670
|
-
// For components: compute filtered bounding box (excludes io-device and connector subtrees)
|
|
671
|
-
var filteredBBox = computeFilteredBoundingBox(object, ['io-device', 'connector']);
|
|
672
|
-
jsonObject.userData.worldBoundingBox = {
|
|
673
|
-
min: filteredBBox.min.toArray(),
|
|
674
|
-
max: filteredBBox.max.toArray()
|
|
675
|
-
};
|
|
676
|
-
console.log("Added filtered world bounding box for component:", jsonObject.userData.worldBoundingBox);
|
|
677
|
-
|
|
678
|
-
// Compute and inject separate io-device bounding boxes as children
|
|
679
|
-
var ioDeviceBBoxes = computeIODeviceBoundingBoxes(object);
|
|
680
|
-
if (ioDeviceBBoxes.length > 0) {
|
|
681
|
-
if (!jsonObject.children) jsonObject.children = [];
|
|
682
|
-
ioDeviceBBoxes.forEach(function (deviceBBox) {
|
|
683
|
-
var existingIndex = jsonObject.children.findIndex(function (c) {
|
|
684
|
-
return c.uuid === deviceBBox.uuid;
|
|
685
|
-
});
|
|
686
|
-
if (existingIndex >= 0) {
|
|
687
|
-
// Update existing entry
|
|
688
|
-
if (!jsonObject.children[existingIndex].userData) jsonObject.children[existingIndex].userData = {};
|
|
689
|
-
jsonObject.children[existingIndex].userData.objectType = 'io-device';
|
|
690
|
-
jsonObject.children[existingIndex].userData.worldBoundingBox = deviceBBox.worldBoundingBox;
|
|
691
|
-
} else {
|
|
692
|
-
// Create new entry
|
|
693
|
-
jsonObject.children.push({
|
|
694
|
-
uuid: deviceBBox.uuid,
|
|
695
|
-
userData: _objectSpread2(_objectSpread2({}, deviceBBox.userData), {}, {
|
|
696
|
-
worldBoundingBox: deviceBBox.worldBoundingBox
|
|
697
|
-
}),
|
|
698
|
-
children: []
|
|
699
|
-
});
|
|
700
|
-
}
|
|
701
|
-
});
|
|
702
|
-
console.log("\uD83D\uDCE6 Injected ".concat(ioDeviceBBoxes.length, " io-device bbox(es) for component ").concat(jsonObject.uuid));
|
|
703
|
-
}
|
|
704
|
-
} else if (jsonObject.userData.objectType !== 'gateway') {
|
|
705
|
-
// For non-component, non-gateway objects: standard bounding box
|
|
706
|
-
var boundingBox = new THREE.Box3().setFromObject(object);
|
|
707
|
-
jsonObject.userData.worldBoundingBox = {
|
|
708
|
-
min: boundingBox.min.toArray(),
|
|
709
|
-
max: boundingBox.max.toArray()
|
|
710
|
-
};
|
|
711
|
-
console.log("Added world bounding box:", jsonObject.userData.worldBoundingBox);
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
// For gateways and connectors, ensure userData.position exists in scene data
|
|
715
|
-
// This is REQUIRED for pathfinder compatibility
|
|
716
|
-
if (jsonObject.userData.objectType === 'gateway' || jsonObject.userData.objectType === 'connector') {
|
|
717
|
-
// Use the object's world position (from Three.js mesh)
|
|
718
|
-
var worldPos = new THREE.Vector3();
|
|
719
|
-
object.getWorldPosition(worldPos);
|
|
720
|
-
|
|
721
|
-
// ALWAYS update userData.position with world position
|
|
722
|
-
// This is critical for manual segment connectors which start with local positions
|
|
723
|
-
jsonObject.userData.position = [worldPos.x, worldPos.y, worldPos.z];
|
|
724
|
-
console.log("\u2705 Set userData.position for ".concat(jsonObject.userData.objectType, " ").concat(jsonObject.uuid, ": [").concat(worldPos.x.toFixed(2), ", ").concat(worldPos.y.toFixed(2), ", ").concat(worldPos.z.toFixed(2), "]"));
|
|
725
|
-
|
|
726
|
-
// For gateways, ensure isDeclared flag is in scene data
|
|
727
|
-
if (jsonObject.userData.objectType === 'gateway') {
|
|
728
|
-
if (jsonObject.userData.isDeclared === undefined) {
|
|
729
|
-
jsonObject.userData.isDeclared = true;
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
// For manual segment connectors, ensure isDeclared is set in scene data
|
|
734
|
-
if (jsonObject.userData.objectType === 'segment-connector' && jsonObject.userData.isDeclared === undefined) {
|
|
735
|
-
jsonObject.userData.isDeclared = true;
|
|
736
|
-
console.log("\u2705 Set isDeclared=true for manual segment connector in scene data: ".concat(jsonObject.uuid));
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
// Also sync the mesh's userData.position (belt and suspenders approach)
|
|
740
|
-
object.userData.position = [worldPos.x, worldPos.y, worldPos.z];
|
|
741
|
-
}
|
|
634
|
+
key: "_syncPositionsForPathfinding",
|
|
635
|
+
value: function _syncPositionsForPathfinding(data) {
|
|
636
|
+
var scene = this.sceneViewer.scene;
|
|
637
|
+
var worldPos = new THREE.Vector3();
|
|
638
|
+
var syncPosition = function syncPosition(jsonObject) {
|
|
639
|
+
var _jsonObject$userData;
|
|
640
|
+
var object = scene.getObjectByProperty('uuid', jsonObject.uuid) || scene.getObjectByProperty('uuid', (_jsonObject$userData = jsonObject.userData) === null || _jsonObject$userData === void 0 ? void 0 : _jsonObject$userData.originalUuid);
|
|
641
|
+
if (!object) return;
|
|
642
|
+
object.getWorldPosition(worldPos);
|
|
643
|
+
var pos = [worldPos.x, worldPos.y, worldPos.z];
|
|
644
|
+
jsonObject.userData.position = pos;
|
|
645
|
+
object.userData.position = pos;
|
|
646
|
+
};
|
|
647
|
+
data.scene.children.forEach(function (jsonObject) {
|
|
648
|
+
var _jsonObject$userData2;
|
|
649
|
+
var type = (_jsonObject$userData2 = jsonObject.userData) === null || _jsonObject$userData2 === void 0 ? void 0 : _jsonObject$userData2.objectType;
|
|
650
|
+
if (type === 'gateway') {
|
|
651
|
+
syncPosition(jsonObject);
|
|
652
|
+
if (jsonObject.userData.isDeclared === undefined) {
|
|
653
|
+
jsonObject.userData.isDeclared = true;
|
|
742
654
|
}
|
|
655
|
+
} else if (type === 'connector') {
|
|
656
|
+
syncPosition(jsonObject);
|
|
657
|
+
} else if (type === 'segment-connector') {
|
|
658
|
+
syncPosition(jsonObject);
|
|
659
|
+
if (jsonObject.userData.isDeclared === undefined) {
|
|
660
|
+
jsonObject.userData.isDeclared = true;
|
|
661
|
+
}
|
|
662
|
+
} else if (type === 'component' && Array.isArray(jsonObject.children)) {
|
|
663
|
+
// Connectors are injected as JSON children by _injectConnectorChildrenFromDictionary
|
|
664
|
+
// and their Three.js objects exist in the scene, created recursively by createSceneObject
|
|
665
|
+
jsonObject.children.forEach(function (childJson) {
|
|
666
|
+
var _childJson$userData;
|
|
667
|
+
if (((_childJson$userData = childJson.userData) === null || _childJson$userData === void 0 ? void 0 : _childJson$userData.objectType) === 'connector') {
|
|
668
|
+
syncPosition(childJson);
|
|
669
|
+
}
|
|
670
|
+
});
|
|
743
671
|
}
|
|
744
672
|
});
|
|
745
673
|
}
|
|
@@ -904,10 +832,10 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
904
832
|
var componentsProcessed = 0;
|
|
905
833
|
var connectorsInjected = 0;
|
|
906
834
|
data.scene.children.forEach(function (child) {
|
|
907
|
-
var _child$
|
|
908
|
-
var childType = ((_child$
|
|
835
|
+
var _child$userData4, _child$userData5, _child$userData6;
|
|
836
|
+
var childType = ((_child$userData4 = child.userData) === null || _child$userData4 === void 0 ? void 0 : _child$userData4.objectType) || ((_child$userData5 = child.userData) === null || _child$userData5 === void 0 ? void 0 : _child$userData5.objectType);
|
|
909
837
|
// Only process components with libraryId
|
|
910
|
-
if (childType === 'component' && (_child$
|
|
838
|
+
if (childType === 'component' && (_child$userData6 = child.userData) !== null && _child$userData6 !== void 0 && _child$userData6.libraryId) {
|
|
911
839
|
var libraryId = child.userData.libraryId;
|
|
912
840
|
var dictEntry = componentDictionary[libraryId];
|
|
913
841
|
|
|
@@ -1064,23 +992,25 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1064
992
|
geometries = this.createSceneGeometries(data, componentDictionary); // Create basic objects and track GLB replacements
|
|
1065
993
|
libraryObjectsToReplace = [];
|
|
1066
994
|
data.scene.children.forEach(function (child, index) {
|
|
1067
|
-
var _child$
|
|
995
|
+
var _child$userData7, _child$userData8;
|
|
1068
996
|
var createdObject = _this4.createSceneObject(child, geometries, materials, componentDictionary);
|
|
1069
997
|
_this4.sceneViewer.scene.add(createdObject);
|
|
1070
998
|
|
|
1071
999
|
// Track objects that need GLB model replacement
|
|
1072
|
-
if ((_child$
|
|
1073
|
-
var _child$
|
|
1000
|
+
if ((_child$userData7 = child.userData) !== null && _child$userData7 !== void 0 && _child$userData7.libraryId && componentDictionary[(_child$userData8 = child.userData) === null || _child$userData8 === void 0 ? void 0 : _child$userData8.libraryId]) {
|
|
1001
|
+
var _child$userData9;
|
|
1074
1002
|
libraryObjectsToReplace.push({
|
|
1075
1003
|
basicObject: createdObject,
|
|
1076
1004
|
jsonData: child,
|
|
1077
|
-
componentData: componentDictionary[(_child$
|
|
1005
|
+
componentData: componentDictionary[(_child$userData9 = child.userData) === null || _child$userData9 === void 0 ? void 0 : _child$userData9.libraryId]
|
|
1078
1006
|
});
|
|
1079
1007
|
}
|
|
1080
1008
|
});
|
|
1081
1009
|
|
|
1082
|
-
//
|
|
1083
|
-
|
|
1010
|
+
// Sync gateway/connector world positions into JSON before pathfinding.
|
|
1011
|
+
// Bounding boxes are computed later by PathfindingManager._enrichSceneDataWithBoundingBoxes
|
|
1012
|
+
// (after GLB models are loaded), so no bbox work is done here.
|
|
1013
|
+
this._syncPositionsForPathfinding(data);
|
|
1084
1014
|
this._saveOriginalWorldMatrices(this.sceneViewer.scene);
|
|
1085
1015
|
return _context6.a(2, {
|
|
1086
1016
|
componentDictionary: componentDictionary,
|
|
@@ -1226,8 +1156,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1226
1156
|
var instanceBehaviors = [];
|
|
1227
1157
|
if (Array.isArray(data === null || data === void 0 || (_data$scene3 = data.scene) === null || _data$scene3 === void 0 ? void 0 : _data$scene3.children)) {
|
|
1228
1158
|
data.scene.children.forEach(function (child) {
|
|
1229
|
-
var _child$
|
|
1230
|
-
var libraryId = (_child$
|
|
1159
|
+
var _child$userData0, _compData$defaultBeha;
|
|
1160
|
+
var libraryId = (_child$userData0 = child.userData) === null || _child$userData0 === void 0 ? void 0 : _child$userData0.libraryId;
|
|
1231
1161
|
if (!libraryId) return;
|
|
1232
1162
|
var instanceUuid = child.uuid;
|
|
1233
1163
|
// Skip instances whose defaults were already resolved by Step A
|
|
@@ -1423,8 +1353,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1423
1353
|
key: "_saveOriginalWorldMatrices",
|
|
1424
1354
|
value: function _saveOriginalWorldMatrices(scene) {
|
|
1425
1355
|
scene.traverse(function (object) {
|
|
1426
|
-
var _object$
|
|
1427
|
-
if ((_object$
|
|
1356
|
+
var _object$userData;
|
|
1357
|
+
if ((_object$userData = object.userData) !== null && _object$userData !== void 0 && _object$userData.direction) {
|
|
1428
1358
|
var originalMatrix = new THREE.Matrix4();
|
|
1429
1359
|
originalMatrix.copy(object.matrixWorld);
|
|
1430
1360
|
}
|
|
@@ -1628,8 +1558,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1628
1558
|
// Process children (connectors, etc.) if they exist
|
|
1629
1559
|
if (componentModel.children && componentModel.children.length > 0) {
|
|
1630
1560
|
componentModel.children.forEach(function (child) {
|
|
1631
|
-
var _child$
|
|
1632
|
-
var childType = ((_child$
|
|
1561
|
+
var _child$userData1, _child$userData10;
|
|
1562
|
+
var childType = ((_child$userData1 = child.userData) === null || _child$userData1 === void 0 ? void 0 : _child$userData1.objectType) || ((_child$userData10 = child.userData) === null || _child$userData10 === void 0 ? void 0 : _child$userData10.objectType);
|
|
1633
1563
|
if (childType === 'connector') {
|
|
1634
1564
|
var _child$geometry;
|
|
1635
1565
|
var childBoundingBox = new THREE.Box3().setFromObject(child);
|
|
@@ -1714,8 +1644,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1714
1644
|
if (segment.children && segment.children.length > 0) {
|
|
1715
1645
|
var childrenToRemove = _toConsumableArray(segment.children);
|
|
1716
1646
|
childrenToRemove.forEach(function (child) {
|
|
1717
|
-
var _child$
|
|
1718
|
-
if ((_child$
|
|
1647
|
+
var _child$userData11;
|
|
1648
|
+
if ((_child$userData11 = child.userData) !== null && _child$userData11 !== void 0 && _child$userData11.isPipeElbow) {
|
|
1719
1649
|
console.log("\uD83D\uDDD1\uFE0F Removing elbow child from segment before manualization: ".concat(child.uuid));
|
|
1720
1650
|
segment.remove(child);
|
|
1721
1651
|
if (child.geometry) child.geometry.dispose();
|
|
@@ -87,6 +87,18 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
87
87
|
// Map of viewport instances by viewType or custom key
|
|
88
88
|
_this2.viewports = new Map();
|
|
89
89
|
|
|
90
|
+
// Per-refresh-cycle bbox cache: keyed by object.uuid, cleared each refresh()
|
|
91
|
+
// so each component bbox is computed once per cycle regardless of viewport count
|
|
92
|
+
_this2._bboxCache = new Map();
|
|
93
|
+
|
|
94
|
+
// Per-refresh-cycle component list cache: eliminates redundant scene traversals
|
|
95
|
+
// when all 3 viewports render in the same cycle
|
|
96
|
+
_this2._componentListCache = null;
|
|
97
|
+
|
|
98
|
+
// rAF debounce flag — prevents multiple same-frame refresh() calls from
|
|
99
|
+
// stacking up independent renderComponents() runs
|
|
100
|
+
_this2._refreshPending = false;
|
|
101
|
+
|
|
90
102
|
// Event listener reference for cleanup
|
|
91
103
|
_this2._objectTransformedListener = null;
|
|
92
104
|
console.log('🔲 Viewport2DManager initialized (multi-instance support)');
|
|
@@ -108,7 +120,6 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
108
120
|
|
|
109
121
|
// Listen for object transformations to refresh all viewports
|
|
110
122
|
this._objectTransformedListener = function (eventData) {
|
|
111
|
-
console.log('🔲 Viewport2DManager detected object transformation, refreshing all viewports');
|
|
112
123
|
_this3.refresh(); // Refresh all viewports
|
|
113
124
|
};
|
|
114
125
|
|
|
@@ -174,6 +185,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
174
185
|
case 3:
|
|
175
186
|
// Create new viewport instance
|
|
176
187
|
viewport = new Viewport2DInstance(this.sceneViewer, this.Konva, viewType, container);
|
|
188
|
+
viewport._instanceKey = key;
|
|
177
189
|
this.viewports.set(key, viewport);
|
|
178
190
|
|
|
179
191
|
// Initialize the stage for this viewport
|
|
@@ -351,9 +363,9 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
351
363
|
viewport.stage.width(width);
|
|
352
364
|
viewport.stage.height(height);
|
|
353
365
|
|
|
354
|
-
// Redraw
|
|
366
|
+
// Redraw grid immediately; schedule debounced component render
|
|
355
367
|
this.drawGrid(viewport);
|
|
356
|
-
this.
|
|
368
|
+
this.refresh(viewport._instanceKey);
|
|
357
369
|
}
|
|
358
370
|
}
|
|
359
371
|
|
|
@@ -536,7 +548,6 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
536
548
|
worldDepth = _this$getComponentDim.worldDepth,
|
|
537
549
|
worldHeight = _this$getComponentDim.worldHeight,
|
|
538
550
|
bboxCenter = _this$getComponentDim.bboxCenter;
|
|
539
|
-
console.log("[2D] ".concat(component.name, " | w=").concat(worldWidth.toFixed(3), " d=").concat(worldDepth.toFixed(3), " h=").concat(worldHeight.toFixed(3), " | center=(").concat(bboxCenter.x.toFixed(2), ",").concat(bboxCenter.y.toFixed(2), ",").concat(bboxCenter.z.toFixed(2), ")"));
|
|
540
551
|
|
|
541
552
|
// Project 3D bbox center to 2D based on view type
|
|
542
553
|
var _this$project3DTo2D = this.project3DTo2D(viewport, bboxCenter, worldWidth, worldDepth, worldHeight),
|
|
@@ -603,21 +614,45 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
603
614
|
}, {
|
|
604
615
|
key: "_getOrComputeWorldBoundingBox",
|
|
605
616
|
value: function _getOrComputeWorldBoundingBox(object) {
|
|
606
|
-
|
|
617
|
+
var _object$userData, _object$userData2;
|
|
618
|
+
// Fast path: offset the stored world bbox by the position delta since load time.
|
|
619
|
+
// Translation only shifts the bbox center — extents stay identical — so this is O(1)
|
|
620
|
+
// instead of O(meshes × vertices) from a full geometry traversal.
|
|
621
|
+
var stored = (_object$userData = object.userData) === null || _object$userData === void 0 ? void 0 : _object$userData.worldBoundingBox;
|
|
622
|
+
var basePos = (_object$userData2 = object.userData) === null || _object$userData2 === void 0 ? void 0 : _object$userData2._wbbBasePosition;
|
|
623
|
+
if (stored && basePos) {
|
|
624
|
+
var dx = object.position.x - basePos.x;
|
|
625
|
+
var dy = object.position.y - basePos.y;
|
|
626
|
+
var dz = object.position.z - basePos.z;
|
|
627
|
+
if (dx === 0 && dy === 0 && dz === 0) return stored;
|
|
628
|
+
return {
|
|
629
|
+
min: [stored.min[0] + dx, stored.min[1] + dy, stored.min[2] + dz],
|
|
630
|
+
max: [stored.max[0] + dx, stored.max[1] + dy, stored.max[2] + dz]
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Slow path: full vertex-accurate traversal (fallback when userData not populated)
|
|
635
|
+
if (this._bboxCache.has(object.uuid)) {
|
|
636
|
+
return this._bboxCache.get(object.uuid);
|
|
637
|
+
}
|
|
607
638
|
var box = computeFilteredBoundingBox(object, []);
|
|
639
|
+
var result;
|
|
608
640
|
if (box.isEmpty()) {
|
|
609
641
|
// Object has no geometry; fall back to a point at world position
|
|
610
642
|
var wp = new THREE.Vector3();
|
|
611
643
|
object.getWorldPosition(wp);
|
|
612
|
-
|
|
644
|
+
result = {
|
|
613
645
|
min: [wp.x, wp.y, wp.z],
|
|
614
646
|
max: [wp.x, wp.y, wp.z]
|
|
615
647
|
};
|
|
648
|
+
} else {
|
|
649
|
+
result = {
|
|
650
|
+
min: [box.min.x, box.min.y, box.min.z],
|
|
651
|
+
max: [box.max.x, box.max.y, box.max.z]
|
|
652
|
+
};
|
|
616
653
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
max: [box.max.x, box.max.y, box.max.z]
|
|
620
|
-
};
|
|
654
|
+
this._bboxCache.set(object.uuid, result);
|
|
655
|
+
return result;
|
|
621
656
|
}
|
|
622
657
|
|
|
623
658
|
/**
|
|
@@ -626,11 +661,12 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
626
661
|
}, {
|
|
627
662
|
key: "getComponentDimensions",
|
|
628
663
|
value: function getComponentDimensions(component) {
|
|
629
|
-
var _component$
|
|
630
|
-
//
|
|
631
|
-
//
|
|
632
|
-
//
|
|
633
|
-
|
|
664
|
+
var _component$getWorldPo;
|
|
665
|
+
// Always recompute from the live Three.js object so that the rect reflects
|
|
666
|
+
// the current world position after translate/drag operations.
|
|
667
|
+
// userData.worldBoundingBox is a load-time snapshot and goes stale whenever
|
|
668
|
+
// the object moves, so we cannot rely on it here.
|
|
669
|
+
var wbb = this._getOrComputeWorldBoundingBox(component);
|
|
634
670
|
if (wbb !== null && wbb !== void 0 && wbb.min && wbb !== null && wbb !== void 0 && wbb.max) {
|
|
635
671
|
var _wbb$min = _slicedToArray(wbb.min, 3),
|
|
636
672
|
minX = _wbb$min[0],
|
|
@@ -741,7 +777,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
741
777
|
rect.stroke('#007bff');
|
|
742
778
|
rect.strokeWidth(3);
|
|
743
779
|
viewport.stage.container().style.cursor = 'grab';
|
|
744
|
-
viewport.componentLayer.
|
|
780
|
+
viewport.componentLayer.batchDraw();
|
|
745
781
|
}
|
|
746
782
|
});
|
|
747
783
|
rect.on('mouseleave', function () {
|
|
@@ -750,7 +786,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
750
786
|
rect.stroke(colors.stroke);
|
|
751
787
|
rect.strokeWidth(2);
|
|
752
788
|
viewport.stage.container().style.cursor = 'default';
|
|
753
|
-
viewport.componentLayer.
|
|
789
|
+
viewport.componentLayer.batchDraw();
|
|
754
790
|
}
|
|
755
791
|
});
|
|
756
792
|
|
|
@@ -794,7 +830,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
794
830
|
// Snap to grid
|
|
795
831
|
var snappedPos = _this6.snapScreenToGrid(viewport, currentPos.x, currentPos.y, scale, worldOriginX, worldOriginY);
|
|
796
832
|
componentGroup.position(snappedPos);
|
|
797
|
-
viewport.componentLayer.
|
|
833
|
+
viewport.componentLayer.batchDraw();
|
|
798
834
|
});
|
|
799
835
|
|
|
800
836
|
// DRAG END
|
|
@@ -967,18 +1003,20 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
967
1003
|
}, {
|
|
968
1004
|
key: "getSceneComponents",
|
|
969
1005
|
value: function getSceneComponents() {
|
|
1006
|
+
if (this._componentListCache) return this._componentListCache;
|
|
970
1007
|
if (!this.sceneViewer || !this.sceneViewer.scene) {
|
|
971
1008
|
return [];
|
|
972
1009
|
}
|
|
973
1010
|
var components = [];
|
|
974
1011
|
this.sceneViewer.scene.traverse(function (object) {
|
|
975
|
-
var _object$
|
|
1012
|
+
var _object$userData3, _object$userData4;
|
|
976
1013
|
// Only match the ROOT component object — must have both objectType:'component'
|
|
977
1014
|
// AND libraryId (inner GLB mesh nodes don't have libraryId)
|
|
978
|
-
if (((_object$
|
|
1015
|
+
if (((_object$userData3 = object.userData) === null || _object$userData3 === void 0 ? void 0 : _object$userData3.objectType) === 'component' && (_object$userData4 = object.userData) !== null && _object$userData4 !== void 0 && _object$userData4.libraryId) {
|
|
979
1016
|
components.push(object);
|
|
980
1017
|
}
|
|
981
1018
|
});
|
|
1019
|
+
this._componentListCache = components;
|
|
982
1020
|
return components;
|
|
983
1021
|
}
|
|
984
1022
|
|
|
@@ -1084,35 +1122,45 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
1084
1122
|
}
|
|
1085
1123
|
|
|
1086
1124
|
/**
|
|
1087
|
-
* Refresh a specific viewport or all viewports
|
|
1125
|
+
* Refresh a specific viewport or all viewports.
|
|
1126
|
+
* Debounced via requestAnimationFrame so multiple calls within the same
|
|
1127
|
+
* frame (e.g. from Viewport2D mount + refreshAll2DViews) collapse into one.
|
|
1088
1128
|
* @param {string} key - Optional viewport key. If not provided, refreshes all viewports
|
|
1089
1129
|
*/
|
|
1090
1130
|
}, {
|
|
1091
1131
|
key: "refresh",
|
|
1092
1132
|
value: function refresh() {
|
|
1133
|
+
var _this7 = this;
|
|
1093
1134
|
var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
1094
|
-
if (
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1135
|
+
if (this._refreshPending) return;
|
|
1136
|
+
this._refreshPending = true;
|
|
1137
|
+
requestAnimationFrame(function () {
|
|
1138
|
+
_this7._refreshPending = false;
|
|
1139
|
+
// Clear per-cycle caches so each component is measured/traversed once per paint
|
|
1140
|
+
_this7._bboxCache.clear();
|
|
1141
|
+
_this7._componentListCache = null;
|
|
1142
|
+
if (key) {
|
|
1143
|
+
var viewport = _this7.viewports.get(key);
|
|
1144
|
+
if (viewport && viewport.isReady) {
|
|
1145
|
+
_this7.renderComponents(viewport);
|
|
1146
|
+
}
|
|
1147
|
+
} else {
|
|
1148
|
+
var _iterator = _createForOfIteratorHelper(_this7.viewports.values()),
|
|
1149
|
+
_step;
|
|
1150
|
+
try {
|
|
1151
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1152
|
+
var _viewport = _step.value;
|
|
1153
|
+
if (_viewport.isReady) {
|
|
1154
|
+
_this7.renderComponents(_viewport);
|
|
1155
|
+
}
|
|
1108
1156
|
}
|
|
1157
|
+
} catch (err) {
|
|
1158
|
+
_iterator.e(err);
|
|
1159
|
+
} finally {
|
|
1160
|
+
_iterator.f();
|
|
1109
1161
|
}
|
|
1110
|
-
} catch (err) {
|
|
1111
|
-
_iterator.e(err);
|
|
1112
|
-
} finally {
|
|
1113
|
-
_iterator.f();
|
|
1114
1162
|
}
|
|
1115
|
-
}
|
|
1163
|
+
});
|
|
1116
1164
|
}
|
|
1117
1165
|
|
|
1118
1166
|
/**
|
|
@@ -222,10 +222,10 @@ var SceneClearingUtility = /*#__PURE__*/function () {
|
|
|
222
222
|
throw new Error('Scene not available for clearing');
|
|
223
223
|
case 1:
|
|
224
224
|
componentsToRemove = [];
|
|
225
|
-
scene = this.sceneViewer.scene; // Collect
|
|
225
|
+
scene = this.sceneViewer.scene; // Collect component, segment, and gateway objects
|
|
226
226
|
scene.traverse(function (child) {
|
|
227
227
|
if (child === scene) return;
|
|
228
|
-
var isComponent = child.userData && (child.userData.objectType === 'component' || child.userData.objectType === '
|
|
228
|
+
var isComponent = child.userData && (child.userData.objectType === 'component' || child.userData.objectType === 'segment' || child.userData.objectType === 'gateway' || child.userData.objectType === 'connector');
|
|
229
229
|
var isDirectChild = child.parent === scene;
|
|
230
230
|
if (isComponent && isDirectChild) {
|
|
231
231
|
componentsToRemove.push(child);
|