如何使用CGAL读写二进制PLY文件?读写异常问题排查
问题分析与修复方案
核心问题:精确内核与PLY二进制格式不兼容
你使用的Exact_predicates_exact_constructions_kernel(EK)是精确计算内核,其Point_3存储的是精确有理数类型(而非普通浮点数)。但二进制PLY文件的标准格式是存储单/双精度浮点数,CGAL写入时会将精确类型转成浮点数输出,但读取时,试图将浮点数二进制数据直接构造为精确内核的点,会导致类型不匹配,进而引发读取失败或内存映射错误。
同时,其他软件无法读取该文件的原因也在于此:精确内核的点在写入时的二进制编码不符合通用PLY的浮点数格式规范。
具体修复步骤
1. 替换为浮点型内核
将精确内核替换为浮点型内核,比如Exact_predicates_inexact_constructions_kernel,这个内核的Point_3使用普通double类型,完全兼容PLY的浮点数存储格式:
// 替换原来的EK定义 typedef CGAL::Exact_predicates_inexact_constructions_kernel EK;
2. 优化二进制文件读写逻辑
调整为更符合CGAL推荐的写法,确保二进制模式的正确设置(原逻辑虽无错误,但统一写法更稳妥):
- 写入时直接以
std::ios::binary打开文件,无需额外调用CGAL::IO::set_binary_mode - 读取时同样确保以二进制模式打开,CGAL的
read_PLY会自动处理二进制格式
修复后的完整代码
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Polygon_mesh_processing/orient_polygon_soup.h> #include <CGAL/Polygon_mesh_processing/orientation.h> #include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h> #include <CGAL/Surface_mesh.h> #include <CGAL/IO/io.h> #include <CGAL/Surface_mesh/IO/PLY.h> #include <fstream> #include <iostream> #include <vector> typedef CGAL::Exact_predicates_inexact_constructions_kernel EK; typedef CGAL::Surface_mesh<EK::Point_3> EMesh3; typedef EK::Point_3 EPoint3; namespace PMP = CGAL::Polygon_mesh_processing; int main() { // octahedron soup ---------- double phi = (1.0 + sqrt(5.0)) / 2.0; std::vector<EPoint3> vertices = {EPoint3(0.0, 0.0, phi), EPoint3(0.0, phi, 0.0), EPoint3(phi, 0.0, 0.0), EPoint3(0.0, 0.0, -phi), EPoint3(0.0, -phi, 0.0), EPoint3(-phi, 0.0, 0.0)}; std::vector<std::vector<int>> faces = {{1, 0, 2}, {0, 5, 4}, {5, 1, 0}, {0, 2, 4}, {3, 2, 1}, {3, 5, 1}, {2, 3, 4}, {5, 3, 4}}; bool success = PMP::orient_polygon_soup(vertices, faces); if(!success) { std::cout << "Polygon orientation failed."; return 1; } // make mesh ---------- EMesh3 mesh; PMP::polygon_soup_to_polygon_mesh(vertices, faces, mesh); // write to binary PLY file ---------- std::ofstream outfile("octahedron.ply", std::ios::binary); bool ok = CGAL::IO::write_PLY(outfile, mesh); outfile.close(); if(!ok) { std::cout << "Writing file failed."; return 1; } else { std::cout << "Writing file successful.\n"; } // read the PLY file ---------- EMesh3 mesh2; std::ifstream infile("octahedron.ply", std::ios::binary); std::cout << "infile is open: " << infile.is_open() << "\n"; bool ok2 = CGAL::IO::read_PLY(infile, mesh2); infile.close(); if(!ok2) { std::cout << "Reading file failed."; return 1; } // print mesh ---------- std::cout << mesh2; return 0; }
额外说明
- 若你确实需要使用精确内核进行计算,可以先在精确内核下处理网格,再转换为浮点型内核的
Surface_mesh后写入PLY文件 - 通用3D软件(如Blender、MeshLab)仅支持浮点数格式的PLY文件,因此必须使用浮点型内核生成兼容文件
内容的提问来源于stack exchange,提问作者Stéphane Laurent
相关产品推荐
相关产品推荐

