需求说明:有立方体的八个顶点坐标,需要判断两个或多个立方体是否有交集。
根据百度搜索结果,CGAL可以提供立方体的布尔运算功能,但是需要根据已知的坐标构建该库的多面体对象。
以下内容参考博客 CGAL多面体布尔运算 - 码农岛
CGAL中的Polyhedron并不能直接进行多面体的布尔运算,真正实现布尔运算的结构是CGAL::Nef_polyhedron_3<Kernel>(包含用于二元布尔运算所需要的结构信息),按照CGAL的官方教程,用Polyhedron来构造Nef_Polyhedron;Nef_Polyhedron重载了+,*,-运算符,分别表示并,交,差。
布尔运算的结果仍为Nef_Polyhedron类型,调用Nef_Polyhedron的convert_to_polyhedron(Polyhedron)函数可以将Nef_Polyhedron转化回为Polyhedron。
然后通过接口函数 polyhedron2mesh将CGAL::Polyhedron_3<Kernel>转换为mesh。得到布尔运算的mesh结果:
void polyhedron2mesh(VFMesh &mesh, Polyhedron &P);
以下代码实现了根据八个顶点坐标构建多面体并进行布尔运算,将结果输出至磁盘的功能。
#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/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h>
#include <iostream>
#include <sstream>
#include <fstream>
typedef CGAL::Exact_predicates_exact_constructions_kernel Exact_kernel;
typedef CGAL::Polyhedron_3<Exact_kernel> Polyhedron;
typedef CGAL::Surface_mesh<Exact_kernel::Point_3> Surface_mesh;
typedef CGAL::Nef_polyhedron_3<Exact_kernel> Nef_polyhedron;
void CreateCube1(Polyhedron& poly)
{
// 第一行是文件类型标识,第二行三个数字依次为顶点数、面数、边数,第三行至第十行为顶点坐标,第十一行以后为各面的描述(点数、点索引)
std::string input =
"OFF\n\
8 6 0\n\
0 0 0\n\
1 0 0\n\
1 1 0\n\
0 1 0\n\
0 0 1\n\
1 0 1\n\
1 1 1\n\
0 1 1\n\
4 0 1 5 4\n\
4 1 2 6 5\n\
4 2 3 7 6\n\
4 3 0 4 7\n\
4 0 3 2 1\n\
4 4 5 6 7";
std::stringstream ss;
ss << input;
ss >> poly;
}
void CreateCube2(Polyhedron& poly)
{
std::string input =
"OFF\n\
8 6 0\n\
0.5 0.5 0.5\n\
1.5 0.5 0.5\n\
1.5 1.5 0.5\n\
0.5 1.5 0.5\n\
0.5 0.5 1.5\n\
1.5 0.5 1.5\n\
1.5 1.5 1.5\n\
0.5 1.5 1.5\n\
4 0 1 5 4\n\
4 1 2 6 5\n\
4 2 3 7 6\n\
4 3 0 4 7\n\
4 0 3 2 1\n\
4 4 5 6 7";
std::stringstream ss;
ss << input;
ss >> poly;
}
void OutputNefPolyhedron(const Nef_polyhedron &nef, std::string strOutFilePath)
{
Surface_mesh output;
CGAL::convert_nef_polyhedron_to_polygon_mesh(nef, output);
std::ofstream out;
out.open(strOutFilePath);
out << output;
out.close();
}
int main(int argc, char *argv[])
{
// 创建两个立方体
Polyhedron cube1, cube2;
CreateCube1(cube1);
CreateCube2(cube2);
Nef_polyhedron nef1(cube1);
Nef_polyhedron nef2(cube2);
// 对两个立方体进行布尔运算
Nef_polyhedron nefUnion = nef1 + nef2;
Nef_polyhedron nefIntersect = nef1 * nef2;
// 输出立方体到文件
OutputNefPolyhedron(nef1, "D:/nef1.off");
OutputNefPolyhedron(nef2, "D:/nef2.off");
OutputNefPolyhedron(nefUnion, "D:/union.off");
OutputNefPolyhedron(nefIntersect, "D:/intersect.off");
return 0;
}
程序中根据顶点坐标构建立方体时假设顶点存储顺序如上图所示,在面描述时需要注意,不能有重合的边,如面0154使用了边15,面1265使用了边51是正确的描述,若改为1562则会因为边15重复使用导致构建多面体失败。
程序运行输出的两个立方体并集结果如下图。