You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

CGAL first_intersection()返回射线原点而非真实交点的问题排查

CGAL射线求交返回原点问题的原因与解决办法

问题原因

  • 你的AABB树中包含了当前的self_segment,且射线起点origin是该线段的端点。CGAL定义线段的端点属于线段本身,因此射线与self_segment的首个交点就是起点origin,这也是first_intersection返回该点的核心原因。
  • first_intersection会返回射线与树中几何体的最近交点,而自身线段的端点与射线起点重合,自然会被优先返回。

解决办法

1. 遍历所有交点并过滤自身线段

first_intersection仅返回第一个交点,无法直接跳过自身线段,因此改用intersections遍历所有交点,筛选掉自身线段的端点后取最近的有效交点:

std::optional<Point> algorithm::nearest_intersection_in_direction(
    const Point& origin,
    const Vector& direction,
    const Tree& tree,
    const Segment& self_segment)
{
    Ray ray(origin, origin + direction);
    std::optional<Point> closest_point;
    // 用平方距离避免开方运算,提高效率
    FT min_sq_dist = std::numeric_limits<FT>::max();

    for (const auto& result : tree.intersections(ray)) {
        if (const Point* ipoint = std::get_if<Point>(&result.first)) {
            // 跳过自身线段的两个端点
            if (*ipoint == self_segment.source() || *ipoint == self_segment.target()) {
                continue;
            }
            FT current_sq_dist = CGAL::squared_distance(origin, *ipoint);
            if (current_sq_dist < min_sq_dist) {
                min_sq_dist = current_sq_dist;
                closest_point = *ipoint;
            }
        }
    }
    return closest_point;
}

2. 微小偏移射线起点

将射线起点向方向向量偏移极小的距离,使其不再与self_segment的端点重合,从而避免优先检测到自身线段的交点:

// 根据你的数值精度调整epsilon,比如使用1e-8(针对double类型)
const FT epsilon = 1e-8;
// 偏移起点,确保射线不从自身线段端点出发
Ray ray(origin + direction * epsilon, origin + direction);

注意:epsilon的取值需匹配你的坐标类型(如CGAL的精确整数类型需调整为合适的小数值),避免引入精度误差。

3. 构建AABB树时排除自身线段

如果场景允许,构建查询用的AABB树时不包含当前的self_segment,从根源上避免自身相交的情况。这种方式适合单次查询对应单独线段的场景,但频繁构建树会影响效率。

内容的提问来源于stack exchange,提问作者Samuel Bergé

火山引擎 最新活动