5.8 KiB
5.8 KiB
SectionClipHelper 使用指南
文件位置
src/Utils/SectionClipHelper.cs
用途
剖面盒辅助类,用于优化碰撞检测性能。通过设置视口剖面盒,只处理路径周围的对象,大幅减少需要检测的对象数量。
核心方法
设置剖面盒
// 根据路径点列表设置剖面盒
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
);
清除剖面盒
// 清除剖面盒,显示全部模型
SectionClipHelper.ClearClipBox();
状态查询
// 检查剖面盒是否已启用
bool isEnabled = SectionClipHelper.IsClipBoxEnabled;
// 获取当前剖面盒
if (SectionClipHelper.TryGetCurrentClipBox(out BoundingBox3D clipBox))
{
LogManager.Info($"剖面盒范围: {clipBox.Min} - {clipBox.Max}");
}
包含性测试
// 测试点是否在剖面盒内
bool isInside = SectionClipHelper.IsPointInClipBox(point);
// 测试包围盒是否与剖面盒相交
bool intersects = SectionClipHelper.IntersectsClipBox(itemBox);
// 使用角点检测(排除大包围盒假阳性)
bool intersects = SectionClipHelper.IntersectsByCornerPoints(itemBox, clipBox);
// 使用棱上自适应采样检测(长物体不会漏检)
bool intersects = SectionClipHelper.IntersectsByEdgeSampling(
itemBox, clipBox, minSamplesPerEdge: 3
);
统计功能
// 统计剖面盒内/外的对象数量
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:路径碰撞检测前设置剖面盒
// 获取路径点
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:吊装路径场景
// 吊装路径通常只需要关注起吊点周围区域
if (liftPoint != null)
{
SectionClipHelper.SetClipBoxByPoint(
liftPoint,
rangeMeters: 15.0, // 15米范围
heightRangeMeters: 20.0 // 20米高度范围
);
}
示例3:精确过滤(排除大包围盒假阳性)
// 获取剖面盒
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:长物体检测(使用棱上采样)
// 对于长管道等物体,使用棱上采样确保不遗漏
if (SectionClipHelper.TryGetCurrentClipBox(out var clipBox))
{
var itemBox = longPipeItem.BoundingBox();
// 使用棱上自适应采样(根据物体大小动态计算采样点)
if (SectionClipHelper.IntersectsByEdgeSampling(itemBox, clipBox, minSamplesPerEdge: 5))
{
// 长管道与剖面盒相交
itemsToCheck.Add(longPipeItem);
}
}
默认参数
private const double DEFAULT_MARGIN_METERS = 2.0; // 默认水平边距
private const double DEFAULT_HEIGHT_MARGIN_METERS = 1.0; // 默认高度边距
注意事项
- 性能优化:剖面盒可以大幅减少碰撞检测的对象数量,提高性能
- JSON设置:使用 JSON 字符串方式设置剖面盒,避免 "Object is Read-Only" 错误
- 过滤策略:
- 先用
IntersectsClipBox快速排除 - 再用
IntersectsByCornerPoints排除大包围盒假阳性 - 最后用
IntersectsByEdgeSampling确保长物体不遗漏
- 先用
- 清除责任:使用完剖面盒后应调用
ClearClipBox()恢复完整视图 - 统计功能:使用
CountObjectsInClipBoxByCorners查看过滤效果和假阳性数量