From 98c55045ade14c488f47f48d33ead6e9edb82ef6 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Thu, 12 Feb 2026 22:12:58 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=89=A9=E4=BD=93=E6=88=96?= =?UTF-8?q?=E8=BD=A6=E8=BE=86=E6=97=B6=E8=AE=A9=E5=AE=83=E4=BB=AC=E5=88=B0?= =?UTF-8?q?=E8=B5=B7=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModels/AnimationControlViewModel.cs | 113 ++++++++++++++++-- 1 file changed, 102 insertions(+), 11 deletions(-) diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index 31f46bf..a0e3034 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -541,6 +541,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels get => _currentPathRoute; set { + var oldRoute = _currentPathRoute; if (SetProperty(ref _currentPathRoute, value)) { // 路径改变时,步长、速度和路径长度需要重新计算 @@ -551,6 +552,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 路径改变时,刷新ClashDetective结果列表 RefreshClashDetectiveResultsList(); + + // 🔥 路径改变时,如果已选择物体或虚拟车辆,立即移动到新路径起点 + // 注意:只有路径真正改变时才移动(避免初始设置null时的不必要移动) + if (value != null && oldRoute != value) + { + MoveAnimatedObjectToPathStart(); + } } } } @@ -575,6 +583,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels if (value != null) { UpdatePassageSpaceVisualization(); + + // 🔥 立即将物体移动到路径起点(如果路径已选择) + MoveAnimatedObjectToPathStart(); } } } @@ -627,11 +638,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels { try { - // 只有在当前动画对象不是虚拟车辆时才执行重置 + // 🔥 将之前选择的实体物体归位(如果存在) + // 注意:使用 SelectedAnimatedObject 而不是 _pathAnimationManager.AnimatedObject + // 因为用户可能只选择了物体但还没有生成动画 if (_pathAnimationManager != null && - _pathAnimationManager.AnimatedObject != null && + SelectedAnimatedObject != null && !VirtualVehicleManager.Instance.IsVirtualVehicleActive) { + // 先将实体物体设置到动画管理器,然后归位 + _pathAnimationManager.SetAnimatedObject(SelectedAnimatedObject); _pathAnimationManager.RestoreObjectToCADPosition(); _pathAnimationManager.ClearAnimationResults(); // 清理手动选择物体留下的动画数据 LogManager.Info("已切换到虚拟车辆模式,将之前的手动选择物体归位并清理动画数据"); @@ -651,6 +666,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels // 设置已选择物体状态(虚拟车辆也算已选择) HasSelectedAnimatedObject = true; + + // 🔥 立即将虚拟车辆移动到路径起点(如果路径已选择) + MoveAnimatedObjectToPathStart(); } catch (Exception ex) { @@ -662,10 +680,25 @@ namespace NavisworksTransport.UI.WPF.ViewModels // ✨ 模式切换清理:切换到手动选择模式时,隐藏虚拟车辆并清理数据 try { - // 不删除虚拟车辆,只隐藏它 + // 🔥 先将虚拟车辆归位(如果之前被移动过) + if (_pathAnimationManager != null && + VirtualVehicleManager.Instance.IsVirtualVehicleActive) + { + _pathAnimationManager.SetVirtualVehicleParameters(true, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight); + _pathAnimationManager.RestoreObjectToCADPosition(); + LogManager.Info("已切换到手动选择模式,虚拟车辆已归位"); + } + + // 隐藏虚拟车辆 VirtualVehicleManager.Instance.HideVirtualVehicle(); _pathAnimationManager?.ClearAnimationResults(); // 清理虚拟车辆留下的动画数据 LogManager.Info("已切换到手动选择模式,自动隐藏虚拟车辆并清理动画数据"); + + // 🔥 如果已选择实体物体且路径已选择,将实体物体移动到路径起点 + if (SelectedAnimatedObject != null && CurrentPathRoute != null) + { + MoveAnimatedObjectToPathStart(); + } } catch (Exception ex) { @@ -2085,6 +2118,70 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + /// + /// 将动画对象(物体或虚拟车辆)移动到当前路径的起点 + /// 用于在选择物体/虚拟车辆或切换路径时立即定位到起点,方便用户预览和调整角度 + /// + private void MoveAnimatedObjectToPathStart() + { + try + { + // 检查是否有路径 + if (CurrentPathRoute == null || CurrentPathRoute.Points == null || CurrentPathRoute.Points.Count < 2) + { + LogManager.Debug("[移动到起点] 路径未选择或路径点不足,跳过移动"); + return; + } + + // 检查是否有动画对象(物体或虚拟车辆) + if (!HasSelectedAnimatedObject) + { + LogManager.Debug("[移动到起点] 未选择动画对象,跳过移动"); + return; + } + + // 获取路径点 + var pathPoints = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList(); + + // 根据当前模式确定动画对象 + ModelItem animatedObject = null; + if (UseVirtualVehicle) + { + // 虚拟车辆模式:获取当前虚拟车辆 + animatedObject = VirtualVehicleManager.Instance.CurrentVirtualVehicle; + if (animatedObject == null) + { + LogManager.Debug("[移动到起点] 虚拟车辆未创建,跳过移动"); + return; + } + + // 设置虚拟车辆参数到动画管理器 + _pathAnimationManager?.SetVirtualVehicleParameters(true, VirtualVehicleLength, VirtualVehicleWidth, VirtualVehicleHeight); + } + else + { + // 实体物体模式:使用选中的物体 + animatedObject = SelectedAnimatedObject; + if (animatedObject == null) + { + LogManager.Debug("[移动到起点] 选中物体为空,跳过移动"); + return; + } + } + + // 执行移动 + if (_pathAnimationManager != null && animatedObject != null) + { + _pathAnimationManager.MoveVehicleToPathStart(animatedObject, pathPoints); + LogManager.Info($"[移动到起点] {(UseVirtualVehicle ? "虚拟车辆" : "物体")} 已移动到路径起点"); + } + } + catch (Exception ex) + { + LogManager.Warning($"[移动到起点] 移动动画对象到路径起点失败: {ex.Message}"); + } + } + #region 手工碰撞对象命令 private void ExecuteApplyManualTargetsFromSelection() @@ -3333,14 +3430,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels return; } - // 将虚拟车辆移到路径起点 - if (CurrentPathRoute != null && CurrentPathRoute.Points != null) - { - var points = CurrentPathRoute.Points.Select(p => new Point3D(p.X, p.Y, p.Z)).ToList(); - _pathAnimationManager?.MoveVehicleToPathStart(animatedObject, points); - LogManager.Info("[ExecuteGenerateAnimation] 虚拟车辆已移到路径起点"); - } - + // 注意:虚拟车辆在选择时已经通过 MoveAnimatedObjectToPathStart 移动到路径起点 + // 这里不需要重复移动,因为 CreateAnimation 内部还会再次调用 MoveVehicleToPathStart LogManager.Info($"使用虚拟车辆: {animatedObject.DisplayName}"); } else