简述思路

借助CGAL几何库,分为以下步骤:
1. 曲面为surface mesh类型,因为要polygon processing接口,其他格式可以用copy_face_graph转换;
2. split用于分割,clip用于切割,剩余部分和clipper的方向有关;
3. slicer用的是AABB_tree,就是射线检测那一套求plane与mesh的交点集返回polyline

问题

  1. 对于split函数,分割成多个mesh后,需要调用split_connected_components分割连通域,这么设计的原则应该是为了泛型和增加内存使用效率;
  2. params里面的参数自行查看,一般要避免自信爱干净报异常。
  3. 用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();
}

结果

相交结果

您必须 登录 才能发表评论