代码实践篇四 如何切割曲面或求平面与曲面的交?
简述思路
借助CGAL几何库,分为以下步骤:
- 曲面为surface mesh类型,因为要polygon processing接口,其他格式可以用copy_face_graph转换;
- split用于分割,clip用于切割,剩余部分和clipper的方向有关;
- slicer用的是AABB_tree,就是射线检测那一套求plane与mesh的交点集返回polyline
问题
- 对于split函数,分割成多个mesh后,需要调用split_connected_components分割连通域,这么设计的原则应该是为了泛型和增加内存使用效率;
- params里面的参数自行查看,一般要避免自信爱干净报异常。
- 用split和clip用plane也是可以的。但为什么例子要用mesh?因为mesh可以即可以模仿平面的范围,也可以用于非平面的结构。
接口原型
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
#include <CGAL/Vector_3.h>
#include <CGAL/Surface_mesh.h>
//clip和split
#include <CGAL/Polygon_mesh_processing/clip.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
//slicer
#include <CGAL/AABB_halfedge_graph_segment_primitive.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Polygon_mesh_slicer.h>
//CGAL里面求交后优化的核心模块
#include <CGAL/Polygon_mesh_processing/corefinement.h>
#include <CGAL\Polygon_mesh_processing\internal\Corefinement\intersection_impl.h>
namespace PMP = CGAL::Polygon_mesh_processing;
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
using Point_3 = Kernel::Point_3;
using Vector_3 = Kernel::Vector_3;
using Plane_3 = Kernel::Plane_3;
using Mesh = CGAL::Surface_mesh<Kernel::Point_3>;
using Polyline3D = std::vector<Point_3>;
using Polyline3Ds = std::vector<Polyline3D>;
typedef CGAL::AABB_halfedge_graph_segment_primitive<Mesh> HGSP;
typedef CGAL::AABB_traits<Kernel, HGSP> AABB_traits;
typedef CGAL::AABB_tree<AABB_traits> AABB_tree;
bool ClipMesh(Mesh& mesh, Mesh& clippermesh);
bool SplitMesh(Mesh& mesh, Mesh& splittermesh,std::vector<Mesh>& AfterSplitterComponents);
void SlicerMesh(Mesh& mesh, Plane_3& SlicerPlane,Polyline3Ds& IntersectionRegions);
代码
bool ClipMesh(Mesh& mesh, Mesh& clippermesh)
{
bool clipresult = false;
try
{
//allow_self_intersections一般设为false,通过捕捉异常处理
//clip实质调用的是corefinement里面的函数
clipresult = PMP::clip(mesh, clippermesh, CGAL::parameters::use_compact_clipper(true).allow_self_intersections(true));
}
catch (const std::exception& e)
{
//自行处理异常,一般异常是自相交共面退化引起的
std::cout << "clip error: " << e.what() << std::endl;
}
return clipresult;
}
bool SplitMesh(Mesh& mesh, Mesh& splittermesh,std::vector<Mesh>& AfterSplitterComponents)
{
namespace params = CGAL::parameters;
bool splitresult = true;
try
{
//throw_on_self_intersection是为了避免报异常,因为自相交太常见
//do_not_modify是为了减少splittermesh的修改,这个参数应该是Corefinement里面为了减少诸如splitter和clipper修改的,但是不是所有接口都更新好了。
PMP::split(mesh, splittermesh,params::throw_on_self_intersection(false),
params::do_not_modify(false));
PMP::split_connected_components(mesh, AfterSplitterComponents, params::default_values());
}
catch (const std::exception& e)
{
//自行处理异常,一般异常是自相交共面退化引起的
std::cout << "split error: " << e.what() << std::endl;
splitresult = false;
}
return splitresult;
}
void SlicerMesh(Mesh& mesh, Plane_3& SlicerPlane,Polyline3Ds& IntersectionRegions)
{
//简单构造
CGAL::Polygon_mesh_slicer<Mesh, Kernel> slicer(mesh);
slicer(SlicerPlane, std::back_inserter(IntersectionRegions));
IntersectionRegions.clear();
//利用AABB_tree加速处理用于多次频繁操作
AABB_tree tree(edges(mesh).first, edges(mesh).second, mesh);
CGAL::Polygon_mesh_slicer<Mesh, Kernel> slicer_aabb(mesh, tree);
slicer_aabb(SlicerPlane, std::back_inserter(IntersectionRegions));
std::cout << "the slicer intersects "
<< IntersectionRegions.size() << " IntersectionRegions" << std::endl;
IntersectionRegions.clear();
}
##结果