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

5.8 KiB
Raw Blame History

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;    // 默认高度边距

注意事项

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