diff --git a/Installation/include/CGAL/Mesh_3/Triangulation_3_fwd.h b/Installation/include/CGAL/Mesh_3/Triangulation_3_fwd.h new file mode 100644 index 000000000000..6207a973e66d --- /dev/null +++ b/Installation/include/CGAL/Mesh_3/Triangulation_3_fwd.h @@ -0,0 +1,25 @@ +// Copyright (C) 2023 GeometryFactory Sarl +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// + +#ifndef CGAL_MESH_3_TRIANGULATION_3_FWD_H +#define CGAL_MESH_3_TRIANGULATION_3_FWD_H + +#include + +#include + +namespace CGAL { + +template < class GT, class Tds = Default, + class Lock_data_structure = Default > +class Triangulation_3; + +} // end namespace CGAL + +#endif // CGAL_MESH_3_TRIANGULATION_3_FWD_H diff --git a/Lab/demo/Lab/Plugins/Mesh_3/C3t3_io_plugin.cpp b/Lab/demo/Lab/Plugins/Mesh_3/C3t3_io_plugin.cpp index af885246ea45..bf12df1dd134 100644 --- a/Lab/demo/Lab/Plugins/Mesh_3/C3t3_io_plugin.cpp +++ b/Lab/demo/Lab/Plugins/Mesh_3/C3t3_io_plugin.cpp @@ -499,6 +499,12 @@ try_load_a_cdt_3(std::istream& is, C3t3& c3t3) } std::getline(is, s); if(s != "") { + if(s.back() == '\r') { // Windows EOL if the file was written without the ios_base::binary flag. + is.setstate(std::ios_base::failbit); + std::cerr << "load_binary_file:" + << "\n Unexpected char : '\\r'. The file's content was probably written without the ios_base::binary flag." << std::endl; + return false; + } if(s != std::string(" ") + CGAL::Get_io_signature()()) { std::cerr << "load_binary_file:" << "\n expected format: " << CGAL::Get_io_signature()() @@ -507,7 +513,7 @@ try_load_a_cdt_3(std::istream& is, C3t3& c3t3) } } if(binary) CGAL::IO::set_binary_mode(is); - if(c3t3.triangulation().file_input< + if(c3t3.file_input< Fake_CDT_3, Update_vertex_from_CDT_3, Update_cell_from_CDT_3>(is)) @@ -582,6 +588,12 @@ try_load_other_binary_format(std::istream& is, C3t3& c3t3) } std::getline(is, s); if(s != "") { + if(s.back() == '\r') { // Windows EOL if the file was written without the ios_base::binary flag. + is.setstate(std::ios_base::failbit); + std::cerr << "Polyhedron_demo_c3t3_binary_io_plugin::try_load_other_binary_format:" + << "\n Unexpected char : '\\r'. The file's content was probably written without the ios_base::binary flag." << std::endl; + return false; + } if(s != std::string(" ") + CGAL::Get_io_signature()()) { std::cerr << "CGAL_Lab_c3t3_binary_io_plugin::try_load_other_binary_format:" << "\n expected format: " << CGAL::Get_io_signature()() @@ -591,7 +603,7 @@ try_load_other_binary_format(std::istream& is, C3t3& c3t3) } if(binary) CGAL::IO::set_binary_mode(is); else CGAL::IO::set_ascii_mode(is); - std::istream& f_is = c3t3.triangulation().file_input< + std::istream& f_is = c3t3.file_input< Fake_c3t3::Triangulation, Update_vertex, Update_cell>(is); diff --git a/SMDS_3/include/CGAL/IO/File_binary_mesh_3.h b/SMDS_3/include/CGAL/IO/File_binary_mesh_3.h index e7363047a924..80887131f10e 100644 --- a/SMDS_3/include/CGAL/IO/File_binary_mesh_3.h +++ b/SMDS_3/include/CGAL/IO/File_binary_mesh_3.h @@ -87,8 +87,11 @@ bool load_binary_file(std::istream& is, C3T3& c3t3) } std::getline(is, s); if(!s.empty()) { - if(s[s.size()-1] == '\r') { // deal with Windows EOL - s.resize(s.size() - 1); + if(s.back() == '\r') { // Windows EOL if the file was written without the ios_base::binary flag. + is.setstate(std::ios_base::failbit); + std::cerr << "load_binary_file:" + << "\n Unexpected char : '\\r'. The file's content was probably written without the ios_base::binary flag." << std::endl; + return false; } if(s != std::string(" ") + CGAL::Get_io_signature()()) { std::cerr << "load_binary_file:" diff --git a/SMDS_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h b/SMDS_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h index c58110c9b32b..c08eb15f3c19 100644 --- a/SMDS_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h +++ b/SMDS_3/include/CGAL/Mesh_complex_3_in_triangulation_3.h @@ -1204,11 +1204,98 @@ class Mesh_complex_3_in_triangulation_3 std::istream& operator>>(std::istream& is, Mesh_complex_3_in_triangulation_3& c3t3); + template + friend + std::ostream & operator<<(std::ostream& os, + const Mesh_complex_3_in_triangulation_3 &c3t3); + + static std::string io_signature() { return Get_io_signature()(); } + std::istream& read_edges(std::istream& is, const std::vector< Vertex_handle >& vertices_handles) + { + // Reads 1D features + std::size_t nEdges; + if(IO::is_ascii(is)) + { + is >> nEdges; + } + else + { + read(is, nEdges); + } + // If the file did not have edges + if (!is) { + return is; + } + + for (std::size_t i = 0; i < nEdges; i++) + { + std::size_t iv1; + std::size_t iv2; + Curve_index index; + if (IO::is_ascii(is)) + is >> iv1 >> iv2 >> index; + else { + read(is, iv1); + read(is, iv2); + read(is, index); + } + Internal_edge edge(vertices_handles[iv1], vertices_handles[iv2]); + add_to_complex(edge, index); + } + return is; + } + + template + std::istream& file_input(std::istream& is, + ConvertVertex convert_vertex = ConvertVertex(), + ConvertCell convert_cell = ConvertCell()) + { + // Reads: + // - the dimension + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + // - the number of cells + // - the cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each cell + // - the neighbors of each cell by their index in the preceding list of cells + // - when dimension < 3 : the same with faces of maximal dimension + // - the number of edges + // - the edges by the indices of their vertices and their curve_index + + // If this is used for a TDS, the vertices are processed from 0 to n. + // Else, we make V[0] the infinite vertex and work from 1 to n+1. + + // Reads triangulation + std::vector< Vertex_handle > vertices_handles; + if (!tr_.template file_input + (is, vertices_handles, convert_vertex, convert_cell)) + { + clear(); + is.setstate(std::ios_base::failbit); + return is; + } + + // Reads 1D Features + read_edges(is, vertices_handles); + // To keep compatibility with previous files, + // the istream errors should be cleared and the progress reversed + if (!is) + { + is.clear(); + edges_.clear(); + return is; + } + + return is; + } + /** * @cond SKIP_IN_MANUAL * creates an `Internal_edge` object (i.e a pair of ordered `Vertex_handle`) @@ -2074,8 +2161,69 @@ std::ostream & operator<< (std::ostream& os, const Mesh_complex_3_in_triangulation_3 &c3t3) { - // TODO: implement edge saving - return os << c3t3.triangulation(); + /* Writes: + * [Triangulation] + * [Header] + * - the dimension + * [Vertices] + * - the number of finite vertices + * - the non combinatorial information on vertices (point, etc) + * [Cells] + * - the number of cells + * - the cells by the indices of their vertices in the preceding list + * of vertices, plus the non combinatorial information on each cell + * [Cells combinatorial information] + * - the neighbors of each cell by their index in the preceding list of cells + * [Cells other info] + * - when dimension < 3 : the same with faces of maximal dimension + * [1D features] + * - the number of edges + * - the edges by the indices of their vertices and their curve_index + */ + using C3t3 = Mesh_complex_3_in_triangulation_3; + using Vertex_handle = typename C3t3::Vertex_handle; + using Curve_index = typename C3t3::Curve_index; + + // Writes triangulation + Unique_hash_map vertices_map; + if (!CGAL::IO::export_triangulation_3(os, c3t3.triangulation(), vertices_map)) + { + os.setstate(std::ios_base::failbit); + return os; + } + + // Writes 1D features + std::size_t nEdges = c3t3.edges_.size(); + if(IO::is_ascii(os)) + { + os << nEdges << '\n'; + } + else + { + write(os, nEdges); + } + + if (!os) + return os; + + for ( typename C3t3::Edge_map::const_iterator it = c3t3.edges_.begin(), + end = c3t3.edges_.end() ; it != end ; ++it ) + { + const Vertex_handle& v1 = it->left; + const Vertex_handle& v2 = it->right; + const std::size_t& iv1 = vertices_map[v1]; + const std::size_t& iv2 = vertices_map[v2]; + const Curve_index& index = it->info; + if (IO::is_ascii(os)) + os << iv1 << ' ' << iv2 << ' ' << index << '\n'; + else { + write(os, iv1); + write(os, iv2); + write(os, index); + } + } + + return os; } @@ -2084,15 +2232,48 @@ std::istream & operator>> (std::istream& is, Mesh_complex_3_in_triangulation_3 &c3t3) { - // TODO: implement edge loading + /* Reads: + * [Triangulation] + * [Header] + * - the dimension + * [Vertices] + * - the number of finite vertices + * - the non combinatorial information on vertices (point, etc) + * [Cells] + * - the number of cells + * - the cells by the indices of their vertices in the preceding list + * of vertices, plus the non combinatorial information on each cell + * [Cells combinatorial information] + * - the neighbors of each cell by their index in the preceding list of cells + * [Cells other info] + * - when dimension < 3 : the same with faces of maximal dimension + * [1D features] + * - the number of edges + * - the edges by the indices of their vertices and their curve_index + */ + using C3t3 = Mesh_complex_3_in_triangulation_3; + using Vertex_handle = typename C3t3::Vertex_handle; + c3t3.clear(); - is >> c3t3.triangulation(); - if (!is) { + // Reads triangulation + std::vector< Vertex_handle > vertices_handles; + if (!CGAL::IO::import_triangulation_3(is, c3t3.triangulation(), vertices_handles)) + { c3t3.clear(); + is.setstate(std::ios_base::failbit); return is; } + c3t3.read_edges(is, vertices_handles); + // To keep compatibility with previous files, + // the istream errors should be cleared and the progress reversed + if (!is) + { + is.clear(); + c3t3.edges_.clear(); + } + c3t3.rescan_after_load_of_triangulation(); return is; } diff --git a/SMDS_3/test/SMDS_3/test_c3t3_io.cpp b/SMDS_3/test/SMDS_3/test_c3t3_io.cpp index cb9e18171511..d092ff04be92 100644 --- a/SMDS_3/test/SMDS_3/test_c3t3_io.cpp +++ b/SMDS_3/test/SMDS_3/test_c3t3_io.cpp @@ -245,13 +245,8 @@ struct Test_c3t3_io { end1 = t1.finite_vertices_end(); vit1 != end1; ++vit1, ++vit2) { - if(!( vit1->in_dimension() == vit2->in_dimension() && - vit1->index() == vit2->index()) ) + if(!compare_vertices(vit1, vit2)) { - std::cerr << "Error: vertices are different:\n"; - std::cerr << *vit1 << "\n" - << *vit2 << std::endl; - assert(false); return false; } } @@ -292,32 +287,84 @@ struct Test_c3t3_io { end1 = t1.finite_cells_end(); cit1 != end1; ++cit1, ++cit2) { - if(cit1->subdomain_index() != cit2->subdomain_index() ) + if (!compare_cells(cit1, cit2)) + return false; + } + return true; + } + + static bool compare_vertices(const Vertex_handle& vit1, const Vertex_handle& vit2) { + if(!( vit1->in_dimension() == vit2->in_dimension() && + vit1->index() == vit2->index()) ) + { + std::cerr << "Error: vertices are different:\n"; + std::cerr << *vit1 << "\n" + << *vit2 << std::endl; + assert(false); + return false; + } + return true; + } + + static bool compare_cells(const Cell_handle& cit1, const Cell_handle& cit2) { + if(cit1->subdomain_index() != cit2->subdomain_index() ) + { + std::cerr << "Error: cells are different:\n"; + std::cerr << *cit1 << "\n" + << *cit2 << std::endl; + assert(false); + return false; + } + for(int i = 0; i < 4; ++i) { + if( cit1->surface_patch_index(i) != + cit2->surface_patch_index(i) ) { std::cerr << "Error: cells are different:\n"; std::cerr << *cit1 << "\n" - << *cit2 << std::endl; + << *cit2 << "\n" + << "surface_patch_index(" << i << "):\n" + << cit1->surface_patch_index(i) << "\n" + << cit2->surface_patch_index(i) << "\n"; assert(false); return false; } - for(int i = 0; i < 4; ++i) { - if( cit1->surface_patch_index(i) != - cit2->surface_patch_index(i) ) - { - std::cerr << "Error: cells are different:\n"; - std::cerr << *cit1 << "\n" - << *cit2 << "\n" - << "surface_patch_index(" << i << "):\n" - << cit1->surface_patch_index(i) << "\n" - << cit2->surface_patch_index(i) << "\n"; - assert(false); - return false; - } - } } return true; } + static bool check_features(const C3t3& c1, const C3t3& c2) { + typedef typename C3t3::Edges_in_complex_iterator Edges_in_complex_iterator; + + if (c1.number_of_edges_in_complex() != c2.number_of_edges_in_complex()) + { + assert(false); + return false; + } +#if 0 + // Not sure if the C3t3 edges in complex iterator order changes after a reload... + for (Edges_in_complex_iterator + eit1 = c1.edges_in_complex_begin(), + eit2 = c2.edges_in_complex_begin(), + end1 = c1.edges_in_complex_end(); + eit1 != end1; ++eit1, ++eit2) + { + Cell_handle cell1 = eit1->first; + Cell_handle cell2 = eit2->first; + if (!compare_cells(cell1, cell2)) + return false; + Vertex_handle vertex1_1 = cell1->vertex(eit1->second); + Vertex_handle vertex1_2 = cell2->vertex(eit2->second); + if (!compare_vertices(vertex1_1, vertex1_2)) + return false; + Vertex_handle vertex2_1 = cell1->vertex(eit1->third); + Vertex_handle vertex2_2 = cell2->vertex(eit2->third); + if (!compare_vertices(vertex2_1, vertex2_2)) + return false; + } +#endif + return true; + } + static bool test_io(const C3t3& c3t3, const char* prefix, bool binary) { std::string filename(prefix); std::cout << "test_io"; @@ -358,7 +405,7 @@ struct Test_c3t3_io { assert(ss_c3t3); assert(ss_c3t3_bis); assert(ss_c3t3.str() == ss_c3t3_bis.str()); - if(!check_equality(c3t3, c3t3_bis)) return false; + if(!check_equality(c3t3, c3t3_bis) || !check_features(c3t3, c3t3_bis)) return false; } c3t3_bis.clear(); @@ -372,7 +419,7 @@ struct Test_c3t3_io { CGAL::IO::load_binary_file(ss, c3t3_bis); assert(ss); } - if(!check_equality(c3t3, c3t3_bis)) return false; + if(!check_equality(c3t3, c3t3_bis) || !check_features(c3t3, c3t3_bis)) return false; #ifndef CGAL_LITTLE_ENDIAN // skip binary I/O with the existing file for big endian @@ -404,6 +451,7 @@ struct Test_c3t3_io { CGAL::IO::load_binary_file(input, c3t3_bis); assert(input); } + // reading from a feature-less c3t3 file, do not check feature if(!check_equality(c3t3, c3t3_bis)) return false; return true; diff --git a/Triangulation_3/include/CGAL/IO/Triangulation_raw_iostream_3.h b/Triangulation_3/include/CGAL/IO/Triangulation_raw_iostream_3.h new file mode 100644 index 000000000000..085c1d7a038c --- /dev/null +++ b/Triangulation_3/include/CGAL/IO/Triangulation_raw_iostream_3.h @@ -0,0 +1,462 @@ +// Copyright (c) 1999-2003 INRIA Sophia-Antipolis (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Monique Teillaud +// Sylvain Pion +// Clement Jamin + +#ifndef CGAL_IO_TRIANGULATION_RAW_IOSTREAM_3_H +#define CGAL_IO_TRIANGULATION_RAW_IOSTREAM_3_H + +#include + +#include +#include + +#include +#include +#include + +namespace CGAL { + +namespace IO { + +namespace internal { + +template < class GT, class Tds_, class Lds_ > +bool construct_vertices_map(const Triangulation_3& tr, + Unique_hash_map::Vertex_handle, std::size_t>& vertices_map) +{ + typedef Triangulation_3 Triangulation; + typedef typename Triangulation::size_type size_type; + typedef typename Triangulation::Vertex_iterator Vertex_iterator; + + size_type i = 0; + vertices_map[tr.infinite_vertex()] = 0; + for(Vertex_iterator it = tr.vertices_begin(), end = tr.vertices_end(); it != end; ++it) + { + vertices_map[it] = i++; + } + + CGAL_assertion(i == tr.number_of_vertices()+1); + + return true; +} + +template < class GT, class Tds_, class Lds_ > +bool write_header(std::ostream& os, const Triangulation_3& tr) +{ + // Writes: + // - the dimension + if(IO::is_ascii(os)) + { + os << tr.dimension() << "\n"; + } + else + { + CGAL::write(os, tr.dimension()); + } + return (bool)os; +} + +template < class GT, class Tds_, class Lds_ > +bool read_header(std::istream& is, Triangulation_3& tr) +{ + // Reads: + // - the dimension + int dimension; + if(IO::is_ascii(is)) + { + is >> dimension; + } + else + { + CGAL::read(is, dimension); + } + if(dimension > 3 || dimension < -2) + return false; + tr.tds().set_dimension(dimension); + return (bool)is; +} + +template < class GT, class Tds_, class Lds_ > +bool write_vertices(std::ostream& os, const Triangulation_3& tr) +{ + // Writes: + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + typedef Triangulation_3 Triangulation; + typedef typename Triangulation::size_type size_type; + typedef typename Triangulation::Vertex_iterator Vertex_iterator; + + size_type n = tr.number_of_vertices(); + + if(IO::is_ascii(os)) + { + os << n << '\n'; + } + else + { + CGAL::write(os, n); + } + + if (n == 0) + return false; + + for(Vertex_iterator it = ++tr.vertices_begin(), end = tr.vertices_end(); it != end; ++it) + { + os << *it; + if(IO::is_ascii(os)) + os << '\n'; + } + + return (bool)os; +} + +template < class GT, class Tds_, class Lds_, + typename Tr_src, + typename ConvertVertex > +bool read_vertices_with_conversion(std::istream& is, Triangulation_3& tr, + std::vector< typename Triangulation_3::Vertex_handle >& vertices_handles, + typename Triangulation_3::size_type n, + ConvertVertex convert_vertex = ConvertVertex()) +{ + // Reads: + // - the non combinatorial information on vertices (point, etc) + // The vertices are read with the type Tr_src::Vertex + // and converted to type Triangulation_3::Vertex + // using the ConvertVertex convertor. + typedef typename Tr_src::Vertex Vertex1; + + for(std::size_t i=1; i <= n; i++) + { + Vertex1 v; + if(!(is >> v)) + return false; + vertices_handles[i] = tr.tds().create_vertex(); + convert_vertex(v, *vertices_handles[i]); + } + + return (bool)is; +} + +template < class GT, class Tds_, class Lds_> +bool read_vertices_without_conversion(std::istream& is, Triangulation_3& tr, + std::vector< typename Triangulation_3::Vertex_handle >& vertices_handles, + typename Triangulation_3::size_type n) +{ + // Reads: + // - the non combinatorial information on vertices (point, etc) + for(std::size_t i=1; i <= n; i++) + { + vertices_handles[i] = tr.tds().create_vertex(); + if(!(is >> *vertices_handles[i])) + return false; + } + return (bool)is; +} + + +template < class GT, class Tds_, class Lds_, + typename Tr_src = Triangulation_3, + typename ConvertVertex = Nullptr_t > +bool read_vertices(std::istream& is, Triangulation_3& tr, + std::vector< typename Triangulation_3::Vertex_handle >& vertices_handles, + ConvertVertex convert_vertex = ConvertVertex()) +{ + // Reads: + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + typedef Triangulation_3 Triangulation; + typedef typename Triangulation::size_type size_type; + + size_type n; + if(IO::is_ascii(is)) + { + is >> n; + } + else + { + CGAL::read(is, n); + } + if((n+1) > vertices_handles.max_size()) + return false; + + vertices_handles.resize(n+1); + vertices_handles[0] = tr.infinite_vertex(); // the infinite vertex is numbered 0 + + if constexpr (std::is_same::value) + { + if (!read_vertices_without_conversion(is, tr, vertices_handles, n)) + return false; + } + else + { + if (!read_vertices_with_conversion(is, tr, vertices_handles, n, convert_vertex)) + return false; + } + + return (bool)is; +} + +struct Cell_accessor +{ + template + auto operator()(const Iterator& it) { return it; } +}; + +struct Cell_accessor_first +{ + template + auto operator()(const Iterator& it) { return it->first; } +}; + +template +bool write_cell_info(std::ostream& os, Iterator start, const Iterator& end) +{ + Cell_accessor accessor; + if(IO::is_ascii(os)) + { + for(; start != end; ++start) + { + os << *(accessor(start)) << '\n'; + } + } + else + { + for(; start != end; ++start) + { + os << *(accessor(start)); + } + } + return (bool)os; +} + +template < class GT, class Tds_, class Lds_ > +bool write_cells(std::ostream& os, const Triangulation_3& tr, + const Unique_hash_map::Vertex_handle, std::size_t>& vertices_map) +{ + // Writes: + // [Call to Tds_::print_cells] + // - the number of cells + // - the cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each cell + // - the neighbors of each cell by their index in the preceding list of cells + // [Cells other info] + // - when dimension < 3 : the same with faces of maximal dimension + + typedef Triangulation_3 Triangulation; + typedef typename Triangulation::Cell_iterator Cell_iterator; + typedef typename Triangulation::Edge_iterator Edge_iterator; + typedef typename Triangulation::Facet_iterator Facet_iterator; + + tr.tds().print_cells(os, vertices_map); + if (!os) + return false; + + // Write the non combinatorial information on the cells + // using the << operator of Cell. + // Works because the iterator of the tds traverses the cells in the + // same order as the iterator of the triangulation + switch(tr.dimension()) + { + case 3: + { + return write_cell_info(os, tr.cells_begin(), tr.cells_end()); + break; + } + case 2: + { + return write_cell_info(os, tr.facets_begin(), tr.facets_end()); + break; + } + case 1: + { + return write_cell_info(os, tr.edges_begin(), tr.edges_end()); + break; + } + } + return false; +} + + +template < class GT, class Tds_, class Lds_, + typename Tr_src, + typename ConvertCell > +bool read_cells_with_conversion(std::istream& is, typename Triangulation_3::size_type m, + std::vector< typename Triangulation_3::Cell_handle >& C, + ConvertCell convert_cell = ConvertCell()) +{ + // Reads: + // [Cells other info] + // - when dimension < 3 : the same with faces of maximal dimension + // The cell are read with the type Tr_src::Cell + // and converted to type Triangulation_3::Cell + // using the ConvertCell convertor. + + typedef typename Tr_src::Cell Cell1; + + for(std::size_t i=0 ; i < m; i++) + { + Cell1 c; + if(!(is >> c)) + return false; + convert_cell(c, *C[i]); + } + + return (bool)is; +} + +template < class GT, class Tds_, class Lds_ > +bool read_cells_without_conversion(std::istream& is, typename Triangulation_3::size_type m, + std::vector< typename Triangulation_3::Cell_handle >& C) +{ + // Reads: + // - the non combinatorial information on vertices (point, etc) + for(std::size_t i=0 ; i < m; i++) + { + if(!(is >> *C[i])) + return false; + } + + return (bool)is; +} + +template < class GT, class Tds_, class Lds_, + typename Tr_src = Triangulation_3, + typename ConvertCell = Nullptr_t > +bool read_cells(std::istream& is, Triangulation_3& tr, + const std::vector< typename Triangulation_3::Vertex_handle >& vertices_handles, + ConvertCell convert_cell = ConvertCell()) +{ + // Reads: + // [Call to Tds_::read_cells] + // - the number of cells + // - the cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each cell + // - the neighbors of each cell by their index in the preceding list of cells + // [Cells other info] + // - when dimension < 3 : the same with faces of maximal dimension + + typedef Triangulation_3 Triangulation; + typedef typename Triangulation::Cell_handle Cell_handle; + + std::vector< Cell_handle > C; + + std::size_t m; + tr.tds().read_cells(is, vertices_handles, m, C); + if(!is) + return false; + + if constexpr (std::is_same::value) + { + if (!read_cells_without_conversion(is, m, C)) + return false; + } + else + { + if (!read_cells_with_conversion(is, m, C, convert_cell)) + return false; + } + + return (bool)is; +} + +} // end namespace internal + + +template < class GT, class Tds_, class Lds_ > +bool export_triangulation_3(std::ostream& os, const Triangulation_3& tr, + Unique_hash_map::Vertex_handle, std::size_t>& vertices_map) +{ + // Writes: + // [Header] + // - the dimension + // [Vertices] + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + // [Cells] + // - the number of cells + // - the cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each cell + // [Cells combinatorial information] + // - the neighbors of each cell by their index in the preceding list of cells + // [Cells other info] + // - when dimension < 3 : the same with faces of maximal dimension + + return internal::write_header(os, tr) + && internal::write_vertices(os, tr) + && internal::construct_vertices_map(tr, vertices_map) + && internal::write_cells(os, tr, vertices_map); +} + +template < class GT, class Tds_, class Lds_ > +bool export_triangulation_3(std::ostream& os, const Triangulation_3& tr) +{ + Unique_hash_map::Vertex_handle, std::size_t> vertices_map; + return export_triangulation_3(os, tr, vertices_map); +} + + +template < class GT, class Tds_, class Lds_, + typename Tr_src = Triangulation_3, + typename ConvertVertex = Nullptr_t, + typename ConvertCell = Nullptr_t > +bool import_triangulation_3(std::istream& is, Triangulation_3& tr, + std::vector::Vertex_handle >& vertices_handles, + ConvertVertex convert_vertex = ConvertVertex(), + ConvertCell convert_cell = ConvertCell()) +{ + // Reads: + // [Header] + // - the dimension + // [Vertices] + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + // [Cells] + // - the number of cells + // - the cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each cell + // [Cells combinatorial information] + // - the neighbors of each cell by their index in the preceding list of cells + // [Cells other info] + // - when dimension < 3 : the same with faces of maximal dimension + + tr.tds().clear(); // infinite vertex deleted + tr.set_infinite_vertex(tr.tds().create_vertex()); + + bool result = internal::read_header(is, tr) + && internal::read_vertices + (is, tr, vertices_handles, convert_vertex) + && internal::read_cells + (is, tr, vertices_handles, convert_cell); + + CGAL_assertion(result && tr.is_valid(false)); + return result; +} + +template < class GT, class Tds_, class Lds_, + typename Tr_src = Triangulation_3, + typename ConvertVertex = Nullptr_t, + typename ConvertCell = Nullptr_t > +bool import_triangulation_3(std::istream& is, Triangulation_3& tr, + ConvertVertex convert_vertex = ConvertVertex(), + ConvertCell convert_cell = ConvertCell()) +{ + std::vector::Vertex_handle > vertices_handles; + return import_triangulation_3 + (is, tr, vertices_handles, convert_vertex, convert_cell); +} + + +} // end namespace IO + +} // end namespace CGAL + +#endif // CGAL_IO_TRIANGULATION_RAW_IOSTREAM_3_H diff --git a/Triangulation_3/include/CGAL/Triangulation_3.h b/Triangulation_3/include/CGAL/Triangulation_3.h index 12e92b654479..48c9cf45ee1b 100644 --- a/Triangulation_3/include/CGAL/Triangulation_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_3.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -45,6 +46,8 @@ #include #include +#include + #include #include #include @@ -81,10 +84,6 @@ namespace CGAL { -template < class GT, class Tds = Default, - class Lock_data_structure = Default > -class Triangulation_3; - template < class GT, class Tds, class Lds > std::istream& operator>> (std::istream& is, Triangulation_3& tr); @@ -2325,70 +2324,40 @@ class Triangulation_3 template - std::istream& file_input(std::istream& is, + std::istream& file_input(std::istream& is, std::vector< Vertex_handle >& vertices_handles, ConvertVertex convert_vertex = ConvertVertex(), ConvertCell convert_cell = ConvertCell()) { - // reads - // the dimension - // the number of finite vertices - // the non combinatorial information on vertices (point, etc) - // the number of cells - // the cells by the indices of their vertices in the preceding list - // of vertices, plus the non combinatorial information on each cell - // the neighbors of each cell by their index in the preceding list of cells - // when dimension < 3 : the same with faces of maximal dimension + // Reads: + // - the dimension + // - the number of finite vertices + // - the non combinatorial information on vertices (point, etc) + // - the number of cells + // - the cells by the indices of their vertices in the preceding list + // of vertices, plus the non combinatorial information on each cell + // - the neighbors of each cell by their index in the preceding list of cells + // - when dimension < 3 : the same with faces of maximal dimension // If this is used for a TDS, the vertices are processed from 0 to n. // Else, we make V[0] the infinite vertex and work from 1 to n+1. - typedef Self Triangulation; - typedef typename Triangulation::Vertex_handle Vertex_handle; - typedef typename Triangulation::Cell_handle Cell_handle; - - typedef typename Tr_src::Vertex Vertex1; - typedef typename Tr_src::Cell Cell1; - - clear(); - tds().cells().clear(); - - std::size_t n; - int d; - if(IO::is_ascii(is)) - is >> d >> n; - else { - read(is, d); - read(is, n); - } - if(!is) return is; - tds().set_dimension(d); - - std::size_t V_size = n+1; - std::vector< Vertex_handle > V(V_size); - - // the infinite vertex is numbered 0 - V[0] = infinite_vertex(); - - for (std::size_t i = 1; i < V_size; ++i) { - Vertex1 v; - if(!(is >> v)) return is; - Vertex_handle vh=tds().create_vertex( convert_vertex(v) ); - V[i] = vh; - convert_vertex(v, *V[i]); - } - - std::vector< Cell_handle > C; - - std::size_t m; - tds().read_cells(is, V, m, C); - - for (std::size_t j=0 ; j < m; j++) { - Cell1 c; - if(!(is >> c)) return is; - convert_cell(c, *C[j]); - } + if (!CGAL::IO::import_triangulation_3 + (is, *this, vertices_handles, convert_vertex, convert_cell)) + is.setstate(std::ios_base::failbit); + return is; + } - CGAL_assertion( is_valid(false) ); + //IO + template + std::istream& file_input(std::istream& is, + ConvertVertex convert_vertex = ConvertVertex(), + ConvertCell convert_cell = ConvertCell()) + { + std::vector< Vertex_handle > vertices_handles; + file_input(is, vertices_handles, convert_vertex, convert_cell); return is; } }; @@ -2406,54 +2375,8 @@ std::istream& operator>> (std::istream& is, Triangulation_3& tr) // of vertices, plus the non combinatorial information on each cell // - the neighbors of each cell by their index in the preceding list of cells // - when dimension < 3 : the same with faces of maximal dimension - - typedef Triangulation_3 Triangulation; - typedef typename Triangulation::Vertex_handle Vertex_handle; - typedef typename Triangulation::Cell_handle Cell_handle; - - tr._tds.clear(); // infinite vertex deleted - tr.infinite = tr._tds.create_vertex(); - - std::size_t n; - int d; - if(IO::is_ascii(is)) - { - is >> d >> n; - } - else - { - read(is, d); - read(is, n); - } - if(!is) - return is; - - std::vector< Vertex_handle > V; - if(d > 3 || d < -2 || (n+1) > V.max_size()) { + if (!CGAL::IO::import_triangulation_3(is, tr)) is.setstate(std::ios_base::failbit); - return is; - } - tr._tds.set_dimension(d); - V.resize(n+1); - V[0] = tr.infinite_vertex(); // the infinite vertex is numbered 0 - - for(std::size_t i=1; i <= n; i++) - { - V[i] = tr._tds.create_vertex(); - if(!(is >> *V[i])) - return is; - } - - std::vector< Cell_handle > C; - - std::size_t m; - tr._tds.read_cells(is, V, m, C); - - for(std::size_t j=0 ; j < m; j++) - if(!(is >> *(C[j]))) - return is; - - CGAL_assertion(tr.is_valid(false)); return is; } @@ -2469,91 +2392,9 @@ std::ostream& operator<< (std::ostream& os, const Triangulation_3& // of vertices, plus the non combinatorial information on each cell // - the neighbors of each cell by their index in the preceding list of cells // - when dimension < 3 : the same with faces of maximal dimension - - typedef Triangulation_3 Triangulation; - typedef typename Triangulation::size_type size_type; - typedef typename Triangulation::Vertex_handle Vertex_handle; - typedef typename Triangulation::Vertex_iterator Vertex_iterator; - typedef typename Triangulation::Cell_iterator Cell_iterator; - typedef typename Triangulation::Edge_iterator Edge_iterator; - typedef typename Triangulation::Facet_iterator Facet_iterator; - - // outputs dimension and number of vertices - size_type n = tr.number_of_vertices(); - if(IO::is_ascii(os)) - { - os << tr.dimension() << std::endl << n << std::endl; - } - else - { - write(os, tr.dimension()); - write(os, n); - } - - if(n == 0) - return os; - - std::vector TV(n+1); - size_type i = 0; - - // write the vertices - for(Vertex_iterator it = tr.vertices_begin(), end = tr.vertices_end(); it != end; ++it) - TV[i++] = it; - - CGAL_assertion(i == n+1); - CGAL_assertion(tr.is_infinite(TV[0])); - - Unique_hash_map V; - V[tr.infinite_vertex()] = 0; - for(i=1; i <= n; i++) - { - os << *TV[i]; - V[TV[i]] = i; - if(IO::is_ascii(os)) - os << std::endl; - } - - // Asks the tds for the combinatorial information - tr.tds().print_cells(os, V); - - // Write the non combinatorial information on the cells - // using the << operator of Cell. - // Works because the iterator of the tds traverses the cells in the - // same order as the iterator of the triangulation - switch(tr.dimension()) - { - case 3: - { - for(Cell_iterator it = tr.cells_begin(), end = tr.cells_end(); it != end; ++it) - { - os << *it; // other information - if(IO::is_ascii(os)) - os << std::endl; - } - break; - } - case 2: - { - for(Facet_iterator it = tr.facets_begin(), end = tr.facets_end(); it != end; ++it) - { - os << *((*it).first); // other information - if(IO::is_ascii(os)) - os << std::endl; - } - break; - } - case 1: - { - for(Edge_iterator it = tr.edges_begin(), end = tr.edges_end(); it != end; ++it) - { - os << *((*it).first); // other information - if(IO::is_ascii(os)) - os << std::endl; - } - break; - } - } - return os ; + if (!CGAL::IO::export_triangulation_3(os, tr)) + os.setstate(std::ios_base::failbit); + return os; } template < class GT, class Tds, class Lds >