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