@2112-lab/central-plant 0.1.49 → 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);
@@ -19259,17 +19274,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19259
19274
 
19260
19275
  // ALWAYS update connector positions after segment movement (first or subsequent moves)
19261
19276
  this.updateSegmentConnectorPositions(segment);
19262
-
19263
- // NEW: Update adjacent manual segments to follow this segment's new position
19264
- var maintainedConnections = this.snapSegmentConnectorsToNearbyEndpoints(segment);
19265
-
19266
- // NOTE: We do NOT remove connections from scene data
19267
- // The connections remain valid - the manual segments are maintaining those connections
19268
- // The pathfinding algorithm should detect that connectors are at the same position
19269
- // and skip creating computed segments for them
19270
- if (maintainedConnections.length > 0) {
19271
- console.log("\u2139\uFE0F ".concat(maintainedConnections.length, " connection(s) maintained by manual segments"));
19272
- }
19277
+ this.snapSegmentConnectorsToNearbyEndpoints(segment);
19273
19278
 
19274
19279
  // Store transform parameters using the OperationHistoryManager BEFORE updatePaths
19275
19280
  // This is critical so that intersection detection can undo the operation
@@ -19286,9 +19291,6 @@ var TransformOperationsManager = /*#__PURE__*/function () {
19286
19291
  // UNLESS skipPathUpdate is true (for batch operations)
19287
19292
  if (!skipPathUpdate) {
19288
19293
  console.log('🔄 Regenerating paths to create connecting pipe segments...');
19289
- if (maintainedConnections.length > 0) {
19290
- console.log("\u2139\uFE0F Manual segments are maintaining connections - pathfinding should skip connectors at same position");
19291
- }
19292
19294
  try {
19293
19295
  if (this.sceneViewer && typeof this.sceneViewer.updatePaths === 'function') {
19294
19296
  this.sceneViewer.updatePaths();
@@ -20333,8 +20335,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20333
20335
  }
20334
20336
 
20335
20337
  /**
20336
- * Recreate segment mesh with new length based on connector positions
20337
- * @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
20338
20340
  * @param {Array<THREE.Object3D>} connectors - The segment's connectors
20339
20341
  * @param {THREE.Vector3} endPoint1 - Explicit world position for first endpoint (optional)
20340
20342
  * @param {THREE.Vector3} endPoint2 - Explicit world position for second endpoint (optional)
@@ -20348,7 +20350,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20348
20350
  var endPoint2 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
20349
20351
  var activeSegment = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
20350
20352
  if (!segment || connectors.length !== 2) {
20351
- console.warn('⚠️ Cannot recreate segment: invalid segment or connectors');
20353
+ console.warn('⚠️ Cannot adjust segment: invalid segment or connectors');
20352
20354
  return;
20353
20355
  }
20354
20356
  var _connectors = _slicedToArray(connectors, 2),
@@ -20391,21 +20393,28 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20391
20393
  this._removeZeroLengthSegment(segment, connectors, activeSegment);
20392
20394
  return;
20393
20395
  }
20394
- 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)));
20395
20398
 
20396
- // Store old geometry and material references
20397
- var oldGeometry = segment.geometry;
20398
- segment.material;
20399
- 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;
20400
20403
 
20401
- // Create new cylinder geometry with updated length
20402
- 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);
20403
20406
 
20404
- // Update segment mesh
20405
- 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
20406
20415
  segment.position.copy(newCenter);
20407
20416
 
20408
- // Calculate and apply rotation
20417
+ // Calculate and apply rotation to align with new direction
20409
20418
  var quaternion = new THREE__namespace.Quaternion();
20410
20419
  var up = new THREE__namespace.Vector3(0, 1, 0);
20411
20420
  quaternion.setFromUnitVectors(up, direction.clone().normalize());
@@ -20414,12 +20423,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
20414
20423
  // Update matrices
20415
20424
  segment.updateMatrix();
20416
20425
  segment.updateMatrixWorld(true);
20417
-
20418
- // Dispose old geometry
20419
- if (oldGeometry && oldGeometry !== newGeometry) {
20420
- oldGeometry.dispose();
20421
- }
20422
- 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), "]"));
20423
20427
  }
20424
20428
 
20425
20429
  /**
@@ -25217,8 +25221,30 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
25217
25221
  value: function createPipePaths(paths, crosscubeTextureSet) {
25218
25222
  var _this3 = this;
25219
25223
  var sceneViewer = this.sceneViewer;
25220
- var globalSegmentIndex = 0; // Counter for globally unique segment indices
25221
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, ")"));
25222
25248
  var pipeRadius = 0.1;
25223
25249
  var pipeMaterial = this.createPipeMaterial(crosscubeTextureSet);
25224
25250
  paths.forEach(function (pathData, index) {
@@ -26564,13 +26590,6 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
26564
26590
  connectionsCopy,
26565
26591
  simplifiedSceneData,
26566
26592
  pathfindingResult,
26567
- intersectionCheck,
26568
- _this$sceneViewer,
26569
- operationHistoryManager,
26570
- lastOp,
26571
- undoSuccess,
26572
- correctedResult,
26573
- _this$sceneViewer2,
26574
26593
  _args = arguments;
26575
26594
  return _regenerator().w(function (_context) {
26576
26595
  while (1) switch (_context.n) {
@@ -26605,93 +26624,79 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
26605
26624
  console.log('Rewired connections:', JSON.parse(JSON.stringify(pathfindingResult.rewiredConnections)));
26606
26625
  console.log("intersectionCheck input:", pathfindingResult.paths);
26607
26626
 
26608
- // Check for path intersections (including manual segments)
26609
- intersectionCheck = this.checkPathIntersections(pathfindingResult.paths, 0.2, true);
26610
- pathfindingResult.intersections = intersectionCheck;
26611
- console.log("intersectionCheck:", intersectionCheck);
26612
- console.log("intersectionCheck.hasIntersections:", intersectionCheck.hasIntersections);
26613
-
26614
- // Handle intersection detection - undo last operation if intersections found
26615
- // Skip this if we're already in the middle of an undo operation
26616
- if (!(intersectionCheck.hasIntersections && !this.isUndoInProgress)) {
26617
- _context.n = 8;
26618
- break;
26619
- }
26620
- console.warn('⚠️ Path intersections detected! Attempting to undo last operation...');
26621
-
26622
- // Set flag to prevent recursive undo attempts
26623
- this.isUndoInProgress = true;
26624
-
26625
- // Access operationHistoryManager through sceneViewer.managers.operationHistory
26626
- 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;
26627
- if (!operationHistoryManager) {
26628
- _context.n = 6;
26629
- break;
26630
- }
26631
- lastOp = operationHistoryManager.getLastOperation();
26632
- if (!lastOp) {
26633
- _context.n = 4;
26634
- break;
26635
- }
26636
- console.warn("\u26A0\uFE0F Intersection caused by operation: ".concat(lastOp.operationName), lastOp.params);
26637
-
26638
- // Attempt to undo the operation FIRST (before removing computed objects)
26639
- // This is important because undo needs to find the segment that was moved
26640
- undoSuccess = operationHistoryManager.undoLastOperation();
26641
- if (!undoSuccess) {
26642
- _context.n = 2;
26643
- break;
26644
- }
26645
- console.log('✅ Successfully undid operation that caused intersection');
26646
-
26647
- // Now remove the buggy computed objects that were created with the invalid state
26648
- console.log('🗑️ Removing buggy computed objects after undo...');
26649
- this.removeComputedObjects();
26650
-
26651
- // Re-run pathfinding after undo to restore valid state
26652
- 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
+ // }
26653
26699
 
26654
- // Recursively call _executePathfinding with the corrected scene state
26655
- // This is safe because we've undone the operation, so we won't get into an infinite loop
26656
- _context.n = 1;
26657
- return this._executePathfinding(sceneData, connections, _objectSpread2(_objectSpread2({}, options), {}, {
26658
- context: "".concat(context, " (After Undo)")
26659
- }));
26660
- case 1:
26661
- correctedResult = _context.v;
26662
- // Mark that we performed an undo and return the corrected result
26663
- correctedResult.undoPerformed = true;
26664
- correctedResult.undoneOperation = lastOp;
26665
-
26666
- // Clear the undo flag before returning
26667
- this.isUndoInProgress = false;
26668
- return _context.a(2, correctedResult);
26669
- case 2:
26670
- console.error('❌ Failed to undo operation that caused intersection');
26671
- pathfindingResult.undoFailed = true;
26672
- // Clear the undo flag even on failure
26673
- this.isUndoInProgress = false;
26674
- case 3:
26675
- _context.n = 5;
26676
- break;
26677
- case 4:
26678
- console.warn('⚠️ No operation in history to undo');
26679
- this.isUndoInProgress = false;
26680
- case 5:
26681
- _context.n = 7;
26682
- break;
26683
- case 6:
26684
- console.error('❌ OperationHistoryManager not available for undo');
26685
- console.error(' Available managers:', Object.keys(((_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.managers) || {}));
26686
- this.isUndoInProgress = false;
26687
- case 7:
26688
- _context.n = 9;
26689
- break;
26690
- case 8:
26691
- if (intersectionCheck.hasIntersections && this.isUndoInProgress) {
26692
- console.log('⏭️ Skipping intersection handling - undo already in progress');
26693
- }
26694
- case 9:
26695
26700
  // Create gateways in the scene if requested
26696
26701
  if (options.createGateways && pathfindingResult.gateways) {
26697
26702
  this.renderingManager.createGateways(pathfindingResult);
@@ -33756,7 +33761,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
33756
33761
  * Initialize the CentralPlant manager
33757
33762
  *
33758
33763
  * @constructor
33759
- * @version 0.1.49
33764
+ * @version 0.1.50
33760
33765
  * @updated 2025-10-22
33761
33766
  *
33762
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.49
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.
@@ -357,17 +357,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
357
357
 
358
358
  // ALWAYS update connector positions after segment movement (first or subsequent moves)
359
359
  this.updateSegmentConnectorPositions(segment);
360
-
361
- // NEW: Update adjacent manual segments to follow this segment's new position
362
- var maintainedConnections = this.snapSegmentConnectorsToNearbyEndpoints(segment);
363
-
364
- // NOTE: We do NOT remove connections from scene data
365
- // The connections remain valid - the manual segments are maintaining those connections
366
- // The pathfinding algorithm should detect that connectors are at the same position
367
- // and skip creating computed segments for them
368
- if (maintainedConnections.length > 0) {
369
- console.log("\u2139\uFE0F ".concat(maintainedConnections.length, " connection(s) maintained by manual segments"));
370
- }
360
+ this.snapSegmentConnectorsToNearbyEndpoints(segment);
371
361
 
372
362
  // Store transform parameters using the OperationHistoryManager BEFORE updatePaths
373
363
  // This is critical so that intersection detection can undo the operation
@@ -384,9 +374,6 @@ var TransformOperationsManager = /*#__PURE__*/function () {
384
374
  // UNLESS skipPathUpdate is true (for batch operations)
385
375
  if (!skipPathUpdate) {
386
376
  console.log('🔄 Regenerating paths to create connecting pipe segments...');
387
- if (maintainedConnections.length > 0) {
388
- console.log("\u2139\uFE0F Manual segments are maintaining connections - pathfinding should skip connectors at same position");
389
- }
390
377
  try {
391
378
  if (this.sceneViewer && typeof this.sceneViewer.updatePaths === 'function') {
392
379
  this.sceneViewer.updatePaths();
@@ -1431,8 +1418,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1431
1418
  }
1432
1419
 
1433
1420
  /**
1434
- * Recreate segment mesh with new length based on connector positions
1435
- * @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
1436
1423
  * @param {Array<THREE.Object3D>} connectors - The segment's connectors
1437
1424
  * @param {THREE.Vector3} endPoint1 - Explicit world position for first endpoint (optional)
1438
1425
  * @param {THREE.Vector3} endPoint2 - Explicit world position for second endpoint (optional)
@@ -1446,7 +1433,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1446
1433
  var endPoint2 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
1447
1434
  var activeSegment = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
1448
1435
  if (!segment || connectors.length !== 2) {
1449
- console.warn('⚠️ Cannot recreate segment: invalid segment or connectors');
1436
+ console.warn('⚠️ Cannot adjust segment: invalid segment or connectors');
1450
1437
  return;
1451
1438
  }
1452
1439
  var _connectors = _rollupPluginBabelHelpers.slicedToArray(connectors, 2),
@@ -1489,21 +1476,28 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1489
1476
  this._removeZeroLengthSegment(segment, connectors, activeSegment);
1490
1477
  return;
1491
1478
  }
1492
- 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;
1493
1486
 
1494
- // Store old geometry and material references
1495
- var oldGeometry = segment.geometry;
1496
- segment.material;
1497
- 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);
1498
1489
 
1499
- // Create new cylinder geometry with updated length
1500
- var newGeometry = new THREE__namespace.CylinderGeometry(pipeRadius, pipeRadius, newLength, 16, 1, false);
1490
+ // Replace geometry
1491
+ segment.geometry = newGeometry;
1501
1492
 
1502
- // Update segment mesh
1503
- segment.geometry = newGeometry;
1493
+ // Dispose old geometry
1494
+ oldGeometry.dispose();
1495
+ }
1496
+
1497
+ // Update segment position to new center
1504
1498
  segment.position.copy(newCenter);
1505
1499
 
1506
- // Calculate and apply rotation
1500
+ // Calculate and apply rotation to align with new direction
1507
1501
  var quaternion = new THREE__namespace.Quaternion();
1508
1502
  var up = new THREE__namespace.Vector3(0, 1, 0);
1509
1503
  quaternion.setFromUnitVectors(up, direction.clone().normalize());
@@ -1512,12 +1506,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1512
1506
  // Update matrices
1513
1507
  segment.updateMatrix();
1514
1508
  segment.updateMatrixWorld(true);
1515
-
1516
- // Dispose old geometry
1517
- if (oldGeometry && oldGeometry !== newGeometry) {
1518
- oldGeometry.dispose();
1519
- }
1520
- 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), "]"));
1521
1510
  }
1522
1511
 
1523
1512
  /**
@@ -1658,11 +1658,15 @@ var TransformControlsManager = /*#__PURE__*/function () {
1658
1658
  _this9.selectedObjects[selectedIndex] = segment;
1659
1659
  console.log("\u2705 Updated selectedObjects[".concat(selectedIndex, "] with refreshed segment reference"));
1660
1660
  }
1661
- console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(i + 1, "/").concat(segments.length, "):"), {
1662
- deltaX: deltaX,
1663
- deltaY: deltaY,
1664
- deltaZ: deltaZ
1665
- });
1661
+ if (segment) {
1662
+ console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(i + 1, "/").concat(segments.length, "):"), {
1663
+ deltaX: deltaX,
1664
+ deltaY: deltaY,
1665
+ deltaZ: deltaZ
1666
+ });
1667
+ } else {
1668
+ console.warn("\u26A0\uFE0F Segment reference became null after translation (".concat(i + 1, "/").concat(segments.length, ")"));
1669
+ }
1666
1670
 
1667
1671
  // Delay between segments to ensure all updates propagate
1668
1672
  if (!(i < segments.length - 1)) {
@@ -1789,11 +1793,15 @@ var TransformControlsManager = /*#__PURE__*/function () {
1789
1793
  _this9.selectedObjects[selectedIndex] = segment;
1790
1794
  console.log("\u2705 Updated selectedObjects[".concat(selectedIndex, "] with refreshed segment reference"));
1791
1795
  }
1792
- console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(_i + 1, "/").concat(segments.length, "):"), {
1793
- deltaX: deltaX,
1794
- deltaY: deltaY,
1795
- deltaZ: deltaZ
1796
- });
1796
+ if (segment) {
1797
+ console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(_i + 1, "/").concat(segments.length, "):"), {
1798
+ deltaX: deltaX,
1799
+ deltaY: deltaY,
1800
+ deltaZ: deltaZ
1801
+ });
1802
+ } else {
1803
+ console.warn("\u26A0\uFE0F Segment reference became null after translation (".concat(_i + 1, "/").concat(segments.length, ")"));
1804
+ }
1797
1805
 
1798
1806
  // Delay between segments
1799
1807
  if (!(_i < segments.length - 1)) {
@@ -1935,17 +1943,24 @@ var TransformControlsManager = /*#__PURE__*/function () {
1935
1943
  deltaZ: deltaZ
1936
1944
  });
1937
1945
  case 21:
1938
- // Reset the multi-selection group transform
1939
- this.multiSelectionGroup.position.set(0, 0, 0);
1940
- this.multiSelectionGroup.rotation.set(0, 0, 0);
1941
- this.multiSelectionGroup.scale.set(1, 1, 1);
1946
+ // Reset the multi-selection group transform (if it still exists)
1947
+ // Note: The group might have been cleared during async operations
1948
+ if (this.multiSelectionGroup) {
1949
+ this.multiSelectionGroup.position.set(0, 0, 0);
1950
+ this.multiSelectionGroup.rotation.set(0, 0, 0);
1951
+ this.multiSelectionGroup.scale.set(1, 1, 1);
1952
+ } else {
1953
+ console.warn('⚠️ Multi-selection group was cleared during transformation');
1954
+ }
1942
1955
 
1943
1956
  // CRITICAL: Clear bounding box cache after manualization
1944
1957
  // Manualization changes object references, making cached boxes invalid
1945
1958
  this.clearBoundingBoxCache();
1946
1959
 
1947
- // Update the multi-selection display with new positions
1948
- this.updateMultiSelection();
1960
+ // Update the multi-selection display with new positions (only if we still have selected objects)
1961
+ if (this.selectedObjects.length > 0) {
1962
+ this.updateMultiSelection();
1963
+ }
1949
1964
  console.log("\u2705 Multi-selection transform applied");
1950
1965
  case 22:
1951
1966
  return _context3.a(2);
@@ -180,8 +180,30 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
180
180
  value: function createPipePaths(paths, crosscubeTextureSet) {
181
181
  var _this3 = this;
182
182
  var sceneViewer = this.sceneViewer;
183
- var globalSegmentIndex = 0; // Counter for globally unique segment indices
184
183
 
184
+ // Find the highest segment index currently in use (both computed SEGMENT-X and manual Segment-X)
185
+ var maxExistingIndex = -1;
186
+ sceneViewer.scene.traverse(function (obj) {
187
+ if (obj.uuid) {
188
+ // Check for computed segments: SEGMENT-123
189
+ var computedMatch = obj.uuid.match(/^SEGMENT-(\d+)$/);
190
+ if (computedMatch) {
191
+ var index = parseInt(computedMatch[1], 10);
192
+ maxExistingIndex = Math.max(maxExistingIndex, index);
193
+ }
194
+
195
+ // Check for manual segments: Segment-123
196
+ var manualMatch = obj.uuid.match(/^Segment-(\d+)$/);
197
+ if (manualMatch) {
198
+ var _index = parseInt(manualMatch[1], 10);
199
+ maxExistingIndex = Math.max(maxExistingIndex, _index);
200
+ }
201
+ }
202
+ });
203
+
204
+ // Start counter after the highest existing index to prevent UUID conflicts
205
+ var globalSegmentIndex = maxExistingIndex + 1;
206
+ console.log("\uD83D\uDD22 Starting segment index at ".concat(globalSegmentIndex, " (max existing: ").concat(maxExistingIndex, ")"));
185
207
  var pipeRadius = 0.1;
186
208
  var pipeMaterial = this.createPipeMaterial(crosscubeTextureSet);
187
209
  paths.forEach(function (pathData, index) {
@@ -127,13 +127,6 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
127
127
  connectionsCopy,
128
128
  simplifiedSceneData,
129
129
  pathfindingResult,
130
- intersectionCheck,
131
- _this$sceneViewer,
132
- operationHistoryManager,
133
- lastOp,
134
- undoSuccess,
135
- correctedResult,
136
- _this$sceneViewer2,
137
130
  _args = arguments;
138
131
  return _rollupPluginBabelHelpers.regenerator().w(function (_context) {
139
132
  while (1) switch (_context.n) {
@@ -168,93 +161,79 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
168
161
  console.log('Rewired connections:', JSON.parse(JSON.stringify(pathfindingResult.rewiredConnections)));
169
162
  console.log("intersectionCheck input:", pathfindingResult.paths);
170
163
 
171
- // Check for path intersections (including manual segments)
172
- intersectionCheck = this.checkPathIntersections(pathfindingResult.paths, 0.2, true);
173
- pathfindingResult.intersections = intersectionCheck;
174
- console.log("intersectionCheck:", intersectionCheck);
175
- console.log("intersectionCheck.hasIntersections:", intersectionCheck.hasIntersections);
176
-
177
- // Handle intersection detection - undo last operation if intersections found
178
- // Skip this if we're already in the middle of an undo operation
179
- if (!(intersectionCheck.hasIntersections && !this.isUndoInProgress)) {
180
- _context.n = 8;
181
- break;
182
- }
183
- console.warn('⚠️ Path intersections detected! Attempting to undo last operation...');
184
-
185
- // Set flag to prevent recursive undo attempts
186
- this.isUndoInProgress = true;
187
-
188
- // Access operationHistoryManager through sceneViewer.managers.operationHistory
189
- 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;
190
- if (!operationHistoryManager) {
191
- _context.n = 6;
192
- break;
193
- }
194
- lastOp = operationHistoryManager.getLastOperation();
195
- if (!lastOp) {
196
- _context.n = 4;
197
- break;
198
- }
199
- console.warn("\u26A0\uFE0F Intersection caused by operation: ".concat(lastOp.operationName), lastOp.params);
200
-
201
- // Attempt to undo the operation FIRST (before removing computed objects)
202
- // This is important because undo needs to find the segment that was moved
203
- undoSuccess = operationHistoryManager.undoLastOperation();
204
- if (!undoSuccess) {
205
- _context.n = 2;
206
- break;
207
- }
208
- console.log('✅ Successfully undid operation that caused intersection');
164
+ // // Check for path intersections (including manual segments)
165
+ // const intersectionCheck = this.checkPathIntersections(pathfindingResult.paths, 0.2, true);
166
+ // pathfindingResult.intersections = intersectionCheck;
167
+
168
+ // console.log("intersectionCheck:", intersectionCheck);
169
+ // console.log("intersectionCheck.hasIntersections:", intersectionCheck.hasIntersections);
170
+
171
+ // // Handle intersection detection - undo last operation if intersections found
172
+ // // Skip this if we're already in the middle of an undo operation
173
+ // if (intersectionCheck.hasIntersections && !this.isUndoInProgress) {
174
+ // console.warn('⚠️ Path intersections detected! Attempting to undo last operation...');
175
+
176
+ // // Set flag to prevent recursive undo attempts
177
+ // this.isUndoInProgress = true;
178
+
179
+ // // Access operationHistoryManager through sceneViewer.managers.operationHistory
180
+ // const operationHistoryManager = this.sceneViewer?.managers?.operationHistory;
181
+
182
+ // if (operationHistoryManager) {
183
+ // const lastOp = operationHistoryManager.getLastOperation();
184
+
185
+ // if (lastOp) {
186
+ // console.warn(`⚠️ Intersection caused by operation: ${lastOp.operationName}`, lastOp.params);
187
+
188
+ // // Attempt to undo the operation FIRST (before removing computed objects)
189
+ // // This is important because undo needs to find the segment that was moved
190
+ // const undoSuccess = operationHistoryManager.undoLastOperation();
191
+
192
+ // if (undoSuccess) {
193
+ // console.log('✅ Successfully undid operation that caused intersection');
194
+
195
+ // // Now remove the buggy computed objects that were created with the invalid state
196
+ // console.log('🗑️ Removing buggy computed objects after undo...');
197
+ // this.removeComputedObjects();
198
+
199
+ // // Re-run pathfinding after undo to restore valid state
200
+ // console.log('🔄 Re-running pathfinding after undo to restore clean state...');
201
+
202
+ // // Recursively call _executePathfinding with the corrected scene state
203
+ // // This is safe because we've undone the operation, so we won't get into an infinite loop
204
+ // const correctedResult = await this._executePathfinding(
205
+ // sceneData,
206
+ // connections,
207
+ // { ...options, context: `${context} (After Undo)` }
208
+ // );
209
+
210
+ // // Mark that we performed an undo and return the corrected result
211
+ // correctedResult.undoPerformed = true;
212
+ // correctedResult.undoneOperation = lastOp;
213
+
214
+ // // Clear the undo flag before returning
215
+ // this.isUndoInProgress = false;
216
+
217
+ // return correctedResult;
218
+ // } else {
219
+ // console.error('❌ Failed to undo operation that caused intersection');
220
+ // pathfindingResult.undoFailed = true;
221
+ // // Clear the undo flag even on failure
222
+ // this.isUndoInProgress = false;
223
+ // }
224
+ // } else {
225
+ // console.warn('⚠️ No operation in history to undo');
226
+ // this.isUndoInProgress = false;
227
+ // }
228
+ // } else {
229
+ // console.error('❌ OperationHistoryManager not available for undo');
230
+ // console.error(' Available managers:', Object.keys(this.sceneViewer?.managers || {}));
231
+ // this.isUndoInProgress = false;
232
+ // }
233
+ // } else if (intersectionCheck.hasIntersections && this.isUndoInProgress) {
234
+ // console.log('⏭️ Skipping intersection handling - undo already in progress');
235
+ // }
209
236
 
210
- // Now remove the buggy computed objects that were created with the invalid state
211
- console.log('🗑️ Removing buggy computed objects after undo...');
212
- this.removeComputedObjects();
213
-
214
- // Re-run pathfinding after undo to restore valid state
215
- console.log('🔄 Re-running pathfinding after undo to restore clean state...');
216
-
217
- // Recursively call _executePathfinding with the corrected scene state
218
- // This is safe because we've undone the operation, so we won't get into an infinite loop
219
- _context.n = 1;
220
- return this._executePathfinding(sceneData, connections, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
221
- context: "".concat(context, " (After Undo)")
222
- }));
223
- case 1:
224
- correctedResult = _context.v;
225
- // Mark that we performed an undo and return the corrected result
226
- correctedResult.undoPerformed = true;
227
- correctedResult.undoneOperation = lastOp;
228
-
229
- // Clear the undo flag before returning
230
- this.isUndoInProgress = false;
231
- return _context.a(2, correctedResult);
232
- case 2:
233
- console.error('❌ Failed to undo operation that caused intersection');
234
- pathfindingResult.undoFailed = true;
235
- // Clear the undo flag even on failure
236
- this.isUndoInProgress = false;
237
- case 3:
238
- _context.n = 5;
239
- break;
240
- case 4:
241
- console.warn('⚠️ No operation in history to undo');
242
- this.isUndoInProgress = false;
243
- case 5:
244
- _context.n = 7;
245
- break;
246
- case 6:
247
- console.error('❌ OperationHistoryManager not available for undo');
248
- console.error(' Available managers:', Object.keys(((_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.managers) || {}));
249
- this.isUndoInProgress = false;
250
- case 7:
251
- _context.n = 9;
252
- break;
253
- case 8:
254
- if (intersectionCheck.hasIntersections && this.isUndoInProgress) {
255
- console.log('⏭️ Skipping intersection handling - undo already in progress');
256
- }
257
- case 9:
258
237
  // Create gateways in the scene if requested
259
238
  if (options.createGateways && pathfindingResult.gateways) {
260
239
  this.renderingManager.createGateways(pathfindingResult);
@@ -15,7 +15,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
15
15
  * Initialize the CentralPlant manager
16
16
  *
17
17
  * @constructor
18
- * @version 0.1.49
18
+ * @version 0.1.50
19
19
  * @updated 2025-10-22
20
20
  *
21
21
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -333,17 +333,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
333
333
 
334
334
  // ALWAYS update connector positions after segment movement (first or subsequent moves)
335
335
  this.updateSegmentConnectorPositions(segment);
336
-
337
- // NEW: Update adjacent manual segments to follow this segment's new position
338
- var maintainedConnections = this.snapSegmentConnectorsToNearbyEndpoints(segment);
339
-
340
- // NOTE: We do NOT remove connections from scene data
341
- // The connections remain valid - the manual segments are maintaining those connections
342
- // The pathfinding algorithm should detect that connectors are at the same position
343
- // and skip creating computed segments for them
344
- if (maintainedConnections.length > 0) {
345
- console.log("\u2139\uFE0F ".concat(maintainedConnections.length, " connection(s) maintained by manual segments"));
346
- }
336
+ this.snapSegmentConnectorsToNearbyEndpoints(segment);
347
337
 
348
338
  // Store transform parameters using the OperationHistoryManager BEFORE updatePaths
349
339
  // This is critical so that intersection detection can undo the operation
@@ -360,9 +350,6 @@ var TransformOperationsManager = /*#__PURE__*/function () {
360
350
  // UNLESS skipPathUpdate is true (for batch operations)
361
351
  if (!skipPathUpdate) {
362
352
  console.log('🔄 Regenerating paths to create connecting pipe segments...');
363
- if (maintainedConnections.length > 0) {
364
- console.log("\u2139\uFE0F Manual segments are maintaining connections - pathfinding should skip connectors at same position");
365
- }
366
353
  try {
367
354
  if (this.sceneViewer && typeof this.sceneViewer.updatePaths === 'function') {
368
355
  this.sceneViewer.updatePaths();
@@ -1407,8 +1394,8 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1407
1394
  }
1408
1395
 
1409
1396
  /**
1410
- * Recreate segment mesh with new length based on connector positions
1411
- * @param {THREE.Object3D} segment - The segment to recreate
1397
+ * Adjust segment geometry and transform to match new endpoint positions
1398
+ * @param {THREE.Object3D} segment - The segment to adjust
1412
1399
  * @param {Array<THREE.Object3D>} connectors - The segment's connectors
1413
1400
  * @param {THREE.Vector3} endPoint1 - Explicit world position for first endpoint (optional)
1414
1401
  * @param {THREE.Vector3} endPoint2 - Explicit world position for second endpoint (optional)
@@ -1422,7 +1409,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1422
1409
  var endPoint2 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
1423
1410
  var activeSegment = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
1424
1411
  if (!segment || connectors.length !== 2) {
1425
- console.warn('⚠️ Cannot recreate segment: invalid segment or connectors');
1412
+ console.warn('⚠️ Cannot adjust segment: invalid segment or connectors');
1426
1413
  return;
1427
1414
  }
1428
1415
  var _connectors = _slicedToArray(connectors, 2),
@@ -1465,21 +1452,28 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1465
1452
  this._removeZeroLengthSegment(segment, connectors, activeSegment);
1466
1453
  return;
1467
1454
  }
1468
- console.log("\uD83D\uDD27 Recreating segment with new length: ".concat(newLength.toFixed(3), " (was ").concat(segment.geometry.parameters.height.toFixed(3), ")"));
1455
+ var oldLength = segment.geometry.parameters.height;
1456
+ console.log("\uD83D\uDD27 Adjusting segment geometry: ".concat(oldLength.toFixed(3), " \u2192 ").concat(newLength.toFixed(3)));
1457
+
1458
+ // Only recreate geometry if length has changed significantly
1459
+ if (Math.abs(newLength - oldLength) > 1e-6) {
1460
+ var oldGeometry = segment.geometry;
1461
+ var pipeRadius = oldGeometry.parameters.radiusTop || 0.1;
1469
1462
 
1470
- // Store old geometry and material references
1471
- var oldGeometry = segment.geometry;
1472
- segment.material;
1473
- var pipeRadius = oldGeometry.parameters.radiusTop || 0.1;
1463
+ // Create new cylinder geometry with updated length
1464
+ var newGeometry = new THREE.CylinderGeometry(pipeRadius, pipeRadius, newLength, 16, 1, false);
1474
1465
 
1475
- // Create new cylinder geometry with updated length
1476
- var newGeometry = new THREE.CylinderGeometry(pipeRadius, pipeRadius, newLength, 16, 1, false);
1466
+ // Replace geometry
1467
+ segment.geometry = newGeometry;
1477
1468
 
1478
- // Update segment mesh
1479
- segment.geometry = newGeometry;
1469
+ // Dispose old geometry
1470
+ oldGeometry.dispose();
1471
+ }
1472
+
1473
+ // Update segment position to new center
1480
1474
  segment.position.copy(newCenter);
1481
1475
 
1482
- // Calculate and apply rotation
1476
+ // Calculate and apply rotation to align with new direction
1483
1477
  var quaternion = new THREE.Quaternion();
1484
1478
  var up = new THREE.Vector3(0, 1, 0);
1485
1479
  quaternion.setFromUnitVectors(up, direction.clone().normalize());
@@ -1488,12 +1482,7 @@ var TransformOperationsManager = /*#__PURE__*/function () {
1488
1482
  // Update matrices
1489
1483
  segment.updateMatrix();
1490
1484
  segment.updateMatrixWorld(true);
1491
-
1492
- // Dispose old geometry
1493
- if (oldGeometry && oldGeometry !== newGeometry) {
1494
- oldGeometry.dispose();
1495
- }
1496
- 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), "]"));
1485
+ 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), "]"));
1497
1486
  }
1498
1487
 
1499
1488
  /**
@@ -1634,11 +1634,15 @@ var TransformControlsManager = /*#__PURE__*/function () {
1634
1634
  _this9.selectedObjects[selectedIndex] = segment;
1635
1635
  console.log("\u2705 Updated selectedObjects[".concat(selectedIndex, "] with refreshed segment reference"));
1636
1636
  }
1637
- console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(i + 1, "/").concat(segments.length, "):"), {
1638
- deltaX: deltaX,
1639
- deltaY: deltaY,
1640
- deltaZ: deltaZ
1641
- });
1637
+ if (segment) {
1638
+ console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(i + 1, "/").concat(segments.length, "):"), {
1639
+ deltaX: deltaX,
1640
+ deltaY: deltaY,
1641
+ deltaZ: deltaZ
1642
+ });
1643
+ } else {
1644
+ console.warn("\u26A0\uFE0F Segment reference became null after translation (".concat(i + 1, "/").concat(segments.length, ")"));
1645
+ }
1642
1646
 
1643
1647
  // Delay between segments to ensure all updates propagate
1644
1648
  if (!(i < segments.length - 1)) {
@@ -1765,11 +1769,15 @@ var TransformControlsManager = /*#__PURE__*/function () {
1765
1769
  _this9.selectedObjects[selectedIndex] = segment;
1766
1770
  console.log("\u2705 Updated selectedObjects[".concat(selectedIndex, "] with refreshed segment reference"));
1767
1771
  }
1768
- console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(_i + 1, "/").concat(segments.length, "):"), {
1769
- deltaX: deltaX,
1770
- deltaY: deltaY,
1771
- deltaZ: deltaZ
1772
- });
1772
+ if (segment) {
1773
+ console.log("\uD83D\uDCE6 Segment ".concat(segment.name, " translated (").concat(_i + 1, "/").concat(segments.length, "):"), {
1774
+ deltaX: deltaX,
1775
+ deltaY: deltaY,
1776
+ deltaZ: deltaZ
1777
+ });
1778
+ } else {
1779
+ console.warn("\u26A0\uFE0F Segment reference became null after translation (".concat(_i + 1, "/").concat(segments.length, ")"));
1780
+ }
1773
1781
 
1774
1782
  // Delay between segments
1775
1783
  if (!(_i < segments.length - 1)) {
@@ -1911,17 +1919,24 @@ var TransformControlsManager = /*#__PURE__*/function () {
1911
1919
  deltaZ: deltaZ
1912
1920
  });
1913
1921
  case 21:
1914
- // Reset the multi-selection group transform
1915
- this.multiSelectionGroup.position.set(0, 0, 0);
1916
- this.multiSelectionGroup.rotation.set(0, 0, 0);
1917
- this.multiSelectionGroup.scale.set(1, 1, 1);
1922
+ // Reset the multi-selection group transform (if it still exists)
1923
+ // Note: The group might have been cleared during async operations
1924
+ if (this.multiSelectionGroup) {
1925
+ this.multiSelectionGroup.position.set(0, 0, 0);
1926
+ this.multiSelectionGroup.rotation.set(0, 0, 0);
1927
+ this.multiSelectionGroup.scale.set(1, 1, 1);
1928
+ } else {
1929
+ console.warn('⚠️ Multi-selection group was cleared during transformation');
1930
+ }
1918
1931
 
1919
1932
  // CRITICAL: Clear bounding box cache after manualization
1920
1933
  // Manualization changes object references, making cached boxes invalid
1921
1934
  this.clearBoundingBoxCache();
1922
1935
 
1923
- // Update the multi-selection display with new positions
1924
- this.updateMultiSelection();
1936
+ // Update the multi-selection display with new positions (only if we still have selected objects)
1937
+ if (this.selectedObjects.length > 0) {
1938
+ this.updateMultiSelection();
1939
+ }
1925
1940
  console.log("\u2705 Multi-selection transform applied");
1926
1941
  case 22:
1927
1942
  return _context3.a(2);
@@ -156,8 +156,30 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
156
156
  value: function createPipePaths(paths, crosscubeTextureSet) {
157
157
  var _this3 = this;
158
158
  var sceneViewer = this.sceneViewer;
159
- var globalSegmentIndex = 0; // Counter for globally unique segment indices
160
159
 
160
+ // Find the highest segment index currently in use (both computed SEGMENT-X and manual Segment-X)
161
+ var maxExistingIndex = -1;
162
+ sceneViewer.scene.traverse(function (obj) {
163
+ if (obj.uuid) {
164
+ // Check for computed segments: SEGMENT-123
165
+ var computedMatch = obj.uuid.match(/^SEGMENT-(\d+)$/);
166
+ if (computedMatch) {
167
+ var index = parseInt(computedMatch[1], 10);
168
+ maxExistingIndex = Math.max(maxExistingIndex, index);
169
+ }
170
+
171
+ // Check for manual segments: Segment-123
172
+ var manualMatch = obj.uuid.match(/^Segment-(\d+)$/);
173
+ if (manualMatch) {
174
+ var _index = parseInt(manualMatch[1], 10);
175
+ maxExistingIndex = Math.max(maxExistingIndex, _index);
176
+ }
177
+ }
178
+ });
179
+
180
+ // Start counter after the highest existing index to prevent UUID conflicts
181
+ var globalSegmentIndex = maxExistingIndex + 1;
182
+ console.log("\uD83D\uDD22 Starting segment index at ".concat(globalSegmentIndex, " (max existing: ").concat(maxExistingIndex, ")"));
161
183
  var pipeRadius = 0.1;
162
184
  var pipeMaterial = this.createPipeMaterial(crosscubeTextureSet);
163
185
  paths.forEach(function (pathData, index) {
@@ -1,4 +1,4 @@
1
- import { inherits as _inherits, createClass as _createClass, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, objectSpread2 as _objectSpread2 } from '../../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { inherits as _inherits, createClass as _createClass, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import 'three';
3
3
  import { Pathfinder } from '@2112-lab/pathfinder';
4
4
  import { BaseDisposable } from '../../core/baseDisposable.js';
@@ -123,13 +123,6 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
123
123
  connectionsCopy,
124
124
  simplifiedSceneData,
125
125
  pathfindingResult,
126
- intersectionCheck,
127
- _this$sceneViewer,
128
- operationHistoryManager,
129
- lastOp,
130
- undoSuccess,
131
- correctedResult,
132
- _this$sceneViewer2,
133
126
  _args = arguments;
134
127
  return _regenerator().w(function (_context) {
135
128
  while (1) switch (_context.n) {
@@ -164,93 +157,79 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
164
157
  console.log('Rewired connections:', JSON.parse(JSON.stringify(pathfindingResult.rewiredConnections)));
165
158
  console.log("intersectionCheck input:", pathfindingResult.paths);
166
159
 
167
- // Check for path intersections (including manual segments)
168
- intersectionCheck = this.checkPathIntersections(pathfindingResult.paths, 0.2, true);
169
- pathfindingResult.intersections = intersectionCheck;
170
- console.log("intersectionCheck:", intersectionCheck);
171
- console.log("intersectionCheck.hasIntersections:", intersectionCheck.hasIntersections);
172
-
173
- // Handle intersection detection - undo last operation if intersections found
174
- // Skip this if we're already in the middle of an undo operation
175
- if (!(intersectionCheck.hasIntersections && !this.isUndoInProgress)) {
176
- _context.n = 8;
177
- break;
178
- }
179
- console.warn('⚠️ Path intersections detected! Attempting to undo last operation...');
180
-
181
- // Set flag to prevent recursive undo attempts
182
- this.isUndoInProgress = true;
183
-
184
- // Access operationHistoryManager through sceneViewer.managers.operationHistory
185
- 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;
186
- if (!operationHistoryManager) {
187
- _context.n = 6;
188
- break;
189
- }
190
- lastOp = operationHistoryManager.getLastOperation();
191
- if (!lastOp) {
192
- _context.n = 4;
193
- break;
194
- }
195
- console.warn("\u26A0\uFE0F Intersection caused by operation: ".concat(lastOp.operationName), lastOp.params);
196
-
197
- // Attempt to undo the operation FIRST (before removing computed objects)
198
- // This is important because undo needs to find the segment that was moved
199
- undoSuccess = operationHistoryManager.undoLastOperation();
200
- if (!undoSuccess) {
201
- _context.n = 2;
202
- break;
203
- }
204
- console.log('✅ Successfully undid operation that caused intersection');
160
+ // // Check for path intersections (including manual segments)
161
+ // const intersectionCheck = this.checkPathIntersections(pathfindingResult.paths, 0.2, true);
162
+ // pathfindingResult.intersections = intersectionCheck;
163
+
164
+ // console.log("intersectionCheck:", intersectionCheck);
165
+ // console.log("intersectionCheck.hasIntersections:", intersectionCheck.hasIntersections);
166
+
167
+ // // Handle intersection detection - undo last operation if intersections found
168
+ // // Skip this if we're already in the middle of an undo operation
169
+ // if (intersectionCheck.hasIntersections && !this.isUndoInProgress) {
170
+ // console.warn('⚠️ Path intersections detected! Attempting to undo last operation...');
171
+
172
+ // // Set flag to prevent recursive undo attempts
173
+ // this.isUndoInProgress = true;
174
+
175
+ // // Access operationHistoryManager through sceneViewer.managers.operationHistory
176
+ // const operationHistoryManager = this.sceneViewer?.managers?.operationHistory;
177
+
178
+ // if (operationHistoryManager) {
179
+ // const lastOp = operationHistoryManager.getLastOperation();
180
+
181
+ // if (lastOp) {
182
+ // console.warn(`⚠️ Intersection caused by operation: ${lastOp.operationName}`, lastOp.params);
183
+
184
+ // // Attempt to undo the operation FIRST (before removing computed objects)
185
+ // // This is important because undo needs to find the segment that was moved
186
+ // const undoSuccess = operationHistoryManager.undoLastOperation();
187
+
188
+ // if (undoSuccess) {
189
+ // console.log('✅ Successfully undid operation that caused intersection');
190
+
191
+ // // Now remove the buggy computed objects that were created with the invalid state
192
+ // console.log('🗑️ Removing buggy computed objects after undo...');
193
+ // this.removeComputedObjects();
194
+
195
+ // // Re-run pathfinding after undo to restore valid state
196
+ // console.log('🔄 Re-running pathfinding after undo to restore clean state...');
197
+
198
+ // // Recursively call _executePathfinding with the corrected scene state
199
+ // // This is safe because we've undone the operation, so we won't get into an infinite loop
200
+ // const correctedResult = await this._executePathfinding(
201
+ // sceneData,
202
+ // connections,
203
+ // { ...options, context: `${context} (After Undo)` }
204
+ // );
205
+
206
+ // // Mark that we performed an undo and return the corrected result
207
+ // correctedResult.undoPerformed = true;
208
+ // correctedResult.undoneOperation = lastOp;
209
+
210
+ // // Clear the undo flag before returning
211
+ // this.isUndoInProgress = false;
212
+
213
+ // return correctedResult;
214
+ // } else {
215
+ // console.error('❌ Failed to undo operation that caused intersection');
216
+ // pathfindingResult.undoFailed = true;
217
+ // // Clear the undo flag even on failure
218
+ // this.isUndoInProgress = false;
219
+ // }
220
+ // } else {
221
+ // console.warn('⚠️ No operation in history to undo');
222
+ // this.isUndoInProgress = false;
223
+ // }
224
+ // } else {
225
+ // console.error('❌ OperationHistoryManager not available for undo');
226
+ // console.error(' Available managers:', Object.keys(this.sceneViewer?.managers || {}));
227
+ // this.isUndoInProgress = false;
228
+ // }
229
+ // } else if (intersectionCheck.hasIntersections && this.isUndoInProgress) {
230
+ // console.log('⏭️ Skipping intersection handling - undo already in progress');
231
+ // }
205
232
 
206
- // Now remove the buggy computed objects that were created with the invalid state
207
- console.log('🗑️ Removing buggy computed objects after undo...');
208
- this.removeComputedObjects();
209
-
210
- // Re-run pathfinding after undo to restore valid state
211
- console.log('🔄 Re-running pathfinding after undo to restore clean state...');
212
-
213
- // Recursively call _executePathfinding with the corrected scene state
214
- // This is safe because we've undone the operation, so we won't get into an infinite loop
215
- _context.n = 1;
216
- return this._executePathfinding(sceneData, connections, _objectSpread2(_objectSpread2({}, options), {}, {
217
- context: "".concat(context, " (After Undo)")
218
- }));
219
- case 1:
220
- correctedResult = _context.v;
221
- // Mark that we performed an undo and return the corrected result
222
- correctedResult.undoPerformed = true;
223
- correctedResult.undoneOperation = lastOp;
224
-
225
- // Clear the undo flag before returning
226
- this.isUndoInProgress = false;
227
- return _context.a(2, correctedResult);
228
- case 2:
229
- console.error('❌ Failed to undo operation that caused intersection');
230
- pathfindingResult.undoFailed = true;
231
- // Clear the undo flag even on failure
232
- this.isUndoInProgress = false;
233
- case 3:
234
- _context.n = 5;
235
- break;
236
- case 4:
237
- console.warn('⚠️ No operation in history to undo');
238
- this.isUndoInProgress = false;
239
- case 5:
240
- _context.n = 7;
241
- break;
242
- case 6:
243
- console.error('❌ OperationHistoryManager not available for undo');
244
- console.error(' Available managers:', Object.keys(((_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.managers) || {}));
245
- this.isUndoInProgress = false;
246
- case 7:
247
- _context.n = 9;
248
- break;
249
- case 8:
250
- if (intersectionCheck.hasIntersections && this.isUndoInProgress) {
251
- console.log('⏭️ Skipping intersection handling - undo already in progress');
252
- }
253
- case 9:
254
233
  // Create gateways in the scene if requested
255
234
  if (options.createGateways && pathfindingResult.gateways) {
256
235
  this.renderingManager.createGateways(pathfindingResult);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2112-lab/central-plant",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "description": "Utility modules for the Central Plant Application",
5
5
  "main": "dist/bundle/index.js",
6
6
  "module": "dist/esm/index.js",