如何实现CGAL网格从lazy exact精确核到double类型非精确核转换
问题描述
我有一个使用三角形结构的CGAL网格,采用精确核(EK, EMesh3, EPoint3),需要将其转换为采用非精确核(K, Mesh3, Point3)的同拓扑网格。我目前的实现方案是遍历精确网格的所有顶点与面片,逐个添加到初始化的空非精确网格对象中,请问是否存在更简洁直接的转换方式?
当前手动实现的转换代码如下:
Mesh3 Convert(EMesh3 emesh) { const size_t nvertices = emesh.number_of_vertices(); const size_t nedges = emesh.number_of_edges(); const size_t nfaces = emesh.number_of_faces(); Mesh3 mesh; mesh.reserve(nvertices, nedges, nfaces); for(EMesh3::Vertex_index vd : emesh.vertices()) { const EPoint3 vertex = emesh.point(vd); const double x = CGAL::to_double<EK::FT>(vertex.x()); const double y = CGAL::to_double<EK::FT>(vertex.y()); const double z = CGAL::to_double<EK::FT>(vertex.z()); mesh.add_vertex(Point3(x, y ,z)); } for(EMesh3::Face_index fd : emesh.faces()) { std::vector<int> face; for(EMesh3::Vertex_index vd : vertices_around_face(emesh.halfedge(fd), emesh)) { face.push_back(vd); } mesh.add_face( CGAL::SM_Vertex_index(face[0]), CGAL::SM_Vertex_index(face[1]), CGAL::SM_Vertex_index(face[2]) ); } return mesh; }
最优解决方案
不需要手动遍历顶点、面片维护拓扑关系,直接使用CGAL内置的CGAL::copy_face_graph工具函数即可完成跨核的网格复制,只需要自定义顶点坐标的转换逻辑即可,代码可以大幅简化,同时鲁棒性更强。
最简实现代码(针对CGAL::Surface_mesh类型):
#include <CGAL/boost/graph/copy_face_graph.h> Mesh3 Convert(const EMesh3& emesh) { Mesh3 mesh; CGAL::copy_face_graph( emesh, mesh, CGAL::parameters::vertex_point_map( CGAL::make_transform_property_map( [](const EPoint3& p) { return Point3( CGAL::to_double(p.x()), CGAL::to_double(p.y()), CGAL::to_double(p.z()) ); }, emesh.points() ) ) ); return mesh; }
这个方案相比手动遍历的优势:
- 自动完整保留原网格的所有拓扑连接关系,不需要手动处理边、面的顶点索引对应
- 内部自动完成内存预留,不需要手动计算顶点、边、面的数量调用reserve
- 兼容所有符合CGAL FaceGraph概念的网格类型,
Surface_mesh、Polyhedron_3等不同网格实现之间都可以用这个方法转换 - 不会出现手动遍历容易遇到的顶点索引错位、面顶点环绕顺序错误的问题
注意:如果精确核使用的是支持开方运算的精确数类型,
CGAL::to_double会做就近舍入,转换后的浮点坐标可能存在极小的数值误差,但网格拓扑结构会和原网格完全一致。
内容的提问来源于stack exchange,提问作者Stéphane Laurent
相关产品推荐
相关产品推荐

