# 吊装路径通行空间设计

## 概述

吊装路径（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);
}
```

### 起点终点延伸

为了确保通行空间完全包裹物体，所有水平段的起点和终点都需要向路径方向延伸半个物体尺寸：

```csharp
// 通行空间包裹调整：水平段起点向反方向、终点向正方向各延伸半个物体尺寸
if (_visualizationMode == PathVisualizationMode.ObjectSpace && !isVerticalSegment)
{
    double offset = alongPathSize / 2.0;  // 沿路径方向的物体尺寸的一半
    
    // 起点向反方向延伸
    adjustedStartPoint = new Point3D(
        adjustedStartPoint.X - dirX * offset,
        adjustedStartPoint.Y - dirY * offset,
        adjustedStartPoint.Z - dirZ * offset
    );
    
    // 终点向正方向延伸
    adjustedEndPoint = new Point3D(
        adjustedEndPoint.X + dirX * offset,
        adjustedEndPoint.Y + dirY * offset,
        adjustedEndPoint.Z + dirZ * offset
    );
}
```

**原因**：路径点使用物体中心坐标，如果不延伸，起点和终点处只会包裹物体的一半。

### 渲染模式

使用 `ObjectSpace` 可视化模式显示吊装路径的通行空间：

- 起吊/下降段：垂直长方体，截面为物体宽度 × 物体长度
- 平移段（初始方向）：水平长方体，截面为物体宽度 × 物体高度
- 平移段（转折90度）：水平长方体，截面为物体长度 × 物体高度
- **所有水平段**：起点和终点向路径方向延伸半个物体尺寸，确保完全包裹

## 参考

- 门式起重机（Gantry Crane）运动学
- 无人物流吊装作业规范
