NavisworksTransport/PathPointRenderPlugin.cs
2025-06-19 18:34:04 +08:00

440 lines
16 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;
using Autodesk.Navisworks.Api.Plugins;
namespace NavisworksTransport
{
/// <summary>
/// 路径点圆形标记渲染插件
/// 使用Graphics.Circle在3D空间绘制圆形标记
/// </summary>
[Plugin("PathPointRenderPlugin", "NavisworksTransport", DisplayName = "路径点圆形标记渲染器")]
public class PathPointRenderPlugin : RenderPlugin
{
private readonly object _lockObject = new object();
private List<CircleMarker> _circleMarkers = new List<CircleMarker>();
private bool _isEnabled = true;
// 静态实例,用于外部访问
private static PathPointRenderPlugin _instance;
/// <summary>
/// 构造函数
/// </summary>
public PathPointRenderPlugin()
{
_instance = this;
LogManager.WriteLog("[RenderPlugin] PathPointRenderPlugin构造函数被调用");
}
/// <summary>
/// 获取静态实例
/// </summary>
public static PathPointRenderPlugin Instance => _instance;
/// <summary>
/// 是否启用渲染
/// </summary>
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
// 触发视图刷新
if (Application.ActiveDocument?.ActiveView != null)
{
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);
}
}
}
/// <summary>
/// 当前圆形标记数量
/// </summary>
public int MarkerCount
{
get
{
lock (_lockObject)
{
return _circleMarkers.Count;
}
}
}
/// <summary>
/// Navisworks渲染回调方法
/// </summary>
/// <param name="view">当前视图</param>
/// <param name="graphics">图形上下文</param>
public override void Render(View view, Graphics graphics)
{
if (!_isEnabled) return;
try
{
// 简单测试:画一条红色线段,看能否看到任何东西
graphics.Color(Color.Red, 0.0);
graphics.LineWidth(10);
var lineStart = new Point3D(19000, -18000, 2000);
var lineEnd = new Point3D(21000, -18000, 2000);
graphics.Line(lineStart, lineEnd);
LogManager.WriteLog($"[简单测试] 绘制测试线段: ({lineStart.X}, {lineStart.Y}, {lineStart.Z}) 到 ({lineEnd.X}, {lineEnd.Y}, {lineEnd.Z})");
// 先绘制测试大圆形 - 验证Graphics.Circle API
var testCenter = new Point3D(19082.41, -18248.14, 4037.26);
var testRadius = 200.0; // 200英寸大圆应该非常明显
var testColor = new Color(1.0, 0.0, 0.0); // 红色,高对比度
graphics.Color(testColor, 0.0); // 完全不透明红色
graphics.Circle(testCenter, new Vector3D(0, 0, 1), testRadius, true); // 实心圆
LogManager.WriteLog($"[测试圆形] 绘制测试大圆: 中心({testCenter.X:F2}, {testCenter.Y:F2}, {testCenter.Z:F2}), 半径={testRadius:F2}, 颜色=红色");
lock (_lockObject)
{
if (_circleMarkers.Count > 0)
{
LogManager.WriteLog($"[圆形渲染] 开始渲染 {_circleMarkers.Count} 个圆形标记");
}
// 遍历所有圆形标记并绘制
foreach (var marker in _circleMarkers)
{
// 设置颜色和透明度
graphics.Color(marker.Color, marker.Transparency);
// 绘制圆形标记
graphics.Circle(marker.Center, marker.Normal, marker.Radius, marker.Filled);
LogManager.WriteLog($"[圆形渲染] 绘制圆形: 中心({marker.Center.X:F2}, {marker.Center.Y:F2}, {marker.Center.Z:F2}), 半径={marker.Radius:F2}, 序号={marker.SequenceNumber}");
}
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[圆形渲染] 渲染错误: {ex.Message}");
LogManager.WriteLog($"[圆形渲染] 异常堆栈: {ex.StackTrace}");
}
}
/// <summary>
/// 添加圆形标记
/// </summary>
/// <param name="center">圆心位置</param>
/// <param name="pointType">路径点类型</param>
/// <param name="sequenceNumber">序号</param>
public void AddCircleMarker(Point3D center, PathPointType pointType, int sequenceNumber)
{
try
{
var marker = new CircleMarker
{
Center = center,
Normal = new Vector3D(0, 0, 1), // 垂直向上
Radius = GetRadiusForPointType(pointType),
Color = GetColorForPointType(pointType),
Transparency = 0.0, // 完全不透明,更容易看见
Filled = true, // 实心圆
PointType = pointType,
SequenceNumber = sequenceNumber,
CreatedTime = DateTime.Now
};
lock (_lockObject)
{
_circleMarkers.Add(marker);
}
LogManager.WriteLog($"[圆形标记] 添加圆形标记: 类型={pointType}, 序号={sequenceNumber}, 中心=({center.X:F2}, {center.Y:F2}, {center.Z:F2})");
// 触发视图刷新
RequestViewRefresh();
}
catch (Exception ex)
{
LogManager.WriteLog($"[圆形标记] 添加标记失败: {ex.Message}");
}
}
/// <summary>
/// 移除指定位置的圆形标记
/// </summary>
/// <param name="position">位置</param>
/// <param name="tolerance">容差距离(米)</param>
/// <returns>是否成功移除</returns>
public bool RemoveMarkerAt(Point3D position, double tolerance = 1.0)
{
bool removed = false;
try
{
lock (_lockObject)
{
for (int i = _circleMarkers.Count - 1; i >= 0; i--)
{
var marker = _circleMarkers[i];
var distance = CalculateDistance(marker.Center, position);
if (distance <= tolerance)
{
_circleMarkers.RemoveAt(i);
removed = true;
LogManager.WriteLog($"[圆形标记] 移除标记: 序号={marker.SequenceNumber}, 距离={distance:F2}m");
}
}
}
if (removed)
{
RequestViewRefresh();
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[圆形标记] 移除标记失败: {ex.Message}");
}
return removed;
}
/// <summary>
/// 清除所有圆形标记
/// </summary>
public void ClearAllMarkers()
{
try
{
int removedCount = 0;
lock (_lockObject)
{
removedCount = _circleMarkers.Count;
_circleMarkers.Clear();
}
LogManager.WriteLog($"[圆形标记] 清除所有标记,共移除 {removedCount} 个圆形标记");
if (removedCount > 0)
{
RequestViewRefresh();
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[圆形标记] 清除标记失败: {ex.Message}");
}
}
/// <summary>
/// 获取所有标记的副本
/// </summary>
/// <returns>标记列表</returns>
public List<CircleMarker> GetAllMarkers()
{
lock (_lockObject)
{
return new List<CircleMarker>(_circleMarkers);
}
}
#region
/// <summary>
/// 根据路径点类型和真实文档单位获取适当的半径
/// 目标路径点半径为0.5米物理尺寸,起点/终点为0.8米物理尺寸
/// </summary>
private double GetRadiusForPointType(PathPointType pointType)
{
// 基础半径(米为单位)
double baseRadiusInMeters = pointType == PathPointType.WayPoint ? 0.5 : 0.8;
// 获取真实文档单位转换系数
double metersToModelUnits = GetMetersToModelUnitsConversionFactor();
// 转换为模型单位
double radiusInModelUnits = baseRadiusInMeters * metersToModelUnits;
LogManager.WriteLog($"[半径计算] 类型={pointType}, 基础半径={baseRadiusInMeters}m, 转换系数={metersToModelUnits:F2}, 最终半径={radiusInModelUnits:F2}");
return radiusInModelUnits;
}
/// <summary>
/// 获取米转换为文档单位的转换系数
/// 使用Navisworks API直接获取真实文档单位而不是猜测
/// </summary>
private double GetMetersToModelUnitsConversionFactor()
{
try
{
var units = Application.ActiveDocument.Units;
LogManager.WriteLog($"[单位检测] API返回的文档单位: {units}");
switch (units)
{
case Units.Millimeters:
LogManager.WriteLog("[单位检测] 确认为毫米单位,转换系数=1000");
return 1000.0; // 1米 = 1000毫米
case Units.Centimeters:
LogManager.WriteLog("[单位检测] 确认为厘米单位,转换系数=100");
return 100.0; // 1米 = 100厘米
case Units.Meters:
LogManager.WriteLog("[单位检测] 确认为米单位,转换系数=1");
return 1.0; // 1米 = 1米
case Units.Inches:
LogManager.WriteLog("[单位检测] 确认为英寸单位,转换系数=39.37");
return 39.37; // 1米 = 39.37英寸
case Units.Feet:
LogManager.WriteLog("[单位检测] 确认为英尺单位,转换系数=3.281");
return 3.281; // 1米 = 3.281英尺
case Units.Kilometers:
LogManager.WriteLog("[单位检测] 确认为公里单位,转换系数=0.001");
return 0.001; // 1米 = 0.001公里
case Units.Micrometers:
LogManager.WriteLog("[单位检测] 确认为微米单位,转换系数=1000000");
return 1000000.0; // 1米 = 1000000微米
case Units.Microinches:
LogManager.WriteLog("[单位检测] 确认为微英寸单位,转换系数=39370078.74");
return 39370078.74; // 1米 = 39370078.74微英寸
case Units.Mils:
LogManager.WriteLog("[单位检测] 确认为密尔单位,转换系数=39370.08");
return 39370.08; // 1米 = 39370.08密尔
case Units.Yards:
LogManager.WriteLog("[单位检测] 确认为码单位,转换系数=1.094");
return 1.094; // 1米 = 1.094码
case Units.Miles:
LogManager.WriteLog("[单位检测] 确认为英里单位,转换系数=0.000621");
return 0.000621; // 1米 = 0.000621英里
default:
LogManager.WriteLog($"[单位检测] 未知单位类型: {units},使用默认米单位,转换系数=1");
return 1.0;
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[单位检测] API调用失败: {ex.Message}");
LogManager.WriteLog("[单位检测] 使用默认米单位,转换系数=1");
return 1.0;
}
}
/// <summary>
/// 根据路径点类型获取颜色
/// </summary>
private Color GetColorForPointType(PathPointType pointType)
{
switch (pointType)
{
case PathPointType.StartPoint:
return Color.Green; // 起点绿色
case PathPointType.EndPoint:
return Color.Red; // 终点红色
case PathPointType.WayPoint:
default:
return new Color(1.0, 0.0, 1.0); // 路径点洋红色RGB(1,0,1) - 高对比度避免与蓝色通道冲突
}
}
/// <summary>
/// 计算两点间距离
/// </summary>
private double CalculateDistance(Point3D point1, Point3D point2)
{
var dx = point1.X - point2.X;
var dy = point1.Y - point2.Y;
var dz = point1.Z - point2.Z;
return Math.Sqrt(dx * dx + dy * dy + dz * dz);
}
/// <summary>
/// 请求视图刷新
/// </summary>
private void RequestViewRefresh()
{
try
{
if (Application.ActiveDocument?.ActiveView != null)
{
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[圆形标记] 视图刷新失败: {ex.Message}");
}
}
#endregion
#region
/// <summary>
/// 清理资源
/// </summary>
public void CleanUp()
{
ClearAllMarkers();
}
#endregion
}
/// <summary>
/// 圆形标记数据结构
/// </summary>
public class CircleMarker
{
/// <summary>
/// 圆心坐标
/// </summary>
public Point3D Center { get; set; }
/// <summary>
/// 圆面法向量
/// </summary>
public Vector3D Normal { get; set; }
/// <summary>
/// 圆形半径
/// </summary>
public double Radius { get; set; }
/// <summary>
/// 圆形颜色
/// </summary>
public Color Color { get; set; }
/// <summary>
/// 透明度 (0.0-1.0)
/// </summary>
public double Transparency { get; set; }
/// <summary>
/// 是否填充
/// </summary>
public bool Filled { get; set; }
/// <summary>
/// 路径点类型
/// </summary>
public PathPointType PointType { get; set; }
/// <summary>
/// 序号
/// </summary>
public int SequenceNumber { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedTime { get; set; }
public override string ToString()
{
return $"CircleMarker[序号={SequenceNumber}, 类型={PointType}, 中心=({Center.X:F2},{Center.Y:F2},{Center.Z:F2}), 半径={Radius:F2}]";
}
}
}