//============================================================================= // Copyright (C) 2001-2005 by Computer Graphics Group, RWTH Aachen // Copyright (C) 2011 by Graphics & Geometry Group, Bielefeld University // Copyright (C) 2014 GeometryFactory // // This file is part of CGAL (www.cgal.org). // You can redistribute it and/or modify it under the terms of the GNU // General Public License as published by the Free Software Foundation, // either version 3 of the License, or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0+ // #ifndef CGAL_SURFACE_MESH_IO_H #define CGAL_SURFACE_MESH_IO_H #include #include //== INCLUDES ================================================================= #include #include #include #include #include #include #include #include #include #include #include #include #include #include //============================================================================= namespace CGAL { namespace internal { // helper function template void read(std::istream& in, T& t) { in.read(reinterpret_cast(&t), sizeof(t)); } template bool read_off_binary(Surface_mesh& mesh, std::istream& in, const bool has_normals, const bool has_texcoords) { typedef Surface_mesh Mesh; typedef typename Kernel_traits::Kernel K; typedef typename K::Vector_3 Vector_3; typedef typename K::Vector_2 Vector_2; typedef typename K::Vector_3 Normal; typedef typename K::Vector_3 Texture_coordinate; unsigned int i, j, idx; unsigned int nV, nF, nE; Point_3 p; Vector_3 n, c; Vector_2 t; typename Mesh::Vertex_index v; // properties typename Mesh::template Property_map normals; typename Mesh::template Property_map texcoords; if (has_normals) normals = mesh.template add_property_map("v:normal").first; if (has_texcoords) texcoords = mesh.template add_property_map("v:texcoord").first; // #Vertice, #Faces, #Edges internal::read(in, nV); internal::read(in, nF); internal::read(in, nE); mesh.clear(); mesh.reserve(nV, (std::max)(3*nV, nE), nF); // read vertices: pos [normal] [color] [texcoord] for (i=0; i vertices; for (i=0; i bool read_off_ascii(Surface_mesh& mesh, std::istream& in, const bool has_normals, const bool has_texcoords) { typedef Surface_mesh Mesh; typedef typename Kernel_traits::Kernel K; typedef typename K::Vector_3 Vector_3; typedef typename K::Vector_3 Normal; typedef typename K::Vector_3 Texture_coordinate; boost::array buffer; std::string line; unsigned int i, j, idx; unsigned int nV, nF, nE; typename Mesh::Vertex_index v; // properties typename Mesh::template Property_map normals; typename Mesh::template Property_map texcoords; if (has_normals) normals = mesh.template add_property_map("v:normal").first; if (has_texcoords) texcoords = mesh.template add_property_map("v:texcoord").first; char c; do { c = in.get(); if(c == '#'){ getline(in,line); } else { in.putback(c); break; } }while(1); // #Vertice, #Faces, #Edges in >> nV >> nF >> nE; getline(in,line); // reads eol mesh.clear(); mesh.reserve(nV, (std::max)(3*nV, nE), nF); // read vertices: pos [normal] [color] [texcoord] for (i=0; i> iformat(buffer[0]) >> iformat(buffer[1]) >> iformat(buffer[2]); v = mesh.add_vertex(Point_3(buffer[0], buffer[1], buffer[2])); // normal if (has_normals) { iss >> iformat(buffer[0]) >> iformat(buffer[1]) >> iformat(buffer[2]); } // tex coord if (has_texcoords) { iss >> iformat(buffer[0]) >> iformat(buffer[1]); texcoords[v] = Vector_3(buffer[0], buffer[1], 0.0); } } // read faces: #N v[1] v[2] ... v[n-1] std::vector vertices; for (i=0; i> nV; vertices.resize(nV); // indices for (j=0; j> idx; vertices[j] = typename Mesh::Vertex_index(idx); } if(!mesh.add_face(vertices).is_valid()) { // adding a face did not succeed, stop reading the rest return false; } } return true; } } #if 0 /// \addtogroup PkgSurfaceMeshIO /// /// I/O functionality for `Surface_mesh`. The top-level functions /// `read_mesh()` and `write_mesh()` dispatch on the available readers /// according to the file extension. Currently only `OFF` files are /// supported. /// /// @{ /// This function reads an `OFF` file into a `Surface_mesh`. It /// supports the `OFF` vertex properties normal, color, and vertex /// coordinates. If a property is detected in the `OFF` file, it will be /// read into the `mesh` as a vertex property with the name /// `"v:normal"`, `"v:color"`, and `"v:texcoord"`, respectivly. /// /// @param mesh The mesh that should contain the file contents. /// @param filename The name of the file to be read. /// /// @returns `true`, if reading succeeded, `false` otherwise /// #endif template bool read_off(Surface_mesh& mesh, const std::string& filename) { std::string line; bool has_texcoords = false; bool has_normals = false; bool has_hcoords = false; bool has_dim = false; bool is_binary = false; // open file (in ASCII mode) std::ifstream in(filename.c_str()); if (!in) return false; // read header: [ST][C][N][4][n]OFF BINARY std::getline(in,line); const char *c = line.c_str(); if (c[0] == 'S' && c[1] == 'T') { has_texcoords = true; c += 2; } if (c[0] == 'N') { has_normals = true; ++c; } if (c[0] == '4') { has_hcoords = true; ++c; } if (c[0] == 'n') { has_dim = true; ++c; } if (strncmp(c, "OFF", 3) != 0) { in.close(); return false; } // no OFF if (strncmp(c+4, "BINARY", 6) == 0) is_binary = true; // homogeneous coords, and vertex dimension != 3 are not supported if (has_hcoords || has_dim) { in.close(); return false; } // if binary: reopen file in binary mode if (is_binary) { in.close(); in.open(filename.c_str(), std::ios::binary); std::getline(in,line); } // read as ASCII or binary bool ok = (is_binary ? internal::read_off_binary(mesh, in, has_normals, has_texcoords) : internal::read_off_ascii(mesh, in, has_normals, has_texcoords)); in.close(); return ok; } #if 0 /// This function writes a `Surface_mesh` into an ASCII `OFF` /// file. It does not support properties. /// /// @param mesh The mesh that should be written. /// @param filename The name of the file to be written. /// /// @returns `true`, if reading succeeded, `false` otherwise /// #endif template bool write_off(const Surface_mesh& mesh, const std::string& filename) { std::ofstream out(filename.c_str()); if (out.fail()) return false; out << std::setprecision(17); write_off(out, mesh); return !out.fail(); } #if 0 /// Read a file into a `Surface_mesh`. The extension of the /// filename determines which reader is used. /// /// Mapping from extension to reader: /// - off/OFF -> `read_off()` /// /// @param mesh The mesh that should contain the input. /// @param filename The name of the file to be read. /// /// @return `true`, if reading succeeded, `false` otherwise /// #endif template bool read_mesh(Surface_mesh& mesh, const std::string& filename) { // clear mesh before reading from file mesh.clear(); // extract file extension std::string::size_type dot(filename.rfind(".")); if (dot == std::string::npos) return false; std::string ext = filename.substr(dot+1, filename.length()-dot-1); std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); // extension determines reader if (ext == "off") { return read_off(mesh, filename); } // we didn't find a reader module return false; } #if 0 /// Write a `Surface_mesh` to a file. The extension of the /// filename determines which writer is used. /// /// Mapping from extension to writer: /// - off/OFF -> `read_off()` /// /// @param mesh The mesh to be written. /// @param filename The name of the file to be written. /// /// @return `true`, if writing succeeded, `false` otherwise /// #endif template bool write_mesh(const Surface_mesh& mesh, const std::string& filename) { // extract file extension std::string::size_type dot(filename.rfind(".")); if (dot == std::string::npos) return false; std::string ext = filename.substr(dot+1, filename.length()-dot-1); std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); // extension determines reader if (ext == "off") { return write_off(mesh, filename); } // we didn't find a writer module return false; } /// group io /// @} template void generic_print_surface_mesh( std::ostream& out, const Surface_mesh

& M, Writer& writer) { // writes M to `out' in the format provided by `writer'. typedef typename boost::graph_traits >::vertex_iterator VCI; typedef typename boost::graph_traits >::face_iterator FCI; typedef typename Surface_mesh

::Halfedge_around_face_circulator HFCC; typedef typename boost::property_map,CGAL::vertex_point_t>::type VPmap; VPmap map = get(CGAL::vertex_point, M); // Print header. writer.write_header( out, num_vertices(M), num_halfedges(M), num_faces(M)); std::map::vertex_index, std::size_t> index_map; typename std::map::vertex_index, std::size_t>::iterator hint = index_map.begin(); std::size_t id = 0; for( VCI vi = vertices(M).begin(); vi != vertices(M).end(); ++vi) { writer.write_vertex( ::CGAL::to_double( get(map, *vi).x()), ::CGAL::to_double( get(map, *vi).y()), ::CGAL::to_double( get(map, *vi).z())); hint = index_map.insert(hint, std::make_pair(*vi, id++)); } writer.write_facet_header(); for( FCI fi = faces(M).begin(); fi != faces(M).end(); ++fi) { HFCC hc(halfedge(*fi, M), M); HFCC hc_end = hc; std::size_t n = circulator_size( hc); CGAL_assertion( n >= 3); writer.write_facet_begin( n); do { writer.write_facet_vertex_index(index_map[target(*hc, M)]); ++hc; } while( hc != hc_end); writer.write_facet_end(); } writer.write_footer(); } } // CGAL #include #endif // CGAL_SURFACE_MESH_IO_H