修改移动物体初始角度不对的问题
This commit is contained in:
parent
dab8dc34c3
commit
736e6e8448
@ -11,6 +11,7 @@
|
||||
5. [ ] (测试)路径规划文件能导入DELMIA
|
||||
6. [ ] (优化)优化路径规划分析和分析报告
|
||||
7. [ ] (功能)增加物流属性自定义
|
||||
8. [x] (BUG) 动画时物流车在起点时应该朝向路径方向,切换虚拟车辆和指定物体时,原有的要归位
|
||||
|
||||
### [2025/12/18]
|
||||
|
||||
|
||||
@ -144,6 +144,11 @@ namespace NavisworksTransport.Core.Animation
|
||||
private TimeLinerIntegrationManager _timeLinerManager;
|
||||
private string _currentTaskId;
|
||||
|
||||
/// <summary>
|
||||
/// 当前正在进行动画的对象
|
||||
/// </summary>
|
||||
public ModelItem AnimatedObject => _animatedObject;
|
||||
|
||||
// --- 新增事件 ---
|
||||
/// <summary>
|
||||
/// 当动画状态发生改变时触发
|
||||
@ -206,6 +211,89 @@ namespace NavisworksTransport.Core.Animation
|
||||
return _instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理当前所有的动画生成结果(帧列表、碰撞结果、状态)
|
||||
/// </summary>
|
||||
public void ClearAnimationResults()
|
||||
{
|
||||
_animationFrames = null;
|
||||
_allCollisionResults = null;
|
||||
SetState(AnimationState.Idle);
|
||||
LogManager.Info("[PathAnimationManager] 动画数据和状态已重置为 Idle");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅仅将物理模型同步到路径起点(不清理数据,不重置状态)
|
||||
/// </summary>
|
||||
public void SyncToPathStart(ModelItem item, List<Point3D> points)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (item == null || points == null || points.Count == 0) return;
|
||||
|
||||
// 更新引用,确保后续 MoveVehicleToPathStart 使用正确物体
|
||||
_animatedObject = item;
|
||||
_pathPoints = new List<Point3D>(points);
|
||||
|
||||
// 记录原始位置(用于归位)
|
||||
_originalTransform = item.Transform;
|
||||
_currentYaw = ModelItemTransformHelper.GetYawFromTransform(_originalTransform);
|
||||
_originalCenter = item.BoundingBox().Center;
|
||||
_currentPosition = new Point3D(_originalCenter.X, _originalCenter.Y, item.BoundingBox().Min.Z);
|
||||
|
||||
if (points.Count >= 2)
|
||||
{
|
||||
double yaw = Math.Atan2(points[1].Y - points[0].Y, points[1].X - points[0].X);
|
||||
UpdateObjectPosition(points[0], yaw);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateObjectPosition(points[0]);
|
||||
}
|
||||
|
||||
LogManager.Debug($"[Sync] 物体 {item.DisplayName} 已移动到起点");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[Sync] 同步到起点失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将动画对象彻底恢复到 CAD 原始位置(清除所有覆盖变换)
|
||||
/// 常用于模式切换或彻底清除动画干扰
|
||||
/// </summary>
|
||||
public void RestoreObjectToCADPosition()
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = NavisApplication.ActiveDocument;
|
||||
if (doc == null || _animatedObject == null) return;
|
||||
|
||||
var modelItems = new ModelItemCollection { _animatedObject };
|
||||
|
||||
// 1. 彻底清除 Navisworks 中的所有覆盖变换,强制恢复到设计文件定义的原始状态
|
||||
doc.Models.ResetPermanentTransform(modelItems);
|
||||
|
||||
// 2. 重置内部跟踪变量(同步到 CAD 原始状态)
|
||||
// 注意:ResetPermanentTransform 后物体的 Transform 属性会自动变回 CAD 原始值
|
||||
_currentYaw = ModelItemTransformHelper.GetYawFromTransform(_animatedObject.Transform);
|
||||
|
||||
var originalBoundingBox = _animatedObject.BoundingBox();
|
||||
_currentPosition = new Point3D(
|
||||
originalBoundingBox.Center.X,
|
||||
originalBoundingBox.Center.Y,
|
||||
originalBoundingBox.Min.Z
|
||||
);
|
||||
|
||||
LogManager.Info($"[归位] 物体 {_animatedObject.DisplayName} 已彻底恢复到 CAD 原始位置, yaw={_currentYaw:F3}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[归位] 恢复物体到 CAD 位置失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置动画参数
|
||||
/// </summary>
|
||||
@ -264,10 +352,21 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 保存原始变换以便重置
|
||||
_originalTransform = _animatedObject.Transform; // 使用真正的Transform,不是自造的
|
||||
|
||||
// 获取并初始化当前偏航角
|
||||
_currentYaw = ModelItemTransformHelper.GetYawFromTransform(_originalTransform);
|
||||
LogManager.Info($"[动画设置] 初始偏航角提取: {_currentYaw:F3}rad ({(_currentYaw * 180 / Math.PI):F1}度)");
|
||||
|
||||
// 保存车辆的原始中心位置
|
||||
var originalBoundingBox = animatedObject.BoundingBox();
|
||||
_originalCenter = originalBoundingBox.Center;
|
||||
|
||||
|
||||
// 初始化当前位置为物体底面中心,用于后续增量变换计算
|
||||
_currentPosition = new Point3D(
|
||||
_originalCenter.X,
|
||||
_originalCenter.Y,
|
||||
originalBoundingBox.Min.Z
|
||||
);
|
||||
|
||||
// 调试:查看原始Transform的组成
|
||||
var origComponents = _originalTransform.Factor();
|
||||
LogManager.Info($"[原始Transform] Translation=({origComponents.Translation.X:F2},{origComponents.Translation.Y:F2},{origComponents.Translation.Z:F2})");
|
||||
@ -315,45 +414,19 @@ namespace NavisworksTransport.Core.Animation
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_pathPoints.Count == 0) return;
|
||||
if (_pathPoints.Count == 0 || _animationFrames == null || _animationFrames.Count == 0) return;
|
||||
|
||||
var doc = NavisApplication.ActiveDocument;
|
||||
var modelItems = new ModelItemCollection { _animatedObject };
|
||||
var firstFrame = _animationFrames[0];
|
||||
|
||||
// 获取物体的包围盒
|
||||
var boundingBox = _animatedObject.BoundingBox();
|
||||
// 使用 UpdateObjectPosition 统一处理移动和旋转
|
||||
// 这将物体从当前位置(底面中心)移动到第一帧的位置,并旋转到第一帧的朝向
|
||||
UpdateObjectPosition(firstFrame.Position, firstFrame.YawRadians);
|
||||
|
||||
// 计算物体底面中心点(而不是整体中心点)
|
||||
var objectBottomCenter = new Point3D(
|
||||
_originalCenter.X,
|
||||
_originalCenter.Y,
|
||||
boundingBox.Min.Z // 使用包围盒的最小Z值作为底面
|
||||
);
|
||||
|
||||
// 计算从物体底面中心到路径起点的偏移
|
||||
var startOffset = new Vector3D(
|
||||
_pathPoints[0].X - objectBottomCenter.X,
|
||||
_pathPoints[0].Y - objectBottomCenter.Y,
|
||||
_pathPoints[0].Z - objectBottomCenter.Z
|
||||
);
|
||||
|
||||
// 创建变换并应用
|
||||
var startTransform = Transform3D.CreateTranslation(startOffset);
|
||||
doc.Models.OverridePermanentTransform(modelItems, startTransform, false);
|
||||
|
||||
// 更新当前位置为路径起点
|
||||
_currentPosition = _pathPoints[0];
|
||||
|
||||
LogManager.Info($"物体已移动到路径起点,底面对齐地面");
|
||||
LogManager.Info($"物体包围盒: Min=({boundingBox.Min.X:F2},{boundingBox.Min.Y:F2},{boundingBox.Min.Z:F2}), Max=({boundingBox.Max.X:F2},{boundingBox.Max.Y:F2},{boundingBox.Max.Z:F2})");
|
||||
LogManager.Info($"物体原始中心: ({_originalCenter.X:F2},{_originalCenter.Y:F2},{_originalCenter.Z:F2})");
|
||||
LogManager.Info($"物体底面中心: ({objectBottomCenter.X:F2},{objectBottomCenter.Y:F2},{objectBottomCenter.Z:F2})");
|
||||
LogManager.Info($"路径起点坐标: ({_pathPoints[0].X:F2},{_pathPoints[0].Y:F2},{_pathPoints[0].Z:F2})");
|
||||
LogManager.Info($"应用的偏移量: ({startOffset.X:F2},{startOffset.Y:F2},{startOffset.Z:F2})");
|
||||
LogManager.Info($"物体已初始化到路径起点并对齐朝向: pos=({firstFrame.Position.X:F2},{firstFrame.Position.Y:F2},{firstFrame.Position.Z:F2}), yaw={firstFrame.YawRadians:F3}rad");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"移动部件到路径起点失败: {ex.Message}");
|
||||
LogManager.Error($"初始化物体到路径起点失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -447,7 +520,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
boundingBoxSize.Z * boundingBoxSize.Z
|
||||
);
|
||||
//空间查询半径,不能设置太小,否则会漏掉周围的对象
|
||||
searchRadiusInModelUnits = objectDiagonal + _detectionGap;
|
||||
searchRadiusInModelUnits = objectDiagonal + _detectionGap;
|
||||
|
||||
LogManager.Info($"空间查询半径: {searchRadiusInModelUnits:F2} 模型单位");
|
||||
}
|
||||
@ -623,7 +696,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 1. 定义物体包围盒的4个底面角点(相对于中心)
|
||||
double halfX = size.X / 2;
|
||||
double halfY = size.Y / 2;
|
||||
|
||||
|
||||
var corners = new[]
|
||||
{
|
||||
new { x = -halfX, y = -halfY },
|
||||
@ -635,7 +708,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 2. 旋转这些角点
|
||||
double cos = Math.Cos(yawRadians);
|
||||
double sin = Math.Sin(yawRadians);
|
||||
|
||||
|
||||
double minX = double.MaxValue;
|
||||
double maxX = double.MinValue;
|
||||
double minY = double.MaxValue;
|
||||
@ -646,7 +719,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 旋转公式:x' = x*cos - y*sin, y' = x*sin + y*cos
|
||||
double rotatedX = corner.x * cos - corner.y * sin;
|
||||
double rotatedY = corner.x * sin + corner.y * cos;
|
||||
|
||||
|
||||
minX = Math.Min(minX, rotatedX);
|
||||
maxX = Math.Max(maxX, rotatedX);
|
||||
minY = Math.Min(minY, rotatedY);
|
||||
@ -771,16 +844,18 @@ namespace NavisworksTransport.Core.Animation
|
||||
_animationFrameCount = 0; // 重置帧计数
|
||||
_currentFrameIndex = 0; // 重置当前帧索引,确保从第一帧开始
|
||||
_pausedProgress = 0.0; // 重置暂停进度
|
||||
|
||||
// 初始化yaw为第一帧的yaw,避免第一帧就产生旋转增量
|
||||
|
||||
// 初始化动画状态时不再强行覆盖 _currentYaw 为第一帧的 yaw
|
||||
// 这样在 UpdateObjectPosition(firstFrame.Position, firstFrame.YawRadians) 时
|
||||
// deltaYaw = firstFrame.YawRadians - 物体初始Yaw,从而产生旋转增量让物体转向
|
||||
|
||||
if (_animationFrames != null && _animationFrames.Count > 0)
|
||||
{
|
||||
var firstFrame = _animationFrames[0];
|
||||
_currentYaw = firstFrame.YawRadians; // 关键:设置为第一帧的yaw,使deltaYaw=0
|
||||
|
||||
// 立即设置到第一帧的位置和朝向(此时deltaYaw=0,只有平移)
|
||||
|
||||
// 立即设置到第一帧的位置和朝向(由于MoveVehicleToPathStart已经设置过了,这里主要是确保状态同步)
|
||||
UpdateObjectPosition(firstFrame.Position, firstFrame.YawRadians);
|
||||
LogManager.Debug($"[动画开始] 设置初始位置和朝向: pos=({firstFrame.Position.X:F2},{firstFrame.Position.Y:F2}), yaw={firstFrame.YawRadians:F3}rad");
|
||||
LogManager.Debug($"[动画开始] 确认初始位置和朝向: pos=({firstFrame.Position.X:F2},{firstFrame.Position.Y:F2}), yaw={firstFrame.YawRadians:F3}rad");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -924,11 +999,11 @@ namespace NavisworksTransport.Core.Animation
|
||||
_pausedProgress = 0.0; // 重置暂停进度
|
||||
_currentFrameIndex = 0; // 重置帧索引
|
||||
|
||||
// 将物体移回起点位置
|
||||
// 将物体移回起点位置并恢复初始朝向
|
||||
if (_pathPoints != null && _pathPoints.Count > 0 && _animatedObject != null)
|
||||
{
|
||||
UpdateObjectPosition(_pathPoints[0]);
|
||||
LogManager.Info($"物体已移回起点位置: ({_pathPoints[0].X:F2},{_pathPoints[0].Y:F2},{_pathPoints[0].Z:F2})");
|
||||
MoveVehicleToPathStart();
|
||||
LogManager.Info($"物体已移回起点位置并恢复初始朝向");
|
||||
}
|
||||
|
||||
LogManager.Info("动画已停止");
|
||||
@ -1018,11 +1093,12 @@ namespace NavisworksTransport.Core.Animation
|
||||
LogManager.Info("动画完成,路径上无碰撞对象");
|
||||
}
|
||||
|
||||
// 将物体移回起点位置
|
||||
// 将物体移回起点位置并恢复初始朝向
|
||||
if (_pathPoints != null && _pathPoints.Count > 0 && _animatedObject != null)
|
||||
{
|
||||
UpdateObjectPosition(_pathPoints[0]);
|
||||
LogManager.Info($"动画完成,物体已移回起点位置: ({_pathPoints[0].X:F2},{_pathPoints[0].Y:F2},{_pathPoints[0].Z:F2})");
|
||||
RestoreObjectToCADPosition();
|
||||
MoveVehicleToPathStart();
|
||||
LogManager.Info($"动画播放自然结束,物体已移回起点位置并恢复初始朝向");
|
||||
}
|
||||
|
||||
// 直接设置为完成状态,避免中间状态切换
|
||||
@ -1156,21 +1232,24 @@ namespace NavisworksTransport.Core.Animation
|
||||
var activeDoc = NavisApplication.ActiveDocument;
|
||||
if (activeDoc != null && activeDoc.Models != null)
|
||||
{
|
||||
// 先安全获取对象名称,避免访问已释放对象的属性
|
||||
string objectName = GetSafeObjectName(_animatedObject);
|
||||
// 第一步:仅仅彻底归位到 CAD 原始位置(不涉及路径起点),这是“清除”按钮的逻辑
|
||||
RestoreObjectToCADPosition();
|
||||
|
||||
var modelItems = new ModelItemCollection { _animatedObject };
|
||||
activeDoc.Models.OverridePermanentTransform(modelItems, _originalTransform, false);
|
||||
LogManager.Info($"部件 {objectName} 已重置到原始位置");
|
||||
// 第二步:如果已经生成了动画路径,则重新对齐到起点(带旋转)
|
||||
if (_animationFrames != null && _animationFrames.Count > 0)
|
||||
{
|
||||
MoveVehicleToPathStart();
|
||||
LogManager.Info("已重新对齐到路径起点");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info("Navisworks文档已不可用,跳过对象重置操作");
|
||||
LogManager.Info("Navisworks文档已不可用,跳回空闲状态");
|
||||
}
|
||||
}
|
||||
catch (Exception resetEx)
|
||||
{
|
||||
LogManager.Warning($"重置对象位置时出现警告(可能因为Navisworks对象已释放): {resetEx.Message}");
|
||||
LogManager.Warning($"重置对象位置时出现警告: {resetEx.Message}");
|
||||
// 不再抛出异常,因为在资源清理阶段这是正常的
|
||||
}
|
||||
}
|
||||
@ -1382,16 +1461,16 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 有旋转:需要实现"绕物体当前位置自转"
|
||||
// 由于Transform3DComponents.Rotation总是绕世界原点旋转
|
||||
// 我们需要手动计算旋转导致的位置偏移,并补偿
|
||||
|
||||
|
||||
double deltaYaw = newYaw - _currentYaw;
|
||||
|
||||
|
||||
// 计算绕当前位置旋转的等效变换:
|
||||
// 1. 如果绕原点旋转deltaYaw,当前位置_currentPosition会移动到哪里?
|
||||
double cos = Math.Cos(deltaYaw);
|
||||
double sin = Math.Sin(deltaYaw);
|
||||
double rotatedX = _currentPosition.X * cos - _currentPosition.Y * sin;
|
||||
double rotatedY = _currentPosition.X * sin + _currentPosition.Y * cos;
|
||||
|
||||
|
||||
// 2. 但我们希望物体绕自己旋转,位置移动到newPosition
|
||||
// 所以需要的平移 = newPosition - (旋转后的位置)
|
||||
var compensatedTranslation = new Vector3D(
|
||||
@ -1399,15 +1478,15 @@ namespace NavisworksTransport.Core.Animation
|
||||
newPosition.Y - rotatedY,
|
||||
newPosition.Z - _currentPosition.Z // Z保持deltaPos
|
||||
);
|
||||
|
||||
|
||||
// 3. 组合:先旋转(绕原点),再平移(补偿+目标位置)
|
||||
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;
|
||||
|
||||
|
||||
incrementalTransform = components.Combine();
|
||||
|
||||
|
||||
_currentYaw = newYaw;
|
||||
}
|
||||
else
|
||||
|
||||
@ -350,28 +350,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
get => _selectedAnimatedObject;
|
||||
set
|
||||
{
|
||||
SetProperty(ref _selectedAnimatedObject, value);
|
||||
UpdateAnimatedObjectInfo();
|
||||
UpdateCanGenerateAnimation();
|
||||
|
||||
// 移动物体改变时清除已生成的动画(如果有的话)
|
||||
if (_pathAnimationManager != null &&
|
||||
(_pathAnimationManager.CurrentState == NavisworksTransport.Core.Animation.AnimationState.Ready ||
|
||||
_pathAnimationManager.CurrentState == NavisworksTransport.Core.Animation.AnimationState.Finished))
|
||||
if (SetProperty(ref _selectedAnimatedObject, value))
|
||||
{
|
||||
try
|
||||
{
|
||||
_pathAnimationManager.CancelAnimation(); // 这会将状态设置为Stopped,需要重新生成动画
|
||||
LogManager.Info("移动物体更改,已清除之前生成的动画");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"清除之前动画时出现警告: {ex.Message}");
|
||||
}
|
||||
}
|
||||
UpdateAnimatedObjectInfo();
|
||||
UpdateCanGenerateAnimation();
|
||||
|
||||
// ✨ 新功能:动画对象选择时预计算排除列表(线程安全版本)
|
||||
_ = PrecomputeCollisionExclusionsAsync(value);
|
||||
// 预计算排除列表(异步)
|
||||
_ = PrecomputeCollisionExclusionsAsync(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -418,6 +404,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
_useVirtualVehicle = false;
|
||||
OnPropertyChanged(nameof(UseVirtualVehicle));
|
||||
|
||||
// ✨ 模式切换清理:切换到手动选择模式时,移除存在的虚拟车辆并清理数据
|
||||
try
|
||||
{
|
||||
VirtualVehicleManager.Instance.RemoveVirtualVehicle();
|
||||
_pathAnimationManager?.ClearAnimationResults(); // 清理虚拟车辆留下的动画数据
|
||||
LogManager.Info("已切换到手动选择模式,自动隐藏虚拟车辆并清理动画数据");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"隐藏虚拟车辆失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
UpdateCanGenerateAnimation();
|
||||
}
|
||||
@ -438,6 +436,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
_useSelectedObject = false;
|
||||
OnPropertyChanged(nameof(UseSelectedObject));
|
||||
|
||||
// ✨ 模式切换清理:切换到虚拟车辆模式时,重置之前手动选择物体的动画状态(恢复到CAD位置)
|
||||
try
|
||||
{
|
||||
// 只有在当前动画对象不是虚拟车辆时才执行重置
|
||||
if (_pathAnimationManager != null &&
|
||||
_pathAnimationManager.AnimatedObject != null &&
|
||||
!VirtualVehicleManager.Instance.IsVirtualVehicleActive)
|
||||
{
|
||||
_pathAnimationManager.RestoreObjectToCADPosition();
|
||||
_pathAnimationManager.ClearAnimationResults(); // 清理手动选择物体留下的动画数据
|
||||
LogManager.Info("已切换到虚拟车辆模式,将之前的手动选择物体归位并清理动画数据");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"重置手动选择物体状态失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
UpdateCanGenerateAnimation();
|
||||
}
|
||||
@ -1080,6 +1096,47 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行选择移动物体命令
|
||||
/// </summary>
|
||||
private void ExecuteSelectAnimatedObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||
if (doc == null || doc.CurrentSelection.IsEmpty)
|
||||
{
|
||||
LogManager.Warning("请先在场景中选择一个物体");
|
||||
return;
|
||||
}
|
||||
|
||||
var newObject = doc.CurrentSelection.SelectedItems.First;
|
||||
if (newObject == null) return;
|
||||
|
||||
// 1. 如果有旧物体,先归位并清理旧动画
|
||||
if (_selectedAnimatedObject != null && !ReferenceEquals(_selectedAnimatedObject, newObject))
|
||||
{
|
||||
_pathAnimationManager?.RestoreObjectToCADPosition();
|
||||
}
|
||||
_pathAnimationManager?.ClearAnimationResults();
|
||||
|
||||
// 2. 设置新物体
|
||||
SelectedAnimatedObject = newObject;
|
||||
LogManager.Info($"已选择移动物体: {SelectedAnimatedObject.DisplayName}");
|
||||
|
||||
// 3. 立即移动到起点(如果路径存在)
|
||||
if (CurrentPathRoute != null && CurrentPathRoute.Points != null && _pathAnimationManager != null)
|
||||
{
|
||||
var points = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList();
|
||||
_pathAnimationManager.SyncToPathStart(newObject, points);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"选择物体失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新媒体控制相关属性
|
||||
/// </summary>
|
||||
@ -1330,60 +1387,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行选择移动物体命令
|
||||
/// </summary>
|
||||
private void ExecuteSelectAnimatedObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info("开始选择移动物体");
|
||||
|
||||
// 获取当前选中的模型项
|
||||
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||
var selectedItems = doc.CurrentSelection.SelectedItems;
|
||||
|
||||
if (selectedItems.Count == 0)
|
||||
{
|
||||
UpdateMainStatus("请先在Navisworks中选择一个物体");
|
||||
LogManager.Warning("用户未选择任何物体");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedItems.Count > 1)
|
||||
{
|
||||
UpdateMainStatus("请只选择一个物体作为移动对象");
|
||||
LogManager.Warning($"用户选择了{selectedItems.Count}个物体,需要只选择一个");
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedItem = selectedItems.First;
|
||||
|
||||
// 检查选中项是否包含几何体(直接包含或子项包含)
|
||||
bool hasAnyGeometry = HasGeometryRecursive(selectedItem);
|
||||
|
||||
if (!hasAnyGeometry)
|
||||
{
|
||||
UpdateMainStatus("选中的项目及其子项都不包含几何体,请选择其他物体");
|
||||
LogManager.Warning("选中的项目及其子项都不包含几何体");
|
||||
return;
|
||||
}
|
||||
|
||||
LogManager.Info($"选中物体信息: DisplayName={selectedItem.DisplayName}, HasGeometry={selectedItem.HasGeometry}, ChildCount={selectedItem.Children.Count()}");
|
||||
|
||||
// 设置选中的移动物体
|
||||
SelectedAnimatedObject = selectedItem;
|
||||
UpdateMainStatus("移动物体选择成功");
|
||||
|
||||
LogManager.Info($"移动物体选择成功: {SelectedAnimatedObject.DisplayName}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateMainStatus("选择移动物体失败");
|
||||
LogManager.Error($"选择移动物体时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行清除移动物体命令
|
||||
/// 清除移动物体选择、停止当前动画并更新按钮状态
|
||||
@ -1392,95 +1395,29 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info("开始清除移动物体选择、当前动画并恢复原始位置");
|
||||
|
||||
// 首先停止当前动画(如果正在播放)
|
||||
if (_pathAnimationManager != null && _pathAnimationManager.IsAnimating)
|
||||
{
|
||||
try
|
||||
{
|
||||
_pathAnimationManager.CancelAnimation();
|
||||
LogManager.Info("已停止当前播放的动画");
|
||||
}
|
||||
catch (Exception stopEx)
|
||||
{
|
||||
LogManager.Warning($"停止当前动画时出现警告: {stopEx.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 清除PathAnimationManager中的动画数据,将状态重置为Idle
|
||||
if (_pathAnimationManager != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 重置动画对象到原始位置并清除动画数据
|
||||
_pathAnimationManager.ResetAnimation();
|
||||
LogManager.Info("已清除PathAnimationManager中的动画数据");
|
||||
}
|
||||
catch (Exception resetEx)
|
||||
{
|
||||
LogManager.Warning($"重置PathAnimationManager时出现警告: {resetEx.Message}");
|
||||
}
|
||||
// 1. 归位并清理
|
||||
_pathAnimationManager.RestoreObjectToCADPosition();
|
||||
_pathAnimationManager.ClearAnimationResults();
|
||||
LogManager.Info("已清除PathAnimationManager中的动画数据并归位物体");
|
||||
}
|
||||
|
||||
// 如果有选中的物体,则恢复到原始位置
|
||||
if (SelectedAnimatedObject != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogManager.Info($"开始恢复物体 '{SelectedAnimatedObject.DisplayName}' 到原始位置");
|
||||
|
||||
// 使用ResetPermanentTransform清除所有增量变换,恢复到设计文件中的原始位置
|
||||
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||
var modelItems = new ModelItemCollection { SelectedAnimatedObject };
|
||||
doc.Models.ResetPermanentTransform(modelItems);
|
||||
|
||||
LogManager.Info($"物体 '{SelectedAnimatedObject.DisplayName}' 已成功恢复到原始位置");
|
||||
UpdateMainStatus("已清除移动物体选择并恢复到原始位置");
|
||||
}
|
||||
catch (Exception restoreEx)
|
||||
{
|
||||
LogManager.Error($"恢复物体到原始位置时发生错误: {restoreEx.Message}");
|
||||
UpdateMainStatus($"已清除物体选择,但恢复位置失败: {restoreEx.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Info("没有选中的物体需要清除");
|
||||
UpdateMainStatus("已清除移动物体选择");
|
||||
}
|
||||
|
||||
// 清理选择状态
|
||||
// 2. 重置属性
|
||||
SelectedAnimatedObject = null;
|
||||
|
||||
// 清理碰撞检测结果
|
||||
HasCollisionResults = false;
|
||||
_latestCollisionResults.Clear();
|
||||
ModelHighlightHelper.ClearCategory(CollisionResultsHighlightCategory);
|
||||
UpdateMainStatus("碰撞检测重置");
|
||||
|
||||
// 清除高亮构件
|
||||
try
|
||||
{
|
||||
_clashIntegration?.ClearHighlights();
|
||||
LogManager.Info("已清除高亮构件");
|
||||
}
|
||||
catch (Exception highlightEx)
|
||||
{
|
||||
LogManager.Warning($"清除高亮构件时出现警告: {highlightEx.Message}");
|
||||
}
|
||||
|
||||
// 更新按钮状态 - 清除动画后应该重新评估按钮状态
|
||||
UpdateAnimationButtonStates();
|
||||
|
||||
// 更新生成动画的能力状态
|
||||
UpdateAnimatedObjectInfo();
|
||||
UpdateCanGenerateAnimation();
|
||||
|
||||
LogManager.Info("移动物体选择和当前动画已完全清除,按钮状态已更新");
|
||||
// 3. 清理高亮
|
||||
_clashIntegration?.ClearHighlights();
|
||||
ModelHighlightHelper.ClearCategory(CollisionResultsHighlightCategory);
|
||||
|
||||
LogManager.Info("移动物体已完全清除并归位");
|
||||
UpdateMainStatus("已清除物体选择并恢复位置");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"清除移动物体选择时发生错误: {ex.Message}");
|
||||
LogManager.Error($"清除失败: {ex.Message}");
|
||||
UpdateMainStatus($"清除失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using Autodesk.Navisworks.Api;
|
||||
|
||||
namespace NavisworksTransport.Utils
|
||||
@ -41,6 +42,50 @@ namespace NavisworksTransport.Utils
|
||||
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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user