@2112-lab/central-plant 0.2.4 → 0.2.8
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 +226 -21
- package/dist/cjs/src/core/centralPlant.js +118 -1
- package/dist/cjs/src/core/centralPlantInternals.js +81 -17
- package/dist/cjs/src/managers/behaviors/BehaviorManager.js +11 -1
- package/dist/cjs/src/managers/controls/componentDragManager.js +8 -1
- package/dist/cjs/src/utils/ioDeviceUtils.js +8 -1
- package/dist/esm/src/core/centralPlant.js +118 -1
- package/dist/esm/src/core/centralPlantInternals.js +81 -17
- package/dist/esm/src/managers/behaviors/BehaviorManager.js +11 -1
- package/dist/esm/src/managers/controls/componentDragManager.js +8 -1
- package/dist/esm/src/utils/ioDeviceUtils.js +8 -1
- package/dist/index.d.ts +19 -0
- package/package.json +1 -1
package/dist/bundle/index.js
CHANGED
|
@@ -28480,7 +28480,7 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
28480
28480
|
if (_this4._testCondition(condition.when, value)) {
|
|
28481
28481
|
if (Array.isArray(condition.actions)) {
|
|
28482
28482
|
condition.actions.forEach(function (action) {
|
|
28483
|
-
_this4._applyAction(output, action.set, action.value);
|
|
28483
|
+
_this4._applyAction(output, action.set, action.value, action.relative === true);
|
|
28484
28484
|
});
|
|
28485
28485
|
}
|
|
28486
28486
|
}
|
|
@@ -28558,6 +28558,7 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
28558
28558
|
}, {
|
|
28559
28559
|
key: "_applyAction",
|
|
28560
28560
|
value: function _applyAction(object, propertyPath, value) {
|
|
28561
|
+
var relative = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
28561
28562
|
if (!object || typeof propertyPath !== 'string') return;
|
|
28562
28563
|
var parts = propertyPath.split('.');
|
|
28563
28564
|
|
|
@@ -28583,6 +28584,15 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
28583
28584
|
return;
|
|
28584
28585
|
}
|
|
28585
28586
|
|
|
28587
|
+
// If relative, capture the mesh's original value on first execution and offset from it.
|
|
28588
|
+
if (relative) {
|
|
28589
|
+
var baselineKey = "_baseline_".concat(propertyPath.replace(/\./g, '_'));
|
|
28590
|
+
if (!(baselineKey in object.userData)) {
|
|
28591
|
+
object.userData[baselineKey] = target[lastKey];
|
|
28592
|
+
}
|
|
28593
|
+
value = object.userData[baselineKey] + parseFloat(value);
|
|
28594
|
+
}
|
|
28595
|
+
|
|
28586
28596
|
// THREE.Color objects must be mutated via .set() rather than replaced
|
|
28587
28597
|
var existing = target[lastKey];
|
|
28588
28598
|
if (existing && existing.isColor && typeof value === 'string') {
|
|
@@ -28635,7 +28645,7 @@ function attachIODevicesToComponent(_x, _x2, _x3, _x4) {
|
|
|
28635
28645
|
}
|
|
28636
28646
|
function _attachIODevicesToComponent() {
|
|
28637
28647
|
_attachIODevicesToComponent = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(componentModel, componentData, modelPreloader, parentComponentId) {
|
|
28638
|
-
var attachedDevices, _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, _t, _t2;
|
|
28648
|
+
var attachedDevices, _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, _attachment$attachmen2, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, rot, deg2rad, _t, _t2;
|
|
28639
28649
|
return _regenerator().w(function (_context) {
|
|
28640
28650
|
while (1) switch (_context.n) {
|
|
28641
28651
|
case 0:
|
|
@@ -28736,6 +28746,13 @@ function _attachIODevicesToComponent() {
|
|
|
28736
28746
|
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
28737
28747
|
}
|
|
28738
28748
|
|
|
28749
|
+
// Apply face-based rotation (stored in degrees, XYZ Euler order)
|
|
28750
|
+
if ((_attachment$attachmen2 = attachment.attachmentPoint) !== null && _attachment$attachmen2 !== void 0 && _attachment$attachmen2.rotation) {
|
|
28751
|
+
rot = attachment.attachmentPoint.rotation;
|
|
28752
|
+
deg2rad = Math.PI / 180;
|
|
28753
|
+
deviceModel.rotation.set((rot.x || 0) * deg2rad, (rot.y || 0) * deg2rad, (rot.z || 0) * deg2rad, 'XYZ');
|
|
28754
|
+
}
|
|
28755
|
+
|
|
28739
28756
|
// IO device models are authored at the same real-world unit scale
|
|
28740
28757
|
// as the host component, so keep them at their natural (1:1) size.
|
|
28741
28758
|
// Note: attachmentPoint.scale is the connector marker sphere size,
|
|
@@ -32575,7 +32592,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
32575
32592
|
key: "_attachIODeviceModelsToPreview",
|
|
32576
32593
|
value: (function () {
|
|
32577
32594
|
var _attachIODeviceModelsToPreview2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(parentObject, componentData, modelPreloader) {
|
|
32578
|
-
var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, _t3;
|
|
32595
|
+
var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, _attachment$attachmen2, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, rot, deg2rad, _t3;
|
|
32579
32596
|
return _regenerator().w(function (_context3) {
|
|
32580
32597
|
while (1) switch (_context3.n) {
|
|
32581
32598
|
case 0:
|
|
@@ -32650,6 +32667,13 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
32650
32667
|
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
32651
32668
|
}
|
|
32652
32669
|
|
|
32670
|
+
// Apply face-based rotation (stored in degrees, XYZ Euler order)
|
|
32671
|
+
if ((_attachment$attachmen2 = attachment.attachmentPoint) !== null && _attachment$attachmen2 !== void 0 && _attachment$attachmen2.rotation) {
|
|
32672
|
+
rot = attachment.attachmentPoint.rotation;
|
|
32673
|
+
deg2rad = Math.PI / 180;
|
|
32674
|
+
deviceModel.rotation.set((rot.x || 0) * deg2rad, (rot.y || 0) * deg2rad, (rot.z || 0) * deg2rad, 'XYZ');
|
|
32675
|
+
}
|
|
32676
|
+
|
|
32653
32677
|
// IO device models use their natural (1:1) scale — the stored
|
|
32654
32678
|
// attachmentPoint.scale value is for the connector marker sphere.
|
|
32655
32679
|
deviceModel.scale.setScalar(1);
|
|
@@ -36018,6 +36042,59 @@ var Viewport2DManager = /*#__PURE__*/function (_BaseDisposable2) {
|
|
|
36018
36042
|
}]);
|
|
36019
36043
|
}(BaseDisposable);
|
|
36020
36044
|
|
|
36045
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
36046
|
+
// Flow-direction helpers (module-level)
|
|
36047
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
36048
|
+
|
|
36049
|
+
/**
|
|
36050
|
+
* Returns the flow direction of a connector from the current scene data.
|
|
36051
|
+
* @param {Object} sceneData - currentSceneData object
|
|
36052
|
+
* @param {string} connectorId
|
|
36053
|
+
* @returns {'in'|'out'|'bi'} Defaults to 'bi' if not set.
|
|
36054
|
+
*/
|
|
36055
|
+
function _getConnectorFlow(sceneData, connectorId) {
|
|
36056
|
+
var _sceneData$scene;
|
|
36057
|
+
var children = (sceneData === null || sceneData === void 0 || (_sceneData$scene = sceneData.scene) === null || _sceneData$scene === void 0 ? void 0 : _sceneData$scene.children) || [];
|
|
36058
|
+
var _iterator = _createForOfIteratorHelper(children),
|
|
36059
|
+
_step;
|
|
36060
|
+
try {
|
|
36061
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
36062
|
+
var component = _step.value;
|
|
36063
|
+
var _iterator2 = _createForOfIteratorHelper(component.children || []),
|
|
36064
|
+
_step2;
|
|
36065
|
+
try {
|
|
36066
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
36067
|
+
var _child$userData;
|
|
36068
|
+
var child = _step2.value;
|
|
36069
|
+
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'connector' && child.uuid === connectorId) {
|
|
36070
|
+
return child.userData.flow || 'bi';
|
|
36071
|
+
}
|
|
36072
|
+
}
|
|
36073
|
+
} catch (err) {
|
|
36074
|
+
_iterator2.e(err);
|
|
36075
|
+
} finally {
|
|
36076
|
+
_iterator2.f();
|
|
36077
|
+
}
|
|
36078
|
+
}
|
|
36079
|
+
} catch (err) {
|
|
36080
|
+
_iterator.e(err);
|
|
36081
|
+
} finally {
|
|
36082
|
+
_iterator.f();
|
|
36083
|
+
}
|
|
36084
|
+
return 'bi';
|
|
36085
|
+
}
|
|
36086
|
+
|
|
36087
|
+
/**
|
|
36088
|
+
* Returns true if fromFlow → toFlow is a valid connection.
|
|
36089
|
+
* @param {'in'|'out'|'bi'} fromFlow
|
|
36090
|
+
* @param {'in'|'out'|'bi'} toFlow
|
|
36091
|
+
* @returns {boolean}
|
|
36092
|
+
*/
|
|
36093
|
+
function _areFlowsCompatible$1(fromFlow, toFlow) {
|
|
36094
|
+
if (fromFlow === 'bi' || toFlow === 'bi') return true;
|
|
36095
|
+
return fromFlow !== toFlow;
|
|
36096
|
+
}
|
|
36097
|
+
|
|
36021
36098
|
/**
|
|
36022
36099
|
* CentralPlantInternals class containing internal methods and functionality
|
|
36023
36100
|
*/
|
|
@@ -36469,12 +36546,12 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36469
36546
|
console.log("\uD83D\uDD27 Translating ".concat(selectedObjects.length, " selected object(s) on ").concat(axis, " axis by ").concat(value));
|
|
36470
36547
|
|
|
36471
36548
|
// Translate each selected object using the appropriate method
|
|
36472
|
-
var
|
|
36473
|
-
|
|
36549
|
+
var _iterator3 = _createForOfIteratorHelper(selectedObjects),
|
|
36550
|
+
_step3;
|
|
36474
36551
|
try {
|
|
36475
|
-
for (
|
|
36552
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
36476
36553
|
var _obj$userData;
|
|
36477
|
-
var obj =
|
|
36554
|
+
var obj = _step3.value;
|
|
36478
36555
|
var objectType = (_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType;
|
|
36479
36556
|
var objectId = obj.uuid;
|
|
36480
36557
|
var success = false;
|
|
@@ -36501,9 +36578,9 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36501
36578
|
}
|
|
36502
36579
|
}
|
|
36503
36580
|
} catch (err) {
|
|
36504
|
-
|
|
36581
|
+
_iterator3.e(err);
|
|
36505
36582
|
} finally {
|
|
36506
|
-
|
|
36583
|
+
_iterator3.f();
|
|
36507
36584
|
}
|
|
36508
36585
|
result.success = result.translatedCount === result.totalCount;
|
|
36509
36586
|
if (result.success) {
|
|
@@ -36687,7 +36764,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36687
36764
|
}, {
|
|
36688
36765
|
key: "addConnection",
|
|
36689
36766
|
value: function addConnection(fromConnectorId, toConnectorId) {
|
|
36690
|
-
var _this$centralPlant$sc4;
|
|
36767
|
+
var _this$centralPlant$sc4, _this$centralPlant$sc5;
|
|
36691
36768
|
// Use centralized validation for connection parameters
|
|
36692
36769
|
var existingConnections = ((_this$centralPlant$sc4 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc4 === void 0 || (_this$centralPlant$sc4 = _this$centralPlant$sc4.currentSceneData) === null || _this$centralPlant$sc4 === void 0 ? void 0 : _this$centralPlant$sc4.connections) || [];
|
|
36693
36770
|
var validation = this.validator.validateConnectionParams(fromConnectorId, toConnectorId, existingConnections);
|
|
@@ -36695,6 +36772,17 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36695
36772
|
return false; // Validator already logged the error
|
|
36696
36773
|
}
|
|
36697
36774
|
|
|
36775
|
+
// Validate flow direction compatibility
|
|
36776
|
+
var sceneData = (_this$centralPlant$sc5 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc5 === void 0 ? void 0 : _this$centralPlant$sc5.currentSceneData;
|
|
36777
|
+
if (sceneData) {
|
|
36778
|
+
var fromFlow = _getConnectorFlow(sceneData, fromConnectorId);
|
|
36779
|
+
var toFlow = _getConnectorFlow(sceneData, toConnectorId);
|
|
36780
|
+
if (!_areFlowsCompatible$1(fromFlow, toFlow)) {
|
|
36781
|
+
console.error("\u274C addConnection(): Incompatible flow directions \u2014 '".concat(fromConnectorId, "' is '").concat(fromFlow, "' and '").concat(toConnectorId, "' is '").concat(toFlow, "'. ") + "'".concat(fromFlow, "' \u2192 '").concat(toFlow, "' connections are not allowed."));
|
|
36782
|
+
return false;
|
|
36783
|
+
}
|
|
36784
|
+
}
|
|
36785
|
+
|
|
36698
36786
|
// Validate scene availability
|
|
36699
36787
|
var sceneValidation = this.validator.validateSceneViewer(this.centralPlant.sceneViewer);
|
|
36700
36788
|
if (!sceneValidation.isValid) {
|
|
@@ -36815,7 +36903,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36815
36903
|
}, {
|
|
36816
36904
|
key: "addComponent",
|
|
36817
36905
|
value: function addComponent(libraryId) {
|
|
36818
|
-
var _this$centralPlant$
|
|
36906
|
+
var _this$centralPlant$sc6;
|
|
36819
36907
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
36820
36908
|
// Use centralized validation for component addition parameters
|
|
36821
36909
|
var existingIds = this.getComponentIds();
|
|
@@ -36825,7 +36913,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36825
36913
|
}
|
|
36826
36914
|
|
|
36827
36915
|
// Validate scene availability
|
|
36828
|
-
var sceneValidation = this.validator.validateSceneViewer(this.centralPlant.sceneViewer, (_this$centralPlant$
|
|
36916
|
+
var sceneValidation = this.validator.validateSceneViewer(this.centralPlant.sceneViewer, (_this$centralPlant$sc6 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc6 === void 0 ? void 0 : _this$centralPlant$sc6.scene);
|
|
36829
36917
|
if (!sceneValidation.isValid) {
|
|
36830
36918
|
return false;
|
|
36831
36919
|
}
|
|
@@ -36844,7 +36932,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36844
36932
|
return false;
|
|
36845
36933
|
}
|
|
36846
36934
|
try {
|
|
36847
|
-
var _componentData$childr, _componentData$childr2, _this$centralPlant$
|
|
36935
|
+
var _componentData$childr, _componentData$childr2, _this$centralPlant$sc7, _componentData$childr3, _componentData$defaul;
|
|
36848
36936
|
// Generate a unique component ID if not provided
|
|
36849
36937
|
var componentId = options.customId || this.generateUniqueComponentId(libraryId);
|
|
36850
36938
|
|
|
@@ -36956,7 +37044,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36956
37044
|
componentModel.updateMatrixWorld(true);
|
|
36957
37045
|
|
|
36958
37046
|
// Check if component is underground and fix if needed (based on settings)
|
|
36959
|
-
var checkUnderground = (_this$centralPlant$
|
|
37047
|
+
var checkUnderground = (_this$centralPlant$sc7 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc7 === void 0 || (_this$centralPlant$sc7 = _this$centralPlant$sc7.managers) === null || _this$centralPlant$sc7 === void 0 || (_this$centralPlant$sc7 = _this$centralPlant$sc7.settingsManager) === null || _this$centralPlant$sc7 === void 0 ? void 0 : _this$centralPlant$sc7.getSetting('scene', 'checkUnderground');
|
|
36960
37048
|
if (checkUnderground) {
|
|
36961
37049
|
var wasFixed = this.fixUndergroundComponent(componentModel);
|
|
36962
37050
|
if (wasFixed) {
|
|
@@ -37054,8 +37142,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
37054
37142
|
// responds to tooltip-driven state changes immediately after drop.
|
|
37055
37143
|
// (The scene-load path uses _processBehaviors instead, which runs on loadSceneData.)
|
|
37056
37144
|
if ((_componentData$defaul = componentData.defaultBehaviors) !== null && _componentData$defaul !== void 0 && _componentData$defaul.length) {
|
|
37057
|
-
var _this$centralPlant$
|
|
37058
|
-
var som = (_this$centralPlant$
|
|
37145
|
+
var _this$centralPlant$sc8, _som$registerBehavior;
|
|
37146
|
+
var som = (_this$centralPlant$sc8 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc8 === void 0 ? void 0 : _this$centralPlant$sc8.sceneOperationsManager;
|
|
37059
37147
|
som === null || som === void 0 || (_som$registerBehavior = som.registerBehaviorsForComponentInstance) === null || _som$registerBehavior === void 0 || _som$registerBehavior.call(som, componentData, componentId);
|
|
37060
37148
|
}
|
|
37061
37149
|
|
|
@@ -37117,9 +37205,9 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
37117
37205
|
}, {
|
|
37118
37206
|
key: "deleteComponent",
|
|
37119
37207
|
value: function deleteComponent(componentId) {
|
|
37120
|
-
var _this$centralPlant$
|
|
37208
|
+
var _this$centralPlant$sc9;
|
|
37121
37209
|
// Check if component manager is available
|
|
37122
|
-
var componentManager = (_this$centralPlant$
|
|
37210
|
+
var componentManager = (_this$centralPlant$sc9 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc9 === void 0 ? void 0 : _this$centralPlant$sc9.componentManager;
|
|
37123
37211
|
if (!componentManager) {
|
|
37124
37212
|
console.error('❌ deleteComponent(): Component manager not available');
|
|
37125
37213
|
return false;
|
|
@@ -37194,8 +37282,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
37194
37282
|
}
|
|
37195
37283
|
var componentIds = [];
|
|
37196
37284
|
this.centralPlant.sceneViewer.scene.traverse(function (child) {
|
|
37197
|
-
var _child$
|
|
37198
|
-
if (((_child$
|
|
37285
|
+
var _child$userData2;
|
|
37286
|
+
if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'component') {
|
|
37199
37287
|
componentIds.push(child.uuid || child.userData.originalUuid);
|
|
37200
37288
|
}
|
|
37201
37289
|
});
|
|
@@ -37204,6 +37292,22 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
37204
37292
|
}]);
|
|
37205
37293
|
}();
|
|
37206
37294
|
|
|
37295
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
37296
|
+
// Flow-direction compatibility helper (module-level, no class dependency)
|
|
37297
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
37298
|
+
|
|
37299
|
+
/**
|
|
37300
|
+
* Returns true if the two flow directions are compatible for a connection.
|
|
37301
|
+
* @param {string} fromFlow - 'in' | 'out' | 'bi'
|
|
37302
|
+
* @param {string} toFlow - 'in' | 'out' | 'bi'
|
|
37303
|
+
* @returns {boolean}
|
|
37304
|
+
*/
|
|
37305
|
+
function _areFlowsCompatible(fromFlow, toFlow) {
|
|
37306
|
+
if (fromFlow === 'bi' || toFlow === 'bi') return true;
|
|
37307
|
+
// in ↔ out are compatible; in → in and out → out are not
|
|
37308
|
+
return fromFlow !== toFlow;
|
|
37309
|
+
}
|
|
37310
|
+
|
|
37207
37311
|
/**
|
|
37208
37312
|
* CentralPlant class that manages all scene utility instances and provides public API
|
|
37209
37313
|
*
|
|
@@ -37214,7 +37318,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37214
37318
|
* Initialize the CentralPlant manager
|
|
37215
37319
|
*
|
|
37216
37320
|
* @constructor
|
|
37217
|
-
* @version 0.2.
|
|
37321
|
+
* @version 0.2.8
|
|
37218
37322
|
* @updated 2025-10-22
|
|
37219
37323
|
*
|
|
37220
37324
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -38147,6 +38251,107 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
38147
38251
|
return availableConnectorIds;
|
|
38148
38252
|
}
|
|
38149
38253
|
|
|
38254
|
+
/**
|
|
38255
|
+
* Get available connectors with their flow direction metadata.
|
|
38256
|
+
* Same filtering logic as getAvailableConnections() but returns objects instead of strings.
|
|
38257
|
+
* @returns {Array<{id: string, flow: string}>} Array of connector info objects.
|
|
38258
|
+
* flow is one of 'in', 'out', 'bi'. Defaults to 'bi' if not set in userData.
|
|
38259
|
+
* @example
|
|
38260
|
+
* const infos = centralPlant.getAvailableConnectionsInfo()
|
|
38261
|
+
* // [{ id: 'PUMP-1-CONNECTOR-1', flow: 'out' }, ...]
|
|
38262
|
+
*/
|
|
38263
|
+
}, {
|
|
38264
|
+
key: "getAvailableConnectionsInfo",
|
|
38265
|
+
value: function getAvailableConnectionsInfo() {
|
|
38266
|
+
if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
|
|
38267
|
+
console.warn('⚠️ getAvailableConnectionsInfo(): Scene viewer or current scene data not available');
|
|
38268
|
+
return [];
|
|
38269
|
+
}
|
|
38270
|
+
var sceneData = this.sceneViewer.currentSceneData;
|
|
38271
|
+
if (!sceneData.scene || !sceneData.scene.children) {
|
|
38272
|
+
console.warn('⚠️ getAvailableConnectionsInfo(): Invalid scene data structure');
|
|
38273
|
+
return [];
|
|
38274
|
+
}
|
|
38275
|
+
var allConnectorInfos = [];
|
|
38276
|
+
sceneData.scene.children.forEach(function (component) {
|
|
38277
|
+
if (component.children && Array.isArray(component.children)) {
|
|
38278
|
+
component.children.forEach(function (child) {
|
|
38279
|
+
if (child.userData && child.userData.objectType === 'connector' && child.uuid) {
|
|
38280
|
+
allConnectorInfos.push({
|
|
38281
|
+
id: child.uuid,
|
|
38282
|
+
flow: child.userData.flow || 'bi'
|
|
38283
|
+
});
|
|
38284
|
+
}
|
|
38285
|
+
});
|
|
38286
|
+
}
|
|
38287
|
+
});
|
|
38288
|
+
var existingConnections = this.getConnections();
|
|
38289
|
+
var usedConnectorIds = new Set();
|
|
38290
|
+
existingConnections.forEach(function (connection) {
|
|
38291
|
+
if (connection.from) usedConnectorIds.add(connection.from);
|
|
38292
|
+
if (connection.to) usedConnectorIds.add(connection.to);
|
|
38293
|
+
});
|
|
38294
|
+
return allConnectorInfos.filter(function (info) {
|
|
38295
|
+
return !usedConnectorIds.has(info.id);
|
|
38296
|
+
});
|
|
38297
|
+
}
|
|
38298
|
+
|
|
38299
|
+
/**
|
|
38300
|
+
* Validate all connections in the current scene for flow direction compatibility.
|
|
38301
|
+
* @returns {{ valid: Array<Object>, invalid: Array<{connection: Object, reason: string}> }}
|
|
38302
|
+
* @example
|
|
38303
|
+
* const result = centralPlant.validateConnections()
|
|
38304
|
+
* result.invalid.forEach(({ connection, reason }) => console.warn(reason, connection))
|
|
38305
|
+
*/
|
|
38306
|
+
}, {
|
|
38307
|
+
key: "validateConnections",
|
|
38308
|
+
value: function validateConnections() {
|
|
38309
|
+
if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
|
|
38310
|
+
console.warn('⚠️ validateConnections(): Scene viewer or current scene data not available');
|
|
38311
|
+
return {
|
|
38312
|
+
valid: [],
|
|
38313
|
+
invalid: []
|
|
38314
|
+
};
|
|
38315
|
+
}
|
|
38316
|
+
var connections = this.getConnections();
|
|
38317
|
+
var sceneData = this.sceneViewer.currentSceneData;
|
|
38318
|
+
|
|
38319
|
+
// Build lookup map: connectorId → flow
|
|
38320
|
+
var flowMap = {};
|
|
38321
|
+
var scene = sceneData.scene || {};
|
|
38322
|
+
var children = scene.children || [];
|
|
38323
|
+
children.forEach(function (component) {
|
|
38324
|
+
if (component.children && Array.isArray(component.children)) {
|
|
38325
|
+
component.children.forEach(function (child) {
|
|
38326
|
+
if (child.userData && child.userData.objectType === 'connector' && child.uuid) {
|
|
38327
|
+
flowMap[child.uuid] = child.userData.flow || 'bi';
|
|
38328
|
+
}
|
|
38329
|
+
});
|
|
38330
|
+
}
|
|
38331
|
+
});
|
|
38332
|
+
var valid = [];
|
|
38333
|
+
var invalid = [];
|
|
38334
|
+
connections.forEach(function (connection) {
|
|
38335
|
+
var fromFlow = flowMap[connection.from] || 'bi';
|
|
38336
|
+
var toFlow = flowMap[connection.to] || 'bi';
|
|
38337
|
+
if (_areFlowsCompatible(fromFlow, toFlow)) {
|
|
38338
|
+
valid.push(connection);
|
|
38339
|
+
} else {
|
|
38340
|
+
var reason = "Incompatible flow directions: connector '".concat(connection.from, "' is '").concat(fromFlow, "' and connector '").concat(connection.to, "' is '").concat(toFlow, "' \u2014 ").concat(fromFlow, " \u2192 ").concat(toFlow, " is not allowed");
|
|
38341
|
+
console.warn("\u26A0\uFE0F validateConnections(): ".concat(reason));
|
|
38342
|
+
invalid.push({
|
|
38343
|
+
connection: connection,
|
|
38344
|
+
reason: reason
|
|
38345
|
+
});
|
|
38346
|
+
}
|
|
38347
|
+
});
|
|
38348
|
+
console.log("\u2705 validateConnections(): ".concat(valid.length, " valid, ").concat(invalid.length, " invalid connections"));
|
|
38349
|
+
return {
|
|
38350
|
+
valid: valid,
|
|
38351
|
+
invalid: invalid
|
|
38352
|
+
};
|
|
38353
|
+
}
|
|
38354
|
+
|
|
38150
38355
|
// ─────────────────────────────────────────────────────────────────────────
|
|
38151
38356
|
// BEHAVIORS API
|
|
38152
38357
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -9,6 +9,22 @@ var DisposalUtilities = require('../utils/DisposalUtilities.js');
|
|
|
9
9
|
var centralPlantInternals = require('./centralPlantInternals.js');
|
|
10
10
|
require('../rendering/modelPreloader.js');
|
|
11
11
|
|
|
12
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
+
// Flow-direction compatibility helper (module-level, no class dependency)
|
|
14
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns true if the two flow directions are compatible for a connection.
|
|
18
|
+
* @param {string} fromFlow - 'in' | 'out' | 'bi'
|
|
19
|
+
* @param {string} toFlow - 'in' | 'out' | 'bi'
|
|
20
|
+
* @returns {boolean}
|
|
21
|
+
*/
|
|
22
|
+
function _areFlowsCompatible(fromFlow, toFlow) {
|
|
23
|
+
if (fromFlow === 'bi' || toFlow === 'bi') return true;
|
|
24
|
+
// in ↔ out are compatible; in → in and out → out are not
|
|
25
|
+
return fromFlow !== toFlow;
|
|
26
|
+
}
|
|
27
|
+
|
|
12
28
|
/**
|
|
13
29
|
* CentralPlant class that manages all scene utility instances and provides public API
|
|
14
30
|
*
|
|
@@ -19,7 +35,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
19
35
|
* Initialize the CentralPlant manager
|
|
20
36
|
*
|
|
21
37
|
* @constructor
|
|
22
|
-
* @version 0.2.
|
|
38
|
+
* @version 0.2.8
|
|
23
39
|
* @updated 2025-10-22
|
|
24
40
|
*
|
|
25
41
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -952,6 +968,107 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
952
968
|
return availableConnectorIds;
|
|
953
969
|
}
|
|
954
970
|
|
|
971
|
+
/**
|
|
972
|
+
* Get available connectors with their flow direction metadata.
|
|
973
|
+
* Same filtering logic as getAvailableConnections() but returns objects instead of strings.
|
|
974
|
+
* @returns {Array<{id: string, flow: string}>} Array of connector info objects.
|
|
975
|
+
* flow is one of 'in', 'out', 'bi'. Defaults to 'bi' if not set in userData.
|
|
976
|
+
* @example
|
|
977
|
+
* const infos = centralPlant.getAvailableConnectionsInfo()
|
|
978
|
+
* // [{ id: 'PUMP-1-CONNECTOR-1', flow: 'out' }, ...]
|
|
979
|
+
*/
|
|
980
|
+
}, {
|
|
981
|
+
key: "getAvailableConnectionsInfo",
|
|
982
|
+
value: function getAvailableConnectionsInfo() {
|
|
983
|
+
if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
|
|
984
|
+
console.warn('⚠️ getAvailableConnectionsInfo(): Scene viewer or current scene data not available');
|
|
985
|
+
return [];
|
|
986
|
+
}
|
|
987
|
+
var sceneData = this.sceneViewer.currentSceneData;
|
|
988
|
+
if (!sceneData.scene || !sceneData.scene.children) {
|
|
989
|
+
console.warn('⚠️ getAvailableConnectionsInfo(): Invalid scene data structure');
|
|
990
|
+
return [];
|
|
991
|
+
}
|
|
992
|
+
var allConnectorInfos = [];
|
|
993
|
+
sceneData.scene.children.forEach(function (component) {
|
|
994
|
+
if (component.children && Array.isArray(component.children)) {
|
|
995
|
+
component.children.forEach(function (child) {
|
|
996
|
+
if (child.userData && child.userData.objectType === 'connector' && child.uuid) {
|
|
997
|
+
allConnectorInfos.push({
|
|
998
|
+
id: child.uuid,
|
|
999
|
+
flow: child.userData.flow || 'bi'
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
var existingConnections = this.getConnections();
|
|
1006
|
+
var usedConnectorIds = new Set();
|
|
1007
|
+
existingConnections.forEach(function (connection) {
|
|
1008
|
+
if (connection.from) usedConnectorIds.add(connection.from);
|
|
1009
|
+
if (connection.to) usedConnectorIds.add(connection.to);
|
|
1010
|
+
});
|
|
1011
|
+
return allConnectorInfos.filter(function (info) {
|
|
1012
|
+
return !usedConnectorIds.has(info.id);
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
/**
|
|
1017
|
+
* Validate all connections in the current scene for flow direction compatibility.
|
|
1018
|
+
* @returns {{ valid: Array<Object>, invalid: Array<{connection: Object, reason: string}> }}
|
|
1019
|
+
* @example
|
|
1020
|
+
* const result = centralPlant.validateConnections()
|
|
1021
|
+
* result.invalid.forEach(({ connection, reason }) => console.warn(reason, connection))
|
|
1022
|
+
*/
|
|
1023
|
+
}, {
|
|
1024
|
+
key: "validateConnections",
|
|
1025
|
+
value: function validateConnections() {
|
|
1026
|
+
if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
|
|
1027
|
+
console.warn('⚠️ validateConnections(): Scene viewer or current scene data not available');
|
|
1028
|
+
return {
|
|
1029
|
+
valid: [],
|
|
1030
|
+
invalid: []
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
var connections = this.getConnections();
|
|
1034
|
+
var sceneData = this.sceneViewer.currentSceneData;
|
|
1035
|
+
|
|
1036
|
+
// Build lookup map: connectorId → flow
|
|
1037
|
+
var flowMap = {};
|
|
1038
|
+
var scene = sceneData.scene || {};
|
|
1039
|
+
var children = scene.children || [];
|
|
1040
|
+
children.forEach(function (component) {
|
|
1041
|
+
if (component.children && Array.isArray(component.children)) {
|
|
1042
|
+
component.children.forEach(function (child) {
|
|
1043
|
+
if (child.userData && child.userData.objectType === 'connector' && child.uuid) {
|
|
1044
|
+
flowMap[child.uuid] = child.userData.flow || 'bi';
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
var valid = [];
|
|
1050
|
+
var invalid = [];
|
|
1051
|
+
connections.forEach(function (connection) {
|
|
1052
|
+
var fromFlow = flowMap[connection.from] || 'bi';
|
|
1053
|
+
var toFlow = flowMap[connection.to] || 'bi';
|
|
1054
|
+
if (_areFlowsCompatible(fromFlow, toFlow)) {
|
|
1055
|
+
valid.push(connection);
|
|
1056
|
+
} else {
|
|
1057
|
+
var reason = "Incompatible flow directions: connector '".concat(connection.from, "' is '").concat(fromFlow, "' and connector '").concat(connection.to, "' is '").concat(toFlow, "' \u2014 ").concat(fromFlow, " \u2192 ").concat(toFlow, " is not allowed");
|
|
1058
|
+
console.warn("\u26A0\uFE0F validateConnections(): ".concat(reason));
|
|
1059
|
+
invalid.push({
|
|
1060
|
+
connection: connection,
|
|
1061
|
+
reason: reason
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
console.log("\u2705 validateConnections(): ".concat(valid.length, " valid, ").concat(invalid.length, " invalid connections"));
|
|
1066
|
+
return {
|
|
1067
|
+
valid: valid,
|
|
1068
|
+
invalid: invalid
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
|
|
955
1072
|
// ─────────────────────────────────────────────────────────────────────────
|
|
956
1073
|
// BEHAVIORS API
|
|
957
1074
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -50,6 +50,59 @@ function _interopNamespace(e) {
|
|
|
50
50
|
|
|
51
51
|
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
52
52
|
|
|
53
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
54
|
+
// Flow-direction helpers (module-level)
|
|
55
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns the flow direction of a connector from the current scene data.
|
|
59
|
+
* @param {Object} sceneData - currentSceneData object
|
|
60
|
+
* @param {string} connectorId
|
|
61
|
+
* @returns {'in'|'out'|'bi'} Defaults to 'bi' if not set.
|
|
62
|
+
*/
|
|
63
|
+
function _getConnectorFlow(sceneData, connectorId) {
|
|
64
|
+
var _sceneData$scene;
|
|
65
|
+
var children = (sceneData === null || sceneData === void 0 || (_sceneData$scene = sceneData.scene) === null || _sceneData$scene === void 0 ? void 0 : _sceneData$scene.children) || [];
|
|
66
|
+
var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(children),
|
|
67
|
+
_step;
|
|
68
|
+
try {
|
|
69
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
70
|
+
var component = _step.value;
|
|
71
|
+
var _iterator2 = _rollupPluginBabelHelpers.createForOfIteratorHelper(component.children || []),
|
|
72
|
+
_step2;
|
|
73
|
+
try {
|
|
74
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
75
|
+
var _child$userData;
|
|
76
|
+
var child = _step2.value;
|
|
77
|
+
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'connector' && child.uuid === connectorId) {
|
|
78
|
+
return child.userData.flow || 'bi';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
_iterator2.e(err);
|
|
83
|
+
} finally {
|
|
84
|
+
_iterator2.f();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} catch (err) {
|
|
88
|
+
_iterator.e(err);
|
|
89
|
+
} finally {
|
|
90
|
+
_iterator.f();
|
|
91
|
+
}
|
|
92
|
+
return 'bi';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Returns true if fromFlow → toFlow is a valid connection.
|
|
97
|
+
* @param {'in'|'out'|'bi'} fromFlow
|
|
98
|
+
* @param {'in'|'out'|'bi'} toFlow
|
|
99
|
+
* @returns {boolean}
|
|
100
|
+
*/
|
|
101
|
+
function _areFlowsCompatible(fromFlow, toFlow) {
|
|
102
|
+
if (fromFlow === 'bi' || toFlow === 'bi') return true;
|
|
103
|
+
return fromFlow !== toFlow;
|
|
104
|
+
}
|
|
105
|
+
|
|
53
106
|
/**
|
|
54
107
|
* CentralPlantInternals class containing internal methods and functionality
|
|
55
108
|
*/
|
|
@@ -501,12 +554,12 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
501
554
|
console.log("\uD83D\uDD27 Translating ".concat(selectedObjects.length, " selected object(s) on ").concat(axis, " axis by ").concat(value));
|
|
502
555
|
|
|
503
556
|
// Translate each selected object using the appropriate method
|
|
504
|
-
var
|
|
505
|
-
|
|
557
|
+
var _iterator3 = _rollupPluginBabelHelpers.createForOfIteratorHelper(selectedObjects),
|
|
558
|
+
_step3;
|
|
506
559
|
try {
|
|
507
|
-
for (
|
|
560
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
508
561
|
var _obj$userData;
|
|
509
|
-
var obj =
|
|
562
|
+
var obj = _step3.value;
|
|
510
563
|
var objectType = (_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType;
|
|
511
564
|
var objectId = obj.uuid;
|
|
512
565
|
var success = false;
|
|
@@ -533,9 +586,9 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
533
586
|
}
|
|
534
587
|
}
|
|
535
588
|
} catch (err) {
|
|
536
|
-
|
|
589
|
+
_iterator3.e(err);
|
|
537
590
|
} finally {
|
|
538
|
-
|
|
591
|
+
_iterator3.f();
|
|
539
592
|
}
|
|
540
593
|
result.success = result.translatedCount === result.totalCount;
|
|
541
594
|
if (result.success) {
|
|
@@ -719,7 +772,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
719
772
|
}, {
|
|
720
773
|
key: "addConnection",
|
|
721
774
|
value: function addConnection(fromConnectorId, toConnectorId) {
|
|
722
|
-
var _this$centralPlant$sc4;
|
|
775
|
+
var _this$centralPlant$sc4, _this$centralPlant$sc5;
|
|
723
776
|
// Use centralized validation for connection parameters
|
|
724
777
|
var existingConnections = ((_this$centralPlant$sc4 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc4 === void 0 || (_this$centralPlant$sc4 = _this$centralPlant$sc4.currentSceneData) === null || _this$centralPlant$sc4 === void 0 ? void 0 : _this$centralPlant$sc4.connections) || [];
|
|
725
778
|
var validation = this.validator.validateConnectionParams(fromConnectorId, toConnectorId, existingConnections);
|
|
@@ -727,6 +780,17 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
727
780
|
return false; // Validator already logged the error
|
|
728
781
|
}
|
|
729
782
|
|
|
783
|
+
// Validate flow direction compatibility
|
|
784
|
+
var sceneData = (_this$centralPlant$sc5 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc5 === void 0 ? void 0 : _this$centralPlant$sc5.currentSceneData;
|
|
785
|
+
if (sceneData) {
|
|
786
|
+
var fromFlow = _getConnectorFlow(sceneData, fromConnectorId);
|
|
787
|
+
var toFlow = _getConnectorFlow(sceneData, toConnectorId);
|
|
788
|
+
if (!_areFlowsCompatible(fromFlow, toFlow)) {
|
|
789
|
+
console.error("\u274C addConnection(): Incompatible flow directions \u2014 '".concat(fromConnectorId, "' is '").concat(fromFlow, "' and '").concat(toConnectorId, "' is '").concat(toFlow, "'. ") + "'".concat(fromFlow, "' \u2192 '").concat(toFlow, "' connections are not allowed."));
|
|
790
|
+
return false;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
730
794
|
// Validate scene availability
|
|
731
795
|
var sceneValidation = this.validator.validateSceneViewer(this.centralPlant.sceneViewer);
|
|
732
796
|
if (!sceneValidation.isValid) {
|
|
@@ -847,7 +911,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
847
911
|
}, {
|
|
848
912
|
key: "addComponent",
|
|
849
913
|
value: function addComponent(libraryId) {
|
|
850
|
-
var _this$centralPlant$
|
|
914
|
+
var _this$centralPlant$sc6;
|
|
851
915
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
852
916
|
// Use centralized validation for component addition parameters
|
|
853
917
|
var existingIds = this.getComponentIds();
|
|
@@ -857,7 +921,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
857
921
|
}
|
|
858
922
|
|
|
859
923
|
// Validate scene availability
|
|
860
|
-
var sceneValidation = this.validator.validateSceneViewer(this.centralPlant.sceneViewer, (_this$centralPlant$
|
|
924
|
+
var sceneValidation = this.validator.validateSceneViewer(this.centralPlant.sceneViewer, (_this$centralPlant$sc6 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc6 === void 0 ? void 0 : _this$centralPlant$sc6.scene);
|
|
861
925
|
if (!sceneValidation.isValid) {
|
|
862
926
|
return false;
|
|
863
927
|
}
|
|
@@ -876,7 +940,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
876
940
|
return false;
|
|
877
941
|
}
|
|
878
942
|
try {
|
|
879
|
-
var _componentData$childr, _componentData$childr2, _this$centralPlant$
|
|
943
|
+
var _componentData$childr, _componentData$childr2, _this$centralPlant$sc7, _componentData$childr3, _componentData$defaul;
|
|
880
944
|
// Generate a unique component ID if not provided
|
|
881
945
|
var componentId = options.customId || this.generateUniqueComponentId(libraryId);
|
|
882
946
|
|
|
@@ -988,7 +1052,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
988
1052
|
componentModel.updateMatrixWorld(true);
|
|
989
1053
|
|
|
990
1054
|
// Check if component is underground and fix if needed (based on settings)
|
|
991
|
-
var checkUnderground = (_this$centralPlant$
|
|
1055
|
+
var checkUnderground = (_this$centralPlant$sc7 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc7 === void 0 || (_this$centralPlant$sc7 = _this$centralPlant$sc7.managers) === null || _this$centralPlant$sc7 === void 0 || (_this$centralPlant$sc7 = _this$centralPlant$sc7.settingsManager) === null || _this$centralPlant$sc7 === void 0 ? void 0 : _this$centralPlant$sc7.getSetting('scene', 'checkUnderground');
|
|
992
1056
|
if (checkUnderground) {
|
|
993
1057
|
var wasFixed = this.fixUndergroundComponent(componentModel);
|
|
994
1058
|
if (wasFixed) {
|
|
@@ -1086,8 +1150,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
1086
1150
|
// responds to tooltip-driven state changes immediately after drop.
|
|
1087
1151
|
// (The scene-load path uses _processBehaviors instead, which runs on loadSceneData.)
|
|
1088
1152
|
if ((_componentData$defaul = componentData.defaultBehaviors) !== null && _componentData$defaul !== void 0 && _componentData$defaul.length) {
|
|
1089
|
-
var _this$centralPlant$
|
|
1090
|
-
var som = (_this$centralPlant$
|
|
1153
|
+
var _this$centralPlant$sc8, _som$registerBehavior;
|
|
1154
|
+
var som = (_this$centralPlant$sc8 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc8 === void 0 ? void 0 : _this$centralPlant$sc8.sceneOperationsManager;
|
|
1091
1155
|
som === null || som === void 0 || (_som$registerBehavior = som.registerBehaviorsForComponentInstance) === null || _som$registerBehavior === void 0 || _som$registerBehavior.call(som, componentData, componentId);
|
|
1092
1156
|
}
|
|
1093
1157
|
|
|
@@ -1149,9 +1213,9 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
1149
1213
|
}, {
|
|
1150
1214
|
key: "deleteComponent",
|
|
1151
1215
|
value: function deleteComponent(componentId) {
|
|
1152
|
-
var _this$centralPlant$
|
|
1216
|
+
var _this$centralPlant$sc9;
|
|
1153
1217
|
// Check if component manager is available
|
|
1154
|
-
var componentManager = (_this$centralPlant$
|
|
1218
|
+
var componentManager = (_this$centralPlant$sc9 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc9 === void 0 ? void 0 : _this$centralPlant$sc9.componentManager;
|
|
1155
1219
|
if (!componentManager) {
|
|
1156
1220
|
console.error('❌ deleteComponent(): Component manager not available');
|
|
1157
1221
|
return false;
|
|
@@ -1226,8 +1290,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
1226
1290
|
}
|
|
1227
1291
|
var componentIds = [];
|
|
1228
1292
|
this.centralPlant.sceneViewer.scene.traverse(function (child) {
|
|
1229
|
-
var _child$
|
|
1230
|
-
if (((_child$
|
|
1293
|
+
var _child$userData2;
|
|
1294
|
+
if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'component') {
|
|
1231
1295
|
componentIds.push(child.uuid || child.userData.originalUuid);
|
|
1232
1296
|
}
|
|
1233
1297
|
});
|
|
@@ -264,7 +264,7 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
264
264
|
if (_this4._testCondition(condition.when, value)) {
|
|
265
265
|
if (Array.isArray(condition.actions)) {
|
|
266
266
|
condition.actions.forEach(function (action) {
|
|
267
|
-
_this4._applyAction(output, action.set, action.value);
|
|
267
|
+
_this4._applyAction(output, action.set, action.value, action.relative === true);
|
|
268
268
|
});
|
|
269
269
|
}
|
|
270
270
|
}
|
|
@@ -342,6 +342,7 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
342
342
|
}, {
|
|
343
343
|
key: "_applyAction",
|
|
344
344
|
value: function _applyAction(object, propertyPath, value) {
|
|
345
|
+
var relative = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
345
346
|
if (!object || typeof propertyPath !== 'string') return;
|
|
346
347
|
var parts = propertyPath.split('.');
|
|
347
348
|
|
|
@@ -367,6 +368,15 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
367
368
|
return;
|
|
368
369
|
}
|
|
369
370
|
|
|
371
|
+
// If relative, capture the mesh's original value on first execution and offset from it.
|
|
372
|
+
if (relative) {
|
|
373
|
+
var baselineKey = "_baseline_".concat(propertyPath.replace(/\./g, '_'));
|
|
374
|
+
if (!(baselineKey in object.userData)) {
|
|
375
|
+
object.userData[baselineKey] = target[lastKey];
|
|
376
|
+
}
|
|
377
|
+
value = object.userData[baselineKey] + parseFloat(value);
|
|
378
|
+
}
|
|
379
|
+
|
|
370
380
|
// THREE.Color objects must be mutated via .set() rather than replaced
|
|
371
381
|
var existing = target[lastKey];
|
|
372
382
|
if (existing && existing.isColor && typeof value === 'string') {
|
|
@@ -345,7 +345,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
345
345
|
key: "_attachIODeviceModelsToPreview",
|
|
346
346
|
value: (function () {
|
|
347
347
|
var _attachIODeviceModelsToPreview2 = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee3(parentObject, componentData, modelPreloader) {
|
|
348
|
-
var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, _t3;
|
|
348
|
+
var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, _attachment$attachmen2, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, rot, deg2rad, _t3;
|
|
349
349
|
return _rollupPluginBabelHelpers.regenerator().w(function (_context3) {
|
|
350
350
|
while (1) switch (_context3.n) {
|
|
351
351
|
case 0:
|
|
@@ -420,6 +420,13 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
420
420
|
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
421
421
|
}
|
|
422
422
|
|
|
423
|
+
// Apply face-based rotation (stored in degrees, XYZ Euler order)
|
|
424
|
+
if ((_attachment$attachmen2 = attachment.attachmentPoint) !== null && _attachment$attachmen2 !== void 0 && _attachment$attachmen2.rotation) {
|
|
425
|
+
rot = attachment.attachmentPoint.rotation;
|
|
426
|
+
deg2rad = Math.PI / 180;
|
|
427
|
+
deviceModel.rotation.set((rot.x || 0) * deg2rad, (rot.y || 0) * deg2rad, (rot.z || 0) * deg2rad, 'XYZ');
|
|
428
|
+
}
|
|
429
|
+
|
|
423
430
|
// IO device models use their natural (1:1) scale — the stored
|
|
424
431
|
// attachmentPoint.scale value is for the connector marker sphere.
|
|
425
432
|
deviceModel.scale.setScalar(1);
|
|
@@ -27,7 +27,7 @@ function attachIODevicesToComponent(_x, _x2, _x3, _x4) {
|
|
|
27
27
|
}
|
|
28
28
|
function _attachIODevicesToComponent() {
|
|
29
29
|
_attachIODevicesToComponent = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee(componentModel, componentData, modelPreloader, parentComponentId) {
|
|
30
|
-
var attachedDevices, _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, _t, _t2;
|
|
30
|
+
var attachedDevices, _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, _attachment$attachmen2, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, rot, deg2rad, _t, _t2;
|
|
31
31
|
return _rollupPluginBabelHelpers.regenerator().w(function (_context) {
|
|
32
32
|
while (1) switch (_context.n) {
|
|
33
33
|
case 0:
|
|
@@ -128,6 +128,13 @@ function _attachIODevicesToComponent() {
|
|
|
128
128
|
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// Apply face-based rotation (stored in degrees, XYZ Euler order)
|
|
132
|
+
if ((_attachment$attachmen2 = attachment.attachmentPoint) !== null && _attachment$attachmen2 !== void 0 && _attachment$attachmen2.rotation) {
|
|
133
|
+
rot = attachment.attachmentPoint.rotation;
|
|
134
|
+
deg2rad = Math.PI / 180;
|
|
135
|
+
deviceModel.rotation.set((rot.x || 0) * deg2rad, (rot.y || 0) * deg2rad, (rot.z || 0) * deg2rad, 'XYZ');
|
|
136
|
+
}
|
|
137
|
+
|
|
131
138
|
// IO device models are authored at the same real-world unit scale
|
|
132
139
|
// as the host component, so keep them at their natural (1:1) size.
|
|
133
140
|
// Note: attachmentPoint.scale is the connector marker sphere size,
|
|
@@ -5,6 +5,22 @@ import { DisposalUtilities } from '../utils/DisposalUtilities.js';
|
|
|
5
5
|
import { CentralPlantInternals } from './centralPlantInternals.js';
|
|
6
6
|
import '../rendering/modelPreloader.js';
|
|
7
7
|
|
|
8
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
9
|
+
// Flow-direction compatibility helper (module-level, no class dependency)
|
|
10
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Returns true if the two flow directions are compatible for a connection.
|
|
14
|
+
* @param {string} fromFlow - 'in' | 'out' | 'bi'
|
|
15
|
+
* @param {string} toFlow - 'in' | 'out' | 'bi'
|
|
16
|
+
* @returns {boolean}
|
|
17
|
+
*/
|
|
18
|
+
function _areFlowsCompatible(fromFlow, toFlow) {
|
|
19
|
+
if (fromFlow === 'bi' || toFlow === 'bi') return true;
|
|
20
|
+
// in ↔ out are compatible; in → in and out → out are not
|
|
21
|
+
return fromFlow !== toFlow;
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
/**
|
|
9
25
|
* CentralPlant class that manages all scene utility instances and provides public API
|
|
10
26
|
*
|
|
@@ -15,7 +31,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
15
31
|
* Initialize the CentralPlant manager
|
|
16
32
|
*
|
|
17
33
|
* @constructor
|
|
18
|
-
* @version 0.2.
|
|
34
|
+
* @version 0.2.8
|
|
19
35
|
* @updated 2025-10-22
|
|
20
36
|
*
|
|
21
37
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -948,6 +964,107 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
948
964
|
return availableConnectorIds;
|
|
949
965
|
}
|
|
950
966
|
|
|
967
|
+
/**
|
|
968
|
+
* Get available connectors with their flow direction metadata.
|
|
969
|
+
* Same filtering logic as getAvailableConnections() but returns objects instead of strings.
|
|
970
|
+
* @returns {Array<{id: string, flow: string}>} Array of connector info objects.
|
|
971
|
+
* flow is one of 'in', 'out', 'bi'. Defaults to 'bi' if not set in userData.
|
|
972
|
+
* @example
|
|
973
|
+
* const infos = centralPlant.getAvailableConnectionsInfo()
|
|
974
|
+
* // [{ id: 'PUMP-1-CONNECTOR-1', flow: 'out' }, ...]
|
|
975
|
+
*/
|
|
976
|
+
}, {
|
|
977
|
+
key: "getAvailableConnectionsInfo",
|
|
978
|
+
value: function getAvailableConnectionsInfo() {
|
|
979
|
+
if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
|
|
980
|
+
console.warn('⚠️ getAvailableConnectionsInfo(): Scene viewer or current scene data not available');
|
|
981
|
+
return [];
|
|
982
|
+
}
|
|
983
|
+
var sceneData = this.sceneViewer.currentSceneData;
|
|
984
|
+
if (!sceneData.scene || !sceneData.scene.children) {
|
|
985
|
+
console.warn('⚠️ getAvailableConnectionsInfo(): Invalid scene data structure');
|
|
986
|
+
return [];
|
|
987
|
+
}
|
|
988
|
+
var allConnectorInfos = [];
|
|
989
|
+
sceneData.scene.children.forEach(function (component) {
|
|
990
|
+
if (component.children && Array.isArray(component.children)) {
|
|
991
|
+
component.children.forEach(function (child) {
|
|
992
|
+
if (child.userData && child.userData.objectType === 'connector' && child.uuid) {
|
|
993
|
+
allConnectorInfos.push({
|
|
994
|
+
id: child.uuid,
|
|
995
|
+
flow: child.userData.flow || 'bi'
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
var existingConnections = this.getConnections();
|
|
1002
|
+
var usedConnectorIds = new Set();
|
|
1003
|
+
existingConnections.forEach(function (connection) {
|
|
1004
|
+
if (connection.from) usedConnectorIds.add(connection.from);
|
|
1005
|
+
if (connection.to) usedConnectorIds.add(connection.to);
|
|
1006
|
+
});
|
|
1007
|
+
return allConnectorInfos.filter(function (info) {
|
|
1008
|
+
return !usedConnectorIds.has(info.id);
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Validate all connections in the current scene for flow direction compatibility.
|
|
1014
|
+
* @returns {{ valid: Array<Object>, invalid: Array<{connection: Object, reason: string}> }}
|
|
1015
|
+
* @example
|
|
1016
|
+
* const result = centralPlant.validateConnections()
|
|
1017
|
+
* result.invalid.forEach(({ connection, reason }) => console.warn(reason, connection))
|
|
1018
|
+
*/
|
|
1019
|
+
}, {
|
|
1020
|
+
key: "validateConnections",
|
|
1021
|
+
value: function validateConnections() {
|
|
1022
|
+
if (!this.sceneViewer || !this.sceneViewer.currentSceneData) {
|
|
1023
|
+
console.warn('⚠️ validateConnections(): Scene viewer or current scene data not available');
|
|
1024
|
+
return {
|
|
1025
|
+
valid: [],
|
|
1026
|
+
invalid: []
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
var connections = this.getConnections();
|
|
1030
|
+
var sceneData = this.sceneViewer.currentSceneData;
|
|
1031
|
+
|
|
1032
|
+
// Build lookup map: connectorId → flow
|
|
1033
|
+
var flowMap = {};
|
|
1034
|
+
var scene = sceneData.scene || {};
|
|
1035
|
+
var children = scene.children || [];
|
|
1036
|
+
children.forEach(function (component) {
|
|
1037
|
+
if (component.children && Array.isArray(component.children)) {
|
|
1038
|
+
component.children.forEach(function (child) {
|
|
1039
|
+
if (child.userData && child.userData.objectType === 'connector' && child.uuid) {
|
|
1040
|
+
flowMap[child.uuid] = child.userData.flow || 'bi';
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
var valid = [];
|
|
1046
|
+
var invalid = [];
|
|
1047
|
+
connections.forEach(function (connection) {
|
|
1048
|
+
var fromFlow = flowMap[connection.from] || 'bi';
|
|
1049
|
+
var toFlow = flowMap[connection.to] || 'bi';
|
|
1050
|
+
if (_areFlowsCompatible(fromFlow, toFlow)) {
|
|
1051
|
+
valid.push(connection);
|
|
1052
|
+
} else {
|
|
1053
|
+
var reason = "Incompatible flow directions: connector '".concat(connection.from, "' is '").concat(fromFlow, "' and connector '").concat(connection.to, "' is '").concat(toFlow, "' \u2014 ").concat(fromFlow, " \u2192 ").concat(toFlow, " is not allowed");
|
|
1054
|
+
console.warn("\u26A0\uFE0F validateConnections(): ".concat(reason));
|
|
1055
|
+
invalid.push({
|
|
1056
|
+
connection: connection,
|
|
1057
|
+
reason: reason
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
});
|
|
1061
|
+
console.log("\u2705 validateConnections(): ".concat(valid.length, " valid, ").concat(invalid.length, " invalid connections"));
|
|
1062
|
+
return {
|
|
1063
|
+
valid: valid,
|
|
1064
|
+
invalid: invalid
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
|
|
951
1068
|
// ─────────────────────────────────────────────────────────────────────────
|
|
952
1069
|
// BEHAVIORS API
|
|
953
1070
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -26,6 +26,59 @@ import { generateUuidFromName, getHardcodedUuid, findObjectByHardcodedUuid, gene
|
|
|
26
26
|
import { attachIODevicesToComponent } from '../utils/ioDeviceUtils.js';
|
|
27
27
|
import modelPreloader from '../rendering/modelPreloader.js';
|
|
28
28
|
|
|
29
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
30
|
+
// Flow-direction helpers (module-level)
|
|
31
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Returns the flow direction of a connector from the current scene data.
|
|
35
|
+
* @param {Object} sceneData - currentSceneData object
|
|
36
|
+
* @param {string} connectorId
|
|
37
|
+
* @returns {'in'|'out'|'bi'} Defaults to 'bi' if not set.
|
|
38
|
+
*/
|
|
39
|
+
function _getConnectorFlow(sceneData, connectorId) {
|
|
40
|
+
var _sceneData$scene;
|
|
41
|
+
var children = (sceneData === null || sceneData === void 0 || (_sceneData$scene = sceneData.scene) === null || _sceneData$scene === void 0 ? void 0 : _sceneData$scene.children) || [];
|
|
42
|
+
var _iterator = _createForOfIteratorHelper(children),
|
|
43
|
+
_step;
|
|
44
|
+
try {
|
|
45
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
46
|
+
var component = _step.value;
|
|
47
|
+
var _iterator2 = _createForOfIteratorHelper(component.children || []),
|
|
48
|
+
_step2;
|
|
49
|
+
try {
|
|
50
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
51
|
+
var _child$userData;
|
|
52
|
+
var child = _step2.value;
|
|
53
|
+
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'connector' && child.uuid === connectorId) {
|
|
54
|
+
return child.userData.flow || 'bi';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} catch (err) {
|
|
58
|
+
_iterator2.e(err);
|
|
59
|
+
} finally {
|
|
60
|
+
_iterator2.f();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} catch (err) {
|
|
64
|
+
_iterator.e(err);
|
|
65
|
+
} finally {
|
|
66
|
+
_iterator.f();
|
|
67
|
+
}
|
|
68
|
+
return 'bi';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Returns true if fromFlow → toFlow is a valid connection.
|
|
73
|
+
* @param {'in'|'out'|'bi'} fromFlow
|
|
74
|
+
* @param {'in'|'out'|'bi'} toFlow
|
|
75
|
+
* @returns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
function _areFlowsCompatible(fromFlow, toFlow) {
|
|
78
|
+
if (fromFlow === 'bi' || toFlow === 'bi') return true;
|
|
79
|
+
return fromFlow !== toFlow;
|
|
80
|
+
}
|
|
81
|
+
|
|
29
82
|
/**
|
|
30
83
|
* CentralPlantInternals class containing internal methods and functionality
|
|
31
84
|
*/
|
|
@@ -477,12 +530,12 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
477
530
|
console.log("\uD83D\uDD27 Translating ".concat(selectedObjects.length, " selected object(s) on ").concat(axis, " axis by ").concat(value));
|
|
478
531
|
|
|
479
532
|
// Translate each selected object using the appropriate method
|
|
480
|
-
var
|
|
481
|
-
|
|
533
|
+
var _iterator3 = _createForOfIteratorHelper(selectedObjects),
|
|
534
|
+
_step3;
|
|
482
535
|
try {
|
|
483
|
-
for (
|
|
536
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
484
537
|
var _obj$userData;
|
|
485
|
-
var obj =
|
|
538
|
+
var obj = _step3.value;
|
|
486
539
|
var objectType = (_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType;
|
|
487
540
|
var objectId = obj.uuid;
|
|
488
541
|
var success = false;
|
|
@@ -509,9 +562,9 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
509
562
|
}
|
|
510
563
|
}
|
|
511
564
|
} catch (err) {
|
|
512
|
-
|
|
565
|
+
_iterator3.e(err);
|
|
513
566
|
} finally {
|
|
514
|
-
|
|
567
|
+
_iterator3.f();
|
|
515
568
|
}
|
|
516
569
|
result.success = result.translatedCount === result.totalCount;
|
|
517
570
|
if (result.success) {
|
|
@@ -695,7 +748,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
695
748
|
}, {
|
|
696
749
|
key: "addConnection",
|
|
697
750
|
value: function addConnection(fromConnectorId, toConnectorId) {
|
|
698
|
-
var _this$centralPlant$sc4;
|
|
751
|
+
var _this$centralPlant$sc4, _this$centralPlant$sc5;
|
|
699
752
|
// Use centralized validation for connection parameters
|
|
700
753
|
var existingConnections = ((_this$centralPlant$sc4 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc4 === void 0 || (_this$centralPlant$sc4 = _this$centralPlant$sc4.currentSceneData) === null || _this$centralPlant$sc4 === void 0 ? void 0 : _this$centralPlant$sc4.connections) || [];
|
|
701
754
|
var validation = this.validator.validateConnectionParams(fromConnectorId, toConnectorId, existingConnections);
|
|
@@ -703,6 +756,17 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
703
756
|
return false; // Validator already logged the error
|
|
704
757
|
}
|
|
705
758
|
|
|
759
|
+
// Validate flow direction compatibility
|
|
760
|
+
var sceneData = (_this$centralPlant$sc5 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc5 === void 0 ? void 0 : _this$centralPlant$sc5.currentSceneData;
|
|
761
|
+
if (sceneData) {
|
|
762
|
+
var fromFlow = _getConnectorFlow(sceneData, fromConnectorId);
|
|
763
|
+
var toFlow = _getConnectorFlow(sceneData, toConnectorId);
|
|
764
|
+
if (!_areFlowsCompatible(fromFlow, toFlow)) {
|
|
765
|
+
console.error("\u274C addConnection(): Incompatible flow directions \u2014 '".concat(fromConnectorId, "' is '").concat(fromFlow, "' and '").concat(toConnectorId, "' is '").concat(toFlow, "'. ") + "'".concat(fromFlow, "' \u2192 '").concat(toFlow, "' connections are not allowed."));
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
706
770
|
// Validate scene availability
|
|
707
771
|
var sceneValidation = this.validator.validateSceneViewer(this.centralPlant.sceneViewer);
|
|
708
772
|
if (!sceneValidation.isValid) {
|
|
@@ -823,7 +887,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
823
887
|
}, {
|
|
824
888
|
key: "addComponent",
|
|
825
889
|
value: function addComponent(libraryId) {
|
|
826
|
-
var _this$centralPlant$
|
|
890
|
+
var _this$centralPlant$sc6;
|
|
827
891
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
828
892
|
// Use centralized validation for component addition parameters
|
|
829
893
|
var existingIds = this.getComponentIds();
|
|
@@ -833,7 +897,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
833
897
|
}
|
|
834
898
|
|
|
835
899
|
// Validate scene availability
|
|
836
|
-
var sceneValidation = this.validator.validateSceneViewer(this.centralPlant.sceneViewer, (_this$centralPlant$
|
|
900
|
+
var sceneValidation = this.validator.validateSceneViewer(this.centralPlant.sceneViewer, (_this$centralPlant$sc6 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc6 === void 0 ? void 0 : _this$centralPlant$sc6.scene);
|
|
837
901
|
if (!sceneValidation.isValid) {
|
|
838
902
|
return false;
|
|
839
903
|
}
|
|
@@ -852,7 +916,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
852
916
|
return false;
|
|
853
917
|
}
|
|
854
918
|
try {
|
|
855
|
-
var _componentData$childr, _componentData$childr2, _this$centralPlant$
|
|
919
|
+
var _componentData$childr, _componentData$childr2, _this$centralPlant$sc7, _componentData$childr3, _componentData$defaul;
|
|
856
920
|
// Generate a unique component ID if not provided
|
|
857
921
|
var componentId = options.customId || this.generateUniqueComponentId(libraryId);
|
|
858
922
|
|
|
@@ -964,7 +1028,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
964
1028
|
componentModel.updateMatrixWorld(true);
|
|
965
1029
|
|
|
966
1030
|
// Check if component is underground and fix if needed (based on settings)
|
|
967
|
-
var checkUnderground = (_this$centralPlant$
|
|
1031
|
+
var checkUnderground = (_this$centralPlant$sc7 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc7 === void 0 || (_this$centralPlant$sc7 = _this$centralPlant$sc7.managers) === null || _this$centralPlant$sc7 === void 0 || (_this$centralPlant$sc7 = _this$centralPlant$sc7.settingsManager) === null || _this$centralPlant$sc7 === void 0 ? void 0 : _this$centralPlant$sc7.getSetting('scene', 'checkUnderground');
|
|
968
1032
|
if (checkUnderground) {
|
|
969
1033
|
var wasFixed = this.fixUndergroundComponent(componentModel);
|
|
970
1034
|
if (wasFixed) {
|
|
@@ -1062,8 +1126,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
1062
1126
|
// responds to tooltip-driven state changes immediately after drop.
|
|
1063
1127
|
// (The scene-load path uses _processBehaviors instead, which runs on loadSceneData.)
|
|
1064
1128
|
if ((_componentData$defaul = componentData.defaultBehaviors) !== null && _componentData$defaul !== void 0 && _componentData$defaul.length) {
|
|
1065
|
-
var _this$centralPlant$
|
|
1066
|
-
var som = (_this$centralPlant$
|
|
1129
|
+
var _this$centralPlant$sc8, _som$registerBehavior;
|
|
1130
|
+
var som = (_this$centralPlant$sc8 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc8 === void 0 ? void 0 : _this$centralPlant$sc8.sceneOperationsManager;
|
|
1067
1131
|
som === null || som === void 0 || (_som$registerBehavior = som.registerBehaviorsForComponentInstance) === null || _som$registerBehavior === void 0 || _som$registerBehavior.call(som, componentData, componentId);
|
|
1068
1132
|
}
|
|
1069
1133
|
|
|
@@ -1125,9 +1189,9 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
1125
1189
|
}, {
|
|
1126
1190
|
key: "deleteComponent",
|
|
1127
1191
|
value: function deleteComponent(componentId) {
|
|
1128
|
-
var _this$centralPlant$
|
|
1192
|
+
var _this$centralPlant$sc9;
|
|
1129
1193
|
// Check if component manager is available
|
|
1130
|
-
var componentManager = (_this$centralPlant$
|
|
1194
|
+
var componentManager = (_this$centralPlant$sc9 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc9 === void 0 ? void 0 : _this$centralPlant$sc9.componentManager;
|
|
1131
1195
|
if (!componentManager) {
|
|
1132
1196
|
console.error('❌ deleteComponent(): Component manager not available');
|
|
1133
1197
|
return false;
|
|
@@ -1202,8 +1266,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
1202
1266
|
}
|
|
1203
1267
|
var componentIds = [];
|
|
1204
1268
|
this.centralPlant.sceneViewer.scene.traverse(function (child) {
|
|
1205
|
-
var _child$
|
|
1206
|
-
if (((_child$
|
|
1269
|
+
var _child$userData2;
|
|
1270
|
+
if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'component') {
|
|
1207
1271
|
componentIds.push(child.uuid || child.userData.originalUuid);
|
|
1208
1272
|
}
|
|
1209
1273
|
});
|
|
@@ -260,7 +260,7 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
260
260
|
if (_this4._testCondition(condition.when, value)) {
|
|
261
261
|
if (Array.isArray(condition.actions)) {
|
|
262
262
|
condition.actions.forEach(function (action) {
|
|
263
|
-
_this4._applyAction(output, action.set, action.value);
|
|
263
|
+
_this4._applyAction(output, action.set, action.value, action.relative === true);
|
|
264
264
|
});
|
|
265
265
|
}
|
|
266
266
|
}
|
|
@@ -338,6 +338,7 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
338
338
|
}, {
|
|
339
339
|
key: "_applyAction",
|
|
340
340
|
value: function _applyAction(object, propertyPath, value) {
|
|
341
|
+
var relative = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
341
342
|
if (!object || typeof propertyPath !== 'string') return;
|
|
342
343
|
var parts = propertyPath.split('.');
|
|
343
344
|
|
|
@@ -363,6 +364,15 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
363
364
|
return;
|
|
364
365
|
}
|
|
365
366
|
|
|
367
|
+
// If relative, capture the mesh's original value on first execution and offset from it.
|
|
368
|
+
if (relative) {
|
|
369
|
+
var baselineKey = "_baseline_".concat(propertyPath.replace(/\./g, '_'));
|
|
370
|
+
if (!(baselineKey in object.userData)) {
|
|
371
|
+
object.userData[baselineKey] = target[lastKey];
|
|
372
|
+
}
|
|
373
|
+
value = object.userData[baselineKey] + parseFloat(value);
|
|
374
|
+
}
|
|
375
|
+
|
|
366
376
|
// THREE.Color objects must be mutated via .set() rather than replaced
|
|
367
377
|
var existing = target[lastKey];
|
|
368
378
|
if (existing && existing.isColor && typeof value === 'string') {
|
|
@@ -321,7 +321,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
321
321
|
key: "_attachIODeviceModelsToPreview",
|
|
322
322
|
value: (function () {
|
|
323
323
|
var _attachIODeviceModelsToPreview2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(parentObject, componentData, modelPreloader) {
|
|
324
|
-
var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, _t3;
|
|
324
|
+
var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, _attachment$attachmen2, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, rot, deg2rad, _t3;
|
|
325
325
|
return _regenerator().w(function (_context3) {
|
|
326
326
|
while (1) switch (_context3.n) {
|
|
327
327
|
case 0:
|
|
@@ -396,6 +396,13 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
396
396
|
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
397
397
|
}
|
|
398
398
|
|
|
399
|
+
// Apply face-based rotation (stored in degrees, XYZ Euler order)
|
|
400
|
+
if ((_attachment$attachmen2 = attachment.attachmentPoint) !== null && _attachment$attachmen2 !== void 0 && _attachment$attachmen2.rotation) {
|
|
401
|
+
rot = attachment.attachmentPoint.rotation;
|
|
402
|
+
deg2rad = Math.PI / 180;
|
|
403
|
+
deviceModel.rotation.set((rot.x || 0) * deg2rad, (rot.y || 0) * deg2rad, (rot.z || 0) * deg2rad, 'XYZ');
|
|
404
|
+
}
|
|
405
|
+
|
|
399
406
|
// IO device models use their natural (1:1) scale — the stored
|
|
400
407
|
// attachmentPoint.scale value is for the connector marker sphere.
|
|
401
408
|
deviceModel.scale.setScalar(1);
|
|
@@ -23,7 +23,7 @@ function attachIODevicesToComponent(_x, _x2, _x3, _x4) {
|
|
|
23
23
|
}
|
|
24
24
|
function _attachIODevicesToComponent() {
|
|
25
25
|
_attachIODevicesToComponent = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(componentModel, componentData, modelPreloader, parentComponentId) {
|
|
26
|
-
var attachedDevices, _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, _t, _t2;
|
|
26
|
+
var attachedDevices, _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, _attachment$attachmen2, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, rot, deg2rad, _t, _t2;
|
|
27
27
|
return _regenerator().w(function (_context) {
|
|
28
28
|
while (1) switch (_context.n) {
|
|
29
29
|
case 0:
|
|
@@ -124,6 +124,13 @@ function _attachIODevicesToComponent() {
|
|
|
124
124
|
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// Apply face-based rotation (stored in degrees, XYZ Euler order)
|
|
128
|
+
if ((_attachment$attachmen2 = attachment.attachmentPoint) !== null && _attachment$attachmen2 !== void 0 && _attachment$attachmen2.rotation) {
|
|
129
|
+
rot = attachment.attachmentPoint.rotation;
|
|
130
|
+
deg2rad = Math.PI / 180;
|
|
131
|
+
deviceModel.rotation.set((rot.x || 0) * deg2rad, (rot.y || 0) * deg2rad, (rot.z || 0) * deg2rad, 'XYZ');
|
|
132
|
+
}
|
|
133
|
+
|
|
127
134
|
// IO device models are authored at the same real-world unit scale
|
|
128
135
|
// as the host component, so keep them at their natural (1:1) size.
|
|
129
136
|
// Note: attachmentPoint.scale is the connector marker sphere size,
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,25 @@
|
|
|
5
5
|
* organized by their functional categories.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// ─── Connector flow types ─────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
/** The flow direction of a connector port. */
|
|
11
|
+
export type FlowDirection = 'in' | 'out' | 'bi'
|
|
12
|
+
|
|
13
|
+
/** Connector descriptor returned by getAvailableConnectionsInfo(). */
|
|
14
|
+
export interface ConnectorInfo {
|
|
15
|
+
/** The connector's UUID as it appears in the scene JSON. */
|
|
16
|
+
id: string
|
|
17
|
+
/** Flow direction. Defaults to 'bi' for connectors that do not declare one. */
|
|
18
|
+
flow: FlowDirection
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Result of validateConnections(). */
|
|
22
|
+
export interface ConnectionValidationResult {
|
|
23
|
+
valid: Array<{ from: string; to: string }>
|
|
24
|
+
invalid: Array<{ connection: { from: string; to: string }; reason: string }>
|
|
25
|
+
}
|
|
26
|
+
|
|
8
27
|
// ─── I/O Device types ────────────────────────────────────────────────────────
|
|
9
28
|
|
|
10
29
|
export interface IoDeviceState {
|