@2112-lab/central-plant 0.1.76 → 0.1.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle/index.js +656 -75
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/core/centralPlantInternals.js +73 -0
- package/dist/cjs/src/managers/controls/componentDragManager.js +145 -32
- package/dist/cjs/src/managers/controls/transformControlsManager.js +22 -30
- package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +52 -8
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +41 -4
- package/dist/cjs/src/utils/boundingBoxUtils.js +356 -0
- package/dist/esm/src/core/centralPlant.js +1 -1
- package/dist/esm/src/core/centralPlantInternals.js +74 -1
- package/dist/esm/src/managers/controls/componentDragManager.js +146 -33
- package/dist/esm/src/managers/controls/transformControlsManager.js +22 -30
- package/dist/esm/src/managers/pathfinding/pathfindingManager.js +52 -8
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +41 -4
- package/dist/esm/src/utils/boundingBoxUtils.js +329 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { inherits as _inherits, createClass as _createClass, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
1
|
+
import { inherits as _inherits, createClass as _createClass, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, slicedToArray as _slicedToArray } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
2
|
import { BaseDisposable } from '../../core/baseDisposable.js';
|
|
3
3
|
import * as THREE from 'three';
|
|
4
4
|
|
|
@@ -167,7 +167,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
167
167
|
console.log("\uD83D\uDD0D ModelPreloader available:", !!modelPreloader);
|
|
168
168
|
console.log("\uD83D\uDD0D ComponentDictionary available:", !!(modelPreloader !== null && modelPreloader !== void 0 && modelPreloader.componentDictionary));
|
|
169
169
|
if (!(modelPreloader && modelPreloader.componentDictionary)) {
|
|
170
|
-
_context2.n =
|
|
170
|
+
_context2.n = 14;
|
|
171
171
|
break;
|
|
172
172
|
}
|
|
173
173
|
console.log("\uD83D\uDCDA Available dictionary keys:", Object.keys(modelPreloader.componentDictionary));
|
|
@@ -183,7 +183,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
183
183
|
});
|
|
184
184
|
}
|
|
185
185
|
if (!(componentData && componentData.modelKey)) {
|
|
186
|
-
_context2.n =
|
|
186
|
+
_context2.n = 12;
|
|
187
187
|
break;
|
|
188
188
|
}
|
|
189
189
|
// Try to get cached model first
|
|
@@ -223,7 +223,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
223
223
|
console.warn("\u26A0\uFE0F Failed to preload model ".concat(componentData.modelKey, ":"), _t2);
|
|
224
224
|
case 8:
|
|
225
225
|
if (!cachedModel) {
|
|
226
|
-
_context2.n =
|
|
226
|
+
_context2.n = 10;
|
|
227
227
|
break;
|
|
228
228
|
}
|
|
229
229
|
this.dragData.previewObject = cachedModel.clone();
|
|
@@ -234,6 +234,14 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
234
234
|
// Store original colors BEFORE making transparent
|
|
235
235
|
this._storeOriginalColors(this.dragData.previewObject);
|
|
236
236
|
|
|
237
|
+
// For smart components, load and attach IO device models to the preview
|
|
238
|
+
if (!(componentData.isSmart && componentData.attachedDevices)) {
|
|
239
|
+
_context2.n = 9;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
_context2.n = 9;
|
|
243
|
+
return this._attachIODeviceModelsToPreview(this.dragData.previewObject, componentData, modelPreloader);
|
|
244
|
+
case 9:
|
|
237
245
|
// Make the preview semi-transparent
|
|
238
246
|
this._setPreviewTransparency(this.dragData.previewObject, 0.5);
|
|
239
247
|
this.dragData.previewObject.userData = {
|
|
@@ -247,19 +255,19 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
247
255
|
this.sceneViewer.scene.add(this.dragData.previewObject);
|
|
248
256
|
console.log("\u2705 Created ".concat(componentData.isS3Component ? 'S3' : 'static', " GLB preview object for: ").concat(componentId));
|
|
249
257
|
return _context2.a(2);
|
|
250
|
-
case 9:
|
|
251
|
-
console.warn("\u26A0\uFE0F Failed to load model for ".concat(componentId, ", will use fallback"));
|
|
252
258
|
case 10:
|
|
253
|
-
|
|
254
|
-
break;
|
|
259
|
+
console.warn("\u26A0\uFE0F Failed to load model for ".concat(componentId, ", will use fallback"));
|
|
255
260
|
case 11:
|
|
256
|
-
|
|
257
|
-
case 12:
|
|
258
|
-
_context2.n = 14;
|
|
261
|
+
_context2.n = 13;
|
|
259
262
|
break;
|
|
263
|
+
case 12:
|
|
264
|
+
console.warn("\u26A0\uFE0F No modelKey found for component ".concat(componentId));
|
|
260
265
|
case 13:
|
|
261
|
-
|
|
266
|
+
_context2.n = 15;
|
|
267
|
+
break;
|
|
262
268
|
case 14:
|
|
269
|
+
console.warn("\u26A0\uFE0F ModelPreloader or component dictionary not available");
|
|
270
|
+
case 15:
|
|
263
271
|
// Fallback: Create a simple preview mesh if model not available
|
|
264
272
|
geometry = new THREE.BoxGeometry(1, 1, 1);
|
|
265
273
|
material = new THREE.MeshPhysicalMaterial({
|
|
@@ -282,7 +290,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
282
290
|
this.dragData.previewObject.position.set(1000, 1000, 1000);
|
|
283
291
|
this.sceneViewer.scene.add(this.dragData.previewObject);
|
|
284
292
|
console.log("\u26A0\uFE0F Created fallback wireframe preview for: ".concat(componentId));
|
|
285
|
-
case
|
|
293
|
+
case 16:
|
|
286
294
|
return _context2.a(2);
|
|
287
295
|
}
|
|
288
296
|
}, _callee2, this, [[5, 7], [1, 3]]);
|
|
@@ -292,6 +300,111 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
292
300
|
}
|
|
293
301
|
return _createPreviewObject;
|
|
294
302
|
}()
|
|
303
|
+
/**
|
|
304
|
+
* Load and attach IO device models to a smart component preview
|
|
305
|
+
* @param {THREE.Object3D} parentObject - The parent preview object
|
|
306
|
+
* @param {Object} componentData - Component dictionary entry (must have attachedDevices)
|
|
307
|
+
* @param {Object} modelPreloader - ModelPreloader instance
|
|
308
|
+
* @private
|
|
309
|
+
*/
|
|
310
|
+
)
|
|
311
|
+
}, {
|
|
312
|
+
key: "_attachIODeviceModelsToPreview",
|
|
313
|
+
value: (function () {
|
|
314
|
+
var _attachIODeviceModelsToPreview2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(parentObject, componentData, modelPreloader) {
|
|
315
|
+
var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _attachment$attachmen, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, _t3;
|
|
316
|
+
return _regenerator().w(function (_context3) {
|
|
317
|
+
while (1) switch (_context3.n) {
|
|
318
|
+
case 0:
|
|
319
|
+
if (componentData.attachedDevices) {
|
|
320
|
+
_context3.n = 1;
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
return _context3.a(2);
|
|
324
|
+
case 1:
|
|
325
|
+
_i = 0, _Object$entries = Object.entries(componentData.attachedDevices);
|
|
326
|
+
case 2:
|
|
327
|
+
if (!(_i < _Object$entries.length)) {
|
|
328
|
+
_context3.n = 12;
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
_Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), attachmentId = _Object$entries$_i[0], attachment = _Object$entries$_i[1];
|
|
332
|
+
_context3.p = 3;
|
|
333
|
+
deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
|
|
334
|
+
if (!(!deviceData || !deviceData.modelKey)) {
|
|
335
|
+
_context3.n = 4;
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
console.warn("\u26A0\uFE0F IO device ".concat(attachment.deviceId, " not found in dictionary for preview"));
|
|
339
|
+
return _context3.a(3, 11);
|
|
340
|
+
case 4:
|
|
341
|
+
// Ensure device model is loaded
|
|
342
|
+
cachedDevice = modelPreloader.getCachedModelWithDimensions(deviceData.modelKey, attachment.deviceId);
|
|
343
|
+
if (cachedDevice) {
|
|
344
|
+
_context3.n = 8;
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
if (!((_modelPreloader$loadi = modelPreloader.loadingPromises) !== null && _modelPreloader$loadi !== void 0 && _modelPreloader$loadi.has(deviceData.modelKey))) {
|
|
348
|
+
_context3.n = 6;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
_context3.n = 5;
|
|
352
|
+
return modelPreloader.loadingPromises.get(deviceData.modelKey);
|
|
353
|
+
case 5:
|
|
354
|
+
_context3.n = 7;
|
|
355
|
+
break;
|
|
356
|
+
case 6:
|
|
357
|
+
_context3.n = 7;
|
|
358
|
+
return modelPreloader.preloadSingleModel(deviceData.modelKey);
|
|
359
|
+
case 7:
|
|
360
|
+
cachedDevice = modelPreloader.getCachedModelWithDimensions(deviceData.modelKey, attachment.deviceId);
|
|
361
|
+
case 8:
|
|
362
|
+
if (cachedDevice) {
|
|
363
|
+
_context3.n = 9;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
console.warn("\u26A0\uFE0F Could not load IO device model: ".concat(deviceData.modelKey));
|
|
367
|
+
return _context3.a(3, 11);
|
|
368
|
+
case 9:
|
|
369
|
+
deviceModel = cachedDevice.clone();
|
|
370
|
+
this._cloneMaterials(deviceModel);
|
|
371
|
+
this._storeOriginalColors(deviceModel);
|
|
372
|
+
deviceModel.userData = {
|
|
373
|
+
objectType: 'io-device',
|
|
374
|
+
deviceId: attachment.deviceId,
|
|
375
|
+
attachmentId: attachmentId,
|
|
376
|
+
attachmentLabel: attachment.attachmentLabel
|
|
377
|
+
};
|
|
378
|
+
if ((_attachment$attachmen = attachment.attachmentPoint) !== null && _attachment$attachmen !== void 0 && _attachment$attachmen.position) {
|
|
379
|
+
pos = attachment.attachmentPoint.position;
|
|
380
|
+
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// IO device models use their natural (1:1) scale — the stored
|
|
384
|
+
// attachmentPoint.scale value is for the connector marker sphere.
|
|
385
|
+
deviceModel.scale.setScalar(1);
|
|
386
|
+
parentObject.add(deviceModel);
|
|
387
|
+
console.log("\u2705 Attached IO device preview: ".concat(attachment.attachmentLabel || attachment.deviceId));
|
|
388
|
+
_context3.n = 11;
|
|
389
|
+
break;
|
|
390
|
+
case 10:
|
|
391
|
+
_context3.p = 10;
|
|
392
|
+
_t3 = _context3.v;
|
|
393
|
+
console.warn("\u26A0\uFE0F Could not attach IO device model ".concat(attachment.deviceId, " to preview:"), _t3);
|
|
394
|
+
case 11:
|
|
395
|
+
_i++;
|
|
396
|
+
_context3.n = 2;
|
|
397
|
+
break;
|
|
398
|
+
case 12:
|
|
399
|
+
return _context3.a(2);
|
|
400
|
+
}
|
|
401
|
+
}, _callee3, this, [[3, 10]]);
|
|
402
|
+
}));
|
|
403
|
+
function _attachIODeviceModelsToPreview(_x5, _x6, _x7) {
|
|
404
|
+
return _attachIODeviceModelsToPreview2.apply(this, arguments);
|
|
405
|
+
}
|
|
406
|
+
return _attachIODeviceModelsToPreview;
|
|
407
|
+
}()
|
|
295
408
|
/**
|
|
296
409
|
* Clone all materials in an object hierarchy to avoid shared material issues
|
|
297
410
|
* @param {THREE.Object3D} object - The object to clone materials for
|
|
@@ -439,8 +552,8 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
439
552
|
});
|
|
440
553
|
|
|
441
554
|
// Check for overlaps
|
|
442
|
-
for (var
|
|
443
|
-
var mesh = _sceneMeshes[
|
|
555
|
+
for (var _i2 = 0, _sceneMeshes = sceneMeshes; _i2 < _sceneMeshes.length; _i2++) {
|
|
556
|
+
var mesh = _sceneMeshes[_i2];
|
|
444
557
|
var meshBBox = new THREE.Box3().setFromObject(mesh);
|
|
445
558
|
if (previewBBox.intersectsBox(meshBBox)) {
|
|
446
559
|
console.log('⚠️ ComponentDragManager: Overlap detected with:', mesh.userData.objectType || mesh.name || mesh.uuid);
|
|
@@ -754,50 +867,50 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
754
867
|
var _this3 = this;
|
|
755
868
|
if (!element || !componentId) return;
|
|
756
869
|
var handleMouseDown = /*#__PURE__*/function () {
|
|
757
|
-
var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
758
|
-
return _regenerator().w(function (
|
|
759
|
-
while (1) switch (
|
|
870
|
+
var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(event) {
|
|
871
|
+
return _regenerator().w(function (_context4) {
|
|
872
|
+
while (1) switch (_context4.n) {
|
|
760
873
|
case 0:
|
|
761
874
|
if (!(event.button !== 0)) {
|
|
762
|
-
|
|
875
|
+
_context4.n = 1;
|
|
763
876
|
break;
|
|
764
877
|
}
|
|
765
|
-
return
|
|
878
|
+
return _context4.a(2);
|
|
766
879
|
case 1:
|
|
767
880
|
// Only left mouse button
|
|
768
881
|
event.preventDefault();
|
|
769
|
-
|
|
882
|
+
_context4.n = 2;
|
|
770
883
|
return _this3.startComponentDrag(componentId, element, event);
|
|
771
884
|
case 2:
|
|
772
|
-
return
|
|
885
|
+
return _context4.a(2);
|
|
773
886
|
}
|
|
774
|
-
},
|
|
887
|
+
}, _callee4);
|
|
775
888
|
}));
|
|
776
|
-
return function handleMouseDown(
|
|
889
|
+
return function handleMouseDown(_x8) {
|
|
777
890
|
return _ref.apply(this, arguments);
|
|
778
891
|
};
|
|
779
892
|
}();
|
|
780
893
|
var handleTouchStart = /*#__PURE__*/function () {
|
|
781
|
-
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
782
|
-
return _regenerator().w(function (
|
|
783
|
-
while (1) switch (
|
|
894
|
+
var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(event) {
|
|
895
|
+
return _regenerator().w(function (_context5) {
|
|
896
|
+
while (1) switch (_context5.n) {
|
|
784
897
|
case 0:
|
|
785
898
|
if (!(event.touches.length !== 1)) {
|
|
786
|
-
|
|
899
|
+
_context5.n = 1;
|
|
787
900
|
break;
|
|
788
901
|
}
|
|
789
|
-
return
|
|
902
|
+
return _context5.a(2);
|
|
790
903
|
case 1:
|
|
791
904
|
// Only single touch
|
|
792
905
|
event.preventDefault();
|
|
793
|
-
|
|
906
|
+
_context5.n = 2;
|
|
794
907
|
return _this3.startComponentDrag(componentId, element, event);
|
|
795
908
|
case 2:
|
|
796
|
-
return
|
|
909
|
+
return _context5.a(2);
|
|
797
910
|
}
|
|
798
|
-
},
|
|
911
|
+
}, _callee5);
|
|
799
912
|
}));
|
|
800
|
-
return function handleTouchStart(
|
|
913
|
+
return function handleTouchStart(_x9) {
|
|
801
914
|
return _ref2.apply(this, arguments);
|
|
802
915
|
};
|
|
803
916
|
}();
|
|
@@ -2,6 +2,7 @@ import { createClass as _createClass, asyncToGenerator as _asyncToGenerator, reg
|
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
import { transformControls } from './transformControls.js';
|
|
4
4
|
import { isSegment, isGateway } from '../../utils/objectTypes.js';
|
|
5
|
+
import { createSelectionBoxHelpers, updateSelectionBoxHelpers } from '../../utils/boundingBoxUtils.js';
|
|
5
6
|
|
|
6
7
|
var TransformControlsManager = /*#__PURE__*/function () {
|
|
7
8
|
function TransformControlsManager(scene, camera, renderer) {
|
|
@@ -918,23 +919,16 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
918
919
|
return;
|
|
919
920
|
}
|
|
920
921
|
try {
|
|
921
|
-
// Create
|
|
922
|
+
// Create bounding box helpers for each selected object
|
|
923
|
+
// Smart components get filtered helpers (component body + individual io-device boxes)
|
|
922
924
|
this.selectedObjects.forEach(function (obj) {
|
|
923
|
-
var
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
isBoundingBox: true
|
|
929
|
-
};
|
|
930
|
-
|
|
931
|
-
// Add to scene
|
|
932
|
-
_this5.scene.add(boundingBoxHelper);
|
|
933
|
-
|
|
934
|
-
// Store in array for later cleanup
|
|
935
|
-
_this5.boundingBoxHelpers.push(boundingBoxHelper);
|
|
925
|
+
var helpers = createSelectionBoxHelpers(obj, _this5.config.boundingBoxColor);
|
|
926
|
+
helpers.forEach(function (helper) {
|
|
927
|
+
_this5.scene.add(helper);
|
|
928
|
+
_this5.boundingBoxHelpers.push(helper);
|
|
929
|
+
});
|
|
936
930
|
});
|
|
937
|
-
console.log("\uD83D\uDCE6 Bounding boxes created for ".concat(this.selectedObjects.length, " object(s)"));
|
|
931
|
+
console.log("\uD83D\uDCE6 Bounding boxes created for ".concat(this.selectedObjects.length, " object(s) (").concat(this.boundingBoxHelpers.length, " helpers)"));
|
|
938
932
|
} catch (error) {
|
|
939
933
|
console.warn('⚠️ Failed to create bounding boxes:', error);
|
|
940
934
|
}
|
|
@@ -1065,21 +1059,19 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
1065
1059
|
// Update bounding boxes for all selected objects
|
|
1066
1060
|
if (this.selectedObjects.length > 0 && this.boundingBoxHelpers.length > 0) {
|
|
1067
1061
|
try {
|
|
1068
|
-
//
|
|
1069
|
-
this.
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
_this6.boundingBoxCache.set(obj, updatedBoundingBox);
|
|
1082
|
-
}
|
|
1062
|
+
// Ensure all selected objects have up-to-date matrices
|
|
1063
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1064
|
+
return obj.updateMatrixWorld(true);
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
// Use the centralized update function which handles filtered, io-device, and standard helpers
|
|
1068
|
+
updateSelectionBoxHelpers(this.boundingBoxHelpers, this.selectedObjects, this.scene);
|
|
1069
|
+
|
|
1070
|
+
// Also update the cached bounding box if it exists
|
|
1071
|
+
this.selectedObjects.forEach(function (obj) {
|
|
1072
|
+
if (_this6.boundingBoxCache.has(obj)) {
|
|
1073
|
+
var updatedBoundingBox = new THREE.Box3().setFromObject(obj);
|
|
1074
|
+
_this6.boundingBoxCache.set(obj, updatedBoundingBox);
|
|
1083
1075
|
}
|
|
1084
1076
|
});
|
|
1085
1077
|
} catch (error) {
|
|
@@ -3,6 +3,7 @@ import * as THREE from 'three';
|
|
|
3
3
|
import { Pathfinder } from '@2112-lab/pathfinder';
|
|
4
4
|
import { BaseDisposable } from '../../core/baseDisposable.js';
|
|
5
5
|
import { PathData } from '../../core/pathfindingData.js';
|
|
6
|
+
import { computeFilteredBoundingBox, computeIODeviceBoundingBoxes } from '../../utils/boundingBoxUtils.js';
|
|
6
7
|
import { SceneDataManager } from './sceneDataManager.js';
|
|
7
8
|
import { PathRenderingManager } from './PathRenderingManager.js';
|
|
8
9
|
import { ConnectorManager } from './ConnectorManager.js';
|
|
@@ -153,20 +154,63 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
153
154
|
// Find the actual component object in the scene
|
|
154
155
|
var componentObject = _this3.sceneViewer.scene.getObjectByProperty('uuid', child.uuid);
|
|
155
156
|
if (componentObject) {
|
|
156
|
-
// Compute
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
// Compute FILTERED bounding box — excludes io-device and connector subtrees
|
|
158
|
+
// so the component body bbox is tight-fitting and doesn't envelop attached devices
|
|
159
|
+
var filteredBBox = computeFilteredBoundingBox(componentObject, ['io-device', 'connector']);
|
|
160
|
+
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), "]"));
|
|
159
161
|
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
return _objectSpread2(_objectSpread2({}, child), {}, {
|
|
162
|
+
// Build the enriched component entry
|
|
163
|
+
var enrichedChild = _objectSpread2(_objectSpread2({}, child), {}, {
|
|
163
164
|
userData: _objectSpread2(_objectSpread2({}, child.userData), {}, {
|
|
164
165
|
worldBoundingBox: {
|
|
165
|
-
min: [
|
|
166
|
-
max: [
|
|
166
|
+
min: [filteredBBox.min.x, filteredBBox.min.y, filteredBBox.min.z],
|
|
167
|
+
max: [filteredBBox.max.x, filteredBBox.max.y, filteredBBox.max.z]
|
|
167
168
|
}
|
|
168
169
|
})
|
|
169
170
|
});
|
|
171
|
+
|
|
172
|
+
// Compute separate bounding boxes for each attached io-device
|
|
173
|
+
// These are injected as children so the pathfinder treats each as an independent obstacle
|
|
174
|
+
var ioDeviceBBoxes = computeIODeviceBoundingBoxes(componentObject);
|
|
175
|
+
if (ioDeviceBBoxes.length > 0) {
|
|
176
|
+
// Ensure children array exists (may already contain connectors)
|
|
177
|
+
if (!enrichedChild.children) {
|
|
178
|
+
enrichedChild.children = [];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Inject io-device entries with their own worldBoundingBox
|
|
182
|
+
ioDeviceBBoxes.forEach(function (deviceBBox) {
|
|
183
|
+
// Check if this io-device already exists in scene data children
|
|
184
|
+
var existingIndex = enrichedChild.children.findIndex(function (c) {
|
|
185
|
+
return c.uuid === deviceBBox.uuid;
|
|
186
|
+
});
|
|
187
|
+
if (existingIndex >= 0) {
|
|
188
|
+
// Update existing entry with bounding box
|
|
189
|
+
enrichedChild.children[existingIndex] = _objectSpread2(_objectSpread2({}, enrichedChild.children[existingIndex]), {}, {
|
|
190
|
+
userData: _objectSpread2(_objectSpread2({}, enrichedChild.children[existingIndex].userData), {}, {
|
|
191
|
+
objectType: 'io-device',
|
|
192
|
+
worldBoundingBox: deviceBBox.worldBoundingBox
|
|
193
|
+
})
|
|
194
|
+
});
|
|
195
|
+
} else {
|
|
196
|
+
// Create new entry for the io-device
|
|
197
|
+
enrichedChild.children.push({
|
|
198
|
+
uuid: deviceBBox.uuid,
|
|
199
|
+
userData: _objectSpread2(_objectSpread2({}, deviceBBox.userData), {}, {
|
|
200
|
+
worldBoundingBox: deviceBBox.worldBoundingBox
|
|
201
|
+
}),
|
|
202
|
+
children: []
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
console.log("\uD83D\uDCE6 Injected io-device bbox for ".concat(deviceBBox.uuid, ": min=[").concat(deviceBBox.worldBoundingBox.min.map(function (v) {
|
|
206
|
+
return v.toFixed(2);
|
|
207
|
+
}).join(', '), "], max=[").concat(deviceBBox.worldBoundingBox.max.map(function (v) {
|
|
208
|
+
return v.toFixed(2);
|
|
209
|
+
}).join(', '), "]"));
|
|
210
|
+
});
|
|
211
|
+
console.log("\uD83D\uDCE6 Injected ".concat(ioDeviceBBoxes.length, " io-device bounding box(es) for component ").concat(child.uuid));
|
|
212
|
+
}
|
|
213
|
+
return enrichedChild;
|
|
170
214
|
} else {
|
|
171
215
|
console.warn("\u26A0\uFE0F Could not find component object in scene: ".concat(child.uuid));
|
|
172
216
|
}
|
|
@@ -3,6 +3,7 @@ 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';
|
|
6
7
|
|
|
7
8
|
var _excluded = ["direction"],
|
|
8
9
|
_excluded2 = ["direction"];
|
|
@@ -618,6 +619,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
618
619
|
|
|
619
620
|
/**
|
|
620
621
|
* Helper function to compute world bounding boxes
|
|
622
|
+
* For components: uses filtered bbox (excludes io-device and connector subtrees)
|
|
623
|
+
* For io-devices: computes separate bounding boxes and injects them as children
|
|
621
624
|
*/
|
|
622
625
|
}, {
|
|
623
626
|
key: "computeWorldBoundingBoxes",
|
|
@@ -656,12 +659,46 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
656
659
|
};
|
|
657
660
|
jsonObject = _findJsonObject(data.scene.children);
|
|
658
661
|
if (jsonObject) {
|
|
659
|
-
// Compute world bounding box
|
|
660
|
-
var boundingBox = new THREE.Box3().setFromObject(object);
|
|
661
|
-
|
|
662
662
|
// Store in JSON userData for pathfinder (skip for gateways - they're just routing points)
|
|
663
663
|
if (!jsonObject.userData) jsonObject.userData = {};
|
|
664
|
-
if (jsonObject.userData.objectType
|
|
664
|
+
if (jsonObject.userData.objectType === 'component') {
|
|
665
|
+
// For components: compute filtered bounding box (excludes io-device and connector subtrees)
|
|
666
|
+
var filteredBBox = computeFilteredBoundingBox(object, ['io-device', 'connector']);
|
|
667
|
+
jsonObject.userData.worldBoundingBox = {
|
|
668
|
+
min: filteredBBox.min.toArray(),
|
|
669
|
+
max: filteredBBox.max.toArray()
|
|
670
|
+
};
|
|
671
|
+
console.log("Added filtered world bounding box for component:", jsonObject.userData.worldBoundingBox);
|
|
672
|
+
|
|
673
|
+
// Compute and inject separate io-device bounding boxes as children
|
|
674
|
+
var ioDeviceBBoxes = computeIODeviceBoundingBoxes(object);
|
|
675
|
+
if (ioDeviceBBoxes.length > 0) {
|
|
676
|
+
if (!jsonObject.children) jsonObject.children = [];
|
|
677
|
+
ioDeviceBBoxes.forEach(function (deviceBBox) {
|
|
678
|
+
var existingIndex = jsonObject.children.findIndex(function (c) {
|
|
679
|
+
return c.uuid === deviceBBox.uuid;
|
|
680
|
+
});
|
|
681
|
+
if (existingIndex >= 0) {
|
|
682
|
+
// Update existing entry
|
|
683
|
+
if (!jsonObject.children[existingIndex].userData) jsonObject.children[existingIndex].userData = {};
|
|
684
|
+
jsonObject.children[existingIndex].userData.objectType = 'io-device';
|
|
685
|
+
jsonObject.children[existingIndex].userData.worldBoundingBox = deviceBBox.worldBoundingBox;
|
|
686
|
+
} else {
|
|
687
|
+
// Create new entry
|
|
688
|
+
jsonObject.children.push({
|
|
689
|
+
uuid: deviceBBox.uuid,
|
|
690
|
+
userData: _objectSpread2(_objectSpread2({}, deviceBBox.userData), {}, {
|
|
691
|
+
worldBoundingBox: deviceBBox.worldBoundingBox
|
|
692
|
+
}),
|
|
693
|
+
children: []
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
console.log("\uD83D\uDCE6 Injected ".concat(ioDeviceBBoxes.length, " io-device bbox(es) for component ").concat(jsonObject.uuid));
|
|
698
|
+
}
|
|
699
|
+
} else if (jsonObject.userData.objectType !== 'gateway') {
|
|
700
|
+
// For non-component, non-gateway objects: standard bounding box
|
|
701
|
+
var boundingBox = new THREE.Box3().setFromObject(object);
|
|
665
702
|
jsonObject.userData.worldBoundingBox = {
|
|
666
703
|
min: boundingBox.min.toArray(),
|
|
667
704
|
max: boundingBox.max.toArray()
|