Several Problems in Reading OFF files
Opened this issue · 4 comments
I've quickly searched the issues list and couldn't find anything similar, so I believe that most of not all of the content of this issue is relevant, but I could be wrong.
Issue Details
There are several problems with the way CGAL handles files in the OFF format. The code listed below is an attempt to cover those reported herel; thus, a bit longer than the typical minimal program. The program reads a file in the OFF format and displays it. It constructs an object the type of which is either an instance of the templates Polyhedron_3 or Surface_mesh, depending on whether the macro USE_SURFACE_MESH is defined; see Line 4 in the listing,
- The first line of a file in the
OFFformat has the lettersOFFto mark the file type. (This is typically referred to as the magic string.) It turns out that the CGAL reader(s) accept eitherOFForCOFFas the magic string, whereCOFFindicates that the file has colors (with faces or vertices). The stringCOFFis not in the standard; thus, redundant. I can live with the fact the whenCOFFis indicated, colors are expected; however, I believe that ifOFFis indicated, colors should still be handled properly. Currently, ifOFFis indicated, colors seem to be ignored. I must add and say that I find it of high priority, because it has to do with standards, - It seems that different pieces of code are used to read files in the
OFFformat based on the provided (named) parameters. This is, naturally bad practice, but here we actually get different behaviors. Assume that the definition ofUSE_SURFACE_MESHis commented out; that is, we are using Polyhedron_3. Assume we are only passingverboseandrepair_polygon_soup(Line 61). Then, if the input data is inconsistent, the build of the mesh fails with a useful error message, e.g.,:
CGAL::Polyhedron_incremental_builder_3::
lookup_halfedge(): input error: facet 336 shares a halfedge from vertex 0 to vertex 1 with facet 0.
However, if we call read_polygon_mesh() and also provide a color map, the call returns false, but we do not get any error message. The split in the code occurs in the file Polyhedron_OFF_iostream.h, Line 69. When providing a color map we end up calling read_OFF_BGL(), and in turn CGAL::Euler::add_face(face, g); see Line 146 in File Generic_facegraph_builder.h. One quick fix is testing whether verbose is true, and if so, precede the call to add_face() with a check in the form of a call to can_add_face(). I think that if we use the Surface_mesh template we don't get any useful error messages whatsoever, so if we use different code, then it should be fixed there as well.
-
The reference of CGAL::Polygon_mesh_processing::IO::read_polygon_mesh is missing the following options:
- face_color_map
- vertex_color_map
- vertex_normal_map
- vertex_texture_map
-
While at it, it would be nice if the very simple example
draw_polyhedron.cppis enhanced with the ability to read and respect face colors as done here.
#include <iostream>
#include <string>
// #define USE_SURFACE_MESH
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#if defined(USE_SURFACE_MESH)
#include <CGAL/Surface_mesh.h>
#include <CGAL/draw_surface_mesh.h>
#else
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Polyhedron_traits_with_normals_3.h>
#include <CGAL/draw_polyhedron.h>
#endif
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
#include <CGAL/IO/Color.h>
#if ! defined(USE_SURFACE_MESH)
#include "Extended_polyhedron_items.h"
#endif
int main(int argc, char* argv[]) {
using Kernel = CGAL::Exact_predicates_exact_constructions_kernel;
#if defined(USE_SURFACE_MESH)
using Mesh = CGAL::Surface_mesh<Kernel::Point_3>;
#else
using Traits = CGAL::Polyhedron_traits_with_normals_3<Kernel>;
using Mesh = CGAL::Polyhedron_3<Traits, Extended_polyhedron_items>;
using Face_color_map = boost::property_map<Mesh, CGAL::dynamic_face_property_t<CGAL::IO::Color> >::type;
#endif
using Vertex_descriptor = boost::graph_traits<Mesh>::vertex_descriptor;
using Edge_descriptor = boost::graph_traits<Mesh>::edge_descriptor;
using Face_descriptor = boost::graph_traits<Mesh>::face_descriptor;
const char* filename = (argc > 1) ? argv[1] : "cube.off";
std::cout << filename << std::endl;
Mesh mesh;
#if defined(USE_SURFACE_MESH)
if (! CGAL::IO::read_polygon_mesh(filename, mesh, CGAL::parameters::verbose(true).repair_polygon_soup(true))) {
std::cerr << "Error: could not read mesh from '" << filename << "'.\n";
return 1;
}
std::cout << "Loaded mesh with " << num_vertices(mesh) << " vertices, " << num_faces(mesh) << " faces.\n";
auto face_property_maps = mesh.properties<Face_descriptor>();
for (const auto& pm : face_property_maps) std::cout << pm << std::endl;
// Show colors for faces
auto fcolors_optional = mesh.property_map<Face_descriptor, CGAL::IO::Color >("f:color");
if (! fcolors_optional) {
std::cerr << "Error: could not read colors from '" << filename << "'.\n";
return 1;
}
auto fcolors = fcolors_optional.value();
#else
Face_color_map fcolors;
#if 0
if (! CGAL::IO::read_polygon_mesh(filename, mesh, CGAL::parameters::verbose(true).repair_polygon_soup(true))) {
#else
if (! CGAL::IO::read_polygon_mesh(filename, mesh, CGAL::parameters::verbose(true).repair_polygon_soup(true).
face_color_map(fcolors))) {
#endif
std::cerr << "Error: could not read mesh from '" << filename << "'.\n";
return 1;
}
std::cout << "Loaded mesh with " << num_vertices(mesh) << " vertices, " << num_faces(mesh) << " faces.\n";
#endif
std::size_t idx = 0;
for (auto fd : CGAL::faces(mesh)) {
CGAL::IO::Color c = get(fcolors, fd);
std::cout << "face[" << idx++ << "]: ("
<< int(c.red()) << ", "
<< int(c.green()) << ", "
<< int(c.blue()) << ", "
<< int(c.alpha()) << ")\n";
}
CGAL::Graphics_scene_options<Mesh, Vertex_descriptor, Edge_descriptor, Face_descriptor> gso;
#if ! defined(USE_SURFACE_MESH)
gso.colored_face=[](const Mesh&, Face_descriptor) -> bool { return true; };
gso.face_color=[&](const Mesh& mesh, Face_descriptor fd) -> CGAL::IO::Color { return get(fcolors, fd); };
#endif
CGAL::draw(mesh, gso, filename);
return 0;
}Environment
- Operating system (Windows/Mac/Linux, 32/64 bits):
- Compiler:
- Release or debug mode:
- Specific flags used (if any):
- CGAL version:
- Boost version:
- Other libraries versions if used (Eigen, TBB, etc.):
I am not sure about the importance of off files. Good support for ply seems much more important. Also today I favor good support for Surfcace_mesh as it has the properties mechanism.