From 10f408e361ee639ec20964660dfe6d619a043ca2 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Wed, 31 Dec 2025 18:13:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=BA=86=E6=9B=B2=E7=BA=BF?= =?UTF-8?q?=E5=8C=96=E8=B7=AF=E5=BE=84=E5=8F=AF=E8=A7=86=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Core/PathCurveEngine.cs | 36 ++- src/Core/PathDatabase.cs | 95 ++++++- src/Core/PathPointRenderPlugin.cs | 412 +++++++++++++++++++++++++++--- 3 files changed, 506 insertions(+), 37 deletions(-) diff --git a/src/Core/PathCurveEngine.cs b/src/Core/PathCurveEngine.cs index b617635..97802ff 100644 --- a/src/Core/PathCurveEngine.cs +++ b/src/Core/PathCurveEngine.cs @@ -151,6 +151,11 @@ namespace NavisworksTransport return points; } + // 打印角度信息 + double angleDegrees = trajectory.DeflectionAngle * 180.0 / Math.PI; + LogManager.Info($"圆弧采样: 角度={angleDegrees:F2}度, 弧度={trajectory.DeflectionAngle:F4}, 半径={trajectory.ActualRadius:F2}m, 长度={trajectory.ArcLength:F2}m"); + LogManager.Info($" Ts=({trajectory.Ts.X:F3},{trajectory.Ts.Y:F3},{trajectory.Ts.Z:F3}), Te=({trajectory.Te.X:F3},{trajectory.Te.Y:F3},{trajectory.Te.Z:F3})"); + // 根据采样步长计算采样点数量 int sampleCount = Math.Max(2, (int)Math.Ceiling(trajectory.ArcLength / samplingStep)); @@ -164,11 +169,23 @@ namespace NavisworksTransport new Point3D(endVec.X, endVec.Y, endVec.Z)); Vector3D rotationAxis = new Vector3D(cross.X, cross.Y, cross.Z).Normalize(); + LogManager.Info($" 旋转轴=({rotationAxis.X:F6},{rotationAxis.Y:F6},{rotationAxis.Z:F6})"); + + // 计算有向旋转角度(使用 Atan2 而不是 Acos,以保留方向信息) + double dot = GeometryHelper.DotProduct( + new Point3D(startVec.X, startVec.Y, startVec.Z), + new Point3D(endVec.X, endVec.Y, endVec.Z)); + double crossMag = new Vector3D(cross.X, cross.Y, cross.Z).Length; + + // 使用 Atan2 计算有向角度,确保旋转方向正确 + double signedAngle = Math.Atan2(crossMag, dot); + LogManager.Info($" 有向角度: {signedAngle:F4}rad ({signedAngle * 180.0 / Math.PI:F2}度)"); + // 等角度插值 for (int i = 0; i <= sampleCount; i++) { double t = i / (double)sampleCount; - double theta = t * trajectory.DeflectionAngle; + double theta = t * signedAngle; // Rodrigues旋转公式 Point3D sampledPoint = RotatePointAroundAxis( @@ -178,9 +195,26 @@ namespace NavisworksTransport theta ); + if (i == 0 || i == sampleCount) + { + LogManager.Info($" 采样点[{i}/{sampleCount}]: t={t:F4}, theta={theta:F4}rad, 坐标=({sampledPoint.X:F3},{sampledPoint.Y:F3},{sampledPoint.Z:F3})"); + } + points.Add(sampledPoint); } + // 验证最后一个点是否接近Te + if (points.Count > 0) + { + var lastPoint = points.Last(); + double distanceToTe = (lastPoint - trajectory.Te).Length; + LogManager.Info($" 终点验证: 目标Te=({trajectory.Te.X:F3},{trajectory.Te.Y:F3},{trajectory.Te.Z:F3}), 实际终点=({lastPoint.X:F3},{lastPoint.Y:F3},{lastPoint.Z:F3}), 误差={distanceToTe:F6}m"); + if (distanceToTe > 0.001) + { + LogManager.Warning($" 圆弧采样终点误差: {distanceToTe:F6}m"); + } + } + return points; } diff --git a/src/Core/PathDatabase.cs b/src/Core/PathDatabase.cs index 61b0575..ff4e47e 100644 --- a/src/Core/PathDatabase.cs +++ b/src/Core/PathDatabase.cs @@ -2,7 +2,9 @@ using System; using System.Collections.Generic; using System.Data.SQLite; using System.IO; +using System.Linq; using Autodesk.Navisworks.Api; +using NavisworksTransport.Core.Config; namespace NavisworksTransport { @@ -585,14 +587,33 @@ namespace NavisworksTransport { cmd.Parameters.AddWithValue("@id", edge.Id); cmd.Parameters.AddWithValue("@routeId", routeId); - cmd.Parameters.AddWithValue("@startId", edge.StartPointId); - cmd.Parameters.AddWithValue("@endId", edge.EndPointId); + cmd.Parameters.AddWithValue("@startId", edge.StartPointId ?? ""); + cmd.Parameters.AddWithValue("@endId", edge.EndPointId ?? ""); cmd.Parameters.AddWithValue("@segType", (int)edge.SegmentType); cmd.Parameters.AddWithValue("@length", edge.PhysicalLength); - // 圆弧轨迹数据 - if (edge.SegmentType == PathSegmentType.Arc && edge.Trajectory != null) + // 直线段:保存起止点坐标 + if (edge.SegmentType == PathSegmentType.Straight && edge.SampledPoints != null && edge.SampledPoints.Count >= 2) { + cmd.Parameters.AddWithValue("@tsx", edge.SampledPoints.First().X); + cmd.Parameters.AddWithValue("@tsy", edge.SampledPoints.First().Y); + cmd.Parameters.AddWithValue("@tsz", edge.SampledPoints.First().Z); + cmd.Parameters.AddWithValue("@tex", edge.SampledPoints.Last().X); + cmd.Parameters.AddWithValue("@tey", edge.SampledPoints.Last().Y); + cmd.Parameters.AddWithValue("@tez", edge.SampledPoints.Last().Z); + + // 圆弧参数为NULL + cmd.Parameters.AddWithValue("@acx", DBNull.Value); + cmd.Parameters.AddWithValue("@acy", DBNull.Value); + cmd.Parameters.AddWithValue("@acz", DBNull.Value); + cmd.Parameters.AddWithValue("@reqR", DBNull.Value); + cmd.Parameters.AddWithValue("@actR", DBNull.Value); + cmd.Parameters.AddWithValue("@angle", DBNull.Value); + cmd.Parameters.AddWithValue("@arcLen", DBNull.Value); + } + else if (edge.SegmentType == PathSegmentType.Arc && edge.Trajectory != null) + { + // 圆弧段:保存圆弧轨迹数据 cmd.Parameters.AddWithValue("@tsx", edge.Trajectory.Ts.X); cmd.Parameters.AddWithValue("@tsy", edge.Trajectory.Ts.Y); cmd.Parameters.AddWithValue("@tsz", edge.Trajectory.Ts.Z); @@ -609,7 +630,7 @@ namespace NavisworksTransport } else { - // 直线段,圆弧参数为NULL + // 其他情况,所有参数为NULL cmd.Parameters.AddWithValue("@tsx", DBNull.Value); cmd.Parameters.AddWithValue("@tsy", DBNull.Value); cmd.Parameters.AddWithValue("@tsz", DBNull.Value); @@ -700,11 +721,75 @@ namespace NavisworksTransport ArcLength = Convert.ToDouble(reader["ArcLength"]) }; } + else if (edge.SegmentType == PathSegmentType.Straight) + { + // 直线段也加载Ts和Te(用于重新计算SampledPoints) + if (!reader.IsDBNull(reader.GetOrdinal("Ts_X")) && + !reader.IsDBNull(reader.GetOrdinal("Te_X"))) + { + edge.Trajectory = new ArcTrajectory + { + Ts = new Point3D( + Convert.ToDouble(reader["Ts_X"]), + Convert.ToDouble(reader["Ts_Y"]), + Convert.ToDouble(reader["Ts_Z"])), + Te = new Point3D( + Convert.ToDouble(reader["Te_X"]), + Convert.ToDouble(reader["Te_Y"]), + Convert.ToDouble(reader["Te_Z"])), + ArcCenter = new Point3D(0, 0, 0), // 直线段没有圆心 + RequestedRadius = 0, + ActualRadius = 0, + DeflectionAngle = 0, + ArcLength = 0 + }; + } + } route.Edges.Add(edge); } } } + + // 重新计算SampledPoints(因为数据库中没有保存采样点) + if (route.Edges.Count > 0) + { + double samplingStep = ConfigManager.Instance.Current.PathEditing.ArcSamplingStep; + foreach (var edge in route.Edges) + { + if (edge.SegmentType == PathSegmentType.Arc && edge.Trajectory != null) + { + // 圆弧段:使用PathCurveEngine重新采样 + edge.SampledPoints = PathCurveEngine.SampleArc(edge.Trajectory, samplingStep); + } + else if (edge.SegmentType == PathSegmentType.Straight) + { + // 直线段:从数据库加载的Ts和Te重新采样 + Point3D startPoint = null; + Point3D endPoint = null; + + // 尝试从Trajectory中获取(直线段也可能用Trajectory存储起止点) + if (edge.Trajectory != null) + { + startPoint = edge.Trajectory.Ts; + endPoint = edge.Trajectory.Te; + } + + // 如果找到了起止点,重新采样 + if (startPoint != null && endPoint != null) + { + int sampleCount = Math.Max(2, (int)Math.Ceiling(edge.PhysicalLength / samplingStep)); + edge.SampledPoints = new List(); + for (int i = 0; i <= sampleCount; i++) + { + double t = i / (double)sampleCount; + Point3D sampledPoint = startPoint + (endPoint - startPoint) * t; + edge.SampledPoints.Add(sampledPoint); + } + } + } + } + } } /// diff --git a/src/Core/PathPointRenderPlugin.cs b/src/Core/PathPointRenderPlugin.cs index 541c727..9e0a607 100644 --- a/src/Core/PathPointRenderPlugin.cs +++ b/src/Core/PathPointRenderPlugin.cs @@ -224,9 +224,24 @@ namespace NavisworksTransport /// 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}, 起点=({StartPoint.X:F2},{StartPoint.Y:F2},{StartPoint.Z:F2}), 终点=({EndPoint.X:F2},{EndPoint.Y:F2},{EndPoint.Z:F2})]"; + return $"LineMarker[{FromIndex}->{ToIndex}, 类型={SegmentType}, 起点=({StartPoint.X:F2},{StartPoint.Y:F2},{StartPoint.Z:F2}), 终点=({EndPoint.X:F2},{EndPoint.Y:F2},{EndPoint.Z:F2})]"; } } @@ -251,15 +266,36 @@ namespace NavisworksTransport 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; + /// /// 最后更新时间 /// @@ -272,13 +308,16 @@ namespace NavisworksTransport { 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}, 连线数={LineMarkers.Count}]"; + return $"PathVisualization[PathId={PathId}, 点数={PointMarkers.Count}, 控制连线={ControlLineMarkers.Count}, 路径连线={PathLineMarkers.Count}]"; } } /// @@ -440,18 +479,45 @@ namespace NavisworksTransport // 渲染所有正式路径 foreach (var visualization in _pathVisualizations.Values) { - // 渲染所有点标记 - foreach (var pointMarker in visualization.PointMarkers) + // 渲染控制点可视化(用户意图) + if (visualization.ShowControlVisualization) { - graphics.Color(pointMarker.Color, pointMarker.Alpha); - RenderPointMarker(graphics, pointMarker); + // 渲染所有点标记 + 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); + } } - // 渲染所有连线(删除频繁的调试日志以避免日志泛滥) - foreach (var lineMarker in visualization.LineMarkers) + // 渲染真实路径可视化(Edges + 切点) + // 先渲染切点(在底层) + foreach (var tangentMarker in visualization.TangentMarkers) { - graphics.Color(lineMarker.Color, 1.0); - graphics.Cylinder(lineMarker.StartPoint, lineMarker.EndPoint, lineMarker.Radius); + 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); } // 渲染车辆通行空间(矩形通道) @@ -615,6 +681,42 @@ namespace NavisworksTransport } } + /// + /// 设置控制点可视化的显示状态 + /// + /// 路径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(); + } + } + } + /// /// 判断是否为网格可视化路径 /// @@ -760,6 +862,9 @@ namespace NavisworksTransport // 清空现有标记 visualization.PointMarkers.Clear(); visualization.LineMarkers.Clear(); + visualization.ControlLineMarkers.Clear(); + visualization.PathLineMarkers.Clear(); + visualization.TangentMarkers.Clear(); visualization.VehicleSpaceMarkers.Clear(); var points = visualization.PathRoute.Points; @@ -768,33 +873,20 @@ namespace NavisworksTransport // 按索引排序点 var sortedPoints = points.OrderBy(p => p.Index).ToList(); - // 构建点标记 + // 构建点标记(所有控制点) foreach (var point in sortedPoints) { var pointMarker = CreatePointMarker(point); visualization.PointMarkers.Add(pointMarker); } - // 根据可视化模式构建连接标记 - if (_visualizationMode == PathVisualizationMode.StandardLine) - { - // 构建标准连线标记(按排序后的顺序连接) - for (int i = 0; i < sortedPoints.Count - 1; i++) - { - var currentPoint = sortedPoints[i]; - var nextPoint = sortedPoints[i + 1]; + // 构建控制点连线(用户意图,半透明) + BuildControlLines(visualization, sortedPoints); - var lineMarker = new LineMarker - { - StartPoint = currentPoint.Position, - EndPoint = nextPoint.Position, - Color = GetRenderColor(RenderColorType.Line), - Radius = GetLineRadius(), - FromIndex = currentPoint.Index, - ToIndex = nextPoint.Index - }; - visualization.LineMarkers.Add(lineMarker); - } + // 构建路径连线(真实路径,不透明,仅当Edges存在时) + if (visualization.PathRoute.Edges != null && visualization.PathRoute.Edges.Count > 0) + { + BuildPathLines(visualization, sortedPoints); } else if (_visualizationMode == PathVisualizationMode.VehicleSpace) { @@ -832,6 +924,143 @@ namespace NavisworksTransport 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); + } + /// /// 创建车辆通行空间标记 /// @@ -1666,6 +1895,60 @@ namespace NavisworksTransport 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); + } + } + /// /// 请求视图刷新(带防抖机制) /// @@ -1776,6 +2059,68 @@ namespace NavisworksTransport #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}]"; + } + } + /// /// 圆形标记数据结构 /// @@ -1835,6 +2180,11 @@ namespace NavisworksTransport /// public bool IsVisible { get; set; } + /// + /// 是否为不在路径上的控制点(半透明) + /// + public bool IsOffPath { get; set; } = false; + /// /// 位置(Center的别名,用于预览点兼容性) ///