我想有效地找到体积中包含或相交的所有三角形(例如多面体网格的面)(例如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树不起作用,因为它只能包含点。
我的想法是:
我错过了什么吗?哪种解决方案最省力?
答案 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);
}
}