@2112-lab/central-plant 0.1.51 → 0.1.53

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.
@@ -239,6 +239,26 @@ function _objectSpread2(e) {
239
239
  }
240
240
  return e;
241
241
  }
242
+ function _objectWithoutProperties(e, t) {
243
+ if (null == e) return {};
244
+ var o,
245
+ r,
246
+ i = _objectWithoutPropertiesLoose(e, t);
247
+ if (Object.getOwnPropertySymbols) {
248
+ var n = Object.getOwnPropertySymbols(e);
249
+ for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
250
+ }
251
+ return i;
252
+ }
253
+ function _objectWithoutPropertiesLoose(r, e) {
254
+ if (null == r) return {};
255
+ var t = {};
256
+ for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
257
+ if (-1 !== e.indexOf(n)) continue;
258
+ t[n] = r[n];
259
+ }
260
+ return t;
261
+ }
242
262
  function _possibleConstructorReturn(t, e) {
243
263
  if (e && ("object" == typeof e || "function" == typeof e)) return e;
244
264
  if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
@@ -19090,23 +19110,30 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19090
19110
  * @param {number} value - The value to translate by
19091
19111
  * @returns {boolean} True if translation was successful, false otherwise
19092
19112
  */
19113
+ /**
19114
+ * Validate all preconditions for translateSegment operation
19115
+ * @param {string} segmentId - The UUID of the segment to translate
19116
+ * @param {string} axis - The axis to translate on ('x', 'y', or 'z')
19117
+ * @param {number} value - The value to translate by
19118
+ * @returns {Object|null} Returns { segment } if all checks pass, null otherwise
19119
+ * @private
19120
+ */
19093
19121
  }, {
19094
- key: "translateSegment",
19095
- value: function translateSegment(segmentId, axis, value) {
19096
- var _segment$userData, _segment$userData2, _segment$userData3, _this$sceneViewer2, _this$sceneViewer$man2, _this$sceneViewer$man3, _this$sceneViewer$man4;
19097
- var skipPathUpdate = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
19122
+ key: "validateTranslateSegment",
19123
+ value: function validateTranslateSegment(segmentId, axis, value) {
19124
+ var _segment$userData, _segment$userData2, _segment$userData3;
19098
19125
  // Validate parameters
19099
19126
  if (!segmentId || !axis || value === undefined || value === null) {
19100
19127
  console.error('❌ translateSegment(): Invalid parameters');
19101
- return false;
19128
+ return null;
19102
19129
  }
19103
19130
  if (!['x', 'y', 'z'].includes(axis)) {
19104
19131
  console.error("\u274C translateSegment(): Invalid axis '".concat(axis, "'. Must be 'x', 'y', or 'z'"));
19105
- return false;
19132
+ return null;
19106
19133
  }
19107
19134
  if (!this.sceneViewer || !this.sceneViewer.scene) {
19108
19135
  console.error('❌ translateSegment(): Scene viewer or scene not available');
19109
- return false;
19136
+ return null;
19110
19137
  }
19111
19138
 
19112
19139
  // Find the segment in the scene
@@ -19119,25 +19146,25 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19119
19146
  });
19120
19147
  if (!segment) {
19121
19148
  console.error("\u274C translateSegment(): Segment with ID '".concat(segmentId, "' not found in scene"));
19122
- return false;
19149
+ return null;
19123
19150
  }
19124
19151
 
19125
19152
  // Validate that it's actually a pipe segment
19126
19153
  if (!((_segment$userData = segment.userData) !== null && _segment$userData !== void 0 && _segment$userData.objectType) === 'segment') {
19127
19154
  console.error("\u274C translateSegment(): Object with ID '".concat(segmentId, "' is not a valid pipe segment"));
19128
- return false;
19155
+ return null;
19129
19156
  }
19130
19157
 
19131
19158
  // Check if segment is transformable
19132
19159
  if (((_segment$userData2 = segment.userData) === null || _segment$userData2 === void 0 ? void 0 : _segment$userData2.transformable) === false) {
19133
19160
  console.warn("\u26A0\uFE0F translateSegment(): Segment '".concat(segmentId, "' is marked as non-transformable (stub segment)"));
19134
- return false;
19161
+ return null;
19135
19162
  }
19136
19163
 
19137
19164
  // Check if segment is immutable (computed from pathfinder)
19138
19165
  if (((_segment$userData3 = segment.userData) === null || _segment$userData3 === void 0 ? void 0 : _segment$userData3.immutable) === true) {
19139
19166
  console.warn("\u26A0\uFE0F translateSegment(): Segment '".concat(segmentId, "' is immutable (computed from pathfinder)"));
19140
- return false;
19167
+ return null;
19141
19168
  }
19142
19169
 
19143
19170
  // Check segment orientation and cancel invalid translations
@@ -19156,62 +19183,74 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19156
19183
  if (absX > tolerance && axis === 'x') {
19157
19184
  console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
19158
19185
  console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
19159
- return false;
19186
+ return null;
19160
19187
  }
19161
19188
  if (absY > tolerance && axis === 'y') {
19162
19189
  console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
19163
19190
  console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
19164
- return false;
19191
+ return null;
19165
19192
  }
19166
19193
  if (absZ > tolerance && axis === 'z') {
19167
19194
  console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
19168
19195
  console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
19169
- return false;
19196
+ return null;
19170
19197
  }
19171
- console.log('[translateSegment] segment:', segment);
19172
19198
 
19173
- // Calculate segment endpoints to check for nearby connectors
19174
- var segmentEndpoints = this.calculateSegmentEndpoints(segment);
19199
+ // All checks passed - return the segment
19200
+ return {
19201
+ segment: segment
19202
+ };
19203
+ }
19175
19204
 
19176
- // Check if there are any connectors (component or manual) at segment endpoints
19177
- var connectorsAtEndpoints = this.findConnectorsAtPositions([segmentEndpoints.start, segmentEndpoints.end], 0.15 // tolerance for position matching
19178
- );
19179
- console.log("\uD83D\uDD0D Found ".concat(connectorsAtEndpoints.length, " total connectors at segment endpoints:"), connectorsAtEndpoints.map(function (c) {
19180
- var _c$userData, _c$parent, _c$parent2;
19181
- return {
19182
- uuid: c.uuid,
19183
- type: (_c$userData = c.userData) === null || _c$userData === void 0 ? void 0 : _c$userData.objectType,
19184
- parent: (_c$parent = c.parent) === null || _c$parent === void 0 ? void 0 : _c$parent.uuid,
19185
- parentType: (_c$parent2 = c.parent) === null || _c$parent2 === void 0 || (_c$parent2 = _c$parent2.userData) === null || _c$parent2 === void 0 ? void 0 : _c$parent2.objectType
19186
- };
19187
- }));
19188
- console.log("\uD83D\uDD04 translateSegment(): Translating segment ".concat(segmentId, " on ").concat(axis, " axis by ").concat(value));
19205
+ /**
19206
+ * Validate collision constraints for translateSegment operation
19207
+ * Temporarily applies the translation to check for collisions, then reverts
19208
+ * @param {THREE.Object3D} segment - The segment to check
19209
+ * @param {string} axis - The axis to translate on ('x', 'y', or 'z')
19210
+ * @param {number} value - The value to translate by
19211
+ * @returns {boolean} True if no collisions detected, false if translation would cause collision
19212
+ * @private
19213
+ */
19214
+ }, {
19215
+ key: "validateTranslateSegmentCollisions",
19216
+ value: function validateTranslateSegmentCollisions(segment, axis, value) {
19217
+ var _this$sceneViewer2;
19218
+ // Store original position for reverting
19219
+ var originalPosition = segment.position[axis];
19189
19220
 
19190
19221
  // Temporarily apply the translation to check for collisions
19191
- var originalPosition = segment.position[axis];
19192
19222
  segment.position[axis] += value;
19193
19223
  segment.updateMatrix();
19194
19224
  segment.updateMatrixWorld(true);
19195
19225
 
19196
19226
  // Check for collision with component connectors along the segment's path
19197
- var collision = this.checkSegmentPathConnectorCollision(segment);
19198
- if (collision) {
19227
+ var connectorCollision = this.checkSegmentPathConnectorCollision(segment);
19228
+ if (connectorCollision) {
19199
19229
  // Revert the translation
19200
19230
  segment.position[axis] = originalPosition;
19201
19231
  segment.updateMatrix();
19202
19232
  segment.updateMatrixWorld(true);
19203
19233
  console.warn("\u26A0\uFE0F translateSegment(): Translation canceled - segment path comes within 0.5 radius of component connector");
19204
- console.warn(" Distance to connector: ".concat(collision.distance.toFixed(3), " (max allowed: 0.5)"));
19205
- console.warn(" Closest point on segment: [".concat(collision.collisionPoint.x.toFixed(3), ", ").concat(collision.collisionPoint.y.toFixed(3), ", ").concat(collision.collisionPoint.z.toFixed(3), "]"));
19206
- console.warn(" Connector position: [".concat(collision.connectorPos.x.toFixed(3), ", ").concat(collision.connectorPos.y.toFixed(3), ", ").concat(collision.connectorPos.z.toFixed(3), "]"));
19207
- console.warn(" Colliding connector: ".concat(collision.connectorId, " on component: ").concat(collision.componentId));
19234
+ console.warn(" Distance to connector: ".concat(connectorCollision.distance.toFixed(3), " (max allowed: 0.5)"));
19235
+ console.warn(" Closest point on segment: [".concat(connectorCollision.collisionPoint.x.toFixed(3), ", ").concat(connectorCollision.collisionPoint.y.toFixed(3), ", ").concat(connectorCollision.collisionPoint.z.toFixed(3), "]"));
19236
+ console.warn(" Connector position: [".concat(connectorCollision.connectorPos.x.toFixed(3), ", ").concat(connectorCollision.connectorPos.y.toFixed(3), ", ").concat(connectorCollision.connectorPos.z.toFixed(3), "]"));
19237
+ console.warn(" Colliding connector: ".concat(connectorCollision.connectorId, " on component: ").concat(connectorCollision.componentId));
19208
19238
  return false;
19209
19239
  }
19210
19240
 
19211
- // Revert the temporary translation before continuing with the normal flow
19212
- segment.position[axis] = originalPosition;
19213
- segment.updateMatrix();
19214
- segment.updateMatrixWorld(true);
19241
+ // Check for collision with component bounding boxes
19242
+ var componentCollision = this.checkSegmentComponentBoundingBoxCollision(segment);
19243
+ if (componentCollision) {
19244
+ // Revert the translation
19245
+ segment.position[axis] = originalPosition;
19246
+ segment.updateMatrix();
19247
+ segment.updateMatrixWorld(true);
19248
+ console.warn("\u26A0\uFE0F translateSegment(): Translation canceled - segment would collide with component bounding box");
19249
+ console.warn(" Component ID: ".concat(componentCollision.componentId));
19250
+ console.warn(" Component Name: ".concat(componentCollision.componentName));
19251
+ console.warn(" Component Type: ".concat(componentCollision.componentType));
19252
+ return false;
19253
+ }
19215
19254
 
19216
19255
  // Check if translationalOverrideForAutomaticSegments is enabled
19217
19256
  var translationalOverride = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 || (_this$sceneViewer2 = _this$sceneViewer2.managers) === null || _this$sceneViewer2 === void 0 || (_this$sceneViewer2 = _this$sceneViewer2.settingsManager) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.getSetting('scene', 'translationalOverrideForAutomaticSegments');
@@ -19220,33 +19259,50 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19220
19259
  if (translationalOverride === false) {
19221
19260
  console.log('🔍 Checking for intersections with computed segments (translationalOverrideForAutomaticSegments is disabled)');
19222
19261
 
19223
- // Temporarily apply the translation to check for intersections
19224
- var _originalPosition = segment.position[axis];
19225
- segment.position[axis] += value;
19226
- segment.updateMatrix();
19227
- segment.updateMatrixWorld(true);
19228
-
19229
19262
  // Check if the translated segment intersects with any computed segments
19230
19263
  var hasIntersection = this.checkSegmentIntersection(segment);
19231
19264
  console.log("\uD83D\uDD04 translateSegment() hasIntersection:", hasIntersection);
19232
19265
  if (hasIntersection) {
19233
19266
  // Revert the translation
19234
- segment.position[axis] = _originalPosition;
19267
+ segment.position[axis] = originalPosition;
19235
19268
  segment.updateMatrix();
19236
19269
  segment.updateMatrixWorld(true);
19237
19270
  console.warn("\u26A0\uFE0F translateSegment(): Translation canceled - segment would intersect with computed segment(s)");
19238
19271
  return false;
19239
19272
  }
19240
19273
  console.log('✅ No intersections detected, proceeding with translation');
19241
- } else {
19242
- // Apply the translation to the Three.js object
19243
- segment.position[axis] += value;
19274
+ }
19244
19275
 
19245
- // Update matrices
19246
- segment.updateMatrix();
19247
- segment.updateMatrixWorld(true);
19276
+ // Revert the temporary translation
19277
+ segment.position[axis] = originalPosition;
19278
+ segment.updateMatrix();
19279
+ segment.updateMatrixWorld(true);
19280
+ return true;
19281
+ }
19282
+ }, {
19283
+ key: "translateSegment",
19284
+ value: function translateSegment(segmentId, axis, value) {
19285
+ var _this$sceneViewer$man2, _this$sceneViewer$man3, _this$sceneViewer$man4;
19286
+ var skipPathUpdate = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
19287
+ // Run all basic validation checks
19288
+ var validationResult = this.validateTranslateSegment(segmentId, axis, value);
19289
+ if (!validationResult) {
19290
+ return false;
19291
+ }
19292
+ var segment = validationResult.segment;
19293
+ console.log("\uD83D\uDD04 translateSegment(): Translating segment ".concat(segmentId, " on ").concat(axis, " axis by ").concat(value));
19294
+
19295
+ // Run collision validation checks
19296
+ var collisionValidation = this.validateTranslateSegmentCollisions(segment, axis, value);
19297
+ if (!collisionValidation) {
19298
+ return false;
19248
19299
  }
19249
19300
 
19301
+ // All validations passed - apply the translation
19302
+ segment.position[axis] += value;
19303
+ segment.updateMatrix();
19304
+ segment.updateMatrixWorld(true);
19305
+
19250
19306
  // Validate PathfindingManager and SceneOperationsManager availability
19251
19307
  var pathfindingManager = (_this$sceneViewer$man2 = this.sceneViewer.managers) === null || _this$sceneViewer$man2 === void 0 ? void 0 : _this$sceneViewer$man2.pathfindingManager;
19252
19308
  var sceneOperationsManager = (_this$sceneViewer$man3 = this.sceneViewer.managers) === null || _this$sceneViewer$man3 === void 0 ? void 0 : _this$sceneViewer$man3.sceneOperationsManager;
@@ -19723,7 +19779,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19723
19779
  }, {
19724
19780
  key: "updateSegmentConnectorPositions",
19725
19781
  value: function updateSegmentConnectorPositions(segment) {
19726
- var _this$sceneViewer4;
19782
+ var _this$sceneViewer4,
19783
+ _this = this;
19727
19784
  console.log("updateSegmentConnectorPositions started:", segment);
19728
19785
  if (!segment || !((_this$sceneViewer4 = this.sceneViewer) !== null && _this$sceneViewer4 !== void 0 && (_this$sceneViewer4 = _this$sceneViewer4.currentSceneData) !== null && _this$sceneViewer4 !== void 0 && _this$sceneViewer4.scene)) {
19729
19786
  console.warn('⚠️ updateSegmentConnectorPositions(): Missing segment or scene data');
@@ -19735,7 +19792,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19735
19792
  return Math.abs(value) < 1e-10 ? 0 : value;
19736
19793
  };
19737
19794
 
19738
- // Find all child connectors of the segment
19795
+ // Find all child connectors of the segment in the Three.js scene
19739
19796
  var connectors = [];
19740
19797
  segment.traverse(function (child) {
19741
19798
  var _child$userData8;
@@ -19749,29 +19806,14 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19749
19806
  }
19750
19807
  console.log("\uD83D\uDCCD Updating ".concat(connectors.length, " connector positions in scene data for segment ").concat(segment.uuid));
19751
19808
 
19752
- // First, find the segment in scene data
19753
- var sceneDataSegment = this.sceneViewer.currentSceneData.scene.children.find(function (child) {
19754
- var _segment$userData4;
19755
- return child.uuid === segment.uuid || child.uuid === ((_segment$userData4 = segment.userData) === null || _segment$userData4 === void 0 ? void 0 : _segment$userData4.originalUuid);
19756
- });
19757
- if (!sceneDataSegment) {
19758
- console.warn("\u26A0\uFE0F Segment ".concat(segment.uuid, " not found in scene data"));
19759
- return;
19760
- }
19761
- if (!sceneDataSegment.children || !Array.isArray(sceneDataSegment.children)) {
19762
- console.warn("\u26A0\uFE0F Segment ".concat(segment.uuid, " has no children array in scene data"));
19763
- return;
19764
- }
19765
- console.log("\u2705 Found segment in scene data with ".concat(sceneDataSegment.children.length, " children"));
19766
-
19767
- // Update each connector's position in scene data
19809
+ // Update each connector's position in scene data (connectors are at root level)
19768
19810
  connectors.forEach(function (connector) {
19769
19811
  // Get world position
19770
19812
  var worldPosition = new THREE__namespace.Vector3();
19771
19813
  connector.getWorldPosition(worldPosition);
19772
19814
 
19773
- // Find the connector in the segment's children array (not root scene.children)
19774
- var sceneDataConnector = sceneDataSegment.children.find(function (child) {
19815
+ // Find the connector at root level in scene data
19816
+ var sceneDataConnector = _this.sceneViewer.currentSceneData.scene.children.find(function (child) {
19775
19817
  var _connector$userData;
19776
19818
  return child.uuid === connector.uuid || child.uuid === ((_connector$userData = connector.userData) === null || _connector$userData === void 0 ? void 0 : _connector$userData.originalUuid);
19777
19819
  });
@@ -19780,9 +19822,14 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19780
19822
  sceneDataConnector.userData.position = [cleanPosition(worldPosition.x), cleanPosition(worldPosition.y), cleanPosition(worldPosition.z)];
19781
19823
  console.log("\u2705 Updated connector ".concat(connector.uuid, " position to [").concat(sceneDataConnector.userData.position.join(', '), "]"));
19782
19824
  } else {
19783
- console.warn("\u26A0\uFE0F Connector ".concat(connector.uuid, " not found in segment's children in scene data"));
19825
+ console.warn("\u26A0\uFE0F Connector ".concat(connector.uuid, " not found in scene data root level"));
19784
19826
  }
19785
19827
  });
19828
+
19829
+ // Update segment matrix and all connector matrices
19830
+ segment.updateMatrix();
19831
+ segment.updateMatrixWorld(true);
19832
+ console.log("\u2705 Updated matrices for segment ".concat(segment.uuid, " and its ").concat(connectors.length, " connectors"));
19786
19833
  }
19787
19834
 
19788
19835
  /**
@@ -19796,7 +19843,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19796
19843
  key: "checkSegmentIntersection",
19797
19844
  value: function checkSegmentIntersection(segment) {
19798
19845
  var _this$sceneViewer5,
19799
- _this = this;
19846
+ _this2 = this;
19800
19847
  if (!((_this$sceneViewer5 = this.sceneViewer) !== null && _this$sceneViewer5 !== void 0 && _this$sceneViewer5.scene)) {
19801
19848
  return false;
19802
19849
  }
@@ -19819,7 +19866,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19819
19866
  // Only check computed segments (isDeclared === false or undefined)
19820
19867
  if (((_child$userData9 = child.userData) === null || _child$userData9 === void 0 ? void 0 : _child$userData9.objectType) === 'segment' && ((_child$userData0 = child.userData) === null || _child$userData0 === void 0 ? void 0 : _child$userData0.isDeclared) !== true) {
19821
19868
  // Get endpoints of the computed segment
19822
- var computedEndpoints = _this.calculateSegmentEndpoints(child);
19869
+ var computedEndpoints = _this2.calculateSegmentEndpoints(child);
19823
19870
  var computedRadius = child.geometry.parameters.radiusTop || 0.05;
19824
19871
 
19825
19872
  // Combined radius threshold - segments intersect if closer than this
@@ -19844,7 +19891,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19844
19891
  }
19845
19892
 
19846
19893
  // Calculate the minimum distance between the two line segments
19847
- var distance = _this.calculateSegmentToSegmentDistance(segmentEndpoints.start, segmentEndpoints.end, computedEndpoints.start, computedEndpoints.end);
19894
+ var distance = _this2.calculateSegmentToSegmentDistance(segmentEndpoints.start, segmentEndpoints.end, computedEndpoints.start, computedEndpoints.end);
19848
19895
 
19849
19896
  // Only flag as intersection if segments are closer than combined radius
19850
19897
  if (distance < combinedRadius) {
@@ -20030,6 +20077,48 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20030
20077
  return collision;
20031
20078
  }
20032
20079
 
20080
+ /**
20081
+ * Check if a segment would collide with any component's bounding box
20082
+ * @param {THREE.Object3D} segment - The segment to check for collisions
20083
+ * @returns {Object|null} Collision info {componentId, componentName, componentType} if collision detected, null otherwise
20084
+ * @private
20085
+ */
20086
+ }, {
20087
+ key: "checkSegmentComponentBoundingBoxCollision",
20088
+ value: function checkSegmentComponentBoundingBoxCollision(segment) {
20089
+ var _this$sceneViewer8;
20090
+ if (!((_this$sceneViewer8 = this.sceneViewer) !== null && _this$sceneViewer8 !== void 0 && _this$sceneViewer8.scene) || !segment) {
20091
+ return null;
20092
+ }
20093
+
20094
+ // Create a bounding box for the segment
20095
+ var segmentBBox = new THREE__namespace.Box3().setFromObject(segment);
20096
+ var collision = null;
20097
+
20098
+ // Traverse scene to find all components
20099
+ this.sceneViewer.scene.traverse(function (child) {
20100
+ var _child$userData11, _child$userData12;
20101
+ if (collision) return; // Stop if collision already found
20102
+
20103
+ // Check if this is a component (equipment)
20104
+ if (((_child$userData11 = child.userData) === null || _child$userData11 === void 0 ? void 0 : _child$userData11.objectType) === 'component' && (_child$userData12 = child.userData) !== null && _child$userData12 !== void 0 && _child$userData12.libraryId) {
20105
+ // Create bounding box for the component
20106
+ var componentBBox = new THREE__namespace.Box3().setFromObject(child);
20107
+
20108
+ // Check if bounding boxes intersect
20109
+ if (segmentBBox.intersectsBox(componentBBox)) {
20110
+ console.log('⚠️ TransformOperationsManager: Segment bounding box collision with component:', child.userData.libraryId || child.name || child.uuid);
20111
+ collision = {
20112
+ componentId: child.uuid,
20113
+ componentName: child.name || 'Unknown',
20114
+ componentType: child.userData.libraryId || 'Unknown'
20115
+ };
20116
+ }
20117
+ }
20118
+ });
20119
+ return collision;
20120
+ }
20121
+
20033
20122
  /**
20034
20123
  * Calculate the minimum distance between two line segments in 3D space
20035
20124
  * @param {THREE.Vector3} p1 - Start point of first segment
@@ -20139,10 +20228,10 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20139
20228
  }, {
20140
20229
  key: "snapSegmentConnectorsToNearbyEndpoints",
20141
20230
  value: function snapSegmentConnectorsToNearbyEndpoints(movedSegment) {
20142
- var _this$sceneViewer8,
20143
- _this$sceneViewer9,
20144
- _this2 = this;
20145
- if (!movedSegment || !((_this$sceneViewer8 = this.sceneViewer) !== null && _this$sceneViewer8 !== void 0 && _this$sceneViewer8.scene)) {
20231
+ var _this$sceneViewer9,
20232
+ _this$sceneViewer0,
20233
+ _this3 = this;
20234
+ if (!movedSegment || !((_this$sceneViewer9 = this.sceneViewer) !== null && _this$sceneViewer9 !== void 0 && _this$sceneViewer9.scene)) {
20146
20235
  return [];
20147
20236
  }
20148
20237
  console.log('🔗 Finding adjacent segments connected to moved segment...');
@@ -20150,8 +20239,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20150
20239
  // Get the moved segment's connectors
20151
20240
  var movedConnectors = [];
20152
20241
  movedSegment.traverse(function (child) {
20153
- var _child$userData11;
20154
- if (((_child$userData11 = child.userData) === null || _child$userData11 === void 0 ? void 0 : _child$userData11.objectType) === 'segment-connector') {
20242
+ var _child$userData13;
20243
+ if (((_child$userData13 = child.userData) === null || _child$userData13 === void 0 ? void 0 : _child$userData13.objectType) === 'segment-connector') {
20155
20244
  movedConnectors.push(child);
20156
20245
  }
20157
20246
  });
@@ -20164,7 +20253,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20164
20253
  var newEndpoints = this.calculateSegmentEndpoints(movedSegment);
20165
20254
 
20166
20255
  // Check scene data for connections involving the moved segment's connectors
20167
- var connections = ((_this$sceneViewer9 = this.sceneViewer) === null || _this$sceneViewer9 === void 0 || (_this$sceneViewer9 = _this$sceneViewer9.currentSceneData) === null || _this$sceneViewer9 === void 0 ? void 0 : _this$sceneViewer9.connections) || [];
20256
+ var connections = ((_this$sceneViewer0 = this.sceneViewer) === null || _this$sceneViewer0 === void 0 || (_this$sceneViewer0 = _this$sceneViewer0.currentSceneData) === null || _this$sceneViewer0 === void 0 ? void 0 : _this$sceneViewer0.connections) || [];
20168
20257
  var movedConnectorIds = movedConnectors.map(function (c) {
20169
20258
  return c.uuid;
20170
20259
  });
@@ -20199,7 +20288,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20199
20288
  // Find the adjacent connector in the scene
20200
20289
  var adjacentConnector = null;
20201
20290
  var adjacentSegment = null;
20202
- _this2.sceneViewer.scene.traverse(function (object) {
20291
+ _this3.sceneViewer.scene.traverse(function (object) {
20203
20292
  var _object$userData;
20204
20293
  if (object.uuid === pair.adjacentConnectorId && ((_object$userData = object.userData) === null || _object$userData === void 0 ? void 0 : _object$userData.objectType) === 'segment-connector') {
20205
20294
  adjacentConnector = object;
@@ -20221,8 +20310,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20221
20310
  // Get all connectors of the adjacent segment
20222
20311
  var adjacentConnectors = [];
20223
20312
  adjacentSegment.traverse(function (child) {
20224
- var _child$userData12;
20225
- if (((_child$userData12 = child.userData) === null || _child$userData12 === void 0 ? void 0 : _child$userData12.objectType) === 'segment-connector') {
20313
+ var _child$userData14;
20314
+ if (((_child$userData14 = child.userData) === null || _child$userData14 === void 0 ? void 0 : _child$userData14.objectType) === 'segment-connector') {
20226
20315
  adjacentConnectors.push(child);
20227
20316
  }
20228
20317
  });
@@ -20248,12 +20337,12 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20248
20337
  // Constrain movement to maintain orthogonal alignment
20249
20338
  // Horizontal segments: only adjust X and Y, keep Z constant
20250
20339
  // Vertical segments: only adjust Z, keep X and Y constant
20251
- var constrainedPosition = _this2.constrainPositionToOrthogonal(pair.newPosition, stationaryWorldPos, adjacentSegment);
20340
+ var constrainedPosition = _this3.constrainPositionToOrthogonal(pair.newPosition, stationaryWorldPos, adjacentSegment);
20252
20341
 
20253
20342
  // Recreate the segment mesh with new length using explicit endpoint positions
20254
20343
  // Pass the intended positions, not the connector objects (which may have temporary positions)
20255
20344
  // Pass movedSegment as activeSegment context so zero-length removal knows which segment to extend
20256
- _this2.recreateSegmentMeshWithNewLength(adjacentSegment, adjacentConnectors, constrainedPosition, stationaryWorldPos, movedSegment);
20345
+ _this3.recreateSegmentMeshWithNewLength(adjacentSegment, adjacentConnectors, constrainedPosition, stationaryWorldPos, movedSegment);
20257
20346
 
20258
20347
  // CRITICAL: After recreating the mesh, BOTH connectors need to be repositioned
20259
20348
  // because the segment's center and rotation have changed
@@ -20262,13 +20351,13 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20262
20351
  var movingLocalPos = adjacentSegment.worldToLocal(constrainedPosition.clone());
20263
20352
  movingConnector.position.copy(movingLocalPos);
20264
20353
  movingConnector.updateMatrixWorld(true);
20265
- _this2.updateConnectorPositionInSceneData(movingConnector, constrainedPosition, adjacentSegment);
20354
+ _this3.updateConnectorPositionInSceneData(movingConnector, constrainedPosition, adjacentSegment);
20266
20355
 
20267
20356
  // Position stationary connector at its original world position
20268
20357
  var stationaryLocalPos = adjacentSegment.worldToLocal(stationaryWorldPos.clone());
20269
20358
  stationaryConnector.position.copy(stationaryLocalPos);
20270
20359
  stationaryConnector.updateMatrixWorld(true);
20271
- _this2.updateConnectorPositionInSceneData(stationaryConnector, stationaryWorldPos, adjacentSegment);
20360
+ _this3.updateConnectorPositionInSceneData(stationaryConnector, stationaryWorldPos, adjacentSegment);
20272
20361
 
20273
20362
  // Record this connection as satisfied
20274
20363
  satisfiedConnections.push({
@@ -20320,27 +20409,27 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20320
20409
  }, {
20321
20410
  key: "updateConnectorPositionInSceneData",
20322
20411
  value: function updateConnectorPositionInSceneData(connector, worldPosition, parentSegment) {
20323
- var _this$sceneViewer0;
20412
+ var _this$sceneViewer1;
20324
20413
  // Update scene data if available
20325
- if (!((_this$sceneViewer0 = this.sceneViewer) !== null && _this$sceneViewer0 !== void 0 && _this$sceneViewer0.currentSceneData)) {
20414
+ if (!((_this$sceneViewer1 = this.sceneViewer) !== null && _this$sceneViewer1 !== void 0 && (_this$sceneViewer1 = _this$sceneViewer1.currentSceneData) !== null && _this$sceneViewer1 !== void 0 && _this$sceneViewer1.scene)) {
20326
20415
  return;
20327
20416
  }
20328
20417
  var cleanPosition = function cleanPosition(value) {
20329
20418
  return Math.abs(value) < 1e-10 ? 0 : value;
20330
20419
  };
20331
20420
 
20332
- // Find connector in scene data and update position
20333
- var segmentInSceneData = this.sceneViewer.currentSceneData.scene.children.find(function (child) {
20334
- return child.uuid === parentSegment.uuid;
20421
+ // Find the connector at root level in scene data
20422
+ // Manual segment connectors are stored at the root level, not nested under the segment
20423
+ var sceneDataConnector = this.sceneViewer.currentSceneData.scene.children.find(function (child) {
20424
+ var _connector$userData2;
20425
+ return child.uuid === connector.uuid || child.uuid === ((_connector$userData2 = connector.userData) === null || _connector$userData2 === void 0 ? void 0 : _connector$userData2.originalUuid);
20335
20426
  });
20336
- if (segmentInSceneData !== null && segmentInSceneData !== void 0 && segmentInSceneData.children) {
20337
- var connectorInSceneData = segmentInSceneData.children.find(function (child) {
20338
- return child.uuid === connector.uuid;
20339
- });
20340
- if (connectorInSceneData !== null && connectorInSceneData !== void 0 && connectorInSceneData.userData) {
20341
- connectorInSceneData.userData.position = [cleanPosition(worldPosition.x), cleanPosition(worldPosition.y), cleanPosition(worldPosition.z)];
20342
- console.log("\u2705 Updated connector ".concat(connector.uuid, " position in scene data to [").concat(connectorInSceneData.userData.position.join(', '), "]"));
20343
- }
20427
+ if (sceneDataConnector && sceneDataConnector.userData) {
20428
+ // Update position as array [x, y, z] for pathfinder compatibility
20429
+ sceneDataConnector.userData.position = [cleanPosition(worldPosition.x), cleanPosition(worldPosition.y), cleanPosition(worldPosition.z)];
20430
+ console.log("\u2705 Updated connector ".concat(connector.uuid, " position in scene data to [").concat(sceneDataConnector.userData.position.join(', '), "]"));
20431
+ } else {
20432
+ console.warn("\u26A0\uFE0F Connector ".concat(connector.uuid, " not found at root level in scene data"));
20344
20433
  }
20345
20434
  }
20346
20435
 
@@ -20532,135 +20621,167 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20532
20621
  currentSceneData.connections = newConnections;
20533
20622
  console.log("\u2705 Updated connections: removed ".concat(removedConnections.length, ", added ").concat(externalId1 && externalId2 ? 1 : 0, ", total now: ").concat(newConnections.length));
20534
20623
 
20535
- // If there's an active segment (the one being translated), extend it to physically connect
20536
- if (activeSegment && externalId1 && externalId2) {
20537
- this._extendActiveSegmentToConnector(activeSegment, externalId1, externalId2, connector1Uuid, connector2Uuid);
20538
- }
20624
+ // Remove the segment's connectors from the scene and scene data
20625
+ connectors.forEach(function (connector) {
20626
+ var connectorUuid = connector.uuid;
20627
+
20628
+ // Remove connector from Three.js scene
20629
+ if (connector.parent) {
20630
+ connector.parent.remove(connector);
20631
+ console.log("\uD83D\uDDD1\uFE0F Removed connector ".concat(connectorUuid, " from Three.js scene"));
20632
+ }
20633
+
20634
+ // Dispose connector geometry and material
20635
+ if (connector.geometry) {
20636
+ connector.geometry.dispose();
20637
+ }
20638
+ if (connector.material) {
20639
+ if (Array.isArray(connector.material)) {
20640
+ connector.material.forEach(function (mat) {
20641
+ return mat.dispose();
20642
+ });
20643
+ } else {
20644
+ connector.material.dispose();
20645
+ }
20646
+ }
20647
+
20648
+ // Remove connector from scene data (connectors are at root level)
20649
+ if (currentSceneData.scene && currentSceneData.scene.children) {
20650
+ var connectorIndex = currentSceneData.scene.children.findIndex(function (child) {
20651
+ var _connector$userData3;
20652
+ return child.uuid === connectorUuid || child.uuid === ((_connector$userData3 = connector.userData) === null || _connector$userData3 === void 0 ? void 0 : _connector$userData3.originalUuid);
20653
+ });
20654
+ if (connectorIndex !== -1) {
20655
+ currentSceneData.scene.children.splice(connectorIndex, 1);
20656
+ console.log("\u2705 Removed connector ".concat(connectorUuid, " from scene data at index ").concat(connectorIndex));
20657
+ }
20658
+ }
20659
+ });
20539
20660
 
20540
20661
  // Remove the segment from the scene
20541
20662
  if (segment.parent) {
20542
20663
  segment.parent.remove(segment);
20664
+ console.log("\uD83D\uDDD1\uFE0F Removed segment ".concat(segment.uuid, " from Three.js scene"));
20543
20665
  }
20544
20666
 
20545
- // Dispose segment geometry and remove from scene data
20667
+ // Dispose segment geometry and material
20546
20668
  if (segment.geometry) {
20547
20669
  segment.geometry.dispose();
20548
20670
  }
20671
+ if (segment.material) {
20672
+ if (Array.isArray(segment.material)) {
20673
+ segment.material.forEach(function (mat) {
20674
+ return mat.dispose();
20675
+ });
20676
+ } else {
20677
+ segment.material.dispose();
20678
+ }
20679
+ }
20549
20680
 
20550
20681
  // Remove segment from scene data
20551
20682
  if (currentSceneData.scene && currentSceneData.scene.children) {
20552
20683
  var segmentIndex = currentSceneData.scene.children.findIndex(function (child) {
20553
- var _segment$userData5;
20554
- return child.uuid === segment.uuid || child.uuid === ((_segment$userData5 = segment.userData) === null || _segment$userData5 === void 0 ? void 0 : _segment$userData5.originalUuid);
20684
+ var _segment$userData4;
20685
+ return child.uuid === segment.uuid || child.uuid === ((_segment$userData4 = segment.userData) === null || _segment$userData4 === void 0 ? void 0 : _segment$userData4.originalUuid);
20555
20686
  });
20556
20687
  if (segmentIndex !== -1) {
20557
20688
  currentSceneData.scene.children.splice(segmentIndex, 1);
20558
20689
  console.log("\u2705 Removed segment from scene data at index ".concat(segmentIndex));
20559
20690
  }
20560
20691
  }
20561
- console.log("\u2705 Zero-length segment removed successfully: ".concat(segment.uuid));
20562
-
20563
- // Trigger path regeneration to create new segments for the merged connections
20564
- console.log('🔄 Triggering path regeneration to handle merged connections...');
20565
- if (sceneViewer && typeof sceneViewer.updatePaths === 'function') {
20566
- sceneViewer.updatePaths();
20567
- }
20568
- }
20569
-
20570
- /**
20571
- * Extend the active segment to physically connect with the connector on the other side
20572
- * @param {THREE.Object3D} activeSegment - The segment being translated (that caused the collapse)
20573
- * @param {string} externalId1 - First external connector UUID
20574
- * @param {string} externalId2 - Second external connector UUID
20575
- * @param {string} collapsedConnector1Uuid - First connector of the collapsed segment
20576
- * @param {string} collapsedConnector2Uuid - Second connector of the collapsed segment
20577
- * @private
20578
- */
20579
- }, {
20580
- key: "_extendActiveSegmentToConnector",
20581
- value: function _extendActiveSegmentToConnector(activeSegment, externalId1, externalId2, collapsedConnector1Uuid, collapsedConnector2Uuid) {
20582
- console.log("\uD83D\uDD17 Extending active segment ".concat(activeSegment.uuid, " to connect with external connector"));
20583
-
20584
- // Get the active segment's connectors
20585
- var activeConnectors = [];
20586
- activeSegment.traverse(function (child) {
20587
- var _child$userData13;
20588
- if (((_child$userData13 = child.userData) === null || _child$userData13 === void 0 ? void 0 : _child$userData13.objectType) === 'segment-connector') {
20589
- activeConnectors.push(child);
20590
- }
20591
- });
20592
- if (activeConnectors.length !== 2) {
20593
- console.warn("\u26A0\uFE0F Active segment doesn't have exactly 2 connectors, cannot extend");
20594
- return;
20595
- }
20596
-
20597
- // Determine which external connector is connected to the active segment
20598
- // and which one is on the other side (needs to be extended to)
20599
- var activeConnectorId = null;
20600
- var targetConnectorId = null;
20692
+ console.log("\u2705 Zero-length segment and its connectors removed successfully: ".concat(segment.uuid));
20601
20693
 
20602
- // Check if externalId1 or externalId2 is one of the active segment's connectors
20603
- var activeConnectorIds = activeConnectors.map(function (c) {
20604
- return c.uuid;
20605
- });
20606
- if (activeConnectorIds.includes(externalId1)) {
20607
- activeConnectorId = externalId1;
20608
- targetConnectorId = externalId2;
20609
- } else if (activeConnectorIds.includes(externalId2)) {
20610
- activeConnectorId = externalId2;
20611
- targetConnectorId = externalId1;
20612
- } else {
20613
- console.warn("\u26A0\uFE0F Neither external connector belongs to active segment - cannot extend");
20614
- return;
20615
- }
20616
- console.log("\uD83C\uDFAF Extending from active connector ".concat(activeConnectorId, " to target connector ").concat(targetConnectorId));
20694
+ // If there's an active segment being moved, extend it to connect to the external connector
20695
+ if (activeSegment && externalId1 && externalId2) {
20696
+ console.log('🔗 Extending active segment to maintain connection with external connector...');
20697
+
20698
+ // Find which connector belongs to the active segment
20699
+ var activeSegmentConnectorId = null;
20700
+ var externalConnectorToReach = null;
20701
+
20702
+ // Check if either external connector belongs to the active segment
20703
+ var activeSegmentConnectors = [];
20704
+ activeSegment.traverse(function (child) {
20705
+ var _child$userData15;
20706
+ if (((_child$userData15 = child.userData) === null || _child$userData15 === void 0 ? void 0 : _child$userData15.objectType) === 'segment-connector') {
20707
+ activeSegmentConnectors.push(child.uuid);
20708
+ }
20709
+ });
20710
+ if (activeSegmentConnectors.includes(externalId1)) {
20711
+ activeSegmentConnectorId = externalId1;
20712
+ externalConnectorToReach = externalId2;
20713
+ } else if (activeSegmentConnectors.includes(externalId2)) {
20714
+ activeSegmentConnectorId = externalId2;
20715
+ externalConnectorToReach = externalId1;
20716
+ }
20717
+ if (activeSegmentConnectorId && externalConnectorToReach) {
20718
+ console.log("\uD83D\uDCCD Active segment connector: ".concat(activeSegmentConnectorId));
20719
+ console.log("\uD83D\uDCCD External connector to reach: ".concat(externalConnectorToReach));
20720
+
20721
+ // Find the external connector object in the scene
20722
+ var externalConnectorObj = null;
20723
+ sceneViewer.scene.traverse(function (child) {
20724
+ if (child.uuid === externalConnectorToReach) {
20725
+ externalConnectorObj = child;
20726
+ }
20727
+ });
20728
+ if (externalConnectorObj) {
20729
+ // Get the external connector's world position
20730
+ var externalWorldPos = new THREE__namespace.Vector3();
20731
+ externalConnectorObj.getWorldPosition(externalWorldPos);
20732
+ console.log("\uD83C\uDFAF Extending active segment connector to position: [".concat(externalWorldPos.x.toFixed(3), ", ").concat(externalWorldPos.y.toFixed(3), ", ").concat(externalWorldPos.z.toFixed(3), "]"));
20733
+
20734
+ // Find the active segment's connector object
20735
+ var activeConnectorObj = null;
20736
+ activeSegment.traverse(function (child) {
20737
+ if (child.uuid === activeSegmentConnectorId) {
20738
+ activeConnectorObj = child;
20739
+ }
20740
+ });
20741
+ if (activeConnectorObj) {
20742
+ // Get all connectors of the active segment
20743
+ var activeConnectors = [];
20744
+ activeSegment.traverse(function (child) {
20745
+ var _child$userData16;
20746
+ if (((_child$userData16 = child.userData) === null || _child$userData16 === void 0 ? void 0 : _child$userData16.objectType) === 'segment-connector') {
20747
+ activeConnectors.push(child);
20748
+ }
20749
+ });
20617
20750
 
20618
- // Find the target connector in the scene
20619
- var targetConnector = null;
20620
- this.sceneViewer.scene.traverse(function (object) {
20621
- if (object.uuid === targetConnectorId) {
20622
- targetConnector = object;
20751
+ // Find the stationary connector (the one we're NOT moving)
20752
+ var stationaryConnector = activeConnectors.find(function (c) {
20753
+ return c.uuid !== activeSegmentConnectorId;
20754
+ });
20755
+ if (stationaryConnector && activeConnectors.length === 2) {
20756
+ var stationaryWorldPos = new THREE__namespace.Vector3();
20757
+ stationaryConnector.getWorldPosition(stationaryWorldPos);
20758
+
20759
+ // Recreate the active segment with new length to reach the external connector
20760
+ this.recreateSegmentMeshWithNewLength(activeSegment, activeConnectors, externalWorldPos, stationaryWorldPos);
20761
+
20762
+ // Update connector positions in scene data
20763
+ var movingLocalPos = activeSegment.worldToLocal(externalWorldPos.clone());
20764
+ activeConnectorObj.position.copy(movingLocalPos);
20765
+ activeConnectorObj.updateMatrixWorld(true);
20766
+ this.updateConnectorPositionInSceneData(activeConnectorObj, externalWorldPos, activeSegment);
20767
+ var stationaryLocalPos = activeSegment.worldToLocal(stationaryWorldPos.clone());
20768
+ stationaryConnector.position.copy(stationaryLocalPos);
20769
+ stationaryConnector.updateMatrixWorld(true);
20770
+ this.updateConnectorPositionInSceneData(stationaryConnector, stationaryWorldPos, activeSegment);
20771
+ console.log("\u2705 Active segment extended to connect with external connector");
20772
+ }
20773
+ }
20774
+ }
20775
+ } else {
20776
+ console.log('ℹ️ No active segment connector found in the connection - will regenerate paths instead');
20623
20777
  }
20624
- });
20625
- if (!targetConnector) {
20626
- console.warn("\u26A0\uFE0F Could not find target connector ".concat(targetConnectorId));
20627
- return;
20628
20778
  }
20629
20779
 
20630
- // Get target connector's world position
20631
- var targetWorldPos = new THREE__namespace.Vector3();
20632
- targetConnector.getWorldPosition(targetWorldPos);
20633
-
20634
- // Find which connector on the active segment needs to be moved
20635
- var movingConnector = activeConnectors.find(function (c) {
20636
- return c.uuid === activeConnectorId;
20637
- });
20638
- var stationaryConnector = activeConnectors.find(function (c) {
20639
- return c.uuid !== activeConnectorId;
20640
- });
20641
- if (!movingConnector || !stationaryConnector) {
20642
- console.warn("\u26A0\uFE0F Could not identify moving/stationary connectors");
20643
- return;
20780
+ // Trigger path regeneration to create new segments for any remaining unconnected endpoints
20781
+ console.log('🔄 Triggering path regeneration to handle any remaining connections...');
20782
+ if (sceneViewer && typeof sceneViewer.updatePaths === 'function') {
20783
+ sceneViewer.updatePaths();
20644
20784
  }
20645
-
20646
- // Get stationary connector's position
20647
- var stationaryWorldPos = new THREE__namespace.Vector3();
20648
- stationaryConnector.getWorldPosition(stationaryWorldPos);
20649
-
20650
- // Recreate the segment with new length to reach the target connector
20651
- console.log("\uD83D\uDCCF Extending active segment to reach target connector at [".concat(targetWorldPos.x.toFixed(2), ", ").concat(targetWorldPos.y.toFixed(2), ", ").concat(targetWorldPos.z.toFixed(2), "]"));
20652
- this.recreateSegmentMeshWithNewLength(activeSegment, activeConnectors, targetWorldPos, stationaryWorldPos);
20653
-
20654
- // Reposition both connectors after mesh recreation
20655
- var movingLocalPos = activeSegment.worldToLocal(targetWorldPos.clone());
20656
- movingConnector.position.copy(movingLocalPos);
20657
- movingConnector.updateMatrixWorld(true);
20658
- this.updateConnectorPositionInSceneData(movingConnector, targetWorldPos, activeSegment);
20659
- var stationaryLocalPos = activeSegment.worldToLocal(stationaryWorldPos.clone());
20660
- stationaryConnector.position.copy(stationaryLocalPos);
20661
- stationaryConnector.updateMatrixWorld(true);
20662
- this.updateConnectorPositionInSceneData(stationaryConnector, stationaryWorldPos, activeSegment);
20663
- console.log("\u2705 Active segment extended successfully to physically connect with target");
20664
20785
  }
20665
20786
  }]);
20666
20787
  }();
@@ -25107,6 +25228,7 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25107
25228
  gatewayMesh.uuid = gateway.id;
25108
25229
 
25109
25230
  // Set userData to make gateways selectable
25231
+ // Note: No 'direction' attribute - gateways don't need it
25110
25232
  gatewayMesh.userData = {
25111
25233
  objectType: 'gateway',
25112
25234
  isDeclared: false,
@@ -25234,6 +25356,11 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25234
25356
  var fromIsComponentConnector = pathData.fromObjectType === 'component-connector';
25235
25357
  var toIsComponentConnector = pathData.toObjectType === 'component-connector';
25236
25358
 
25359
+ // Check if endpoints have direction constraints (more accurate for immutability)
25360
+ // Segments adjacent to connectors with direction should be immutable
25361
+ var fromHasDirection = pathData.fromHasDirection !== undefined ? pathData.fromHasDirection : fromIsComponentConnector;
25362
+ var toHasDirection = pathData.toHasDirection !== undefined ? pathData.toHasDirection : toIsComponentConnector;
25363
+
25237
25364
  // Create one cylinder per segment (after colinear optimization, this should be minimal segments)
25238
25365
  for (var j = 0; j < pathPoints.length - 1; j++) {
25239
25366
  var start = pathPoints[j];
@@ -25262,10 +25389,12 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25262
25389
  // Make pipe segments selectable and add identifying data
25263
25390
  var segmentId = cylinder.uuid;
25264
25391
 
25265
- // Determine if this segment should be immutable (first or last 0.5-unit segment connected to component)
25392
+ // Determine if this segment should be immutable (first or last segment connected to connector with direction)
25393
+ // Segments adjacent to connectors with direction constraints are immutable (cannot be edited)
25394
+ // Segments adjacent to gateways (no direction) can be edited
25266
25395
  var isFirstSegment = j === 0;
25267
25396
  var isLastSegment = j === pathPoints.length - 2;
25268
- var isImmutable = fromIsComponentConnector && isFirstSegment || toIsComponentConnector && isLastSegment;
25397
+ var isImmutable = fromHasDirection && isFirstSegment || toHasDirection && isLastSegment;
25269
25398
 
25270
25399
  // Add userData to make pipe segments selectable and for tooltip display
25271
25400
  cylinder.userData = {
@@ -25287,7 +25416,6 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25287
25416
  _this3.createAndAddElbowIfNeeded(pathPoints, j, pipeRadius, pipeMaterial, pathData, index, sceneViewer.scene // Pass scene instead of polyline
25288
25417
  );
25289
25418
  }
25290
- console.log("\u2705 Created pipe path ".concat(pathData.from, "-").concat(pathData.to, " with ").concat(pathPoints.length - 1, " segments"));
25291
25419
  }
25292
25420
  });
25293
25421
  }
@@ -25439,6 +25567,7 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25439
25567
  }]);
25440
25568
  }(BaseDisposable);
25441
25569
 
25570
+ var _excluded$1 = ["direction"];
25442
25571
  var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25443
25572
  function ConnectorManager(sceneViewer) {
25444
25573
  var _this;
@@ -25493,6 +25622,7 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25493
25622
  connectorType: 'start',
25494
25623
  manualSegmentUuid: segment.uuid,
25495
25624
  isDeclared: true
25625
+ // Note: No 'direction' attribute - manual segment connectors don't need it
25496
25626
  };
25497
25627
 
25498
25628
  // Add start connector as child of segment
@@ -25513,6 +25643,7 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25513
25643
  connectorType: 'end',
25514
25644
  manualSegmentUuid: segment.uuid,
25515
25645
  isDeclared: true
25646
+ // Note: No 'direction' attribute - manual segment connectors don't need it
25516
25647
  };
25517
25648
 
25518
25649
  // Add end connector as child of segment
@@ -25555,6 +25686,7 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25555
25686
  /**
25556
25687
  * Add connectors to the scene and scene data
25557
25688
  * Note: Connectors are already children of the segment in the Three.js scene.
25689
+ * In scene data, they are added at the root level for faster pathfinder lookups.
25558
25690
  * @param {Array} connectors - Array of connector objects
25559
25691
  */
25560
25692
  }, {
@@ -25565,7 +25697,7 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25565
25697
  // Connectors are already children of the segment in Three.js, no need to add to scene
25566
25698
  console.log("\uD83D\uDD0C Connector already added as child of segment: ".concat(connector.uuid));
25567
25699
 
25568
- // Add to scene data structure as children of the segment (not at top level)
25700
+ // Add to scene data structure at root level for faster pathfinder lookups
25569
25701
  if (sceneViewer.currentSceneData && sceneViewer.currentSceneData.scene) {
25570
25702
  // Helper function to clean up floating-point precision errors
25571
25703
  var cleanPosition = function cleanPosition(value) {
@@ -25573,52 +25705,17 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25573
25705
  return Math.abs(value) < 1e-10 ? 0 : value;
25574
25706
  };
25575
25707
 
25576
- // Get world position for scene data (since connectors are now in local space)
25708
+ // Get world position for scene data (since connectors are in local space in Three.js)
25577
25709
  var worldPosition = new THREE__namespace.Vector3();
25578
25710
  connector.getWorldPosition(worldPosition);
25579
25711
 
25580
- // Get the segment UUID from connector's userData
25581
- var segmentUuid = connector.userData.manualSegmentUuid;
25582
- if (!segmentUuid) {
25583
- console.warn("\u26A0\uFE0F Connector ".concat(connector.uuid, " missing manualSegmentUuid, cannot add to scene data"));
25584
- return;
25585
- }
25586
-
25587
- // Find the segment in scene data
25588
- var _findSegment = function findSegment(children) {
25589
- var _iterator = _createForOfIteratorHelper(children),
25590
- _step;
25591
- try {
25592
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
25593
- var child = _step.value;
25594
- if (child.uuid === segmentUuid) {
25595
- return child;
25596
- }
25597
- if (child.children) {
25598
- var found = _findSegment(child.children);
25599
- if (found) return found;
25600
- }
25601
- }
25602
- } catch (err) {
25603
- _iterator.e(err);
25604
- } finally {
25605
- _iterator.f();
25606
- }
25607
- return null;
25608
- };
25609
- var segmentInSceneData = _findSegment(sceneViewer.currentSceneData.scene.children);
25610
- if (!segmentInSceneData) {
25611
- console.warn("\u26A0\uFE0F Could not find segment ".concat(segmentUuid, " in scene data for connector ").concat(connector.uuid));
25612
- return;
25613
- }
25614
-
25615
- // Ensure segment has a children array in scene data
25616
- if (!segmentInSceneData.children) {
25617
- segmentInSceneData.children = [];
25618
- }
25712
+ // Filter out 'direction' attribute - manual segment connectors don't need it
25713
+ var _ref = connector.userData || {};
25714
+ _ref.direction;
25715
+ var cleanedUserData = _objectWithoutProperties(_ref, _excluded$1);
25619
25716
  var sceneDataConnector = {
25620
25717
  uuid: connector.uuid,
25621
- userData: _objectSpread2(_objectSpread2({}, connector.userData), {}, {
25718
+ userData: _objectSpread2(_objectSpread2({}, cleanedUserData), {}, {
25622
25719
  isDeclared: true,
25623
25720
  // Mark manual segment connectors as declared
25624
25721
  // Position MUST be an array [x, y, z] for pathfinder compatibility
@@ -25626,9 +25723,10 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25626
25723
  })
25627
25724
  };
25628
25725
 
25629
- // Add connector as child of segment in scene data (not at top level)
25630
- segmentInSceneData.children.push(sceneDataConnector);
25631
- console.log("\uD83D\uDD0C Added connector to scene data as child of segment ".concat(segmentUuid, ": ").concat(connector.uuid));
25726
+ // Add connector at root level in scene data (not nested under segment)
25727
+ // This provides faster UUID lookups for the pathfinder
25728
+ sceneViewer.currentSceneData.scene.children.push(sceneDataConnector);
25729
+ console.log("\uD83D\uDD0C Added connector to scene data at root level: ".concat(connector.uuid));
25632
25730
  } else {
25633
25731
  console.warn('⚠️ Could not add connector to scene data - currentSceneData not available');
25634
25732
  }
@@ -25637,7 +25735,8 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25637
25735
 
25638
25736
  /**
25639
25737
  * Restructure connections to use the new connectors
25640
- * @param {string} authoritativeConnectorUUID - The authoritative connector UUID
25738
+ * Measures distance from point-a to both connectors and connects to the nearest one
25739
+ * @param {string} authoritativeConnectorUUID - The authoritative connector UUID (point-a)
25641
25740
  * @param {Array} connectors - Array of connector objects (0: start, 1: end)
25642
25741
  * @param {Object} currentSceneData - Current scene data
25643
25742
  * @param {Array<string>} convertedGatewayUUIDs - Array of gateway UUIDs that were converted to manual (optional)
@@ -25652,6 +25751,66 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25652
25751
 
25653
25752
  console.log("\uD83D\uDD27 [restructureConnections] connectors:", JSON.parse(JSON.stringify(connectors)));
25654
25753
  console.log("\uD83D\uDD27 [restructureConnections] convertedGatewayUUIDs:", convertedGatewayUUIDs);
25754
+ console.log("\uD83D\uDD27 [restructureConnections] authoritativeConnectorUUID:", authoritativeConnectorUUID);
25755
+
25756
+ // Find the authoritative connector object (point-a) in the scene to measure distances
25757
+ var authoritativeObject = null;
25758
+ this.sceneViewer.scene.traverse(function (obj) {
25759
+ if (obj.uuid === authoritativeConnectorUUID) {
25760
+ authoritativeObject = obj;
25761
+ }
25762
+ });
25763
+ if (!authoritativeObject) {
25764
+ console.error("\u274C [restructureConnections] Could not find authoritative connector: ".concat(authoritativeConnectorUUID));
25765
+ console.error("\u274C [restructureConnections] This may indicate:");
25766
+ console.error(" 1. The connector UUID changed during gateway manualization");
25767
+ console.error(" 2. The original connection was removed/modified before restructuring");
25768
+ console.error(" 3. The findOriginalConnection method returned a stale connection");
25769
+ console.error("\u274C [restructureConnections] Current connections:", JSON.stringify(currentSceneData.connections, null, 2));
25770
+
25771
+ // FALLBACK: Try to find any connector that might be the authoritative one
25772
+ // Look for objects with similar UUID patterns or check the original connection endpoints
25773
+ console.warn("\u26A0\uFE0F [restructureConnections] Attempting fallback connector search...");
25774
+
25775
+ // Search for possible matches (component connectors, gateway connectors, etc.)
25776
+ var possibleMatches = [];
25777
+ this.sceneViewer.scene.traverse(function (obj) {
25778
+ var _obj$userData, _obj$userData2, _obj$userData3;
25779
+ if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'connector' || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.objectType) === 'segment-connector' || ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.objectType) === 'gateway-connector') {
25780
+ possibleMatches.push({
25781
+ uuid: obj.uuid,
25782
+ objectType: obj.userData.objectType,
25783
+ isDeclared: obj.userData.isDeclared
25784
+ });
25785
+ }
25786
+ });
25787
+ console.warn("\u26A0\uFE0F [restructureConnections] Found ".concat(possibleMatches.length, " possible connectors:"), possibleMatches);
25788
+ console.error("\u274C [restructureConnections] Cannot proceed without authoritative connector");
25789
+ return;
25790
+ }
25791
+
25792
+ // Get world positions for distance calculation
25793
+ var pointA = new THREE__namespace.Vector3();
25794
+ authoritativeObject.getWorldPosition(pointA);
25795
+ var connector1Position = new THREE__namespace.Vector3();
25796
+ var connector2Position = new THREE__namespace.Vector3();
25797
+ connectors[0].getWorldPosition(connector1Position);
25798
+ connectors[1].getWorldPosition(connector2Position);
25799
+
25800
+ // Calculate distances from point-a to both segment connectors
25801
+ var distanceToConnector1 = pointA.distanceTo(connector1Position);
25802
+ var distanceToConnector2 = pointA.distanceTo(connector2Position);
25803
+ console.log("\uD83D\uDCCF [restructureConnections] Distance from ".concat(authoritativeConnectorUUID, " to:"));
25804
+ console.log(" - ".concat(startConnectorUUID, ": ").concat(distanceToConnector1.toFixed(4)));
25805
+ console.log(" - ".concat(endConnectorUUID, ": ").concat(distanceToConnector2.toFixed(4)));
25806
+
25807
+ // Determine which connector is nearest to point-a
25808
+ var nearestConnector = distanceToConnector1 <= distanceToConnector2 ? connectors[0] : connectors[1];
25809
+ var farthestConnector = distanceToConnector1 > distanceToConnector2 ? connectors[0] : connectors[1];
25810
+ var nearestConnectorUUID = nearestConnector.uuid;
25811
+ var farthestConnectorUUID = farthestConnector.uuid;
25812
+ console.log("\u2705 [restructureConnections] Nearest connector: ".concat(nearestConnectorUUID, " (distance: ").concat(Math.min(distanceToConnector1, distanceToConnector2).toFixed(4), ")"));
25813
+ console.log("\uD83D\uDCCD [restructureConnections] Farthest connector: ".concat(farthestConnectorUUID, " (distance: ").concat(Math.max(distanceToConnector1, distanceToConnector2).toFixed(4), ")"));
25655
25814
 
25656
25815
  // Deep copy connections array to prevent unintended mutations during iteration
25657
25816
  // Then map to update references, creating new connection objects
@@ -25660,30 +25819,32 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25660
25819
 
25661
25820
  // Create a shallow copy of the connection object
25662
25821
  var updatedConnection = _objectSpread2({}, connection);
25822
+
25823
+ // Update connections to point to the FARTHEST connector (opposite end from point-a)
25663
25824
  if (connection.from === authoritativeConnectorUUID) {
25664
- updatedConnection.from = endConnectorUUID;
25665
- console.log("\u2705 [restructureConnections] Updated connection.from to ".concat(endConnectorUUID));
25825
+ updatedConnection.from = farthestConnectorUUID;
25826
+ console.log("\u2705 [restructureConnections] Updated connection.from to ".concat(farthestConnectorUUID, " (farthest)"));
25666
25827
  }
25667
25828
  if (connection.to === authoritativeConnectorUUID) {
25668
- updatedConnection.to = endConnectorUUID;
25669
- console.log("\u2705 [restructureConnections] Updated connection.to to ".concat(endConnectorUUID));
25829
+ updatedConnection.to = farthestConnectorUUID;
25830
+ console.log("\u2705 [restructureConnections] Updated connection.to to ".concat(farthestConnectorUUID, " (farthest)"));
25670
25831
  }
25671
25832
  return updatedConnection;
25672
25833
  });
25673
25834
 
25674
25835
  // Check if the new connection already exists to prevent duplicates
25675
25836
  var newConnectionExists = currentSceneData.connections.some(function (conn) {
25676
- return conn.from === authoritativeConnectorUUID && conn.to === startConnectorUUID || conn.from === startConnectorUUID && conn.to === authoritativeConnectorUUID;
25837
+ return conn.from === authoritativeConnectorUUID && conn.to === nearestConnectorUUID || conn.from === nearestConnectorUUID && conn.to === authoritativeConnectorUUID;
25677
25838
  });
25678
25839
  if (!newConnectionExists) {
25679
- // Add new connection from authoritative connector to the segment start
25840
+ // Add new connection from authoritative connector (point-a) to the NEAREST segment connector
25680
25841
  currentSceneData.connections.push({
25681
25842
  from: authoritativeConnectorUUID,
25682
- to: startConnectorUUID
25843
+ to: nearestConnectorUUID
25683
25844
  });
25684
- console.log("\u2705 [restructureConnections] Added new connection: ".concat(authoritativeConnectorUUID, " \u2192 ").concat(startConnectorUUID));
25845
+ console.log("\u2705 [restructureConnections] Added new connection: ".concat(authoritativeConnectorUUID, " \u2192 ").concat(nearestConnectorUUID, " (nearest)"));
25685
25846
  } else {
25686
- console.log("\u26A0\uFE0F [restructureConnections] Connection already exists, skipping: ".concat(authoritativeConnectorUUID, " \u2192 ").concat(startConnectorUUID));
25847
+ console.log("\u26A0\uFE0F [restructureConnections] Connection already exists, skipping: ".concat(authoritativeConnectorUUID, " \u2192 ").concat(nearestConnectorUUID));
25687
25848
  }
25688
25849
 
25689
25850
  // Log converted gateways for tracking
@@ -25730,11 +25891,11 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25730
25891
  var fromObject = null;
25731
25892
  var toObject = null;
25732
25893
  sceneViewer.scene.traverse(function (obj) {
25733
- var _obj$userData, _obj$userData2;
25734
- if (obj.uuid === pathFrom || ((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.originalUuid) === pathFrom) {
25894
+ var _obj$userData4, _obj$userData5;
25895
+ if (obj.uuid === pathFrom || ((_obj$userData4 = obj.userData) === null || _obj$userData4 === void 0 ? void 0 : _obj$userData4.originalUuid) === pathFrom) {
25735
25896
  fromObject = obj;
25736
25897
  }
25737
- if (obj.uuid === pathTo || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.originalUuid) === pathTo) {
25898
+ if (obj.uuid === pathTo || ((_obj$userData5 = obj.userData) === null || _obj$userData5 === void 0 ? void 0 : _obj$userData5.originalUuid) === pathTo) {
25738
25899
  toObject = obj;
25739
25900
  }
25740
25901
  });
@@ -26562,12 +26723,11 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
26562
26723
  key: "_executePathfinding",
26563
26724
  value: function () {
26564
26725
  var _executePathfinding2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(sceneData, connections) {
26565
- var _simplifiedSceneData$;
26566
26726
  var options,
26567
26727
  _options$context,
26568
26728
  context,
26569
26729
  connectionsCopy,
26570
- simplifiedSceneData,
26730
+ sceneDataCopy,
26571
26731
  pathfindingResult,
26572
26732
  _args = arguments;
26573
26733
  return _regenerator().w(function (_context) {
@@ -26584,20 +26744,28 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
26584
26744
 
26585
26745
  // Deep copy connections to prevent pathfinder from mutating the original
26586
26746
  connectionsCopy = JSON.parse(JSON.stringify(connections));
26587
- simplifiedSceneData = JSON.parse(JSON.stringify(this.getSimplifiedSceneData())); // Take snapshot before pathfinding execution (capture Three.js scene)
26588
- this.snapshotManager.takeSnapshot(this.sceneViewer.scene,
26589
- // Pass the actual Three.js scene
26590
- connectionsCopy, context);
26591
- console.log('[Pathfinder] simplifiedSceneData length at creation:', (_simplifiedSceneData$ = simplifiedSceneData.children) === null || _simplifiedSceneData$ === void 0 ? void 0 : _simplifiedSceneData$.length);
26592
- console.log('[Pathfinder] simplifiedSceneData (deep clone for inspection):', JSON.parse(JSON.stringify(simplifiedSceneData)));
26747
+ sceneDataCopy = JSON.parse(JSON.stringify(sceneData));
26748
+ console.log("[Pathfinder] sceneDataCopy:", sceneDataCopy);
26749
+
26750
+ // const simplifiedSceneData = JSON.parse(JSON.stringify( this.getSimplifiedSceneData() ));
26593
26751
 
26594
- // Add debugging for pathfinder input
26595
- console.log('🔍 PATHFINDER DEBUGGING:');
26596
- console.log('🔗 [Pathfinder] Connections:', JSON.parse(JSON.stringify(connectionsCopy)));
26752
+ // // Take snapshot before pathfinding execution (capture Three.js scene)
26753
+ // this.snapshotManager.takeSnapshot(
26754
+ // this.sceneViewer.scene, // Pass the actual Three.js scene
26755
+ // connectionsCopy,
26756
+ // context
26757
+ // );
26758
+
26759
+ // console.log('[Pathfinder] simplifiedSceneData length at creation:', simplifiedSceneData.children?.length);
26760
+ // console.log('[Pathfinder] simplifiedSceneData (deep clone for inspection):', JSON.parse(JSON.stringify(simplifiedSceneData)));
26761
+
26762
+ // // Add debugging for pathfinder input
26763
+ // console.log('🔍 PATHFINDER DEBUGGING:');
26764
+ // console.log('🔗 [Pathfinder] Connections:', JSON.parse(JSON.stringify(connectionsCopy)));
26597
26765
 
26598
26766
  // Find paths using v1.0.17 API (sceneData and connections separately)
26599
26767
  // Pass deep copy to ensure pathfinder cannot mutate original connections
26600
- pathfindingResult = this.pathfinder.findPaths(simplifiedSceneData, connectionsCopy);
26768
+ pathfindingResult = this.pathfinder.findPaths(sceneDataCopy, connectionsCopy);
26601
26769
  console.log('[Pathfinder] Found paths:', JSON.parse(JSON.stringify(pathfindingResult.paths)));
26602
26770
  console.log('Generated gateways:', JSON.parse(JSON.stringify(pathfindingResult.gateways)));
26603
26771
  console.log('Rewired connections:', JSON.parse(JSON.stringify(pathfindingResult.rewiredConnections)));
@@ -28034,6 +28202,8 @@ var SceneClearingUtility = /*#__PURE__*/function () {
28034
28202
  }]);
28035
28203
  }();
28036
28204
 
28205
+ var _excluded = ["direction"],
28206
+ _excluded2 = ["direction"];
28037
28207
  var SceneOperationsManager = /*#__PURE__*/function () {
28038
28208
  function SceneOperationsManager(sceneViewer) {
28039
28209
  _classCallCheck(this, SceneOperationsManager);
@@ -28586,7 +28756,12 @@ var SceneOperationsManager = /*#__PURE__*/function () {
28586
28756
  if (connectorData.position) {
28587
28757
  _connectorMesh.position.set(connectorData.position.x || 0, connectorData.position.y || 0, connectorData.position.z || 0);
28588
28758
  }
28589
- _connectorMesh.userData = _objectSpread2(_objectSpread2({}, connectorData.userData), {}, {
28759
+
28760
+ // Initialize userData (filter out 'direction' - manual segment connectors don't need it)
28761
+ var _ref = connectorData.userData || {};
28762
+ _ref.direction;
28763
+ var _cleanedUserData = _objectWithoutProperties(_ref, _excluded);
28764
+ _connectorMesh.userData = _objectSpread2(_objectSpread2({}, _cleanedUserData), {}, {
28590
28765
  originalUuid: connectorData.uuid,
28591
28766
  objectType: 'segment-connector',
28592
28767
  isManualSegmentConnector: true,
@@ -28605,8 +28780,11 @@ var SceneOperationsManager = /*#__PURE__*/function () {
28605
28780
  connectorMesh.position.set(connectorData.position.x || 0, connectorData.position.y || 0, connectorData.position.z || 0);
28606
28781
  }
28607
28782
 
28608
- // Initialize userData
28609
- connectorMesh.userData = _objectSpread2(_objectSpread2({}, connectorData.userData), {}, {
28783
+ // Initialize userData (filter out 'direction' - manual segment connectors don't need it)
28784
+ var _ref2 = connectorData.userData || {};
28785
+ _ref2.direction;
28786
+ var cleanedUserData = _objectWithoutProperties(_ref2, _excluded2);
28787
+ connectorMesh.userData = _objectSpread2(_objectSpread2({}, cleanedUserData), {}, {
28610
28788
  originalUuid: connectorData.uuid,
28611
28789
  objectType: 'segment-connector',
28612
28790
  isManualSegmentConnector: true,
@@ -29444,20 +29622,29 @@ var SceneOperationsManager = /*#__PURE__*/function () {
29444
29622
  // Now add connectors to the segment's children array in scene data
29445
29623
  connectorManager.addConnectorsToScene(connectors);
29446
29624
 
29447
- // Find the original connection that this segment belongs to (after gateways are converted)
29625
+ // Check and convert connected gateways to manual (declared) FIRST
29626
+ // CRITICAL: This must happen BEFORE finding the authoritative connector
29627
+ // because gateway conversion may modify the connections array
29628
+ // NOTE: This may trigger path regeneration via translateGateway, so segment must already be renamed
29629
+ var convertedGatewayUUIDs = this._convertConnectedGatewaysToManual(connectors, currentSceneData);
29630
+ console.log('🔍 Gateway conversion completed, now finding authoritative connector with updated connections');
29631
+
29632
+ // Find the original connection that this segment belongs to (AFTER gateways are converted)
29633
+ // IMPORTANT: This must run after gateway conversion because connections may have changed
29448
29634
  var originalConnection = connectorManager.findOriginalConnection(segment, currentSceneData.connections);
29449
29635
  if (!originalConnection) {
29450
29636
  console.warn('⚠️ Could not find original connection for segment:', segment.uuid);
29637
+ console.warn('⚠️ This may indicate the connection was modified during gateway conversion');
29638
+ console.warn('⚠️ Available connections:', JSON.stringify(currentSceneData.connections, null, 2));
29451
29639
  return;
29452
29640
  }
29453
- console.log('🔍 Found original connection:', originalConnection);
29641
+ console.log('🔍 Found original connection (after gateway conversion):', originalConnection);
29642
+
29643
+ // Determine the authoritative connector (the non-gateway endpoint)
29644
+ // After gateway conversion, gateways should have connectors, so check for "Gateway" pattern
29454
29645
  var authoritativeConnectorUUID = originalConnection.from.includes("Gateway") === false ? originalConnection.from : originalConnection.to;
29455
29646
  console.log('[SceneOperations] authoritativeConnectorUUID:', authoritativeConnectorUUID);
29456
29647
 
29457
- // Check and convert connected gateways to manual (declared)
29458
- // NOTE: This may trigger path regeneration via translateGateway, so segment must already be renamed
29459
- var convertedGatewayUUIDs = this._convertConnectedGatewaysToManual(connectors, currentSceneData);
29460
-
29461
29648
  // Restructure connections, passing any converted gateway UUIDs
29462
29649
  connectorManager.restructureConnections(authoritativeConnectorUUID, connectors, currentSceneData, convertedGatewayUUIDs);
29463
29650
 
@@ -33609,7 +33796,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
33609
33796
  * Initialize the CentralPlant manager
33610
33797
  *
33611
33798
  * @constructor
33612
- * @version 0.1.51
33799
+ * @version 0.1.53
33613
33800
  * @updated 2025-10-22
33614
33801
  *
33615
33802
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.