@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,387 @@
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
+
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n["default"] = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
27
+
28
+ /**
29
+ * PathIntersectionDetector - Detects intersections between pipe paths
30
+ *
31
+ * This class handles all intersection detection logic for both computed paths
32
+ * (from pathfinding) and manual segments (user-positioned pipes).
33
+ *
34
+ * @class PathIntersectionDetector
35
+ */
36
+ var PathIntersectionDetector = /*#__PURE__*/function () {
37
+ /**
38
+ * Create a new PathIntersectionDetector
39
+ * @param {Object} sceneViewer - Reference to the scene viewer
40
+ */
41
+ function PathIntersectionDetector(sceneViewer) {
42
+ _rollupPluginBabelHelpers.classCallCheck(this, PathIntersectionDetector);
43
+ this.sceneViewer = sceneViewer;
44
+ }
45
+
46
+ /**
47
+ * Check for intersections between paths
48
+ * @param {Array} paths - Array of path objects from pathfinder
49
+ * @param {number} tolerance - Distance tolerance for considering pipes as intersecting (default: 0.2)
50
+ * @param {boolean} includeManualSegments - Whether to include manual segments in the check (default: true)
51
+ * @returns {Object} Intersection results
52
+ * @property {boolean} hasIntersections - Whether any intersections were found
53
+ * @property {Array<Object>} intersections - Array of intersection details
54
+ * @property {number} count - Total number of intersections found
55
+ */
56
+ return _rollupPluginBabelHelpers.createClass(PathIntersectionDetector, [{
57
+ key: "checkPathIntersections",
58
+ value: function checkPathIntersections(paths) {
59
+ var tolerance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.2;
60
+ var includeManualSegments = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
61
+ var intersections = [];
62
+
63
+ // Convert all paths to line segments for comparison
64
+ var pathSegments = paths.map(function (pathData, pathIndex) {
65
+ if (!pathData.path || pathData.path.length < 2) {
66
+ return null;
67
+ }
68
+ var segments = [];
69
+ var pathPoints = pathData.path.map(function (point) {
70
+ if (point instanceof THREE__namespace.Vector3) {
71
+ return point.clone();
72
+ } else if (Array.isArray(point)) {
73
+ return new THREE__namespace.Vector3().fromArray(point);
74
+ } else if (point.x !== undefined && point.y !== undefined && point.z !== undefined) {
75
+ return new THREE__namespace.Vector3(point.x, point.y, point.z);
76
+ }
77
+ return null;
78
+ }).filter(function (p) {
79
+ return p !== null;
80
+ });
81
+ for (var i = 0; i < pathPoints.length - 1; i++) {
82
+ segments.push({
83
+ start: pathPoints[i],
84
+ end: pathPoints[i + 1],
85
+ pathIndex: pathIndex,
86
+ segmentIndex: i,
87
+ pathFrom: pathData.from,
88
+ pathTo: pathData.to,
89
+ isFirstSegment: i === 0,
90
+ isLastSegment: i === pathPoints.length - 2,
91
+ isManual: false // Computed path segment
92
+ });
93
+ }
94
+ return segments;
95
+ }).filter(function (s) {
96
+ return s !== null;
97
+ }).flat();
98
+
99
+ // Add manual segments if requested
100
+ if (includeManualSegments) {
101
+ var manualSegments = this._collectManualSegments(pathSegments.length);
102
+ pathSegments.push.apply(pathSegments, _rollupPluginBabelHelpers.toConsumableArray(manualSegments));
103
+ console.log("\uD83D\uDCE6 Added ".concat(manualSegments.length, " manual segment(s) to intersection check"));
104
+ }
105
+ console.log("\uD83D\uDD0D Checking ".concat(pathSegments.length, " segments for intersections..."));
106
+
107
+ // Check each pair of segments
108
+ for (var i = 0; i < pathSegments.length; i++) {
109
+ for (var j = i + 1; j < pathSegments.length; j++) {
110
+ var seg1 = pathSegments[i];
111
+ var seg2 = pathSegments[j];
112
+
113
+ // Skip if segments are from the same path
114
+ if (seg1.pathIndex === seg2.pathIndex) {
115
+ continue;
116
+ }
117
+
118
+ // Check if segments intersect
119
+ var intersection = this._checkLineSegmentIntersection(seg1.start, seg1.end, seg2.start, seg2.end, tolerance);
120
+ if (intersection) {
121
+ // Check if this is a shared endpoint (connector/gateway)
122
+ // Paths naturally touch at shared connectors - this is not an intersection
123
+ var endpointTolerance = 0.01; // Very small tolerance for endpoint matching
124
+ var touchingAtEndpoint = this._areSegmentsTouchingAtSharedEndpoint(seg1, seg2, endpointTolerance);
125
+ if (touchingAtEndpoint) {
126
+ console.log("\u2139\uFE0F Segments share endpoint (not an intersection): ".concat(seg1.pathFrom, " \u2194 ").concat(seg2.pathFrom));
127
+ continue; // Skip this - it's a valid shared connection point
128
+ }
129
+ intersections.push({
130
+ path1: {
131
+ from: seg1.pathFrom,
132
+ to: seg1.pathTo,
133
+ segmentIndex: seg1.segmentIndex,
134
+ isManual: seg1.isManual
135
+ },
136
+ path2: {
137
+ from: seg2.pathFrom,
138
+ to: seg2.pathTo,
139
+ segmentIndex: seg2.segmentIndex,
140
+ isManual: seg2.isManual
141
+ },
142
+ point: intersection.point,
143
+ distance: intersection.distance,
144
+ type: intersection.type
145
+ });
146
+ var seg1Type = seg1.isManual ? 'manual' : 'computed';
147
+ var seg2Type = seg2.isManual ? 'manual' : 'computed';
148
+ console.log("\u26A0\uFE0F Intersection found between paths:\n Path 1 (".concat(seg1Type, "): ").concat(seg1.pathFrom, " \u2192 ").concat(seg1.pathTo, " (segment ").concat(seg1.segmentIndex, ")\n Path 2 (").concat(seg2Type, "): ").concat(seg2.pathFrom, " \u2192 ").concat(seg2.pathTo, " (segment ").concat(seg2.segmentIndex, ")\n Distance: ").concat(intersection.distance.toFixed(4), "\n Type: ").concat(intersection.type));
149
+ }
150
+ }
151
+ }
152
+ var result = {
153
+ hasIntersections: intersections.length > 0,
154
+ intersections: intersections,
155
+ count: intersections.length
156
+ };
157
+ if (result.hasIntersections) {
158
+ console.log("\uD83D\uDEA8 Found ".concat(result.count, " intersection(s) between paths"));
159
+ } else {
160
+ console.log("\u2705 No path intersections detected");
161
+ }
162
+ return result;
163
+ }
164
+
165
+ /**
166
+ * Collect manual segments from the scene and convert them to path segments format
167
+ * @private
168
+ * @param {number} startingPathIndex - The starting index for manual segment paths
169
+ * @returns {Array} Array of segment objects in the same format as computed paths
170
+ */
171
+ }, {
172
+ key: "_collectManualSegments",
173
+ value: function _collectManualSegments(startingPathIndex) {
174
+ var _this = this;
175
+ var manualSegments = [];
176
+ var sceneViewer = this.sceneViewer;
177
+ var pathIndex = startingPathIndex;
178
+
179
+ // Traverse the scene to find manual segments (lowercase "Segment-")
180
+ sceneViewer.scene.traverse(function (obj) {
181
+ var _obj$userData, _obj$userData2;
182
+ if (obj.uuid && obj.uuid.startsWith('Segment-') && ((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'segment' && ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.isDeclared) === true) {
183
+ // Calculate segment endpoints from the cylinder geometry
184
+ var endpoints = _this._calculateSegmentEndpoints(obj);
185
+
186
+ // Create segment object in the same format as computed paths
187
+ manualSegments.push({
188
+ start: endpoints.start,
189
+ end: endpoints.end,
190
+ pathIndex: pathIndex,
191
+ segmentIndex: 0,
192
+ // Manual segments are single-segment paths
193
+ pathFrom: obj.userData.pathFrom || obj.uuid,
194
+ pathTo: obj.userData.pathTo || obj.uuid,
195
+ isFirstSegment: true,
196
+ isLastSegment: true,
197
+ isManual: true,
198
+ // Flag to identify manual segments
199
+ segmentUuid: obj.uuid
200
+ });
201
+ pathIndex++;
202
+ console.log("\uD83D\uDCE6 Collected manual segment: ".concat(obj.uuid));
203
+ }
204
+ });
205
+ return manualSegments;
206
+ }
207
+
208
+ /**
209
+ * Calculate the start and end points of a pipe segment in world coordinates
210
+ * @private
211
+ * @param {THREE.Object3D} segment - The pipe segment
212
+ * @returns {Object} Object with start and end points
213
+ */
214
+ }, {
215
+ key: "_calculateSegmentEndpoints",
216
+ value: function _calculateSegmentEndpoints(segment) {
217
+ // Get the segment's geometry to determine its length and orientation
218
+ var geometry = segment.geometry;
219
+ var length = geometry.parameters.height || 1;
220
+
221
+ // Calculate start and end points based on segment position and orientation
222
+ var startPoint = new THREE__namespace.Vector3();
223
+ var endPoint = new THREE__namespace.Vector3();
224
+
225
+ // Get the segment's direction vector
226
+ var direction = new THREE__namespace.Vector3(0, 1, 0);
227
+ direction.applyQuaternion(segment.quaternion);
228
+
229
+ // Calculate start point (half length back from center)
230
+ startPoint.copy(segment.position).sub(direction.clone().multiplyScalar(length / 2));
231
+
232
+ // Calculate end point (half length forward from center)
233
+ endPoint.copy(segment.position).add(direction.clone().multiplyScalar(length / 2));
234
+ return {
235
+ start: startPoint,
236
+ end: endPoint
237
+ };
238
+ }
239
+
240
+ /**
241
+ * Check if two segments are touching at a shared endpoint (connector/gateway)
242
+ * @private
243
+ * @param {Object} seg1 - First segment
244
+ * @param {Object} seg2 - Second segment
245
+ * @param {number} tolerance - Distance tolerance for considering points as the same
246
+ * @returns {boolean} True if segments share an endpoint
247
+ */
248
+ }, {
249
+ key: "_areSegmentsTouchingAtSharedEndpoint",
250
+ value: function _areSegmentsTouchingAtSharedEndpoint(seg1, seg2, tolerance) {
251
+ // Check all possible endpoint combinations
252
+ var endpoints = [
253
+ // seg1.start with seg2 endpoints
254
+ {
255
+ p1: seg1.start,
256
+ p2: seg2.start,
257
+ isSeg1Start: true,
258
+ isSeg2Start: true
259
+ }, {
260
+ p1: seg1.start,
261
+ p2: seg2.end,
262
+ isSeg1Start: true,
263
+ isSeg2Start: false
264
+ },
265
+ // seg1.end with seg2 endpoints
266
+ {
267
+ p1: seg1.end,
268
+ p2: seg2.start,
269
+ isSeg1Start: false,
270
+ isSeg2Start: true
271
+ }, {
272
+ p1: seg1.end,
273
+ p2: seg2.end,
274
+ isSeg1Start: false,
275
+ isSeg2Start: false
276
+ }];
277
+ for (var _i = 0, _endpoints = endpoints; _i < _endpoints.length; _i++) {
278
+ var _endpoints$_i = _endpoints[_i],
279
+ p1 = _endpoints$_i.p1,
280
+ p2 = _endpoints$_i.p2,
281
+ isSeg1Start = _endpoints$_i.isSeg1Start,
282
+ isSeg2Start = _endpoints$_i.isSeg2Start;
283
+ var distance = p1.distanceTo(p2);
284
+ if (distance <= tolerance) {
285
+ // Verify this is actually an endpoint of the path (not just any segment point)
286
+ var isSeg1Endpoint = isSeg1Start && seg1.isFirstSegment || !isSeg1Start && seg1.isLastSegment;
287
+ var isSeg2Endpoint = isSeg2Start && seg2.isFirstSegment || !isSeg2Start && seg2.isLastSegment;
288
+
289
+ // Only count as shared endpoint if at least one is a path endpoint
290
+ // (This handles both connector-to-connector and connector-to-gateway cases)
291
+ if (isSeg1Endpoint || isSeg2Endpoint) {
292
+ return true;
293
+ }
294
+ }
295
+ }
296
+ return false;
297
+ }
298
+
299
+ /**
300
+ * Check if two line segments intersect or come within tolerance distance
301
+ * @private
302
+ * @param {THREE.Vector3} p1 - Start of first segment
303
+ * @param {THREE.Vector3} p2 - End of first segment
304
+ * @param {THREE.Vector3} p3 - Start of second segment
305
+ * @param {THREE.Vector3} p4 - End of second segment
306
+ * @param {number} tolerance - Distance tolerance
307
+ * @returns {Object|null} Intersection details or null
308
+ */
309
+ }, {
310
+ key: "_checkLineSegmentIntersection",
311
+ value: function _checkLineSegmentIntersection(p1, p2, p3, p4, tolerance) {
312
+ // Calculate closest points on two line segments
313
+ var d1 = new THREE__namespace.Vector3().subVectors(p2, p1); // Direction of segment 1
314
+ var d2 = new THREE__namespace.Vector3().subVectors(p4, p3); // Direction of segment 2
315
+ var r = new THREE__namespace.Vector3().subVectors(p1, p3);
316
+ var a = d1.dot(d1);
317
+ var b = d1.dot(d2);
318
+ var c = d2.dot(d2);
319
+ var d = d1.dot(r);
320
+ var e = d2.dot(r);
321
+ var denom = a * c - b * b;
322
+
323
+ // Check if lines are parallel
324
+ if (Math.abs(denom) < 1e-10) {
325
+ // Lines are parallel, check if they're close enough
326
+ var distToLine = this._distancePointToLineSegment(p3, p1, p2);
327
+ if (distToLine <= tolerance) {
328
+ return {
329
+ point: p3.clone(),
330
+ distance: distToLine,
331
+ type: 'parallel'
332
+ };
333
+ }
334
+ return null;
335
+ }
336
+
337
+ // Calculate parameters for closest points
338
+ var s = (b * e - c * d) / denom;
339
+ var t = (a * e - b * d) / denom;
340
+
341
+ // Clamp to segment bounds
342
+ s = Math.max(0, Math.min(1, s));
343
+ t = Math.max(0, Math.min(1, t));
344
+
345
+ // Calculate closest points
346
+ var closestPoint1 = new THREE__namespace.Vector3().addVectors(p1, d1.clone().multiplyScalar(s));
347
+ var closestPoint2 = new THREE__namespace.Vector3().addVectors(p3, d2.clone().multiplyScalar(t));
348
+
349
+ // Calculate distance between closest points
350
+ var distance = closestPoint1.distanceTo(closestPoint2);
351
+
352
+ // Check if within tolerance
353
+ if (distance <= tolerance) {
354
+ var midPoint = new THREE__namespace.Vector3().addVectors(closestPoint1, closestPoint2).multiplyScalar(0.5);
355
+ return {
356
+ point: midPoint,
357
+ distance: distance,
358
+ type: distance < 0.01 ? 'crossing' : 'near'
359
+ };
360
+ }
361
+ return null;
362
+ }
363
+
364
+ /**
365
+ * Calculate distance from a point to a line segment
366
+ * @private
367
+ * @param {THREE.Vector3} point - The point
368
+ * @param {THREE.Vector3} lineStart - Start of line segment
369
+ * @param {THREE.Vector3} lineEnd - End of line segment
370
+ * @returns {number} Distance to line segment
371
+ */
372
+ }, {
373
+ key: "_distancePointToLineSegment",
374
+ value: function _distancePointToLineSegment(point, lineStart, lineEnd) {
375
+ var line = new THREE__namespace.Vector3().subVectors(lineEnd, lineStart);
376
+ var lineLength = line.length();
377
+ if (lineLength < 1e-10) {
378
+ return point.distanceTo(lineStart);
379
+ }
380
+ var t = Math.max(0, Math.min(1, new THREE__namespace.Vector3().subVectors(point, lineStart).dot(line) / (lineLength * lineLength)));
381
+ var projection = new THREE__namespace.Vector3().addVectors(lineStart, line.multiplyScalar(t));
382
+ return point.distanceTo(projection);
383
+ }
384
+ }]);
385
+ }();
386
+
387
+ exports.PathIntersectionDetector = PathIntersectionDetector;