@2112-lab/central-plant 0.1.25 → 0.1.26

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.
@@ -25865,8 +25865,8 @@ var CentralPlant = /*#__PURE__*/function () {
25865
25865
  * Update paths in the scene
25866
25866
  * @returns {boolean} True if paths were updated successfully, false otherwise
25867
25867
  * @description Triggers an update of all connection paths/pipes in the scene to reflect
25868
- * current component positions and connections. This should be called after moving components
25869
- * or adding/removing connections.
25868
+ * current component positions and connections. This method ensures all scene data is
25869
+ * synchronized before updating paths for guaranteed accuracy.
25870
25870
  * @example
25871
25871
  * // After moving components or changing connections
25872
25872
  * const success = centralPlant.updatePaths();
@@ -25882,8 +25882,15 @@ var CentralPlant = /*#__PURE__*/function () {
25882
25882
  return false;
25883
25883
  }
25884
25884
  try {
25885
+ // Step 1: Ensure scene data is synchronized before updating paths
25886
+ console.log('🔄 updatePaths(): Synchronizing scene data before path update...');
25887
+ if (!this.syncSceneData()) {
25888
+ console.warn('⚠️ updatePaths(): Scene data synchronization failed, proceeding with caution');
25889
+ }
25890
+
25891
+ // Step 2: Update paths with synchronized data
25885
25892
  this.sceneViewer.updatePaths();
25886
- console.log('✅ updatePaths(): Paths updated successfully');
25893
+ console.log('✅ updatePaths(): Paths updated successfully with synchronized data');
25887
25894
  return true;
25888
25895
  } catch (error) {
25889
25896
  console.error('❌ updatePaths(): Error updating paths:', error);
@@ -25891,6 +25898,262 @@ var CentralPlant = /*#__PURE__*/function () {
25891
25898
  }
25892
25899
  }
25893
25900
 
25901
+ /**
25902
+ * Synchronize scene data to ensure all component positions and properties are up-to-date
25903
+ * @returns {boolean} True if synchronization was successful, false otherwise
25904
+ * @description Updates the currentSceneData to match the actual Three.js scene state.
25905
+ * This includes component positions, rotations, scales, and world bounding boxes.
25906
+ * Should be called before operations that depend on accurate scene data.
25907
+ * @example
25908
+ * // Ensure scene data is current before pathfinding
25909
+ * const success = centralPlant.syncSceneData();
25910
+ * if (success) {
25911
+ * console.log('Scene data synchronized with Three.js scene');
25912
+ * }
25913
+ */
25914
+ }, {
25915
+ key: "syncSceneData",
25916
+ value: function syncSceneData() {
25917
+ var _this = this;
25918
+ // Check if scene viewer and currentSceneData are available
25919
+ if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
25920
+ console.warn('⚠️ syncSceneData(): Scene viewer or current scene data not available');
25921
+ return false;
25922
+ }
25923
+ if (!this.sceneViewer.scene) {
25924
+ console.warn('⚠️ syncSceneData(): Three.js scene not available');
25925
+ return false;
25926
+ }
25927
+ try {
25928
+ console.log('🔄 syncSceneData(): Starting scene data synchronization...');
25929
+
25930
+ // Get reference to currentSceneData
25931
+ var currentSceneData = this.sceneViewer.currentSceneData;
25932
+ if (!currentSceneData.scene || !currentSceneData.scene.object || !currentSceneData.scene.object.children) {
25933
+ console.warn('⚠️ syncSceneData(): Invalid currentSceneData structure');
25934
+ return false;
25935
+ }
25936
+
25937
+ // Update each component in scene data to match Three.js scene
25938
+ var updatedCount = 0;
25939
+ currentSceneData.scene.object.children.forEach(function (sceneDataChild, index) {
25940
+ // Find matching Three.js object
25941
+ var matchingThreeObject = null;
25942
+ _this.sceneViewer.scene.traverse(function (threeObject) {
25943
+ var _sceneDataChild$userD, _threeObject$userData, _threeObject$userData2;
25944
+ // Check various UUID matching strategies
25945
+ if (threeObject.uuid === sceneDataChild.uuid || threeObject.uuid === ((_sceneDataChild$userD = sceneDataChild.userData) === null || _sceneDataChild$userD === void 0 ? void 0 : _sceneDataChild$userD.originalUuid) || ((_threeObject$userData = threeObject.userData) === null || _threeObject$userData === void 0 ? void 0 : _threeObject$userData.originalUuid) === sceneDataChild.uuid || ((_threeObject$userData2 = threeObject.userData) === null || _threeObject$userData2 === void 0 ? void 0 : _threeObject$userData2.hardcodedUuid) === sceneDataChild.uuid) {
25946
+ matchingThreeObject = threeObject;
25947
+ }
25948
+ });
25949
+ if (matchingThreeObject) {
25950
+ // Update position, rotation, and scale
25951
+ sceneDataChild.position = {
25952
+ x: matchingThreeObject.position.x,
25953
+ y: matchingThreeObject.position.y,
25954
+ z: matchingThreeObject.position.z
25955
+ };
25956
+ sceneDataChild.rotation = {
25957
+ x: matchingThreeObject.rotation.x,
25958
+ y: matchingThreeObject.rotation.y,
25959
+ z: matchingThreeObject.rotation.z
25960
+ };
25961
+ sceneDataChild.scale = {
25962
+ x: matchingThreeObject.scale.x,
25963
+ y: matchingThreeObject.scale.y,
25964
+ z: matchingThreeObject.scale.z
25965
+ };
25966
+
25967
+ // Update matrix
25968
+ sceneDataChild.matrix = matchingThreeObject.matrix.elements;
25969
+
25970
+ // Update world bounding box
25971
+ if (matchingThreeObject.isMesh) {
25972
+ var boundingBox = new THREE__namespace.Box3().setFromObject(matchingThreeObject);
25973
+ if (!sceneDataChild.userData) sceneDataChild.userData = {};
25974
+ sceneDataChild.userData.worldBoundingBox = {
25975
+ min: boundingBox.min.toArray(),
25976
+ max: boundingBox.max.toArray()
25977
+ };
25978
+ }
25979
+
25980
+ // Sync children (connectors) if they exist
25981
+ if (sceneDataChild.children && matchingThreeObject.children) {
25982
+ sceneDataChild.children.forEach(function (sceneChild, childIndex) {
25983
+ var matchingChild = matchingThreeObject.children.find(function (threeChild) {
25984
+ var _sceneChild$userData, _threeChild$userData;
25985
+ return threeChild.uuid === sceneChild.uuid || threeChild.uuid === ((_sceneChild$userData = sceneChild.userData) === null || _sceneChild$userData === void 0 ? void 0 : _sceneChild$userData.originalUuid) || ((_threeChild$userData = threeChild.userData) === null || _threeChild$userData === void 0 ? void 0 : _threeChild$userData.originalUuid) === sceneChild.uuid;
25986
+ });
25987
+ if (matchingChild) {
25988
+ var _matchingChild$userDa;
25989
+ // Update child position, rotation, and scale
25990
+ sceneChild.position = {
25991
+ x: matchingChild.position.x,
25992
+ y: matchingChild.position.y,
25993
+ z: matchingChild.position.z
25994
+ };
25995
+ sceneChild.rotation = {
25996
+ x: matchingChild.rotation.x,
25997
+ y: matchingChild.rotation.y,
25998
+ z: matchingChild.rotation.z
25999
+ };
26000
+ sceneChild.scale = {
26001
+ x: matchingChild.scale.x,
26002
+ y: matchingChild.scale.y,
26003
+ z: matchingChild.scale.z
26004
+ };
26005
+
26006
+ // Update direction vector for connectors
26007
+ if ((_matchingChild$userDa = matchingChild.userData) !== null && _matchingChild$userDa !== void 0 && _matchingChild$userDa.direction) {
26008
+ if (!sceneChild.userData) sceneChild.userData = {};
26009
+ sceneChild.userData.direction = _toConsumableArray(matchingChild.userData.direction);
26010
+ }
26011
+ }
26012
+ });
26013
+ }
26014
+ updatedCount++;
26015
+ } else {
26016
+ console.warn("\u26A0\uFE0F syncSceneData(): No matching Three.js object found for scene data child: ".concat(sceneDataChild.uuid));
26017
+ }
26018
+ });
26019
+
26020
+ // Force recompute world bounding boxes for pathfinding accuracy
26021
+ if (this.sceneViewer.pathfindingManager && typeof this.sceneViewer.pathfindingManager.recomputeWorldBoundingBoxes === 'function') {
26022
+ this.sceneViewer.pathfindingManager.recomputeWorldBoundingBoxes(currentSceneData);
26023
+ console.log('🔄 syncSceneData(): Recomputed world bounding boxes for pathfinding');
26024
+ }
26025
+ console.log("\u2705 syncSceneData(): Synchronized ".concat(updatedCount, " components successfully"));
26026
+ return true;
26027
+ } catch (error) {
26028
+ console.error('❌ syncSceneData(): Error synchronizing scene data:', error);
26029
+ return false;
26030
+ }
26031
+ }
26032
+
26033
+ /**
26034
+ * Force complete scene data synchronization using SceneOperationsManager
26035
+ * @returns {boolean} True if forced synchronization was successful, false otherwise
26036
+ * @description Uses the SceneOperationsManager's updateSceneDataAfterTransform method
26037
+ * to update scene data for every component. This is more thorough than syncSceneData()
26038
+ * and should be used when maximum accuracy is required.
26039
+ * @example
26040
+ * // Force complete synchronization before critical operations
26041
+ * const success = centralPlant.forceSyncSceneData();
26042
+ * if (success) {
26043
+ * console.log('Complete scene data synchronization completed');
26044
+ * }
26045
+ */
26046
+ }, {
26047
+ key: "forceSyncSceneData",
26048
+ value: function forceSyncSceneData() {
26049
+ var _this2 = this;
26050
+ // Check if scene viewer and sceneOperationsManager are available
26051
+ if (!this.sceneViewer || !this.sceneViewer.sceneOperationsManager) {
26052
+ console.warn('⚠️ forceSyncSceneData(): Scene viewer or scene operations manager not available');
26053
+ return false;
26054
+ }
26055
+ if (!this.sceneViewer.currentSceneData) {
26056
+ console.warn('⚠️ forceSyncSceneData(): Current scene data not available');
26057
+ return false;
26058
+ }
26059
+ if (!this.sceneViewer.scene) {
26060
+ console.warn('⚠️ forceSyncSceneData(): Three.js scene not available');
26061
+ return false;
26062
+ }
26063
+ try {
26064
+ console.log('🔄 forceSyncSceneData(): Starting forced scene data synchronization...');
26065
+ var syncedCount = 0;
26066
+ var currentSceneData = this.sceneViewer.currentSceneData;
26067
+
26068
+ // Traverse all objects in the Three.js scene and update their scene data
26069
+ this.sceneViewer.scene.traverse(function (threeObject) {
26070
+ // Only sync objects that have component-related userData
26071
+ if (threeObject.userData && (threeObject.userData.componentType === 'component' || threeObject.userData.componentType === 'gateway' || threeObject.userData.libraryId)) {
26072
+ console.log("\uD83D\uDD04 Syncing object: ".concat(threeObject.uuid, " (").concat(threeObject.userData.componentType || 'unknown', ")"));
26073
+
26074
+ // Use the existing updateSceneDataAfterTransform method
26075
+ var success = _this2.sceneViewer.sceneOperationsManager.updateSceneDataAfterTransform(threeObject, currentSceneData);
26076
+ if (success) {
26077
+ syncedCount++;
26078
+ } else {
26079
+ console.warn("\u26A0\uFE0F Failed to sync object: ".concat(threeObject.uuid));
26080
+ }
26081
+ }
26082
+ });
26083
+ console.log("\u2705 forceSyncSceneData(): Force synchronized ".concat(syncedCount, " objects successfully"));
26084
+ return true;
26085
+ } catch (error) {
26086
+ console.error('❌ forceSyncSceneData(): Error during forced scene data synchronization:', error);
26087
+ return false;
26088
+ }
26089
+ }
26090
+
26091
+ /**
26092
+ * Update paths with optional scene data synchronization level
26093
+ * @param {string} [syncLevel='auto'] - Level of synchronization: 'none', 'basic', 'complete', or 'auto'
26094
+ * @returns {boolean} True if paths were updated successfully, false otherwise
26095
+ * @description Enhanced updatePaths method that allows choosing the level of scene data
26096
+ * synchronization before updating paths. The 'auto' level intelligently chooses based
26097
+ * on scene complexity and recent changes.
26098
+ * @example
26099
+ * // Update paths with automatic synchronization (recommended)
26100
+ * centralPlant.updatePathsWithSync('auto');
26101
+ *
26102
+ * // Update paths with complete synchronization (most accurate)
26103
+ * centralPlant.updatePathsWithSync('complete');
26104
+ *
26105
+ * // Update paths without synchronization (fastest)
26106
+ * centralPlant.updatePathsWithSync('none');
26107
+ */
26108
+ }, {
26109
+ key: "updatePathsWithSync",
26110
+ value: function updatePathsWithSync() {
26111
+ var syncLevel = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'auto';
26112
+ if (!this.sceneViewer || !this.sceneViewer.updatePaths) {
26113
+ console.warn('⚠️ updatePathsWithSync(): Scene viewer or updatePaths method not available');
26114
+ return false;
26115
+ }
26116
+ try {
26117
+ // Determine sync level automatically if needed
26118
+ if (syncLevel === 'auto') {
26119
+ var _this$transformHistor;
26120
+ // Use basic sync by default, but upgrade to complete if recent transforms detected
26121
+ syncLevel = (_this$transformHistor = this.transformHistory) !== null && _this$transformHistor !== void 0 && _this$transformHistor.lastTransform && Date.now() - new Date(this.transformHistory.lastTransform.timestamp).getTime() < 5000 ? 'complete' : 'basic';
26122
+ console.log("\uD83E\uDD16 updatePathsWithSync(): Auto-selected sync level: ".concat(syncLevel));
26123
+ }
26124
+
26125
+ // Perform synchronization based on level
26126
+ var syncSuccess = true;
26127
+ switch (syncLevel) {
26128
+ case 'none':
26129
+ console.log('⚡ updatePathsWithSync(): Skipping synchronization for speed');
26130
+ break;
26131
+ case 'basic':
26132
+ console.log('🔄 updatePathsWithSync(): Performing basic scene data synchronization...');
26133
+ syncSuccess = this.syncSceneData();
26134
+ break;
26135
+ case 'complete':
26136
+ console.log('🔄 updatePathsWithSync(): Performing complete scene data synchronization...');
26137
+ syncSuccess = this.forceSyncSceneData();
26138
+ break;
26139
+ default:
26140
+ console.warn("\u26A0\uFE0F updatePathsWithSync(): Unknown sync level '".concat(syncLevel, "', defaulting to basic"));
26141
+ syncSuccess = this.syncSceneData();
26142
+ }
26143
+ if (!syncSuccess && syncLevel !== 'none') {
26144
+ console.warn('⚠️ updatePathsWithSync(): Scene data synchronization failed, proceeding with caution');
26145
+ }
26146
+
26147
+ // Update paths
26148
+ this.sceneViewer.updatePaths();
26149
+ console.log("\u2705 updatePathsWithSync(): Paths updated successfully with '".concat(syncLevel, "' synchronization"));
26150
+ return true;
26151
+ } catch (error) {
26152
+ console.error('❌ updatePathsWithSync(): Error updating paths with sync:', error);
26153
+ return false;
26154
+ }
26155
+ }
26156
+
25894
26157
  /**
25895
26158
  * Add a connection between two connector IDs to the connections list
25896
26159
  * @param {string} fromConnectorId - The UUID of the source connector
@@ -569,8 +569,8 @@ var CentralPlant = /*#__PURE__*/function () {
569
569
  * Update paths in the scene
570
570
  * @returns {boolean} True if paths were updated successfully, false otherwise
571
571
  * @description Triggers an update of all connection paths/pipes in the scene to reflect
572
- * current component positions and connections. This should be called after moving components
573
- * or adding/removing connections.
572
+ * current component positions and connections. This method ensures all scene data is
573
+ * synchronized before updating paths for guaranteed accuracy.
574
574
  * @example
575
575
  * // After moving components or changing connections
576
576
  * const success = centralPlant.updatePaths();
@@ -586,8 +586,15 @@ var CentralPlant = /*#__PURE__*/function () {
586
586
  return false;
587
587
  }
588
588
  try {
589
+ // Step 1: Ensure scene data is synchronized before updating paths
590
+ console.log('🔄 updatePaths(): Synchronizing scene data before path update...');
591
+ if (!this.syncSceneData()) {
592
+ console.warn('⚠️ updatePaths(): Scene data synchronization failed, proceeding with caution');
593
+ }
594
+
595
+ // Step 2: Update paths with synchronized data
589
596
  this.sceneViewer.updatePaths();
590
- console.log('✅ updatePaths(): Paths updated successfully');
597
+ console.log('✅ updatePaths(): Paths updated successfully with synchronized data');
591
598
  return true;
592
599
  } catch (error) {
593
600
  console.error('❌ updatePaths(): Error updating paths:', error);
@@ -595,6 +602,262 @@ var CentralPlant = /*#__PURE__*/function () {
595
602
  }
596
603
  }
597
604
 
605
+ /**
606
+ * Synchronize scene data to ensure all component positions and properties are up-to-date
607
+ * @returns {boolean} True if synchronization was successful, false otherwise
608
+ * @description Updates the currentSceneData to match the actual Three.js scene state.
609
+ * This includes component positions, rotations, scales, and world bounding boxes.
610
+ * Should be called before operations that depend on accurate scene data.
611
+ * @example
612
+ * // Ensure scene data is current before pathfinding
613
+ * const success = centralPlant.syncSceneData();
614
+ * if (success) {
615
+ * console.log('Scene data synchronized with Three.js scene');
616
+ * }
617
+ */
618
+ }, {
619
+ key: "syncSceneData",
620
+ value: function syncSceneData() {
621
+ var _this = this;
622
+ // Check if scene viewer and currentSceneData are available
623
+ if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
624
+ console.warn('⚠️ syncSceneData(): Scene viewer or current scene data not available');
625
+ return false;
626
+ }
627
+ if (!this.sceneViewer.scene) {
628
+ console.warn('⚠️ syncSceneData(): Three.js scene not available');
629
+ return false;
630
+ }
631
+ try {
632
+ console.log('🔄 syncSceneData(): Starting scene data synchronization...');
633
+
634
+ // Get reference to currentSceneData
635
+ var currentSceneData = this.sceneViewer.currentSceneData;
636
+ if (!currentSceneData.scene || !currentSceneData.scene.object || !currentSceneData.scene.object.children) {
637
+ console.warn('⚠️ syncSceneData(): Invalid currentSceneData structure');
638
+ return false;
639
+ }
640
+
641
+ // Update each component in scene data to match Three.js scene
642
+ var updatedCount = 0;
643
+ currentSceneData.scene.object.children.forEach(function (sceneDataChild, index) {
644
+ // Find matching Three.js object
645
+ var matchingThreeObject = null;
646
+ _this.sceneViewer.scene.traverse(function (threeObject) {
647
+ var _sceneDataChild$userD, _threeObject$userData, _threeObject$userData2;
648
+ // Check various UUID matching strategies
649
+ if (threeObject.uuid === sceneDataChild.uuid || threeObject.uuid === ((_sceneDataChild$userD = sceneDataChild.userData) === null || _sceneDataChild$userD === void 0 ? void 0 : _sceneDataChild$userD.originalUuid) || ((_threeObject$userData = threeObject.userData) === null || _threeObject$userData === void 0 ? void 0 : _threeObject$userData.originalUuid) === sceneDataChild.uuid || ((_threeObject$userData2 = threeObject.userData) === null || _threeObject$userData2 === void 0 ? void 0 : _threeObject$userData2.hardcodedUuid) === sceneDataChild.uuid) {
650
+ matchingThreeObject = threeObject;
651
+ }
652
+ });
653
+ if (matchingThreeObject) {
654
+ // Update position, rotation, and scale
655
+ sceneDataChild.position = {
656
+ x: matchingThreeObject.position.x,
657
+ y: matchingThreeObject.position.y,
658
+ z: matchingThreeObject.position.z
659
+ };
660
+ sceneDataChild.rotation = {
661
+ x: matchingThreeObject.rotation.x,
662
+ y: matchingThreeObject.rotation.y,
663
+ z: matchingThreeObject.rotation.z
664
+ };
665
+ sceneDataChild.scale = {
666
+ x: matchingThreeObject.scale.x,
667
+ y: matchingThreeObject.scale.y,
668
+ z: matchingThreeObject.scale.z
669
+ };
670
+
671
+ // Update matrix
672
+ sceneDataChild.matrix = matchingThreeObject.matrix.elements;
673
+
674
+ // Update world bounding box
675
+ if (matchingThreeObject.isMesh) {
676
+ var boundingBox = new THREE__namespace.Box3().setFromObject(matchingThreeObject);
677
+ if (!sceneDataChild.userData) sceneDataChild.userData = {};
678
+ sceneDataChild.userData.worldBoundingBox = {
679
+ min: boundingBox.min.toArray(),
680
+ max: boundingBox.max.toArray()
681
+ };
682
+ }
683
+
684
+ // Sync children (connectors) if they exist
685
+ if (sceneDataChild.children && matchingThreeObject.children) {
686
+ sceneDataChild.children.forEach(function (sceneChild, childIndex) {
687
+ var matchingChild = matchingThreeObject.children.find(function (threeChild) {
688
+ var _sceneChild$userData, _threeChild$userData;
689
+ return threeChild.uuid === sceneChild.uuid || threeChild.uuid === ((_sceneChild$userData = sceneChild.userData) === null || _sceneChild$userData === void 0 ? void 0 : _sceneChild$userData.originalUuid) || ((_threeChild$userData = threeChild.userData) === null || _threeChild$userData === void 0 ? void 0 : _threeChild$userData.originalUuid) === sceneChild.uuid;
690
+ });
691
+ if (matchingChild) {
692
+ var _matchingChild$userDa;
693
+ // Update child position, rotation, and scale
694
+ sceneChild.position = {
695
+ x: matchingChild.position.x,
696
+ y: matchingChild.position.y,
697
+ z: matchingChild.position.z
698
+ };
699
+ sceneChild.rotation = {
700
+ x: matchingChild.rotation.x,
701
+ y: matchingChild.rotation.y,
702
+ z: matchingChild.rotation.z
703
+ };
704
+ sceneChild.scale = {
705
+ x: matchingChild.scale.x,
706
+ y: matchingChild.scale.y,
707
+ z: matchingChild.scale.z
708
+ };
709
+
710
+ // Update direction vector for connectors
711
+ if ((_matchingChild$userDa = matchingChild.userData) !== null && _matchingChild$userDa !== void 0 && _matchingChild$userDa.direction) {
712
+ if (!sceneChild.userData) sceneChild.userData = {};
713
+ sceneChild.userData.direction = _rollupPluginBabelHelpers.toConsumableArray(matchingChild.userData.direction);
714
+ }
715
+ }
716
+ });
717
+ }
718
+ updatedCount++;
719
+ } else {
720
+ console.warn("\u26A0\uFE0F syncSceneData(): No matching Three.js object found for scene data child: ".concat(sceneDataChild.uuid));
721
+ }
722
+ });
723
+
724
+ // Force recompute world bounding boxes for pathfinding accuracy
725
+ if (this.sceneViewer.pathfindingManager && typeof this.sceneViewer.pathfindingManager.recomputeWorldBoundingBoxes === 'function') {
726
+ this.sceneViewer.pathfindingManager.recomputeWorldBoundingBoxes(currentSceneData);
727
+ console.log('🔄 syncSceneData(): Recomputed world bounding boxes for pathfinding');
728
+ }
729
+ console.log("\u2705 syncSceneData(): Synchronized ".concat(updatedCount, " components successfully"));
730
+ return true;
731
+ } catch (error) {
732
+ console.error('❌ syncSceneData(): Error synchronizing scene data:', error);
733
+ return false;
734
+ }
735
+ }
736
+
737
+ /**
738
+ * Force complete scene data synchronization using SceneOperationsManager
739
+ * @returns {boolean} True if forced synchronization was successful, false otherwise
740
+ * @description Uses the SceneOperationsManager's updateSceneDataAfterTransform method
741
+ * to update scene data for every component. This is more thorough than syncSceneData()
742
+ * and should be used when maximum accuracy is required.
743
+ * @example
744
+ * // Force complete synchronization before critical operations
745
+ * const success = centralPlant.forceSyncSceneData();
746
+ * if (success) {
747
+ * console.log('Complete scene data synchronization completed');
748
+ * }
749
+ */
750
+ }, {
751
+ key: "forceSyncSceneData",
752
+ value: function forceSyncSceneData() {
753
+ var _this2 = this;
754
+ // Check if scene viewer and sceneOperationsManager are available
755
+ if (!this.sceneViewer || !this.sceneViewer.sceneOperationsManager) {
756
+ console.warn('⚠️ forceSyncSceneData(): Scene viewer or scene operations manager not available');
757
+ return false;
758
+ }
759
+ if (!this.sceneViewer.currentSceneData) {
760
+ console.warn('⚠️ forceSyncSceneData(): Current scene data not available');
761
+ return false;
762
+ }
763
+ if (!this.sceneViewer.scene) {
764
+ console.warn('⚠️ forceSyncSceneData(): Three.js scene not available');
765
+ return false;
766
+ }
767
+ try {
768
+ console.log('🔄 forceSyncSceneData(): Starting forced scene data synchronization...');
769
+ var syncedCount = 0;
770
+ var currentSceneData = this.sceneViewer.currentSceneData;
771
+
772
+ // Traverse all objects in the Three.js scene and update their scene data
773
+ this.sceneViewer.scene.traverse(function (threeObject) {
774
+ // Only sync objects that have component-related userData
775
+ if (threeObject.userData && (threeObject.userData.componentType === 'component' || threeObject.userData.componentType === 'gateway' || threeObject.userData.libraryId)) {
776
+ console.log("\uD83D\uDD04 Syncing object: ".concat(threeObject.uuid, " (").concat(threeObject.userData.componentType || 'unknown', ")"));
777
+
778
+ // Use the existing updateSceneDataAfterTransform method
779
+ var success = _this2.sceneViewer.sceneOperationsManager.updateSceneDataAfterTransform(threeObject, currentSceneData);
780
+ if (success) {
781
+ syncedCount++;
782
+ } else {
783
+ console.warn("\u26A0\uFE0F Failed to sync object: ".concat(threeObject.uuid));
784
+ }
785
+ }
786
+ });
787
+ console.log("\u2705 forceSyncSceneData(): Force synchronized ".concat(syncedCount, " objects successfully"));
788
+ return true;
789
+ } catch (error) {
790
+ console.error('❌ forceSyncSceneData(): Error during forced scene data synchronization:', error);
791
+ return false;
792
+ }
793
+ }
794
+
795
+ /**
796
+ * Update paths with optional scene data synchronization level
797
+ * @param {string} [syncLevel='auto'] - Level of synchronization: 'none', 'basic', 'complete', or 'auto'
798
+ * @returns {boolean} True if paths were updated successfully, false otherwise
799
+ * @description Enhanced updatePaths method that allows choosing the level of scene data
800
+ * synchronization before updating paths. The 'auto' level intelligently chooses based
801
+ * on scene complexity and recent changes.
802
+ * @example
803
+ * // Update paths with automatic synchronization (recommended)
804
+ * centralPlant.updatePathsWithSync('auto');
805
+ *
806
+ * // Update paths with complete synchronization (most accurate)
807
+ * centralPlant.updatePathsWithSync('complete');
808
+ *
809
+ * // Update paths without synchronization (fastest)
810
+ * centralPlant.updatePathsWithSync('none');
811
+ */
812
+ }, {
813
+ key: "updatePathsWithSync",
814
+ value: function updatePathsWithSync() {
815
+ var syncLevel = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'auto';
816
+ if (!this.sceneViewer || !this.sceneViewer.updatePaths) {
817
+ console.warn('⚠️ updatePathsWithSync(): Scene viewer or updatePaths method not available');
818
+ return false;
819
+ }
820
+ try {
821
+ // Determine sync level automatically if needed
822
+ if (syncLevel === 'auto') {
823
+ var _this$transformHistor;
824
+ // Use basic sync by default, but upgrade to complete if recent transforms detected
825
+ syncLevel = (_this$transformHistor = this.transformHistory) !== null && _this$transformHistor !== void 0 && _this$transformHistor.lastTransform && Date.now() - new Date(this.transformHistory.lastTransform.timestamp).getTime() < 5000 ? 'complete' : 'basic';
826
+ console.log("\uD83E\uDD16 updatePathsWithSync(): Auto-selected sync level: ".concat(syncLevel));
827
+ }
828
+
829
+ // Perform synchronization based on level
830
+ var syncSuccess = true;
831
+ switch (syncLevel) {
832
+ case 'none':
833
+ console.log('⚡ updatePathsWithSync(): Skipping synchronization for speed');
834
+ break;
835
+ case 'basic':
836
+ console.log('🔄 updatePathsWithSync(): Performing basic scene data synchronization...');
837
+ syncSuccess = this.syncSceneData();
838
+ break;
839
+ case 'complete':
840
+ console.log('🔄 updatePathsWithSync(): Performing complete scene data synchronization...');
841
+ syncSuccess = this.forceSyncSceneData();
842
+ break;
843
+ default:
844
+ console.warn("\u26A0\uFE0F updatePathsWithSync(): Unknown sync level '".concat(syncLevel, "', defaulting to basic"));
845
+ syncSuccess = this.syncSceneData();
846
+ }
847
+ if (!syncSuccess && syncLevel !== 'none') {
848
+ console.warn('⚠️ updatePathsWithSync(): Scene data synchronization failed, proceeding with caution');
849
+ }
850
+
851
+ // Update paths
852
+ this.sceneViewer.updatePaths();
853
+ console.log("\u2705 updatePathsWithSync(): Paths updated successfully with '".concat(syncLevel, "' synchronization"));
854
+ return true;
855
+ } catch (error) {
856
+ console.error('❌ updatePathsWithSync(): Error updating paths with sync:', error);
857
+ return false;
858
+ }
859
+ }
860
+
598
861
  /**
599
862
  * Add a connection between two connector IDs to the connections list
600
863
  * @param {string} fromConnectorId - The UUID of the source connector
@@ -1,4 +1,4 @@
1
- import { createClass as _createClass, objectSpread2 as _objectSpread2, classCallCheck as _classCallCheck } from '../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { createClass as _createClass, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray, classCallCheck as _classCallCheck } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import * as THREE from 'three';
3
3
  import { CentralPlantInternals } from './centralPlantInternals.js';
4
4
  import '../rendering/modelPreloader.js';
@@ -545,8 +545,8 @@ var CentralPlant = /*#__PURE__*/function () {
545
545
  * Update paths in the scene
546
546
  * @returns {boolean} True if paths were updated successfully, false otherwise
547
547
  * @description Triggers an update of all connection paths/pipes in the scene to reflect
548
- * current component positions and connections. This should be called after moving components
549
- * or adding/removing connections.
548
+ * current component positions and connections. This method ensures all scene data is
549
+ * synchronized before updating paths for guaranteed accuracy.
550
550
  * @example
551
551
  * // After moving components or changing connections
552
552
  * const success = centralPlant.updatePaths();
@@ -562,8 +562,15 @@ var CentralPlant = /*#__PURE__*/function () {
562
562
  return false;
563
563
  }
564
564
  try {
565
+ // Step 1: Ensure scene data is synchronized before updating paths
566
+ console.log('🔄 updatePaths(): Synchronizing scene data before path update...');
567
+ if (!this.syncSceneData()) {
568
+ console.warn('⚠️ updatePaths(): Scene data synchronization failed, proceeding with caution');
569
+ }
570
+
571
+ // Step 2: Update paths with synchronized data
565
572
  this.sceneViewer.updatePaths();
566
- console.log('✅ updatePaths(): Paths updated successfully');
573
+ console.log('✅ updatePaths(): Paths updated successfully with synchronized data');
567
574
  return true;
568
575
  } catch (error) {
569
576
  console.error('❌ updatePaths(): Error updating paths:', error);
@@ -571,6 +578,262 @@ var CentralPlant = /*#__PURE__*/function () {
571
578
  }
572
579
  }
573
580
 
581
+ /**
582
+ * Synchronize scene data to ensure all component positions and properties are up-to-date
583
+ * @returns {boolean} True if synchronization was successful, false otherwise
584
+ * @description Updates the currentSceneData to match the actual Three.js scene state.
585
+ * This includes component positions, rotations, scales, and world bounding boxes.
586
+ * Should be called before operations that depend on accurate scene data.
587
+ * @example
588
+ * // Ensure scene data is current before pathfinding
589
+ * const success = centralPlant.syncSceneData();
590
+ * if (success) {
591
+ * console.log('Scene data synchronized with Three.js scene');
592
+ * }
593
+ */
594
+ }, {
595
+ key: "syncSceneData",
596
+ value: function syncSceneData() {
597
+ var _this = this;
598
+ // Check if scene viewer and currentSceneData are available
599
+ if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
600
+ console.warn('⚠️ syncSceneData(): Scene viewer or current scene data not available');
601
+ return false;
602
+ }
603
+ if (!this.sceneViewer.scene) {
604
+ console.warn('⚠️ syncSceneData(): Three.js scene not available');
605
+ return false;
606
+ }
607
+ try {
608
+ console.log('🔄 syncSceneData(): Starting scene data synchronization...');
609
+
610
+ // Get reference to currentSceneData
611
+ var currentSceneData = this.sceneViewer.currentSceneData;
612
+ if (!currentSceneData.scene || !currentSceneData.scene.object || !currentSceneData.scene.object.children) {
613
+ console.warn('⚠️ syncSceneData(): Invalid currentSceneData structure');
614
+ return false;
615
+ }
616
+
617
+ // Update each component in scene data to match Three.js scene
618
+ var updatedCount = 0;
619
+ currentSceneData.scene.object.children.forEach(function (sceneDataChild, index) {
620
+ // Find matching Three.js object
621
+ var matchingThreeObject = null;
622
+ _this.sceneViewer.scene.traverse(function (threeObject) {
623
+ var _sceneDataChild$userD, _threeObject$userData, _threeObject$userData2;
624
+ // Check various UUID matching strategies
625
+ if (threeObject.uuid === sceneDataChild.uuid || threeObject.uuid === ((_sceneDataChild$userD = sceneDataChild.userData) === null || _sceneDataChild$userD === void 0 ? void 0 : _sceneDataChild$userD.originalUuid) || ((_threeObject$userData = threeObject.userData) === null || _threeObject$userData === void 0 ? void 0 : _threeObject$userData.originalUuid) === sceneDataChild.uuid || ((_threeObject$userData2 = threeObject.userData) === null || _threeObject$userData2 === void 0 ? void 0 : _threeObject$userData2.hardcodedUuid) === sceneDataChild.uuid) {
626
+ matchingThreeObject = threeObject;
627
+ }
628
+ });
629
+ if (matchingThreeObject) {
630
+ // Update position, rotation, and scale
631
+ sceneDataChild.position = {
632
+ x: matchingThreeObject.position.x,
633
+ y: matchingThreeObject.position.y,
634
+ z: matchingThreeObject.position.z
635
+ };
636
+ sceneDataChild.rotation = {
637
+ x: matchingThreeObject.rotation.x,
638
+ y: matchingThreeObject.rotation.y,
639
+ z: matchingThreeObject.rotation.z
640
+ };
641
+ sceneDataChild.scale = {
642
+ x: matchingThreeObject.scale.x,
643
+ y: matchingThreeObject.scale.y,
644
+ z: matchingThreeObject.scale.z
645
+ };
646
+
647
+ // Update matrix
648
+ sceneDataChild.matrix = matchingThreeObject.matrix.elements;
649
+
650
+ // Update world bounding box
651
+ if (matchingThreeObject.isMesh) {
652
+ var boundingBox = new THREE.Box3().setFromObject(matchingThreeObject);
653
+ if (!sceneDataChild.userData) sceneDataChild.userData = {};
654
+ sceneDataChild.userData.worldBoundingBox = {
655
+ min: boundingBox.min.toArray(),
656
+ max: boundingBox.max.toArray()
657
+ };
658
+ }
659
+
660
+ // Sync children (connectors) if they exist
661
+ if (sceneDataChild.children && matchingThreeObject.children) {
662
+ sceneDataChild.children.forEach(function (sceneChild, childIndex) {
663
+ var matchingChild = matchingThreeObject.children.find(function (threeChild) {
664
+ var _sceneChild$userData, _threeChild$userData;
665
+ return threeChild.uuid === sceneChild.uuid || threeChild.uuid === ((_sceneChild$userData = sceneChild.userData) === null || _sceneChild$userData === void 0 ? void 0 : _sceneChild$userData.originalUuid) || ((_threeChild$userData = threeChild.userData) === null || _threeChild$userData === void 0 ? void 0 : _threeChild$userData.originalUuid) === sceneChild.uuid;
666
+ });
667
+ if (matchingChild) {
668
+ var _matchingChild$userDa;
669
+ // Update child position, rotation, and scale
670
+ sceneChild.position = {
671
+ x: matchingChild.position.x,
672
+ y: matchingChild.position.y,
673
+ z: matchingChild.position.z
674
+ };
675
+ sceneChild.rotation = {
676
+ x: matchingChild.rotation.x,
677
+ y: matchingChild.rotation.y,
678
+ z: matchingChild.rotation.z
679
+ };
680
+ sceneChild.scale = {
681
+ x: matchingChild.scale.x,
682
+ y: matchingChild.scale.y,
683
+ z: matchingChild.scale.z
684
+ };
685
+
686
+ // Update direction vector for connectors
687
+ if ((_matchingChild$userDa = matchingChild.userData) !== null && _matchingChild$userDa !== void 0 && _matchingChild$userDa.direction) {
688
+ if (!sceneChild.userData) sceneChild.userData = {};
689
+ sceneChild.userData.direction = _toConsumableArray(matchingChild.userData.direction);
690
+ }
691
+ }
692
+ });
693
+ }
694
+ updatedCount++;
695
+ } else {
696
+ console.warn("\u26A0\uFE0F syncSceneData(): No matching Three.js object found for scene data child: ".concat(sceneDataChild.uuid));
697
+ }
698
+ });
699
+
700
+ // Force recompute world bounding boxes for pathfinding accuracy
701
+ if (this.sceneViewer.pathfindingManager && typeof this.sceneViewer.pathfindingManager.recomputeWorldBoundingBoxes === 'function') {
702
+ this.sceneViewer.pathfindingManager.recomputeWorldBoundingBoxes(currentSceneData);
703
+ console.log('🔄 syncSceneData(): Recomputed world bounding boxes for pathfinding');
704
+ }
705
+ console.log("\u2705 syncSceneData(): Synchronized ".concat(updatedCount, " components successfully"));
706
+ return true;
707
+ } catch (error) {
708
+ console.error('❌ syncSceneData(): Error synchronizing scene data:', error);
709
+ return false;
710
+ }
711
+ }
712
+
713
+ /**
714
+ * Force complete scene data synchronization using SceneOperationsManager
715
+ * @returns {boolean} True if forced synchronization was successful, false otherwise
716
+ * @description Uses the SceneOperationsManager's updateSceneDataAfterTransform method
717
+ * to update scene data for every component. This is more thorough than syncSceneData()
718
+ * and should be used when maximum accuracy is required.
719
+ * @example
720
+ * // Force complete synchronization before critical operations
721
+ * const success = centralPlant.forceSyncSceneData();
722
+ * if (success) {
723
+ * console.log('Complete scene data synchronization completed');
724
+ * }
725
+ */
726
+ }, {
727
+ key: "forceSyncSceneData",
728
+ value: function forceSyncSceneData() {
729
+ var _this2 = this;
730
+ // Check if scene viewer and sceneOperationsManager are available
731
+ if (!this.sceneViewer || !this.sceneViewer.sceneOperationsManager) {
732
+ console.warn('⚠️ forceSyncSceneData(): Scene viewer or scene operations manager not available');
733
+ return false;
734
+ }
735
+ if (!this.sceneViewer.currentSceneData) {
736
+ console.warn('⚠️ forceSyncSceneData(): Current scene data not available');
737
+ return false;
738
+ }
739
+ if (!this.sceneViewer.scene) {
740
+ console.warn('⚠️ forceSyncSceneData(): Three.js scene not available');
741
+ return false;
742
+ }
743
+ try {
744
+ console.log('🔄 forceSyncSceneData(): Starting forced scene data synchronization...');
745
+ var syncedCount = 0;
746
+ var currentSceneData = this.sceneViewer.currentSceneData;
747
+
748
+ // Traverse all objects in the Three.js scene and update their scene data
749
+ this.sceneViewer.scene.traverse(function (threeObject) {
750
+ // Only sync objects that have component-related userData
751
+ if (threeObject.userData && (threeObject.userData.componentType === 'component' || threeObject.userData.componentType === 'gateway' || threeObject.userData.libraryId)) {
752
+ console.log("\uD83D\uDD04 Syncing object: ".concat(threeObject.uuid, " (").concat(threeObject.userData.componentType || 'unknown', ")"));
753
+
754
+ // Use the existing updateSceneDataAfterTransform method
755
+ var success = _this2.sceneViewer.sceneOperationsManager.updateSceneDataAfterTransform(threeObject, currentSceneData);
756
+ if (success) {
757
+ syncedCount++;
758
+ } else {
759
+ console.warn("\u26A0\uFE0F Failed to sync object: ".concat(threeObject.uuid));
760
+ }
761
+ }
762
+ });
763
+ console.log("\u2705 forceSyncSceneData(): Force synchronized ".concat(syncedCount, " objects successfully"));
764
+ return true;
765
+ } catch (error) {
766
+ console.error('❌ forceSyncSceneData(): Error during forced scene data synchronization:', error);
767
+ return false;
768
+ }
769
+ }
770
+
771
+ /**
772
+ * Update paths with optional scene data synchronization level
773
+ * @param {string} [syncLevel='auto'] - Level of synchronization: 'none', 'basic', 'complete', or 'auto'
774
+ * @returns {boolean} True if paths were updated successfully, false otherwise
775
+ * @description Enhanced updatePaths method that allows choosing the level of scene data
776
+ * synchronization before updating paths. The 'auto' level intelligently chooses based
777
+ * on scene complexity and recent changes.
778
+ * @example
779
+ * // Update paths with automatic synchronization (recommended)
780
+ * centralPlant.updatePathsWithSync('auto');
781
+ *
782
+ * // Update paths with complete synchronization (most accurate)
783
+ * centralPlant.updatePathsWithSync('complete');
784
+ *
785
+ * // Update paths without synchronization (fastest)
786
+ * centralPlant.updatePathsWithSync('none');
787
+ */
788
+ }, {
789
+ key: "updatePathsWithSync",
790
+ value: function updatePathsWithSync() {
791
+ var syncLevel = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'auto';
792
+ if (!this.sceneViewer || !this.sceneViewer.updatePaths) {
793
+ console.warn('⚠️ updatePathsWithSync(): Scene viewer or updatePaths method not available');
794
+ return false;
795
+ }
796
+ try {
797
+ // Determine sync level automatically if needed
798
+ if (syncLevel === 'auto') {
799
+ var _this$transformHistor;
800
+ // Use basic sync by default, but upgrade to complete if recent transforms detected
801
+ syncLevel = (_this$transformHistor = this.transformHistory) !== null && _this$transformHistor !== void 0 && _this$transformHistor.lastTransform && Date.now() - new Date(this.transformHistory.lastTransform.timestamp).getTime() < 5000 ? 'complete' : 'basic';
802
+ console.log("\uD83E\uDD16 updatePathsWithSync(): Auto-selected sync level: ".concat(syncLevel));
803
+ }
804
+
805
+ // Perform synchronization based on level
806
+ var syncSuccess = true;
807
+ switch (syncLevel) {
808
+ case 'none':
809
+ console.log('⚡ updatePathsWithSync(): Skipping synchronization for speed');
810
+ break;
811
+ case 'basic':
812
+ console.log('🔄 updatePathsWithSync(): Performing basic scene data synchronization...');
813
+ syncSuccess = this.syncSceneData();
814
+ break;
815
+ case 'complete':
816
+ console.log('🔄 updatePathsWithSync(): Performing complete scene data synchronization...');
817
+ syncSuccess = this.forceSyncSceneData();
818
+ break;
819
+ default:
820
+ console.warn("\u26A0\uFE0F updatePathsWithSync(): Unknown sync level '".concat(syncLevel, "', defaulting to basic"));
821
+ syncSuccess = this.syncSceneData();
822
+ }
823
+ if (!syncSuccess && syncLevel !== 'none') {
824
+ console.warn('⚠️ updatePathsWithSync(): Scene data synchronization failed, proceeding with caution');
825
+ }
826
+
827
+ // Update paths
828
+ this.sceneViewer.updatePaths();
829
+ console.log("\u2705 updatePathsWithSync(): Paths updated successfully with '".concat(syncLevel, "' synchronization"));
830
+ return true;
831
+ } catch (error) {
832
+ console.error('❌ updatePathsWithSync(): Error updating paths with sync:', error);
833
+ return false;
834
+ }
835
+ }
836
+
574
837
  /**
575
838
  * Add a connection between two connector IDs to the connections list
576
839
  * @param {string} fromConnectorId - The UUID of the source connector
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@2112-lab/central-plant",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
4
4
  "description": "Utility modules for the Central Plant Application",
5
5
  "main": "dist/bundle/index.js",
6
6
  "module": "dist/esm/index.js",