# SectionClipHelper 使用指南

## 文件位置

`src/Utils/SectionClipHelper.cs`

## 用途

剖面盒辅助类，用于优化碰撞检测性能。通过设置视口剖面盒，只处理路径周围的对象，大幅减少需要检测的对象数量。

## 核心方法

### 设置剖面盒

```csharp
// 根据路径点列表设置剖面盒
bool success = SectionClipHelper.SetClipBoxByPath(
    pathPoints: points,
    marginInMeters: 2.0,              // 水平边距（米）
    heightMarginInMeters: 1.0         // 高度边距（米）
);

// 根据路径点设置剖面盒（支持分别设置上下边距）
bool success = SectionClipHelper.SetClipBoxByPathWithMargins(
    pathPoints: points,
    marginInMeters: 2.0,
    heightMarginBottomInMeters: 0.5,  // 底部边距
    heightMarginTopInMeters: 2.0      // 顶部边距
);

// 根据单个点设置剖面盒（用于吊装路径等）
bool success = SectionClipHelper.SetClipBoxByPoint(
    centerPoint: point,
    rangeMeters: 10.0,                // 范围（米）
    heightRangeMeters: 5.0            // 高度范围（米）
);

// 根据楼层设置剖面盒
bool success = SectionClipHelper.SetClipBoxByFloor(
    floorItem: floor,
    marginMeters: 1.0
);
```

### 清除剖面盒

```csharp
// 清除剖面盒，显示全部模型
SectionClipHelper.ClearClipBox();
```

### 状态查询

```csharp
// 检查剖面盒是否已启用
bool isEnabled = SectionClipHelper.IsClipBoxEnabled;

// 获取当前剖面盒
if (SectionClipHelper.TryGetCurrentClipBox(out BoundingBox3D clipBox))
{
    LogManager.Info($"剖面盒范围: {clipBox.Min} - {clipBox.Max}");
}
```

### 包含性测试

```csharp
// 测试点是否在剖面盒内
bool isInside = SectionClipHelper.IsPointInClipBox(point);

// 测试包围盒是否与剖面盒相交
bool intersects = SectionClipHelper.IntersectsClipBox(itemBox);

// 使用角点检测（排除大包围盒假阳性）
bool intersects = SectionClipHelper.IntersectsByCornerPoints(itemBox, clipBox);

// 使用棱上自适应采样检测（长物体不会漏检）
bool intersects = SectionClipHelper.IntersectsByEdgeSampling(
    itemBox, clipBox, minSamplesPerEdge: 3
);
```

### 统计功能

```csharp
// 统计剖面盒内/外的对象数量
SectionClipHelper.CountObjectsInClipBox(
    out int totalCount, 
    out int insideCount, 
    out int outsideCount
);

// 使用角点检测统计（排除大包围盒假阳性）
SectionClipHelper.CountObjectsInClipBoxByCorners(
    out int totalCount,
    out int insideCount,
    out int outsideCount,
    out int largeBoxFiltered,
    debugDetails: detailsList  // 可选的详细信息列表
);

// 测试相交检测（调试用）
SectionClipHelper.TestIntersection();
```

## 使用示例

### 示例1：路径碰撞检测前设置剖面盒

```csharp
// 获取路径点
var pathPoints = pathRoute.Points.Select(p => p.Position).ToList();

// 设置剖面盒
bool success = SectionClipHelper.SetClipBoxByPath(
    pathPoints,
    marginInMeters: 2.0,      // 路径周围2米
    heightMarginInMeters: 1.0  // 上下各1米
);

if (success)
{
    // 统计过滤效果
    SectionClipHelper.CountObjectsInClipBoxByCorners(
        out int total, out int inside, out int outside, out int filtered
    );
    LogManager.Info($"剖面盒过滤: 总数{total}, 盒内{inside}, 过滤{filtered}");
    
    // 执行碰撞检测（只检测剖面盒内对象）
    var collisions = collisionDetector.DetectCollisions();
}

// 完成后清除剖面盒
SectionClipHelper.ClearClipBox();
```

### 示例2：吊装路径场景

```csharp
// 吊装路径通常只需要关注起吊点周围区域
if (liftPoint != null)
{
    SectionClipHelper.SetClipBoxByPoint(
        liftPoint,
        rangeMeters: 15.0,       // 15米范围
        heightRangeMeters: 20.0   // 20米高度范围
    );
}
```

### 示例3：精确过滤（排除大包围盒假阳性）

```csharp
// 获取剖面盒
if (!SectionClipHelper.TryGetCurrentClipBox(out var clipBox))
    return;

// 遍历模型进行过滤
foreach (var item in modelItems)
{
    var itemBox = item.BoundingBox();
    
    // 先用包围盒快速排除
    if (!clipBox.Intersects(itemBox))
        continue;
    
    // 再用角点检测精确判断
    if (!SectionClipHelper.IntersectsByCornerPoints(itemBox, clipBox))
    {
        // 包围盒相交但没有角点在盒内，可能是大包围盒假阳性
        LogManager.Debug($"跳过假阳性: {item.DisplayName}");
        continue;
    }
    
    // 该对象真正与剖面盒相交，加入检测列表
    itemsToCheck.Add(item);
}
```

### 示例4：长物体检测（使用棱上采样）

```csharp
// 对于长管道等物体，使用棱上采样确保不遗漏
if (SectionClipHelper.TryGetCurrentClipBox(out var clipBox))
{
    var itemBox = longPipeItem.BoundingBox();
    
    // 使用棱上自适应采样（根据物体大小动态计算采样点）
    if (SectionClipHelper.IntersectsByEdgeSampling(itemBox, clipBox, minSamplesPerEdge: 5))
    {
        // 长管道与剖面盒相交
        itemsToCheck.Add(longPipeItem);
    }
}
```

## 默认参数

```csharp
private const double DEFAULT_MARGIN_METERS = 2.0;           // 默认水平边距
private const double DEFAULT_HEIGHT_MARGIN_METERS = 1.0;    // 默认高度边距
```

## 注意事项

1. **性能优化**：剖面盒可以大幅减少碰撞检测的对象数量，提高性能
2. **JSON设置**：使用 JSON 字符串方式设置剖面盒，避免 "Object is Read-Only" 错误
3. **过滤策略**：
   - 先用 `IntersectsClipBox` 快速排除
   - 再用 `IntersectsByCornerPoints` 排除大包围盒假阳性
   - 最后用 `IntersectsByEdgeSampling` 确保长物体不遗漏
4. **清除责任**：使用完剖面盒后应调用 `ClearClipBox()` 恢复完整视图
5. **统计功能**：使用 `CountObjectsInClipBoxByCorners` 查看过滤效果和假阳性数量
