@2112-lab/central-plant 0.1.21 → 0.1.23

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.
@@ -20452,6 +20452,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
20452
20452
  }
20453
20453
 
20454
20454
  // Ensure transform controls are still properly attached after scene operations
20455
+ // Use false here since we're in the middle of clearing - enable them later in loadSceneData
20455
20456
  this.ensureTransformControlsAttached(false);
20456
20457
  console.log('✅ Scene clear operation completed');
20457
20458
  }
@@ -20486,16 +20487,22 @@ var SceneOperationsManager = /*#__PURE__*/function () {
20486
20487
  if (wasReattached) {
20487
20488
  console.log('🔧 Transform controls were reattached after scene operation');
20488
20489
 
20489
- // Override visibility based on allowVisible parameter
20490
- if (!allowVisible && component.transformManager.transformControls) {
20490
+ // Set enablement based on allowVisible parameter
20491
+ if (allowVisible) {
20492
+ component.transformManager.setEnabled(true);
20493
+ console.log('🔧 Transform controls enabled and ready for use');
20494
+ } else if (component.transformManager.transformControls) {
20491
20495
  component.transformManager.transformControls.visible = false;
20492
20496
  console.log('🔧 Forcing transform controls to be invisible during load');
20493
20497
  }
20494
20498
  } else {
20495
20499
  console.log('✓ Transform controls are properly attached');
20496
20500
 
20497
- // Still ensure visibility is set correctly even if not reattached
20498
- if (!allowVisible && component.transformManager.transformControls) {
20501
+ // Ensure proper enablement/visibility based on allowVisible parameter
20502
+ if (allowVisible) {
20503
+ component.transformManager.setEnabled(true);
20504
+ console.log('🔧 Transform controls enabled and ready for use');
20505
+ } else if (component.transformManager.transformControls) {
20499
20506
  component.transformManager.transformControls.visible = false;
20500
20507
  console.log('🔧 Ensuring transform controls remain invisible during load');
20501
20508
  }
@@ -21043,7 +21050,9 @@ var SceneOperationsManager = /*#__PURE__*/function () {
21043
21050
  // For non-library objects (connectors, gateways), create shared sphere geometry
21044
21051
  var isConnectorOrGateway = child.uuid && (child.uuid.toLowerCase().includes('connector') || child.uuid.toLowerCase().includes('gateway'));
21045
21052
  if (isConnectorOrGateway) {
21046
- geometries[child.geometry] = new THREE__namespace.SphereGeometry(0.1, 16, 16);
21053
+ if (!(child.position.x == 0 && child.position.y == 0 && child.position.z == 0)) {
21054
+ geometries[child.geometry] = new THREE__namespace.SphereGeometry(0.1, 16, 16);
21055
+ }
21047
21056
  } else {
21048
21057
  // Default fallback geometry
21049
21058
  geometries[child.geometry] = new THREE__namespace.BoxGeometry(1, 1, 1);
@@ -21399,23 +21408,19 @@ var SceneOperationsManager = /*#__PURE__*/function () {
21399
21408
  console.log('🔧 Re-initializing transform controls after scene load');
21400
21409
  component.initTransformControls();
21401
21410
  } else {
21402
- // Keep transform controls invisible
21411
+ // Re-enable transform controls after scene load is complete
21403
21412
  if (component.transformManager.transformControls) {
21413
+ console.log('🔧 Re-enabling transform controls after scene load');
21414
+ component.transformManager.setEnabled(true);
21415
+ // Keep invisible initially, but enable functionality
21404
21416
  component.transformManager.transformControls.visible = false;
21405
- console.log('🔧 Making transform controls invisible after scene load');
21406
21417
  }
21407
21418
  }
21408
21419
 
21409
21420
  // Ensure transform controls are still properly attached to the scene after import
21410
- component.ensureTransformControlsAttached(false);
21411
-
21412
- // Keep transform controls inactive after loading scene data
21413
- if (component.transformManager && component.transformManager.transformControls) {
21414
- console.log('🔧 Keeping transform controls inactive after scene data load');
21415
- component.keepTransformControlsInactive();
21416
- component.transformManager.transformControls.visible = false;
21417
- console.log('🔒 Final verification: transform controls visibility forced to false');
21418
- }
21421
+ // Pass true to allow visibility when objects are selected
21422
+ this.ensureTransformControlsAttached(true);
21423
+ console.log('✅ Transform controls re-enabled and ready for use after scene import');
21419
21424
  }
21420
21425
  _context5.n = 13;
21421
21426
  break;
@@ -25445,6 +25450,9 @@ var CentralPlant = /*#__PURE__*/function () {
25445
25450
  lastTransform: null
25446
25451
  };
25447
25452
 
25453
+ // Add component counter for unique ID generation
25454
+ this.componentCounter = 0;
25455
+
25448
25456
  // Set default scene metadata
25449
25457
  this.setDefaultSceneMetadata();
25450
25458
 
@@ -25622,6 +25630,8 @@ var CentralPlant = /*#__PURE__*/function () {
25622
25630
  key: "setImportedSceneData",
25623
25631
  value: function setImportedSceneData(sceneData) {
25624
25632
  var _this$importedSceneDa, _this$importedSceneDa2;
25633
+ // Clear existing scene components before importing new data
25634
+ this.clearSceneComponents();
25625
25635
  this.importedSceneData = _objectSpread2({}, sceneData);
25626
25636
  console.log('📥 Imported scene data stored in CentralPlant:', {
25627
25637
  connections: ((_this$importedSceneDa = this.importedSceneData.connections) === null || _this$importedSceneDa === void 0 ? void 0 : _this$importedSceneDa.length) || 0,
@@ -25629,6 +25639,9 @@ var CentralPlant = /*#__PURE__*/function () {
25629
25639
  timestamp: new Date().toISOString()
25630
25640
  });
25631
25641
 
25642
+ // Reset component counter based on imported components to avoid ID conflicts
25643
+ this.resetComponentCounter();
25644
+
25632
25645
  // Set default metadata for imported scene data
25633
25646
  this.setDefaultImportedSceneMetadata(sceneData);
25634
25647
 
@@ -25680,6 +25693,94 @@ var CentralPlant = /*#__PURE__*/function () {
25680
25693
  console.log('🗑️ Imported scene data cleared from CentralPlant');
25681
25694
  }
25682
25695
 
25696
+ /**
25697
+ * Clear all components from the scene while preserving lights, cameras, and environment
25698
+ * This method safely removes only objects with userData.componentType = "component"
25699
+ * while keeping all other scene elements like lights, cameras, controls, and environment objects
25700
+ */
25701
+ }, {
25702
+ key: "clearSceneComponents",
25703
+ value: function clearSceneComponents() {
25704
+ var _this2 = this;
25705
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
25706
+ console.warn('⚠️ clearSceneComponents(): Scene viewer or scene not available');
25707
+ return;
25708
+ }
25709
+ console.log('🗑️ Clearing existing scene components (userData.componentType = "component")...');
25710
+
25711
+ // Get all children to remove (only components with userData.componentType = "component")
25712
+ var childrenToRemove = [];
25713
+ this.sceneViewer.scene.traverse(function (child) {
25714
+ // Skip the scene itself
25715
+ if (child === _this2.sceneViewer.scene) return;
25716
+
25717
+ // Only remove objects that have userData.componentType = "component"
25718
+ var isComponent = child.userData && child.userData.componentType === 'component';
25719
+
25720
+ // If it's a component and it's a direct child of the scene, mark for removal
25721
+ if (isComponent && child.parent === _this2.sceneViewer.scene) {
25722
+ childrenToRemove.push(child);
25723
+ }
25724
+ });
25725
+
25726
+ // Remove the identified objects
25727
+ var removedCount = 0;
25728
+ childrenToRemove.forEach(function (child) {
25729
+ try {
25730
+ // Dispose of geometries and materials to prevent memory leaks
25731
+ if (child.geometry) {
25732
+ child.geometry.dispose();
25733
+ }
25734
+ if (child.material) {
25735
+ if (Array.isArray(child.material)) {
25736
+ child.material.forEach(function (material) {
25737
+ if (material.map) material.map.dispose();
25738
+ if (material.normalMap) material.normalMap.dispose();
25739
+ if (material.roughnessMap) material.roughnessMap.dispose();
25740
+ if (material.metalnessMap) material.metalnessMap.dispose();
25741
+ material.dispose();
25742
+ });
25743
+ } else {
25744
+ if (child.material.map) child.material.map.dispose();
25745
+ if (child.material.normalMap) child.material.normalMap.dispose();
25746
+ if (child.material.roughnessMap) child.material.roughnessMap.dispose();
25747
+ if (child.material.metalnessMap) child.material.metalnessMap.dispose();
25748
+ child.material.dispose();
25749
+ }
25750
+ }
25751
+
25752
+ // Remove from scene
25753
+ _this2.sceneViewer.scene.remove(child);
25754
+ removedCount++;
25755
+ } catch (error) {
25756
+ console.warn('⚠️ Error removing scene object:', error, child);
25757
+ }
25758
+ });
25759
+
25760
+ // Clear any active selections or transform controls
25761
+ if (this.sceneViewer.transformManager) {
25762
+ try {
25763
+ this.sceneViewer.transformManager.deselectObject();
25764
+ } catch (error) {
25765
+ console.warn('⚠️ Error deselecting objects during scene clear:', error);
25766
+ }
25767
+ }
25768
+
25769
+ // Clear connections if they exist in currentSceneData
25770
+ if (this.sceneViewer.currentSceneData && this.sceneViewer.currentSceneData.connections) {
25771
+ this.sceneViewer.currentSceneData.connections = [];
25772
+ }
25773
+
25774
+ // Reset component counter
25775
+ this.componentCounter = 0;
25776
+ console.log("\u2705 clearSceneComponents(): Removed ".concat(removedCount, " objects from scene, preserved essential elements"));
25777
+
25778
+ // Trigger a render update
25779
+ if (this.sceneViewer.renderer) {
25780
+ this.sceneViewer.renderer.render(this.sceneViewer.scene, this.sceneViewer.camera);
25781
+ }
25782
+ }
25783
+
25683
25784
  /**
25684
25785
  * Set a metadata attribute
25685
25786
  * @param {string} key - The metadata key
@@ -25845,7 +25946,7 @@ var CentralPlant = /*#__PURE__*/function () {
25845
25946
  }, {
25846
25947
  key: "setDefaultSceneMetadata",
25847
25948
  value: function setDefaultSceneMetadata() {
25848
- var _this2 = this;
25949
+ var _this3 = this;
25849
25950
  var defaultMetadata = {
25850
25951
  // Scene Information
25851
25952
  sceneInfo: {
@@ -25920,8 +26021,8 @@ var CentralPlant = /*#__PURE__*/function () {
25920
26021
 
25921
26022
  // Set each default metadata category
25922
26023
  Object.keys(defaultMetadata).forEach(function (category) {
25923
- if (!_this2.hasMetadata(category)) {
25924
- _this2.setMetadata(category, defaultMetadata[category]);
26024
+ if (!_this3.hasMetadata(category)) {
26025
+ _this3.setMetadata(category, defaultMetadata[category]);
25925
26026
  }
25926
26027
  });
25927
26028
  console.log('🎯 Default scene metadata initialized:', Object.keys(defaultMetadata));
@@ -26643,7 +26744,7 @@ var CentralPlant = /*#__PURE__*/function () {
26643
26744
 
26644
26745
  // Perform the translation
26645
26746
  var normalizedAxis = axis.toLowerCase();
26646
- var previousPosition = component.position[normalizedAxis];
26747
+ component.position[normalizedAxis];
26647
26748
  try {
26648
26749
  // Apply the translation
26649
26750
  component.position[normalizedAxis] += value;
@@ -26709,19 +26810,6 @@ var CentralPlant = /*#__PURE__*/function () {
26709
26810
  // // Update scene data and paths after successful translation
26710
26811
  // this.updatePaths(component)
26711
26812
 
26712
- // Log successful translation
26713
- console.log("\u2705 translate(): Component ".concat(componentId, " translated ").concat(value, " units along ").concat(normalizedAxis.toUpperCase(), "-axis"), {
26714
- componentId: componentId,
26715
- axis: normalizedAxis,
26716
- value: value,
26717
- previousPosition: previousPosition,
26718
- newPosition: component.position[normalizedAxis],
26719
- totalPosition: {
26720
- x: component.position.x.toFixed(3),
26721
- y: component.position.y.toFixed(3),
26722
- z: component.position.z.toFixed(3)
26723
- }
26724
- });
26725
26813
  return component;
26726
26814
  } catch (error) {
26727
26815
  console.error("\u274C translate(): Error translating component ".concat(componentId, ":"), error);
@@ -26739,6 +26827,71 @@ var CentralPlant = /*#__PURE__*/function () {
26739
26827
  }
26740
26828
  }
26741
26829
 
26830
+ /**
26831
+ * Generate a unique component ID that doesn't conflict with existing components
26832
+ * @param {string} libraryId - The library identifier for the component type
26833
+ * @returns {string} A unique component ID
26834
+ */
26835
+ }, {
26836
+ key: "generateUniqueComponentId",
26837
+ value: function generateUniqueComponentId(libraryId) {
26838
+ // Get all existing component IDs
26839
+ var existingIds = this.getComponentIds();
26840
+ var existingIdSet = new Set(existingIds);
26841
+ var attempts = 0;
26842
+ var maxAttempts = 1000; // Safety limit to prevent infinite loops
26843
+
26844
+ while (attempts < maxAttempts) {
26845
+ // Generate a candidate ID using the current counter
26846
+ var candidateId = this.utilities.generateUuidFromName(libraryId + '-' + (this.componentCounter + 1));
26847
+
26848
+ // Check if this ID already exists
26849
+ if (!existingIdSet.has(candidateId)) {
26850
+ // ID is unique, increment counter and return it
26851
+ this.componentCounter++;
26852
+ console.log("\u2705 generateUniqueComponentId(): Generated unique ID ".concat(candidateId, " for ").concat(libraryId, " (counter: ").concat(this.componentCounter, ")"));
26853
+ return candidateId;
26854
+ }
26855
+
26856
+ // ID exists, increment counter and try again
26857
+ this.componentCounter++;
26858
+ attempts++;
26859
+ console.warn("\u26A0\uFE0F generateUniqueComponentId(): ID collision detected for ".concat(candidateId, ", trying again (attempt ").concat(attempts, ")"));
26860
+ }
26861
+
26862
+ // Fallback: use timestamp + random number if we can't find a unique ID with counter
26863
+ var fallbackId = this.utilities.generateUuidFromName(libraryId + '-' + Date.now() + '-' + Math.random().toString(36).substring(2, 8));
26864
+ console.warn("\u26A0\uFE0F generateUniqueComponentId(): Max attempts reached, using fallback ID: ".concat(fallbackId));
26865
+ return fallbackId;
26866
+ }
26867
+
26868
+ /**
26869
+ * Reset the component counter based on existing components in the scene
26870
+ * This is useful when loading scenes that already have numbered components
26871
+ */
26872
+ }, {
26873
+ key: "resetComponentCounter",
26874
+ value: function resetComponentCounter() {
26875
+ var existingIds = this.getComponentIds();
26876
+ var maxCounter = 0;
26877
+
26878
+ // Extract counter values from existing component IDs
26879
+ existingIds.forEach(function (id) {
26880
+ // Look for patterns like "PUMP-1", "CHILLER-2", etc.
26881
+ var match = id.match(/-(\d+)(?:-|$)/);
26882
+ if (match) {
26883
+ var counter = parseInt(match[1], 10);
26884
+ if (!isNaN(counter) && counter > maxCounter) {
26885
+ maxCounter = counter;
26886
+ }
26887
+ }
26888
+ });
26889
+
26890
+ // Set the counter to one more than the highest found
26891
+ this.componentCounter = maxCounter;
26892
+ console.log("\uD83D\uDD04 resetComponentCounter(): Counter reset to ".concat(this.componentCounter, " based on ").concat(existingIds.length, " existing components"));
26893
+ }
26894
+
26742
26895
  /**
26743
26896
  * Add a new component to the scene using its library ID
26744
26897
  * @param {string} libraryId - The library identifier for the component type (e.g., 'PUMP', 'CHILLER', 'COOLING-TOWER')
@@ -26780,7 +26933,16 @@ var CentralPlant = /*#__PURE__*/function () {
26780
26933
  }
26781
26934
  try {
26782
26935
  // Generate a unique component ID if not provided
26783
- var componentId = options.customId || this.utilities.generateUuidFromName(libraryId + '_' + Date.now());
26936
+ var componentId = options.customId || this.generateUniqueComponentId(libraryId);
26937
+
26938
+ // Validate that custom IDs don't conflict with existing components
26939
+ if (options.customId) {
26940
+ var existingIds = this.getComponentIds();
26941
+ if (existingIds.includes(options.customId)) {
26942
+ console.error("\u274C addComponent(): Custom ID '".concat(options.customId, "' already exists in scene. Existing IDs:"), existingIds);
26943
+ return false;
26944
+ }
26945
+ }
26784
26946
 
26785
26947
  // Set default position within scene boundaries if not provided
26786
26948
  var position = options.position || {
@@ -27107,6 +27269,102 @@ var CentralPlant = /*#__PURE__*/function () {
27107
27269
  return this.sceneViewer.currentSceneData.connections || [];
27108
27270
  }
27109
27271
 
27272
+ /**
27273
+ * Get all connector IDs from the currentSceneData
27274
+ * @returns {Array} Array of all connector ID strings, or empty array if none exist
27275
+ */
27276
+ }, {
27277
+ key: "getAllConnectorIds",
27278
+ value: function getAllConnectorIds() {
27279
+ if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
27280
+ console.warn('⚠️ getAllConnectorIds(): Scene viewer or current scene data not available');
27281
+ return [];
27282
+ }
27283
+ var allConnectorIds = [];
27284
+ var sceneData = this.sceneViewer.currentSceneData;
27285
+
27286
+ // Check if scene data has the expected structure
27287
+ if (!sceneData.scene || !sceneData.scene.object || !sceneData.scene.object.children) {
27288
+ console.warn('⚠️ getAllConnectorIds(): Invalid scene data structure');
27289
+ return [];
27290
+ }
27291
+
27292
+ // Traverse through all components in the scene data
27293
+ sceneData.scene.object.children.forEach(function (component) {
27294
+ // Each component may have connector children
27295
+ if (component.children && Array.isArray(component.children)) {
27296
+ component.children.forEach(function (child) {
27297
+ // Check if this child is a connector
27298
+ if (child.userData && child.userData.componentType === 'connector' && child.uuid) {
27299
+ allConnectorIds.push(child.uuid);
27300
+ }
27301
+ });
27302
+ }
27303
+ });
27304
+ console.log("\uD83D\uDD0C getAllConnectorIds(): Found ".concat(allConnectorIds.length, " total connector IDs in currentSceneData"));
27305
+ return allConnectorIds;
27306
+ }
27307
+
27308
+ /**
27309
+ * Get all available connector IDs that are not currently used in connections
27310
+ * @returns {Array} Array of available connector ID strings, or empty array if none exist
27311
+ */
27312
+ }, {
27313
+ key: "getAvailableConnections",
27314
+ value: function getAvailableConnections() {
27315
+ if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
27316
+ console.warn('⚠️ getAvailableConnections(): Scene viewer or current scene data not available');
27317
+ return [];
27318
+ }
27319
+
27320
+ // Get all connector IDs from the currentSceneData
27321
+ var allConnectorIds = this.getAllConnectorIds();
27322
+
27323
+ // Get existing connections
27324
+ var existingConnections = this.getConnections();
27325
+
27326
+ // Collect all connector IDs that are already used in connections
27327
+ var usedConnectorIds = new Set();
27328
+ existingConnections.forEach(function (connection) {
27329
+ if (connection.from) usedConnectorIds.add(connection.from);
27330
+ if (connection.to) usedConnectorIds.add(connection.to);
27331
+ });
27332
+
27333
+ // Filter out used connectors to get only available ones
27334
+ var availableConnectorIds = allConnectorIds.filter(function (id) {
27335
+ return !usedConnectorIds.has(id);
27336
+ });
27337
+ console.log("\uD83D\uDD0C getAvailableConnections(): Found ".concat(availableConnectorIds.length, " available connectors out of ").concat(allConnectorIds.length, " total connectors"));
27338
+ console.log('📋 Available connector IDs:', availableConnectorIds);
27339
+ return availableConnectorIds;
27340
+ }
27341
+
27342
+ /**
27343
+ * Get all component IDs from the scene
27344
+ * @returns {Array} Array of component ID strings, or empty array if none exist
27345
+ */
27346
+ }, {
27347
+ key: "getComponentIds",
27348
+ value: function getComponentIds() {
27349
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
27350
+ console.warn('⚠️ getComponentIds(): Scene viewer or scene not available');
27351
+ return [];
27352
+ }
27353
+ var componentIds = [];
27354
+
27355
+ // Traverse the scene to find all components
27356
+ this.sceneViewer.scene.traverse(function (child) {
27357
+ if (child.userData && child.userData.componentType === 'component') {
27358
+ var id = child.uuid || child.userData.originalUuid || child.name;
27359
+ if (id) {
27360
+ componentIds.push(id);
27361
+ }
27362
+ }
27363
+ });
27364
+ console.log("\uD83D\uDCCB getComponentIds(): Found ".concat(componentIds.length, " component IDs in scene:"), componentIds);
27365
+ return componentIds;
27366
+ }
27367
+
27110
27368
  /**
27111
27369
  * Remove a connection between two connector IDs from the connections list
27112
27370
  * @param {string} fromConnectorId - The ID of the source connector
@@ -27198,6 +27456,8 @@ var CentralPlant = /*#__PURE__*/function () {
27198
27456
  }, {
27199
27457
  key: "updatePaths",
27200
27458
  value: function updatePaths() {
27459
+ var componentId = this.sceneViewer.currentSceneData.scene.object.children[0].uuid;
27460
+ this.translate(componentId, "x", 0);
27201
27461
  this.sceneViewer.updatePaths();
27202
27462
  }
27203
27463
  }]);
@@ -71,6 +71,9 @@ var CentralPlant = /*#__PURE__*/function () {
71
71
  lastTransform: null
72
72
  };
73
73
 
74
+ // Add component counter for unique ID generation
75
+ this.componentCounter = 0;
76
+
74
77
  // Set default scene metadata
75
78
  this.setDefaultSceneMetadata();
76
79
 
@@ -248,6 +251,8 @@ var CentralPlant = /*#__PURE__*/function () {
248
251
  key: "setImportedSceneData",
249
252
  value: function setImportedSceneData(sceneData) {
250
253
  var _this$importedSceneDa, _this$importedSceneDa2;
254
+ // Clear existing scene components before importing new data
255
+ this.clearSceneComponents();
251
256
  this.importedSceneData = _rollupPluginBabelHelpers.objectSpread2({}, sceneData);
252
257
  console.log('📥 Imported scene data stored in CentralPlant:', {
253
258
  connections: ((_this$importedSceneDa = this.importedSceneData.connections) === null || _this$importedSceneDa === void 0 ? void 0 : _this$importedSceneDa.length) || 0,
@@ -255,6 +260,9 @@ var CentralPlant = /*#__PURE__*/function () {
255
260
  timestamp: new Date().toISOString()
256
261
  });
257
262
 
263
+ // Reset component counter based on imported components to avoid ID conflicts
264
+ this.resetComponentCounter();
265
+
258
266
  // Set default metadata for imported scene data
259
267
  this.setDefaultImportedSceneMetadata(sceneData);
260
268
 
@@ -306,6 +314,94 @@ var CentralPlant = /*#__PURE__*/function () {
306
314
  console.log('🗑️ Imported scene data cleared from CentralPlant');
307
315
  }
308
316
 
317
+ /**
318
+ * Clear all components from the scene while preserving lights, cameras, and environment
319
+ * This method safely removes only objects with userData.componentType = "component"
320
+ * while keeping all other scene elements like lights, cameras, controls, and environment objects
321
+ */
322
+ }, {
323
+ key: "clearSceneComponents",
324
+ value: function clearSceneComponents() {
325
+ var _this2 = this;
326
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
327
+ console.warn('⚠️ clearSceneComponents(): Scene viewer or scene not available');
328
+ return;
329
+ }
330
+ console.log('🗑️ Clearing existing scene components (userData.componentType = "component")...');
331
+
332
+ // Get all children to remove (only components with userData.componentType = "component")
333
+ var childrenToRemove = [];
334
+ this.sceneViewer.scene.traverse(function (child) {
335
+ // Skip the scene itself
336
+ if (child === _this2.sceneViewer.scene) return;
337
+
338
+ // Only remove objects that have userData.componentType = "component"
339
+ var isComponent = child.userData && child.userData.componentType === 'component';
340
+
341
+ // If it's a component and it's a direct child of the scene, mark for removal
342
+ if (isComponent && child.parent === _this2.sceneViewer.scene) {
343
+ childrenToRemove.push(child);
344
+ }
345
+ });
346
+
347
+ // Remove the identified objects
348
+ var removedCount = 0;
349
+ childrenToRemove.forEach(function (child) {
350
+ try {
351
+ // Dispose of geometries and materials to prevent memory leaks
352
+ if (child.geometry) {
353
+ child.geometry.dispose();
354
+ }
355
+ if (child.material) {
356
+ if (Array.isArray(child.material)) {
357
+ child.material.forEach(function (material) {
358
+ if (material.map) material.map.dispose();
359
+ if (material.normalMap) material.normalMap.dispose();
360
+ if (material.roughnessMap) material.roughnessMap.dispose();
361
+ if (material.metalnessMap) material.metalnessMap.dispose();
362
+ material.dispose();
363
+ });
364
+ } else {
365
+ if (child.material.map) child.material.map.dispose();
366
+ if (child.material.normalMap) child.material.normalMap.dispose();
367
+ if (child.material.roughnessMap) child.material.roughnessMap.dispose();
368
+ if (child.material.metalnessMap) child.material.metalnessMap.dispose();
369
+ child.material.dispose();
370
+ }
371
+ }
372
+
373
+ // Remove from scene
374
+ _this2.sceneViewer.scene.remove(child);
375
+ removedCount++;
376
+ } catch (error) {
377
+ console.warn('⚠️ Error removing scene object:', error, child);
378
+ }
379
+ });
380
+
381
+ // Clear any active selections or transform controls
382
+ if (this.sceneViewer.transformManager) {
383
+ try {
384
+ this.sceneViewer.transformManager.deselectObject();
385
+ } catch (error) {
386
+ console.warn('⚠️ Error deselecting objects during scene clear:', error);
387
+ }
388
+ }
389
+
390
+ // Clear connections if they exist in currentSceneData
391
+ if (this.sceneViewer.currentSceneData && this.sceneViewer.currentSceneData.connections) {
392
+ this.sceneViewer.currentSceneData.connections = [];
393
+ }
394
+
395
+ // Reset component counter
396
+ this.componentCounter = 0;
397
+ console.log("\u2705 clearSceneComponents(): Removed ".concat(removedCount, " objects from scene, preserved essential elements"));
398
+
399
+ // Trigger a render update
400
+ if (this.sceneViewer.renderer) {
401
+ this.sceneViewer.renderer.render(this.sceneViewer.scene, this.sceneViewer.camera);
402
+ }
403
+ }
404
+
309
405
  /**
310
406
  * Set a metadata attribute
311
407
  * @param {string} key - The metadata key
@@ -471,7 +567,7 @@ var CentralPlant = /*#__PURE__*/function () {
471
567
  }, {
472
568
  key: "setDefaultSceneMetadata",
473
569
  value: function setDefaultSceneMetadata() {
474
- var _this2 = this;
570
+ var _this3 = this;
475
571
  var defaultMetadata = {
476
572
  // Scene Information
477
573
  sceneInfo: {
@@ -546,8 +642,8 @@ var CentralPlant = /*#__PURE__*/function () {
546
642
 
547
643
  // Set each default metadata category
548
644
  Object.keys(defaultMetadata).forEach(function (category) {
549
- if (!_this2.hasMetadata(category)) {
550
- _this2.setMetadata(category, defaultMetadata[category]);
645
+ if (!_this3.hasMetadata(category)) {
646
+ _this3.setMetadata(category, defaultMetadata[category]);
551
647
  }
552
648
  });
553
649
  console.log('🎯 Default scene metadata initialized:', Object.keys(defaultMetadata));
@@ -1269,7 +1365,7 @@ var CentralPlant = /*#__PURE__*/function () {
1269
1365
 
1270
1366
  // Perform the translation
1271
1367
  var normalizedAxis = axis.toLowerCase();
1272
- var previousPosition = component.position[normalizedAxis];
1368
+ component.position[normalizedAxis];
1273
1369
  try {
1274
1370
  // Apply the translation
1275
1371
  component.position[normalizedAxis] += value;
@@ -1335,19 +1431,6 @@ var CentralPlant = /*#__PURE__*/function () {
1335
1431
  // // Update scene data and paths after successful translation
1336
1432
  // this.updatePaths(component)
1337
1433
 
1338
- // Log successful translation
1339
- console.log("\u2705 translate(): Component ".concat(componentId, " translated ").concat(value, " units along ").concat(normalizedAxis.toUpperCase(), "-axis"), {
1340
- componentId: componentId,
1341
- axis: normalizedAxis,
1342
- value: value,
1343
- previousPosition: previousPosition,
1344
- newPosition: component.position[normalizedAxis],
1345
- totalPosition: {
1346
- x: component.position.x.toFixed(3),
1347
- y: component.position.y.toFixed(3),
1348
- z: component.position.z.toFixed(3)
1349
- }
1350
- });
1351
1434
  return component;
1352
1435
  } catch (error) {
1353
1436
  console.error("\u274C translate(): Error translating component ".concat(componentId, ":"), error);
@@ -1365,6 +1448,71 @@ var CentralPlant = /*#__PURE__*/function () {
1365
1448
  }
1366
1449
  }
1367
1450
 
1451
+ /**
1452
+ * Generate a unique component ID that doesn't conflict with existing components
1453
+ * @param {string} libraryId - The library identifier for the component type
1454
+ * @returns {string} A unique component ID
1455
+ */
1456
+ }, {
1457
+ key: "generateUniqueComponentId",
1458
+ value: function generateUniqueComponentId(libraryId) {
1459
+ // Get all existing component IDs
1460
+ var existingIds = this.getComponentIds();
1461
+ var existingIdSet = new Set(existingIds);
1462
+ var attempts = 0;
1463
+ var maxAttempts = 1000; // Safety limit to prevent infinite loops
1464
+
1465
+ while (attempts < maxAttempts) {
1466
+ // Generate a candidate ID using the current counter
1467
+ var candidateId = this.utilities.generateUuidFromName(libraryId + '-' + (this.componentCounter + 1));
1468
+
1469
+ // Check if this ID already exists
1470
+ if (!existingIdSet.has(candidateId)) {
1471
+ // ID is unique, increment counter and return it
1472
+ this.componentCounter++;
1473
+ console.log("\u2705 generateUniqueComponentId(): Generated unique ID ".concat(candidateId, " for ").concat(libraryId, " (counter: ").concat(this.componentCounter, ")"));
1474
+ return candidateId;
1475
+ }
1476
+
1477
+ // ID exists, increment counter and try again
1478
+ this.componentCounter++;
1479
+ attempts++;
1480
+ console.warn("\u26A0\uFE0F generateUniqueComponentId(): ID collision detected for ".concat(candidateId, ", trying again (attempt ").concat(attempts, ")"));
1481
+ }
1482
+
1483
+ // Fallback: use timestamp + random number if we can't find a unique ID with counter
1484
+ var fallbackId = this.utilities.generateUuidFromName(libraryId + '-' + Date.now() + '-' + Math.random().toString(36).substring(2, 8));
1485
+ console.warn("\u26A0\uFE0F generateUniqueComponentId(): Max attempts reached, using fallback ID: ".concat(fallbackId));
1486
+ return fallbackId;
1487
+ }
1488
+
1489
+ /**
1490
+ * Reset the component counter based on existing components in the scene
1491
+ * This is useful when loading scenes that already have numbered components
1492
+ */
1493
+ }, {
1494
+ key: "resetComponentCounter",
1495
+ value: function resetComponentCounter() {
1496
+ var existingIds = this.getComponentIds();
1497
+ var maxCounter = 0;
1498
+
1499
+ // Extract counter values from existing component IDs
1500
+ existingIds.forEach(function (id) {
1501
+ // Look for patterns like "PUMP-1", "CHILLER-2", etc.
1502
+ var match = id.match(/-(\d+)(?:-|$)/);
1503
+ if (match) {
1504
+ var counter = parseInt(match[1], 10);
1505
+ if (!isNaN(counter) && counter > maxCounter) {
1506
+ maxCounter = counter;
1507
+ }
1508
+ }
1509
+ });
1510
+
1511
+ // Set the counter to one more than the highest found
1512
+ this.componentCounter = maxCounter;
1513
+ console.log("\uD83D\uDD04 resetComponentCounter(): Counter reset to ".concat(this.componentCounter, " based on ").concat(existingIds.length, " existing components"));
1514
+ }
1515
+
1368
1516
  /**
1369
1517
  * Add a new component to the scene using its library ID
1370
1518
  * @param {string} libraryId - The library identifier for the component type (e.g., 'PUMP', 'CHILLER', 'COOLING-TOWER')
@@ -1406,7 +1554,16 @@ var CentralPlant = /*#__PURE__*/function () {
1406
1554
  }
1407
1555
  try {
1408
1556
  // Generate a unique component ID if not provided
1409
- var componentId = options.customId || this.utilities.generateUuidFromName(libraryId + '_' + Date.now());
1557
+ var componentId = options.customId || this.generateUniqueComponentId(libraryId);
1558
+
1559
+ // Validate that custom IDs don't conflict with existing components
1560
+ if (options.customId) {
1561
+ var existingIds = this.getComponentIds();
1562
+ if (existingIds.includes(options.customId)) {
1563
+ console.error("\u274C addComponent(): Custom ID '".concat(options.customId, "' already exists in scene. Existing IDs:"), existingIds);
1564
+ return false;
1565
+ }
1566
+ }
1410
1567
 
1411
1568
  // Set default position within scene boundaries if not provided
1412
1569
  var position = options.position || {
@@ -1733,6 +1890,102 @@ var CentralPlant = /*#__PURE__*/function () {
1733
1890
  return this.sceneViewer.currentSceneData.connections || [];
1734
1891
  }
1735
1892
 
1893
+ /**
1894
+ * Get all connector IDs from the currentSceneData
1895
+ * @returns {Array} Array of all connector ID strings, or empty array if none exist
1896
+ */
1897
+ }, {
1898
+ key: "getAllConnectorIds",
1899
+ value: function getAllConnectorIds() {
1900
+ if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
1901
+ console.warn('⚠️ getAllConnectorIds(): Scene viewer or current scene data not available');
1902
+ return [];
1903
+ }
1904
+ var allConnectorIds = [];
1905
+ var sceneData = this.sceneViewer.currentSceneData;
1906
+
1907
+ // Check if scene data has the expected structure
1908
+ if (!sceneData.scene || !sceneData.scene.object || !sceneData.scene.object.children) {
1909
+ console.warn('⚠️ getAllConnectorIds(): Invalid scene data structure');
1910
+ return [];
1911
+ }
1912
+
1913
+ // Traverse through all components in the scene data
1914
+ sceneData.scene.object.children.forEach(function (component) {
1915
+ // Each component may have connector children
1916
+ if (component.children && Array.isArray(component.children)) {
1917
+ component.children.forEach(function (child) {
1918
+ // Check if this child is a connector
1919
+ if (child.userData && child.userData.componentType === 'connector' && child.uuid) {
1920
+ allConnectorIds.push(child.uuid);
1921
+ }
1922
+ });
1923
+ }
1924
+ });
1925
+ console.log("\uD83D\uDD0C getAllConnectorIds(): Found ".concat(allConnectorIds.length, " total connector IDs in currentSceneData"));
1926
+ return allConnectorIds;
1927
+ }
1928
+
1929
+ /**
1930
+ * Get all available connector IDs that are not currently used in connections
1931
+ * @returns {Array} Array of available connector ID strings, or empty array if none exist
1932
+ */
1933
+ }, {
1934
+ key: "getAvailableConnections",
1935
+ value: function getAvailableConnections() {
1936
+ if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
1937
+ console.warn('⚠️ getAvailableConnections(): Scene viewer or current scene data not available');
1938
+ return [];
1939
+ }
1940
+
1941
+ // Get all connector IDs from the currentSceneData
1942
+ var allConnectorIds = this.getAllConnectorIds();
1943
+
1944
+ // Get existing connections
1945
+ var existingConnections = this.getConnections();
1946
+
1947
+ // Collect all connector IDs that are already used in connections
1948
+ var usedConnectorIds = new Set();
1949
+ existingConnections.forEach(function (connection) {
1950
+ if (connection.from) usedConnectorIds.add(connection.from);
1951
+ if (connection.to) usedConnectorIds.add(connection.to);
1952
+ });
1953
+
1954
+ // Filter out used connectors to get only available ones
1955
+ var availableConnectorIds = allConnectorIds.filter(function (id) {
1956
+ return !usedConnectorIds.has(id);
1957
+ });
1958
+ console.log("\uD83D\uDD0C getAvailableConnections(): Found ".concat(availableConnectorIds.length, " available connectors out of ").concat(allConnectorIds.length, " total connectors"));
1959
+ console.log('📋 Available connector IDs:', availableConnectorIds);
1960
+ return availableConnectorIds;
1961
+ }
1962
+
1963
+ /**
1964
+ * Get all component IDs from the scene
1965
+ * @returns {Array} Array of component ID strings, or empty array if none exist
1966
+ */
1967
+ }, {
1968
+ key: "getComponentIds",
1969
+ value: function getComponentIds() {
1970
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
1971
+ console.warn('⚠️ getComponentIds(): Scene viewer or scene not available');
1972
+ return [];
1973
+ }
1974
+ var componentIds = [];
1975
+
1976
+ // Traverse the scene to find all components
1977
+ this.sceneViewer.scene.traverse(function (child) {
1978
+ if (child.userData && child.userData.componentType === 'component') {
1979
+ var id = child.uuid || child.userData.originalUuid || child.name;
1980
+ if (id) {
1981
+ componentIds.push(id);
1982
+ }
1983
+ }
1984
+ });
1985
+ console.log("\uD83D\uDCCB getComponentIds(): Found ".concat(componentIds.length, " component IDs in scene:"), componentIds);
1986
+ return componentIds;
1987
+ }
1988
+
1736
1989
  /**
1737
1990
  * Remove a connection between two connector IDs from the connections list
1738
1991
  * @param {string} fromConnectorId - The ID of the source connector
@@ -1824,6 +2077,8 @@ var CentralPlant = /*#__PURE__*/function () {
1824
2077
  }, {
1825
2078
  key: "updatePaths",
1826
2079
  value: function updatePaths() {
2080
+ var componentId = this.sceneViewer.currentSceneData.scene.object.children[0].uuid;
2081
+ this.translate(componentId, "x", 0);
1827
2082
  this.sceneViewer.updatePaths();
1828
2083
  }
1829
2084
  }]);
@@ -103,6 +103,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
103
103
  }
104
104
 
105
105
  // Ensure transform controls are still properly attached after scene operations
106
+ // Use false here since we're in the middle of clearing - enable them later in loadSceneData
106
107
  this.ensureTransformControlsAttached(false);
107
108
  console.log('✅ Scene clear operation completed');
108
109
  }
@@ -137,16 +138,22 @@ var SceneOperationsManager = /*#__PURE__*/function () {
137
138
  if (wasReattached) {
138
139
  console.log('🔧 Transform controls were reattached after scene operation');
139
140
 
140
- // Override visibility based on allowVisible parameter
141
- if (!allowVisible && component.transformManager.transformControls) {
141
+ // Set enablement based on allowVisible parameter
142
+ if (allowVisible) {
143
+ component.transformManager.setEnabled(true);
144
+ console.log('🔧 Transform controls enabled and ready for use');
145
+ } else if (component.transformManager.transformControls) {
142
146
  component.transformManager.transformControls.visible = false;
143
147
  console.log('🔧 Forcing transform controls to be invisible during load');
144
148
  }
145
149
  } else {
146
150
  console.log('✓ Transform controls are properly attached');
147
151
 
148
- // Still ensure visibility is set correctly even if not reattached
149
- if (!allowVisible && component.transformManager.transformControls) {
152
+ // Ensure proper enablement/visibility based on allowVisible parameter
153
+ if (allowVisible) {
154
+ component.transformManager.setEnabled(true);
155
+ console.log('🔧 Transform controls enabled and ready for use');
156
+ } else if (component.transformManager.transformControls) {
150
157
  component.transformManager.transformControls.visible = false;
151
158
  console.log('🔧 Ensuring transform controls remain invisible during load');
152
159
  }
@@ -694,7 +701,9 @@ var SceneOperationsManager = /*#__PURE__*/function () {
694
701
  // For non-library objects (connectors, gateways), create shared sphere geometry
695
702
  var isConnectorOrGateway = child.uuid && (child.uuid.toLowerCase().includes('connector') || child.uuid.toLowerCase().includes('gateway'));
696
703
  if (isConnectorOrGateway) {
697
- geometries[child.geometry] = new THREE__namespace.SphereGeometry(0.1, 16, 16);
704
+ if (!(child.position.x == 0 && child.position.y == 0 && child.position.z == 0)) {
705
+ geometries[child.geometry] = new THREE__namespace.SphereGeometry(0.1, 16, 16);
706
+ }
698
707
  } else {
699
708
  // Default fallback geometry
700
709
  geometries[child.geometry] = new THREE__namespace.BoxGeometry(1, 1, 1);
@@ -1050,23 +1059,19 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1050
1059
  console.log('🔧 Re-initializing transform controls after scene load');
1051
1060
  component.initTransformControls();
1052
1061
  } else {
1053
- // Keep transform controls invisible
1062
+ // Re-enable transform controls after scene load is complete
1054
1063
  if (component.transformManager.transformControls) {
1064
+ console.log('🔧 Re-enabling transform controls after scene load');
1065
+ component.transformManager.setEnabled(true);
1066
+ // Keep invisible initially, but enable functionality
1055
1067
  component.transformManager.transformControls.visible = false;
1056
- console.log('🔧 Making transform controls invisible after scene load');
1057
1068
  }
1058
1069
  }
1059
1070
 
1060
1071
  // Ensure transform controls are still properly attached to the scene after import
1061
- component.ensureTransformControlsAttached(false);
1062
-
1063
- // Keep transform controls inactive after loading scene data
1064
- if (component.transformManager && component.transformManager.transformControls) {
1065
- console.log('🔧 Keeping transform controls inactive after scene data load');
1066
- component.keepTransformControlsInactive();
1067
- component.transformManager.transformControls.visible = false;
1068
- console.log('🔒 Final verification: transform controls visibility forced to false');
1069
- }
1072
+ // Pass true to allow visibility when objects are selected
1073
+ this.ensureTransformControlsAttached(true);
1074
+ console.log('✅ Transform controls re-enabled and ready for use after scene import');
1070
1075
  }
1071
1076
  _context5.n = 13;
1072
1077
  break;
@@ -47,6 +47,9 @@ var CentralPlant = /*#__PURE__*/function () {
47
47
  lastTransform: null
48
48
  };
49
49
 
50
+ // Add component counter for unique ID generation
51
+ this.componentCounter = 0;
52
+
50
53
  // Set default scene metadata
51
54
  this.setDefaultSceneMetadata();
52
55
 
@@ -224,6 +227,8 @@ var CentralPlant = /*#__PURE__*/function () {
224
227
  key: "setImportedSceneData",
225
228
  value: function setImportedSceneData(sceneData) {
226
229
  var _this$importedSceneDa, _this$importedSceneDa2;
230
+ // Clear existing scene components before importing new data
231
+ this.clearSceneComponents();
227
232
  this.importedSceneData = _objectSpread2({}, sceneData);
228
233
  console.log('📥 Imported scene data stored in CentralPlant:', {
229
234
  connections: ((_this$importedSceneDa = this.importedSceneData.connections) === null || _this$importedSceneDa === void 0 ? void 0 : _this$importedSceneDa.length) || 0,
@@ -231,6 +236,9 @@ var CentralPlant = /*#__PURE__*/function () {
231
236
  timestamp: new Date().toISOString()
232
237
  });
233
238
 
239
+ // Reset component counter based on imported components to avoid ID conflicts
240
+ this.resetComponentCounter();
241
+
234
242
  // Set default metadata for imported scene data
235
243
  this.setDefaultImportedSceneMetadata(sceneData);
236
244
 
@@ -282,6 +290,94 @@ var CentralPlant = /*#__PURE__*/function () {
282
290
  console.log('🗑️ Imported scene data cleared from CentralPlant');
283
291
  }
284
292
 
293
+ /**
294
+ * Clear all components from the scene while preserving lights, cameras, and environment
295
+ * This method safely removes only objects with userData.componentType = "component"
296
+ * while keeping all other scene elements like lights, cameras, controls, and environment objects
297
+ */
298
+ }, {
299
+ key: "clearSceneComponents",
300
+ value: function clearSceneComponents() {
301
+ var _this2 = this;
302
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
303
+ console.warn('⚠️ clearSceneComponents(): Scene viewer or scene not available');
304
+ return;
305
+ }
306
+ console.log('🗑️ Clearing existing scene components (userData.componentType = "component")...');
307
+
308
+ // Get all children to remove (only components with userData.componentType = "component")
309
+ var childrenToRemove = [];
310
+ this.sceneViewer.scene.traverse(function (child) {
311
+ // Skip the scene itself
312
+ if (child === _this2.sceneViewer.scene) return;
313
+
314
+ // Only remove objects that have userData.componentType = "component"
315
+ var isComponent = child.userData && child.userData.componentType === 'component';
316
+
317
+ // If it's a component and it's a direct child of the scene, mark for removal
318
+ if (isComponent && child.parent === _this2.sceneViewer.scene) {
319
+ childrenToRemove.push(child);
320
+ }
321
+ });
322
+
323
+ // Remove the identified objects
324
+ var removedCount = 0;
325
+ childrenToRemove.forEach(function (child) {
326
+ try {
327
+ // Dispose of geometries and materials to prevent memory leaks
328
+ if (child.geometry) {
329
+ child.geometry.dispose();
330
+ }
331
+ if (child.material) {
332
+ if (Array.isArray(child.material)) {
333
+ child.material.forEach(function (material) {
334
+ if (material.map) material.map.dispose();
335
+ if (material.normalMap) material.normalMap.dispose();
336
+ if (material.roughnessMap) material.roughnessMap.dispose();
337
+ if (material.metalnessMap) material.metalnessMap.dispose();
338
+ material.dispose();
339
+ });
340
+ } else {
341
+ if (child.material.map) child.material.map.dispose();
342
+ if (child.material.normalMap) child.material.normalMap.dispose();
343
+ if (child.material.roughnessMap) child.material.roughnessMap.dispose();
344
+ if (child.material.metalnessMap) child.material.metalnessMap.dispose();
345
+ child.material.dispose();
346
+ }
347
+ }
348
+
349
+ // Remove from scene
350
+ _this2.sceneViewer.scene.remove(child);
351
+ removedCount++;
352
+ } catch (error) {
353
+ console.warn('⚠️ Error removing scene object:', error, child);
354
+ }
355
+ });
356
+
357
+ // Clear any active selections or transform controls
358
+ if (this.sceneViewer.transformManager) {
359
+ try {
360
+ this.sceneViewer.transformManager.deselectObject();
361
+ } catch (error) {
362
+ console.warn('⚠️ Error deselecting objects during scene clear:', error);
363
+ }
364
+ }
365
+
366
+ // Clear connections if they exist in currentSceneData
367
+ if (this.sceneViewer.currentSceneData && this.sceneViewer.currentSceneData.connections) {
368
+ this.sceneViewer.currentSceneData.connections = [];
369
+ }
370
+
371
+ // Reset component counter
372
+ this.componentCounter = 0;
373
+ console.log("\u2705 clearSceneComponents(): Removed ".concat(removedCount, " objects from scene, preserved essential elements"));
374
+
375
+ // Trigger a render update
376
+ if (this.sceneViewer.renderer) {
377
+ this.sceneViewer.renderer.render(this.sceneViewer.scene, this.sceneViewer.camera);
378
+ }
379
+ }
380
+
285
381
  /**
286
382
  * Set a metadata attribute
287
383
  * @param {string} key - The metadata key
@@ -447,7 +543,7 @@ var CentralPlant = /*#__PURE__*/function () {
447
543
  }, {
448
544
  key: "setDefaultSceneMetadata",
449
545
  value: function setDefaultSceneMetadata() {
450
- var _this2 = this;
546
+ var _this3 = this;
451
547
  var defaultMetadata = {
452
548
  // Scene Information
453
549
  sceneInfo: {
@@ -522,8 +618,8 @@ var CentralPlant = /*#__PURE__*/function () {
522
618
 
523
619
  // Set each default metadata category
524
620
  Object.keys(defaultMetadata).forEach(function (category) {
525
- if (!_this2.hasMetadata(category)) {
526
- _this2.setMetadata(category, defaultMetadata[category]);
621
+ if (!_this3.hasMetadata(category)) {
622
+ _this3.setMetadata(category, defaultMetadata[category]);
527
623
  }
528
624
  });
529
625
  console.log('🎯 Default scene metadata initialized:', Object.keys(defaultMetadata));
@@ -1245,7 +1341,7 @@ var CentralPlant = /*#__PURE__*/function () {
1245
1341
 
1246
1342
  // Perform the translation
1247
1343
  var normalizedAxis = axis.toLowerCase();
1248
- var previousPosition = component.position[normalizedAxis];
1344
+ component.position[normalizedAxis];
1249
1345
  try {
1250
1346
  // Apply the translation
1251
1347
  component.position[normalizedAxis] += value;
@@ -1311,19 +1407,6 @@ var CentralPlant = /*#__PURE__*/function () {
1311
1407
  // // Update scene data and paths after successful translation
1312
1408
  // this.updatePaths(component)
1313
1409
 
1314
- // Log successful translation
1315
- console.log("\u2705 translate(): Component ".concat(componentId, " translated ").concat(value, " units along ").concat(normalizedAxis.toUpperCase(), "-axis"), {
1316
- componentId: componentId,
1317
- axis: normalizedAxis,
1318
- value: value,
1319
- previousPosition: previousPosition,
1320
- newPosition: component.position[normalizedAxis],
1321
- totalPosition: {
1322
- x: component.position.x.toFixed(3),
1323
- y: component.position.y.toFixed(3),
1324
- z: component.position.z.toFixed(3)
1325
- }
1326
- });
1327
1410
  return component;
1328
1411
  } catch (error) {
1329
1412
  console.error("\u274C translate(): Error translating component ".concat(componentId, ":"), error);
@@ -1341,6 +1424,71 @@ var CentralPlant = /*#__PURE__*/function () {
1341
1424
  }
1342
1425
  }
1343
1426
 
1427
+ /**
1428
+ * Generate a unique component ID that doesn't conflict with existing components
1429
+ * @param {string} libraryId - The library identifier for the component type
1430
+ * @returns {string} A unique component ID
1431
+ */
1432
+ }, {
1433
+ key: "generateUniqueComponentId",
1434
+ value: function generateUniqueComponentId(libraryId) {
1435
+ // Get all existing component IDs
1436
+ var existingIds = this.getComponentIds();
1437
+ var existingIdSet = new Set(existingIds);
1438
+ var attempts = 0;
1439
+ var maxAttempts = 1000; // Safety limit to prevent infinite loops
1440
+
1441
+ while (attempts < maxAttempts) {
1442
+ // Generate a candidate ID using the current counter
1443
+ var candidateId = this.utilities.generateUuidFromName(libraryId + '-' + (this.componentCounter + 1));
1444
+
1445
+ // Check if this ID already exists
1446
+ if (!existingIdSet.has(candidateId)) {
1447
+ // ID is unique, increment counter and return it
1448
+ this.componentCounter++;
1449
+ console.log("\u2705 generateUniqueComponentId(): Generated unique ID ".concat(candidateId, " for ").concat(libraryId, " (counter: ").concat(this.componentCounter, ")"));
1450
+ return candidateId;
1451
+ }
1452
+
1453
+ // ID exists, increment counter and try again
1454
+ this.componentCounter++;
1455
+ attempts++;
1456
+ console.warn("\u26A0\uFE0F generateUniqueComponentId(): ID collision detected for ".concat(candidateId, ", trying again (attempt ").concat(attempts, ")"));
1457
+ }
1458
+
1459
+ // Fallback: use timestamp + random number if we can't find a unique ID with counter
1460
+ var fallbackId = this.utilities.generateUuidFromName(libraryId + '-' + Date.now() + '-' + Math.random().toString(36).substring(2, 8));
1461
+ console.warn("\u26A0\uFE0F generateUniqueComponentId(): Max attempts reached, using fallback ID: ".concat(fallbackId));
1462
+ return fallbackId;
1463
+ }
1464
+
1465
+ /**
1466
+ * Reset the component counter based on existing components in the scene
1467
+ * This is useful when loading scenes that already have numbered components
1468
+ */
1469
+ }, {
1470
+ key: "resetComponentCounter",
1471
+ value: function resetComponentCounter() {
1472
+ var existingIds = this.getComponentIds();
1473
+ var maxCounter = 0;
1474
+
1475
+ // Extract counter values from existing component IDs
1476
+ existingIds.forEach(function (id) {
1477
+ // Look for patterns like "PUMP-1", "CHILLER-2", etc.
1478
+ var match = id.match(/-(\d+)(?:-|$)/);
1479
+ if (match) {
1480
+ var counter = parseInt(match[1], 10);
1481
+ if (!isNaN(counter) && counter > maxCounter) {
1482
+ maxCounter = counter;
1483
+ }
1484
+ }
1485
+ });
1486
+
1487
+ // Set the counter to one more than the highest found
1488
+ this.componentCounter = maxCounter;
1489
+ console.log("\uD83D\uDD04 resetComponentCounter(): Counter reset to ".concat(this.componentCounter, " based on ").concat(existingIds.length, " existing components"));
1490
+ }
1491
+
1344
1492
  /**
1345
1493
  * Add a new component to the scene using its library ID
1346
1494
  * @param {string} libraryId - The library identifier for the component type (e.g., 'PUMP', 'CHILLER', 'COOLING-TOWER')
@@ -1382,7 +1530,16 @@ var CentralPlant = /*#__PURE__*/function () {
1382
1530
  }
1383
1531
  try {
1384
1532
  // Generate a unique component ID if not provided
1385
- var componentId = options.customId || this.utilities.generateUuidFromName(libraryId + '_' + Date.now());
1533
+ var componentId = options.customId || this.generateUniqueComponentId(libraryId);
1534
+
1535
+ // Validate that custom IDs don't conflict with existing components
1536
+ if (options.customId) {
1537
+ var existingIds = this.getComponentIds();
1538
+ if (existingIds.includes(options.customId)) {
1539
+ console.error("\u274C addComponent(): Custom ID '".concat(options.customId, "' already exists in scene. Existing IDs:"), existingIds);
1540
+ return false;
1541
+ }
1542
+ }
1386
1543
 
1387
1544
  // Set default position within scene boundaries if not provided
1388
1545
  var position = options.position || {
@@ -1709,6 +1866,102 @@ var CentralPlant = /*#__PURE__*/function () {
1709
1866
  return this.sceneViewer.currentSceneData.connections || [];
1710
1867
  }
1711
1868
 
1869
+ /**
1870
+ * Get all connector IDs from the currentSceneData
1871
+ * @returns {Array} Array of all connector ID strings, or empty array if none exist
1872
+ */
1873
+ }, {
1874
+ key: "getAllConnectorIds",
1875
+ value: function getAllConnectorIds() {
1876
+ if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
1877
+ console.warn('⚠️ getAllConnectorIds(): Scene viewer or current scene data not available');
1878
+ return [];
1879
+ }
1880
+ var allConnectorIds = [];
1881
+ var sceneData = this.sceneViewer.currentSceneData;
1882
+
1883
+ // Check if scene data has the expected structure
1884
+ if (!sceneData.scene || !sceneData.scene.object || !sceneData.scene.object.children) {
1885
+ console.warn('⚠️ getAllConnectorIds(): Invalid scene data structure');
1886
+ return [];
1887
+ }
1888
+
1889
+ // Traverse through all components in the scene data
1890
+ sceneData.scene.object.children.forEach(function (component) {
1891
+ // Each component may have connector children
1892
+ if (component.children && Array.isArray(component.children)) {
1893
+ component.children.forEach(function (child) {
1894
+ // Check if this child is a connector
1895
+ if (child.userData && child.userData.componentType === 'connector' && child.uuid) {
1896
+ allConnectorIds.push(child.uuid);
1897
+ }
1898
+ });
1899
+ }
1900
+ });
1901
+ console.log("\uD83D\uDD0C getAllConnectorIds(): Found ".concat(allConnectorIds.length, " total connector IDs in currentSceneData"));
1902
+ return allConnectorIds;
1903
+ }
1904
+
1905
+ /**
1906
+ * Get all available connector IDs that are not currently used in connections
1907
+ * @returns {Array} Array of available connector ID strings, or empty array if none exist
1908
+ */
1909
+ }, {
1910
+ key: "getAvailableConnections",
1911
+ value: function getAvailableConnections() {
1912
+ if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
1913
+ console.warn('⚠️ getAvailableConnections(): Scene viewer or current scene data not available');
1914
+ return [];
1915
+ }
1916
+
1917
+ // Get all connector IDs from the currentSceneData
1918
+ var allConnectorIds = this.getAllConnectorIds();
1919
+
1920
+ // Get existing connections
1921
+ var existingConnections = this.getConnections();
1922
+
1923
+ // Collect all connector IDs that are already used in connections
1924
+ var usedConnectorIds = new Set();
1925
+ existingConnections.forEach(function (connection) {
1926
+ if (connection.from) usedConnectorIds.add(connection.from);
1927
+ if (connection.to) usedConnectorIds.add(connection.to);
1928
+ });
1929
+
1930
+ // Filter out used connectors to get only available ones
1931
+ var availableConnectorIds = allConnectorIds.filter(function (id) {
1932
+ return !usedConnectorIds.has(id);
1933
+ });
1934
+ console.log("\uD83D\uDD0C getAvailableConnections(): Found ".concat(availableConnectorIds.length, " available connectors out of ").concat(allConnectorIds.length, " total connectors"));
1935
+ console.log('📋 Available connector IDs:', availableConnectorIds);
1936
+ return availableConnectorIds;
1937
+ }
1938
+
1939
+ /**
1940
+ * Get all component IDs from the scene
1941
+ * @returns {Array} Array of component ID strings, or empty array if none exist
1942
+ */
1943
+ }, {
1944
+ key: "getComponentIds",
1945
+ value: function getComponentIds() {
1946
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
1947
+ console.warn('⚠️ getComponentIds(): Scene viewer or scene not available');
1948
+ return [];
1949
+ }
1950
+ var componentIds = [];
1951
+
1952
+ // Traverse the scene to find all components
1953
+ this.sceneViewer.scene.traverse(function (child) {
1954
+ if (child.userData && child.userData.componentType === 'component') {
1955
+ var id = child.uuid || child.userData.originalUuid || child.name;
1956
+ if (id) {
1957
+ componentIds.push(id);
1958
+ }
1959
+ }
1960
+ });
1961
+ console.log("\uD83D\uDCCB getComponentIds(): Found ".concat(componentIds.length, " component IDs in scene:"), componentIds);
1962
+ return componentIds;
1963
+ }
1964
+
1712
1965
  /**
1713
1966
  * Remove a connection between two connector IDs from the connections list
1714
1967
  * @param {string} fromConnectorId - The ID of the source connector
@@ -1800,6 +2053,8 @@ var CentralPlant = /*#__PURE__*/function () {
1800
2053
  }, {
1801
2054
  key: "updatePaths",
1802
2055
  value: function updatePaths() {
2056
+ var componentId = this.sceneViewer.currentSceneData.scene.object.children[0].uuid;
2057
+ this.translate(componentId, "x", 0);
1803
2058
  this.sceneViewer.updatePaths();
1804
2059
  }
1805
2060
  }]);
@@ -79,6 +79,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
79
79
  }
80
80
 
81
81
  // Ensure transform controls are still properly attached after scene operations
82
+ // Use false here since we're in the middle of clearing - enable them later in loadSceneData
82
83
  this.ensureTransformControlsAttached(false);
83
84
  console.log('✅ Scene clear operation completed');
84
85
  }
@@ -113,16 +114,22 @@ var SceneOperationsManager = /*#__PURE__*/function () {
113
114
  if (wasReattached) {
114
115
  console.log('🔧 Transform controls were reattached after scene operation');
115
116
 
116
- // Override visibility based on allowVisible parameter
117
- if (!allowVisible && component.transformManager.transformControls) {
117
+ // Set enablement based on allowVisible parameter
118
+ if (allowVisible) {
119
+ component.transformManager.setEnabled(true);
120
+ console.log('🔧 Transform controls enabled and ready for use');
121
+ } else if (component.transformManager.transformControls) {
118
122
  component.transformManager.transformControls.visible = false;
119
123
  console.log('🔧 Forcing transform controls to be invisible during load');
120
124
  }
121
125
  } else {
122
126
  console.log('✓ Transform controls are properly attached');
123
127
 
124
- // Still ensure visibility is set correctly even if not reattached
125
- if (!allowVisible && component.transformManager.transformControls) {
128
+ // Ensure proper enablement/visibility based on allowVisible parameter
129
+ if (allowVisible) {
130
+ component.transformManager.setEnabled(true);
131
+ console.log('🔧 Transform controls enabled and ready for use');
132
+ } else if (component.transformManager.transformControls) {
126
133
  component.transformManager.transformControls.visible = false;
127
134
  console.log('🔧 Ensuring transform controls remain invisible during load');
128
135
  }
@@ -670,7 +677,9 @@ var SceneOperationsManager = /*#__PURE__*/function () {
670
677
  // For non-library objects (connectors, gateways), create shared sphere geometry
671
678
  var isConnectorOrGateway = child.uuid && (child.uuid.toLowerCase().includes('connector') || child.uuid.toLowerCase().includes('gateway'));
672
679
  if (isConnectorOrGateway) {
673
- geometries[child.geometry] = new THREE.SphereGeometry(0.1, 16, 16);
680
+ if (!(child.position.x == 0 && child.position.y == 0 && child.position.z == 0)) {
681
+ geometries[child.geometry] = new THREE.SphereGeometry(0.1, 16, 16);
682
+ }
674
683
  } else {
675
684
  // Default fallback geometry
676
685
  geometries[child.geometry] = new THREE.BoxGeometry(1, 1, 1);
@@ -1026,23 +1035,19 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1026
1035
  console.log('🔧 Re-initializing transform controls after scene load');
1027
1036
  component.initTransformControls();
1028
1037
  } else {
1029
- // Keep transform controls invisible
1038
+ // Re-enable transform controls after scene load is complete
1030
1039
  if (component.transformManager.transformControls) {
1040
+ console.log('🔧 Re-enabling transform controls after scene load');
1041
+ component.transformManager.setEnabled(true);
1042
+ // Keep invisible initially, but enable functionality
1031
1043
  component.transformManager.transformControls.visible = false;
1032
- console.log('🔧 Making transform controls invisible after scene load');
1033
1044
  }
1034
1045
  }
1035
1046
 
1036
1047
  // Ensure transform controls are still properly attached to the scene after import
1037
- component.ensureTransformControlsAttached(false);
1038
-
1039
- // Keep transform controls inactive after loading scene data
1040
- if (component.transformManager && component.transformManager.transformControls) {
1041
- console.log('🔧 Keeping transform controls inactive after scene data load');
1042
- component.keepTransformControlsInactive();
1043
- component.transformManager.transformControls.visible = false;
1044
- console.log('🔒 Final verification: transform controls visibility forced to false');
1045
- }
1048
+ // Pass true to allow visibility when objects are selected
1049
+ this.ensureTransformControlsAttached(true);
1050
+ console.log('✅ Transform controls re-enabled and ready for use after scene import');
1046
1051
  }
1047
1052
  _context5.n = 13;
1048
1053
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2112-lab/central-plant",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "Utility modules for the Central Plant Application",
5
5
  "main": "dist/bundle/index.js",
6
6
  "module": "dist/esm/index.js",