@2112-lab/central-plant 0.1.39 → 0.1.41

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.
Files changed (45) hide show
  1. package/dist/bundle/index.js +7991 -7054
  2. package/dist/cjs/src/core/centralPlant.js +48 -3
  3. package/dist/cjs/src/core/centralPlantInternals.js +75 -566
  4. package/dist/cjs/src/core/sceneViewer.js +38 -13
  5. package/dist/cjs/src/index.js +6 -4
  6. package/dist/cjs/src/managers/components/pathfindingManager.js +75 -60
  7. package/dist/cjs/src/managers/components/transformOperationsManager.js +929 -0
  8. package/dist/cjs/src/managers/controls/keyboardControlsManager.js +57 -1
  9. package/dist/cjs/src/managers/controls/transformControls.js +11 -3
  10. package/dist/cjs/src/managers/controls/transformControlsManager.js +563 -263
  11. package/dist/cjs/src/managers/pathfinding/ConnectorManager.js +385 -0
  12. package/dist/cjs/src/managers/pathfinding/PathIntersectionDetector.js +387 -0
  13. package/dist/cjs/src/managers/pathfinding/PathRenderingManager.js +401 -0
  14. package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +378 -0
  15. package/dist/cjs/src/managers/pathfinding/sceneDataManager.js +256 -0
  16. package/dist/cjs/src/managers/scene/animationManager.js +145 -0
  17. package/dist/cjs/src/managers/scene/sceneExportManager.js +14 -13
  18. package/dist/cjs/src/managers/scene/sceneOperationsManager.js +516 -21
  19. package/dist/cjs/src/managers/scene/sceneTooltipsManager.js +1 -8
  20. package/dist/cjs/src/managers/system/operationHistoryManager.js +414 -0
  21. package/dist/cjs/src/managers/system/settingsManager.js +2 -1
  22. package/dist/cjs/src/utils/objectTypes.js +5 -7
  23. package/dist/esm/src/core/centralPlant.js +48 -3
  24. package/dist/esm/src/core/centralPlantInternals.js +76 -567
  25. package/dist/esm/src/core/sceneViewer.js +38 -13
  26. package/dist/esm/src/index.js +4 -3
  27. package/dist/esm/src/managers/components/pathfindingManager.js +75 -60
  28. package/dist/esm/src/managers/components/transformOperationsManager.js +904 -0
  29. package/dist/esm/src/managers/controls/keyboardControlsManager.js +57 -1
  30. package/dist/esm/src/managers/controls/transformControls.js +11 -3
  31. package/dist/esm/src/managers/controls/transformControlsManager.js +564 -264
  32. package/dist/esm/src/managers/pathfinding/ConnectorManager.js +361 -0
  33. package/dist/esm/src/managers/pathfinding/PathIntersectionDetector.js +363 -0
  34. package/dist/esm/src/managers/pathfinding/PathRenderingManager.js +377 -0
  35. package/dist/esm/src/managers/pathfinding/pathfindingManager.js +374 -0
  36. package/dist/esm/src/managers/pathfinding/sceneDataManager.js +232 -0
  37. package/dist/esm/src/managers/scene/animationManager.js +141 -0
  38. package/dist/esm/src/managers/scene/sceneExportManager.js +14 -13
  39. package/dist/esm/src/managers/scene/sceneOperationsManager.js +516 -21
  40. package/dist/esm/src/managers/scene/sceneTooltipsManager.js +1 -8
  41. package/dist/esm/src/managers/system/operationHistoryManager.js +409 -0
  42. package/dist/esm/src/managers/system/settingsManager.js +2 -1
  43. package/dist/esm/src/utils/objectTypes.js +5 -7
  44. package/dist/index.d.ts +2 -2
  45. package/package.json +1 -1
@@ -345,11 +345,6 @@ var SceneOperationsManager = /*#__PURE__*/function () {
345
345
  // If a gateway appears in the JSON, it's manual by definition
346
346
  mesh.userData.isDeclared = true;
347
347
  }
348
-
349
- // For gateways, also set origin flag for backward compatibility
350
- if (mesh.userData.objectType === 'gateway') {
351
- mesh.userData.origin = 'declared'; // Explicit origin marker for manual gateways
352
- }
353
348
  if (mesh.isMesh) {
354
349
  mesh.castShadow = true;
355
350
  mesh.receiveShadow = true;
@@ -440,6 +435,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
440
435
  // Check if we have crosscubeTextureSet from scene loading
441
436
  var crosscubeTextureSet = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.crosscubeTextureSet;
442
437
  if (crosscubeTextureSet) {
438
+ // Match PathfindingManager.createPipeMaterial() with textures
443
439
  var pathColor = '#245e29'; // Default green color from PathfindingManager.getPathColor()
444
440
 
445
441
  var materialProps = _objectSpread2(_objectSpread2({}, crosscubeTextureSet.config.materialProps), {}, {
@@ -490,7 +486,6 @@ var SceneOperationsManager = /*#__PURE__*/function () {
490
486
  // Initialize userData
491
487
  segmentMesh.userData = _objectSpread2(_objectSpread2({}, obj.userData), {}, {
492
488
  originalUuid: obj.uuid,
493
- isPipeSegment: true,
494
489
  isDeclared: true
495
490
  });
496
491
 
@@ -563,7 +558,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
563
558
  }
564
559
  _connectorMesh.userData = _objectSpread2(_objectSpread2({}, connectorData.userData), {}, {
565
560
  originalUuid: connectorData.uuid,
566
- objectType: 'connector',
561
+ objectType: 'segment-connector',
567
562
  isManualSegmentConnector: true,
568
563
  isDeclared: true // Manual segment connectors are always declared (user-created)
569
564
  });
@@ -583,7 +578,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
583
578
  // Initialize userData
584
579
  connectorMesh.userData = _objectSpread2(_objectSpread2({}, connectorData.userData), {}, {
585
580
  originalUuid: connectorData.uuid,
586
- objectType: 'connector',
581
+ objectType: 'segment-connector',
587
582
  isManualSegmentConnector: true,
588
583
  isDeclared: true // Manual segment connectors are always declared (user-created)
589
584
  });
@@ -655,18 +650,15 @@ var SceneOperationsManager = /*#__PURE__*/function () {
655
650
  jsonObject.userData.position = [worldPos.x, worldPos.y, worldPos.z];
656
651
  console.log("\u2705 Set userData.position for ".concat(jsonObject.userData.objectType, " ").concat(jsonObject.uuid, ": [").concat(worldPos.x.toFixed(2), ", ").concat(worldPos.y.toFixed(2), ", ").concat(worldPos.z.toFixed(2), "]"));
657
652
 
658
- // For gateways, ensure origin and isDeclared flags are in scene data
653
+ // For gateways, ensure isDeclared flag is in scene data
659
654
  if (jsonObject.userData.objectType === 'gateway') {
660
- if (!jsonObject.userData.origin) {
661
- jsonObject.userData.origin = 'declared'; // Mark as declared gateway
662
- }
663
655
  if (jsonObject.userData.isDeclared === undefined) {
664
656
  jsonObject.userData.isDeclared = true;
665
657
  }
666
658
  }
667
659
 
668
660
  // For manual segment connectors, ensure isDeclared is set in scene data
669
- if (jsonObject.userData.isManualSegmentConnector && jsonObject.userData.isDeclared === undefined) {
661
+ if (jsonObject.userData.objectType === 'segment-connector' && jsonObject.userData.isDeclared === undefined) {
670
662
  jsonObject.userData.isDeclared = true;
671
663
  console.log("\u2705 Set isDeclared=true for manual segment connector in scene data: ".concat(jsonObject.uuid));
672
664
  }
@@ -760,6 +752,9 @@ var SceneOperationsManager = /*#__PURE__*/function () {
760
752
  _context5.n = 1;
761
753
  return this.clearSceneObjects();
762
754
  case 1:
755
+ // Mark all imported objects as declared in the scene data
756
+ // This ensures manual segment connectors and other objects are recognized as declared
757
+ this._markImportedObjectsAsDeclared(data);
763
758
  component.currentSceneData = data;
764
759
  case 2:
765
760
  return _context5.a(2);
@@ -771,19 +766,55 @@ var SceneOperationsManager = /*#__PURE__*/function () {
771
766
  }
772
767
  return _prepareSceneForLoading;
773
768
  }()
769
+ /**
770
+ * Recursively mark all objects in imported scene data as declared
771
+ * This ensures that manual segments and their connectors are properly recognized
772
+ * @param {Object} data - Scene data object
773
+ */
774
+ )
775
+ }, {
776
+ key: "_markImportedObjectsAsDeclared",
777
+ value: function _markImportedObjectsAsDeclared(data) {
778
+ var _data$scene;
779
+ if (!(data !== null && data !== void 0 && (_data$scene = data.scene) !== null && _data$scene !== void 0 && _data$scene.children)) {
780
+ return;
781
+ }
782
+ var _markChildren = function markChildren(children) {
783
+ if (!Array.isArray(children)) {
784
+ return;
785
+ }
786
+ children.forEach(function (child) {
787
+ if (!child.userData) {
788
+ child.userData = {};
789
+ }
790
+
791
+ // Set isDeclared to true for all imported objects
792
+ if (child.userData.isDeclared === undefined) {
793
+ child.userData.isDeclared = true;
794
+ }
795
+
796
+ // Recursively process children (e.g., manual segment connectors)
797
+ if (child.children && Array.isArray(child.children)) {
798
+ _markChildren(child.children);
799
+ }
800
+ });
801
+ };
802
+ _markChildren(data.scene.children);
803
+ console.log('✅ Marked all imported objects as declared in scene data');
804
+ }
805
+
774
806
  /**
775
807
  * Inject connector children from component dictionary into scene data components
776
808
  * This allows scene files to omit connector children since they're defined in the dictionary
777
809
  * @param {Object} data - Scene data to modify
778
810
  * @param {Object} componentDictionary - Component dictionary with connector definitions
779
811
  */
780
- )
781
812
  }, {
782
813
  key: "_injectConnectorChildrenFromDictionary",
783
814
  value: function _injectConnectorChildrenFromDictionary(data, componentDictionary) {
784
- var _data$scene,
815
+ var _data$scene2,
785
816
  _this3 = this;
786
- if (!(data !== null && data !== void 0 && (_data$scene = data.scene) !== null && _data$scene !== void 0 && _data$scene.children) || !componentDictionary) {
817
+ if (!(data !== null && data !== void 0 && (_data$scene2 = data.scene) !== null && _data$scene2 !== void 0 && _data$scene2.children) || !componentDictionary) {
787
818
  return;
788
819
  }
789
820
  var componentsProcessed = 0;
@@ -1083,7 +1114,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1083
1114
  key: "loadSceneFromData",
1084
1115
  value: (function () {
1085
1116
  var _loadSceneFromData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9(data) {
1086
- var _data$scene2, _data$scene3, _data$scene4, _data$scene5;
1117
+ var _data$scene3, _data$scene4, _data$scene5, _data$scene6;
1087
1118
  return _regenerator().w(function (_context9) {
1088
1119
  while (1) switch (_context9.n) {
1089
1120
  case 0:
@@ -1093,10 +1124,10 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1093
1124
  dataType: _typeof(data),
1094
1125
  hasScene: !!(data !== null && data !== void 0 && data.scene),
1095
1126
  sceneType: _typeof(data === null || data === void 0 ? void 0 : data.scene),
1096
- hasChildren: !!(data !== null && data !== void 0 && (_data$scene2 = data.scene) !== null && _data$scene2 !== void 0 && _data$scene2.children),
1097
- childrenType: data !== null && data !== void 0 && (_data$scene3 = data.scene) !== null && _data$scene3 !== void 0 && _data$scene3.children ? _typeof(data.scene.children) : 'undefined',
1098
- isArray: Array.isArray(data === null || data === void 0 || (_data$scene4 = data.scene) === null || _data$scene4 === void 0 ? void 0 : _data$scene4.children),
1099
- childrenLength: data === null || data === void 0 || (_data$scene5 = data.scene) === null || _data$scene5 === void 0 || (_data$scene5 = _data$scene5.children) === null || _data$scene5 === void 0 ? void 0 : _data$scene5.length,
1127
+ hasChildren: !!(data !== null && data !== void 0 && (_data$scene3 = data.scene) !== null && _data$scene3 !== void 0 && _data$scene3.children),
1128
+ childrenType: data !== null && data !== void 0 && (_data$scene4 = data.scene) !== null && _data$scene4 !== void 0 && _data$scene4.children ? _typeof(data.scene.children) : 'undefined',
1129
+ isArray: Array.isArray(data === null || data === void 0 || (_data$scene5 = data.scene) === null || _data$scene5 === void 0 ? void 0 : _data$scene5.children),
1130
+ childrenLength: data === null || data === void 0 || (_data$scene6 = data.scene) === null || _data$scene6 === void 0 || (_data$scene6 = _data$scene6.children) === null || _data$scene6 === void 0 ? void 0 : _data$scene6.length,
1100
1131
  dataKeys: data ? Object.keys(data) : [],
1101
1132
  sceneKeys: data !== null && data !== void 0 && data.scene ? Object.keys(data.scene) : []
1102
1133
  });
@@ -1281,6 +1312,470 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1281
1312
  return false;
1282
1313
  }
1283
1314
  }
1315
+
1316
+ // ===== MANUAL SEGMENT AND GATEWAY OPERATIONS =====
1317
+
1318
+ /**
1319
+ * Handle manual segment transformation by creating connectors and restructuring connections
1320
+ * @param {THREE.Object3D} segment - The transformed pipe segment
1321
+ * @param {Object} currentSceneData - Current scene data with connections
1322
+ */
1323
+ }, {
1324
+ key: "manualizeSegment",
1325
+ value: function manualizeSegment(segment, currentSceneData) {
1326
+ var _segment$userData, _this$sceneViewer$man;
1327
+ if (!segment || !((_segment$userData = segment.userData) !== null && _segment$userData !== void 0 && _segment$userData.objectType) === 'segment') {
1328
+ console.log('❌ Object is not a pipe segment:', {
1329
+ isObject: !!segment,
1330
+ hasUserData: !!(segment && segment.userData)
1331
+ });
1332
+ return;
1333
+ }
1334
+ console.log('🔧 Handling manual segment transformation:', segment.uuid);
1335
+
1336
+ // Get access to pathfinding manager's connector manager
1337
+ var pathfindingManager = (_this$sceneViewer$man = this.sceneViewer.managers) === null || _this$sceneViewer$man === void 0 ? void 0 : _this$sceneViewer$man.pathfindingManager;
1338
+ if (!pathfindingManager || !pathfindingManager.connectorManager) {
1339
+ console.error('❌ PathfindingManager or ConnectorManager not available');
1340
+ return;
1341
+ }
1342
+ var connectorManager = pathfindingManager.connectorManager;
1343
+ var sceneDataManager = pathfindingManager.sceneDataManager;
1344
+
1345
+ // IMPORTANT: Rename UUID FIRST to prevent removal by removeComputedObjects()
1346
+ // This must happen before convertConnectedGatewaysToManual() which triggers path regeneration
1347
+ // Change from "SEGMENT-X" to "Segment-X" (capital S to lowercase s)
1348
+ var segmentIndex = segment.userData.segmentIndex;
1349
+ var oldUuid = segment.uuid;
1350
+ segment.uuid = "Segment-".concat(segmentIndex);
1351
+ console.log("\uD83D\uDD27 Renamed segment UUID from ".concat(oldUuid, " to: ").concat(segment.uuid));
1352
+
1353
+ // Calculate segment endpoints in world coordinates
1354
+ var segmentEndpoints = connectorManager.calculateSegmentEndpoints(segment);
1355
+ console.log('📍 Segment endpoints:', segmentEndpoints);
1356
+
1357
+ // Create connectors at the segment endpoints
1358
+ var connectors = connectorManager.createSegmentConnectors(segment, segmentEndpoints);
1359
+ console.log('🔌 Created connectors:', connectors);
1360
+
1361
+ // IMPORTANT: Mark segment as declared FIRST to ensure it exists in scene data
1362
+ // This must happen BEFORE addConnectorsToScene so connectors have a parent to attach to
1363
+ segment.userData.manualConnectors = connectors.map(function (c) {
1364
+ return c.uuid;
1365
+ });
1366
+ sceneDataManager.markObjectAsDeclared(segment, currentSceneData, {});
1367
+ console.log('✅ Segment marked as declared in scene data');
1368
+
1369
+ // Now add connectors to the segment's children array in scene data
1370
+ connectorManager.addConnectorsToScene(connectors);
1371
+
1372
+ // Find the original connection that this segment belongs to (after gateways are converted)
1373
+ var originalConnection = connectorManager.findOriginalConnection(segment, currentSceneData.connections);
1374
+ if (!originalConnection) {
1375
+ console.warn('⚠️ Could not find original connection for segment:', segment.uuid);
1376
+ return;
1377
+ }
1378
+ console.log('🔍 Found original connection:', originalConnection);
1379
+ var authoritativeConnectorUUID = originalConnection.from.includes("Gateway") === false ? originalConnection.from : originalConnection.to;
1380
+ console.log('[SceneOperations] authoritativeConnectorUUID:', authoritativeConnectorUUID);
1381
+
1382
+ // Check and convert connected gateways to manual (declared)
1383
+ // NOTE: This may trigger path regeneration via translateGateway, so segment must already be renamed
1384
+ var convertedGatewayUUIDs = this._convertConnectedGatewaysToManual(connectors, currentSceneData);
1385
+
1386
+ // Restructure connections, passing any converted gateway UUIDs
1387
+ connectorManager.restructureConnections(authoritativeConnectorUUID, connectors, currentSceneData, convertedGatewayUUIDs);
1388
+
1389
+ // Mark segment as manually positioned and declared
1390
+ segment.userData.manualConnectors = connectors.map(function (c) {
1391
+ return c.uuid;
1392
+ });
1393
+
1394
+ // Use shared helper to mark as declared and add to scene data
1395
+ sceneDataManager.markObjectAsDeclared(segment, currentSceneData, {});
1396
+
1397
+ // Verify segment structure in scene data
1398
+ var segmentInSceneData = currentSceneData.scene.children.find(function (child) {
1399
+ return child.uuid === segment.uuid;
1400
+ });
1401
+ if (segmentInSceneData) {
1402
+ var _segmentInSceneData$c, _segmentInSceneData$c2;
1403
+ console.log("\uD83D\uDCCA Segment in scene data:", {
1404
+ uuid: segmentInSceneData.uuid,
1405
+ hasChildren: !!segmentInSceneData.children,
1406
+ childrenCount: ((_segmentInSceneData$c = segmentInSceneData.children) === null || _segmentInSceneData$c === void 0 ? void 0 : _segmentInSceneData$c.length) || 0,
1407
+ childrenUUIDs: ((_segmentInSceneData$c2 = segmentInSceneData.children) === null || _segmentInSceneData$c2 === void 0 ? void 0 : _segmentInSceneData$c2.map(function (c) {
1408
+ return c.uuid;
1409
+ })) || []
1410
+ });
1411
+ }
1412
+ console.log('✅ Manual segment transformation completed');
1413
+ }
1414
+
1415
+ /**
1416
+ * Check and convert gateways at the original path endpoints to manual (declared)
1417
+ * This method now delegates to manualizeGateway to ensure consistent gateway handling
1418
+ * @param {Array} connectors - Array of connector objects (used to get segment reference)
1419
+ * @param {Object} currentSceneData - Current scene data
1420
+ * @returns {Array<string>} Array of converted gateway UUIDs
1421
+ * @private
1422
+ */
1423
+ }, {
1424
+ key: "_convertConnectedGatewaysToManual",
1425
+ value: function _convertConnectedGatewaysToManual(connectors, currentSceneData) {
1426
+ var _connectors$,
1427
+ _segment$userData2,
1428
+ _this5 = this;
1429
+ console.log('🔍 Checking for connected gateways to convert to manual...');
1430
+ var sceneViewer = this.sceneViewer;
1431
+ var convertedGateways = [];
1432
+
1433
+ // Get the segment from the first connector's userData
1434
+ var segment = (_connectors$ = connectors[0]) !== null && _connectors$ !== void 0 && (_connectors$ = _connectors$.userData) !== null && _connectors$ !== void 0 && _connectors$.manualSegmentUuid ? sceneViewer.scene.getObjectByProperty('uuid', connectors[0].userData.manualSegmentUuid) : null;
1435
+ if (!segment || !((_segment$userData2 = segment.userData) !== null && _segment$userData2 !== void 0 && _segment$userData2.objectType) === 'segment') {
1436
+ console.log('❌ Could not find segment for gateway conversion');
1437
+ return [];
1438
+ }
1439
+ var pathFrom = segment.userData.pathFrom;
1440
+ var pathTo = segment.userData.pathTo;
1441
+ console.log("\uD83D\uDD0D Checking original path endpoints for gateways: ".concat(pathFrom, " \u2192 ").concat(pathTo));
1442
+
1443
+ // Check the original path endpoints for gateways
1444
+ [pathFrom, pathTo].forEach(function (endpointUuid) {
1445
+ console.log("\uD83D\uDD0D Checking endpoint: ".concat(endpointUuid));
1446
+
1447
+ // Find the object in the scene that corresponds to this endpoint
1448
+ var endpointObject = null;
1449
+ sceneViewer.scene.traverse(function (obj) {
1450
+ var _obj$userData3;
1451
+ if (obj.uuid === endpointUuid || ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.originalUuid) === endpointUuid) {
1452
+ endpointObject = obj;
1453
+ }
1454
+ });
1455
+ if (endpointObject) {
1456
+ var _endpointObject$userD, _endpointObject$userD2, _endpointObject$userD3, _endpointObject$userD4, _endpointObject$userD5, _endpointObject$userD6;
1457
+ console.log("\uD83D\uDD0D Found endpoint object: ".concat(endpointObject.uuid, " - objectType: ").concat((_endpointObject$userD = endpointObject.userData) === null || _endpointObject$userD === void 0 ? void 0 : _endpointObject$userD.objectType, ", isDeclared: ").concat((_endpointObject$userD2 = endpointObject.userData) === null || _endpointObject$userD2 === void 0 ? void 0 : _endpointObject$userD2.isDeclared));
1458
+
1459
+ // Check if this endpoint is a gateway that needs to be converted to manual
1460
+ // IMPORTANT: Only convert if it's NOT already declared to prevent double-processing
1461
+ if (((_endpointObject$userD3 = endpointObject.userData) === null || _endpointObject$userD3 === void 0 ? void 0 : _endpointObject$userD3.objectType) === 'gateway' && ((_endpointObject$userD4 = endpointObject.userData) === null || _endpointObject$userD4 === void 0 ? void 0 : _endpointObject$userD4.isDeclared) !== true) {
1462
+ console.log("\uD83D\uDD27 Found computed gateway at endpoint: ".concat(endpointObject.uuid, " - converting to manual"));
1463
+
1464
+ // Convert gateway to manual (declared) using manualizeGateway for consistency
1465
+ _this5.manualizeGateway(endpointObject, currentSceneData);
1466
+ convertedGateways.push(endpointObject);
1467
+ } else if (((_endpointObject$userD5 = endpointObject.userData) === null || _endpointObject$userD5 === void 0 ? void 0 : _endpointObject$userD5.objectType) === 'gateway' && ((_endpointObject$userD6 = endpointObject.userData) === null || _endpointObject$userD6 === void 0 ? void 0 : _endpointObject$userD6.isDeclared) === true) {
1468
+ console.log("\u2139\uFE0F Gateway ".concat(endpointObject.uuid, " is already declared (manual), skipping conversion"));
1469
+ }
1470
+ } else {
1471
+ console.log("\u26A0\uFE0F Could not find object for endpoint: ".concat(endpointUuid));
1472
+ }
1473
+ });
1474
+ if (convertedGateways.length > 0) {
1475
+ console.log("\u2705 Converted ".concat(convertedGateways.length, " gateways to manual:"), convertedGateways.map(function (g) {
1476
+ return g.uuid;
1477
+ }));
1478
+ } else {
1479
+ console.log('ℹ️ No computed gateways found to convert (all may already be declared)');
1480
+ }
1481
+
1482
+ // Return array of gateway UUIDs
1483
+ return convertedGateways.map(function (g) {
1484
+ return g.uuid;
1485
+ });
1486
+ }
1487
+
1488
+ /**
1489
+ * Handle manual gateway transformation by converting it to declared status and processing connections
1490
+ * @param {THREE.Object3D} gateway - The transformed gateway object
1491
+ * @param {Object} currentSceneData - Current scene data with connections
1492
+ */
1493
+ }, {
1494
+ key: "manualizeGateway",
1495
+ value: function manualizeGateway(gateway, currentSceneData) {
1496
+ var _this$sceneViewer$man2;
1497
+ console.log("[SceneOperations] manualizeGateway started:", gateway);
1498
+ if (!gateway || !gateway.userData || gateway.userData.objectType !== 'gateway') {
1499
+ console.log('❌ Object is not a gateway:', {
1500
+ isObject: !!gateway,
1501
+ hasUserData: !!(gateway && gateway.userData)
1502
+ });
1503
+ return;
1504
+ }
1505
+ console.log('🔧 Handling manual gateway transformation:', gateway.uuid);
1506
+
1507
+ // Get access to pathfinding manager's scene data manager
1508
+ var pathfindingManager = (_this$sceneViewer$man2 = this.sceneViewer.managers) === null || _this$sceneViewer$man2 === void 0 ? void 0 : _this$sceneViewer$man2.pathfindingManager;
1509
+ if (!pathfindingManager || !pathfindingManager.sceneDataManager) {
1510
+ console.error('❌ PathfindingManager or SceneDataManager not available');
1511
+ return;
1512
+ }
1513
+ var sceneDataManager = pathfindingManager.sceneDataManager;
1514
+
1515
+ // IMPORTANT: Check if gateway is already declared to prevent double-processing of connections
1516
+ if (gateway.userData.isDeclared === true) {
1517
+ console.log("\u2139\uFE0F Gateway ".concat(gateway.uuid, " is already declared (manual)"));
1518
+
1519
+ // Update position in scene data for subsequent moves
1520
+ sceneDataManager.markObjectAsDeclared(gateway, currentSceneData, {});
1521
+ console.log('✅ Updated gateway position in scene data');
1522
+ return;
1523
+ }
1524
+
1525
+ // Convert gateway from computed to declared status (first-time manualization)
1526
+ console.log('🔧 Converting gateway to declared status via convertGatewayToManual');
1527
+ this.convertGatewayToManual(gateway, currentSceneData);
1528
+ console.log('✅ Manual gateway transformation completed');
1529
+ }
1530
+
1531
+ /**
1532
+ * Convert a gateway from computed to manual (declared) - reusing logic from sceneOperationsManager
1533
+ * @param {THREE.Object3D} gateway - The gateway object to convert
1534
+ * @param {Object} currentSceneData - Current scene data
1535
+ */
1536
+ }, {
1537
+ key: "convertGatewayToManual",
1538
+ value: function convertGatewayToManual(gateway, currentSceneData) {
1539
+ var _this$sceneViewer$man3, _gateway$userData;
1540
+ console.log("\uD83D\uDD27 Converting gateway from computed to declared: ".concat(gateway.uuid, " (").concat(gateway.uuid, ")"));
1541
+ console.log("[SceneOperations] currentSceneData:", currentSceneData);
1542
+
1543
+ // Get access to pathfinding manager's scene data manager
1544
+ var pathfindingManager = (_this$sceneViewer$man3 = this.sceneViewer.managers) === null || _this$sceneViewer$man3 === void 0 ? void 0 : _this$sceneViewer$man3.pathfindingManager;
1545
+ if (!pathfindingManager || !pathfindingManager.sceneDataManager) {
1546
+ console.error('❌ PathfindingManager or SceneDataManager not available');
1547
+ return;
1548
+ }
1549
+ var sceneDataManager = pathfindingManager.sceneDataManager;
1550
+
1551
+ // Use shared helper to mark as declared
1552
+ sceneDataManager.markObjectAsDeclared(gateway, currentSceneData, {});
1553
+
1554
+ // Process gateway connections (same logic as in sceneOperationsManager)
1555
+ if ((_gateway$userData = gateway.userData) !== null && _gateway$userData !== void 0 && _gateway$userData.connections && currentSceneData.connections) {
1556
+ console.log('🔗 Processing gateway connections for filtering:', gateway.userData.connections);
1557
+ var gatewayConnections = gateway.userData.connections;
1558
+
1559
+ // Filter out removed connections (creates new array, doesn't mutate)
1560
+ if (gatewayConnections.removed && Array.isArray(gatewayConnections.removed)) {
1561
+ console.log('🗑️ Filtering out removed connections:', gatewayConnections.removed);
1562
+ currentSceneData.connections = currentSceneData.connections.filter(function (connection) {
1563
+ var isRemoved = gatewayConnections.removed.some(function (removedConn) {
1564
+ return removedConn.from === connection.from && removedConn.to === connection.to || removedConn.from === connection.to && removedConn.to === connection.from;
1565
+ });
1566
+ if (isRemoved) {
1567
+ console.log("\uD83D\uDDD1\uFE0F Removed connection: ".concat(connection.from, " \u2192 ").concat(connection.to));
1568
+ }
1569
+ return !isRemoved;
1570
+ });
1571
+ }
1572
+
1573
+ // Add new connections (deep copy to prevent reference issues)
1574
+ if (gatewayConnections.added && Array.isArray(gatewayConnections.added)) {
1575
+ console.log('➕ Adding new connections:', gatewayConnections.added);
1576
+ gatewayConnections.added.forEach(function (newConnection) {
1577
+ // Check if connection already exists to avoid duplicates
1578
+ var alreadyExists = currentSceneData.connections.some(function (conn) {
1579
+ return conn.from === newConnection.from && conn.to === newConnection.to || conn.from === newConnection.to && conn.to === newConnection.from;
1580
+ });
1581
+ if (!alreadyExists) {
1582
+ // Deep copy the connection object to prevent reference issues
1583
+ currentSceneData.connections.push(_objectSpread2({}, newConnection));
1584
+ console.log("\u2795 Added new connection: ".concat(newConnection.from, " \u2192 ").concat(newConnection.to));
1585
+ } else {
1586
+ console.log("\u26A0\uFE0F Connection already exists, skipping: ".concat(newConnection.from, " \u2192 ").concat(newConnection.to));
1587
+ }
1588
+ });
1589
+ }
1590
+ console.log('✅ Gateway connections processing completed. Total connections:', currentSceneData.connections.length);
1591
+ }
1592
+ console.log("\u2705 Gateway ".concat(gateway.uuid, " successfully converted to manual (declared)"));
1593
+ }
1594
+
1595
+ /**
1596
+ * Split a pipe segment in half at its midpoint
1597
+ * Creates two simple pipe meshes without manualization
1598
+ * @param {string|THREE.Object3D} segmentIdOrObject - The UUID or Three.js object of the segment to split
1599
+ * @returns {Object|null} Object with the two new segments {segment1, segment2} or null on failure
1600
+ */
1601
+ }, {
1602
+ key: "splitSegment",
1603
+ value: function splitSegment(segmentIdOrObject) {
1604
+ var _segment$userData3,
1605
+ _this6 = this;
1606
+ console.log('✂️ splitSegment started:', segmentIdOrObject);
1607
+
1608
+ // Find the segment object
1609
+ var segment = null;
1610
+ if (typeof segmentIdOrObject === 'string') {
1611
+ this.sceneViewer.scene.traverse(function (child) {
1612
+ var _child$userData10;
1613
+ if (child.uuid === segmentIdOrObject || ((_child$userData10 = child.userData) === null || _child$userData10 === void 0 ? void 0 : _child$userData10.originalUuid) === segmentIdOrObject) {
1614
+ segment = child;
1615
+ }
1616
+ });
1617
+ } else if (segmentIdOrObject && segmentIdOrObject.isObject3D) {
1618
+ segment = segmentIdOrObject;
1619
+ }
1620
+
1621
+ // Validate segment
1622
+ if (!segment || ((_segment$userData3 = segment.userData) === null || _segment$userData3 === void 0 ? void 0 : _segment$userData3.objectType) !== 'segment') {
1623
+ console.error('❌ splitSegment(): Invalid segment or not found');
1624
+ return null;
1625
+ }
1626
+ console.log('✂️ Splitting segment:', segment.uuid);
1627
+
1628
+ // Get segment geometry to calculate split point
1629
+ var geometry = segment.geometry;
1630
+ if (!geometry || !geometry.parameters) {
1631
+ console.error('❌ splitSegment(): Segment has invalid geometry');
1632
+ return null;
1633
+ }
1634
+ var segmentLength = geometry.parameters.height || 1;
1635
+ var segmentRadius = geometry.parameters.radiusTop || 0.1;
1636
+
1637
+ // Calculate segment direction vector
1638
+ var direction = new THREE.Vector3(0, 1, 0);
1639
+ direction.applyQuaternion(segment.quaternion);
1640
+ direction.normalize();
1641
+
1642
+ // Calculate segment endpoints
1643
+ var startPoint = new THREE.Vector3();
1644
+ startPoint.copy(segment.position).sub(direction.clone().multiplyScalar(segmentLength / 2));
1645
+ var endPoint = new THREE.Vector3();
1646
+ endPoint.copy(segment.position).add(direction.clone().multiplyScalar(segmentLength / 2));
1647
+
1648
+ // Check for component connectors at endpoints
1649
+ var findConnectorsAtPosition = function findConnectorsAtPosition(position) {
1650
+ var tolerance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.15;
1651
+ var connectors = [];
1652
+ _this6.sceneViewer.scene.traverse(function (child) {
1653
+ var _child$userData11;
1654
+ if (((_child$userData11 = child.userData) === null || _child$userData11 === void 0 ? void 0 : _child$userData11.objectType) === 'connector') {
1655
+ var connectorWorldPos = new THREE.Vector3();
1656
+ child.getWorldPosition(connectorWorldPos);
1657
+ var distance = connectorWorldPos.distanceTo(position);
1658
+ if (distance <= tolerance) {
1659
+ connectors.push(child);
1660
+ }
1661
+ }
1662
+ });
1663
+ return connectors.filter(function (c) {
1664
+ var _c$userData;
1665
+ return ((_c$userData = c.userData) === null || _c$userData === void 0 ? void 0 : _c$userData.objectType) !== 'segment-connector';
1666
+ });
1667
+ };
1668
+ var startConnectors = findConnectorsAtPosition(startPoint);
1669
+ var endConnectors = findConnectorsAtPosition(endPoint);
1670
+
1671
+ // Determine split position: 0.5 on component connector side, remaining on free side
1672
+ var segment1Length, segment2Length, splitPoint;
1673
+ var fixedLength = 0.5; // Fixed length for component connector side
1674
+
1675
+ if (startConnectors.length > 0) {
1676
+ // Component connector at start - make segment1 = 0.5, segment2 = remaining
1677
+ segment1Length = fixedLength;
1678
+ segment2Length = segmentLength - fixedLength;
1679
+ splitPoint = new THREE.Vector3();
1680
+ splitPoint.copy(startPoint).add(direction.clone().multiplyScalar(fixedLength));
1681
+ console.log("\uD83D\uDCCD Component connector at START - split: ".concat(segment1Length, " (start) + ").concat(segment2Length, " (end)"));
1682
+ } else if (endConnectors.length > 0) {
1683
+ // Component connector at end - make segment1 = remaining, segment2 = 0.5
1684
+ segment1Length = segmentLength - fixedLength;
1685
+ segment2Length = fixedLength;
1686
+ splitPoint = new THREE.Vector3();
1687
+ splitPoint.copy(endPoint).sub(direction.clone().multiplyScalar(fixedLength));
1688
+ console.log("\uD83D\uDCCD Component connector at END - split: ".concat(segment1Length, " (start) + ").concat(segment2Length, " (end)"));
1689
+ } else {
1690
+ // No component connectors - split at midpoint (default behavior)
1691
+ segment1Length = segmentLength / 2;
1692
+ segment2Length = segmentLength / 2;
1693
+ splitPoint = new THREE.Vector3();
1694
+ splitPoint.copy(segment.position);
1695
+ console.log("\uD83D\uDCCD No component connectors - split at midpoint: ".concat(segment1Length, " + ").concat(segment2Length));
1696
+ }
1697
+ console.log('📍 Segment split points:', {
1698
+ start: startPoint.toArray(),
1699
+ split: splitPoint.toArray(),
1700
+ end: endPoint.toArray(),
1701
+ length: segmentLength,
1702
+ segment1Length: segment1Length,
1703
+ segment2Length: segment2Length,
1704
+ originalUuid: segment.uuid
1705
+ });
1706
+
1707
+ // Get material from existing segment
1708
+ var material = segment.material;
1709
+
1710
+ // Create first segment (start to split point)
1711
+ var segment1Geometry = new THREE.CylinderGeometry(segmentRadius, segmentRadius, segment1Length, 16, 1, false);
1712
+ var segment1 = new THREE.Mesh(segment1Geometry, material);
1713
+
1714
+ // Position segment1 between start and split point
1715
+ var segment1Position = new THREE.Vector3();
1716
+ segment1Position.lerpVectors(startPoint, splitPoint, 0.5);
1717
+ segment1.position.copy(segment1Position);
1718
+ segment1.quaternion.copy(segment.quaternion);
1719
+
1720
+ // Set UUID and copy userData
1721
+ segment1.uuid = "".concat(segment.uuid, "-part1");
1722
+ segment1.userData = _objectSpread2(_objectSpread2({}, segment.userData), {}, {
1723
+ originalUuid: segment1.uuid,
1724
+ splitFromUuid: segment.uuid
1725
+ });
1726
+
1727
+ // Mark segment1 as non-selectable/non-transformable if it's the 0.5 stub
1728
+ if (startConnectors.length > 0 && segment1Length === fixedLength) {
1729
+ segment1.userData.isStub = true;
1730
+ segment1.userData.selectable = false;
1731
+ segment1.userData.transformable = false;
1732
+ console.log("\uD83D\uDD12 Segment1 marked as non-selectable stub (length: ".concat(fixedLength, ")"));
1733
+ }
1734
+
1735
+ // Create second segment (split point to end)
1736
+ var segment2Geometry = new THREE.CylinderGeometry(segmentRadius, segmentRadius, segment2Length, 16, 1, false);
1737
+ var segment2 = new THREE.Mesh(segment2Geometry, material);
1738
+
1739
+ // Position segment2 between split point and end
1740
+ var segment2Position = new THREE.Vector3();
1741
+ segment2Position.lerpVectors(splitPoint, endPoint, 0.5);
1742
+ segment2.position.copy(segment2Position);
1743
+ segment2.quaternion.copy(segment.quaternion);
1744
+
1745
+ // Set UUID and copy userData
1746
+ segment2.uuid = "".concat(segment.uuid, "-part2");
1747
+ segment2.userData = _objectSpread2(_objectSpread2({}, segment.userData), {}, {
1748
+ originalUuid: segment2.uuid,
1749
+ splitFromUuid: segment.uuid
1750
+ });
1751
+
1752
+ // Mark segment2 as non-selectable/non-transformable if it's the 0.5 stub
1753
+ if (endConnectors.length > 0 && segment2Length === fixedLength) {
1754
+ segment2.userData.isStub = true;
1755
+ segment2.userData.selectable = false;
1756
+ segment2.userData.transformable = false;
1757
+ console.log("\uD83D\uDD12 Segment2 marked as non-selectable stub (length: ".concat(fixedLength, ")"));
1758
+ }
1759
+
1760
+ // Add new segments to scene
1761
+ this.sceneViewer.scene.add(segment1);
1762
+ this.sceneViewer.scene.add(segment2);
1763
+ console.log('✅ Created two new segments:', {
1764
+ segment1: segment1.uuid,
1765
+ segment2: segment2.uuid,
1766
+ originalSegment: segment.uuid
1767
+ });
1768
+
1769
+ // Remove the original segment
1770
+ this.sceneViewer.scene.remove(segment);
1771
+ if (segment.geometry) segment.geometry.dispose();
1772
+ console.log('🗑️ Removed original segment:', segment.uuid);
1773
+ console.log('✅ Segment split completed successfully');
1774
+ return {
1775
+ segment1: segment1,
1776
+ segment2: segment2
1777
+ };
1778
+ }
1284
1779
  }]);
1285
1780
  }();
1286
1781
 
@@ -2,7 +2,6 @@ import { inherits as _inherits, createClass as _createClass, classCallCheck as _
2
2
  import { CSS2DRenderer, CSS2DObject } from '../../../node_modules/three/examples/jsm/renderers/CSS2DRenderer.js';
3
3
  import * as THREE from 'three';
4
4
  import { BaseDisposable } from '../../core/baseDisposable.js';
5
- import { isSegment } from '../../utils/objectTypes.js';
6
5
 
7
6
  // Add a simple debug logger for tooltip events
8
7
  var tooltipLogger = {
@@ -399,7 +398,7 @@ var SceneTooltipsManager = /*#__PURE__*/function (_BaseDisposable) {
399
398
  };
400
399
 
401
400
  // If transform controls are available and have a selected object
402
- if (this.transformControlsManager && this.transformControlsManager.selectedObject === this.selectedMesh) {
401
+ if (this.transformControlsManager && this.transformControlsManager.selectedObjects && this.transformControlsManager.selectedObjects.length > 0 && this.transformControlsManager.selectedObjects[0] === this.selectedMesh) {
403
402
  try {
404
403
  // Get world transform data from transform controls
405
404
  var worldTransform = this.transformControlsManager.getWorldTransformData();
@@ -608,16 +607,10 @@ var SceneTooltipsManager = /*#__PURE__*/function (_BaseDisposable) {
608
607
  }, {
609
608
  key: "isSelectableComponent",
610
609
  value: function isSelectableComponent(object) {
611
- var _object$userData;
612
610
  // Check if the object has component data
613
611
  if (object && object.userData && object.userData.component) {
614
612
  return true;
615
613
  }
616
-
617
- // Check if the object is a pipe segment or junction
618
- if (object && (isSegment(object) || (_object$userData = object.userData) !== null && _object$userData !== void 0 && _object$userData.isPipeJunction)) {
619
- return true;
620
- }
621
614
  return false;
622
615
  }
623
616
  }, {