@2112-lab/central-plant 0.3.4 → 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 +286 -272
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/managers/scene/modelManager.js +20 -6
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +62 -132
- package/dist/cjs/src/managers/scene/viewport2DManager.js +203 -129
- 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 +20 -6
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +63 -133
- package/dist/esm/src/managers/scene/viewport2DManager.js +202 -130
- package/dist/esm/src/utils/sceneClearingUtility.js +2 -2
- package/package.json +1 -1
|
@@ -4,6 +4,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHelpers.js');
|
|
6
6
|
var baseDisposable = require('../../core/baseDisposable.js');
|
|
7
|
+
var THREE = require('three');
|
|
8
|
+
var boundingBoxUtils = require('../../utils/boundingBoxUtils.js');
|
|
7
9
|
|
|
8
10
|
function _interopNamespace(e) {
|
|
9
11
|
if (e && e.__esModule) return e;
|
|
@@ -23,6 +25,8 @@ function _interopNamespace(e) {
|
|
|
23
25
|
return Object.freeze(n);
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
29
|
+
|
|
26
30
|
/**
|
|
27
31
|
* Viewport2DInstance
|
|
28
32
|
* Represents a single 2D viewport with its own Konva stage and configuration
|
|
@@ -107,6 +111,18 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
107
111
|
// Map of viewport instances by viewType or custom key
|
|
108
112
|
_this2.viewports = new Map();
|
|
109
113
|
|
|
114
|
+
// Per-refresh-cycle bbox cache: keyed by object.uuid, cleared each refresh()
|
|
115
|
+
// so each component bbox is computed once per cycle regardless of viewport count
|
|
116
|
+
_this2._bboxCache = new Map();
|
|
117
|
+
|
|
118
|
+
// Per-refresh-cycle component list cache: eliminates redundant scene traversals
|
|
119
|
+
// when all 3 viewports render in the same cycle
|
|
120
|
+
_this2._componentListCache = null;
|
|
121
|
+
|
|
122
|
+
// rAF debounce flag — prevents multiple same-frame refresh() calls from
|
|
123
|
+
// stacking up independent renderComponents() runs
|
|
124
|
+
_this2._refreshPending = false;
|
|
125
|
+
|
|
110
126
|
// Event listener reference for cleanup
|
|
111
127
|
_this2._objectTransformedListener = null;
|
|
112
128
|
console.log('🔲 Viewport2DManager initialized (multi-instance support)');
|
|
@@ -128,7 +144,6 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
128
144
|
|
|
129
145
|
// Listen for object transformations to refresh all viewports
|
|
130
146
|
this._objectTransformedListener = function (eventData) {
|
|
131
|
-
console.log('🔲 Viewport2DManager detected object transformation, refreshing all viewports');
|
|
132
147
|
_this3.refresh(); // Refresh all viewports
|
|
133
148
|
};
|
|
134
149
|
|
|
@@ -194,6 +209,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
194
209
|
case 3:
|
|
195
210
|
// Create new viewport instance
|
|
196
211
|
viewport = new Viewport2DInstance(this.sceneViewer, this.Konva, viewType, container);
|
|
212
|
+
viewport._instanceKey = key;
|
|
197
213
|
this.viewports.set(key, viewport);
|
|
198
214
|
|
|
199
215
|
// Initialize the stage for this viewport
|
|
@@ -371,9 +387,9 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
371
387
|
viewport.stage.width(width);
|
|
372
388
|
viewport.stage.height(height);
|
|
373
389
|
|
|
374
|
-
// Redraw
|
|
390
|
+
// Redraw grid immediately; schedule debounced component render
|
|
375
391
|
this.drawGrid(viewport);
|
|
376
|
-
this.
|
|
392
|
+
this.refresh(viewport._instanceKey);
|
|
377
393
|
}
|
|
378
394
|
}
|
|
379
395
|
|
|
@@ -550,32 +566,19 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
550
566
|
}, {
|
|
551
567
|
key: "renderComponent",
|
|
552
568
|
value: function renderComponent(viewport, component, centerX, centerY, scale) {
|
|
553
|
-
|
|
554
|
-
// Get component position and rotation
|
|
555
|
-
var pos3D = {
|
|
556
|
-
x: (_component$position$x = (_component$position = component.position) === null || _component$position === void 0 ? void 0 : _component$position.x) !== null && _component$position$x !== void 0 ? _component$position$x : 0,
|
|
557
|
-
y: (_component$position$y = (_component$position2 = component.position) === null || _component$position2 === void 0 ? void 0 : _component$position2.y) !== null && _component$position$y !== void 0 ? _component$position$y : 0,
|
|
558
|
-
z: (_component$position$z = (_component$position3 = component.position) === null || _component$position3 === void 0 ? void 0 : _component$position3.z) !== null && _component$position$z !== void 0 ? _component$position$z : 0
|
|
559
|
-
};
|
|
560
|
-
var rot3D = {
|
|
561
|
-
x: (_component$rotation$x = (_component$rotation = component.rotation) === null || _component$rotation === void 0 ? void 0 : _component$rotation.x) !== null && _component$rotation$x !== void 0 ? _component$rotation$x : 0,
|
|
562
|
-
y: (_component$rotation$y = (_component$rotation2 = component.rotation) === null || _component$rotation2 === void 0 ? void 0 : _component$rotation2.y) !== null && _component$rotation$y !== void 0 ? _component$rotation$y : 0,
|
|
563
|
-
z: (_component$rotation$z = (_component$rotation3 = component.rotation) === null || _component$rotation3 === void 0 ? void 0 : _component$rotation3.z) !== null && _component$rotation$z !== void 0 ? _component$rotation$z : 0
|
|
564
|
-
};
|
|
565
|
-
|
|
566
|
-
// Get bounding box dimensions
|
|
569
|
+
// Get world-space bounding box dimensions and center
|
|
567
570
|
var _this$getComponentDim = this.getComponentDimensions(component),
|
|
568
571
|
worldWidth = _this$getComponentDim.worldWidth,
|
|
569
572
|
worldDepth = _this$getComponentDim.worldDepth,
|
|
570
|
-
worldHeight = _this$getComponentDim.worldHeight
|
|
573
|
+
worldHeight = _this$getComponentDim.worldHeight,
|
|
574
|
+
bboxCenter = _this$getComponentDim.bboxCenter;
|
|
571
575
|
|
|
572
|
-
// Project 3D
|
|
573
|
-
var _this$project3DTo2D = this.project3DTo2D(viewport,
|
|
576
|
+
// Project 3D bbox center to 2D based on view type
|
|
577
|
+
var _this$project3DTo2D = this.project3DTo2D(viewport, bboxCenter, worldWidth, worldDepth, worldHeight),
|
|
574
578
|
posX = _this$project3DTo2D.posX,
|
|
575
579
|
posY = _this$project3DTo2D.posY,
|
|
576
580
|
rectWidth = _this$project3DTo2D.rectWidth,
|
|
577
581
|
rectHeight = _this$project3DTo2D.rectHeight;
|
|
578
|
-
_this$project3DTo2D.rotationDegrees;
|
|
579
582
|
var screenX = centerX + posX * scale;
|
|
580
583
|
var screenY = centerY - posY * scale; // Flip Y for screen coords
|
|
581
584
|
|
|
@@ -619,105 +622,156 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
619
622
|
});
|
|
620
623
|
|
|
621
624
|
// Add mouse event handlers
|
|
622
|
-
this.addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight);
|
|
625
|
+
this.addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter);
|
|
623
626
|
componentGroup.add(rect);
|
|
624
627
|
componentGroup.add(label);
|
|
625
628
|
viewport.componentLayer.add(componentGroup);
|
|
626
629
|
}
|
|
627
630
|
|
|
628
631
|
/**
|
|
629
|
-
*
|
|
632
|
+
* Compute worldBoundingBox for a live Three.js Object3D using the same
|
|
633
|
+
* vertex-accurate approach as computeFilteredBoundingBox (explicitly calls
|
|
634
|
+
* geometry.computeBoundingBox() on each mesh before measuring).
|
|
635
|
+
* @param {THREE.Object3D} object
|
|
636
|
+
* @returns {{min: number[], max: number[]}}
|
|
637
|
+
*/
|
|
638
|
+
}, {
|
|
639
|
+
key: "_getOrComputeWorldBoundingBox",
|
|
640
|
+
value: function _getOrComputeWorldBoundingBox(object) {
|
|
641
|
+
var _object$userData, _object$userData2;
|
|
642
|
+
// Fast path: offset the stored world bbox by the position delta since load time.
|
|
643
|
+
// Translation only shifts the bbox center — extents stay identical — so this is O(1)
|
|
644
|
+
// instead of O(meshes × vertices) from a full geometry traversal.
|
|
645
|
+
var stored = (_object$userData = object.userData) === null || _object$userData === void 0 ? void 0 : _object$userData.worldBoundingBox;
|
|
646
|
+
var basePos = (_object$userData2 = object.userData) === null || _object$userData2 === void 0 ? void 0 : _object$userData2._wbbBasePosition;
|
|
647
|
+
if (stored && basePos) {
|
|
648
|
+
var dx = object.position.x - basePos.x;
|
|
649
|
+
var dy = object.position.y - basePos.y;
|
|
650
|
+
var dz = object.position.z - basePos.z;
|
|
651
|
+
if (dx === 0 && dy === 0 && dz === 0) return stored;
|
|
652
|
+
return {
|
|
653
|
+
min: [stored.min[0] + dx, stored.min[1] + dy, stored.min[2] + dz],
|
|
654
|
+
max: [stored.max[0] + dx, stored.max[1] + dy, stored.max[2] + dz]
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Slow path: full vertex-accurate traversal (fallback when userData not populated)
|
|
659
|
+
if (this._bboxCache.has(object.uuid)) {
|
|
660
|
+
return this._bboxCache.get(object.uuid);
|
|
661
|
+
}
|
|
662
|
+
var box = boundingBoxUtils.computeFilteredBoundingBox(object, []);
|
|
663
|
+
var result;
|
|
664
|
+
if (box.isEmpty()) {
|
|
665
|
+
// Object has no geometry; fall back to a point at world position
|
|
666
|
+
var wp = new THREE__namespace.Vector3();
|
|
667
|
+
object.getWorldPosition(wp);
|
|
668
|
+
result = {
|
|
669
|
+
min: [wp.x, wp.y, wp.z],
|
|
670
|
+
max: [wp.x, wp.y, wp.z]
|
|
671
|
+
};
|
|
672
|
+
} else {
|
|
673
|
+
result = {
|
|
674
|
+
min: [box.min.x, box.min.y, box.min.z],
|
|
675
|
+
max: [box.max.x, box.max.y, box.max.z]
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
this._bboxCache.set(object.uuid, result);
|
|
679
|
+
return result;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Get component dimensions and world-space center from worldBoundingBox
|
|
630
684
|
*/
|
|
631
685
|
}, {
|
|
632
686
|
key: "getComponentDimensions",
|
|
633
687
|
value: function getComponentDimensions(component) {
|
|
634
|
-
var _component$
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
if (
|
|
641
|
-
var
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
688
|
+
var _component$getWorldPo;
|
|
689
|
+
// Always recompute from the live Three.js object so that the rect reflects
|
|
690
|
+
// the current world position after translate/drag operations.
|
|
691
|
+
// userData.worldBoundingBox is a load-time snapshot and goes stale whenever
|
|
692
|
+
// the object moves, so we cannot rely on it here.
|
|
693
|
+
var wbb = this._getOrComputeWorldBoundingBox(component);
|
|
694
|
+
if (wbb !== null && wbb !== void 0 && wbb.min && wbb !== null && wbb !== void 0 && wbb.max) {
|
|
695
|
+
var _wbb$min = _rollupPluginBabelHelpers.slicedToArray(wbb.min, 3),
|
|
696
|
+
minX = _wbb$min[0],
|
|
697
|
+
minY = _wbb$min[1],
|
|
698
|
+
minZ = _wbb$min[2];
|
|
699
|
+
var _wbb$max = _rollupPluginBabelHelpers.slicedToArray(wbb.max, 3),
|
|
700
|
+
maxX = _wbb$max[0],
|
|
701
|
+
maxY = _wbb$max[1],
|
|
702
|
+
maxZ = _wbb$max[2];
|
|
703
|
+
var cx = (minX + maxX) / 2;
|
|
704
|
+
var cy = (minY + maxY) / 2;
|
|
705
|
+
var cz = (minZ + maxZ) / 2;
|
|
706
|
+
// Guard against Infinity/NaN from empty or degenerate boxes
|
|
707
|
+
if (isFinite(cx) && isFinite(cy) && isFinite(cz)) {
|
|
708
|
+
return {
|
|
709
|
+
worldWidth: Math.max(maxX - minX, 0.01),
|
|
710
|
+
worldDepth: Math.max(maxY - minY, 0.01),
|
|
711
|
+
worldHeight: Math.max(maxZ - minZ, 0.01),
|
|
712
|
+
bboxCenter: {
|
|
713
|
+
x: cx,
|
|
714
|
+
y: cy,
|
|
715
|
+
z: cz
|
|
716
|
+
}
|
|
717
|
+
};
|
|
646
718
|
}
|
|
647
719
|
}
|
|
648
|
-
// Fallback
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
worldWidth = Math.abs(dims.x);
|
|
652
|
-
worldDepth = Math.abs(dims.y);
|
|
653
|
-
worldHeight = Math.abs(dims.z);
|
|
654
|
-
}
|
|
655
|
-
// Last resort: geometry bounding box
|
|
656
|
-
else if ((_component$geometry = component.geometry) !== null && _component$geometry !== void 0 && _component$geometry.boundingBox) {
|
|
657
|
-
var _bbox = component.geometry.boundingBox;
|
|
658
|
-
worldWidth = Math.abs(_bbox.max.x - _bbox.min.x);
|
|
659
|
-
worldDepth = Math.abs(_bbox.max.y - _bbox.min.y);
|
|
660
|
-
worldHeight = Math.abs(_bbox.max.z - _bbox.min.z);
|
|
661
|
-
}
|
|
720
|
+
// Fallback: world position of the object, unit dimensions
|
|
721
|
+
var wp = new THREE__namespace.Vector3();
|
|
722
|
+
(_component$getWorldPo = component.getWorldPosition) === null || _component$getWorldPo === void 0 || _component$getWorldPo.call(component, wp);
|
|
662
723
|
return {
|
|
663
|
-
worldWidth:
|
|
664
|
-
worldDepth:
|
|
665
|
-
worldHeight:
|
|
724
|
+
worldWidth: 1,
|
|
725
|
+
worldDepth: 1,
|
|
726
|
+
worldHeight: 1,
|
|
727
|
+
bboxCenter: {
|
|
728
|
+
x: wp.x,
|
|
729
|
+
y: wp.y,
|
|
730
|
+
z: wp.z
|
|
731
|
+
}
|
|
666
732
|
};
|
|
667
733
|
}
|
|
668
734
|
|
|
669
735
|
/**
|
|
670
|
-
* Project
|
|
736
|
+
* Project world-space bbox center to 2D based on view type.
|
|
737
|
+
* worldBoundingBox is an AABB so rotation is already encoded in the extents —
|
|
738
|
+
* no separate rotation correction is needed.
|
|
671
739
|
* @param {Viewport2DInstance} viewport - The viewport instance
|
|
740
|
+
* @param {Object} bboxCenter - World-space center {x, y, z}
|
|
741
|
+
* @param {number} worldWidth - X extent (max[0] - min[0])
|
|
742
|
+
* @param {number} worldDepth - Y extent (max[1] - min[1])
|
|
743
|
+
* @param {number} worldHeight - Z extent (max[2] - min[2])
|
|
672
744
|
*/
|
|
673
745
|
}, {
|
|
674
746
|
key: "project3DTo2D",
|
|
675
|
-
value: function project3DTo2D(viewport,
|
|
676
|
-
var posX, posY, rectWidth, rectHeight;
|
|
677
|
-
var rotationAngle = rot3D.z;
|
|
678
|
-
var rotationDegrees = rotationAngle * 180 / Math.PI;
|
|
747
|
+
value: function project3DTo2D(viewport, bboxCenter, worldWidth, worldDepth, worldHeight) {
|
|
679
748
|
var scale = viewport.PIXELS_PER_UNIT;
|
|
749
|
+
var posX, posY, rectWidth, rectHeight;
|
|
680
750
|
switch (viewport.viewType) {
|
|
681
751
|
case 'top':
|
|
682
|
-
//
|
|
683
|
-
posX =
|
|
684
|
-
posY =
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
if (Math.abs(rotationDegrees) === 90 || Math.abs(rotationDegrees) === 270) {
|
|
688
|
-
rectWidth = worldDepth * scale;
|
|
689
|
-
rectHeight = worldWidth * scale;
|
|
690
|
-
} else {
|
|
691
|
-
rectWidth = worldWidth * scale;
|
|
692
|
-
rectHeight = worldDepth * scale;
|
|
693
|
-
}
|
|
752
|
+
// Looking down Z-axis — X/Y plane
|
|
753
|
+
posX = bboxCenter.x;
|
|
754
|
+
posY = bboxCenter.y;
|
|
755
|
+
rectWidth = worldWidth * scale;
|
|
756
|
+
rectHeight = worldDepth * scale;
|
|
694
757
|
break;
|
|
695
758
|
case 'front':
|
|
696
|
-
//
|
|
697
|
-
posX =
|
|
698
|
-
posY =
|
|
699
|
-
|
|
700
|
-
if (Math.abs(rotationDegrees) === 90 || Math.abs(rotationDegrees) === 270) {
|
|
701
|
-
rectWidth = worldDepth * scale;
|
|
702
|
-
} else {
|
|
703
|
-
rectWidth = worldWidth * scale;
|
|
704
|
-
}
|
|
759
|
+
// Looking along Y-axis — X/Z plane
|
|
760
|
+
posX = bboxCenter.x;
|
|
761
|
+
posY = bboxCenter.z;
|
|
762
|
+
rectWidth = worldWidth * scale;
|
|
705
763
|
rectHeight = worldHeight * scale;
|
|
706
764
|
break;
|
|
707
765
|
case 'side':
|
|
708
|
-
//
|
|
709
|
-
posX = -
|
|
710
|
-
posY =
|
|
711
|
-
|
|
712
|
-
rectWidth = worldWidth * scale;
|
|
713
|
-
} else {
|
|
714
|
-
rectWidth = worldDepth * scale;
|
|
715
|
-
}
|
|
766
|
+
// Looking along X-axis — Y/Z plane (Y negated for left-right orientation)
|
|
767
|
+
posX = -bboxCenter.y;
|
|
768
|
+
posY = bboxCenter.z;
|
|
769
|
+
rectWidth = worldDepth * scale;
|
|
716
770
|
rectHeight = worldHeight * scale;
|
|
717
771
|
break;
|
|
718
772
|
default:
|
|
719
|
-
posX =
|
|
720
|
-
posY =
|
|
773
|
+
posX = bboxCenter.x;
|
|
774
|
+
posY = bboxCenter.y;
|
|
721
775
|
rectWidth = worldWidth * scale;
|
|
722
776
|
rectHeight = worldDepth * scale;
|
|
723
777
|
}
|
|
@@ -725,8 +779,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
725
779
|
posX: posX,
|
|
726
780
|
posY: posY,
|
|
727
781
|
rectWidth: rectWidth,
|
|
728
|
-
rectHeight: rectHeight
|
|
729
|
-
rotationDegrees: rotationDegrees
|
|
782
|
+
rectHeight: rectHeight
|
|
730
783
|
};
|
|
731
784
|
}
|
|
732
785
|
|
|
@@ -736,7 +789,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
736
789
|
*/
|
|
737
790
|
}, {
|
|
738
791
|
key: "addComponentInteractions",
|
|
739
|
-
value: function addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight) {
|
|
792
|
+
value: function addComponentInteractions(viewport, rect, componentGroup, component, worldWidth, worldDepth, worldHeight, bboxCenter) {
|
|
740
793
|
var _this6 = this;
|
|
741
794
|
if (!this.Konva) return;
|
|
742
795
|
var colors = this.generateComponentColor(component.id);
|
|
@@ -748,7 +801,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
748
801
|
rect.stroke('#007bff');
|
|
749
802
|
rect.strokeWidth(3);
|
|
750
803
|
viewport.stage.container().style.cursor = 'grab';
|
|
751
|
-
viewport.componentLayer.
|
|
804
|
+
viewport.componentLayer.batchDraw();
|
|
752
805
|
}
|
|
753
806
|
});
|
|
754
807
|
rect.on('mouseleave', function () {
|
|
@@ -757,7 +810,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
757
810
|
rect.stroke(colors.stroke);
|
|
758
811
|
rect.strokeWidth(2);
|
|
759
812
|
viewport.stage.container().style.cursor = 'default';
|
|
760
|
-
viewport.componentLayer.
|
|
813
|
+
viewport.componentLayer.batchDraw();
|
|
761
814
|
}
|
|
762
815
|
});
|
|
763
816
|
|
|
@@ -801,7 +854,7 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
801
854
|
// Snap to grid
|
|
802
855
|
var snappedPos = _this6.snapScreenToGrid(viewport, currentPos.x, currentPos.y, scale, worldOriginX, worldOriginY);
|
|
803
856
|
componentGroup.position(snappedPos);
|
|
804
|
-
viewport.componentLayer.
|
|
857
|
+
viewport.componentLayer.batchDraw();
|
|
805
858
|
});
|
|
806
859
|
|
|
807
860
|
// DRAG END
|
|
@@ -819,9 +872,9 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
819
872
|
// Convert screen to world coordinates
|
|
820
873
|
var worldCoords = _this6.screenToWorldCoords(viewport, finalPos.x, finalPos.y, scale, worldOriginX, worldOriginY);
|
|
821
874
|
|
|
822
|
-
// Calculate new position
|
|
875
|
+
// Calculate new position: delta from old bbox center to new bbox center
|
|
823
876
|
var currentPos = component.position;
|
|
824
|
-
var newPosition = _this6.worldCoordsToObjectPosition(viewport, worldCoords, currentPos,
|
|
877
|
+
var newPosition = _this6.worldCoordsToObjectPosition(viewport, worldCoords, currentPos, bboxCenter);
|
|
825
878
|
|
|
826
879
|
// Apply translation via centralPlant API
|
|
827
880
|
var deltaX = newPosition.x - currentPos.x;
|
|
@@ -924,37 +977,45 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
924
977
|
}
|
|
925
978
|
|
|
926
979
|
/**
|
|
927
|
-
* Convert world coordinates to 3D object position
|
|
980
|
+
* Convert dragged 2D world coordinates to a new 3D object position.
|
|
981
|
+
* coord1/coord2 represent where the bbox CENTER should be in the view's 2D plane;
|
|
982
|
+
* we compute the delta from the old bbox center and apply it to the pivot position.
|
|
928
983
|
* @param {Viewport2DInstance} viewport - The viewport instance
|
|
984
|
+
* @param {{coord1, coord2}} worldCoords - Projected world coordinates from screen
|
|
985
|
+
* @param {{x,y,z}} currentPosition - Current Three.js object position (pivot)
|
|
986
|
+
* @param {{x,y,z}} bboxCenter - Old world-space bbox center
|
|
929
987
|
*/
|
|
930
988
|
}, {
|
|
931
989
|
key: "worldCoordsToObjectPosition",
|
|
932
|
-
value: function worldCoordsToObjectPosition(viewport, worldCoords, currentPosition,
|
|
990
|
+
value: function worldCoordsToObjectPosition(viewport, worldCoords, currentPosition, bboxCenter) {
|
|
933
991
|
var coord1 = worldCoords.coord1,
|
|
934
992
|
coord2 = worldCoords.coord2;
|
|
935
993
|
switch (viewport.viewType) {
|
|
936
994
|
case 'top':
|
|
995
|
+
// coord1=X, coord2=Y in world space
|
|
937
996
|
return {
|
|
938
|
-
x: coord1,
|
|
939
|
-
y: coord2,
|
|
997
|
+
x: currentPosition.x + (coord1 - bboxCenter.x),
|
|
998
|
+
y: currentPosition.y + (coord2 - bboxCenter.y),
|
|
940
999
|
z: currentPosition.z
|
|
941
1000
|
};
|
|
942
1001
|
case 'front':
|
|
1002
|
+
// coord1=X, coord2=Z in world space
|
|
943
1003
|
return {
|
|
944
|
-
x: coord1,
|
|
1004
|
+
x: currentPosition.x + (coord1 - bboxCenter.x),
|
|
945
1005
|
y: currentPosition.y,
|
|
946
|
-
z: coord2 -
|
|
1006
|
+
z: currentPosition.z + (coord2 - bboxCenter.z)
|
|
947
1007
|
};
|
|
948
1008
|
case 'side':
|
|
1009
|
+
// coord1=-Y (negated), coord2=Z in world space
|
|
949
1010
|
return {
|
|
950
1011
|
x: currentPosition.x,
|
|
951
|
-
y: -coord1,
|
|
952
|
-
z: coord2 -
|
|
1012
|
+
y: currentPosition.y + (-coord1 - bboxCenter.y),
|
|
1013
|
+
z: currentPosition.z + (coord2 - bboxCenter.z)
|
|
953
1014
|
};
|
|
954
1015
|
default:
|
|
955
1016
|
return {
|
|
956
|
-
x: coord1,
|
|
957
|
-
y: coord2,
|
|
1017
|
+
x: currentPosition.x + (coord1 - bboxCenter.x),
|
|
1018
|
+
y: currentPosition.y + (coord2 - bboxCenter.y),
|
|
958
1019
|
z: currentPosition.z
|
|
959
1020
|
};
|
|
960
1021
|
}
|
|
@@ -966,17 +1027,20 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
966
1027
|
}, {
|
|
967
1028
|
key: "getSceneComponents",
|
|
968
1029
|
value: function getSceneComponents() {
|
|
1030
|
+
if (this._componentListCache) return this._componentListCache;
|
|
969
1031
|
if (!this.sceneViewer || !this.sceneViewer.scene) {
|
|
970
1032
|
return [];
|
|
971
1033
|
}
|
|
972
1034
|
var components = [];
|
|
973
1035
|
this.sceneViewer.scene.traverse(function (object) {
|
|
974
|
-
var _object$
|
|
975
|
-
|
|
976
|
-
|
|
1036
|
+
var _object$userData3, _object$userData4;
|
|
1037
|
+
// Only match the ROOT component object — must have both objectType:'component'
|
|
1038
|
+
// AND libraryId (inner GLB mesh nodes don't have libraryId)
|
|
1039
|
+
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) {
|
|
977
1040
|
components.push(object);
|
|
978
1041
|
}
|
|
979
1042
|
});
|
|
1043
|
+
this._componentListCache = components;
|
|
980
1044
|
return components;
|
|
981
1045
|
}
|
|
982
1046
|
|
|
@@ -1082,35 +1146,45 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
1082
1146
|
}
|
|
1083
1147
|
|
|
1084
1148
|
/**
|
|
1085
|
-
* Refresh a specific viewport or all viewports
|
|
1149
|
+
* Refresh a specific viewport or all viewports.
|
|
1150
|
+
* Debounced via requestAnimationFrame so multiple calls within the same
|
|
1151
|
+
* frame (e.g. from Viewport2D mount + refreshAll2DViews) collapse into one.
|
|
1086
1152
|
* @param {string} key - Optional viewport key. If not provided, refreshes all viewports
|
|
1087
1153
|
*/
|
|
1088
1154
|
}, {
|
|
1089
1155
|
key: "refresh",
|
|
1090
1156
|
value: function refresh() {
|
|
1157
|
+
var _this7 = this;
|
|
1091
1158
|
var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
1092
|
-
if (
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1159
|
+
if (this._refreshPending) return;
|
|
1160
|
+
this._refreshPending = true;
|
|
1161
|
+
requestAnimationFrame(function () {
|
|
1162
|
+
_this7._refreshPending = false;
|
|
1163
|
+
// Clear per-cycle caches so each component is measured/traversed once per paint
|
|
1164
|
+
_this7._bboxCache.clear();
|
|
1165
|
+
_this7._componentListCache = null;
|
|
1166
|
+
if (key) {
|
|
1167
|
+
var viewport = _this7.viewports.get(key);
|
|
1168
|
+
if (viewport && viewport.isReady) {
|
|
1169
|
+
_this7.renderComponents(viewport);
|
|
1170
|
+
}
|
|
1171
|
+
} else {
|
|
1172
|
+
var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(_this7.viewports.values()),
|
|
1173
|
+
_step;
|
|
1174
|
+
try {
|
|
1175
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1176
|
+
var _viewport = _step.value;
|
|
1177
|
+
if (_viewport.isReady) {
|
|
1178
|
+
_this7.renderComponents(_viewport);
|
|
1179
|
+
}
|
|
1106
1180
|
}
|
|
1181
|
+
} catch (err) {
|
|
1182
|
+
_iterator.e(err);
|
|
1183
|
+
} finally {
|
|
1184
|
+
_iterator.f();
|
|
1107
1185
|
}
|
|
1108
|
-
} catch (err) {
|
|
1109
|
-
_iterator.e(err);
|
|
1110
|
-
} finally {
|
|
1111
|
-
_iterator.f();
|
|
1112
1186
|
}
|
|
1113
|
-
}
|
|
1187
|
+
});
|
|
1114
1188
|
}
|
|
1115
1189
|
|
|
1116
1190
|
/**
|
|
@@ -226,10 +226,10 @@ var SceneClearingUtility = /*#__PURE__*/function () {
|
|
|
226
226
|
throw new Error('Scene not available for clearing');
|
|
227
227
|
case 1:
|
|
228
228
|
componentsToRemove = [];
|
|
229
|
-
scene = this.sceneViewer.scene; // Collect
|
|
229
|
+
scene = this.sceneViewer.scene; // Collect component, segment, and gateway objects
|
|
230
230
|
scene.traverse(function (child) {
|
|
231
231
|
if (child === scene) return;
|
|
232
|
-
var isComponent = child.userData && (child.userData.objectType === 'component' || child.userData.objectType === '
|
|
232
|
+
var isComponent = child.userData && (child.userData.objectType === 'component' || child.userData.objectType === 'segment' || child.userData.objectType === 'gateway' || child.userData.objectType === 'connector');
|
|
233
233
|
var isDirectChild = child.parent === scene;
|
|
234
234
|
if (isComponent && isDirectChild) {
|
|
235
235
|
componentsToRemove.push(child);
|
|
@@ -31,7 +31,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31
31
|
* Initialize the CentralPlant manager
|
|
32
32
|
*
|
|
33
33
|
* @constructor
|
|
34
|
-
* @version 0.3.
|
|
34
|
+
* @version 0.3.6
|
|
35
35
|
* @updated 2025-10-22
|
|
36
36
|
*
|
|
37
37
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -2,6 +2,7 @@ import { createClass as _createClass, objectSpread2 as _objectSpread2, toConsuma
|
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
import { attachIODevicesToComponent } from '../../utils/ioDeviceUtils.js';
|
|
4
4
|
import modelPreloader from '../../rendering/modelPreloader.js';
|
|
5
|
+
import { computeFilteredBoundingBox } from '../../utils/boundingBoxUtils.js';
|
|
5
6
|
|
|
6
7
|
var ModelManager = /*#__PURE__*/function () {
|
|
7
8
|
function ModelManager(sceneViewer) {
|
|
@@ -555,15 +556,28 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
555
556
|
_context5.n = 2;
|
|
556
557
|
return Promise.all(glbLoadingPromises);
|
|
557
558
|
case 2:
|
|
558
|
-
// Update world bounding boxes for loaded models
|
|
559
|
+
// Update world bounding boxes for loaded models and propagate to the live Three.js objects
|
|
559
560
|
libraryObjectsToReplace.forEach(function (_ref2) {
|
|
560
|
-
var _jsonData$userData2;
|
|
561
561
|
var jsonData = _ref2.jsonData,
|
|
562
562
|
glbModel = _ref2.glbModel;
|
|
563
|
-
if (glbModel
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
563
|
+
if (!glbModel) return;
|
|
564
|
+
// Use filtered bbox (excludes connectors + io-devices) so it matches
|
|
565
|
+
// what pathfindingManager._enrichSceneDataWithBoundingBoxes produces
|
|
566
|
+
var filteredBox = computeFilteredBoundingBox(glbModel, ['io-device', 'connector']);
|
|
567
|
+
var worldBoundingBox = filteredBox.isEmpty() ? _this3._calculateWorldBoundingBox(glbModel) : {
|
|
568
|
+
min: [filteredBox.min.x, filteredBox.min.y, filteredBox.min.z],
|
|
569
|
+
max: [filteredBox.max.x, filteredBox.max.y, filteredBox.max.z]
|
|
570
|
+
};
|
|
571
|
+
// Update both the JSON data object AND the live scene object
|
|
572
|
+
jsonData.userData.worldBoundingBox = worldBoundingBox;
|
|
573
|
+
glbModel.userData.worldBoundingBox = worldBoundingBox;
|
|
574
|
+
// Snapshot the object's local position so viewport2DManager can compute
|
|
575
|
+
// world-bbox updates via a fast O(1) position delta instead of re-traversing geometry
|
|
576
|
+
glbModel.userData._wbbBasePosition = {
|
|
577
|
+
x: glbModel.position.x,
|
|
578
|
+
y: glbModel.position.y,
|
|
579
|
+
z: glbModel.position.z
|
|
580
|
+
};
|
|
567
581
|
});
|
|
568
582
|
|
|
569
583
|
// Dispatch completion event
|