256 lines
9.9 KiB
C#
256 lines
9.9 KiB
C#
using System;
|
||
using Autodesk.Navisworks.Api;
|
||
|
||
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();
|
||
var rotation = components.Rotation;
|
||
|
||
// 使用ToAxisAndAngle()提取轴和角度
|
||
var rotationResult = rotation.ToAxisAndAngle();
|
||
double angle = rotationResult.Angle;
|
||
double ux = rotationResult.Axis.X;
|
||
double uy = rotationResult.Axis.Y;
|
||
double uz = rotationResult.Axis.Z;
|
||
|
||
// 旋转公式(罗德里格旋转公式简化版,提取局部X轴(1,0,0)旋转后的方向)
|
||
// 旋转后的向量 v' = v*cosθ + (u×v)*sinθ + u*(u·v)*(1-cosθ)
|
||
// 当 v = (1,0,0) 时:
|
||
// v'.x = cosθ + ux*ux*(1-cosθ)
|
||
// v'.y = uz*sinθ + ux*uy*(1-cosθ)
|
||
|
||
double cos = Math.Cos(angle);
|
||
double sin = Math.Sin(angle);
|
||
|
||
// 计算旋转后的X轴在世界坐标系XY平面上的分量
|
||
double vx = cos + ux * ux * (1 - cos);
|
||
double vy = uz * sin + ux * uy * (1 - cos);
|
||
|
||
// 在XY平面上通过Atan2计算偏航角
|
||
return Math.Atan2(vy, vx);
|
||
}
|
||
catch (Exception)
|
||
{
|
||
return 0.0;
|
||
}
|
||
}
|
||
|
||
/// <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 originalGroundPos = new Point3D(
|
||
originalBounds.Center.X,
|
||
originalBounds.Center.Y,
|
||
originalBounds.Min.Z
|
||
);
|
||
var originalYaw = GetYawFromTransform(item.Transform);
|
||
|
||
// 计算从CAD原始位置到目标位置的增量
|
||
var deltaPos = new Vector3D(
|
||
targetPosition.X - originalGroundPos.X,
|
||
targetPosition.Y - originalGroundPos.Y,
|
||
targetPosition.Z - originalGroundPos.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 = originalGroundPos.X * cos - originalGroundPos.Y * sin;
|
||
double rotatedY = originalGroundPos.X * sin + originalGroundPos.Y * cos;
|
||
|
||
var compensatedTranslation = new Vector3D(
|
||
targetPosition.X - rotatedX,
|
||
targetPosition.Y - rotatedY,
|
||
deltaPos.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>
|
||
/// 物体状态快照,用于保存和恢复
|
||
/// </summary>
|
||
public class ObjectStateSnapshot
|
||
{
|
||
public Point3D Position { get; set; }
|
||
public double YawRadians { get; set; }
|
||
public Transform3D Transform { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存物体当前状态
|
||
/// </summary>
|
||
public static ObjectStateSnapshot SaveObjectState(ModelItem item)
|
||
{
|
||
if (item == null) return null;
|
||
|
||
var bounds = item.BoundingBox();
|
||
return new ObjectStateSnapshot
|
||
{
|
||
Position = new Point3D(bounds.Center.X, bounds.Center.Y, bounds.Min.Z),
|
||
YawRadians = GetYawFromTransform(item.Transform),
|
||
Transform = item.Transform
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从状态快照恢复物体位置
|
||
/// 先回到CAD原始位置,再移动到保存的位置
|
||
/// </summary>
|
||
public static void RestoreObjectState(ModelItem item, ObjectStateSnapshot state)
|
||
{
|
||
if (item == null || state == null) return;
|
||
|
||
var doc = Application.ActiveDocument;
|
||
var modelItems = new ModelItemCollection { item };
|
||
|
||
// 1. 先回到CAD原始位置
|
||
doc.Models.ResetPermanentTransform(modelItems);
|
||
|
||
// 2. 从CAD原始位置移动到保存的位置
|
||
// 获取CAD原始状态
|
||
var originalBounds = item.BoundingBox();
|
||
var originalGroundPos = new Point3D(
|
||
originalBounds.Center.X,
|
||
originalBounds.Center.Y,
|
||
originalBounds.Min.Z
|
||
);
|
||
var originalYaw = GetYawFromTransform(item.Transform);
|
||
|
||
// 计算到保存位置的增量
|
||
var deltaPos = new Vector3D(
|
||
state.Position.X - originalGroundPos.X,
|
||
state.Position.Y - originalGroundPos.Y,
|
||
state.Position.Z - originalGroundPos.Z
|
||
);
|
||
double deltaYaw = state.YawRadians - originalYaw;
|
||
|
||
// 应用增量变换
|
||
Transform3D transform;
|
||
if (Math.Abs(deltaYaw) > 0.001)
|
||
{
|
||
double cos = Math.Cos(deltaYaw);
|
||
double sin = Math.Sin(deltaYaw);
|
||
double rotatedX = originalGroundPos.X * cos - originalGroundPos.Y * sin;
|
||
double rotatedY = originalGroundPos.X * sin + originalGroundPos.Y * cos;
|
||
|
||
var compensatedTranslation = new Vector3D(
|
||
state.Position.X - rotatedX,
|
||
state.Position.Y - rotatedY,
|
||
deltaPos.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);
|
||
}
|
||
}
|
||
}
|