From eeeaceacc4727235febb4a40cd80ec77dc7030fd Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Wed, 4 Feb 2026 11:54:39 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=8A=E8=A3=85=E8=B7=AF?=
=?UTF-8?q?=E5=BE=84=E9=80=9A=E8=A1=8C=E7=A9=BA=E9=97=B4=E7=A9=BA=E4=B8=AD?=
=?UTF-8?q?=E6=AE=B5=E6=96=B9=E5=90=91=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
doc/design/2026/吊装路径通行空间设计.md | 142 ++++++++++++++++++++++++
doc/requirement/todo_features.md | 4 +-
src/Core/PathPointRenderPlugin.cs | 36 +++++-
3 files changed, 174 insertions(+), 8 deletions(-)
create mode 100644 doc/design/2026/吊装路径通行空间设计.md
diff --git a/doc/design/2026/吊装路径通行空间设计.md b/doc/design/2026/吊装路径通行空间设计.md
new file mode 100644
index 0000000..f304f50
--- /dev/null
+++ b/doc/design/2026/吊装路径通行空间设计.md
@@ -0,0 +1,142 @@
+# 吊装路径通行空间设计
+
+## 概述
+
+吊装路径(Hoisting Path)采用门式起重机(Gantry Crane)的运动方式,与车辆沿地面路径行驶不同,物体在平移过程中**不发生旋转**。
+
+## 运动阶段
+
+吊装路径由三个明确的阶段组成:
+
+```
+起吊段(垂直) → 平移段(水平) → 下降段(垂直)
+ ↑ ↓
+ 地面 地面
+```
+
+### 1. 起吊段
+
+- **方向**:垂直向上
+- **通行空间截面**:宽度 × 长度(水平方向)
+- **特点**:物体从地面垂直起升到安全高度
+
+### 2. 平移段
+
+- **方向**:水平移动(可直角转折)
+- **特点**:物体姿态保持不变,仅做平移运动
+- **方向处理**:
+ - 初始方向:通行空间正面(物体宽度方向)垂直于路径
+ - 转折90度:通行空间侧面(物体长度方向)垂直于路径
+
+### 3. 下降段
+
+- **方向**:垂直向下
+- **通行空间截面**:宽度 × 长度(水平方向)
+- **特点**:物体从安全高度下降到目标地面位置
+
+## 通行空间尺寸设计
+
+### 关键设计原则
+
+由于吊装过程中**物体不旋转**,当路径水平转折90度时,相对于路径方向的物体朝向发生了变化:
+
+- 初始方向:物体正面朝向路径垂直方向
+- 转折90度:物体侧面朝向路径垂直方向
+
+因此需要检测水平段是否转折90度,并相应调整通行空间尺寸。
+
+### 尺寸计算
+
+| 段类型 | 路径方向 | 与初始方向关系 | 通行空间 width(垂直于路径) | 通行空间 height |
+|--------|----------|--------------|---------------------------|----------------|
+| 起吊/下降段 | 垂直 | - | 物体宽度 | 物体长度 |
+| 平移段 | 水平 | 相同(0度) | **物体宽度**(正面) | 物体高度 |
+| 平移段 | 水平 | 垂直(90度转折) | **物体长度**(侧面) | 物体高度 |
+
+### 代码实现
+
+在 `BuildDirectPathLines` 方法中检测90度转折:
+
+```csharp
+// 对于吊装路径水平段,检测是否转折90度
+bool isTurn90Horizontal = false;
+if (!isVerticalSegment && visualization.PathRoute.PathType == NavisworksTransport.PathType.Hoisting && horizontalDirection != null)
+{
+ // 计算当前水平段方向与初始水平段方向的点积
+ double dotProduct = currentDirection.X * horizontalDirection.X + currentDirection.Y * horizontalDirection.Y;
+ // 点积接近0表示垂直(90度转折)
+ isTurn90Horizontal = Math.Abs(dotProduct) < 0.1;
+}
+```
+
+在 `CalculatePassageSpaceParameters` 方法中:
+
+```csharp
+if (visualization.PathRoute.PathType == NavisworksTransport.PathType.Hoisting)
+{
+ // 吊装路径:根据段类型和方向设置尺寸
+ // 默认:width=物体宽度(垂直于路径),height=物体高度/长度
+ widthInMeters = _passageAcrossPath;
+ heightInMeters = isVerticalSegment ? _objectLength : _objectHeight;
+
+ // 🔥 水平段转折90度特殊处理:width改用物体长度
+ if (!isVerticalSegment && isTurn90Horizontal)
+ {
+ widthInMeters = _objectLength;
+ }
+}
+else
+{
+ // 其他路径类型
+ widthInMeters = _passageAcrossPath;
+ heightInMeters = _passageNormalToPath;
+}
+```
+
+### 关键变更说明
+
+**2025-02-01 修正**:
+
+- **问题**:吊装路径平移段转折90度后,通行空间方向与物体实际方向不符(物体不旋转,但通行空间尺寸未跟随路径方向变化)
+- **修正**:
+ - 检测水平段是否与初始方向垂直(90度转折)
+ - 初始方向:width = 物体宽度(正面朝向路径垂直方向)
+ - 转折90度:width = 物体长度(侧面朝向路径垂直方向)
+- **原因**:门式起重机平移时物体不旋转,路径转折90度后,物体相对于路径的朝向发生变化,通行空间需要相应调整以准确描述物体占据的空间
+
+## 与车辆路径的区别
+
+| 特性 | 车辆路径(地面) | 吊装路径(空中) |
+|------|----------------|----------------|
+| 运动方式 | 沿路径行驶,随路径转向 | 平移,姿态保持不变 |
+| 转向行为 | 车辆旋转以适应路径 | 物体不旋转 |
+| 通行空间方向 | 跟随路径方向 | 保持物体固有方向 |
+| 适用场景 | 地面物流运输 | 空中吊装作业 |
+
+## 可视化渲染
+
+### 方向计算
+
+在渲染通行空间时,使用 `horizontalDirection` 参数确保方向一致性:
+
+```csharp
+// 吊装路径特殊处理:物体平移不旋转,通行空间方向保持一致
+if (horizontalDirection != null)
+{
+ // 垂直段的 right 向量应该垂直于水平段的方向向量
+ right = new Vector3D(horizontalDirection.Y, -horizontalDirection.X, 0);
+}
+```
+
+### 渲染模式
+
+使用 `VehicleSpace` 可视化模式显示吊装路径的通行空间:
+
+- 起吊/下降段:垂直长方体,截面为物体宽度 × 物体长度
+- 平移段(初始方向):水平长方体,截面为物体宽度 × 物体高度
+- 平移段(转折90度):水平长方体,截面为物体长度 × 物体高度
+
+## 参考
+
+- 门式起重机(Gantry Crane)运动学
+- 无人物流吊装作业规范
diff --git a/doc/requirement/todo_features.md b/doc/requirement/todo_features.md
index 4462006..9d5cb04 100644
--- a/doc/requirement/todo_features.md
+++ b/doc/requirement/todo_features.md
@@ -6,11 +6,11 @@
1. [x] (优化)预计算高亮正确,结果高亮错误,高亮了很多不相干的同名物体
2. [ ] (BUG)预计算一个目标物体,161帧碰撞,机制有问题
-3. [ ] (BUG)吊装路径,终点前的一段拐弯,通行空间方向不对
+3. [x] (BUG)吊装路径,终点前的一段拐弯,通行空间方向不对
4. [x] (BUG)批处理时杀死程序,重新打开有执行中的任务,但删除选中没激活,再运行批处理,收到停止信号结束
5. [x] (BUG)碰撞检测历史列表,不自动加载,不自动刷新
6. [x] (优化)将通行空间透明度变成系统参数,可以修改
-7. [ ] (优化)ClashDetective检测中,每执行100次打印一下日志
+7. [x] (优化)ClashDetective检测中,每执行100次打印一下日志
8. [ ] (研究)如何利用剖面,过滤被隐藏的内容
9. [ ] (研究)根据路径高度范围,过滤几何体
10. [x] (BUG)批处理指定检测物体,预计算时没有忽略空间缓存建立
diff --git a/src/Core/PathPointRenderPlugin.cs b/src/Core/PathPointRenderPlugin.cs
index 9213c54..dbb2664 100644
--- a/src/Core/PathPointRenderPlugin.cs
+++ b/src/Core/PathPointRenderPlugin.cs
@@ -1369,9 +1369,10 @@ namespace NavisworksTransport
/// 路径可视化对象
/// 米到模型单位的转换系数
/// 是否是垂直段(仅用于吊装路径)
+ /// 是否是与初始方向垂直的水平段(吊装路径转折90度)
/// 通行空间参数元组
private (double heightInModelUnits, double widthInModelUnits, Color lineColor, double lineOpacity, double verticalOffset)
- CalculatePassageSpaceParameters(PathVisualization visualization, double metersToModelUnits, bool isVerticalSegment = false)
+ CalculatePassageSpaceParameters(PathVisualization visualization, double metersToModelUnits, bool isVerticalSegment = false, bool isTurn90Horizontal = false)
{
double heightInMeters;
double widthInMeters;
@@ -1383,11 +1384,16 @@ namespace NavisworksTransport
// VehicleSpace 模式:根据路径类型和段类型计算通行空间尺寸
if (visualization.PathRoute.PathType == NavisworksTransport.PathType.Hoisting)
{
- // 吊装路径:根据段类型设置尺寸
- // 水平段(空中平移):width=物体长度(前进方向宽度),height=物体高度
- // 垂直段(起吊/下降):width=物体宽度,height=物体长度
- widthInMeters = isVerticalSegment ? _passageAcrossPath : _objectLength;
+ // 吊装路径:根据段类型和方向设置尺寸
+ // 默认:width=物体宽度(垂直于路径),height=物体高度/长度
+ widthInMeters = _passageAcrossPath;
heightInMeters = isVerticalSegment ? _objectLength : _objectHeight;
+
+ // 🔥 水平段转折90度特殊处理:width改用物体长度
+ if (!isVerticalSegment && isTurn90Horizontal)
+ {
+ widthInMeters = _objectLength;
+ }
}
else
{
@@ -1775,8 +1781,26 @@ namespace NavisworksTransport
}
// 计算通行空间参数(根据段类型)
+ // 对于吊装路径水平段,检测是否转折90度
+ bool isTurn90Horizontal = false;
+ if (!isVerticalSegment && visualization.PathRoute.PathType == NavisworksTransport.PathType.Hoisting && horizontalDirection != null)
+ {
+ // 计算当前水平段方向
+ var currentDx = endPoint.Position.X - startPoint.Position.X;
+ var currentDy = endPoint.Position.Y - startPoint.Position.Y;
+ var currentLength = Math.Sqrt(currentDx * currentDx + currentDy * currentDy);
+ if (currentLength > 0.001)
+ {
+ var currentDirection = new Vector3D(currentDx / currentLength, currentDy / currentLength, 0);
+ // 计算与初始水平段方向的点积
+ double dotProduct = currentDirection.X * horizontalDirection.X + currentDirection.Y * horizontalDirection.Y;
+ // 点积接近0表示垂直(90度转折)
+ isTurn90Horizontal = Math.Abs(dotProduct) < 0.1;
+ }
+ }
+
var (heightInModelUnits, widthInModelUnits, lineColor, lineOpacity, verticalOffset) =
- CalculatePassageSpaceParameters(visualization, metersToModelUnits, isVerticalSegment);
+ CalculatePassageSpaceParameters(visualization, metersToModelUnits, isVerticalSegment, isTurn90Horizontal);
// 计算长方体的轴向量(right和up向量)
var (right, up) = CalculateCuboidAxes(startPoint.Position, endPoint.Position, horizontalDirection);