diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
index cdf52a7..ae53a65 100644
--- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
+++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
@@ -2212,6 +2212,32 @@ namespace NavisworksTransport.UI.WPF.ViewModels
UpdateMainStatus("已清除手工对象高亮");
}
+ ///
+ /// 聚焦到手工指定的对象
+ ///
+ public void FocusOnManualTarget(ManualCollisionTargetViewModel target)
+ {
+ if (target?.ModelItem == null) return;
+
+ try
+ {
+ // 先高亮该对象
+ var items = new List { target.ModelItem };
+ ModelHighlightHelper.HighlightItems(ManualTargetsHighlightCategory, items);
+
+ // 聚焦到对象(斜上方45度视角)
+ ViewpointHelper.FocusOnModelItem(target.ModelItem, viewAngleDegrees: 45.0, targetViewRatio: 0.33);
+
+ UpdateMainStatus($"已聚焦到: {target.DisplayName}");
+ LogManager.Info($"聚焦到手工指定对象: {target.DisplayName}");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"聚焦到手工指定对象失败: {ex.Message}", ex);
+ UpdateMainStatus($"聚焦失败: {ex.Message}");
+ }
+ }
+
#endregion
#region 检测排除对象命令
diff --git a/src/UI/WPF/Views/AnimationControlView.xaml b/src/UI/WPF/Views/AnimationControlView.xaml
index 5a5ae75..79c3a19 100644
--- a/src/UI/WPF/Views/AnimationControlView.xaml
+++ b/src/UI/WPF/Views/AnimationControlView.xaml
@@ -186,7 +186,8 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
MinHeight="60"
MaxHeight="200"
BorderBrush="#FFE2E8F0"
- BorderThickness="1">
+ BorderThickness="1"
+ MouseDoubleClick="OnManualTargetDoubleClick">
diff --git a/src/UI/WPF/Views/AnimationControlView.xaml.cs b/src/UI/WPF/Views/AnimationControlView.xaml.cs
index a5f84ba..b422c1c 100644
--- a/src/UI/WPF/Views/AnimationControlView.xaml.cs
+++ b/src/UI/WPF/Views/AnimationControlView.xaml.cs
@@ -154,5 +154,28 @@ namespace NavisworksTransport.UI.WPF.Views
LogManager.Error($"[AnimationControlView] 处理排除对象选择变化失败: {ex.Message}", ex);
}
}
+
+ ///
+ /// 手工指定对象列表双击事件处理 - 聚焦到对象
+ ///
+ private void OnManualTargetDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
+ {
+ try
+ {
+ if (ViewModel == null) return;
+
+ // 获取双击的对象
+ var listView = sender as ListView;
+ if (listView?.SelectedItem is ManualCollisionTargetViewModel selectedTarget)
+ {
+ // 聚焦到对象
+ ViewModel.FocusOnManualTarget(selectedTarget);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"[AnimationControlView] 处理手工指定对象双击失败: {ex.Message}", ex);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Utils/ViewpointHelper.cs b/src/Utils/ViewpointHelper.cs
index 0805d38..97dd9a0 100644
--- a/src/Utils/ViewpointHelper.cs
+++ b/src/Utils/ViewpointHelper.cs
@@ -276,5 +276,235 @@ namespace NavisworksTransport.Utils
{
System.Threading.Thread.Sleep(VIEW_UPDATE_DELAY_MS);
}
+
+ #region 模型元素聚焦方法
+
+ ///
+ /// 聚焦到指定模型元素,使用斜上方45度视角
+ /// 相机会 positioned 在元素斜上方,使元素占据视图约1/3宽度
+ ///
+ /// 要聚焦的模型元素
+ /// 视角角度(默认45度斜上方)
+ /// 目标占据视图比例(默认1/3)
+ public static void FocusOnModelItem(ModelItem modelItem, double viewAngleDegrees = 45.0, double targetViewRatio = 0.25)
+ {
+ if (modelItem == null)
+ {
+ throw new ArgumentNullException(nameof(modelItem));
+ }
+
+ Document doc = Application.ActiveDocument;
+ if (doc == null || doc.IsClear)
+ {
+ throw new InvalidOperationException("没有活动的文档");
+ }
+
+ try
+ {
+ // 1. 获取模型元素的包围盒
+ BoundingBox3D boundingBox = modelItem.BoundingBox();
+ if (boundingBox == null || boundingBox.Size == new Vector3D(0, 0, 0))
+ {
+ LogManager.Warning($"模型元素 {modelItem.DisplayName} 没有有效的包围盒,使用默认视角");
+ return;
+ }
+
+ // 2. 计算包围盒中心和尺寸
+ Point3D center = new Point3D(
+ (boundingBox.Min.X + boundingBox.Max.X) / 2,
+ (boundingBox.Min.Y + boundingBox.Max.Y) / 2,
+ (boundingBox.Min.Z + boundingBox.Max.Z) / 2
+ );
+
+ double maxDimension = Math.Max(
+ boundingBox.Max.X - boundingBox.Min.X,
+ Math.Max(boundingBox.Max.Y - boundingBox.Min.Y, boundingBox.Max.Z - boundingBox.Min.Z)
+ );
+
+ LogManager.Info($"聚焦到模型元素: {modelItem.DisplayName}, 最大边: {maxDimension:F2}");
+
+ // 3. 计算相机位置(使用模型标准视角方向)
+ Point3D cameraPosition = CalculateCameraPosition(center, maxDimension, viewAngleDegrees, targetViewRatio);
+
+ // 4. 创建视角并设置相机
+ Viewpoint newViewpoint = doc.CurrentViewpoint.Value.CreateCopy();
+ newViewpoint.Position = cameraPosition;
+
+ // 获取模型的标准视角向量
+ Vector3D viewDirection = doc.FrontRightTopViewVector;
+ viewDirection.Normalize();
+
+ // 使用 AlignDirection 设置相机朝向(看向目标方向)
+ // 方向是从相机指向目标
+ Vector3D lookDirection = new Vector3D(
+ center.X - cameraPosition.X,
+ center.Y - cameraPosition.Y,
+ center.Z - cameraPosition.Z
+ );
+ lookDirection.Normalize();
+ newViewpoint.AlignDirection(lookDirection);
+
+ // 使用 AlignUp 设置相机的上方向(基于模型的标准上方向)
+ Vector3D upVector = doc.FrontRightTopViewUpVector;
+ upVector.Normalize();
+ newViewpoint.AlignUp(upVector);
+
+ // 5. 应用视角(不使用 ZoomBox,让相机距离决定视野比例)
+ doc.CurrentViewpoint.CopyFrom(newViewpoint);
+
+ LogManager.Info($"视角已调整: 标准前右上视角, 目标占据视图{targetViewRatio:P0}");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"聚焦到模型元素失败: {ex.Message}", ex);
+ throw;
+ }
+ }
+
+ ///
+ /// 聚焦到多个模型元素(如碰撞中的两个对象)
+ ///
+ /// 第一个模型元素(运动物体)
+ /// 第二个模型元素(被撞对象)
+ /// 视角角度(默认45度斜上方)
+ public static void FocusOnCollision(ModelItem item1, ModelItem item2, double viewAngleDegrees = 45.0)
+ {
+ if (item1 == null && item2 == null)
+ {
+ throw new ArgumentException("至少需要一个模型元素");
+ }
+
+ try
+ {
+ // 计算两个元素的联合包围盒
+ BoundingBox3D combinedBounds = null;
+
+ if (item1 != null)
+ {
+ combinedBounds = item1.BoundingBox();
+ }
+
+ if (item2 != null)
+ {
+ if (combinedBounds == null)
+ {
+ combinedBounds = item2.BoundingBox();
+ }
+ else
+ {
+ BoundingBox3D item2Box = item2.BoundingBox();
+ combinedBounds.Extend(item2Box.Min);
+ combinedBounds.Extend(item2Box.Max);
+ }
+ }
+
+ if (combinedBounds == null || combinedBounds.Size == new Vector3D(0, 0, 0))
+ {
+ LogManager.Warning("碰撞对象没有有效的包围盒");
+ return;
+ }
+
+ // 使用联合包围盒的中心点和尺寸
+ Point3D center = new Point3D(
+ (combinedBounds.Min.X + combinedBounds.Max.X) / 2,
+ (combinedBounds.Min.Y + combinedBounds.Max.Y) / 2,
+ (combinedBounds.Min.Z + combinedBounds.Max.Z) / 2
+ );
+
+ double maxDimension = Math.Max(
+ combinedBounds.Max.X - combinedBounds.Min.X,
+ Math.Max(combinedBounds.Max.Y - combinedBounds.Min.Y, combinedBounds.Max.Z - combinedBounds.Min.Z)
+ );
+
+ FocusOnPosition(center, maxDimension, viewAngleDegrees);
+
+ LogManager.Info($"已聚焦到碰撞位置: {item1?.DisplayName} ↔ {item2?.DisplayName}");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"聚焦到碰撞位置失败: {ex.Message}", ex);
+ throw;
+ }
+ }
+
+ ///
+ /// 聚焦到指定位置和尺寸
+ ///
+ /// 目标中心点
+ /// 目标尺寸(最大边)
+ /// 视角角度
+ public static void FocusOnPosition(Point3D center, double targetSize, double viewAngleDegrees = 45.0)
+ {
+ Document doc = Application.ActiveDocument;
+ if (doc == null || doc.IsClear)
+ {
+ throw new InvalidOperationException("没有活动的文档");
+ }
+
+ try
+ {
+ // 计算相机位置(使用模型标准视角方向)
+ Point3D cameraPosition = CalculateCameraPosition(center, targetSize, viewAngleDegrees, 0.25);
+
+ // 创建视角并设置相机
+ Viewpoint newViewpoint = doc.CurrentViewpoint.Value.CreateCopy();
+ newViewpoint.Position = cameraPosition;
+
+ // 获取模型的标准视角向量
+ Vector3D viewDirection = doc.FrontRightTopViewVector;
+ viewDirection.Normalize();
+
+ // 使用 AlignDirection 设置相机朝向
+ Vector3D lookDirection = new Vector3D(
+ center.X - cameraPosition.X,
+ center.Y - cameraPosition.Y,
+ center.Z - cameraPosition.Z
+ );
+ lookDirection.Normalize();
+ newViewpoint.AlignDirection(lookDirection);
+
+ // 使用 AlignUp 设置相机的上方向
+ Vector3D upVector = doc.FrontRightTopViewUpVector;
+ upVector.Normalize();
+ newViewpoint.AlignUp(upVector);
+
+ // 应用视角(不使用 ZoomBox,让相机距离决定视野比例)
+ doc.CurrentViewpoint.CopyFrom(newViewpoint);
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"聚焦到位置失败: {ex.Message}", ex);
+ throw;
+ }
+ }
+
+ ///
+ /// 计算相机位置(使用模型标准前右上视角)
+ /// 基于 Navisworks 的标准 FrontRightTopViewVector 确定相机方向
+ ///
+ private static Point3D CalculateCameraPosition(Point3D center, double targetSize, double viewAngleDegrees, double targetViewRatio)
+ {
+ // 计算相机距离(目标占据视图 targetViewRatio)
+ double fovRadians = 0.785398; // Navisworks 默认 FOV 45度
+ double cameraDistance = (targetSize / 2.0) / Math.Tan(fovRadians / 2.0) / targetViewRatio;
+ cameraDistance *= 1.2; // 添加边距
+
+ // 获取模型的标准前右上视角向量
+ // 这个向量定义了模型的"正方向",基于模型坐标系
+ Vector3D viewDirection = Application.ActiveDocument.FrontRightTopViewVector;
+
+ // 归一化方向向量
+ viewDirection.Normalize();
+
+ // 沿标准视角方向偏移相机位置
+ // 相机位置 = 目标中心 - 方向向量 * 距离
+ return new Point3D(
+ center.X - viewDirection.X * cameraDistance,
+ center.Y - viewDirection.Y * cameraDistance,
+ center.Z - viewDirection.Z * cameraDistance
+ );
+ }
+
+ #endregion
}
}
\ No newline at end of file