CGAL:有效地查找体积中的所有三角形(边界框或球查询)

时间:2019-05-22 10:49:03

标签: cgal

我想有效地找到体积中包含或相交的所有三角形(例如多面体网格的面)(例如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. 修改closet_point_and_primitive()方法,提供可选的max_distance参数,并返回该距离内的所有图元。这将需要我弄乱CGAL代码。
  5. 编写我自己的数据结构。这需要一些时间才能解决。

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

2 个答案:

答案 0 :(得分:0)

对于一组相交的三角形,您可以使用:

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树以节省内存和时间)。

如果您的包围盒是bbox,则可以对球形进行调整。

答案 1 :(得分:0)

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

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

但是,AABB树支持使用BBox_3的查询,而do_intersect()文档中未提及。

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

通过这种优化,我可以在具有100k面的网格上将查询时间从20 ms(简单的蛮力)减少到3 ms,其中一个查询返回大约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);
    }
}