// Copyright (c) 2020 GeometryFactory // // 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é // Maxime Gimeno #ifndef CGAL_IO_GOCAD_H #define CGAL_IO_GOCAD_H #include #include #include #include #include #include #include #include #include #include #include #include namespace CGAL { //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// /// Read template bool read_GOCAD(std::istream& is, std::pair& name_and_color, PointRange& points, PolygonRange& polygons, const CGAL_BGL_NP_CLASS&, bool verbose = true) { if(!is) { if(verbose) std::cerr<<"File doesn't exist."<::type Point; typedef typename boost::range_value::type Poly; set_ascii_mode(is); // GOCAD is ASCII only int offset = 0; std::string s; Point p; bool vertices_read = false, end_read = false; std::string line; std::size_t nb_gocad=1, //don't read the first one, it is optional anyway. nb_end=0; while(std::getline(is, line)) { if(line.empty()) continue; std::istringstream iss(line); if(!(iss >> s)) continue; // can't read anything on the line, whitespace only? if(s == "TFACE") { break; } std::string::size_type idx; if((idx = s.find("name")) != std::string::npos) { std::size_t pos = s.find(":")+1; name_and_color.first = s.substr(pos, s.length()); } if((idx = s.find("color")) != std::string::npos) { std::size_t pos = s.find(":")+1; name_and_color.second = s.substr(pos, s.length()); } } while(std::getline(is, line)) { if(line.empty()) continue; std::istringstream iss(line); if(line.find("GOCAD ") != std::string::npos) //the whitespace matters, it is used to define a gocad type, but not in the coord system keyword, for example. nb_gocad++; if((line.find("VRTX") != std::string::npos)) { int i; if(!(iss >> s >> i >> p)) { if(verbose) std::cerr << "error while reading vertex." << std::endl; return false; } if(!vertices_read) { vertices_read = true; offset -= i; // Some files start with index 0 others with 1 } points.push_back(p); } else if(line[0] == 'T') { iss >> s; if(s != "TRGL") continue; int i,j,k; if(!(iss >> i >> j >> k)) { if(verbose) std::cerr << "error while reading triangle." << std::endl; return false; } Poly new_face(3); new_face[0] = offset + i; new_face[1] = offset + j; new_face[2] = offset + k; polygons.push_back(new_face); } else if(line == "END") { end_read=true; nb_end++; } } if(is.eof()) is.clear(std::ios::goodbit); return end_read && nb_gocad == nb_end && !is.bad(); } template bool read_GOCAD(std::istream& is, PointRange& points, PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np) { std::pair dummy; return read_GOCAD(is, dummy, points, polygons, np); } template bool read_GOCAD(const char* fname, PointRange& points, PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np) { std::ifstream in(fname); std::pair dummy; return read_GOCAD(in, dummy, points, polygons, np); } template bool read_GOCAD(const std::string& fname, PointRange& points, PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np) { return read_GOCAD(fname.c_str(), points, polygons, np); } /*! * \ingroup GocadIoFuncs * * reads the content of `is` into `points` and `polygons`, in the GOCAD format. * * \tparam PointRange a model of the concept `RandomAccessContainer` whose value type is the point type. * \tparam PolygonRange a model of the concept `SequenceContainer` * whose value_type is itself a model of the concept `SequenceContainer` * whose value_type is an integer type. * * \param is the input stream * \param points points of the soup of polygons. * \param polygons a `PolygonRange`. Each element in it describes a polygon * using the indices of the points in `points`. * * \returns `true` if the reading was successful, `false` otherwise. * \see \ref IOStreamGocad */ template bool read_GOCAD(std::istream& is, PointRange& points, PolygonRange& polygons) { std::pair dummy; return read_GOCAD(is, dummy, points, polygons, parameters::all_default()); } /*! * \ingroup GocadIoFuncs * * reads the content of the file `fname` into `points` and `polygons`, in the GOCAD format. * * \tparam PointRange a model of the concept `RandomAccessContainer` whose value type is the point type. * \tparam PolygonRange a model of the concept `SequenceContainer` * whose value_type is itself a model of the concept `SequenceContainer` * whose value_type is an integer type. * * \param fname the path to the input file * \param points points of the soup of polygons. * \param polygons a `PolygonRange`. Each element in it describes a polygon * using the indices of the points in `points`. * * \returns `true` if the reading was successful, `false` otherwise. * \see \ref IOStreamGocad */ template bool read_GOCAD(const char* fname, PointRange& points, PolygonRange& polygons) { return read_GOCAD(fname, points, polygons, parameters::all_default()); } template bool read_GOCAD(const std::string& fname, PointRange& points, PolygonRange& polygons) { return read_GOCAD(fname, points, polygons, parameters::all_default()); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// /// Write namespace IO { namespace internal { template bool write_GOCAD(std::ostream& os, const char* fname, const PointRange& points, const PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np) { typedef typename boost::range_value::type Poly; using parameters::choose_parameter; using parameters::get_parameter; typedef typename CGAL::GetPointMap::type PointMap; PointMap point_map = choose_parameter(get_parameter(np, internal_np::point_map)); set_ascii_mode(os); // GOCAD is ASCII only if(!os.good()) return false; os << "GOCAD TSurf 1\n" "HEADER {\n" "name:"; os << fname << std::endl; os << "*border:on\n" "*border*bstone:on\n" "}\n" "GOCAD_ORIGINAL_COORDINATE_SYSTEM\n" "NAME Default\n" "AXIS_NAME \"X\" \"Y\" \"Z\"\n" "AXIS_UNIT \"m\" \"m\" \"m\"\n" "ZPOSITIVE Elevation\n" "END_ORIGINAL_COORDINATE_SYSTEM\n" "TFACE\n"; for(std::size_t i=0, end=points.size(); i bool write_GOCAD(std::ostream& os, const PointRange& points, const PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np) { return IO::internal::write_GOCAD(os, "anonymous", points, polygons, np); } template bool write_GOCAD(const char* fname, const PointRange& points, const PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np) { std::ofstream os(fname); return IO::internal::write_GOCAD(os, fname, points, polygons, np); } /*! \ingroup GocadIoFuncs * writes the content of `points` and `polygons` in `os`, in the TS format. * * \tparam PointRange a model of the concept `RandomAccessContainer` whose value type is the point type. * \tparam PolygonRange a model of the concept `SequenceContainer` * whose value_type is itself a model of the concept `SequenceContainer` * whose value_type is an integer type. * * \param os the output stream * \param points points of the soup of polygons. * \param polygons a `PolygonRange`. Each element in it describes a polygon * using the indices of the points in `points`. * * \return `true` if the writing was successful, `false` otherwise. * \see \ref IOStreamGocad */ template bool write_GOCAD(std::ostream& os, const PointRange& points, const PolygonRange& polygons) { return IO::internal::write_GOCAD(os, "anonymous", points, polygons, parameters::all_default()); } /*! \ingroup GocadIoFuncs * writes the content of `points` and `polygons` in `fname`, in the TS format. * * \tparam PointRange a model of the concept `RandomAccessContainer` whose value type is the point type. * \tparam PolygonRange a model of the concept `SequenceContainer` * whose value_type is itself a model of the concept `SequenceContainer` * whose value_type is an integer type. * * \param fname the path to the output file * \param points points of the soup of polygons. * \param polygons a `PolygonRange`. Each element in it describes a polygon * using the indices of the points in `points`. * * \return `true` if the writing was successful, `false` otherwise. * \see \ref IOStreamGocad */ template bool write_GOCAD(const char* fname, const PointRange& points, const PolygonRange& polygons) { return write_GOCAD(fname, points, polygons, parameters::all_default()); } template bool write_GOCAD(const std::string& fname, const PointRange& points, const PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np) { std::ofstream os(fname.c_str()); return IO::internal::write_GOCAD(os, fname.c_str(), points, polygons, np); } template bool write_GOCAD(const std::string& fname, const PointRange& points, const PolygonRange& polygons) { return write_GOCAD(fname, points, polygons, parameters::all_default()); } } // namespace CGAL #endif // CGAL_IO_GOCAD_H