@2112-lab/central-plant 0.3.29 → 0.3.31
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 +177 -64
- package/dist/cjs/src/core/centralPlant.js +1 -1
- package/dist/cjs/src/core/sceneViewer.js +2 -2
- package/dist/cjs/src/managers/behaviors/IoBehaviorManager.js +166 -57
- package/dist/cjs/src/managers/controls/transformControlsManager.js +6 -2
- package/dist/cjs/src/managers/scene/componentTooltipManager.js +2 -2
- package/dist/esm/src/core/centralPlant.js +1 -1
- package/dist/esm/src/core/sceneViewer.js +2 -2
- package/dist/esm/src/managers/behaviors/IoBehaviorManager.js +166 -57
- package/dist/esm/src/managers/controls/transformControlsManager.js +6 -2
- package/dist/esm/src/managers/scene/componentTooltipManager.js +2 -2
- package/package.json +1 -1
package/dist/bundle/index.js
CHANGED
|
@@ -4171,6 +4171,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4171
4171
|
raycaster.setFromCamera(mouse, _this4.camera);
|
|
4172
4172
|
var allIntersects = raycaster.intersectObjects(_this4.scene.children, true);
|
|
4173
4173
|
var ioDeviceObject = null;
|
|
4174
|
+
var hitMesh = null;
|
|
4174
4175
|
var _iterator = _createForOfIteratorHelper(allIntersects),
|
|
4175
4176
|
_step;
|
|
4176
4177
|
try {
|
|
@@ -4185,7 +4186,10 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4185
4186
|
}
|
|
4186
4187
|
obj = obj.parent;
|
|
4187
4188
|
}
|
|
4188
|
-
if (ioDeviceObject)
|
|
4189
|
+
if (ioDeviceObject) {
|
|
4190
|
+
hitMesh = hit.object;
|
|
4191
|
+
break;
|
|
4192
|
+
}
|
|
4189
4193
|
}
|
|
4190
4194
|
} catch (err) {
|
|
4191
4195
|
_iterator.e(err);
|
|
@@ -4200,7 +4204,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
4200
4204
|
_this4._ioDragStartY = event.clientY;
|
|
4201
4205
|
_this4._ioDragMoved = false;
|
|
4202
4206
|
if (_this4.orbitControls) _this4.orbitControls.enabled = false;
|
|
4203
|
-
_this4.callbacks.onIODeviceDrag(ioDeviceObject, 0, true);
|
|
4207
|
+
_this4.callbacks.onIODeviceDrag(ioDeviceObject, 0, true, hitMesh);
|
|
4204
4208
|
var onMove = function onMove(e) {
|
|
4205
4209
|
var dx = e.clientX - _this4._ioDragStartX;
|
|
4206
4210
|
var dy = e.clientY - _this4._ioDragStartY;
|
|
@@ -36669,7 +36673,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
36669
36673
|
*/
|
|
36670
36674
|
}, {
|
|
36671
36675
|
key: "startIODeviceDrag",
|
|
36672
|
-
value: function startIODeviceDrag(ioDeviceObject) {
|
|
36676
|
+
value: function startIODeviceDrag(ioDeviceObject, hitMesh) {
|
|
36673
36677
|
var _this$sceneViewer2,
|
|
36674
36678
|
_this2 = this;
|
|
36675
36679
|
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
@@ -36688,7 +36692,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
36688
36692
|
}
|
|
36689
36693
|
var scopedAttachmentId = this._getScopedAttachmentKey(attachmentId, parentUuid);
|
|
36690
36694
|
var ioBehavMgr = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 || (_this$sceneViewer2 = _this$sceneViewer2.managers) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.ioBehaviorManager;
|
|
36691
|
-
var dataPoints = ((ioBehavMgr === null || ioBehavMgr === void 0 ? void 0 : ioBehavMgr.getAnimationDataPoints(parentUuid, attachmentId)) || []).concat((ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [])
|
|
36695
|
+
var dataPoints = ((ioBehavMgr === null || ioBehavMgr === void 0 ? void 0 : ioBehavMgr.getAnimationDataPoints(parentUuid, attachmentId, hitMesh)) || []).concat((ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [])
|
|
36692
36696
|
// deduplicate by id
|
|
36693
36697
|
.filter(function (dp, i, arr) {
|
|
36694
36698
|
return arr.findIndex(function (d) {
|
|
@@ -37401,6 +37405,19 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37401
37405
|
if (!anims.length) return;
|
|
37402
37406
|
var key = this._key(parentUuid, attachmentId);
|
|
37403
37407
|
var entries = [];
|
|
37408
|
+
|
|
37409
|
+
// Capture the device root's world orientation once so each entry can
|
|
37410
|
+
// convert the configured axis from device-local space to world space.
|
|
37411
|
+
var deviceWorldQuat = new THREE__namespace.Quaternion();
|
|
37412
|
+
deviceModelRoot.getWorldQuaternion(deviceWorldQuat);
|
|
37413
|
+
|
|
37414
|
+
// Compute the model's native max dimension so rotAxisOffset values (stored
|
|
37415
|
+
// in dialog-viewer-world units, where the model is normalised to 1 unit)
|
|
37416
|
+
// can be scaled to runtime-world units. viewerMaxDim = 1 / ns_viewer.
|
|
37417
|
+
var _deviceBox = new THREE__namespace.Box3().setFromObject(deviceModelRoot);
|
|
37418
|
+
var _deviceSize = new THREE__namespace.Vector3();
|
|
37419
|
+
_deviceBox.getSize(_deviceSize);
|
|
37420
|
+
var viewerMaxDim = Math.max(_deviceSize.x, _deviceSize.y, _deviceSize.z) || 1;
|
|
37404
37421
|
var _iterator = _createForOfIteratorHelper(anims),
|
|
37405
37422
|
_step;
|
|
37406
37423
|
try {
|
|
@@ -37411,11 +37428,23 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37411
37428
|
console.warn("[IoBehaviorManager] Could not find mesh for animation \"".concat(anim.name || anim.stateVariable, "\" (uuid: ").concat(anim.meshUuid, ", name: \"").concat(anim.meshName, "\")"));
|
|
37412
37429
|
continue;
|
|
37413
37430
|
}
|
|
37431
|
+
var worldPos = new THREE__namespace.Vector3();
|
|
37432
|
+
mesh.getWorldPosition(worldPos);
|
|
37433
|
+
var worldQuat = new THREE__namespace.Quaternion();
|
|
37434
|
+
mesh.getWorldQuaternion(worldQuat);
|
|
37435
|
+
var box = new THREE__namespace.Box3().setFromObject(mesh);
|
|
37436
|
+
var worldCenter = new THREE__namespace.Vector3();
|
|
37437
|
+
if (!box.isEmpty()) box.getCenter(worldCenter);else worldCenter.copy(worldPos);
|
|
37414
37438
|
entries.push({
|
|
37415
37439
|
anim: anim,
|
|
37416
37440
|
mesh: mesh,
|
|
37417
37441
|
origPos: mesh.position.clone(),
|
|
37418
|
-
origRot: mesh.rotation.clone()
|
|
37442
|
+
origRot: mesh.rotation.clone(),
|
|
37443
|
+
origWorldPos: worldPos,
|
|
37444
|
+
origWorldQuat: worldQuat,
|
|
37445
|
+
origWorldCenter: worldCenter,
|
|
37446
|
+
deviceWorldQuat: deviceWorldQuat.clone(),
|
|
37447
|
+
viewerMaxDim: viewerMaxDim
|
|
37419
37448
|
});
|
|
37420
37449
|
}
|
|
37421
37450
|
} catch (err) {
|
|
@@ -37445,16 +37474,24 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37445
37474
|
}, {
|
|
37446
37475
|
key: "triggerState",
|
|
37447
37476
|
value: function triggerState(attachmentId, dataPointId, value, parentUuid) {
|
|
37448
|
-
var
|
|
37449
|
-
var entries = this._entries.get(key);
|
|
37450
|
-
if (!(entries !== null && entries !== void 0 && entries.length)) return;
|
|
37451
|
-
var _iterator2 = _createForOfIteratorHelper(entries),
|
|
37477
|
+
var _iterator2 = _createForOfIteratorHelper(this._entries.values()),
|
|
37452
37478
|
_step2;
|
|
37453
37479
|
try {
|
|
37454
37480
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
37455
|
-
var
|
|
37456
|
-
|
|
37457
|
-
|
|
37481
|
+
var entries = _step2.value;
|
|
37482
|
+
var _iterator3 = _createForOfIteratorHelper(entries),
|
|
37483
|
+
_step3;
|
|
37484
|
+
try {
|
|
37485
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
37486
|
+
var entry = _step3.value;
|
|
37487
|
+
if (entry.anim.stateVariable !== dataPointId) continue;
|
|
37488
|
+
this._applyAnimation(entry, value);
|
|
37489
|
+
}
|
|
37490
|
+
} catch (err) {
|
|
37491
|
+
_iterator3.e(err);
|
|
37492
|
+
} finally {
|
|
37493
|
+
_iterator3.f();
|
|
37494
|
+
}
|
|
37458
37495
|
}
|
|
37459
37496
|
} catch (err) {
|
|
37460
37497
|
_iterator2.e(err);
|
|
@@ -37489,34 +37526,47 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37489
37526
|
}, {
|
|
37490
37527
|
key: "getAnimationDataPoints",
|
|
37491
37528
|
value: function getAnimationDataPoints(parentUuid, attachmentId) {
|
|
37529
|
+
var _this2 = this;
|
|
37530
|
+
var hitMesh = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
37492
37531
|
var key = this._key(parentUuid, attachmentId);
|
|
37493
37532
|
var entries = this._entries.get(key);
|
|
37494
37533
|
if (!(entries !== null && entries !== void 0 && entries.length)) return [];
|
|
37495
37534
|
|
|
37535
|
+
// When a specific mesh was clicked, filter to only animations whose target
|
|
37536
|
+
// mesh is the clicked mesh or an ancestor of it (e.g. the clicked primitive
|
|
37537
|
+
// is inside a group that is the animation target).
|
|
37538
|
+
var filtered = entries;
|
|
37539
|
+
if (hitMesh) {
|
|
37540
|
+
var matching = entries.filter(function (e) {
|
|
37541
|
+
return _this2._isMeshOrDescendant(hitMesh, e.mesh);
|
|
37542
|
+
});
|
|
37543
|
+
if (matching.length > 0) filtered = matching;
|
|
37544
|
+
}
|
|
37545
|
+
|
|
37496
37546
|
// Collapse multiple mesh entries that share the same stateVariable
|
|
37497
37547
|
var seen = new Map(); // stateVariable → anim
|
|
37498
|
-
var
|
|
37499
|
-
|
|
37548
|
+
var _iterator4 = _createForOfIteratorHelper(filtered),
|
|
37549
|
+
_step4;
|
|
37500
37550
|
try {
|
|
37501
|
-
for (
|
|
37502
|
-
var anim =
|
|
37551
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
37552
|
+
var anim = _step4.value.anim;
|
|
37503
37553
|
if (!seen.has(anim.stateVariable)) {
|
|
37504
37554
|
seen.set(anim.stateVariable, anim);
|
|
37505
37555
|
}
|
|
37506
37556
|
}
|
|
37507
37557
|
} catch (err) {
|
|
37508
|
-
|
|
37558
|
+
_iterator4.e(err);
|
|
37509
37559
|
} finally {
|
|
37510
|
-
|
|
37560
|
+
_iterator4.f();
|
|
37511
37561
|
}
|
|
37512
37562
|
var dps = [];
|
|
37513
|
-
var
|
|
37514
|
-
|
|
37563
|
+
var _iterator5 = _createForOfIteratorHelper(seen),
|
|
37564
|
+
_step5;
|
|
37515
37565
|
try {
|
|
37516
|
-
for (
|
|
37517
|
-
var
|
|
37518
|
-
stateVar =
|
|
37519
|
-
_anim =
|
|
37566
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
37567
|
+
var _step5$value = _slicedToArray(_step5.value, 2),
|
|
37568
|
+
stateVar = _step5$value[0],
|
|
37569
|
+
_anim = _step5$value[1];
|
|
37520
37570
|
// Normalise stateType from AnimateDevicesDialog variants
|
|
37521
37571
|
var stateType = void 0;
|
|
37522
37572
|
var raw = (_anim.stateType || '').toLowerCase();
|
|
@@ -37567,9 +37617,9 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37567
37617
|
});
|
|
37568
37618
|
}
|
|
37569
37619
|
} catch (err) {
|
|
37570
|
-
|
|
37620
|
+
_iterator5.e(err);
|
|
37571
37621
|
} finally {
|
|
37572
|
-
|
|
37622
|
+
_iterator5.f();
|
|
37573
37623
|
}
|
|
37574
37624
|
return dps;
|
|
37575
37625
|
}
|
|
@@ -37604,19 +37654,19 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37604
37654
|
key: "unloadForComponent",
|
|
37605
37655
|
value: function unloadForComponent(parentUuid) {
|
|
37606
37656
|
var prefix = "".concat(parentUuid, "::");
|
|
37607
|
-
var
|
|
37608
|
-
|
|
37657
|
+
var _iterator6 = _createForOfIteratorHelper(this._entries.keys()),
|
|
37658
|
+
_step6;
|
|
37609
37659
|
try {
|
|
37610
|
-
for (
|
|
37611
|
-
var key =
|
|
37660
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
37661
|
+
var key = _step6.value;
|
|
37612
37662
|
if (key.startsWith(prefix)) {
|
|
37613
37663
|
this._entries.delete(key);
|
|
37614
37664
|
}
|
|
37615
37665
|
}
|
|
37616
37666
|
} catch (err) {
|
|
37617
|
-
|
|
37667
|
+
_iterator6.e(err);
|
|
37618
37668
|
} finally {
|
|
37619
|
-
|
|
37669
|
+
_iterator6.f();
|
|
37620
37670
|
}
|
|
37621
37671
|
}
|
|
37622
37672
|
}, {
|
|
@@ -37635,6 +37685,22 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37635
37685
|
return "".concat(parentUuid, "::").concat(attachmentId);
|
|
37636
37686
|
}
|
|
37637
37687
|
|
|
37688
|
+
/**
|
|
37689
|
+
* Returns true if `candidate` is `ancestor` or any descendant of `ancestor`.
|
|
37690
|
+
* @param {THREE.Object3D} candidate
|
|
37691
|
+
* @param {THREE.Object3D} ancestor
|
|
37692
|
+
*/
|
|
37693
|
+
}, {
|
|
37694
|
+
key: "_isMeshOrDescendant",
|
|
37695
|
+
value: function _isMeshOrDescendant(candidate, ancestor) {
|
|
37696
|
+
var obj = candidate;
|
|
37697
|
+
while (obj) {
|
|
37698
|
+
if (obj === ancestor) return true;
|
|
37699
|
+
obj = obj.parent;
|
|
37700
|
+
}
|
|
37701
|
+
return false;
|
|
37702
|
+
}
|
|
37703
|
+
|
|
37638
37704
|
/**
|
|
37639
37705
|
* Find the mesh inside `root` using UUID first, then name as fallback.
|
|
37640
37706
|
* GLTFLoader assigns fresh UUIDs on every load, so name is the reliable key.
|
|
@@ -37675,27 +37741,32 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37675
37741
|
var anim = entry.anim,
|
|
37676
37742
|
mesh = entry.mesh,
|
|
37677
37743
|
origPos = entry.origPos,
|
|
37678
|
-
origRot = entry.origRot
|
|
37744
|
+
origRot = entry.origRot,
|
|
37745
|
+
origWorldPos = entry.origWorldPos,
|
|
37746
|
+
origWorldQuat = entry.origWorldQuat,
|
|
37747
|
+
origWorldCenter = entry.origWorldCenter,
|
|
37748
|
+
deviceWorldQuat = entry.deviceWorldQuat,
|
|
37749
|
+
viewerMaxDim = entry.viewerMaxDim;
|
|
37679
37750
|
var mapping = this._resolveMapping(anim, value);
|
|
37680
37751
|
if (!mapping) return;
|
|
37681
37752
|
var types = anim.transformTypes || [];
|
|
37682
|
-
var
|
|
37683
|
-
|
|
37753
|
+
var _iterator7 = _createForOfIteratorHelper(types),
|
|
37754
|
+
_step7;
|
|
37684
37755
|
try {
|
|
37685
|
-
for (
|
|
37686
|
-
var type =
|
|
37756
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
37757
|
+
var type = _step7.value;
|
|
37687
37758
|
if (type === 'translation') {
|
|
37688
37759
|
this._applyTranslation(mesh, origPos, mapping.transform);
|
|
37689
37760
|
} else if (type === 'rotation') {
|
|
37690
|
-
this._applyRotation(mesh, origPos, origRot, anim, mapping.rotationTransform);
|
|
37761
|
+
this._applyRotation(mesh, origPos, origRot, anim, mapping.rotationTransform, origWorldPos, origWorldQuat, origWorldCenter, deviceWorldQuat, viewerMaxDim);
|
|
37691
37762
|
} else if (type === 'color') {
|
|
37692
37763
|
this._applyColor(mesh, mapping.colorTransform);
|
|
37693
37764
|
}
|
|
37694
37765
|
}
|
|
37695
37766
|
} catch (err) {
|
|
37696
|
-
|
|
37767
|
+
_iterator7.e(err);
|
|
37697
37768
|
} finally {
|
|
37698
|
-
|
|
37769
|
+
_iterator7.f();
|
|
37699
37770
|
}
|
|
37700
37771
|
}
|
|
37701
37772
|
|
|
@@ -37832,26 +37903,24 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37832
37903
|
}
|
|
37833
37904
|
|
|
37834
37905
|
/**
|
|
37835
|
-
* Apply a rotation around an arbitrary pivot point
|
|
37836
|
-
*
|
|
37837
|
-
*
|
|
37838
|
-
*
|
|
37839
|
-
* pivot = rotAxisOffset
|
|
37840
|
-
* delta = origPos - pivot
|
|
37841
|
-
* newDelta = rotate(delta, angle, axis)
|
|
37842
|
-
* newPos = pivot + newDelta
|
|
37843
|
-
* newRot[axis] = origRot[axis] + angle
|
|
37906
|
+
* Apply a rotation around an arbitrary pivot point using world-space quaternion
|
|
37907
|
+
* math matching the ReconstructionViewer's setMeshPreviewRotationAxis approach.
|
|
37908
|
+
* This ensures the runtime axis/pivot matches what the user configured in the
|
|
37909
|
+
* animation dialog, regardless of the device's parent transform in the scene.
|
|
37844
37910
|
*
|
|
37845
37911
|
* @param {THREE.Object3D} mesh
|
|
37846
|
-
* @param {THREE.Vector3} origPos
|
|
37847
|
-
* @param {THREE.Euler} origRot
|
|
37912
|
+
* @param {THREE.Vector3} origPos - local position at load time (unused, kept for signature compat)
|
|
37913
|
+
* @param {THREE.Euler} origRot - local rotation at load time (unused)
|
|
37848
37914
|
* @param {Object} anim
|
|
37849
|
-
* @param {number} angleDeg
|
|
37915
|
+
* @param {number} angleDeg - Degrees
|
|
37916
|
+
* @param {THREE.Vector3} origWorldPos - world position at load time
|
|
37917
|
+
* @param {THREE.Quaternion} origWorldQuat - world quaternion at load time
|
|
37918
|
+
* @param {THREE.Vector3} origWorldCenter - world bounding-box center at load time
|
|
37850
37919
|
*/
|
|
37851
37920
|
}, {
|
|
37852
37921
|
key: "_applyRotation",
|
|
37853
|
-
value: function _applyRotation(mesh, origPos, origRot, anim, angleDeg) {
|
|
37854
|
-
var _anim$rotAxis, _anim$rotAxisOffset
|
|
37922
|
+
value: function _applyRotation(mesh, origPos, origRot, anim, angleDeg, origWorldPos, origWorldQuat, origWorldCenter, deviceWorldQuat, viewerMaxDim) {
|
|
37923
|
+
var _anim$rotAxis, _anim$rotAxisOffset;
|
|
37855
37924
|
var angle = THREE__namespace.MathUtils.degToRad(typeof angleDeg === 'number' ? angleDeg : 0);
|
|
37856
37925
|
var axis = ((_anim$rotAxis = anim.rotAxis) !== null && _anim$rotAxis !== void 0 ? _anim$rotAxis : 'x').toLowerCase();
|
|
37857
37926
|
var off = (_anim$rotAxisOffset = anim.rotAxisOffset) !== null && _anim$rotAxisOffset !== void 0 ? _anim$rotAxisOffset : {
|
|
@@ -37860,13 +37929,57 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37860
37929
|
z: 0
|
|
37861
37930
|
};
|
|
37862
37931
|
|
|
37863
|
-
//
|
|
37864
|
-
var
|
|
37865
|
-
|
|
37866
|
-
|
|
37867
|
-
|
|
37868
|
-
|
|
37869
|
-
|
|
37932
|
+
// Local axis in the device's coordinate system
|
|
37933
|
+
var localAxisVec = new THREE__namespace.Vector3(axis === 'x' ? 1 : 0, axis === 'y' ? 1 : 0, axis === 'z' ? 1 : 0);
|
|
37934
|
+
if (origWorldPos && origWorldQuat && origWorldCenter) {
|
|
37935
|
+
// Transform the configured axis from device-local space into world space
|
|
37936
|
+
// so that 'X' means the device's local X, not the world X.
|
|
37937
|
+
var worldAxisVec = localAxisVec.clone().applyQuaternion(deviceWorldQuat || new THREE__namespace.Quaternion());
|
|
37938
|
+
|
|
37939
|
+
// rotAxisOffset is stored in dialog-viewer-world space where the model root
|
|
37940
|
+
// has been rotated Rot_Z(π) by default (ReconstructionViewer's else branch).
|
|
37941
|
+
// Translation uses the same convention and negates X/Y to compensate.
|
|
37942
|
+
// For rotation offset we apply the same compensation mathematically:
|
|
37943
|
+
// offset_runtime = deviceWorldQuat × Rot_Z(π) × offset_dialog × scale
|
|
37944
|
+
// This maps from dialog world space (post Z+180° flip) → model local → world.
|
|
37945
|
+
var scale = viewerMaxDim || 1;
|
|
37946
|
+
var rotZ180 = new THREE__namespace.Quaternion().setFromAxisAngle(new THREE__namespace.Vector3(0, 0, 1), Math.PI);
|
|
37947
|
+
var qCombined = (deviceWorldQuat || new THREE__namespace.Quaternion()).clone().multiply(rotZ180);
|
|
37948
|
+
var offWorld = new THREE__namespace.Vector3((off.x || 0) * scale, (off.y || 0) * scale, (off.z || 0) * scale).applyQuaternion(qCombined);
|
|
37949
|
+
var pivot = origWorldCenter.clone().add(offWorld);
|
|
37950
|
+
var deltaQuat = new THREE__namespace.Quaternion().setFromAxisAngle(worldAxisVec, angle);
|
|
37951
|
+
|
|
37952
|
+
// Rotate world position around pivot
|
|
37953
|
+
var offsetVec = origWorldPos.clone().sub(pivot);
|
|
37954
|
+
offsetVec.applyQuaternion(deltaQuat);
|
|
37955
|
+
var newWorldPos = pivot.clone().add(offsetVec);
|
|
37956
|
+
|
|
37957
|
+
// Compose world quaternion
|
|
37958
|
+
var newWorldQuat = deltaQuat.clone().multiply(origWorldQuat);
|
|
37959
|
+
|
|
37960
|
+
// Convert world position → parent local space
|
|
37961
|
+
if (mesh.parent) {
|
|
37962
|
+
mesh.parent.worldToLocal(newWorldPos);
|
|
37963
|
+
}
|
|
37964
|
+
mesh.position.copy(newWorldPos);
|
|
37965
|
+
|
|
37966
|
+
// Convert quaternion → parent local space
|
|
37967
|
+
if (mesh.parent) {
|
|
37968
|
+
var parentWorldQuat = new THREE__namespace.Quaternion();
|
|
37969
|
+
mesh.parent.getWorldQuaternion(parentWorldQuat);
|
|
37970
|
+
parentWorldQuat.invert();
|
|
37971
|
+
newWorldQuat.premultiply(parentWorldQuat);
|
|
37972
|
+
}
|
|
37973
|
+
mesh.quaternion.copy(newWorldQuat);
|
|
37974
|
+
} else {
|
|
37975
|
+
var _off$x, _off$y, _off$z;
|
|
37976
|
+
// Fallback for entries loaded without world data
|
|
37977
|
+
var _pivot = new THREE__namespace.Vector3((_off$x = off.x) !== null && _off$x !== void 0 ? _off$x : 0, (_off$y = off.y) !== null && _off$y !== void 0 ? _off$y : 0, (_off$z = off.z) !== null && _off$z !== void 0 ? _off$z : 0);
|
|
37978
|
+
var delta = origPos.clone().sub(_pivot);
|
|
37979
|
+
delta.applyAxisAngle(localAxisVec, angle);
|
|
37980
|
+
mesh.position.copy(_pivot).add(delta);
|
|
37981
|
+
mesh.rotation[axis] = origRot[axis] + angle;
|
|
37982
|
+
}
|
|
37870
37983
|
}
|
|
37871
37984
|
|
|
37872
37985
|
/**
|
|
@@ -39550,7 +39663,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
39550
39663
|
* Initialize the CentralPlant manager
|
|
39551
39664
|
*
|
|
39552
39665
|
* @constructor
|
|
39553
|
-
* @version 0.3.
|
|
39666
|
+
* @version 0.3.31
|
|
39554
39667
|
* @updated 2025-10-22
|
|
39555
39668
|
*
|
|
39556
39669
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -42790,7 +42903,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
42790
42903
|
_this4.componentTooltipManager.toggleIODeviceBinaryState(ioDeviceObject);
|
|
42791
42904
|
}
|
|
42792
42905
|
},
|
|
42793
|
-
onIODeviceDrag: function onIODeviceDrag(ioDeviceObject, signedDelta, isStart) {
|
|
42906
|
+
onIODeviceDrag: function onIODeviceDrag(ioDeviceObject, signedDelta, isStart, hitMesh) {
|
|
42794
42907
|
if (isStart) {
|
|
42795
42908
|
var _ioDeviceObject$userD, _this4$managers$ioBeh, _this4$managers, _this4$managers2;
|
|
42796
42909
|
// Resolve parentUuid by walking up to the host component.
|
|
@@ -42817,7 +42930,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
42817
42930
|
}
|
|
42818
42931
|
if (!_this4.componentTooltipManager) return;
|
|
42819
42932
|
if (isStart) {
|
|
42820
|
-
_this4.componentTooltipManager.startIODeviceDrag(ioDeviceObject);
|
|
42933
|
+
_this4.componentTooltipManager.startIODeviceDrag(ioDeviceObject, hitMesh);
|
|
42821
42934
|
} else {
|
|
42822
42935
|
_this4.componentTooltipManager.updateIODeviceDrag(signedDelta);
|
|
42823
42936
|
}
|
|
@@ -35,7 +35,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
35
35
|
* Initialize the CentralPlant manager
|
|
36
36
|
*
|
|
37
37
|
* @constructor
|
|
38
|
-
* @version 0.3.
|
|
38
|
+
* @version 0.3.31
|
|
39
39
|
* @updated 2025-10-22
|
|
40
40
|
*
|
|
41
41
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -432,7 +432,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
432
432
|
_this4.componentTooltipManager.toggleIODeviceBinaryState(ioDeviceObject);
|
|
433
433
|
}
|
|
434
434
|
},
|
|
435
|
-
onIODeviceDrag: function onIODeviceDrag(ioDeviceObject, signedDelta, isStart) {
|
|
435
|
+
onIODeviceDrag: function onIODeviceDrag(ioDeviceObject, signedDelta, isStart, hitMesh) {
|
|
436
436
|
if (isStart) {
|
|
437
437
|
var _ioDeviceObject$userD, _this4$managers$ioBeh, _this4$managers, _this4$managers2;
|
|
438
438
|
// Resolve parentUuid by walking up to the host component.
|
|
@@ -459,7 +459,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
459
459
|
}
|
|
460
460
|
if (!_this4.componentTooltipManager) return;
|
|
461
461
|
if (isStart) {
|
|
462
|
-
_this4.componentTooltipManager.startIODeviceDrag(ioDeviceObject);
|
|
462
|
+
_this4.componentTooltipManager.startIODeviceDrag(ioDeviceObject, hitMesh);
|
|
463
463
|
} else {
|
|
464
464
|
_this4.componentTooltipManager.updateIODeviceDrag(signedDelta);
|
|
465
465
|
}
|
|
@@ -70,6 +70,19 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
70
70
|
if (!anims.length) return;
|
|
71
71
|
var key = this._key(parentUuid, attachmentId);
|
|
72
72
|
var entries = [];
|
|
73
|
+
|
|
74
|
+
// Capture the device root's world orientation once so each entry can
|
|
75
|
+
// convert the configured axis from device-local space to world space.
|
|
76
|
+
var deviceWorldQuat = new THREE__namespace.Quaternion();
|
|
77
|
+
deviceModelRoot.getWorldQuaternion(deviceWorldQuat);
|
|
78
|
+
|
|
79
|
+
// Compute the model's native max dimension so rotAxisOffset values (stored
|
|
80
|
+
// in dialog-viewer-world units, where the model is normalised to 1 unit)
|
|
81
|
+
// can be scaled to runtime-world units. viewerMaxDim = 1 / ns_viewer.
|
|
82
|
+
var _deviceBox = new THREE__namespace.Box3().setFromObject(deviceModelRoot);
|
|
83
|
+
var _deviceSize = new THREE__namespace.Vector3();
|
|
84
|
+
_deviceBox.getSize(_deviceSize);
|
|
85
|
+
var viewerMaxDim = Math.max(_deviceSize.x, _deviceSize.y, _deviceSize.z) || 1;
|
|
73
86
|
var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(anims),
|
|
74
87
|
_step;
|
|
75
88
|
try {
|
|
@@ -80,11 +93,23 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
80
93
|
console.warn("[IoBehaviorManager] Could not find mesh for animation \"".concat(anim.name || anim.stateVariable, "\" (uuid: ").concat(anim.meshUuid, ", name: \"").concat(anim.meshName, "\")"));
|
|
81
94
|
continue;
|
|
82
95
|
}
|
|
96
|
+
var worldPos = new THREE__namespace.Vector3();
|
|
97
|
+
mesh.getWorldPosition(worldPos);
|
|
98
|
+
var worldQuat = new THREE__namespace.Quaternion();
|
|
99
|
+
mesh.getWorldQuaternion(worldQuat);
|
|
100
|
+
var box = new THREE__namespace.Box3().setFromObject(mesh);
|
|
101
|
+
var worldCenter = new THREE__namespace.Vector3();
|
|
102
|
+
if (!box.isEmpty()) box.getCenter(worldCenter);else worldCenter.copy(worldPos);
|
|
83
103
|
entries.push({
|
|
84
104
|
anim: anim,
|
|
85
105
|
mesh: mesh,
|
|
86
106
|
origPos: mesh.position.clone(),
|
|
87
|
-
origRot: mesh.rotation.clone()
|
|
107
|
+
origRot: mesh.rotation.clone(),
|
|
108
|
+
origWorldPos: worldPos,
|
|
109
|
+
origWorldQuat: worldQuat,
|
|
110
|
+
origWorldCenter: worldCenter,
|
|
111
|
+
deviceWorldQuat: deviceWorldQuat.clone(),
|
|
112
|
+
viewerMaxDim: viewerMaxDim
|
|
88
113
|
});
|
|
89
114
|
}
|
|
90
115
|
} catch (err) {
|
|
@@ -114,16 +139,24 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
114
139
|
}, {
|
|
115
140
|
key: "triggerState",
|
|
116
141
|
value: function triggerState(attachmentId, dataPointId, value, parentUuid) {
|
|
117
|
-
var
|
|
118
|
-
var entries = this._entries.get(key);
|
|
119
|
-
if (!(entries !== null && entries !== void 0 && entries.length)) return;
|
|
120
|
-
var _iterator2 = _rollupPluginBabelHelpers.createForOfIteratorHelper(entries),
|
|
142
|
+
var _iterator2 = _rollupPluginBabelHelpers.createForOfIteratorHelper(this._entries.values()),
|
|
121
143
|
_step2;
|
|
122
144
|
try {
|
|
123
145
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
124
|
-
var
|
|
125
|
-
|
|
126
|
-
|
|
146
|
+
var entries = _step2.value;
|
|
147
|
+
var _iterator3 = _rollupPluginBabelHelpers.createForOfIteratorHelper(entries),
|
|
148
|
+
_step3;
|
|
149
|
+
try {
|
|
150
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
151
|
+
var entry = _step3.value;
|
|
152
|
+
if (entry.anim.stateVariable !== dataPointId) continue;
|
|
153
|
+
this._applyAnimation(entry, value);
|
|
154
|
+
}
|
|
155
|
+
} catch (err) {
|
|
156
|
+
_iterator3.e(err);
|
|
157
|
+
} finally {
|
|
158
|
+
_iterator3.f();
|
|
159
|
+
}
|
|
127
160
|
}
|
|
128
161
|
} catch (err) {
|
|
129
162
|
_iterator2.e(err);
|
|
@@ -158,34 +191,47 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
158
191
|
}, {
|
|
159
192
|
key: "getAnimationDataPoints",
|
|
160
193
|
value: function getAnimationDataPoints(parentUuid, attachmentId) {
|
|
194
|
+
var _this2 = this;
|
|
195
|
+
var hitMesh = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
161
196
|
var key = this._key(parentUuid, attachmentId);
|
|
162
197
|
var entries = this._entries.get(key);
|
|
163
198
|
if (!(entries !== null && entries !== void 0 && entries.length)) return [];
|
|
164
199
|
|
|
200
|
+
// When a specific mesh was clicked, filter to only animations whose target
|
|
201
|
+
// mesh is the clicked mesh or an ancestor of it (e.g. the clicked primitive
|
|
202
|
+
// is inside a group that is the animation target).
|
|
203
|
+
var filtered = entries;
|
|
204
|
+
if (hitMesh) {
|
|
205
|
+
var matching = entries.filter(function (e) {
|
|
206
|
+
return _this2._isMeshOrDescendant(hitMesh, e.mesh);
|
|
207
|
+
});
|
|
208
|
+
if (matching.length > 0) filtered = matching;
|
|
209
|
+
}
|
|
210
|
+
|
|
165
211
|
// Collapse multiple mesh entries that share the same stateVariable
|
|
166
212
|
var seen = new Map(); // stateVariable → anim
|
|
167
|
-
var
|
|
168
|
-
|
|
213
|
+
var _iterator4 = _rollupPluginBabelHelpers.createForOfIteratorHelper(filtered),
|
|
214
|
+
_step4;
|
|
169
215
|
try {
|
|
170
|
-
for (
|
|
171
|
-
var anim =
|
|
216
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
217
|
+
var anim = _step4.value.anim;
|
|
172
218
|
if (!seen.has(anim.stateVariable)) {
|
|
173
219
|
seen.set(anim.stateVariable, anim);
|
|
174
220
|
}
|
|
175
221
|
}
|
|
176
222
|
} catch (err) {
|
|
177
|
-
|
|
223
|
+
_iterator4.e(err);
|
|
178
224
|
} finally {
|
|
179
|
-
|
|
225
|
+
_iterator4.f();
|
|
180
226
|
}
|
|
181
227
|
var dps = [];
|
|
182
|
-
var
|
|
183
|
-
|
|
228
|
+
var _iterator5 = _rollupPluginBabelHelpers.createForOfIteratorHelper(seen),
|
|
229
|
+
_step5;
|
|
184
230
|
try {
|
|
185
|
-
for (
|
|
186
|
-
var
|
|
187
|
-
stateVar =
|
|
188
|
-
_anim =
|
|
231
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
232
|
+
var _step5$value = _rollupPluginBabelHelpers.slicedToArray(_step5.value, 2),
|
|
233
|
+
stateVar = _step5$value[0],
|
|
234
|
+
_anim = _step5$value[1];
|
|
189
235
|
// Normalise stateType from AnimateDevicesDialog variants
|
|
190
236
|
var stateType = void 0;
|
|
191
237
|
var raw = (_anim.stateType || '').toLowerCase();
|
|
@@ -236,9 +282,9 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
236
282
|
});
|
|
237
283
|
}
|
|
238
284
|
} catch (err) {
|
|
239
|
-
|
|
285
|
+
_iterator5.e(err);
|
|
240
286
|
} finally {
|
|
241
|
-
|
|
287
|
+
_iterator5.f();
|
|
242
288
|
}
|
|
243
289
|
return dps;
|
|
244
290
|
}
|
|
@@ -273,19 +319,19 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
273
319
|
key: "unloadForComponent",
|
|
274
320
|
value: function unloadForComponent(parentUuid) {
|
|
275
321
|
var prefix = "".concat(parentUuid, "::");
|
|
276
|
-
var
|
|
277
|
-
|
|
322
|
+
var _iterator6 = _rollupPluginBabelHelpers.createForOfIteratorHelper(this._entries.keys()),
|
|
323
|
+
_step6;
|
|
278
324
|
try {
|
|
279
|
-
for (
|
|
280
|
-
var key =
|
|
325
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
326
|
+
var key = _step6.value;
|
|
281
327
|
if (key.startsWith(prefix)) {
|
|
282
328
|
this._entries.delete(key);
|
|
283
329
|
}
|
|
284
330
|
}
|
|
285
331
|
} catch (err) {
|
|
286
|
-
|
|
332
|
+
_iterator6.e(err);
|
|
287
333
|
} finally {
|
|
288
|
-
|
|
334
|
+
_iterator6.f();
|
|
289
335
|
}
|
|
290
336
|
}
|
|
291
337
|
}, {
|
|
@@ -304,6 +350,22 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
304
350
|
return "".concat(parentUuid, "::").concat(attachmentId);
|
|
305
351
|
}
|
|
306
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Returns true if `candidate` is `ancestor` or any descendant of `ancestor`.
|
|
355
|
+
* @param {THREE.Object3D} candidate
|
|
356
|
+
* @param {THREE.Object3D} ancestor
|
|
357
|
+
*/
|
|
358
|
+
}, {
|
|
359
|
+
key: "_isMeshOrDescendant",
|
|
360
|
+
value: function _isMeshOrDescendant(candidate, ancestor) {
|
|
361
|
+
var obj = candidate;
|
|
362
|
+
while (obj) {
|
|
363
|
+
if (obj === ancestor) return true;
|
|
364
|
+
obj = obj.parent;
|
|
365
|
+
}
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
|
|
307
369
|
/**
|
|
308
370
|
* Find the mesh inside `root` using UUID first, then name as fallback.
|
|
309
371
|
* GLTFLoader assigns fresh UUIDs on every load, so name is the reliable key.
|
|
@@ -344,27 +406,32 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
344
406
|
var anim = entry.anim,
|
|
345
407
|
mesh = entry.mesh,
|
|
346
408
|
origPos = entry.origPos,
|
|
347
|
-
origRot = entry.origRot
|
|
409
|
+
origRot = entry.origRot,
|
|
410
|
+
origWorldPos = entry.origWorldPos,
|
|
411
|
+
origWorldQuat = entry.origWorldQuat,
|
|
412
|
+
origWorldCenter = entry.origWorldCenter,
|
|
413
|
+
deviceWorldQuat = entry.deviceWorldQuat,
|
|
414
|
+
viewerMaxDim = entry.viewerMaxDim;
|
|
348
415
|
var mapping = this._resolveMapping(anim, value);
|
|
349
416
|
if (!mapping) return;
|
|
350
417
|
var types = anim.transformTypes || [];
|
|
351
|
-
var
|
|
352
|
-
|
|
418
|
+
var _iterator7 = _rollupPluginBabelHelpers.createForOfIteratorHelper(types),
|
|
419
|
+
_step7;
|
|
353
420
|
try {
|
|
354
|
-
for (
|
|
355
|
-
var type =
|
|
421
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
422
|
+
var type = _step7.value;
|
|
356
423
|
if (type === 'translation') {
|
|
357
424
|
this._applyTranslation(mesh, origPos, mapping.transform);
|
|
358
425
|
} else if (type === 'rotation') {
|
|
359
|
-
this._applyRotation(mesh, origPos, origRot, anim, mapping.rotationTransform);
|
|
426
|
+
this._applyRotation(mesh, origPos, origRot, anim, mapping.rotationTransform, origWorldPos, origWorldQuat, origWorldCenter, deviceWorldQuat, viewerMaxDim);
|
|
360
427
|
} else if (type === 'color') {
|
|
361
428
|
this._applyColor(mesh, mapping.colorTransform);
|
|
362
429
|
}
|
|
363
430
|
}
|
|
364
431
|
} catch (err) {
|
|
365
|
-
|
|
432
|
+
_iterator7.e(err);
|
|
366
433
|
} finally {
|
|
367
|
-
|
|
434
|
+
_iterator7.f();
|
|
368
435
|
}
|
|
369
436
|
}
|
|
370
437
|
|
|
@@ -501,26 +568,24 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
501
568
|
}
|
|
502
569
|
|
|
503
570
|
/**
|
|
504
|
-
* Apply a rotation around an arbitrary pivot point
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
* pivot = rotAxisOffset
|
|
509
|
-
* delta = origPos - pivot
|
|
510
|
-
* newDelta = rotate(delta, angle, axis)
|
|
511
|
-
* newPos = pivot + newDelta
|
|
512
|
-
* newRot[axis] = origRot[axis] + angle
|
|
571
|
+
* Apply a rotation around an arbitrary pivot point using world-space quaternion
|
|
572
|
+
* math matching the ReconstructionViewer's setMeshPreviewRotationAxis approach.
|
|
573
|
+
* This ensures the runtime axis/pivot matches what the user configured in the
|
|
574
|
+
* animation dialog, regardless of the device's parent transform in the scene.
|
|
513
575
|
*
|
|
514
576
|
* @param {THREE.Object3D} mesh
|
|
515
|
-
* @param {THREE.Vector3} origPos
|
|
516
|
-
* @param {THREE.Euler} origRot
|
|
577
|
+
* @param {THREE.Vector3} origPos - local position at load time (unused, kept for signature compat)
|
|
578
|
+
* @param {THREE.Euler} origRot - local rotation at load time (unused)
|
|
517
579
|
* @param {Object} anim
|
|
518
|
-
* @param {number} angleDeg
|
|
580
|
+
* @param {number} angleDeg - Degrees
|
|
581
|
+
* @param {THREE.Vector3} origWorldPos - world position at load time
|
|
582
|
+
* @param {THREE.Quaternion} origWorldQuat - world quaternion at load time
|
|
583
|
+
* @param {THREE.Vector3} origWorldCenter - world bounding-box center at load time
|
|
519
584
|
*/
|
|
520
585
|
}, {
|
|
521
586
|
key: "_applyRotation",
|
|
522
|
-
value: function _applyRotation(mesh, origPos, origRot, anim, angleDeg) {
|
|
523
|
-
var _anim$rotAxis, _anim$rotAxisOffset
|
|
587
|
+
value: function _applyRotation(mesh, origPos, origRot, anim, angleDeg, origWorldPos, origWorldQuat, origWorldCenter, deviceWorldQuat, viewerMaxDim) {
|
|
588
|
+
var _anim$rotAxis, _anim$rotAxisOffset;
|
|
524
589
|
var angle = THREE__namespace.MathUtils.degToRad(typeof angleDeg === 'number' ? angleDeg : 0);
|
|
525
590
|
var axis = ((_anim$rotAxis = anim.rotAxis) !== null && _anim$rotAxis !== void 0 ? _anim$rotAxis : 'x').toLowerCase();
|
|
526
591
|
var off = (_anim$rotAxisOffset = anim.rotAxisOffset) !== null && _anim$rotAxisOffset !== void 0 ? _anim$rotAxisOffset : {
|
|
@@ -529,13 +594,57 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
529
594
|
z: 0
|
|
530
595
|
};
|
|
531
596
|
|
|
532
|
-
//
|
|
533
|
-
var
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
597
|
+
// Local axis in the device's coordinate system
|
|
598
|
+
var localAxisVec = new THREE__namespace.Vector3(axis === 'x' ? 1 : 0, axis === 'y' ? 1 : 0, axis === 'z' ? 1 : 0);
|
|
599
|
+
if (origWorldPos && origWorldQuat && origWorldCenter) {
|
|
600
|
+
// Transform the configured axis from device-local space into world space
|
|
601
|
+
// so that 'X' means the device's local X, not the world X.
|
|
602
|
+
var worldAxisVec = localAxisVec.clone().applyQuaternion(deviceWorldQuat || new THREE__namespace.Quaternion());
|
|
603
|
+
|
|
604
|
+
// rotAxisOffset is stored in dialog-viewer-world space where the model root
|
|
605
|
+
// has been rotated Rot_Z(π) by default (ReconstructionViewer's else branch).
|
|
606
|
+
// Translation uses the same convention and negates X/Y to compensate.
|
|
607
|
+
// For rotation offset we apply the same compensation mathematically:
|
|
608
|
+
// offset_runtime = deviceWorldQuat × Rot_Z(π) × offset_dialog × scale
|
|
609
|
+
// This maps from dialog world space (post Z+180° flip) → model local → world.
|
|
610
|
+
var scale = viewerMaxDim || 1;
|
|
611
|
+
var rotZ180 = new THREE__namespace.Quaternion().setFromAxisAngle(new THREE__namespace.Vector3(0, 0, 1), Math.PI);
|
|
612
|
+
var qCombined = (deviceWorldQuat || new THREE__namespace.Quaternion()).clone().multiply(rotZ180);
|
|
613
|
+
var offWorld = new THREE__namespace.Vector3((off.x || 0) * scale, (off.y || 0) * scale, (off.z || 0) * scale).applyQuaternion(qCombined);
|
|
614
|
+
var pivot = origWorldCenter.clone().add(offWorld);
|
|
615
|
+
var deltaQuat = new THREE__namespace.Quaternion().setFromAxisAngle(worldAxisVec, angle);
|
|
616
|
+
|
|
617
|
+
// Rotate world position around pivot
|
|
618
|
+
var offsetVec = origWorldPos.clone().sub(pivot);
|
|
619
|
+
offsetVec.applyQuaternion(deltaQuat);
|
|
620
|
+
var newWorldPos = pivot.clone().add(offsetVec);
|
|
621
|
+
|
|
622
|
+
// Compose world quaternion
|
|
623
|
+
var newWorldQuat = deltaQuat.clone().multiply(origWorldQuat);
|
|
624
|
+
|
|
625
|
+
// Convert world position → parent local space
|
|
626
|
+
if (mesh.parent) {
|
|
627
|
+
mesh.parent.worldToLocal(newWorldPos);
|
|
628
|
+
}
|
|
629
|
+
mesh.position.copy(newWorldPos);
|
|
630
|
+
|
|
631
|
+
// Convert quaternion → parent local space
|
|
632
|
+
if (mesh.parent) {
|
|
633
|
+
var parentWorldQuat = new THREE__namespace.Quaternion();
|
|
634
|
+
mesh.parent.getWorldQuaternion(parentWorldQuat);
|
|
635
|
+
parentWorldQuat.invert();
|
|
636
|
+
newWorldQuat.premultiply(parentWorldQuat);
|
|
637
|
+
}
|
|
638
|
+
mesh.quaternion.copy(newWorldQuat);
|
|
639
|
+
} else {
|
|
640
|
+
var _off$x, _off$y, _off$z;
|
|
641
|
+
// Fallback for entries loaded without world data
|
|
642
|
+
var _pivot = new THREE__namespace.Vector3((_off$x = off.x) !== null && _off$x !== void 0 ? _off$x : 0, (_off$y = off.y) !== null && _off$y !== void 0 ? _off$y : 0, (_off$z = off.z) !== null && _off$z !== void 0 ? _off$z : 0);
|
|
643
|
+
var delta = origPos.clone().sub(_pivot);
|
|
644
|
+
delta.applyAxisAngle(localAxisVec, angle);
|
|
645
|
+
mesh.position.copy(_pivot).add(delta);
|
|
646
|
+
mesh.rotation[axis] = origRot[axis] + angle;
|
|
647
|
+
}
|
|
539
648
|
}
|
|
540
649
|
|
|
541
650
|
/**
|
|
@@ -469,6 +469,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
469
469
|
raycaster.setFromCamera(mouse, _this4.camera);
|
|
470
470
|
var allIntersects = raycaster.intersectObjects(_this4.scene.children, true);
|
|
471
471
|
var ioDeviceObject = null;
|
|
472
|
+
var hitMesh = null;
|
|
472
473
|
var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(allIntersects),
|
|
473
474
|
_step;
|
|
474
475
|
try {
|
|
@@ -483,7 +484,10 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
483
484
|
}
|
|
484
485
|
obj = obj.parent;
|
|
485
486
|
}
|
|
486
|
-
if (ioDeviceObject)
|
|
487
|
+
if (ioDeviceObject) {
|
|
488
|
+
hitMesh = hit.object;
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
487
491
|
}
|
|
488
492
|
} catch (err) {
|
|
489
493
|
_iterator.e(err);
|
|
@@ -498,7 +502,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
498
502
|
_this4._ioDragStartY = event.clientY;
|
|
499
503
|
_this4._ioDragMoved = false;
|
|
500
504
|
if (_this4.orbitControls) _this4.orbitControls.enabled = false;
|
|
501
|
-
_this4.callbacks.onIODeviceDrag(ioDeviceObject, 0, true);
|
|
505
|
+
_this4.callbacks.onIODeviceDrag(ioDeviceObject, 0, true, hitMesh);
|
|
502
506
|
var onMove = function onMove(e) {
|
|
503
507
|
var dx = e.clientX - _this4._ioDragStartX;
|
|
504
508
|
var dy = e.clientY - _this4._ioDragStartY;
|
|
@@ -178,7 +178,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
178
178
|
*/
|
|
179
179
|
}, {
|
|
180
180
|
key: "startIODeviceDrag",
|
|
181
|
-
value: function startIODeviceDrag(ioDeviceObject) {
|
|
181
|
+
value: function startIODeviceDrag(ioDeviceObject, hitMesh) {
|
|
182
182
|
var _this$sceneViewer2,
|
|
183
183
|
_this2 = this;
|
|
184
184
|
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
@@ -197,7 +197,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
197
197
|
}
|
|
198
198
|
var scopedAttachmentId = this._getScopedAttachmentKey(attachmentId, parentUuid);
|
|
199
199
|
var ioBehavMgr = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 || (_this$sceneViewer2 = _this$sceneViewer2.managers) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.ioBehaviorManager;
|
|
200
|
-
var dataPoints = ((ioBehavMgr === null || ioBehavMgr === void 0 ? void 0 : ioBehavMgr.getAnimationDataPoints(parentUuid, attachmentId)) || []).concat((ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [])
|
|
200
|
+
var dataPoints = ((ioBehavMgr === null || ioBehavMgr === void 0 ? void 0 : ioBehavMgr.getAnimationDataPoints(parentUuid, attachmentId, hitMesh)) || []).concat((ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [])
|
|
201
201
|
// deduplicate by id
|
|
202
202
|
.filter(function (dp, i, arr) {
|
|
203
203
|
return arr.findIndex(function (d) {
|
|
@@ -31,7 +31,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
31
31
|
* Initialize the CentralPlant manager
|
|
32
32
|
*
|
|
33
33
|
* @constructor
|
|
34
|
-
* @version 0.3.
|
|
34
|
+
* @version 0.3.31
|
|
35
35
|
* @updated 2025-10-22
|
|
36
36
|
*
|
|
37
37
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -428,7 +428,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
428
428
|
_this4.componentTooltipManager.toggleIODeviceBinaryState(ioDeviceObject);
|
|
429
429
|
}
|
|
430
430
|
},
|
|
431
|
-
onIODeviceDrag: function onIODeviceDrag(ioDeviceObject, signedDelta, isStart) {
|
|
431
|
+
onIODeviceDrag: function onIODeviceDrag(ioDeviceObject, signedDelta, isStart, hitMesh) {
|
|
432
432
|
if (isStart) {
|
|
433
433
|
var _ioDeviceObject$userD, _this4$managers$ioBeh, _this4$managers, _this4$managers2;
|
|
434
434
|
// Resolve parentUuid by walking up to the host component.
|
|
@@ -455,7 +455,7 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
455
455
|
}
|
|
456
456
|
if (!_this4.componentTooltipManager) return;
|
|
457
457
|
if (isStart) {
|
|
458
|
-
_this4.componentTooltipManager.startIODeviceDrag(ioDeviceObject);
|
|
458
|
+
_this4.componentTooltipManager.startIODeviceDrag(ioDeviceObject, hitMesh);
|
|
459
459
|
} else {
|
|
460
460
|
_this4.componentTooltipManager.updateIODeviceDrag(signedDelta);
|
|
461
461
|
}
|
|
@@ -46,6 +46,19 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
46
46
|
if (!anims.length) return;
|
|
47
47
|
var key = this._key(parentUuid, attachmentId);
|
|
48
48
|
var entries = [];
|
|
49
|
+
|
|
50
|
+
// Capture the device root's world orientation once so each entry can
|
|
51
|
+
// convert the configured axis from device-local space to world space.
|
|
52
|
+
var deviceWorldQuat = new THREE.Quaternion();
|
|
53
|
+
deviceModelRoot.getWorldQuaternion(deviceWorldQuat);
|
|
54
|
+
|
|
55
|
+
// Compute the model's native max dimension so rotAxisOffset values (stored
|
|
56
|
+
// in dialog-viewer-world units, where the model is normalised to 1 unit)
|
|
57
|
+
// can be scaled to runtime-world units. viewerMaxDim = 1 / ns_viewer.
|
|
58
|
+
var _deviceBox = new THREE.Box3().setFromObject(deviceModelRoot);
|
|
59
|
+
var _deviceSize = new THREE.Vector3();
|
|
60
|
+
_deviceBox.getSize(_deviceSize);
|
|
61
|
+
var viewerMaxDim = Math.max(_deviceSize.x, _deviceSize.y, _deviceSize.z) || 1;
|
|
49
62
|
var _iterator = _createForOfIteratorHelper(anims),
|
|
50
63
|
_step;
|
|
51
64
|
try {
|
|
@@ -56,11 +69,23 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
56
69
|
console.warn("[IoBehaviorManager] Could not find mesh for animation \"".concat(anim.name || anim.stateVariable, "\" (uuid: ").concat(anim.meshUuid, ", name: \"").concat(anim.meshName, "\")"));
|
|
57
70
|
continue;
|
|
58
71
|
}
|
|
72
|
+
var worldPos = new THREE.Vector3();
|
|
73
|
+
mesh.getWorldPosition(worldPos);
|
|
74
|
+
var worldQuat = new THREE.Quaternion();
|
|
75
|
+
mesh.getWorldQuaternion(worldQuat);
|
|
76
|
+
var box = new THREE.Box3().setFromObject(mesh);
|
|
77
|
+
var worldCenter = new THREE.Vector3();
|
|
78
|
+
if (!box.isEmpty()) box.getCenter(worldCenter);else worldCenter.copy(worldPos);
|
|
59
79
|
entries.push({
|
|
60
80
|
anim: anim,
|
|
61
81
|
mesh: mesh,
|
|
62
82
|
origPos: mesh.position.clone(),
|
|
63
|
-
origRot: mesh.rotation.clone()
|
|
83
|
+
origRot: mesh.rotation.clone(),
|
|
84
|
+
origWorldPos: worldPos,
|
|
85
|
+
origWorldQuat: worldQuat,
|
|
86
|
+
origWorldCenter: worldCenter,
|
|
87
|
+
deviceWorldQuat: deviceWorldQuat.clone(),
|
|
88
|
+
viewerMaxDim: viewerMaxDim
|
|
64
89
|
});
|
|
65
90
|
}
|
|
66
91
|
} catch (err) {
|
|
@@ -90,16 +115,24 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
90
115
|
}, {
|
|
91
116
|
key: "triggerState",
|
|
92
117
|
value: function triggerState(attachmentId, dataPointId, value, parentUuid) {
|
|
93
|
-
var
|
|
94
|
-
var entries = this._entries.get(key);
|
|
95
|
-
if (!(entries !== null && entries !== void 0 && entries.length)) return;
|
|
96
|
-
var _iterator2 = _createForOfIteratorHelper(entries),
|
|
118
|
+
var _iterator2 = _createForOfIteratorHelper(this._entries.values()),
|
|
97
119
|
_step2;
|
|
98
120
|
try {
|
|
99
121
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
100
|
-
var
|
|
101
|
-
|
|
102
|
-
|
|
122
|
+
var entries = _step2.value;
|
|
123
|
+
var _iterator3 = _createForOfIteratorHelper(entries),
|
|
124
|
+
_step3;
|
|
125
|
+
try {
|
|
126
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
127
|
+
var entry = _step3.value;
|
|
128
|
+
if (entry.anim.stateVariable !== dataPointId) continue;
|
|
129
|
+
this._applyAnimation(entry, value);
|
|
130
|
+
}
|
|
131
|
+
} catch (err) {
|
|
132
|
+
_iterator3.e(err);
|
|
133
|
+
} finally {
|
|
134
|
+
_iterator3.f();
|
|
135
|
+
}
|
|
103
136
|
}
|
|
104
137
|
} catch (err) {
|
|
105
138
|
_iterator2.e(err);
|
|
@@ -134,34 +167,47 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
134
167
|
}, {
|
|
135
168
|
key: "getAnimationDataPoints",
|
|
136
169
|
value: function getAnimationDataPoints(parentUuid, attachmentId) {
|
|
170
|
+
var _this2 = this;
|
|
171
|
+
var hitMesh = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
137
172
|
var key = this._key(parentUuid, attachmentId);
|
|
138
173
|
var entries = this._entries.get(key);
|
|
139
174
|
if (!(entries !== null && entries !== void 0 && entries.length)) return [];
|
|
140
175
|
|
|
176
|
+
// When a specific mesh was clicked, filter to only animations whose target
|
|
177
|
+
// mesh is the clicked mesh or an ancestor of it (e.g. the clicked primitive
|
|
178
|
+
// is inside a group that is the animation target).
|
|
179
|
+
var filtered = entries;
|
|
180
|
+
if (hitMesh) {
|
|
181
|
+
var matching = entries.filter(function (e) {
|
|
182
|
+
return _this2._isMeshOrDescendant(hitMesh, e.mesh);
|
|
183
|
+
});
|
|
184
|
+
if (matching.length > 0) filtered = matching;
|
|
185
|
+
}
|
|
186
|
+
|
|
141
187
|
// Collapse multiple mesh entries that share the same stateVariable
|
|
142
188
|
var seen = new Map(); // stateVariable → anim
|
|
143
|
-
var
|
|
144
|
-
|
|
189
|
+
var _iterator4 = _createForOfIteratorHelper(filtered),
|
|
190
|
+
_step4;
|
|
145
191
|
try {
|
|
146
|
-
for (
|
|
147
|
-
var anim =
|
|
192
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
193
|
+
var anim = _step4.value.anim;
|
|
148
194
|
if (!seen.has(anim.stateVariable)) {
|
|
149
195
|
seen.set(anim.stateVariable, anim);
|
|
150
196
|
}
|
|
151
197
|
}
|
|
152
198
|
} catch (err) {
|
|
153
|
-
|
|
199
|
+
_iterator4.e(err);
|
|
154
200
|
} finally {
|
|
155
|
-
|
|
201
|
+
_iterator4.f();
|
|
156
202
|
}
|
|
157
203
|
var dps = [];
|
|
158
|
-
var
|
|
159
|
-
|
|
204
|
+
var _iterator5 = _createForOfIteratorHelper(seen),
|
|
205
|
+
_step5;
|
|
160
206
|
try {
|
|
161
|
-
for (
|
|
162
|
-
var
|
|
163
|
-
stateVar =
|
|
164
|
-
_anim =
|
|
207
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
208
|
+
var _step5$value = _slicedToArray(_step5.value, 2),
|
|
209
|
+
stateVar = _step5$value[0],
|
|
210
|
+
_anim = _step5$value[1];
|
|
165
211
|
// Normalise stateType from AnimateDevicesDialog variants
|
|
166
212
|
var stateType = void 0;
|
|
167
213
|
var raw = (_anim.stateType || '').toLowerCase();
|
|
@@ -212,9 +258,9 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
212
258
|
});
|
|
213
259
|
}
|
|
214
260
|
} catch (err) {
|
|
215
|
-
|
|
261
|
+
_iterator5.e(err);
|
|
216
262
|
} finally {
|
|
217
|
-
|
|
263
|
+
_iterator5.f();
|
|
218
264
|
}
|
|
219
265
|
return dps;
|
|
220
266
|
}
|
|
@@ -249,19 +295,19 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
249
295
|
key: "unloadForComponent",
|
|
250
296
|
value: function unloadForComponent(parentUuid) {
|
|
251
297
|
var prefix = "".concat(parentUuid, "::");
|
|
252
|
-
var
|
|
253
|
-
|
|
298
|
+
var _iterator6 = _createForOfIteratorHelper(this._entries.keys()),
|
|
299
|
+
_step6;
|
|
254
300
|
try {
|
|
255
|
-
for (
|
|
256
|
-
var key =
|
|
301
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
302
|
+
var key = _step6.value;
|
|
257
303
|
if (key.startsWith(prefix)) {
|
|
258
304
|
this._entries.delete(key);
|
|
259
305
|
}
|
|
260
306
|
}
|
|
261
307
|
} catch (err) {
|
|
262
|
-
|
|
308
|
+
_iterator6.e(err);
|
|
263
309
|
} finally {
|
|
264
|
-
|
|
310
|
+
_iterator6.f();
|
|
265
311
|
}
|
|
266
312
|
}
|
|
267
313
|
}, {
|
|
@@ -280,6 +326,22 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
280
326
|
return "".concat(parentUuid, "::").concat(attachmentId);
|
|
281
327
|
}
|
|
282
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Returns true if `candidate` is `ancestor` or any descendant of `ancestor`.
|
|
331
|
+
* @param {THREE.Object3D} candidate
|
|
332
|
+
* @param {THREE.Object3D} ancestor
|
|
333
|
+
*/
|
|
334
|
+
}, {
|
|
335
|
+
key: "_isMeshOrDescendant",
|
|
336
|
+
value: function _isMeshOrDescendant(candidate, ancestor) {
|
|
337
|
+
var obj = candidate;
|
|
338
|
+
while (obj) {
|
|
339
|
+
if (obj === ancestor) return true;
|
|
340
|
+
obj = obj.parent;
|
|
341
|
+
}
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
|
|
283
345
|
/**
|
|
284
346
|
* Find the mesh inside `root` using UUID first, then name as fallback.
|
|
285
347
|
* GLTFLoader assigns fresh UUIDs on every load, so name is the reliable key.
|
|
@@ -320,27 +382,32 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
320
382
|
var anim = entry.anim,
|
|
321
383
|
mesh = entry.mesh,
|
|
322
384
|
origPos = entry.origPos,
|
|
323
|
-
origRot = entry.origRot
|
|
385
|
+
origRot = entry.origRot,
|
|
386
|
+
origWorldPos = entry.origWorldPos,
|
|
387
|
+
origWorldQuat = entry.origWorldQuat,
|
|
388
|
+
origWorldCenter = entry.origWorldCenter,
|
|
389
|
+
deviceWorldQuat = entry.deviceWorldQuat,
|
|
390
|
+
viewerMaxDim = entry.viewerMaxDim;
|
|
324
391
|
var mapping = this._resolveMapping(anim, value);
|
|
325
392
|
if (!mapping) return;
|
|
326
393
|
var types = anim.transformTypes || [];
|
|
327
|
-
var
|
|
328
|
-
|
|
394
|
+
var _iterator7 = _createForOfIteratorHelper(types),
|
|
395
|
+
_step7;
|
|
329
396
|
try {
|
|
330
|
-
for (
|
|
331
|
-
var type =
|
|
397
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
398
|
+
var type = _step7.value;
|
|
332
399
|
if (type === 'translation') {
|
|
333
400
|
this._applyTranslation(mesh, origPos, mapping.transform);
|
|
334
401
|
} else if (type === 'rotation') {
|
|
335
|
-
this._applyRotation(mesh, origPos, origRot, anim, mapping.rotationTransform);
|
|
402
|
+
this._applyRotation(mesh, origPos, origRot, anim, mapping.rotationTransform, origWorldPos, origWorldQuat, origWorldCenter, deviceWorldQuat, viewerMaxDim);
|
|
336
403
|
} else if (type === 'color') {
|
|
337
404
|
this._applyColor(mesh, mapping.colorTransform);
|
|
338
405
|
}
|
|
339
406
|
}
|
|
340
407
|
} catch (err) {
|
|
341
|
-
|
|
408
|
+
_iterator7.e(err);
|
|
342
409
|
} finally {
|
|
343
|
-
|
|
410
|
+
_iterator7.f();
|
|
344
411
|
}
|
|
345
412
|
}
|
|
346
413
|
|
|
@@ -477,26 +544,24 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
477
544
|
}
|
|
478
545
|
|
|
479
546
|
/**
|
|
480
|
-
* Apply a rotation around an arbitrary pivot point
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
* pivot = rotAxisOffset
|
|
485
|
-
* delta = origPos - pivot
|
|
486
|
-
* newDelta = rotate(delta, angle, axis)
|
|
487
|
-
* newPos = pivot + newDelta
|
|
488
|
-
* newRot[axis] = origRot[axis] + angle
|
|
547
|
+
* Apply a rotation around an arbitrary pivot point using world-space quaternion
|
|
548
|
+
* math matching the ReconstructionViewer's setMeshPreviewRotationAxis approach.
|
|
549
|
+
* This ensures the runtime axis/pivot matches what the user configured in the
|
|
550
|
+
* animation dialog, regardless of the device's parent transform in the scene.
|
|
489
551
|
*
|
|
490
552
|
* @param {THREE.Object3D} mesh
|
|
491
|
-
* @param {THREE.Vector3} origPos
|
|
492
|
-
* @param {THREE.Euler} origRot
|
|
553
|
+
* @param {THREE.Vector3} origPos - local position at load time (unused, kept for signature compat)
|
|
554
|
+
* @param {THREE.Euler} origRot - local rotation at load time (unused)
|
|
493
555
|
* @param {Object} anim
|
|
494
|
-
* @param {number} angleDeg
|
|
556
|
+
* @param {number} angleDeg - Degrees
|
|
557
|
+
* @param {THREE.Vector3} origWorldPos - world position at load time
|
|
558
|
+
* @param {THREE.Quaternion} origWorldQuat - world quaternion at load time
|
|
559
|
+
* @param {THREE.Vector3} origWorldCenter - world bounding-box center at load time
|
|
495
560
|
*/
|
|
496
561
|
}, {
|
|
497
562
|
key: "_applyRotation",
|
|
498
|
-
value: function _applyRotation(mesh, origPos, origRot, anim, angleDeg) {
|
|
499
|
-
var _anim$rotAxis, _anim$rotAxisOffset
|
|
563
|
+
value: function _applyRotation(mesh, origPos, origRot, anim, angleDeg, origWorldPos, origWorldQuat, origWorldCenter, deviceWorldQuat, viewerMaxDim) {
|
|
564
|
+
var _anim$rotAxis, _anim$rotAxisOffset;
|
|
500
565
|
var angle = THREE.MathUtils.degToRad(typeof angleDeg === 'number' ? angleDeg : 0);
|
|
501
566
|
var axis = ((_anim$rotAxis = anim.rotAxis) !== null && _anim$rotAxis !== void 0 ? _anim$rotAxis : 'x').toLowerCase();
|
|
502
567
|
var off = (_anim$rotAxisOffset = anim.rotAxisOffset) !== null && _anim$rotAxisOffset !== void 0 ? _anim$rotAxisOffset : {
|
|
@@ -505,13 +570,57 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
505
570
|
z: 0
|
|
506
571
|
};
|
|
507
572
|
|
|
508
|
-
//
|
|
509
|
-
var
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
573
|
+
// Local axis in the device's coordinate system
|
|
574
|
+
var localAxisVec = new THREE.Vector3(axis === 'x' ? 1 : 0, axis === 'y' ? 1 : 0, axis === 'z' ? 1 : 0);
|
|
575
|
+
if (origWorldPos && origWorldQuat && origWorldCenter) {
|
|
576
|
+
// Transform the configured axis from device-local space into world space
|
|
577
|
+
// so that 'X' means the device's local X, not the world X.
|
|
578
|
+
var worldAxisVec = localAxisVec.clone().applyQuaternion(deviceWorldQuat || new THREE.Quaternion());
|
|
579
|
+
|
|
580
|
+
// rotAxisOffset is stored in dialog-viewer-world space where the model root
|
|
581
|
+
// has been rotated Rot_Z(π) by default (ReconstructionViewer's else branch).
|
|
582
|
+
// Translation uses the same convention and negates X/Y to compensate.
|
|
583
|
+
// For rotation offset we apply the same compensation mathematically:
|
|
584
|
+
// offset_runtime = deviceWorldQuat × Rot_Z(π) × offset_dialog × scale
|
|
585
|
+
// This maps from dialog world space (post Z+180° flip) → model local → world.
|
|
586
|
+
var scale = viewerMaxDim || 1;
|
|
587
|
+
var rotZ180 = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 0, 1), Math.PI);
|
|
588
|
+
var qCombined = (deviceWorldQuat || new THREE.Quaternion()).clone().multiply(rotZ180);
|
|
589
|
+
var offWorld = new THREE.Vector3((off.x || 0) * scale, (off.y || 0) * scale, (off.z || 0) * scale).applyQuaternion(qCombined);
|
|
590
|
+
var pivot = origWorldCenter.clone().add(offWorld);
|
|
591
|
+
var deltaQuat = new THREE.Quaternion().setFromAxisAngle(worldAxisVec, angle);
|
|
592
|
+
|
|
593
|
+
// Rotate world position around pivot
|
|
594
|
+
var offsetVec = origWorldPos.clone().sub(pivot);
|
|
595
|
+
offsetVec.applyQuaternion(deltaQuat);
|
|
596
|
+
var newWorldPos = pivot.clone().add(offsetVec);
|
|
597
|
+
|
|
598
|
+
// Compose world quaternion
|
|
599
|
+
var newWorldQuat = deltaQuat.clone().multiply(origWorldQuat);
|
|
600
|
+
|
|
601
|
+
// Convert world position → parent local space
|
|
602
|
+
if (mesh.parent) {
|
|
603
|
+
mesh.parent.worldToLocal(newWorldPos);
|
|
604
|
+
}
|
|
605
|
+
mesh.position.copy(newWorldPos);
|
|
606
|
+
|
|
607
|
+
// Convert quaternion → parent local space
|
|
608
|
+
if (mesh.parent) {
|
|
609
|
+
var parentWorldQuat = new THREE.Quaternion();
|
|
610
|
+
mesh.parent.getWorldQuaternion(parentWorldQuat);
|
|
611
|
+
parentWorldQuat.invert();
|
|
612
|
+
newWorldQuat.premultiply(parentWorldQuat);
|
|
613
|
+
}
|
|
614
|
+
mesh.quaternion.copy(newWorldQuat);
|
|
615
|
+
} else {
|
|
616
|
+
var _off$x, _off$y, _off$z;
|
|
617
|
+
// Fallback for entries loaded without world data
|
|
618
|
+
var _pivot = new THREE.Vector3((_off$x = off.x) !== null && _off$x !== void 0 ? _off$x : 0, (_off$y = off.y) !== null && _off$y !== void 0 ? _off$y : 0, (_off$z = off.z) !== null && _off$z !== void 0 ? _off$z : 0);
|
|
619
|
+
var delta = origPos.clone().sub(_pivot);
|
|
620
|
+
delta.applyAxisAngle(localAxisVec, angle);
|
|
621
|
+
mesh.position.copy(_pivot).add(delta);
|
|
622
|
+
mesh.rotation[axis] = origRot[axis] + angle;
|
|
623
|
+
}
|
|
515
624
|
}
|
|
516
625
|
|
|
517
626
|
/**
|
|
@@ -445,6 +445,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
445
445
|
raycaster.setFromCamera(mouse, _this4.camera);
|
|
446
446
|
var allIntersects = raycaster.intersectObjects(_this4.scene.children, true);
|
|
447
447
|
var ioDeviceObject = null;
|
|
448
|
+
var hitMesh = null;
|
|
448
449
|
var _iterator = _createForOfIteratorHelper(allIntersects),
|
|
449
450
|
_step;
|
|
450
451
|
try {
|
|
@@ -459,7 +460,10 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
459
460
|
}
|
|
460
461
|
obj = obj.parent;
|
|
461
462
|
}
|
|
462
|
-
if (ioDeviceObject)
|
|
463
|
+
if (ioDeviceObject) {
|
|
464
|
+
hitMesh = hit.object;
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
463
467
|
}
|
|
464
468
|
} catch (err) {
|
|
465
469
|
_iterator.e(err);
|
|
@@ -474,7 +478,7 @@ var TransformControlsManager = /*#__PURE__*/function () {
|
|
|
474
478
|
_this4._ioDragStartY = event.clientY;
|
|
475
479
|
_this4._ioDragMoved = false;
|
|
476
480
|
if (_this4.orbitControls) _this4.orbitControls.enabled = false;
|
|
477
|
-
_this4.callbacks.onIODeviceDrag(ioDeviceObject, 0, true);
|
|
481
|
+
_this4.callbacks.onIODeviceDrag(ioDeviceObject, 0, true, hitMesh);
|
|
478
482
|
var onMove = function onMove(e) {
|
|
479
483
|
var dx = e.clientX - _this4._ioDragStartX;
|
|
480
484
|
var dy = e.clientY - _this4._ioDragStartY;
|
|
@@ -154,7 +154,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
154
154
|
*/
|
|
155
155
|
}, {
|
|
156
156
|
key: "startIODeviceDrag",
|
|
157
|
-
value: function startIODeviceDrag(ioDeviceObject) {
|
|
157
|
+
value: function startIODeviceDrag(ioDeviceObject, hitMesh) {
|
|
158
158
|
var _this$sceneViewer2,
|
|
159
159
|
_this2 = this;
|
|
160
160
|
if (!ioDeviceObject || !this._stateAdapter) return;
|
|
@@ -173,7 +173,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
173
173
|
}
|
|
174
174
|
var scopedAttachmentId = this._getScopedAttachmentKey(attachmentId, parentUuid);
|
|
175
175
|
var ioBehavMgr = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 || (_this$sceneViewer2 = _this$sceneViewer2.managers) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.ioBehaviorManager;
|
|
176
|
-
var dataPoints = ((ioBehavMgr === null || ioBehavMgr === void 0 ? void 0 : ioBehavMgr.getAnimationDataPoints(parentUuid, attachmentId)) || []).concat((ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [])
|
|
176
|
+
var dataPoints = ((ioBehavMgr === null || ioBehavMgr === void 0 ? void 0 : ioBehavMgr.getAnimationDataPoints(parentUuid, attachmentId, hitMesh)) || []).concat((ud === null || ud === void 0 ? void 0 : ud.dataPoints) || [])
|
|
177
177
|
// deduplicate by id
|
|
178
178
|
.filter(function (dp, i, arr) {
|
|
179
179
|
return arr.findIndex(function (d) {
|