@2112-lab/central-plant 0.1.39 → 0.1.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/bundle/index.js +7991 -7054
  2. package/dist/cjs/src/core/centralPlant.js +48 -3
  3. package/dist/cjs/src/core/centralPlantInternals.js +75 -566
  4. package/dist/cjs/src/core/sceneViewer.js +38 -13
  5. package/dist/cjs/src/index.js +6 -4
  6. package/dist/cjs/src/managers/components/pathfindingManager.js +75 -60
  7. package/dist/cjs/src/managers/components/transformOperationsManager.js +929 -0
  8. package/dist/cjs/src/managers/controls/keyboardControlsManager.js +57 -1
  9. package/dist/cjs/src/managers/controls/transformControls.js +11 -3
  10. package/dist/cjs/src/managers/controls/transformControlsManager.js +563 -263
  11. package/dist/cjs/src/managers/pathfinding/ConnectorManager.js +385 -0
  12. package/dist/cjs/src/managers/pathfinding/PathIntersectionDetector.js +387 -0
  13. package/dist/cjs/src/managers/pathfinding/PathRenderingManager.js +401 -0
  14. package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +378 -0
  15. package/dist/cjs/src/managers/pathfinding/sceneDataManager.js +256 -0
  16. package/dist/cjs/src/managers/scene/animationManager.js +145 -0
  17. package/dist/cjs/src/managers/scene/sceneExportManager.js +14 -13
  18. package/dist/cjs/src/managers/scene/sceneOperationsManager.js +516 -21
  19. package/dist/cjs/src/managers/scene/sceneTooltipsManager.js +1 -8
  20. package/dist/cjs/src/managers/system/operationHistoryManager.js +414 -0
  21. package/dist/cjs/src/managers/system/settingsManager.js +2 -1
  22. package/dist/cjs/src/utils/objectTypes.js +5 -7
  23. package/dist/esm/src/core/centralPlant.js +48 -3
  24. package/dist/esm/src/core/centralPlantInternals.js +76 -567
  25. package/dist/esm/src/core/sceneViewer.js +38 -13
  26. package/dist/esm/src/index.js +4 -3
  27. package/dist/esm/src/managers/components/pathfindingManager.js +75 -60
  28. package/dist/esm/src/managers/components/transformOperationsManager.js +904 -0
  29. package/dist/esm/src/managers/controls/keyboardControlsManager.js +57 -1
  30. package/dist/esm/src/managers/controls/transformControls.js +11 -3
  31. package/dist/esm/src/managers/controls/transformControlsManager.js +564 -264
  32. package/dist/esm/src/managers/pathfinding/ConnectorManager.js +361 -0
  33. package/dist/esm/src/managers/pathfinding/PathIntersectionDetector.js +363 -0
  34. package/dist/esm/src/managers/pathfinding/PathRenderingManager.js +377 -0
  35. package/dist/esm/src/managers/pathfinding/pathfindingManager.js +374 -0
  36. package/dist/esm/src/managers/pathfinding/sceneDataManager.js +232 -0
  37. package/dist/esm/src/managers/scene/animationManager.js +141 -0
  38. package/dist/esm/src/managers/scene/sceneExportManager.js +14 -13
  39. package/dist/esm/src/managers/scene/sceneOperationsManager.js +516 -21
  40. package/dist/esm/src/managers/scene/sceneTooltipsManager.js +1 -8
  41. package/dist/esm/src/managers/system/operationHistoryManager.js +409 -0
  42. package/dist/esm/src/managers/system/settingsManager.js +2 -1
  43. package/dist/esm/src/utils/objectTypes.js +5 -7
  44. package/dist/index.d.ts +2 -2
  45. package/package.json +1 -1
@@ -0,0 +1,401 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHelpers.js');
6
+ var THREE = require('three');
7
+ var baseDisposable = require('../../core/baseDisposable.js');
8
+
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n["default"] = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
28
+
29
+ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
30
+ function PathRenderingManager(sceneViewer) {
31
+ var _this;
32
+ _rollupPluginBabelHelpers.classCallCheck(this, PathRenderingManager);
33
+ _this = _rollupPluginBabelHelpers.callSuper(this, PathRenderingManager);
34
+ _this.sceneViewer = sceneViewer;
35
+
36
+ // Shared gateway resources to prevent memory leaks
37
+ _this._gatewayGeometry = new THREE__namespace.SphereGeometry(0.15, 16, 16);
38
+ _this._gatewayMaterial = new THREE__namespace.MeshStandardMaterial({
39
+ color: 0xFFFFFF,
40
+ roughness: 0.7,
41
+ metalness: 0.3,
42
+ emissive: 0
43
+ });
44
+ _this.registerDisposable(_this._gatewayGeometry, _this._gatewayMaterial);
45
+ return _this;
46
+ }
47
+
48
+ /**
49
+ * Get path colors for visual distinction
50
+ * @param {number} index - Path index
51
+ * @returns {string} Hex color string
52
+ */
53
+ _rollupPluginBabelHelpers.inherits(PathRenderingManager, _BaseDisposable);
54
+ return _rollupPluginBabelHelpers.createClass(PathRenderingManager, [{
55
+ key: "getPathColor",
56
+ value: function getPathColor(index) {
57
+ var colors = [
58
+ // '#468e49',
59
+ '#245e29'
60
+ // '#2e80d2',
61
+ // '#1d51a1'
62
+ ];
63
+ return colors[index % colors.length];
64
+ }
65
+
66
+ /**
67
+ * Create gateways in the scene from pathfinding results
68
+ * @param {Object} pathfindingResult - Result object from pathfinder containing gateways
69
+ */
70
+ }, {
71
+ key: "createGateways",
72
+ value: function createGateways(pathfindingResult) {
73
+ var _this2 = this;
74
+ pathfindingResult.gateways.forEach(function (gateway) {
75
+ if (!gateway.position) {
76
+ console.warn("\u26A0\uFE0F Gateway ".concat(gateway.id, " missing position, skipping creation"));
77
+ return;
78
+ }
79
+
80
+ // Check if gateway already exists in scene (prevent duplicates)
81
+ var existingGateway = _this2.sceneViewer.scene.getObjectByProperty('uuid', gateway.id);
82
+ if (existingGateway) {
83
+ console.log("\u2139\uFE0F Gateway ".concat(gateway.id, " already exists, skipping creation"));
84
+ return;
85
+ }
86
+
87
+ // Create gateway mesh using shared geometry and material
88
+ var gatewayMesh = new THREE__namespace.Mesh(_this2._gatewayGeometry, _this2._gatewayMaterial);
89
+
90
+ // Handle position format: pathfinder returns {x,y,z} object or [x,y,z] array
91
+ if (Array.isArray(gateway.position)) {
92
+ gatewayMesh.position.fromArray(gateway.position);
93
+ } else if (gateway.position.x !== undefined) {
94
+ gatewayMesh.position.set(gateway.position.x, gateway.position.y, gateway.position.z);
95
+ } else {
96
+ console.error("\u274C Invalid gateway position format for ".concat(gateway.id, ":"), gateway.position);
97
+ return;
98
+ }
99
+ gatewayMesh.uuid = gateway.id;
100
+
101
+ // Set userData to make gateways selectable
102
+ gatewayMesh.userData = {
103
+ objectType: 'gateway',
104
+ isDeclared: false,
105
+ gatewayId: gateway.id,
106
+ originalUuid: gateway.id,
107
+ // Deep copy connections to prevent mutations affecting pathfinder's internal state
108
+ connections: gateway.connections ? {
109
+ removed: gateway.connections.removed ? _rollupPluginBabelHelpers.toConsumableArray(gateway.connections.removed) : [],
110
+ added: gateway.connections.added ? _rollupPluginBabelHelpers.toConsumableArray(gateway.connections.added) : []
111
+ } : {
112
+ removed: [],
113
+ added: []
114
+ }
115
+ };
116
+
117
+ // Add to scene
118
+ _this2.sceneViewer.scene.add(gatewayMesh);
119
+ console.log("\uD83D\uDD27 Created gateway: ".concat(gateway.id, " at [").concat(gatewayMesh.position.x.toFixed(2), ", ").concat(gatewayMesh.position.y.toFixed(2), ", ").concat(gatewayMesh.position.z.toFixed(2), "]"));
120
+ });
121
+ }
122
+
123
+ /**
124
+ * Material factory function for pipe materials
125
+ * @param {Object} crosscubeTextureSet - Texture set for pipe materials
126
+ * @returns {THREE.Material} Pipe material
127
+ */
128
+ }, {
129
+ key: "createPipeMaterial",
130
+ value: function createPipeMaterial(crosscubeTextureSet) {
131
+ if (crosscubeTextureSet) {
132
+ var materialProps = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, crosscubeTextureSet.config.materialProps), {}, {
133
+ color: this.getPathColor(0),
134
+ map: crosscubeTextureSet.textures.diffuse,
135
+ normalMap: crosscubeTextureSet.textures.normal,
136
+ roughnessMap: crosscubeTextureSet.textures.roughness,
137
+ metalness: 0.2,
138
+ roughness: 0.9,
139
+ clearcoat: 0.2,
140
+ clearcoatRoughness: 0.2,
141
+ envMapIntensity: 0.6,
142
+ reflectivity: 0.4
143
+ // transparent: true,
144
+ // opacity: 0.75
145
+ });
146
+
147
+ // Handle normalScale conversion to Vector2
148
+ if (materialProps.normalScale && Array.isArray(materialProps.normalScale)) {
149
+ materialProps.normalScale = _rollupPluginBabelHelpers.construct(THREE__namespace.Vector2, _rollupPluginBabelHelpers.toConsumableArray(materialProps.normalScale));
150
+ }
151
+ var material = new THREE__namespace.MeshPhysicalMaterial(materialProps);
152
+
153
+ // Configure texture wrapping and repeat
154
+ var pipeTextures = [material.map, material.normalMap, material.roughnessMap].filter(Boolean);
155
+ pipeTextures.forEach(function (texture) {
156
+ texture.wrapS = texture.wrapT = THREE__namespace.RepeatWrapping;
157
+ texture.repeat.set(crosscubeTextureSet.config.repeat.x * 2, crosscubeTextureSet.config.repeat.y * 2);
158
+ });
159
+ return material;
160
+ } else {
161
+ return new THREE__namespace.MeshPhysicalMaterial({
162
+ color: this.getPathColor(0),
163
+ metalness: 0.9,
164
+ roughness: 0.7,
165
+ clearcoat: 0.1,
166
+ clearcoatRoughness: 0.3,
167
+ envMapIntensity: 1.5,
168
+ reflectivity: 0.3
169
+ });
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Create pipe paths from pathfinding results
175
+ * @param {Array} paths - Array of path objects from pathfinder
176
+ * @param {Object} crosscubeTextureSet - Texture set for pipe materials
177
+ */
178
+ }, {
179
+ key: "createPipePaths",
180
+ value: function createPipePaths(paths, crosscubeTextureSet) {
181
+ var _this3 = this;
182
+ var sceneViewer = this.sceneViewer;
183
+ var globalSegmentIndex = 0; // Counter for globally unique segment indices
184
+
185
+ paths.forEach(function (pathData, index) {
186
+ if (pathData.path && pathData.path.length >= 2) {
187
+ var pipeRadius = 0.1;
188
+ var pipeMaterial = _this3.createPipeMaterial(crosscubeTextureSet);
189
+
190
+ // Convert path points to Vector3 objects for consistent handling
191
+ var pathPoints = pathData.path.map(function (point) {
192
+ if (point instanceof THREE__namespace.Vector3) {
193
+ return point.clone();
194
+ } else if (Array.isArray(point)) {
195
+ return new THREE__namespace.Vector3().fromArray(point);
196
+ } else if (point.x !== undefined && point.y !== undefined && point.z !== undefined) {
197
+ return new THREE__namespace.Vector3(point.x, point.y, point.z);
198
+ } else {
199
+ console.warn('Unknown point format in createPipePaths:', point);
200
+ return new THREE__namespace.Vector3(0, 0, 0);
201
+ }
202
+ });
203
+
204
+ // Create one cylinder per segment (after colinear optimization, this should be minimal segments)
205
+ for (var j = 0; j < pathPoints.length - 1; j++) {
206
+ var start = pathPoints[j];
207
+ var end = pathPoints[j + 1];
208
+ var direction = new THREE__namespace.Vector3().subVectors(end, start);
209
+ var length = direction.length();
210
+
211
+ // Skip zero-length segments
212
+ if (length < 1e-6) {
213
+ console.warn("Skipping zero-length segment in path ".concat(pathData.from, "-").concat(pathData.to));
214
+ continue;
215
+ }
216
+ var cylinderGeometry = new THREE__namespace.CylinderGeometry(pipeRadius, pipeRadius, length, 16, 1, false);
217
+ var cylinder = new THREE__namespace.Mesh(cylinderGeometry, pipeMaterial);
218
+ cylinder.position.copy(start).add(end).multiplyScalar(0.5);
219
+ var quaternion = new THREE__namespace.Quaternion();
220
+ var up = new THREE__namespace.Vector3(0, 1, 0);
221
+ quaternion.setFromUnitVectors(up, direction.clone().normalize());
222
+ cylinder.quaternion.copy(quaternion);
223
+ cylinder.castShadow = true;
224
+ cylinder.receiveShadow = true;
225
+
226
+ // Set UUID to SEGMENT-{globalSegmentIndex} format
227
+ cylinder.uuid = "SEGMENT-".concat(globalSegmentIndex);
228
+
229
+ // Make pipe segments selectable and add identifying data
230
+ var segmentId = cylinder.uuid;
231
+
232
+ // Add userData to make pipe segments selectable and for tooltip display
233
+ cylinder.userData = {
234
+ objectType: 'segment',
235
+ segmentId: segmentId,
236
+ segmentIndex: globalSegmentIndex,
237
+ pathFrom: pathData.from,
238
+ pathTo: pathData.to
239
+ };
240
+
241
+ // Increment global segment counter
242
+ globalSegmentIndex++;
243
+
244
+ // Add segment directly to scene instead of to polyline
245
+ sceneViewer.scene.add(cylinder);
246
+
247
+ // Add smooth elbow joints only at actual direction changes (not at every point)
248
+ _this3.createAndAddElbowIfNeeded(pathPoints, j, pipeRadius, pipeMaterial, pathData, index, sceneViewer.scene // Pass scene instead of polyline
249
+ );
250
+ }
251
+ console.log("\u2705 Created pipe path ".concat(pathData.from, "-").concat(pathData.to, " with ").concat(pathPoints.length - 1, " segments"));
252
+ }
253
+ });
254
+ }
255
+
256
+ /**
257
+ * Create and add elbow joint if there's a direction change at the current segment
258
+ * @param {Array<THREE.Vector3>} pathPoints - Array of path points
259
+ * @param {number} j - Current segment index
260
+ * @param {number} pipeRadius - Radius of the pipe
261
+ * @param {THREE.Material} pipeMaterial - Material for the elbow
262
+ * @param {Object} pathData - Path data object with from/to information
263
+ * @param {number} index - Path index for naming
264
+ * @param {THREE.Scene} scene - Scene object to add elbow to directly
265
+ */
266
+ }, {
267
+ key: "createAndAddElbowIfNeeded",
268
+ value: function createAndAddElbowIfNeeded(pathPoints, j, pipeRadius, pipeMaterial, pathData, index, scene) {
269
+ // Only check if there are at least 2 more points ahead
270
+ if (j >= pathPoints.length - 2) {
271
+ return;
272
+ }
273
+ var currentSegment = pathPoints[j + 1].clone().sub(pathPoints[j]).normalize();
274
+ var nextSegment = pathPoints[j + 2].clone().sub(pathPoints[j + 1]).normalize();
275
+
276
+ // Check if there's actually a direction change (not just continuing straight)
277
+ var angle = currentSegment.angleTo(nextSegment);
278
+ var minAngle = Math.PI / 36; // 5 degrees minimum for creating an elbow
279
+
280
+ if (angle <= minAngle) {
281
+ return; // No significant direction change
282
+ }
283
+ var elbowGeometry = this.createElbowGeometry(pathPoints[j], pathPoints[j + 1], pathPoints[j + 2], pipeRadius);
284
+ if (!elbowGeometry) {
285
+ return; // Failed to create geometry
286
+ }
287
+ var elbow = new THREE__namespace.Mesh(elbowGeometry, pipeMaterial);
288
+ elbow.castShadow = true;
289
+ elbow.receiveShadow = true;
290
+
291
+ // Make elbows selectable as well
292
+ var elbowId = "pipe-elbow-".concat(pathData.from, "-").concat(pathData.to, "-").concat(j);
293
+ elbow.uuid = "Pipe Elbow ".concat(j + 1, ": ").concat(pathData.from, "-").concat(pathData.to);
294
+
295
+ // Add userData for elbows too
296
+ elbow.userData = {
297
+ isPipeElbow: true,
298
+ elbowId: elbowId,
299
+ elbowIndex: j,
300
+ pathFrom: pathData.from,
301
+ pathTo: pathData.to,
302
+ angle: (angle * 180 / Math.PI).toFixed(1),
303
+ // Add component data for tooltips
304
+ component: {
305
+ type: 'PipeElbow',
306
+ attributes: {
307
+ angle: {
308
+ key: 'Bend Angle',
309
+ value: (angle * 180 / Math.PI).toFixed(1),
310
+ unit: '°'
311
+ }
312
+ }
313
+ }
314
+ };
315
+ scene.add(elbow);
316
+ }
317
+
318
+ /**
319
+ * Create smooth elbow geometry to connect two pipe segments (optimized for 90-degree angles)
320
+ * @param {THREE.Vector3} point1 - First point (before the joint)
321
+ * @param {THREE.Vector3} point2 - Joint point (center of the elbow)
322
+ * @param {THREE.Vector3} point3 - Third point (after the joint)
323
+ * @param {number} radius - Pipe radius
324
+ * @returns {THREE.BufferGeometry} Elbow geometry
325
+ */
326
+ }, {
327
+ key: "createElbowGeometry",
328
+ value: function createElbowGeometry(point1, point2, point3, radius) {
329
+ try {
330
+ // Fixed elbow radius for 90-degree bends (simplified)
331
+ var elbowRadius = radius * 3;
332
+
333
+ // Create a curve for the 90-degree elbow
334
+ var curve = this.createElbowCurve(point1, point2, point3, elbowRadius);
335
+
336
+ // Fixed tubular segments for 90-degree bends (quarter circle)
337
+ var tubularSegments = 12; // Good balance for smooth 90° curves
338
+ var radialSegments = 16;
339
+ var closed = false;
340
+ var elbowGeometry = new THREE__namespace.TubeGeometry(curve, tubularSegments, radius, radialSegments, closed);
341
+ return elbowGeometry;
342
+ } catch (error) {
343
+ console.warn('Failed to create elbow geometry:', error);
344
+ return null;
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Create a smooth curve for the 90-degree elbow joint (simplified)
350
+ * @param {THREE.Vector3} point1 - First point
351
+ * @param {THREE.Vector3} point2 - Joint point
352
+ * @param {THREE.Vector3} point3 - Third point
353
+ * @param {number} elbowRadius - Radius of the elbow curve
354
+ * @returns {THREE.Curve} Curve for the elbow
355
+ */
356
+ }, {
357
+ key: "createElbowCurve",
358
+ value: function createElbowCurve(point1, point2, point3, elbowRadius) {
359
+ // Calculate direction vectors
360
+ var dir1 = point2.clone().sub(point1).normalize();
361
+ var dir2 = point3.clone().sub(point2).normalize();
362
+
363
+ // For 90-degree bends, we can use a simpler approach with a quarter circle
364
+ // The curve radius is proportional to the elbow radius
365
+ var curveRadius = elbowRadius * 0.001;
366
+
367
+ // Calculate the offset distance from the joint point
368
+ var offset = curveRadius;
369
+
370
+ // Calculate start and end points of the curve (offset from the joint)
371
+ var curveStart = point2.clone().sub(dir1.clone().multiplyScalar(offset));
372
+ var curveEnd = point2.clone().add(dir2.clone().multiplyScalar(offset));
373
+
374
+ // For a 90-degree bend, the control point is at the corner
375
+ // We can use a quadratic bezier curve for simplicity
376
+ var controlPoint = point2.clone();
377
+
378
+ // Create a quadratic bezier curve (simpler than cubic for 90° bends)
379
+ var curve = new THREE__namespace.QuadraticBezierCurve3(curveStart, controlPoint, curveEnd);
380
+ return curve;
381
+ }
382
+
383
+ /**
384
+ * Dispose of rendering resources
385
+ */
386
+ }, {
387
+ key: "dispose",
388
+ value: function dispose() {
389
+ console.log('🗑️ Disposing PathRenderingManager...');
390
+
391
+ // Call parent dispose to clean up registered resources (shared gateway geometry/material)
392
+ _rollupPluginBabelHelpers.superPropGet(PathRenderingManager, "dispose", this, 3)([]);
393
+
394
+ // Nullify properties
395
+ this.sceneViewer = null;
396
+ console.log('✅ PathRenderingManager disposed');
397
+ }
398
+ }]);
399
+ }(baseDisposable.BaseDisposable);
400
+
401
+ exports.PathRenderingManager = PathRenderingManager;