NavisworksTransport/src/Utils/CollisionSceneHelper.cs

223 lines
10 KiB
C#

using System;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Core;
using NavisworksTransport.Core.Animation;
namespace NavisworksTransport.Utils
{
/// <summary>
/// 碰撞场景辅助类
/// 提供碰撞场景还原和截图的通用功能
/// </summary>
public static class CollisionSceneHelper
{
/// <summary>
/// 将动画物体移动到碰撞位置并聚焦到碰撞场景
/// </summary>
/// <param name="collision">碰撞结果</param>
/// <param name="animatedObject">动画物体(运动物体)</param>
public static void MoveToCollisionAndFocus(CollisionResult collision, ModelItem animatedObject)
{
if (collision == null) return;
MoveToCollisionAndFocus(collision.Item2 ?? collision.Item1, animatedObject,
collision.Item1Position, collision.Item1YawRadians, collision.Item1Rotation,
collision.Item1HasCustomRotation, collision.HasPositionInfo);
}
/// <summary>
/// 将动画物体移动到碰撞位置并聚焦到碰撞场景(通用版本)
/// </summary>
/// <param name="hitObject">被撞对象</param>
/// <param name="animatedObject">动画物体(运动物体)</param>
/// <param name="item1Position">碰撞位置</param>
/// <param name="item1YawRadians">碰撞朝向</param>
/// <param name="item1Rotation">碰撞完整姿态</param>
/// <param name="item1HasCustomRotation">是否有完整姿态</param>
/// <param name="hasPositionInfo">是否有位置信息</param>
public static void MoveToCollisionAndFocus(ModelItem hitObject, ModelItem animatedObject,
Point3D item1Position, double item1YawRadians, Rotation3D item1Rotation,
bool item1HasCustomRotation, bool hasPositionInfo)
{
try
{
if (hitObject != null)
{
// 清除之前的高亮
ModelHighlightHelper.ClearAllHighlights();
// 高亮被撞对象(使用碰撞检测结果专用红色)
ModelHighlightHelper.HighlightItems(ModelHighlightHelper.ClashDetectiveResultsCategory, new[] { hitObject });
// 聚焦到被撞对象
ViewpointHelper.FocusOnModelItem(hitObject, viewAngleDegrees: 60.0, targetViewRatio: 0.25);
LogManager.Info(string.Format("聚焦到被撞对象: {0}", hitObject.DisplayName));
}
// 移动动画物体到碰撞位置
if (animatedObject != null && hasPositionInfo && item1Position != null)
{
var pam = PathAnimationManager.GetInstance();
bool useAnimationPipeline = pam != null &&
pam.ControlsAnimatedObject(animatedObject) &&
item1HasCustomRotation &&
item1Rotation != null;
// 检查是否是虚拟物体
bool isVirtual = VirtualObjectManager.Instance.IsVirtualObjectActive &&
VirtualObjectManager.Instance.CurrentVirtualObject == animatedObject;
if (useAnimationPipeline)
{
pam.MoveAnimatedObjectToPose(
animatedObject,
item1Position,
item1YawRadians,
item1Rotation,
true);
LogManager.Info(string.Format(
"运动物体已通过动画链路移动到碰撞位置: 位置=({0:F2}, {1:F2}, {2:F2}), customRotation={3}",
item1Position.X, item1Position.Y, item1Position.Z,
true));
}
else if (item1HasCustomRotation && item1Rotation != null)
{
throw new InvalidOperationException(
$"三维碰撞点恢复必须复用动画主链路,当前对象未受 PathAnimationManager 控制: {animatedObject.DisplayName}");
}
else
{
var bounds = animatedObject.BoundingBox();
double halfHeight = (bounds.Max.Z - bounds.Min.Z) / 2.0;
var targetGroundPosition = new Point3D(
item1Position.X,
item1Position.Y,
item1Position.Z - halfHeight
);
if (isVirtual)
{
ModelItemTransformHelper.MoveItemToPositionAndYawWithCurrentScale(
animatedObject, targetGroundPosition, item1YawRadians);
}
else
{
ModelItemTransformHelper.MoveItemToPositionAndYaw(animatedObject, targetGroundPosition, item1YawRadians);
}
LogManager.Info(string.Format("运动物体已移动到碰撞位置: ({0:F2}, {1:F2}, {2:F2}), 朝向: {3:F2}°",
targetGroundPosition.X, targetGroundPosition.Y, targetGroundPosition.Z,
item1YawRadians * 180 / Math.PI));
}
}
}
catch (Exception ex)
{
LogManager.Error(string.Format("移动并聚焦到碰撞位置失败: {0}", ex.Message), ex);
}
}
/// <summary>
/// 保存动画物体当前状态
/// </summary>
/// <param name="animatedObject">动画物体</param>
/// <returns>状态快照</returns>
public static ModelItemTransformHelper.ObjectStateSnapshot SaveAnimatedObjectState(ModelItem animatedObject)
{
if (animatedObject == null) return null;
try
{
// 从PathAnimationManager获取当前实际朝向
var pam = PathAnimationManager.GetInstance();
var currentYaw = pam.CurrentYaw;
var currentRotation = pam.CurrentRotation;
var hasCustomRotation = pam.HasCurrentRotation;
var currentState = pam.GetObjectCurrentPosition(animatedObject);
pam.SaveObjectState(animatedObject);
var state = ModelItemTransformHelper.SaveObjectState(
animatedObject,
currentYaw,
currentState.Position,
currentRotation,
hasCustomRotation);
LogManager.Info(string.Format("已保存动画物体状态: {0}, 位置=({1:F2},{2:F2},{3:F2}), 朝向={4:F2}°, customRotation={5}",
animatedObject.DisplayName, state.Position.X, state.Position.Y, state.Position.Z,
currentYaw * 180 / Math.PI, state.HasCustomRotation));
return state;
}
catch (Exception ex)
{
LogManager.Error(string.Format("保存动画物体状态失败: {0}", ex.Message), ex);
return null;
}
}
/// <summary>
/// 恢复动画物体到保存的状态
/// </summary>
/// <param name="animatedObject">动画物体</param>
/// <param name="state">状态快照</param>
public static void RestoreAnimatedObjectState(ModelItem animatedObject, ModelItemTransformHelper.ObjectStateSnapshot state)
{
if (animatedObject == null || state == null) return;
try
{
var pam = PathAnimationManager.GetInstance();
if (state.HasCustomRotation)
{
if (pam != null && ReferenceEquals(pam.AnimatedObject, animatedObject))
{
pam.RestoreAnimatedObjectState(animatedObject);
LogManager.Info(string.Format("动画物体已通过PathAnimationManager恢复三维姿态: {0}", animatedObject.DisplayName));
return;
}
bool isVirtualWithCustomRotation = VirtualObjectManager.Instance.IsVirtualObjectActive &&
VirtualObjectManager.Instance.CurrentVirtualObject == animatedObject;
if (isVirtualWithCustomRotation)
{
ModelItemTransformHelper.RestoreObjectStateWithScale(animatedObject, state);
}
else
{
ModelItemTransformHelper.RestoreObjectState(animatedObject, state);
}
LogManager.Info(string.Format("动画物体已通过状态快照恢复三维姿态: {0}", animatedObject.DisplayName));
return;
}
// 检查是否是虚拟物体
bool isVirtual = VirtualObjectManager.Instance.IsVirtualObjectActive &&
VirtualObjectManager.Instance.CurrentVirtualObject == animatedObject;
if (isVirtual)
{
// 虚拟物体:使用带当前缩放的移动方法
ModelItemTransformHelper.MoveItemToPositionAndYawWithCurrentScale(
animatedObject, state.Position, state.YawRadians);
LogManager.Info(string.Format("虚拟物体已恢复到原始状态: {0}, 位置=({1:F2},{2:F2},{3:F2}), 朝向={4:F2}°",
animatedObject.DisplayName, state.Position.X, state.Position.Y, state.Position.Z,
state.YawRadians * 180 / Math.PI));
}
else
{
// 普通物体:使用标准恢复
ModelItemTransformHelper.RestoreObjectState(animatedObject, state);
LogManager.Info(string.Format("动画物体已恢复到原始状态: {0}", animatedObject.DisplayName));
}
}
catch (Exception ex)
{
LogManager.Error(string.Format("恢复动画物体状态失败: {0}", ex.Message), ex);
}
}
}
}