官方文档:Polygon_mesh_processing Silcer 本文代码:Mesh_slicer.cpp

The CGAL::Polygon_mesh_slicer is an operator that intersects a triangle surface mesh with a plane. It records the intersection as a set of polylines since the intersection can be made of more than one connected component. The degenerate case where the intersection is a single point is handled.

Polygon_mesh_slicer是一个将三角形表面网格平面相交的运算符。在CGAL中,此相交的计算结果为一组折线

  • 因为交集可能由多个连通组件组成,所以CGAL没有帮你闭合成面,保留原始的相交结果,即折线集
  • 本算法会处理相交结果退化成单点的情况

Figure 66.15 shows the polylines returned by the slicing operation for a triangle mesh and a set of parallel planes.

在左图中,蓝色物体是一个三角形表面网格。我们用多组平面与它相交,得到右图的结果。在右图中,可以看到蓝色物体被切割成了多组折线集。

  • 这些平面在图中并未画出,从右图结果可知,这些平面从左到右相隔一定距离排序,并且它们是相互平行的
  • 黄色物体只是为了叠加对比,没有被切片。

切片Slicer - 图1
Figure 66.15 Slicing a mesh. A triangle mesh (left) and the polylines computed by the mesh slicer by intersecting a set of parallel planes (right).

官方示例

  1. void Sample(const std::string& filename)
  2. {
  3. //将filename读取成Mesh
  4. Mesh mesh;
  5. if (!PMP::IO::read_polygon_mesh(filename, mesh) || is_empty(mesh) || !is_triangle_mesh(mesh))
  6. {
  7. std::cerr << "Invalid input." << std::endl;
  8. return;
  9. }
  10. //
  11. //用Mesh构造出切片器
  12. //
  13. CGAL::Polygon_mesh_slicer<Mesh, K> slicer(mesh);
  14. Polylines polylines; //切片结果是一个线集
  15. //用一个平面进行切片,获得线集
  16. slicer(K::Plane_3(0, 0, 1, -0.4), std::back_inserter(polylines));
  17. std::cout << "At z = 0.4, the slicer intersects " << polylines.size() << " polylines" << std::endl;
  18. polylines.clear();
  19. //用一个平面进行切片,获得线集
  20. slicer(K::Plane_3(0, 0, 1, 0.2), std::back_inserter(polylines));
  21. std::cout << "At z = -0.2, the slicer intersects " << polylines.size() << " polylines" << std::endl;
  22. polylines.clear();
  23. //
  24. //使用AABB_tree加速
  25. //
  26. AABB_tree tree(edges(mesh).first, edges(mesh).second, mesh);
  27. CGAL::Polygon_mesh_slicer<Mesh, K> slicer_aabb(mesh, tree);
  28. slicer_aabb(K::Plane_3(0, 0, 1, -0.4), std::back_inserter(polylines));
  29. std::cout << "At z = 0.4, the slicer intersects " << polylines.size() << " polylines" << std::endl;
  30. polylines.clear();
  31. }

性能测试代码:按某个间隔多次切片

  1. void PerformanceTest(const std::string& filename, double interval, const std::string& out_dir)
  2. {
  3. Mesh mesh;
  4. if (!PMP::IO::read_polygon_mesh(filename, mesh) || is_empty(mesh) || !is_triangle_mesh(mesh))
  5. {
  6. std::cerr << "Invalid input." << std::endl;
  7. return;
  8. }
  9. //构造切片器
  10. AABB_tree tree(edges(mesh).first, edges(mesh).second, mesh);
  11. CGAL::Polygon_mesh_slicer<Mesh, K> slicer_aabb(mesh, tree);
  12. Polylines polylines; //切片结果是一个线集
  13. CGAL::Bbox_3 bbox = CGAL::bbox_3(mesh.points().begin(), mesh.points().end());
  14. const double z_range = bbox.max(2) - bbox.min(2);
  15. int size = static_cast<int>(z_range / interval + 0.5);
  16. CGAL::Timer t;
  17. t.start();
  18. //切片
  19. for (int i{0}; i < size; ++i)
  20. {
  21. double z = bbox.min(2) + i * interval;
  22. slicer_aabb(K::Plane_3(0, 0, 1, z), std::back_inserter(polylines));
  23. std::cout << "At z = " << z << ", the slicer intersects " << polylines.size() << " polylines" << std::endl;
  24. ObjIOPlugin::PolylinesToObj(polylines, out_dir + "polylines" + std::to_string(i));
  25. polylines.clear();
  26. }
  27. std::cout << "z的间隔范围" << interval << std::endl;
  28. std::cout << "切片次数:" << size << std::endl;
  29. std::cout << t.time() << " 秒." << std::endl;
  30. }

测试数据

单体三角网

这个是一个石头模型(单体),是一个三角网。间隔为0.05,构造出多组与XOY面平行的切面
image.png
image.pngimage.png

性能

  1. 模型:石头
  2. 顶点个数98;面片个数192
  3. 切片个数:756
  4. 计算时间:0.774秒

有空洞的三角网

用Meshlab将石头模型的三角网删掉一些,人为制造孔洞。然后,以间隔为0.5,构造出多组与XOY面平行的切面
image.pngimage.png
结果显示,CGAL的切片支持有空洞的三角网。

复杂三角网(多个连通组件)

测试数据:半架飞机
测试:从zMin到zMax构造多个与XOY平行的切面,只有三四个平面有结果,其他平面都切不出结果
还没有找到原因
image.png
image.png