// Copyright (c) 2015-2020 GeometryFactory (France). All rights reserved. // // This file is part of CGAL (www.cgal.org) // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // Author(s) : Andreas Fabri // Mael Rouxel-Labbé #ifndef CGAL_BGL_IO_VTK_H #define CGAL_BGL_IO_VTK_H #include #include #include #include #include #include #include #include #ifdef CGAL_USE_VTK #include #include #include #include #endif #if defined(CGAL_USE_VTK) || defined(DOXYGEN_RUNNING) namespace CGAL { //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // Read namespace IO { namespace internal { template bool vtkPointSet_to_polygon_mesh(vtkPointSet* poly_data, Graph& g, const NameddParameters& np) { typedef typename CGAL::GetVertexPointMap::type VPM; typedef typename boost::property_traits::value_type Point; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; using parameters::get_parameter; using parameters::choose_parameter; VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), get_property_map(CGAL::vertex_point, g)); vtkIdType nb_points = poly_data->GetNumberOfPoints(); vtkIdType nb_cells = poly_data->GetNumberOfCells(); reserve(g, num_vertices(g) + static_cast::vertices_size_type>(nb_points), num_edges(g) + static_cast::edges_size_type>(nb_points + nb_cells), num_faces(g) + static_cast::faces_size_type>(nb_cells)); // extract points std::vector vertex_map(nb_points); for(vtkIdType i=0; iGetPoint(i, coords); vertex_descriptor v = add_vertex(g); put(vpm, v, Point(coords[0], coords[1], coords[2])); vertex_map[i] = v; } // extract cells for(vtkIdType i=0; iGetCellType(i); if(cell_type != 5 && cell_type != 7 && cell_type != 9) // only supported cells are triangles, quads and polygons continue; vtkCell* cell_ptr = poly_data->GetCell(i); vtkIdType nb_vertices = cell_ptr->GetNumberOfPoints(); if(nb_vertices < 3) return false; std::vector vr(nb_vertices); for(vtkIdType k=0; kGetPointId(k); vr[k] = vertex_map[id]; } face_descriptor f = CGAL::Euler::add_face(vr, g); if(f == boost::graph_traits::null_face()) return false; } return true; } } // namespace internal /*! * \ingroup PkgBGLIoFuncsVTP * * \brief reads a PolyData in the \ref IOStreamVTK into a triangulated surface mesh. * * The data is expected to represent a 2-manifold (possibly with borders). * * \attention The graph `g` is not cleared, and the data from the file are appended. * * \tparam Graph a model of `MutableFaceGraph` * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * * \param fname the path to the file that will be read * \param g the output mesh * \param np optional \ref bgl_namedparameters "Named Parameters" described below * * \cgalNamedParamsBegin * \cgalParamNBegin{vertex_point_map} * \cgalParamDescription{a property map associating points to the vertices of `g`} * \cgalParamType{a class model of `WritablePropertyMap` with `boost::graph_traits::%vertex_descriptor` * as key type and `%Point_3` as value type} * \cgalParamDefault{`boost::get(CGAL::vertex_point, g)`} * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` * must be available in `Graph`.} * \cgalParamNEnd * * \cgalNamedParamsEnd * * * \returns `true` if reading was successful, `false` otherwise. */ template bool read_VTP(const std::string& fname, Graph& g, const CGAL_NP_CLASS& np = parameters::default_values()) { std::ifstream test(fname); if(!test.good()) { std::cerr<<"File doesn't exist."< data; vtkSmartPointer obs = vtkSmartPointer::New(); data = vtkPolyData::SafeDownCast(internal::read_vtk_file(fname, obs)->GetOutput()); if (obs->GetError()) return false; return internal::vtkPointSet_to_polygon_mesh(data, g, np); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // Write namespace internal { // writes the polys appended data at the end of the .vtp file template void write_polys(std::ostream& os, const Graph& g, const NamedParameters& np) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename CGAL::GetInitializedVertexIndexMap::const_type Vimap; Vimap V = CGAL::get_initialized_vertex_index_map(g, np); std::vector connectivity_table; std::vector offsets; std::vector cell_type(faces(g).size(), 5); // triangle == 5 std::size_t off = 0; for(const face_descriptor f : faces(g)) { off += 3; offsets.push_back(off); for(const vertex_descriptor v : vertices_around_face(halfedge(f, g), g)) connectivity_table.push_back(get(V, v)); } write_vector(os, connectivity_table); write_vector(os, offsets); write_vector(os, cell_type); } //todo use named params for maps template void write_polys_tag(std::ostream& os, const Graph& g, bool binary, std::size_t& offset, const NamedParameters& np) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename CGAL::GetInitializedVertexIndexMap::const_type Vimap; Vimap V = CGAL::get_initialized_vertex_index_map(g, np); std::string formatattribute = binary ? " format=\"appended\"" : " format=\"ascii\""; std::string typeattribute; switch(sizeof(std::size_t)) { case 8: typeattribute = " type=\"UInt64\""; break; case 4: typeattribute = " type=\"UInt32\""; break; default: CGAL_error_msg("Unknown size of std::size_t"); } // Write connectivity table os << " \n" << " \n"; offset += (3 * faces(g).size() + 1) * sizeof(std::size_t); // 3 indices (size_t) per triangle + length of the encoded data (size_t) } else { os << ">\n"; for(face_descriptor f : faces(g)) { for(vertex_descriptor v : vertices_around_face(halfedge(f, g), g)) os << get(V, v) << " "; } os << " \n"; } // Write offsets os << " \n"; offset += (faces(g).size() + 1) * sizeof(std::size_t); // 1 offset (size_t) per triangle + length of the encoded data (size_t) } else { os << ">\n"; std::size_t polys_offset = 0; for(std::size_t i = 0; i< faces(g).size(); ++i) { polys_offset += 3; os << polys_offset << " "; } os << " \n"; } // Write cell type (triangle == 5) os << " \n"; offset += faces(g).size() + sizeof(std::size_t); // 1 unsigned char per cell + length of the encoded data (size_t) } else { os << ">\n"; for(std::size_t i=0; i\n"; } os << " \n"; } //todo : use namedparams for points and ids //overload for facegraph template void write_points_tag(std::ostream& os, const Graph& g, bool binary, std::size_t& offset, const NamedParameters& np) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename CGAL::GetVertexPointMap::const_type VPM; typedef typename boost::property_traits::value_type Point; typedef typename CGAL::Kernel_traits::Kernel Gt; typedef typename Gt::FT FT; using parameters::get_parameter; using parameters::choose_parameter; VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), get_const_property_map(CGAL::vertex_point, g)); std::string format = binary ? "appended" : "ascii"; std::string type = (sizeof(FT) == 8) ? "Float64" : "Float32"; os << " \n" << " \n"; offset += 3 * vertices(g).size() * sizeof(FT) + sizeof(std::size_t); // 3 coords per points + length of the encoded data (size_t) } else { os << "\">\n"; for(const vertex_descriptor v : vertices(g)) os << get(vpm, v).x() << " " << get(vpm, v).y() << " " << get(vpm, v).z() << " "; os << " \n"; } os << " \n"; } // writes the points appended data at the end of the .vtp file template void write_polys_points(std::ostream& os, const Graph& g, const NamedParameters& np) { typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename CGAL::GetVertexPointMap::const_type VPM; typedef typename boost::property_traits::value_type Point; typedef typename CGAL::Kernel_traits::Kernel Gt; typedef typename Gt::FT FT; using parameters::get_parameter; using parameters::choose_parameter; VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), get_const_property_map(CGAL::vertex_point, g)); std::vector coordinates; for(vertex_descriptor v : vertices(g)) { coordinates.push_back(get(vpm, v).x()); coordinates.push_back(get(vpm, v).y()); coordinates.push_back(get(vpm, v).z()); } write_vector(os, coordinates); } } // namespace internal /*! \ingroup PkgBGLIoFuncsVTP * * \brief writes a triangulated surface mesh in the `PolyData` XML format (\ref IOStreamVTK). * * \tparam Graph a model of `FaceListGraph` * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * * \param os the output stream * \param g the triangle mesh to be output * \param np optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd * * \cgalParamNBegin{vertex_point_map} * \cgalParamDescription{a property map associating points to the vertices of `g`} * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` * as key type and `%Point_3` as value type} * \cgalParamDefault{`boost::get(CGAL::vertex_point, g)`} * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` * must be available in `Graph`.} * \cgalParamNEnd * * \cgalParamNBegin{vertex_index_map} * \cgalParamDescription{a property map associating to each vertex of `graph` a unique index between `0` and `num_vertices(graph) - 1`} * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` * as key type and `std::size_t` as value type} * \cgalParamDefault{no vertex indices in the output} * \cgalParamNEnd * * \cgalParamNBegin{stream_precision} * \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} * \cgalParamType{int} * \cgalParamDefault{the precision of the stream `os`} * \cgalParamNEnd * \cgalNamedParamsEnd * * \pre `g` contains only triangular faces * * \returns `true` if writing was successful, `false` otherwise. */ template bool write_VTP(std::ostream& os, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values()) { using parameters::get_parameter; using parameters::choose_parameter; if(!os.good()) return false; set_stream_precision_from_NP(os, np); os << "\n" << "\n" << " " << "\n"; os << " \n"; std::size_t offset = 0; const bool binary = choose_parameter(get_parameter(np, internal_np::use_binary_mode), true); internal::write_points_tag(os, g, binary, offset, np); internal::write_polys_tag(os, g, binary, offset, np); os << " \n" << " \n"; if(binary) { os << "\n_"; internal::write_polys_points(os, g, np); internal::write_polys(os, g, np); } os << "" << std::endl; return os.good(); } /*! \ingroup PkgBGLIoFuncsVTP * * \brief writes a triangulated surface mesh the file `fname`, in the `PolyData` XML format (\ref IOStreamVTK). * * \tparam Graph a model of `FaceListGraph` * \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * * \param fname the name of the output file * \param g the triangle mesh to be output * \param np optional sequence of \ref bgl_namedparameters "Named Parameters" among the * ones listed below * * \cgalNamedParamsBegin * \cgalParamNBegin{use_binary_mode} * \cgalParamDescription{indicates whether data should be written in binary (`true`) or in \ascii (`false`)} * \cgalParamType{Boolean} * \cgalParamDefault{`true`} * \cgalParamNEnd * * \cgalParamNBegin{vertex_point_map} * \cgalParamDescription{a property map associating points to the vertices of `g`} * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` * as key type and `%Point_3` as value type} * \cgalParamDefault{`boost::get(CGAL::vertex_point, g)`} * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` * must be available in `Graph`.} * \cgalParamNEnd * * \cgalParamNBegin{vertex_index_map} * \cgalParamDescription{a property map associating to each vertex of `graph` a unique index between `0` and `num_vertices(graph) - 1`} * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` * as key type and `std::size_t` as value type} * \cgalParamDefault{no vertex indices in the output} * \cgalParamNEnd * * \cgalParamNBegin{stream_precision} * \cgalParamDescription{a parameter used to set the precision (i.e. how many digits are generated) of the output stream} * \cgalParamType{int} * \cgalParamDefault{`6`} * \cgalParamNEnd * \cgalNamedParamsEnd * * \pre `g` contains only triangular faces * * \returns `true` if writing was successful, `false` otherwise. */ template bool write_VTP(const std::string& fname, const Graph& g, const CGAL_NP_CLASS& np = parameters::default_values()) { const bool binary = CGAL::parameters::choose_parameter(CGAL::parameters::get_parameter(np, internal_np::use_binary_mode), true); std::ofstream os; if(binary){ os.open(fname, std::ios::binary); CGAL::IO::set_mode(os, CGAL::IO::BINARY); } else os.open(fname); return write_VTP(os, g, np); } } // namespace IO } // namespace CGAL #endif // defined(CGAL_USE_VTK) || defined(DOXYGEN_RUNNING) #endif // CGAL_BGL_IO_VTK_H