You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
12 KiB
284 lines
12 KiB
/**************************************************************************** |
|
* 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 <iostream> |
|
#include <wrap/nanoply/include/nanoply.hpp> |
|
|
|
template<typename T, int N> |
|
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<T, N> const & m) const |
|
{ |
|
bool flag = true; |
|
for (int i = 0; i < N; i++) |
|
flag = flag && (data[i] == m.data[i]); |
|
return flag; |
|
} |
|
}; |
|
|
|
|
|
typedef Container<float, 3> Point3f; |
|
typedef Container<unsigned char, 4> Color4f; |
|
typedef Container<int, 3> 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<Point3f> coordVec; |
|
std::vector<Point3f> normalVec; |
|
std::vector<MyVertexInfo> infoVec; |
|
std::vector<VertexIndex> faceIndex; |
|
std::vector<MyMaterialInfo> 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 }; |
|
int 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); |
|
size_t 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<Point3f, 3, float>(nanoply::NNP_PXYZ, (*mesh.coordVec.begin()).V())); |
|
vertex.dataDescriptor.push_back(new nanoply::DataDescriptor<Point3f, 3, float>(nanoply::NNP_NXYZ, (*mesh.normalVec.begin()).V())); |
|
vertex.dataDescriptor.push_back(new nanoply::DataDescriptor<MyVertexInfo, 4, unsigned char>(nanoply::NNP_CRGBA, (*mesh.infoVec.begin()).c.V())); |
|
vertex.dataDescriptor.push_back(new nanoply::DataDescriptor<MyVertexInfo, 1, float>(nanoply::NNP_DENSITY, &(*mesh.infoVec.begin()).density)); |
|
vertex.dataDescriptor.push_back(new nanoply::DataDescriptor<MyVertexInfo, 1, int>(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<VertexIndex, 3, int>(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<MyMaterialInfo, 3, float>(std::string("kd"), (*mesh.material.begin()).kd.V())); |
|
material.dataDescriptor.push_back(new nanoply::DataDescriptor<MyMaterialInfo, 3, float>(std::string("ks"), (*mesh.material.begin()).ks.V())); |
|
material.dataDescriptor.push_back(new nanoply::DataDescriptor<MyMaterialInfo, 1, float>(std::string("rho"), &(*mesh.material.begin()).rho)); |
|
} |
|
|
|
//Create the mesh descriptor |
|
std::vector<nanoply::ElementDescriptor*> 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<nanoply::PlyProperty> 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<nanoply::PlyProperty> 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<nanoply::PlyProperty> 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<Point3f, 3, float>(nanoply::NNP_PXYZ, (*mesh.coordVec.begin()).V())); |
|
vertex.dataDescriptor.push_back(new nanoply::DataDescriptor<Point3f, 3, float>(nanoply::NNP_NXYZ, (*mesh.normalVec.begin()).V())); |
|
vertex.dataDescriptor.push_back(new nanoply::DataDescriptor<MyVertexInfo, 4, unsigned char>(nanoply::NNP_CRGBA, (*mesh.infoVec.begin()).c.V())); |
|
vertex.dataDescriptor.push_back(new nanoply::DataDescriptor<MyVertexInfo, 1, float>(nanoply::NNP_DENSITY, &(*mesh.infoVec.begin()).density)); |
|
vertex.dataDescriptor.push_back(new nanoply::DataDescriptor<MyVertexInfo, 1, int>(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<VertexIndex, 3, int>(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<MyMaterialInfo, 3, float>(std::string("kd"), (*mesh.material.begin()).kd.V())); |
|
material.dataDescriptor.push_back(new nanoply::DataDescriptor<MyMaterialInfo, 3, float>(std::string("ks"), (*mesh.material.begin()).ks.V())); |
|
material.dataDescriptor.push_back(new nanoply::DataDescriptor<MyMaterialInfo, 1, float>(std::string("rho"), &(*mesh.material.begin()).rho)); |
|
} |
|
|
|
//Create the mesh descriptor |
|
std::vector<nanoply::ElementDescriptor*> 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 0; |
|
}
|
|
|