/* This file is part of the Gudhi Library. The Gudhi library
* (Geometric Understanding in Higher Dimensions) is a generic C++
* library for computational topology.
*
* Author(s): David Salinas
*
* Copyright (C) 2014 Inria
*
* This program is free software: 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef OFF_READER_H_
#define OFF_READER_H_
#include
#include
#include
#include
#include
#include
namespace Gudhi {
/** \brief OFF file reader top class visitor.
*
* OFF file must be conform to format described here :
* http://www.geomview.org/docs/html/OFF.html
*/
class Off_reader {
public:
Off_reader(std::ifstream& stream) : stream_(stream) { }
~Off_reader() {
stream_.close();
}
/** \brief
* Read an OFF file and calls the following methods :
*
* void init(int dim,int num_vertices,int num_faces,int num_edges); // from file header - num_edges may not be set
*
* void point(const std::vector& point); // for each point read
*
* void maximal_face(const std::list& face); // for each face read
*
* void done(); // upon file read is finished
*
* of the visitor when reading a point or a maximal face. Edges are not taken into account.
*/
template
bool read(OffVisitor& off_visitor) {
bool success_read_off_preambule = read_off_preambule(off_visitor);
if (!success_read_off_preambule) {
std::cerr << "could not read off preambule\n";
return false;
}
bool success_read_off_points = read_off_points(off_visitor);
if (!success_read_off_points) {
std::cerr << "could not read off points\n";
return false;
}
bool success_read_off_faces = read_off_faces(off_visitor);
if (!success_read_off_faces) {
std::cerr << "could not read off faces\n";
return false;
}
off_visitor.done();
return success_read_off_preambule && success_read_off_points && success_read_off_faces;
}
private:
std::ifstream& stream_;
struct Off_info {
int dim;
int num_vertices;
int num_edges;
int num_faces;
};
Off_info off_info_;
template
bool read_off_preambule(OffVisitor& off_visitor) {
std::string line;
if (!goto_next_uncomment_line(line)) return false;
bool is_off_file = (line.find("OFF") != std::string::npos);
bool is_noff_file = (line.find("nOFF") != std::string::npos);
if (!is_off_file && !is_noff_file) {
std::cerr << line << std::endl;
std::cerr << "missing off header\n";
return false;
}
if (is_noff_file) {
// Should be on a separate line, but we accept it on the same line as the number of vertices
stream_ >> off_info_.dim;
} else {
off_info_.dim = 3;
}
if (!goto_next_uncomment_line(line)) return false;
std::istringstream iss(line);
if (!(iss >> off_info_.num_vertices >> off_info_.num_faces >> off_info_.num_edges)) {
std::cerr << "incorrect number of vertices/faces/edges\n";
return false;
}
off_visitor.init(off_info_.dim, off_info_.num_vertices, off_info_.num_faces, off_info_.num_edges);
return true;
}
bool goto_next_uncomment_line(std::string& uncomment_line) {
do {
// skip whitespace, including empty lines
if (!std::ifstream::sentry(stream_)) return false;
std::getline(stream_, uncomment_line);
} while (uncomment_line[0] == '#');
return static_cast(stream_);
}
template
bool read_off_points(OffVisitor& visitor) {
int num_vertices_to_read = off_info_.num_vertices;
while (num_vertices_to_read--) {
std::string line;
if (!goto_next_uncomment_line(line)) return false;
std::vector point;
std::istringstream iss(line);
point.assign(std::istream_iterator(iss), std::istream_iterator());
// if(point.size() != off_info_.dim) return false;
visitor.point(point);
}
return true;
}
template
bool read_off_faces(OffVisitor& visitor) {
std::string line;
while (goto_next_uncomment_line(line)) {
std::istringstream iss(line);
int num_face_vertices;
iss >> num_face_vertices;
std::vector face;
face.assign(std::istream_iterator(iss), std::istream_iterator());
// if (face.size() != (off_info_.dim + 1)) return false;
visitor.maximal_face(face);
}
return true;
}
};
template
void read_off(const std::string& name_file_off, OFFVisitor& vis) {
std::ifstream stream(name_file_off);
if (!stream.is_open()) {
std::cerr << "could not open file \n";
} else {
Off_reader off_reader(stream);
off_reader.read(vis);
}
}
} // namespace Gudhi
#endif // OFF_READER_H_