/**************************************************************************** * NanoPLY * * NanoPLY is a C++11 header-only library to read and write PLY file * * * * Copyright(C) 2014-2015 * * Visual Computing Lab * * ISTI - Italian National Research Council * * * * This Source Code Form is subject to the terms of the Mozilla Public * * License, v. 2.0. If a copy of the MPL was not distributed with this * * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * * ****************************************************************************/ #include #include template struct Container { public: T data[N]; Container(){} Container(T* temp, int n) { for (int i = 0; i < std::min(n, N); i++) data[i] = temp[i]; } T* V() { return data; } bool operator == (Container const & m) const { bool flag = true; for (int i = 0; i < N; i++) flag = flag && (data[i] == m.data[i]); return flag; } }; typedef Container Point3f; typedef Container Color4f; typedef Container VertexIndex; struct MyVertexInfo { Color4f c; float density; int materialId; bool operator == (MyVertexInfo const & m) const { return (c == m.c && m.density == density && m.materialId == materialId); } }; struct MyMaterialInfo { Point3f kd; Point3f ks; float rho; bool operator == (MyMaterialInfo const & m) const { return (kd == m.kd && ks == m.ks && rho == m.rho); } }; class MyMesh { public: std::vector coordVec; std::vector normalVec; std::vector infoVec; std::vector faceIndex; std::vector material; void FillMesh() { float pos[] = { 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0 }; int index[] = { 0, 1, 2, 0, 2, 3, 0, 3, 1, 3, 2, 1 }; float norm[] = { 0.57735, 0.57735, 0.57735, -0.57735, 0.57735, -0.57735, -0.57735, -0.57735, 0.57735, 0.57735, -0.57735, -0.57735 }; unsigned char color[] = { 68, 68, 68, 255, 177, 68, 177, 255, 177, 177, 68, 255, 68, 177, 177 }; float density[] = { 3.5, 2.0, 4.0, 3.0 }; float materialId[] = { 1, 0, -1, 1 }; float materialValue[] = { 0.2, 0.3, 0.2, 0.5, 0.5, 0.6, 20.0, 0.1, 0.1, 0.1, 0.7, 0.5, 0.4, 1.0 }; coordVec.push_back(Point3f(pos, 3)); coordVec.push_back(Point3f(&pos[3], 3)); coordVec.push_back(Point3f(&pos[6], 3)); coordVec.push_back(Point3f(&pos[9], 3)); normalVec.push_back(Point3f(norm, 3)); normalVec.push_back(Point3f(&norm[3], 3)); normalVec.push_back(Point3f(&norm[6], 3)); normalVec.push_back(Point3f(&norm[9], 3)); MyVertexInfo info1 = { Color4f(color, 4), density[0], materialId[0] }; infoVec.push_back(info1); MyVertexInfo info2 = { Color4f(&color[4], 4), density[1], materialId[1] }; infoVec.push_back(info2); MyVertexInfo info3 = { Color4f(&color[8], 4), density[2], materialId[2] }; infoVec.push_back(info3); MyVertexInfo info4 = { Color4f(&color[12], 4), density[3], materialId[3] }; infoVec.push_back(info4); faceIndex.push_back(VertexIndex(index, 3)); faceIndex.push_back(VertexIndex(&index[3], 3)); faceIndex.push_back(VertexIndex(&index[6], 3)); faceIndex.push_back(VertexIndex(&index[9], 3)); MyMaterialInfo mat1 = { Point3f(materialValue, 3), Point3f(&materialValue[3], 3), materialValue[6] }; material.push_back(mat1); MyMaterialInfo mat2 = { Point3f(&materialValue[7], 3), Point3f(&materialValue[10], 3), materialValue[13] }; material.push_back(mat2); } bool operator == (MyMesh& m) { bool flag = (coordVec == m.coordVec); flag = flag && (normalVec == m.normalVec); flag = flag && (infoVec == m.infoVec); flag = flag && (faceIndex == m.faceIndex); flag = flag && (material == m.material); return flag; } }; bool Load(const char* filename, MyMesh& mesh) { //Get file info nanoply::Info info(filename); if (info.errInfo != nanoply::NNP_OK) { std::cout << "Invalid file format" << std::endl; return false; } //Resize the element containers int vertCnt = info.GetVertexCount(); if (vertCnt <= 0) { std::cout << "The file does't contain any vertex." << std::endl; return false; } mesh.coordVec.resize(vertCnt); mesh.normalVec.resize(vertCnt); mesh.infoVec.resize(vertCnt); int faceCnt = info.GetFaceCount(); mesh.faceIndex.resize(faceCnt); int materialCnt = info.GetElementCount(std::string("material")); mesh.material.resize(2); //Create the vertex properties descriptor (what ply property and where to save its data) nanoply::ElementDescriptor vertex(nanoply::NNP_VERTEX_ELEM); if (vertCnt > 0) { vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_PXYZ, (*mesh.coordVec.begin()).V())); vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_NXYZ, (*mesh.normalVec.begin()).V())); vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_CRGBA, (*mesh.infoVec.begin()).c.V())); vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_DENSITY, &(*mesh.infoVec.begin()).density)); vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(std::string("materialId"), &(*mesh.infoVec.begin()).materialId)); } //Create the face properties descriptor (what ply property and where the data is stored) nanoply::ElementDescriptor face(nanoply::NNP_FACE_ELEM); if (mesh.faceIndex.size() > 0) face.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_FACE_VERTEX_LIST, (*mesh.faceIndex.begin()).V())); //Create the material properties descriptor (what ply property and where the data is stored) nanoply::ElementDescriptor material(std::string("material")); if (mesh.material.size() > 0) { material.dataDescriptor.push_back(new nanoply::DataDescriptor(std::string("kd"), (*mesh.material.begin()).kd.V())); material.dataDescriptor.push_back(new nanoply::DataDescriptor(std::string("ks"), (*mesh.material.begin()).ks.V())); material.dataDescriptor.push_back(new nanoply::DataDescriptor(std::string("rho"), &(*mesh.material.begin()).rho)); } //Create the mesh descriptor std::vector meshDescr; meshDescr.push_back(&vertex); meshDescr.push_back(&face); meshDescr.push_back(&material); //Open the file and save the element data according the relative element descriptor OpenModel(info, meshDescr); for (int i = 0; i < vertex.dataDescriptor.size(); i++) delete vertex.dataDescriptor[i]; for (int i = 0; i < face.dataDescriptor.size(); i++) delete face.dataDescriptor[i]; for (int i = 0; i < material.dataDescriptor.size(); i++) delete material.dataDescriptor[i]; return (info.errInfo == nanoply::NNP_OK); } bool Save(const char* filename, MyMesh& mesh, bool binary) { //Create the vector of vertex properties to save in the file std::vector vertexProp; vertexProp.push_back(nanoply::PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_PXYZ)); vertexProp.push_back(nanoply::PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_NXYZ)); vertexProp.push_back(nanoply::PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_DENSITY)); vertexProp.push_back(nanoply::PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_CRGBA)); vertexProp.push_back(nanoply::PlyProperty(nanoply::NNP_INT32, "materialId")); //Create the vector of face properties to save in the file std::vector faceProp; faceProp.push_back(nanoply::PlyProperty(nanoply::NNP_LIST_UINT8_UINT32, nanoply::NNP_FACE_VERTEX_LIST)); //Create the vector of material properties to save in the file std::vector materialProp; materialProp.push_back(nanoply::PlyProperty(nanoply::NNP_LIST_UINT8_FLOAT32, "kd")); materialProp.push_back(nanoply::PlyProperty(nanoply::NNP_LIST_UINT8_FLOAT32, "ks")); materialProp.push_back(nanoply::PlyProperty(nanoply::NNP_FLOAT32, "rho")); //Create the PlyElement nanoply::PlyElement vertexElem(nanoply::NNP_VERTEX_ELEM, vertexProp, mesh.coordVec.size()); nanoply::PlyElement faceElem(nanoply::NNP_FACE_ELEM, faceProp, mesh.faceIndex.size()); nanoply::PlyElement materialElem(std::string("material"), materialProp, mesh.material.size()); //Create the Info object with the data to save in the header nanoply::Info infoSave; infoSave.filename = filename; infoSave.binary = binary; infoSave.AddPlyElement(vertexElem); infoSave.AddPlyElement(faceElem); infoSave.AddPlyElement(materialElem); //Create the vertex properties descriptor (what ply property and where the data is stored) nanoply::ElementDescriptor vertex(nanoply::NNP_VERTEX_ELEM); if (mesh.coordVec.size() > 0) { vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_PXYZ, (*mesh.coordVec.begin()).V())); vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_NXYZ, (*mesh.normalVec.begin()).V())); vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_CRGBA, (*mesh.infoVec.begin()).c.V())); vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_DENSITY, &(*mesh.infoVec.begin()).density)); vertex.dataDescriptor.push_back(new nanoply::DataDescriptor(std::string("materialId"), &(*mesh.infoVec.begin()).materialId)); } //Create the face properties descriptor (what ply property and where the data is stored) nanoply::ElementDescriptor face(nanoply::NNP_FACE_ELEM); if (mesh.faceIndex.size() > 0) face.dataDescriptor.push_back(new nanoply::DataDescriptor(nanoply::NNP_FACE_VERTEX_LIST, (*mesh.faceIndex.begin()).V())); //Create the material properties descriptor (what ply property and where the data is stored) nanoply::ElementDescriptor material(std::string("material")); if (mesh.material.size() > 0) { material.dataDescriptor.push_back(new nanoply::DataDescriptor(std::string("kd"), (*mesh.material.begin()).kd.V())); material.dataDescriptor.push_back(new nanoply::DataDescriptor(std::string("ks"), (*mesh.material.begin()).ks.V())); material.dataDescriptor.push_back(new nanoply::DataDescriptor(std::string("rho"), &(*mesh.material.begin()).rho)); } //Create the mesh descriptor std::vector meshDescr; meshDescr.push_back(&vertex); meshDescr.push_back(&face); meshDescr.push_back(&material); //Save the file bool result = nanoply::SaveModel(infoSave.filename, meshDescr, infoSave); for (int i = 0; i < vertex.dataDescriptor.size(); i++) delete vertex.dataDescriptor[i]; for (int i = 0; i < face.dataDescriptor.size(); i++) delete face.dataDescriptor[i]; for (int i = 0; i < material.dataDescriptor.size(); i++) delete material.dataDescriptor[i]; return result; } int main() { MyMesh mesh1; mesh1.FillMesh(); Save("example_ascii.ply", mesh1, false); Save("example_binary.ply", mesh1, true); MyMesh mesh2, mesh3; Load("example_ascii.ply", mesh2); Load("example_binary.ply", mesh3); if (mesh2 == mesh1) std::cout << "Write and read ASCII ply file: SUCCESS\n"; else std::cout << "Write and read ASCII ply file: FAIL\n"; if (mesh3 == mesh1) std::cout << "Write and read binary ply file: SUCCESS\n"; else std::cout << "Write and read binary ply file: FAIL\n"; return true; }