NavisworksTransport/PathVisualizer.cs

651 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
namespace NavisworksTransport
{
/// <summary>
/// 3D路径可视化组件
/// 负责在Navisworks 3D视图中绘制路径
/// </summary>
public class PathVisualizer
{
private List<PathRoute> _routes;
private PathRoute _activeRoute;
private bool _isVisualizationEnabled;
// 可视化样式配置
private readonly Autodesk.Navisworks.Api.Color _startPointColor = Autodesk.Navisworks.Api.Color.Green;
private readonly Autodesk.Navisworks.Api.Color _endPointColor = Autodesk.Navisworks.Api.Color.Red;
private readonly Autodesk.Navisworks.Api.Color _wayPointColor = Autodesk.Navisworks.Api.Color.Blue;
private readonly Autodesk.Navisworks.Api.Color _pathLineColor = Autodesk.Navisworks.Api.Color.Blue;
private readonly Autodesk.Navisworks.Api.Color _activeRouteColor = new Autodesk.Navisworks.Api.Color(1.0, 0.5, 0.0);
private readonly double _pointSize = 0.5; // 路径点大小(米)
private readonly double _lineWidth = 0.1; // 路径线宽度(米)
/// <summary>
/// 是否启用可视化
/// </summary>
public bool IsVisualizationEnabled
{
get { return _isVisualizationEnabled; }
set
{
_isVisualizationEnabled = value;
if (!_isVisualizationEnabled)
{
ClearAllVisualizations();
}
else
{
RefreshVisualization();
}
}
}
/// <summary>
/// 当前活动路径
/// </summary>
public PathRoute ActiveRoute
{
get { return _activeRoute; }
set
{
_activeRoute = value;
if (_isVisualizationEnabled)
{
RefreshVisualization();
}
}
}
/// <summary>
/// 路径点大小
/// </summary>
public double PointSize
{
get { return _pointSize; }
}
/// <summary>
/// 路径线宽度
/// </summary>
public double LineWidth
{
get { return _lineWidth; }
}
/// <summary>
/// 构造函数
/// </summary>
public PathVisualizer()
{
_routes = new List<PathRoute>();
_isVisualizationEnabled = true;
}
/// <summary>
/// 添加要可视化的路径
/// </summary>
/// <param name="route">路径</param>
public void AddRoute(PathRoute route)
{
if (route == null) return;
if (!_routes.Contains(route))
{
_routes.Add(route);
if (_isVisualizationEnabled)
{
VisualizeRoute(route);
}
}
}
/// <summary>
/// 移除路径可视化
/// </summary>
/// <param name="route">路径</param>
public void RemoveRoute(PathRoute route)
{
if (route == null) return;
if (_routes.Remove(route))
{
if (_isVisualizationEnabled)
{
ClearRouteVisualization(route);
}
}
}
/// <summary>
/// 清空所有路径
/// </summary>
public void ClearAllRoutes()
{
_routes.Clear();
_activeRoute = null;
if (_isVisualizationEnabled)
{
ClearAllVisualizations();
}
}
/// <summary>
/// 可视化单个路径
/// </summary>
/// <param name="route">路径</param>
public void VisualizeRoute(PathRoute route)
{
if (route == null || !route.IsValid()) return;
try
{
// 先清除该路径的现有可视化
ClearRouteVisualization(route);
var sortedPoints = route.GetSortedPoints();
if (sortedPoints.Count < 2) return;
bool isActiveRoute = route == _activeRoute;
var lineColor = isActiveRoute ? _activeRouteColor : _pathLineColor;
// 绘制路径线条
DrawPathLines(sortedPoints, lineColor);
// 绘制路径点
DrawPathPoints(sortedPoints, isActiveRoute);
}
catch (Exception ex)
{
// 记录错误但不中断程序
System.Diagnostics.Debug.WriteLine($"可视化路径时发生错误: {ex.Message}");
}
}
/// <summary>
/// 绘制路径线条
/// </summary>
/// <param name="points">路径点集合</param>
/// <param name="lineColor">线条颜色</param>
private void DrawPathLines(List<PathPoint> points, Autodesk.Navisworks.Api.Color lineColor)
{
if (points.Count < 2) return;
try
{
// 绘制线段
for (int i = 0; i < points.Count - 1; i++)
{
var startPoint = points[i].Position;
var endPoint = points[i + 1].Position;
// 创建线段几何
DrawLine(startPoint, endPoint, lineColor, _lineWidth);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"绘制路径线条时发生错误: {ex.Message}");
}
}
/// <summary>
/// 绘制路径点
/// </summary>
/// <param name="points">路径点集合</param>
/// <param name="isActiveRoute">是否为活动路径</param>
private void DrawPathPoints(List<PathPoint> points, bool isActiveRoute)
{
foreach (var point in points)
{
try
{
var pointColor = GetPointColor(point.Type);
var pointSize = isActiveRoute ? _pointSize * 1.5 : _pointSize;
// 绘制路径点球体
DrawSphere(point.Position, pointSize, pointColor);
// 绘制点标签(如果有名称)
if (!string.IsNullOrEmpty(point.Name))
{
DrawPointLabel(point.Position, point.Name, pointColor);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"绘制路径点时发生错误: {ex.Message}");
}
}
}
/// <summary>
/// 绘制线段
/// </summary>
/// <param name="startPoint">起点</param>
/// <param name="endPoint">终点</param>
/// <param name="color">颜色</param>
/// <param name="width">宽度</param>
private void DrawLine(Point3D startPoint, Point3D endPoint, Autodesk.Navisworks.Api.Color color, double width)
{
try
{
// 计算线段方向和长度
var direction = new Vector3D(
endPoint.X - startPoint.X,
endPoint.Y - startPoint.Y,
endPoint.Z - startPoint.Z
);
var length = Math.Sqrt(direction.X * direction.X + direction.Y * direction.Y + direction.Z * direction.Z);
if (length < 0.001) return; // 忽略过短的线段
// 标准化方向向量
direction = new Vector3D(
direction.X / length,
direction.Y / length,
direction.Z / length
);
// 创建圆柱体几何来表示线段
var cylinderCenter = new Point3D(
(startPoint.X + endPoint.X) / 2,
(startPoint.Y + endPoint.Y) / 2,
(startPoint.Z + endPoint.Z) / 2
);
// 使用临时图形绘制
using (var state = Application.ActiveDocument.State)
{
// 这里可以使用Navisworks的临时图形API
// 由于API限制我们使用简化的方法
DrawCylinder(cylinderCenter, direction, length, width / 2, color);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"绘制线段时发生错误: {ex.Message}");
}
}
/// <summary>
/// 绘制球体(路径点标记)
/// </summary>
/// <param name="center">中心点</param>
/// <param name="radius">半径</param>
/// <param name="color">颜色</param>
public void DrawSphere(Point3D center, double radius, Autodesk.Navisworks.Api.Color color)
{
try
{
LogManager.WriteLog($"[PathVisualizer] 开始绘制球体: 中心({center.X:F3}, {center.Y:F3}, {center.Z:F3}), 半径={radius:F3}");
// 使用Navisworks临时几何API绘制球体
// 简化实现:绘制多个圆环来模拟球体
const int segments = 8; // 减少分段数以提高性能
const int rings = 6; // 减少环数以提高性能
var vertices = new List<Point3D>();
// 生成球体的顶点
for (int ring = 0; ring <= rings; ring++)
{
var phi = Math.PI * ring / rings; // 纬度角
var y = Math.Cos(phi) * radius;
var ringRadius = Math.Sin(phi) * radius;
for (int segment = 0; segment < segments; segment++)
{
var theta = 2 * Math.PI * segment / segments; // 经度角
var x = Math.Cos(theta) * ringRadius;
var z = Math.Sin(theta) * ringRadius;
var vertex = new Point3D(center.X + x, center.Y + y, center.Z + z);
vertices.Add(vertex);
}
}
// 绘制纬线(水平圆环)
for (int ring = 0; ring <= rings; ring++)
{
for (int segment = 0; segment < segments; segment++)
{
var current = ring * segments + segment;
var next = ring * segments + ((segment + 1) % segments);
if (current < vertices.Count && next < vertices.Count)
{
DrawLine(vertices[current], vertices[next], color, radius * 0.1);
}
}
}
// 绘制经线(垂直线)
for (int segment = 0; segment < segments; segment++)
{
for (int ring = 0; ring < rings; ring++)
{
var current = ring * segments + segment;
var next = (ring + 1) * segments + segment;
if (current < vertices.Count && next < vertices.Count)
{
DrawLine(vertices[current], vertices[next], color, radius * 0.1);
}
}
}
LogManager.WriteLog($"[PathVisualizer] 球体绘制完成,共绘制 {vertices.Count} 个顶点");
}
catch (Exception ex)
{
LogManager.WriteLog($"[PathVisualizer] 绘制球体时发生错误: {ex.Message}");
System.Diagnostics.Debug.WriteLine($"绘制球体时发生错误: {ex.Message}");
}
}
/// <summary>
/// 绘制圆柱体
/// </summary>
/// <param name="center">中心点</param>
/// <param name="direction">方向向量</param>
/// <param name="height">高度</param>
/// <param name="radius">半径</param>
/// <param name="color">颜色</param>
private void DrawCylinder(Point3D center, Vector3D direction, double height, double radius, Autodesk.Navisworks.Api.Color color)
{
try
{
// 圆柱体绘制的简化实现
// 实际应用中需要使用Navisworks Graphics API
const int segments = 12;
var halfHeight = height / 2;
// 计算圆柱体的两个端点
var startCenter = new Point3D(
center.X - direction.X * halfHeight,
center.Y - direction.Y * halfHeight,
center.Z - direction.Z * halfHeight
);
var endCenter = new Point3D(
center.X + direction.X * halfHeight,
center.Y + direction.Y * halfHeight,
center.Z + direction.Z * halfHeight
);
// 创建垂直于方向的向量
Vector3D perpendicular1, perpendicular2;
CreatePerpendicularVectors(direction, out perpendicular1, out perpendicular2);
// 绘制圆柱体侧面
for (int i = 0; i < segments; i++)
{
var angle1 = 2 * Math.PI * i / segments;
var angle2 = 2 * Math.PI * (i + 1) / segments;
var cos1 = Math.Cos(angle1);
var sin1 = Math.Sin(angle1);
var cos2 = Math.Cos(angle2);
var sin2 = Math.Sin(angle2);
// 计算圆周上的点
var offset1 = new Vector3D(
perpendicular1.X * cos1 + perpendicular2.X * sin1,
perpendicular1.Y * cos1 + perpendicular2.Y * sin1,
perpendicular1.Z * cos1 + perpendicular2.Z * sin1
);
var offset2 = new Vector3D(
perpendicular1.X * cos2 + perpendicular2.X * sin2,
perpendicular1.Y * cos2 + perpendicular2.Y * sin2,
perpendicular1.Z * cos2 + perpendicular2.Z * sin2
);
// 计算四个顶点
var p1 = new Point3D(startCenter.X + offset1.X * radius, startCenter.Y + offset1.Y * radius, startCenter.Z + offset1.Z * radius);
var p2 = new Point3D(endCenter.X + offset1.X * radius, endCenter.Y + offset1.Y * radius, endCenter.Z + offset1.Z * radius);
var p3 = new Point3D(endCenter.X + offset2.X * radius, endCenter.Y + offset2.Y * radius, endCenter.Z + offset2.Z * radius);
var p4 = new Point3D(startCenter.X + offset2.X * radius, startCenter.Y + offset2.Y * radius, startCenter.Z + offset2.Z * radius);
// 这里应该使用Graphics API绘制四边形
// 由于API复杂性使用简化实现
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"绘制圆柱体时发生错误: {ex.Message}");
}
}
/// <summary>
/// 创建垂直向量
/// </summary>
/// <param name="direction">方向向量</param>
/// <param name="perpendicular1">第一个垂直向量</param>
/// <param name="perpendicular2">第二个垂直向量</param>
private void CreatePerpendicularVectors(Vector3D direction, out Vector3D perpendicular1, out Vector3D perpendicular2)
{
// 找到一个与direction不平行的向量
Vector3D temp;
if (Math.Abs(direction.X) < 0.9)
{
temp = new Vector3D(1, 0, 0);
}
else
{
temp = new Vector3D(0, 1, 0);
}
// 计算第一个垂直向量(叉积)
perpendicular1 = CrossProduct(direction, temp);
perpendicular1 = Normalize(perpendicular1);
// 计算第二个垂直向量
perpendicular2 = CrossProduct(direction, perpendicular1);
perpendicular2 = Normalize(perpendicular2);
}
/// <summary>
/// 向量叉积
/// </summary>
/// <param name="a">向量A</param>
/// <param name="b">向量B</param>
/// <returns>叉积结果</returns>
private Vector3D CrossProduct(Vector3D a, Vector3D b)
{
return new Vector3D(
a.Y * b.Z - a.Z * b.Y,
a.Z * b.X - a.X * b.Z,
a.X * b.Y - a.Y * b.X
);
}
/// <summary>
/// 向量标准化
/// </summary>
/// <param name="vector">向量</param>
/// <returns>标准化后的向量</returns>
private Vector3D Normalize(Vector3D vector)
{
var length = Math.Sqrt(vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z);
if (length < 0.001) return new Vector3D(1, 0, 0);
return new Vector3D(vector.X / length, vector.Y / length, vector.Z / length);
}
/// <summary>
/// 绘制点标签
/// </summary>
/// <param name="position">位置</param>
/// <param name="text">文本</param>
/// <param name="color">颜色</param>
private void DrawPointLabel(Point3D position, string text, Autodesk.Navisworks.Api.Color color)
{
try
{
// 在点的上方偏移位置绘制文本标签
var labelPosition = new Point3D(position.X, position.Y, position.Z + _pointSize * 2);
// 这里应该使用Navisworks的文本绘制API
// 由于API限制这里是简化实现
// 实际实现可能需要创建临时的文本几何或使用注释功能
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"绘制点标签时发生错误: {ex.Message}");
}
}
/// <summary>
/// 获取路径点颜色
/// </summary>
/// <param name="type">路径点类型</param>
/// <returns>颜色</returns>
private Autodesk.Navisworks.Api.Color GetPointColor(PathPointType type)
{
switch (type)
{
case PathPointType.StartPoint: return _startPointColor;
case PathPointType.EndPoint: return _endPointColor;
case PathPointType.WayPoint: return _wayPointColor;
default: return _wayPointColor;
}
}
/// <summary>
/// 清除路径可视化
/// </summary>
/// <param name="route">路径</param>
private void ClearRouteVisualization(PathRoute route)
{
try
{
// 这里应该清除特定路径的可视化元素
// 由于Navisworks API的限制可能需要重新绘制所有路径
RefreshVisualization();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"清除路径可视化时发生错误: {ex.Message}");
}
}
/// <summary>
/// 清除所有可视化
/// </summary>
/// <param name="preserveChannelHighlight">是否保留通道高亮</param>
private void ClearAllVisualizations(bool preserveChannelHighlight = true)
{
try
{
if (!preserveChannelHighlight)
{
// 只有在明确要求时才清除所有临时材质(包括通道高亮)
Application.ActiveDocument.Models.ResetAllTemporaryMaterials();
}
// 如果preserveChannelHighlight为true则不调用ResetAllTemporaryMaterials
// 这样可以保留通道的绿色高亮显示
// 刷新视图
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"清除所有可视化时发生错误: {ex.Message}");
}
}
/// <summary>
/// 刷新可视化
/// </summary>
public void RefreshVisualization()
{
if (!_isVisualizationEnabled) return;
try
{
// 清除现有可视化,但保留通道高亮
ClearAllVisualizations(preserveChannelHighlight: true);
// 重新绘制所有路径
foreach (var route in _routes)
{
VisualizeRoute(route);
}
// 刷新视图
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.All);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"刷新可视化时发生错误: {ex.Message}");
}
}
/// <summary>
/// 设置路径可见性
/// </summary>
/// <param name="route">路径</param>
/// <param name="visible">是否可见</param>
public void SetRouteVisibility(PathRoute route, bool visible)
{
if (route == null) return;
if (visible)
{
if (!_routes.Contains(route))
{
AddRoute(route);
}
else if (_isVisualizationEnabled)
{
VisualizeRoute(route);
}
}
else
{
RemoveRoute(route);
}
}
/// <summary>
/// 获取可视化统计信息
/// </summary>
/// <returns>统计信息</returns>
public string GetVisualizationStats()
{
var totalPoints = _routes.Sum(r => r.Points.Count);
var totalLines = _routes.Sum(r => Math.Max(0, r.Points.Count - 1));
return $"可视化路径: {_routes.Count}条\n" +
$"路径点: {totalPoints}个\n" +
$"路径线段: {totalLines}段\n" +
$"可视化状态: {(_isVisualizationEnabled ? "" : "")}";
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
try
{
// 在释放时清除所有可视化,包括通道高亮
ClearAllVisualizations(preserveChannelHighlight: false);
_routes.Clear();
_activeRoute = null;
}
catch
{
// 忽略清理错误
}
}
}
}