651 lines
23 KiB
C#
651 lines
23 KiB
C#
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
|
||
{
|
||
// 忽略清理错误
|
||
}
|
||
}
|
||
}
|
||
} |