如何遍历CGAL球面排列中每个面的边界并输出顶点坐标
解决CGAL球面排列面顶点XYZ坐标获取问题
需求说明
基于球面三角形创建CGAL球面排列,该排列将球面分为两个面(球面三角形面及其补面),需输出两个面的顶点XYZ坐标,示例输出如下:
Face 0: // the spherical triangle face 0 1 0 0 0 1 1 0 0 Face 1: // the complement face 1 0 0 0 0 1 0 1 0
现有代码
#include <list> #include <CGAL/Exact_predicates_exact_constructions_kernel.h> #include <CGAL/Arrangement_on_surface_2.h> #include <CGAL/Arr_geodesic_arc_on_sphere_traits_2.h> #include <CGAL/Arr_spherical_topology_traits_2.h> #include "arr_print.h" typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Arr_geodesic_arc_on_sphere_traits_2<Kernel> Geom_traits; typedef Geom_traits::Point_2 Point; typedef Geom_traits::Curve_2 Curve; typedef CGAL::Arr_spherical_topology_traits_2<Geom_traits> Topol_traits; typedef CGAL::Arrangement_on_surface_2<Geom_traits, Topol_traits> Arrangement; int main() { Geom_traits traits; Arrangement arr(&traits); auto ctr_p = traits.construct_point_2_object(); auto ctr_cv = traits.construct_curve_2_object(); std::list<Curve> arcs; arcs.push_back(ctr_cv(ctr_p(1, 0, 0), ctr_p(0, 1, 0))); arcs.push_back(ctr_cv(ctr_p(0, 1, 0), ctr_p(0, 0, 1))); arcs.push_back(ctr_cv(ctr_p(0, 0, 1), ctr_p(1, 0, 0))); CGAL::insert(arr, arcs.begin(), arcs.end()); typename Arrangement::Face_const_iterator fit; for(fit = arr.faces_begin(); fit != arr.faces_end(); ++fit) { if (fit->is_unbounded()) continue; // How to print the XYZ position of each vertex // from each face. } return 0; }
遇到的问题
尝试用逆时针边界(CCB)迭代器遍历面边界时出现类型转换错误,错误代码如下:
Arrangement::Inner_ccb_const_iterator hc_it; for (hc_it = fit->inner_ccbs_begin(); hc_it != fit->inner_ccbs_end(); ++hc_it) { Arrangement::Halfedge_handle he_handle = hc_it; // error here (can't convert) // how can I get the vertex data? }
正确实现方法
核心修正点
- 不跳过无界面:补面属于无界面,是需要输出的目标之一;
- 使用外边界迭代器:球面三角形面和补面都没有内部洞,应使用
outer_ccb()而非inner_ccbs; - 正确遍历CCB半边:CCB迭代器直接指向半边对象,无需类型转换即可访问顶点。
完整修正后的代码
将原main函数中的遍历部分替换为以下代码:
int face_idx = 0; typename Arrangement::Face_const_iterator fit; for(fit = arr.faces_begin(); fit != arr.faces_end(); ++fit) { // 输出面标识与类型注释 std::cout << "Face " << face_idx << ": "; fit->is_unbounded() ? std::cout << "// the complement face" : std::cout << "// the spherical triangle face"; std::cout << std::endl; // 获取面的外边界CCB迭代器 Arrangement::Ccb_halfedge_const_iterator hc_it = fit->outer_ccb(); const Arrangement::Ccb_halfedge_const_iterator start = hc_it; // 遍历CCB所有半边,避免重复输出起始顶点 do { // 获取当前半边的起点顶点 const Point& p = hc_it->vertex()->point(); // 转换为double格式输出XYZ坐标 std::cout << CGAL::to_double(p.x()) << " " << CGAL::to_double(p.y()) << " " << CGAL::to_double(p.z()) << std::endl; ++hc_it; } while (hc_it != start); std::cout << std::endl; face_idx++; }
代码说明
- CCB遍历逻辑:球面排列中每个面的外边界是闭合逆时针环,用
do-while循环确保完整遍历所有顶点且不重复输出起始点; - 坐标提取:通过
vertex()->point()获取球面点,用CGAL::to_double()将精确的Kernel::FT类型转换为可打印的double值; - 面类型区分:通过
is_unbounded()判断是球面三角形面(有界)还是补面(无界),对应输出注释。
内容的提问来源于stack exchange,提问作者Cedric Martens
相关产品推荐
相关产品推荐

