【问题标题】:CGAL: efficiently finding all triangles in a volume (bounding box or ball query)CGAL:有效地查找体积中的所有三角形(边界框或球查询)
【发布时间】:2019-05-22 10:49:02
【问题描述】:

我想有效地找到包含在体积中或与体积相交的所有三角形(例如多面体网格的面)(例如 AABB 或球体查询)。如果可能且合理,我想使用 CGAL 内置功能来做到这一点。

我目前的解决方案是简单的蛮力:对于网格中的所有面,检查面到球中心的距离是否小于球半径。我之前在顶点上使用了 KD-tree 的模糊球体查询,但它对我的应用程序来说不够准确。我需要完整的球体三角形交点。

CGAL AABB 树 (https://doc.cgal.org/latest/AABB_tree/index.html) 似乎是最好的数据结构,但我需要 3D 线性内核,它对三角形和任何类型的体积 (https://doc.cgal.org/latest/Kernel_23/group__intersection__linear__grp.html) 没有交叉测试。 CGAL KD 树不起作用,因为它只能包含点。

我的想法是:

  1. 为 AABB 树可以使用的 Triangle_3 和 Sphere_3 添加自定义 do_intersect()。这甚至可能吗?这可能还需要自定义 squared_distance()。
  2. 通过将三角形投影到例如,将体积查询转换为两个区域查询XY 和 YZ 平面。 AABB 树甚至可以处理 2D 搜索吗?圆形和 2D 三角形没有交集,但我可以使用 Iso_rectangle_2 和 Triangle_2 的交集作为初步猜测。
  3. 不知何故遍历 AABB 树的内部并在我找到不再包含我的查询的节点之前停止。
  4. 修改closest_point_and_primitive() 方法,提供可选的max_distance 参数并返回该距离内的所有图元。这需要我弄乱 CGAL 代码。
  5. 编写我自己的数据结构。这需要一些时间才能正确完成。

我错过了什么吗?哪种解决方案最省力?

【问题讨论】:

    标签: cgal


    【解决方案1】:

    使用 sloriot 回答中的一些想法,我能够解决我的问题。

    由于 do_intersect() 的文档没有显示 Sphere_3 和 Triangle_3 的重载,因此 AABB 树不支持使用 Sphere_3 进行查询也就不足为奇了。

    但是,AABB 树支持使用 BBox_3 的查询,这在 do_intersect() 文档中没有提及。

    使用 Bbox_3 调用 all_intersected_primitives() 会返回 Bbox_3 包含或相交的 AABB 树的所有图元。这是获得与球体实际交点的第一个很好的猜测。

    通过这种优化,我可以将查询时间从 20 毫秒(简单的蛮力)减少到 3 毫秒,在具有 100k 个面的网格上,一个查询返回大约 10 个面。

    以下是相关代码:

    double r = CGAL::sqrt(patch_radius_squared);
    CGAL::Bbox_3 query(
        sphere_center.x() - r, 
        sphere_center.y() - r, 
        sphere_center.z() - r, 
        sphere_center.x() + r, 
        sphere_center.y() + r, 
        sphere_center.z() + r);
    
    std::list<Tree::Primitive_id> primitives;
    tree.all_intersected_primitives(query, std::back_inserter(primitives));
    
    std::vector<Triangle_3> intersected_facets;
    for (const Tree::Primitive_id& p : primitives)
    {
        // intersection with bb gives only a good first guess -> check actual intersection
        if (CGAL::squared_distance(*p, sphere_center) <= patch_radius_squared)
        {
            intersected_facets.push_back(*p);
        }
    }
    

    【讨论】:

      【解决方案2】:

      对于相交三角形的集合,您可以使用:

      std::vector<Primitive> primitives;
      tree.all_intersected_primitives(sphere, std::back_inserter(primitives));
      //or
      tree.all_intersected_primitives(tree2, std::back_inserter(primitives));
      

      tree2 是您的边界体积的三角形 AABB 树。

      这将为您提供与您的体积边界相交的元素。然后您可以使用Surface_mesh properties 为所有相交的面设置一个布尔值true。然后在边上创建一个新属性并将其设置为true,如果您将其中一个事件面的属性设置为true

      然后调用connected_components(),您将能够将网格分割成包围体内部和外部的部分(忽略相交部分)。

      要完成,您需要为每个连接的组件选择一个点,并查看它是在包围体内部还是外部。对于球体来说是直截了当的,您可以将Side_of_triangle_mesh 用于网格案例(无需复制 AABB-tree 以节省内存和时间)。

      如果您的包围体是一个 bbox,您可以对球体进行类似操作。

      【讨论】:

      • 塞巴斯蒂安,感谢您的意见。澄清一下:版本 1 all_intersected_primitives(sphere, ...) 接受 Sphere_3 作为输入,尽管 the 3D Kartesian kernel has only do_intersection for Sphere_3 with another Sphere_3 and with Plane_3?
      • 版本 2 all_intersected_primitives(tree2, ...) 会使用基于多面体网格近似球体的另一棵 AABB 树吗?如何在网格三角形的 BB 和我的球体的 BB 上使用“dD 等向框的相交序列”作为查询?这将是一个很好的初步猜测。
      • 第一个版本可以采用球体、平面……任何内核原语,只要do_intersect 有一个重载。第二个版本适用于您首先放入 AABB 树的任意三角形网格。
      猜你喜欢
      • 1970-01-01
      • 2023-03-23
      • 2016-10-12
      • 2017-02-19
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      • 2011-10-09
      • 1970-01-01
      相关资源
      最近更新 更多