实现了曲线化路径可视化
This commit is contained in:
parent
33296c7415
commit
10f408e361
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user