NavisworksTransport/.agents/skills/project-tools/utils/SectionClipHelper.md
2026-02-25 02:01:38 +08:00

214 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` 查看过滤效果和假阳性数量