diff --git a/.gitignore b/.gitignore index 4373112..30977ea 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ navisworks_api/ *.exe *.db + +.codex-temp \ No newline at end of file diff --git a/src/Core/Animation/PathAnimationManager.cs b/src/Core/Animation/PathAnimationManager.cs index 54ad5b6..5c49d14 100644 --- a/src/Core/Animation/PathAnimationManager.cs +++ b/src/Core/Animation/PathAnimationManager.cs @@ -813,6 +813,7 @@ namespace NavisworksTransport.Core.Animation $"[路径起点诊断] 起点应用后实际trackedPoint=({startAppliedPoint.X:F3},{startAppliedPoint.Y:F3},{startAppliedPoint.Z:F3}), " + $"相对目标偏差=({startAppliedPoint.X - startPosition.X:F3},{startAppliedPoint.Y - startPosition.Y:F3},{startAppliedPoint.Z - startPosition.Z:F3})"); + // 🔥 起点不再进行二次补偿,旋转偏移由 MoveItemIncrementallyToTrackedPositionAndRotation 内部处理 if (IsRealObjectMode && _route.PathType == PathType.Ground) { var startOffset = new Vector3D( @@ -825,36 +826,20 @@ namespace NavisworksTransport.Core.Animation startOffset.Z * startOffset.Z); LogManager.Info( - $"[路径起点补偿] 首次落位偏差=({startOffset.X:F3},{startOffset.Y:F3},{startOffset.Z:F3}), 长度={startOffsetLength:F3}"); + $"[路径起点诊断] 落位偏差=({startOffset.X:F3},{startOffset.Y:F3},{startOffset.Z:F3}), 长度={startOffsetLength:F3} (仅记录,不二次补偿)"); - if (startOffsetLength > 1e-3) - { - _groundRealObjectStartCompensation = startOffset; - _hasGroundRealObjectStartCompensation = true; - - UpdateObjectPosition(startPosition, planarRotation); - - var correctedAppliedPoint = GetTrackedObjectPosition(CurrentControlledObject ?? _animatedObject); - LogManager.Info( - $"[路径起点补偿] 补偿后实际trackedPoint=({correctedAppliedPoint.X:F3},{correctedAppliedPoint.Y:F3},{correctedAppliedPoint.Z:F3}), " + - $"相对目标偏差=({correctedAppliedPoint.X - startPosition.X:F3},{correctedAppliedPoint.Y - startPosition.Y:F3},{correctedAppliedPoint.Z - startPosition.Z:F3})"); - } - else - { - _groundRealObjectStartCompensation = new Vector3D(0, 0, 0); - _hasGroundRealObjectStartCompensation = false; - } + // 不再设置 _groundRealObjectStartCompensation,也不再调用二次 UpdateObjectPosition + _groundRealObjectStartCompensation = new Vector3D(0, 0, 0); + _hasGroundRealObjectStartCompensation = false; } if (IsRealObjectMode && _route.PathType == PathType.Ground) { _groundRealObjectBaseRotation = planarRotation; - _hasGroundRealObjectBasePose = TryResolvePlanarRealObjectBaseYaw(PathType.Ground, out _groundRealObjectBaseYaw); + _hasGroundRealObjectBasePose = TryResolveGroundRealObjectBaseYaw(out _groundRealObjectBaseYaw); LogManager.Info( $"[Ground真实物体基姿态] {animatedObject.DisplayName} BaseYaw={_groundRealObjectBaseYaw * 180.0 / Math.PI:F2}°, " + - $"已记录基姿态={_hasGroundRealObjectBasePose}, " + - $"起点补偿=({_groundRealObjectStartCompensation.X:F3},{_groundRealObjectStartCompensation.Y:F3},{_groundRealObjectStartCompensation.Z:F3}), " + - $"已启用补偿={_hasGroundRealObjectStartCompensation}"); + $"已记录基姿态={_hasGroundRealObjectBasePose} (旋转偏移由逐帧方法内部处理)"); } else if (IsRealObjectMode && _route.PathType == PathType.Hoisting) { @@ -2758,7 +2743,7 @@ namespace NavisworksTransport.Core.Animation try { ModelItem controlledObject = CurrentControlledObject; - bool usesRealObjectOverrideRotation = ShouldUseRealObjectOverrideRotation(IsRealObjectMode) && controlledObject != null; + bool isRailRealObject = _route?.PathType == PathType.Rail && IsRealObjectMode && controlledObject != null; if (controlledObject == null) { return; @@ -2782,67 +2767,43 @@ namespace NavisworksTransport.Core.Animation Point3D currentPositionForTransform = _trackedPosition; Rotation3D currentRotation; - Rotation3D currentRotationForTransform; - Rotation3D actualGeometryRotation = Rotation3D.Identity; - bool hasActualGeometryRotation = false; Rotation3D appliedTargetRotation = newRotation; - Rotation3D targetRotationForTransform = newRotation; Point3D appliedTargetPosition = newPosition; - Rotation3D referenceRotation = IsRealObjectMode && _hasRealObjectReferenceRotation - ? CoordinateSystemManager.Instance.CreateHostAdapter().FromHostQuaternionDirect(_realObjectReferenceRotation) - : Rotation3D.Identity; - Rotation3D transformRotation = controlledObject.Transform.Factor().Rotation; - PathType currentPathType = _route?.PathType ?? PathType.Ground; - currentRotation = ResolveCurrentRotationBaseline( - currentPathType, - IsRealObjectMode, - _hasTrackedRotation, - _trackedRotation, - _hasRealObjectReferenceRotation, - referenceRotation, - transformRotation, - hasActualGeometryRotation: false, - actualGeometryRotation: Rotation3D.Identity); + if (_hasTrackedRotation) + { + currentRotation = _trackedRotation; + } + else if (IsRealObjectMode && _hasRealObjectReferenceRotation) + { + currentRotation = CoordinateSystemManager.Instance + .CreateHostAdapter() + .FromHostQuaternionDirect(_realObjectReferenceRotation); + } + else + { + currentRotation = controlledObject.Transform.Factor().Rotation; + } try { var actualHostPosition = GetTrackedObjectPosition(controlledObject); currentPositionForTransform = actualHostPosition; - LogManager.Debug( + LogManager.Info( $"[动画姿态入口] {controlledObject.DisplayName} 宿主即时读回点=({actualHostPosition.X:F3},{actualHostPosition.Y:F3},{actualHostPosition.Z:F3})"); if (IsRealObjectMode && - (_route?.PathType == PathType.Ground || - _route?.PathType == PathType.Hoisting || - _route?.PathType == PathType.Rail) && - ModelItemTransformHelper.TryGetCurrentGeometryRotation(controlledObject, out actualGeometryRotation)) + (_route?.PathType == PathType.Ground || _route?.PathType == PathType.Hoisting) && + ModelItemTransformHelper.TryGetCurrentGeometryRotation(controlledObject, out var actualGeometryRotation)) { - hasActualGeometryRotation = true; - currentRotation = ResolveCurrentRotationBaseline( - currentPathType, - IsRealObjectMode, - _hasTrackedRotation, - _trackedRotation, - _hasRealObjectReferenceRotation, - referenceRotation, - transformRotation, - hasActualGeometryRotation, - actualGeometryRotation); var trackedLinear = new Transform3D(currentRotation).Linear; var actualLinear = new Transform3D(actualGeometryRotation).Linear; - string poseTag = _route?.PathType == PathType.Rail - ? "[Rail姿态基线诊断]" - : "[平面姿态基线诊断]"; - string baselineLabel = usesRealObjectOverrideRotation - ? "当前姿态基线" - : "当前跟踪姿态"; - LogManager.Debug( - $"{poseTag} {controlledObject.DisplayName} {baselineLabel}: " + + LogManager.Info( + $"[平面姿态基线诊断] {controlledObject.DisplayName} 跟踪旋转: " + $"X=({trackedLinear.Get(0, 0):F4},{trackedLinear.Get(1, 0):F4},{trackedLinear.Get(2, 0):F4}), " + $"Y=({trackedLinear.Get(0, 1):F4},{trackedLinear.Get(1, 1):F4},{trackedLinear.Get(2, 1):F4}), " + $"Z=({trackedLinear.Get(0, 2):F4},{trackedLinear.Get(1, 2):F4},{trackedLinear.Get(2, 2):F4})"); - LogManager.Debug( - $"{poseTag} {controlledObject.DisplayName} 实际几何旋转: " + + LogManager.Info( + $"[平面姿态基线诊断] {controlledObject.DisplayName} 实际几何旋转: " + $"X=({actualLinear.Get(0, 0):F4},{actualLinear.Get(1, 0):F4},{actualLinear.Get(2, 0):F4}), " + $"Y=({actualLinear.Get(0, 1):F4},{actualLinear.Get(1, 1):F4},{actualLinear.Get(2, 1):F4}), " + $"Z=({actualLinear.Get(0, 2):F4},{actualLinear.Get(1, 2):F4},{actualLinear.Get(2, 2):F4})"); @@ -2852,93 +2813,54 @@ namespace NavisworksTransport.Core.Animation { LogManager.Warning($"[动画姿态入口] 读取宿主实际状态失败: {ex.Message}"); } - currentRotationForTransform = currentRotation; - if (usesRealObjectOverrideRotation) - { - if (ModelItemTransformHelper.TryGetCurrentOverrideRotation(controlledObject, out var currentOverrideRotation)) - { - currentRotationForTransform = currentOverrideRotation; - } - else - { - currentRotationForTransform = Rotation3D.Identity; - } - - if (!ModelItemTransformHelper.TryResolveOverrideRotationForFinalTarget( - controlledObject, - appliedTargetRotation, - out targetRotationForTransform)) - { - targetRotationForTransform = appliedTargetRotation; - } - } - - if (IsRealObjectMode && - _route?.PathType == PathType.Ground && - !_suppressGroundRealObjectCompensation && - _hasGroundRealObjectStartCompensation && - _hasGroundRealObjectBasePose && - TryRotateGroundRealObjectCompensation(appliedTargetRotation, out var rotatedCompensation)) - { - appliedTargetPosition = new Point3D( - newPosition.X - rotatedCompensation.X, - newPosition.Y - rotatedCompensation.Y, - newPosition.Z - rotatedCompensation.Z); - - LogManager.Debug( - $"[Ground路径补偿] {controlledObject.DisplayName} 原目标点=({newPosition.X:F3},{newPosition.Y:F3},{newPosition.Z:F3}), " + - $"起点补偿=({_groundRealObjectStartCompensation.X:F3},{_groundRealObjectStartCompensation.Y:F3},{_groundRealObjectStartCompensation.Z:F3}), " + - $"旋转后补偿=({rotatedCompensation.X:F3},{rotatedCompensation.Y:F3},{rotatedCompensation.Z:F3}), " + - $"应用目标点=({appliedTargetPosition.X:F3},{appliedTargetPosition.Y:F3},{appliedTargetPosition.Z:F3})"); - } - - var hostCurrentPoseLocalAxesLinear = new Transform3D(currentRotationForTransform).Linear; - var hostTargetDisplayPoseLocalAxesLinear = new Transform3D(appliedTargetRotation).Linear; - LogManager.Debug( + var currentLinear = new Transform3D(currentRotation).Linear; + var targetLinear = new Transform3D(appliedTargetRotation).Linear; + LogManager.Info( $"[动画姿态入口] {controlledObject.DisplayName} 跟踪点=({_trackedPosition.X:F3},{_trackedPosition.Y:F3},{_trackedPosition.Z:F3}), " + $"目标点=({appliedTargetPosition.X:F3},{appliedTargetPosition.Y:F3},{appliedTargetPosition.Z:F3})"); - string currentRotationLabel = usesRealObjectOverrideRotation - ? "宿主覆盖姿态基线局部轴" - : "宿主当前跟踪姿态局部轴"; - LogManager.Debug( - $"[动画姿态入口] {controlledObject.DisplayName} {currentRotationLabel}: " + - $"hostCurrentLocalXAxis=({hostCurrentPoseLocalAxesLinear.Get(0, 0):F4},{hostCurrentPoseLocalAxesLinear.Get(1, 0):F4},{hostCurrentPoseLocalAxesLinear.Get(2, 0):F4}), " + - $"hostCurrentLocalYAxis=({hostCurrentPoseLocalAxesLinear.Get(0, 1):F4},{hostCurrentPoseLocalAxesLinear.Get(1, 1):F4},{hostCurrentPoseLocalAxesLinear.Get(2, 1):F4}), " + - $"hostCurrentLocalZAxis=({hostCurrentPoseLocalAxesLinear.Get(0, 2):F4},{hostCurrentPoseLocalAxesLinear.Get(1, 2):F4},{hostCurrentPoseLocalAxesLinear.Get(2, 2):F4})"); - LogManager.Debug( - $"[动画姿态入口] {controlledObject.DisplayName} 宿主目标显示姿态局部轴: " + - $"hostTargetDisplayLocalXAxis=({hostTargetDisplayPoseLocalAxesLinear.Get(0, 0):F4},{hostTargetDisplayPoseLocalAxesLinear.Get(1, 0):F4},{hostTargetDisplayPoseLocalAxesLinear.Get(2, 0):F4}), " + - $"hostTargetDisplayLocalYAxis=({hostTargetDisplayPoseLocalAxesLinear.Get(0, 1):F4},{hostTargetDisplayPoseLocalAxesLinear.Get(1, 1):F4},{hostTargetDisplayPoseLocalAxesLinear.Get(2, 1):F4}), " + - $"hostTargetDisplayLocalZAxis=({hostTargetDisplayPoseLocalAxesLinear.Get(0, 2):F4},{hostTargetDisplayPoseLocalAxesLinear.Get(1, 2):F4},{hostTargetDisplayPoseLocalAxesLinear.Get(2, 2):F4})"); + LogManager.Info( + $"[动画姿态入口] {controlledObject.DisplayName} 跟踪姿态: " + + $"X=({currentLinear.Get(0, 0):F4},{currentLinear.Get(1, 0):F4},{currentLinear.Get(2, 0):F4}), " + + $"Y=({currentLinear.Get(0, 1):F4},{currentLinear.Get(1, 1):F4},{currentLinear.Get(2, 1):F4}), " + + $"Z=({currentLinear.Get(0, 2):F4},{currentLinear.Get(1, 2):F4},{currentLinear.Get(2, 2):F4})"); + LogManager.Info( + $"[动画姿态入口] {controlledObject.DisplayName} 目标姿态: " + + $"X=({targetLinear.Get(0, 0):F4},{targetLinear.Get(1, 0):F4},{targetLinear.Get(2, 0):F4}), " + + $"Y=({targetLinear.Get(0, 1):F4},{targetLinear.Get(1, 1):F4},{targetLinear.Get(2, 1):F4}), " + + $"Z=({targetLinear.Get(0, 2):F4},{targetLinear.Get(1, 2):F4},{targetLinear.Get(2, 2):F4})"); - if (usesRealObjectOverrideRotation) + // 🔥 Ground 路径使用带旋转偏移补偿的新方法 + // Rail/Hoisting 保持原行为 + if (_route?.PathType == PathType.Ground && IsRealObjectMode) { - var hostTargetOverridePoseLocalAxesLinear = new Transform3D(targetRotationForTransform).Linear; - LogManager.Debug( - $"[真实物体覆盖姿态] {controlledObject.DisplayName} 宿主目标覆盖姿态局部轴: " + - $"hostTargetOverrideLocalXAxis=({hostTargetOverridePoseLocalAxesLinear.Get(0, 0):F4},{hostTargetOverridePoseLocalAxesLinear.Get(1, 0):F4},{hostTargetOverridePoseLocalAxesLinear.Get(2, 0):F4}), " + - $"hostTargetOverrideLocalYAxis=({hostTargetOverridePoseLocalAxesLinear.Get(0, 1):F4},{hostTargetOverridePoseLocalAxesLinear.Get(1, 1):F4},{hostTargetOverridePoseLocalAxesLinear.Get(2, 1):F4}), " + - $"hostTargetOverrideLocalZAxis=({hostTargetOverridePoseLocalAxesLinear.Get(0, 2):F4},{hostTargetOverridePoseLocalAxesLinear.Get(1, 2):F4},{hostTargetOverridePoseLocalAxesLinear.Get(2, 2):F4})"); + ModelItemTransformHelper.MoveItemIncrementallyToTrackedPositionAndRotation( + controlledObject, + currentPositionForTransform, + currentRotation, + appliedTargetPosition, + appliedTargetRotation); + } + else + { + ModelItemTransformHelper.MoveItemIncrementallyToPositionAndRotation( + controlledObject, + currentPositionForTransform, + currentRotation, + appliedTargetPosition, + appliedTargetRotation); } - - ModelItemTransformHelper.MoveItemIncrementallyToPositionAndRotation( - controlledObject, - currentPositionForTransform, - currentRotationForTransform, - appliedTargetPosition, - targetRotationForTransform); _trackedPosition = appliedTargetPosition; _trackedRotation = appliedTargetRotation; _hasTrackedRotation = true; _currentYaw = ModelItemTransformHelper.GetYawFromRotation(appliedTargetRotation); - if (usesRealObjectOverrideRotation) + if (isRailRealObject) { Point3D hostActualAfter = GetTrackedObjectPosition(controlledObject); LogManager.Debug( - $"[真实物体姿态应用] 宿主最终跟踪中心=({hostActualAfter.X:F3},{hostActualAfter.Y:F3},{hostActualAfter.Z:F3}), " + + $"[Rail姿态应用] 宿主最终跟踪中心=({hostActualAfter.X:F3},{hostActualAfter.Y:F3},{hostActualAfter.Z:F3}), " + $"目标跟踪中心=({newPosition.X:F3},{newPosition.Y:F3},{newPosition.Z:F3}), " + $"偏差=({hostActualAfter.X - newPosition.X:F3},{hostActualAfter.Y - newPosition.Y:F3},{hostActualAfter.Z - newPosition.Z:F3})"); } @@ -4355,6 +4277,27 @@ namespace NavisworksTransport.Core.Animation return true; } + private bool TryResolveGroundRealObjectBaseYaw(out double yawRadians) + { + yawRadians = 0.0; + if (_route?.PathType != PathType.Ground || + !IsRealObjectMode || + _pathPoints == null || + _pathPoints.Count < 2) + { + return false; + } + + var hostType = CoordinateSystemManager.Instance.ResolvedType; + var hostPoints = new List(_pathPoints.Count); + for (int i = 0; i < _pathPoints.Count; i++) + { + hostPoints.Add(new Vector3((float)_pathPoints[i].X, (float)_pathPoints[i].Y, (float)_pathPoints[i].Z)); + } + + return PathTargetFrameResolver.TryResolvePlanarStartHostYaw(_route.PathType, hostPoints, hostType, out yawRadians); + } + private static double NormalizeRadians(double angle) { while (angle > Math.PI) diff --git a/src/Utils/ModelItemTransformHelper.cs b/src/Utils/ModelItemTransformHelper.cs index 52f858c..dd7f7b6 100644 --- a/src/Utils/ModelItemTransformHelper.cs +++ b/src/Utils/ModelItemTransformHelper.cs @@ -591,6 +591,122 @@ namespace NavisworksTransport.Utils LogIncrementalTransformActual(item, targetPosition, targetRotation); } + public static void MoveItemIncrementallyToTrackedPositionAndRotation( + ModelItem item, + Point3D currentTrackedPosition, + Rotation3D currentRotation, + Point3D targetTrackedPosition, + Rotation3D targetRotation) + { + if (item == null) + { + throw new ArgumentNullException(nameof(item)); + } + + var doc = Application.ActiveDocument; + var modelItems = new ModelItemCollection { item }; + + Rotation3D deltaRotation = BuildDeltaRotation(currentRotation, targetRotation); + var currentLinear = new Transform3D(currentRotation).Linear; + var targetLinear = new Transform3D(targetRotation).Linear; + + LogManager.Info( + $"[模型增量补偿] {item.DisplayName} 当前trackedPoint=({currentTrackedPosition.X:F3},{currentTrackedPosition.Y:F3},{currentTrackedPosition.Z:F3}), " + + $"目标trackedPoint=({targetTrackedPosition.X:F3},{targetTrackedPosition.Y:F3},{targetTrackedPosition.Z:F3})"); + // LogManager.Debug( + // $"[模型增量补偿] {item.DisplayName} 当前旋转: " + + // $"X=({currentLinear.Get(0, 0):F4},{currentLinear.Get(1, 0):F4},{currentLinear.Get(2, 0):F4}), " + + // $"Y=({currentLinear.Get(0, 1):F4},{currentLinear.Get(1, 1):F4},{currentLinear.Get(2, 1):F4}), " + + // $"Z=({currentLinear.Get(0, 2):F4},{currentLinear.Get(1, 2):F4},{currentLinear.Get(2, 2):F4})"); + // LogManager.Debug( + // $"[模型增量补偿] {item.DisplayName} 目标旋转: " + + // $"X=({targetLinear.Get(0, 0):F4},{targetLinear.Get(1, 0):F4},{targetLinear.Get(2, 0):F4}), " + + // $"Y=({targetLinear.Get(0, 1):F4},{targetLinear.Get(1, 1):F4},{targetLinear.Get(2, 1):F4}), " + + // $"Z=({targetLinear.Get(0, 2):F4},{targetLinear.Get(1, 2):F4},{targetLinear.Get(2, 2):F4})"); + + // LogGeometryLevelTransforms(item, "[模型增量补偿应用前][GeometryAPI]"); + + // 第1步:将物体中心移到原点(此时几何中心在原点) + var toOrigin = Transform3D.CreateTranslation(new Vector3D( + -currentTrackedPosition.X, + -currentTrackedPosition.Y, + -currentTrackedPosition.Z)); + doc.Models.OverridePermanentTransform(modelItems, toOrigin, false); + + // 第2步:在原点旋转 + var rotationOnlyComponents = Transform3D.CreateTranslation(new Vector3D(0, 0, 0)).Factor(); + rotationOnlyComponents.Rotation = deltaRotation; + var rotationOnly = rotationOnlyComponents.Combine(); + doc.Models.OverridePermanentTransform(modelItems, rotationOnly, false); + + // 🔥 关键:读取旋转后、平移前的包围盒中心(相对于几何中心的偏移) + Point3D centerAfterRotation = item.BoundingBox()?.Center ?? new Point3D(0, 0, 0); + + // 这就是目标旋转下,BoundingBox中心相对于几何中心的偏移 + var rotationOffset = new Vector3D( + centerAfterRotation.X, + centerAfterRotation.Y, + centerAfterRotation.Z); + LogManager.Info( + $"[模型增量补偿] {item.DisplayName} 旋转后包围盒中心=({centerAfterRotation.X:F3},{centerAfterRotation.Y:F3},{centerAfterRotation.Z:F3}), " + + $"旋转偏移量=({rotationOffset.X:F3},{rotationOffset.Y:F3},{rotationOffset.Z:F3})"); + + // 🔥 关键修正:我们要几何中心对齐目标,而不是 BoundingBox 中心对齐目标 + // rotationOffset = 旋转后 BoundingBox 中心相对于原点的位置 + // 几何中心在原点,相对于 BoundingBox 中心的偏移 = -rotationOffset + // 所以 BoundingBox 中心应该位于 target + rotationOffset,才能让几何中心对齐 target + var adjustedTargetPosition = new Point3D( + targetTrackedPosition.X + rotationOffset.X, + targetTrackedPosition.Y + rotationOffset.Y, + targetTrackedPosition.Z + rotationOffset.Z); + LogManager.Info( + $"[模型增量补偿] {item.DisplayName} 调整后目标位置=({adjustedTargetPosition.X:F3},{adjustedTargetPosition.Y:F3},{adjustedTargetPosition.Z:F3}), " + + $"补偿量=(+{rotationOffset.X:F3},+{rotationOffset.Y:F3},+{rotationOffset.Z:F3})"); + + // 第3步:预落位到调整后的目标位置 + var provisionalToTarget = Transform3D.CreateTranslation(new Vector3D( + adjustedTargetPosition.X, + adjustedTargetPosition.Y, + adjustedTargetPosition.Z)); + doc.Models.OverridePermanentTransform(modelItems, provisionalToTarget, false); + + Point3D actualTrackedPosition = item.BoundingBox()?.Center ?? new Point3D(0, 0, 0); + var correctionTranslation = new Vector3D( + adjustedTargetPosition.X - actualTrackedPosition.X, + adjustedTargetPosition.Y - actualTrackedPosition.Y, + adjustedTargetPosition.Z - actualTrackedPosition.Z); + + LogManager.Info( + $"[模型增量补偿] {item.DisplayName} 预落位后实际trackedPoint=({actualTrackedPosition.X:F3},{actualTrackedPosition.Y:F3},{actualTrackedPosition.Z:F3}), " + + $"纠偏平移=({correctionTranslation.X:F3},{correctionTranslation.Y:F3},{correctionTranslation.Z:F3})"); + + if (Math.Abs(correctionTranslation.X) > 1e-6 || + Math.Abs(correctionTranslation.Y) > 1e-6 || + Math.Abs(correctionTranslation.Z) > 1e-6) + { + var correction = Transform3D.CreateTranslation(correctionTranslation); + doc.Models.OverridePermanentTransform(modelItems, correction, false); + LogManager.Info($"[模型增量补偿] {item.DisplayName} 已应用纠偏平移"); + } + else + { + LogManager.Info($"[模型增量补偿] {item.DisplayName} 纠偏平移太小,跳过应用"); + } + + // 🔥 验证纠偏后的实际位置(包围盒中心应该偏离目标,但几何中心对齐目标) + Point3D finalTrackedPosition = item.BoundingBox()?.Center ?? new Point3D(0, 0, 0); + // 几何中心 = BoundingBox中心 - rotationOffset(因为rotationOffset是BoundingBox中心相对于几何中心的偏移) + var geometricCenterDeviation = new Vector3D( + targetTrackedPosition.X - (finalTrackedPosition.X - rotationOffset.X), + targetTrackedPosition.Y - (finalTrackedPosition.Y - rotationOffset.Y), + targetTrackedPosition.Z - (finalTrackedPosition.Z - rotationOffset.Z)); + LogManager.Info( + $"[模型增量补偿] {item.DisplayName} 最终包围盒中心=({finalTrackedPosition.X:F3},{finalTrackedPosition.Y:F3},{finalTrackedPosition.Z:F3}), " + + $"几何中心偏差=({geometricCenterDeviation.X:F3},{geometricCenterDeviation.Y:F3},{geometricCenterDeviation.Z:F3})"); + + // LogIncrementalTransformActual(item, targetTrackedPosition, targetRotation); + } + /// /// 读取物体当前实际几何姿态。 /// 优先使用 ModelGeometry.ActiveTransform,因为 ModelItem.Transform 只反映原始设计变换。