@2112-lab/central-plant 0.3.25 → 0.3.27
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 +948 -137
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/core/centralPlantInternals.js +56 -14
- package/dist/cjs/src/core/sceneViewer.js +55 -2
- package/dist/cjs/src/managers/behaviors/IoAnimationManager.js +29 -2
- package/dist/cjs/src/managers/behaviors/IoOutlineManager.js +258 -0
- package/dist/cjs/src/managers/controls/transformControlsManager.js +319 -43
- package/dist/cjs/src/managers/scene/animationManager.js +9 -2
- package/dist/cjs/src/managers/scene/componentTooltipManager.js +198 -31
- package/dist/cjs/src/managers/scene/modelManager.js +17 -2
- package/dist/cjs/src/utils/boundingBoxUtils.js +38 -40
- package/dist/esm/src/core/centralPlant.js +1 -1
- package/dist/esm/src/core/centralPlantInternals.js +57 -15
- package/dist/esm/src/core/sceneViewer.js +55 -2
- package/dist/esm/src/managers/behaviors/IoAnimationManager.js +29 -2
- package/dist/esm/src/managers/behaviors/IoOutlineManager.js +234 -0
- package/dist/esm/src/managers/controls/transformControlsManager.js +319 -43
- package/dist/esm/src/managers/scene/animationManager.js +9 -2
- package/dist/esm/src/managers/scene/componentTooltipManager.js +199 -32
- package/dist/esm/src/managers/scene/modelManager.js +18 -3
- package/dist/esm/src/utils/boundingBoxUtils.js +39 -42
- package/package.json +1 -1
package/dist/bundle/index.js
CHANGED
|
@@ -3611,6 +3611,34 @@ function computeIODeviceBoundingBoxes(componentObject) {
|
|
|
3611
3611
|
* const helpers = createSelectionBoxHelpers(pumpModel, 0x00ff00)
|
|
3612
3612
|
* helpers.forEach(h => scene.add(h))
|
|
3613
3613
|
*/
|
|
3614
|
+
/**
|
|
3615
|
+
* Returns a filtered bounding box for `object`, using a cache stored on
|
|
3616
|
+
* `object.userData._filteredBBoxCache`. The cache key is the serialised
|
|
3617
|
+
* world-matrix elements string; if the object has moved the cache is
|
|
3618
|
+
* automatically invalidated and recomputed.
|
|
3619
|
+
*
|
|
3620
|
+
* This avoids the expensive full-traverse on every selection event for
|
|
3621
|
+
* large smart components with many child meshes.
|
|
3622
|
+
*
|
|
3623
|
+
* @param {THREE.Object3D} object
|
|
3624
|
+
* @param {string[]} excludeTypes
|
|
3625
|
+
* @returns {THREE.Box3}
|
|
3626
|
+
*/
|
|
3627
|
+
function computeFilteredBoundingBoxCached(object, excludeTypes) {
|
|
3628
|
+
object.updateMatrixWorld(true);
|
|
3629
|
+
var matrixKey = object.matrixWorld.elements.join(',');
|
|
3630
|
+
var cache = object.userData._filteredBBoxCache;
|
|
3631
|
+
if (cache && cache.matrixKey === matrixKey) {
|
|
3632
|
+
return new THREE__namespace.Box3(_construct(THREE__namespace.Vector3, _toConsumableArray(cache.min)), _construct(THREE__namespace.Vector3, _toConsumableArray(cache.max)));
|
|
3633
|
+
}
|
|
3634
|
+
var box = computeFilteredBoundingBox(object, excludeTypes);
|
|
3635
|
+
object.userData._filteredBBoxCache = {
|
|
3636
|
+
matrixKey: matrixKey,
|
|
3637
|
+
min: box.min.toArray(),
|
|
3638
|
+
max: box.max.toArray()
|
|
3639
|
+
};
|
|
3640
|
+
return box;
|
|
3641
|
+
}
|
|
3614
3642
|
function createSelectionBoxHelpers(object) {
|
|
3615
3643
|
var _object$children;
|
|
3616
3644
|
var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0x00ff00;
|
|
@@ -3624,7 +3652,7 @@ function createSelectionBoxHelpers(object) {
|
|
|
3624
3652
|
});
|
|
3625
3653
|
if (hasIODevices) {
|
|
3626
3654
|
// 1. Create filtered helper for the component body
|
|
3627
|
-
var filteredBox =
|
|
3655
|
+
var filteredBox = computeFilteredBoundingBoxCached(object, excludeTypes);
|
|
3628
3656
|
var componentHelper = _createBoxHelperFromBox3(filteredBox, color);
|
|
3629
3657
|
componentHelper.isHelper = true;
|
|
3630
3658
|
componentHelper.userData = {
|
|
@@ -3634,33 +3662,6 @@ function createSelectionBoxHelpers(object) {
|
|
|
3634
3662
|
excludeTypes: excludeTypes
|
|
3635
3663
|
};
|
|
3636
3664
|
helpers.push(componentHelper);
|
|
3637
|
-
|
|
3638
|
-
// 2. Create individual helpers for each io-device
|
|
3639
|
-
var _iterator2 = _createForOfIteratorHelper(object.children),
|
|
3640
|
-
_step2;
|
|
3641
|
-
try {
|
|
3642
|
-
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
3643
|
-
var _child$userData3;
|
|
3644
|
-
var child = _step2.value;
|
|
3645
|
-
if (((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) !== 'io-device') continue;
|
|
3646
|
-
var deviceBox = new THREE__namespace.Box3().setFromObject(child);
|
|
3647
|
-
if (deviceBox.isEmpty()) continue;
|
|
3648
|
-
var deviceHelper = _createBoxHelperFromBox3(deviceBox, color);
|
|
3649
|
-
deviceHelper.isHelper = true;
|
|
3650
|
-
deviceHelper.userData = {
|
|
3651
|
-
isBoundingBox: true,
|
|
3652
|
-
sourceObjectUuid: child.uuid,
|
|
3653
|
-
isFiltered: false,
|
|
3654
|
-
isIODevice: true,
|
|
3655
|
-
parentComponentUuid: object.uuid
|
|
3656
|
-
};
|
|
3657
|
-
helpers.push(deviceHelper);
|
|
3658
|
-
}
|
|
3659
|
-
} catch (err) {
|
|
3660
|
-
_iterator2.e(err);
|
|
3661
|
-
} finally {
|
|
3662
|
-
_iterator2.f();
|
|
3663
|
-
}
|
|
3664
3665
|
} else {
|
|
3665
3666
|
// Standard BoxHelper for non-smart objects
|
|
3666
3667
|
var boxHelper = new THREE__namespace.BoxHelper(object, color);
|
|
@@ -3684,11 +3685,11 @@ function createSelectionBoxHelpers(object) {
|
|
|
3684
3685
|
* @param {THREE.Scene} scene - The scene (for finding objects by uuid)
|
|
3685
3686
|
*/
|
|
3686
3687
|
function updateSelectionBoxHelpers(helpers, selectedObjects, scene) {
|
|
3687
|
-
var
|
|
3688
|
-
|
|
3688
|
+
var _iterator2 = _createForOfIteratorHelper(helpers),
|
|
3689
|
+
_step2;
|
|
3689
3690
|
try {
|
|
3690
3691
|
var _loop = function _loop() {
|
|
3691
|
-
var helper =
|
|
3692
|
+
var helper = _step2.value;
|
|
3692
3693
|
var _helper$userData = helper.userData,
|
|
3693
3694
|
sourceObjectUuid = _helper$userData.sourceObjectUuid,
|
|
3694
3695
|
isFiltered = _helper$userData.isFiltered,
|
|
@@ -3711,25 +3712,21 @@ function updateSelectionBoxHelpers(helpers, selectedObjects, scene) {
|
|
|
3711
3712
|
if (!sourceObject) return 1; // continue
|
|
3712
3713
|
sourceObject.updateMatrixWorld(true);
|
|
3713
3714
|
if (isFiltered && excludeTypes) {
|
|
3714
|
-
// Recompute filtered bbox
|
|
3715
|
-
var box =
|
|
3715
|
+
// Recompute filtered bbox (uses cache when the object hasn't moved)
|
|
3716
|
+
var box = computeFilteredBoundingBoxCached(sourceObject, excludeTypes);
|
|
3716
3717
|
_updateBoxHelperPositions(helper, box);
|
|
3717
|
-
} else if (isIODevice) {
|
|
3718
|
-
// Recompute io-device bbox
|
|
3719
|
-
var _box = new THREE__namespace.Box3().setFromObject(sourceObject);
|
|
3720
|
-
_updateBoxHelperPositions(helper, _box);
|
|
3721
3718
|
} else if (helper.update) {
|
|
3722
3719
|
// Standard BoxHelper — use built-in update
|
|
3723
3720
|
helper.update();
|
|
3724
3721
|
}
|
|
3725
3722
|
};
|
|
3726
|
-
for (
|
|
3723
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
3727
3724
|
if (_loop()) continue;
|
|
3728
3725
|
}
|
|
3729
3726
|
} catch (err) {
|
|
3730
|
-
|
|
3727
|
+
_iterator2.e(err);
|
|
3731
3728
|
} finally {
|
|
3732
|
-
|
|
3729
|
+
_iterator2.f();
|
|
3733
3730
|
}
|
|
3734
3731
|
}
|
|
3735
3732
|
|
|
@@ -3823,8 +3820,17 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
3823
3820
|
onModeChange: null,
|
|
3824
3821
|
onObjectRemoved: null,
|
|
3825
3822
|
onSelectionChanged: null,
|
|
3826
|
-
onIODeviceClick: null
|
|
3823
|
+
onIODeviceClick: null,
|
|
3824
|
+
onIODeviceDrag: null,
|
|
3825
|
+
onIODeviceDragEnd: null
|
|
3827
3826
|
};
|
|
3827
|
+
|
|
3828
|
+
// IO device drag tracking state
|
|
3829
|
+
this._ioDragMesh = null;
|
|
3830
|
+
this._ioDragStartX = 0;
|
|
3831
|
+
this._ioDragStartY = 0;
|
|
3832
|
+
this._ioDragMoved = false;
|
|
3833
|
+
this._suppressNextClick = false;
|
|
3828
3834
|
this.init();
|
|
3829
3835
|
}
|
|
3830
3836
|
|
|
@@ -3904,6 +3910,12 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
3904
3910
|
if (callbacks.onIODeviceClick) {
|
|
3905
3911
|
this.callbacks.onIODeviceClick = callbacks.onIODeviceClick;
|
|
3906
3912
|
}
|
|
3913
|
+
if (callbacks.onIODeviceDrag) {
|
|
3914
|
+
this.callbacks.onIODeviceDrag = callbacks.onIODeviceDrag;
|
|
3915
|
+
}
|
|
3916
|
+
if (callbacks.onIODeviceDragEnd) {
|
|
3917
|
+
this.callbacks.onIODeviceDragEnd = callbacks.onIODeviceDragEnd;
|
|
3918
|
+
}
|
|
3907
3919
|
console.log('🔗 Transform controls callbacks registered');
|
|
3908
3920
|
}
|
|
3909
3921
|
/**
|
|
@@ -4110,6 +4122,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4110
4122
|
value: function setupKeyboardControls() {
|
|
4111
4123
|
var _this3 = this;
|
|
4112
4124
|
this.eventHandlers.keydown = function (event) {
|
|
4125
|
+
// Restore perspective camera when pressing Escape from ortho face view
|
|
4126
|
+
if (event.code === 'Escape') {
|
|
4127
|
+
_this3._restorePerspectiveCamera();
|
|
4128
|
+
}
|
|
4129
|
+
|
|
4113
4130
|
// Only handle keys when transform controls are active
|
|
4114
4131
|
if (!_this3.transformControls.enabled || _this3.transformState.isTransforming) {
|
|
4115
4132
|
return;
|
|
@@ -4144,9 +4161,82 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4144
4161
|
var raycaster = new THREE__namespace.Raycaster();
|
|
4145
4162
|
var mouse = new THREE__namespace.Vector2();
|
|
4146
4163
|
|
|
4147
|
-
//
|
|
4164
|
+
// ── IO device drag ────────────────────────────────────────────────────
|
|
4165
|
+
// Detect pointerdown on an IO device mesh and convert a drag gesture into
|
|
4166
|
+
// state changes. Up/right = positive direction, down/left = negative.
|
|
4167
|
+
this.eventHandlers.pointerdown = function (event) {
|
|
4168
|
+
if (_this4.transformState.isTransforming) return;
|
|
4169
|
+
if (!_this4.callbacks.onIODeviceDrag) return;
|
|
4170
|
+
_this4._calculateMousePosition(event, mouse);
|
|
4171
|
+
raycaster.setFromCamera(mouse, _this4.camera);
|
|
4172
|
+
var allIntersects = raycaster.intersectObjects(_this4.scene.children, true);
|
|
4173
|
+
var ioDeviceObject = null;
|
|
4174
|
+
var _iterator = _createForOfIteratorHelper(allIntersects),
|
|
4175
|
+
_step;
|
|
4176
|
+
try {
|
|
4177
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
4178
|
+
var hit = _step.value;
|
|
4179
|
+
var obj = hit.object;
|
|
4180
|
+
while (obj) {
|
|
4181
|
+
var _obj$userData;
|
|
4182
|
+
if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'io-device') {
|
|
4183
|
+
ioDeviceObject = obj;
|
|
4184
|
+
break;
|
|
4185
|
+
}
|
|
4186
|
+
obj = obj.parent;
|
|
4187
|
+
}
|
|
4188
|
+
if (ioDeviceObject) break;
|
|
4189
|
+
}
|
|
4190
|
+
} catch (err) {
|
|
4191
|
+
_iterator.e(err);
|
|
4192
|
+
} finally {
|
|
4193
|
+
_iterator.f();
|
|
4194
|
+
}
|
|
4195
|
+
if (!ioDeviceObject) return;
|
|
4196
|
+
|
|
4197
|
+
// Begin session
|
|
4198
|
+
_this4._ioDragMesh = ioDeviceObject;
|
|
4199
|
+
_this4._ioDragStartX = event.clientX;
|
|
4200
|
+
_this4._ioDragStartY = event.clientY;
|
|
4201
|
+
_this4._ioDragMoved = false;
|
|
4202
|
+
if (_this4.orbitControls) _this4.orbitControls.enabled = false;
|
|
4203
|
+
_this4.callbacks.onIODeviceDrag(ioDeviceObject, 0, true);
|
|
4204
|
+
var onMove = function onMove(e) {
|
|
4205
|
+
var dx = e.clientX - _this4._ioDragStartX;
|
|
4206
|
+
var dy = e.clientY - _this4._ioDragStartY;
|
|
4207
|
+
if (Math.abs(dx) > 4 || Math.abs(dy) > 4) _this4._ioDragMoved = true;
|
|
4208
|
+
// Up (−screenY) and right (+screenX) are positive
|
|
4209
|
+
var signedDelta = _this4._ioDragStartY - e.clientY + (e.clientX - _this4._ioDragStartX);
|
|
4210
|
+
_this4.callbacks.onIODeviceDrag(_this4._ioDragMesh, signedDelta, false);
|
|
4211
|
+
};
|
|
4212
|
+
var _onUp = function onUp() {
|
|
4213
|
+
window.removeEventListener('pointermove', onMove);
|
|
4214
|
+
window.removeEventListener('pointerup', _onUp);
|
|
4215
|
+
if (_this4.orbitControls) _this4.orbitControls.enabled = true;
|
|
4216
|
+
if (_this4._ioDragMoved) {
|
|
4217
|
+
// Suppress the click event that will fire after this pointerup
|
|
4218
|
+
_this4._suppressNextClick = true;
|
|
4219
|
+
}
|
|
4220
|
+
if (_this4.callbacks.onIODeviceDragEnd) {
|
|
4221
|
+
_this4.callbacks.onIODeviceDragEnd(_this4._ioDragMesh);
|
|
4222
|
+
}
|
|
4223
|
+
_this4._ioDragMesh = null;
|
|
4224
|
+
};
|
|
4225
|
+
window.addEventListener('pointermove', onMove);
|
|
4226
|
+
window.addEventListener('pointerup', _onUp);
|
|
4227
|
+
};
|
|
4228
|
+
this.renderer.domElement.addEventListener('pointerdown', this.eventHandlers.pointerdown);
|
|
4229
|
+
|
|
4230
|
+
// Click handler: left-click selects the object (bounding box + transform controls).
|
|
4231
|
+
// Right-click on a component shows the tooltip.
|
|
4148
4232
|
this.eventHandlers.click = function (event) {
|
|
4149
4233
|
var _targetObject$userDat;
|
|
4234
|
+
// Suppress click that follows an IO device drag
|
|
4235
|
+
if (_this4._suppressNextClick) {
|
|
4236
|
+
_this4._suppressNextClick = false;
|
|
4237
|
+
return;
|
|
4238
|
+
}
|
|
4239
|
+
|
|
4150
4240
|
// Skip if currently transforming
|
|
4151
4241
|
if (_this4.transformState.isTransforming) {
|
|
4152
4242
|
return;
|
|
@@ -4159,15 +4249,15 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4159
4249
|
// Check for direct io-device mesh click (before bounding box selection)
|
|
4160
4250
|
if (_this4.callbacks.onIODeviceClick) {
|
|
4161
4251
|
var allIntersects = raycaster.intersectObjects(_this4.scene.children, true);
|
|
4162
|
-
var
|
|
4163
|
-
|
|
4252
|
+
var _iterator2 = _createForOfIteratorHelper(allIntersects),
|
|
4253
|
+
_step2;
|
|
4164
4254
|
try {
|
|
4165
|
-
for (
|
|
4166
|
-
var hit =
|
|
4255
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
4256
|
+
var hit = _step2.value;
|
|
4167
4257
|
var obj = hit.object;
|
|
4168
4258
|
while (obj) {
|
|
4169
|
-
var _obj$
|
|
4170
|
-
if (((_obj$
|
|
4259
|
+
var _obj$userData2;
|
|
4260
|
+
if (((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.objectType) === 'io-device') {
|
|
4171
4261
|
_this4.callbacks.onIODeviceClick(obj);
|
|
4172
4262
|
return;
|
|
4173
4263
|
}
|
|
@@ -4175,9 +4265,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4175
4265
|
}
|
|
4176
4266
|
}
|
|
4177
4267
|
} catch (err) {
|
|
4178
|
-
|
|
4268
|
+
_iterator2.e(err);
|
|
4179
4269
|
} finally {
|
|
4180
|
-
|
|
4270
|
+
_iterator2.f();
|
|
4181
4271
|
}
|
|
4182
4272
|
}
|
|
4183
4273
|
|
|
@@ -4212,23 +4302,194 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4212
4302
|
return;
|
|
4213
4303
|
}
|
|
4214
4304
|
|
|
4215
|
-
//
|
|
4216
|
-
|
|
4217
|
-
if (isAlreadySelected) {
|
|
4218
|
-
// Second click on already-selected object: Full selection including tooltips
|
|
4219
|
-
_this4.selectObject(targetObject);
|
|
4220
|
-
} else {
|
|
4221
|
-
// First click on a new object: Transform controls and bounding box only
|
|
4222
|
-
// Always deselect first (this clears tooltips via the callback)
|
|
4305
|
+
// Left-click: select for transform only (bounding box, no tooltip)
|
|
4306
|
+
if (!_this4.selectedObjects.includes(targetObject)) {
|
|
4223
4307
|
_this4.deselectObject();
|
|
4224
|
-
|
|
4225
|
-
// Then select the new object if there is one (this shows transform controls and bounding box)
|
|
4226
|
-
if (targetObject) {
|
|
4227
|
-
_this4.selectObjectForTransformOnly(targetObject);
|
|
4228
|
-
}
|
|
4229
4308
|
}
|
|
4309
|
+
_this4.selectObjectForTransformOnly(targetObject);
|
|
4230
4310
|
};
|
|
4231
4311
|
this.renderer.domElement.addEventListener('click', this.eventHandlers.click);
|
|
4312
|
+
|
|
4313
|
+
// Right-click handler: show tooltip for the clicked component.
|
|
4314
|
+
this.eventHandlers.contextmenu = function (event) {
|
|
4315
|
+
var _targetObject$userDat2;
|
|
4316
|
+
event.preventDefault();
|
|
4317
|
+
if (_this4.transformState.isTransforming) return;
|
|
4318
|
+
_this4._calculateMousePosition(event, mouse);
|
|
4319
|
+
raycaster.setFromCamera(mouse, _this4.camera);
|
|
4320
|
+
var targetObject = _this4._findTargetObject(raycaster, objectFilter);
|
|
4321
|
+
if (!targetObject) return;
|
|
4322
|
+
var objectType = (_targetObject$userDat2 = targetObject.userData) === null || _targetObject$userDat2 === void 0 ? void 0 : _targetObject$userDat2.objectType;
|
|
4323
|
+
if (objectType !== 'component' && objectType !== 'gateway' && objectType !== 'segment') return;
|
|
4324
|
+
|
|
4325
|
+
// Ensure the object is selected, then show the full tooltip.
|
|
4326
|
+
if (!_this4.selectedObjects.includes(targetObject)) {
|
|
4327
|
+
_this4.deselectObject();
|
|
4328
|
+
_this4.selectObjectForTransformOnly(targetObject);
|
|
4329
|
+
}
|
|
4330
|
+
_this4.selectObject(targetObject);
|
|
4331
|
+
};
|
|
4332
|
+
this.renderer.domElement.addEventListener('contextmenu', this.eventHandlers.contextmenu);
|
|
4333
|
+
|
|
4334
|
+
// Double-click handler: switch to orthographic camera fixed to the clicked face.
|
|
4335
|
+
// Press Escape to restore the perspective camera.
|
|
4336
|
+
this.eventHandlers.dblclick = function (event) {
|
|
4337
|
+
if (_this4.transformState.isTransforming) return;
|
|
4338
|
+
var sv = _this4.sceneViewer;
|
|
4339
|
+
if (!sv) return;
|
|
4340
|
+
_this4._calculateMousePosition(event, mouse);
|
|
4341
|
+
raycaster.setFromCamera(_this4.camera, _this4.camera); // ensure raycaster uses current camera
|
|
4342
|
+
raycaster.setFromCamera(mouse, _this4.camera);
|
|
4343
|
+
|
|
4344
|
+
// Raycast directly against scene meshes to obtain the face normal
|
|
4345
|
+
var allHits = raycaster.intersectObjects(_this4.scene.children, true).filter(function (h) {
|
|
4346
|
+
var _h$object$userData, _h$object$userData2;
|
|
4347
|
+
return !((_h$object$userData = h.object.userData) !== null && _h$object$userData !== void 0 && _h$object$userData.isTransformControls) && !((_h$object$userData2 = h.object.userData) !== null && _h$object$userData2 !== void 0 && _h$object$userData2.isBoundingBox);
|
|
4348
|
+
});
|
|
4349
|
+
if (!allHits.length || !allHits[0].face) return;
|
|
4350
|
+
var hit = allHits[0];
|
|
4351
|
+
|
|
4352
|
+
// Walk up to find the component root
|
|
4353
|
+
var componentObj = hit.object;
|
|
4354
|
+
while (componentObj) {
|
|
4355
|
+
var _componentObj$userDat;
|
|
4356
|
+
if (((_componentObj$userDat = componentObj.userData) === null || _componentObj$userDat === void 0 ? void 0 : _componentObj$userDat.objectType) === 'component') break;
|
|
4357
|
+
componentObj = componentObj.parent;
|
|
4358
|
+
}
|
|
4359
|
+
if (!componentObj) return;
|
|
4360
|
+
|
|
4361
|
+
// Transform face normal from local object space to world space
|
|
4362
|
+
var normalMatrix = new THREE__namespace.Matrix3().getNormalMatrix(hit.object.matrixWorld);
|
|
4363
|
+
var worldNormal = hit.face.normal.clone().applyMatrix3(normalMatrix).normalize();
|
|
4364
|
+
|
|
4365
|
+
// Snap to the closest cardinal axis (Z-up: ±X, ±Y, ±Z)
|
|
4366
|
+
var cardinals = [new THREE__namespace.Vector3(1, 0, 0), new THREE__namespace.Vector3(-1, 0, 0), new THREE__namespace.Vector3(0, 1, 0), new THREE__namespace.Vector3(0, -1, 0), new THREE__namespace.Vector3(0, 0, 1), new THREE__namespace.Vector3(0, 0, -1)];
|
|
4367
|
+
var faceDir = cardinals.reduce(function (best, c) {
|
|
4368
|
+
return c.dot(worldNormal) > best.dot(worldNormal) ? c : best;
|
|
4369
|
+
});
|
|
4370
|
+
|
|
4371
|
+
// Bounding box of the component
|
|
4372
|
+
var bbox = new THREE__namespace.Box3().setFromObject(componentObj);
|
|
4373
|
+
var center = bbox.getCenter(new THREE__namespace.Vector3());
|
|
4374
|
+
var size = bbox.getSize(new THREE__namespace.Vector3());
|
|
4375
|
+
|
|
4376
|
+
// Ortho half-extents: axes perpendicular to the face direction
|
|
4377
|
+
var isXFace = Math.abs(faceDir.x) > 0.5;
|
|
4378
|
+
var isYFace = Math.abs(faceDir.y) > 0.5;
|
|
4379
|
+
var halfW, halfH;
|
|
4380
|
+
if (isXFace) {
|
|
4381
|
+
halfW = size.y / 2;
|
|
4382
|
+
halfH = size.z / 2;
|
|
4383
|
+
} else if (isYFace) {
|
|
4384
|
+
halfW = size.x / 2;
|
|
4385
|
+
halfH = size.z / 2;
|
|
4386
|
+
} else {
|
|
4387
|
+
halfW = size.x / 2;
|
|
4388
|
+
halfH = size.y / 2;
|
|
4389
|
+
}
|
|
4390
|
+
var padding = 1.6;
|
|
4391
|
+
var domEl = sv.renderer.domElement;
|
|
4392
|
+
var aspect = domEl.clientWidth / (domEl.clientHeight || 1);
|
|
4393
|
+
|
|
4394
|
+
// Frustum must satisfy both:
|
|
4395
|
+
// frustumHalfW >= halfW * padding (object fits horizontally)
|
|
4396
|
+
// frustumHalfH >= halfH * padding (object fits vertically)
|
|
4397
|
+
// frustumHalfW / frustumHalfH == aspect (no squishing)
|
|
4398
|
+
var minHalfH = halfH * padding;
|
|
4399
|
+
var minHalfW = halfW * padding;
|
|
4400
|
+
var frustumHalfH = Math.max(minHalfH, minHalfW / aspect);
|
|
4401
|
+
var frustumHalfW = frustumHalfH * aspect;
|
|
4402
|
+
var isZFace = Math.abs(faceDir.z) > 0.5;
|
|
4403
|
+
var upVec = isZFace ? new THREE__namespace.Vector3(0, 1, 0) : new THREE__namespace.Vector3(0, 0, 1);
|
|
4404
|
+
|
|
4405
|
+
// Store the perspective camera snapshot on first entry
|
|
4406
|
+
if (!sv._perspCameraSnapshot) {
|
|
4407
|
+
var _sv$controls$target$c, _sv$controls, _sv$controls2, _sv$controls3, _sv$controls4;
|
|
4408
|
+
sv._perspCameraSnapshot = {
|
|
4409
|
+
camera: sv.camera,
|
|
4410
|
+
controlsTarget: (_sv$controls$target$c = (_sv$controls = sv.controls) === null || _sv$controls === void 0 || (_sv$controls = _sv$controls.target) === null || _sv$controls === void 0 ? void 0 : _sv$controls.clone()) !== null && _sv$controls$target$c !== void 0 ? _sv$controls$target$c : new THREE__namespace.Vector3(),
|
|
4411
|
+
controlsMinDist: (_sv$controls2 = sv.controls) === null || _sv$controls2 === void 0 ? void 0 : _sv$controls2.minDistance,
|
|
4412
|
+
controlsMaxDist: (_sv$controls3 = sv.controls) === null || _sv$controls3 === void 0 ? void 0 : _sv$controls3.maxDistance,
|
|
4413
|
+
controlsMaxPolar: (_sv$controls4 = sv.controls) === null || _sv$controls4 === void 0 ? void 0 : _sv$controls4.maxPolarAngle
|
|
4414
|
+
};
|
|
4415
|
+
}
|
|
4416
|
+
|
|
4417
|
+
// Build the orthographic camera
|
|
4418
|
+
var ortho = new THREE__namespace.OrthographicCamera(-frustumHalfW, frustumHalfW, frustumHalfH, -frustumHalfH, 0.01, 1000);
|
|
4419
|
+
ortho.up.copy(upVec);
|
|
4420
|
+
var dist = Math.max(size.x, size.y, size.z) * 3;
|
|
4421
|
+
ortho.position.copy(center).addScaledVector(faceDir, dist);
|
|
4422
|
+
ortho.lookAt(center);
|
|
4423
|
+
// Store half-extents for resize updates (pre-aspect values so resize can recompute)
|
|
4424
|
+
ortho.userData._orthoHalfExtents = {
|
|
4425
|
+
halfW: halfW * padding,
|
|
4426
|
+
halfH: halfH * padding
|
|
4427
|
+
};
|
|
4428
|
+
ortho.updateProjectionMatrix();
|
|
4429
|
+
sv.camera = ortho;
|
|
4430
|
+
_this4.camera = ortho;
|
|
4431
|
+
if (sv.controls) {
|
|
4432
|
+
sv.controls.object = ortho;
|
|
4433
|
+
sv.controls.target.copy(center);
|
|
4434
|
+
sv.controls.minDistance = 0.1;
|
|
4435
|
+
sv.controls.maxDistance = 500;
|
|
4436
|
+
sv.controls.maxPolarAngle = Math.PI;
|
|
4437
|
+
sv.controls.update();
|
|
4438
|
+
|
|
4439
|
+
// Exit ortho mode when the camera actually moves (orbit/pan/zoom).
|
|
4440
|
+
// Using 'change' instead of 'start' so a simple click (e.g. io-device
|
|
4441
|
+
// toggle) never triggers the exit — only real camera movement does.
|
|
4442
|
+
// Skip the first 'change' that fires from controls.update() below.
|
|
4443
|
+
var _skipChanges = 1;
|
|
4444
|
+
var _onOrbitChange = function onOrbitChange() {
|
|
4445
|
+
if (_skipChanges-- > 0) return;
|
|
4446
|
+
sv.controls.removeEventListener('change', _onOrbitChange);
|
|
4447
|
+
_this4._orthoOrbitStartListener = null;
|
|
4448
|
+
_this4._restorePerspectiveCamera();
|
|
4449
|
+
};
|
|
4450
|
+
sv.controls.addEventListener('change', _onOrbitChange);
|
|
4451
|
+
_this4._orthoOrbitStartListener = {
|
|
4452
|
+
controls: sv.controls,
|
|
4453
|
+
fn: _onOrbitChange
|
|
4454
|
+
};
|
|
4455
|
+
}
|
|
4456
|
+
console.log('📐 Switched to orthographic face view:', faceDir);
|
|
4457
|
+
};
|
|
4458
|
+
this.renderer.domElement.addEventListener('dblclick', this.eventHandlers.dblclick);
|
|
4459
|
+
}
|
|
4460
|
+
|
|
4461
|
+
/**
|
|
4462
|
+
* Restore the perspective camera after an orthographic face view.
|
|
4463
|
+
* Safe to call when not in ortho mode (no-op).
|
|
4464
|
+
* @private
|
|
4465
|
+
*/
|
|
4466
|
+
}, {
|
|
4467
|
+
key: "_restorePerspectiveCamera",
|
|
4468
|
+
value: function _restorePerspectiveCamera() {
|
|
4469
|
+
var sv = this.sceneViewer;
|
|
4470
|
+
if (!(sv !== null && sv !== void 0 && sv._perspCameraSnapshot)) return;
|
|
4471
|
+
|
|
4472
|
+
// Clean up any pending orbit-change listener
|
|
4473
|
+
if (this._orthoOrbitStartListener) {
|
|
4474
|
+
var _this$_orthoOrbitStar = this._orthoOrbitStartListener,
|
|
4475
|
+
controls = _this$_orthoOrbitStar.controls,
|
|
4476
|
+
fn = _this$_orthoOrbitStar.fn;
|
|
4477
|
+
controls.removeEventListener('change', fn);
|
|
4478
|
+
this._orthoOrbitStartListener = null;
|
|
4479
|
+
}
|
|
4480
|
+
var snap = sv._perspCameraSnapshot;
|
|
4481
|
+
sv.camera = snap.camera;
|
|
4482
|
+
this.camera = snap.camera;
|
|
4483
|
+
if (sv.controls) {
|
|
4484
|
+
sv.controls.object = snap.camera;
|
|
4485
|
+
sv.controls.target.copy(snap.controlsTarget);
|
|
4486
|
+
if (snap.controlsMinDist != null) sv.controls.minDistance = snap.controlsMinDist;
|
|
4487
|
+
if (snap.controlsMaxDist != null) sv.controls.maxDistance = snap.controlsMaxDist;
|
|
4488
|
+
if (snap.controlsMaxPolar != null) sv.controls.maxPolarAngle = snap.controlsMaxPolar;
|
|
4489
|
+
sv.controls.update();
|
|
4490
|
+
}
|
|
4491
|
+
sv._perspCameraSnapshot = null;
|
|
4492
|
+
console.log('📐 Restored perspective camera from ortho face view');
|
|
4232
4493
|
}
|
|
4233
4494
|
|
|
4234
4495
|
/**
|
|
@@ -4378,11 +4639,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4378
4639
|
var isNewSegmentHorizontal = this._isSegmentHorizontal(segment);
|
|
4379
4640
|
|
|
4380
4641
|
// Check if all existing segments have the same orientation
|
|
4381
|
-
var
|
|
4382
|
-
|
|
4642
|
+
var _iterator3 = _createForOfIteratorHelper(existingSegments),
|
|
4643
|
+
_step3;
|
|
4383
4644
|
try {
|
|
4384
|
-
for (
|
|
4385
|
-
var existingSegment =
|
|
4645
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
4646
|
+
var existingSegment = _step3.value;
|
|
4386
4647
|
var isExistingHorizontal = this._isSegmentHorizontal(existingSegment);
|
|
4387
4648
|
|
|
4388
4649
|
// Disallow mixing horizontal and vertical
|
|
@@ -4391,9 +4652,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4391
4652
|
}
|
|
4392
4653
|
}
|
|
4393
4654
|
} catch (err) {
|
|
4394
|
-
|
|
4655
|
+
_iterator3.e(err);
|
|
4395
4656
|
} finally {
|
|
4396
|
-
|
|
4657
|
+
_iterator3.f();
|
|
4397
4658
|
}
|
|
4398
4659
|
return true;
|
|
4399
4660
|
}
|
|
@@ -4845,12 +5106,12 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4845
5106
|
value: function _applyDeltaToBoundingBoxHelpers() {
|
|
4846
5107
|
if (!this._dragStartGroupPosition || this.boundingBoxHelpers.length === 0) return;
|
|
4847
5108
|
var delta = this.multiSelectionGroup.position.clone().sub(this._dragStartGroupPosition);
|
|
4848
|
-
var
|
|
4849
|
-
|
|
5109
|
+
var _iterator4 = _createForOfIteratorHelper(this.boundingBoxHelpers),
|
|
5110
|
+
_step4;
|
|
4850
5111
|
try {
|
|
4851
|
-
for (
|
|
5112
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
4852
5113
|
var _helper$geometry2;
|
|
4853
|
-
var helper =
|
|
5114
|
+
var helper = _step4.value;
|
|
4854
5115
|
var startPositions = helper.userData._dragStartPositions;
|
|
4855
5116
|
var posAttr = (_helper$geometry2 = helper.geometry) === null || _helper$geometry2 === void 0 || (_helper$geometry2 = _helper$geometry2.attributes) === null || _helper$geometry2 === void 0 ? void 0 : _helper$geometry2.position;
|
|
4856
5117
|
if (!startPositions || !posAttr) continue;
|
|
@@ -4864,9 +5125,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4864
5125
|
posAttr.needsUpdate = true;
|
|
4865
5126
|
}
|
|
4866
5127
|
} catch (err) {
|
|
4867
|
-
|
|
5128
|
+
_iterator4.e(err);
|
|
4868
5129
|
} finally {
|
|
4869
|
-
|
|
5130
|
+
_iterator4.f();
|
|
4870
5131
|
}
|
|
4871
5132
|
}
|
|
4872
5133
|
|
|
@@ -5244,11 +5505,11 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
5244
5505
|
var objectFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
5245
5506
|
var objectsWithBounds = this.getSelectableObjectsWithBounds(objectFilter);
|
|
5246
5507
|
var intersections = [];
|
|
5247
|
-
var
|
|
5248
|
-
|
|
5508
|
+
var _iterator5 = _createForOfIteratorHelper(objectsWithBounds),
|
|
5509
|
+
_step5;
|
|
5249
5510
|
try {
|
|
5250
|
-
for (
|
|
5251
|
-
var item =
|
|
5511
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
5512
|
+
var item = _step5.value;
|
|
5252
5513
|
var object = item.object,
|
|
5253
5514
|
boundingBox = item.boundingBox;
|
|
5254
5515
|
|
|
@@ -5268,9 +5529,9 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
5268
5529
|
|
|
5269
5530
|
// Sort by distance (closest first)
|
|
5270
5531
|
} catch (err) {
|
|
5271
|
-
|
|
5532
|
+
_iterator5.e(err);
|
|
5272
5533
|
} finally {
|
|
5273
|
-
|
|
5534
|
+
_iterator5.f();
|
|
5274
5535
|
}
|
|
5275
5536
|
intersections.sort(function (a, b) {
|
|
5276
5537
|
return a.distance - b.distance;
|
|
@@ -5656,8 +5917,8 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
5656
5917
|
key: "_updateSegmentReference",
|
|
5657
5918
|
value: function _updateSegmentReference(oldSegment, newSegment, index) {
|
|
5658
5919
|
var selectedIndex = this.selectedObjects.findIndex(function (obj) {
|
|
5659
|
-
var _obj$
|
|
5660
|
-
return obj.uuid === oldSegment.uuid || ((_obj$
|
|
5920
|
+
var _obj$userData3;
|
|
5921
|
+
return obj.uuid === oldSegment.uuid || ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.originalUuid) === oldSegment.uuid;
|
|
5661
5922
|
});
|
|
5662
5923
|
if (selectedIndex !== -1 && newSegment) {
|
|
5663
5924
|
// Clear bounding box cache
|
|
@@ -6044,9 +6305,21 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
6044
6305
|
if (this.eventHandlers.keydown) {
|
|
6045
6306
|
window.removeEventListener('keydown', this.eventHandlers.keydown);
|
|
6046
6307
|
}
|
|
6308
|
+
if (this.eventHandlers.pointerdown) {
|
|
6309
|
+
this.renderer.domElement.removeEventListener('pointerdown', this.eventHandlers.pointerdown);
|
|
6310
|
+
}
|
|
6047
6311
|
if (this.eventHandlers.click) {
|
|
6048
6312
|
this.renderer.domElement.removeEventListener('click', this.eventHandlers.click);
|
|
6049
6313
|
}
|
|
6314
|
+
if (this.eventHandlers.contextmenu) {
|
|
6315
|
+
this.renderer.domElement.removeEventListener('contextmenu', this.eventHandlers.contextmenu);
|
|
6316
|
+
}
|
|
6317
|
+
if (this.eventHandlers.dblclick) {
|
|
6318
|
+
this.renderer.domElement.removeEventListener('dblclick', this.eventHandlers.dblclick);
|
|
6319
|
+
}
|
|
6320
|
+
|
|
6321
|
+
// Restore perspective camera if disposed while in ortho face view
|
|
6322
|
+
this._restorePerspectiveCamera();
|
|
6050
6323
|
|
|
6051
6324
|
// Remove sceneViewer event listener
|
|
6052
6325
|
if (this._objectTransformedListener && this.sceneViewer && typeof this.sceneViewer.off === 'function') {
|
|
@@ -31463,7 +31736,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
31463
31736
|
key: "loadLibraryModel",
|
|
31464
31737
|
value: function () {
|
|
31465
31738
|
var _loadLibraryModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(targetMesh, jsonEntry, componentData) {
|
|
31466
|
-
var component, _jsonEntry$userData, _jsonEntry$userData2, _jsonEntry$userData3, originalProps, connectorChildren, gltfScene, libraryModel, _this$sceneViewer, ioAnimMgr, _loop, _i, _Object$entries, _jsonEntry$userData4, _t;
|
|
31739
|
+
var component, _jsonEntry$userData, _jsonEntry$userData2, _jsonEntry$userData3, originalProps, connectorChildren, gltfScene, libraryModel, _this$sceneViewer, ioAnimMgr, _loop, _i, _Object$entries, warmFn, _jsonEntry$userData4, _t;
|
|
31467
31740
|
return _regenerator().w(function (_context2) {
|
|
31468
31741
|
while (1) switch (_context2.n) {
|
|
31469
31742
|
case 0:
|
|
@@ -31513,13 +31786,14 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
31513
31786
|
break;
|
|
31514
31787
|
}
|
|
31515
31788
|
_loop = /*#__PURE__*/_regenerator().m(function _loop() {
|
|
31516
|
-
var _modelPreloader$compo;
|
|
31789
|
+
var _modelPreloader$compo, _deviceData$animation;
|
|
31517
31790
|
var _Object$entries$_i, attachmentId, attachment, deviceData, deviceRoot;
|
|
31518
31791
|
return _regenerator().w(function (_context) {
|
|
31519
31792
|
while (1) switch (_context.n) {
|
|
31520
31793
|
case 0:
|
|
31521
31794
|
_Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), attachmentId = _Object$entries$_i[0], attachment = _Object$entries$_i[1];
|
|
31522
31795
|
deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
|
|
31796
|
+
console.log("[ModelManager] attachment \"".concat(attachmentId, "\" \u2192 deviceId \"").concat(attachment.deviceId, "\" \u2192 animationConfig:"), (_deviceData$animation = deviceData === null || deviceData === void 0 ? void 0 : deviceData.animationConfig) !== null && _deviceData$animation !== void 0 ? _deviceData$animation : 'NONE');
|
|
31523
31797
|
if (deviceData !== null && deviceData !== void 0 && deviceData.animationConfig) {
|
|
31524
31798
|
_context.n = 1;
|
|
31525
31799
|
break;
|
|
@@ -31559,6 +31833,20 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
31559
31833
|
case 8:
|
|
31560
31834
|
// Replace mesh in scene
|
|
31561
31835
|
this._replaceMeshInScene(targetMesh, libraryModel, originalProps.parent, component);
|
|
31836
|
+
|
|
31837
|
+
// Pre-warm the filtered bounding-box cache for smart components so the
|
|
31838
|
+
// first selection is instant. Deferred to idle time so it does not
|
|
31839
|
+
// block the current frame.
|
|
31840
|
+
if (componentData.isSmart) {
|
|
31841
|
+
warmFn = function warmFn() {
|
|
31842
|
+
return computeFilteredBoundingBoxCached(libraryModel, ['io-device', 'connector']);
|
|
31843
|
+
};
|
|
31844
|
+
if (typeof requestIdleCallback !== 'undefined') {
|
|
31845
|
+
requestIdleCallback(warmFn);
|
|
31846
|
+
} else {
|
|
31847
|
+
setTimeout(warmFn, 0);
|
|
31848
|
+
}
|
|
31849
|
+
}
|
|
31562
31850
|
console.log("\uD83C\uDF89 ".concat((_jsonEntry$userData3 = jsonEntry.userData) === null || _jsonEntry$userData3 === void 0 ? void 0 : _jsonEntry$userData3.libraryId, " GLB model successfully rendered in scene"));
|
|
31563
31851
|
return _context2.a(2, libraryModel);
|
|
31564
31852
|
case 9:
|
|
@@ -34790,11 +35078,18 @@ var AnimationManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
34790
35078
|
sceneViewer.performanceMonitorManager.beginFrame();
|
|
34791
35079
|
}
|
|
34792
35080
|
try {
|
|
35081
|
+
var _sceneViewer$managers;
|
|
34793
35082
|
// Update controls
|
|
34794
35083
|
sceneViewer.controls.update();
|
|
34795
35084
|
|
|
34796
|
-
// Render the scene
|
|
34797
|
-
|
|
35085
|
+
// Render the scene — route through the outline manager when active so
|
|
35086
|
+
// the mask pass and screen-space composite run after the main render.
|
|
35087
|
+
var ioOutline = (_sceneViewer$managers = sceneViewer.managers) === null || _sceneViewer$managers === void 0 ? void 0 : _sceneViewer$managers.ioOutlineManager;
|
|
35088
|
+
if (ioOutline !== null && ioOutline !== void 0 && ioOutline.isActive) {
|
|
35089
|
+
ioOutline.render();
|
|
35090
|
+
} else {
|
|
35091
|
+
sceneViewer.renderer.render(sceneViewer.scene, sceneViewer.camera);
|
|
35092
|
+
}
|
|
34798
35093
|
} catch (renderError) {
|
|
34799
35094
|
// Catch WebGL or rendering errors to prevent the animation loop from
|
|
34800
35095
|
// producing a permanent white screen. Log once and continue so that
|
|
@@ -37068,6 +37363,169 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37068
37363
|
console.log("\uD83D\uDD04 [IODevice] Toggled ".concat(scopedAttachmentId, ".").concat(dpId, ": ").concat(currentVal, " \u2192 ").concat(newVal));
|
|
37069
37364
|
}
|
|
37070
37365
|
|
|
37366
|
+
// ── IO device drag-to-state ─────────────────────────────────────────────
|
|
37367
|
+
|
|
37368
|
+
/**
|
|
37369
|
+
* Begin tracking a drag gesture on an IO device mesh.
|
|
37370
|
+
* Records the initial state of each animation data point so that
|
|
37371
|
+
* `updateIODeviceDrag` can compute relative offsets from it.
|
|
37372
|
+
*
|
|
37373
|
+
* @param {THREE.Object3D} ioDeviceObject
|
|
37374
|
+
*/
|
|
37375
|
+
}, {
|
|
37376
|
+
key: "startIODeviceDrag",
|
|
37377
|
+
value: function startIODeviceDrag(ioDeviceObject) {
|
|
37378
|
+
var _this$sceneViewer3,
|
|
37379
|
+
_this2 = this;
|
|
37380
|
+
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
37381
|
+
var ud = ioDeviceObject.userData;
|
|
37382
|
+
var attachmentId = ud === null || ud === void 0 ? void 0 : ud.attachmentId;
|
|
37383
|
+
if (!attachmentId) return;
|
|
37384
|
+
var parentUuid = null;
|
|
37385
|
+
var obj = ioDeviceObject.parent;
|
|
37386
|
+
while (obj) {
|
|
37387
|
+
var _obj$userData2;
|
|
37388
|
+
if (((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.objectType) === 'component') {
|
|
37389
|
+
parentUuid = obj.uuid;
|
|
37390
|
+
break;
|
|
37391
|
+
}
|
|
37392
|
+
obj = obj.parent;
|
|
37393
|
+
}
|
|
37394
|
+
var scopedAttachmentId = this._getScopedAttachmentKey(attachmentId, parentUuid);
|
|
37395
|
+
var ioAnimMgr = (_this$sceneViewer3 = this.sceneViewer) === null || _this$sceneViewer3 === void 0 || (_this$sceneViewer3 = _this$sceneViewer3.managers) === null || _this$sceneViewer3 === void 0 ? void 0 : _this$sceneViewer3.ioAnimationManager;
|
|
37396
|
+
var dataPoints = ((ioAnimMgr === null || ioAnimMgr === void 0 ? void 0 : ioAnimMgr.getAnimationDataPoints(parentUuid, attachmentId)) || []).concat((ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [])
|
|
37397
|
+
// deduplicate by id
|
|
37398
|
+
.filter(function (dp, i, arr) {
|
|
37399
|
+
return arr.findIndex(function (d) {
|
|
37400
|
+
return d.id === dp.id;
|
|
37401
|
+
}) === i;
|
|
37402
|
+
});
|
|
37403
|
+
var dpSessions = [];
|
|
37404
|
+
var _iterator = _createForOfIteratorHelper(dataPoints),
|
|
37405
|
+
_step;
|
|
37406
|
+
try {
|
|
37407
|
+
var _loop = function _loop() {
|
|
37408
|
+
var _this2$_stateAdapter$;
|
|
37409
|
+
var dp = _step.value;
|
|
37410
|
+
var stateType = (dp.stateType || '').toLowerCase();
|
|
37411
|
+
if (stateType !== 'binary' && stateType !== 'boolean' && stateType !== 'enum') return 1; // continue
|
|
37412
|
+
var curVal = (_this2$_stateAdapter$ = _this2._stateAdapter.getState(scopedAttachmentId, dp.id)) !== null && _this2$_stateAdapter$ !== void 0 ? _this2$_stateAdapter$ : dp.defaultValue;
|
|
37413
|
+
if (stateType === 'binary' || stateType === 'boolean') {
|
|
37414
|
+
dpSessions.push({
|
|
37415
|
+
dp: dp,
|
|
37416
|
+
scopedAttachmentId: scopedAttachmentId,
|
|
37417
|
+
attachmentId: attachmentId,
|
|
37418
|
+
parentUuid: parentUuid,
|
|
37419
|
+
stateType: 'binary',
|
|
37420
|
+
lastApplied: curVal
|
|
37421
|
+
});
|
|
37422
|
+
} else {
|
|
37423
|
+
var _dp$stateConfig;
|
|
37424
|
+
var opts = ((_dp$stateConfig = dp.stateConfig) === null || _dp$stateConfig === void 0 ? void 0 : _dp$stateConfig.options) || [];
|
|
37425
|
+
var curIdx = opts.findIndex(function (o) {
|
|
37426
|
+
return String(o) === String(curVal);
|
|
37427
|
+
});
|
|
37428
|
+
dpSessions.push({
|
|
37429
|
+
dp: dp,
|
|
37430
|
+
scopedAttachmentId: scopedAttachmentId,
|
|
37431
|
+
attachmentId: attachmentId,
|
|
37432
|
+
parentUuid: parentUuid,
|
|
37433
|
+
stateType: 'enum',
|
|
37434
|
+
opts: opts,
|
|
37435
|
+
startIdx: curIdx >= 0 ? curIdx : 0,
|
|
37436
|
+
lastAppliedIdx: curIdx >= 0 ? curIdx : 0
|
|
37437
|
+
});
|
|
37438
|
+
}
|
|
37439
|
+
};
|
|
37440
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
37441
|
+
if (_loop()) continue;
|
|
37442
|
+
}
|
|
37443
|
+
} catch (err) {
|
|
37444
|
+
_iterator.e(err);
|
|
37445
|
+
} finally {
|
|
37446
|
+
_iterator.f();
|
|
37447
|
+
}
|
|
37448
|
+
this._ioDragSession = dpSessions.length ? {
|
|
37449
|
+
dpSessions: dpSessions
|
|
37450
|
+
} : null;
|
|
37451
|
+
}
|
|
37452
|
+
|
|
37453
|
+
/**
|
|
37454
|
+
* Update animated mesh state while a drag is in progress.
|
|
37455
|
+
* Called continuously during pointermove.
|
|
37456
|
+
*
|
|
37457
|
+
* Sign convention: up/right = positive `signedDelta`.
|
|
37458
|
+
* - Binary: > +20 px → true/on state, < −20 px → false/off state.
|
|
37459
|
+
* - Enum: each ±30 px step advances/retreats one option in the list.
|
|
37460
|
+
*
|
|
37461
|
+
* @param {number} signedDelta - Cumulative signed pixel displacement since drag start
|
|
37462
|
+
*/
|
|
37463
|
+
}, {
|
|
37464
|
+
key: "updateIODeviceDrag",
|
|
37465
|
+
value: function updateIODeviceDrag(signedDelta) {
|
|
37466
|
+
var session = this._ioDragSession;
|
|
37467
|
+
if (!session) return;
|
|
37468
|
+
var BINARY_THRESHOLD = 20;
|
|
37469
|
+
var ENUM_STEP_PX = 30;
|
|
37470
|
+
var _iterator2 = _createForOfIteratorHelper(session.dpSessions),
|
|
37471
|
+
_step2;
|
|
37472
|
+
try {
|
|
37473
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
37474
|
+
var dps = _step2.value;
|
|
37475
|
+
if (dps.stateType === 'binary') {
|
|
37476
|
+
var newVal = void 0;
|
|
37477
|
+
if (signedDelta > BINARY_THRESHOLD) {
|
|
37478
|
+
newVal = true;
|
|
37479
|
+
} else if (signedDelta < -BINARY_THRESHOLD) {
|
|
37480
|
+
newVal = false;
|
|
37481
|
+
} else {
|
|
37482
|
+
continue; // dead zone
|
|
37483
|
+
}
|
|
37484
|
+
if (newVal === dps.lastApplied) continue;
|
|
37485
|
+
dps.lastApplied = newVal;
|
|
37486
|
+
this._applyDpState(dps, newVal);
|
|
37487
|
+
} else if (dps.stateType === 'enum') {
|
|
37488
|
+
var steps = Math.round(signedDelta / ENUM_STEP_PX);
|
|
37489
|
+
var newIdx = Math.max(0, Math.min(dps.opts.length - 1, dps.startIdx + steps));
|
|
37490
|
+
if (newIdx === dps.lastAppliedIdx) continue;
|
|
37491
|
+
dps.lastAppliedIdx = newIdx;
|
|
37492
|
+
this._applyDpState(dps, dps.opts[newIdx]);
|
|
37493
|
+
}
|
|
37494
|
+
}
|
|
37495
|
+
} catch (err) {
|
|
37496
|
+
_iterator2.e(err);
|
|
37497
|
+
} finally {
|
|
37498
|
+
_iterator2.f();
|
|
37499
|
+
}
|
|
37500
|
+
}
|
|
37501
|
+
|
|
37502
|
+
/**
|
|
37503
|
+
* Clean up drag session state on pointerup.
|
|
37504
|
+
*/
|
|
37505
|
+
}, {
|
|
37506
|
+
key: "endIODeviceDrag",
|
|
37507
|
+
value: function endIODeviceDrag() {
|
|
37508
|
+
this._ioDragSession = null;
|
|
37509
|
+
}
|
|
37510
|
+
|
|
37511
|
+
/**
|
|
37512
|
+
* Apply a new value to a data point, updating Vuex state and firing behavior/animation triggers.
|
|
37513
|
+
* @private
|
|
37514
|
+
*/
|
|
37515
|
+
}, {
|
|
37516
|
+
key: "_applyDpState",
|
|
37517
|
+
value: function _applyDpState(_ref2, newVal) {
|
|
37518
|
+
var _this$_stateAdapter, _this$sceneViewer4, _this$sceneViewer5;
|
|
37519
|
+
var scopedAttachmentId = _ref2.scopedAttachmentId,
|
|
37520
|
+
attachmentId = _ref2.attachmentId,
|
|
37521
|
+
parentUuid = _ref2.parentUuid,
|
|
37522
|
+
dp = _ref2.dp;
|
|
37523
|
+
var dpId = dp.id;
|
|
37524
|
+
(_this$_stateAdapter = this._stateAdapter) === null || _this$_stateAdapter === void 0 || _this$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
37525
|
+
(_this$sceneViewer4 = this.sceneViewer) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.managers) === null || _this$sceneViewer4 === void 0 || (_this$sceneViewer4 = _this$sceneViewer4.behaviorManager) === null || _this$sceneViewer4 === void 0 || _this$sceneViewer4.triggerState(attachmentId, dpId, newVal, parentUuid);
|
|
37526
|
+
(_this$sceneViewer5 = this.sceneViewer) === null || _this$sceneViewer5 === void 0 || (_this$sceneViewer5 = _this$sceneViewer5.managers) === null || _this$sceneViewer5 === void 0 || (_this$sceneViewer5 = _this$sceneViewer5.ioAnimationManager) === null || _this$sceneViewer5 === void 0 || _this$sceneViewer5.triggerState(attachmentId, dpId, newVal, parentUuid);
|
|
37527
|
+
}
|
|
37528
|
+
|
|
37071
37529
|
/**
|
|
37072
37530
|
* Should be called when an object is selected or deselected.
|
|
37073
37531
|
* @param {THREE.Object3D|null} object
|
|
@@ -37181,26 +37639,30 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37181
37639
|
}, {
|
|
37182
37640
|
key: "_getIODevices",
|
|
37183
37641
|
value: function _getIODevices(object) {
|
|
37184
|
-
var
|
|
37642
|
+
var _this3 = this;
|
|
37185
37643
|
var devices = [];
|
|
37186
37644
|
var parentUuid = object.uuid; // The component's own UUID
|
|
37187
37645
|
object.traverse(function (child) {
|
|
37188
37646
|
var _child$userData;
|
|
37189
37647
|
if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
|
|
37190
|
-
var
|
|
37648
|
+
var _this3$sceneViewer$ma, _this3$sceneViewer;
|
|
37191
37649
|
var attachmentId = child.userData.attachmentId || '';
|
|
37192
37650
|
|
|
37193
|
-
//
|
|
37194
|
-
//
|
|
37195
|
-
var
|
|
37196
|
-
|
|
37651
|
+
// Use only data points from the animate window (animationConfig).
|
|
37652
|
+
// The static ioConfig.states[] snapshot on userData is intentionally ignored.
|
|
37653
|
+
var dataPoints = (_this3$sceneViewer$ma = (_this3$sceneViewer = _this3.sceneViewer) === null || _this3$sceneViewer === void 0 || (_this3$sceneViewer = _this3$sceneViewer.managers) === null || _this3$sceneViewer === void 0 || (_this3$sceneViewer = _this3$sceneViewer.ioAnimationManager) === null || _this3$sceneViewer === void 0 ? void 0 : _this3$sceneViewer.getAnimationDataPoints(parentUuid, attachmentId)) !== null && _this3$sceneViewer$ma !== void 0 ? _this3$sceneViewer$ma : [];
|
|
37654
|
+
|
|
37655
|
+
// When data points come from animationConfig they already carry direction:'input'.
|
|
37656
|
+
// Pass null so _buildDataPointRow uses the per-dp direction instead of the
|
|
37657
|
+
// device-level ioDirection (which may be 'output' and would hide controls).
|
|
37658
|
+
var deviceDirection = dataPoints.length > 0 ? null : child.userData.ioDirection || 'output';
|
|
37197
37659
|
devices.push({
|
|
37198
37660
|
label: child.userData.attachmentLabel || child.name || child.userData.deviceId || 'Unknown Device',
|
|
37199
37661
|
deviceId: child.userData.deviceId || '',
|
|
37200
37662
|
attachmentId: attachmentId,
|
|
37201
|
-
scopedAttachmentId:
|
|
37663
|
+
scopedAttachmentId: _this3._getScopedAttachmentKey(attachmentId, parentUuid),
|
|
37202
37664
|
dataPoints: dataPoints,
|
|
37203
|
-
direction:
|
|
37665
|
+
direction: deviceDirection
|
|
37204
37666
|
});
|
|
37205
37667
|
}
|
|
37206
37668
|
});
|
|
@@ -37214,7 +37676,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37214
37676
|
}, {
|
|
37215
37677
|
key: "_buildTooltip",
|
|
37216
37678
|
value: function _buildTooltip(object) {
|
|
37217
|
-
var
|
|
37679
|
+
var _this4 = this;
|
|
37218
37680
|
// Remove any existing tooltip first
|
|
37219
37681
|
this.hide();
|
|
37220
37682
|
// Re-assign selected object since hide() clears it
|
|
@@ -37285,7 +37747,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37285
37747
|
// Use scopedAttachmentId to ensure state is isolated per component instance
|
|
37286
37748
|
if (device.scopedAttachmentId && device.dataPoints.length > 0) {
|
|
37287
37749
|
device.dataPoints.forEach(function (dp) {
|
|
37288
|
-
var row =
|
|
37750
|
+
var row = _this4._buildDataPointRow(device.scopedAttachmentId, dp, device.direction, device.attachmentId);
|
|
37289
37751
|
list.appendChild(row);
|
|
37290
37752
|
});
|
|
37291
37753
|
}
|
|
@@ -37296,11 +37758,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37296
37758
|
// Hover expand/collapse
|
|
37297
37759
|
trigger.addEventListener('mouseenter', function () {
|
|
37298
37760
|
ioSection.classList.add('expanded');
|
|
37299
|
-
|
|
37761
|
+
_this4._ioExpanded = true;
|
|
37300
37762
|
});
|
|
37301
37763
|
ioSection.addEventListener('mouseleave', function () {
|
|
37302
37764
|
ioSection.classList.remove('expanded');
|
|
37303
|
-
|
|
37765
|
+
_this4._ioExpanded = false;
|
|
37304
37766
|
});
|
|
37305
37767
|
card.appendChild(ioSection);
|
|
37306
37768
|
} else {
|
|
@@ -37344,11 +37806,11 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37344
37806
|
}, {
|
|
37345
37807
|
key: "_positionTooltip",
|
|
37346
37808
|
value: function _positionTooltip() {
|
|
37347
|
-
var _this$
|
|
37809
|
+
var _this$sceneViewer6, _this$sceneViewer7;
|
|
37348
37810
|
if (!this.tooltipEl || !this.selectedObject) return;
|
|
37349
37811
|
var container = this._getContainer();
|
|
37350
|
-
var camera = (_this$
|
|
37351
|
-
var renderer = (_this$
|
|
37812
|
+
var camera = (_this$sceneViewer6 = this.sceneViewer) === null || _this$sceneViewer6 === void 0 ? void 0 : _this$sceneViewer6.camera;
|
|
37813
|
+
var renderer = (_this$sceneViewer7 = this.sceneViewer) === null || _this$sceneViewer7 === void 0 ? void 0 : _this$sceneViewer7.renderer;
|
|
37352
37814
|
if (!container || !camera || !renderer) return;
|
|
37353
37815
|
|
|
37354
37816
|
// Compute bounding box to position above the component
|
|
@@ -37385,8 +37847,8 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37385
37847
|
}, {
|
|
37386
37848
|
key: "_getContainer",
|
|
37387
37849
|
value: function _getContainer() {
|
|
37388
|
-
var _this$
|
|
37389
|
-
return ((_this$
|
|
37850
|
+
var _this$sceneViewer8;
|
|
37851
|
+
return ((_this$sceneViewer8 = this.sceneViewer) === null || _this$sceneViewer8 === void 0 || (_this$sceneViewer8 = _this$sceneViewer8.renderer) === null || _this$sceneViewer8 === void 0 || (_this$sceneViewer8 = _this$sceneViewer8.domElement) === null || _this$sceneViewer8 === void 0 ? void 0 : _this$sceneViewer8.parentElement) || null;
|
|
37390
37852
|
}
|
|
37391
37853
|
|
|
37392
37854
|
// -----------------------------------------------------------------------
|
|
@@ -37408,10 +37870,10 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37408
37870
|
}, {
|
|
37409
37871
|
key: "_buildDataPointRow",
|
|
37410
37872
|
value: function _buildDataPointRow(scopedAttachmentId, dp, deviceDirection, originalAttachmentId) {
|
|
37411
|
-
var
|
|
37873
|
+
var _ref3,
|
|
37412
37874
|
_this$_stateAdapter$g,
|
|
37413
|
-
_this$
|
|
37414
|
-
|
|
37875
|
+
_this$_stateAdapter2,
|
|
37876
|
+
_this5 = this;
|
|
37415
37877
|
var row = document.createElement('div');
|
|
37416
37878
|
row.className = 'cp-tooltip__dp-row';
|
|
37417
37879
|
var nameEl = document.createElement('span');
|
|
@@ -37423,18 +37885,18 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37423
37885
|
// Device-level direction takes precedence; fall back to per-dp direction
|
|
37424
37886
|
var resolvedDirection = deviceDirection || dp.direction || 'output';
|
|
37425
37887
|
var isInput = resolvedDirection === 'input' || resolvedDirection === 'bidirectional';
|
|
37426
|
-
var currentVal = (
|
|
37888
|
+
var currentVal = (_ref3 = (_this$_stateAdapter$g = (_this$_stateAdapter2 = this._stateAdapter) === null || _this$_stateAdapter2 === void 0 ? void 0 : _this$_stateAdapter2.getState(scopedAttachmentId, dpId)) !== null && _this$_stateAdapter$g !== void 0 ? _this$_stateAdapter$g : dp.defaultValue) !== null && _ref3 !== void 0 ? _ref3 : null;
|
|
37427
37889
|
if (isInput) {
|
|
37428
37890
|
var ctrl = this._buildInputControl(dp, currentVal, function (newVal) {
|
|
37429
|
-
var
|
|
37430
|
-
(
|
|
37891
|
+
var _this5$_stateAdapter, _this5$selectedObject, _this5$sceneViewer, _this5$sceneViewer2;
|
|
37892
|
+
(_this5$_stateAdapter = _this5._stateAdapter) === null || _this5$_stateAdapter === void 0 || _this5$_stateAdapter.setState(scopedAttachmentId, dpId, newVal);
|
|
37431
37893
|
// Also fire BehaviorManager so any wired behaviors react immediately.
|
|
37432
37894
|
// Pass the parent component UUID so behaviors scoped to a specific instance
|
|
37433
37895
|
// don't bleed across clones that share the same attachmentId.
|
|
37434
37896
|
// Use originalAttachmentId for behavior triggering as behaviors are keyed by original ID
|
|
37435
|
-
var parentUuid = ((
|
|
37436
|
-
(
|
|
37437
|
-
(
|
|
37897
|
+
var parentUuid = ((_this5$selectedObject = _this5.selectedObject) === null || _this5$selectedObject === void 0 ? void 0 : _this5$selectedObject.uuid) || null;
|
|
37898
|
+
(_this5$sceneViewer = _this5.sceneViewer) === null || _this5$sceneViewer === void 0 || (_this5$sceneViewer = _this5$sceneViewer.managers) === null || _this5$sceneViewer === void 0 || (_this5$sceneViewer = _this5$sceneViewer.behaviorManager) === null || _this5$sceneViewer === void 0 || _this5$sceneViewer.triggerState(originalAttachmentId || scopedAttachmentId, dpId, newVal, parentUuid);
|
|
37899
|
+
(_this5$sceneViewer2 = _this5.sceneViewer) === null || _this5$sceneViewer2 === void 0 || (_this5$sceneViewer2 = _this5$sceneViewer2.managers) === null || _this5$sceneViewer2 === void 0 || (_this5$sceneViewer2 = _this5$sceneViewer2.ioAnimationManager) === null || _this5$sceneViewer2 === void 0 || _this5$sceneViewer2.triggerState(originalAttachmentId || scopedAttachmentId, dpId, newVal, parentUuid);
|
|
37438
37900
|
});
|
|
37439
37901
|
row.appendChild(ctrl);
|
|
37440
37902
|
this._stateElements.set(key, {
|
|
@@ -37443,9 +37905,9 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37443
37905
|
isInput: true
|
|
37444
37906
|
});
|
|
37445
37907
|
} else {
|
|
37446
|
-
var _dp$
|
|
37908
|
+
var _dp$stateConfig2;
|
|
37447
37909
|
// unit suffix (optional, shown between name and badge)
|
|
37448
|
-
var unit = (_dp$
|
|
37910
|
+
var unit = (_dp$stateConfig2 = dp.stateConfig) === null || _dp$stateConfig2 === void 0 ? void 0 : _dp$stateConfig2.unit;
|
|
37449
37911
|
if (unit) {
|
|
37450
37912
|
var unitEl = document.createElement('span');
|
|
37451
37913
|
unitEl.className = 'cp-tooltip__dp-unit';
|
|
@@ -37590,7 +38052,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37590
38052
|
}, {
|
|
37591
38053
|
key: "_refreshStateDisplays",
|
|
37592
38054
|
value: function _refreshStateDisplays() {
|
|
37593
|
-
var
|
|
38055
|
+
var _this6 = this;
|
|
37594
38056
|
if (!this._stateAdapter || !this._stateElements.size) return;
|
|
37595
38057
|
this._stateElements.forEach(function (entry, key) {
|
|
37596
38058
|
if (entry.isInput) return; // interactive controls are user-driven; don't overwrite
|
|
@@ -37599,8 +38061,8 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37599
38061
|
if (sepIdx === -1) return;
|
|
37600
38062
|
var scopedAttachmentId = key.slice(0, sepIdx);
|
|
37601
38063
|
var dataPointId = key.slice(sepIdx + 2);
|
|
37602
|
-
var val =
|
|
37603
|
-
|
|
38064
|
+
var val = _this6._stateAdapter.getState(scopedAttachmentId, dataPointId);
|
|
38065
|
+
_this6._applyBadgeValue(entry.el, val, entry.dp);
|
|
37604
38066
|
});
|
|
37605
38067
|
}
|
|
37606
38068
|
}]);
|
|
@@ -37674,7 +38136,11 @@ var IoAnimationManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37674
38136
|
}
|
|
37675
38137
|
if (entries.length) {
|
|
37676
38138
|
this._entries.set(key, entries);
|
|
37677
|
-
console.log("[IoAnimationManager] Loaded ".concat(entries.length, " animation(s) for attachment \"").concat(attachmentId, "\" (parent: ").concat(parentUuid, ")"))
|
|
38139
|
+
console.log("[IoAnimationManager] Loaded ".concat(entries.length, " animation(s) for attachment \"").concat(attachmentId, "\" (parent: ").concat(parentUuid, ") \u2014 stateVariables: ").concat(entries.map(function (e) {
|
|
38140
|
+
return e.anim.stateVariable;
|
|
38141
|
+
}).join(', ')));
|
|
38142
|
+
} else {
|
|
38143
|
+
console.warn("[IoAnimationManager] No mesh entries resolved for attachment \"".concat(attachmentId, "\" \u2014 animationConfig had ").concat(anims.length, " entries but none matched a mesh"));
|
|
37678
38144
|
}
|
|
37679
38145
|
}
|
|
37680
38146
|
|
|
@@ -37819,6 +38285,26 @@ var IoAnimationManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37819
38285
|
return dps;
|
|
37820
38286
|
}
|
|
37821
38287
|
|
|
38288
|
+
/**
|
|
38289
|
+
* Return the Three.js mesh objects that are animated for a given attachment.
|
|
38290
|
+
* Used by IoOutlineManager to include animated meshes in the outline.
|
|
38291
|
+
*
|
|
38292
|
+
* @param {string} parentUuid
|
|
38293
|
+
* @param {string} attachmentId
|
|
38294
|
+
* @returns {THREE.Object3D[]}
|
|
38295
|
+
*/
|
|
38296
|
+
}, {
|
|
38297
|
+
key: "getAnimatedMeshes",
|
|
38298
|
+
value: function getAnimatedMeshes(parentUuid, attachmentId) {
|
|
38299
|
+
var key = this._key(parentUuid, attachmentId);
|
|
38300
|
+
var entries = this._entries.get(key);
|
|
38301
|
+
if (!(entries !== null && entries !== void 0 && entries.length)) return [];
|
|
38302
|
+
// Deduplicate — multiple animations can target the same mesh
|
|
38303
|
+
return _toConsumableArray(new Set(entries.map(function (e) {
|
|
38304
|
+
return e.mesh;
|
|
38305
|
+
})));
|
|
38306
|
+
}
|
|
38307
|
+
|
|
37822
38308
|
/**
|
|
37823
38309
|
* Remove all animation entries associated with a given host component.
|
|
37824
38310
|
* Call when a component is removed from the scene.
|
|
@@ -38050,7 +38536,10 @@ var IoAnimationManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
38050
38536
|
value: function _applyTranslation(mesh, origPos, transform) {
|
|
38051
38537
|
var _transform$x, _transform$y, _transform$z;
|
|
38052
38538
|
if (!transform) return;
|
|
38053
|
-
|
|
38539
|
+
// X and Y are negated to match the sign convention used in the AnimateDevicesDialog
|
|
38540
|
+
// preview (_syncViewerTransform negates x and y before calling setMeshPreviewOffset).
|
|
38541
|
+
// Z is added directly (no negation) — matching the dialog's z handling.
|
|
38542
|
+
mesh.position.set(origPos.x - ((_transform$x = transform.x) !== null && _transform$x !== void 0 ? _transform$x : 0), origPos.y - ((_transform$y = transform.y) !== null && _transform$y !== void 0 ? _transform$y : 0), origPos.z + ((_transform$z = transform.z) !== null && _transform$z !== void 0 ? _transform$z : 0));
|
|
38054
38543
|
}
|
|
38055
38544
|
|
|
38056
38545
|
/**
|
|
@@ -38121,6 +38610,235 @@ var IoAnimationManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
38121
38610
|
}]);
|
|
38122
38611
|
}(BaseDisposable);
|
|
38123
38612
|
|
|
38613
|
+
/**
|
|
38614
|
+
* Three.js layer reserved exclusively for the outline mask pass.
|
|
38615
|
+
* Layer 20 is high enough to be well clear of typical app layer usage.
|
|
38616
|
+
*/
|
|
38617
|
+
var OUTLINE_LAYER = 20;
|
|
38618
|
+
|
|
38619
|
+
// ── Shaders ──────────────────────────────────────────────────────────────────
|
|
38620
|
+
|
|
38621
|
+
var VERT_SHADER = /* glsl */"\nvarying vec2 vUv;\nvoid main() {\n vUv = uv;\n gl_Position = vec4(position.xy, 0.0, 1.0);\n}\n";
|
|
38622
|
+
|
|
38623
|
+
/**
|
|
38624
|
+
* Screen-space outline shader.
|
|
38625
|
+
*
|
|
38626
|
+
* Samples in a circular kernel to find the nearest filled (silhouette) pixel.
|
|
38627
|
+
* Applies a smooth alpha falloff at the outer edge using smoothstep so the
|
|
38628
|
+
* outline fades cleanly rather than cutting off hard.
|
|
38629
|
+
*
|
|
38630
|
+
* RADIUS — maximum distance in pixels from the silhouette edge to draw.
|
|
38631
|
+
* SAMPLES — kernel half-extent; must be an integer ≥ ceil(RADIUS).
|
|
38632
|
+
*/
|
|
38633
|
+
var FRAG_SHADER = /* glsl */"\nuniform sampler2D tMask;\nuniform vec2 uInvSize;\nvarying vec2 vUv;\n\nconst float RADIUS = 3.0; // total outline width in pixels\nconst int SAMPLES = 4; // kernel half-extent (\u2265 ceil(RADIUS))\n\nvoid main() {\n float center = texture2D(tMask, vUv).r;\n\n // Pixels inside the silhouette: the main render already drew them.\n if (center > 0.5) discard;\n\n // Find the closest filled neighbour within the circular kernel.\n float minDist = 99.0;\n for (int x = -SAMPLES; x <= SAMPLES; x++) {\n for (int y = -SAMPLES; y <= SAMPLES; y++) {\n float dist = length(vec2(float(x), float(y)));\n if (dist > RADIUS + 1.0) continue; // skip corners outside circle\n vec2 offset = vec2(float(x), float(y)) * uInvSize;\n if (texture2D(tMask, vUv + offset).r > 0.5) {\n minDist = min(minDist, dist);\n }\n }\n }\n\n if (minDist > RADIUS + 0.5) discard;\n\n // Smooth alpha: full opacity near the edge, fades to 0 at RADIUS pixels out.\n float alpha = 1.0 - smoothstep(RADIUS - 1.0, RADIUS + 0.5, minDist);\n gl_FragColor = vec4(1.0, 1.0, 1.0, alpha);\n}\n";
|
|
38634
|
+
var IoOutlineManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
38635
|
+
function IoOutlineManager(sceneViewer) {
|
|
38636
|
+
var _this;
|
|
38637
|
+
_classCallCheck(this, IoOutlineManager);
|
|
38638
|
+
_this = _callSuper(this, IoOutlineManager);
|
|
38639
|
+
_this.sceneViewer = sceneViewer;
|
|
38640
|
+
_this._maskTarget = null;
|
|
38641
|
+
_this._maskMat = null;
|
|
38642
|
+
_this._overlayScene = null;
|
|
38643
|
+
_this._overlayCamera = null;
|
|
38644
|
+
_this._overlayMat = null;
|
|
38645
|
+
|
|
38646
|
+
/**
|
|
38647
|
+
* Meshes that have been moved onto OUTLINE_LAYER, stored with their
|
|
38648
|
+
* original layers.mask so they can be restored on clearance.
|
|
38649
|
+
* @type {{ mesh: THREE.Mesh, originalMask: number }[]}
|
|
38650
|
+
*/
|
|
38651
|
+
_this._layeredMeshes = [];
|
|
38652
|
+
|
|
38653
|
+
/** @type {boolean} Whether an outline is currently active. */
|
|
38654
|
+
_this.isActive = false;
|
|
38655
|
+
return _this;
|
|
38656
|
+
}
|
|
38657
|
+
|
|
38658
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
38659
|
+
// PUBLIC API
|
|
38660
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
38661
|
+
|
|
38662
|
+
/**
|
|
38663
|
+
* Set the objects to outline. Pass an empty array (or call with no args)
|
|
38664
|
+
* to remove the outline.
|
|
38665
|
+
* @param {THREE.Object3D[]} objects
|
|
38666
|
+
*/
|
|
38667
|
+
_inherits(IoOutlineManager, _BaseDisposable);
|
|
38668
|
+
return _createClass(IoOutlineManager, [{
|
|
38669
|
+
key: "setTargets",
|
|
38670
|
+
value: function setTargets() {
|
|
38671
|
+
var _this2 = this;
|
|
38672
|
+
var objects = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
38673
|
+
this._clearLayeredMeshes();
|
|
38674
|
+
if (!objects.length) {
|
|
38675
|
+
this.isActive = false;
|
|
38676
|
+
return;
|
|
38677
|
+
}
|
|
38678
|
+
objects.forEach(function (obj) {
|
|
38679
|
+
obj.traverse(function (child) {
|
|
38680
|
+
if (!child.isMesh) return;
|
|
38681
|
+
var originalMask = child.layers.mask;
|
|
38682
|
+
child.layers.enable(OUTLINE_LAYER);
|
|
38683
|
+
_this2._layeredMeshes.push({
|
|
38684
|
+
mesh: child,
|
|
38685
|
+
originalMask: originalMask
|
|
38686
|
+
});
|
|
38687
|
+
});
|
|
38688
|
+
});
|
|
38689
|
+
this.isActive = this._layeredMeshes.length > 0;
|
|
38690
|
+
}
|
|
38691
|
+
|
|
38692
|
+
/**
|
|
38693
|
+
* Render one frame: main scene → mask pass → outline composite.
|
|
38694
|
+
* Must be called instead of renderer.render() when isActive is true.
|
|
38695
|
+
*/
|
|
38696
|
+
}, {
|
|
38697
|
+
key: "render",
|
|
38698
|
+
value: function render() {
|
|
38699
|
+
var sv = this.sceneViewer;
|
|
38700
|
+
var renderer = sv.renderer,
|
|
38701
|
+
scene = sv.scene,
|
|
38702
|
+
camera = sv.camera;
|
|
38703
|
+
if (!renderer || !scene || !camera) return;
|
|
38704
|
+
|
|
38705
|
+
// ── Step 1: Normal scene render — sky, transparency, all unaffected ──
|
|
38706
|
+
renderer.render(scene, camera);
|
|
38707
|
+
if (!this.isActive) return;
|
|
38708
|
+
this._ensureResources();
|
|
38709
|
+
if (!this._maskTarget) return;
|
|
38710
|
+
|
|
38711
|
+
// Stash renderer / scene / camera state we are about to mutate
|
|
38712
|
+
var prevBg = scene.background;
|
|
38713
|
+
var prevOverride = scene.overrideMaterial;
|
|
38714
|
+
var prevLayerMask = camera.layers.mask;
|
|
38715
|
+
var prevAutoClear = renderer.autoClear;
|
|
38716
|
+
var prevClearClr = renderer.getClearColor(new THREE__namespace.Color());
|
|
38717
|
+
var prevClearA = renderer.getClearAlpha();
|
|
38718
|
+
|
|
38719
|
+
// ── Step 2: Render the device silhouette into the private mask target ──
|
|
38720
|
+
scene.background = null; // transparent clear
|
|
38721
|
+
scene.overrideMaterial = this._maskMat; // flat white for all geometry
|
|
38722
|
+
camera.layers.set(OUTLINE_LAYER); // only see the device meshes
|
|
38723
|
+
renderer.setClearColor(0x000000, 0);
|
|
38724
|
+
renderer.autoClear = true;
|
|
38725
|
+
renderer.setRenderTarget(this._maskTarget);
|
|
38726
|
+
renderer.render(scene, camera);
|
|
38727
|
+
renderer.setRenderTarget(null);
|
|
38728
|
+
|
|
38729
|
+
// Restore mutated state
|
|
38730
|
+
scene.background = prevBg;
|
|
38731
|
+
scene.overrideMaterial = prevOverride;
|
|
38732
|
+
camera.layers.mask = prevLayerMask;
|
|
38733
|
+
renderer.setClearColor(prevClearClr, prevClearA);
|
|
38734
|
+
|
|
38735
|
+
// ── Step 3: Composite the outline on top without clearing the framebuffer
|
|
38736
|
+
renderer.autoClear = false;
|
|
38737
|
+
renderer.render(this._overlayScene, this._overlayCamera);
|
|
38738
|
+
renderer.autoClear = prevAutoClear;
|
|
38739
|
+
}
|
|
38740
|
+
|
|
38741
|
+
/**
|
|
38742
|
+
* Call when the canvas is resized to keep the mask target and shader in sync.
|
|
38743
|
+
* @param {number} width
|
|
38744
|
+
* @param {number} height
|
|
38745
|
+
*/
|
|
38746
|
+
}, {
|
|
38747
|
+
key: "setSize",
|
|
38748
|
+
value: function setSize(width, height) {
|
|
38749
|
+
if (this._maskTarget) this._maskTarget.setSize(width, height);
|
|
38750
|
+
if (this._overlayMat) {
|
|
38751
|
+
this._overlayMat.uniforms.uInvSize.value.set(1 / width, 1 / height);
|
|
38752
|
+
}
|
|
38753
|
+
}
|
|
38754
|
+
}, {
|
|
38755
|
+
key: "dispose",
|
|
38756
|
+
value: function dispose() {
|
|
38757
|
+
this._clearLayeredMeshes();
|
|
38758
|
+
if (this._maskTarget) {
|
|
38759
|
+
this._maskTarget.dispose();
|
|
38760
|
+
this._maskTarget = null;
|
|
38761
|
+
}
|
|
38762
|
+
if (this._maskMat) {
|
|
38763
|
+
this._maskMat.dispose();
|
|
38764
|
+
this._maskMat = null;
|
|
38765
|
+
}
|
|
38766
|
+
if (this._overlayMat) {
|
|
38767
|
+
this._overlayMat.dispose();
|
|
38768
|
+
this._overlayMat = null;
|
|
38769
|
+
}
|
|
38770
|
+
_superPropGet(IoOutlineManager, "dispose", this, 3)([]);
|
|
38771
|
+
}
|
|
38772
|
+
|
|
38773
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
38774
|
+
// PRIVATE
|
|
38775
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
38776
|
+
|
|
38777
|
+
/** Lazy-initialise GPU resources on first use. */
|
|
38778
|
+
}, {
|
|
38779
|
+
key: "_ensureResources",
|
|
38780
|
+
value: function _ensureResources() {
|
|
38781
|
+
if (this._maskTarget) return;
|
|
38782
|
+
var renderer = this.sceneViewer.renderer;
|
|
38783
|
+
if (!renderer) return;
|
|
38784
|
+
var size = renderer.getSize(new THREE__namespace.Vector2());
|
|
38785
|
+
var w = size.x;
|
|
38786
|
+
var h = size.y;
|
|
38787
|
+
|
|
38788
|
+
// Private render target — receives the flat white device silhouette
|
|
38789
|
+
this._maskTarget = new THREE__namespace.WebGLRenderTarget(w, h);
|
|
38790
|
+
|
|
38791
|
+
// Flat white material used during the mask pass
|
|
38792
|
+
this._maskMat = new THREE__namespace.MeshBasicMaterial({
|
|
38793
|
+
color: 0xffffff
|
|
38794
|
+
});
|
|
38795
|
+
|
|
38796
|
+
// Screen-space overlay: reads the mask and draws only the outline pixels
|
|
38797
|
+
this._overlayMat = new THREE__namespace.ShaderMaterial({
|
|
38798
|
+
uniforms: {
|
|
38799
|
+
tMask: {
|
|
38800
|
+
value: this._maskTarget.texture
|
|
38801
|
+
},
|
|
38802
|
+
uInvSize: {
|
|
38803
|
+
value: new THREE__namespace.Vector2(1 / w, 1 / h)
|
|
38804
|
+
}
|
|
38805
|
+
},
|
|
38806
|
+
vertexShader: VERT_SHADER,
|
|
38807
|
+
fragmentShader: FRAG_SHADER,
|
|
38808
|
+
transparent: true,
|
|
38809
|
+
depthTest: false,
|
|
38810
|
+
depthWrite: false
|
|
38811
|
+
});
|
|
38812
|
+
var quad = new THREE__namespace.Mesh(new THREE__namespace.PlaneGeometry(2, 2), this._overlayMat);
|
|
38813
|
+
quad.frustumCulled = false;
|
|
38814
|
+
this._overlayScene = new THREE__namespace.Scene();
|
|
38815
|
+
this._overlayScene.add(quad);
|
|
38816
|
+
this._overlayCamera = new THREE__namespace.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
|
38817
|
+
}
|
|
38818
|
+
|
|
38819
|
+
/** Remove OUTLINE_LAYER from all tracked meshes and clear the list. */
|
|
38820
|
+
}, {
|
|
38821
|
+
key: "_clearLayeredMeshes",
|
|
38822
|
+
value: function _clearLayeredMeshes() {
|
|
38823
|
+
var _iterator = _createForOfIteratorHelper(this._layeredMeshes),
|
|
38824
|
+
_step;
|
|
38825
|
+
try {
|
|
38826
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
38827
|
+
var _step$value = _step.value,
|
|
38828
|
+
mesh = _step$value.mesh,
|
|
38829
|
+
originalMask = _step$value.originalMask;
|
|
38830
|
+
mesh.layers.mask = originalMask;
|
|
38831
|
+
}
|
|
38832
|
+
} catch (err) {
|
|
38833
|
+
_iterator.e(err);
|
|
38834
|
+
} finally {
|
|
38835
|
+
_iterator.f();
|
|
38836
|
+
}
|
|
38837
|
+
this._layeredMeshes = [];
|
|
38838
|
+
}
|
|
38839
|
+
}]);
|
|
38840
|
+
}(BaseDisposable);
|
|
38841
|
+
|
|
38124
38842
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
38125
38843
|
// Flow-direction helpers (module-level)
|
|
38126
38844
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -38243,6 +38961,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
38243
38961
|
this.centralPlant.managers.componentDragManager = new ComponentDragManager(this.centralPlant.sceneViewer);
|
|
38244
38962
|
this.centralPlant.managers.viewport2DManager = new Viewport2DManager(this.centralPlant.sceneViewer);
|
|
38245
38963
|
this.centralPlant.managers.ioAnimationManager = new IoAnimationManager(this.centralPlant.sceneViewer);
|
|
38964
|
+
this.centralPlant.managers.ioOutlineManager = new IoOutlineManager(this.centralPlant.sceneViewer);
|
|
38246
38965
|
|
|
38247
38966
|
// All managers are now stored in the managers collection and will be attached via attachToComponent()
|
|
38248
38967
|
}
|
|
@@ -39217,15 +39936,40 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
39217
39936
|
|
|
39218
39937
|
// Add attached IO device models for smart components
|
|
39219
39938
|
if (componentData.isSmart && componentData.attachedDevices) {
|
|
39939
|
+
var _this$centralPlant$sc8;
|
|
39220
39940
|
attachIODevicesToComponent(componentModel, componentData, modelPreloader, componentId);
|
|
39941
|
+
|
|
39942
|
+
// Register animation configs so IoAnimationManager can respond to state changes
|
|
39943
|
+
var ioAnimMgr = (_this$centralPlant$sc8 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc8 === void 0 || (_this$centralPlant$sc8 = _this$centralPlant$sc8.managers) === null || _this$centralPlant$sc8 === void 0 ? void 0 : _this$centralPlant$sc8.ioAnimationManager;
|
|
39944
|
+
if (ioAnimMgr) {
|
|
39945
|
+
var _loop = function _loop() {
|
|
39946
|
+
var _modelPreloader$compo;
|
|
39947
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
39948
|
+
attachmentId = _Object$entries$_i[0],
|
|
39949
|
+
attachment = _Object$entries$_i[1];
|
|
39950
|
+
var deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
|
|
39951
|
+
if (!(deviceData !== null && deviceData !== void 0 && deviceData.animationConfig)) return 1; // continue
|
|
39952
|
+
var deviceRoot = null;
|
|
39953
|
+
componentModel.traverse(function (obj) {
|
|
39954
|
+
var _obj$userData2;
|
|
39955
|
+
if (!deviceRoot && ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.attachmentId) === attachmentId) deviceRoot = obj;
|
|
39956
|
+
});
|
|
39957
|
+
if (deviceRoot) {
|
|
39958
|
+
ioAnimMgr.loadAnimations(attachmentId, deviceData.animationConfig, deviceRoot, componentId);
|
|
39959
|
+
}
|
|
39960
|
+
};
|
|
39961
|
+
for (var _i = 0, _Object$entries = Object.entries(componentData.attachedDevices); _i < _Object$entries.length; _i++) {
|
|
39962
|
+
if (_loop()) continue;
|
|
39963
|
+
}
|
|
39964
|
+
}
|
|
39221
39965
|
}
|
|
39222
39966
|
|
|
39223
39967
|
// Register default behaviors for smart components so the BehaviorManager
|
|
39224
39968
|
// responds to tooltip-driven state changes immediately after drop.
|
|
39225
39969
|
// (The scene-load path uses _processBehaviors instead, which runs on loadSceneData.)
|
|
39226
39970
|
if ((_componentData$defaul = componentData.defaultBehaviors) !== null && _componentData$defaul !== void 0 && _componentData$defaul.length) {
|
|
39227
|
-
var _this$centralPlant$
|
|
39228
|
-
var som = (_this$centralPlant$
|
|
39971
|
+
var _this$centralPlant$sc9, _som$registerBehavior;
|
|
39972
|
+
var som = (_this$centralPlant$sc9 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc9 === void 0 ? void 0 : _this$centralPlant$sc9.sceneOperationsManager;
|
|
39229
39973
|
som === null || som === void 0 || (_som$registerBehavior = som.registerBehaviorsForComponentInstance) === null || _som$registerBehavior === void 0 || _som$registerBehavior.call(som, componentData, componentId);
|
|
39230
39974
|
}
|
|
39231
39975
|
|
|
@@ -39234,6 +39978,20 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
39234
39978
|
componentManager.registerComponent(componentModel);
|
|
39235
39979
|
}
|
|
39236
39980
|
|
|
39981
|
+
// Pre-warm the filtered bounding-box cache for smart components so the
|
|
39982
|
+
// first selection is instant. Deferred to idle time so it does not
|
|
39983
|
+
// block the current frame.
|
|
39984
|
+
if (componentData.isSmart) {
|
|
39985
|
+
var warmFn = function warmFn() {
|
|
39986
|
+
return computeFilteredBoundingBoxCached(componentModel, ['io-device', 'connector']);
|
|
39987
|
+
};
|
|
39988
|
+
if (typeof requestIdleCallback !== 'undefined') {
|
|
39989
|
+
requestIdleCallback(warmFn);
|
|
39990
|
+
} else {
|
|
39991
|
+
setTimeout(warmFn, 0);
|
|
39992
|
+
}
|
|
39993
|
+
}
|
|
39994
|
+
|
|
39237
39995
|
// EMIT COMPONENT ADDED EVENT
|
|
39238
39996
|
// This allows UI components (like SceneHierarchy) to update reactively
|
|
39239
39997
|
if (this.centralPlant.sceneViewer.emit) {
|
|
@@ -39287,18 +40045,18 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
39287
40045
|
}, {
|
|
39288
40046
|
key: "deleteComponent",
|
|
39289
40047
|
value: function deleteComponent(componentId) {
|
|
39290
|
-
var _this$centralPlant$
|
|
40048
|
+
var _this$centralPlant$sc0;
|
|
39291
40049
|
// Check if component manager is available
|
|
39292
|
-
var componentManager = (_this$centralPlant$
|
|
40050
|
+
var componentManager = (_this$centralPlant$sc0 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc0 === void 0 ? void 0 : _this$centralPlant$sc0.componentManager;
|
|
39293
40051
|
if (!componentManager) {
|
|
39294
40052
|
console.error('❌ deleteComponent(): Component manager not available');
|
|
39295
40053
|
return false;
|
|
39296
40054
|
}
|
|
39297
40055
|
try {
|
|
39298
|
-
var _this$centralPlant$
|
|
40056
|
+
var _this$centralPlant$sc1, _this$centralPlant$sc10, _sceneData$scene2, _sceneData$scene3;
|
|
39299
40057
|
console.log("\uD83D\uDDD1\uFE0F deleteComponent(): Deleting component ".concat(componentId));
|
|
39300
|
-
var threeScene = (_this$centralPlant$
|
|
39301
|
-
var sceneData = (_this$centralPlant$
|
|
40058
|
+
var threeScene = (_this$centralPlant$sc1 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc1 === void 0 ? void 0 : _this$centralPlant$sc1.scene;
|
|
40059
|
+
var sceneData = (_this$centralPlant$sc10 = this.centralPlant.sceneViewer) === null || _this$centralPlant$sc10 === void 0 ? void 0 : _this$centralPlant$sc10.currentSceneData;
|
|
39302
40060
|
|
|
39303
40061
|
// Step 1: Resolve the actual Three.js UUID from componentId.
|
|
39304
40062
|
// The UI emits object.name (e.g. "Pump (PUMP-1)") as the selection ID, but
|
|
@@ -39342,8 +40100,8 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
39342
40100
|
// the component (e.g., dynamically added but not yet synced to sceneData)
|
|
39343
40101
|
if (connectorIds.size === 0 && threeScene) {
|
|
39344
40102
|
threeScene.traverse(function (obj) {
|
|
39345
|
-
var _obj$
|
|
39346
|
-
if ((obj.uuid === resolvedUuid || ((_obj$
|
|
40103
|
+
var _obj$userData3, _obj$userData4;
|
|
40104
|
+
if ((obj.uuid === resolvedUuid || ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.originalUuid) === resolvedUuid) && ((_obj$userData4 = obj.userData) === null || _obj$userData4 === void 0 ? void 0 : _obj$userData4.objectType) === 'component') {
|
|
39347
40105
|
obj.children.forEach(function (child) {
|
|
39348
40106
|
var _child$userData3;
|
|
39349
40107
|
if (((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) === 'connector') {
|
|
@@ -39393,12 +40151,12 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
39393
40151
|
if (connectorIds.size > 0 && threeScene) {
|
|
39394
40152
|
var objectsToRemove = [];
|
|
39395
40153
|
threeScene.traverse(function (obj) {
|
|
39396
|
-
var _obj$uuid, _obj$
|
|
39397
|
-
var isComputedSegment = ((_obj$uuid = obj.uuid) === null || _obj$uuid === void 0 ? void 0 : _obj$uuid.startsWith('SEGMENT-')) && ((_obj$
|
|
39398
|
-
var isComputedGateway = ((_obj$uuid2 = obj.uuid) === null || _obj$uuid2 === void 0 ? void 0 : _obj$uuid2.includes('Gateway')) && ((_obj$
|
|
40154
|
+
var _obj$uuid, _obj$userData5, _obj$uuid2, _obj$userData6;
|
|
40155
|
+
var isComputedSegment = ((_obj$uuid = obj.uuid) === null || _obj$uuid === void 0 ? void 0 : _obj$uuid.startsWith('SEGMENT-')) && ((_obj$userData5 = obj.userData) === null || _obj$userData5 === void 0 ? void 0 : _obj$userData5.isDeclared) !== true;
|
|
40156
|
+
var isComputedGateway = ((_obj$uuid2 = obj.uuid) === null || _obj$uuid2 === void 0 ? void 0 : _obj$uuid2.includes('Gateway')) && ((_obj$userData6 = obj.userData) === null || _obj$userData6 === void 0 ? void 0 : _obj$userData6.isDeclared) !== true;
|
|
39399
40157
|
if (isComputedSegment || isComputedGateway) {
|
|
39400
|
-
var _obj$
|
|
39401
|
-
if (connectorIds.has((_obj$
|
|
40158
|
+
var _obj$userData7, _obj$userData8;
|
|
40159
|
+
if (connectorIds.has((_obj$userData7 = obj.userData) === null || _obj$userData7 === void 0 ? void 0 : _obj$userData7.pathFrom) || connectorIds.has((_obj$userData8 = obj.userData) === null || _obj$userData8 === void 0 ? void 0 : _obj$userData8.pathTo)) {
|
|
39402
40160
|
objectsToRemove.push(obj);
|
|
39403
40161
|
}
|
|
39404
40162
|
}
|
|
@@ -39513,7 +40271,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
39513
40271
|
* Initialize the CentralPlant manager
|
|
39514
40272
|
*
|
|
39515
40273
|
* @constructor
|
|
39516
|
-
* @version 0.3.
|
|
40274
|
+
* @version 0.3.27
|
|
39517
40275
|
* @updated 2025-10-22
|
|
39518
40276
|
*
|
|
39519
40277
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -42530,7 +43288,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
42530
43288
|
this.centralPlant.attachToComponent();
|
|
42531
43289
|
|
|
42532
43290
|
// Sync our managers tracking object after attachment
|
|
42533
|
-
managerKeys = ['threeJSResourceManager', 'performanceMonitorManager', 'settingsManager', 'sceneExportManager', 'componentManager', 'sceneInitializationManager', 'environmentManager', 'keyboardControlsManager', 'pathfindingManager', 'pathFlowManager', 'behaviorManager', 'ioAnimationManager', 'sceneOperationsManager', 'animationManager', 'cameraControlsManager', 'componentDragManager', 'tooltipsManager', 'componentTooltipManager']; // Populate our managers tracking object
|
|
43291
|
+
managerKeys = ['threeJSResourceManager', 'performanceMonitorManager', 'settingsManager', 'sceneExportManager', 'componentManager', 'sceneInitializationManager', 'environmentManager', 'keyboardControlsManager', 'pathfindingManager', 'pathFlowManager', 'behaviorManager', 'ioAnimationManager', 'ioOutlineManager', 'sceneOperationsManager', 'animationManager', 'cameraControlsManager', 'componentDragManager', 'tooltipsManager', 'componentTooltipManager']; // Populate our managers tracking object
|
|
42534
43292
|
managerKeys.forEach(function (key) {
|
|
42535
43293
|
if (_this2[key]) {
|
|
42536
43294
|
_this2.managers[key] = _this2[key];
|
|
@@ -42718,7 +43476,21 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
42718
43476
|
}
|
|
42719
43477
|
|
|
42720
43478
|
// Update camera aspect ratio
|
|
42721
|
-
this.camera.
|
|
43479
|
+
if (this.camera.isPerspectiveCamera) {
|
|
43480
|
+
this.camera.aspect = width / height;
|
|
43481
|
+
} else if (this.camera.isOrthographicCamera) {
|
|
43482
|
+
var _this$camera$userData;
|
|
43483
|
+
var aspect = width / height;
|
|
43484
|
+
var extents = (_this$camera$userData = this.camera.userData) === null || _this$camera$userData === void 0 ? void 0 : _this$camera$userData._orthoHalfExtents;
|
|
43485
|
+
if (extents) {
|
|
43486
|
+
var frustumHalfH = Math.max(extents.halfH, extents.halfW / aspect);
|
|
43487
|
+
var frustumHalfW = frustumHalfH * aspect;
|
|
43488
|
+
this.camera.left = -frustumHalfW;
|
|
43489
|
+
this.camera.right = frustumHalfW;
|
|
43490
|
+
this.camera.top = frustumHalfH;
|
|
43491
|
+
this.camera.bottom = -frustumHalfH;
|
|
43492
|
+
}
|
|
43493
|
+
}
|
|
42722
43494
|
this.camera.updateProjectionMatrix();
|
|
42723
43495
|
|
|
42724
43496
|
// Update renderer size (updateStyle=true to sync canvas CSS)
|
|
@@ -42845,6 +43617,45 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
42845
43617
|
if (_this4.componentTooltipManager) {
|
|
42846
43618
|
_this4.componentTooltipManager.toggleIODeviceBinaryState(ioDeviceObject);
|
|
42847
43619
|
}
|
|
43620
|
+
},
|
|
43621
|
+
onIODeviceDrag: function onIODeviceDrag(ioDeviceObject, signedDelta, isStart) {
|
|
43622
|
+
if (isStart) {
|
|
43623
|
+
var _ioDeviceObject$userD, _this4$managers$ioAni, _this4$managers, _this4$managers2;
|
|
43624
|
+
// Resolve parentUuid by walking up to the host component.
|
|
43625
|
+
// Use userData.originalUuid (the custom componentId) because that
|
|
43626
|
+
// is what IoAnimationManager uses as the map key — NOT obj.uuid.
|
|
43627
|
+
var parentUuid = null;
|
|
43628
|
+
var obj = ioDeviceObject.parent;
|
|
43629
|
+
while (obj) {
|
|
43630
|
+
var _obj$userData;
|
|
43631
|
+
if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'component') {
|
|
43632
|
+
parentUuid = obj.userData.originalUuid || obj.uuid;
|
|
43633
|
+
break;
|
|
43634
|
+
}
|
|
43635
|
+
obj = obj.parent;
|
|
43636
|
+
}
|
|
43637
|
+
var attachmentId = (_ioDeviceObject$userD = ioDeviceObject.userData) === null || _ioDeviceObject$userD === void 0 ? void 0 : _ioDeviceObject$userD.attachmentId;
|
|
43638
|
+
// When animated meshes are available, outline ONLY them so their
|
|
43639
|
+
// silhouette is isolated and the outline ring is visible around
|
|
43640
|
+
// them specifically (not swallowed by the larger device body).
|
|
43641
|
+
// Fall back to the whole device group when none are registered.
|
|
43642
|
+
var animatedMeshes = attachmentId && parentUuid ? (_this4$managers$ioAni = (_this4$managers = _this4.managers) === null || _this4$managers === void 0 || (_this4$managers = _this4$managers.ioAnimationManager) === null || _this4$managers === void 0 ? void 0 : _this4$managers.getAnimatedMeshes(parentUuid, attachmentId)) !== null && _this4$managers$ioAni !== void 0 ? _this4$managers$ioAni : [] : [];
|
|
43643
|
+
var targets = animatedMeshes.length > 0 ? animatedMeshes : [ioDeviceObject];
|
|
43644
|
+
(_this4$managers2 = _this4.managers) === null || _this4$managers2 === void 0 || (_this4$managers2 = _this4$managers2.ioOutlineManager) === null || _this4$managers2 === void 0 || _this4$managers2.setTargets(targets);
|
|
43645
|
+
}
|
|
43646
|
+
if (!_this4.componentTooltipManager) return;
|
|
43647
|
+
if (isStart) {
|
|
43648
|
+
_this4.componentTooltipManager.startIODeviceDrag(ioDeviceObject);
|
|
43649
|
+
} else {
|
|
43650
|
+
_this4.componentTooltipManager.updateIODeviceDrag(signedDelta);
|
|
43651
|
+
}
|
|
43652
|
+
},
|
|
43653
|
+
onIODeviceDragEnd: function onIODeviceDragEnd(ioDeviceObject) {
|
|
43654
|
+
var _this4$managers3;
|
|
43655
|
+
(_this4$managers3 = _this4.managers) === null || _this4$managers3 === void 0 || (_this4$managers3 = _this4$managers3.ioOutlineManager) === null || _this4$managers3 === void 0 || _this4$managers3.setTargets([]);
|
|
43656
|
+
if (_this4.componentTooltipManager) {
|
|
43657
|
+
_this4.componentTooltipManager.endIODeviceDrag();
|
|
43658
|
+
}
|
|
42848
43659
|
}
|
|
42849
43660
|
});
|
|
42850
43661
|
|