You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 19:32:01