From e8e448bb9bc6a9c6391200a4d0ab7cdf9f7819ce Mon Sep 17 00:00:00 2001 From: Jean-Marie Favreau <J-Marie.Favreau@udamail.fr> Date: Mon, 11 Feb 2013 12:11:46 +0100 Subject: [PATCH] Implement the common tool to save PLY --- src/PlyLoader.cpp | 5 - src/PlyLoader.h | 18 --- src/core/Mesh.cpp | 170 +----------------------- src/core/PLY.cpp | 156 ++++++++++++++++++++++ src/core/PLY.h | 102 +++++++++++++++ src/parameterization/Mapping2D3D.cpp | 185 +-------------------------- src/parameterization/Mapping2D3D.h | 4 - src/utils/MeshMap.h | 15 +++ 8 files changed, 286 insertions(+), 369 deletions(-) delete mode 100644 src/PlyLoader.cpp delete mode 100644 src/PlyLoader.h create mode 100644 src/core/PLY.cpp create mode 100644 src/core/PLY.h diff --git a/src/PlyLoader.cpp b/src/PlyLoader.cpp deleted file mode 100644 index 6fd30f7..0000000 --- a/src/PlyLoader.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "PlyLoader.h" - -PLYLoader::PLYLoader() -{ -} diff --git a/src/PlyLoader.h b/src/PlyLoader.h deleted file mode 100644 index 8bbcdab..0000000 --- a/src/PlyLoader.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef PLYLOADER_H -#define PLYLOADER_H - -#include "FileManipulator.h" -#include "Mesh.h" -#include "Mapping2D3D.h" -#include "MeshMap.h" - -namespace Taglut { - -class PLYLoader : FileManipulator { -public: - PLYLoader(); -}; - -} - -#endif // PLYLOADER_H diff --git a/src/core/Mesh.cpp b/src/core/Mesh.cpp index ff3a368..8f2976c 100644 --- a/src/core/Mesh.cpp +++ b/src/core/Mesh.cpp @@ -40,6 +40,7 @@ #include "NLoop.h" #include "PointOnEdge.h" #include "PLPath.h" +#include "PLY.h" using namespace Taglut; @@ -2851,23 +2852,8 @@ void Mesh::loadASC(const std::string & fileName, const std::string & object) { } void Mesh::loadPLY(const std::string & fileName) { - points.clear(); - triangles.clear(); - - std::ifstream infile(fileName.c_str()); - - if (!infile.is_open()) - throw ExceptionFileNotFound(); - - if (!checkFormatPLY(infile)) - throw ExceptionUnknownFormat(); - - if (!loadPLY(infile)) - throw ExceptionErrorDuringReadingFile(); - - infile.close(); - - initIsBoundaryFlag(); + PLYLoader plyLoader(fileName); + plyLoader.loadMeshFromPLY(*this); } void Mesh::loadOFF(const std::string & fileName) { @@ -3561,127 +3547,6 @@ bool Mesh::loadOFF(std::ifstream & file) { return true; } -bool Mesh::checkFormatPLY(std::ifstream & file) { - std::string firstLine, secondLine; - getline(file, firstLine); - getline(file, secondLine); - return (((firstLine == "ply") || (firstLine == "ply\r")) && - ((secondLine == "format ascii 1.0") || (secondLine == "format ascii 1.0\r"))); -} - - -bool Mesh::loadPLY(std::ifstream & file) { - std::string buf; - VertexID nbPt = 0; - unsigned int nbProp = 0; - TriangleID nbPrimitives = 0; - - - /* find definition of vertices in the header */ - while(!file.eof()) { - file >> buf; - if (buf == "element") { - file >> buf; - if (buf != "vertex") - return false; - file >> nbPt; - break; - } - } - if (file.eof()) - return false; - if (nbPt < 3) - return false; - - /* compute number of properties for points */ - while(!file.eof()) { - file >> buf; - if (buf == "property") { // the point properties are not really checked, assuming that the 3 first properties are the coordinates - file >> buf; - if (buf == "list") - file >> buf; - file >> buf; - ++nbProp; - } - else - break; - } - if (file.eof()) - return false; - - if (buf != "end_header") { - while(buf != "element") { - file >> buf; - if (file.eof()) - return false; - } - file >> buf; - if (buf != "face") - return false; - /* read the definition of primitives in the header */ - file >> nbPrimitives; - - /* go to the end of the header */ - while(!file.eof()) { - file >> buf; - if (buf == "end_header") - break; - } - if (file.eof()) - return false; - } - // then read points - for(VertexID i = 0; i < nbPt; ++i) { - double x, y , z; - file >> x >> y >> z; - for (unsigned int s = 0; s < nbProp - 3; ++s) - file >> buf; // skip the other point's informations - points.push_back(Point3D(x, y, z, nbPoints++)); - } - - // and read faces - bool start1 = false; - for(TriangleID i = 0; i < nbPrimitives; ++i) { - VertexID nbP; - file >> nbP; - - if((nbP != 3) && (nbP != 4)) - return false; - - VertexID x, y, z; - file >> x >> y >> z; - if (nbP == 3) { - if ((x == nbPoints) || - (y == nbPoints) || - (z == nbPoints)) - start1 = true; - - addTriangle(Triangle(x, y, z)); - } - else { - unsigned int t; - file >> t; - if ((x == nbPoints) || - (y == nbPoints) || - (z == nbPoints) || - (t == nbPoints)) - start1 = true; - - addTriangle(Triangle(x, y, z)); - addTriangle(Triangle(x, z, t)); - - } - } - - if (start1) { - for(std::vector<Triangle>::iterator t = triangles.begin(); t != triangles.end(); ++t) - (*t).incIds(-1, 0); - } - - updateNeighboursAndTriangles(); - - return true; -} void Mesh::loadXYZ(const std::string & fileName) { Point3D point_l; @@ -3788,33 +3653,10 @@ void Mesh::saveAltFormat(const std::string & fileName, const std::string & forma throw Exception("Unknown format"); } -void Mesh::savePLY(const std::string & fileName, const std::string & objectName) const { - std::ofstream outfile(fileName.c_str(), std::ios::out); - - if (!outfile.is_open()) - throw ExceptionCannotOpenOutputFile(); - - outfile << "ply" << std::endl; - outfile << "format ascii 1.0" << std::endl; - outfile << "comment Generated by savePLY" << std::endl; - if (objectName != "") - outfile << "comment " << objectName << std::endl; - - outfile << "element vertex " << nbPoints << std::endl; - outfile << "property double x" << std::endl; - outfile << "property double y" << std::endl; - outfile << "property double z" << std::endl; - outfile << "element face " << nbTriangles << std::endl; - outfile << "property list uchar integer vertex_index" << std::endl; - outfile << "end_header" << std::endl; +void Mesh::savePLY(const std::string & fileName, const std::string &) const { + PLYSaver plysaver; - for(Mesh::const_point_iterator p = point_begin(); p != point_end(); ++p) - outfile << (*p).getX() << " " << (*p).getY() << " " << (*p).getZ() << std::endl; - - for(Mesh::const_triangle_iterator t = triangle_begin(); t != triangle_end(); ++t) - outfile << " 3 " << (*t).getP1() << " " << (*t).getP2() << " " << (*t).getP3() << std::endl; - - outfile.close(); + plysaver.savePLY(*this, fileName); } void Mesh::saveOFF(const std::string & fileName, const std::string & objectName) const { diff --git a/src/core/PLY.cpp b/src/core/PLY.cpp new file mode 100644 index 0000000..17ff4a3 --- /dev/null +++ b/src/core/PLY.cpp @@ -0,0 +1,156 @@ +#include "PLY.h" +#include "Mesh.h" +#include "Mapping2D3D.h" +#include "MeshMap.h" + +using namespace Taglut; + +void PLY::reset() { + properties.clear(); + vertices.clear(); + triangles.clear(); +} + +PLYLoader::PLYLoader() { + addFormats(); +} + +void PLYLoader::addFormats() { + addLoadFormat("ply"); +} + + +PLYLoader::PLYLoader(const std::string & filename, const std::string & objectName) { + addFormats(); + load(filename); +} + +void PLYLoader::loadAltFormat(const std::string & fileName, const std::string & altFormat, const std::string &) { + if (altFormat == "ply") + loadPLY(fileName); + else + throw Exception("Unknown format"); +} + +void PLYLoader::loadPLY(const std::string & fileName) { + // TODO +} + +void PLYLoader::loadMeshFromPLY(Mesh & mesh) const { + // TODO +} + +void PLYLoader::loadMapping2D3DFromPLY(Mapping2D3D & mapping) const { + // TODO +} + +void PLYLoader::loadMeshMapFromPLY(const MeshMap & mmap) const { + // TODO +} + +/** PLY saver */ + +PLYSaver::PLYSaver() { + +} + +void PLYSaver::addFormats() { + addSaveFormat("ply"); +} + +void PLYSaver::initDataFromMesh(const Mesh & mesh) { + triangles.clear(); + vertices.clear(); + + vertices.insert(vertices.begin(), mesh.getPoints().begin(), mesh.getPoints().end()); + triangles.insert(triangles.begin(), mesh.getTriangles().begin(), mesh.getTriangles().end()); +} + +void PLYSaver::initDataFromMapping(const Mapping2D3D & mapping) { + properties["s"] = std::list<double>(); + properties["t"] = std::list<double>(); + for(Mapping2D3D::const_iterator p = mapping.begin(); p != mapping.end(); ++p) { + properties["s"].push_back((*p).get2DX()); + properties["t"].push_back((*p).get2DY()); + } +} + +void PLYSaver::initDataFromMap(const MeshMap & mmap) { + properties["intensity"] = std::list<double>(); + for(VertexID id = 0; id != mmap.getNbValues(); ++id) + properties["intensity"].push_back(mmap.getValue(id)); +} + +void PLYSaver::savePLY(const std::string & fileName) const { + if (vertices.empty()) + return; + std::ofstream outfile(fileName.c_str(), std::ios::out); + + if (!outfile.is_open()) + throw ExceptionCannotOpenOutputFile(); + outfile << "ply" << std::endl; + outfile << "format ascii 1.0" << std::endl; + outfile << "comment Generated by PLYSaver" << std::endl; + + outfile << "element vertex " << vertices.size() << std::endl; + outfile << "property float x" << std::endl; + outfile << "property float y" << std::endl; + outfile << "property float z" << std::endl; + std::list<std::list<double>::const_iterator> itProps; + for(std::map<std::string, std::list<double> >::const_iterator p = properties.begin(); p != properties.end(); ++p) { + outfile << "property double " << (*p).first << std::endl; + assert((*p).second.size() == vertices.size()); + itProps.push_back((*p).second.begin()); + } + + outfile << "element face " << triangles.size() << std::endl; + outfile << "property list uchar int vertex_indices" << std::endl; + outfile << "end_header" << std::endl; + + for(std::list<Point3D>::const_iterator p = vertices.begin(); p != vertices.end(); ++p) { + outfile << (*p).getX() << " " << (*p).getY() << " " << (*p).getZ(); + for(std::list<std::list<double>::const_iterator>::iterator pr = itProps.begin(); pr != itProps.end(); ++pr) { + outfile << " " << **pr; + ++(*pr); + } + outfile << std::endl; + } + + for(std::list<Triangle>::const_iterator t = triangles.begin(); t != triangles.end(); ++t) + outfile << " 3 " << (*t).getP1() << " " << (*t).getP2() << " " << (*t).getP3() << std::endl; + + outfile.close(); +} + +void PLYSaver::saveAltFormat(const std::string & fileName, const std::string &, + const std::string &) const { + savePLY(fileName); +} + +void PLYSaver::savePLY(const Mesh & mesh, const std::string & fileName) { + initDataFromMesh(mesh); + savePLY(fileName); +} + +void PLYSaver::savePLY(const MeshMap & mmap, const std::string & fileName) { + reset(); + initDataFromMesh(mmap.getMesh()); + initDataFromMap(mmap); + savePLY(fileName); +} + +void PLYSaver::savePLY(const Mapping2D3D & mapping, const std::string & fileName) { + reset(); + initDataFromMapping(mapping); + initDataFromMesh(mapping.getMesh()); + savePLY(fileName); +} + +void PLYSaver::savePLY(const Mapping2D3D & mapping, const MeshMap & mmap, const std::string & fileName) { + reset(); + initDataFromMapping(mapping); + initDataFromMesh(mmap.getMesh()); + initDataFromMap(mmap); + savePLY(fileName); +} + diff --git a/src/core/PLY.h b/src/core/PLY.h new file mode 100644 index 0000000..a55b991 --- /dev/null +++ b/src/core/PLY.h @@ -0,0 +1,102 @@ +#include "MeshMap.h" + +#ifndef PLYLOADER_H +#define PLYLOADER_H + +#include "FileManipulator.h" + +#include <string> +#include <map> +#include <list> + +#include "Point3D.h" + +namespace Taglut { +class Mesh; +class Mapping2D3D; +class Triangle; + +class PLY { +protected: + std::map<std::string, std::list<double> > properties; + std::list<Point3D> vertices; + std::list<Triangle> triangles; + void reset(); +}; + +class PLYLoader : public FileManipulator, public PLY { +private: + bool loadPLY(std::ifstream & file); + + void addFormats(); +public: + PLYLoader(); + PLYLoader(const std::string & filename, const std::string & objectName = ""); + + /** no save function */ + virtual void saveAltFormat(const std::string &, const std::string & = "", + const std::string & = "") const { + } + + virtual void loadAltFormat(const std::string & fileName, const std::string & altFormat = "", const std::string & object = ""); + + /** + Load Mesh from file (PLY format) + */ + void loadPLY(const std::string & fileName); + + /** given a mesh, it modifies it according to the data of the PLY file */ + void loadMeshFromPLY(Mesh & mesh) const; + + /** given a mapping2D3D, it modifies it according to the data of the PLY file */ + void loadMapping2D3DFromPLY(Mapping2D3D & mapping) const; + + /** given a mesh map, it modifies it according to the data of the PLY file */ + void loadMeshMapFromPLY(const MeshMap & mmap) const; + +}; + +class PLYSaver : public FileManipulator, public PLY { +private: + void initDataFromMesh(const Mesh & mesh); + void initDataFromMapping(const Mapping2D3D & mapping); + void initDataFromMap(const MeshMap & mmap); + void savePLY(const std::string & fileName) const; + void addFormats(); +public: + PLYSaver(); + + /** no load function */ + virtual void loadAltFormat(const std::string &, const std::string & = "", const std::string & = "") { + } + + /** + Save Mesh to file + */ + virtual void saveAltFormat(const std::string & fileName, const std::string & format = "", + const std::string & objectName = "") const; + /** + Save Mesh to file (PLY format) + */ + void savePLY(const Mesh & mesh, const std::string & fileName); + + /** + Save Mesh and meshmap to file (PLY format) + */ + void savePLY(const MeshMap & mmap, const std::string & fileName); + + /** + Save Mesh and Mapping2D3D to file (PLY format) + */ + void savePLY(const Mapping2D3D & mapping, const std::string & fileName); + + /** + Save Mesh, Mapping2D3D and meshmap to file (PLY format) + */ + void savePLY(const Mapping2D3D & mapping, const MeshMap & mmap, const std::string & fileName); + +}; + +} + +#endif // PLYLOADER_H diff --git a/src/parameterization/Mapping2D3D.cpp b/src/parameterization/Mapping2D3D.cpp index 3d3823f..49b71ea 100644 --- a/src/parameterization/Mapping2D3D.cpp +++ b/src/parameterization/Mapping2D3D.cpp @@ -34,6 +34,7 @@ #include "PlaneSpliter.h" #include "StringManipulation.h" #include "PointOnEdge.h" +#include "PLY.h" #ifdef USE_LIBXML #include <libxml/xmlreader.h> @@ -233,164 +234,12 @@ void Mapping2D3D::loadAltFormat(const std::string & fileName, const std::string throw Exception("Unknow format"); } -bool Mapping2D3D::loadPLY(std::ifstream & file) { - std::string buf; - VertexID nbPt = 0; - unsigned int nbProp = 0; - TriangleID nbPrimitives = 0; - VertexID nbPoints = 0; - std::deque<Point3D> pts3d; - std::deque<Triangle> triangles; - - (*mesh).clear(); - clear(); - - /* find definition of vertices in the header */ - while(!file.eof()) { - file >> buf; - if (buf == "element") { - file >> buf; - if (buf != "vertex") - return false; - file >> nbPt; - break; - } - } - if (file.eof()) - return false; - if (nbPt < 3) - return false; - - /* compute number of properties for points */ - while(!file.eof()) { - file >> buf; - if (buf == "property") { // the point properties are not really checked, assuming that the 3 first properties are the coordinates - file >> buf; - if (buf == "list") - file >> buf; - file >> buf; - ++nbProp; - } - else if (buf != "element") - return false; - else - break; - } - if (file.eof()) - return false; - - /* read the definition of primitives in the header */ - file >> buf; - file >> nbPrimitives; - if (nbPrimitives == 0) - return false; - - /* go to the end of the header */ - while(!file.eof()) { - file >> buf; - if (buf == "end_header") - break; - } - if (file.eof()) - return false; - - // then read points - for(VertexID i = 0; i < nbPt; ++i) { - double x, y, z; - file >> x >> y >> z; - unsigned int nbRead = 3; - if (nbProp >= 5) { - Point2D p2D; - double x2, y2; - file >> x2 >> y2; - nbRead += 2; - - // set point - p2D.set2DX(x2); - p2D.set2DY(y2); - p2D.setId(size()); - update2DExtrema(p2D); - - // add point to the mapping - push_back(p2D); - } - for (unsigned int s = 0; s < nbProp - nbRead; ++s) - file >> buf; // skip the other point's informations - pts3d.push_back(Point3D(x, y, z, nbPoints++)); - } - - // and read faces - bool start1 = false; - for(TriangleID i = 0; i < nbPrimitives; ++i) { - VertexID nbP; - file >> nbP; - - if((nbP != 3) && (nbP != 4)) - return false; - - VertexID x, y, z; - - file >> x >> y >> z; - if (nbP == 3) { - if ((x == nbPoints) || - (y == nbPoints) || - (z == nbPoints)) - start1 = true; - - triangles.push_back(Triangle(x, y, z, triangles.size())); - } - else { - unsigned int t; - file >> t; - if ((x == nbPoints) || - (y == nbPoints) || - (z == nbPoints) || - (t == nbPoints)) - start1 = true; - - triangles.push_back(Triangle(x, y, z, triangles.size())); - triangles.push_back(Triangle(x, z, t, triangles.size())); - - } - } - - if (start1) { - std::cout << "-1" << std::endl; - for(std::deque<Triangle>::iterator t = triangles.begin(); t != triangles.end(); ++t) - (*t).incIds(-1, 0); - } - - (*mesh).setPointsAndbuildMesh(pts3d, triangles); - - - if (size() == (*mesh).getNbPoints()) - flatten = true; - else { - if(size() == 0) - std::cout << "Warning: no UV data available" << std::endl; - else { - std::cout << "Warning: UV data not fully available, cleaning." << std::endl; - clear(); - } - reinit(); - } - return true; -} - void Mapping2D3D::loadPLY(const std::string & fileName) { - std::ifstream infile(fileName.c_str()); - - if (!infile.is_open()) - throw ExceptionFileNotFound(); - - if (!checkFormatPLY(infile)) - throw ExceptionUnknownFormat(); - - if (!loadPLY(infile)) - throw ExceptionErrorDuringReadingFile(); - - infile.close(); + PLYLoader plyLoader(fileName); + plyLoader.loadMapping2D3DFromPLY(*this); + if (mesh != NULL) + plyLoader.loadMeshFromPLY(*mesh); } bool Mapping2D3D::checkFormatPLY(std::ifstream & file) { @@ -585,29 +434,9 @@ void Mapping2D3D::saveAltFormat(const std::string & fileName, const std::string outFile << "f " << ((*t).getP1() + 1) << "/" << ((*t).getP1() + 1) << " " << ((*t).getP2() + 1) << "/" << ((*t).getP2() + 1) << " " << ((*t).getP3() + 1) << "/" << ((*t).getP3() + 1) << std::endl; } else if (format == "ply") { - outFile << "ply" << std::endl; - outFile << "format ascii 1.0" << std::endl; - outFile << "comment Generated by savePLY" << std::endl; - if (objectName != "") - outFile << "comment " << objectName << std::endl; - - outFile << "element vertex " << (*mesh).getNbPoints() << std::endl; - outFile << "property double x" << std::endl; - outFile << "property double y" << std::endl; - outFile << "property double z" << std::endl; - outFile << "property double s" << std::endl; - outFile << "property double t" << std::endl; - outFile << "element face " << (*mesh).getNbTriangles() << std::endl; - outFile << "property list uchar integer vertex_index" << std::endl; - outFile << "end_header" << std::endl; - - Mapping2D3D::const_iterator pm = begin(); - for(Mesh::const_point_iterator p = (*mesh).point_begin(); p != (*mesh).point_end(); ++p, ++pm) - outFile << (*p).getX() << " " << (*p).getY() << " " << (*p).getZ() << " " << (*pm).get2DX() << " " << (*pm).get2DY() << std::endl; - - for(Mesh::const_triangle_iterator t = (*mesh).triangle_begin(); t != (*mesh).triangle_end(); ++t) - outFile << " 3 " << (*t).getP1() << " " << (*t).getP2() << " " << (*t).getP3() << std::endl; + PLYSaver plysaver; + plysaver.savePLY(*this, fileName); } else if ((format == "xml") || (format == "map")) outFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl << toStringXML(); diff --git a/src/parameterization/Mapping2D3D.h b/src/parameterization/Mapping2D3D.h index 169b4a0..c146cd4 100644 --- a/src/parameterization/Mapping2D3D.h +++ b/src/parameterization/Mapping2D3D.h @@ -124,10 +124,6 @@ namespace Taglut { */ bool loadOBJ(std::ifstream & file); - /** - Load the mapping from a ply file - */ - bool loadPLY(std::ifstream & file); /** Check the ply format, reading the header diff --git a/src/utils/MeshMap.h b/src/utils/MeshMap.h index ad2af01..556d009 100644 --- a/src/utils/MeshMap.h +++ b/src/utils/MeshMap.h @@ -26,6 +26,7 @@ #include "FileManipulator.h" #include "IDTranslator.h" + namespace Taglut { class Mesh; class MeshManipulator; @@ -517,6 +518,7 @@ namespace Taglut { #include "FileExceptions.h" #include "PointOnEdge.h" #include "PLPath.h" +#include "PLY.h" namespace Taglut { @@ -1808,6 +1810,19 @@ namespace Taglut { } } + template <typename T> + void MeshMapT<T>::savePLY(const std::string & fileName) const { + PLYSaver plysaver; + plysaver.savePLY(*this, fileName); + } + + template <typename T> + void MeshMapT<T>::loadPLY(const std::string & fileName) { + PLYLoader plyLoader(fileName); + plyLoader.loadMapping2D3DFromPLY(*this); + if (mesh != NULL) + plyLoader.loadMeshFromPLY(*mesh); + } } -- GitLab