@2112-lab/central-plant 0.3.47 → 0.3.49
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 +591 -476
- 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 +23 -30
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +48 -21
- 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 +24 -31
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +48 -21
- 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,4 +1,4 @@
|
|
|
1
|
-
import { createClass as _createClass, classCallCheck as _classCallCheck, toConsumableArray as _toConsumableArray,
|
|
1
|
+
import { createClass as _createClass, classCallCheck as _classCallCheck, toConsumableArray as _toConsumableArray, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
2
|
import 'three';
|
|
3
3
|
import { GLTFExporter } from '../../../node_modules/three/examples/jsm/exporters/GLTFExporter.js';
|
|
4
4
|
import { getHardcodedUuid } from '../../utils/nameUtils.js';
|
|
@@ -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
|
|
@@ -219,11 +224,10 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
219
224
|
};
|
|
220
225
|
}
|
|
221
226
|
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
227
|
+
// Only manual segments persist their connector children here.
|
|
228
|
+
// Component connectors are NOT exported — they are regenerated from the
|
|
229
|
+
// component dictionary on load (see note below), keeping the scene JSON minimal.
|
|
225
230
|
if (threeObject.children && threeObject.children.length > 0) {
|
|
226
|
-
var _threeObject$userData11;
|
|
227
231
|
var exportableChildren = [];
|
|
228
232
|
if (isManualSegment) {
|
|
229
233
|
// For manual segments, export their connector children
|
|
@@ -237,26 +241,15 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
237
241
|
}
|
|
238
242
|
}
|
|
239
243
|
});
|
|
240
|
-
} else if (((_threeObject$userData11 = threeObject.userData) === null || _threeObject$userData11 === void 0 ? void 0 : _threeObject$userData11.objectType) === 'component') {
|
|
241
|
-
// For components, only export connectors that have objectType='connector'
|
|
242
|
-
// Standard dictionary-injected connectors should be exported so connections work on re-import
|
|
243
|
-
threeObject.children.forEach(function (child) {
|
|
244
|
-
var _child$userData2;
|
|
245
|
-
if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'connector') {
|
|
246
|
-
exportableChildren.push({
|
|
247
|
-
uuid: child.uuid,
|
|
248
|
-
name: child.name,
|
|
249
|
-
type: 'Mesh',
|
|
250
|
-
position: {
|
|
251
|
-
x: roundIfClose(child.position.x),
|
|
252
|
-
y: roundIfClose(child.position.y),
|
|
253
|
-
z: roundIfClose(child.position.z)
|
|
254
|
-
},
|
|
255
|
-
userData: _objectSpread2({}, child.userData)
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
244
|
}
|
|
245
|
+
// NOTE: Component connectors are intentionally NOT exported.
|
|
246
|
+
// They are defined in the component dictionary and regenerated on load by
|
|
247
|
+
// sceneOperationsManager._injectConnectorChildrenFromDictionary using the
|
|
248
|
+
// matching uuid scheme (`${componentUuid}_${dictConnectorUuid}`), and the
|
|
249
|
+
// pathfinder rebuilds their world positions/bounding boxes on every run
|
|
250
|
+
// (computeConnectorBoundingBoxes). Connections still resolve because the
|
|
251
|
+
// regenerated connector uuids match the connection endpoints.
|
|
252
|
+
|
|
260
253
|
if (exportableChildren.length > 0) {
|
|
261
254
|
jsonObject.children = exportableChildren;
|
|
262
255
|
}
|
|
@@ -270,9 +263,9 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
270
263
|
// Extract main scene objects (components and standalone connectors)
|
|
271
264
|
var sceneChildren = [];
|
|
272
265
|
this.sceneViewer.scene.children.forEach(function (child) {
|
|
273
|
-
var _child$
|
|
266
|
+
var _child$userData2;
|
|
274
267
|
// Only export components and connectors; skip segments, gateways, polylines, etc.
|
|
275
|
-
var objectType = (_child$
|
|
268
|
+
var objectType = (_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType;
|
|
276
269
|
if (objectType !== 'component' && objectType !== 'connector') {
|
|
277
270
|
return;
|
|
278
271
|
}
|
|
@@ -436,14 +429,14 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
436
429
|
BufferGeometryUtils = BufferGeometryUtilsModule.BufferGeometryUtils || BufferGeometryUtilsModule.default || BufferGeometryUtilsModule; // Create a new scene for export instead of cloning
|
|
437
430
|
exportScene = new _THREE.Scene(); // Helper function to check if an object should be exported
|
|
438
431
|
shouldExport = function shouldExport(child) {
|
|
439
|
-
var _child$name, _child$
|
|
432
|
+
var _child$name, _child$userData3, _child$userData4, _child$userData5, _child$userData6;
|
|
440
433
|
if ((_child$name = child.name) !== null && _child$name !== void 0 && _child$name.includes('Polyline')) return false; // Will handle separately
|
|
441
434
|
if (child.name === 'fogPlane') return false; // Skip fog plane
|
|
442
|
-
if ((_child$
|
|
443
|
-
if ((_child$
|
|
444
|
-
if ((_child$
|
|
435
|
+
if ((_child$userData3 = child.userData) !== null && _child$userData3 !== void 0 && _child$userData3.isBrickWall) return false; // Skip environment
|
|
436
|
+
if ((_child$userData4 = child.userData) !== null && _child$userData4 !== void 0 && _child$userData4.isBaseGround) return false; // Skip environment
|
|
437
|
+
if ((_child$userData5 = child.userData) !== null && _child$userData5 !== void 0 && _child$userData5.isBaseGrid) return false; // Skip environment
|
|
445
438
|
if (child.isLight) return false; // Skip lights
|
|
446
|
-
if ((_child$
|
|
439
|
+
if ((_child$userData6 = child.userData) !== null && _child$userData6 !== void 0 && _child$userData6.isTransformControls) return false; // Skip transform controls
|
|
447
440
|
if (child.isTransformControls) return false; // Skip transform controls
|
|
448
441
|
if (child.type && child.type.includes('TransformControls')) return false;
|
|
449
442
|
if (child.type && child.type.includes('Helper')) return false; // Skip helpers
|
|
@@ -866,6 +866,19 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
866
866
|
if (!(data !== null && data !== void 0 && (_data$scene2 = data.scene) !== null && _data$scene2 !== void 0 && _data$scene2.children) || !componentDictionary) {
|
|
867
867
|
return;
|
|
868
868
|
}
|
|
869
|
+
|
|
870
|
+
// Collect every connector uuid referenced by the scene's connections so we
|
|
871
|
+
// can inject connectors under the SAME uuid scheme the scene actually uses.
|
|
872
|
+
// Two schemes exist in the wild:
|
|
873
|
+
// - Preferred (runtime add path + minimal export): `${componentUuid}_${dictConnectorUuid}`
|
|
874
|
+
// - Legacy (older hand-authored scenes): `${componentUuid}-CONNECTOR-${index+1}`
|
|
875
|
+
var connectionEndpoints = new Set();
|
|
876
|
+
if (Array.isArray(data.connections)) {
|
|
877
|
+
data.connections.forEach(function (conn) {
|
|
878
|
+
if (conn !== null && conn !== void 0 && conn.from) connectionEndpoints.add(conn.from);
|
|
879
|
+
if (conn !== null && conn !== void 0 && conn.to) connectionEndpoints.add(conn.to);
|
|
880
|
+
});
|
|
881
|
+
}
|
|
869
882
|
var componentsProcessed = 0;
|
|
870
883
|
var connectorsInjected = 0;
|
|
871
884
|
data.scene.children.forEach(function (child) {
|
|
@@ -888,9 +901,18 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
888
901
|
|
|
889
902
|
// Deep clone the connector children from the dictionary
|
|
890
903
|
child.children = dictEntry.children.map(function (connector, index) {
|
|
891
|
-
//
|
|
892
|
-
//
|
|
893
|
-
|
|
904
|
+
// Choose the connector uuid that matches the scheme the scene's
|
|
905
|
+
// connections reference. Prefer `${componentUuid}_${dictConnectorUuid}`
|
|
906
|
+
// (sandbox add path + minimal export); fall back to the legacy
|
|
907
|
+
// index-based scheme `${componentUuid}-CONNECTOR-${index+1}` when the
|
|
908
|
+
// connections reference that form. If neither is referenced (e.g. an
|
|
909
|
+
// unconnected connector), default to the preferred scheme.
|
|
910
|
+
var legacyUuid = "".concat(child.uuid, "-CONNECTOR-").concat(index + 1);
|
|
911
|
+
var preferredUuid = connector.uuid ? "".concat(child.uuid, "_").concat(connector.uuid) : legacyUuid;
|
|
912
|
+
var connectorUuid = preferredUuid;
|
|
913
|
+
if (!connectionEndpoints.has(preferredUuid) && connectionEndpoints.has(legacyUuid)) {
|
|
914
|
+
connectorUuid = legacyUuid;
|
|
915
|
+
}
|
|
894
916
|
|
|
895
917
|
// Clone connector with deep copy of userData
|
|
896
918
|
var clonedConnector = _objectSpread2(_objectSpread2({}, connector), {}, {
|
|
@@ -1324,24 +1346,29 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1324
1346
|
children: [] // Initialize children array
|
|
1325
1347
|
};
|
|
1326
1348
|
|
|
1327
|
-
// Collect children that are connectors
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1349
|
+
// Collect children that are connectors (using traverse to find deep children in models)
|
|
1350
|
+
componentModel.traverse(function (child) {
|
|
1351
|
+
if (child.userData && child.userData.objectType === 'connector') {
|
|
1352
|
+
// Calculate position relative to component root
|
|
1353
|
+
// This ensures that when we re-add it as a direct child of the component,
|
|
1354
|
+
// it maintains the same world position relative to the component.
|
|
1355
|
+
var componentMatrixWorldInverse = componentModel.matrixWorld.clone().invert();
|
|
1356
|
+
var childWorldPos = new THREE.Vector3();
|
|
1357
|
+
child.getWorldPosition(childWorldPos);
|
|
1358
|
+
var relativePos = childWorldPos.applyMatrix4(componentMatrixWorldInverse);
|
|
1359
|
+
componentSceneData.children.push({
|
|
1360
|
+
uuid: child.uuid,
|
|
1361
|
+
name: child.name,
|
|
1362
|
+
type: 'Mesh',
|
|
1363
|
+
position: {
|
|
1364
|
+
x: relativePos.x,
|
|
1365
|
+
y: relativePos.y,
|
|
1366
|
+
z: relativePos.z
|
|
1367
|
+
},
|
|
1368
|
+
userData: _objectSpread2({}, child.userData)
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1345
1372
|
|
|
1346
1373
|
// Add the component to the scene data
|
|
1347
1374
|
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
|
|