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