实现了曲线化路径可视化

This commit is contained in:
tian 2025-12-31 18:13:11 +08:00
parent 33296c7415
commit 10f408e361
3 changed files with 506 additions and 37 deletions

View File

@ -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;
}

View File

@ -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<Point3D>();
for (int i = 0; i <= sampleCount; i++)
{
double t = i / (double)sampleCount;
Point3D sampledPoint = startPoint + (endPoint - startPoint) * t;
edge.SampledPoints.Add(sampledPoint);
}
}
}
}
}
}
/// <summary>

View File

@ -224,9 +224,24 @@ namespace NavisworksTransport
/// </summary>
public int ToIndex { get; set; }
/// <summary>
/// 路径段类型
/// </summary>
public PathSegmentType SegmentType { get; set; } = PathSegmentType.Straight;
/// <summary>
/// 圆弧轨迹数据仅当SegmentType=Arc时有效
/// </summary>
public ArcTrajectory Trajectory { get; set; }
/// <summary>
/// 采样点列表(用于圆弧段的多段圆柱体渲染)
/// </summary>
public List<Point3D> 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<CircleMarker> PointMarkers { get; set; }
/// <summary>
/// 连线标记集合
/// 连线标记集合(已废弃,保留用于兼容)
/// </summary>
[Obsolete("使用ControlLineMarkers或PathLineMarkers代替")]
public List<LineMarker> LineMarkers { get; set; }
/// <summary>
/// 控制点连线集合(用户意图,半透明)
/// </summary>
public List<LineMarker> ControlLineMarkers { get; set; }
/// <summary>
/// 路径连线集合(真实路径,不透明)
/// </summary>
public List<LineMarker> PathLineMarkers { get; set; }
/// <summary>
/// 切点标记集合
/// </summary>
public List<SquareMarker> TangentMarkers { get; set; }
/// <summary>
/// 车辆通行空间标记集合
/// </summary>
public List<VehicleSpaceMarker> VehicleSpaceMarkers { get; set; }
/// <summary>
/// 是否显示控制点可视化(用户意图)
/// </summary>
public bool ShowControlVisualization { get; set; } = true;
/// <summary>
/// 最后更新时间
/// </summary>
@ -272,13 +308,16 @@ namespace NavisworksTransport
{
PointMarkers = new List<CircleMarker>();
LineMarkers = new List<LineMarker>();
ControlLineMarkers = new List<LineMarker>();
PathLineMarkers = new List<LineMarker>();
TangentMarkers = new List<SquareMarker>();
VehicleSpaceMarkers = new List<VehicleSpaceMarker>();
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}]";
}
}
/// <summary>
@ -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
}
}
/// <summary>
/// 设置控制点可视化的显示状态
/// </summary>
/// <param name="pathId">路径ID</param>
/// <param name="show">是否显示</param>
public void SetControlVisualizationVisibility(string pathId, bool show)
{
lock (_lockObject)
{
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
{
if (visualization.ShowControlVisualization != show)
{
visualization.ShowControlVisualization = show;
RequestViewRefresh();
}
}
}
}
/// <summary>
/// 切换控制点可视化的显示状态
/// </summary>
/// <param name="pathId">路径ID</param>
public void ToggleControlVisualization(string pathId)
{
lock (_lockObject)
{
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
{
visualization.ShowControlVisualization = !visualization.ShowControlVisualization;
RequestViewRefresh();
}
}
}
/// <summary>
/// 判断是否为网格可视化路径
/// </summary>
@ -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;
}
/// <summary>
/// 构建控制点连线(用户意图,半透明)
/// </summary>
/// <param name="visualization">路径可视化对象</param>
/// <param name="sortedPoints">排序后的路径点列表</param>
private void BuildControlLines(PathVisualization visualization, List<PathPoint> 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);
}
}
/// <summary>
/// 构建路径连线(真实路径,不透明)
/// </summary>
/// <param name="visualization">路径可视化对象</param>
/// <param name="sortedPoints">排序后的路径点列表</param>
private void BuildPathLines(PathVisualization visualization, List<PathPoint> sortedPoints)
{
var edges = visualization.PathRoute.Edges;
// 1. 收集在路径上的控制点ID
var onPathPointIds = new HashSet<string>();
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);
}
}
}
/// <summary>
/// 添加切点标记
/// </summary>
/// <param name="visualization">路径可视化对象</param>
/// <param name="edge">路径边</param>
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);
}
/// <summary>
/// 创建车辆通行空间标记
/// </summary>
@ -1666,6 +1895,60 @@ namespace NavisworksTransport
graphics.Circle(adjustCenterPoint, pointMarker.Normal, pointMarker.Radius, true);
}
/// <summary>
/// 渲染方块标记(切点)
/// </summary>
/// <param name="graphics">图形上下文</param>
/// <param name="marker">方块标记</param>
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);
}
/// <summary>
/// 渲染连线标记(支持直线段和圆弧段)
/// </summary>
/// <param name="graphics">图形上下文</param>
/// <param name="lineMarker">连线标记</param>
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);
}
}
/// <summary>
/// 请求视图刷新(带防抖机制)
/// </summary>
@ -1776,6 +2059,68 @@ namespace NavisworksTransport
#endregion
}
/// <summary>
/// 切点类型枚举
/// </summary>
public enum TangentPointType
{
/// <summary>
/// 进入切点Ts
/// </summary>
EntryTangent,
/// <summary>
/// 退出切点Te
/// </summary>
ExitTangent
}
/// <summary>
/// 方块标记数据结构(用于切点)
/// </summary>
public class SquareMarker
{
/// <summary>
/// 中心坐标
/// </summary>
public Point3D Center { get; set; }
/// <summary>
/// 方块面法向量
/// </summary>
public Vector3D Normal { get; set; }
/// <summary>
/// 方块边长
/// </summary>
public double Size { get; set; }
/// <summary>
/// 方块颜色
/// </summary>
public Color Color { get; set; }
/// <summary>
/// 不透明度 (1.0 = 完全不透明, 0.0 = 完全透明)
/// </summary>
public double Alpha { get; set; }
/// <summary>
/// 所属边ID
/// </summary>
public string EdgeId { get; set; }
/// <summary>
/// 切点类型
/// </summary>
public TangentPointType TangentType { get; set; }
public override string ToString()
{
return $"SquareMarker[类型={TangentType}, 中心=({Center.X:F2},{Center.Y:F2},{Center.Z:F2}), 边长={Size:F2}]";
}
}
/// <summary>
/// 圆形标记数据结构
/// </summary>
@ -1835,6 +2180,11 @@ namespace NavisworksTransport
/// </summary>
public bool IsVisible { get; set; }
/// <summary>
/// 是否为不在路径上的控制点(半透明)
/// </summary>
public bool IsOffPath { get; set; } = false;
/// <summary>
/// 位置Center的别名用于预览点兼容性
/// </summary>