diff --git a/wrap/nanoply/include/nanoply.hpp b/wrap/nanoply/include/nanoply.hpp index 26efb2a9..e250a28c 100644 --- a/wrap/nanoply/include/nanoply.hpp +++ b/wrap/nanoply/include/nanoply.hpp @@ -1,3 +1,18 @@ +/**************************************************************************** +* NanoPLY * +* NanoPLY is a C++11 header-only library to read and write PLY file * +* * +* Copyright(C) 2014 * +* 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/. * +* * +****************************************************************************/ + + #ifndef NANOPLY_HPP #define NANOPLY_HPP @@ -6,9 +21,10 @@ #include #include #include -#include // for fwrite() -#include // for fabs(),... +#include +#include #include +#include // Avoid conflicting declaration of min/max macros in windows headers #if !defined(NOMINMAX) && (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64)) @@ -19,263 +35,1660 @@ # endif #endif +#define USE_H4D_OUTPUT + namespace nanoply { + /** + * @cond HIDDEN_SYMBOLS + */ + template < size_t T> struct SizeT {}; + /** + * @endcond + */ -typedef enum NNP_ERROR { - NNP_OK = 0x0000, - NNP_UNABLE_TO_OPEN = 0x0001, - NNP_MISSING_HEADER = 0x0002, - NNP_MISSING_FORMAT = 0x0004 -} ErrorCode; + /** Error Type. + * Error type returned by the open of a PLY file. + */ + typedef enum NNP_ERROR + { + NNP_OK = 0x0000, /**< No error. */ + NNP_UNABLE_TO_OPEN = 0x0001, /**< The file cannot be opend. */ + NNP_MISSING_HEADER = 0x0002, /**< The file does not contain a valid PLY header. */ + NNP_MISSING_FORMAT = 0x0004 /**< The file has an invalid internal format. */ + } ErrorCode; -typedef enum NNP_ENTITY { - NNP_UNKNOWN_ENTITY = 0x0000, - NNP_PX = 0x0001, - NNP_PY = 0x0002, - NNP_PZ = 0x0004, - NNP_PXYZ = 0x0007, - NNP_NX = 0x0010, - NNP_NY = 0x0020, - NNP_NZ = 0x0040, - NNP_NXYZ = 0x0070, + /** PLY Entity. + * Property that can be saved in a PLY file. + */ + typedef enum NNP_ENTITY + { + NNP_UNKNOWN_ENTITY = 0x0000, /**< Unknown property. */ + NNP_PX = 0x0001, /**< Position x cordinate. */ + NNP_PY = 0x0002, /**< Position y cordinate. */ + NNP_PZ = 0x0004, /**< Position z cordinate. */ + NNP_PXYZ = 0x0007, /**< Position (x, y, z). */ - NNP_CR = 0x0100, - NNP_CG = 0x0200, - NNP_CB = 0x0400, - NNP_CA = 0x0800, + NNP_NX = 0x0010, /**< Normal x component. */ + NNP_NY = 0x0020, /**< Normal y component. */ + NNP_NZ = 0x0040, /**< Normal z component. */ + NNP_NXYZ = 0x0070, /**< Normal (x, y, z). */ - NNP_RADIUS = 0x1000, - NNP_SCALE = 0x2000 -} PlyEntity; + NNP_CR = 0x0100, /**< Color red component. */ + NNP_CG = 0x0200, /**< Color green component. */ + NNP_CB = 0x0400, /**< Color blue component. */ + NNP_CRGB = 0x0700, /**< Color RGB. */ + NNP_CA = 0x0800, /**< Color alpha component. */ + NNP_CRGBA = 0x0F00, /**< Color RGBA. */ -typedef enum NNP_PLYTYPE { - NNP_UNKNOWN_TYPE= 0x0000, - NNP_FLOAT32 = 0x0001, - NNP_FLOAT64 = 0x0002, - NNP_INT8 = 0x0010, - NNP_INT16 = 0x0020, - NNP_INT32 = 0x0040, - NNP_UINT8 = 0x0100, - NNP_UINT16 = 0x0200, - NNP_UINT32 = 0x0400, - NNP_LIST_UINT8_UINT32 = 0x1000, - NNP_LIST_INT8_UINT32 = 0x2000, - NNP_LIST_UINT8_INT32 = 0x4000, - NNP_LIST_INT8_INT32 = 0x8000 -} PlyType; + NNP_DENSITY = 0x1000, /**< Density or Radius property. */ + NNP_SCALE = 0x2000, /**< Scale property. */ + NNP_QUALITY = 0x4000, /**< Quality property. */ + NNP_REFLECTANCE = 0x8000, /**< Refelctance property. */ + NNP_BITFLAG = 0x10000, /**< Bit flags. */ -class PlyProperty -{ -public: - PlyProperty(PlyType _t, PlyEntity _e):type(_t),elem(_e){} - PlyType type; - PlyEntity elem; -}; + NNP_VERTEX_LIST = 0x20000 /**< List of vertec index. */ + } PlyEntity; -// In Ply an element is a collection of properties. -// -class PlyElement -{ -public: - std::string name; - int cnt; - std::vector propVec; - bool AddProperty(const char *line); - bool InitFromHeader(FILE *fp, char *line); -}; -// -bool PlyElement::InitFromHeader(FILE *fp, char *line) -{ - char buf[128]; - for(int i=0;line[i]!=0;++i) buf[i]=tolower(line[i]); - strtok(buf," \t"); // property - assert(strstr(buf,"element")); - char *el = strtok(0," \t\n"); // float - name = std::string(el); - sscanf(line,"%*s %*s %i",&cnt); - printf("Adding Element '%s' (%i) \n",name.c_str(),cnt); - fgets(line,4096,fp); - while(strstr(line,"property")) - { - AddProperty(line); - fgets(line,4096,fp); - } -} -// Skip all the elements in a file -bool PlyElement::SkipAsciiElementsInFile(FILE *fp) -{ - char line[4096]; - for(int i=0;icnt;++i) - fgets(line,4096,fp); -} -// Skip all the elements in a file -bool PlyElement::SkipBinaryElementsInFile(FILE *fp) -{ - for(int i=0;icnt;++i) - { - for(j=0;jpropVec.size();++j) + /** PLY Type. + * Type of a PLY property. + */ + typedef enum NNP_PLYTYPE + { + NNP_UNKNOWN_TYPE = 0x0000, /**< Unknown type. */ + NNP_FLOAT32 = 0x0001, /**< Float. */ + NNP_FLOAT64 = 0x0002, /**< Double. */ + NNP_INT8 = 0x0010, /**< Char. */ + NNP_INT16 = 0x0020, /**< Short. */ + NNP_INT32 = 0x0040, /**< Int. */ + NNP_UINT8 = 0x0100, /**< Unsigned Char. */ + NNP_UINT16 = 0x0200, /**< Unsigned Short. */ + NNP_UINT32 = 0x0400, /**< Unsigned Int. */ + NNP_LIST_UINT8_UINT32 = 0x1000, /**< List (size Unsigned Char) of Unsigned Int. */ + NNP_LIST_INT8_UINT32 = 0x2000, /**< List (size Char) of Unsigned Int. */ + NNP_LIST_UINT8_INT32 = 0x4000, /**< List (size Unsigned Char) of Int. */ + NNP_LIST_INT8_INT32 = 0x8000 /**< List (size Char) of Int. */ + } PlyType; + + + /** PLY Property. + * Define a PLY property (entity and type). + */ + class PlyProperty + { + public: + PlyType type; /**< Property type. */ + PlyEntity elem; /**< Property entity. */ + + + /** + * Constructor that sets the type and the entity of the PLY property. + * + * @param _t Property type. + * @param _e Property entity. + */ + PlyProperty(PlyType _t, PlyEntity _e):type(_t),elem(_e){} + + /** + * Get the description string of the property entity. + * + * @return Description string of the property entity. + */ + const char* EntityStr(); + + /** + * Get the name of the property entity. + * + * @return Name of the property entity. + */ + const char* EntityName(); + + /** + * Get the description string of the property type. + * + * @return Description string of the property type. + */ + const char* TypeStr(); + + /** + * Get the size in byte of the property type. + * + * @return Size in byte of the property type. + */ + int TypeSize(); + + /** + * Skip the property in an Ascii file. + * + * @param *fp Pointer to the opened file. + * @return If successful returns true. Otherwise, it returns false. + */ + bool SkipAsciiPropertyInFile(FILE *fp); + + /** + * Skip the property in a binary file. + * + * @param *fp Pointer to the opened file. + * @return If successful returns true. Otherwise, it returns false. + */ + bool SkipBinaryPropertyInFile(FILE *fp); + + /** + * Write the property in the header of the PLY file. + * + * @param *fp Pointer to the file. + * @return If successful returns true. Otherwise, it returns false. + */ + bool WriteHeader(FILE *fp); + }; + + const char* PlyProperty::EntityStr() + { + switch (this->elem) + { + case NNP_UNKNOWN_ENTITY : return "NNP_UNKNOWN_ENTITY"; + case NNP_PX : return "NNP_PX "; + case NNP_PY : return "NNP_PY "; + case NNP_PZ : return "NNP_PZ "; + case NNP_PXYZ : return "NNP_PXYZ "; + + case NNP_NX : return "NNP_NX "; + case NNP_NY : return "NNP_NY "; + case NNP_NZ : return "NNP_NZ "; + case NNP_NXYZ : return "NNP_NXYZ "; + + case NNP_CR : return "NNP_CR "; + case NNP_CG : return "NNP_CG "; + case NNP_CB : return "NNP_CB "; + case NNP_CRGB : return "NNP_CRGB "; + case NNP_CA : return "NNP_CA "; + case NNP_CRGBA : return "NNP_CRGBA "; + + case NNP_DENSITY : return "NNP_DENSITY "; + case NNP_SCALE : return "NNP_SCALE "; + case NNP_QUALITY : return "NNP_QUALITY "; + case NNP_REFLECTANCE : return "NNP_REFLECTANCE "; + + case NNP_VERTEX_LIST : return "NNP_VERTEX_LIST "; + + default: assert(0); + break; + } + return 0; + } + + + const char* PlyProperty::EntityName() + { +#ifdef USE_H4D_OUTPUT + switch (this->elem) + { + case NNP_UNKNOWN_ENTITY : return "unknown"; + case NNP_PX : return "x"; + case NNP_PY : return "y"; + case NNP_PZ : return "z"; + case NNP_PXYZ : return "x y z"; + + case NNP_NX : return "nx"; + case NNP_NY : return "ny"; + case NNP_NZ : return "nz"; + case NNP_NXYZ : return "nx ny nz"; + + case NNP_CR : return "red"; + case NNP_CG : return "green"; + case NNP_CB : return "blue"; + case NNP_CRGB : return "rgb"; + case NNP_CA : return "alpha"; + case NNP_CRGBA : return "rgba"; + + case NNP_DENSITY : return "radius"; + case NNP_SCALE : return "scale"; + case NNP_QUALITY : return "quality"; + case NNP_REFLECTANCE : return "reflectance"; + + case NNP_VERTEX_LIST : return "vertex_indices"; + + default: assert(0); + break; + } +#else + switch (this->elem) + { + case NNP_UNKNOWN_ENTITY : return "unknown"; + case NNP_PX : return "x"; + case NNP_PY : return "y"; + case NNP_PZ : return "z"; + case NNP_PXYZ : return "x y z"; + + case NNP_NX : return "nx"; + case NNP_NY : return "ny"; + case NNP_NZ : return "nz"; + case NNP_NXYZ : return "nx ny nz"; + + case NNP_CR : return "diffuse_red"; + case NNP_CG : return "diffuse_green"; + case NNP_CB : return "diffuse_blue"; + case NNP_CRGB : return "diffuse_rgb"; + case NNP_CA : return "alpha"; + case NNP_CRGBA : return "diffuse_rgba"; + + case NNP_DENSITY : return "radius"; + case NNP_SCALE : return "value"; + case NNP_QUALITY : return "confidence"; + case NNP_REFLECTANCE : return "reflectance"; + + case NNP_VERTEX_LIST : return "vertex_indices"; + + default: assert(0); + break; + } +#endif + + return 0; + } + + + const char* PlyProperty::TypeStr() + { + switch (this->type) + { + case NNP_UNKNOWN_TYPE : return "NNP_UNKNOWN_TYPE "; + case NNP_FLOAT32 : return "NNP_FLOAT32 "; + case NNP_FLOAT64 : return "NNP_FLOAT64 "; + case NNP_INT8 : return "NNP_INT8 "; + case NNP_INT16 : return "NNP_INT16 "; + case NNP_INT32 : return "NNP_INT32 "; + case NNP_UINT8 : return "NNP_UINT8 "; + case NNP_UINT16 : return "NNP_UINT16 "; + case NNP_UINT32 : return "NNP_UINT32 "; + case NNP_LIST_UINT8_UINT32: return "NNP_LIST_UINT8_UINT32"; + case NNP_LIST_INT8_UINT32 : return "NNP_LIST_INT8_UINT32 "; + case NNP_LIST_UINT8_INT32 : return "NNP_LIST_UINT8_INT32 "; + case NNP_LIST_INT8_INT32 : return "NNP_LIST_INT8_INT32 "; + default: assert(0); + break; + } + return 0; + } + + int PlyProperty::TypeSize() + { + switch (this->type) + { + case NNP_UNKNOWN_TYPE: + return 0; + case NNP_INT8: + case NNP_UINT8: + return 1; + case NNP_INT16: + case NNP_UINT16: + return 2; + case NNP_FLOAT32: + case NNP_INT32: + case NNP_UINT32: + return 4; + case NNP_FLOAT64: + return 8; + case NNP_LIST_UINT8_UINT32: + case NNP_LIST_INT8_UINT32 : + case NNP_LIST_UINT8_INT32 : + case NNP_LIST_INT8_INT32 : + return 1; + default: assert(0); + break; + } + return 0; + } + + + bool PlyProperty::SkipAsciiPropertyInFile(FILE *fp) + { + int count = 1; + if (this->elem == NNP_CRGB || this->elem == NNP_NXYZ || this->elem == NNP_PXYZ) + count = 3; + else if (this->elem == NNP_CRGBA) + count = 4; + switch(type) + { + case NNP_INT8: + case NNP_INT16: + case NNP_INT32: + { + int* temp = new int[count]; + for (int i = 0; i < count ; i++) + fscanf(fp, "%d", &temp[i]); + delete[] temp; + break; + } + case NNP_UINT8: + case NNP_UINT16: + case NNP_UINT32: + { + unsigned int* temp = new unsigned int[count]; + for (int i = 0; i < count ; i++) + fscanf(fp, "%u", &temp[i]); + delete[] temp; + break; + } + case NNP_FLOAT32: + { + float* temp = new float[count]; + for (int i = 0; i < count ; i++) + fscanf(fp, "%f", &temp[i]); + delete[] temp; + break; + } + case NNP_FLOAT64: + { + double* temp = new double[count]; + for (int i = 0; i < count ; i++) + fscanf(fp, "%f", &temp[i]); + delete[] temp; + break; + } + case NNP_LIST_UINT8_UINT32: + case NNP_LIST_INT8_UINT32 : + { + fscanf(fp, "%d", &count); + unsigned int* temp = new unsigned int[count]; + for (int i = 0; i < count ; i++) + fscanf(fp, "%u", &temp[i]); + delete[] temp; + break; + } + case NNP_LIST_UINT8_INT32 : + case NNP_LIST_INT8_INT32 : + { + fscanf(fp, "%d", &count); + int* temp = new int[count]; + for (int i = 0; i < count ; i++) + fscanf(fp, "%d", &temp[i]); + delete[] temp; + break; + } + } + return true; + } + + bool PlyProperty::SkipBinaryPropertyInFile(FILE *fp) + { + int count = 1; + if (this->elem == NNP_CRGB || this->elem == NNP_NXYZ || this->elem == NNP_PXYZ) + count = 3; + else if (this->elem == NNP_CRGBA) + count = 4; + if (this->type >= NNP_LIST_UINT8_UINT32) + { + unsigned char cntList = 0; + fread(&cntList, sizeof(char), 1, fp); + fseek(fp, 4 * cntList, SEEK_CUR); + } + else + fseek(fp, this->TypeSize() * count, SEEK_CUR); + return true; + } + + + bool PlyProperty::WriteHeader(FILE *fp) + { + std::string name, type; + + switch (this->type) + { + case NNP_UNKNOWN_TYPE : type = "unknonw"; break; + case NNP_FLOAT32 : type = "float"; break; + case NNP_FLOAT64 : type = "double"; break; + case NNP_INT8 : type = "char"; break; + case NNP_INT16 : type = "short"; break; + case NNP_INT32 : type = "int"; break; + case NNP_UINT8 : type = "uchar"; break; + case NNP_UINT16 : type = "ushort"; break; + case NNP_UINT32 : type = "uint"; break; + case NNP_LIST_UINT8_UINT32: type = "list uchar uint"; break; + case NNP_LIST_INT8_UINT32 : type = "list char uint"; break; + case NNP_LIST_UINT8_INT32 : type = "list uchar int"; break; + case NNP_LIST_INT8_INT32 : type = "list char int"; break; + } + + name = this->EntityName(); + switch (this->elem) + { + case NNP_PXYZ : + { + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_PX).EntityName(); + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_PY).EntityName(); + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_PZ).EntityName(); + break; + } + case NNP_NXYZ : + { + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_NX).EntityName(); + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_NY).EntityName(); + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_NZ).EntityName(); + break; + } + case NNP_CRGB : + { + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_CR).EntityName(); + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_CG).EntityName(); + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_CB).EntityName(); + break; + } + case NNP_CRGBA: + { + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_CR).EntityName(); + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_CG).EntityName(); + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_CB).EntityName(); + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + name = PlyProperty(nanoply::NNP_FLOAT32, nanoply::NNP_CA).EntityName();; + break; + } + } + fprintf(fp, "property %s %s\n", type.c_str(), name.c_str()); + return true; + } + + + + /** PLY Element. + * Define a PLY Element as a collection of properties. + */ + class PlyElement + { + public: + + std::string name; /**< Name of the elment in the PLY header (for example "vertex" or "face") */ + int cnt; /**< Number of instances of the elment in the PLY file */ + std::vector propVec; /**< Collection of properties that define the element */ + + /** + * Default Constructor + */ + PlyElement(); + + /** + * Constructor that sets the name, the properties and the number of instances of the element. + * + * @param *name Name of the element. + * @param &prop Vector of properties. + * @param nElem Number of instances. + */ + PlyElement(const char *name, std::vector &prop, int nElem); + + + /** + * Parse the input line and add the properties to the element. + * It assumes that the passed line has the folowing structure: "property PLYTYPE PLYELEMENT" + * + * @param *line Input line. + * @return If successful returns true. Otherwise, it returns false. + */ + bool AddProperty(const char *line); + + + /** + * Initialize an element from an header file. + * The first line of the buf is passed into line and must start with the 'element' keyword + * + * @param *fp Pointer to the opened file. + * @param *line First buffer line. + * @return If successful returns true. Otherwise, it returns false. + */ + bool InitFromHeader(FILE *fp, char *line); + + + /** + * Write the element descriport in the header file. + * + * @param *fp Pointer to the file. + * @return If successful returns true. Otherwise, it returns false. + */ + bool WriteHeader(FILE *fp); + + + /** + * Skip the element in an Ascii file. + * + * @param *fp Pointer to the opened file. + * @return If successful returns true. Otherwise, it returns false. + */ + bool SkipAsciiElementsInFile(FILE *fp); + + + /** + * Skip the element in a binary file. + * + * @param *fp Pointer to the opened file. + * @return If successful returns true. Otherwise, it returns false. + */ + bool SkipBinaryElementsInFile(FILE *fp); + + + /** + * Check if the input entity is in the property of the element. + * + * @param entity Input entity. + * @return If successful returns true. Otherwise, it returns false. + */ + bool Contains(NNP_ENTITY entity); + }; + + + PlyElement::PlyElement(){} + + PlyElement::PlyElement(const char *_name, std::vector &prop, int nElem):name(_name), cnt(nElem), propVec(prop) { } - } -} -bool PlyElement::AddProperty(const char *line) -{ - char buf[128]; - for(int i=0;line[i]!=0;++i) buf[i]=tolower(line[i]); - strtok(buf," \t"); // property - char *ty = strtok(0," \t\n"); // float - PlyType type = NNP_UNKNOWN_TYPE; - PlyEntity prop = NNP_UNKNOWN_ENTITY; - - if(strstr(ty,"float") || strstr(ty,"float32") ) type = NNP_FLOAT32; - if(strstr(ty,"double") || strstr(ty,"float64") ) type = NNP_FLOAT64; - if(strstr(ty,"char") || strstr(ty,"int8") ) type = NNP_INT8; - if(strstr(ty,"short") || strstr(ty,"int16") ) type = NNP_INT16; - if(strstr(ty,"int") || strstr(ty,"int32") ) type = NNP_INT32; - if(strstr(ty,"uchar") || strstr(ty,"uint8") ) type = NNP_UINT8; - if(strstr(ty,"ushort") || strstr(ty,"uint16") ) type = NNP_UINT16; - if(strstr(ty,"uint") || strstr(ty,"uint32") ) type = NNP_UINT32; - if(strstr(ty,"list") ) { - char *ty1 = strtok(0," \t\n"); - char *ty2 = strtok(0," \t\n"); - if( (strstr(ty1,"uchar")||strstr(ty1,"uint8") ) && (strstr(ty2,"uint")|| strstr(ty2,"uint32")) ) type = NNP_LIST_UINT8_UINT32; - if( (strstr(ty1,"char") || strstr(ty1,"int8") ) && (strstr(ty2,"uint")|| strstr(ty2,"uint32")) ) type = NNP_LIST_INT8_UINT32; - if( (strstr(ty1,"uchar")||strstr(ty1,"uint8") ) && (strstr(ty2,"int") || strstr(ty2,"int32")) ) type = NNP_LIST_UINT8_INT32; - if( (strstr(ty1,"char") || strstr(ty1,"int8") ) && (strstr(ty2,"int") || strstr(ty2,"int32")) ) type = NNP_LIST_INT8_INT32; - } - - assert(type != NNP_UNKNOWN_TYPE); - char *el = strtok(0," \t\n"); // x - - if(strstr(el,"x")) prop = NNP_PX; - if(strstr(el,"y")) prop = NNP_PY; - if(strstr(el,"z")) prop = NNP_PZ; - if(strstr(el,"nx")) prop = NNP_NX; - if(strstr(el,"ny")) prop = NNP_NY; - if(strstr(el,"nz")) prop = NNP_NZ; - -// assert(prop != NNP_UNKNOWN_PROP); - propVec.push_back(PlyProperty(type,prop)); - printf("Adding Property %i %i\n",type,prop); -} - -class Info -{ -public: - ErrorCode errInfo; - bool binary; - int mask; - int vertexNum; - std::vector elemVec; - void Clear() { errInfo=NNP_OK; } -}; - - - -inline bool GetInfo(const char *filename, nanoply::Info &info) -{ - FILE *fp=fopen(filename,"r"); - info.Clear(); - - if(!fp) - { - info.errInfo = NNP_UNABLE_TO_OPEN; - return false; - } - char buf[4096]; - fgets(buf,4096,fp); - if( (strncmp(buf,"PLY",3)!=0) && (strncmp(buf,"ply",3)!=0) ) - { - info.errInfo = NNP_MISSING_HEADER; - return false; - } - fgets(buf,4096,fp); - if(strncmp(buf,"format",strlen("format"))!=0) + bool PlyElement::InitFromHeader(FILE *fp, char *line) { - info.errInfo = NNP_MISSING_FORMAT; - return false; + char buf[4096]; + for(int i=0;line[i]!=0;++i) buf[i]=tolower(line[i]); + strtok(buf," \t"); // property + assert(strstr(buf,"element")); + char *el = strtok(0," \t\n"); + name = std::string(el); + + sscanf(line,"%*s %*s %i",&cnt); + //printf("Adding Element '%s' (%i) \n",name.c_str(),cnt); + fgets(line,4096,fp); + while(strstr(line,"property")) + { + AddProperty(line); + fgets(line,4096,fp); + } + unsigned int mask = 0; + for (int i = 0; i < propVec.size(); i++) + mask |= propVec[i].elem; + std::vector compactPropVec; + for (int i = 0; i < propVec.size(); i++) + { + switch (propVec[i].elem) + { + case NNP_NX: + case NNP_NY: + if ((mask & NNP_NXYZ) != NNP_NXYZ) + compactPropVec.push_back(propVec[i]); + break; + case NNP_NZ: + if ((mask & NNP_NXYZ) != NNP_NXYZ) + compactPropVec.push_back(propVec[i]); + else + compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_NXYZ)); + break; + case NNP_PX: + case NNP_PY: + if ((mask & NNP_PXYZ) != NNP_PXYZ) + compactPropVec.push_back(propVec[i]); + break; + case NNP_PZ: + if ((mask & NNP_PXYZ) != NNP_PXYZ) + compactPropVec.push_back(propVec[i]); + else + compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_PXYZ)); + break; + case NNP_CR: + case NNP_CG: + if ((mask & NNP_CRGB) != NNP_CRGB & (mask & NNP_CRGBA) != NNP_CRGBA) + compactPropVec.push_back(propVec[i]); + break; + case NNP_CB: + if ((mask & NNP_CRGB) != NNP_CRGB & (mask & NNP_CRGBA) != NNP_CRGBA) + compactPropVec.push_back(propVec[i]); + else if ((mask & NNP_CRGB) == NNP_CRGB & (mask & NNP_CRGBA) != NNP_CRGBA) + compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_CRGB)); + break; + case NNP_CA: + if ((mask & NNP_CRGB) != NNP_CRGB & (mask & NNP_CRGBA) != NNP_CRGBA) + compactPropVec.push_back(propVec[i]); + else if ((mask & NNP_CRGBA) == NNP_CRGBA) + compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_CRGBA)); + break; + default: + compactPropVec.push_back(propVec[i]); + break; + } + } + + propVec.clear(); + propVec = compactPropVec; + return true; } - if(strstr(buf,"ascii") || strstr(buf,"ASCII")) - info.binary=false; - else - { - if(strstr(buf,"binary") || strstr(buf,"BINARY")) - info.binary=true; - else + + bool PlyElement::WriteHeader(FILE *fp) { - info.errInfo = NNP_MISSING_FORMAT; - return false; + fprintf(fp, "element %s %d\n", name.c_str(), cnt); + for(int i = 0; i < propVec.size(); i++) + propVec[i].WriteHeader(fp); + return true; } - } - fgets(buf,4096,fp); - while(strncmp(buf,"end_header",strlen("end_header"))) - { - if(strstr(buf,"comment") || strstr(buf,"COMMENT") ) + + + bool PlyElement::SkipAsciiElementsInFile(FILE *fp) { - fgets(buf,4096,fp); - continue; + char line[4096]; + for(int i = 0; i < this->cnt; ++i) + fgets(line, 4096, fp); + return true; } - if(strstr(buf,"element")) + + + bool PlyElement::SkipBinaryElementsInFile(FILE *fp) { - PlyElement pe; - pe.InitFromHeader(fp,buf); - info.elemVec.push_back(pe); + for(int i = 0; i < this->cnt; ++i) + for(int j = 0; j < this->propVec.size(); ++j) + this->propVec[j].SkipBinaryPropertyInFile(fp); + return true; } - } - } -template -class DataDescriptor -{ - DestinationType *base; - int curPos; - PlyProperty elem; -public: - DataDescriptor(PlyProperty _e, DestinationType *_b):elem(_e),base(_b),curPos(0) - { - } + bool PlyElement::AddProperty(const char *line) + { + char buf[128]; + for(int i=0;line[i]!=0;++i) buf[i]=tolower(line[i]); + strtok(buf," \t"); // property + char *ty = strtok(0," \t\n"); // float - DataDescriptor(PlyProperty _e, void *_b ):elem(_e),base((DestinationType *)_b),curPos(0) - { + PlyType type = NNP_UNKNOWN_TYPE; + if(strcmp(ty,"float") == 0 || strcmp(ty,"float32") == 0) type = NNP_FLOAT32; + if(strcmp(ty,"double") == 0 || strcmp(ty,"float64") == 0) type = NNP_FLOAT64; + if(strcmp(ty,"char") == 0 || strcmp(ty,"int8") == 0) type = NNP_INT8; + if(strcmp(ty,"short") == 0 || strcmp(ty,"int16") == 0) type = NNP_INT16; + if(strcmp(ty,"int") == 0 || strcmp(ty,"int32") == 0) type = NNP_INT32; + if(strcmp(ty,"uchar") == 0 || strcmp(ty,"uint8") == 0 ) type = NNP_UINT8; + if(strcmp(ty,"ushort") == 0|| strcmp(ty,"uint16") == 0 ) type = NNP_UINT16; + if(strcmp(ty,"uint") == 0 || strcmp(ty,"uint32") == 0 ) type = NNP_UINT32; + if(strcmp(ty,"list") == 0 ) { + char *ty1 = strtok(0," \t\n"); + char *ty2 = strtok(0," \t\n"); + if( (strcmp(ty1,"uchar") == 0 ||strcmp(ty1,"uint8") == 0 ) && (strcmp(ty2,"uint") == 0 || strcmp(ty2,"uint32") == 0) ) + type = NNP_LIST_UINT8_UINT32; + if( (strcmp(ty1,"char") == 0 || strcmp(ty1,"int8") == 0) && (strcmp(ty2,"uint") == 0|| strcmp(ty2,"uint32") == 0) ) + type = NNP_LIST_INT8_UINT32; + if( (strcmp(ty1,"uchar") == 0 ||strcmp(ty1,"uint8") == 0) && (strcmp(ty2,"int") == 0 || strcmp(ty2,"int32") == 0) ) + type = NNP_LIST_UINT8_INT32; + if( (strcmp(ty1,"char") == 0 || strcmp(ty1,"int8") == 0) && (strcmp(ty2,"int") == 0 || strcmp(ty2,"int32") ) ) + type = NNP_LIST_INT8_INT32; + } - } - void Restart(){curPos=0;} - void ReadElem(FILE *fp, int numOfElemToRead) - { - fread(base+curPos,sizeof(DestinationType),numOfElemToRead,fp); - } -}; + assert(type != NNP_UNKNOWN_TYPE); + char *el = strtok(0," \t\n"); // x + + PlyEntity ent = NNP_UNKNOWN_ENTITY; + if(strstr(el,"x")) ent = NNP_PX; + if(strstr(el,"y")) ent = NNP_PY; + if(strstr(el,"z")) ent = NNP_PZ; + if(strstr(el,"nx")) ent = NNP_NX; + if(strstr(el,"ny")) ent = NNP_NY; + if(strstr(el,"nz")) ent = NNP_NZ; + if (strstr(el,"red")) ent = NNP_CR; + if (strstr(el,"diffuse_red")) ent = NNP_CR; + if (strstr(el,"green")) ent = NNP_CG; + if (strstr(el,"diffuse_green")) ent = NNP_CG; + if (strstr(el,"blue")) ent = NNP_CB; + if (strstr(el,"diffuse_blue")) ent = NNP_CB; + if(strstr(el,"alpha")) ent = NNP_CA; + if (strstr(el,"scale")) ent = NNP_SCALE; + if (strstr(el,"value")) ent = NNP_SCALE; + if(strstr(el,"density")) ent = NNP_DENSITY; + if(strstr(el,"radius")) ent = NNP_DENSITY; + if (strstr(el,"quality")) ent = NNP_QUALITY; + if (strstr(el,"confidence")) ent = NNP_QUALITY; + if(strstr(el,"reflectance")) ent = NNP_REFLECTANCE; + if(strstr(el,"vertex_index")) ent = NNP_VERTEX_LIST; + if(strstr(el,"vertex_indices")) ent = NNP_VERTEX_LIST; + //assert(ent != NNP_UNKNOWN_ENTITY); + + propVec.push_back(PlyProperty(type,ent)); + //printf("Adding Property %s %s\n",propVec.back().TypeStr(),propVec.back().EntityStr()); + + return true; + } + + + bool PlyElement::Contains(PlyEntity entity) + { + for (int i = 0; i < propVec.size(); i++) + { + if (propVec[i].elem == entity) + return true; + } + return false; + } + + + /** PLY header info. + * Define the data of the PLY header + */ + class Info + { + + public: + ErrorCode errInfo; /**< Error code returned by the reading of a PLY file */ + bool binary; /**< Boolean about the file format (Binary = true, Ascci = false) */ + std::vector elemVec; /**< Elements defided in the header */ + bool bigEndian; /**< Endianess of the binary file */ + + + /** + * Default Constructor + */ + Info(); + + + /** + * Constructor that reads the header info from a file. + * + * @param *filename Path of the file to read. + */ + Info(const char *filename); + + + /** + * Constructor that creates the header info for a mesh. + * + * @param &vertex Vertex element object. + * @param &face Face element object. + * @param binary File format (binary = true, ascci = false). + */ + Info(PlyElement &vertex, PlyElement &face, bool binary); + + + /** + * Constructor that creates the header info for a point cloud. + * + * @param &vertex Vertex element object. + * @param binary File format (binary = true, ascci = false). + */ + Info(PlyElement &vertex, bool binary); + + + /** + * Clear the object. + */ + void Clear() { errInfo=NNP_OK; } + + + /** + * Return the number of vertex instances + * + * @return The number of vertex instances + */ + int GetVertexCount() const; + + + /** + * Return the number of face instances + * + * @return The number of face instances + */ + int GetFaceCount() const; + + + /** + * Return a reference to the vertex element + * + * @return The reference to the vertex element + */ + PlyElement* GetVertexElement(); + + + /** + * Return a reference to the face element + * + * @return The reference to the face element + */ + PlyElement* GetFaceElement(); + }; + + + Info::Info(){} + + Info::Info(const char *filename) + { + this->errInfo = NNP_OK; + FILE *fp=fopen(filename,"r"); + + if(!fp) + { + this->errInfo = NNP_UNABLE_TO_OPEN; + return; + } + char buf[4096]; + fgets(buf,4096,fp); + if( (strncmp(buf,"PLY",3)!=0) && (strncmp(buf,"ply",3)!=0) ) + { + this->errInfo = NNP_MISSING_HEADER; + return; + } + fgets(buf,4096,fp); + if(strncmp(buf,"format",strlen("format"))!=0) + { + this->errInfo = NNP_MISSING_FORMAT; + return; + } + + if(strstr(buf,"ascii") || strstr(buf,"ASCII")) + { + this->binary=false; + } + else if(strstr(buf,"binary") || strstr(buf,"BINARY")) + { + this->binary=true; + if (strstr(buf, "binary_big") || strstr(buf, "BINARY_BIG")) + this->bigEndian = true; + else + this->bigEndian = false; + } + else + { + this->errInfo = NNP_MISSING_FORMAT; + return; + } + + fgets(buf,4096,fp); + while(strncmp(buf,"end_header",strlen("end_header"))) + { + if(strstr(buf,"comment") || strstr(buf,"COMMENT") ) + { + fgets(buf,4096,fp); + continue; + } + if(strstr(buf,"element")) + { + PlyElement pe; + pe.InitFromHeader(fp,buf); + this->elemVec.push_back(pe); + } + } + fclose(fp); + } + + Info::Info(PlyElement &vertex, PlyElement &face, bool binary) + { + elemVec.push_back(vertex); + elemVec.push_back(face); + this->binary = binary; + } + + Info::Info(PlyElement &vertex, bool binary) + { + elemVec.push_back(vertex); + this->binary = binary; + } + + int Info::GetVertexCount() const + { + for (int i = 0; i < elemVec.size(); i++) + { + if (elemVec[i].name.compare(std::string("vertex")) == 0) + return elemVec[i].cnt; + } + return -1; + } + + int Info::GetFaceCount() const + { + for (int i = 0; i < elemVec.size(); i++) + { + if (elemVec[i].name.compare(std::string("face")) == 0) + return elemVec[i].cnt; + } + return -1; + } + + + PlyElement* Info::GetVertexElement() + { + for (int i = 0; i < elemVec.size(); i++) + { + if (elemVec[i].name.compare(std::string("vertex")) == 0) + return &elemVec[i]; + } + return NULL; + } + + + PlyElement* Info::GetFaceElement() + { + for (int i = 0; i < elemVec.size(); i++) + { + if (elemVec[i].name.compare(std::string("face")) == 0) + return &elemVec[i]; + } + return NULL; + } + + + /** + * @cond HIDDEN_SYMBOLS + */ + void adjustEndianess(unsigned char* buffer, int typeSize, int count) + { + for (int i = 0; i < count; i++) + { + int offset = i*typeSize; + for (int j = 0; j < typeSize/2; j++) + { + unsigned char temp = buffer[offset+j]; + buffer[offset+j] = buffer[offset + typeSize - 1 - j]; + buffer[offset + typeSize - 1 - j] = temp; + } + } + } + /** + * @endcond + */ + + + /** Memory descriptor of a vector of properties. + * The class defines how a vector of PlyProperty is saved in memory. + * + * @tparam CointainerType Type of the container of the property + * @tparam VectorSize Number of values stored in the property. + * @tparam ScalarType Type of the values stored in the property. + */ + template + class VectorDescriptor + { + int64_t curPos; /**< Position of the next property to read or to write. */ + PlyEntity elem; /**< Ply entity managed by the descriptor. */ + void *base; /**< Pointer to the memory location that contains the data of the property. */ + + public: + + /** + * Void constructor. + * + */ + VectorDescriptor(); + + + /** + * Constructor of the descriptor. + * + * @param _e Ply entity managed by the descriptor. + * @param *_b Pointer to the memory location that contains the data of the property. + */ + VectorDescriptor(PlyEntity _e, void *_b); + + + /** + * Restart the descriptor. + */ + void Restart(); + + + /** + * Read the property data from the binary file if the entity of the property prop is equals to the entity of the descriptor. + * + * @param *fp Pointer to the opened file. + * @param &prop Next PLY property to read from the file. + * @param bigEndian Endianess of the binary data (true = big endian, false = little endian). + * @return If successful returns true. Otherwise, it returns false. + */ + bool ReadElemBinary(FILE *fp, PlyProperty &prop, bool bigEndian); + + + /** + * Read the property data from the ascii file if the entity of the property prop is equals to the entity of the descriptor. + * + * @param *fp Pointer to the opened file. + * @param &prop Next PLY property to read from the file. + * @return If successful returns true. Otherwise, it returns false. + */ + bool ReadElemAscii(FILE *fp, PlyProperty &prop); + + + /** + * Write the property data in the binary file if the entity of the property prop is equals to the entity of the descriptor. + * + * @param *fp Pointer to the file. + * @param &prop Next PLY property to write from the file. + * @return If successful returns true. Otherwise, it returns false. + */ + bool WriteElemBinary(FILE *fp, PlyProperty &prop); + + + /** + * Write the property data in the ascii file if the entity of the property prop is equals to the entity of the descriptor. + * + * @param *fp Pointer to the file. + * @param &prop Next PLY property to write from the file. + * @return If successful returns true. Otherwise, it returns false. + */ + bool WriteElemAscii(FILE *fp, PlyProperty &prop); + + private: + + template + void ReadBinary(FILE *fp, PlyProperty &prop, bool bigEndian); + + template + void ReadAscii(FILE *fp, PlyProperty &prop, const char *format); + + template + void WriteBinary(FILE *fp, PlyProperty &prop); + + template + void WriteAscii(FILE *fp, PlyProperty &prop, const char *format); + + }; + + + template + VectorDescriptor::VectorDescriptor() + { + + } + + template + VectorDescriptor::VectorDescriptor(PlyEntity _e, void *_b):curPos(0),elem(_e),base(_b) + { + + } + + template + void VectorDescriptor::Restart() + { + this->curPos=0; + } + + template + template + void VectorDescriptor::ReadBinary(FILE *fp, PlyProperty &prop, bool bigEndian) + { + int count = 1; + if (prop.elem == NNP_CRGB || prop.elem == NNP_NXYZ || prop.elem == NNP_PXYZ) + count = 3; + else if (prop.elem == NNP_CRGBA) + count = 4; + int typeSize = prop.TypeSize(); + unsigned char* buffer = new unsigned char[count*typeSize]; + fread(buffer, typeSize, count, fp); + if (typeSize > 1 && bigEndian) + adjustEndianess(buffer, typeSize, count); + if (prop.type == NNP_LIST_UINT8_UINT32 || prop.type == NNP_LIST_UINT8_INT32) + { + count = buffer[0]; + delete[] buffer; + buffer = new unsigned char[count*4]; + fread(buffer, 4, count, fp); + if (bigEndian) + adjustEndianess(buffer, 4, count); + } + else if (prop.type == NNP_LIST_INT8_UINT32 || prop.type == NNP_LIST_INT8_INT32) + { + count = char(buffer[0]); + delete[] buffer; + buffer = new unsigned char[count*4]; + fread(buffer, 4, count, fp); + if (bigEndian) + adjustEndianess(buffer, 4, count); + } + C* temp = (C*)buffer; + + unsigned char* baseProp = (unsigned char*)base + this->curPos*sizeof(ContainerType); + for (int i = 0; i < std::min(VectorSize, count); i++) + *(ScalarType *)(baseProp + i*sizeof(ScalarType)) = ScalarType(temp[i]); + + ++(this->curPos); + delete[] buffer; + } + + template + bool VectorDescriptor::ReadElemBinary(FILE *fp, PlyProperty &prop, bool bigEndian) + { + if (prop.elem != elem) + return false; + switch(prop.type) + { + case NNP_INT8: this->ReadBinary(fp, prop, bigEndian); break; + case NNP_UINT8: this->ReadBinary(fp, prop, bigEndian); break; + case NNP_INT16: this->ReadBinary(fp, prop, bigEndian); break; + case NNP_UINT16: this->ReadBinary(fp, prop, bigEndian); break; + case NNP_FLOAT32: this->ReadBinary(fp, prop, bigEndian); break; + case NNP_INT32: this->ReadBinary(fp, prop, bigEndian); break; + case NNP_UINT32: this->ReadBinary(fp, prop, bigEndian); break; + case NNP_FLOAT64: this->ReadBinary(fp, prop, bigEndian); break; + case NNP_LIST_UINT8_UINT32: + case NNP_LIST_INT8_UINT32: this->ReadBinary(fp, prop, bigEndian); break; + case NNP_LIST_UINT8_INT32: + case NNP_LIST_INT8_INT32: this->ReadBinary(fp, prop, bigEndian); break; + } + return true; + } -template -bool Open(const char *filename, DataAdaptorTuple vertexAdaptor, nanoply::Info &info) -{ - FILE *fp=fopen(filename,"rb"); - if(!fp) - { - return false; - } - char buf[4096]; - do - { - fgets(buf,4096,fp); - } - while(strncmp(buf,"end_header",strlen("end_header")) ); - // Now start the real reading! - for(int i =0; i< info.elemVec.size();++i) - { + template + template + void VectorDescriptor::ReadAscii(FILE *fp, PlyProperty &prop, const char *format) + { + int count = 1; + if (prop.elem == NNP_CRGB || prop.elem == NNP_NXYZ || prop.elem == NNP_PXYZ) + count = 3; + else if (prop.elem == NNP_CRGBA) + count = 4; - } -} + if (prop.type == NNP_LIST_UINT8_UINT32 || prop.type == NNP_LIST_UINT8_INT32) + { + unsigned char listSize; + fscanf(fp, "%u", &listSize); + count = listSize; + } + else if (prop.type == NNP_LIST_INT8_UINT32 || prop.type == NNP_LIST_INT8_INT32) + { + char listSize; + fscanf(fp, "%d", &listSize); + count = listSize; + } + + C* temp = new C[count]; + for (int i = 0; i < count ; i++) + fscanf(fp, format, &temp[i]); + + unsigned char* baseProp = (unsigned char*)base + this->curPos*sizeof(ContainerType); + for (int i = 0; i < std::min(VectorSize,count); i++) + *(ScalarType *)(baseProp + i*sizeof(ScalarType)) = ScalarType(temp[i]); + + delete[] temp; + ++(this->curPos); + } + + + + template + bool VectorDescriptor::ReadElemAscii(FILE *fp, PlyProperty &prop) + { + if (prop.elem != elem) + return false; + switch(prop.type) + { + case NNP_INT8: this->ReadAscii(fp, prop, "%d"); break; + case NNP_UINT8: this->ReadAscii(fp, prop, "%u"); break; + case NNP_INT16: this->ReadAscii(fp, prop, "%d"); break; + case NNP_UINT16: this->ReadAscii(fp, prop, "%u"); break; + case NNP_FLOAT32: this->ReadAscii(fp, prop, "%f"); break; + case NNP_INT32: this->ReadAscii(fp, prop, "%d"); break; + case NNP_UINT32: this->ReadAscii(fp, prop, "%u"); break; + case NNP_FLOAT64: this->ReadAscii(fp, prop, "%f"); break; + case NNP_LIST_UINT8_UINT32: + case NNP_LIST_INT8_UINT32: this->ReadAscii(fp, prop, "%u"); break; + case NNP_LIST_UINT8_INT32: + case NNP_LIST_INT8_INT32: this->ReadAscii(fp, prop, "%d"); break; + } + return true; + } + + + + template + template + void VectorDescriptor::WriteBinary(FILE *fp, PlyProperty &prop) + { + int count = 1; + if (prop.elem == NNP_CRGB || prop.elem == NNP_NXYZ || prop.elem == NNP_PXYZ) + count = 3; + else if (prop.elem == NNP_CRGBA) + count = 4; + + C data[VectorSize]; + + if (prop.type == NNP_LIST_UINT8_UINT32 || prop.type == NNP_LIST_UINT8_INT32) + { + unsigned char listSize = (unsigned char) VectorSize; + fwrite(&listSize, sizeof(unsigned char), 1, fp); + count = VectorSize; + } + else if (prop.type == NNP_LIST_INT8_UINT32 || prop.type == NNP_LIST_INT8_INT32) + { + char listSize = (char) VectorSize; + fwrite(&listSize, sizeof(char), 1, fp); + count = VectorSize; + } + C temp = 0; + unsigned char* baseProp = (unsigned char*)base + this->curPos*sizeof(ContainerType); + for (int i = 0; i < std::min(VectorSize, count); i++) + data[i] = (C)(*(ScalarType*)(baseProp + i*sizeof(ScalarType))); + fwrite(data, sizeof(C), std::min(VectorSize, count), fp); + for (int i = 0; i < (count - VectorSize); i++) + fwrite(&temp, sizeof(C), 1, fp); + ++(this->curPos); + } + + + template + bool VectorDescriptor::WriteElemBinary(FILE *fp, PlyProperty &prop) + { + if (prop.elem != elem) + return false; + switch(prop.type) + { + case NNP_INT8: this->WriteBinary(fp, prop); break; + case NNP_UINT8: this->WriteBinary(fp, prop); break; + case NNP_INT16: this->WriteBinary(fp, prop); break; + case NNP_UINT16: this->WriteBinary(fp, prop); break; + case NNP_FLOAT32: this->WriteBinary(fp, prop); break; + case NNP_INT32: this->WriteBinary(fp, prop); break; + case NNP_UINT32: this->WriteBinary(fp, prop); break; + case NNP_FLOAT64: this->WriteBinary(fp, prop); break; + case NNP_LIST_UINT8_UINT32: + case NNP_LIST_INT8_UINT32: this->WriteBinary(fp, prop); break; + case NNP_LIST_UINT8_INT32: + case NNP_LIST_INT8_INT32: this->WriteBinary(fp, prop); break; + } + return true; + } + + + template + template + void VectorDescriptor::WriteAscii(FILE *fp, PlyProperty &prop, const char *format) + { + int count = 1; + if (prop.elem == NNP_CRGB || prop.elem == NNP_NXYZ || prop.elem == NNP_PXYZ) + count = 3; + else if (prop.elem == NNP_CRGBA) + count = 4; + + if (prop.type == NNP_LIST_UINT8_UINT32 || prop.type == NNP_LIST_UINT8_INT32) + { + fprintf(fp, "%u ", (unsigned char)(VectorSize)); + count = VectorSize; + } + else if (prop.type == NNP_LIST_INT8_UINT32 || prop.type == NNP_LIST_INT8_INT32) + { + fprintf(fp, "%d ", (char)(VectorSize)); + count = VectorSize; + } + + unsigned char* baseProp = (unsigned char*)base + this->curPos*sizeof(ContainerType); + for (int i = 0; i < std::min(VectorSize, count); i++) + fprintf(fp, format, (C)(*(ScalarType*)(baseProp + i*sizeof(ScalarType)))); + for (int i = 0; i < (count - VectorSize); i++) + fprintf(fp, format, (C)(0)); + ++(this->curPos); + } + + template + bool VectorDescriptor::WriteElemAscii(FILE *fp, PlyProperty& prop) + { + if (prop.elem != elem) + return false; + + switch(prop.type) + { + case NNP_INT8: this->WriteAscii(fp, prop, "%d "); break; + case NNP_UINT8: this->WriteAscii(fp, prop, "%u "); break; + case NNP_INT16: this->WriteAscii(fp, prop, "%d "); break; + case NNP_UINT16: this->WriteAscii(fp, prop, "%u "); break; + case NNP_FLOAT32: this->WriteAscii(fp, prop, "%f "); break; + case NNP_INT32: this->WriteAscii(fp, prop, "%d "); break; + case NNP_UINT32: this->WriteAscii(fp, prop, "%u "); break; + case NNP_FLOAT64: this->WriteAscii(fp, prop, "%f "); break; + case NNP_LIST_UINT8_UINT32: + case NNP_LIST_INT8_UINT32: this->WriteAscii(fp, prop, "%u "); break; + case NNP_LIST_UINT8_INT32: + case NNP_LIST_INT8_INT32: this->WriteAscii(fp, prop, "%d "); break; + } + return true; + } + + + + + /** + * @cond HIDDEN_SYMBOLS + */ + template + void ReadBinaryElement(TupleType &adaptor, PlyElement &elem, FILE *fp, bool bigEndian) + { + for (int i = 0 ; i < elem.cnt; i++) + { + for (int j = 0; j < elem.propVec.size(); j++) + { + PlyProperty& prop = elem.propVec[j]; + if (!TupleForEach(adaptor, fp, prop, bigEndian, SizeT<0>())) + prop.SkipBinaryPropertyInFile(fp); + } + } + } + + + template + void ReadAsciiElement(TupleType &adaptor, PlyElement &elem, FILE *fp) + { + for (int i = 0 ; i < elem.cnt; i++) + { + for (int j = 0; j < elem.propVec.size(); j++) + { + PlyProperty& prop = elem.propVec[j]; + if (!TupleForEach(adaptor, fp, prop, false, SizeT<1>())) + prop.SkipAsciiPropertyInFile(fp); + } + } + } + /** + * @endcond + */ + + + + /** + * Read a point cloud from a PLY file. + * + * @tparam VertexAdaptorTuple Type that defines the management of the vertex data in memory + * + * @param filename Path to the file to read + * @param vertexAdaptor std::tuple that defines how to manage the vertex data in memory + */ + template + bool OpenPointCloud(const char *filename, VertexAdaptorTuple vertexAdaptor) + { + nanoply::Info info(filename); + if (info.errInfo != NNP_OK) + return false; + FILE *fp=fopen(filename,"rb"); + if(!fp) + { + return false; + } + char buf[4096]; + do + { + fgets(buf,4096,fp); + } + while(strncmp(buf,"end_header",strlen("end_header")) ); + // Now start the real reading! + + if (info.binary) + { + for(int i = 0; i < info.elemVec.size();++i) + if (strcmp(info.elemVec[i].name.c_str(), "vertex") == 0) + ReadBinaryElement(vertexAdaptor, info.elemVec[i], fp, info.bigEndian); + else + info.elemVec[i].SkipBinaryElementsInFile(fp); + } + else + { + for(int i = 0; i < info.elemVec.size();++i) + if (strcmp(info.elemVec[i].name.c_str(), "vertex") == 0) + ReadAsciiElement(vertexAdaptor, info.elemVec[i], fp); + else + info.elemVec[i].SkipAsciiElementsInFile(fp); + } + return true; + } + + + /** + * Read a mesh from a PLY file. + * + * @tparam VertexAdaptorTuple Type that defines the management of the vertex data in memory + * @tparam FaceAdaptorTuple Type that defines the management of the face data in memory + * + * @param filename Path to the file to read + * @param vertexAdaptor std::tuple that defines how to manage the vertex data in memory + * @param faceAdaptor std::tuple that defines how to manage the face data in memory + */ + template + bool OpenMesh(const char *filename, VertexAdaptorTuple vertexAdaptor, FaceAdaptorTuple faceAdaptor) + { + nanoply::Info info(filename); + if (info.errInfo != NNP_OK) + return false; + FILE *fp=fopen(filename,"rb"); + if(!fp) + { + return false; + } + char buf[4096]; + do + { + fgets(buf,4096,fp); + } + while(strncmp(buf,"end_header",strlen("end_header")) ); + // Now start the real reading! + + if (info.binary) + { + for(int i = 0; i < info.elemVec.size();++i) + { + if (strcmp(info.elemVec[i].name.c_str(), "vertex") == 0) + ReadBinaryElement(vertexAdaptor, info.elemVec[i], fp, info.bigEndian); + else if (strcmp(info.elemVec[i].name.c_str(), "face") == 0) + ReadBinaryElement(faceAdaptor, info.elemVec[i], fp, info.bigEndian); + else + info.elemVec[i].SkipBinaryElementsInFile(fp); + } + } + else + { + for(int i = 0; i < info.elemVec.size();++i) + { + if (strcmp(info.elemVec[i].name.c_str(), "vertex") == 0) + ReadAsciiElement(vertexAdaptor, info.elemVec[i], fp); + else if (strcmp(info.elemVec[i].name.c_str(), "face") == 0) + ReadAsciiElement(faceAdaptor, info.elemVec[i], fp); + else + info.elemVec[i].SkipAsciiElementsInFile(fp); + } + } + } + + + + /** + * @cond HIDDEN_SYMBOLS + */ + template + void WriteBinaryElement(TupleType &adaptor, PlyElement &elem, FILE *fp) + { + for (int i = 0 ; i < elem.cnt; i++) + { + for (int j = 0; j < elem.propVec.size(); j++) + { + PlyProperty& prop = elem.propVec[j]; + TupleForEach(adaptor, fp, prop, false, SizeT<2>()); + } + } + } + + + template + void WriteAsciiElement(TupleType &adaptor, PlyElement &elem, FILE *fp) + { + for (int i = 0 ; i < elem.cnt; i++) + { + for (int j = 0; j < elem.propVec.size(); j++) + { + PlyProperty& prop = elem.propVec[j]; + TupleForEach(adaptor, fp, prop, false, SizeT<3>()); + } + fprintf(fp, "\n"); + } + } + + /** + * @endcond + */ + + + /** + * Save a point cloud from a PLY file. + * + * @tparam VertexAdaptorTuple Type that defines the management of the vertex data in memory + * + * @param filename Path to the file to save + * @param vertexAdaptor std::tuple that defines how to manage the vertex data in memory + * @param info Info to saved in the PLY header + */ + template + bool SavePointCloud(const char *filename, VertexAdaptorTuple vertexAdaptor, nanoply::Info &info) + { + FILE *fp=fopen(filename,"wb"); + if(!fp) + { + return false; + } + fprintf(fp, "ply\n"); + if (info.binary) + fprintf(fp, "format binary_little_endian 1.0\n"); + else + fprintf(fp, "format ascii 1.0\n"); + + for (int i = 0; i < info.elemVec.size(); i++) + { + if (strcmp(info.elemVec[i].name.c_str(), "vertex") != 0) + { + info.elemVec[i].cnt = 0; + info.elemVec[i].WriteHeader(fp); + } + else + info.elemVec[i].WriteHeader(fp); + } + + fprintf(fp, "end_header\n"); + + if (info.binary) + { + for(int i = 0; i < info.elemVec.size();++i) + if (strcmp(info.elemVec[i].name.c_str(), "vertex") == 0) + WriteBinaryElement(vertexAdaptor, info.elemVec[i], fp); + } + else + { + for(int i = 0; i < info.elemVec.size();++i) + if (strcmp(info.elemVec[i].name.c_str(), "vertex") == 0) + WriteAsciiElement(vertexAdaptor, info.elemVec[i], fp); + } + + fclose(fp); + return true; + } + + + /** + * Save a mesh from a PLY file. + * + * @tparam VertexAdaptorTuple Type that defines the management of the vertex data in memory + * @tparam FaceAdaptorTuple Type that defines the management of the face data in memory + * + * @param filename Path to the file to save + * @param vertexAdaptor std::tuple that defines how to manage the vertex data in memory + * @param faceAdaptor std::tuple that defines how to manage the face data in memory + * @param info Info to saved in the PLY header + */ + template + bool SaveMesh(const char *filename, VertexAdaptorTuple vertexAdaptor, FaceAdaptorTuple faceAdaptor, nanoply::Info &info) + { + FILE *fp=fopen(filename,"wb"); + if(!fp) + { + return false; + } + fprintf(fp, "ply\n"); + if (info.binary) + fprintf(fp, "format binary_little_endian 1.0\n"); + else + fprintf(fp, "format ascii 1.0\n"); + + for (int i = 0; i < info.elemVec.size(); i++) + { + if (strcmp(info.elemVec[i].name.c_str(), "vertex") != 0 && strcmp(info.elemVec[i].name.c_str(), "face") != 0) + { + info.elemVec[i].cnt = 0; + info.elemVec[i].WriteHeader(fp); + } + else + info.elemVec[i].WriteHeader(fp); + } + + fprintf(fp, "end_header\n"); + + if (info.binary) + { + for(int i = 0; i < info.elemVec.size();++i) + { + if (strcmp(info.elemVec[i].name.c_str(), "vertex") == 0) + WriteBinaryElement(vertexAdaptor, info.elemVec[i], fp); + else if (strcmp(info.elemVec[i].name.c_str(), "face") == 0) + WriteBinaryElement(faceAdaptor, info.elemVec[i], fp); + } + } + else + { + for(int i = 0; i < info.elemVec.size();++i) + { + if (strcmp(info.elemVec[i].name.c_str(), "vertex") == 0) + WriteAsciiElement(vertexAdaptor, info.elemVec[i], fp); + else if (strcmp(info.elemVec[i].name.c_str(), "face") == 0) + WriteAsciiElement(faceAdaptor, info.elemVec[i], fp); + } + } + + fclose(fp); + return true; + } + + + + /** + * @cond HIDDEN_SYMBOLS + */ + template < typename TupleType, size_t ActionType> + inline bool TupleForEach( TupleType &tuple, FILE *fp, PlyProperty &pro, bool bigEndian, SizeT a) + { + return TupleForEach( tuple, pro, fp, bigEndian, SizeT::value>(), a); + } + + template < typename TupleType, size_t ActionType> + inline bool TupleForEach( TupleType &tuple, PlyProperty &pro, FILE *fp, bool bigEndian, SizeT<0> t, SizeT a) {return false; } + + template < typename TupleType, size_t N, size_t ActionType> + inline bool TupleForEach( TupleType &tuple, PlyProperty &pro, FILE *fp, bool bigEndian, SizeT t, SizeT a) + { + typename std::tuple_element::type &dataDescr = std::get(tuple); + if (ActionType == 0) + { + if (dataDescr.ReadElemBinary(fp, pro, bigEndian)) + return true; + } + else if (ActionType == 1) + { + if (dataDescr.ReadElemAscii(fp, pro)) + return true; + } + else if (ActionType == 2) + { + if (dataDescr.WriteElemBinary(fp, pro)) + return true; + } + else if (ActionType == 3) + { + if (dataDescr.WriteElemAscii(fp, pro)) + return true; + } + return TupleForEach( tuple, pro, fp, bigEndian, SizeT(), a); + } + + /** + * @endcond + */ } // end namespace nanoply #endif // NANOPLY_HPP