@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
@@ -369,11 +369,6 @@ var SceneOperationsManager = /*#__PURE__*/function () {
369
369
  // If a gateway appears in the JSON, it's manual by definition
370
370
  mesh.userData.isDeclared = true;
371
371
  }
372
-
373
- // For gateways, also set origin flag for backward compatibility
374
- if (mesh.userData.objectType === 'gateway') {
375
- mesh.userData.origin = 'declared'; // Explicit origin marker for manual gateways
376
- }
377
372
  if (mesh.isMesh) {
378
373
  mesh.castShadow = true;
379
374
  mesh.receiveShadow = true;
@@ -464,6 +459,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
464
459
  // Check if we have crosscubeTextureSet from scene loading
465
460
  var crosscubeTextureSet = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.crosscubeTextureSet;
466
461
  if (crosscubeTextureSet) {
462
+ // Match PathfindingManager.createPipeMaterial() with textures
467
463
  var pathColor = '#245e29'; // Default green color from PathfindingManager.getPathColor()
468
464
 
469
465
  var materialProps = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, crosscubeTextureSet.config.materialProps), {}, {
@@ -514,7 +510,6 @@ var SceneOperationsManager = /*#__PURE__*/function () {
514
510
  // Initialize userData
515
511
  segmentMesh.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, obj.userData), {}, {
516
512
  originalUuid: obj.uuid,
517
- isPipeSegment: true,
518
513
  isDeclared: true
519
514
  });
520
515
 
@@ -587,7 +582,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
587
582
  }
588
583
  _connectorMesh.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, connectorData.userData), {}, {
589
584
  originalUuid: connectorData.uuid,
590
- objectType: 'connector',
585
+ objectType: 'segment-connector',
591
586
  isManualSegmentConnector: true,
592
587
  isDeclared: true // Manual segment connectors are always declared (user-created)
593
588
  });
@@ -607,7 +602,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
607
602
  // Initialize userData
608
603
  connectorMesh.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, connectorData.userData), {}, {
609
604
  originalUuid: connectorData.uuid,
610
- objectType: 'connector',
605
+ objectType: 'segment-connector',
611
606
  isManualSegmentConnector: true,
612
607
  isDeclared: true // Manual segment connectors are always declared (user-created)
613
608
  });
@@ -679,18 +674,15 @@ var SceneOperationsManager = /*#__PURE__*/function () {
679
674
  jsonObject.userData.position = [worldPos.x, worldPos.y, worldPos.z];
680
675
  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), "]"));
681
676
 
682
- // For gateways, ensure origin and isDeclared flags are in scene data
677
+ // For gateways, ensure isDeclared flag is in scene data
683
678
  if (jsonObject.userData.objectType === 'gateway') {
684
- if (!jsonObject.userData.origin) {
685
- jsonObject.userData.origin = 'declared'; // Mark as declared gateway
686
- }
687
679
  if (jsonObject.userData.isDeclared === undefined) {
688
680
  jsonObject.userData.isDeclared = true;
689
681
  }
690
682
  }
691
683
 
692
684
  // For manual segment connectors, ensure isDeclared is set in scene data
693
- if (jsonObject.userData.isManualSegmentConnector && jsonObject.userData.isDeclared === undefined) {
685
+ if (jsonObject.userData.objectType === 'segment-connector' && jsonObject.userData.isDeclared === undefined) {
694
686
  jsonObject.userData.isDeclared = true;
695
687
  console.log("\u2705 Set isDeclared=true for manual segment connector in scene data: ".concat(jsonObject.uuid));
696
688
  }
@@ -784,6 +776,9 @@ var SceneOperationsManager = /*#__PURE__*/function () {
784
776
  _context5.n = 1;
785
777
  return this.clearSceneObjects();
786
778
  case 1:
779
+ // Mark all imported objects as declared in the scene data
780
+ // This ensures manual segment connectors and other objects are recognized as declared
781
+ this._markImportedObjectsAsDeclared(data);
787
782
  component.currentSceneData = data;
788
783
  case 2:
789
784
  return _context5.a(2);
@@ -795,19 +790,55 @@ var SceneOperationsManager = /*#__PURE__*/function () {
795
790
  }
796
791
  return _prepareSceneForLoading;
797
792
  }()
793
+ /**
794
+ * Recursively mark all objects in imported scene data as declared
795
+ * This ensures that manual segments and their connectors are properly recognized
796
+ * @param {Object} data - Scene data object
797
+ */
798
+ )
799
+ }, {
800
+ key: "_markImportedObjectsAsDeclared",
801
+ value: function _markImportedObjectsAsDeclared(data) {
802
+ var _data$scene;
803
+ if (!(data !== null && data !== void 0 && (_data$scene = data.scene) !== null && _data$scene !== void 0 && _data$scene.children)) {
804
+ return;
805
+ }
806
+ var _markChildren = function markChildren(children) {
807
+ if (!Array.isArray(children)) {
808
+ return;
809
+ }
810
+ children.forEach(function (child) {
811
+ if (!child.userData) {
812
+ child.userData = {};
813
+ }
814
+
815
+ // Set isDeclared to true for all imported objects
816
+ if (child.userData.isDeclared === undefined) {
817
+ child.userData.isDeclared = true;
818
+ }
819
+
820
+ // Recursively process children (e.g., manual segment connectors)
821
+ if (child.children && Array.isArray(child.children)) {
822
+ _markChildren(child.children);
823
+ }
824
+ });
825
+ };
826
+ _markChildren(data.scene.children);
827
+ console.log('✅ Marked all imported objects as declared in scene data');
828
+ }
829
+
798
830
  /**
799
831
  * Inject connector children from component dictionary into scene data components
800
832
  * This allows scene files to omit connector children since they're defined in the dictionary
801
833
  * @param {Object} data - Scene data to modify
802
834
  * @param {Object} componentDictionary - Component dictionary with connector definitions
803
835
  */
804
- )
805
836
  }, {
806
837
  key: "_injectConnectorChildrenFromDictionary",
807
838
  value: function _injectConnectorChildrenFromDictionary(data, componentDictionary) {
808
- var _data$scene,
839
+ var _data$scene2,
809
840
  _this3 = this;
810
- if (!(data !== null && data !== void 0 && (_data$scene = data.scene) !== null && _data$scene !== void 0 && _data$scene.children) || !componentDictionary) {
841
+ if (!(data !== null && data !== void 0 && (_data$scene2 = data.scene) !== null && _data$scene2 !== void 0 && _data$scene2.children) || !componentDictionary) {
811
842
  return;
812
843
  }
813
844
  var componentsProcessed = 0;
@@ -1107,7 +1138,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1107
1138
  key: "loadSceneFromData",
1108
1139
  value: (function () {
1109
1140
  var _loadSceneFromData = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee9(data) {
1110
- var _data$scene2, _data$scene3, _data$scene4, _data$scene5;
1141
+ var _data$scene3, _data$scene4, _data$scene5, _data$scene6;
1111
1142
  return _rollupPluginBabelHelpers.regenerator().w(function (_context9) {
1112
1143
  while (1) switch (_context9.n) {
1113
1144
  case 0:
@@ -1117,10 +1148,10 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1117
1148
  dataType: _rollupPluginBabelHelpers["typeof"](data),
1118
1149
  hasScene: !!(data !== null && data !== void 0 && data.scene),
1119
1150
  sceneType: _rollupPluginBabelHelpers["typeof"](data === null || data === void 0 ? void 0 : data.scene),
1120
- hasChildren: !!(data !== null && data !== void 0 && (_data$scene2 = data.scene) !== null && _data$scene2 !== void 0 && _data$scene2.children),
1121
- childrenType: data !== null && data !== void 0 && (_data$scene3 = data.scene) !== null && _data$scene3 !== void 0 && _data$scene3.children ? _rollupPluginBabelHelpers["typeof"](data.scene.children) : 'undefined',
1122
- isArray: Array.isArray(data === null || data === void 0 || (_data$scene4 = data.scene) === null || _data$scene4 === void 0 ? void 0 : _data$scene4.children),
1123
- 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,
1151
+ hasChildren: !!(data !== null && data !== void 0 && (_data$scene3 = data.scene) !== null && _data$scene3 !== void 0 && _data$scene3.children),
1152
+ childrenType: data !== null && data !== void 0 && (_data$scene4 = data.scene) !== null && _data$scene4 !== void 0 && _data$scene4.children ? _rollupPluginBabelHelpers["typeof"](data.scene.children) : 'undefined',
1153
+ isArray: Array.isArray(data === null || data === void 0 || (_data$scene5 = data.scene) === null || _data$scene5 === void 0 ? void 0 : _data$scene5.children),
1154
+ 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,
1124
1155
  dataKeys: data ? Object.keys(data) : [],
1125
1156
  sceneKeys: data !== null && data !== void 0 && data.scene ? Object.keys(data.scene) : []
1126
1157
  });
@@ -1305,6 +1336,470 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1305
1336
  return false;
1306
1337
  }
1307
1338
  }
1339
+
1340
+ // ===== MANUAL SEGMENT AND GATEWAY OPERATIONS =====
1341
+
1342
+ /**
1343
+ * Handle manual segment transformation by creating connectors and restructuring connections
1344
+ * @param {THREE.Object3D} segment - The transformed pipe segment
1345
+ * @param {Object} currentSceneData - Current scene data with connections
1346
+ */
1347
+ }, {
1348
+ key: "manualizeSegment",
1349
+ value: function manualizeSegment(segment, currentSceneData) {
1350
+ var _segment$userData, _this$sceneViewer$man;
1351
+ if (!segment || !((_segment$userData = segment.userData) !== null && _segment$userData !== void 0 && _segment$userData.objectType) === 'segment') {
1352
+ console.log('❌ Object is not a pipe segment:', {
1353
+ isObject: !!segment,
1354
+ hasUserData: !!(segment && segment.userData)
1355
+ });
1356
+ return;
1357
+ }
1358
+ console.log('🔧 Handling manual segment transformation:', segment.uuid);
1359
+
1360
+ // Get access to pathfinding manager's connector manager
1361
+ var pathfindingManager = (_this$sceneViewer$man = this.sceneViewer.managers) === null || _this$sceneViewer$man === void 0 ? void 0 : _this$sceneViewer$man.pathfindingManager;
1362
+ if (!pathfindingManager || !pathfindingManager.connectorManager) {
1363
+ console.error('❌ PathfindingManager or ConnectorManager not available');
1364
+ return;
1365
+ }
1366
+ var connectorManager = pathfindingManager.connectorManager;
1367
+ var sceneDataManager = pathfindingManager.sceneDataManager;
1368
+
1369
+ // IMPORTANT: Rename UUID FIRST to prevent removal by removeComputedObjects()
1370
+ // This must happen before convertConnectedGatewaysToManual() which triggers path regeneration
1371
+ // Change from "SEGMENT-X" to "Segment-X" (capital S to lowercase s)
1372
+ var segmentIndex = segment.userData.segmentIndex;
1373
+ var oldUuid = segment.uuid;
1374
+ segment.uuid = "Segment-".concat(segmentIndex);
1375
+ console.log("\uD83D\uDD27 Renamed segment UUID from ".concat(oldUuid, " to: ").concat(segment.uuid));
1376
+
1377
+ // Calculate segment endpoints in world coordinates
1378
+ var segmentEndpoints = connectorManager.calculateSegmentEndpoints(segment);
1379
+ console.log('📍 Segment endpoints:', segmentEndpoints);
1380
+
1381
+ // Create connectors at the segment endpoints
1382
+ var connectors = connectorManager.createSegmentConnectors(segment, segmentEndpoints);
1383
+ console.log('🔌 Created connectors:', connectors);
1384
+
1385
+ // IMPORTANT: Mark segment as declared FIRST to ensure it exists in scene data
1386
+ // This must happen BEFORE addConnectorsToScene so connectors have a parent to attach to
1387
+ segment.userData.manualConnectors = connectors.map(function (c) {
1388
+ return c.uuid;
1389
+ });
1390
+ sceneDataManager.markObjectAsDeclared(segment, currentSceneData, {});
1391
+ console.log('✅ Segment marked as declared in scene data');
1392
+
1393
+ // Now add connectors to the segment's children array in scene data
1394
+ connectorManager.addConnectorsToScene(connectors);
1395
+
1396
+ // Find the original connection that this segment belongs to (after gateways are converted)
1397
+ var originalConnection = connectorManager.findOriginalConnection(segment, currentSceneData.connections);
1398
+ if (!originalConnection) {
1399
+ console.warn('⚠️ Could not find original connection for segment:', segment.uuid);
1400
+ return;
1401
+ }
1402
+ console.log('🔍 Found original connection:', originalConnection);
1403
+ var authoritativeConnectorUUID = originalConnection.from.includes("Gateway") === false ? originalConnection.from : originalConnection.to;
1404
+ console.log('[SceneOperations] authoritativeConnectorUUID:', authoritativeConnectorUUID);
1405
+
1406
+ // Check and convert connected gateways to manual (declared)
1407
+ // NOTE: This may trigger path regeneration via translateGateway, so segment must already be renamed
1408
+ var convertedGatewayUUIDs = this._convertConnectedGatewaysToManual(connectors, currentSceneData);
1409
+
1410
+ // Restructure connections, passing any converted gateway UUIDs
1411
+ connectorManager.restructureConnections(authoritativeConnectorUUID, connectors, currentSceneData, convertedGatewayUUIDs);
1412
+
1413
+ // Mark segment as manually positioned and declared
1414
+ segment.userData.manualConnectors = connectors.map(function (c) {
1415
+ return c.uuid;
1416
+ });
1417
+
1418
+ // Use shared helper to mark as declared and add to scene data
1419
+ sceneDataManager.markObjectAsDeclared(segment, currentSceneData, {});
1420
+
1421
+ // Verify segment structure in scene data
1422
+ var segmentInSceneData = currentSceneData.scene.children.find(function (child) {
1423
+ return child.uuid === segment.uuid;
1424
+ });
1425
+ if (segmentInSceneData) {
1426
+ var _segmentInSceneData$c, _segmentInSceneData$c2;
1427
+ console.log("\uD83D\uDCCA Segment in scene data:", {
1428
+ uuid: segmentInSceneData.uuid,
1429
+ hasChildren: !!segmentInSceneData.children,
1430
+ childrenCount: ((_segmentInSceneData$c = segmentInSceneData.children) === null || _segmentInSceneData$c === void 0 ? void 0 : _segmentInSceneData$c.length) || 0,
1431
+ childrenUUIDs: ((_segmentInSceneData$c2 = segmentInSceneData.children) === null || _segmentInSceneData$c2 === void 0 ? void 0 : _segmentInSceneData$c2.map(function (c) {
1432
+ return c.uuid;
1433
+ })) || []
1434
+ });
1435
+ }
1436
+ console.log('✅ Manual segment transformation completed');
1437
+ }
1438
+
1439
+ /**
1440
+ * Check and convert gateways at the original path endpoints to manual (declared)
1441
+ * This method now delegates to manualizeGateway to ensure consistent gateway handling
1442
+ * @param {Array} connectors - Array of connector objects (used to get segment reference)
1443
+ * @param {Object} currentSceneData - Current scene data
1444
+ * @returns {Array<string>} Array of converted gateway UUIDs
1445
+ * @private
1446
+ */
1447
+ }, {
1448
+ key: "_convertConnectedGatewaysToManual",
1449
+ value: function _convertConnectedGatewaysToManual(connectors, currentSceneData) {
1450
+ var _connectors$,
1451
+ _segment$userData2,
1452
+ _this5 = this;
1453
+ console.log('🔍 Checking for connected gateways to convert to manual...');
1454
+ var sceneViewer = this.sceneViewer;
1455
+ var convertedGateways = [];
1456
+
1457
+ // Get the segment from the first connector's userData
1458
+ 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;
1459
+ if (!segment || !((_segment$userData2 = segment.userData) !== null && _segment$userData2 !== void 0 && _segment$userData2.objectType) === 'segment') {
1460
+ console.log('❌ Could not find segment for gateway conversion');
1461
+ return [];
1462
+ }
1463
+ var pathFrom = segment.userData.pathFrom;
1464
+ var pathTo = segment.userData.pathTo;
1465
+ console.log("\uD83D\uDD0D Checking original path endpoints for gateways: ".concat(pathFrom, " \u2192 ").concat(pathTo));
1466
+
1467
+ // Check the original path endpoints for gateways
1468
+ [pathFrom, pathTo].forEach(function (endpointUuid) {
1469
+ console.log("\uD83D\uDD0D Checking endpoint: ".concat(endpointUuid));
1470
+
1471
+ // Find the object in the scene that corresponds to this endpoint
1472
+ var endpointObject = null;
1473
+ sceneViewer.scene.traverse(function (obj) {
1474
+ var _obj$userData3;
1475
+ if (obj.uuid === endpointUuid || ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.originalUuid) === endpointUuid) {
1476
+ endpointObject = obj;
1477
+ }
1478
+ });
1479
+ if (endpointObject) {
1480
+ var _endpointObject$userD, _endpointObject$userD2, _endpointObject$userD3, _endpointObject$userD4, _endpointObject$userD5, _endpointObject$userD6;
1481
+ 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));
1482
+
1483
+ // Check if this endpoint is a gateway that needs to be converted to manual
1484
+ // IMPORTANT: Only convert if it's NOT already declared to prevent double-processing
1485
+ 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) {
1486
+ console.log("\uD83D\uDD27 Found computed gateway at endpoint: ".concat(endpointObject.uuid, " - converting to manual"));
1487
+
1488
+ // Convert gateway to manual (declared) using manualizeGateway for consistency
1489
+ _this5.manualizeGateway(endpointObject, currentSceneData);
1490
+ convertedGateways.push(endpointObject);
1491
+ } 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) {
1492
+ console.log("\u2139\uFE0F Gateway ".concat(endpointObject.uuid, " is already declared (manual), skipping conversion"));
1493
+ }
1494
+ } else {
1495
+ console.log("\u26A0\uFE0F Could not find object for endpoint: ".concat(endpointUuid));
1496
+ }
1497
+ });
1498
+ if (convertedGateways.length > 0) {
1499
+ console.log("\u2705 Converted ".concat(convertedGateways.length, " gateways to manual:"), convertedGateways.map(function (g) {
1500
+ return g.uuid;
1501
+ }));
1502
+ } else {
1503
+ console.log('ℹ️ No computed gateways found to convert (all may already be declared)');
1504
+ }
1505
+
1506
+ // Return array of gateway UUIDs
1507
+ return convertedGateways.map(function (g) {
1508
+ return g.uuid;
1509
+ });
1510
+ }
1511
+
1512
+ /**
1513
+ * Handle manual gateway transformation by converting it to declared status and processing connections
1514
+ * @param {THREE.Object3D} gateway - The transformed gateway object
1515
+ * @param {Object} currentSceneData - Current scene data with connections
1516
+ */
1517
+ }, {
1518
+ key: "manualizeGateway",
1519
+ value: function manualizeGateway(gateway, currentSceneData) {
1520
+ var _this$sceneViewer$man2;
1521
+ console.log("[SceneOperations] manualizeGateway started:", gateway);
1522
+ if (!gateway || !gateway.userData || gateway.userData.objectType !== 'gateway') {
1523
+ console.log('❌ Object is not a gateway:', {
1524
+ isObject: !!gateway,
1525
+ hasUserData: !!(gateway && gateway.userData)
1526
+ });
1527
+ return;
1528
+ }
1529
+ console.log('🔧 Handling manual gateway transformation:', gateway.uuid);
1530
+
1531
+ // Get access to pathfinding manager's scene data manager
1532
+ var pathfindingManager = (_this$sceneViewer$man2 = this.sceneViewer.managers) === null || _this$sceneViewer$man2 === void 0 ? void 0 : _this$sceneViewer$man2.pathfindingManager;
1533
+ if (!pathfindingManager || !pathfindingManager.sceneDataManager) {
1534
+ console.error('❌ PathfindingManager or SceneDataManager not available');
1535
+ return;
1536
+ }
1537
+ var sceneDataManager = pathfindingManager.sceneDataManager;
1538
+
1539
+ // IMPORTANT: Check if gateway is already declared to prevent double-processing of connections
1540
+ if (gateway.userData.isDeclared === true) {
1541
+ console.log("\u2139\uFE0F Gateway ".concat(gateway.uuid, " is already declared (manual)"));
1542
+
1543
+ // Update position in scene data for subsequent moves
1544
+ sceneDataManager.markObjectAsDeclared(gateway, currentSceneData, {});
1545
+ console.log('✅ Updated gateway position in scene data');
1546
+ return;
1547
+ }
1548
+
1549
+ // Convert gateway from computed to declared status (first-time manualization)
1550
+ console.log('🔧 Converting gateway to declared status via convertGatewayToManual');
1551
+ this.convertGatewayToManual(gateway, currentSceneData);
1552
+ console.log('✅ Manual gateway transformation completed');
1553
+ }
1554
+
1555
+ /**
1556
+ * Convert a gateway from computed to manual (declared) - reusing logic from sceneOperationsManager
1557
+ * @param {THREE.Object3D} gateway - The gateway object to convert
1558
+ * @param {Object} currentSceneData - Current scene data
1559
+ */
1560
+ }, {
1561
+ key: "convertGatewayToManual",
1562
+ value: function convertGatewayToManual(gateway, currentSceneData) {
1563
+ var _this$sceneViewer$man3, _gateway$userData;
1564
+ console.log("\uD83D\uDD27 Converting gateway from computed to declared: ".concat(gateway.uuid, " (").concat(gateway.uuid, ")"));
1565
+ console.log("[SceneOperations] currentSceneData:", currentSceneData);
1566
+
1567
+ // Get access to pathfinding manager's scene data manager
1568
+ var pathfindingManager = (_this$sceneViewer$man3 = this.sceneViewer.managers) === null || _this$sceneViewer$man3 === void 0 ? void 0 : _this$sceneViewer$man3.pathfindingManager;
1569
+ if (!pathfindingManager || !pathfindingManager.sceneDataManager) {
1570
+ console.error('❌ PathfindingManager or SceneDataManager not available');
1571
+ return;
1572
+ }
1573
+ var sceneDataManager = pathfindingManager.sceneDataManager;
1574
+
1575
+ // Use shared helper to mark as declared
1576
+ sceneDataManager.markObjectAsDeclared(gateway, currentSceneData, {});
1577
+
1578
+ // Process gateway connections (same logic as in sceneOperationsManager)
1579
+ if ((_gateway$userData = gateway.userData) !== null && _gateway$userData !== void 0 && _gateway$userData.connections && currentSceneData.connections) {
1580
+ console.log('🔗 Processing gateway connections for filtering:', gateway.userData.connections);
1581
+ var gatewayConnections = gateway.userData.connections;
1582
+
1583
+ // Filter out removed connections (creates new array, doesn't mutate)
1584
+ if (gatewayConnections.removed && Array.isArray(gatewayConnections.removed)) {
1585
+ console.log('🗑️ Filtering out removed connections:', gatewayConnections.removed);
1586
+ currentSceneData.connections = currentSceneData.connections.filter(function (connection) {
1587
+ var isRemoved = gatewayConnections.removed.some(function (removedConn) {
1588
+ return removedConn.from === connection.from && removedConn.to === connection.to || removedConn.from === connection.to && removedConn.to === connection.from;
1589
+ });
1590
+ if (isRemoved) {
1591
+ console.log("\uD83D\uDDD1\uFE0F Removed connection: ".concat(connection.from, " \u2192 ").concat(connection.to));
1592
+ }
1593
+ return !isRemoved;
1594
+ });
1595
+ }
1596
+
1597
+ // Add new connections (deep copy to prevent reference issues)
1598
+ if (gatewayConnections.added && Array.isArray(gatewayConnections.added)) {
1599
+ console.log('➕ Adding new connections:', gatewayConnections.added);
1600
+ gatewayConnections.added.forEach(function (newConnection) {
1601
+ // Check if connection already exists to avoid duplicates
1602
+ var alreadyExists = currentSceneData.connections.some(function (conn) {
1603
+ return conn.from === newConnection.from && conn.to === newConnection.to || conn.from === newConnection.to && conn.to === newConnection.from;
1604
+ });
1605
+ if (!alreadyExists) {
1606
+ // Deep copy the connection object to prevent reference issues
1607
+ currentSceneData.connections.push(_rollupPluginBabelHelpers.objectSpread2({}, newConnection));
1608
+ console.log("\u2795 Added new connection: ".concat(newConnection.from, " \u2192 ").concat(newConnection.to));
1609
+ } else {
1610
+ console.log("\u26A0\uFE0F Connection already exists, skipping: ".concat(newConnection.from, " \u2192 ").concat(newConnection.to));
1611
+ }
1612
+ });
1613
+ }
1614
+ console.log('✅ Gateway connections processing completed. Total connections:', currentSceneData.connections.length);
1615
+ }
1616
+ console.log("\u2705 Gateway ".concat(gateway.uuid, " successfully converted to manual (declared)"));
1617
+ }
1618
+
1619
+ /**
1620
+ * Split a pipe segment in half at its midpoint
1621
+ * Creates two simple pipe meshes without manualization
1622
+ * @param {string|THREE.Object3D} segmentIdOrObject - The UUID or Three.js object of the segment to split
1623
+ * @returns {Object|null} Object with the two new segments {segment1, segment2} or null on failure
1624
+ */
1625
+ }, {
1626
+ key: "splitSegment",
1627
+ value: function splitSegment(segmentIdOrObject) {
1628
+ var _segment$userData3,
1629
+ _this6 = this;
1630
+ console.log('✂️ splitSegment started:', segmentIdOrObject);
1631
+
1632
+ // Find the segment object
1633
+ var segment = null;
1634
+ if (typeof segmentIdOrObject === 'string') {
1635
+ this.sceneViewer.scene.traverse(function (child) {
1636
+ var _child$userData10;
1637
+ if (child.uuid === segmentIdOrObject || ((_child$userData10 = child.userData) === null || _child$userData10 === void 0 ? void 0 : _child$userData10.originalUuid) === segmentIdOrObject) {
1638
+ segment = child;
1639
+ }
1640
+ });
1641
+ } else if (segmentIdOrObject && segmentIdOrObject.isObject3D) {
1642
+ segment = segmentIdOrObject;
1643
+ }
1644
+
1645
+ // Validate segment
1646
+ if (!segment || ((_segment$userData3 = segment.userData) === null || _segment$userData3 === void 0 ? void 0 : _segment$userData3.objectType) !== 'segment') {
1647
+ console.error('❌ splitSegment(): Invalid segment or not found');
1648
+ return null;
1649
+ }
1650
+ console.log('✂️ Splitting segment:', segment.uuid);
1651
+
1652
+ // Get segment geometry to calculate split point
1653
+ var geometry = segment.geometry;
1654
+ if (!geometry || !geometry.parameters) {
1655
+ console.error('❌ splitSegment(): Segment has invalid geometry');
1656
+ return null;
1657
+ }
1658
+ var segmentLength = geometry.parameters.height || 1;
1659
+ var segmentRadius = geometry.parameters.radiusTop || 0.1;
1660
+
1661
+ // Calculate segment direction vector
1662
+ var direction = new THREE__namespace.Vector3(0, 1, 0);
1663
+ direction.applyQuaternion(segment.quaternion);
1664
+ direction.normalize();
1665
+
1666
+ // Calculate segment endpoints
1667
+ var startPoint = new THREE__namespace.Vector3();
1668
+ startPoint.copy(segment.position).sub(direction.clone().multiplyScalar(segmentLength / 2));
1669
+ var endPoint = new THREE__namespace.Vector3();
1670
+ endPoint.copy(segment.position).add(direction.clone().multiplyScalar(segmentLength / 2));
1671
+
1672
+ // Check for component connectors at endpoints
1673
+ var findConnectorsAtPosition = function findConnectorsAtPosition(position) {
1674
+ var tolerance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.15;
1675
+ var connectors = [];
1676
+ _this6.sceneViewer.scene.traverse(function (child) {
1677
+ var _child$userData11;
1678
+ if (((_child$userData11 = child.userData) === null || _child$userData11 === void 0 ? void 0 : _child$userData11.objectType) === 'connector') {
1679
+ var connectorWorldPos = new THREE__namespace.Vector3();
1680
+ child.getWorldPosition(connectorWorldPos);
1681
+ var distance = connectorWorldPos.distanceTo(position);
1682
+ if (distance <= tolerance) {
1683
+ connectors.push(child);
1684
+ }
1685
+ }
1686
+ });
1687
+ return connectors.filter(function (c) {
1688
+ var _c$userData;
1689
+ return ((_c$userData = c.userData) === null || _c$userData === void 0 ? void 0 : _c$userData.objectType) !== 'segment-connector';
1690
+ });
1691
+ };
1692
+ var startConnectors = findConnectorsAtPosition(startPoint);
1693
+ var endConnectors = findConnectorsAtPosition(endPoint);
1694
+
1695
+ // Determine split position: 0.5 on component connector side, remaining on free side
1696
+ var segment1Length, segment2Length, splitPoint;
1697
+ var fixedLength = 0.5; // Fixed length for component connector side
1698
+
1699
+ if (startConnectors.length > 0) {
1700
+ // Component connector at start - make segment1 = 0.5, segment2 = remaining
1701
+ segment1Length = fixedLength;
1702
+ segment2Length = segmentLength - fixedLength;
1703
+ splitPoint = new THREE__namespace.Vector3();
1704
+ splitPoint.copy(startPoint).add(direction.clone().multiplyScalar(fixedLength));
1705
+ console.log("\uD83D\uDCCD Component connector at START - split: ".concat(segment1Length, " (start) + ").concat(segment2Length, " (end)"));
1706
+ } else if (endConnectors.length > 0) {
1707
+ // Component connector at end - make segment1 = remaining, segment2 = 0.5
1708
+ segment1Length = segmentLength - fixedLength;
1709
+ segment2Length = fixedLength;
1710
+ splitPoint = new THREE__namespace.Vector3();
1711
+ splitPoint.copy(endPoint).sub(direction.clone().multiplyScalar(fixedLength));
1712
+ console.log("\uD83D\uDCCD Component connector at END - split: ".concat(segment1Length, " (start) + ").concat(segment2Length, " (end)"));
1713
+ } else {
1714
+ // No component connectors - split at midpoint (default behavior)
1715
+ segment1Length = segmentLength / 2;
1716
+ segment2Length = segmentLength / 2;
1717
+ splitPoint = new THREE__namespace.Vector3();
1718
+ splitPoint.copy(segment.position);
1719
+ console.log("\uD83D\uDCCD No component connectors - split at midpoint: ".concat(segment1Length, " + ").concat(segment2Length));
1720
+ }
1721
+ console.log('📍 Segment split points:', {
1722
+ start: startPoint.toArray(),
1723
+ split: splitPoint.toArray(),
1724
+ end: endPoint.toArray(),
1725
+ length: segmentLength,
1726
+ segment1Length: segment1Length,
1727
+ segment2Length: segment2Length,
1728
+ originalUuid: segment.uuid
1729
+ });
1730
+
1731
+ // Get material from existing segment
1732
+ var material = segment.material;
1733
+
1734
+ // Create first segment (start to split point)
1735
+ var segment1Geometry = new THREE__namespace.CylinderGeometry(segmentRadius, segmentRadius, segment1Length, 16, 1, false);
1736
+ var segment1 = new THREE__namespace.Mesh(segment1Geometry, material);
1737
+
1738
+ // Position segment1 between start and split point
1739
+ var segment1Position = new THREE__namespace.Vector3();
1740
+ segment1Position.lerpVectors(startPoint, splitPoint, 0.5);
1741
+ segment1.position.copy(segment1Position);
1742
+ segment1.quaternion.copy(segment.quaternion);
1743
+
1744
+ // Set UUID and copy userData
1745
+ segment1.uuid = "".concat(segment.uuid, "-part1");
1746
+ segment1.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, segment.userData), {}, {
1747
+ originalUuid: segment1.uuid,
1748
+ splitFromUuid: segment.uuid
1749
+ });
1750
+
1751
+ // Mark segment1 as non-selectable/non-transformable if it's the 0.5 stub
1752
+ if (startConnectors.length > 0 && segment1Length === fixedLength) {
1753
+ segment1.userData.isStub = true;
1754
+ segment1.userData.selectable = false;
1755
+ segment1.userData.transformable = false;
1756
+ console.log("\uD83D\uDD12 Segment1 marked as non-selectable stub (length: ".concat(fixedLength, ")"));
1757
+ }
1758
+
1759
+ // Create second segment (split point to end)
1760
+ var segment2Geometry = new THREE__namespace.CylinderGeometry(segmentRadius, segmentRadius, segment2Length, 16, 1, false);
1761
+ var segment2 = new THREE__namespace.Mesh(segment2Geometry, material);
1762
+
1763
+ // Position segment2 between split point and end
1764
+ var segment2Position = new THREE__namespace.Vector3();
1765
+ segment2Position.lerpVectors(splitPoint, endPoint, 0.5);
1766
+ segment2.position.copy(segment2Position);
1767
+ segment2.quaternion.copy(segment.quaternion);
1768
+
1769
+ // Set UUID and copy userData
1770
+ segment2.uuid = "".concat(segment.uuid, "-part2");
1771
+ segment2.userData = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, segment.userData), {}, {
1772
+ originalUuid: segment2.uuid,
1773
+ splitFromUuid: segment.uuid
1774
+ });
1775
+
1776
+ // Mark segment2 as non-selectable/non-transformable if it's the 0.5 stub
1777
+ if (endConnectors.length > 0 && segment2Length === fixedLength) {
1778
+ segment2.userData.isStub = true;
1779
+ segment2.userData.selectable = false;
1780
+ segment2.userData.transformable = false;
1781
+ console.log("\uD83D\uDD12 Segment2 marked as non-selectable stub (length: ".concat(fixedLength, ")"));
1782
+ }
1783
+
1784
+ // Add new segments to scene
1785
+ this.sceneViewer.scene.add(segment1);
1786
+ this.sceneViewer.scene.add(segment2);
1787
+ console.log('✅ Created two new segments:', {
1788
+ segment1: segment1.uuid,
1789
+ segment2: segment2.uuid,
1790
+ originalSegment: segment.uuid
1791
+ });
1792
+
1793
+ // Remove the original segment
1794
+ this.sceneViewer.scene.remove(segment);
1795
+ if (segment.geometry) segment.geometry.dispose();
1796
+ console.log('🗑️ Removed original segment:', segment.uuid);
1797
+ console.log('✅ Segment split completed successfully');
1798
+ return {
1799
+ segment1: segment1,
1800
+ segment2: segment2
1801
+ };
1802
+ }
1308
1803
  }]);
1309
1804
  }();
1310
1805
 
@@ -6,7 +6,6 @@ var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHel
6
6
  var CSS2DRenderer = require('../../../node_modules/three/examples/jsm/renderers/CSS2DRenderer.js');
7
7
  var THREE = require('three');
8
8
  var baseDisposable = require('../../core/baseDisposable.js');
9
- var objectTypes = require('../../utils/objectTypes.js');
10
9
 
11
10
  function _interopNamespace(e) {
12
11
  if (e && e.__esModule) return e;
@@ -423,7 +422,7 @@ var SceneTooltipsManager = /*#__PURE__*/function (_BaseDisposable) {
423
422
  };
424
423
 
425
424
  // If transform controls are available and have a selected object
426
- if (this.transformControlsManager && this.transformControlsManager.selectedObject === this.selectedMesh) {
425
+ if (this.transformControlsManager && this.transformControlsManager.selectedObjects && this.transformControlsManager.selectedObjects.length > 0 && this.transformControlsManager.selectedObjects[0] === this.selectedMesh) {
427
426
  try {
428
427
  // Get world transform data from transform controls
429
428
  var worldTransform = this.transformControlsManager.getWorldTransformData();
@@ -632,16 +631,10 @@ var SceneTooltipsManager = /*#__PURE__*/function (_BaseDisposable) {
632
631
  }, {
633
632
  key: "isSelectableComponent",
634
633
  value: function isSelectableComponent(object) {
635
- var _object$userData;
636
634
  // Check if the object has component data
637
635
  if (object && object.userData && object.userData.component) {
638
636
  return true;
639
637
  }
640
-
641
- // Check if the object is a pipe segment or junction
642
- if (object && (objectTypes.isSegment(object) || (_object$userData = object.userData) !== null && _object$userData !== void 0 && _object$userData.isPipeJunction)) {
643
- return true;
644
- }
645
638
  return false;
646
639
  }
647
640
  }, {