新增指定对象聚焦功能
This commit is contained in:
parent
9a7a2da3c6
commit
78158c1cb1
@ -2212,6 +2212,32 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
UpdateMainStatus("已清除手工对象高亮");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 聚焦到手工指定的对象
|
||||
/// </summary>
|
||||
public void FocusOnManualTarget(ManualCollisionTargetViewModel target)
|
||||
{
|
||||
if (target?.ModelItem == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
// 先高亮该对象
|
||||
var items = new List<ModelItem> { 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 检测排除对象命令
|
||||
|
||||
@ -186,7 +186,8 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
MinHeight="60"
|
||||
MaxHeight="200"
|
||||
BorderBrush="#FFE2E8F0"
|
||||
BorderThickness="1">
|
||||
BorderThickness="1"
|
||||
MouseDoubleClick="OnManualTargetDoubleClick">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Header="序号" Width="45">
|
||||
|
||||
@ -154,5 +154,28 @@ namespace NavisworksTransport.UI.WPF.Views
|
||||
LogManager.Error($"[AnimationControlView] 处理排除对象选择变化失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手工指定对象列表双击事件处理 - 聚焦到对象
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -276,5 +276,235 @@ namespace NavisworksTransport.Utils
|
||||
{
|
||||
System.Threading.Thread.Sleep(VIEW_UPDATE_DELAY_MS);
|
||||
}
|
||||
|
||||
#region 模型元素聚焦方法
|
||||
|
||||
/// <summary>
|
||||
/// 聚焦到指定模型元素,使用斜上方45度视角
|
||||
/// 相机会 positioned 在元素斜上方,使元素占据视图约1/3宽度
|
||||
/// </summary>
|
||||
/// <param name="modelItem">要聚焦的模型元素</param>
|
||||
/// <param name="viewAngleDegrees">视角角度(默认45度斜上方)</param>
|
||||
/// <param name="targetViewRatio">目标占据视图比例(默认1/3)</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 聚焦到多个模型元素(如碰撞中的两个对象)
|
||||
/// </summary>
|
||||
/// <param name="item1">第一个模型元素(运动物体)</param>
|
||||
/// <param name="item2">第二个模型元素(被撞对象)</param>
|
||||
/// <param name="viewAngleDegrees">视角角度(默认45度斜上方)</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 聚焦到指定位置和尺寸
|
||||
/// </summary>
|
||||
/// <param name="center">目标中心点</param>
|
||||
/// <param name="targetSize">目标尺寸(最大边)</param>
|
||||
/// <param name="viewAngleDegrees">视角角度</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算相机位置(使用模型标准前右上视角)
|
||||
/// 基于 Navisworks 的标准 FrontRightTopViewVector 确定相机方向
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user