@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,929 @@
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
+ var TransformOperationsManager = /*#__PURE__*/function () {
29
+ /**
30
+ * @param {Object} sceneViewer - The scene viewer instance
31
+ */
32
+ function TransformOperationsManager(sceneViewer) {
33
+ _rollupPluginBabelHelpers.classCallCheck(this, TransformOperationsManager);
34
+ this.sceneViewer = sceneViewer;
35
+ }
36
+
37
+ /**
38
+ * Translate a component by componentId
39
+ * @param {string} componentId - The UUID of the component to translate
40
+ * @param {string} axis - The axis to translate on ('x', 'y', or 'z')
41
+ * @param {number} value - The value to translate by
42
+ * @returns {boolean} True if translation was successful, false otherwise
43
+ */
44
+ return _rollupPluginBabelHelpers.createClass(TransformOperationsManager, [{
45
+ key: "translateComponent",
46
+ value: function translateComponent(componentId, axis, value) {
47
+ var _this$sceneViewer$man, _this$sceneViewer;
48
+ // Store transform parameters using the OperationHistoryManager
49
+ if ((_this$sceneViewer$man = this.sceneViewer.managers) !== null && _this$sceneViewer$man !== void 0 && _this$sceneViewer$man.operationHistoryManager) {
50
+ this.sceneViewer.managers.operationHistoryManager.addToOperationHistory('translateComponent', {
51
+ componentId: componentId,
52
+ axis: axis,
53
+ value: value
54
+ });
55
+ }
56
+
57
+ // Validate parameters
58
+ if (!componentId || !axis || value === undefined || value === null) {
59
+ console.error('❌ translateComponent(): Invalid parameters');
60
+ return false;
61
+ }
62
+ if (!['x', 'y', 'z'].includes(axis)) {
63
+ console.error("\u274C translateComponent(): Invalid axis '".concat(axis, "'. Must be 'x', 'y', or 'z'"));
64
+ return false;
65
+ }
66
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
67
+ console.error('❌ translateComponent(): Scene viewer or scene not available');
68
+ return false;
69
+ }
70
+
71
+ // Find the component in the scene
72
+ var component = null;
73
+ this.sceneViewer.scene.traverse(function (child) {
74
+ var _child$userData;
75
+ if (child.uuid === componentId || ((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.originalUuid) === componentId) {
76
+ component = child;
77
+ }
78
+ });
79
+ if (!component) {
80
+ console.error("\u274C translateComponent(): Component with ID '".concat(componentId, "' not found in scene"));
81
+ return false;
82
+ }
83
+
84
+ // Validate that it's actually a component
85
+ if (!component.userData || !component.userData.objectType) {
86
+ console.error("\u274C translateComponent(): Object with ID '".concat(componentId, "' is not a valid component"));
87
+ return false;
88
+ }
89
+
90
+ // Apply the translation
91
+ console.log("\uD83D\uDD04 translateComponent(): Translating component ".concat(componentId, " on ").concat(axis, " axis by ").concat(value));
92
+
93
+ // Update the Three.js object position
94
+ component.position[axis] += value;
95
+
96
+ // Update matrices
97
+ component.updateMatrix();
98
+ component.updateMatrixWorld(true);
99
+
100
+ // Check if component is underground and fix if needed (based on settings)
101
+ var checkUnderground = (_this$sceneViewer = this.sceneViewer) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.managers) === null || _this$sceneViewer === void 0 || (_this$sceneViewer = _this$sceneViewer.settingsManager) === null || _this$sceneViewer === void 0 ? void 0 : _this$sceneViewer.getSetting('scene', 'checkUnderground');
102
+ if (checkUnderground) {
103
+ this.fixUndergroundComponent(component);
104
+ }
105
+
106
+ // Emit transform event if available
107
+ if (this.sceneViewer.emit && typeof this.sceneViewer.emit === 'function') {
108
+ this.sceneViewer.emit('objectTransformed', {
109
+ object: component,
110
+ transformType: 'translate',
111
+ axis: axis,
112
+ value: value
113
+ });
114
+ }
115
+ console.log("\u2705 translateComponent(): Component ".concat(componentId, " translated successfully"));
116
+ return true;
117
+ }
118
+
119
+ /**
120
+ * Translate a pipe segment by segmentId
121
+ * @param {string} segmentId - The UUID of the pipe segment to translate
122
+ * @param {string} axis - The axis to translate on ('x', 'y', or 'z')
123
+ * @param {number} value - The value to translate by
124
+ * @returns {boolean} True if translation was successful, false otherwise
125
+ */
126
+ }, {
127
+ key: "translateSegment",
128
+ value: function translateSegment(segmentId, axis, value) {
129
+ var _this$sceneViewer$man2, _segment$userData, _segment$userData2, _this$sceneViewer3, _this$sceneViewer$man4, _this$sceneViewer$man5;
130
+ // Store transform parameters using the OperationHistoryManager
131
+ if ((_this$sceneViewer$man2 = this.sceneViewer.managers) !== null && _this$sceneViewer$man2 !== void 0 && _this$sceneViewer$man2.operationHistoryManager) {
132
+ this.sceneViewer.managers.operationHistoryManager.addToOperationHistory('translateSegment', {
133
+ segmentId: segmentId,
134
+ axis: axis,
135
+ value: value
136
+ });
137
+ }
138
+
139
+ // Validate parameters
140
+ if (!segmentId || !axis || value === undefined || value === null) {
141
+ console.error('❌ translateSegment(): Invalid parameters');
142
+ return false;
143
+ }
144
+ if (!['x', 'y', 'z'].includes(axis)) {
145
+ console.error("\u274C translateSegment(): Invalid axis '".concat(axis, "'. Must be 'x', 'y', or 'z'"));
146
+ return false;
147
+ }
148
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
149
+ console.error('❌ translateSegment(): Scene viewer or scene not available');
150
+ return false;
151
+ }
152
+
153
+ // Find the segment in the scene
154
+ var segment = null;
155
+ this.sceneViewer.scene.traverse(function (child) {
156
+ var _child$userData2;
157
+ if (child.uuid === segmentId || ((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.originalUuid) === segmentId) {
158
+ segment = child;
159
+ }
160
+ });
161
+ if (!segment) {
162
+ console.error("\u274C translateSegment(): Segment with ID '".concat(segmentId, "' not found in scene"));
163
+ return false;
164
+ }
165
+
166
+ // Validate that it's actually a pipe segment
167
+ if (!((_segment$userData = segment.userData) !== null && _segment$userData !== void 0 && _segment$userData.objectType) === 'segment') {
168
+ console.error("\u274C translateSegment(): Object with ID '".concat(segmentId, "' is not a valid pipe segment"));
169
+ return false;
170
+ }
171
+
172
+ // Check if segment is transformable
173
+ if (((_segment$userData2 = segment.userData) === null || _segment$userData2 === void 0 ? void 0 : _segment$userData2.transformable) === false) {
174
+ console.warn("\u26A0\uFE0F translateSegment(): Segment '".concat(segmentId, "' is marked as non-transformable (stub segment)"));
175
+ return false;
176
+ }
177
+ console.log('[translateSegment] segment:', segment);
178
+
179
+ // Calculate segment endpoints to check for nearby connectors
180
+ var segmentEndpoints = this.calculateSegmentEndpoints(segment);
181
+
182
+ // Check if there are any connectors (component or manual) at segment endpoints
183
+ var connectorsAtEndpoints = this.findConnectorsAtPositions([segmentEndpoints.start, segmentEndpoints.end], 0.15 // tolerance for position matching
184
+ );
185
+
186
+ // Filter out segment connectors - we only care about component connectors
187
+ var componentConnectorsAtEndpoints = connectorsAtEndpoints.filter(function (connector) {
188
+ var _connector$userData;
189
+ return ((_connector$userData = connector.userData) === null || _connector$userData === void 0 ? void 0 : _connector$userData.objectType) !== 'segment-connector';
190
+ });
191
+ if (componentConnectorsAtEndpoints.length > 0) {
192
+ var _this$sceneViewer$man3, _this$sceneViewer2;
193
+ console.warn("\u26A0\uFE0F translateSegment(): Segment '".concat(segmentId, "' has component connectors at endpoints. Splitting segment..."));
194
+ console.log(" Found ".concat(componentConnectorsAtEndpoints.length, " component connector(s):"), componentConnectorsAtEndpoints.map(function (c) {
195
+ var _c$parent;
196
+ return {
197
+ uuid: c.uuid,
198
+ parent: (_c$parent = c.parent) === null || _c$parent === void 0 ? void 0 : _c$parent.uuid
199
+ };
200
+ }));
201
+
202
+ // Split the segment using SceneOperationsManager (will auto-detect component connectors)
203
+ var _sceneOperationsManager = (_this$sceneViewer$man3 = this.sceneViewer.managers) === null || _this$sceneViewer$man3 === void 0 ? void 0 : _this$sceneViewer$man3.sceneOperationsManager;
204
+ if (!_sceneOperationsManager) {
205
+ console.error('❌ translateSegment(): SceneOperationsManager not available for splitting');
206
+ return false;
207
+ }
208
+
209
+ // Check if segment splitting is enabled in settings
210
+ var splitSegmentsEnabled = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 || (_this$sceneViewer2 = _this$sceneViewer2.managers) === null || _this$sceneViewer2 === void 0 || (_this$sceneViewer2 = _this$sceneViewer2.settingsManager) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.getSetting('scene', 'splitSegmentsWithComponentConnectors');
211
+ if (splitSegmentsEnabled === false) {
212
+ return false;
213
+ }
214
+ try {
215
+ var splitResult = _sceneOperationsManager.splitSegment(segment);
216
+ if (splitResult && splitResult.segment1 && splitResult.segment2) {
217
+ console.log("\u2705 Segment split: ".concat(splitResult.segment1.uuid, " (").concat(splitResult.segment1.geometry.parameters.height, "), ").concat(splitResult.segment2.uuid, " (").concat(splitResult.segment2.geometry.parameters.height, ")"));
218
+
219
+ // Determine which segment is the longer one (free side) to translate
220
+ var segment1Length = splitResult.segment1.geometry.parameters.height;
221
+ var segment2Length = splitResult.segment2.geometry.parameters.height;
222
+
223
+ // The longer segment is the one WITHOUT the component connector
224
+ var segmentToTranslate = segment1Length > segment2Length ? splitResult.segment1 : splitResult.segment2;
225
+ console.log("\uD83C\uDFAF Translating ".concat(segmentToTranslate.uuid, " (length: ").concat(segmentToTranslate.geometry.parameters.height, ") - the free segment"));
226
+
227
+ // Now translate the chosen segment (recursive call with the new segment)
228
+ var translateSuccess = this.translateSegment(segmentToTranslate.uuid, axis, value);
229
+ if (!translateSuccess) {
230
+ console.error('❌ translateSegment(): Failed to translate split segment half');
231
+ return false;
232
+ }
233
+ console.log('✅ Split and translate operation completed successfully');
234
+ return true;
235
+ } else {
236
+ console.error('❌ translateSegment(): Split operation failed');
237
+ return false;
238
+ }
239
+ } catch (error) {
240
+ console.error('❌ translateSegment(): Error splitting segment:', error);
241
+ return false;
242
+ }
243
+ }
244
+ console.log("\uD83D\uDD04 translateSegment(): Translating segment ".concat(segmentId, " on ").concat(axis, " axis by ").concat(value));
245
+
246
+ // Check if translationalOverrideForAutomaticSegments is enabled
247
+ var translationalOverride = (_this$sceneViewer3 = this.sceneViewer) === null || _this$sceneViewer3 === void 0 || (_this$sceneViewer3 = _this$sceneViewer3.managers) === null || _this$sceneViewer3 === void 0 || (_this$sceneViewer3 = _this$sceneViewer3.settingsManager) === null || _this$sceneViewer3 === void 0 ? void 0 : _this$sceneViewer3.getSetting('scene', 'translationalOverrideForAutomaticSegments');
248
+
249
+ // If override is disabled (false), check for intersections with computed segments
250
+ if (translationalOverride === false) {
251
+ console.log('🔍 Checking for intersections with computed segments (translationalOverrideForAutomaticSegments is disabled)');
252
+
253
+ // Temporarily apply the translation to check for intersections
254
+ var originalPosition = segment.position[axis];
255
+ segment.position[axis] += value;
256
+ segment.updateMatrix();
257
+ segment.updateMatrixWorld(true);
258
+
259
+ // Check if the translated segment intersects with any computed segments
260
+ var hasIntersection = this.checkSegmentIntersection(segment);
261
+ console.log("\uD83D\uDD04 translateSegment() hasIntersection:", hasIntersection);
262
+ if (hasIntersection) {
263
+ // Revert the translation
264
+ segment.position[axis] = originalPosition;
265
+ segment.updateMatrix();
266
+ segment.updateMatrixWorld(true);
267
+ console.warn("\u26A0\uFE0F translateSegment(): Translation canceled - segment would intersect with computed segment(s)");
268
+ return false;
269
+ }
270
+ console.log('✅ No intersections detected, proceeding with translation');
271
+ } else {
272
+ // Apply the translation to the Three.js object
273
+ segment.position[axis] += value;
274
+
275
+ // Update matrices
276
+ segment.updateMatrix();
277
+ segment.updateMatrixWorld(true);
278
+ }
279
+
280
+ // Validate PathfindingManager and SceneOperationsManager availability
281
+ var pathfindingManager = (_this$sceneViewer$man4 = this.sceneViewer.managers) === null || _this$sceneViewer$man4 === void 0 ? void 0 : _this$sceneViewer$man4.pathfindingManager;
282
+ var sceneOperationsManager = (_this$sceneViewer$man5 = this.sceneViewer.managers) === null || _this$sceneViewer$man5 === void 0 ? void 0 : _this$sceneViewer$man5.sceneOperationsManager;
283
+ if (!pathfindingManager || !sceneOperationsManager) {
284
+ console.error('❌ translateSegment(): PathfindingManager or SceneOperationsManager not available');
285
+ return false;
286
+ }
287
+
288
+ // Check if segment is already declared - if not, manualize it first
289
+ if (segment.userData.isDeclared !== true) {
290
+ console.log('🔌 Handling manual segment transformation via SceneOperationsManager (first move)');
291
+ try {
292
+ sceneOperationsManager.manualizeSegment(segment, this.sceneViewer.currentSceneData);
293
+ } catch (error) {
294
+ console.error('❌ translateSegment(): Error in manualizeSegment:', error);
295
+ return false;
296
+ }
297
+ } else {
298
+ console.log('🔄 Segment already declared, updating connector positions (subsequent move)');
299
+ }
300
+
301
+ // ALWAYS update connector positions after segment movement (first or subsequent moves)
302
+ this.updateSegmentConnectorPositions(segment);
303
+
304
+ // Regenerate paths to create new pipe segments that connect to the moved segment
305
+ console.log('🔄 Regenerating paths to create connecting pipe segments...');
306
+ try {
307
+ if (this.sceneViewer && typeof this.sceneViewer.updatePaths === 'function') {
308
+ this.sceneViewer.updatePaths();
309
+ console.log('✅ Paths regenerated successfully - new connecting segments created');
310
+ } else {
311
+ console.warn('⚠️ updatePaths method not available on sceneViewer');
312
+ }
313
+ } catch (error) {
314
+ console.error('❌ Error regenerating paths:', error);
315
+ }
316
+
317
+ // Emit transform event if available
318
+ if (this.sceneViewer.emit && typeof this.sceneViewer.emit === 'function') {
319
+ this.sceneViewer.emit('objectTransformed', {
320
+ object: segment,
321
+ transformType: 'translateSegment',
322
+ axis: axis,
323
+ value: value
324
+ });
325
+ }
326
+ console.log("\u2705 translateSegment(): Segment ".concat(segmentId, " translated and connections restructured successfully"));
327
+ return true;
328
+ }
329
+
330
+ /**
331
+ * Translate a gateway by gatewayId
332
+ * @param {string} gatewayId - The UUID of the gateway to translate
333
+ * @param {string} axis - The axis to translate on ('x', 'y', or 'z')
334
+ * @param {number} value - The value to translate by
335
+ * @returns {boolean} True if translation was successful, false otherwise
336
+ */
337
+ }, {
338
+ key: "translateGateway",
339
+ value: function translateGateway(gatewayId, axis, value) {
340
+ var _this$sceneViewer$man6, _this$sceneViewer$man7;
341
+ console.log("[Pathfinder] translateGateway started");
342
+
343
+ // Store transform parameters using the OperationHistoryManager
344
+ if ((_this$sceneViewer$man6 = this.sceneViewer.managers) !== null && _this$sceneViewer$man6 !== void 0 && _this$sceneViewer$man6.operationHistoryManager) {
345
+ this.sceneViewer.managers.operationHistoryManager.addToOperationHistory('translateGateway', {
346
+ gatewayId: gatewayId,
347
+ axis: axis,
348
+ value: value
349
+ });
350
+ }
351
+
352
+ // Validate parameters
353
+ if (!gatewayId || !axis || value === undefined || value === null) {
354
+ console.error('❌ translateGateway(): Invalid parameters');
355
+ return false;
356
+ }
357
+ if (!['x', 'y', 'z'].includes(axis)) {
358
+ console.error("\u274C translateGateway(): Invalid axis '".concat(axis, "'. Must be 'x', 'y', or 'z'"));
359
+ return false;
360
+ }
361
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
362
+ console.error('❌ translateGateway(): Scene viewer or scene not available');
363
+ return false;
364
+ }
365
+
366
+ // Find the gateway in the scene
367
+ var gateway = null;
368
+ this.sceneViewer.scene.traverse(function (child) {
369
+ var _child$userData3;
370
+ if (child.uuid === gatewayId || ((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.originalUuid) === gatewayId) {
371
+ gateway = child;
372
+ }
373
+ });
374
+ if (!gateway) {
375
+ console.error("\u274C translateGateway(): Gateway with ID '".concat(gatewayId, "' not found in scene"));
376
+ return false;
377
+ }
378
+
379
+ // Validate that it's actually a gateway
380
+ if (!gateway.userData || gateway.userData.objectType !== 'gateway') {
381
+ console.error("\u274C translateGateway(): Object with ID '".concat(gatewayId, "' is not a valid gateway"));
382
+ return false;
383
+ }
384
+ console.log("\uD83D\uDD04 translateGateway(): Translating gateway ".concat(gatewayId, " on ").concat(axis, " axis by ").concat(value));
385
+
386
+ // Apply the translation to the Three.js object
387
+ gateway.position[axis] += value;
388
+
389
+ // Update matrices
390
+ gateway.updateMatrix();
391
+ gateway.updateMatrixWorld(true);
392
+
393
+ // Handle manual gateway transformation (convert to declared and process connections)
394
+ console.log('🔧 Handling manual gateway transformation via SceneOperationsManager');
395
+ var sceneOperationsManager = (_this$sceneViewer$man7 = this.sceneViewer.managers) === null || _this$sceneViewer$man7 === void 0 ? void 0 : _this$sceneViewer$man7.sceneOperationsManager;
396
+ if (!sceneOperationsManager) {
397
+ console.error('❌ translateGateway(): SceneOperationsManager not available');
398
+ return false;
399
+ }
400
+ try {
401
+ sceneOperationsManager.manualizeGateway(gateway, this.sceneViewer.currentSceneData);
402
+ } catch (error) {
403
+ console.error('❌ translateGateway(): Error in manualizeGateway:', error);
404
+ return false;
405
+ }
406
+
407
+ // Regenerate paths to reflect the gateway's new position
408
+ console.log('🔄 Regenerating paths to reflect gateway movement...');
409
+ try {
410
+ if (this.sceneViewer && typeof this.sceneViewer.updatePaths === 'function') {
411
+ this.sceneViewer.updatePaths();
412
+ console.log('✅ Paths regenerated successfully - routing updated for new gateway position');
413
+ } else {
414
+ console.warn('⚠️ updatePaths method not available on sceneViewer');
415
+ }
416
+ } catch (error) {
417
+ console.error('❌ Error regenerating paths:', error);
418
+ }
419
+
420
+ // Emit transform event if available
421
+ if (this.sceneViewer.emit && typeof this.sceneViewer.emit === 'function') {
422
+ this.sceneViewer.emit('objectTransformed', {
423
+ object: gateway,
424
+ transformType: 'translateGateway',
425
+ axis: axis,
426
+ value: value
427
+ });
428
+ }
429
+ console.log("\u2705 translateGateway(): Gateway ".concat(gatewayId, " translated and marked as declared successfully"));
430
+ return true;
431
+ }
432
+
433
+ /**
434
+ * Rotate a component by componentId
435
+ * @param {string} componentId - The UUID of the component to rotate
436
+ * @param {string} axis - The axis to rotate around ('x', 'y', or 'z')
437
+ * @param {number} value - The value to rotate by in degrees
438
+ * @returns {boolean} True if rotation was successful, false otherwise
439
+ */
440
+ }, {
441
+ key: "rotateComponent",
442
+ value: function rotateComponent(componentId, axis, value) {
443
+ // Validate parameters
444
+ if (!componentId || !axis || value === undefined || value === null) {
445
+ console.error('❌ rotateComponent(): Invalid parameters');
446
+ return false;
447
+ }
448
+ if (!['x', 'y', 'z'].includes(axis)) {
449
+ console.error("\u274C rotateComponent(): Invalid axis '".concat(axis, "'. Must be 'x', 'y', or 'z'"));
450
+ return false;
451
+ }
452
+ if (!this.sceneViewer || !this.sceneViewer.scene) {
453
+ console.error('❌ rotateComponent(): Scene viewer or scene not available');
454
+ return false;
455
+ }
456
+
457
+ // Find the component in the scene
458
+ var component = null;
459
+ this.sceneViewer.scene.traverse(function (child) {
460
+ var _child$userData4;
461
+ if (child.uuid === componentId || ((_child$userData4 = child.userData) === null || _child$userData4 === void 0 ? void 0 : _child$userData4.originalUuid) === componentId) {
462
+ component = child;
463
+ }
464
+ });
465
+ if (!component) {
466
+ console.error("\u274C rotateComponent(): Component with ID '".concat(componentId, "' not found in scene"));
467
+ return false;
468
+ }
469
+ if (!component.userData.libraryId) {
470
+ console.error("\u274C rotateComponent(): Object with ID '".concat(componentId, "' is not a valid component"));
471
+ return false;
472
+ }
473
+
474
+ // Store previous rotation for potential undo
475
+ var previousRotation = {
476
+ x: component.rotation.x,
477
+ y: component.rotation.y,
478
+ z: component.rotation.z
479
+ };
480
+
481
+ // Convert degrees to radians
482
+ var radians = value * Math.PI / 180;
483
+ console.log("\uD83D\uDD04 rotateComponent(): Rotating component ".concat(componentId, " around ").concat(axis, " axis by ").concat(value, " degrees (").concat(radians, " radians)"));
484
+
485
+ // Apply the rotation
486
+ component.rotation[axis] += radians;
487
+
488
+ // Update direction vectors for connectors if this is a 90-degree rotation
489
+ if (value % 90 === 0) {
490
+ this.updateConnectorDirections(component, axis, value);
491
+ }
492
+
493
+ // Update matrices
494
+ component.updateMatrix();
495
+ component.updateMatrixWorld(true);
496
+
497
+ // Emit transform event if available
498
+ if (this.sceneViewer.emit && typeof this.sceneViewer.emit === 'function') {
499
+ this.sceneViewer.emit('objectTransformed', {
500
+ object: component,
501
+ transformType: 'rotate',
502
+ axis: axis,
503
+ value: value,
504
+ radians: radians,
505
+ previousRotation: previousRotation
506
+ });
507
+ }
508
+ console.log("\u2705 rotateComponent(): Component ".concat(componentId, " rotated successfully"));
509
+ return true;
510
+ }
511
+
512
+ /**
513
+ * Update connector direction vectors after component rotation
514
+ * @param {THREE.Object3D} component - The component that was rotated
515
+ * @param {string} axis - The axis of rotation ('x', 'y', or 'z')
516
+ * @param {number} degrees - The rotation angle in degrees (should be multiple of 90)
517
+ * @private
518
+ */
519
+ }, {
520
+ key: "updateConnectorDirections",
521
+ value: function updateConnectorDirections(component, axis, degrees) {
522
+ if (!component || degrees % 90 !== 0) {
523
+ return;
524
+ }
525
+ console.log("\uD83D\uDD04 Updating connector directions after ".concat(degrees, "\xB0 rotation around ").concat(axis, " axis"));
526
+
527
+ // Simple approach: just log that directions may need manual verification
528
+ // In most cases, Three.js world matrices handle the actual positioning correctly
529
+ component.traverse(function (child) {
530
+ var _child$userData5, _child$userData6;
531
+ if (((_child$userData5 = child.userData) === null || _child$userData5 === void 0 ? void 0 : _child$userData5.objectType) === 'connector' && (_child$userData6 = child.userData) !== null && _child$userData6 !== void 0 && _child$userData6.direction) {
532
+ console.log("\uD83D\uDCCD Connector ".concat(child.uuid, " direction may need verification after rotation"));
533
+ }
534
+ });
535
+ }
536
+
537
+ /**
538
+ * Check if a component is positioned underground (below Z=0 in Z-up coordinate system)
539
+ * @param {THREE.Object3D} component - The component to check
540
+ * @returns {Object} Object with { isUnderground: boolean, lowestZ: number, correction: number }
541
+ */
542
+ }, {
543
+ key: "checkComponentUnderground",
544
+ value: function checkComponentUnderground(component) {
545
+ if (!component) {
546
+ return {
547
+ isUnderground: false,
548
+ lowestZ: 0,
549
+ correction: 0
550
+ };
551
+ }
552
+ try {
553
+ // Calculate bounding box in world coordinates
554
+ var boundingBox = new THREE__namespace.Box3().setFromObject(component);
555
+
556
+ // In Z-up coordinate system, ground is at z=0
557
+ // Check the lowest Z point of the bounding box
558
+ var lowestZ = boundingBox.min.z;
559
+ var isUnderground = lowestZ < 0;
560
+
561
+ // Calculate how much we need to move up to put the lowest point at ground level
562
+ var correction = isUnderground ? Math.abs(lowestZ) : 0;
563
+ return {
564
+ isUnderground: isUnderground,
565
+ lowestZ: lowestZ,
566
+ correction: correction
567
+ };
568
+ } catch (error) {
569
+ console.warn('⚠️ Error checking component underground status:', error);
570
+ return {
571
+ isUnderground: false,
572
+ lowestZ: 0,
573
+ correction: 0
574
+ };
575
+ }
576
+ }
577
+
578
+ /**
579
+ * Fix component position if it's underground
580
+ * @param {THREE.Object3D} component - The component to fix
581
+ * @returns {boolean} True if component was adjusted, false otherwise
582
+ */
583
+ }, {
584
+ key: "fixUndergroundComponent",
585
+ value: function fixUndergroundComponent(component) {
586
+ if (!component) {
587
+ return false;
588
+ }
589
+ var checkResult = this.checkComponentUnderground(component);
590
+ if (checkResult.isUnderground) {
591
+ var _component$userData;
592
+ var componentId = component.uuid || ((_component$userData = component.userData) === null || _component$userData === void 0 ? void 0 : _component$userData.originalUuid) || 'unknown';
593
+ console.log("\uD83D\uDD27 Component ".concat(componentId, " is underground (lowest Z: ").concat(checkResult.lowestZ.toFixed(3), "), moving up by ").concat(checkResult.correction.toFixed(3)));
594
+
595
+ // Move the component up so its lowest point is at ground level (z=0)
596
+ component.position.z += checkResult.correction;
597
+
598
+ // Update matrices
599
+ component.updateMatrix();
600
+ component.updateMatrixWorld(true);
601
+ console.log("\u2705 Component ".concat(componentId, " moved to surface (new position Z: ").concat(component.position.z.toFixed(3), ")"));
602
+ return true;
603
+ }
604
+ return false;
605
+ }
606
+
607
+ /**
608
+ * Check if a pipe segment is horizontal (Z-axis aligned in Z-up coordinate system)
609
+ * A segment is considered horizontal if its direction vector has minimal Z component
610
+ * @param {THREE.Object3D} segment - The pipe segment to check
611
+ * @param {number} tolerance - Angular tolerance in radians (default: ~5.7 degrees)
612
+ * @returns {boolean} True if segment is horizontal, false otherwise
613
+ * @private
614
+ */
615
+ }, {
616
+ key: "isSegmentHorizontal",
617
+ value: function isSegmentHorizontal(segment) {
618
+ var tolerance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.1;
619
+ if (!segment || !segment.geometry || !segment.quaternion) {
620
+ console.warn('⚠️ Invalid segment provided to isSegmentHorizontal');
621
+ return false;
622
+ }
623
+
624
+ // Get the segment's direction vector (cylinder aligned with Y-axis by default)
625
+ var direction = new THREE__namespace.Vector3(0, 1, 0);
626
+ direction.applyQuaternion(segment.quaternion);
627
+ direction.normalize();
628
+
629
+ // In Z-up coordinate system, horizontal segments should have Z component near 0
630
+ // A perfectly horizontal segment would have direction.z = 0
631
+ var zComponent = Math.abs(direction.z);
632
+
633
+ // Allow small tolerance for floating point precision
634
+ return zComponent < tolerance;
635
+ }
636
+
637
+ /**
638
+ * Calculate segment endpoints in world coordinates
639
+ * @param {THREE.Object3D} segment - The pipe segment
640
+ * @returns {Object} Object with start and end Vector3 points
641
+ * @private
642
+ */
643
+ }, {
644
+ key: "calculateSegmentEndpoints",
645
+ value: function calculateSegmentEndpoints(segment) {
646
+ // Get the segment's geometry to determine its length and orientation
647
+ var geometry = segment.geometry;
648
+ var length = geometry.parameters.height || 1;
649
+
650
+ // Calculate start and end points based on segment position and orientation
651
+ var startPoint = new THREE__namespace.Vector3();
652
+ var endPoint = new THREE__namespace.Vector3();
653
+
654
+ // Get the segment's direction vector
655
+ var direction = new THREE__namespace.Vector3(0, 1, 0);
656
+ direction.applyQuaternion(segment.quaternion);
657
+
658
+ // Calculate start point (half length back from center)
659
+ startPoint.copy(segment.position).sub(direction.clone().multiplyScalar(length / 2));
660
+
661
+ // Calculate end point (half length forward from center)
662
+ endPoint.copy(segment.position).add(direction.clone().multiplyScalar(length / 2));
663
+ return {
664
+ start: startPoint,
665
+ end: endPoint
666
+ };
667
+ }
668
+
669
+ /**
670
+ * Find all connectors (component or manual) at given positions
671
+ * @param {Array<THREE.Vector3>} positions - Array of positions to check
672
+ * @param {number} tolerance - Distance tolerance for position matching
673
+ * @returns {Array<THREE.Object3D>} Array of connector objects found at positions
674
+ * @private
675
+ */
676
+ }, {
677
+ key: "findConnectorsAtPositions",
678
+ value: function findConnectorsAtPositions(positions) {
679
+ var _this$sceneViewer4;
680
+ var tolerance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.15;
681
+ if (!((_this$sceneViewer4 = this.sceneViewer) !== null && _this$sceneViewer4 !== void 0 && _this$sceneViewer4.scene)) {
682
+ return [];
683
+ }
684
+ var foundConnectors = [];
685
+
686
+ // Traverse scene to find all connectors
687
+ this.sceneViewer.scene.traverse(function (child) {
688
+ var _child$userData7;
689
+ // Check if this is a connector (component connector or manual segment connector)
690
+ if (((_child$userData7 = child.userData) === null || _child$userData7 === void 0 ? void 0 : _child$userData7.objectType) === 'connector') {
691
+ // Get world position of connector
692
+ var connectorWorldPos = new THREE__namespace.Vector3();
693
+ child.getWorldPosition(connectorWorldPos);
694
+
695
+ // Check if connector is near any of the target positions
696
+ var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(positions),
697
+ _step;
698
+ try {
699
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
700
+ var position = _step.value;
701
+ var distance = connectorWorldPos.distanceTo(position);
702
+ if (distance <= tolerance) {
703
+ foundConnectors.push(child);
704
+ break; // Don't count the same connector twice
705
+ }
706
+ }
707
+ } catch (err) {
708
+ _iterator.e(err);
709
+ } finally {
710
+ _iterator.f();
711
+ }
712
+ }
713
+ });
714
+ return foundConnectors;
715
+ }
716
+
717
+ /**
718
+ * Update connector positions in scene data after a declared segment is moved
719
+ * @param {THREE.Object3D} segment - The segment whose connectors need updating
720
+ * @private
721
+ */
722
+ }, {
723
+ key: "updateSegmentConnectorPositions",
724
+ value: function updateSegmentConnectorPositions(segment) {
725
+ var _this$sceneViewer5;
726
+ console.log("updateSegmentConnectorPositions started:", segment);
727
+ if (!segment || !((_this$sceneViewer5 = this.sceneViewer) !== null && _this$sceneViewer5 !== void 0 && (_this$sceneViewer5 = _this$sceneViewer5.currentSceneData) !== null && _this$sceneViewer5 !== void 0 && _this$sceneViewer5.scene)) {
728
+ console.warn('⚠️ updateSegmentConnectorPositions(): Missing segment or scene data');
729
+ return;
730
+ }
731
+
732
+ // Helper function to clean up floating-point precision errors
733
+ var cleanPosition = function cleanPosition(value) {
734
+ return Math.abs(value) < 1e-10 ? 0 : value;
735
+ };
736
+
737
+ // Find all child connectors of the segment
738
+ var connectors = [];
739
+ segment.traverse(function (child) {
740
+ var _child$userData8;
741
+ if (((_child$userData8 = child.userData) === null || _child$userData8 === void 0 ? void 0 : _child$userData8.objectType) === 'segment-connector') {
742
+ connectors.push(child);
743
+ }
744
+ });
745
+ if (connectors.length === 0) {
746
+ console.warn("\u26A0\uFE0F No connectors found for segment ".concat(segment.uuid));
747
+ return;
748
+ }
749
+ console.log("\uD83D\uDCCD Updating ".concat(connectors.length, " connector positions in scene data for segment ").concat(segment.uuid));
750
+
751
+ // First, find the segment in scene data
752
+ var sceneDataSegment = this.sceneViewer.currentSceneData.scene.children.find(function (child) {
753
+ var _segment$userData3;
754
+ return child.uuid === segment.uuid || child.uuid === ((_segment$userData3 = segment.userData) === null || _segment$userData3 === void 0 ? void 0 : _segment$userData3.originalUuid);
755
+ });
756
+ if (!sceneDataSegment) {
757
+ console.warn("\u26A0\uFE0F Segment ".concat(segment.uuid, " not found in scene data"));
758
+ return;
759
+ }
760
+ if (!sceneDataSegment.children || !Array.isArray(sceneDataSegment.children)) {
761
+ console.warn("\u26A0\uFE0F Segment ".concat(segment.uuid, " has no children array in scene data"));
762
+ return;
763
+ }
764
+ console.log("\u2705 Found segment in scene data with ".concat(sceneDataSegment.children.length, " children"));
765
+
766
+ // Update each connector's position in scene data
767
+ connectors.forEach(function (connector) {
768
+ // Get world position
769
+ var worldPosition = new THREE__namespace.Vector3();
770
+ connector.getWorldPosition(worldPosition);
771
+
772
+ // Find the connector in the segment's children array (not root scene.children)
773
+ var sceneDataConnector = sceneDataSegment.children.find(function (child) {
774
+ var _connector$userData2;
775
+ return child.uuid === connector.uuid || child.uuid === ((_connector$userData2 = connector.userData) === null || _connector$userData2 === void 0 ? void 0 : _connector$userData2.originalUuid);
776
+ });
777
+ if (sceneDataConnector && sceneDataConnector.userData) {
778
+ // Update position as array [x, y, z] for pathfinder compatibility
779
+ sceneDataConnector.userData.position = [cleanPosition(worldPosition.x), cleanPosition(worldPosition.y), cleanPosition(worldPosition.z)];
780
+ console.log("\u2705 Updated connector ".concat(connector.uuid, " position to [").concat(sceneDataConnector.userData.position.join(', '), "]"));
781
+ } else {
782
+ console.warn("\u26A0\uFE0F Connector ".concat(connector.uuid, " not found in segment's children in scene data"));
783
+ }
784
+ });
785
+ }
786
+
787
+ /**
788
+ * Check if a segment intersects with any computed segments in the scene
789
+ * Uses segment-to-segment distance calculation, excluding endpoint connections
790
+ * @param {THREE.Object3D} segment - The segment to check for intersections
791
+ * @returns {boolean} True if segment intersects with any computed segment (not just touching at ends)
792
+ * @private
793
+ */
794
+ }, {
795
+ key: "checkSegmentIntersection",
796
+ value: function checkSegmentIntersection(segment) {
797
+ var _this$sceneViewer6,
798
+ _this = this;
799
+ if (!((_this$sceneViewer6 = this.sceneViewer) !== null && _this$sceneViewer6 !== void 0 && _this$sceneViewer6.scene)) {
800
+ return false;
801
+ }
802
+
803
+ // Get endpoints of the segment being checked
804
+ var segmentEndpoints = this.calculateSegmentEndpoints(segment);
805
+ var segmentRadius = segment.geometry.parameters.radiusTop || 0.05;
806
+
807
+ // Track if any intersection was found
808
+ var hasIntersection = false;
809
+
810
+ // Check all segments in the scene
811
+ this.sceneViewer.scene.traverse(function (child) {
812
+ var _child$userData9, _child$userData0;
813
+ // Skip the segment itself
814
+ if (child.uuid === segment.uuid) {
815
+ return;
816
+ }
817
+
818
+ // Only check computed segments (isDeclared === false or undefined)
819
+ if (((_child$userData9 = child.userData) === null || _child$userData9 === void 0 ? void 0 : _child$userData9.objectType) === 'segment' && ((_child$userData0 = child.userData) === null || _child$userData0 === void 0 ? void 0 : _child$userData0.isDeclared) !== true) {
820
+ // Get endpoints of the computed segment
821
+ var computedEndpoints = _this.calculateSegmentEndpoints(child);
822
+ var computedRadius = child.geometry.parameters.radiusTop || 0.05;
823
+
824
+ // Combined radius threshold - segments intersect if closer than this
825
+ var combinedRadius = segmentRadius + computedRadius;
826
+
827
+ // First, check if segments are connected at endpoints
828
+ // This is a cheaper check than full segment-to-segment distance
829
+ var endpointTolerance = 0.55; // Generous tolerance for endpoint connections
830
+
831
+ var d1 = segmentEndpoints.start.distanceTo(computedEndpoints.start);
832
+ var d2 = segmentEndpoints.start.distanceTo(computedEndpoints.end);
833
+ var d3 = segmentEndpoints.end.distanceTo(computedEndpoints.start);
834
+ var d4 = segmentEndpoints.end.distanceTo(computedEndpoints.end);
835
+
836
+ // Check if any endpoint of segment A is near any endpoint of segment B (they're connected)
837
+ var isConnectedAtEnds = d1 < endpointTolerance || d2 < endpointTolerance || d3 < endpointTolerance || d4 < endpointTolerance;
838
+
839
+ // If connected at ends, skip this segment (no collision)
840
+ if (isConnectedAtEnds) {
841
+ console.log("\u2705 Segments connected at endpoints - skipping intersection check (min endpoint distance: ".concat(Math.min(d1, d2, d3, d4).toFixed(3), ")"));
842
+ return;
843
+ }
844
+
845
+ // Calculate the minimum distance between the two line segments
846
+ var distance = _this.calculateSegmentToSegmentDistance(segmentEndpoints.start, segmentEndpoints.end, computedEndpoints.start, computedEndpoints.end);
847
+
848
+ // Only flag as intersection if segments are closer than combined radius
849
+ if (distance < combinedRadius) {
850
+ console.log("\uD83D\uDD34 Intersection detected with computed segment: ".concat(child.uuid || child.name));
851
+ console.log(" Distance: ".concat(distance.toFixed(3), ", Combined radius: ").concat(combinedRadius.toFixed(3)));
852
+ console.log(" Endpoint distances: [".concat(d1.toFixed(3), ", ").concat(d2.toFixed(3), ", ").concat(d3.toFixed(3), ", ").concat(d4.toFixed(3), "]"));
853
+ hasIntersection = true;
854
+ }
855
+ }
856
+ });
857
+ return hasIntersection;
858
+ }
859
+
860
+ /**
861
+ * Calculate the minimum distance between two line segments in 3D space
862
+ * @param {THREE.Vector3} p1 - Start point of first segment
863
+ * @param {THREE.Vector3} p2 - End point of first segment
864
+ * @param {THREE.Vector3} p3 - Start point of second segment
865
+ * @param {THREE.Vector3} p4 - End point of second segment
866
+ * @returns {number} Minimum distance between the two segments
867
+ * @private
868
+ */
869
+ }, {
870
+ key: "calculateSegmentToSegmentDistance",
871
+ value: function calculateSegmentToSegmentDistance(p1, p2, p3, p4) {
872
+ // Direction vectors
873
+ var d1 = new THREE__namespace.Vector3().subVectors(p2, p1); // Segment 1 direction
874
+ var d2 = new THREE__namespace.Vector3().subVectors(p4, p3); // Segment 2 direction
875
+ var r = new THREE__namespace.Vector3().subVectors(p1, p3); // Vector between start points
876
+
877
+ var a = d1.dot(d1); // Squared length of segment 1
878
+ var e = d2.dot(d2); // Squared length of segment 2
879
+ var f = d2.dot(r);
880
+
881
+ // Handle degenerate cases (zero-length segments)
882
+ if (a <= 1e-10 && e <= 1e-10) {
883
+ // Both segments are points
884
+ return p1.distanceTo(p3);
885
+ }
886
+ if (a <= 1e-10) {
887
+ // First segment is a point
888
+ var _t = Math.max(0, Math.min(1, f / e));
889
+ var closestPoint = new THREE__namespace.Vector3().addVectors(p3, d2.clone().multiplyScalar(_t));
890
+ return p1.distanceTo(closestPoint);
891
+ }
892
+ var c = d1.dot(r);
893
+ if (e <= 1e-10) {
894
+ // Second segment is a point
895
+ var _s = Math.max(0, Math.min(1, -c / a));
896
+ var _closestPoint = new THREE__namespace.Vector3().addVectors(p1, d1.clone().multiplyScalar(_s));
897
+ return p3.distanceTo(_closestPoint);
898
+ }
899
+
900
+ // General case - both segments have length
901
+ var b = d1.dot(d2);
902
+ var denom = a * e - b * b;
903
+
904
+ // Compute parameters for closest points
905
+ var s, t;
906
+ if (denom !== 0) {
907
+ s = Math.max(0, Math.min(1, (b * f - c * e) / denom));
908
+ } else {
909
+ s = 0;
910
+ }
911
+ t = (b * s + f) / e;
912
+ if (t < 0) {
913
+ t = 0;
914
+ s = Math.max(0, Math.min(1, -c / a));
915
+ } else if (t > 1) {
916
+ t = 1;
917
+ s = Math.max(0, Math.min(1, (b - c) / a));
918
+ }
919
+
920
+ // Calculate closest points
921
+ var c1 = new THREE__namespace.Vector3().addVectors(p1, d1.clone().multiplyScalar(s));
922
+ var c2 = new THREE__namespace.Vector3().addVectors(p3, d2.clone().multiplyScalar(t));
923
+ return c1.distanceTo(c2);
924
+ }
925
+ }]);
926
+ }();
927
+
928
+ exports.TransformOperationsManager = TransformOperationsManager;
929
+ exports["default"] = TransformOperationsManager;