1004 lines
35 KiB
C#
1004 lines
35 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using Autodesk.Navisworks.Api;
|
||
using Autodesk.Navisworks.Api.Plugins;
|
||
using NavisworksTransport.Core;
|
||
|
||
namespace NavisworksTransport
|
||
{
|
||
/// <summary>
|
||
/// 连线标记,用于渲染路径点之间的连接线
|
||
/// </summary>
|
||
public class LineMarker
|
||
{
|
||
/// <summary>
|
||
/// 连线起点
|
||
/// </summary>
|
||
public Point3D StartPoint { get; set; }
|
||
|
||
/// <summary>
|
||
/// 连线终点
|
||
/// </summary>
|
||
public Point3D EndPoint { get; set; }
|
||
|
||
/// <summary>
|
||
/// 连线颜色
|
||
/// </summary>
|
||
public Color Color { get; set; }
|
||
|
||
/// <summary>
|
||
/// 连线半径
|
||
/// </summary>
|
||
public double Radius { get; set; }
|
||
|
||
/// <summary>
|
||
/// 起点在路径中的索引
|
||
/// </summary>
|
||
public int FromIndex { get; set; }
|
||
|
||
/// <summary>
|
||
/// 终点在路径中的索引
|
||
/// </summary>
|
||
public int ToIndex { get; set; }
|
||
|
||
public override string ToString()
|
||
{
|
||
return $"LineMarker[{FromIndex}->{ToIndex}, 起点=({StartPoint.X:F2},{StartPoint.Y:F2},{StartPoint.Z:F2}), 终点=({EndPoint.X:F2},{EndPoint.Y:F2},{EndPoint.Z:F2})]";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 路径可视化数据,包含一个完整路径的所有可视化元素
|
||
/// </summary>
|
||
public class PathVisualization
|
||
{
|
||
/// <summary>
|
||
/// 路径唯一标识
|
||
/// </summary>
|
||
public string PathId { get; set; }
|
||
|
||
/// <summary>
|
||
/// 路径数据引用
|
||
/// </summary>
|
||
public PathRoute PathRoute { get; set; }
|
||
|
||
/// <summary>
|
||
/// 点标记集合
|
||
/// </summary>
|
||
public List<CircleMarker> PointMarkers { get; set; }
|
||
|
||
/// <summary>
|
||
/// 连线标记集合
|
||
/// </summary>
|
||
public List<LineMarker> LineMarkers { get; set; }
|
||
|
||
/// <summary>
|
||
/// 最后更新时间
|
||
/// </summary>
|
||
public DateTime LastUpdated { get; set; }
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
public PathVisualization()
|
||
{
|
||
PointMarkers = new List<CircleMarker>();
|
||
LineMarkers = new List<LineMarker>();
|
||
LastUpdated = DateTime.Now;
|
||
}
|
||
|
||
public override string ToString()
|
||
{
|
||
return $"PathVisualization[PathId={PathId}, 点数={PointMarkers.Count}, 连线数={LineMarkers.Count}]";
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 路径点圆形标记渲染插件
|
||
/// 使用Graphics.Circle在3D空间绘制圆形标记
|
||
/// </summary>
|
||
[Plugin("PathPointRenderPlugin", "NavisworksTransport", DisplayName = "路径点圆形标记渲染器")]
|
||
public class PathPointRenderPlugin : RenderPlugin
|
||
{
|
||
private readonly object _lockObject = new object();
|
||
private Dictionary<string, PathVisualization> _pathVisualizations = new Dictionary<string, PathVisualization>();
|
||
private bool _isEnabled = true;
|
||
|
||
// 为向后兼容保留的旧字段
|
||
private List<CircleMarker> _circleMarkers = new List<CircleMarker>();
|
||
|
||
// 静态实例,用于外部访问
|
||
private static PathPointRenderPlugin _instance;
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
public PathPointRenderPlugin()
|
||
{
|
||
_instance = this;
|
||
}
|
||
|
||
/// <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 PathCount
|
||
{
|
||
get
|
||
{
|
||
lock (_lockObject)
|
||
{
|
||
return _pathVisualizations.Count;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前点标记总数
|
||
/// </summary>
|
||
public int MarkerCount
|
||
{
|
||
get
|
||
{
|
||
lock (_lockObject)
|
||
{
|
||
return _pathVisualizations.Values.Sum(v => v.PointMarkers.Count);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Navisworks渲染回调方法
|
||
/// </summary>
|
||
/// <param name="view">当前视图</param>
|
||
/// <param name="graphics">图形上下文</param>
|
||
public override void Render(View view, Graphics graphics)
|
||
{
|
||
if (!_isEnabled) return;
|
||
|
||
try
|
||
{
|
||
// 快速检查,避免频繁的API调用
|
||
var activeDoc = Application.ActiveDocument;
|
||
if (activeDoc?.Models == null || activeDoc.Models.Count == 0)
|
||
{
|
||
return; // 静默返回,避免日志泛滥
|
||
}
|
||
|
||
// 检查是否有路径需要渲染
|
||
int pathCount;
|
||
lock (_lockObject)
|
||
{
|
||
pathCount = _pathVisualizations.Count;
|
||
}
|
||
|
||
if (pathCount == 0) return;
|
||
|
||
// 使用BeginModelContext确保正确的渲染上下文
|
||
graphics.BeginModelContext();
|
||
|
||
lock (_lockObject)
|
||
{
|
||
foreach (var visualization in _pathVisualizations.Values)
|
||
{
|
||
// 渲染所有点标记
|
||
foreach (var pointMarker in visualization.PointMarkers)
|
||
{
|
||
graphics.Color(pointMarker.Color, pointMarker.Alpha);
|
||
graphics.Sphere(pointMarker.Center, pointMarker.Radius);
|
||
}
|
||
|
||
// 渲染所有连线
|
||
LogManager.WriteLog($"[渲染连线] 路径 {visualization.PathId} 有 {visualization.LineMarkers.Count} 条连线");
|
||
foreach (var lineMarker in visualization.LineMarkers)
|
||
{
|
||
graphics.Color(lineMarker.Color, 1.0);
|
||
graphics.Cylinder(lineMarker.StartPoint, lineMarker.EndPoint, lineMarker.Radius);
|
||
LogManager.WriteLog($"[渲染连线] 绘制连线 {lineMarker.FromIndex}->{lineMarker.ToIndex}, 半径={lineMarker.Radius:F3}");
|
||
}
|
||
}
|
||
}
|
||
|
||
graphics.EndModelContext();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 渲染异常应该静默处理,避免影响Navisworks主程序
|
||
LogManager.WriteLog($"[渲染异常] {ex.Message}");
|
||
// 不输出堆栈信息,避免日志过量
|
||
}
|
||
}
|
||
|
||
#region 新的统一路径可视化接口
|
||
|
||
/// <summary>
|
||
/// 渲染完整路径
|
||
/// </summary>
|
||
/// <param name="pathRoute">路径数据</param>
|
||
public void RenderPath(PathRoute pathRoute)
|
||
{
|
||
if (pathRoute == null)
|
||
{
|
||
LogManager.WriteLog("[路径渲染] 路径数据为空");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var visualization = new PathVisualization
|
||
{
|
||
PathId = pathRoute.Id,
|
||
PathRoute = pathRoute
|
||
};
|
||
|
||
BuildVisualization(visualization);
|
||
|
||
lock (_lockObject)
|
||
{
|
||
_pathVisualizations[pathRoute.Id] = visualization;
|
||
}
|
||
|
||
LogManager.WriteLog($"[路径渲染] 渲染路径: {pathRoute.Name}, 点数: {pathRoute.Points.Count}");
|
||
RequestViewRefresh();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[路径渲染] 渲染路径失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 只渲染点标记,不绘制连线(用于自动路径规划的起终点显示)
|
||
/// </summary>
|
||
public void RenderPointOnly(PathRoute pathRoute)
|
||
{
|
||
if (pathRoute == null)
|
||
{
|
||
LogManager.WriteLog("[点标记渲染] 路径数据为空");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var visualization = new PathVisualization
|
||
{
|
||
PathId = pathRoute.Id,
|
||
PathRoute = pathRoute
|
||
};
|
||
|
||
// 只构建点标记,不构建连线
|
||
BuildPointMarkersOnly(visualization);
|
||
|
||
lock (_lockObject)
|
||
{
|
||
_pathVisualizations[pathRoute.Id] = visualization;
|
||
}
|
||
|
||
LogManager.WriteLog($"[点标记渲染] 渲染点标记: {pathRoute.Name}, 点数: {pathRoute.Points.Count}");
|
||
RequestViewRefresh();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[点标记渲染] 渲染点标记失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 只构建点标记,不构建连线
|
||
/// </summary>
|
||
private void BuildPointMarkersOnly(PathVisualization visualization)
|
||
{
|
||
// 清空现有标记
|
||
visualization.PointMarkers.Clear();
|
||
visualization.LineMarkers.Clear(); // 确保没有连线
|
||
|
||
var points = visualization.PathRoute.Points;
|
||
if (points.Count == 0) return;
|
||
|
||
// 按索引排序点
|
||
var sortedPoints = points.OrderBy(p => p.Index).ToList();
|
||
|
||
// 只构建点标记,不构建连线
|
||
foreach (var point in sortedPoints)
|
||
{
|
||
var pointMarker = CreatePointMarker(point);
|
||
visualization.PointMarkers.Add(pointMarker);
|
||
}
|
||
|
||
visualization.LastUpdated = DateTime.Now;
|
||
LogManager.WriteLog($"[点标记构建] 已构建 {visualization.PointMarkers.Count} 个点标记,无连线");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刷新路径可视化
|
||
/// </summary>
|
||
/// <param name="pathId">路径ID</param>
|
||
public void RefreshPath(string pathId)
|
||
{
|
||
lock (_lockObject)
|
||
{
|
||
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
|
||
{
|
||
BuildVisualization(visualization);
|
||
LogManager.WriteLog($"[路径刷新] 刷新路径: {pathId}");
|
||
RequestViewRefresh();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除路径
|
||
/// </summary>
|
||
/// <param name="pathId">路径ID</param>
|
||
public void RemovePath(string pathId)
|
||
{
|
||
lock (_lockObject)
|
||
{
|
||
if (_pathVisualizations.Remove(pathId))
|
||
{
|
||
LogManager.WriteLog($"[路径移除] 移除路径: {pathId}");
|
||
RequestViewRefresh();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空所有路径
|
||
/// </summary>
|
||
public void ClearAllPaths()
|
||
{
|
||
lock (_lockObject)
|
||
{
|
||
var count = _pathVisualizations.Count;
|
||
_pathVisualizations.Clear();
|
||
LogManager.WriteLog($"[路径清空] 清空所有路径,共{count}个");
|
||
RequestViewRefresh();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建路径可视化
|
||
/// </summary>
|
||
/// <param name="visualization">路径可视化对象</param>
|
||
private void BuildVisualization(PathVisualization visualization)
|
||
{
|
||
// 清空现有标记
|
||
visualization.PointMarkers.Clear();
|
||
visualization.LineMarkers.Clear();
|
||
|
||
var points = visualization.PathRoute.Points;
|
||
if (points.Count == 0) return;
|
||
|
||
// 按索引排序点
|
||
var sortedPoints = points.OrderBy(p => p.Index).ToList();
|
||
|
||
// 构建点标记
|
||
foreach (var point in sortedPoints)
|
||
{
|
||
var pointMarker = CreatePointMarker(point);
|
||
visualization.PointMarkers.Add(pointMarker);
|
||
}
|
||
|
||
// 构建连线标记(按排序后的顺序连接)
|
||
for (int i = 0; i < sortedPoints.Count - 1; i++)
|
||
{
|
||
var currentPoint = sortedPoints[i];
|
||
var nextPoint = sortedPoints[i + 1];
|
||
|
||
var lineMarker = new LineMarker
|
||
{
|
||
StartPoint = currentPoint.Position,
|
||
EndPoint = nextPoint.Position,
|
||
Color = GetLineColor(),
|
||
Radius = GetLineRadius(),
|
||
FromIndex = currentPoint.Index,
|
||
ToIndex = nextPoint.Index
|
||
};
|
||
visualization.LineMarkers.Add(lineMarker);
|
||
|
||
LogManager.WriteLog($"[连线构建] 创建连线: {currentPoint.Index} -> {nextPoint.Index}, " +
|
||
$"起点({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2}) -> " +
|
||
$"终点({nextPoint.Position.X:F2}, {nextPoint.Position.Y:F2}, {nextPoint.Position.Z:F2})");
|
||
}
|
||
|
||
visualization.LastUpdated = DateTime.Now;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建点标记
|
||
/// </summary>
|
||
/// <param name="point">路径点</param>
|
||
/// <returns>圆形标记</returns>
|
||
private CircleMarker CreatePointMarker(PathPoint point)
|
||
{
|
||
return new CircleMarker
|
||
{
|
||
Center = point.Position,
|
||
Normal = new Vector3D(0, 0, 1),
|
||
Radius = GetRadiusForPointType(point.Type),
|
||
Color = GetColorForPointType(point.Type),
|
||
Alpha = 1.0,
|
||
Filled = true,
|
||
PointType = point.Type,
|
||
SequenceNumber = point.Index, // 使用Index而不是任意序号
|
||
CreatedTime = DateTime.Now
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取连线颜色(统一使用橙色)
|
||
/// </summary>
|
||
/// <returns>连线颜色</returns>
|
||
private Color GetLineColor()
|
||
{
|
||
return Color.FromByteRGB(255, 165, 0); // 统一使用橙色连线
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取连线半径
|
||
/// </summary>
|
||
/// <returns>连线半径</returns>
|
||
private double GetLineRadius()
|
||
{
|
||
double lineRadiusInMeters = 0.2;
|
||
return lineRadiusInMeters * GetMetersToModelUnitsConversionFactor();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加路径点到指定路径
|
||
/// </summary>
|
||
/// <param name="pathId">路径ID</param>
|
||
/// <param name="newPoint">新的路径点</param>
|
||
/// <param name="insertIndex">插入位置索引,-1表示添加到末尾</param>
|
||
public void AddPointToPath(string pathId, PathPoint newPoint, int insertIndex = -1)
|
||
{
|
||
var visualization = GetPathVisualization(pathId);
|
||
if (visualization == null)
|
||
{
|
||
LogManager.WriteLog($"[路径编辑] 未找到路径: {pathId}");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var pathRoute = visualization.PathRoute;
|
||
|
||
if (insertIndex == -1)
|
||
{
|
||
// 添加到末尾
|
||
newPoint.Index = pathRoute.Points.Count;
|
||
pathRoute.Points.Add(newPoint);
|
||
}
|
||
else
|
||
{
|
||
// 插入到指定位置
|
||
pathRoute.Points.Insert(insertIndex, newPoint);
|
||
// 重新分配所有点的索引
|
||
ReindexPoints(pathRoute);
|
||
}
|
||
|
||
// 重建可视化
|
||
BuildVisualization(visualization);
|
||
LogManager.WriteLog($"[路径编辑] 添加路径点: {newPoint.Name} 到路径 {pathId}");
|
||
RequestViewRefresh();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[路径编辑] 添加路径点失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从指定路径移除路径点
|
||
/// </summary>
|
||
/// <param name="pathId">路径ID</param>
|
||
/// <param name="pointIndex">要移除的点索引</param>
|
||
public void RemovePointFromPath(string pathId, int pointIndex)
|
||
{
|
||
var visualization = GetPathVisualization(pathId);
|
||
if (visualization == null)
|
||
{
|
||
LogManager.WriteLog($"[路径编辑] 未找到路径: {pathId}");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var pathRoute = visualization.PathRoute;
|
||
var pointToRemove = pathRoute.Points.FirstOrDefault(p => p.Index == pointIndex);
|
||
|
||
if (pointToRemove != null)
|
||
{
|
||
pathRoute.Points.Remove(pointToRemove);
|
||
// 重新分配索引
|
||
ReindexPoints(pathRoute);
|
||
|
||
// 重建可视化
|
||
BuildVisualization(visualization);
|
||
LogManager.WriteLog($"[路径编辑] 移除路径点: 索引 {pointIndex} 从路径 {pathId}");
|
||
RequestViewRefresh();
|
||
}
|
||
else
|
||
{
|
||
LogManager.WriteLog($"[路径编辑] 未找到索引为 {pointIndex} 的路径点");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[路径编辑] 移除路径点失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新指定路径中的路径点
|
||
/// </summary>
|
||
/// <param name="pathId">路径ID</param>
|
||
/// <param name="pointIndex">要更新的点索引</param>
|
||
/// <param name="updatedPoint">更新后的路径点</param>
|
||
public void UpdatePointInPath(string pathId, int pointIndex, PathPoint updatedPoint)
|
||
{
|
||
var visualization = GetPathVisualization(pathId);
|
||
if (visualization == null)
|
||
{
|
||
LogManager.WriteLog($"[路径编辑] 未找到路径: {pathId}");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
var pathRoute = visualization.PathRoute;
|
||
var existingPoint = pathRoute.Points.FirstOrDefault(p => p.Index == pointIndex);
|
||
|
||
if (existingPoint != null)
|
||
{
|
||
// 保持索引不变
|
||
updatedPoint.Index = pointIndex;
|
||
|
||
// 替换点
|
||
var index = pathRoute.Points.IndexOf(existingPoint);
|
||
pathRoute.Points[index] = updatedPoint;
|
||
|
||
// 重建可视化
|
||
BuildVisualization(visualization);
|
||
LogManager.WriteLog($"[路径编辑] 更新路径点: 索引 {pointIndex} 在路径 {pathId}");
|
||
RequestViewRefresh();
|
||
}
|
||
else
|
||
{
|
||
LogManager.WriteLog($"[路径编辑] 未找到索引为 {pointIndex} 的路径点");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[路径编辑] 更新路径点失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重新分配路径点索引
|
||
/// </summary>
|
||
/// <param name="pathRoute">路径对象</param>
|
||
private void ReindexPoints(PathRoute pathRoute)
|
||
{
|
||
// 按照当前在List中的位置重新分配连续索引
|
||
for (int i = 0; i < pathRoute.Points.Count; i++)
|
||
{
|
||
pathRoute.Points[i].Index = i;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取路径可视化对象
|
||
/// </summary>
|
||
/// <param name="pathId">路径ID</param>
|
||
/// <returns>路径可视化对象,如果不存在返回null</returns>
|
||
private PathVisualization GetPathVisualization(string pathId)
|
||
{
|
||
lock (_lockObject)
|
||
{
|
||
_pathVisualizations.TryGetValue(pathId, out var visualization);
|
||
return visualization;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 向后兼容的旧接口(保留以避免编译错误)
|
||
|
||
/// <summary>
|
||
/// [已过时] 添加球体标记 - 请使用RenderPath方法代替
|
||
/// </summary>
|
||
/// <param name="center">圆心位置</param>
|
||
/// <param name="pointType">路径点类型</param>
|
||
/// <param name="sequenceNumber">序号</param>
|
||
[Obsolete("此方法已过时,请使用RenderPath方法进行统一的路径可视化", false)]
|
||
public void AddCircleMarker(Point3D center, PathPointType pointType, int sequenceNumber)
|
||
{
|
||
LogManager.WriteLog($"[兼容性警告] 使用了已过时的AddCircleMarker方法,建议使用RenderPath方法");
|
||
|
||
try
|
||
{
|
||
// 为了兼容性,创建一个临时路径
|
||
var tempPath = new PathRoute($"TempPath_{Guid.NewGuid().ToString("N").Substring(0, 8)}")
|
||
{
|
||
Id = $"temp_{sequenceNumber}_{DateTime.Now.Ticks}"
|
||
};
|
||
|
||
var pathPoint = new PathPoint(center, $"Point_{sequenceNumber}", pointType)
|
||
{
|
||
Index = 0
|
||
};
|
||
tempPath.Points.Add(pathPoint);
|
||
|
||
// 使用新的渲染方法
|
||
RenderPath(tempPath);
|
||
}
|
||
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>
|
||
/// [已过时] 清除所有球体标记 - 请使用ClearAllPaths方法代替
|
||
/// </summary>
|
||
[Obsolete("此方法已过时,请使用ClearAllPaths方法", false)]
|
||
public void ClearAllMarkers()
|
||
{
|
||
LogManager.WriteLog($"[兼容性警告] 使用了已过时的ClearAllMarkers方法,建议使用ClearAllPaths方法");
|
||
ClearAllPaths();
|
||
}
|
||
|
||
/// <summary>
|
||
/// [已过时] 清除所有自动路径标记 - 请使用ClearAllPaths方法代替
|
||
/// </summary>
|
||
[Obsolete("此方法已过时,请使用ClearAllPaths方法", false)]
|
||
public void ClearAutoPathMarkers()
|
||
{
|
||
LogManager.WriteLog($"[兼容性警告] 使用了已过时的ClearAutoPathMarkers方法,建议使用ClearAllPaths方法");
|
||
ClearAllPaths();
|
||
}
|
||
|
||
/// <summary>
|
||
/// [已过时] 清除手动路径标记 - 请使用ClearAllPaths方法代替
|
||
/// </summary>
|
||
[Obsolete("此方法已过时,请使用ClearAllPaths方法", false)]
|
||
public void ClearManualPathMarkers()
|
||
{
|
||
LogManager.WriteLog($"[兼容性警告] 使用了已过时的ClearManualPathMarkers方法,建议使用ClearAllPaths方法");
|
||
ClearAllPaths();
|
||
}
|
||
|
||
/// <summary>
|
||
/// [已过时] 获取所有球体标记的副本 - 此方法不再适用于新的路径系统
|
||
/// </summary>
|
||
/// <returns>空列表</returns>
|
||
[Obsolete("此方法已过时,新的路径系统不使用独立的标记概念", false)]
|
||
public List<CircleMarker> GetAllMarkers()
|
||
{
|
||
LogManager.WriteLog($"[兼容性警告] 使用了已过时的GetAllMarkers方法,新系统不再支持独立标记");
|
||
return new List<CircleMarker>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// [已过时] 根据序号更新一个已存在的球体标记 - 请使用UpdatePointInPath方法代替
|
||
/// </summary>
|
||
[Obsolete("此方法已过时,请使用UpdatePointInPath方法更新路径中的点", false)]
|
||
public void UpdateMarker(int sequenceNumber, Color newColor, double newRadius)
|
||
{
|
||
LogManager.WriteLog($"[兼容性警告] 使用了已过时的UpdateMarker方法,请使用UpdatePointInPath方法");
|
||
// 由于新系统没有直接的序号对应关系,这个方法不再有效
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 私有辅助方法
|
||
|
||
/// <summary>
|
||
/// 根据路径点类型和真实文档单位获取适当的半径
|
||
/// 目标:路径点半径为0.5米物理尺寸,起点/终点为0.8米物理尺寸
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <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>
|
||
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) - 高对比度避免与蓝色通道冲突
|
||
}
|
||
}
|
||
|
||
/// <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
|
||
{
|
||
// 使用静态变量实现简单的防抖机制
|
||
var now = DateTime.Now;
|
||
if ((now - _lastRefreshTime).TotalMilliseconds < 50) // 最小间隔50ms
|
||
{
|
||
return; // 忽略过于频繁的刷新请求
|
||
}
|
||
_lastRefreshTime = now;
|
||
|
||
if (Application.ActiveDocument?.ActiveView != null)
|
||
{
|
||
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[视图刷新] 失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private static DateTime _lastRefreshTime = DateTime.MinValue;
|
||
|
||
#endregion
|
||
|
||
#region 兼容性方法
|
||
|
||
/// <summary>
|
||
/// 清除路径标记(兼容性方法)
|
||
/// </summary>
|
||
public void ClearPathMarkers()
|
||
{
|
||
ClearAllMarkers();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除路径点标记(兼容性方法)
|
||
/// </summary>
|
||
/// <param name="pathPoint">路径点</param>
|
||
/// <returns>是否成功移除</returns>
|
||
public bool RemovePathPointMarker(PathPoint pathPoint)
|
||
{
|
||
if (pathPoint?.Position != null)
|
||
{
|
||
return RemoveMarkerAt(pathPoint.Position, 1.0);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除路径点标记(兼容性方法)
|
||
/// </summary>
|
||
/// <param name="marker">路径点标记</param>
|
||
/// <returns>是否成功移除</returns>
|
||
public bool RemovePathPointMarker(PathPointMarker marker)
|
||
{
|
||
if (marker?.PathPoint?.Position != null)
|
||
{
|
||
return RemoveMarkerAt(marker.PathPoint.Position, 1.0);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
#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>
|
||
/// 不透明度 (1.0 = 完全不透明, 0.0 = 完全透明)
|
||
/// </summary>
|
||
public double Alpha { 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}]";
|
||
}
|
||
}
|
||
} |