@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.
@@ -161,10 +161,11 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
161
161
  }, {
162
162
  key: "_matrixHash",
163
163
  value: function _matrixHash(obj) {
164
+ // Force matrix update to ensure we're looking at the latest data
165
+ obj.updateMatrixWorld(true);
164
166
  var e = obj.matrixWorld.elements;
165
- // Use position (12-14) + first diagonal entries (0,5,10) — covers
166
- // translation AND rotation/scale changes with minimal work.
167
- 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));
167
+ // Just hash the position/rotation/scale part of the matrix (12 elements)
168
+ 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));
168
169
  }
169
170
 
170
171
  /**
@@ -182,11 +183,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
182
183
  * Compute a lightweight fingerprint of the pathfinding inputs so that
183
184
  * consecutive identical runs can be skipped entirely.
184
185
  *
185
- * The fingerprint captures:
186
- * • The connections list (from / to pairs)
187
- * • The world transform of every top-level child in sceneData
188
- *
189
- * @param {Object} sceneData - scene data object with .children
186
+ * @param {Object} sceneData - scene object or manifest
190
187
  * @param {Array} connections - array of {from, to}
191
188
  * @returns {string}
192
189
  * @private
@@ -194,277 +191,241 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
194
191
  }, {
195
192
  key: "_computePathfindingFingerprint",
196
193
  value: function _computePathfindingFingerprint(sceneData, connections) {
194
+ var _this3 = this;
197
195
  var parts = [];
198
196
 
199
197
  // 1. Connections (sorted so order doesn't matter)
200
- parts.push(connections.map(function (c) {
198
+ parts.push((connections || []).map(function (c) {
201
199
  return "".concat(c.from, "->").concat(c.to);
202
200
  }).sort().join(','));
203
201
 
204
- // 2. World transforms of every referenced scene object
205
- if (sceneData.children) {
206
- var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(sceneData.children),
207
- _step;
208
- try {
209
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
210
- var child = _step.value;
211
- var obj = this.sceneViewer.scene.getObjectByProperty('uuid', child.uuid);
212
- if (obj) {
213
- parts.push("".concat(child.uuid, ":").concat(this._matrixHash(obj)));
214
- } else {
215
- var _p$x, _p$y, _p$z;
216
- // Object only in data, not in scene — include its serialised position
217
- var p = child.position || {};
218
- 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)));
219
- }
202
+ // 2. World transforms of every referenced scene object (recursive)
203
+ var _addTransformsRecursive = function addTransformsRecursive(node) {
204
+ if (node.uuid) {
205
+ var obj = _this3.sceneViewer.scene.getObjectByProperty('uuid', node.uuid);
206
+ if (obj) {
207
+ parts.push("".concat(node.uuid, ":").concat(_this3._matrixHash(obj)));
208
+ } else {
209
+ var _p$x, _p$y, _p$z;
210
+ // Object only in data, not in scene — include its serialised position
211
+ var p = node.position || {};
212
+ 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)));
220
213
  }
221
- } catch (err) {
222
- _iterator.e(err);
223
- } finally {
224
- _iterator.f();
225
214
  }
215
+
216
+ // Handle both flattened array and nested Three.js JSON structures
217
+ var children = node.children || node.object && node.object.children;
218
+ if (children && Array.isArray(children)) {
219
+ children.forEach(_addTransformsRecursive);
220
+ }
221
+ };
222
+ if (sceneData) {
223
+ _addTransformsRecursive(sceneData);
226
224
  }
227
225
  return parts.join('|');
228
226
  }
229
227
 
230
228
  /**
231
- * Enrich sceneData with worldBoundingBox for segments and components
232
- * Connectors remain with just position information.
233
- *
234
- * Uses _bboxCache to avoid recomputing filtered / io-device bboxes
235
- * when the underlying object's world matrix has not changed.
236
- *
237
- * @param {Object} sceneData - Original scene data
238
- * @returns {Object} Enriched scene data (shallow copy with modifications)
229
+ * Enrich scene data with world-space bounding boxes and positions for collision avoidance
230
+ * @param {Object|Array} sceneData - Original scene data or array of children
231
+ * @returns {Object|Array} Enriched scene data (shallow copy with modifications)
239
232
  * @private
240
233
  */
241
234
  }, {
242
235
  key: "_enrichSceneDataWithBoundingBoxes",
243
236
  value: function _enrichSceneDataWithBoundingBoxes(sceneData) {
244
- var _this3 = this;
245
- // Create a shallow copy of sceneData structure
246
- var enriched = _rollupPluginBabelHelpers.objectSpread2({}, sceneData);
247
- if (!sceneData.children || !Array.isArray(sceneData.children)) {
248
- console.warn('⚠️ sceneData has no children array');
249
- return enriched;
250
- }
237
+ var _this4 = this;
238
+ if (!sceneData) return sceneData;
239
+
240
+ // Recursive helper to enrich a node and its children
241
+ var _enrichNode = function enrichNode(node) {
242
+ if (!node) return node;
243
+ var enrichedNode = _rollupPluginBabelHelpers.objectSpread2({}, node);
251
244
 
252
- // Process children to add worldBoundingBox to segments and components
253
- enriched.children = sceneData.children.map(function (child) {
254
- // Enrich segments (check if objectType is 'segment' in userData)
255
- if (child.userData && child.userData.objectType === 'segment') {
256
- // Find the actual segment object in the scene
257
- var segmentObject = _this3.sceneViewer.scene.getObjectByProperty('uuid', child.uuid);
245
+ // Skip computed objects ( elbows etc )
246
+ if (node.userData && (node.userData.isComputed === true || node.userData.objectType === 'elbow')) {
247
+ return node;
248
+ }
249
+
250
+ // ── Enrich Segments ──
251
+ if (node.userData && node.userData.objectType === 'segment') {
252
+ var segmentObject = _this4.sceneViewer.scene.getObjectByProperty('uuid', node.uuid);
258
253
  if (segmentObject) {
259
- // ── Cache check ──
260
- var hash = _this3._matrixHash(segmentObject);
261
- var cached = _this3._bboxCache.get(child.uuid);
254
+ var hash = _this4._matrixHash(segmentObject);
255
+ var cached = _this4._bboxCache.get(node.uuid);
262
256
  if (cached && cached.matrixHash === hash && cached.segmentBBox) {
263
- return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child), {}, {
264
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child.userData), {}, {
265
- worldBoundingBox: cached.segmentBBox
266
- })
257
+ enrichedNode.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, node.userData), {}, {
258
+ worldBoundingBox: cached.segmentBBox
267
259
  });
268
- }
269
-
270
- // Compute world bounding box
271
- var worldBBox = new THREE__namespace.Box3().setFromObject(segmentObject);
272
- var bboxData = {
273
- min: [worldBBox.min.x, worldBBox.min.y, worldBBox.min.z],
274
- max: [worldBBox.max.x, worldBBox.max.y, worldBBox.max.z]
275
- };
276
-
277
- // Store in cache
278
- _this3._bboxCache.set(child.uuid, {
279
- matrixHash: hash,
280
- segmentBBox: bboxData
281
- });
282
- return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child), {}, {
283
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child.userData), {}, {
260
+ } else {
261
+ var worldBBox = new THREE__namespace.Box3().setFromObject(segmentObject);
262
+ var bboxData = {
263
+ min: [worldBBox.min.x, worldBBox.min.y, worldBBox.min.z],
264
+ max: [worldBBox.max.x, worldBBox.max.y, worldBBox.max.z]
265
+ };
266
+ _this4._bboxCache.set(node.uuid, {
267
+ matrixHash: hash,
268
+ segmentBBox: bboxData
269
+ });
270
+ enrichedNode.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, node.userData), {}, {
284
271
  worldBoundingBox: bboxData
285
- })
286
- });
287
- } else {
288
- console.warn("\u26A0\uFE0F Could not find segment object in scene: ".concat(child.uuid));
272
+ });
273
+ }
289
274
  }
290
275
  }
291
276
 
292
- // Enrich components (check if objectType is 'component' in userData)
293
- if (child.userData && child.userData.objectType === 'component') {
294
- // Find the actual component object in the scene
295
- var componentObject = _this3.sceneViewer.scene.getObjectByProperty('uuid', child.uuid);
277
+ // ── Enrich Components ──
278
+ else if (node.userData && node.userData.objectType === 'component') {
279
+ var componentObject = _this4.sceneViewer.scene.getObjectByProperty('uuid', node.uuid);
296
280
  if (componentObject) {
297
- // ── Cache check ──
298
- var _hash = _this3._matrixHash(componentObject);
299
- var _cached = _this3._bboxCache.get(child.uuid);
281
+ componentObject.updateMatrixWorld(true);
282
+ var _hash = _this4._matrixHash(componentObject);
283
+ var _cached = _this4._bboxCache.get(node.uuid);
300
284
  if (_cached && _cached.matrixHash === _hash && _cached.filteredBBox) {
301
- // Rebuild enriched child from cached data
302
- var _enrichedChild = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child), {}, {
303
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child.userData), {}, {
304
- worldBoundingBox: _cached.filteredBBox
305
- })
285
+ enrichedNode.position = {
286
+ x: componentObject.position.x,
287
+ y: componentObject.position.y,
288
+ z: componentObject.position.z
289
+ };
290
+ enrichedNode.rotation = {
291
+ x: THREE__namespace.MathUtils.radToDeg(componentObject.rotation.x),
292
+ y: THREE__namespace.MathUtils.radToDeg(componentObject.rotation.y),
293
+ z: THREE__namespace.MathUtils.radToDeg(componentObject.rotation.z)
294
+ };
295
+ enrichedNode.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, node.userData), {}, {
296
+ worldBoundingBox: _cached.filteredBBox,
297
+ position: [componentObject.position.x, componentObject.position.y, componentObject.position.z]
306
298
  });
307
- if (_cached.ioDeviceBBoxes && _cached.ioDeviceBBoxes.length > 0) {
308
- if (!_enrichedChild.children) _enrichedChild.children = [];
309
- _cached.ioDeviceBBoxes.forEach(function (deviceBBox) {
310
- var existingIndex = _enrichedChild.children.findIndex(function (c) {
311
- return c.uuid === deviceBBox.uuid;
312
- });
313
- if (existingIndex >= 0) {
314
- _enrichedChild.children[existingIndex] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _enrichedChild.children[existingIndex]), {}, {
315
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _enrichedChild.children[existingIndex].userData), {}, {
316
- objectType: 'io-device',
317
- worldBoundingBox: deviceBBox.worldBoundingBox
318
- })
319
- });
320
- } else {
321
- _enrichedChild.children.push({
322
- uuid: deviceBBox.uuid,
323
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, deviceBBox.userData), {}, {
324
- worldBoundingBox: deviceBBox.worldBoundingBox
325
- }),
326
- children: []
327
- });
328
- }
299
+
300
+ // Re-merge cached connectors and devices if they exist
301
+ if (!enrichedNode.children) enrichedNode.children = [];
302
+ if (_cached.connectorBBoxes) {
303
+ _cached.connectorBBoxes.forEach(function (conn) {
304
+ return _this4._mergeEnrichedChild(enrichedNode.children, conn);
329
305
  });
330
306
  }
331
-
332
- // Also reinject connectors from cache
333
- if (_cached.connectorBBoxes && _cached.connectorBBoxes.length > 0) {
334
- if (!_enrichedChild.children) _enrichedChild.children = [];
335
- _cached.connectorBBoxes.forEach(function (connBBox) {
336
- var existingIndex = _enrichedChild.children.findIndex(function (c) {
337
- return c.uuid === connBBox.uuid;
338
- });
339
- if (existingIndex >= 0) {
340
- _enrichedChild.children[existingIndex] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _enrichedChild.children[existingIndex]), {}, {
341
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _enrichedChild.children[existingIndex].userData), {}, {
342
- worldBoundingBox: connBBox.worldBoundingBox
343
- })
344
- });
345
- } else {
346
- _enrichedChild.children.push({
347
- uuid: connBBox.uuid,
348
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, connBBox.userData), {}, {
349
- worldBoundingBox: connBBox.worldBoundingBox
350
- }),
351
- children: []
352
- });
353
- }
307
+ if (_cached.ioDeviceBBoxes) {
308
+ _cached.ioDeviceBBoxes.forEach(function (dev) {
309
+ return _this4._mergeEnrichedChild(enrichedNode.children, dev);
354
310
  });
355
311
  }
356
- return _enrichedChild;
312
+ } else {
313
+ var filteredBBox = boundingBoxUtils.computeFilteredBoundingBox(componentObject, ['io-device', 'connector']);
314
+ var _bboxData = {
315
+ min: [filteredBBox.min.x, filteredBBox.min.y, filteredBBox.min.z],
316
+ max: [filteredBBox.max.x, filteredBBox.max.y, filteredBBox.max.z]
317
+ };
318
+ enrichedNode.position = {
319
+ x: componentObject.position.x,
320
+ y: componentObject.position.y,
321
+ z: componentObject.position.z
322
+ };
323
+ enrichedNode.rotation = {
324
+ x: THREE__namespace.MathUtils.radToDeg(componentObject.rotation.x),
325
+ y: THREE__namespace.MathUtils.radToDeg(componentObject.rotation.y),
326
+ z: THREE__namespace.MathUtils.radToDeg(componentObject.rotation.z)
327
+ };
328
+ enrichedNode.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, node.userData), {}, {
329
+ worldBoundingBox: _bboxData,
330
+ position: [componentObject.position.x, componentObject.position.y, componentObject.position.z]
331
+ });
332
+ var connectorBBoxes = boundingBoxUtils.computeConnectorBoundingBoxes(componentObject);
333
+ var ioDeviceBBoxes = boundingBoxUtils.computeIODeviceBoundingBoxes(componentObject);
334
+ if (!enrichedNode.children) enrichedNode.children = [];
335
+ connectorBBoxes.forEach(function (conn) {
336
+ return _this4._mergeEnrichedChild(enrichedNode.children, conn);
337
+ });
338
+ ioDeviceBBoxes.forEach(function (dev) {
339
+ return _this4._mergeEnrichedChild(enrichedNode.children, dev);
340
+ });
341
+ _this4._bboxCache.set(node.uuid, {
342
+ matrixHash: _hash,
343
+ filteredBBox: _bboxData,
344
+ ioDeviceBBoxes: ioDeviceBBoxes,
345
+ connectorBBoxes: connectorBBoxes
346
+ });
357
347
  }
348
+ }
349
+ }
358
350
 
359
- // Compute FILTERED bounding box excludes io-device and connector subtrees
360
- // so the component body bbox is tight-fitting and doesn't envelop attached devices
361
- var filteredBBox = boundingBoxUtils.computeFilteredBoundingBox(componentObject, ['io-device', 'connector']);
362
- 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), "]"));
363
- var _bboxData = {
364
- min: [filteredBBox.min.x, filteredBBox.min.y, filteredBBox.min.z],
365
- max: [filteredBBox.max.x, filteredBBox.max.y, filteredBBox.max.z]
351
+ // ── Enrich Standalone Objects (Gateways/Connectors) ──
352
+ else if (node.userData && (node.userData.objectType === 'gateway' || node.userData.objectType === 'connector')) {
353
+ var _node$userData;
354
+ 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);
355
+ if (object) {
356
+ var worldPos = new THREE__namespace.Vector3();
357
+ object.getWorldPosition(worldPos);
358
+ enrichedNode.position = {
359
+ x: worldPos.x,
360
+ y: worldPos.y,
361
+ z: worldPos.z
366
362
  };
367
-
368
- // Build the enriched component entry
369
- var enrichedChild = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child), {}, {
370
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child.userData), {}, {
371
- worldBoundingBox: _bboxData
372
- })
363
+ enrichedNode.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, node.userData), {}, {
364
+ position: [worldPos.x, worldPos.y, worldPos.z]
373
365
  });
374
366
 
375
- // Compute separate bounding boxes for each attached io-device
376
- var ioDeviceBBoxes = boundingBoxUtils.computeIODeviceBoundingBoxes(componentObject);
377
- if (ioDeviceBBoxes.length > 0) {
378
- // Ensure children array exists (may already contain connectors)
379
- if (!enrichedChild.children) {
380
- enrichedChild.children = [];
381
- }
382
-
383
- // Inject io-device entries with their own worldBoundingBox
384
- ioDeviceBBoxes.forEach(function (deviceBBox) {
385
- var existingIndex = enrichedChild.children.findIndex(function (c) {
386
- return c.uuid === deviceBBox.uuid;
387
- });
388
- if (existingIndex >= 0) {
389
- enrichedChild.children[existingIndex] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, enrichedChild.children[existingIndex]), {}, {
390
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, enrichedChild.children[existingIndex].userData), {}, {
391
- objectType: 'io-device',
392
- worldBoundingBox: deviceBBox.worldBoundingBox
393
- })
394
- });
395
- } else {
396
- enrichedChild.children.push({
397
- uuid: deviceBBox.uuid,
398
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, deviceBBox.userData), {}, {
399
- worldBoundingBox: deviceBBox.worldBoundingBox
400
- }),
401
- children: []
402
- });
403
- }
404
- console.log("\uD83D\uDCE6 Injected io-device bbox for ".concat(deviceBBox.uuid, ": min=[").concat(deviceBBox.worldBoundingBox.min.map(function (v) {
405
- return v.toFixed(2);
406
- }).join(', '), "], max=[").concat(deviceBBox.worldBoundingBox.max.map(function (v) {
407
- return v.toFixed(2);
408
- }).join(', '), "]"));
409
- });
410
- console.log("\uD83D\uDCE6 Injected ".concat(ioDeviceBBoxes.length, " io-device bounding box(es) for component ").concat(child.uuid));
411
- }
412
-
413
- // PHASE 2: Enrich Connectors (CRITICAL for pathfinding API)
414
- // Also compute world bounding boxes for connectors and inject into children.
415
- // This ensures endpoints have world coordinates in sceneDataCopy.
416
- var connectorBBoxes = boundingBoxUtils.computeConnectorBoundingBoxes(componentObject);
417
- if (connectorBBoxes.length > 0) {
418
- if (!enrichedChild.children) enrichedChild.children = [];
419
- connectorBBoxes.forEach(function (connBBox) {
420
- var existingIndex = enrichedChild.children.findIndex(function (c) {
421
- return c.uuid === connBBox.uuid;
422
- });
423
- if (existingIndex >= 0) {
424
- enrichedChild.children[existingIndex] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, enrichedChild.children[existingIndex]), {}, {
425
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, enrichedChild.children[existingIndex].userData), {}, {
426
- worldBoundingBox: connBBox.worldBoundingBox
427
- })
428
- });
429
- } else {
430
- enrichedChild.children.push({
431
- uuid: connBBox.uuid,
432
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, connBBox.userData), {}, {
433
- worldBoundingBox: connBBox.worldBoundingBox
434
- }),
435
- children: []
436
- });
437
- }
438
- });
367
+ // If it's a connector, also sync direction
368
+ if (node.userData.objectType === 'connector') {
369
+ var worldDir = new THREE__namespace.Vector3(0, 0, 1);
370
+ if (node.userData.direction) worldDir.set(node.userData.direction[0], node.userData.direction[1], node.userData.direction[2]);
371
+ worldDir.applyQuaternion(object.getWorldQuaternion(new THREE__namespace.Quaternion())).normalize();
372
+ enrichedNode.userData.direction = [worldDir.x, worldDir.y, worldDir.z];
439
373
  }
440
-
441
- // Store in cache
442
- _this3._bboxCache.set(child.uuid, {
443
- matrixHash: _hash,
444
- filteredBBox: _bboxData,
445
- ioDeviceBBoxes: ioDeviceBBoxes,
446
- connectorBBoxes: connectorBBoxes
447
- });
448
- return enrichedChild;
449
- } else {
450
- console.warn("\u26A0\uFE0F Could not find component object in scene: ".concat(child.uuid));
451
374
  }
452
375
  }
453
376
 
454
- // For non-segments and non-components (including connectors), return as-is
455
- return child;
456
- });
457
- return enriched;
377
+ // Recurse into children
378
+ if (node.children && Array.isArray(node.children)) {
379
+ enrichedNode.children = node.children.map(_enrichNode);
380
+ }
381
+ return enrichedNode;
382
+ };
383
+
384
+ // Handle root being an array or object
385
+ if (Array.isArray(sceneData)) {
386
+ return sceneData.map(_enrichNode);
387
+ } else if (sceneData.children && Array.isArray(sceneData.children)) {
388
+ var enrichedRoot = _rollupPluginBabelHelpers.objectSpread2({}, sceneData);
389
+ enrichedRoot.children = sceneData.children.map(_enrichNode);
390
+ return enrichedRoot;
391
+ } else {
392
+ return _enrichNode(sceneData);
393
+ }
458
394
  }
459
395
 
460
396
  /**
461
- * Core pathfinding logic shared across initialization and updates
397
+ * Helper to merge an enriched child (connector/device) into a children array
398
+ * @private
462
399
  */
400
+ }, {
401
+ key: "_mergeEnrichedChild",
402
+ value: function _mergeEnrichedChild(childrenArray, enrichedData) {
403
+ var existingIndex = childrenArray.findIndex(function (c) {
404
+ return c.uuid === enrichedData.uuid;
405
+ });
406
+ var nodeToMerge = {
407
+ uuid: enrichedData.uuid,
408
+ position: {
409
+ x: enrichedData.userData.position[0],
410
+ y: enrichedData.userData.position[1],
411
+ z: enrichedData.userData.position[2]
412
+ },
413
+ userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, enrichedData.userData), {}, {
414
+ worldBoundingBox: enrichedData.worldBoundingBox
415
+ }),
416
+ children: []
417
+ };
418
+ if (existingIndex >= 0) {
419
+ childrenArray[existingIndex] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, childrenArray[existingIndex]), nodeToMerge);
420
+ } else {
421
+ childrenArray.push(nodeToMerge);
422
+ }
423
+ }
463
424
  }, {
464
425
  key: "_executePathfinding",
465
- value: (function () {
426
+ value: function () {
466
427
  var _executePathfinding2 = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee(sceneData, connections) {
467
- var _this4 = this,
428
+ var _this5 = this,
468
429
  _sceneDataCopy$childr,
469
430
  _sceneDataCopy$childr2,
470
431
  _pathfindingResult$pa,
@@ -476,6 +437,12 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
476
437
  totalStart,
477
438
  inputGenStart,
478
439
  enrichedSceneData,
440
+ _from$userData,
441
+ _to$userData,
442
+ firstConn,
443
+ findEndpoint,
444
+ from,
445
+ to,
479
446
  connectionsCopy,
480
447
  sceneDataCopy,
481
448
  algoStart,
@@ -492,6 +459,10 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
492
459
  while (1) switch (_context.n) {
493
460
  case 0:
494
461
  options = _args.length > 2 && _args[2] !== undefined ? _args[2] : {};
462
+ // Fallback to sceneData connections if not explicitly provided (e.g. during transform updates)
463
+ if (!connections && sceneData && sceneData.connections) {
464
+ connections = sceneData.connections;
465
+ }
495
466
  options.createGateways, _options$context = options.context, context = _options$context === void 0 ? 'Pathfinding' : _options$context;
496
467
  timers = {};
497
468
  totalStart = performance.now(); // Create pathfinder instance with configuration only
@@ -520,7 +491,50 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
520
491
  console.log("\uD83D\uDD04 Updated matrix world for ".concat(context, " pathfinding execution"));
521
492
 
522
493
  // Enrich sceneData with worldBoundingBox for segments before deep copy
523
- enrichedSceneData = this._enrichSceneDataWithBoundingBoxes(sceneData); // Deep copy connections and sceneData to prevent pathfinder from mutating the original
494
+ enrichedSceneData = this._enrichSceneDataWithBoundingBoxes(sceneData); // DEBUG: Log first connection endpoints in enriched data
495
+ if (connections && connections.length > 0 && enrichedSceneData.children) {
496
+ firstConn = connections[0];
497
+ findEndpoint = function findEndpoint(uuid) {
498
+ var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(enrichedSceneData.children),
499
+ _step;
500
+ try {
501
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
502
+ var child = _step.value;
503
+ if (child.uuid === uuid) return child;
504
+ if (child.children) {
505
+ var _iterator2 = _rollupPluginBabelHelpers.createForOfIteratorHelper(child.children),
506
+ _step2;
507
+ try {
508
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
509
+ var nested = _step2.value;
510
+ if (nested.uuid === uuid) return nested;
511
+ }
512
+ } catch (err) {
513
+ _iterator2.e(err);
514
+ } finally {
515
+ _iterator2.f();
516
+ }
517
+ }
518
+ }
519
+ } catch (err) {
520
+ _iterator.e(err);
521
+ } finally {
522
+ _iterator.f();
523
+ }
524
+ return null;
525
+ };
526
+ from = findEndpoint(firstConn.from);
527
+ to = findEndpoint(firstConn.to);
528
+ console.log("\uD83D\uDCE1 [DEBUG] Pathfinding from ".concat(firstConn.from, " to ").concat(firstConn.to));
529
+ 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) {
530
+ return v.toFixed(2);
531
+ }), "]"));
532
+ 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) {
533
+ return v.toFixed(2);
534
+ }), "]"));
535
+ }
536
+
537
+ // Deep copy connections and sceneData to prevent pathfinder from mutating the original
524
538
  connectionsCopy = structuredClone(connections);
525
539
  sceneDataCopy = structuredClone(enrichedSceneData);
526
540
  timers.inputGeneration = performance.now() - inputGenStart;
@@ -551,7 +565,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
551
565
  if (pathfindingResult.paths) {
552
566
  pathfindingResult.paths.forEach(function (path) {
553
567
  var pathId = "".concat(path.from, "-->").concat(path.to);
554
- _this4._getOrCreatePathData(pathId, path.from, path.to);
568
+ _this5._getOrCreatePathData(pathId, path.from, path.to);
555
569
  });
556
570
  }
557
571
  timers.pathRendering = performance.now() - renderStart;
@@ -584,7 +598,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
584
598
  return _executePathfinding2.apply(this, arguments);
585
599
  }
586
600
  return _executePathfinding;
587
- }())
601
+ }()
588
602
  }, {
589
603
  key: "getSimplifiedSceneData",
590
604
  value: function getSimplifiedSceneData() {
@@ -623,7 +637,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
623
637
  }, {
624
638
  key: "_propagateFlowAttributesAndApplyVisualizations",
625
639
  value: function _propagateFlowAttributesAndApplyVisualizations(connections, pathfindingResult) {
626
- var _this5 = this,
640
+ var _this6 = this,
627
641
  _this$sceneViewer;
628
642
  if (!Array.isArray(connections) || !pathfindingResult) return;
629
643
 
@@ -651,7 +665,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
651
665
  var subPathIds = new Set(originalToSubPaths.get(origId) || []);
652
666
  subPathIds.add(origId);
653
667
  subPathIds.forEach(function (subPathId) {
654
- var pd = _this5.pathDataStore.get(subPathId);
668
+ var pd = _this6.pathDataStore.get(subPathId);
655
669
  if (pd && Object.keys(pd.flowAttributes).length === 0) {
656
670
  Object.entries(conn.flowAttributes).forEach(function (_ref2) {
657
671
  var _ref3 = _rollupPluginBabelHelpers.slicedToArray(_ref2, 2),
@@ -715,7 +729,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
715
729
  key: "initializePathfinder",
716
730
  value: (function () {
717
731
  var _initializePathfinder = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee2(data, crosscubeTextureSet) {
718
- var _this6 = this;
732
+ var _this7 = this;
719
733
  var pathfindingResult;
720
734
  return _rollupPluginBabelHelpers.regenerator().w(function (_context2) {
721
735
  while (1) switch (_context2.n) {
@@ -729,7 +743,7 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
729
743
  data.connections.forEach(function (conn) {
730
744
  if (conn.flowAttributes && _rollupPluginBabelHelpers["typeof"](conn.flowAttributes) === 'object') {
731
745
  var pathId = "".concat(conn.from, "-->").concat(conn.to);
732
- var pd = _this6._getOrCreatePathData(pathId, conn.from, conn.to);
746
+ var pd = _this7._getOrCreatePathData(pathId, conn.from, conn.to);
733
747
  Object.entries(conn.flowAttributes).forEach(function (_ref6) {
734
748
  var _ref7 = _rollupPluginBabelHelpers.slicedToArray(_ref6, 2),
735
749
  key = _ref7[0],
@@ -847,33 +861,47 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
847
861
  key: "updatePathfindingAfterTransform",
848
862
  value: (function () {
849
863
  var _updatePathfindingAfterTransform = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee3(currentSceneData) {
850
- var fingerprint, result;
864
+ var _currentSceneData$sce;
865
+ var fingerprint, dataRoot, connections, result;
851
866
  return _rollupPluginBabelHelpers.regenerator().w(function (_context3) {
852
867
  while (1) switch (_context3.n) {
853
868
  case 0:
869
+ if (!(!currentSceneData || !currentSceneData.scene)) {
870
+ _context3.n = 1;
871
+ break;
872
+ }
873
+ console.warn('⚠️ updatePathfindingAfterTransform: Invalid scene data');
874
+ return _context3.a(2, null);
875
+ case 1:
854
876
  // ── Skip-unchanged-paths check ──────────────────────────────────
855
877
  // Ensure matrices are fresh so the fingerprint is accurate.
856
878
  this.sceneViewer.scene.updateMatrixWorld(true);
857
879
  fingerprint = this._computePathfindingFingerprint(currentSceneData.scene, currentSceneData.connections);
880
+ console.log("\uD83D\uDD0D Pathfinding update check. Fingerprint: ".concat(fingerprint.substring(0, 50), "..."));
858
881
  if (!(fingerprint === this._lastPathfindingFingerprint && this._lastPathfindingResult)) {
859
- _context3.n = 1;
882
+ _context3.n = 2;
860
883
  break;
861
884
  }
862
885
  console.log('⏭️ Pathfinding skipped — inputs unchanged since last run');
863
886
  return _context3.a(2, this._lastPathfindingResult);
864
- case 1:
887
+ case 2:
888
+ // Clear the cache for the specific fingerprint mismatch to ensure fresh enrichment
889
+ this.invalidateBBoxCache();
890
+
865
891
  // Remove all existing paths from the scene
866
892
  this.removeComputedObjects();
867
893
  console.log('🔄 Starting pathfinding with updated scene data...');
868
894
 
869
- // Note: Matrix updates and bounding box recomputation now handled in _executePathfinding
895
+ // Robust root discovery for different manifest structures
896
+ dataRoot = ((_currentSceneData$sce = currentSceneData.scene) === null || _currentSceneData$sce === void 0 ? void 0 : _currentSceneData$sce.object) || currentSceneData.scene || currentSceneData;
897
+ connections = currentSceneData.connections || []; // Note: Matrix updates and bounding box recomputation now handled in _executePathfinding
870
898
  // Use shared pathfinding logic (no gateways needed for transform updates)
871
- _context3.n = 2;
872
- return this._executePathfinding(currentSceneData.scene, currentSceneData.connections, {
899
+ _context3.n = 3;
900
+ return this._executePathfinding(dataRoot, connections, {
873
901
  createGateways: true,
874
902
  context: 'Transform Update'
875
903
  });
876
- case 2:
904
+ case 3:
877
905
  result = _context3.v;
878
906
  // Re-apply flow attribute colors (new materials are created on each execution)
879
907
  this._propagateFlowAttributesAndApplyVisualizations(currentSceneData.connections, result);