@2112-lab/central-plant 0.3.47 → 0.3.48

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.
@@ -1,9 +1,9 @@
1
- import { inherits as _inherits, createClass as _createClass, createForOfIteratorHelper as _createForOfIteratorHelper, objectSpread2 as _objectSpread2, slicedToArray as _slicedToArray, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, toConsumableArray as _toConsumableArray, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, typeof as _typeof } from '../../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { inherits as _inherits, createClass as _createClass, objectSpread2 as _objectSpread2, slicedToArray as _slicedToArray, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, toConsumableArray as _toConsumableArray, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, typeof as _typeof, createForOfIteratorHelper as _createForOfIteratorHelper } from '../../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  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, computeConnectorBoundingBoxes } from '../../utils/boundingBoxUtils.js';
6
+ import { computeFilteredBoundingBox, computeConnectorBoundingBoxes, computeIODeviceBoundingBoxes } from '../../utils/boundingBoxUtils.js';
7
7
  import { SceneDataManager } from './sceneDataManager.js';
8
8
  import { PathRenderingManager } from './PathRenderingManager.js';
9
9
  import { ConnectorManager } from './ConnectorManager.js';
@@ -137,10 +137,11 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
137
137
  }, {
138
138
  key: "_matrixHash",
139
139
  value: function _matrixHash(obj) {
140
+ // Force matrix update to ensure we're looking at the latest data
141
+ obj.updateMatrixWorld(true);
140
142
  var e = obj.matrixWorld.elements;
141
- // Use position (12-14) + first diagonal entries (0,5,10) — covers
142
- // translation AND rotation/scale changes with minimal work.
143
- return "".concat(e[0].toFixed(5), ",").concat(e[5].toFixed(5), ",").concat(e[10].toFixed(5), ",").concat(e[12].toFixed(5), ",").concat(e[13].toFixed(5), ",").concat(e[14].toFixed(5));
143
+ // Just hash the position/rotation/scale part of the matrix (12 elements)
144
+ return "".concat(e[0].toFixed(3), ",").concat(e[1].toFixed(3), ",").concat(e[2].toFixed(3), ",").concat(e[4].toFixed(3), ",").concat(e[5].toFixed(3), ",").concat(e[6].toFixed(3), ",").concat(e[8].toFixed(3), ",").concat(e[9].toFixed(3), ",").concat(e[10].toFixed(3), ",").concat(e[12].toFixed(3), ",").concat(e[13].toFixed(3), ",").concat(e[14].toFixed(3));
144
145
  }
145
146
 
146
147
  /**
@@ -158,11 +159,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
158
159
  * Compute a lightweight fingerprint of the pathfinding inputs so that
159
160
  * consecutive identical runs can be skipped entirely.
160
161
  *
161
- * The fingerprint captures:
162
- * • The connections list (from / to pairs)
163
- * • The world transform of every top-level child in sceneData
164
- *
165
- * @param {Object} sceneData - scene data object with .children
162
+ * @param {Object} sceneData - scene object or manifest
166
163
  * @param {Array} connections - array of {from, to}
167
164
  * @returns {string}
168
165
  * @private
@@ -170,277 +167,241 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
170
167
  }, {
171
168
  key: "_computePathfindingFingerprint",
172
169
  value: function _computePathfindingFingerprint(sceneData, connections) {
170
+ var _this3 = this;
173
171
  var parts = [];
174
172
 
175
173
  // 1. Connections (sorted so order doesn't matter)
176
- parts.push(connections.map(function (c) {
174
+ parts.push((connections || []).map(function (c) {
177
175
  return "".concat(c.from, "->").concat(c.to);
178
176
  }).sort().join(','));
179
177
 
180
- // 2. World transforms of every referenced scene object
181
- if (sceneData.children) {
182
- var _iterator = _createForOfIteratorHelper(sceneData.children),
183
- _step;
184
- try {
185
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
186
- var child = _step.value;
187
- var obj = this.sceneViewer.scene.getObjectByProperty('uuid', child.uuid);
188
- if (obj) {
189
- parts.push("".concat(child.uuid, ":").concat(this._matrixHash(obj)));
190
- } else {
191
- var _p$x, _p$y, _p$z;
192
- // Object only in data, not in scene — include its serialised position
193
- var p = child.position || {};
194
- parts.push("".concat(child.uuid, ":").concat(((_p$x = p.x) !== null && _p$x !== void 0 ? _p$x : 0).toFixed(5), ",").concat(((_p$y = p.y) !== null && _p$y !== void 0 ? _p$y : 0).toFixed(5), ",").concat(((_p$z = p.z) !== null && _p$z !== void 0 ? _p$z : 0).toFixed(5)));
195
- }
178
+ // 2. World transforms of every referenced scene object (recursive)
179
+ var _addTransformsRecursive = function addTransformsRecursive(node) {
180
+ if (node.uuid) {
181
+ var obj = _this3.sceneViewer.scene.getObjectByProperty('uuid', node.uuid);
182
+ if (obj) {
183
+ parts.push("".concat(node.uuid, ":").concat(_this3._matrixHash(obj)));
184
+ } else {
185
+ var _p$x, _p$y, _p$z;
186
+ // Object only in data, not in scene — include its serialised position
187
+ var p = node.position || {};
188
+ parts.push("".concat(node.uuid, ":").concat(((_p$x = p.x) !== null && _p$x !== void 0 ? _p$x : 0).toFixed(5), ",").concat(((_p$y = p.y) !== null && _p$y !== void 0 ? _p$y : 0).toFixed(5), ",").concat(((_p$z = p.z) !== null && _p$z !== void 0 ? _p$z : 0).toFixed(5)));
196
189
  }
197
- } catch (err) {
198
- _iterator.e(err);
199
- } finally {
200
- _iterator.f();
201
190
  }
191
+
192
+ // Handle both flattened array and nested Three.js JSON structures
193
+ var children = node.children || node.object && node.object.children;
194
+ if (children && Array.isArray(children)) {
195
+ children.forEach(_addTransformsRecursive);
196
+ }
197
+ };
198
+ if (sceneData) {
199
+ _addTransformsRecursive(sceneData);
202
200
  }
203
201
  return parts.join('|');
204
202
  }
205
203
 
206
204
  /**
207
- * Enrich sceneData with worldBoundingBox for segments and components
208
- * Connectors remain with just position information.
209
- *
210
- * Uses _bboxCache to avoid recomputing filtered / io-device bboxes
211
- * when the underlying object's world matrix has not changed.
212
- *
213
- * @param {Object} sceneData - Original scene data
214
- * @returns {Object} Enriched scene data (shallow copy with modifications)
205
+ * Enrich scene data with world-space bounding boxes and positions for collision avoidance
206
+ * @param {Object|Array} sceneData - Original scene data or array of children
207
+ * @returns {Object|Array} Enriched scene data (shallow copy with modifications)
215
208
  * @private
216
209
  */
217
210
  }, {
218
211
  key: "_enrichSceneDataWithBoundingBoxes",
219
212
  value: function _enrichSceneDataWithBoundingBoxes(sceneData) {
220
- var _this3 = this;
221
- // Create a shallow copy of sceneData structure
222
- var enriched = _objectSpread2({}, sceneData);
223
- if (!sceneData.children || !Array.isArray(sceneData.children)) {
224
- console.warn('⚠️ sceneData has no children array');
225
- return enriched;
226
- }
213
+ var _this4 = this;
214
+ if (!sceneData) return sceneData;
215
+
216
+ // Recursive helper to enrich a node and its children
217
+ var _enrichNode = function enrichNode(node) {
218
+ if (!node) return node;
219
+ var enrichedNode = _objectSpread2({}, node);
227
220
 
228
- // Process children to add worldBoundingBox to segments and components
229
- enriched.children = sceneData.children.map(function (child) {
230
- // Enrich segments (check if objectType is 'segment' in userData)
231
- if (child.userData && child.userData.objectType === 'segment') {
232
- // Find the actual segment object in the scene
233
- var segmentObject = _this3.sceneViewer.scene.getObjectByProperty('uuid', child.uuid);
221
+ // Skip computed objects ( elbows etc )
222
+ if (node.userData && (node.userData.isComputed === true || node.userData.objectType === 'elbow')) {
223
+ return node;
224
+ }
225
+
226
+ // ── Enrich Segments ──
227
+ if (node.userData && node.userData.objectType === 'segment') {
228
+ var segmentObject = _this4.sceneViewer.scene.getObjectByProperty('uuid', node.uuid);
234
229
  if (segmentObject) {
235
- // ── Cache check ──
236
- var hash = _this3._matrixHash(segmentObject);
237
- var cached = _this3._bboxCache.get(child.uuid);
230
+ var hash = _this4._matrixHash(segmentObject);
231
+ var cached = _this4._bboxCache.get(node.uuid);
238
232
  if (cached && cached.matrixHash === hash && cached.segmentBBox) {
239
- return _objectSpread2(_objectSpread2({}, child), {}, {
240
- userData: _objectSpread2(_objectSpread2({}, child.userData), {}, {
241
- worldBoundingBox: cached.segmentBBox
242
- })
233
+ enrichedNode.userData = _objectSpread2(_objectSpread2({}, node.userData), {}, {
234
+ worldBoundingBox: cached.segmentBBox
243
235
  });
244
- }
245
-
246
- // Compute world bounding box
247
- var worldBBox = new THREE.Box3().setFromObject(segmentObject);
248
- var bboxData = {
249
- min: [worldBBox.min.x, worldBBox.min.y, worldBBox.min.z],
250
- max: [worldBBox.max.x, worldBBox.max.y, worldBBox.max.z]
251
- };
252
-
253
- // Store in cache
254
- _this3._bboxCache.set(child.uuid, {
255
- matrixHash: hash,
256
- segmentBBox: bboxData
257
- });
258
- return _objectSpread2(_objectSpread2({}, child), {}, {
259
- userData: _objectSpread2(_objectSpread2({}, child.userData), {}, {
236
+ } else {
237
+ var worldBBox = new THREE.Box3().setFromObject(segmentObject);
238
+ var bboxData = {
239
+ min: [worldBBox.min.x, worldBBox.min.y, worldBBox.min.z],
240
+ max: [worldBBox.max.x, worldBBox.max.y, worldBBox.max.z]
241
+ };
242
+ _this4._bboxCache.set(node.uuid, {
243
+ matrixHash: hash,
244
+ segmentBBox: bboxData
245
+ });
246
+ enrichedNode.userData = _objectSpread2(_objectSpread2({}, node.userData), {}, {
260
247
  worldBoundingBox: bboxData
261
- })
262
- });
263
- } else {
264
- console.warn("\u26A0\uFE0F Could not find segment object in scene: ".concat(child.uuid));
248
+ });
249
+ }
265
250
  }
266
251
  }
267
252
 
268
- // Enrich components (check if objectType is 'component' in userData)
269
- if (child.userData && child.userData.objectType === 'component') {
270
- // Find the actual component object in the scene
271
- var componentObject = _this3.sceneViewer.scene.getObjectByProperty('uuid', child.uuid);
253
+ // ── Enrich Components ──
254
+ else if (node.userData && node.userData.objectType === 'component') {
255
+ var componentObject = _this4.sceneViewer.scene.getObjectByProperty('uuid', node.uuid);
272
256
  if (componentObject) {
273
- // ── Cache check ──
274
- var _hash = _this3._matrixHash(componentObject);
275
- var _cached = _this3._bboxCache.get(child.uuid);
257
+ componentObject.updateMatrixWorld(true);
258
+ var _hash = _this4._matrixHash(componentObject);
259
+ var _cached = _this4._bboxCache.get(node.uuid);
276
260
  if (_cached && _cached.matrixHash === _hash && _cached.filteredBBox) {
277
- // Rebuild enriched child from cached data
278
- var _enrichedChild = _objectSpread2(_objectSpread2({}, child), {}, {
279
- userData: _objectSpread2(_objectSpread2({}, child.userData), {}, {
280
- worldBoundingBox: _cached.filteredBBox
281
- })
261
+ enrichedNode.position = {
262
+ x: componentObject.position.x,
263
+ y: componentObject.position.y,
264
+ z: componentObject.position.z
265
+ };
266
+ enrichedNode.rotation = {
267
+ x: THREE.MathUtils.radToDeg(componentObject.rotation.x),
268
+ y: THREE.MathUtils.radToDeg(componentObject.rotation.y),
269
+ z: THREE.MathUtils.radToDeg(componentObject.rotation.z)
270
+ };
271
+ enrichedNode.userData = _objectSpread2(_objectSpread2({}, node.userData), {}, {
272
+ worldBoundingBox: _cached.filteredBBox,
273
+ position: [componentObject.position.x, componentObject.position.y, componentObject.position.z]
282
274
  });
283
- if (_cached.ioDeviceBBoxes && _cached.ioDeviceBBoxes.length > 0) {
284
- if (!_enrichedChild.children) _enrichedChild.children = [];
285
- _cached.ioDeviceBBoxes.forEach(function (deviceBBox) {
286
- var existingIndex = _enrichedChild.children.findIndex(function (c) {
287
- return c.uuid === deviceBBox.uuid;
288
- });
289
- if (existingIndex >= 0) {
290
- _enrichedChild.children[existingIndex] = _objectSpread2(_objectSpread2({}, _enrichedChild.children[existingIndex]), {}, {
291
- userData: _objectSpread2(_objectSpread2({}, _enrichedChild.children[existingIndex].userData), {}, {
292
- objectType: 'io-device',
293
- worldBoundingBox: deviceBBox.worldBoundingBox
294
- })
295
- });
296
- } else {
297
- _enrichedChild.children.push({
298
- uuid: deviceBBox.uuid,
299
- userData: _objectSpread2(_objectSpread2({}, deviceBBox.userData), {}, {
300
- worldBoundingBox: deviceBBox.worldBoundingBox
301
- }),
302
- children: []
303
- });
304
- }
275
+
276
+ // Re-merge cached connectors and devices if they exist
277
+ if (!enrichedNode.children) enrichedNode.children = [];
278
+ if (_cached.connectorBBoxes) {
279
+ _cached.connectorBBoxes.forEach(function (conn) {
280
+ return _this4._mergeEnrichedChild(enrichedNode.children, conn);
305
281
  });
306
282
  }
307
-
308
- // Also reinject connectors from cache
309
- if (_cached.connectorBBoxes && _cached.connectorBBoxes.length > 0) {
310
- if (!_enrichedChild.children) _enrichedChild.children = [];
311
- _cached.connectorBBoxes.forEach(function (connBBox) {
312
- var existingIndex = _enrichedChild.children.findIndex(function (c) {
313
- return c.uuid === connBBox.uuid;
314
- });
315
- if (existingIndex >= 0) {
316
- _enrichedChild.children[existingIndex] = _objectSpread2(_objectSpread2({}, _enrichedChild.children[existingIndex]), {}, {
317
- userData: _objectSpread2(_objectSpread2({}, _enrichedChild.children[existingIndex].userData), {}, {
318
- worldBoundingBox: connBBox.worldBoundingBox
319
- })
320
- });
321
- } else {
322
- _enrichedChild.children.push({
323
- uuid: connBBox.uuid,
324
- userData: _objectSpread2(_objectSpread2({}, connBBox.userData), {}, {
325
- worldBoundingBox: connBBox.worldBoundingBox
326
- }),
327
- children: []
328
- });
329
- }
283
+ if (_cached.ioDeviceBBoxes) {
284
+ _cached.ioDeviceBBoxes.forEach(function (dev) {
285
+ return _this4._mergeEnrichedChild(enrichedNode.children, dev);
330
286
  });
331
287
  }
332
- return _enrichedChild;
288
+ } else {
289
+ var filteredBBox = computeFilteredBoundingBox(componentObject, ['io-device', 'connector']);
290
+ var _bboxData = {
291
+ min: [filteredBBox.min.x, filteredBBox.min.y, filteredBBox.min.z],
292
+ max: [filteredBBox.max.x, filteredBBox.max.y, filteredBBox.max.z]
293
+ };
294
+ enrichedNode.position = {
295
+ x: componentObject.position.x,
296
+ y: componentObject.position.y,
297
+ z: componentObject.position.z
298
+ };
299
+ enrichedNode.rotation = {
300
+ x: THREE.MathUtils.radToDeg(componentObject.rotation.x),
301
+ y: THREE.MathUtils.radToDeg(componentObject.rotation.y),
302
+ z: THREE.MathUtils.radToDeg(componentObject.rotation.z)
303
+ };
304
+ enrichedNode.userData = _objectSpread2(_objectSpread2({}, node.userData), {}, {
305
+ worldBoundingBox: _bboxData,
306
+ position: [componentObject.position.x, componentObject.position.y, componentObject.position.z]
307
+ });
308
+ var connectorBBoxes = computeConnectorBoundingBoxes(componentObject);
309
+ var ioDeviceBBoxes = computeIODeviceBoundingBoxes(componentObject);
310
+ if (!enrichedNode.children) enrichedNode.children = [];
311
+ connectorBBoxes.forEach(function (conn) {
312
+ return _this4._mergeEnrichedChild(enrichedNode.children, conn);
313
+ });
314
+ ioDeviceBBoxes.forEach(function (dev) {
315
+ return _this4._mergeEnrichedChild(enrichedNode.children, dev);
316
+ });
317
+ _this4._bboxCache.set(node.uuid, {
318
+ matrixHash: _hash,
319
+ filteredBBox: _bboxData,
320
+ ioDeviceBBoxes: ioDeviceBBoxes,
321
+ connectorBBoxes: connectorBBoxes
322
+ });
333
323
  }
324
+ }
325
+ }
334
326
 
335
- // Compute FILTERED bounding box excludes io-device and connector subtrees
336
- // so the component body bbox is tight-fitting and doesn't envelop attached devices
337
- var filteredBBox = computeFilteredBoundingBox(componentObject, ['io-device', 'connector']);
338
- 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), "]"));
339
- var _bboxData = {
340
- min: [filteredBBox.min.x, filteredBBox.min.y, filteredBBox.min.z],
341
- max: [filteredBBox.max.x, filteredBBox.max.y, filteredBBox.max.z]
327
+ // ── Enrich Standalone Objects (Gateways/Connectors) ──
328
+ else if (node.userData && (node.userData.objectType === 'gateway' || node.userData.objectType === 'connector')) {
329
+ var _node$userData;
330
+ var object = _this4.sceneViewer.scene.getObjectByProperty('uuid', node.uuid) || _this4.sceneViewer.scene.getObjectByProperty('uuid', (_node$userData = node.userData) === null || _node$userData === void 0 ? void 0 : _node$userData.originalUuid);
331
+ if (object) {
332
+ var worldPos = new THREE.Vector3();
333
+ object.getWorldPosition(worldPos);
334
+ enrichedNode.position = {
335
+ x: worldPos.x,
336
+ y: worldPos.y,
337
+ z: worldPos.z
342
338
  };
343
-
344
- // Build the enriched component entry
345
- var enrichedChild = _objectSpread2(_objectSpread2({}, child), {}, {
346
- userData: _objectSpread2(_objectSpread2({}, child.userData), {}, {
347
- worldBoundingBox: _bboxData
348
- })
339
+ enrichedNode.userData = _objectSpread2(_objectSpread2({}, node.userData), {}, {
340
+ position: [worldPos.x, worldPos.y, worldPos.z]
349
341
  });
350
342
 
351
- // Compute separate bounding boxes for each attached io-device
352
- var ioDeviceBBoxes = computeIODeviceBoundingBoxes(componentObject);
353
- if (ioDeviceBBoxes.length > 0) {
354
- // Ensure children array exists (may already contain connectors)
355
- if (!enrichedChild.children) {
356
- enrichedChild.children = [];
357
- }
358
-
359
- // Inject io-device entries with their own worldBoundingBox
360
- ioDeviceBBoxes.forEach(function (deviceBBox) {
361
- var existingIndex = enrichedChild.children.findIndex(function (c) {
362
- return c.uuid === deviceBBox.uuid;
363
- });
364
- if (existingIndex >= 0) {
365
- enrichedChild.children[existingIndex] = _objectSpread2(_objectSpread2({}, enrichedChild.children[existingIndex]), {}, {
366
- userData: _objectSpread2(_objectSpread2({}, enrichedChild.children[existingIndex].userData), {}, {
367
- objectType: 'io-device',
368
- worldBoundingBox: deviceBBox.worldBoundingBox
369
- })
370
- });
371
- } else {
372
- enrichedChild.children.push({
373
- uuid: deviceBBox.uuid,
374
- userData: _objectSpread2(_objectSpread2({}, deviceBBox.userData), {}, {
375
- worldBoundingBox: deviceBBox.worldBoundingBox
376
- }),
377
- children: []
378
- });
379
- }
380
- console.log("\uD83D\uDCE6 Injected io-device bbox for ".concat(deviceBBox.uuid, ": min=[").concat(deviceBBox.worldBoundingBox.min.map(function (v) {
381
- return v.toFixed(2);
382
- }).join(', '), "], max=[").concat(deviceBBox.worldBoundingBox.max.map(function (v) {
383
- return v.toFixed(2);
384
- }).join(', '), "]"));
385
- });
386
- console.log("\uD83D\uDCE6 Injected ".concat(ioDeviceBBoxes.length, " io-device bounding box(es) for component ").concat(child.uuid));
387
- }
388
-
389
- // PHASE 2: Enrich Connectors (CRITICAL for pathfinding API)
390
- // Also compute world bounding boxes for connectors and inject into children.
391
- // This ensures endpoints have world coordinates in sceneDataCopy.
392
- var connectorBBoxes = computeConnectorBoundingBoxes(componentObject);
393
- if (connectorBBoxes.length > 0) {
394
- if (!enrichedChild.children) enrichedChild.children = [];
395
- connectorBBoxes.forEach(function (connBBox) {
396
- var existingIndex = enrichedChild.children.findIndex(function (c) {
397
- return c.uuid === connBBox.uuid;
398
- });
399
- if (existingIndex >= 0) {
400
- enrichedChild.children[existingIndex] = _objectSpread2(_objectSpread2({}, enrichedChild.children[existingIndex]), {}, {
401
- userData: _objectSpread2(_objectSpread2({}, enrichedChild.children[existingIndex].userData), {}, {
402
- worldBoundingBox: connBBox.worldBoundingBox
403
- })
404
- });
405
- } else {
406
- enrichedChild.children.push({
407
- uuid: connBBox.uuid,
408
- userData: _objectSpread2(_objectSpread2({}, connBBox.userData), {}, {
409
- worldBoundingBox: connBBox.worldBoundingBox
410
- }),
411
- children: []
412
- });
413
- }
414
- });
343
+ // If it's a connector, also sync direction
344
+ if (node.userData.objectType === 'connector') {
345
+ var worldDir = new THREE.Vector3(0, 0, 1);
346
+ if (node.userData.direction) worldDir.set(node.userData.direction[0], node.userData.direction[1], node.userData.direction[2]);
347
+ worldDir.applyQuaternion(object.getWorldQuaternion(new THREE.Quaternion())).normalize();
348
+ enrichedNode.userData.direction = [worldDir.x, worldDir.y, worldDir.z];
415
349
  }
416
-
417
- // Store in cache
418
- _this3._bboxCache.set(child.uuid, {
419
- matrixHash: _hash,
420
- filteredBBox: _bboxData,
421
- ioDeviceBBoxes: ioDeviceBBoxes,
422
- connectorBBoxes: connectorBBoxes
423
- });
424
- return enrichedChild;
425
- } else {
426
- console.warn("\u26A0\uFE0F Could not find component object in scene: ".concat(child.uuid));
427
350
  }
428
351
  }
429
352
 
430
- // For non-segments and non-components (including connectors), return as-is
431
- return child;
432
- });
433
- return enriched;
353
+ // Recurse into children
354
+ if (node.children && Array.isArray(node.children)) {
355
+ enrichedNode.children = node.children.map(_enrichNode);
356
+ }
357
+ return enrichedNode;
358
+ };
359
+
360
+ // Handle root being an array or object
361
+ if (Array.isArray(sceneData)) {
362
+ return sceneData.map(_enrichNode);
363
+ } else if (sceneData.children && Array.isArray(sceneData.children)) {
364
+ var enrichedRoot = _objectSpread2({}, sceneData);
365
+ enrichedRoot.children = sceneData.children.map(_enrichNode);
366
+ return enrichedRoot;
367
+ } else {
368
+ return _enrichNode(sceneData);
369
+ }
434
370
  }
435
371
 
436
372
  /**
437
- * Core pathfinding logic shared across initialization and updates
373
+ * Helper to merge an enriched child (connector/device) into a children array
374
+ * @private
438
375
  */
376
+ }, {
377
+ key: "_mergeEnrichedChild",
378
+ value: function _mergeEnrichedChild(childrenArray, enrichedData) {
379
+ var existingIndex = childrenArray.findIndex(function (c) {
380
+ return c.uuid === enrichedData.uuid;
381
+ });
382
+ var nodeToMerge = {
383
+ uuid: enrichedData.uuid,
384
+ position: {
385
+ x: enrichedData.userData.position[0],
386
+ y: enrichedData.userData.position[1],
387
+ z: enrichedData.userData.position[2]
388
+ },
389
+ userData: _objectSpread2(_objectSpread2({}, enrichedData.userData), {}, {
390
+ worldBoundingBox: enrichedData.worldBoundingBox
391
+ }),
392
+ children: []
393
+ };
394
+ if (existingIndex >= 0) {
395
+ childrenArray[existingIndex] = _objectSpread2(_objectSpread2({}, childrenArray[existingIndex]), nodeToMerge);
396
+ } else {
397
+ childrenArray.push(nodeToMerge);
398
+ }
399
+ }
439
400
  }, {
440
401
  key: "_executePathfinding",
441
- value: (function () {
402
+ value: function () {
442
403
  var _executePathfinding2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(sceneData, connections) {
443
- var _this4 = this,
404
+ var _this5 = this,
444
405
  _sceneDataCopy$childr,
445
406
  _sceneDataCopy$childr2,
446
407
  _pathfindingResult$pa,
@@ -452,6 +413,12 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
452
413
  totalStart,
453
414
  inputGenStart,
454
415
  enrichedSceneData,
416
+ _from$userData,
417
+ _to$userData,
418
+ firstConn,
419
+ findEndpoint,
420
+ from,
421
+ to,
455
422
  connectionsCopy,
456
423
  sceneDataCopy,
457
424
  algoStart,
@@ -468,6 +435,10 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
468
435
  while (1) switch (_context.n) {
469
436
  case 0:
470
437
  options = _args.length > 2 && _args[2] !== undefined ? _args[2] : {};
438
+ // Fallback to sceneData connections if not explicitly provided (e.g. during transform updates)
439
+ if (!connections && sceneData && sceneData.connections) {
440
+ connections = sceneData.connections;
441
+ }
471
442
  options.createGateways, _options$context = options.context, context = _options$context === void 0 ? 'Pathfinding' : _options$context;
472
443
  timers = {};
473
444
  totalStart = performance.now(); // Create pathfinder instance with configuration only
@@ -496,7 +467,50 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
496
467
  console.log("\uD83D\uDD04 Updated matrix world for ".concat(context, " pathfinding execution"));
497
468
 
498
469
  // Enrich sceneData with worldBoundingBox for segments before deep copy
499
- enrichedSceneData = this._enrichSceneDataWithBoundingBoxes(sceneData); // Deep copy connections and sceneData to prevent pathfinder from mutating the original
470
+ enrichedSceneData = this._enrichSceneDataWithBoundingBoxes(sceneData); // DEBUG: Log first connection endpoints in enriched data
471
+ if (connections && connections.length > 0 && enrichedSceneData.children) {
472
+ firstConn = connections[0];
473
+ findEndpoint = function findEndpoint(uuid) {
474
+ var _iterator = _createForOfIteratorHelper(enrichedSceneData.children),
475
+ _step;
476
+ try {
477
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
478
+ var child = _step.value;
479
+ if (child.uuid === uuid) return child;
480
+ if (child.children) {
481
+ var _iterator2 = _createForOfIteratorHelper(child.children),
482
+ _step2;
483
+ try {
484
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
485
+ var nested = _step2.value;
486
+ if (nested.uuid === uuid) return nested;
487
+ }
488
+ } catch (err) {
489
+ _iterator2.e(err);
490
+ } finally {
491
+ _iterator2.f();
492
+ }
493
+ }
494
+ }
495
+ } catch (err) {
496
+ _iterator.e(err);
497
+ } finally {
498
+ _iterator.f();
499
+ }
500
+ return null;
501
+ };
502
+ from = findEndpoint(firstConn.from);
503
+ to = findEndpoint(firstConn.to);
504
+ console.log("\uD83D\uDCE1 [DEBUG] Pathfinding from ".concat(firstConn.from, " to ").concat(firstConn.to));
505
+ if (from) console.log(" From BBox: min=[".concat((_from$userData = from.userData) === null || _from$userData === void 0 || (_from$userData = _from$userData.worldBoundingBox) === null || _from$userData === void 0 || (_from$userData = _from$userData.min) === null || _from$userData === void 0 ? void 0 : _from$userData.map(function (v) {
506
+ return v.toFixed(2);
507
+ }), "]"));
508
+ if (to) console.log(" To BBox: min=[".concat((_to$userData = to.userData) === null || _to$userData === void 0 || (_to$userData = _to$userData.worldBoundingBox) === null || _to$userData === void 0 || (_to$userData = _to$userData.min) === null || _to$userData === void 0 ? void 0 : _to$userData.map(function (v) {
509
+ return v.toFixed(2);
510
+ }), "]"));
511
+ }
512
+
513
+ // Deep copy connections and sceneData to prevent pathfinder from mutating the original
500
514
  connectionsCopy = structuredClone(connections);
501
515
  sceneDataCopy = structuredClone(enrichedSceneData);
502
516
  timers.inputGeneration = performance.now() - inputGenStart;
@@ -527,7 +541,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
527
541
  if (pathfindingResult.paths) {
528
542
  pathfindingResult.paths.forEach(function (path) {
529
543
  var pathId = "".concat(path.from, "-->").concat(path.to);
530
- _this4._getOrCreatePathData(pathId, path.from, path.to);
544
+ _this5._getOrCreatePathData(pathId, path.from, path.to);
531
545
  });
532
546
  }
533
547
  timers.pathRendering = performance.now() - renderStart;
@@ -560,7 +574,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
560
574
  return _executePathfinding2.apply(this, arguments);
561
575
  }
562
576
  return _executePathfinding;
563
- }())
577
+ }()
564
578
  }, {
565
579
  key: "getSimplifiedSceneData",
566
580
  value: function getSimplifiedSceneData() {
@@ -599,7 +613,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
599
613
  }, {
600
614
  key: "_propagateFlowAttributesAndApplyVisualizations",
601
615
  value: function _propagateFlowAttributesAndApplyVisualizations(connections, pathfindingResult) {
602
- var _this5 = this,
616
+ var _this6 = this,
603
617
  _this$sceneViewer;
604
618
  if (!Array.isArray(connections) || !pathfindingResult) return;
605
619
 
@@ -627,7 +641,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
627
641
  var subPathIds = new Set(originalToSubPaths.get(origId) || []);
628
642
  subPathIds.add(origId);
629
643
  subPathIds.forEach(function (subPathId) {
630
- var pd = _this5.pathDataStore.get(subPathId);
644
+ var pd = _this6.pathDataStore.get(subPathId);
631
645
  if (pd && Object.keys(pd.flowAttributes).length === 0) {
632
646
  Object.entries(conn.flowAttributes).forEach(function (_ref2) {
633
647
  var _ref3 = _slicedToArray(_ref2, 2),
@@ -691,7 +705,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
691
705
  key: "initializePathfinder",
692
706
  value: (function () {
693
707
  var _initializePathfinder = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(data, crosscubeTextureSet) {
694
- var _this6 = this;
708
+ var _this7 = this;
695
709
  var pathfindingResult;
696
710
  return _regenerator().w(function (_context2) {
697
711
  while (1) switch (_context2.n) {
@@ -705,7 +719,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
705
719
  data.connections.forEach(function (conn) {
706
720
  if (conn.flowAttributes && _typeof(conn.flowAttributes) === 'object') {
707
721
  var pathId = "".concat(conn.from, "-->").concat(conn.to);
708
- var pd = _this6._getOrCreatePathData(pathId, conn.from, conn.to);
722
+ var pd = _this7._getOrCreatePathData(pathId, conn.from, conn.to);
709
723
  Object.entries(conn.flowAttributes).forEach(function (_ref6) {
710
724
  var _ref7 = _slicedToArray(_ref6, 2),
711
725
  key = _ref7[0],
@@ -823,33 +837,47 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
823
837
  key: "updatePathfindingAfterTransform",
824
838
  value: (function () {
825
839
  var _updatePathfindingAfterTransform = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(currentSceneData) {
826
- var fingerprint, result;
840
+ var _currentSceneData$sce;
841
+ var fingerprint, dataRoot, connections, result;
827
842
  return _regenerator().w(function (_context3) {
828
843
  while (1) switch (_context3.n) {
829
844
  case 0:
845
+ if (!(!currentSceneData || !currentSceneData.scene)) {
846
+ _context3.n = 1;
847
+ break;
848
+ }
849
+ console.warn('⚠️ updatePathfindingAfterTransform: Invalid scene data');
850
+ return _context3.a(2, null);
851
+ case 1:
830
852
  // ── Skip-unchanged-paths check ──────────────────────────────────
831
853
  // Ensure matrices are fresh so the fingerprint is accurate.
832
854
  this.sceneViewer.scene.updateMatrixWorld(true);
833
855
  fingerprint = this._computePathfindingFingerprint(currentSceneData.scene, currentSceneData.connections);
856
+ console.log("\uD83D\uDD0D Pathfinding update check. Fingerprint: ".concat(fingerprint.substring(0, 50), "..."));
834
857
  if (!(fingerprint === this._lastPathfindingFingerprint && this._lastPathfindingResult)) {
835
- _context3.n = 1;
858
+ _context3.n = 2;
836
859
  break;
837
860
  }
838
861
  console.log('⏭️ Pathfinding skipped — inputs unchanged since last run');
839
862
  return _context3.a(2, this._lastPathfindingResult);
840
- case 1:
863
+ case 2:
864
+ // Clear the cache for the specific fingerprint mismatch to ensure fresh enrichment
865
+ this.invalidateBBoxCache();
866
+
841
867
  // Remove all existing paths from the scene
842
868
  this.removeComputedObjects();
843
869
  console.log('🔄 Starting pathfinding with updated scene data...');
844
870
 
845
- // Note: Matrix updates and bounding box recomputation now handled in _executePathfinding
871
+ // Robust root discovery for different manifest structures
872
+ dataRoot = ((_currentSceneData$sce = currentSceneData.scene) === null || _currentSceneData$sce === void 0 ? void 0 : _currentSceneData$sce.object) || currentSceneData.scene || currentSceneData;
873
+ connections = currentSceneData.connections || []; // Note: Matrix updates and bounding box recomputation now handled in _executePathfinding
846
874
  // Use shared pathfinding logic (no gateways needed for transform updates)
847
- _context3.n = 2;
848
- return this._executePathfinding(currentSceneData.scene, currentSceneData.connections, {
875
+ _context3.n = 3;
876
+ return this._executePathfinding(dataRoot, connections, {
849
877
  createGateways: true,
850
878
  context: 'Transform Update'
851
879
  });
852
- case 2:
880
+ case 3:
853
881
  result = _context3.v;
854
882
  // Re-apply flow attribute colors (new materials are created on each execution)
855
883
  this._propagateFlowAttributesAndApplyVisualizations(currentSceneData.connections, result);