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