NavisworksTransport/src/Utils/ModelItemTransformHelper.cs
tian f5387c8699 fix: 自动调整评测与姿态对准修正
1. GetYawFromRotation: 通过 canonical space 转换计算 yaw,修复 YUp 下 atan2(Y,X) 用错平面
2. ApplyRotationCorrectionInPlace: 新增 CAD 原位纯旋转,评测旋转顺序与增量链一致
3. 评测器两轮优化: 先无约束找最小面积,不满足约束再带约束重搜
4. ApplyAutoAdjustedPoseAndMoveToPathStart: 确认时先校正再偏航,不读 CAD yaw
5. OnAutoAdjustClick: 去掉 Y 轴 yaw 叠加
2026-06-06 12:47:12 +08:00

1295 lines
58 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils.CoordinateSystem;
using System.Numerics;
namespace NavisworksTransport.Utils
{
/// <summary>
/// ModelItem变换辅助工具
/// 提供临时移动和恢复物体位置的通用方法
/// </summary>
public static class ModelItemTransformHelper
{
/// <summary>
/// 临时移动物体到指定位置
/// </summary>
/// <param name="item">要移动的物体</param>
/// <param name="targetPosition">目标位置(物体中心)</param>
/// <returns>用于恢复的偏移向量</returns>
public static Vector3D MoveItemToPosition(ModelItem item, Point3D targetPosition)
{
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
// 计算当前中心位置
var currentBounds = item.BoundingBox();
var currentPos = new Point3D(
(currentBounds.Min.X + currentBounds.Max.X) / 2,
(currentBounds.Min.Y + currentBounds.Max.Y) / 2,
(currentBounds.Min.Z + currentBounds.Max.Z) / 2
);
// 计算偏移
var offset = new Vector3D(
targetPosition.X - currentPos.X,
targetPosition.Y - currentPos.Y,
targetPosition.Z - currentPos.Z
);
// 应用变换
var transform = Transform3D.CreateTranslation(offset);
doc.Models.OverridePermanentTransform(modelItems, transform, false);
return offset;
}
/// <summary>
/// 从Transform3D中提取Yaw角度绕Z轴旋转单位弧度
/// </summary>
/// <param name="transform">变换矩阵</param>
/// <returns>Yaw角度弧度</returns>
public static double GetYawFromTransform(Transform3D transform)
{
if (transform == null) return 0.0;
try
{
var components = transform.Factor();
return GetYawFromRotation(components.Rotation);
}
catch (Exception)
{
return 0.0;
}
}
/// <summary>
/// 从 Rotation3D 中提取 XY 平面的 yaw 角(弧度)。
/// </summary>
public static double GetYawFromRotation(Rotation3D rotation)
{
if (rotation == null)
{
return 0.0;
}
try
{
var linear = new Transform3D(rotation).Linear;
Vector3 hostForward = new Vector3(
(float)linear.Get(0, 0),
(float)linear.Get(1, 0),
(float)linear.Get(2, 0));
// 转 canonical (ZUp),在 XY 平面算 yaw
var adapter = new HostCoordinateAdapter(CoordinateSystemManager.Instance.ResolvedType);
Vector3 canonicalForward = adapter.ToCanonicalVector3(hostForward);
canonicalForward.Z = 0f;
if (canonicalForward.LengthSquared() < 1e-9f)
{
return 0.0;
}
canonicalForward = Vector3.Normalize(canonicalForward);
return System.Math.Atan2(canonicalForward.Y, canonicalForward.X);
}
catch (Exception)
{
return 0.0;
}
}
/// <summary>
/// 获取变换后局部 X 轴在世界坐标中的方向,通常可作为物体主朝向。
/// </summary>
public static Vector3D GetForwardDirectionFromTransform(Transform3D transform)
{
return GetAxisDirectionFromTransform(transform, 0, new Vector3D(1, 0, 0));
}
/// <summary>
/// 获取变换后局部 Z 轴在世界坐标中的方向,可作为构件顶/底面法向。
/// </summary>
public static Vector3D GetUpDirectionFromTransform(Transform3D transform)
{
return GetAxisDirectionFromTransform(transform, 2, new Vector3D(0, 0, 1));
}
/// <summary>
/// 根据模型局部轴约定,获取指定局部轴在世界坐标中的方向。
/// </summary>
public static Vector3D GetDirectionFromTransform(
Transform3D transform,
LocalAxisDirection axisDirection)
{
GetAxisIndexAndSign(axisDirection, out int axisIndex, out int sign);
Vector3D fallback = GetFallbackAxis(axisDirection);
Vector3D direction = GetAxisDirectionFromTransform(transform, axisIndex, fallback);
return sign >= 0
? direction
: new Vector3D(-direction.X, -direction.Y, -direction.Z);
}
/// <summary>
/// 获取绑定在物体局部坐标中的稳定底面锚点。
/// 适用于带俯仰/侧倾的三维姿态对象,避免使用世界 AABB 底面中心导致锚点漂移。
/// </summary>
public static Point3D GetStableBottomAnchorPoint(BoundingBox3D bounds, Transform3D transform)
{
if (bounds == null)
{
return new Point3D(0, 0, 0);
}
if (transform == null)
{
return new Point3D(bounds.Center.X, bounds.Center.Y, bounds.Min.Z);
}
var up = GetUpDirectionFromTransform(transform);
var localSize = EstimateLocalBoxSize(bounds, transform);
double halfHeight = localSize.Z / 2.0;
return new Point3D(
bounds.Center.X - up.X * halfHeight,
bounds.Center.Y - up.Y * halfHeight,
bounds.Center.Z - up.Z * halfHeight);
}
/// <summary>
/// 使用宿主坐标系的 up 轴,从世界 AABB 中提取“底部锚点”。
/// 适用于真实模型仍保持宿主坐标语义(如 Y-up 模型)的场景。
/// </summary>
public static Point3D GetHostBottomAnchorPoint(BoundingBox3D bounds, HostCoordinateAdapter adapter)
{
if (bounds == null)
{
return new Point3D(0, 0, 0);
}
if (adapter == null)
{
throw new ArgumentNullException(nameof(adapter));
}
switch (adapter.HostUpAxisIndex)
{
case 1:
return new Point3D(bounds.Center.X, bounds.Min.Y, bounds.Center.Z);
case 2:
default:
return new Point3D(bounds.Center.X, bounds.Center.Y, bounds.Min.Z);
}
}
/// <summary>
/// 使用宿主坐标系的 up 轴,从世界 AABB 中提取高度。
/// 适用于真实模型仍保持宿主坐标语义(如 Y-up 模型)的场景。
/// </summary>
public static double GetHostHeight(BoundingBox3D bounds, HostCoordinateAdapter adapter)
{
if (bounds == null)
{
return 0.0;
}
if (adapter == null)
{
throw new ArgumentNullException(nameof(adapter));
}
switch (adapter.HostUpAxisIndex)
{
case 1:
return bounds.Max.Y - bounds.Min.Y;
case 2:
default:
return bounds.Max.Z - bounds.Min.Z;
}
}
/// <summary>
/// 根据世界轴对齐包围盒和物体变换,估算物体在局部坐标系中的尺寸。
/// 适用于刚性箱体类对象,用于顶/底面对接点推导。
/// </summary>
public static Vector3D EstimateLocalBoxSize(BoundingBox3D bounds, Transform3D transform)
{
double halfXWorld = Math.Max(0.0, (bounds.Max.X - bounds.Min.X) / 2.0);
double halfYWorld = Math.Max(0.0, (bounds.Max.Y - bounds.Min.Y) / 2.0);
double halfZWorld = Math.Max(0.0, (bounds.Max.Z - bounds.Min.Z) / 2.0);
if (transform == null)
{
return new Vector3D(halfXWorld * 2.0, halfYWorld * 2.0, halfZWorld * 2.0);
}
try
{
var forward = GetForwardDirectionFromTransform(transform);
var localY = GetAxisDirectionFromTransform(transform, 1, new Vector3D(0, 1, 0));
var up = GetUpDirectionFromTransform(transform);
double[,] matrix =
{
{ Math.Abs(forward.X), Math.Abs(localY.X), Math.Abs(up.X) },
{ Math.Abs(forward.Y), Math.Abs(localY.Y), Math.Abs(up.Y) },
{ Math.Abs(forward.Z), Math.Abs(localY.Z), Math.Abs(up.Z) }
};
double[] worldHalfExtents = { halfXWorld, halfYWorld, halfZWorld };
double[] localHalfExtents = SolveLinearSystem3x3(matrix, worldHalfExtents);
return new Vector3D(
Math.Max(0.0, localHalfExtents[0] * 2.0),
Math.Max(0.0, localHalfExtents[1] * 2.0),
Math.Max(0.0, localHalfExtents[2] * 2.0));
}
catch (Exception)
{
return new Vector3D(halfXWorld * 2.0, halfYWorld * 2.0, halfZWorld * 2.0);
}
}
/// <summary>
/// 根据箱体局部尺寸和世界原点方向,推导“背离球心”的真实长轴方向。
/// 先选局部最长轴,再用箱体中心相对世界原点的方向决定正负。
/// </summary>
public static Vector3D GetLongestAxisDirectionAwayFromOrigin(BoundingBox3D bounds, Transform3D transform)
{
Vector3D localSize = EstimateLocalBoxSize(bounds, transform);
int longestAxisIndex = 0;
double longestAxisLength = localSize.X;
if (localSize.Y > longestAxisLength)
{
longestAxisIndex = 1;
longestAxisLength = localSize.Y;
}
if (localSize.Z > longestAxisLength)
{
longestAxisIndex = 2;
}
Vector3D axisDirection = GetAxisDirectionFromTransform(
transform,
longestAxisIndex,
longestAxisIndex == 0 ? new Vector3D(1, 0, 0) :
longestAxisIndex == 1 ? new Vector3D(0, 1, 0) :
new Vector3D(0, 0, 1));
Vector3D awayFromOrigin = new Vector3D(bounds.Center.X, bounds.Center.Y, bounds.Center.Z);
double awayLengthSquared = awayFromOrigin.X * awayFromOrigin.X + awayFromOrigin.Y * awayFromOrigin.Y + awayFromOrigin.Z * awayFromOrigin.Z;
if (awayLengthSquared < 1e-9)
{
return axisDirection;
}
double dot = axisDirection.X * awayFromOrigin.X + axisDirection.Y * awayFromOrigin.Y + axisDirection.Z * awayFromOrigin.Z;
if (dot < 0.0)
{
return new Vector3D(-axisDirection.X, -axisDirection.Y, -axisDirection.Z);
}
return axisDirection;
}
private static Vector3D GetAxisDirectionFromTransform(Transform3D transform, int axisIndex, Vector3D fallback)
{
if (transform == null)
{
return fallback;
}
try
{
var linear = transform.Linear;
var direction = new Vector3D(
linear.Get(0, axisIndex),
linear.Get(1, axisIndex),
linear.Get(2, axisIndex));
double lengthSquared = direction.X * direction.X + direction.Y * direction.Y + direction.Z * direction.Z;
if (lengthSquared < 1e-9)
{
return fallback;
}
double length = Math.Sqrt(lengthSquared);
return new Vector3D(direction.X / length, direction.Y / length, direction.Z / length);
}
catch (Exception)
{
return fallback;
}
}
private static void GetAxisIndexAndSign(LocalAxisDirection axisDirection, out int axisIndex, out int sign)
{
switch (axisDirection)
{
case LocalAxisDirection.PositiveX:
axisIndex = 0;
sign = 1;
break;
case LocalAxisDirection.NegativeX:
axisIndex = 0;
sign = -1;
break;
case LocalAxisDirection.PositiveY:
axisIndex = 1;
sign = 1;
break;
case LocalAxisDirection.NegativeY:
axisIndex = 1;
sign = -1;
break;
case LocalAxisDirection.PositiveZ:
axisIndex = 2;
sign = 1;
break;
case LocalAxisDirection.NegativeZ:
axisIndex = 2;
sign = -1;
break;
default:
throw new ArgumentOutOfRangeException(nameof(axisDirection), axisDirection, null);
}
}
private static Vector3D GetFallbackAxis(LocalAxisDirection axisDirection)
{
switch (axisDirection)
{
case LocalAxisDirection.PositiveX:
return new Vector3D(1, 0, 0);
case LocalAxisDirection.NegativeX:
return new Vector3D(-1, 0, 0);
case LocalAxisDirection.PositiveY:
return new Vector3D(0, 1, 0);
case LocalAxisDirection.NegativeY:
return new Vector3D(0, -1, 0);
case LocalAxisDirection.PositiveZ:
return new Vector3D(0, 0, 1);
case LocalAxisDirection.NegativeZ:
return new Vector3D(0, 0, -1);
default:
throw new ArgumentOutOfRangeException(nameof(axisDirection), axisDirection, null);
}
}
private static double[] SolveLinearSystem3x3(double[,] matrix, double[] values)
{
double determinant =
matrix[0, 0] * (matrix[1, 1] * matrix[2, 2] - matrix[1, 2] * matrix[2, 1]) -
matrix[0, 1] * (matrix[1, 0] * matrix[2, 2] - matrix[1, 2] * matrix[2, 0]) +
matrix[0, 2] * (matrix[1, 0] * matrix[2, 1] - matrix[1, 1] * matrix[2, 0]);
if (Math.Abs(determinant) < 1e-9)
{
return new[] { values[0], values[1], values[2] };
}
double inverseDeterminant = 1.0 / determinant;
double[,] inverse =
{
{
(matrix[1, 1] * matrix[2, 2] - matrix[1, 2] * matrix[2, 1]) * inverseDeterminant,
(matrix[0, 2] * matrix[2, 1] - matrix[0, 1] * matrix[2, 2]) * inverseDeterminant,
(matrix[0, 1] * matrix[1, 2] - matrix[0, 2] * matrix[1, 1]) * inverseDeterminant
},
{
(matrix[1, 2] * matrix[2, 0] - matrix[1, 0] * matrix[2, 2]) * inverseDeterminant,
(matrix[0, 0] * matrix[2, 2] - matrix[0, 2] * matrix[2, 0]) * inverseDeterminant,
(matrix[0, 2] * matrix[1, 0] - matrix[0, 0] * matrix[1, 2]) * inverseDeterminant
},
{
(matrix[1, 0] * matrix[2, 1] - matrix[1, 1] * matrix[2, 0]) * inverseDeterminant,
(matrix[0, 1] * matrix[2, 0] - matrix[0, 0] * matrix[2, 1]) * inverseDeterminant,
(matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0]) * inverseDeterminant
}
};
return new[]
{
inverse[0, 0] * values[0] + inverse[0, 1] * values[1] + inverse[0, 2] * values[2],
inverse[1, 0] * values[0] + inverse[1, 1] * values[1] + inverse[1, 2] * values[2],
inverse[2, 0] * values[0] + inverse[2, 1] * values[1] + inverse[2, 2] * values[2]
};
}
/// <summary>
/// 恢复物体到原位置
/// </summary>
/// <param name="item">要恢复的物体</param>
/// <param name="originalOffset">原始移动偏移向量</param>
public static void RestoreItemPosition(ModelItem item, Vector3D originalOffset)
{
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
// 反向偏移
var restoreOffset = new Vector3D(-originalOffset.X, -originalOffset.Y, -originalOffset.Z);
var restoreTransform = Transform3D.CreateTranslation(restoreOffset);
doc.Models.OverridePermanentTransform(modelItems, restoreTransform, false);
}
/// <summary>
/// 将物体移动到指定位置和朝向先回到CAD原始位置再移动
/// 适用于碰撞位置还原等场景
/// </summary>
/// <param name="item">要移动的物体</param>
/// <param name="targetPosition">目标位置(动画跟踪点,当前统一为几何中心)</param>
/// <param name="targetYaw">目标朝向弧度绕Z轴</param>
public static void MoveItemToPositionAndYaw(ModelItem item, Point3D targetPosition, double targetYaw)
{
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
// 🔥 关键先回到CAD原始位置确保从已知状态开始计算
doc.Models.ResetPermanentTransform(modelItems);
// 获取CAD原始状态
var originalBounds = item.BoundingBox();
var originalCenterPos = originalBounds.Center;
var originalYaw = GetYawFromTransform(item.Transform);
// 计算从CAD原始位置到目标位置的增量
var deltaPos = new Vector3D(
targetPosition.X - originalCenterPos.X,
targetPosition.Y - originalCenterPos.Y,
targetPosition.Z - originalCenterPos.Z
);
double deltaYaw = targetYaw - originalYaw;
// 应用增量变换
Transform3D transform;
if (Math.Abs(deltaYaw) > 0.001)
{
// 有旋转:需要补偿绕原点旋转带来的位置偏移
double cos = Math.Cos(deltaYaw);
double sin = Math.Sin(deltaYaw);
double rotatedX = originalCenterPos.X * cos - originalCenterPos.Y * sin;
double rotatedY = originalCenterPos.X * sin + originalCenterPos.Y * cos;
var compensatedTranslation = new Vector3D(
targetPosition.X - rotatedX,
targetPosition.Y - rotatedY,
targetPosition.Z - originalCenterPos.Z
);
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
components.Translation = compensatedTranslation;
transform = components.Combine();
}
else
{
// 纯平移
transform = Transform3D.CreateTranslation(deltaPos);
}
doc.Models.OverridePermanentTransform(modelItems, transform, false);
}
/// <summary>
/// 将物体移动到指定位置和完整三维朝向先回到CAD原始位置再移动
/// </summary>
public static void MoveItemToPositionAndRotation(ModelItem item, Point3D targetPosition, Rotation3D targetRotation)
{
ApplyAbsoluteTransform(item, targetPosition, targetRotation, preserveCurrentScale: false);
}
/// <summary>
/// 将物体移动到指定位置和完整三维朝向,同时保留当前缩放。
/// </summary>
public static void MoveItemToPositionAndRotationWithCurrentScale(ModelItem item, Point3D targetPosition, Rotation3D targetRotation)
{
ApplyAbsoluteTransform(item, targetPosition, targetRotation, preserveCurrentScale: true);
}
/// <summary>
/// 基于物体当前实际姿态,增量移动到目标位置和完整三维朝向。
/// 适用于动画过程中的真实模型物体,避免每次回到 CAD 原始状态导致位置跑偏。
/// </summary>
public static void MoveItemIncrementallyToPositionAndRotation(
ModelItem item,
Point3D currentPosition,
Rotation3D currentRotation,
Point3D targetPosition,
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 deltaLinear = new Transform3D(deltaRotation).Linear;
var currentLinear = new Transform3D(currentRotation).Linear;
var targetLinear = new Transform3D(targetRotation).Linear;
var rotatedCurrentPosition = new Point3D(
deltaLinear.Get(0, 0) * currentPosition.X + deltaLinear.Get(0, 1) * currentPosition.Y + deltaLinear.Get(0, 2) * currentPosition.Z,
deltaLinear.Get(1, 0) * currentPosition.X + deltaLinear.Get(1, 1) * currentPosition.Y + deltaLinear.Get(1, 2) * currentPosition.Z,
deltaLinear.Get(2, 0) * currentPosition.X + deltaLinear.Get(2, 1) * currentPosition.Y + deltaLinear.Get(2, 2) * currentPosition.Z);
var translation = new Vector3D(
targetPosition.X - rotatedCurrentPosition.X,
targetPosition.Y - rotatedCurrentPosition.Y,
targetPosition.Z - rotatedCurrentPosition.Z);
LogManager.Debug(
$"[模型增量姿态] {item.DisplayName} 当前=({currentPosition.X:F3},{currentPosition.Y:F3},{currentPosition.Z:F3}), " +
$"目标=({targetPosition.X:F3},{targetPosition.Y:F3},{targetPosition.Z:F3}), " +
$"平移=({translation.X:F3},{translation.Y:F3},{translation.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})");
LogManager.Debug(
$"[模型增量姿态] {item.DisplayName} 增量旋转: " +
$"X=({deltaLinear.Get(0, 0):F4},{deltaLinear.Get(1, 0):F4},{deltaLinear.Get(2, 0):F4}), " +
$"Y=({deltaLinear.Get(0, 1):F4},{deltaLinear.Get(1, 1):F4},{deltaLinear.Get(2, 1):F4}), " +
$"Z=({deltaLinear.Get(0, 2):F4},{deltaLinear.Get(1, 2):F4},{deltaLinear.Get(2, 2):F4}), " +
$"旋后当前点=({rotatedCurrentPosition.X:F3},{rotatedCurrentPosition.Y:F3},{rotatedCurrentPosition.Z:F3})");
LogGeometryLevelTransforms(item, "[模型增量姿态应用前][GeometryAPI]");
// 用显式三步法应用三维增量位姿:
// 1. 把当前锚点移到原点
// 2. 绕原点旋转到目标姿态
// 3. 再把锚点移到目标位置
// 这与旧 yaw 链路的补偿语义一致,只是从二维扩展到三维。
var toOrigin = Transform3D.CreateTranslation(new Vector3D(
-currentPosition.X,
-currentPosition.Y,
-currentPosition.Z));
doc.Models.OverridePermanentTransform(modelItems, toOrigin, false);
var rotationOnlyComponents = Transform3D.CreateTranslation(new Vector3D(0, 0, 0)).Factor();
rotationOnlyComponents.Rotation = deltaRotation;
var rotationOnly = rotationOnlyComponents.Combine();
doc.Models.OverridePermanentTransform(modelItems, rotationOnly, false);
var toTarget = Transform3D.CreateTranslation(new Vector3D(
targetPosition.X,
targetPosition.Y,
targetPosition.Z));
doc.Models.OverridePermanentTransform(modelItems, toTarget, false);
LogIncrementalTransformActual(item, targetPosition, targetRotation);
}
/// <summary>
/// 合并三次绕宿主轴的旋转 + 一次平移为单次 OverridePermanentTransform 调用。
/// 等价于依次调用三次 MoveItemIncrementallyByAxisRotationAndTranslation但 NW API 调用次数减少 66%。
/// </summary>
public static void MoveItemCombinedAxisRotationAndTranslation(
ModelItem item,
Point3D trackedPosition,
Vector3 axis1, double angle1Radians,
Vector3 axis2, double angle2Radians,
Vector3 axis3, double angle3Radians,
Point3D targetPosition)
{
if (item == null) throw new ArgumentNullException(nameof(item));
// 用 System.Numerics 合成三个旋转
var q1 = Quaternion.CreateFromAxisAngle(Vector3.Normalize(axis1), (float)angle1Radians);
var q2 = Quaternion.CreateFromAxisAngle(Vector3.Normalize(axis2), (float)angle2Radians);
var q3 = Quaternion.CreateFromAxisAngle(Vector3.Normalize(axis3), (float)angle3Radians);
// q3 * q2 * q1: apply q1 first, then q2, then q3与 Override 左乘积累顺序一致)
var totalQ = Quaternion.Normalize(q3 * q2 * q1);
// 计算旋后跟踪点位置
var tp = new Vector3((float)trackedPosition.X, (float)trackedPosition.Y, (float)trackedPosition.Z);
var rotatedTp = Vector3.Transform(tp, totalQ);
// 计算组合变换(调用方已在 RestoreObjectToCADPosition 中执行 ResetPermanentTransform此处不重复
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Rotation = new Rotation3D(totalQ.X, totalQ.Y, totalQ.Z, totalQ.W);
components.Translation = new Vector3D(
targetPosition.X - rotatedTp.X,
targetPosition.Y - rotatedTp.Y,
targetPosition.Z - rotatedTp.Z);
var combined = components.Combine();
LogManager.Debug(
$"[组合旋转平移] tracked=({trackedPosition.X:F3},{trackedPosition.Y:F3},{trackedPosition.Z:F3}), " +
$"target=({targetPosition.X:F3},{targetPosition.Y:F3},{targetPosition.Z:F3}), " +
$"translation=({components.Translation.X:F3},{components.Translation.Y:F3},{components.Translation.Z:F3})");
doc.Models.OverridePermanentTransform(modelItems, combined, false);
}
/// <summary>
/// 直接对当前显示结果施加宿主轴旋转增量,再补一段平移把业务跟踪点拉回目标点。
/// 不先构造 targetRotation也不从 current/target 姿态反推 deltaRotation。
/// </summary>
public static void MoveItemIncrementallyByAxisRotationAndTranslation(
ModelItem item,
Point3D currentPosition,
Vector3 hostAxis,
double deltaAngleRadians,
Point3D targetPosition)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
if (hostAxis.LengthSquared() < 1e-12f)
{
throw new ArgumentException("hostAxis must be non-zero.", nameof(hostAxis));
}
Vector3 normalizedHostAxis = Vector3.Normalize(hostAxis);
Rotation3D deltaRotation = new Rotation3D(
new UnitVector3D(normalizedHostAxis.X, normalizedHostAxis.Y, normalizedHostAxis.Z),
deltaAngleRadians);
Matrix3 deltaLinear = new Transform3D(deltaRotation).Linear;
Point3D rotatedCurrentPosition = new Point3D(
deltaLinear.Get(0, 0) * currentPosition.X + deltaLinear.Get(0, 1) * currentPosition.Y + deltaLinear.Get(0, 2) * currentPosition.Z,
deltaLinear.Get(1, 0) * currentPosition.X + deltaLinear.Get(1, 1) * currentPosition.Y + deltaLinear.Get(1, 2) * currentPosition.Z,
deltaLinear.Get(2, 0) * currentPosition.X + deltaLinear.Get(2, 1) * currentPosition.Y + deltaLinear.Get(2, 2) * currentPosition.Z);
Vector3D compensatedTranslation = new Vector3D(
targetPosition.X - rotatedCurrentPosition.X,
targetPosition.Y - rotatedCurrentPosition.Y,
targetPosition.Z - rotatedCurrentPosition.Z);
LogManager.Debug(
$"[模型纯增量旋转平移] {item.DisplayName} 当前=({currentPosition.X:F3},{currentPosition.Y:F3},{currentPosition.Z:F3}), " +
$"目标=({targetPosition.X:F3},{targetPosition.Y:F3},{targetPosition.Z:F3}), " +
$"Axis=({normalizedHostAxis.X:F4},{normalizedHostAxis.Y:F4},{normalizedHostAxis.Z:F4}), " +
$"Angle={deltaAngleRadians * 180.0 / Math.PI:F2}°, " +
$"旋后当前点=({rotatedCurrentPosition.X:F3},{rotatedCurrentPosition.Y:F3},{rotatedCurrentPosition.Z:F3}), " +
$"平移=({compensatedTranslation.X:F3},{compensatedTranslation.Y:F3},{compensatedTranslation.Z:F3})");
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
LogGeometryLevelTransforms(item, "[模型纯增量旋转平移应用前][GeometryAPI]");
var toOrigin = Transform3D.CreateTranslation(new Vector3D(
-currentPosition.X,
-currentPosition.Y,
-currentPosition.Z));
doc.Models.OverridePermanentTransform(modelItems, toOrigin, false);
var rotationOnlyComponents = Transform3D.CreateTranslation(new Vector3D(0, 0, 0)).Factor();
rotationOnlyComponents.Rotation = deltaRotation;
var rotationOnly = rotationOnlyComponents.Combine();
doc.Models.OverridePermanentTransform(modelItems, rotationOnly, false);
var toTarget = Transform3D.CreateTranslation(new Vector3D(
targetPosition.X,
targetPosition.Y,
targetPosition.Z));
doc.Models.OverridePermanentTransform(modelItems, toTarget, false);
LogGeometryLevelTransforms(item, "[模型纯增量旋转平移应用后][GeometryAPI]");
}
/// <summary>
/// 读取物体当前实际几何姿态。
/// 优先使用 ModelGeometry.ActiveTransform因为 ModelItem.Transform 只反映原始设计变换。
/// </summary>
public static bool TryGetCurrentGeometryRotation(ModelItem item, out Rotation3D rotation)
{
rotation = Rotation3D.Identity;
if (item == null)
{
return false;
}
try
{
ModelGeometry geometry = item.FindFirstGeometry() ?? item.Geometry;
if (geometry?.ActiveTransform == null)
{
return false;
}
rotation = geometry.ActiveTransform.Factor().Rotation;
return true;
}
catch (Exception ex)
{
LogManager.Warning($"[当前几何姿态] 读取 ActiveTransform 失败: {ex.Message}");
return false;
}
}
public static bool TryGetCurrentOverrideRotation(ModelItem item, out Rotation3D rotation)
{
rotation = Rotation3D.Identity;
if (item == null)
{
return false;
}
try
{
ModelGeometry geometry = item.FindFirstGeometry() ?? item.Geometry;
if (geometry?.PermanentOverrideTransform == null)
{
return true;
}
rotation = geometry.PermanentOverrideTransform.Factor().Rotation;
return true;
}
catch (Exception ex)
{
LogManager.Warning($"[当前覆盖姿态] 读取 PermanentOverrideTransform 失败: {ex.Message}");
return false;
}
}
public static bool TryResolveOverrideRotationForFinalTarget(
ModelItem item,
Rotation3D finalTargetRotation,
out Rotation3D overrideRotation)
{
overrideRotation = Rotation3D.Identity;
if (item == null)
{
return false;
}
try
{
ModelGeometry geometry = item.FindFirstGeometry() ?? item.Geometry;
Transform3D originalTransform = geometry?.OriginalTransform ?? item.Transform;
Rotation3D originalRotation = originalTransform.Factor().Rotation;
var originalInverse = originalRotation.Invert();
var overrideTransform = Transform3D.Multiply(
new Transform3D(originalInverse),
new Transform3D(finalTargetRotation));
overrideRotation = overrideTransform.Factor().Rotation;
return true;
}
catch (Exception ex)
{
LogManager.Warning($"[覆盖姿态换算] 计算 override 姿态失败: {ex.Message}");
return false;
}
}
public static void LogCurrentGeometryTransformsForDebug(ModelItem item, string prefix)
{
LogGeometryLevelTransforms(item, prefix);
}
private static void LogIncrementalTransformActual(ModelItem item, Point3D targetPosition, Rotation3D targetRotation)
{
try
{
var actualBounds = item.BoundingBox();
var actualTransform = item.Transform;
var actualRotation = actualTransform.Factor().Rotation;
var actualLinear = new Transform3D(actualRotation).Linear;
var targetLinear = new Transform3D(targetRotation).Linear;
var actualPosition = actualBounds.Center;
LogManager.Debug(
$"[模型增量姿态] {item.DisplayName} 立即读回位置(可能滞后): " +
$"实际=({actualPosition.X:F3},{actualPosition.Y:F3},{actualPosition.Z:F3}), " +
$"期望=({targetPosition.X:F3},{targetPosition.Y:F3},{targetPosition.Z:F3}), " +
$"偏差=({actualPosition.X - targetPosition.X:F3},{actualPosition.Y - targetPosition.Y:F3},{actualPosition.Z - targetPosition.Z:F3})");
LogManager.Debug(
$"[模型增量姿态] {item.DisplayName} 立即读回旋转(可能滞后/不反映override): " +
$"实际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}), " +
$"期望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]");
}
catch (Exception ex)
{
LogManager.Warning($"[模型增量姿态] 输出应用后日志失败: {ex.Message}");
}
}
/// <summary>
/// 将物体移动到指定中心点和完整三维朝向,同时保留当前缩放。
/// 仅适用于“几何中心就是业务定位点”的实体,例如参考杆、辅助几何、虚拟包围盒。
/// 不适用于真实模型物体的动画、碰撞验证或场景恢复;真实模型应使用增量三步法,
/// 即先将固定参考点移到原点,再旋转,再移动到目标位置。
/// </summary>
public static void MoveItemToCenterAndRotationWithCurrentScale(ModelItem item, Point3D targetCenter, Rotation3D targetRotation)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
var currentComponents = item.Transform.Factor();
Vector3D currentScale = currentComponents.Scale;
doc.Models.ResetPermanentTransform(modelItems);
var originalBounds = item.BoundingBox();
Point3D originalCenter = originalBounds.Center;
var rotationTransform = new Transform3D(targetRotation);
var linear = rotationTransform.Linear;
var rotatedCenter = new Point3D(
linear.Get(0, 0) * originalCenter.X + linear.Get(0, 1) * originalCenter.Y + linear.Get(0, 2) * originalCenter.Z,
linear.Get(1, 0) * originalCenter.X + linear.Get(1, 1) * originalCenter.Y + linear.Get(1, 2) * originalCenter.Z,
linear.Get(2, 0) * originalCenter.X + linear.Get(2, 1) * originalCenter.Y + linear.Get(2, 2) * originalCenter.Z);
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Scale = currentScale;
components.Rotation = targetRotation;
components.Translation = new Vector3D(
targetCenter.X - rotatedCenter.X,
targetCenter.Y - rotatedCenter.Y,
targetCenter.Z - rotatedCenter.Z);
doc.Models.OverridePermanentTransform(modelItems, components.Combine(), false);
}
/// <summary>
/// 将物体移动到指定中心点和完整三维朝向。
/// 仅应用位置和旋转,不保留当前缩放。
/// 仅适用于“几何中心就是业务定位点”的实体,例如缩放已经在 Model 层完成的参考杆。
/// 不适用于真实模型物体的动画、碰撞验证或场景恢复;真实模型应使用增量三步法,
/// 即先将固定参考点移到原点,再旋转,再移动到目标位置。
/// </summary>
public static void MoveItemToCenterAndRotation(ModelItem item, Point3D targetCenter, Rotation3D targetRotation)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
doc.Models.ResetPermanentTransform(modelItems);
var originalBounds = item.BoundingBox();
Point3D originalCenter = originalBounds.Center;
var rotationTransform = new Transform3D(targetRotation);
var linear = rotationTransform.Linear;
var rotatedCenter = new Point3D(
linear.Get(0, 0) * originalCenter.X + linear.Get(0, 1) * originalCenter.Y + linear.Get(0, 2) * originalCenter.Z,
linear.Get(1, 0) * originalCenter.X + linear.Get(1, 1) * originalCenter.Y + linear.Get(1, 2) * originalCenter.Z,
linear.Get(2, 0) * originalCenter.X + linear.Get(2, 1) * originalCenter.Y + linear.Get(2, 2) * originalCenter.Z);
var translation = new Vector3D(
targetCenter.X - rotatedCenter.X,
targetCenter.Y - rotatedCenter.Y,
targetCenter.Z - rotatedCenter.Z);
doc.Models.OverridePermanentTransform(modelItems, new Transform3D(targetRotation, translation), false);
}
/// <summary>
/// 将物体的局部正 X 端面中心对齐到目标点,并保留当前缩放。
/// 适用于单位立方体/单位圆柱体沿 +X 定义长度方向的参考杆资源。
/// </summary>
public static void MoveItemPositiveXEndToPointAndRotationWithCurrentScale(ModelItem item, Point3D targetPoint, Rotation3D targetRotation)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
var currentComponents = item.Transform.Factor();
Vector3D currentScale = currentComponents.Scale;
doc.Models.ResetPermanentTransform(modelItems);
var originalBounds = item.BoundingBox();
Point3D originalPositiveXEndCenter = new Point3D(
originalBounds.Max.X,
originalBounds.Center.Y,
originalBounds.Center.Z);
var rotationTransform = new Transform3D(targetRotation);
var linear = rotationTransform.Linear;
var rotatedPositiveXEndCenter = new Point3D(
linear.Get(0, 0) * originalPositiveXEndCenter.X + linear.Get(0, 1) * originalPositiveXEndCenter.Y + linear.Get(0, 2) * originalPositiveXEndCenter.Z,
linear.Get(1, 0) * originalPositiveXEndCenter.X + linear.Get(1, 1) * originalPositiveXEndCenter.Y + linear.Get(1, 2) * originalPositiveXEndCenter.Z,
linear.Get(2, 0) * originalPositiveXEndCenter.X + linear.Get(2, 1) * originalPositiveXEndCenter.Y + linear.Get(2, 2) * originalPositiveXEndCenter.Z);
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Scale = currentScale;
components.Rotation = targetRotation;
components.Translation = new Vector3D(
targetPoint.X - rotatedPositiveXEndCenter.X,
targetPoint.Y - rotatedPositiveXEndCenter.Y,
targetPoint.Z - rotatedPositiveXEndCenter.Z);
doc.Models.OverridePermanentTransform(modelItems, components.Combine(), false);
}
/// <summary>
/// 将物体的局部正 X 端面中心对齐到目标点。
/// 仅应用位置和旋转,不保留当前缩放。
/// 适用于缩放已经在 Model 层完成、Item 层只负责定位的场景。
/// </summary>
public static void MoveItemPositiveXEndToPointAndRotation(ModelItem item, Point3D targetPoint, Rotation3D targetRotation)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
doc.Models.ResetPermanentTransform(modelItems);
var originalBounds = item.BoundingBox();
Point3D originalPositiveXEndCenter = new Point3D(
originalBounds.Max.X,
originalBounds.Center.Y,
originalBounds.Center.Z);
var rotationTransform = new Transform3D(targetRotation);
var linear = rotationTransform.Linear;
var rotatedPositiveXEndCenter = new Point3D(
linear.Get(0, 0) * originalPositiveXEndCenter.X + linear.Get(0, 1) * originalPositiveXEndCenter.Y + linear.Get(0, 2) * originalPositiveXEndCenter.Z,
linear.Get(1, 0) * originalPositiveXEndCenter.X + linear.Get(1, 1) * originalPositiveXEndCenter.Y + linear.Get(1, 2) * originalPositiveXEndCenter.Z,
linear.Get(2, 0) * originalPositiveXEndCenter.X + linear.Get(2, 1) * originalPositiveXEndCenter.Y + linear.Get(2, 2) * originalPositiveXEndCenter.Z);
var translation = new Vector3D(
targetPoint.X - rotatedPositiveXEndCenter.X,
targetPoint.Y - rotatedPositiveXEndCenter.Y,
targetPoint.Z - rotatedPositiveXEndCenter.Z);
doc.Models.OverridePermanentTransform(modelItems, new Transform3D(targetRotation, translation), false);
}
private static void ApplyAbsoluteTransform(ModelItem item, Point3D targetPosition, Rotation3D targetRotation, bool preserveCurrentScale)
{
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
Vector3D currentScale = new Vector3D(1, 1, 1);
ModelGeometry geometry = item.FindFirstGeometry() ?? item.Geometry;
if (preserveCurrentScale)
{
var currentBaseTransform = geometry?.PermanentOverrideTransform ?? item.Transform;
var currentComponents = currentBaseTransform.Factor();
currentScale = currentComponents.Scale;
}
doc.Models.ResetPermanentTransform(modelItems);
var originalTransform = geometry?.OriginalTransform ?? item.Transform;
var originalComponents = originalTransform.Factor();
var originalRotation = originalComponents.Rotation;
var originalBounds = geometry?.BoundingBox ?? item.BoundingBox();
var originalCenterPos = originalBounds.Center;
Rotation3D deltaRotation = BuildDeltaRotation(originalRotation, targetRotation);
var rotationTransform = new Transform3D(deltaRotation);
var linear = rotationTransform.Linear;
var rotatedCenterPos = new Point3D(
linear.Get(0, 0) * originalCenterPos.X + linear.Get(0, 1) * originalCenterPos.Y + linear.Get(0, 2) * originalCenterPos.Z,
linear.Get(1, 0) * originalCenterPos.X + linear.Get(1, 1) * originalCenterPos.Y + linear.Get(1, 2) * originalCenterPos.Z,
linear.Get(2, 0) * originalCenterPos.X + linear.Get(2, 1) * originalCenterPos.Y + linear.Get(2, 2) * originalCenterPos.Z
);
var translation = new Vector3D(
targetPosition.X - rotatedCenterPos.X,
targetPosition.Y - rotatedCenterPos.Y,
targetPosition.Z - rotatedCenterPos.Z
);
Transform3D transform;
if (preserveCurrentScale)
{
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Scale = currentScale;
components.Rotation = deltaRotation;
components.Translation = translation;
transform = components.Combine();
}
else
{
transform = new Transform3D(deltaRotation, translation);
}
LogAbsoluteTransformDiagnostics(item, originalRotation, targetRotation, deltaRotation, originalCenterPos, targetPosition, translation);
doc.Models.OverridePermanentTransform(modelItems, transform, false);
LogAbsoluteTransformActual(item, preserveCurrentScale, currentScale, targetPosition, targetRotation);
}
private static Rotation3D BuildDeltaRotation(Rotation3D originalRotation, Rotation3D targetRotation)
{
var originalInverse = originalRotation.Invert();
var deltaTransform = Transform3D.Multiply(
new Transform3D(targetRotation),
new Transform3D(originalInverse));
return deltaTransform.Factor().Rotation;
}
private static void LogAbsoluteTransformDiagnostics(
ModelItem item,
Rotation3D originalRotation,
Rotation3D targetRotation,
Rotation3D deltaRotation,
Point3D originalTrackedPosition,
Point3D targetPosition,
Vector3D translation)
{
try
{
var originalLinear = new Transform3D(originalRotation).Linear;
var targetLinear = new Transform3D(targetRotation).Linear;
var deltaLinear = new Transform3D(deltaRotation).Linear;
LogManager.Debug(
$"[模型姿态] {item.DisplayName} 原始: " +
$"X=({originalLinear.Get(0, 0):F4},{originalLinear.Get(1, 0):F4},{originalLinear.Get(2, 0):F4}), " +
$"Y=({originalLinear.Get(0, 1):F4},{originalLinear.Get(1, 1):F4},{originalLinear.Get(2, 1):F4}), " +
$"Z=({originalLinear.Get(0, 2):F4},{originalLinear.Get(1, 2):F4},{originalLinear.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})");
LogManager.Debug(
$"[模型姿态] {item.DisplayName} 增量: " +
$"X=({deltaLinear.Get(0, 0):F4},{deltaLinear.Get(1, 0):F4},{deltaLinear.Get(2, 0):F4}), " +
$"Y=({deltaLinear.Get(0, 1):F4},{deltaLinear.Get(1, 1):F4},{deltaLinear.Get(2, 1):F4}), " +
$"Z=({deltaLinear.Get(0, 2):F4},{deltaLinear.Get(1, 2):F4},{deltaLinear.Get(2, 2):F4}), " +
$"原始跟踪点=({originalTrackedPosition.X:F3},{originalTrackedPosition.Y:F3},{originalTrackedPosition.Z:F3}), " +
$"目标跟踪点=({targetPosition.X:F3},{targetPosition.Y:F3},{targetPosition.Z:F3}), " +
$"平移=({translation.X:F3},{translation.Y:F3},{translation.Z:F3})");
}
catch (Exception ex)
{
LogManager.Warning($"[模型姿态] 输出诊断日志失败: {ex.Message}");
}
}
private static void LogAbsoluteTransformActual(
ModelItem item,
bool preserveCurrentScale,
Vector3D currentScale,
Point3D targetPosition,
Rotation3D targetRotation)
{
try
{
Transform3D actualTransform = item.Transform;
var actualComponents = actualTransform.Factor();
var actualRotation = actualComponents.Rotation;
var actualScale = actualComponents.Scale;
var actualLinear = new Transform3D(actualRotation).Linear;
var targetLinear = new Transform3D(targetRotation).Linear;
var actualBounds = item.BoundingBox();
Point3D actualCenter = actualBounds?.Center ?? new Point3D(0, 0, 0);
LogManager.Debug(
$"[模型姿态应用后] {item.DisplayName} PreserveScale={preserveCurrentScale}, " +
$"输入Scale=({currentScale.X:F4},{currentScale.Y:F4},{currentScale.Z:F4}), " +
$"实际Scale=({actualScale.X:F4},{actualScale.Y:F4},{actualScale.Z:F4}), " +
$"目标中心=({targetPosition.X:F3},{targetPosition.Y:F3},{targetPosition.Z:F3}), " +
$"实际中心=({actualCenter.X:F3},{actualCenter.Y:F3},{actualCenter.Z:F3})");
LogManager.Debug(
$"[模型姿态应用后] {item.DisplayName} 目标Transform轴: " +
$"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})");
LogManager.Debug(
$"[模型姿态应用后] {item.DisplayName} 实际Transform轴: " +
$"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})");
LogGeometryLevelTransforms(item, "[模型姿态应用后][GeometryAPI]");
}
catch (Exception ex)
{
LogManager.Warning($"[模型姿态应用后] 输出诊断日志失败: {ex.Message}");
}
}
private static void LogGeometryLevelTransforms(ModelItem item, string prefix)
{
if (item == null)
{
return;
}
try
{
ModelGeometry geometry = item.FindFirstGeometry() ?? item.Geometry;
if (geometry == null)
{
LogManager.Debug($"{prefix} Geometry=null");
return;
}
LogManager.Debug(
$"{prefix} GeometryType={geometry.GetType().FullName}, " +
$"FragmentCount={geometry.FragmentCount}, " +
$"BoundsCenter=({geometry.BoundingBox.Center.X:F3},{geometry.BoundingBox.Center.Y:F3},{geometry.BoundingBox.Center.Z:F3})");
LogTransformProperty(geometry.OriginalTransform, $"{prefix} OriginalTransform");
LogTransformProperty(geometry.PermanentOverrideTransform, $"{prefix} PermanentOverrideTransform");
LogTransformProperty(geometry.PermanentTransform, $"{prefix} PermanentTransform");
LogTransformProperty(geometry.ActiveTransform, $"{prefix} ActiveTransform");
}
catch (Exception ex)
{
LogManager.Warning($"{prefix} 读取几何层当前变换失败: {ex.Message}");
}
}
private static void LogTransformProperty(Transform3D transform, string prefix)
{
if (transform == null)
{
LogManager.Debug($"{prefix}=null");
return;
}
try
{
var linear = transform.Linear;
var components = transform.Factor();
LogManager.Debug(
$"{prefix}: " +
$"X=({linear.Get(0, 0):F4},{linear.Get(1, 0):F4},{linear.Get(2, 0):F4}), " +
$"Y=({linear.Get(0, 1):F4},{linear.Get(1, 1):F4},{linear.Get(2, 1):F4}), " +
$"Z=({linear.Get(0, 2):F4},{linear.Get(1, 2):F4},{linear.Get(2, 2):F4}), " +
$"T=({components.Translation.X:F3},{components.Translation.Y:F3},{components.Translation.Z:F3})");
}
catch (Exception ex)
{
LogManager.Warning($"{prefix} 读取失败: {ex.Message}");
}
}
/// <summary>
/// 将物体移动到指定位置和朝向,同时保持缩放比例
/// 专为虚拟物体设计,避免缩放被覆盖
/// </summary>
/// <param name="item">要移动的物体</param>
/// <param name="targetPosition">目标位置(地面位置)</param>
/// <param name="targetYaw">目标朝向(弧度)</param>
/// <param name="scaleX">X方向缩放</param>
/// <param name="scaleY">Y方向缩放</param>
/// <param name="scaleZ">Z方向缩放</param>
public static void MoveItemToPositionAndYawWithScale(ModelItem item, Point3D targetPosition, double targetYaw,
double scaleX, double scaleY, double scaleZ)
{
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { item };
// 重置到CAD原始状态
doc.Models.ResetPermanentTransform(modelItems);
// 获取CAD原始状态
var originalBounds = item.BoundingBox();
var originalCenterPos = originalBounds.Center;
var originalYaw = GetYawFromTransform(item.Transform);
// 计算从CAD原始位置到目标位置的增量
var deltaPos = new Vector3D(
targetPosition.X - originalCenterPos.X,
targetPosition.Y - originalCenterPos.Y,
targetPosition.Z - originalCenterPos.Z
);
double deltaYaw = targetYaw - originalYaw;
// 构建变换组件
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
// 应用缩放
components.Scale = new Vector3D(scaleX, scaleY, scaleZ);
// 应用旋转
if (Math.Abs(deltaYaw) > 0.001)
{
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
}
// 计算平移(考虑旋转带来的位置偏移)
if (Math.Abs(deltaYaw) > 0.001)
{
double cos = Math.Cos(deltaYaw);
double sin = Math.Sin(deltaYaw);
double rotatedX = originalCenterPos.X * cos - originalCenterPos.Y * sin;
double rotatedY = originalCenterPos.X * sin + originalCenterPos.Y * cos;
components.Translation = new Vector3D(
targetPosition.X - rotatedX,
targetPosition.Y - rotatedY,
targetPosition.Z - originalCenterPos.Z
);
}
else
{
components.Translation = deltaPos;
}
// 应用组合变换
Transform3D transform = components.Combine();
doc.Models.OverridePermanentTransform(modelItems, transform, false);
}
/// <summary>
/// 物体状态快照,用于保存和恢复
/// </summary>
public class ObjectStateSnapshot
{
public Point3D Position { get; set; }
public Rotation3D Rotation { get; set; }
public bool HasCustomRotation { get; set; }
}
}
}