using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Plugins;
using NavisworksTransport.Utils;
namespace NavisworksTransport
{
///
/// 路径可视化模式枚举
///
public enum PathVisualizationMode
{
///
/// 标准连线模式 - 圆柱形连线
///
StandardLine,
///
/// 车辆通行空间模式 - 矩形通道
///
VehicleSpace
}
///
/// 网格点类型枚举
///
public enum GridPointType
{
///
/// 球形
///
Sphere,
///
/// 正方形
///
Rectangle,
///
/// 圆
///
Circle
}
///
/// 渲染颜色类型枚举
///
public enum RenderColorType
{
///
/// 路径起点颜色(绿色)
///
StartPoint,
///
/// 路径终点颜色(红色)
///
EndPoint,
///
/// 路径中间点颜色(洋红色)
///
WayPoint,
///
/// 连线颜色(橙色)
///
Line,
///
/// 车辆通行空间颜色(淡蓝色亚克力)
///
VehicleSpace,
///
/// 预览点颜色(白色)
///
PreviewPoint,
///
/// 预览连线颜色(灰色)
///
PreviewLine,
///
/// 未到达终点颜色(深红色)
///
UnreachedEndPoint,
///
/// 网格通道颜色(绿色)
///
GridChannel,
///
/// 网格障碍物颜色(灰色)
///
GridObstacle,
///
/// 网格未知区域颜色(红色)
///
GridUnknown
}
///
/// 渲染样式,包含颜色和透明度
///
public struct RenderStyle
{
///
/// 颜色
///
public Color Color { get; }
///
/// 透明度 (0.0 = 完全透明, 1.0 = 完全不透明)
///
public double Alpha { get; }
///
/// 构造函数
///
/// 颜色
/// 透明度
public RenderStyle(Color color, double alpha)
{
Color = color;
Alpha = alpha;
}
public override string ToString()
{
return $"RenderStyle[Color={Color}, Alpha={Alpha:F2}]";
}
}
///
/// 车辆通行空间标记,用于渲染车辆通道空间
///
public class VehicleSpaceMarker
{
///
/// 通道起点
///
public Point3D StartPoint { get; set; }
///
/// 通道终点
///
public Point3D EndPoint { get; set; }
///
/// 通道宽度(车辆长宽最大值+2倍安全间隙)
///
public double Width { get; set; }
///
/// 通道高度(车辆高度+安全间隙)
///
public double Height { get; set; }
///
/// 通道颜色
///
public Color Color { get; set; }
///
/// 透明度(0.0-1.0,默认0.5即50%透明)
///
public double Alpha { get; set; } = 0.5;
///
/// 起点在路径中的索引
///
public int FromIndex { get; set; }
///
/// 终点在路径中的索引
///
public int ToIndex { get; set; }
public override string ToString()
{
return $"VehicleSpaceMarker[{FromIndex}->{ToIndex}, 宽度={Width:F2}m, 高度={Height:F2}m, 透明度={Alpha:F1}]";
}
}
///
/// 连线标记,用于渲染路径点之间的连接线
///
public class LineMarker
{
///
/// 连线起点
///
public Point3D StartPoint { get; set; }
///
/// 连线终点
///
public Point3D EndPoint { get; set; }
///
/// 连线颜色
///
public Color Color { get; set; }
///
/// 连线半径
///
public double Radius { get; set; }
///
/// 起点在路径中的索引
///
public int FromIndex { get; set; }
///
/// 终点在路径中的索引
///
public int ToIndex { get; set; }
///
/// 路径段类型
///
public PathSegmentType SegmentType { get; set; } = PathSegmentType.Straight;
///
/// 圆弧轨迹数据(仅当SegmentType=Arc时有效)
///
public ArcTrajectory Trajectory { get; set; }
///
/// 采样点列表(用于圆弧段的多段圆柱体渲染)
///
public List SampledPoints { get; set; }
public override string ToString()
{
return $"LineMarker[{FromIndex}->{ToIndex}, 类型={SegmentType}, 起点=({StartPoint.X:F2},{StartPoint.Y:F2},{StartPoint.Z:F2}), 终点=({EndPoint.X:F2},{EndPoint.Y:F2},{EndPoint.Z:F2})]";
}
}
///
/// 路径可视化数据,包含一个完整路径的所有可视化元素
///
public class PathVisualization
{
///
/// 路径唯一标识
///
public string PathId { get; set; }
///
/// 路径数据引用
///
public PathRoute PathRoute { get; set; }
///
/// 点标记集合
///
public List PointMarkers { get; set; }
///
/// 连线标记集合(已废弃,保留用于兼容)
///
[Obsolete("使用ControlLineMarkers或PathLineMarkers代替")]
public List LineMarkers { get; set; }
///
/// 控制点连线集合(用户意图,半透明)
///
public List ControlLineMarkers { get; set; }
///
/// 路径连线集合(真实路径,不透明)
///
public List PathLineMarkers { get; set; }
///
/// 切点标记集合
///
public List TangentMarkers { get; set; }
///
/// 车辆通行空间标记集合
///
public List VehicleSpaceMarkers { get; set; }
///
/// 是否显示控制点可视化(用户意图)
///
public bool ShowControlVisualization { get; set; } = true;
///
/// 最后更新时间
///
public DateTime LastUpdated { get; set; }
///
/// 构造函数
///
public PathVisualization()
{
PointMarkers = new List();
LineMarkers = new List();
ControlLineMarkers = new List();
PathLineMarkers = new List();
TangentMarkers = new List();
VehicleSpaceMarkers = new List();
LastUpdated = DateTime.Now;
}
public override string ToString()
{
return $"PathVisualization[PathId={PathId}, 点数={PointMarkers.Count}, 控制连线={ControlLineMarkers.Count}, 路径连线={PathLineMarkers.Count}]";
}
}
///
/// 路径点圆形标记渲染插件
/// 使用Graphics.Circle在3D空间绘制圆形标记
///
[Plugin("PathPointRenderPlugin", "NavisworksTransport", DisplayName = "路径点圆形标记渲染器")]
public class PathPointRenderPlugin : RenderPlugin
{
private readonly object _lockObject = new object();
private Dictionary _pathVisualizations = new Dictionary();
private bool _isEnabled = true;
// 预览点标记
private CircleMarker _previewMarker = null;
// 预览连线标记
private List _previewLines = new List();
// 当前网格大小(米),用于自适应点大小计算
private double _currentGridSizeInMeters;
// 路径可视化模式配置
private PathVisualizationMode _visualizationMode = PathVisualizationMode.StandardLine;
// 网格点类型配置
private GridPointType _gridPointType = GridPointType.Rectangle;
// 车辆参数(必须通过SetVehicleParameters方法设置)
private double _vehicleLength;
private double _vehicleWidth;
private double _vehicleHeight;
private double _safetyMargin;
// 静态实例,用于外部访问
private static PathPointRenderPlugin _instance;
///
/// 构造函数
///
public PathPointRenderPlugin()
{
_instance = this;
}
///
/// 获取静态实例
///
public static PathPointRenderPlugin Instance => _instance;
///
/// 路径可视化模式
///
public PathVisualizationMode VisualizationMode
{
get { return _visualizationMode; }
set
{
_visualizationMode = value;
// 模式改变时刷新所有普通路径(排除网格)
RefreshNormalPaths();
}
}
///
/// 网格点类型
///
public GridPointType GridPointType
{
get { return _gridPointType; }
set
{
_gridPointType = value;
// 类型改变时刷新所有网格路径
RefreshGridPaths();
}
}
///
/// 是否启用渲染
///
public bool IsEnabled
{
get { return _isEnabled; }
set
{
_isEnabled = value;
// 触发视图刷新
if (Application.ActiveDocument?.ActiveView != null)
{
Application.ActiveDocument.ActiveView.RequestDelayedRedraw(ViewRedrawRequests.Render);
}
}
}
///
/// 当前路径总数
///
public int PathCount
{
get
{
lock (_lockObject)
{
return _pathVisualizations.Count;
}
}
}
///
/// 当前点标记总数
///
public int MarkerCount
{
get
{
lock (_lockObject)
{
return _pathVisualizations.Values.Sum(v => v.PointMarkers.Count);
}
}
}
///
/// Navisworks渲染回调方法
///
/// 当前视图
/// 图形上下文
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;
bool hasPreviewPoint;
lock (_lockObject)
{
pathCount = _pathVisualizations.Count;
hasPreviewPoint = _previewMarker != null;
}
if (pathCount == 0 && !hasPreviewPoint) return;
// 使用BeginModelContext确保正确的渲染上下文
graphics.BeginModelContext();
lock (_lockObject)
{
// 渲染所有正式路径
foreach (var visualization in _pathVisualizations.Values)
{
// 渲染控制点可视化(用户意图)
if (visualization.ShowControlVisualization)
{
// 渲染所有点标记
foreach (var pointMarker in visualization.PointMarkers)
{
graphics.Color(pointMarker.Color, pointMarker.Alpha);
RenderPointMarker(graphics, pointMarker);
}
// 渲染控制点连线(半透明)
foreach (var controlLineMarker in visualization.ControlLineMarkers)
{
graphics.Color(controlLineMarker.Color, 0.3); // 30%透明度
graphics.Cylinder(controlLineMarker.StartPoint, controlLineMarker.EndPoint, controlLineMarker.Radius);
}
}
// 渲染真实路径可视化(Edges + 切点)
// 先渲染切点(在底层)
foreach (var tangentMarker in visualization.TangentMarkers)
{
graphics.Color(tangentMarker.Color, tangentMarker.Alpha);
RenderSquareMarker(graphics, tangentMarker);
}
// 再渲染路径连线(直线段和圆弧段)
foreach (var pathLineMarker in visualization.PathLineMarkers)
{
// 圆弧段使用半透明灰色,直线段使用正常颜色
if (pathLineMarker.SegmentType == PathSegmentType.Arc)
{
graphics.Color(GetRenderColor(RenderColorType.PreviewLine), 0.5); // 半透明灰色
}
else
{
graphics.Color(pathLineMarker.Color, 1.0); // 不透明
}
RenderLineMarker(graphics, pathLineMarker);
}
// 渲染车辆通行空间(矩形通道)
foreach (var vehicleSpaceMarker in visualization.VehicleSpaceMarkers)
{
graphics.Color(vehicleSpaceMarker.Color, vehicleSpaceMarker.Alpha);
RenderVehicleSpace(graphics, vehicleSpaceMarker);
}
}
// 渲染预览点(灰色)
if (_previewMarker != null && _previewMarker.IsVisible)
{
graphics.Color(_previewMarker.Color, 0.7); // 使用半透明效果
RenderPointMarker(graphics, _previewMarker);
}
// 渲染预览连线(灰色)
if (_previewLines.Count > 0)
{
foreach (var previewLine in _previewLines)
{
graphics.Color(previewLine.Color, 0.7); // 使用半透明效果
graphics.Cylinder(previewLine.StartPoint, previewLine.EndPoint, previewLine.Radius);
}
}
}
graphics.EndModelContext();
}
catch (Exception ex)
{
// 渲染异常应该静默处理,避免影响Navisworks主程序
LogManager.Error($"[渲染异常] {ex.Message}", ex);
// 不输出堆栈信息,避免日志过量
}
}
#region 新的统一路径可视化接口
///
/// 渲染完整路径
///
/// 路径数据
public void RenderPath(PathRoute pathRoute)
{
if (pathRoute == null)
{
return;
}
try
{
var visualization = new PathVisualization
{
PathId = pathRoute.Id,
PathRoute = pathRoute
};
BuildVisualization(visualization);
lock (_lockObject)
{
_pathVisualizations[pathRoute.Id] = visualization;
}
RequestViewRefresh();
}
catch (Exception ex)
{
LogManager.Error($"[路径渲染] 渲染路径失败: {ex.Message}", ex);
}
}
///
/// 只渲染点标记,不绘制连线(用于自动路径规划的起终点显示)
///
public void RenderPointOnly(PathRoute pathRoute)
{
if (pathRoute == null)
{
return;
}
try
{
// 检查是否是网格可视化路径
bool isGridVisualization = pathRoute.Id == "grid_visualization_all" ||
pathRoute.Id == "grid_visualization_channel" ||
pathRoute.Id == "grid_visualization_door" ||
pathRoute.Id == "grid_visualization_unknown" ||
pathRoute.Id == "grid_visualization_obstacle";
var visualization = new PathVisualization
{
PathId = pathRoute.Id,
PathRoute = pathRoute
};
// 只构建点标记,不构建连线
BuildPointMarkersOnly(visualization);
lock (_lockObject)
{
_pathVisualizations[pathRoute.Id] = visualization;
}
RequestViewRefresh();
}
catch (Exception ex)
{
LogManager.Error($"[点标记渲染] 渲染点标记失败: {ex.Message}", ex);
}
}
///
/// 只构建点标记,不构建连线
///
private void BuildPointMarkersOnly(PathVisualization visualization)
{
// 清空现有标记
visualization.PointMarkers.Clear();
visualization.LineMarkers.Clear(); // 确保没有连线
var points = visualization.PathRoute.Points;
if (points.Count == 0) return;
// 检查是否是网格可视化路径
bool isGridVisualization = visualization.PathId == "grid_visualization_all" ||
visualization.PathId == "grid_visualization_channel" ||
visualization.PathId == "grid_visualization_door" ||
visualization.PathId == "grid_visualization_unknown" ||
visualization.PathId == "grid_visualization_obstacle";
// 按索引排序点
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;
}
///
/// 刷新路径可视化
///
/// 路径ID
public void RefreshPath(string pathId)
{
lock (_lockObject)
{
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
{
BuildVisualization(visualization);
RequestViewRefresh();
}
}
}
///
/// 设置控制点可视化的显示状态
///
/// 路径ID
/// 是否显示
public void SetControlVisualizationVisibility(string pathId, bool show)
{
lock (_lockObject)
{
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
{
if (visualization.ShowControlVisualization != show)
{
visualization.ShowControlVisualization = show;
RequestViewRefresh();
}
}
}
}
///
/// 切换控制点可视化的显示状态
///
/// 路径ID
public void ToggleControlVisualization(string pathId)
{
lock (_lockObject)
{
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
{
visualization.ShowControlVisualization = !visualization.ShowControlVisualization;
RequestViewRefresh();
}
}
}
///
/// 判断是否为网格可视化路径
///
private bool IsGridVisualizationPath(string pathId)
{
return pathId != null && (
pathId.StartsWith("grid_visualization_") ||
pathId == "grid_visualization_all" ||
pathId == "voxel_grid_visualization"); // 体素网格可视化
}
///
/// 刷新所有普通路径(排除网格可视化)
///
private void RefreshNormalPaths()
{
lock (_lockObject)
{
var normalPathIds = _pathVisualizations.Keys
.Where(id => !IsGridVisualizationPath(id))
.ToList();
foreach (var pathId in normalPathIds)
{
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
{
BuildVisualization(visualization);
}
}
if (normalPathIds.Count > 0)
{
RequestViewRefresh();
}
}
}
///
/// 刷新所有网格路径
///
private void RefreshGridPaths()
{
lock (_lockObject)
{
var gridPathIds = _pathVisualizations.Keys
.Where(id => IsGridVisualizationPath(id))
.ToList();
foreach (var pathId in gridPathIds)
{
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
{
BuildPointMarkersOnly(visualization);
}
}
if (gridPathIds.Count > 0)
{
RequestViewRefresh();
}
}
}
///
/// 移除路径
///
/// 路径ID
public void RemovePath(string pathId)
{
lock (_lockObject)
{
if (_pathVisualizations.Remove(pathId))
{
RequestViewRefresh();
}
}
}
///
/// 清空所有路径
///
public void ClearAllPaths()
{
lock (_lockObject)
{
var count = _pathVisualizations.Count;
_pathVisualizations.Clear();
RequestViewRefresh();
}
}
///
/// 清空路径,但保留指定的路径
///
/// 要保留的路径ID列表
public void ClearPathsExcept(params string[] excludedPathIds)
{
try
{
lock (_lockObject)
{
// 防御性编程:处理空参数
if (excludedPathIds == null)
{
excludedPathIds = new string[0];
}
var excludedSet = new HashSet(excludedPathIds.Where(id => !string.IsNullOrEmpty(id)));
var toRemove = _pathVisualizations.Keys.Where(id => !excludedSet.Contains(id)).ToList();
// 检查排除的路径是否实际存在
var existingExcluded = excludedSet.Where(id => _pathVisualizations.ContainsKey(id)).ToList();
var nonExistingExcluded = excludedSet.Where(id => !_pathVisualizations.ContainsKey(id)).ToList();
int removedCount = 0;
foreach (var pathId in toRemove)
{
if (_pathVisualizations.Remove(pathId))
{
removedCount++;
}
}
if (removedCount > 0)
{
RequestViewRefresh();
}
}
}
catch (Exception ex)
{
LogManager.Error($"[选择性清空] 清理路径时发生异常: {ex.Message}", ex);
// 即使发生异常也不抛出,避免影响主流程
}
}
///
/// 构建路径可视化
///
/// 路径可视化对象
private void BuildVisualization(PathVisualization visualization)
{
// 清空现有标记
visualization.PointMarkers.Clear();
visualization.LineMarkers.Clear();
visualization.ControlLineMarkers.Clear();
visualization.PathLineMarkers.Clear();
visualization.TangentMarkers.Clear();
visualization.VehicleSpaceMarkers.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);
}
// 构建控制点连线(用户意图,半透明)
BuildControlLines(visualization, sortedPoints);
// 构建路径连线(真实路径,不透明,仅当Edges存在时)
if (visualization.PathRoute.Edges != null && visualization.PathRoute.Edges.Count > 0)
{
BuildPathLines(visualization, sortedPoints);
}
else if (_visualizationMode == PathVisualizationMode.VehicleSpace)
{
// 构建车辆通行空间标记
for (int i = 0; i < sortedPoints.Count - 1; i++)
{
var currentPoint = sortedPoints[i];
var nextPoint = sortedPoints[i + 1];
var vehicleSpaceMarker = CreateVehicleSpaceMarker(currentPoint, nextPoint);
visualization.VehicleSpaceMarkers.Add(vehicleSpaceMarker);
}
}
// 如果路径未完成,添加灰色的原始终点标记
if (!visualization.PathRoute.IsComplete && visualization.PathRoute.OriginalEndPoint != null)
{
var originalEndPoint = visualization.PathRoute.OriginalEndPoint;
var unreachedStyle = GetRenderStyle(RenderColorType.UnreachedEndPoint);
var grayEndMarker = new CircleMarker
{
Center = originalEndPoint,
Normal = new Vector3D(0, 0, 1),
Radius = GetRadiusForPointType(PathPointType.EndPoint),
Color = unreachedStyle.Color, // 未到达终点颜色
Alpha = unreachedStyle.Alpha, // 透明度,统一管理
Filled = true,
PointType = PathPointType.EndPoint,
SequenceNumber = -1, // 特殊序号表示这是未到达的终点
CreatedTime = DateTime.Now
};
visualization.PointMarkers.Add(grayEndMarker);
}
visualization.LastUpdated = DateTime.Now;
}
///
/// 构建控制点连线(用户意图,半透明)
///
/// 路径可视化对象
/// 排序后的路径点列表
private void BuildControlLines(PathVisualization visualization, List sortedPoints)
{
// 构建控制点之间的连线(所有相邻控制点)
for (int i = 0; i < sortedPoints.Count - 1; i++)
{
var currentPoint = sortedPoints[i];
var nextPoint = sortedPoints[i + 1];
var controlLineMarker = new LineMarker
{
StartPoint = currentPoint.Position,
EndPoint = nextPoint.Position,
Color = GetRenderColor(RenderColorType.Line),
Radius = GetLineRadius() * 0.5, // 比实际路径细
SegmentType = PathSegmentType.Straight,
FromIndex = currentPoint.Index,
ToIndex = nextPoint.Index
};
visualization.ControlLineMarkers.Add(controlLineMarker);
}
}
///
/// 构建路径连线(真实路径,不透明)
///
/// 路径可视化对象
/// 排序后的路径点列表
private void BuildPathLines(PathVisualization visualization, List sortedPoints)
{
var edges = visualization.PathRoute.Edges;
// 1. 收集在路径上的控制点ID
var onPathPointIds = new HashSet();
foreach (var edge in edges)
{
if (!string.IsNullOrEmpty(edge.StartPointId))
onPathPointIds.Add(edge.StartPointId);
if (!string.IsNullOrEmpty(edge.EndPointId))
onPathPointIds.Add(edge.EndPointId);
}
// 2. 更新点标记的透明度
foreach (var pointMarker in visualization.PointMarkers)
{
var point = sortedPoints.FirstOrDefault(p => p.Id == pointMarker.PathPoint?.Id);
if (point != null)
{
bool isOnPath = onPathPointIds.Contains(point.Id);
pointMarker.IsOffPath = !isOnPath;
}
}
// 3. 构建路径连线(Edges包含直线段和圆弧段)
foreach (var edge in edges)
{
if (edge.SegmentType == PathSegmentType.Straight)
{
// 直线段:检查SampledPoints是否有效
if (edge.SampledPoints != null && edge.SampledPoints.Count >= 2)
{
var lineMarker = new LineMarker
{
StartPoint = edge.SampledPoints.First(),
EndPoint = edge.SampledPoints.Last(),
Color = GetRenderColor(RenderColorType.Line),
Radius = GetLineRadius(),
SegmentType = PathSegmentType.Straight,
SampledPoints = edge.SampledPoints
};
visualization.PathLineMarkers.Add(lineMarker);
}
}
else if (edge.SegmentType == PathSegmentType.Arc && edge.Trajectory != null)
{
// 圆弧段:检查Trajectory是否有效
var arcMarker = new LineMarker
{
StartPoint = edge.Trajectory.Ts,
EndPoint = edge.Trajectory.Te,
Color = GetRenderColor(RenderColorType.Line),
Radius = GetLineRadius(),
SegmentType = PathSegmentType.Arc,
Trajectory = edge.Trajectory,
SampledPoints = edge.SampledPoints
};
visualization.PathLineMarkers.Add(arcMarker);
// 添加切点标记
AddTangentMarkers(visualization, edge);
}
}
}
///
/// 添加切点标记
///
/// 路径可视化对象
/// 路径边
private void AddTangentMarkers(PathVisualization visualization, PathEdge edge)
{
if (edge.Trajectory == null) return;
// 切点颜色与路径点相同
var tangentColor = GetRenderColor(RenderColorType.WayPoint);
// 进入切点Ts
var tsMarker = new SquareMarker
{
Center = edge.Trajectory.Ts,
Normal = new Vector3D(0, 0, 1),
Size = GetLineRadius() * 1.5,
Color = tangentColor,
Alpha = 0.9,
EdgeId = edge.Id,
TangentType = TangentPointType.EntryTangent
};
visualization.TangentMarkers.Add(tsMarker);
// 退出切点Te
var teMarker = new SquareMarker
{
Center = edge.Trajectory.Te,
Normal = new Vector3D(0, 0, 1),
Size = GetLineRadius() * 1.5,
Color = tangentColor,
Alpha = 0.9,
EdgeId = edge.Id,
TangentType = TangentPointType.ExitTangent
};
visualization.TangentMarkers.Add(teMarker);
}
///
/// 创建车辆通行空间标记
///
/// 起点
/// 终点
/// 车辆通行空间标记
private VehicleSpaceMarker CreateVehicleSpaceMarker(PathPoint fromPoint, PathPoint toPoint)
{
// 获取单位转换系数
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
// 计算车辆通行空间宽度(米)
double vehicleInflationWidthInMeters = Math.Max(_vehicleLength, _vehicleWidth) + 2 * _safetyMargin;
// 计算车辆通行空间高度(米):车辆高度 + 安全间隙
double vehicleSpaceHeightInMeters = _vehicleHeight + _safetyMargin;
var style = GetRenderStyle(RenderColorType.VehicleSpace);
return new VehicleSpaceMarker
{
StartPoint = fromPoint.Position,
EndPoint = toPoint.Position,
Width = vehicleInflationWidthInMeters * metersToModelUnits, // 转换为模型单位
Height = vehicleSpaceHeightInMeters * metersToModelUnits, // 转换为模型单位
Color = style.Color, // 车辆通行空间颜色
Alpha = style.Alpha, // 透明度,统一管理
FromIndex = fromPoint.Index,
ToIndex = toPoint.Index
};
}
///
/// 创建点标记
///
/// 路径点
/// 圆形标记
private CircleMarker CreatePointMarker(PathPoint point)
{
// 检查是否是网格/体素可视化点(通过名称判断)
bool isGridVisualization = point.Name.StartsWith("网格(") || point.Name.StartsWith("网格_") ||
point.Name.StartsWith("体素("); // 体素点
// 确定网格点样式(颜色+透明度)
RenderStyle gridStyle = new RenderStyle(Color.White, 1.0); // 默认样式
if (isGridVisualization)
{
// 根据网格类型确定样式
if (point.Name.Contains("空洞") || point.Name.Contains("Unknown"))
{
gridStyle = GetRenderStyle(RenderColorType.GridUnknown);
}
else if (point.Name.Contains("障碍") || point.Name.Contains("Obstacle"))
{
gridStyle = GetRenderStyle(RenderColorType.GridObstacle);
}
else if (point.Name.Contains("通道") || point.Name.Contains("Channel") || point.Name.Contains("开放"))
{
gridStyle = GetRenderStyle(RenderColorType.GridChannel);
}
// 也可以通过Notes字段检查
else if (!string.IsNullOrEmpty(point.Notes) && point.Notes.StartsWith("GridType:"))
{
var gridTypeStr = point.Notes.Substring(9); // 去掉"GridType:"前缀
if (gridTypeStr == "Unknown")
gridStyle = GetRenderStyle(RenderColorType.GridUnknown);
else if (gridTypeStr == "Obstacle")
gridStyle = GetRenderStyle(RenderColorType.GridObstacle);
else
gridStyle = GetRenderStyle(RenderColorType.GridChannel);
}
// 门网格点使用50%透明度覆盖默认透明度
if (point.Name.Contains("门"))
{
gridStyle = new RenderStyle(gridStyle.Color, 0.5);
}
}
return new CircleMarker
{
Center = point.Position,
Normal = new Vector3D(0, 0, 1),
Radius = isGridVisualization ? GetRadiusForGridVisualization() : GetRadiusForPointType(point.Type),
Color = isGridVisualization ? gridStyle.Color : GetColorForPointType(point.Type),
Alpha = isGridVisualization ? gridStyle.Alpha : 1.0,
Filled = true,
PointType = point.Type,
GridPointType = isGridVisualization ? _gridPointType : GridPointType.Sphere, // 网格点使用配置的类型,其他点使用球形
SequenceNumber = point.Index, // 使用Index而不是任意序号
CreatedTime = DateTime.Now
};
}
///
/// 获取网格可视化小球的半径(比正常路径点小)
///
/// 网格可视化半径
private double GetRadiusForGridVisualization()
{
// 使用标准尺寸的1/5作为网格点尺寸
double standardRadiusInMeters = GetStandardRadiusInMeters();
double radiusInMeters = standardRadiusInMeters / 5.0;
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
return radiusInMeters * metersToModelUnits;
}
///
/// 设置当前网格大小(米),用于自适应点大小计算
///
/// 网格大小(米)
public void SetGridSize(double gridSizeInMeters)
{
_currentGridSizeInMeters = gridSizeInMeters;
}
///
/// 设置车辆参数(从PathPlanningManager同步)
///
/// 车辆长度(米)
/// 车辆宽度(米)
/// 车辆高度(米)
/// 安全间隙(米)
public void SetVehicleParameters(double vehicleLength, double vehicleWidth, double vehicleHeight, double safetyMargin)
{
_vehicleLength = vehicleLength;
_vehicleWidth = vehicleWidth;
_vehicleHeight = vehicleHeight;
_safetyMargin = safetyMargin;
// 车辆参数改变时刷新车辆空间模式下的所有普通路径
if (_visualizationMode == PathVisualizationMode.VehicleSpace)
{
RefreshNormalPaths();
}
}
#region 颜色管理
///
/// 根据颜色类型获取对应的渲染样式(颜色+透明度)
///
/// 颜色类型
/// 对应的渲染样式
private RenderStyle GetRenderStyle(RenderColorType colorType)
{
switch (colorType)
{
case RenderColorType.StartPoint:
return new RenderStyle(Color.FromByteRGB(76, 175, 80), 0.9); // Material Green起点,10%透明
case RenderColorType.EndPoint:
return new RenderStyle(Color.FromByteRGB(244, 67, 54), 0.9); // Material Red终点,10%透明
case RenderColorType.WayPoint:
return new RenderStyle(Color.FromByteRGB(33, 150, 243), 0.9); // Material Blue路径点,10%透明
case RenderColorType.Line:
return new RenderStyle(Color.FromByteRGB(255, 152, 0), 0.85); // Material Orange连线,15%透明
case RenderColorType.VehicleSpace:
return new RenderStyle(Color.FromByteRGB(158, 158, 158), 0.4); // Material Grey车辆空间,60%透明
case RenderColorType.PreviewPoint:
return new RenderStyle(Color.White, 0.7); // 白色预览点,30%透明
case RenderColorType.PreviewLine:
return new RenderStyle(Color.FromByteRGB(128, 128, 128), 0.7); // 灰色预览连线,30%透明
case RenderColorType.UnreachedEndPoint:
return new RenderStyle(Color.FromByteRGB(139, 0, 0), 0.7); // 深红色未到达终点,30%透明
case RenderColorType.GridChannel:
return new RenderStyle(Color.FromByteRGB(129, 199, 132), 0.8); // Material Light Green网格通道,20%透明
case RenderColorType.GridObstacle:
return new RenderStyle(Color.FromByteRGB(117, 117, 117), 0.8); // Material Grey网格障碍物,20%透明
case RenderColorType.GridUnknown:
return new RenderStyle(Color.FromByteRGB(255, 112, 67), 0.8); // Material Deep Orange网格未知区域,20%透明
default:
return new RenderStyle(Color.White, 1.0); // 默认白色,完全不透明
}
}
///
/// 根据颜色类型获取对应的颜色(向后兼容方法)
///
/// 颜色类型
/// 对应的颜色
private Color GetRenderColor(RenderColorType colorType)
{
return GetRenderStyle(colorType).Color;
}
#endregion
///
/// 获取连线半径
///
/// 连线半径
private double GetLineRadius()
{
// 获取标准尺寸(起点尺寸)
double standardRadiusInMeters = GetStandardRadiusInMeters();
// 连线半径为标准尺寸的40%
double lineRadiusInMeters = standardRadiusInMeters * 0.4;
return lineRadiusInMeters * UnitsConverter.GetMetersToUnitsConversionFactor();
}
///
/// 添加路径点到指定路径
///
/// 路径ID
/// 新的路径点
/// 插入位置索引,-1表示添加到末尾
public void AddPointToPath(string pathId, PathPoint newPoint, int insertIndex = -1)
{
var visualization = GetPathVisualization(pathId);
if (visualization == null)
{
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);
RequestViewRefresh();
}
catch (Exception ex)
{
LogManager.Error($"[路径编辑] 添加路径点失败: {ex.Message}", ex);
}
}
///
/// 从指定路径移除路径点
///
/// 路径ID
/// 要移除的点索引
public void RemovePointFromPath(string pathId, int pointIndex)
{
var visualization = GetPathVisualization(pathId);
if (visualization == null)
{
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);
RequestViewRefresh();
}
else
{
LogManager.Warning($"[路径编辑] 未找到索引为 {pointIndex} 的路径点");
}
}
catch (Exception ex)
{
LogManager.Error($"[路径编辑] 移除路径点失败: {ex.Message}", ex);
}
}
///
/// 更新指定路径中的路径点
///
/// 路径ID
/// 要更新的点索引
/// 更新后的路径点
public void UpdatePointInPath(string pathId, int pointIndex, PathPoint updatedPoint)
{
var visualization = GetPathVisualization(pathId);
if (visualization == null)
{
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);
RequestViewRefresh();
}
else
{
LogManager.Warning($"[路径编辑] 未找到索引为 {pointIndex} 的路径点");
}
}
catch (Exception ex)
{
LogManager.Error($"[路径编辑] 更新路径点失败: {ex.Message}", ex);
}
}
///
/// 重新分配路径点索引
///
/// 路径对象
private void ReindexPoints(PathRoute pathRoute)
{
// 按照当前在List中的位置重新分配连续索引
for (int i = 0; i < pathRoute.Points.Count; i++)
{
pathRoute.Points[i].Index = i;
}
}
///
/// 获取路径可视化对象
///
/// 路径ID
/// 路径可视化对象,如果不存在返回null
private PathVisualization GetPathVisualization(string pathId)
{
lock (_lockObject)
{
_pathVisualizations.TryGetValue(pathId, out var visualization);
return visualization;
}
}
#endregion
///
/// 渲染预览点(灰色显示)
///
/// 预览点对象
public void RenderPreviewPoint(PathPoint previewPoint)
{
try
{
if (previewPoint == null)
{
return;
}
lock (_lockObject)
{
// 获取适当的半径
double radius = GetRadiusForPointType(previewPoint.Type);
// 获取预览点样式(颜色+透明度)
var previewStyle = GetRenderStyle(RenderColorType.PreviewPoint);
// 创建预览点标记
_previewMarker = new CircleMarker
{
Position = previewPoint.Position,
Radius = radius,
Color = previewStyle.Color,
Alpha = previewStyle.Alpha,
IsVisible = true,
PathPoint = previewPoint
};
// 请求刷新视图
RequestViewRefresh();
}
}
catch (Exception ex)
{
LogManager.Error($"[预览点渲染] 渲染预览点失败: {ex.Message}", ex);
}
}
///
/// 清除预览点
///
public void ClearPreviewPoint()
{
try
{
lock (_lockObject)
{
if (_previewMarker != null || _previewLines.Count > 0)
{
_previewMarker = null;
_previewLines.Clear();
// 请求刷新视图
RequestViewRefresh();
}
}
}
catch (Exception ex)
{
LogManager.Error($"[预览点渲染] 清除预览点失败: {ex.Message}", ex);
}
}
///
/// 渲染预览连线
///
/// 预览点
/// 当前路径点列表
public void RenderPreviewLines(PathPoint previewPoint, List pathPoints)
{
try
{
if (previewPoint == null || pathPoints == null || pathPoints.Count == 0)
{
return;
}
lock (_lockObject)
{
// 清除旧的预览连线
_previewLines.Clear();
// 找到预览点应该插入的最近线段
var nearestSegment = FindNearestLineSegment(previewPoint.Position, pathPoints);
if (nearestSegment.HasValue)
{
var (prevPoint, nextPoint) = nearestSegment.Value;
// 创建两条预览连线
// 1. 前一个点 -> 预览点
var line1 = new LineMarker
{
StartPoint = prevPoint.Position,
EndPoint = previewPoint.Position,
Color = GetRenderColor(RenderColorType.PreviewLine), // 预览连线颜色
Radius = GetLineRadius() // 使用与正常连线相同的直径
};
_previewLines.Add(line1);
// 2. 预览点 -> 后一个点
var line2 = new LineMarker
{
StartPoint = previewPoint.Position,
EndPoint = nextPoint.Position,
Color = GetRenderColor(RenderColorType.PreviewLine), // 预览连线颜色
Radius = GetLineRadius()
};
_previewLines.Add(line2);
}
else
{
LogManager.Warning("[预览连线渲染] 未找到合适的线段插入预览点");
}
// 请求刷新视图
RequestViewRefresh();
}
}
catch (Exception ex)
{
LogManager.Error($"[预览连线渲染] 渲染预览连线失败: {ex.Message}", ex);
}
}
///
/// 清除预览连线
///
public void ClearPreviewLines()
{
try
{
lock (_lockObject)
{
if (_previewLines.Count > 0)
{
_previewLines.Clear();
// 请求刷新视图
RequestViewRefresh();
}
}
}
catch (Exception ex)
{
LogManager.Error($"[预览连线渲染] 清除预览连线失败: {ex.Message}", ex);
}
}
///
/// 渲染预览路径(用于修改路径点时的预览)
///
/// 包含预览修改的路径
public void RenderPreviewPath(PathRoute previewRoute)
{
try
{
if (previewRoute == null || previewRoute.Points.Count == 0)
{
return;
}
lock (_lockObject)
{
// 只清理预览元素,不影响原有路径
ClearPreviewPoint();
ClearPreviewLines();
// 找到预览点及其索引
var previewPointIndex = -1;
PathPoint previewPoint = null;
for (int i = 0; i < previewRoute.Points.Count; i++)
{
if (previewRoute.Points[i].Name.Contains("_预览"))
{
previewPointIndex = i;
previewPoint = previewRoute.Points[i];
break;
}
}
if (previewPoint != null && previewPointIndex >= 0)
{
// 只渲染预览点
RenderPreviewPoint(previewPoint);
// 只渲染与预览点相关的连线
// 连接前一个点到预览点
if (previewPointIndex > 0)
{
var prevPoint = previewRoute.Points[previewPointIndex - 1];
var line1 = new LineMarker
{
StartPoint = prevPoint.Position,
EndPoint = previewPoint.Position,
Color = GetRenderColor(RenderColorType.PreviewLine), // 预览连线颜色
Radius = GetLineRadius()
};
_previewLines.Add(line1);
}
// 连接预览点到下一个点
if (previewPointIndex < previewRoute.Points.Count - 1)
{
var nextPoint = previewRoute.Points[previewPointIndex + 1];
var line2 = new LineMarker
{
StartPoint = previewPoint.Position,
EndPoint = nextPoint.Position,
Color = GetRenderColor(RenderColorType.PreviewLine), // 预览连线颜色
Radius = GetLineRadius()
};
_previewLines.Add(line2);
}
}
else
{
LogManager.Warning("[预览路径渲染] 未找到预览点,跳过渲染");
}
RequestViewRefresh();
}
}
catch (Exception ex)
{
LogManager.Error($"[预览路径渲染] 渲染预览路径失败: {ex.Message}", ex);
}
}
///
/// 清理所有预览渲染
///
public void ClearPreview()
{
try
{
lock (_lockObject)
{
// 清理预览点
ClearPreviewPoint();
// 清理预览连线
ClearPreviewLines();
RequestViewRefresh();
}
}
catch (Exception ex)
{
LogManager.Error($"[清理预览] 清理预览失败: {ex.Message}", ex);
}
}
#region 私有辅助方法
/// 标准尺寸(米)
///
/// 计算标准尺寸(起点尺寸),其他元素以此为基准按比例计算
///
/// 标准尺寸(米)
private double GetStandardRadiusInMeters()
{
// 起点尺寸为网格大小的100%,并限制在合理范围内
double standardRadius = _currentGridSizeInMeters * 1.0;
// 边界限制:最小0.1米,最大0.5米
return Math.Max(0.1, Math.Min(0.5, standardRadius));
}
public double GetRadiusForPointType(PathPointType pointType)
{
// 获取标准尺寸(起点尺寸)
double standardRadiusInMeters = GetStandardRadiusInMeters();
// 根据点类型应用比例系数
double baseRadiusInMeters;
if (pointType == PathPointType.WayPoint)
{
// 路径点为标准尺寸的80%
baseRadiusInMeters = standardRadiusInMeters * 0.8;
}
else
{
// 起点/终点使用标准尺寸(100%)
baseRadiusInMeters = standardRadiusInMeters * 1.0;
}
// 获取真实文档单位转换系数
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
// 转换为模型单位
double radiusInModelUnits = baseRadiusInMeters * metersToModelUnits;
return radiusInModelUnits;
}
///
/// 根据路径点类型获取颜色
///
public Color GetColorForPointType(PathPointType pointType)
{
switch (pointType)
{
case PathPointType.StartPoint:
return GetRenderColor(RenderColorType.StartPoint); // 起点绿色
case PathPointType.EndPoint:
return GetRenderColor(RenderColorType.EndPoint); // 终点红色
case PathPointType.WayPoint:
default:
return GetRenderColor(RenderColorType.WayPoint); // 路径中间点洋红色
}
}
///
/// 计算两点间距离
///
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);
}
///
/// 渲染车辆通行空间(矩形通道)- 使用Cuboid API简化实现
///
/// 图形上下文
/// 车辆通行空间标记
private void RenderVehicleSpace(Graphics graphics, VehicleSpaceMarker vehicleSpace)
{
try
{
// 计算通道方向向量
var direction = new Vector3D(
vehicleSpace.EndPoint.X - vehicleSpace.StartPoint.X,
vehicleSpace.EndPoint.Y - vehicleSpace.StartPoint.Y,
vehicleSpace.EndPoint.Z - vehicleSpace.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);
// 计算垂直向量(在XY平面内垂直于方向向量)
var right = new Vector3D(-direction.Y, direction.X, 0);
// 如果方向向量垂直于XY平面,则使用不同的right向量
if (Math.Abs(direction.Z) > 0.9)
{
right = new Vector3D(1, 0, 0);
}
// 归一化right向量
var rightLength = Math.Sqrt(right.X * right.X + right.Y * right.Y + right.Z * right.Z);
if (rightLength > 0.001)
{
right = new Vector3D(right.X / rightLength, right.Y / rightLength, right.Z / rightLength);
}
// 计算通道的边界框和向量
var halfWidth = vehicleSpace.Width / 2.0;
// 计算立方体原点(起点左下角)
var origin = new Point3D(
vehicleSpace.StartPoint.X - halfWidth * right.X,
vehicleSpace.StartPoint.Y - halfWidth * right.Y,
vehicleSpace.StartPoint.Z
);
// 定义立方体的三个轴向量
var xVector = new Vector3D(direction.X * length, direction.Y * length, direction.Z * length); // 长度方向
var yVector = new Vector3D(right.X * vehicleSpace.Width, right.Y * vehicleSpace.Width, right.Z * vehicleSpace.Width); // 宽度方向
var zVector = new Vector3D(0, 0, vehicleSpace.Height); // 高度方向
// 设置颜色和透明度
graphics.Color(vehicleSpace.Color, vehicleSpace.Alpha);
// 使用Cuboid API渲染长方体通道
graphics.Cuboid(origin, xVector, yVector, zVector, true);
}
catch (Exception ex)
{
LogManager.Error($"[车辆空间渲染] 渲染车辆通行空间失败: {ex.Message}", ex);
}
}
///
/// 渲染点标记
///
/// 图形上下文
/// 点标记
private void RenderPointMarker(Graphics graphics, CircleMarker pointMarker)
{
switch (pointMarker.GridPointType)
{
case GridPointType.Rectangle:
// 渲染立方体
RenderCubeMarker(graphics, pointMarker);
break;
case GridPointType.Circle:
// 渲染圆
RenderCircleMarker(graphics, pointMarker);
break;
case GridPointType.Sphere:
default:
// 渲染球形(默认)
graphics.Sphere(pointMarker.Center, pointMarker.Radius);
break;
}
}
///
/// 渲染立方体标记
///
/// 图形上下文
/// 点标记
private void RenderCubeMarker(Graphics graphics, CircleMarker pointMarker)
{
// 计算正方形的边长(直径)
double sideLength = pointMarker.Radius * 2;
// 定义正方形的两个轴向量(沿X、Y轴)
var xVector = new Vector3D(sideLength, 0, 0);
var yVector = new Vector3D(0, sideLength, 0);
// 计算正方形原点(中心点减去各轴向量的一半),略微抬高以避免与模型重叠
var origin = new Point3D(
pointMarker.Center.X - pointMarker.Radius,
pointMarker.Center.Y - pointMarker.Radius,
pointMarker.Center.Z + 0.01
);
// 使用Rectangle API渲染正方形
graphics.Rectangle(origin, xVector, yVector, pointMarker.Filled);
}
///
/// 渲染圆形标记
///
/// 图形上下文
/// 点标记
private void RenderCircleMarker(Graphics graphics, CircleMarker pointMarker)
{
// 调整中心点位置,略微抬高以避免与模型重叠
Point3D adjustCenterPoint = new Point3D(
pointMarker.Center.X,
pointMarker.Center.Y,
pointMarker.Center.Z + 0.01
);
// 使用Circle API渲染圆形
graphics.Circle(adjustCenterPoint, pointMarker.Normal, pointMarker.Radius, true);
}
///
/// 渲染方块标记(切点)
///
/// 图形上下文
/// 方块标记
private void RenderSquareMarker(Graphics graphics, SquareMarker marker)
{
// 计算立方体的三个轴向量
var halfSize = marker.Size / 2.0;
// X轴向量(沿X方向)
var xVector = new Vector3D(marker.Size, 0, 0);
// Y轴向量(沿Y方向)
var yVector = new Vector3D(0, marker.Size, 0);
// Z轴向量(沿Z方向,高度很小,形成扁平立方体)
var zVector = new Vector3D(0, 0, marker.Size * 0.2);
// 计算立方体原点(中心点偏移)
var origin = new Point3D(
marker.Center.X - halfSize,
marker.Center.Y - halfSize,
marker.Center.Z - zVector.Z / 2
);
// 使用Cuboid API绘制方块
graphics.Cuboid(origin, xVector, yVector, zVector, true);
}
///
/// 渲染连线标记(支持直线段和圆弧段)
///
/// 图形上下文
/// 连线标记
private void RenderLineMarker(Graphics graphics, LineMarker lineMarker)
{
if (lineMarker.SegmentType == PathSegmentType.Arc &&
lineMarker.SampledPoints != null &&
lineMarker.SampledPoints.Count >= 2)
{
// 圆弧段:多段圆柱体
for (int i = 0; i < lineMarker.SampledPoints.Count - 1; i++)
{
graphics.Cylinder(lineMarker.SampledPoints[i], lineMarker.SampledPoints[i + 1], lineMarker.Radius);
}
}
else
{
// 直线段:单个圆柱体
graphics.Cylinder(lineMarker.StartPoint, lineMarker.EndPoint, lineMarker.Radius);
}
}
///
/// 请求视图刷新(带防抖机制)
///
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.Error($"[视图刷新] 失败: {ex.Message}", ex);
}
}
///
/// 找到预览点应该插入的最近线段
///
/// 预览点位置
/// 路径点列表
/// 最近线段的前后两个点,如果找不到则返回null
private (PathPoint prevPoint, PathPoint nextPoint)? FindNearestLineSegment(Point3D previewPosition, List pathPoints)
{
if (pathPoints == null || pathPoints.Count < 2)
{
return null;
}
// 按索引排序路径点
var sortedPoints = pathPoints.OrderBy(p => p.Index).ToList();
double minDistance = double.MaxValue;
(PathPoint prevPoint, PathPoint nextPoint)? nearestSegment = null;
// 遍历相邻的路径点对,找到距离预览点最近的线段
for (int i = 0; i < sortedPoints.Count - 1; i++)
{
var currentPoint = sortedPoints[i];
var nextPoint = sortedPoints[i + 1];
// 计算预览点到线段的距离
var distance = CalculatePointToLineSegmentDistance(previewPosition, currentPoint.Position, nextPoint.Position);
if (distance < minDistance)
{
minDistance = distance;
nearestSegment = (currentPoint, nextPoint);
}
}
return nearestSegment;
}
///
/// 计算点到线段的距离
///
/// 目标点
/// 线段起点
/// 线段终点
/// 点到线段的最短距离
private double CalculatePointToLineSegmentDistance(Point3D point, Point3D lineStart, Point3D lineEnd)
{
// 线段向量
var lineVector = new Point3D(lineEnd.X - lineStart.X, lineEnd.Y - lineStart.Y, lineEnd.Z - lineStart.Z);
// 点到线段起点的向量
var pointVector = new Point3D(point.X - lineStart.X, point.Y - lineStart.Y, point.Z - lineStart.Z);
// 计算线段长度的平方
var lineLengthSquared = lineVector.X * lineVector.X + lineVector.Y * lineVector.Y + lineVector.Z * lineVector.Z;
if (lineLengthSquared == 0)
{
// 线段退化为点,返回点到点的距离
return CalculateDistance(point, lineStart);
}
// 计算投影参数t
var t = (pointVector.X * lineVector.X + pointVector.Y * lineVector.Y + pointVector.Z * lineVector.Z) / lineLengthSquared;
// 将t限制在[0,1]范围内
t = Math.Max(0, Math.Min(1, t));
// 计算线段上最近点
var closestPoint = new Point3D(
lineStart.X + t * lineVector.X,
lineStart.Y + t * lineVector.Y,
lineStart.Z + t * lineVector.Z
);
// 返回点到最近点的距离
return CalculateDistance(point, closestPoint);
}
private static DateTime _lastRefreshTime = DateTime.MinValue;
#endregion
}
///
/// 切点类型枚举
///
public enum TangentPointType
{
///
/// 进入切点(Ts)
///
EntryTangent,
///
/// 退出切点(Te)
///
ExitTangent
}
///
/// 方块标记数据结构(用于切点)
///
public class SquareMarker
{
///
/// 中心坐标
///
public Point3D Center { get; set; }
///
/// 方块面法向量
///
public Vector3D Normal { get; set; }
///
/// 方块边长
///
public double Size { get; set; }
///
/// 方块颜色
///
public Color Color { get; set; }
///
/// 不透明度 (1.0 = 完全不透明, 0.0 = 完全透明)
///
public double Alpha { get; set; }
///
/// 所属边ID
///
public string EdgeId { get; set; }
///
/// 切点类型
///
public TangentPointType TangentType { get; set; }
public override string ToString()
{
return $"SquareMarker[类型={TangentType}, 中心=({Center.X:F2},{Center.Y:F2},{Center.Z:F2}), 边长={Size:F2}]";
}
}
///
/// 圆形标记数据结构
///
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 GridPointType GridPointType { get; set; } = GridPointType.Sphere;
///
/// 序号
///
public int SequenceNumber { get; set; }
///
/// 创建时间
///
public DateTime CreatedTime { get; set; }
///
/// 是否可见
///
public bool IsVisible { get; set; }
///
/// 是否为不在路径上的控制点(半透明)
///
public bool IsOffPath { get; set; } = false;
///
/// 位置(Center的别名,用于预览点兼容性)
///
public Point3D Position
{
get { return Center; }
set { Center = value; }
}
///
/// 关联的路径点对象
///
public PathPoint PathPoint { get; set; }
public override string ToString()
{
return $"CircleMarker[序号={SequenceNumber}, 类型={PointType}, 中心=({Center.X:F2},{Center.Y:F2},{Center.Z:F2}), 半径={Radius:F2}]";
}
}
}