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



我想有效地找到包含或与体积相交的所有三角形(例如,多面部网格的相位((例如AABB或SPHERHE COLERY(。如果可能和合理,我想使用内置功能来做到这一点。

我当前的解决方案是简单的蛮力:对于网格中的所有刻面,检查刻面与球中心的距离是否小于球半径。我之前在顶点上使用了KD-Tree的模糊球体查询,但对于我的应用还不够准确。我需要全球 - 三角形交集。

CGAL AABB树(https://doc.cgal.org/latest/aabb_tree/index.html(似乎是最好的数据架构(https://doc.cgal.org/latest/kernel_23/group__intersection__intersection_linear_er_grp.html(。CGAL KD树不起作用,因为它只能包含点。

我的想法是:

  1. 为triangle_3添加一个自定义do_intersect((和aabb树可以使用的sphere_3。那甚至可能吗?这可能还需要一个自定义squared_distance((。
  2. 通过在例如XY和YZ飞机。AABB树甚至可以处理2D搜索吗?圆圈和2D三角形没有交叉点,但我可以使用ISO_Rectangle_2和Triangle_2的交叉点作为很好的第一个猜测。
  3. 以某种方式穿越AABB树的内部,然后在我找到不再包含我查询的节点之前停止。
  4. 修改kersest_point_and_primitive((方法,给出一个可选的max_distance参数,然后在该距离内返回所有原始人。这需要我弄乱CGAL代码。
  5. 写自己的数据架构。这将需要一些时间才能使它正确。

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

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

由于do_intersect((的文档未显示Sphere_3和Triangle_3的过载,因此AABB树不支持Sphere_3。

但是,AABB树支持Bbox_3的查询,do_intersect((docu中未提及。

使用bbox_3调用all_intersected_primitives((返回bbox_3包含或相交的AABB树的所有原始图。这是获得与球体实际交集的第一个好猜测。

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

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

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-tree。

这将为您提供与音量边界相交的元素。然后,您可以使用Surface_mesh属性将Bool设置为true的所有面孔。然后在边缘创建一个新属性,并将其设置为true,如果将事件面的一个属性设置为true

然后调用connected_components(),您将能够将网格分为边界内外的部分(忽略相交的部分(。

要完成,您需要选择每个连接的组件一个点,并查看其在边界卷内还是外部。它对于球体来说很简单,您可以将Side_of_triangle_mesh用于网格盒(而不复制AABB-Tree来节省内存和时间(。

如果您的边界卷是一个Bbox,您可以喜欢球。

最新更新