From b7cbc64dd4c4185f2c238e5b3156dec87f820faf Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Sat, 30 Aug 2025 21:54:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=B7=AF=E5=BE=84=E7=82=B9?= =?UTF-8?q?=E6=8F=92=E5=85=A5=E4=BD=8D=E7=BD=AE=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E8=B7=AF=E5=BE=84=E7=82=B9=E7=8E=B0=E5=9C=A8=E4=BC=9A?= =?UTF-8?q?=E6=8F=92=E5=85=A5=E5=88=B0=E9=A2=84=E8=A7=88=E8=BF=9E=E7=BA=BF?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E7=9A=84=E6=AD=A3=E7=A1=AE=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 在PathPlanningManager中添加_previewInsertIndex字段保存预览插入索引 2. 添加FindNearestLineSegmentWithIndex等方法计算最近线段和插入位置 3. 修改SetPreviewPoint方法,在设置预览点时计算并保存插入索引 4. 修改ConfirmPreviewPoint方法,使用Insert()而不是Add()进行插入操作 5. 修改ClearPreviewPoint方法,清除预览时也清除保存的插入索引 问题:之前预览连线工作正常能显示正确插入位置,但确认添加时新路径点被错误地添加到路径末尾 解决:现在新路径点会插入到预览时计算出的正确位置,确保路径点顺序符合用户期望 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/Core/PathPlanningManager.cs | 153 +++++++++++++++++++++++++++++++- test_insert_position.md | 46 ++++++++++ 2 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 test_insert_position.md diff --git a/src/Core/PathPlanningManager.cs b/src/Core/PathPlanningManager.cs index cb5a242..8109839 100644 --- a/src/Core/PathPlanningManager.cs +++ b/src/Core/PathPlanningManager.cs @@ -49,6 +49,7 @@ namespace NavisworksTransport // 预览点管理 private PathPoint _previewPoint = null; private bool _isPreviewMode = false; + private int _previewInsertIndex = -1; // 保存预览点应该插入的索引位置 /// /// 获取当前是否在预览模式 @@ -1418,6 +1419,19 @@ namespace NavisworksTransport : PathPointType.WayPoint; } + // 计算预览点应该插入的位置 + _previewInsertIndex = -1; // 重置插入索引 + if (CurrentRoute.Points.Count >= 2) + { + // 如果路径中有至少2个点,计算最佳插入位置 + var nearestSegment = FindNearestLineSegmentWithIndex(worldPoint, CurrentRoute.Points.ToList()); + if (nearestSegment.HasValue) + { + _previewInsertIndex = nearestSegment.Value.insertIndex; + LogManager.Info($"预览点计算出插入索引: {_previewInsertIndex},位于 {nearestSegment.Value.prevPoint.Name} 和 {nearestSegment.Value.nextPoint.Name} 之间"); + } + } + // 创建预览点(不添加到路径中) _previewPoint = new PathPoint { @@ -1427,13 +1441,20 @@ namespace NavisworksTransport }; _isPreviewMode = true; - LogManager.Info($"预览点已设置: {_previewPoint.Name}, 位置: ({worldPoint.X:F2}, {worldPoint.Y:F2}, {worldPoint.Z:F2})"); + LogManager.Info($"预览点已设置: {_previewPoint.Name}, 位置: ({worldPoint.X:F2}, {worldPoint.Y:F2}, {worldPoint.Z:F2}), 插入索引: {_previewInsertIndex}"); // 绘制预览点可视化(灰色) try { DrawPreviewPointVisualization(_previewPoint); LogManager.Info($"预览点3D可视化已更新: {_previewPoint.Name}"); + + // 如果路径中有足够的点,绘制预览连线 + if (CurrentRoute.Points.Count >= 2) + { + DrawPreviewLinesVisualization(_previewPoint, CurrentRoute.Points.ToList()); + LogManager.Info($"预览连线已绘制: {_previewPoint.Name}"); + } } catch (Exception renderEx) { @@ -1477,9 +1498,19 @@ namespace NavisworksTransport Type = _previewPoint.Type }; - // 添加到当前路径 - CurrentRoute.Points.Add(confirmPoint); - LogManager.Info($"路径点已确认添加: {confirmPoint.Name}, 位置: ({confirmPoint.Position.X:F2}, {confirmPoint.Position.Y:F2}, {confirmPoint.Position.Z:F2})"); + // 根据保存的插入索引决定添加方式 + if (_previewInsertIndex >= 0 && _previewInsertIndex <= CurrentRoute.Points.Count) + { + // 在指定位置插入路径点 + CurrentRoute.Points.Insert(_previewInsertIndex, confirmPoint); + LogManager.Info($"路径点已插入到索引 {_previewInsertIndex}: {confirmPoint.Name}, 位置: ({confirmPoint.Position.X:F2}, {confirmPoint.Position.Y:F2}, {confirmPoint.Position.Z:F2})"); + } + else + { + // 如果没有有效的插入索引,添加到末尾(原来的行为) + CurrentRoute.Points.Add(confirmPoint); + LogManager.Info($"路径点已添加到末尾: {confirmPoint.Name}, 位置: ({confirmPoint.Position.X:F2}, {confirmPoint.Position.Y:F2}, {confirmPoint.Position.Z:F2})"); + } // 清除预览状态 ClearPreviewPoint(); @@ -1532,6 +1563,7 @@ namespace NavisworksTransport _previewPoint = null; _isPreviewMode = false; + _previewInsertIndex = -1; // 清除保存的插入索引 } /// @@ -1551,6 +1583,21 @@ namespace NavisworksTransport } } + /// + /// 绘制预览连线的3D可视化(灰色) + /// + /// 预览点 + /// 当前路径点列表 + private void DrawPreviewLinesVisualization(PathPoint previewPoint, List pathPoints) + { + if (_renderPlugin != null && previewPoint != null && pathPoints != null) + { + // 绘制预览连线 + _renderPlugin.RenderPreviewLines(previewPoint, pathPoints); + LogManager.Info($"预览连线可视化已绘制: {previewPoint.Name}"); + } + } + /// /// 清除预览点可视化 /// @@ -2642,6 +2689,104 @@ namespace NavisworksTransport #endregion + #region 预览插入位置计算方法 + + /// + /// 查找预览点应该插入的最近线段和插入索引 + /// + /// 预览点位置 + /// 路径点列表 + /// 最近线段的前后两点以及插入索引,未找到时返回null + private (PathPoint prevPoint, PathPoint nextPoint, int insertIndex)? FindNearestLineSegmentWithIndex(Point3D previewPosition, List pathPoints) + { + if (pathPoints == null || pathPoints.Count < 2) + { + return null; + } + + // 对路径点进行排序(按添加顺序,即列表中的索引) + var sortedPoints = pathPoints.ToList(); + + double minDistance = double.MaxValue; + (PathPoint prevPoint, PathPoint nextPoint, int insertIndex)? 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; + // 插入索引应该是nextPoint的索引位置,这样新点会插入到currentPoint和nextPoint之间 + nearestSegment = (currentPoint, nextPoint, i + 1); + } + } + + 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 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); + } + + #endregion + #region 静态方法 /// diff --git a/test_insert_position.md b/test_insert_position.md new file mode 100644 index 0000000..aeb9503 --- /dev/null +++ b/test_insert_position.md @@ -0,0 +1,46 @@ +# 路径点插入位置修复测试 + +## 问题描述 +修复了预览连线功能工作正常,但确认添加路径点时,新的路径点被错误地添加到路径末尾,而不是插入到预览时计算出来的正确位置的问题。 + +## 修改内容 + +### 1. 在 PathPlanningManager 中添加字段保存预览插入的索引位置 +```csharp +private int _previewInsertIndex = -1; // 保存预览点应该插入的索引位置 +``` + +### 2. 添加了查找最近线段的方法 +- `FindNearestLineSegmentWithIndex()` - 查找最近线段并返回插入索引 +- `CalculatePointToLineSegmentDistance()` - 计算点到线段距离 +- `CalculateDistance()` - 计算两点间距离 + +### 3. 修改 SetPreviewPoint 方法 +- 在设置预览点时,计算并保存最佳插入位置索引 +- 当路径中有至少2个点时,调用 `FindNearestLineSegmentWithIndex()` 计算插入位置 + +### 4. 修改 ConfirmPreviewPoint 方法 +- 使用保存的 `_previewInsertIndex` 进行 `Insert()` 操作,而不是 `Add()` +- 如果没有有效插入索引,则回退到原来的添加到末尾的行为 + +### 5. 修改 ClearPreviewPoint 方法 +- 清除预览时也清除保存的插入索引 + +## 测试步骤 +1. 创建新路径,添加至少2个路径点 +2. 启用添加路径点模式 +3. 将鼠标移动到两个现有路径点之间的位置 +4. 观察预览连线是否正确显示插入位置 +5. 点击确认添加路径点 +6. 验证新路径点是否插入到预览显示的正确位置,而不是路径末尾 + +## 预期结果 +- 预览连线正确显示新路径点应该插入的位置 +- 确认添加时,新路径点插入到预览时计算的正确位置 +- 路径点顺序符合用户的期望 + +## 技术细节 +- 插入索引的计算基于点到线段的最短距离 +- 使用了几何算法计算点到线段的垂直距离 +- 插入索引是最近线段的第二个点的索引位置 +- 例如:如果最近线段是点1到点2,新点应该插入到索引2的位置 \ No newline at end of file