如何使用CGAL对3D闭合2流形点集生成三角形网格(非四面体)
解决CGAL生成曲面三角形网格的问题
首先明确:Triangulation_3是三维空间的四面体三角化工具,生成的是三维网格,自然会得到四面体。要生成嵌入R³的闭合2流形的三角形网格,应该用CGAL针对曲面的工具,以下是两种适配你场景的方案:
方案一:利用Delaunay三角化提取凸包表面(适配球面这类凸曲面)
因为你生成的是球面点,球面的凸包就是其本身,凸包的面都是三角形。步骤如下:
- 构建三维Delaunay三角化
- 遍历三角化的凸包面,提取每个面的三个顶点,组成三角形网格
示例代码:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Delaunay_triangulation_3.h> #include <vector> typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Delaunay_triangulation_3<K> Delaunay; typedef K::Point_3 Point; int main() { std::vector<Point> points; int num_theta = 30; int num_phi = 15; // 改进球面点生成:双层循环生成均匀分布的点 for (int i = 0; i < num_phi; ++i) { double phi = CGAL_PI * i / (num_phi - 1); for (int j = 0; j < num_theta; ++j) { double theta = 2 * CGAL_PI * j / num_theta; double x = std::sin(phi) * std::cos(theta); double y = std::sin(phi) * std::sin(theta); double z = std::cos(phi); points.emplace_back(x, y, z); } } Delaunay dt(points.begin(), points.end()); // 遍历凸包面,输出三角形 for (auto f = dt.finite_faces_begin(); f != dt.finite_faces_end(); ++f) { if (dt.is_on_convex_hull(f)) { // 获取面的三个顶点 Point p0 = f->vertex(0)->point(); Point p1 = f->vertex(1)->point(); Point p2 = f->vertex(2)->point(); // 这里可以将三个点存入你的三角形网格结构,比如Surface_mesh std::cout << p0 << ", " << p1 << ", " << p2 << std::endl; } } return 0; }
方案二:Poisson曲面重建(适配一般闭合2流形)
如果你的点集来自非凸的闭合2流形,Poisson曲面重建可以从散点生成闭合的三角形网格,步骤如下:
- 为点集计算法向量(如果没有的话)
- 调用Poisson重建函数生成曲面网格
示例代码:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Poisson_surface_reconstruction.h> #include <CGAL/Surface_mesh.h> #include <vector> typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef K::Point_3 Point; typedef K::Vector_3 Vector; typedef CGAL::Surface_mesh<Point> Mesh; int main() { std::vector<std::pair<Point, Vector>> points_with_normals; // 先生成球面点并计算法向量(球面点的法向量就是点本身的单位向量) int num_theta = 30; int num_phi = 15; for (int i = 0; i < num_phi; ++i) { double phi = CGAL_PI * i / (num_phi - 1); for (int j = 0; j < num_theta; ++j) { double theta = 2 * CGAL_PI * j / num_theta; double x = std::sin(phi) * std::cos(theta); double y = std::sin(phi) * std::sin(theta); double z = std::cos(phi); Point p(x, y, z); Vector n(x, y, z); // 球面法向量等于点坐标 points_with_normals.emplace_back(p, n); } } Mesh mesh; // 执行Poisson重建 CGAL::poisson_surface_reconstruction_delaunay( points_with_normals.begin(), points_with_normals.end(), mesh, CGAL::parameters::relative_weight(2.0) // 可调整参数优化结果 ); // 输出网格信息或保存到文件 std::cout << "Mesh has " << mesh.number_of_vertices() << " vertices and " << mesh.number_of_faces() << " faces." << std::endl; return 0; }
额外说明
你原来的球面点生成代码存在问题:用同一个i生成theta和phi,导致点集中在一条螺旋线上,分布极不均匀,会影响后续三角化效果。上面的示例代码改用双层循环生成theta和phi,能得到更均匀的球面点。
内容的提问来源于stack exchange,提问作者Cedric Martens
相关产品推荐
相关产品推荐

