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}]"; } } }