@2112-lab/central-plant 0.2.8 → 0.2.12

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.
@@ -410,7 +410,11 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
410
410
  key: "_executePathfinding",
411
411
  value: (function () {
412
412
  var _executePathfinding2 = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee(sceneData, connections) {
413
- var _sceneDataCopy$childr, _sceneDataCopy$childr2, _pathfindingResult$pa, _pathfindingResult$pa2;
413
+ var _this4 = this,
414
+ _sceneDataCopy$childr,
415
+ _sceneDataCopy$childr2,
416
+ _pathfindingResult$pa,
417
+ _pathfindingResult$pa2;
414
418
  var options,
415
419
  _options$context,
416
420
  context,
@@ -471,6 +475,15 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
471
475
 
472
476
  // Create pipe paths with materials using the paths from pathfinder
473
477
  this.renderingManager.createPipePaths(pathfindingResult.paths, this.crosscubeTextureSet);
478
+
479
+ // ── Stage 3b: Ensure PathData entries exist for all rendered paths ──────
480
+ // This preserves any flowAttributes already set on existing entries.
481
+ if (pathfindingResult.paths) {
482
+ pathfindingResult.paths.forEach(function (path) {
483
+ var pathId = "".concat(path.from, "-->").concat(path.to);
484
+ _this4._getOrCreatePathData(pathId, path.from, path.to);
485
+ });
486
+ }
474
487
  timers.pathRendering = performance.now() - renderStart;
475
488
 
476
489
  // ── Performance Summary ────────────────────────────────────────────
@@ -508,6 +521,123 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
508
521
  return this.sceneDataManager.getSimplifiedSceneData();
509
522
  }
510
523
 
524
+ /**
525
+ * Return an existing PathData for pathId from the store, or create and register a new one.
526
+ * Preserves existing flowAttributes when the entry already exists.
527
+ *
528
+ * @param {string} pathId - Canonical path identifier "${from}-->${to}"
529
+ * @param {string} from - Source connector ID
530
+ * @param {string} to - Target connector ID
531
+ * @returns {PathData}
532
+ * @private
533
+ */
534
+ }, {
535
+ key: "_getOrCreatePathData",
536
+ value: function _getOrCreatePathData(pathId, from, to) {
537
+ if (!this.pathDataStore.has(pathId)) {
538
+ var pd = new pathfindingData.PathData(pathId, from, to);
539
+ this.pathDataStore.set(pathId, pd);
540
+ }
541
+ return this.pathDataStore.get(pathId);
542
+ }
543
+
544
+ /**
545
+ * Propagate flowAttributes from the original connection list to any gateway-split
546
+ * rendered sub-paths in pathDataStore, then apply all flow visualizations.
547
+ * Called after every pathfinding execution (initial load and transform updates).
548
+ *
549
+ * @param {Array} connections - Original connections array (may include flowAttributes)
550
+ * @param {object} pathfindingResult - Result returned by _executePathfinding
551
+ * @private
552
+ */
553
+ }, {
554
+ key: "_propagateFlowAttributesAndApplyVisualizations",
555
+ value: function _propagateFlowAttributesAndApplyVisualizations(connections, pathfindingResult) {
556
+ var _this5 = this,
557
+ _this$sceneViewer;
558
+ if (!Array.isArray(connections) || !pathfindingResult) return;
559
+
560
+ // Pass 1: use the explicit gateway connection mappings to build a precise
561
+ // original-pathId → Set<renderedPathId> map.
562
+ var originalToSubPaths = new Map();
563
+ if (pathfindingResult.gateways) {
564
+ pathfindingResult.gateways.forEach(function (gateway) {
565
+ var _ref = gateway.connections || {},
566
+ removed = _ref.removed,
567
+ added = _ref.added;
568
+ if (!(removed !== null && removed !== void 0 && removed.length) || !(added !== null && added !== void 0 && added.length)) return;
569
+ removed.forEach(function (removedConn) {
570
+ var origId = "".concat(removedConn.from, "-->").concat(removedConn.to);
571
+ if (!originalToSubPaths.has(origId)) originalToSubPaths.set(origId, new Set());
572
+ added.forEach(function (addedConn) {
573
+ originalToSubPaths.get(origId).add("".concat(addedConn.from, "-->").concat(addedConn.to));
574
+ });
575
+ });
576
+ });
577
+ }
578
+ connections.forEach(function (conn) {
579
+ if (!conn.flowAttributes) return;
580
+ var origId = "".concat(conn.from, "-->").concat(conn.to);
581
+ var subPathIds = new Set(originalToSubPaths.get(origId) || []);
582
+ subPathIds.add(origId);
583
+ subPathIds.forEach(function (subPathId) {
584
+ var pd = _this5.pathDataStore.get(subPathId);
585
+ if (pd && Object.keys(pd.flowAttributes).length === 0) {
586
+ Object.entries(conn.flowAttributes).forEach(function (_ref2) {
587
+ var _ref3 = _rollupPluginBabelHelpers.slicedToArray(_ref2, 2),
588
+ key = _ref3[0],
589
+ value = _ref3[1];
590
+ return pd.setFlowAttribute(key, value);
591
+ });
592
+ }
593
+ });
594
+ });
595
+
596
+ // Pass 2: endpoint fallback for Gateway→Gateway intermediate segments and
597
+ // for paths whose connections were restructured by manualizeSegment/manualizeGateway.
598
+ // After manualization, currentSceneData.connections no longer contains the original
599
+ // A→B entry with flowAttributes (it's been split into new sub-connections), so we
600
+ // seed the endpoint maps from both the connections array AND from existing pathDataStore
601
+ // entries that already carry flowAttributes — those persist across re-executions.
602
+ var fromEndpointAttrs = new Map();
603
+ var toEndpointAttrs = new Map();
604
+
605
+ // Seed from persisted pathDataStore entries first (covers post-manualization re-runs)
606
+ this.pathDataStore.forEach(function (pd, pathId) {
607
+ if (Object.keys(pd.flowAttributes).length === 0) return;
608
+ var sepIdx = pathId.indexOf('-->');
609
+ if (sepIdx === -1) return;
610
+ var from = pathId.slice(0, sepIdx);
611
+ var to = pathId.slice(sepIdx + 3);
612
+ if (!fromEndpointAttrs.has(from)) fromEndpointAttrs.set(from, pd.flowAttributes);
613
+ if (!toEndpointAttrs.has(to)) toEndpointAttrs.set(to, pd.flowAttributes);
614
+ });
615
+
616
+ // Also seed from connections array (covers initial load before pathDataStore has any attrs)
617
+ connections.forEach(function (conn) {
618
+ if (!conn.flowAttributes) return;
619
+ if (!fromEndpointAttrs.has(conn.from)) fromEndpointAttrs.set(conn.from, conn.flowAttributes);
620
+ if (!toEndpointAttrs.has(conn.to)) toEndpointAttrs.set(conn.to, conn.flowAttributes);
621
+ });
622
+ this.pathDataStore.forEach(function (pd, pathId) {
623
+ if (Object.keys(pd.flowAttributes).length > 0) return;
624
+ var sepIdx = pathId.indexOf('-->');
625
+ if (sepIdx === -1) return;
626
+ var from = pathId.slice(0, sepIdx);
627
+ var to = pathId.slice(sepIdx + 3);
628
+ var attrs = fromEndpointAttrs.get(from) || toEndpointAttrs.get(to);
629
+ if (attrs) Object.entries(attrs).forEach(function (_ref4) {
630
+ var _ref5 = _rollupPluginBabelHelpers.slicedToArray(_ref4, 2),
631
+ key = _ref5[0],
632
+ value = _ref5[1];
633
+ return pd.setFlowAttribute(key, value);
634
+ });
635
+ });
636
+
637
+ // Apply visualizations
638
+ (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.pathFlowManager) === null || _this$sceneViewer === void 0 || _this$sceneViewer.applyAllVisualizations();
639
+ }
640
+
511
641
  /**
512
642
  * Initialize pathfinder and create paths
513
643
  */
@@ -515,12 +645,32 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
515
645
  key: "initializePathfinder",
516
646
  value: (function () {
517
647
  var _initializePathfinder = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee2(data, crosscubeTextureSet) {
648
+ var _this6 = this;
518
649
  var pathfindingResult;
519
650
  return _rollupPluginBabelHelpers.regenerator().w(function (_context2) {
520
651
  while (1) switch (_context2.n) {
521
652
  case 0:
522
653
  this.crosscubeTextureSet = crosscubeTextureSet;
523
654
 
655
+ // ── Pre-load declared flowAttributes from connections JSON ─────────────
656
+ // This must happen before pathfinding so that PathData entries carrying
657
+ // flowAttributes are available for visualization right after rendering.
658
+ if (Array.isArray(data.connections)) {
659
+ data.connections.forEach(function (conn) {
660
+ if (conn.flowAttributes && _rollupPluginBabelHelpers["typeof"](conn.flowAttributes) === 'object') {
661
+ var pathId = "".concat(conn.from, "-->").concat(conn.to);
662
+ var pd = _this6._getOrCreatePathData(pathId, conn.from, conn.to);
663
+ Object.entries(conn.flowAttributes).forEach(function (_ref6) {
664
+ var _ref7 = _rollupPluginBabelHelpers.slicedToArray(_ref6, 2),
665
+ key = _ref7[0],
666
+ value = _ref7[1];
667
+ pd.setFlowAttribute(key, value);
668
+ });
669
+ console.log("\uD83C\uDF0A Loaded flowAttributes for path \"".concat(pathId, "\":"), conn.flowAttributes);
670
+ }
671
+ });
672
+ }
673
+
524
674
  // Use shared pathfinding logic with gateway creation enabled
525
675
  _context2.n = 1;
526
676
  return this._executePathfinding(data.scene, data.connections, {
@@ -529,6 +679,8 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
529
679
  });
530
680
  case 1:
531
681
  pathfindingResult = _context2.v;
682
+ this._propagateFlowAttributesAndApplyVisualizations(data.connections, pathfindingResult);
683
+
532
684
  // Update connections with rewired connections
533
685
  if (pathfindingResult.rewiredConnections) {
534
686
  // data.connections = pathfindingResult.rewiredConnections;
@@ -653,6 +805,9 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
653
805
  });
654
806
  case 2:
655
807
  result = _context3.v;
808
+ // Re-apply flow attribute colors (new materials are created on each execution)
809
+ this._propagateFlowAttributesAndApplyVisualizations(currentSceneData.connections, result);
810
+
656
811
  // Cache fingerprint + result for next comparison
657
812
  this._lastPathfindingFingerprint = fingerprint;
658
813
  this._lastPathfindingResult = result;
@@ -1771,7 +1771,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1771
1771
  if (typeof window !== 'undefined') {
1772
1772
  isDev = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
1773
1773
  }
1774
- if (isDev && segment.material) {
1774
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true' && segment.material) {
1775
1775
  segment.material.color.setHex(0x0000ff); // Blue
1776
1776
  console.log('🎨 Set manual segment material color to blue (dev mode)');
1777
1777
  }
@@ -1802,7 +1802,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1802
1802
  console.log('🔌 Created connectors:', connectors);
1803
1803
 
1804
1804
  // In dev mode, enlarge connectors by 1.5x and turn them red
1805
- if (isDev) {
1805
+ if (isDev && process.env.DISABLE_MANUALIZED_SEGMENT_COLORING !== 'true') {
1806
1806
  connectors.forEach(function (connector) {
1807
1807
  if (connector) {
1808
1808
  connector.scale.set(1.25, 1.25, 1.25);
@@ -31,7 +31,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
31
31
  * Initialize the CentralPlant manager
32
32
  *
33
33
  * @constructor
34
- * @version 0.2.8
34
+ * @version 0.2.12
35
35
  * @updated 2025-10-22
36
36
  *
37
37
  * @description Creates a new CentralPlant instance and initializes internal managers and utilities.
@@ -14,6 +14,7 @@ import { SceneInitializationManager } from '../managers/scene/sceneInitializatio
14
14
  import { EnvironmentManager } from '../managers/environment/environmentManager.js';
15
15
  import { KeyboardControlsManager } from '../managers/controls/keyboardControlsManager.js';
16
16
  import { PathfindingManager } from '../managers/pathfinding/pathfindingManager.js';
17
+ import { PathFlowManager } from '../managers/pathfinding/PathFlowManager.js';
17
18
  import { BehaviorManager } from '../managers/behaviors/BehaviorManager.js';
18
19
  import { SceneOperationsManager } from '../managers/scene/sceneOperationsManager.js';
19
20
  import { AnimationManager } from '../managers/scene/animationManager.js';
@@ -140,6 +141,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
140
141
  this.centralPlant.managers.environmentManager = new EnvironmentManager(this.centralPlant.sceneViewer);
141
142
  this.centralPlant.managers.keyboardControlsManager = new KeyboardControlsManager(this.centralPlant.sceneViewer);
142
143
  this.centralPlant.managers.pathfindingManager = new PathfindingManager(this.centralPlant.sceneViewer);
144
+ this.centralPlant.managers.pathFlowManager = new PathFlowManager(this.centralPlant.sceneViewer);
143
145
  this.centralPlant.managers.behaviorManager = new BehaviorManager(this.centralPlant.sceneViewer);
144
146
  this.centralPlant.managers.sceneOperationsManager = new SceneOperationsManager(this.centralPlant.sceneViewer);
145
147
  this.centralPlant.managers.animationManager = new AnimationManager(this.centralPlant.sceneViewer);
@@ -64,10 +64,19 @@ function createPathfindingRequest(startConnector, endConnector) {
64
64
  };
65
65
  }
66
66
 
67
+ /**
68
+ * The official set of flow-related attribute keys that can be set on a path.
69
+ * These attributes belong to the full path and are inherited by all segments.
70
+ *
71
+ * @type {string[]}
72
+ */
73
+ var FLOW_ATTRIBUTE_KEYS = ['flowDirection', 'flowSpeed', 'flowTemperature', 'flowMaterial'];
74
+
67
75
  /**
68
76
  * Data structure for storing path information with segments.
69
77
  * Tracks both computed and declared (manually edited) segments.
70
- *
78
+ * Also stores path-level flow attributes shared by all segments.
79
+ *
71
80
  * Business logic layer - stores coordinate data without Three.js dependencies.
72
81
  */
73
82
  var PathData = /*#__PURE__*/function () {
@@ -87,16 +96,60 @@ var PathData = /*#__PURE__*/function () {
87
96
  * @type {Array<{start: {x, y, z}, end: {x, y, z}, isDeclared: boolean, modifiedAt: number|null}>}
88
97
  */
89
98
  this.segments = [];
99
+
100
+ /**
101
+ * Path-level flow attributes shared by all segments within this path.
102
+ * Keys must come from FLOW_ATTRIBUTE_KEYS. Values are application-defined.
103
+ * @type {Record<string, any>}
104
+ */
105
+ this.flowAttributes = {};
90
106
  this.createdAt = Date.now();
91
107
  }
92
108
 
93
109
  /**
94
- * Add a computed segment (from pathfinding algorithm)
95
- *
96
- * @param {{x: number, y: number, z: number}} start - Start coordinate
97
- * @param {{x: number, y: number, z: number}} end - End coordinate
110
+ * Set a flow attribute on this path.
111
+ * All segments within this path inherit the value.
112
+ *
113
+ * @param {string} key - Attribute key (should be one of FLOW_ATTRIBUTE_KEYS)
114
+ * @param {any} value - Attribute value
98
115
  */
99
116
  return _createClass(PathData, [{
117
+ key: "setFlowAttribute",
118
+ value: function setFlowAttribute(key, value) {
119
+ this.flowAttributes[key] = value;
120
+ }
121
+
122
+ /**
123
+ * Get the declared value of a flow attribute.
124
+ * Returns null if the attribute has not been set.
125
+ *
126
+ * @param {string} key - Attribute key
127
+ * @returns {any|null}
128
+ */
129
+ }, {
130
+ key: "getFlowAttribute",
131
+ value: function getFlowAttribute(key) {
132
+ return Object.prototype.hasOwnProperty.call(this.flowAttributes, key) ? this.flowAttributes[key] : null;
133
+ }
134
+
135
+ /**
136
+ * Get a shallow copy of all declared flow attributes.
137
+ *
138
+ * @returns {Record<string, any>}
139
+ */
140
+ }, {
141
+ key: "getAllFlowAttributes",
142
+ value: function getAllFlowAttributes() {
143
+ return _objectSpread2({}, this.flowAttributes);
144
+ }
145
+
146
+ /**
147
+ * Add a computed segment (from pathfinding algorithm)
148
+ *
149
+ * @param {{x: number, y: number, z: number}} start - Start coordinate
150
+ * @param {{x: number, y: number, z: number}} end - End coordinate
151
+ */
152
+ }, {
100
153
  key: "addSegment",
101
154
  value: function addSegment(start, end) {
102
155
  this.segments.push({
@@ -173,6 +226,7 @@ var PathData = /*#__PURE__*/function () {
173
226
  segments: this.segments.map(function (seg) {
174
227
  return _objectSpread2({}, seg);
175
228
  }),
229
+ flowAttributes: _objectSpread2({}, this.flowAttributes),
176
230
  createdAt: this.createdAt
177
231
  };
178
232
  }
@@ -233,10 +287,11 @@ var PathData = /*#__PURE__*/function () {
233
287
  pathData.segments = json.segments.map(function (seg) {
234
288
  return _objectSpread2({}, seg);
235
289
  });
290
+ pathData.flowAttributes = json.flowAttributes ? _objectSpread2({}, json.flowAttributes) : {};
236
291
  pathData.createdAt = json.createdAt || Date.now();
237
292
  return pathData;
238
293
  }
239
294
  }]);
240
295
  }();
241
296
 
242
- export { PathData, createPathfindingRequest };
297
+ export { FLOW_ATTRIBUTE_KEYS, PathData, createPathfindingRequest };
@@ -98,7 +98,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
98
98
  this.centralPlant.attachToComponent();
99
99
 
100
100
  // Sync our managers tracking object after attachment
101
- managerKeys = ['threeJSResourceManager', 'performanceMonitorManager', 'settingsManager', 'sceneExportManager', 'componentManager', 'sceneInitializationManager', 'environmentManager', 'keyboardControlsManager', 'pathfindingManager', 'behaviorManager', 'sceneOperationsManager', 'animationManager', 'cameraControlsManager', 'componentDragManager', 'tooltipsManager', 'componentTooltipManager']; // Populate our managers tracking object
101
+ managerKeys = ['threeJSResourceManager', 'performanceMonitorManager', 'settingsManager', 'sceneExportManager', 'componentManager', 'sceneInitializationManager', 'environmentManager', 'keyboardControlsManager', 'pathfindingManager', 'pathFlowManager', 'behaviorManager', 'sceneOperationsManager', 'animationManager', 'cameraControlsManager', 'componentDragManager', 'tooltipsManager', 'componentTooltipManager']; // Populate our managers tracking object
102
102
  managerKeys.forEach(function (key) {
103
103
  if (_this2[key]) {
104
104
  _this2.managers[key] = _this2[key];
@@ -1,7 +1,7 @@
1
1
  export { default as CentralPlant } from './core/centralPlant.js';
2
2
  export { default as sceneViewer } from './core/sceneViewer.js';
3
3
  export { findObjectByHardcodedUuid, generateUniqueComponentId, generateUuidFromName, getHardcodedUuid } from './utils/nameUtils.js';
4
- export { PathData, createPathfindingRequest } from './core/pathfindingData.js';
4
+ export { FLOW_ATTRIBUTE_KEYS, PathData, createPathfindingRequest } from './core/pathfindingData.js';
5
5
  export { getObjectTypeName, getObjectsByType, isComponent, isComputed, isConnector, isDeclared, isExportable, isGateway, isSegment, markAsComputed, markAsDeclared, shouldRemoveOnRegeneration } from './utils/objectTypes.js';
6
6
  export { SceneInitializationManager } from './managers/scene/sceneInitializationManager.js';
7
7
  export { SceneOperationsManager } from './managers/scene/sceneOperationsManager.js';
@@ -13,6 +13,7 @@ export { BehaviorManager } from './managers/behaviors/BehaviorManager.js';
13
13
  export { ComponentManager } from './managers/components/componentManager.js';
14
14
  export { AnimationManager } from './managers/scene/animationManager.js';
15
15
  export { PathfindingManager } from './managers/pathfinding/pathfindingManager.js';
16
+ export { PathFlowManager } from './managers/pathfinding/PathFlowManager.js';
16
17
  export { SnapshotManager } from './managers/pathfinding/SnapshotManager.js';
17
18
  export { ComponentDataManager } from './managers/components/componentDataManager.js';
18
19
  export { createTransformControls } from './managers/controls/transformControlsManager.js';
@@ -0,0 +1,261 @@
1
+ import { inherits as _inherits, createClass as _createClass, toConsumableArray as _toConsumableArray, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper } from '../../../_virtual/_rollupPluginBabelHelpers.js';
2
+ import { BaseDisposable } from '../../core/baseDisposable.js';
3
+ import { FLOW_ATTRIBUTE_KEYS } from '../../core/pathfindingData.js';
4
+
5
+ // ── Temperature visualisation constants ────────────────────────────────────
6
+
7
+ /** Minimum temperature in the colour ramp (maps to pure blue). */
8
+ var TEMP_MIN = 0;
9
+
10
+ /** Maximum temperature in the colour ramp (maps to pure red). */
11
+ var TEMP_MAX = 100;
12
+
13
+ /**
14
+ * Convert a temperature value to a CSS hex colour string using a blue→red HSL
15
+ * ramp. Values are clamped to [TEMP_MIN, TEMP_MAX].
16
+ *
17
+ * • TEMP_MIN → hsl(240, 80%, 50%) — blue
18
+ * • TEMP_MAX → hsl(0, 80%, 50%) — red
19
+ *
20
+ * @param {number} temp
21
+ * @returns {string} CSS hex colour string e.g. '#2255cc'
22
+ */
23
+ function temperatureToColor(temp) {
24
+ var clamped = Math.max(TEMP_MIN, Math.min(TEMP_MAX, temp));
25
+ var t = (clamped - TEMP_MIN) / (TEMP_MAX - TEMP_MIN); // 0 (cold) → 1 (hot)
26
+ // Map t=0 → hue 240 (blue), t=1 → hue 0 (red)
27
+ var hue = Math.round(240 - t * 240);
28
+ return "hsl(".concat(hue, ", 80%, 50%)");
29
+ }
30
+
31
+ // ── PathFlowManager ─────────────────────────────────────────────────────────
32
+
33
+ var PathFlowManager = /*#__PURE__*/function (_BaseDisposable) {
34
+ /**
35
+ * @param {Object} sceneViewer - The central sceneViewer hub
36
+ */
37
+ function PathFlowManager(sceneViewer) {
38
+ var _this;
39
+ _classCallCheck(this, PathFlowManager);
40
+ _this = _callSuper(this, PathFlowManager);
41
+ _this.sceneViewer = sceneViewer;
42
+
43
+ /**
44
+ * Runtime-only attribute overrides.
45
+ * Map<pathId, Record<attributeKey, value>>
46
+ * Cleared when the session ends or resetDerived() is called.
47
+ * @type {Map<string, Record<string, any>>}
48
+ */
49
+ _this._derivedStore = new Map();
50
+ return _this;
51
+ }
52
+
53
+ // ── Public API — attribute write ──────────────────────────────────────────
54
+
55
+ /**
56
+ * Set a declared (persistent) flow attribute on a path.
57
+ * The value is stored in PathData and will be serialised with the scene.
58
+ * Triggers a visual update.
59
+ *
60
+ * @param {string} pathId - e.g. "PUMP-1-CONN-1-->CHILLER-1-CONN-2"
61
+ * @param {string} key - One of FLOW_ATTRIBUTE_KEYS
62
+ * @param {any} value
63
+ */
64
+ _inherits(PathFlowManager, _BaseDisposable);
65
+ return _createClass(PathFlowManager, [{
66
+ key: "setDeclared",
67
+ value: function setDeclared(pathId, key, value) {
68
+ var pd = this._getPathData(pathId);
69
+ if (!pd) {
70
+ console.warn("PathFlowManager.setDeclared: no PathData found for \"".concat(pathId, "\""));
71
+ return;
72
+ }
73
+ pd.setFlowAttribute(key, value);
74
+ this.applyVisualizationForPath(pathId);
75
+ }
76
+
77
+ /**
78
+ * Set a derived (runtime) flow attribute on a path.
79
+ * Overrides the declared value during this session but is not persisted.
80
+ * Triggers a visual update.
81
+ *
82
+ * @param {string} pathId
83
+ * @param {string} key
84
+ * @param {any} value
85
+ */
86
+ }, {
87
+ key: "setDerived",
88
+ value: function setDerived(pathId, key, value) {
89
+ if (!this._derivedStore.has(pathId)) {
90
+ this._derivedStore.set(pathId, {});
91
+ }
92
+ this._derivedStore.get(pathId)[key] = value;
93
+ this.applyVisualizationForPath(pathId);
94
+ }
95
+
96
+ /**
97
+ * Clear derived overrides for one path or all paths, then re-apply
98
+ * visualizations so that declared values take effect again.
99
+ *
100
+ * @param {string} [pathId] - Omit to reset all paths.
101
+ */
102
+ }, {
103
+ key: "resetDerived",
104
+ value: function resetDerived(pathId) {
105
+ var _this2 = this;
106
+ if (pathId !== undefined) {
107
+ this._derivedStore.delete(pathId);
108
+ this.applyVisualizationForPath(pathId);
109
+ } else {
110
+ var affected = _toConsumableArray(this._derivedStore.keys());
111
+ this._derivedStore.clear();
112
+ affected.forEach(function (id) {
113
+ return _this2.applyVisualizationForPath(id);
114
+ });
115
+ }
116
+ }
117
+
118
+ // ── Public API — attribute read ───────────────────────────────────────────
119
+
120
+ /**
121
+ * Resolve the effective value of a single attribute for a path.
122
+ * Resolution order: derived > declared > null.
123
+ *
124
+ * @param {string} pathId
125
+ * @param {string} key
126
+ * @returns {any|null}
127
+ */
128
+ }, {
129
+ key: "resolve",
130
+ value: function resolve(pathId, key) {
131
+ var derived = this._derivedStore.get(pathId);
132
+ if (derived && Object.prototype.hasOwnProperty.call(derived, key)) {
133
+ return derived[key];
134
+ }
135
+ var pd = this._getPathData(pathId);
136
+ if (pd) {
137
+ return pd.getFlowAttribute(key);
138
+ }
139
+ return null;
140
+ }
141
+
142
+ /**
143
+ * Resolve all four flow attributes for a path as a plain object.
144
+ * Each key is either the effective value or null if unset.
145
+ *
146
+ * @param {string} pathId
147
+ * @returns {{ flowDirection: any, flowSpeed: any, flowTemperature: any, flowMaterial: any }}
148
+ */
149
+ }, {
150
+ key: "resolveAll",
151
+ value: function resolveAll(pathId) {
152
+ var _this3 = this;
153
+ return Object.fromEntries(FLOW_ATTRIBUTE_KEYS.map(function (key) {
154
+ return [key, _this3.resolve(pathId, key)];
155
+ }));
156
+ }
157
+
158
+ // ── Visualization ─────────────────────────────────────────────────────────
159
+
160
+ /**
161
+ * Compute and apply the visual colour for a single path based on its resolved
162
+ * flow attributes. Currently maps flowTemperature to a blue→red colour ramp.
163
+ * No-ops gracefully if the path has no renderable attributes or no pipe
164
+ * material exists yet.
165
+ *
166
+ * @param {string} pathId
167
+ */
168
+ }, {
169
+ key: "applyVisualizationForPath",
170
+ value: function applyVisualizationForPath(pathId) {
171
+ var temp = this.resolve(pathId, 'flowTemperature');
172
+ if (temp === null || temp === undefined) {
173
+ return; // No temperature declared — leave default pipe color
174
+ }
175
+ var color = temperatureToColor(temp);
176
+ var renderingManager = this._getRenderingManager();
177
+ if (!renderingManager) return;
178
+
179
+ // pathId = "from-->to"; extract the two halves
180
+ var sepIdx = pathId.indexOf('-->');
181
+ if (sepIdx === -1) {
182
+ console.warn("PathFlowManager: malformed pathId \"".concat(pathId, "\""));
183
+ return;
184
+ }
185
+ var from = pathId.slice(0, sepIdx);
186
+ var to = pathId.slice(sepIdx + 3);
187
+ renderingManager.updatePathColor(from, to, color);
188
+ console.log("\uD83C\uDF21\uFE0F PathFlowManager: \"".concat(pathId, "\" \u2192 flowTemperature ").concat(temp, " \u2192 ").concat(color));
189
+ }
190
+
191
+ /**
192
+ * Apply visualizations for every known path (union of pathDataStore and derived store).
193
+ * Call this after scene load or after bulk attribute changes.
194
+ */
195
+ }, {
196
+ key: "applyAllVisualizations",
197
+ value: function applyAllVisualizations() {
198
+ var _this4 = this;
199
+ var pathIds = new Set();
200
+ var pfMgr = this._getPathfindingManager();
201
+ if (pfMgr !== null && pfMgr !== void 0 && pfMgr.pathDataStore) {
202
+ pfMgr.pathDataStore.forEach(function (_, id) {
203
+ return pathIds.add(id);
204
+ });
205
+ }
206
+ this._derivedStore.forEach(function (_, id) {
207
+ return pathIds.add(id);
208
+ });
209
+ pathIds.forEach(function (id) {
210
+ return _this4.applyVisualizationForPath(id);
211
+ });
212
+ console.log("\uD83C\uDF0A PathFlowManager.applyAllVisualizations: processed ".concat(pathIds.size, " path(s)"));
213
+ }
214
+
215
+ // ── Lifecycle ─────────────────────────────────────────────────────────────
216
+ }, {
217
+ key: "dispose",
218
+ value: function dispose() {
219
+ this._derivedStore.clear();
220
+ this.sceneViewer = null;
221
+ _superPropGet(PathFlowManager, "dispose", this, 3)([]);
222
+ }
223
+
224
+ // ── Private helpers ───────────────────────────────────────────────────────
225
+
226
+ /**
227
+ * @returns {import('../../core/pathfindingData.js').PathData|null}
228
+ * @private
229
+ */
230
+ }, {
231
+ key: "_getPathData",
232
+ value: function _getPathData(pathId) {
233
+ var _this$_getPathfinding, _this$_getPathfinding2;
234
+ return (_this$_getPathfinding = (_this$_getPathfinding2 = this._getPathfindingManager()) === null || _this$_getPathfinding2 === void 0 || (_this$_getPathfinding2 = _this$_getPathfinding2.pathDataStore) === null || _this$_getPathfinding2 === void 0 ? void 0 : _this$_getPathfinding2.get(pathId)) !== null && _this$_getPathfinding !== void 0 ? _this$_getPathfinding : null;
235
+ }
236
+
237
+ /**
238
+ * @returns {import('../pathfinding/pathfindingManager.js').PathfindingManager|null}
239
+ * @private
240
+ */
241
+ }, {
242
+ key: "_getPathfindingManager",
243
+ value: function _getPathfindingManager() {
244
+ var _this$sceneViewer$man, _this$sceneViewer;
245
+ return (_this$sceneViewer$man = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.pathfindingManager) !== null && _this$sceneViewer$man !== void 0 ? _this$sceneViewer$man : null;
246
+ }
247
+
248
+ /**
249
+ * @returns {import('../pathfinding/PathRenderingManager.js').PathRenderingManager|null}
250
+ * @private
251
+ */
252
+ }, {
253
+ key: "_getRenderingManager",
254
+ value: function _getRenderingManager() {
255
+ var _this$_getPathfinding3, _this$_getPathfinding4;
256
+ return (_this$_getPathfinding3 = (_this$_getPathfinding4 = this._getPathfindingManager()) === null || _this$_getPathfinding4 === void 0 ? void 0 : _this$_getPathfinding4.renderingManager) !== null && _this$_getPathfinding3 !== void 0 ? _this$_getPathfinding3 : null;
257
+ }
258
+ }]);
259
+ }(BaseDisposable);
260
+
261
+ export { PathFlowManager };