@2112-lab/central-plant 0.1.49 → 0.1.51
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.
- package/dist/bundle/index.js +417 -609
- package/dist/cjs/src/core/centralPlant.js +3 -48
- package/dist/cjs/src/managers/components/transformOperationsManager.js +86 -123
- package/dist/cjs/src/managers/controls/keyboardControlsManager.js +0 -56
- package/dist/cjs/src/managers/controls/transformControlsManager.js +195 -144
- package/dist/cjs/src/managers/pathfinding/PathRenderingManager.js +36 -2
- package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +72 -93
- package/dist/cjs/src/managers/pathfinding/sceneDataManager.js +13 -0
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +12 -143
- package/dist/esm/src/core/centralPlant.js +3 -48
- package/dist/esm/src/managers/components/transformOperationsManager.js +86 -123
- package/dist/esm/src/managers/controls/keyboardControlsManager.js +0 -56
- package/dist/esm/src/managers/controls/transformControlsManager.js +196 -145
- package/dist/esm/src/managers/pathfinding/PathRenderingManager.js +36 -2
- package/dist/esm/src/managers/pathfinding/pathfindingManager.js +73 -94
- package/dist/esm/src/managers/pathfinding/sceneDataManager.js +13 -0
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +12 -143
- package/package.json +2 -2
|
@@ -180,8 +180,30 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
180
180
|
value: function createPipePaths(paths, crosscubeTextureSet) {
|
|
181
181
|
var _this3 = this;
|
|
182
182
|
var sceneViewer = this.sceneViewer;
|
|
183
|
-
var globalSegmentIndex = 0; // Counter for globally unique segment indices
|
|
184
183
|
|
|
184
|
+
// Find the highest segment index currently in use (both computed SEGMENT-X and manual Segment-X)
|
|
185
|
+
var maxExistingIndex = -1;
|
|
186
|
+
sceneViewer.scene.traverse(function (obj) {
|
|
187
|
+
if (obj.uuid) {
|
|
188
|
+
// Check for computed segments: SEGMENT-123
|
|
189
|
+
var computedMatch = obj.uuid.match(/^SEGMENT-(\d+)$/);
|
|
190
|
+
if (computedMatch) {
|
|
191
|
+
var index = parseInt(computedMatch[1], 10);
|
|
192
|
+
maxExistingIndex = Math.max(maxExistingIndex, index);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Check for manual segments: Segment-123
|
|
196
|
+
var manualMatch = obj.uuid.match(/^Segment-(\d+)$/);
|
|
197
|
+
if (manualMatch) {
|
|
198
|
+
var _index = parseInt(manualMatch[1], 10);
|
|
199
|
+
maxExistingIndex = Math.max(maxExistingIndex, _index);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Start counter after the highest existing index to prevent UUID conflicts
|
|
205
|
+
var globalSegmentIndex = maxExistingIndex + 1;
|
|
206
|
+
console.log("\uD83D\uDD22 Starting segment index at ".concat(globalSegmentIndex, " (max existing: ").concat(maxExistingIndex, ")"));
|
|
185
207
|
var pipeRadius = 0.1;
|
|
186
208
|
var pipeMaterial = this.createPipeMaterial(crosscubeTextureSet);
|
|
187
209
|
paths.forEach(function (pathData, index) {
|
|
@@ -200,6 +222,10 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
200
222
|
}
|
|
201
223
|
});
|
|
202
224
|
|
|
225
|
+
// Check if endpoints are component connectors (from pathfinder result)
|
|
226
|
+
var fromIsComponentConnector = pathData.fromObjectType === 'component-connector';
|
|
227
|
+
var toIsComponentConnector = pathData.toObjectType === 'component-connector';
|
|
228
|
+
|
|
203
229
|
// Create one cylinder per segment (after colinear optimization, this should be minimal segments)
|
|
204
230
|
for (var j = 0; j < pathPoints.length - 1; j++) {
|
|
205
231
|
var start = pathPoints[j];
|
|
@@ -228,13 +254,19 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
228
254
|
// Make pipe segments selectable and add identifying data
|
|
229
255
|
var segmentId = cylinder.uuid;
|
|
230
256
|
|
|
257
|
+
// Determine if this segment should be immutable (first or last 0.5-unit segment connected to component)
|
|
258
|
+
var isFirstSegment = j === 0;
|
|
259
|
+
var isLastSegment = j === pathPoints.length - 2;
|
|
260
|
+
var isImmutable = fromIsComponentConnector && isFirstSegment || toIsComponentConnector && isLastSegment;
|
|
261
|
+
|
|
231
262
|
// Add userData to make pipe segments selectable and for tooltip display
|
|
232
263
|
cylinder.userData = {
|
|
233
264
|
objectType: 'segment',
|
|
234
265
|
segmentId: segmentId,
|
|
235
266
|
segmentIndex: globalSegmentIndex,
|
|
236
267
|
pathFrom: pathData.from,
|
|
237
|
-
pathTo: pathData.to
|
|
268
|
+
pathTo: pathData.to,
|
|
269
|
+
immutable: isImmutable // Mark segments connected to component connectors as immutable
|
|
238
270
|
};
|
|
239
271
|
|
|
240
272
|
// Increment global segment counter
|
|
@@ -299,6 +331,8 @@ var PathRenderingManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
299
331
|
pathFrom: pathData.from,
|
|
300
332
|
pathTo: pathData.to,
|
|
301
333
|
angle: (angle * 180 / Math.PI).toFixed(1),
|
|
334
|
+
immutable: true,
|
|
335
|
+
// Mark computed elbows as immutable
|
|
302
336
|
// Add component data for tooltips
|
|
303
337
|
component: {
|
|
304
338
|
type: 'PipeElbow',
|
|
@@ -127,13 +127,6 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
127
127
|
connectionsCopy,
|
|
128
128
|
simplifiedSceneData,
|
|
129
129
|
pathfindingResult,
|
|
130
|
-
intersectionCheck,
|
|
131
|
-
_this$sceneViewer,
|
|
132
|
-
operationHistoryManager,
|
|
133
|
-
lastOp,
|
|
134
|
-
undoSuccess,
|
|
135
|
-
correctedResult,
|
|
136
|
-
_this$sceneViewer2,
|
|
137
130
|
_args = arguments;
|
|
138
131
|
return _rollupPluginBabelHelpers.regenerator().w(function (_context) {
|
|
139
132
|
while (1) switch (_context.n) {
|
|
@@ -168,93 +161,79 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
168
161
|
console.log('Rewired connections:', JSON.parse(JSON.stringify(pathfindingResult.rewiredConnections)));
|
|
169
162
|
console.log("intersectionCheck input:", pathfindingResult.paths);
|
|
170
163
|
|
|
171
|
-
// Check for path intersections (including manual segments)
|
|
172
|
-
intersectionCheck = this.checkPathIntersections(pathfindingResult.paths, 0.2, true);
|
|
173
|
-
pathfindingResult.intersections = intersectionCheck;
|
|
174
|
-
|
|
175
|
-
console.log("intersectionCheck
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
164
|
+
// // Check for path intersections (including manual segments)
|
|
165
|
+
// const intersectionCheck = this.checkPathIntersections(pathfindingResult.paths, 0.2, true);
|
|
166
|
+
// pathfindingResult.intersections = intersectionCheck;
|
|
167
|
+
|
|
168
|
+
// console.log("intersectionCheck:", intersectionCheck);
|
|
169
|
+
// console.log("intersectionCheck.hasIntersections:", intersectionCheck.hasIntersections);
|
|
170
|
+
|
|
171
|
+
// // Handle intersection detection - undo last operation if intersections found
|
|
172
|
+
// // Skip this if we're already in the middle of an undo operation
|
|
173
|
+
// if (intersectionCheck.hasIntersections && !this.isUndoInProgress) {
|
|
174
|
+
// console.warn('⚠️ Path intersections detected! Attempting to undo last operation...');
|
|
175
|
+
|
|
176
|
+
// // Set flag to prevent recursive undo attempts
|
|
177
|
+
// this.isUndoInProgress = true;
|
|
178
|
+
|
|
179
|
+
// // Access operationHistoryManager through sceneViewer.managers.operationHistory
|
|
180
|
+
// const operationHistoryManager = this.sceneViewer?.managers?.operationHistory;
|
|
181
|
+
|
|
182
|
+
// if (operationHistoryManager) {
|
|
183
|
+
// const lastOp = operationHistoryManager.getLastOperation();
|
|
184
|
+
|
|
185
|
+
// if (lastOp) {
|
|
186
|
+
// console.warn(`⚠️ Intersection caused by operation: ${lastOp.operationName}`, lastOp.params);
|
|
187
|
+
|
|
188
|
+
// // Attempt to undo the operation FIRST (before removing computed objects)
|
|
189
|
+
// // This is important because undo needs to find the segment that was moved
|
|
190
|
+
// const undoSuccess = operationHistoryManager.undoLastOperation();
|
|
191
|
+
|
|
192
|
+
// if (undoSuccess) {
|
|
193
|
+
// console.log('✅ Successfully undid operation that caused intersection');
|
|
194
|
+
|
|
195
|
+
// // Now remove the buggy computed objects that were created with the invalid state
|
|
196
|
+
// console.log('🗑️ Removing buggy computed objects after undo...');
|
|
197
|
+
// this.removeComputedObjects();
|
|
198
|
+
|
|
199
|
+
// // Re-run pathfinding after undo to restore valid state
|
|
200
|
+
// console.log('🔄 Re-running pathfinding after undo to restore clean state...');
|
|
201
|
+
|
|
202
|
+
// // Recursively call _executePathfinding with the corrected scene state
|
|
203
|
+
// // This is safe because we've undone the operation, so we won't get into an infinite loop
|
|
204
|
+
// const correctedResult = await this._executePathfinding(
|
|
205
|
+
// sceneData,
|
|
206
|
+
// connections,
|
|
207
|
+
// { ...options, context: `${context} (After Undo)` }
|
|
208
|
+
// );
|
|
209
|
+
|
|
210
|
+
// // Mark that we performed an undo and return the corrected result
|
|
211
|
+
// correctedResult.undoPerformed = true;
|
|
212
|
+
// correctedResult.undoneOperation = lastOp;
|
|
213
|
+
|
|
214
|
+
// // Clear the undo flag before returning
|
|
215
|
+
// this.isUndoInProgress = false;
|
|
216
|
+
|
|
217
|
+
// return correctedResult;
|
|
218
|
+
// } else {
|
|
219
|
+
// console.error('❌ Failed to undo operation that caused intersection');
|
|
220
|
+
// pathfindingResult.undoFailed = true;
|
|
221
|
+
// // Clear the undo flag even on failure
|
|
222
|
+
// this.isUndoInProgress = false;
|
|
223
|
+
// }
|
|
224
|
+
// } else {
|
|
225
|
+
// console.warn('⚠️ No operation in history to undo');
|
|
226
|
+
// this.isUndoInProgress = false;
|
|
227
|
+
// }
|
|
228
|
+
// } else {
|
|
229
|
+
// console.error('❌ OperationHistoryManager not available for undo');
|
|
230
|
+
// console.error(' Available managers:', Object.keys(this.sceneViewer?.managers || {}));
|
|
231
|
+
// this.isUndoInProgress = false;
|
|
232
|
+
// }
|
|
233
|
+
// } else if (intersectionCheck.hasIntersections && this.isUndoInProgress) {
|
|
234
|
+
// console.log('⏭️ Skipping intersection handling - undo already in progress');
|
|
235
|
+
// }
|
|
209
236
|
|
|
210
|
-
// Now remove the buggy computed objects that were created with the invalid state
|
|
211
|
-
console.log('🗑️ Removing buggy computed objects after undo...');
|
|
212
|
-
this.removeComputedObjects();
|
|
213
|
-
|
|
214
|
-
// Re-run pathfinding after undo to restore valid state
|
|
215
|
-
console.log('🔄 Re-running pathfinding after undo to restore clean state...');
|
|
216
|
-
|
|
217
|
-
// Recursively call _executePathfinding with the corrected scene state
|
|
218
|
-
// This is safe because we've undone the operation, so we won't get into an infinite loop
|
|
219
|
-
_context.n = 1;
|
|
220
|
-
return this._executePathfinding(sceneData, connections, _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
|
|
221
|
-
context: "".concat(context, " (After Undo)")
|
|
222
|
-
}));
|
|
223
|
-
case 1:
|
|
224
|
-
correctedResult = _context.v;
|
|
225
|
-
// Mark that we performed an undo and return the corrected result
|
|
226
|
-
correctedResult.undoPerformed = true;
|
|
227
|
-
correctedResult.undoneOperation = lastOp;
|
|
228
|
-
|
|
229
|
-
// Clear the undo flag before returning
|
|
230
|
-
this.isUndoInProgress = false;
|
|
231
|
-
return _context.a(2, correctedResult);
|
|
232
|
-
case 2:
|
|
233
|
-
console.error('❌ Failed to undo operation that caused intersection');
|
|
234
|
-
pathfindingResult.undoFailed = true;
|
|
235
|
-
// Clear the undo flag even on failure
|
|
236
|
-
this.isUndoInProgress = false;
|
|
237
|
-
case 3:
|
|
238
|
-
_context.n = 5;
|
|
239
|
-
break;
|
|
240
|
-
case 4:
|
|
241
|
-
console.warn('⚠️ No operation in history to undo');
|
|
242
|
-
this.isUndoInProgress = false;
|
|
243
|
-
case 5:
|
|
244
|
-
_context.n = 7;
|
|
245
|
-
break;
|
|
246
|
-
case 6:
|
|
247
|
-
console.error('❌ OperationHistoryManager not available for undo');
|
|
248
|
-
console.error(' Available managers:', Object.keys(((_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.managers) || {}));
|
|
249
|
-
this.isUndoInProgress = false;
|
|
250
|
-
case 7:
|
|
251
|
-
_context.n = 9;
|
|
252
|
-
break;
|
|
253
|
-
case 8:
|
|
254
|
-
if (intersectionCheck.hasIntersections && this.isUndoInProgress) {
|
|
255
|
-
console.log('⏭️ Skipping intersection handling - undo already in progress');
|
|
256
|
-
}
|
|
257
|
-
case 9:
|
|
258
237
|
// Create gateways in the scene if requested
|
|
259
238
|
if (options.createGateways && pathfindingResult.gateways) {
|
|
260
239
|
this.renderingManager.createGateways(pathfindingResult);
|
|
@@ -119,10 +119,23 @@ var SceneDataManager = /*#__PURE__*/function () {
|
|
|
119
119
|
worldBoundingBox: worldBoundingBox
|
|
120
120
|
})
|
|
121
121
|
};
|
|
122
|
+
|
|
123
|
+
// For connectors and gateways, add world position
|
|
122
124
|
if (obj.userData.objectType.includes('connector') || obj.userData.objectType === 'gateway') {
|
|
123
125
|
var worldPosition = new THREE__namespace.Vector3();
|
|
124
126
|
obj.getWorldPosition(worldPosition);
|
|
125
127
|
results.userData.position = [worldPosition.x, worldPosition.y, worldPosition.z];
|
|
128
|
+
|
|
129
|
+
// Differentiate component connectors from segment connectors for pathfinder
|
|
130
|
+
// Component connectors are children of components
|
|
131
|
+
if (obj.userData.objectType === 'connector') {
|
|
132
|
+
var _parent$userData;
|
|
133
|
+
// Check if parent is a component (not a segment)
|
|
134
|
+
var parent = obj.parent;
|
|
135
|
+
if (parent && ((_parent$userData = parent.userData) === null || _parent$userData === void 0 ? void 0 : _parent$userData.objectType) === 'component') {
|
|
136
|
+
results.userData.objectType = 'component-connector';
|
|
137
|
+
}
|
|
138
|
+
}
|
|
126
139
|
}
|
|
127
140
|
return results;
|
|
128
141
|
});
|
|
@@ -1352,7 +1352,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1352
1352
|
}, {
|
|
1353
1353
|
key: "manualizeSegment",
|
|
1354
1354
|
value: function manualizeSegment(segment, currentSceneData) {
|
|
1355
|
-
var _segment$userData, _this$sceneViewer$man;
|
|
1355
|
+
var _segment$userData, _segment$material$use, _this$sceneViewer$man;
|
|
1356
1356
|
if (!segment || !((_segment$userData = segment.userData) !== null && _segment$userData !== void 0 && _segment$userData.objectType) === 'segment') {
|
|
1357
1357
|
console.log('❌ Object is not a pipe segment:', {
|
|
1358
1358
|
isObject: !!segment,
|
|
@@ -1369,6 +1369,16 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1369
1369
|
return;
|
|
1370
1370
|
}
|
|
1371
1371
|
|
|
1372
|
+
// CRITICAL: Clone the material BEFORE changing its color
|
|
1373
|
+
// This prevents the color change from affecting other segments that share the same material instance
|
|
1374
|
+
if (segment.material && !((_segment$material$use = segment.material.userData) !== null && _segment$material$use !== void 0 && _segment$material$use.isCloned)) {
|
|
1375
|
+
var originalMaterial = segment.material;
|
|
1376
|
+
segment.material = originalMaterial.clone();
|
|
1377
|
+
segment.material.userData = segment.material.userData || {};
|
|
1378
|
+
segment.material.userData.isCloned = true;
|
|
1379
|
+
console.log('📋 Cloned segment material to prevent shared material mutation');
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1372
1382
|
// Override material color to blue in dev mode
|
|
1373
1383
|
var isDev = false;
|
|
1374
1384
|
if (typeof window !== 'undefined') {
|
|
@@ -1393,7 +1403,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1393
1403
|
// Change from "SEGMENT-X" to "Segment-X" (capital S to lowercase s)
|
|
1394
1404
|
var segmentIndex = segment.userData.segmentIndex;
|
|
1395
1405
|
var oldUuid = segment.uuid;
|
|
1396
|
-
segment.uuid = "
|
|
1406
|
+
segment.uuid = "SEGMENT-".concat(segmentIndex);
|
|
1397
1407
|
console.log("\uD83D\uDD27 Renamed segment UUID from ".concat(oldUuid, " to: ").concat(segment.uuid));
|
|
1398
1408
|
|
|
1399
1409
|
// Calculate segment endpoints in world coordinates
|
|
@@ -1650,147 +1660,6 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1650
1660
|
}
|
|
1651
1661
|
console.log("\u2705 Gateway ".concat(gateway.uuid, " successfully converted to manual (declared)"));
|
|
1652
1662
|
}
|
|
1653
|
-
|
|
1654
|
-
/**
|
|
1655
|
-
* Split a segment by manualizing it and shortening it by 0.5 units
|
|
1656
|
-
* The segment gets converted to a declared (manual) segment with connectors,
|
|
1657
|
-
* and is shortened from the end that has a component connector (or the end if no connectors)
|
|
1658
|
-
* @param {string|THREE.Object3D} segmentIdOrObject - The UUID or Three.js object of the segment to split
|
|
1659
|
-
* @param {Object} currentSceneData - Current scene data with connections
|
|
1660
|
-
* @returns {THREE.Object3D|null} The shortened manual segment or null on failure
|
|
1661
|
-
*/
|
|
1662
|
-
}, {
|
|
1663
|
-
key: "splitSegment",
|
|
1664
|
-
value: function splitSegment(segmentIdOrObject, currentSceneData) {
|
|
1665
|
-
var _segment$userData3,
|
|
1666
|
-
_this6 = this;
|
|
1667
|
-
console.log('✂️ splitSegment started:', segmentIdOrObject);
|
|
1668
|
-
|
|
1669
|
-
// Find the segment object
|
|
1670
|
-
var segment = null;
|
|
1671
|
-
if (typeof segmentIdOrObject === 'string') {
|
|
1672
|
-
this.sceneViewer.scene.traverse(function (child) {
|
|
1673
|
-
var _child$userData10;
|
|
1674
|
-
if (child.uuid === segmentIdOrObject || ((_child$userData10 = child.userData) === null || _child$userData10 === void 0 ? void 0 : _child$userData10.originalUuid) === segmentIdOrObject) {
|
|
1675
|
-
segment = child;
|
|
1676
|
-
}
|
|
1677
|
-
});
|
|
1678
|
-
} else if (segmentIdOrObject && segmentIdOrObject.isObject3D) {
|
|
1679
|
-
segment = segmentIdOrObject;
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
// Validate segment
|
|
1683
|
-
if (!segment || ((_segment$userData3 = segment.userData) === null || _segment$userData3 === void 0 ? void 0 : _segment$userData3.objectType) !== 'segment') {
|
|
1684
|
-
console.error('❌ splitSegment(): Invalid segment or not found');
|
|
1685
|
-
return null;
|
|
1686
|
-
}
|
|
1687
|
-
if (!currentSceneData) {
|
|
1688
|
-
console.error('❌ splitSegment(): currentSceneData is required');
|
|
1689
|
-
return null;
|
|
1690
|
-
}
|
|
1691
|
-
console.log('✂️ Splitting/shortening segment:', segment.uuid);
|
|
1692
|
-
|
|
1693
|
-
// Get segment geometry to calculate endpoints
|
|
1694
|
-
var geometry = segment.geometry;
|
|
1695
|
-
if (!geometry || !geometry.parameters) {
|
|
1696
|
-
console.error('❌ splitSegment(): Segment has invalid geometry');
|
|
1697
|
-
return null;
|
|
1698
|
-
}
|
|
1699
|
-
var segmentLength = geometry.parameters.height || 1;
|
|
1700
|
-
var segmentRadius = geometry.parameters.radiusTop || 0.1;
|
|
1701
|
-
var shortenAmount = 0.5;
|
|
1702
|
-
var newLength = segmentLength - shortenAmount;
|
|
1703
|
-
if (newLength <= 0) {
|
|
1704
|
-
console.error('❌ splitSegment(): Segment too short to shorten by 0.5');
|
|
1705
|
-
return null;
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
// Calculate segment direction vector
|
|
1709
|
-
var direction = new THREE__namespace.Vector3(0, 1, 0);
|
|
1710
|
-
direction.applyQuaternion(segment.quaternion);
|
|
1711
|
-
direction.normalize();
|
|
1712
|
-
|
|
1713
|
-
// Calculate original segment endpoints
|
|
1714
|
-
var startPoint = new THREE__namespace.Vector3();
|
|
1715
|
-
startPoint.copy(segment.position).sub(direction.clone().multiplyScalar(segmentLength / 2));
|
|
1716
|
-
var endPoint = new THREE__namespace.Vector3();
|
|
1717
|
-
endPoint.copy(segment.position).add(direction.clone().multiplyScalar(segmentLength / 2));
|
|
1718
|
-
|
|
1719
|
-
// Check for component connectors at endpoints
|
|
1720
|
-
var findConnectorsAtPosition = function findConnectorsAtPosition(position) {
|
|
1721
|
-
var tolerance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0.15;
|
|
1722
|
-
var connectors = [];
|
|
1723
|
-
_this6.sceneViewer.scene.traverse(function (child) {
|
|
1724
|
-
var _child$userData11;
|
|
1725
|
-
if (((_child$userData11 = child.userData) === null || _child$userData11 === void 0 ? void 0 : _child$userData11.objectType) === 'connector') {
|
|
1726
|
-
var connectorWorldPos = new THREE__namespace.Vector3();
|
|
1727
|
-
child.getWorldPosition(connectorWorldPos);
|
|
1728
|
-
var distance = connectorWorldPos.distanceTo(position);
|
|
1729
|
-
if (distance <= tolerance) {
|
|
1730
|
-
connectors.push(child);
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
});
|
|
1734
|
-
return connectors.filter(function (c) {
|
|
1735
|
-
var _c$userData;
|
|
1736
|
-
return ((_c$userData = c.userData) === null || _c$userData === void 0 ? void 0 : _c$userData.objectType) !== 'segment-connector';
|
|
1737
|
-
});
|
|
1738
|
-
};
|
|
1739
|
-
var startConnectors = findConnectorsAtPosition(startPoint);
|
|
1740
|
-
var endConnectors = findConnectorsAtPosition(endPoint);
|
|
1741
|
-
|
|
1742
|
-
// Determine which end to shorten from
|
|
1743
|
-
var newStartPoint, newEndPoint;
|
|
1744
|
-
if (endConnectors.length > 0) {
|
|
1745
|
-
// Component connector at end - shorten from end
|
|
1746
|
-
newStartPoint = startPoint.clone();
|
|
1747
|
-
newEndPoint = endPoint.clone().sub(direction.clone().multiplyScalar(shortenAmount));
|
|
1748
|
-
console.log("\uD83D\uDCCD Component connector at END - shortening from end by ".concat(shortenAmount));
|
|
1749
|
-
} else if (startConnectors.length > 0) {
|
|
1750
|
-
// Component connector at start - shorten from start
|
|
1751
|
-
newStartPoint = startPoint.clone().add(direction.clone().multiplyScalar(shortenAmount));
|
|
1752
|
-
newEndPoint = endPoint.clone();
|
|
1753
|
-
console.log("\uD83D\uDCCD Component connector at START - shortening from start by ".concat(shortenAmount));
|
|
1754
|
-
} else {
|
|
1755
|
-
// No component connectors - shorten from end (default)
|
|
1756
|
-
newStartPoint = startPoint.clone();
|
|
1757
|
-
newEndPoint = endPoint.clone().sub(direction.clone().multiplyScalar(shortenAmount));
|
|
1758
|
-
console.log("\uD83D\uDCCD No component connectors - shortening from end by ".concat(shortenAmount));
|
|
1759
|
-
}
|
|
1760
|
-
console.log('📍 Segment shortening:', {
|
|
1761
|
-
originalStart: startPoint.toArray(),
|
|
1762
|
-
originalEnd: endPoint.toArray(),
|
|
1763
|
-
newStart: newStartPoint.toArray(),
|
|
1764
|
-
newEnd: newEndPoint.toArray(),
|
|
1765
|
-
originalLength: segmentLength,
|
|
1766
|
-
newLength: newLength,
|
|
1767
|
-
shortenAmount: shortenAmount
|
|
1768
|
-
});
|
|
1769
|
-
|
|
1770
|
-
// Get material from existing segment
|
|
1771
|
-
segment.material;
|
|
1772
|
-
|
|
1773
|
-
// Dispose old geometry and create new shortened geometry
|
|
1774
|
-
if (segment.geometry) {
|
|
1775
|
-
segment.geometry.dispose();
|
|
1776
|
-
}
|
|
1777
|
-
var newGeometry = new THREE__namespace.CylinderGeometry(segmentRadius, segmentRadius, newLength, 16, 1, false);
|
|
1778
|
-
segment.geometry = newGeometry;
|
|
1779
|
-
|
|
1780
|
-
// Reposition the segment to the new center
|
|
1781
|
-
var newPosition = new THREE__namespace.Vector3();
|
|
1782
|
-
newPosition.lerpVectors(newStartPoint, newEndPoint, 0.5);
|
|
1783
|
-
segment.position.copy(newPosition);
|
|
1784
|
-
// Quaternion stays the same
|
|
1785
|
-
|
|
1786
|
-
console.log('✅ Segment geometry updated and repositioned');
|
|
1787
|
-
|
|
1788
|
-
// Now manualize the shortened segment
|
|
1789
|
-
console.log('🔧 Manualizing the shortened segment...');
|
|
1790
|
-
this.manualizeSegment(segment, currentSceneData);
|
|
1791
|
-
console.log('✅ Segment split completed successfully - segment shortened and manualized');
|
|
1792
|
-
return segment;
|
|
1793
|
-
}
|
|
1794
1663
|
}]);
|
|
1795
1664
|
}();
|
|
1796
1665
|
|
|
@@ -15,7 +15,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
15
15
|
* Initialize the CentralPlant manager
|
|
16
16
|
*
|
|
17
17
|
* @constructor
|
|
18
|
-
* @version 0.1.
|
|
18
|
+
* @version 0.1.51
|
|
19
19
|
* @updated 2025-10-22
|
|
20
20
|
*
|
|
21
21
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -320,51 +320,6 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
320
320
|
return this.internals.translateGateway(gatewayId, axis, value);
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
-
/**
|
|
324
|
-
* Split a pipe segment by shortening it by 0.5 units and manualizing it
|
|
325
|
-
* @param {string} segmentId - The UUID of the segment to split
|
|
326
|
-
* @returns {THREE.Object3D|null} The shortened manual segment or null on failure
|
|
327
|
-
* @description Shortens a selected pipe segment by 0.5 units and converts it to
|
|
328
|
-
* manual/declared status with connectors. The segment is shortened from the end that
|
|
329
|
-
* has a component connector (or from the end if no connectors are present).
|
|
330
|
-
* The segment becomes transformable after this operation. Paths are regenerated
|
|
331
|
-
* to ensure proper connections.
|
|
332
|
-
* @example
|
|
333
|
-
* // Split/shorten a segment when selected via transform controls
|
|
334
|
-
* const result = centralPlant.splitSegment('SEGMENT-12345');
|
|
335
|
-
* if (result) {
|
|
336
|
-
* console.log('Segment shortened and manualized:', result.uuid);
|
|
337
|
-
* }
|
|
338
|
-
*
|
|
339
|
-
* @since 0.1.37
|
|
340
|
-
*/
|
|
341
|
-
}, {
|
|
342
|
-
key: "splitSegment",
|
|
343
|
-
value: function splitSegment(segmentId) {
|
|
344
|
-
var _this$sceneViewer$man;
|
|
345
|
-
if (!this.sceneViewer || !((_this$sceneViewer$man = this.sceneViewer.managers) !== null && _this$sceneViewer$man !== void 0 && _this$sceneViewer$man.sceneOperationsManager)) {
|
|
346
|
-
console.warn('⚠️ splitSegment(): Scene viewer or scene operations manager not available');
|
|
347
|
-
return null;
|
|
348
|
-
}
|
|
349
|
-
if (!segmentId) {
|
|
350
|
-
console.error('❌ splitSegment(): No segment ID provided');
|
|
351
|
-
return null;
|
|
352
|
-
}
|
|
353
|
-
try {
|
|
354
|
-
var result = this.sceneViewer.managers.sceneOperationsManager.splitSegment(segmentId, this.sceneViewer.currentSceneData);
|
|
355
|
-
if (result) {
|
|
356
|
-
console.log('✅ splitSegment(): Segment split successfully');
|
|
357
|
-
return result;
|
|
358
|
-
} else {
|
|
359
|
-
console.warn('⚠️ splitSegment(): Split operation returned null');
|
|
360
|
-
return null;
|
|
361
|
-
}
|
|
362
|
-
} catch (error) {
|
|
363
|
-
console.error('❌ splitSegment(): Error splitting segment:', error);
|
|
364
|
-
return null;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
323
|
/**
|
|
369
324
|
* Rotate a component by componentId
|
|
370
325
|
* @param {string} componentId - The UUID of the component to rotate
|
|
@@ -1646,8 +1601,8 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
1646
1601
|
}, {
|
|
1647
1602
|
key: "generatePath",
|
|
1648
1603
|
value: function generatePath(fromConnectorId, toConnectorId) {
|
|
1649
|
-
var _this$sceneViewer$
|
|
1650
|
-
if (!this.sceneViewer || !((_this$sceneViewer$
|
|
1604
|
+
var _this$sceneViewer$man;
|
|
1605
|
+
if (!this.sceneViewer || !((_this$sceneViewer$man = this.sceneViewer.managers) !== null && _this$sceneViewer$man !== void 0 && _this$sceneViewer$man.pathfinding)) {
|
|
1651
1606
|
return null;
|
|
1652
1607
|
}
|
|
1653
1608
|
try {
|