@2112-lab/central-plant 0.3.45 → 0.3.46

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.
@@ -21,6 +21,7 @@ var keyboardControlsManager = require('../managers/controls/keyboardControlsMana
21
21
  var pathfindingManager = require('../managers/pathfinding/pathfindingManager.js');
22
22
  var PathFlowManager = require('../managers/pathfinding/PathFlowManager.js');
23
23
  var sceneOperationsManager = require('../managers/scene/sceneOperationsManager.js');
24
+ var collisionManager = require('../managers/scene/collisionManager.js');
24
25
  var animationManager = require('../managers/scene/animationManager.js');
25
26
  var cameraControlsManager = require('../managers/controls/cameraControlsManager.js');
26
27
  var componentDragManager = require('../managers/controls/componentDragManager.js');
@@ -169,6 +170,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
169
170
  this.centralPlant.managers.keyboardControlsManager = new keyboardControlsManager.KeyboardControlsManager(this.centralPlant.sceneViewer);
170
171
  this.centralPlant.managers.pathfindingManager = new pathfindingManager.PathfindingManager(this.centralPlant.sceneViewer);
171
172
  this.centralPlant.managers.pathFlowManager = new PathFlowManager.PathFlowManager(this.centralPlant.sceneViewer);
173
+ this.centralPlant.managers.collisionManager = new collisionManager.CollisionManager(this.centralPlant.sceneViewer);
172
174
  this.centralPlant.managers.sceneOperationsManager = new sceneOperationsManager.SceneOperationsManager(this.centralPlant.sceneViewer);
173
175
  this.centralPlant.managers.animationManager = new animationManager.AnimationManager(this.centralPlant.sceneViewer);
174
176
  this.centralPlant.managers.cameraControlsManager = new cameraControlsManager.CameraControlsManager(this.centralPlant.sceneViewer);
@@ -667,6 +667,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
667
667
  // Find intersection with ground plane
668
668
  var intersection = this.raycaster.ray.intersectPlane(this.dropPlane, this.dropIntersection);
669
669
  if (intersection) {
670
+ var _this$sceneViewer$col;
670
671
  // Apply 0.5 unit transform snapping to intersection point
671
672
  var snappedPosition = this._applyTransformSnap(intersection);
672
673
  this.dragData.previewObject.position.copy(snappedPosition);
@@ -674,7 +675,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
674
675
 
675
676
  // Check for overlap and update color accordingly
676
677
  var wasOverlapping = this.dragData.isOverlapping;
677
- this.dragData.isOverlapping = this._checkBoundingBoxOverlap();
678
+ this.dragData.isOverlapping = !!((_this$sceneViewer$col = this.sceneViewer.collisionManager) !== null && _this$sceneViewer$col !== void 0 && _this$sceneViewer$col.checkCollision(this.dragData.previewObject));
678
679
 
679
680
  // Update color if overlap state changed
680
681
  if (wasOverlapping !== this.dragData.isOverlapping) {
@@ -0,0 +1,143 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHelpers.js');
6
+ var THREE = require('three');
7
+
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n["default"] = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
27
+
28
+ var CollisionManager = /*#__PURE__*/function () {
29
+ /**
30
+ * @param {Object} sceneViewer - The scene viewer instance
31
+ */
32
+ function CollisionManager(sceneViewer) {
33
+ _rollupPluginBabelHelpers.classCallCheck(this, CollisionManager);
34
+ this.sceneViewer = sceneViewer;
35
+ }
36
+
37
+ /**
38
+ * Check if a given object overlaps with any other relevant objects in the scene.
39
+ * @param {THREE.Object3D} object - The object to check for collisions
40
+ * @param {Array<string>} excludeTypes - Object types to exclude from checking (e.g. ['ground'])
41
+ * @returns {Object|null} Collision info {object, objectType} if collision detected, null otherwise
42
+ */
43
+ return _rollupPluginBabelHelpers.createClass(CollisionManager, [{
44
+ key: "checkCollision",
45
+ value: function checkCollision(object) {
46
+ var _this$sceneViewer,
47
+ _this = this;
48
+ var excludeTypes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ['isBaseGround', 'isBaseGrid', 'isBrickWall'];
49
+ if (!((_this$sceneViewer = this.sceneViewer) !== null && _this$sceneViewer !== void 0 && _this$sceneViewer.scene) || !object) return null;
50
+
51
+ // Compute high-quality bounding box for the object being checked
52
+ // We use setFromObject here because the target object just moved
53
+ var objectBBox = new THREE__namespace.Box3().setFromObject(object);
54
+
55
+ // Narrow down potential colliders
56
+ var collisionDetected = null;
57
+
58
+ // Optimization: Only check the root-level CP objects to avoid O(N^2) complexity with meshes
59
+ this.sceneViewer.scene.traverse(function (child) {
60
+ var _child$userData, _child$userData2, _child$userData3, _child$userData4, _child$userData5;
61
+ if (collisionDetected) return; // Short circuit
62
+
63
+ // Skip the object itself and its descendants
64
+ if (child === object || _this._isDescendantOf(object, child)) return;
65
+
66
+ // Filter by CP object types at the root level (skip internal meshes during traverse)
67
+ var isCPRootObject = ((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'component' || ((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'segment' || ((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) === 'gateway' || ((_child$userData4 = child.userData) === null || _child$userData4 === void 0 ? void 0 : _child$userData4.objectType) === 'connector' || ((_child$userData5 = child.userData) === null || _child$userData5 === void 0 ? void 0 : _child$userData5.ioConfig); // IO Device
68
+
69
+ if (isCPRootObject && !_this._shouldExclude(child, excludeTypes)) {
70
+ // Use cached worldBoundingBox if available, otherwise compute it (and cache it)
71
+ var childBBox;
72
+ if (child.userData.worldBoundingBox && !child.userData.isMoving) {
73
+ var _min$x, _min$y, _min$z, _max$x, _max$y, _max$z;
74
+ // Use stored worldBoundingBox (handles array or Box3 format)
75
+ var min = child.userData.worldBoundingBox.min;
76
+ var max = child.userData.worldBoundingBox.max;
77
+ childBBox = new THREE__namespace.Box3(new THREE__namespace.Vector3((_min$x = min.x) !== null && _min$x !== void 0 ? _min$x : min[0], (_min$y = min.y) !== null && _min$y !== void 0 ? _min$y : min[1], (_min$z = min.z) !== null && _min$z !== void 0 ? _min$z : min[2]), new THREE__namespace.Vector3((_max$x = max.x) !== null && _max$x !== void 0 ? _max$x : max[0], (_max$y = max.y) !== null && _max$y !== void 0 ? _max$y : max[1], (_max$z = max.z) !== null && _max$z !== void 0 ? _max$z : max[2]));
78
+ } else {
79
+ // Fallback to high-quality computation for moving objects or first-time checks
80
+ childBBox = new THREE__namespace.Box3().setFromObject(child);
81
+
82
+ // Cache the result for next time (non-moving objects)
83
+ if (!child.userData.isMoving) {
84
+ child.userData.worldBoundingBox = {
85
+ min: [childBBox.min.x, childBBox.min.y, childBBox.min.z],
86
+ max: [childBBox.max.x, childBBox.max.y, childBBox.max.z]
87
+ };
88
+ }
89
+ }
90
+ if (objectBBox.intersectsBox(childBBox)) {
91
+ collisionDetected = {
92
+ object: child,
93
+ objectType: child.userData.objectType,
94
+ uuid: child.uuid,
95
+ name: child.name || child.userData.libraryId || child.uuid
96
+ };
97
+ }
98
+ }
99
+ });
100
+ return collisionDetected;
101
+ }
102
+
103
+ /**
104
+ * Helper to check if a node is a descendant of a specific parent
105
+ * @private
106
+ */
107
+ }, {
108
+ key: "_isDescendantOf",
109
+ value: function _isDescendantOf(parent, child) {
110
+ var node = child.parent;
111
+ while (node !== null) {
112
+ if (node === parent) return true;
113
+ node = node.parent;
114
+ }
115
+ return false;
116
+ }
117
+
118
+ /**
119
+ * Helper to determine if an object should be excluded from collision checking
120
+ * @private
121
+ */
122
+ }, {
123
+ key: "_shouldExclude",
124
+ value: function _shouldExclude(object, excludeTypes) {
125
+ if (object.userData.isPreview) return true;
126
+ var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(excludeTypes),
127
+ _step;
128
+ try {
129
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
130
+ var type = _step.value;
131
+ if (object.userData[type]) return true;
132
+ }
133
+ } catch (err) {
134
+ _iterator.e(err);
135
+ } finally {
136
+ _iterator.f();
137
+ }
138
+ return false;
139
+ }
140
+ }]);
141
+ }();
142
+
143
+ exports.CollisionManager = CollisionManager;
@@ -167,6 +167,8 @@ var SceneExportManager = /*#__PURE__*/function () {
167
167
  // Internal tracking - not needed in export
168
168
  'initialPosition',
169
169
  // Internal tracking - not needed in export
170
+ 'attachedDevices',
171
+ // Stored in smart component dictionary, not scene JSON
170
172
  // Exclude internal segment tracking properties
171
173
  'segmentId',
172
174
  // Internal tracking
@@ -1333,55 +1333,20 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1333
1333
  y: componentModel.scale.y,
1334
1334
  z: componentModel.scale.z
1335
1335
  },
1336
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, componentModel.userData), {}, {
1336
+ userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, function () {
1337
+ var ud = _rollupPluginBabelHelpers.objectSpread2({}, componentModel.userData);
1338
+ delete ud.attachedDevices; // Instance data belongs in dictionary, not scene JSON
1339
+ delete ud.isDeclared; // Runtime flag
1340
+ delete ud.originalUuid; // Runtime tracking
1341
+ return ud;
1342
+ }()), {}, {
1337
1343
  worldBoundingBox: {
1338
1344
  min: boundingBox.min.toArray(),
1339
1345
  max: boundingBox.max.toArray()
1340
1346
  }
1341
- }),
1342
- children: []
1347
+ })
1343
1348
  };
1344
1349
 
1345
- // Process children (connectors, etc.) if they exist
1346
- if (componentModel.children && componentModel.children.length > 0) {
1347
- componentModel.children.forEach(function (child) {
1348
- var _child$userData0, _child$userData1;
1349
- var childType = ((_child$userData0 = child.userData) === null || _child$userData0 === void 0 ? void 0 : _child$userData0.objectType) || ((_child$userData1 = child.userData) === null || _child$userData1 === void 0 ? void 0 : _child$userData1.objectType);
1350
- if (childType === 'connector') {
1351
- var _child$geometry;
1352
- var childBoundingBox = new THREE__namespace.Box3().setFromObject(child);
1353
- var childSceneData = {
1354
- uuid: child.uuid,
1355
- name: child.name,
1356
- type: child.type,
1357
- position: {
1358
- x: child.position.x,
1359
- y: child.position.y,
1360
- z: child.position.z
1361
- },
1362
- rotation: {
1363
- x: THREE__namespace.MathUtils.radToDeg(child.rotation.x),
1364
- y: THREE__namespace.MathUtils.radToDeg(child.rotation.y),
1365
- z: THREE__namespace.MathUtils.radToDeg(child.rotation.z)
1366
- },
1367
- scale: {
1368
- x: child.scale.x,
1369
- y: child.scale.y,
1370
- z: child.scale.z
1371
- },
1372
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child.userData), {}, {
1373
- worldBoundingBox: {
1374
- min: childBoundingBox.min.toArray(),
1375
- max: childBoundingBox.max.toArray()
1376
- }
1377
- }),
1378
- geometry: ((_child$geometry = child.geometry) === null || _child$geometry === void 0 ? void 0 : _child$geometry.uuid) || 'CONNECTOR-GEO'
1379
- };
1380
- componentSceneData.children.push(childSceneData);
1381
- }
1382
- });
1383
- }
1384
-
1385
1350
  // Add the component to the scene data
1386
1351
  if (!currentSceneData.scene.children) {
1387
1352
  currentSceneData.scene.children = [];
@@ -1390,7 +1355,6 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1390
1355
  console.log('✅ addComponentToSceneData: Component added to scene data successfully', {
1391
1356
  componentId: componentModel.uuid,
1392
1357
  libraryId: (_componentModel$userD = componentModel.userData) === null || _componentModel$userD === void 0 ? void 0 : _componentModel$userD.libraryId,
1393
- childrenCount: componentSceneData.children.length,
1394
1358
  totalSceneChildren: currentSceneData.scene.children.length
1395
1359
  });
1396
1360
  return true;
@@ -1431,8 +1395,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1431
1395
  if (segment.children && segment.children.length > 0) {
1432
1396
  var childrenToRemove = _rollupPluginBabelHelpers.toConsumableArray(segment.children);
1433
1397
  childrenToRemove.forEach(function (child) {
1434
- var _child$userData10;
1435
- if ((_child$userData10 = child.userData) !== null && _child$userData10 !== void 0 && _child$userData10.isPipeElbow) {
1398
+ var _child$userData0;
1399
+ if ((_child$userData0 = child.userData) !== null && _child$userData0 !== void 0 && _child$userData0.isPipeElbow) {
1436
1400
  console.log("\uD83D\uDDD1\uFE0F Removing elbow child from segment before manualization: ".concat(child.uuid));
1437
1401
  segment.remove(child);
1438
1402
  if (child.geometry) child.geometry.dispose();