@2112-lab/central-plant 0.1.48 → 0.1.50

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.
@@ -5014,11 +5014,15 @@ var TransformControlsManager = /*#__PURE__*/function () {
5014
5014
  _this9.selectedObjects[selectedIndex] = segment;
5015
5015
  console.log("\u2705 Updated selectedObjects[".concat(selectedIndex, "] with refreshed segment reference"));
5016
5016
  }
5017
- console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(i + 1, "/").concat(segments.length, "):"), {
5018
- deltaX: deltaX,
5019
- deltaY: deltaY,
5020
- deltaZ: deltaZ
5021
- });
5017
+ if (segment) {
5018
+ console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(i + 1, "/").concat(segments.length, "):"), {
5019
+ deltaX: deltaX,
5020
+ deltaY: deltaY,
5021
+ deltaZ: deltaZ
5022
+ });
5023
+ } else {
5024
+ console.warn("\u26A0\uFE0F Segment reference became null after translation (".concat(i + 1, "/").concat(segments.length, ")"));
5025
+ }
5022
5026
 
5023
5027
  // Delay between segments to ensure all updates propagate
5024
5028
  if (!(i < segments.length - 1)) {
@@ -5145,11 +5149,15 @@ var TransformControlsManager = /*#__PURE__*/function () {
5145
5149
  _this9.selectedObjects[selectedIndex] = segment;
5146
5150
  console.log("\u2705 Updated selectedObjects[".concat(selectedIndex, "] with refreshed segment reference"));
5147
5151
  }
5148
- console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(_i + 1, "/").concat(segments.length, "):"), {
5149
- deltaX: deltaX,
5150
- deltaY: deltaY,
5151
- deltaZ: deltaZ
5152
- });
5152
+ if (segment) {
5153
+ console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(_i + 1, "/").concat(segments.length, "):"), {
5154
+ deltaX: deltaX,
5155
+ deltaY: deltaY,
5156
+ deltaZ: deltaZ
5157
+ });
5158
+ } else {
5159
+ console.warn("\u26A0\uFE0F Segment reference became null after translation (".concat(_i + 1, "/").concat(segments.length, ")"));
5160
+ }
5153
5161
 
5154
5162
  // Delay between segments
5155
5163
  if (!(_i < segments.length - 1)) {
@@ -5291,17 +5299,24 @@ var TransformControlsManager = /*#__PURE__*/function () {
5291
5299
  deltaZ: deltaZ
5292
5300
  });
5293
5301
  case 21:
5294
- // Reset the multi-selection group transform
5295
- this.multiSelectionGroup.position.set(0, 0, 0);
5296
- this.multiSelectionGroup.rotation.set(0, 0, 0);
5297
- this.multiSelectionGroup.scale.set(1, 1, 1);
5302
+ // Reset the multi-selection group transform (if it still exists)
5303
+ // Note: The group might have been cleared during async operations
5304
+ if (this.multiSelectionGroup) {
5305
+ this.multiSelectionGroup.position.set(0, 0, 0);
5306
+ this.multiSelectionGroup.rotation.set(0, 0, 0);
5307
+ this.multiSelectionGroup.scale.set(1, 1, 1);
5308
+ } else {
5309
+ console.warn('⚠️ Multi-selection group was cleared during transformation');
5310
+ }
5298
5311
 
5299
5312
  // CRITICAL: Clear bounding box cache after manualization
5300
5313
  // Manualization changes object references, making cached boxes invalid
5301
5314
  this.clearBoundingBoxCache();
5302
5315
 
5303
- // Update the multi-selection display with new positions
5304
- this.updateMultiSelection();
5316
+ // Update the multi-selection display with new positions (only if we still have selected objects)
5317
+ if (this.selectedObjects.length > 0) {
5318
+ this.updateMultiSelection();
5319
+ }
5305
5320
  console.log("\u2705 Multi-selection transform applied");
5306
5321
  case 22:
5307
5322
  return _context3.a(2);
@@ -19070,15 +19085,31 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19070
19085
  }
19071
19086
 
19072
19087
  // Check segment orientation and cancel invalid translations
19073
- var isHorizontal = this.isSegmentHorizontal(segment);
19074
- if (isHorizontal && (axis === 'x' || axis === 'y')) {
19075
- console.warn("\u26A0\uFE0F translateSegment(): Cannot translate horizontal segment along ".concat(axis.toUpperCase(), " axis"));
19076
- console.warn(" Horizontal segments can only be translated along the Z axis");
19088
+ // Get the segment's direction vector to determine which axis it runs along
19089
+ var direction = new THREE__namespace.Vector3(0, 1, 0);
19090
+ direction.applyQuaternion(segment.quaternion);
19091
+ direction.normalize();
19092
+
19093
+ // Determine which axis the segment primarily runs along
19094
+ var absX = Math.abs(direction.x);
19095
+ var absY = Math.abs(direction.y);
19096
+ var absZ = Math.abs(direction.z);
19097
+ var tolerance = 0.9; // Direction component must be > 0.9 to be considered aligned with axis
19098
+
19099
+ // Block translation along the axis that the segment runs parallel to
19100
+ if (absX > tolerance && axis === 'x') {
19101
+ console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
19102
+ console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
19103
+ return false;
19104
+ }
19105
+ if (absY > tolerance && axis === 'y') {
19106
+ console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
19107
+ console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
19077
19108
  return false;
19078
19109
  }
19079
- if (!isHorizontal && axis === 'z') {
19080
- console.warn("\u26A0\uFE0F translateSegment(): Cannot translate vertical segment along Z axis");
19081
- console.warn(" Vertical segments can only be translated along X or Y axes");
19110
+ if (absZ > tolerance && axis === 'z') {
19111
+ console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
19112
+ console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
19082
19113
  return false;
19083
19114
  }
19084
19115
  console.log('[translateSegment] segment:', segment);
@@ -19243,17 +19274,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19243
19274
 
19244
19275
  // ALWAYS update connector positions after segment movement (first or subsequent moves)
19245
19276
  this.updateSegmentConnectorPositions(segment);
19246
-
19247
- // NEW: Update adjacent manual segments to follow this segment's new position
19248
- var maintainedConnections = this.snapSegmentConnectorsToNearbyEndpoints(segment);
19249
-
19250
- // NOTE: We do NOT remove connections from scene data
19251
- // The connections remain valid - the manual segments are maintaining those connections
19252
- // The pathfinding algorithm should detect that connectors are at the same position
19253
- // and skip creating computed segments for them
19254
- if (maintainedConnections.length > 0) {
19255
- console.log("\u2139\uFE0F ".concat(maintainedConnections.length, " connection(s) maintained by manual segments"));
19256
- }
19277
+ this.snapSegmentConnectorsToNearbyEndpoints(segment);
19257
19278
 
19258
19279
  // Store transform parameters using the OperationHistoryManager BEFORE updatePaths
19259
19280
  // This is critical so that intersection detection can undo the operation
@@ -19270,9 +19291,6 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19270
19291
  // UNLESS skipPathUpdate is true (for batch operations)
19271
19292
  if (!skipPathUpdate) {
19272
19293
  console.log('🔄 Regenerating paths to create connecting pipe segments...');
19273
- if (maintainedConnections.length > 0) {
19274
- console.log("\u2139\uFE0F Manual segments are maintaining connections - pathfinding should skip connectors at same position");
19275
- }
19276
19294
  try {
19277
19295
  if (this.sceneViewer && typeof this.sceneViewer.updatePaths === 'function') {
19278
19296
  this.sceneViewer.updatePaths();
@@ -20317,8 +20335,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20317
20335
  }
20318
20336
 
20319
20337
  /**
20320
- * Recreate segment mesh with new length based on connector positions
20321
- * @param {THREE.Object3D} segment - The segment to recreate
20338
+ * Adjust segment geometry and transform to match new endpoint positions
20339
+ * @param {THREE.Object3D} segment - The segment to adjust
20322
20340
  * @param {Array<THREE.Object3D>} connectors - The segment's connectors
20323
20341
  * @param {THREE.Vector3} endPoint1 - Explicit world position for first endpoint (optional)
20324
20342
  * @param {THREE.Vector3} endPoint2 - Explicit world position for second endpoint (optional)
@@ -20332,7 +20350,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20332
20350
  var endPoint2 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
20333
20351
  var activeSegment = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
20334
20352
  if (!segment || connectors.length !== 2) {
20335
- console.warn('⚠️ Cannot recreate segment: invalid segment or connectors');
20353
+ console.warn('⚠️ Cannot adjust segment: invalid segment or connectors');
20336
20354
  return;
20337
20355
  }
20338
20356
  var _connectors = _slicedToArray(connectors, 2),
@@ -20375,21 +20393,28 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20375
20393
  this._removeZeroLengthSegment(segment, connectors, activeSegment);
20376
20394
  return;
20377
20395
  }
20378
- console.log("\uD83D\uDD27 Recreating segment with new length: ".concat(newLength.toFixed(3), " (was ").concat(segment.geometry.parameters.height.toFixed(3), ")"));
20396
+ var oldLength = segment.geometry.parameters.height;
20397
+ console.log("\uD83D\uDD27 Adjusting segment geometry: ".concat(oldLength.toFixed(3), " \u2192 ").concat(newLength.toFixed(3)));
20379
20398
 
20380
- // Store old geometry and material references
20381
- var oldGeometry = segment.geometry;
20382
- segment.material;
20383
- var pipeRadius = oldGeometry.parameters.radiusTop || 0.1;
20399
+ // Only recreate geometry if length has changed significantly
20400
+ if (Math.abs(newLength - oldLength) > 1e-6) {
20401
+ var oldGeometry = segment.geometry;
20402
+ var pipeRadius = oldGeometry.parameters.radiusTop || 0.1;
20384
20403
 
20385
- // Create new cylinder geometry with updated length
20386
- var newGeometry = new THREE__namespace.CylinderGeometry(pipeRadius, pipeRadius, newLength, 16, 1, false);
20404
+ // Create new cylinder geometry with updated length
20405
+ var newGeometry = new THREE__namespace.CylinderGeometry(pipeRadius, pipeRadius, newLength, 16, 1, false);
20387
20406
 
20388
- // Update segment mesh
20389
- segment.geometry = newGeometry;
20407
+ // Replace geometry
20408
+ segment.geometry = newGeometry;
20409
+
20410
+ // Dispose old geometry
20411
+ oldGeometry.dispose();
20412
+ }
20413
+
20414
+ // Update segment position to new center
20390
20415
  segment.position.copy(newCenter);
20391
20416
 
20392
- // Calculate and apply rotation
20417
+ // Calculate and apply rotation to align with new direction
20393
20418
  var quaternion = new THREE__namespace.Quaternion();
20394
20419
  var up = new THREE__namespace.Vector3(0, 1, 0);
20395
20420
  quaternion.setFromUnitVectors(up, direction.clone().normalize());
@@ -20398,12 +20423,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20398
20423
  // Update matrices
20399
20424
  segment.updateMatrix();
20400
20425
  segment.updateMatrixWorld(true);
20401
-
20402
- // Dispose old geometry
20403
- if (oldGeometry && oldGeometry !== newGeometry) {
20404
- oldGeometry.dispose();
20405
- }
20406
- console.log("\u2705 Segment mesh recreated: new length = ".concat(newLength.toFixed(3), ", center = [").concat(newCenter.x.toFixed(2), ", ").concat(newCenter.y.toFixed(2), ", ").concat(newCenter.z.toFixed(2), "]"));
20426
+ console.log("\u2705 Segment adjusted: length = ".concat(newLength.toFixed(3), ", center = [").concat(newCenter.x.toFixed(2), ", ").concat(newCenter.y.toFixed(2), ", ").concat(newCenter.z.toFixed(2), "]"));
20407
20427
  }
20408
20428
 
20409
20429
  /**
@@ -25201,8 +25221,30 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25201
25221
  value: function createPipePaths(paths, crosscubeTextureSet) {
25202
25222
  var _this3 = this;
25203
25223
  var sceneViewer = this.sceneViewer;
25204
- var globalSegmentIndex = 0; // Counter for globally unique segment indices
25205
25224
 
25225
+ // Find the highest segment index currently in use (both computed SEGMENT-X and manual Segment-X)
25226
+ var maxExistingIndex = -1;
25227
+ sceneViewer.scene.traverse(function (obj) {
25228
+ if (obj.uuid) {
25229
+ // Check for computed segments: SEGMENT-123
25230
+ var computedMatch = obj.uuid.match(/^SEGMENT-(\d+)$/);
25231
+ if (computedMatch) {
25232
+ var index = parseInt(computedMatch[1], 10);
25233
+ maxExistingIndex = Math.max(maxExistingIndex, index);
25234
+ }
25235
+
25236
+ // Check for manual segments: Segment-123
25237
+ var manualMatch = obj.uuid.match(/^Segment-(\d+)$/);
25238
+ if (manualMatch) {
25239
+ var _index = parseInt(manualMatch[1], 10);
25240
+ maxExistingIndex = Math.max(maxExistingIndex, _index);
25241
+ }
25242
+ }
25243
+ });
25244
+
25245
+ // Start counter after the highest existing index to prevent UUID conflicts
25246
+ var globalSegmentIndex = maxExistingIndex + 1;
25247
+ console.log("\uD83D\uDD22 Starting segment index at ".concat(globalSegmentIndex, " (max existing: ").concat(maxExistingIndex, ")"));
25206
25248
  var pipeRadius = 0.1;
25207
25249
  var pipeMaterial = this.createPipeMaterial(crosscubeTextureSet);
25208
25250
  paths.forEach(function (pathData, index) {
@@ -26548,13 +26590,6 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
26548
26590
  connectionsCopy,
26549
26591
  simplifiedSceneData,
26550
26592
  pathfindingResult,
26551
- intersectionCheck,
26552
- _this$sceneViewer,
26553
- operationHistoryManager,
26554
- lastOp,
26555
- undoSuccess,
26556
- correctedResult,
26557
- _this$sceneViewer2,
26558
26593
  _args = arguments;
26559
26594
  return _regenerator().w(function (_context) {
26560
26595
  while (1) switch (_context.n) {
@@ -26589,93 +26624,79 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
26589
26624
  console.log('Rewired connections:', JSON.parse(JSON.stringify(pathfindingResult.rewiredConnections)));
26590
26625
  console.log("intersectionCheck input:", pathfindingResult.paths);
26591
26626
 
26592
- // Check for path intersections (including manual segments)
26593
- intersectionCheck = this.checkPathIntersections(pathfindingResult.paths, 0.2, true);
26594
- pathfindingResult.intersections = intersectionCheck;
26595
- console.log("intersectionCheck:", intersectionCheck);
26596
- console.log("intersectionCheck.hasIntersections:", intersectionCheck.hasIntersections);
26597
-
26598
- // Handle intersection detection - undo last operation if intersections found
26599
- // Skip this if we're already in the middle of an undo operation
26600
- if (!(intersectionCheck.hasIntersections && !this.isUndoInProgress)) {
26601
- _context.n = 8;
26602
- break;
26603
- }
26604
- console.warn('⚠️ Path intersections detected! Attempting to undo last operation...');
26605
-
26606
- // Set flag to prevent recursive undo attempts
26607
- this.isUndoInProgress = true;
26608
-
26609
- // Access operationHistoryManager through sceneViewer.managers.operationHistory
26610
- operationHistoryManager = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.operationHistory;
26611
- if (!operationHistoryManager) {
26612
- _context.n = 6;
26613
- break;
26614
- }
26615
- lastOp = operationHistoryManager.getLastOperation();
26616
- if (!lastOp) {
26617
- _context.n = 4;
26618
- break;
26619
- }
26620
- console.warn("\u26A0\uFE0F Intersection caused by operation: ".concat(lastOp.operationName), lastOp.params);
26621
-
26622
- // Attempt to undo the operation FIRST (before removing computed objects)
26623
- // This is important because undo needs to find the segment that was moved
26624
- undoSuccess = operationHistoryManager.undoLastOperation();
26625
- if (!undoSuccess) {
26626
- _context.n = 2;
26627
- break;
26628
- }
26629
- console.log('✅ Successfully undid operation that caused intersection');
26630
-
26631
- // Now remove the buggy computed objects that were created with the invalid state
26632
- console.log('🗑️ Removing buggy computed objects after undo...');
26633
- this.removeComputedObjects();
26634
-
26635
- // Re-run pathfinding after undo to restore valid state
26636
- console.log('🔄 Re-running pathfinding after undo to restore clean state...');
26627
+ // // Check for path intersections (including manual segments)
26628
+ // const intersectionCheck = this.checkPathIntersections(pathfindingResult.paths, 0.2, true);
26629
+ // pathfindingResult.intersections = intersectionCheck;
26630
+
26631
+ // console.log("intersectionCheck:", intersectionCheck);
26632
+ // console.log("intersectionCheck.hasIntersections:", intersectionCheck.hasIntersections);
26633
+
26634
+ // // Handle intersection detection - undo last operation if intersections found
26635
+ // // Skip this if we're already in the middle of an undo operation
26636
+ // if (intersectionCheck.hasIntersections && !this.isUndoInProgress) {
26637
+ // console.warn('⚠️ Path intersections detected! Attempting to undo last operation...');
26638
+
26639
+ // // Set flag to prevent recursive undo attempts
26640
+ // this.isUndoInProgress = true;
26641
+
26642
+ // // Access operationHistoryManager through sceneViewer.managers.operationHistory
26643
+ // const operationHistoryManager = this.sceneViewer?.managers?.operationHistory;
26644
+
26645
+ // if (operationHistoryManager) {
26646
+ // const lastOp = operationHistoryManager.getLastOperation();
26647
+
26648
+ // if (lastOp) {
26649
+ // console.warn(`⚠️ Intersection caused by operation: ${lastOp.operationName}`, lastOp.params);
26650
+
26651
+ // // Attempt to undo the operation FIRST (before removing computed objects)
26652
+ // // This is important because undo needs to find the segment that was moved
26653
+ // const undoSuccess = operationHistoryManager.undoLastOperation();
26654
+
26655
+ // if (undoSuccess) {
26656
+ // console.log('✅ Successfully undid operation that caused intersection');
26657
+
26658
+ // // Now remove the buggy computed objects that were created with the invalid state
26659
+ // console.log('🗑️ Removing buggy computed objects after undo...');
26660
+ // this.removeComputedObjects();
26661
+
26662
+ // // Re-run pathfinding after undo to restore valid state
26663
+ // console.log('🔄 Re-running pathfinding after undo to restore clean state...');
26664
+
26665
+ // // Recursively call _executePathfinding with the corrected scene state
26666
+ // // This is safe because we've undone the operation, so we won't get into an infinite loop
26667
+ // const correctedResult = await this._executePathfinding(
26668
+ // sceneData,
26669
+ // connections,
26670
+ // { ...options, context: `${context} (After Undo)` }
26671
+ // );
26672
+
26673
+ // // Mark that we performed an undo and return the corrected result
26674
+ // correctedResult.undoPerformed = true;
26675
+ // correctedResult.undoneOperation = lastOp;
26676
+
26677
+ // // Clear the undo flag before returning
26678
+ // this.isUndoInProgress = false;
26679
+
26680
+ // return correctedResult;
26681
+ // } else {
26682
+ // console.error('❌ Failed to undo operation that caused intersection');
26683
+ // pathfindingResult.undoFailed = true;
26684
+ // // Clear the undo flag even on failure
26685
+ // this.isUndoInProgress = false;
26686
+ // }
26687
+ // } else {
26688
+ // console.warn('⚠️ No operation in history to undo');
26689
+ // this.isUndoInProgress = false;
26690
+ // }
26691
+ // } else {
26692
+ // console.error('❌ OperationHistoryManager not available for undo');
26693
+ // console.error(' Available managers:', Object.keys(this.sceneViewer?.managers || {}));
26694
+ // this.isUndoInProgress = false;
26695
+ // }
26696
+ // } else if (intersectionCheck.hasIntersections && this.isUndoInProgress) {
26697
+ // console.log('⏭️ Skipping intersection handling - undo already in progress');
26698
+ // }
26637
26699
 
26638
- // Recursively call _executePathfinding with the corrected scene state
26639
- // This is safe because we've undone the operation, so we won't get into an infinite loop
26640
- _context.n = 1;
26641
- return this._executePathfinding(sceneData, connections, _objectSpread2(_objectSpread2({}, options), {}, {
26642
- context: "".concat(context, " (After Undo)")
26643
- }));
26644
- case 1:
26645
- correctedResult = _context.v;
26646
- // Mark that we performed an undo and return the corrected result
26647
- correctedResult.undoPerformed = true;
26648
- correctedResult.undoneOperation = lastOp;
26649
-
26650
- // Clear the undo flag before returning
26651
- this.isUndoInProgress = false;
26652
- return _context.a(2, correctedResult);
26653
- case 2:
26654
- console.error('❌ Failed to undo operation that caused intersection');
26655
- pathfindingResult.undoFailed = true;
26656
- // Clear the undo flag even on failure
26657
- this.isUndoInProgress = false;
26658
- case 3:
26659
- _context.n = 5;
26660
- break;
26661
- case 4:
26662
- console.warn('⚠️ No operation in history to undo');
26663
- this.isUndoInProgress = false;
26664
- case 5:
26665
- _context.n = 7;
26666
- break;
26667
- case 6:
26668
- console.error('❌ OperationHistoryManager not available for undo');
26669
- console.error(' Available managers:', Object.keys(((_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.managers) || {}));
26670
- this.isUndoInProgress = false;
26671
- case 7:
26672
- _context.n = 9;
26673
- break;
26674
- case 8:
26675
- if (intersectionCheck.hasIntersections && this.isUndoInProgress) {
26676
- console.log('⏭️ Skipping intersection handling - undo already in progress');
26677
- }
26678
- case 9:
26679
26700
  // Create gateways in the scene if requested
26680
26701
  if (options.createGateways && pathfindingResult.gateways) {
26681
26702
  this.renderingManager.createGateways(pathfindingResult);
@@ -33740,7 +33761,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
33740
33761
  * Initialize the CentralPlant manager
33741
33762
  *
33742
33763
  * @constructor
33743
- * @version 0.1.48
33764
+ * @version 0.1.50
33744
33765
  * @updated 2025-10-22
33745
33766
  *
33746
33767
  * @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.48
22
+ * @version 0.1.50
23
23
  * @updated 2025-10-22
24
24
  *
25
25
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -168,15 +168,31 @@ var TransformOperationsManager = /*#__PURE__*/function () {
168
168
  }
169
169
 
170
170
  // Check segment orientation and cancel invalid translations
171
- var isHorizontal = this.isSegmentHorizontal(segment);
172
- if (isHorizontal && (axis === 'x' || axis === 'y')) {
173
- console.warn("\u26A0\uFE0F translateSegment(): Cannot translate horizontal segment along ".concat(axis.toUpperCase(), " axis"));
174
- console.warn(" Horizontal segments can only be translated along the Z axis");
171
+ // Get the segment's direction vector to determine which axis it runs along
172
+ var direction = new THREE__namespace.Vector3(0, 1, 0);
173
+ direction.applyQuaternion(segment.quaternion);
174
+ direction.normalize();
175
+
176
+ // Determine which axis the segment primarily runs along
177
+ var absX = Math.abs(direction.x);
178
+ var absY = Math.abs(direction.y);
179
+ var absZ = Math.abs(direction.z);
180
+ var tolerance = 0.9; // Direction component must be > 0.9 to be considered aligned with axis
181
+
182
+ // Block translation along the axis that the segment runs parallel to
183
+ if (absX > tolerance && axis === 'x') {
184
+ console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
185
+ console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
175
186
  return false;
176
187
  }
177
- if (!isHorizontal && axis === 'z') {
178
- console.warn("\u26A0\uFE0F translateSegment(): Cannot translate vertical segment along Z axis");
179
- console.warn(" Vertical segments can only be translated along X or Y axes");
188
+ if (absY > tolerance && axis === 'y') {
189
+ console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
190
+ console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
191
+ return false;
192
+ }
193
+ if (absZ > tolerance && axis === 'z') {
194
+ console.warn("\u26A0\uFE0F translateSegment(): Cannot translate segment along ".concat(axis.toUpperCase(), " axis - segment runs along this axis"));
195
+ console.warn(" Segment direction: [".concat(direction.x.toFixed(3), ", ").concat(direction.y.toFixed(3), ", ").concat(direction.z.toFixed(3), "]"));
180
196
  return false;
181
197
  }
182
198
  console.log('[translateSegment] segment:', segment);
@@ -341,17 +357,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
341
357
 
342
358
  // ALWAYS update connector positions after segment movement (first or subsequent moves)
343
359
  this.updateSegmentConnectorPositions(segment);
344
-
345
- // NEW: Update adjacent manual segments to follow this segment's new position
346
- var maintainedConnections = this.snapSegmentConnectorsToNearbyEndpoints(segment);
347
-
348
- // NOTE: We do NOT remove connections from scene data
349
- // The connections remain valid - the manual segments are maintaining those connections
350
- // The pathfinding algorithm should detect that connectors are at the same position
351
- // and skip creating computed segments for them
352
- if (maintainedConnections.length > 0) {
353
- console.log("\u2139\uFE0F ".concat(maintainedConnections.length, " connection(s) maintained by manual segments"));
354
- }
360
+ this.snapSegmentConnectorsToNearbyEndpoints(segment);
355
361
 
356
362
  // Store transform parameters using the OperationHistoryManager BEFORE updatePaths
357
363
  // This is critical so that intersection detection can undo the operation
@@ -368,9 +374,6 @@ var TransformOperationsManager = /*#__PURE__*/function () {
368
374
  // UNLESS skipPathUpdate is true (for batch operations)
369
375
  if (!skipPathUpdate) {
370
376
  console.log('🔄 Regenerating paths to create connecting pipe segments...');
371
- if (maintainedConnections.length > 0) {
372
- console.log("\u2139\uFE0F Manual segments are maintaining connections - pathfinding should skip connectors at same position");
373
- }
374
377
  try {
375
378
  if (this.sceneViewer && typeof this.sceneViewer.updatePaths === 'function') {
376
379
  this.sceneViewer.updatePaths();
@@ -1415,8 +1418,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1415
1418
  }
1416
1419
 
1417
1420
  /**
1418
- * Recreate segment mesh with new length based on connector positions
1419
- * @param {THREE.Object3D} segment - The segment to recreate
1421
+ * Adjust segment geometry and transform to match new endpoint positions
1422
+ * @param {THREE.Object3D} segment - The segment to adjust
1420
1423
  * @param {Array<THREE.Object3D>} connectors - The segment's connectors
1421
1424
  * @param {THREE.Vector3} endPoint1 - Explicit world position for first endpoint (optional)
1422
1425
  * @param {THREE.Vector3} endPoint2 - Explicit world position for second endpoint (optional)
@@ -1430,7 +1433,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1430
1433
  var endPoint2 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
1431
1434
  var activeSegment = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
1432
1435
  if (!segment || connectors.length !== 2) {
1433
- console.warn('⚠️ Cannot recreate segment: invalid segment or connectors');
1436
+ console.warn('⚠️ Cannot adjust segment: invalid segment or connectors');
1434
1437
  return;
1435
1438
  }
1436
1439
  var _connectors = _rollupPluginBabelHelpers.slicedToArray(connectors, 2),
@@ -1473,21 +1476,28 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1473
1476
  this._removeZeroLengthSegment(segment, connectors, activeSegment);
1474
1477
  return;
1475
1478
  }
1476
- console.log("\uD83D\uDD27 Recreating segment with new length: ".concat(newLength.toFixed(3), " (was ").concat(segment.geometry.parameters.height.toFixed(3), ")"));
1479
+ var oldLength = segment.geometry.parameters.height;
1480
+ console.log("\uD83D\uDD27 Adjusting segment geometry: ".concat(oldLength.toFixed(3), " \u2192 ").concat(newLength.toFixed(3)));
1481
+
1482
+ // Only recreate geometry if length has changed significantly
1483
+ if (Math.abs(newLength - oldLength) > 1e-6) {
1484
+ var oldGeometry = segment.geometry;
1485
+ var pipeRadius = oldGeometry.parameters.radiusTop || 0.1;
1477
1486
 
1478
- // Store old geometry and material references
1479
- var oldGeometry = segment.geometry;
1480
- segment.material;
1481
- var pipeRadius = oldGeometry.parameters.radiusTop || 0.1;
1487
+ // Create new cylinder geometry with updated length
1488
+ var newGeometry = new THREE__namespace.CylinderGeometry(pipeRadius, pipeRadius, newLength, 16, 1, false);
1482
1489
 
1483
- // Create new cylinder geometry with updated length
1484
- var newGeometry = new THREE__namespace.CylinderGeometry(pipeRadius, pipeRadius, newLength, 16, 1, false);
1490
+ // Replace geometry
1491
+ segment.geometry = newGeometry;
1485
1492
 
1486
- // Update segment mesh
1487
- segment.geometry = newGeometry;
1493
+ // Dispose old geometry
1494
+ oldGeometry.dispose();
1495
+ }
1496
+
1497
+ // Update segment position to new center
1488
1498
  segment.position.copy(newCenter);
1489
1499
 
1490
- // Calculate and apply rotation
1500
+ // Calculate and apply rotation to align with new direction
1491
1501
  var quaternion = new THREE__namespace.Quaternion();
1492
1502
  var up = new THREE__namespace.Vector3(0, 1, 0);
1493
1503
  quaternion.setFromUnitVectors(up, direction.clone().normalize());
@@ -1496,12 +1506,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1496
1506
  // Update matrices
1497
1507
  segment.updateMatrix();
1498
1508
  segment.updateMatrixWorld(true);
1499
-
1500
- // Dispose old geometry
1501
- if (oldGeometry && oldGeometry !== newGeometry) {
1502
- oldGeometry.dispose();
1503
- }
1504
- console.log("\u2705 Segment mesh recreated: new length = ".concat(newLength.toFixed(3), ", center = [").concat(newCenter.x.toFixed(2), ", ").concat(newCenter.y.toFixed(2), ", ").concat(newCenter.z.toFixed(2), "]"));
1509
+ console.log("\u2705 Segment adjusted: length = ".concat(newLength.toFixed(3), ", center = [").concat(newCenter.x.toFixed(2), ", ").concat(newCenter.y.toFixed(2), ", ").concat(newCenter.z.toFixed(2), "]"));
1505
1510
  }
1506
1511
 
1507
1512
  /**