CGAL Nef_Polyhedron布尔运算结果异常问题求助
CGAL Nef多面体布尔差运算异常问题
我通过Polyhedron_incremental_builder_3创建Polyhedron_3,再以此初始化两个Nef多面体立方体。执行cube2 - cube1布尔差运算时结果不正确,较大的面上多出两个点。
问题复现代码
#include <CGAL/Exact_predicates_exact_constructions_kernel.h> #include <CGAL/Polyhedron_3.h> #include <CGAL/Surface_mesh.h> #include <CGAL/Nef_polyhedron_3.h> #include <CGAL/Aff_transformation_3.h> #include <CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h> #include <CGAL/Polyhedron_incremental_builder_3.h> #include <CGAL/Polygon_mesh_processing/corefinement.h> #include <iostream> typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polyhedron_3<Kernel> Polyhedron; typedef CGAL::Nef_polyhedron_3<Kernel> Nef_polyhedron; typedef CGAL::Surface_mesh<Kernel::Point_3> Surface_mesh; typedef CGAL::Point_3<Kernel> Point_3; typedef CGAL::Aff_transformation_3<Kernel> AFT_3; typedef Nef_polyhedron::Halffacet_const_iterator Halffacet_iterator; typedef Nef_polyhedron::Vertex_iterator Vertex_iterator; typedef Nef_polyhedron::Halfedge_const_iterator Halfedge_iteator; typedef Nef_polyhedron::Vertex_const_handle Vertex_Handle; class PolyhedronBuilder : public CGAL::Modifier_base<Polyhedron::HalfedgeDS> { public: void setType(bool type) { _type = type; } void operator()(Polyhedron::HalfedgeDS& hds) { typedef typename Polyhedron::HalfedgeDS HalfedgeDS; CGAL::Polyhedron_incremental_builder_3<HalfedgeDS> builder(hds, true); builder.begin_surface(8, 6); std::vector<Point_3> Points = { Point_3(-10.699169f, -15.407307f, 0.0f), // Vertex0 Point_3(-9.425352f, -16.199387f, 0.0f), // Vertex1 Point_3(-9.425352f, -16.199387f, 2.0f), // Vertex2 Point_3(-10.699169f, -15.407307f, 2.0f), // Vertex3 Point_3(2.5042138f, 5.8263035f, 2.0f), // Vertex4 Point_3(3.7780309f, 5.0342245f, 2.0f), // Vertex5 Point_3(3.7780309f, 5.0342245f, 0.0f), // Vertex6 Point_3(2.5042138f, 5.8263035f, 0.0f) //Vertex7 }; std::vector<Point_3> Points2 = { Point_3(-3.3673427f, -15.031566f, 0.0f), // Vertex0 Point_3(12.594898f, -15.031566f, 0.0f), // Vertex1 Point_3(12.594898f, -15.031566f, 2.0f), // Vertex2 Point_3(-3.3673427f, -15.031566f, 2.0f), // Vertex3 Point_3(-3.3673427f, 12.258608f, 2.0f), // Vertex4 Point_3(12.594898f, 12.258608f, 2.0f), // Vertex5 Point_3(12.594898f, 12.258608f, 0.0f), // Vertex6 Point_3(-3.3673427f, 12.258608f, 0.0f) //Vertex7 }; if (_type) { for (auto point : Points) { builder.add_vertex(point); } } else { for (auto point : Points2) { builder.add_vertex(point); } } builder.begin_facet(); builder.add_vertex_to_facet(0); builder.add_vertex_to_facet(1); builder.add_vertex_to_facet(2); builder.add_vertex_to_facet(3); builder.end_facet(); builder.begin_facet(); builder.add_vertex_to_facet(4); builder.add_vertex_to_facet(5); builder.add_vertex_to_facet(6); builder.add_vertex_to_facet(7); builder.end_facet(); builder.begin_facet(); builder.add_vertex_to_facet(1); builder.add_vertex_to_facet(0); builder.add_vertex_to_facet(7); builder.add_vertex_to_facet(6); builder.end_facet(); builder.begin_facet(); builder.add_vertex_to_facet(3); builder.add_vertex_to_facet(2); builder.add_vertex_to_facet(5); builder.add_vertex_to_facet(4); builder.end_facet(); builder.begin_facet(); builder.add_vertex_to_facet(0); builder.add_vertex_to_facet(3); builder.add_vertex_to_facet(4); builder.add_vertex_to_facet(7); builder.end_facet(); builder.begin_facet(); builder.add_vertex_to_facet(2); builder.add_vertex_to_facet(1); builder.add_vertex_to_facet(6); builder.add_vertex_to_facet(5); builder.end_facet(); builder.end_surface(); } private: bool _type = true; }; void OutputNefPolyhedron(const Nef_polyhedron& nef, std::string strOutFilePath) { Polyhedron temp; nef.convert_to_polyhedron(temp); Surface_mesh output; CGAL::convert_nef_polyhedron_to_polygon_mesh(nef, output); std::ofstream out; out.open(strOutFilePath); out << output; out.close(); } int main() { Polyhedron cube1; PolyhedronBuilder builder; cube1.delegate(builder); Polyhedron cube2; PolyhedronBuilder builder1; builder1.setType(false); cube2.delegate(builder1); Nef_polyhedron nef1(cube1); Nef_polyhedron nef2(cube2); Nef_polyhedron nefUnion = nef2 + nef1; Nef_polyhedron nefIntersect = nef2 * nef1; Nef_polyhedron nefSubtract = nef2 - nef1; for (Halfedge_iteator e = nefSubtract.halfedges_begin(); e != nefSubtract.halfedges_end(); ++e) { Point_3 source = e->source()->point(); Point_3 target = e->target()->point(); std::cout << "Edge: " << source << " --> " << target << std::endl; } OutputNefPolyhedron(nefSubtract, "D:/subtract.off"); return 0; }
问题排查与修复方案
1. 精确内核与浮点数精度冲突
你使用的Exact_predicates_exact_constructions_kernel要求几何构造完全精确,但代码中用了float类型的字面量初始化顶点。浮点数的精度损失会导致原本应该对齐的几何元素被误判为不重合,布尔运算时就会生成多余的顶点。
修复:
将所有float后缀(f)去掉,改用double类型或精确分数形式初始化顶点:
// 示例:替换float为double Point_3(-10.699169, -15.407307, 0.0),
如果需要绝对精确,可使用CGAL的有理数构造方式(齐次坐标):
// 表示-10.699169 = -10699169/1000000 Point_3(-10699169, 1000000, -15407307, 1000000, 0, 1)
2. 多面体面的方向一致性
CGAL的多面体要求所有面的顶点顺序保持统一的环绕方向(比如从外部观察为逆时针)。如果部分面方向错误,会导致Nef多面体无法正确识别内部/外部空间,进而影响布尔运算结果。
修复:
逐个检查每个面的顶点顺序,确保符合右手定则。比如第一个面的顶点顺序0→1→2→3,从外部看应该是逆时针方向,若方向相反则调整顶点顺序。
3. 简化Nef多面体转换流程
当前OutputNefPolyhedron函数中先转换为Polyhedron再转Surface_mesh,中间步骤可能引入不必要的顶点细分。直接转换即可避免该问题:
void OutputNefPolyhedron(const Nef_polyhedron& nef, std::string strOutFilePath) { Surface_mesh output; CGAL::convert_nef_polyhedron_to_polygon_mesh(nef, output); std::ofstream out(strOutFilePath); out << output; out.close(); }
4. 确认布尔运算逻辑
代码中执行的是nef2 - nef1(cube2减去cube1),确认这是你需要的运算逻辑。若实际需求是cube1减去cube2,需改为nef1 - nef2。
内容的提问来源于stack exchange,提问作者Ttoxicx
相关产品推荐
相关产品推荐

