using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Plugins;
namespace NavisworksTransport
{
///
/// 路径点圆形标记渲染插件
/// 使用Graphics.Circle在3D空间绘制圆形标记
///
[Plugin("PathPointRenderPlugin", "NavisworksTransport", DisplayName = "路径点圆形标记渲染器")]
public class PathPointRenderPlugin : RenderPlugin
{
private readonly object _lockObject = new object();
private List _circleMarkers = new List();
private bool _isEnabled = true;
// 静态实例,用于外部访问
private static PathPointRenderPlugin _instance;
///
/// 构造函数
///
public PathPointRenderPlugin()
{
_instance = this;
}
///
/// 获取静态实例
///
public static PathPointRenderPlugin Instance => _instance;
///
/// 是否启用渲染
///
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
// 触发视图刷新
if (Application.ActiveDocument?.ActiveView != null)
{
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);
}
}
}
///
/// 当前圆形标记数量
///
public int MarkerCount
{
get
{
lock (_lockObject)
{
return _circleMarkers.Count;
}
}
}
///
/// Navisworks渲染回调方法
///
/// 当前视图
/// 图形上下文
public override void Render(View view, Graphics graphics)
{
if (!_isEnabled) return;
try
{
// 首先检查文档和模型状态
var activeDoc = Application.ActiveDocument;
//LogManager.WriteLog($"[文档状态] ActiveDocument: {activeDoc?.GetType().Name ?? "null"}");
if (activeDoc == null)
{
LogManager.WriteLog($"[文档状态] ❌ 没有活动文档,跳过渲染");
return;
}
if (activeDoc.Models == null || activeDoc.Models.Count == 0)
{
LogManager.WriteLog($"[文档状态] ❌ 没有加载的模型,跳过渲染");
return;
}
//LogManager.WriteLog($"[文档状态] ✓ 文档正常,模型数量: {activeDoc.Models.Count}");
//LogManager.WriteLog($"[Graphics状态] Graphics对象: {graphics?.GetType().Name ?? "null"}");
//LogManager.WriteLog($"[Graphics状态] View对象: {view?.GetType().Name ?? "null"}");
// 使用BeginModelContext确保正确的渲染上下文
graphics.BeginModelContext();
//LogManager.WriteLog($"[Graphics状态] BeginModelContext完成");
lock (_lockObject)
{
// 绘制连接线段(作为圆柱体)
if (_circleMarkers.Count > 1)
{
graphics.Color(Color.FromByteRGB(0, 0, 0), 1.0); // 黑色连线
// 定义连线的物理半径(例如:20厘米)
double lineRadiusInMeters = 0.2;
double lineRadiusInModelUnits = lineRadiusInMeters * GetMetersToModelUnitsConversionFactor();
for (int i = 0; i < _circleMarkers.Count - 1; i++)
{
var start = _circleMarkers[i].Center;
var end = _circleMarkers[i + 1].Center;
// 使用圆柱体来绘制具有物理尺寸的连线
graphics.Cylinder(start, end, lineRadiusInModelUnits);
}
}
// 遍历所有圆形标记并根据其自身属性绘制
foreach (var marker in _circleMarkers)
{
// 使用标记自身存储的颜色和不透明度
graphics.Color(marker.Color, marker.Alpha);
// 使用标记自身存储的半径
graphics.Sphere(marker.Center, marker.Radius);
}
}
// 结束ModelContext
graphics.EndModelContext();
//LogManager.WriteLog($"[Graphics状态] EndModelContext完成");
//LogManager.WriteLog($"[Graphics状态] === 3D渲染完成,如果仍看不到图形,问题可能在Graphics API兼容性 ===");
}
catch (Exception ex)
{
LogManager.WriteLog($"[圆形渲染] 渲染错误: {ex.Message}");
LogManager.WriteLog($"[圆形渲染] 异常堆栈: {ex.StackTrace}");
}
}
///
/// 添加球体标记
///
/// 圆心位置
/// 路径点类型
/// 序号
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),
Alpha = 1.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}");
}
}
///
/// 移除指定位置的球体标记
///
/// 位置
/// 容差距离(米)
/// 是否成功移除
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;
}
///
/// 清除所有球体标记
///
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}");
}
}
///
/// 获取所有球体标记的副本
///
/// 标记列表
public List GetAllMarkers()
{
lock (_lockObject)
{
return new List(_circleMarkers);
}
}
///
/// 根据序号更新一个已存在的球体标记
///
public void UpdateMarker(int sequenceNumber, Color newColor, double newRadius)
{
try
{
lock (_lockObject)
{
var markerToUpdate = _circleMarkers.FirstOrDefault(m => m.SequenceNumber == sequenceNumber);
if (markerToUpdate != null)
{
markerToUpdate.Color = newColor;
markerToUpdate.Radius = newRadius;
LogManager.WriteLog($"[球体标记] 更新标记: 序号={sequenceNumber}, 新颜色={newColor}, 新半径={newRadius:F2}");
RequestViewRefresh();
}
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[球体标记] 更新标记失败: {ex.Message}");
}
}
#region 私有辅助方法
///
/// 根据路径点类型和真实文档单位获取适当的半径
/// 目标:路径点半径为0.5米物理尺寸,起点/终点为0.8米物理尺寸
///
public double GetRadiusForPointType(PathPointType pointType)
{
// 基础半径(米为单位),起点和终点为0.5米,路径点为0.4米
double baseRadiusInMeters = pointType == PathPointType.WayPoint ? 0.4 : 0.5;
// 获取真实文档单位转换系数
double metersToModelUnits = GetMetersToModelUnitsConversionFactor();
// 转换为模型单位
double radiusInModelUnits = baseRadiusInMeters * metersToModelUnits;
//LogManager.WriteLog($"[半径计算] 类型={pointType}, 基础半径={baseRadiusInMeters}m, 转换系数={metersToModelUnits:F2}, 最终半径={radiusInModelUnits:F2}");
return radiusInModelUnits;
}
///
/// 获取米转换为文档单位的转换系数
/// 使用Navisworks API直接获取真实文档单位,而不是猜测
///
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;
}
}
///
/// 根据路径点类型获取颜色
///
public 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) - 高对比度避免与蓝色通道冲突
}
}
///
/// 计算两点间距离
///
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);
}
///
/// 请求视图刷新
///
private void RequestViewRefresh()
{
try
{
if (Application.ActiveDocument?.ActiveView != null)
{
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[球体标记] 视图刷新失败: {ex.Message}");
}
}
#endregion
#region 清理资源
///
/// 清理资源
///
public void CleanUp()
{
ClearAllMarkers();
}
#endregion
}
///
/// 圆形标记数据结构
///
public class CircleMarker
{
///
/// 圆心坐标
///
public Point3D Center { get; set; }
///
/// 圆面法向量
///
public Vector3D Normal { get; set; }
///
/// 圆形半径
///
public double Radius { get; set; }
///
/// 圆形颜色
///
public Color Color { get; set; }
///
/// 不透明度 (1.0 = 完全不透明, 0.0 = 完全透明)
///
public double Alpha { get; set; }
///
/// 是否填充
///
public bool Filled { get; set; }
///
/// 路径点类型
///
public PathPointType PointType { get; set; }
///
/// 序号
///
public int SequenceNumber { get; set; }
///
/// 创建时间
///
public DateTime CreatedTime { get; set; }
public override string ToString()
{
return $"CircleMarker[序号={SequenceNumber}, 类型={PointType}, 中心=({Center.X:F2},{Center.Y:F2},{Center.Z:F2}), 半径={Radius:F2}]";
}
}
}