我想有效地找到包含或与体积相交的所有三角形(例如,多面部网格的相位((例如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树不起作用,因为它只能包含点。
我的想法是:
- 为triangle_3添加一个自定义do_intersect((和aabb树可以使用的sphere_3。那甚至可能吗?这可能还需要一个自定义squared_distance((。
- 通过在例如XY和YZ飞机。AABB树甚至可以处理2D搜索吗?圆圈和2D三角形没有交叉点,但我可以使用ISO_Rectangle_2和Triangle_2的交叉点作为很好的第一个猜测。
- 以某种方式穿越AABB树的内部,然后在我找到不再包含我查询的节点之前停止。
- 修改kersest_point_and_primitive((方法,给出一个可选的max_distance参数,然后在该距离内返回所有原始人。这需要我弄乱CGAL代码。
- 写自己的数据架构。这将需要一些时间才能使它正确。
我错过了什么吗?哪种解决方案最少?
使用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,您可以喜欢球。