@2112-lab/central-plant 0.3.47 → 0.3.48
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 +558 -449
- package/dist/cjs/src/core/centralPlant.js +44 -43
- package/dist/cjs/src/core/centralPlantInternals.js +4 -2
- package/dist/cjs/src/core/sceneViewer.js +1 -1
- package/dist/cjs/src/managers/components/componentManager.js +11 -3
- package/dist/cjs/src/managers/components/transformOperationsManager.js +9 -11
- package/dist/cjs/src/managers/controls/transformControlsManager.js +83 -44
- package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +272 -244
- package/dist/cjs/src/managers/scene/modelManager.js +33 -10
- package/dist/cjs/src/managers/scene/sceneExportManager.js +18 -7
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +23 -18
- package/dist/cjs/src/utils/boundingBoxUtils.js +62 -65
- package/dist/esm/src/core/centralPlant.js +44 -43
- package/dist/esm/src/core/centralPlantInternals.js +4 -2
- package/dist/esm/src/core/sceneViewer.js +1 -1
- package/dist/esm/src/managers/components/componentManager.js +11 -3
- package/dist/esm/src/managers/components/transformOperationsManager.js +9 -11
- package/dist/esm/src/managers/controls/transformControlsManager.js +83 -44
- package/dist/esm/src/managers/pathfinding/pathfindingManager.js +274 -246
- package/dist/esm/src/managers/scene/modelManager.js +33 -10
- package/dist/esm/src/managers/scene/sceneExportManager.js +16 -7
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +23 -18
- package/dist/esm/src/utils/boundingBoxUtils.js +62 -65
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createClass as _createClass, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray, typeof as _typeof, classCallCheck as _classCallCheck, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, createForOfIteratorHelper as _createForOfIteratorHelper } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
+
import { getHardcodedUuid } from '../../utils/nameUtils.js';
|
|
3
4
|
import { attachIODevicesToComponent } from '../../utils/ioDeviceUtils.js';
|
|
4
5
|
import { registerBehaviorsForComponent } from '../../utils/behaviorRegistration.js';
|
|
5
6
|
import modelPreloader from '../../rendering/modelPreloader.js';
|
|
@@ -138,36 +139,58 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
138
139
|
* @param {THREE.Object3D} targetMesh - The mesh whose connectors to preserve
|
|
139
140
|
* @param {string} parentUuid - The UUID of the parent component
|
|
140
141
|
*/
|
|
142
|
+
/**
|
|
143
|
+
* Identifies all connector objects within a model hierarchy and prepares them
|
|
144
|
+
* to be preserved when the model is replaced or modified.
|
|
145
|
+
* Uses traverse() to find connectors at any depth in the hierarchy.
|
|
146
|
+
* @param {THREE.Object3D} targetMesh - The root of the model to search
|
|
147
|
+
* @param {string} parentUuid - The UUID of the parent component
|
|
148
|
+
* @returns {Array<THREE.Object3D>} Array of cloned and prepared connector objects
|
|
149
|
+
*/
|
|
141
150
|
}, {
|
|
142
151
|
key: "_preserveConnectorChildren",
|
|
143
152
|
value: function _preserveConnectorChildren(targetMesh, parentUuid) {
|
|
144
153
|
var _this = this;
|
|
145
154
|
var connectorChildren = [];
|
|
146
|
-
|
|
155
|
+
var connectorIndex = 0;
|
|
156
|
+
|
|
157
|
+
// Use traverse to find connectors at ANY depth in the hierarchy
|
|
158
|
+
targetMesh.traverse(function (child) {
|
|
147
159
|
var _child$userData;
|
|
148
160
|
var isConnectorGeometry = child.geometry && (child.geometry.uuid === 'CONNECTOR-GEO' || child.geometry.type === 'SphereGeometry' && child.geometry.parameters);
|
|
149
161
|
var isConnectorByName = child.name && child.name.toLowerCase().includes('connector');
|
|
150
|
-
// Also recognise connectors declared via userData (e.g. inline connectors from SAMPLE_1.json
|
|
151
|
-
// whose geometry may be a fallback BufferGeometry rather than a SphereGeometry).
|
|
152
162
|
var isConnectorByUserData = ((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'connector';
|
|
153
163
|
if (isConnectorGeometry && isConnectorByName || isConnectorByUserData) {
|
|
164
|
+
connectorIndex++;
|
|
165
|
+
|
|
154
166
|
// Ensure userData exists and has worldBoundingBox
|
|
155
167
|
if (!child.userData) child.userData = {};
|
|
156
168
|
if (!child.userData.worldBoundingBox) {
|
|
157
169
|
child.userData.worldBoundingBox = _this._calculateWorldBoundingBox(child);
|
|
158
170
|
}
|
|
159
171
|
|
|
160
|
-
// Clone
|
|
172
|
+
// Clone the connector
|
|
161
173
|
var clonedConnector = child.clone();
|
|
162
174
|
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
var
|
|
175
|
+
// CRITICAL: Convert nested world position to root-relative position
|
|
176
|
+
// This ensures the connector stays in the same place when re-added as a direct child of targetMesh
|
|
177
|
+
var targetInverse = targetMesh.matrixWorld.clone().invert();
|
|
178
|
+
var worldPos = new THREE.Vector3();
|
|
179
|
+
child.getWorldPosition(worldPos);
|
|
180
|
+
clonedConnector.position.copy(worldPos.applyMatrix4(targetInverse));
|
|
181
|
+
|
|
182
|
+
// Get hardcoded UUID if it exists (e.g. from JSON mesh placeholder)
|
|
183
|
+
// This ensures compatibility with existing scene JSON naming conventions
|
|
184
|
+
var existingUuid = getHardcodedUuid(child);
|
|
185
|
+
|
|
186
|
+
// Generate fallback UUID only if existing one isn't already parent-prefixed
|
|
187
|
+
// Format: COMPONENT-UUID-CONNECTOR-INDEX (stable fallback)
|
|
188
|
+
var connectorUuid = existingUuid && existingUuid.includes(parentUuid) ? existingUuid : "".concat(parentUuid, "-CONNECTOR-").concat(connectorIndex);
|
|
166
189
|
clonedConnector.uuid = connectorUuid;
|
|
167
190
|
if (child.userData) {
|
|
168
191
|
clonedConnector.userData = _objectSpread2({}, child.userData);
|
|
169
192
|
|
|
170
|
-
// Deep copy critical data
|
|
193
|
+
// Deep copy critical data
|
|
171
194
|
if (child.userData.worldBoundingBox) {
|
|
172
195
|
var wbb = child.userData.worldBoundingBox;
|
|
173
196
|
clonedConnector.userData.worldBoundingBox = {
|
|
@@ -176,7 +199,6 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
176
199
|
};
|
|
177
200
|
}
|
|
178
201
|
if (child.userData.direction) {
|
|
179
|
-
// Handle both array [x,y,z] and object {x,y,z} formats
|
|
180
202
|
if (Array.isArray(child.userData.direction)) {
|
|
181
203
|
clonedConnector.userData.direction = _toConsumableArray(child.userData.direction);
|
|
182
204
|
} else if (_typeof(child.userData.direction) === 'object') {
|
|
@@ -188,11 +210,12 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
188
210
|
|
|
189
211
|
// Set originalUuid to match the actual uuid (maintains consistency)
|
|
190
212
|
clonedConnector.userData.originalUuid = connectorUuid;
|
|
191
|
-
clonedConnector.userData.objectType = child.userData.objectType ||
|
|
213
|
+
clonedConnector.userData.objectType = child.userData.objectType || 'connector';
|
|
192
214
|
}
|
|
193
215
|
connectorChildren.push(clonedConnector);
|
|
194
216
|
}
|
|
195
217
|
});
|
|
218
|
+
console.log("\uD83D\uDEE1\uFE0F Preserved ".concat(connectorChildren.length, " connector(s) for component ").concat(parentUuid));
|
|
196
219
|
return connectorChildren;
|
|
197
220
|
}
|
|
198
221
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createClass as _createClass, classCallCheck as _classCallCheck, toConsumableArray as _toConsumableArray, objectSpread2 as _objectSpread2, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
-
import 'three';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
3
|
import { GLTFExporter } from '../../../node_modules/three/examples/jsm/exporters/GLTFExporter.js';
|
|
4
4
|
import { getHardcodedUuid } from '../../utils/nameUtils.js';
|
|
5
5
|
|
|
@@ -81,6 +81,11 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
81
81
|
// Helper function to convert Three.js object to minimal JSON format
|
|
82
82
|
var convertObjectToJson = function convertObjectToJson(threeObject) {
|
|
83
83
|
var _threeObject$name, _threeObject$userData, _threeObject$userData2, _threeObject$userData3, _threeObject$userData4, _threeObject$userData5, _threeObject$userData6, _threeObject$userData7, _threeObject$userData8, _threeObject$userData9, _threeObject$userData0, _threeObject$userData1, _threeObject$userData10;
|
|
84
|
+
// Ensure world matrices are updated for this subtree before exporting
|
|
85
|
+
if (threeObject.updateMatrixWorld) {
|
|
86
|
+
threeObject.updateMatrixWorld(true);
|
|
87
|
+
}
|
|
88
|
+
|
|
84
89
|
// Skip certain objects that shouldn't be exported
|
|
85
90
|
if (!threeObject || (_threeObject$name = threeObject.name) !== null && _threeObject$name !== void 0 && _threeObject$name.includes('Polyline') ||
|
|
86
91
|
// Skip pipe paths
|
|
@@ -238,19 +243,23 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
238
243
|
}
|
|
239
244
|
});
|
|
240
245
|
} else if (((_threeObject$userData11 = threeObject.userData) === null || _threeObject$userData11 === void 0 ? void 0 : _threeObject$userData11.objectType) === 'component') {
|
|
241
|
-
// For components,
|
|
242
|
-
|
|
243
|
-
threeObject.children.forEach(function (child) {
|
|
246
|
+
// For components, export all connectors (including deep children within GLFs)
|
|
247
|
+
threeObject.traverse(function (child) {
|
|
244
248
|
var _child$userData2;
|
|
245
249
|
if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'connector') {
|
|
250
|
+
// Calculate position relative to component root
|
|
251
|
+
var componentMatrixWorldInverse = threeObject.matrixWorld.clone().invert();
|
|
252
|
+
var childWorldPos = new THREE.Vector3();
|
|
253
|
+
child.getWorldPosition(childWorldPos);
|
|
254
|
+
var relativePos = childWorldPos.applyMatrix4(componentMatrixWorldInverse);
|
|
246
255
|
exportableChildren.push({
|
|
247
256
|
uuid: child.uuid,
|
|
248
257
|
name: child.name,
|
|
249
258
|
type: 'Mesh',
|
|
250
259
|
position: {
|
|
251
|
-
x: roundIfClose(
|
|
252
|
-
y: roundIfClose(
|
|
253
|
-
z: roundIfClose(
|
|
260
|
+
x: roundIfClose(relativePos.x),
|
|
261
|
+
y: roundIfClose(relativePos.y),
|
|
262
|
+
z: roundIfClose(relativePos.z)
|
|
254
263
|
},
|
|
255
264
|
userData: _objectSpread2({}, child.userData)
|
|
256
265
|
});
|
|
@@ -1324,24 +1324,29 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1324
1324
|
children: [] // Initialize children array
|
|
1325
1325
|
};
|
|
1326
1326
|
|
|
1327
|
-
// Collect children that are connectors
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1327
|
+
// Collect children that are connectors (using traverse to find deep children in models)
|
|
1328
|
+
componentModel.traverse(function (child) {
|
|
1329
|
+
if (child.userData && child.userData.objectType === 'connector') {
|
|
1330
|
+
// Calculate position relative to component root
|
|
1331
|
+
// This ensures that when we re-add it as a direct child of the component,
|
|
1332
|
+
// it maintains the same world position relative to the component.
|
|
1333
|
+
var componentMatrixWorldInverse = componentModel.matrixWorld.clone().invert();
|
|
1334
|
+
var childWorldPos = new THREE.Vector3();
|
|
1335
|
+
child.getWorldPosition(childWorldPos);
|
|
1336
|
+
var relativePos = childWorldPos.applyMatrix4(componentMatrixWorldInverse);
|
|
1337
|
+
componentSceneData.children.push({
|
|
1338
|
+
uuid: child.uuid,
|
|
1339
|
+
name: child.name,
|
|
1340
|
+
type: 'Mesh',
|
|
1341
|
+
position: {
|
|
1342
|
+
x: relativePos.x,
|
|
1343
|
+
y: relativePos.y,
|
|
1344
|
+
z: relativePos.z
|
|
1345
|
+
},
|
|
1346
|
+
userData: _objectSpread2({}, child.userData)
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
});
|
|
1345
1350
|
|
|
1346
1351
|
// Add the component to the scene data
|
|
1347
1352
|
if (!currentSceneData.scene.children) {
|
|
@@ -155,41 +155,36 @@ function computeFilteredBoundingBox(object) {
|
|
|
155
155
|
*/
|
|
156
156
|
function computeIODeviceBoundingBoxes(componentObject) {
|
|
157
157
|
var results = [];
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
158
|
+
componentObject.traverse(function (child) {
|
|
159
|
+
var _child$userData;
|
|
160
|
+
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) !== 'io-device') return;
|
|
161
|
+
var bbox = new THREE.Box3().setFromObject(child);
|
|
162
|
+
var worldPos = new THREE.Vector3();
|
|
163
|
+
child.getWorldPosition(worldPos);
|
|
164
|
+
if (!bbox.isEmpty()) {
|
|
165
|
+
results.push({
|
|
166
|
+
uuid: child.uuid,
|
|
167
|
+
userData: {
|
|
168
|
+
objectType: 'io-device',
|
|
169
|
+
deviceId: child.userData.deviceId || null,
|
|
170
|
+
attachmentId: child.userData.attachmentId || null,
|
|
171
|
+
parentComponentId: child.userData.parentComponentId || componentObject.uuid,
|
|
172
|
+
// Sync position for pathfinder
|
|
173
|
+
position: [worldPos.x, worldPos.y, worldPos.z]
|
|
174
|
+
},
|
|
175
|
+
worldBoundingBox: {
|
|
176
|
+
min: [bbox.min.x, bbox.min.y, bbox.min.z],
|
|
177
|
+
max: [bbox.max.x, bbox.max.y, bbox.max.z]
|
|
178
|
+
}
|
|
179
|
+
});
|
|
181
180
|
}
|
|
182
|
-
}
|
|
183
|
-
_iterator.e(err);
|
|
184
|
-
} finally {
|
|
185
|
-
_iterator.f();
|
|
186
|
-
}
|
|
181
|
+
});
|
|
187
182
|
return results;
|
|
188
183
|
}
|
|
189
184
|
|
|
190
185
|
/**
|
|
191
186
|
* Computes individual world-space bounding boxes for each connector child
|
|
192
|
-
* of a component.
|
|
187
|
+
* of a component. Supports deep children (e.g. within GLB model hierarchy).
|
|
193
188
|
*
|
|
194
189
|
* @param {THREE.Object3D} componentObject - The component's Three.js object
|
|
195
190
|
* @returns {Array<{uuid: string, userData: Object, worldBoundingBox: {min: number[], max: number[]}}>}
|
|
@@ -197,38 +192,40 @@ function computeIODeviceBoundingBoxes(componentObject) {
|
|
|
197
192
|
*/
|
|
198
193
|
function computeConnectorBoundingBoxes(componentObject) {
|
|
199
194
|
var results = [];
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) !== 'connector') continue;
|
|
207
|
-
var bbox = new THREE.Box3().setFromObject(child);
|
|
195
|
+
componentObject.traverse(function (child) {
|
|
196
|
+
var _child$userData2;
|
|
197
|
+
if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) !== 'connector') return;
|
|
198
|
+
var bbox = new THREE.Box3().setFromObject(child);
|
|
199
|
+
var worldPos = new THREE.Vector3();
|
|
200
|
+
child.getWorldPosition(worldPos);
|
|
208
201
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
worldBoundingBox: {
|
|
222
|
-
min: [bbox.min.x, bbox.min.y, bbox.min.z],
|
|
223
|
-
max: [bbox.max.x, bbox.max.y, bbox.max.z]
|
|
224
|
-
}
|
|
225
|
-
});
|
|
202
|
+
// Compute world-space direction vector (Crucial for rotation-aware pathfinding)
|
|
203
|
+
// Default to [0, 0, 1] if not specified (Standard for our coordinate system)
|
|
204
|
+
var localDirData = child.userData && Array.isArray(child.userData.direction) ? child.userData.direction : [0, 0, 1];
|
|
205
|
+
var localDir = new THREE.Vector3(localDirData[0], localDirData[1], localDirData[2]);
|
|
206
|
+
var worldQuat = new THREE.Quaternion();
|
|
207
|
+
child.getWorldQuaternion(worldQuat);
|
|
208
|
+
var worldDir = localDir.clone().applyQuaternion(worldQuat).normalize();
|
|
209
|
+
|
|
210
|
+
// Fallback if mesh is too small or empty (sometimes connectors are just points)
|
|
211
|
+
if (bbox.isEmpty() || bbox.getSize(new THREE.Vector3()).length() < 0.01) {
|
|
212
|
+
var size = 0.1;
|
|
213
|
+
bbox.setFromCenterAndSize(worldPos, new THREE.Vector3(size, size, size));
|
|
226
214
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
215
|
+
results.push({
|
|
216
|
+
uuid: child.uuid,
|
|
217
|
+
userData: _objectSpread2(_objectSpread2({}, child.userData), {}, {
|
|
218
|
+
objectType: 'connector',
|
|
219
|
+
// Update both position AND direction for pathfinder
|
|
220
|
+
position: [worldPos.x, worldPos.y, worldPos.z],
|
|
221
|
+
direction: [worldDir.x, worldDir.y, worldDir.z]
|
|
222
|
+
}),
|
|
223
|
+
worldBoundingBox: {
|
|
224
|
+
min: [bbox.min.x, bbox.min.y, bbox.min.z],
|
|
225
|
+
max: [bbox.max.x, bbox.max.y, bbox.max.z]
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
});
|
|
232
229
|
return results;
|
|
233
230
|
}
|
|
234
231
|
|
|
@@ -328,11 +325,11 @@ function createSelectionBoxHelpers(object) {
|
|
|
328
325
|
* @param {THREE.Scene} scene - The scene (for finding objects by uuid)
|
|
329
326
|
*/
|
|
330
327
|
function updateSelectionBoxHelpers(helpers, selectedObjects, scene) {
|
|
331
|
-
var
|
|
332
|
-
|
|
328
|
+
var _iterator = _createForOfIteratorHelper(helpers),
|
|
329
|
+
_step;
|
|
333
330
|
try {
|
|
334
331
|
var _loop = function _loop() {
|
|
335
|
-
var helper =
|
|
332
|
+
var helper = _step.value;
|
|
336
333
|
var _helper$userData = helper.userData,
|
|
337
334
|
sourceObjectUuid = _helper$userData.sourceObjectUuid,
|
|
338
335
|
isFiltered = _helper$userData.isFiltered,
|
|
@@ -363,13 +360,13 @@ function updateSelectionBoxHelpers(helpers, selectedObjects, scene) {
|
|
|
363
360
|
helper.update();
|
|
364
361
|
}
|
|
365
362
|
};
|
|
366
|
-
for (
|
|
363
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
367
364
|
if (_loop()) continue;
|
|
368
365
|
}
|
|
369
366
|
} catch (err) {
|
|
370
|
-
|
|
367
|
+
_iterator.e(err);
|
|
371
368
|
} finally {
|
|
372
|
-
|
|
369
|
+
_iterator.f();
|
|
373
370
|
}
|
|
374
371
|
}
|
|
375
372
|
|