You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何直接从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

问题原因

两种构建路径的内部实现逻辑存在差异,对输入的要求不同:

  1. 直接加载路径(OFF_to_nef_3):
    内部会直接解析OFF文件,自动处理非凸面、退化顶点等拓扑或几何上的特殊情况,比如将非凸面分解为凸面,因此兼容性更强。

  2. 中转路径(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 02:52:03