@2112-lab/central-plant 0.1.51 → 0.1.52

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.
@@ -19090,23 +19090,30 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19090
19090
  * @param {number} value - The value to translate by
19091
19091
  * @returns {boolean} True if translation was successful, false otherwise
19092
19092
  */
19093
+ /**
19094
+ * Validate all preconditions for translateSegment operation
19095
+ * @param {string} segmentId - The UUID of the segment to translate
19096
+ * @param {string} axis - The axis to translate on ('x', 'y', or 'z')
19097
+ * @param {number} value - The value to translate by
19098
+ * @returns {Object|null} Returns { segment } if all checks pass, null otherwise
19099
+ * @private
19100
+ */
19093
19101
  }, {
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;
19102
+ key: "validateTranslateSegment",
19103
+ value: function validateTranslateSegment(segmentId, axis, value) {
19104
+ var _segment$userData, _segment$userData2, _segment$userData3;
19098
19105
  // Validate parameters
19099
19106
  if (!segmentId || !axis || value === undefined || value === null) {
19100
19107
  console.error('❌ translateSegment(): Invalid parameters');
19101
- return false;
19108
+ return null;
19102
19109
  }
19103
19110
  if (!['x', 'y', 'z'].includes(axis)) {
19104
19111
  console.error("\u274C translateSegment(): Invalid axis '".concat(axis, "'. Must be 'x', 'y', or 'z'"));
19105
- return false;
19112
+ return null;
19106
19113
  }
19107
19114
  if (!this.sceneViewer || !this.sceneViewer.scene) {
19108
19115
  console.error('❌ translateSegment(): Scene viewer or scene not available');
19109
- return false;
19116
+ return null;
19110
19117
  }
19111
19118
 
19112
19119
  // Find the segment in the scene
@@ -19119,25 +19126,25 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19119
19126
  });
19120
19127
  if (!segment) {
19121
19128
  console.error("\u274C translateSegment(): Segment with ID '".concat(segmentId, "' not found in scene"));
19122
- return false;
19129
+ return null;
19123
19130
  }
19124
19131
 
19125
19132
  // Validate that it's actually a pipe segment
19126
19133
  if (!((_segment$userData = segment.userData) !== null && _segment$userData !== void 0 && _segment$userData.objectType) === 'segment') {
19127
19134
  console.error("\u274C translateSegment(): Object with ID '".concat(segmentId, "' is not a valid pipe segment"));
19128
- return false;
19135
+ return null;
19129
19136
  }
19130
19137
 
19131
19138
  // Check if segment is transformable
19132
19139
  if (((_segment$userData2 = segment.userData) === null || _segment$userData2 === void 0 ? void 0 : _segment$userData2.transformable) === false) {
19133
19140
  console.warn("\u26A0\uFE0F translateSegment(): Segment '".concat(segmentId, "' is marked as non-transformable (stub segment)"));
19134
- return false;
19141
+ return null;
19135
19142
  }
19136
19143
 
19137
19144
  // Check if segment is immutable (computed from pathfinder)
19138
19145
  if (((_segment$userData3 = segment.userData) === null || _segment$userData3 === void 0 ? void 0 : _segment$userData3.immutable) === true) {
19139
19146
  console.warn("\u26A0\uFE0F translateSegment(): Segment '".concat(segmentId, "' is immutable (computed from pathfinder)"));
19140
- return false;
19147
+ return null;
19141
19148
  }
19142
19149
 
19143
19150
  // Check segment orientation and cancel invalid translations
@@ -19156,62 +19163,74 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19156
19163
  if (absX > tolerance && axis === 'x') {
19157
19164
  console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
19158
19165
  console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
19159
- return false;
19166
+ return null;
19160
19167
  }
19161
19168
  if (absY > tolerance && axis === 'y') {
19162
19169
  console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
19163
19170
  console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
19164
- return false;
19171
+ return null;
19165
19172
  }
19166
19173
  if (absZ > tolerance && axis === 'z') {
19167
19174
  console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
19168
19175
  console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
19169
- return false;
19176
+ return null;
19170
19177
  }
19171
- console.log('[translateSegment] segment:', segment);
19172
19178
 
19173
- // Calculate segment endpoints to check for nearby connectors
19174
- var segmentEndpoints = this.calculateSegmentEndpoints(segment);
19179
+ // All checks passed - return the segment
19180
+ return {
19181
+ segment: segment
19182
+ };
19183
+ }
19175
19184
 
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));
19185
+ /**
19186
+ * Validate collision constraints for translateSegment operation
19187
+ * Temporarily applies the translation to check for collisions, then reverts
19188
+ * @param {THREE.Object3D} segment - The segment to check
19189
+ * @param {string} axis - The axis to translate on ('x', 'y', or 'z')
19190
+ * @param {number} value - The value to translate by
19191
+ * @returns {boolean} True if no collisions detected, false if translation would cause collision
19192
+ * @private
19193
+ */
19194
+ }, {
19195
+ key: "validateTranslateSegmentCollisions",
19196
+ value: function validateTranslateSegmentCollisions(segment, axis, value) {
19197
+ var _this$sceneViewer2;
19198
+ // Store original position for reverting
19199
+ var originalPosition = segment.position[axis];
19189
19200
 
19190
19201
  // Temporarily apply the translation to check for collisions
19191
- var originalPosition = segment.position[axis];
19192
19202
  segment.position[axis] += value;
19193
19203
  segment.updateMatrix();
19194
19204
  segment.updateMatrixWorld(true);
19195
19205
 
19196
19206
  // Check for collision with component connectors along the segment's path
19197
- var collision = this.checkSegmentPathConnectorCollision(segment);
19198
- if (collision) {
19207
+ var connectorCollision = this.checkSegmentPathConnectorCollision(segment);
19208
+ if (connectorCollision) {
19199
19209
  // Revert the translation
19200
19210
  segment.position[axis] = originalPosition;
19201
19211
  segment.updateMatrix();
19202
19212
  segment.updateMatrixWorld(true);
19203
19213
  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));
19214
+ console.warn(" Distance to connector: ".concat(connectorCollision.distance.toFixed(3), " (max allowed: 0.5)"));
19215
+ console.warn(" Closest point on segment: [".concat(connectorCollision.collisionPoint.x.toFixed(3), ", ").concat(connectorCollision.collisionPoint.y.toFixed(3), ", ").concat(connectorCollision.collisionPoint.z.toFixed(3), "]"));
19216
+ console.warn(" Connector position: [".concat(connectorCollision.connectorPos.x.toFixed(3), ", ").concat(connectorCollision.connectorPos.y.toFixed(3), ", ").concat(connectorCollision.connectorPos.z.toFixed(3), "]"));
19217
+ console.warn(" Colliding connector: ".concat(connectorCollision.connectorId, " on component: ").concat(connectorCollision.componentId));
19208
19218
  return false;
19209
19219
  }
19210
19220
 
19211
- // Revert the temporary translation before continuing with the normal flow
19212
- segment.position[axis] = originalPosition;
19213
- segment.updateMatrix();
19214
- segment.updateMatrixWorld(true);
19221
+ // Check for collision with component bounding boxes
19222
+ var componentCollision = this.checkSegmentComponentBoundingBoxCollision(segment);
19223
+ if (componentCollision) {
19224
+ // Revert the translation
19225
+ segment.position[axis] = originalPosition;
19226
+ segment.updateMatrix();
19227
+ segment.updateMatrixWorld(true);
19228
+ console.warn("\u26A0\uFE0F translateSegment(): Translation canceled - segment would collide with component bounding box");
19229
+ console.warn(" Component ID: ".concat(componentCollision.componentId));
19230
+ console.warn(" Component Name: ".concat(componentCollision.componentName));
19231
+ console.warn(" Component Type: ".concat(componentCollision.componentType));
19232
+ return false;
19233
+ }
19215
19234
 
19216
19235
  // Check if translationalOverrideForAutomaticSegments is enabled
19217
19236
  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 +19239,50 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19220
19239
  if (translationalOverride === false) {
19221
19240
  console.log('🔍 Checking for intersections with computed segments (translationalOverrideForAutomaticSegments is disabled)');
19222
19241
 
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
19242
  // Check if the translated segment intersects with any computed segments
19230
19243
  var hasIntersection = this.checkSegmentIntersection(segment);
19231
19244
  console.log("\uD83D\uDD04 translateSegment() hasIntersection:", hasIntersection);
19232
19245
  if (hasIntersection) {
19233
19246
  // Revert the translation
19234
- segment.position[axis] = _originalPosition;
19247
+ segment.position[axis] = originalPosition;
19235
19248
  segment.updateMatrix();
19236
19249
  segment.updateMatrixWorld(true);
19237
19250
  console.warn("\u26A0\uFE0F translateSegment(): Translation canceled - segment would intersect with computed segment(s)");
19238
19251
  return false;
19239
19252
  }
19240
19253
  console.log('✅ No intersections detected, proceeding with translation');
19241
- } else {
19242
- // Apply the translation to the Three.js object
19243
- segment.position[axis] += value;
19254
+ }
19244
19255
 
19245
- // Update matrices
19246
- segment.updateMatrix();
19247
- segment.updateMatrixWorld(true);
19256
+ // Revert the temporary translation
19257
+ segment.position[axis] = originalPosition;
19258
+ segment.updateMatrix();
19259
+ segment.updateMatrixWorld(true);
19260
+ return true;
19261
+ }
19262
+ }, {
19263
+ key: "translateSegment",
19264
+ value: function translateSegment(segmentId, axis, value) {
19265
+ var _this$sceneViewer$man2, _this$sceneViewer$man3, _this$sceneViewer$man4;
19266
+ var skipPathUpdate = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
19267
+ // Run all basic validation checks
19268
+ var validationResult = this.validateTranslateSegment(segmentId, axis, value);
19269
+ if (!validationResult) {
19270
+ return false;
19271
+ }
19272
+ var segment = validationResult.segment;
19273
+ console.log("\uD83D\uDD04 translateSegment(): Translating segment ".concat(segmentId, " on ").concat(axis, " axis by ").concat(value));
19274
+
19275
+ // Run collision validation checks
19276
+ var collisionValidation = this.validateTranslateSegmentCollisions(segment, axis, value);
19277
+ if (!collisionValidation) {
19278
+ return false;
19248
19279
  }
19249
19280
 
19281
+ // All validations passed - apply the translation
19282
+ segment.position[axis] += value;
19283
+ segment.updateMatrix();
19284
+ segment.updateMatrixWorld(true);
19285
+
19250
19286
  // Validate PathfindingManager and SceneOperationsManager availability
19251
19287
  var pathfindingManager = (_this$sceneViewer$man2 = this.sceneViewer.managers) === null || _this$sceneViewer$man2 === void 0 ? void 0 : _this$sceneViewer$man2.pathfindingManager;
19252
19288
  var sceneOperationsManager = (_this$sceneViewer$man3 = this.sceneViewer.managers) === null || _this$sceneViewer$man3 === void 0 ? void 0 : _this$sceneViewer$man3.sceneOperationsManager;
@@ -20030,6 +20066,48 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20030
20066
  return collision;
20031
20067
  }
20032
20068
 
20069
+ /**
20070
+ * Check if a segment would collide with any component's bounding box
20071
+ * @param {THREE.Object3D} segment - The segment to check for collisions
20072
+ * @returns {Object|null} Collision info {componentId, componentName, componentType} if collision detected, null otherwise
20073
+ * @private
20074
+ */
20075
+ }, {
20076
+ key: "checkSegmentComponentBoundingBoxCollision",
20077
+ value: function checkSegmentComponentBoundingBoxCollision(segment) {
20078
+ var _this$sceneViewer8;
20079
+ if (!((_this$sceneViewer8 = this.sceneViewer) !== null && _this$sceneViewer8 !== void 0 && _this$sceneViewer8.scene) || !segment) {
20080
+ return null;
20081
+ }
20082
+
20083
+ // Create a bounding box for the segment
20084
+ var segmentBBox = new THREE__namespace.Box3().setFromObject(segment);
20085
+ var collision = null;
20086
+
20087
+ // Traverse scene to find all components
20088
+ this.sceneViewer.scene.traverse(function (child) {
20089
+ var _child$userData11, _child$userData12;
20090
+ if (collision) return; // Stop if collision already found
20091
+
20092
+ // Check if this is a component (equipment)
20093
+ 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) {
20094
+ // Create bounding box for the component
20095
+ var componentBBox = new THREE__namespace.Box3().setFromObject(child);
20096
+
20097
+ // Check if bounding boxes intersect
20098
+ if (segmentBBox.intersectsBox(componentBBox)) {
20099
+ console.log('⚠️ TransformOperationsManager: Segment bounding box collision with component:', child.userData.libraryId || child.name || child.uuid);
20100
+ collision = {
20101
+ componentId: child.uuid,
20102
+ componentName: child.name || 'Unknown',
20103
+ componentType: child.userData.libraryId || 'Unknown'
20104
+ };
20105
+ }
20106
+ }
20107
+ });
20108
+ return collision;
20109
+ }
20110
+
20033
20111
  /**
20034
20112
  * Calculate the minimum distance between two line segments in 3D space
20035
20113
  * @param {THREE.Vector3} p1 - Start point of first segment
@@ -20139,10 +20217,10 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20139
20217
  }, {
20140
20218
  key: "snapSegmentConnectorsToNearbyEndpoints",
20141
20219
  value: function snapSegmentConnectorsToNearbyEndpoints(movedSegment) {
20142
- var _this$sceneViewer8,
20143
- _this$sceneViewer9,
20220
+ var _this$sceneViewer9,
20221
+ _this$sceneViewer0,
20144
20222
  _this2 = this;
20145
- if (!movedSegment || !((_this$sceneViewer8 = this.sceneViewer) !== null && _this$sceneViewer8 !== void 0 && _this$sceneViewer8.scene)) {
20223
+ if (!movedSegment || !((_this$sceneViewer9 = this.sceneViewer) !== null && _this$sceneViewer9 !== void 0 && _this$sceneViewer9.scene)) {
20146
20224
  return [];
20147
20225
  }
20148
20226
  console.log('🔗 Finding adjacent segments connected to moved segment...');
@@ -20150,8 +20228,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20150
20228
  // Get the moved segment's connectors
20151
20229
  var movedConnectors = [];
20152
20230
  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') {
20231
+ var _child$userData13;
20232
+ if (((_child$userData13 = child.userData) === null || _child$userData13 === void 0 ? void 0 : _child$userData13.objectType) === 'segment-connector') {
20155
20233
  movedConnectors.push(child);
20156
20234
  }
20157
20235
  });
@@ -20164,7 +20242,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20164
20242
  var newEndpoints = this.calculateSegmentEndpoints(movedSegment);
20165
20243
 
20166
20244
  // 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) || [];
20245
+ 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
20246
  var movedConnectorIds = movedConnectors.map(function (c) {
20169
20247
  return c.uuid;
20170
20248
  });
@@ -20221,8 +20299,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20221
20299
  // Get all connectors of the adjacent segment
20222
20300
  var adjacentConnectors = [];
20223
20301
  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') {
20302
+ var _child$userData14;
20303
+ if (((_child$userData14 = child.userData) === null || _child$userData14 === void 0 ? void 0 : _child$userData14.objectType) === 'segment-connector') {
20226
20304
  adjacentConnectors.push(child);
20227
20305
  }
20228
20306
  });
@@ -20320,9 +20398,9 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20320
20398
  }, {
20321
20399
  key: "updateConnectorPositionInSceneData",
20322
20400
  value: function updateConnectorPositionInSceneData(connector, worldPosition, parentSegment) {
20323
- var _this$sceneViewer0;
20401
+ var _this$sceneViewer1;
20324
20402
  // Update scene data if available
20325
- if (!((_this$sceneViewer0 = this.sceneViewer) !== null && _this$sceneViewer0 !== void 0 && _this$sceneViewer0.currentSceneData)) {
20403
+ if (!((_this$sceneViewer1 = this.sceneViewer) !== null && _this$sceneViewer1 !== void 0 && _this$sceneViewer1.currentSceneData)) {
20326
20404
  return;
20327
20405
  }
20328
20406
  var cleanPosition = function cleanPosition(value) {
@@ -20584,8 +20662,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20584
20662
  // Get the active segment's connectors
20585
20663
  var activeConnectors = [];
20586
20664
  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') {
20665
+ var _child$userData15;
20666
+ if (((_child$userData15 = child.userData) === null || _child$userData15 === void 0 ? void 0 : _child$userData15.objectType) === 'segment-connector') {
20589
20667
  activeConnectors.push(child);
20590
20668
  }
20591
20669
  });
@@ -25234,6 +25312,11 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25234
25312
  var fromIsComponentConnector = pathData.fromObjectType === 'component-connector';
25235
25313
  var toIsComponentConnector = pathData.toObjectType === 'component-connector';
25236
25314
 
25315
+ // Check if endpoints have direction constraints (more accurate for immutability)
25316
+ // Segments adjacent to connectors with direction should be immutable
25317
+ var fromHasDirection = pathData.fromHasDirection !== undefined ? pathData.fromHasDirection : fromIsComponentConnector;
25318
+ var toHasDirection = pathData.toHasDirection !== undefined ? pathData.toHasDirection : toIsComponentConnector;
25319
+
25237
25320
  // Create one cylinder per segment (after colinear optimization, this should be minimal segments)
25238
25321
  for (var j = 0; j < pathPoints.length - 1; j++) {
25239
25322
  var start = pathPoints[j];
@@ -25262,10 +25345,12 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25262
25345
  // Make pipe segments selectable and add identifying data
25263
25346
  var segmentId = cylinder.uuid;
25264
25347
 
25265
- // Determine if this segment should be immutable (first or last 0.5-unit segment connected to component)
25348
+ // Determine if this segment should be immutable (first or last segment connected to connector with direction)
25349
+ // Segments adjacent to connectors with direction constraints are immutable (cannot be edited)
25350
+ // Segments adjacent to gateways (no direction) can be edited
25266
25351
  var isFirstSegment = j === 0;
25267
25352
  var isLastSegment = j === pathPoints.length - 2;
25268
- var isImmutable = fromIsComponentConnector && isFirstSegment || toIsComponentConnector && isLastSegment;
25353
+ var isImmutable = fromHasDirection && isFirstSegment || toHasDirection && isLastSegment;
25269
25354
 
25270
25355
  // Add userData to make pipe segments selectable and for tooltip display
25271
25356
  cylinder.userData = {
@@ -25287,7 +25372,6 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25287
25372
  _this3.createAndAddElbowIfNeeded(pathPoints, j, pipeRadius, pipeMaterial, pathData, index, sceneViewer.scene // Pass scene instead of polyline
25288
25373
  );
25289
25374
  }
25290
- console.log("\u2705 Created pipe path ".concat(pathData.from, "-").concat(pathData.to, " with ").concat(pathPoints.length - 1, " segments"));
25291
25375
  }
25292
25376
  });
25293
25377
  }
@@ -25637,7 +25721,8 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25637
25721
 
25638
25722
  /**
25639
25723
  * Restructure connections to use the new connectors
25640
- * @param {string} authoritativeConnectorUUID - The authoritative connector UUID
25724
+ * Measures distance from point-a to both connectors and connects to the nearest one
25725
+ * @param {string} authoritativeConnectorUUID - The authoritative connector UUID (point-a)
25641
25726
  * @param {Array} connectors - Array of connector objects (0: start, 1: end)
25642
25727
  * @param {Object} currentSceneData - Current scene data
25643
25728
  * @param {Array<string>} convertedGatewayUUIDs - Array of gateway UUIDs that were converted to manual (optional)
@@ -25652,6 +25737,66 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25652
25737
 
25653
25738
  console.log("\uD83D\uDD27 [restructureConnections] connectors:", JSON.parse(JSON.stringify(connectors)));
25654
25739
  console.log("\uD83D\uDD27 [restructureConnections] convertedGatewayUUIDs:", convertedGatewayUUIDs);
25740
+ console.log("\uD83D\uDD27 [restructureConnections] authoritativeConnectorUUID:", authoritativeConnectorUUID);
25741
+
25742
+ // Find the authoritative connector object (point-a) in the scene to measure distances
25743
+ var authoritativeObject = null;
25744
+ this.sceneViewer.scene.traverse(function (obj) {
25745
+ if (obj.uuid === authoritativeConnectorUUID) {
25746
+ authoritativeObject = obj;
25747
+ }
25748
+ });
25749
+ if (!authoritativeObject) {
25750
+ console.error("\u274C [restructureConnections] Could not find authoritative connector: ".concat(authoritativeConnectorUUID));
25751
+ console.error("\u274C [restructureConnections] This may indicate:");
25752
+ console.error(" 1. The connector UUID changed during gateway manualization");
25753
+ console.error(" 2. The original connection was removed/modified before restructuring");
25754
+ console.error(" 3. The findOriginalConnection method returned a stale connection");
25755
+ console.error("\u274C [restructureConnections] Current connections:", JSON.stringify(currentSceneData.connections, null, 2));
25756
+
25757
+ // FALLBACK: Try to find any connector that might be the authoritative one
25758
+ // Look for objects with similar UUID patterns or check the original connection endpoints
25759
+ console.warn("\u26A0\uFE0F [restructureConnections] Attempting fallback connector search...");
25760
+
25761
+ // Search for possible matches (component connectors, gateway connectors, etc.)
25762
+ var possibleMatches = [];
25763
+ this.sceneViewer.scene.traverse(function (obj) {
25764
+ var _obj$userData, _obj$userData2, _obj$userData3;
25765
+ 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') {
25766
+ possibleMatches.push({
25767
+ uuid: obj.uuid,
25768
+ objectType: obj.userData.objectType,
25769
+ isDeclared: obj.userData.isDeclared
25770
+ });
25771
+ }
25772
+ });
25773
+ console.warn("\u26A0\uFE0F [restructureConnections] Found ".concat(possibleMatches.length, " possible connectors:"), possibleMatches);
25774
+ console.error("\u274C [restructureConnections] Cannot proceed without authoritative connector");
25775
+ return;
25776
+ }
25777
+
25778
+ // Get world positions for distance calculation
25779
+ var pointA = new THREE__namespace.Vector3();
25780
+ authoritativeObject.getWorldPosition(pointA);
25781
+ var connector1Position = new THREE__namespace.Vector3();
25782
+ var connector2Position = new THREE__namespace.Vector3();
25783
+ connectors[0].getWorldPosition(connector1Position);
25784
+ connectors[1].getWorldPosition(connector2Position);
25785
+
25786
+ // Calculate distances from point-a to both segment connectors
25787
+ var distanceToConnector1 = pointA.distanceTo(connector1Position);
25788
+ var distanceToConnector2 = pointA.distanceTo(connector2Position);
25789
+ console.log("\uD83D\uDCCF [restructureConnections] Distance from ".concat(authoritativeConnectorUUID, " to:"));
25790
+ console.log(" - ".concat(startConnectorUUID, ": ").concat(distanceToConnector1.toFixed(4)));
25791
+ console.log(" - ".concat(endConnectorUUID, ": ").concat(distanceToConnector2.toFixed(4)));
25792
+
25793
+ // Determine which connector is nearest to point-a
25794
+ var nearestConnector = distanceToConnector1 <= distanceToConnector2 ? connectors[0] : connectors[1];
25795
+ var farthestConnector = distanceToConnector1 > distanceToConnector2 ? connectors[0] : connectors[1];
25796
+ var nearestConnectorUUID = nearestConnector.uuid;
25797
+ var farthestConnectorUUID = farthestConnector.uuid;
25798
+ console.log("\u2705 [restructureConnections] Nearest connector: ".concat(nearestConnectorUUID, " (distance: ").concat(Math.min(distanceToConnector1, distanceToConnector2).toFixed(4), ")"));
25799
+ console.log("\uD83D\uDCCD [restructureConnections] Farthest connector: ".concat(farthestConnectorUUID, " (distance: ").concat(Math.max(distanceToConnector1, distanceToConnector2).toFixed(4), ")"));
25655
25800
 
25656
25801
  // Deep copy connections array to prevent unintended mutations during iteration
25657
25802
  // Then map to update references, creating new connection objects
@@ -25660,30 +25805,32 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25660
25805
 
25661
25806
  // Create a shallow copy of the connection object
25662
25807
  var updatedConnection = _objectSpread2({}, connection);
25808
+
25809
+ // Update connections to point to the FARTHEST connector (opposite end from point-a)
25663
25810
  if (connection.from === authoritativeConnectorUUID) {
25664
- updatedConnection.from = endConnectorUUID;
25665
- console.log("\u2705 [restructureConnections] Updated connection.from to ".concat(endConnectorUUID));
25811
+ updatedConnection.from = farthestConnectorUUID;
25812
+ console.log("\u2705 [restructureConnections] Updated connection.from to ".concat(farthestConnectorUUID, " (farthest)"));
25666
25813
  }
25667
25814
  if (connection.to === authoritativeConnectorUUID) {
25668
- updatedConnection.to = endConnectorUUID;
25669
- console.log("\u2705 [restructureConnections] Updated connection.to to ".concat(endConnectorUUID));
25815
+ updatedConnection.to = farthestConnectorUUID;
25816
+ console.log("\u2705 [restructureConnections] Updated connection.to to ".concat(farthestConnectorUUID, " (farthest)"));
25670
25817
  }
25671
25818
  return updatedConnection;
25672
25819
  });
25673
25820
 
25674
25821
  // Check if the new connection already exists to prevent duplicates
25675
25822
  var newConnectionExists = currentSceneData.connections.some(function (conn) {
25676
- return conn.from === authoritativeConnectorUUID && conn.to === startConnectorUUID || conn.from === startConnectorUUID && conn.to === authoritativeConnectorUUID;
25823
+ return conn.from === authoritativeConnectorUUID && conn.to === nearestConnectorUUID || conn.from === nearestConnectorUUID && conn.to === authoritativeConnectorUUID;
25677
25824
  });
25678
25825
  if (!newConnectionExists) {
25679
- // Add new connection from authoritative connector to the segment start
25826
+ // Add new connection from authoritative connector (point-a) to the NEAREST segment connector
25680
25827
  currentSceneData.connections.push({
25681
25828
  from: authoritativeConnectorUUID,
25682
- to: startConnectorUUID
25829
+ to: nearestConnectorUUID
25683
25830
  });
25684
- console.log("\u2705 [restructureConnections] Added new connection: ".concat(authoritativeConnectorUUID, " \u2192 ").concat(startConnectorUUID));
25831
+ console.log("\u2705 [restructureConnections] Added new connection: ".concat(authoritativeConnectorUUID, " \u2192 ").concat(nearestConnectorUUID, " (nearest)"));
25685
25832
  } else {
25686
- console.log("\u26A0\uFE0F [restructureConnections] Connection already exists, skipping: ".concat(authoritativeConnectorUUID, " \u2192 ").concat(startConnectorUUID));
25833
+ console.log("\u26A0\uFE0F [restructureConnections] Connection already exists, skipping: ".concat(authoritativeConnectorUUID, " \u2192 ").concat(nearestConnectorUUID));
25687
25834
  }
25688
25835
 
25689
25836
  // Log converted gateways for tracking
@@ -25730,11 +25877,11 @@ var ConnectorManager = /*#__PURE__*/function (_BaseDisposable) {
25730
25877
  var fromObject = null;
25731
25878
  var toObject = null;
25732
25879
  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) {
25880
+ var _obj$userData4, _obj$userData5;
25881
+ if (obj.uuid === pathFrom || ((_obj$userData4 = obj.userData) === null || _obj$userData4 === void 0 ? void 0 : _obj$userData4.originalUuid) === pathFrom) {
25735
25882
  fromObject = obj;
25736
25883
  }
25737
- if (obj.uuid === pathTo || ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.originalUuid) === pathTo) {
25884
+ if (obj.uuid === pathTo || ((_obj$userData5 = obj.userData) === null || _obj$userData5 === void 0 ? void 0 : _obj$userData5.originalUuid) === pathTo) {
25738
25885
  toObject = obj;
25739
25886
  }
25740
25887
  });
@@ -29444,20 +29591,29 @@ var SceneOperationsManager = /*#__PURE__*/function () {
29444
29591
  // Now add connectors to the segment's children array in scene data
29445
29592
  connectorManager.addConnectorsToScene(connectors);
29446
29593
 
29447
- // Find the original connection that this segment belongs to (after gateways are converted)
29594
+ // Check and convert connected gateways to manual (declared) FIRST
29595
+ // CRITICAL: This must happen BEFORE finding the authoritative connector
29596
+ // because gateway conversion may modify the connections array
29597
+ // NOTE: This may trigger path regeneration via translateGateway, so segment must already be renamed
29598
+ var convertedGatewayUUIDs = this._convertConnectedGatewaysToManual(connectors, currentSceneData);
29599
+ console.log('🔍 Gateway conversion completed, now finding authoritative connector with updated connections');
29600
+
29601
+ // Find the original connection that this segment belongs to (AFTER gateways are converted)
29602
+ // IMPORTANT: This must run after gateway conversion because connections may have changed
29448
29603
  var originalConnection = connectorManager.findOriginalConnection(segment, currentSceneData.connections);
29449
29604
  if (!originalConnection) {
29450
29605
  console.warn('⚠️ Could not find original connection for segment:', segment.uuid);
29606
+ console.warn('⚠️ This may indicate the connection was modified during gateway conversion');
29607
+ console.warn('⚠️ Available connections:', JSON.stringify(currentSceneData.connections, null, 2));
29451
29608
  return;
29452
29609
  }
29453
- console.log('🔍 Found original connection:', originalConnection);
29610
+ console.log('🔍 Found original connection (after gateway conversion):', originalConnection);
29611
+
29612
+ // Determine the authoritative connector (the non-gateway endpoint)
29613
+ // After gateway conversion, gateways should have connectors, so check for "Gateway" pattern
29454
29614
  var authoritativeConnectorUUID = originalConnection.from.includes("Gateway") === false ? originalConnection.from : originalConnection.to;
29455
29615
  console.log('[SceneOperations] authoritativeConnectorUUID:', authoritativeConnectorUUID);
29456
29616
 
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
29617
  // Restructure connections, passing any converted gateway UUIDs
29462
29618
  connectorManager.restructureConnections(authoritativeConnectorUUID, connectors, currentSceneData, convertedGatewayUUIDs);
29463
29619
 
@@ -33609,7 +33765,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
33609
33765
  * Initialize the CentralPlant manager
33610
33766
  *
33611
33767
  * @constructor
33612
- * @version 0.1.51
33768
+ * @version 0.1.52
33613
33769
  * @updated 2025-10-22
33614
33770
  *
33615
33771
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -19,7 +19,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
19
19
  * Initialize the CentralPlant manager
20
20
  *
21
21
  * @constructor
22
- * @version 0.1.51
22
+ * @version 0.1.52
23
23
  * @updated 2025-10-22
24
24
  *
25
25
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.