为何直接从OFF构建Nef_polyhedron_3与经Polyhedron_3转换结果不同?
CGAL中Nef_polyhedron_3两种构建方式的差异问题
构建方式说明
在CGAL中,Nef_polyhedron_3有两种常见构建方式:
- 直接加载OFF文件:通过
CGAL::OFF_to_nef_3函数直接从OFF文件生成Nef_polyhedron_3 - 经
Polyhedron_3中转:先通过CGAL::IO::read_OFF加载OFF文件得到Polyhedron_3,再通过Nef_polyhedron_3的构造函数转换得到目标对象
代码示例
直接构建代码
#include "common.hpp" int main(int argc, char ** argv) { Nef_polyhedron nef_poly; std::ifstream is("test.off", std::ios::in); CGAL::OFF_to_nef_3(is, nef_poly); is.close(); return 0; }
经Polyhedron_3中转的构建代码
#include "common.hpp" int main(int argc, char ** argv) { Polyhedron poly; std::ifstream is("test.off", std::ios::in); bool success = CGAL::IO::read_OFF(is, poly); is.close(); assert(success); assert(poly.is_valid()); assert(poly.is_closed()); Nef_polyhedron nef_poly(poly); // <--- 错误触发位置 return 0; }
common.hpp内容
#pragma once #include <iostream> #include <fstream> #include <cassert> #include <CGAL/Exact_predicates_exact_constructions_kernel.h> #include <CGAL/Polyhedron_3.h> #include <CGAL/Nef_polyhedron_3.h> #include <CGAL/IO/Polyhedron_OFF_iostream.h> #include <CGAL/OFF_to_nef_3.h> using Exact_kernel = CGAL::Exact_predicates_exact_constructions_kernel; using Polyhedron = CGAL::Polyhedron_3<Exact_kernel>; using Surface_mesh = CGAL::Surface_mesh<Exact_kernel::Point_3>; using Nef_polyhedron = CGAL::Nef_polyhedron_3<Exact_kernel>;
问题现象
根据CGAL文档,两种方式应生成数学等价的Nef_polyhedron_3,但实际测试发现:
- 部分OFF文件下两种方式结果一致(比如正四棱台的OFF文件)
- 部分OFF文件下,仅直接构建方式可行,经
Polyhedron_3中转的方式会触发断言错误:
terminate called after throwing an instance of 'CGAL::Assertion_exception' what(): CGAL ERROR: assertion violation! Expr: ss_circle.has_on(sp) File: /usr/include/CGAL/Nef_3/polygon_mesh_to_nef_3.h Line: 253
触发问题的OFF文件示例
OFF 5 5 10 -0.193282 0.100467 0.339231 -0.183855 0.102082 0.334972 -0.183473 0.103303 0.332011 -0.181318 0.104688 0.348585 0.000000 0.000000 0.000000 3 4 0 1 3 4 1 2 3 4 2 3 3 4 3 0 4 3 2 1 0
正常工作的OFF文件示例
OFF 8 6 12 1.0 0.0 1 0.0 1.0 1 -1.0 0.0 1 0.0 -1.0 1 1.0 0.0 0.0 0.0 1.0 0.0 -1.0 0.0 0.0 0.0 -1.0 0.0 4 0 1 2 3 4 7 4 0 3 4 4 5 1 0 4 5 6 2 1 4 3 2 6 7
问题原因
两种构建路径的内部实现逻辑存在差异,对输入的要求不同:
直接加载路径(
OFF_to_nef_3):
内部会直接解析OFF文件,自动处理非凸面、退化顶点等拓扑或几何上的特殊情况,比如将非凸面分解为凸面,因此兼容性更强。中转路径(
Polyhedron_3转Nef_polyhedron_3):
转换依赖的polygon_mesh_to_nef_3函数对输入Polyhedron_3有严格要求:- 每个面必须是平面凸多边形
- 顶点按正确的环绕顺序排列
- 不能存在顶点共线等退化情况
触发问题的OFF文件中,最后一个四边形面(顶点3、2、1、0)不满足上述要求:要么该四边形是非凸的,要么顶点并非严格共面,导致转换时计算面的支撑圆出错,触发ss_circle.has_on(sp)断言失败。
解决方案
- 优先使用
CGAL::OFF_to_nef_3直接加载OFF文件,避免中转带来的限制。 - 若必须通过
Polyhedron_3中转,需先对Polyhedron_3进行预处理:- 使用
CGAL::Polygon_mesh_processing::triangulate_faces将所有非三角面三角化 - 或使用凸分解工具将非凸面拆分为凸面,确保每个面都符合转换要求
- 使用
内容的提问来源于stack exchange,提问作者gspr
相关产品推荐
相关产品推荐

