00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifndef NANOPLY_HPP
00017 #define NANOPLY_HPP
00018
00019 #include <vector>
00020 #include <unordered_map>
00021 #include <tuple>
00022 #include <cassert>
00023 #include <algorithm>
00024 #include <stdexcept>
00025 #include <cstdio>
00026 #include <cmath>
00027 #include <limits>
00028 #include <fstream>
00029 #include <sstream>
00030 #include <stdint.h>
00031 #include <string>
00032
00033
00034
00035 #if !defined(NOMINMAX) && (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64))
00036 # define NOMINMAX
00037 # ifdef max
00038 # undef max
00039 # undef min
00040 # endif
00041 #endif
00042
00043 namespace nanoply
00044 {
00045
00049 typedef enum NNP_ERROR
00050 {
00051 NNP_OK = 0x0000,
00052 NNP_UNABLE_TO_OPEN = 0x0001,
00053 NNP_MISSING_HEADER = 0x0002,
00054 NNP_MISSING_FORMAT = 0x0004,
00055 NNP_INVALID_ELEMENT = 0x0008,
00056 NNP_INVALID_PROPERTY = 0x0010
00057 } ErrorCode;
00058
00059
00063 typedef enum NNP_ELEM
00064 {
00065 NNP_UNKNOWN_ELEM = 0x0,
00066 NNP_VERTEX_ELEM = 0x1,
00067 NNP_EDGE_ELEM = 0x2,
00068 NNP_FACE_ELEM = 0x4
00069 } PlyElemEntity;
00070
00071
00075 typedef enum NNP_ENTITY
00076 {
00077 NNP_UNKNOWN_ENTITY = 0x00000000,
00078 NNP_PX = 0x00000001,
00079 NNP_PY = 0x00000002,
00080 NNP_PZ = 0x00000004,
00081 NNP_PXYZ = 0x00000007,
00082 NNP_NX = 0x00000010,
00083 NNP_NY = 0x00000020,
00084 NNP_NZ = 0x00000040,
00085 NNP_NXYZ = 0x00000070,
00086 NNP_CR = 0x00000100,
00087 NNP_CG = 0x00000200,
00088 NNP_CB = 0x00000400,
00089 NNP_CRGB = 0x00000700,
00090 NNP_CA = 0x00000800,
00091 NNP_CRGBA = 0x00000F00,
00092 NNP_DENSITY = 0x00000008,
00093 NNP_SCALE = 0x00000080,
00094 NNP_TEXTUREU = 0x00001000,
00095 NNP_TEXTUREV = 0x00002000,
00096 NNP_TEXTURE2D = 0x00003000,
00097 NNP_TEXTUREW = 0x00004000,
00098 NNP_TEXTURE3D = 0x00007000,
00099 NNP_TEXTUREINDEX = 0x00008000,
00100 NNP_QUALITY = 0x00010000,
00101 NNP_REFLECTANCE = 0x00020000,
00102 NNP_BITFLAG = 0x00040000,
00103 NNP_K1 = 0x00080000,
00104 NNP_K2 = 0x00100000,
00105 NNP_KG = 0x00200000,
00106 NNP_KH = 0x00400000,
00107 NNP_K1DIR = 0x00800000,
00108 NNP_K2DIR = 0x01000000,
00109 NNP_EDGE_V1 = 0x02000000,
00110 NNP_EDGE_V2 = 0x04000000,
00111 NNP_FACE_VERTEX_LIST = 0x08000000,
00112 NNP_FACE_WEDGE_COLOR = 0x10000000,
00113 NNP_FACE_WEDGE_NORMAL = 0x20000000,
00114 NNP_FACE_WEDGE_TEX = 0x40000000
00115 } PlyEntity;
00116
00117
00121 typedef enum NNP_PLYTYPE
00122 {
00123 NNP_UNKNOWN_TYPE = 0x000000,
00124 NNP_FLOAT32 = 0x000001,
00125 NNP_FLOAT64 = 0x000002,
00126 NNP_INT8 = 0x000004,
00127 NNP_INT16 = 0x000008,
00128 NNP_INT32 = 0x000010,
00129 NNP_UINT8 = 0x000020,
00130 NNP_UINT16 = 0x000040,
00131 NNP_UINT32 = 0x000080,
00132 NNP_LIST_UINT8_UINT32 = 0x000100,
00133 NNP_LIST_INT8_UINT32 = 0x000200,
00134 NNP_LIST_UINT8_INT32 = 0x000400,
00135 NNP_LIST_INT8_INT32 = 0x000800,
00136 NNP_LIST_UINT8_FLOAT32 = 0x001000,
00137 NNP_LIST_INT8_FLOAT32 = 0x002000,
00138 NNP_LIST_UINT8_FLOAT64 = 0x004000,
00139 NNP_LIST_INT8_FLOAT64 = 0x008000,
00140 NNP_LIST_UINT8_UINT8 = 0x010000,
00141 NNP_LIST_INT8_UINT8 = 0x020000,
00142 NNP_LIST_UINT8_INT8 = 0x040000,
00143 NNP_LIST_INT8_INT8 = 0x080000,
00144 NNP_LIST_UINT8_UINT16 = 0x100000,
00145 NNP_LIST_INT8_UINT16 = 0x200000,
00146 NNP_LIST_UINT8_INT16 = 0x400000,
00147 NNP_LIST_INT8_INT16 = 0x800000
00148 } PlyType;
00149
00150
00154 template < size_t T> struct SizeT {};
00155
00156 typedef std::vector<std::string> NameVector;
00157 typedef std::unordered_map<PlyType, NameVector> TypeMap;
00158 typedef std::unordered_map<PlyType, NameVector>::iterator TypeMapIterator;
00159 typedef std::unordered_map<PlyEntity, NameVector> EntityMap;
00160 typedef std::unordered_map<PlyEntity, NameVector>::iterator EntityMapIterator;
00161 typedef std::unordered_map<PlyElemEntity, NameVector> ElementMap;
00162 typedef std::unordered_map<PlyElemEntity, NameVector>::iterator ElementMapIterator;
00163
00164 static NameVector emptyVec;
00165
00166
00167 static TypeMap mapType({
00168 { PlyType::NNP_UNKNOWN_TYPE, NameVector({ "unknonw" }) },
00169 { PlyType::NNP_FLOAT32, NameVector({ "float", "float32" }) },
00170 { PlyType::NNP_FLOAT64, NameVector({ "double", "float64" }) },
00171 { PlyType::NNP_INT8, NameVector({ "char", "int8" }) },
00172 { PlyType::NNP_INT16, NameVector({ "short", "int16" }) },
00173 { PlyType::NNP_INT32, NameVector({ "int", "int32" }) },
00174 { PlyType::NNP_UINT8, NameVector({ "uchar", "uint8" }) },
00175 { PlyType::NNP_UINT16, NameVector({ "ushort", "uint16" }) },
00176 { PlyType::NNP_UINT32, NameVector({ "uint", "uint32" }) },
00177 { PlyType::NNP_LIST_UINT8_UINT32, NameVector({ "list uchar uint", "list uint8 uint32" }) },
00178 { PlyType::NNP_LIST_INT8_UINT32, NameVector({ "list char uint", "list int8 uint32" }) },
00179 { PlyType::NNP_LIST_UINT8_INT32, NameVector({ "list uchar int", "list uint8 int32" }) },
00180 { PlyType::NNP_LIST_INT8_INT32, NameVector({ "list char int", "list int8 int32" }) },
00181 { PlyType::NNP_LIST_UINT8_FLOAT32, NameVector({ "list uchar float", "list uint8 float32" }) },
00182 { PlyType::NNP_LIST_INT8_FLOAT32, NameVector({ "list char float", "list int8 float32" }) },
00183 { PlyType::NNP_LIST_UINT8_FLOAT64, NameVector({ "list uchar double", "list uint8 float64" }) },
00184 { PlyType::NNP_LIST_INT8_FLOAT64, NameVector({ "list char double", "list int8 float64" }) },
00185 { PlyType::NNP_LIST_UINT8_UINT8, NameVector({ "list uchar uchar", "list uint8 uint8" }) },
00186 { PlyType::NNP_LIST_INT8_UINT8, NameVector({ "list char uchar", "list int8 uint8" }) },
00187 { PlyType::NNP_LIST_UINT8_INT8, NameVector({ "list uchar char", "list uint8 int8" }) },
00188 { PlyType::NNP_LIST_INT8_INT8, NameVector({ "list char char", "list int8 int8" }) },
00189 { PlyType::NNP_LIST_UINT8_UINT16, NameVector({ "list uchar ushort", "list uint8 uint16" }) },
00190 { PlyType::NNP_LIST_INT8_UINT16, NameVector({ "list char ushort", "list int8 uint16" }) },
00191 { PlyType::NNP_LIST_UINT8_INT16, NameVector({ "list uchar short", "list uint8 int16" }) },
00192 { PlyType::NNP_LIST_INT8_INT16, NameVector({ "list char short", "list int8 int16" }) }
00193 });
00194
00195
00196
00197 static EntityMap mapProp({
00198 { PlyEntity::NNP_UNKNOWN_ENTITY, NameVector({ "unknonw" }) },
00199 { PlyEntity::NNP_PX, NameVector({ "x", "px", "posx" }) },
00200 { PlyEntity::NNP_PY, NameVector({ "y", "py", "posy" }) },
00201 { PlyEntity::NNP_PZ, NameVector({ "z", "pz", "posz" }) },
00202 { PlyEntity::NNP_PXYZ, NameVector({ "x y z", "px py pz", "posx posy posz" }) },
00203 { PlyEntity::NNP_NX, NameVector({ "nx", "normalx" }) },
00204 { PlyEntity::NNP_NY, NameVector({ "ny", "normaly" }) },
00205 { PlyEntity::NNP_NZ, NameVector({ "nz", "normalz" }) },
00206 { PlyEntity::NNP_NXYZ, NameVector({ "nx ny nz", "normalx normaly normalz" }) },
00207 { PlyEntity::NNP_CR, NameVector({ "red", "diffuse_red", "r", "diffuse_r" }) },
00208 { PlyEntity::NNP_CG, NameVector({ "green", "diffuse_green", "g", "diffuse_g" }) },
00209 { PlyEntity::NNP_CB, NameVector({ "blue", "diffuse_blue", "b", "diffuse_b" }) },
00210 { PlyEntity::NNP_CA, NameVector({ "alpha", "diffuse_alpha", "a", "diffuse_a" }) },
00211 { PlyEntity::NNP_CRGB, NameVector({ "rgb", "diffuse_rgb" }) },
00212 { PlyEntity::NNP_CRGBA, NameVector({ "rgba", "diffuse_rgba" }) },
00213 { PlyEntity::NNP_DENSITY, NameVector({ "radius", "density" }) },
00214 { PlyEntity::NNP_SCALE, NameVector({ "scale", "value" }) },
00215 { PlyEntity::NNP_TEXTUREU, NameVector({ "texture_u", "u", "s" }) },
00216 { PlyEntity::NNP_TEXTUREV, NameVector({ "texture_v", "v", "t" }) },
00217 { PlyEntity::NNP_TEXTURE2D, NameVector({ "texture_uv", "uv" }) },
00218 { PlyEntity::NNP_TEXTUREW, NameVector({ "texture_w", "w" }) },
00219 { PlyEntity::NNP_TEXTURE3D, NameVector({ "texture_uvw", "uvw" }) },
00220 { PlyEntity::NNP_TEXTUREINDEX, NameVector({ "texnumber", "texid" }) },
00221 { PlyEntity::NNP_QUALITY, NameVector({ "quality", "confidence" }) },
00222 { PlyEntity::NNP_REFLECTANCE, NameVector({ "reflectance" }) },
00223 { PlyEntity::NNP_BITFLAG, NameVector({ "flags" }) },
00224 { PlyEntity::NNP_K1, NameVector({ "k1" }) },
00225 { PlyEntity::NNP_K2, NameVector({ "k2" }) },
00226 { PlyEntity::NNP_KG, NameVector({ "k" }) },
00227 { PlyEntity::NNP_KH, NameVector({ "h" }) },
00228 { PlyEntity::NNP_K1DIR, NameVector({ "k1dir" }) },
00229 { PlyEntity::NNP_K2DIR, NameVector({ "k2dir" }) },
00230 { PlyEntity::NNP_EDGE_V1, NameVector({ "vertex1", "v1" }) },
00231 { PlyEntity::NNP_EDGE_V2, NameVector({ "vertex2", "v2" }) },
00232 { PlyEntity::NNP_FACE_VERTEX_LIST, NameVector({ "vertex_index", "vertex_indices" }) },
00233 { PlyEntity::NNP_FACE_WEDGE_COLOR, NameVector({ "color" }) },
00234 { PlyEntity::NNP_FACE_WEDGE_NORMAL, NameVector({ "normal" }) },
00235 { PlyEntity::NNP_FACE_WEDGE_TEX, NameVector({ "texcoord" }) }
00236 });
00237
00238
00239
00240 static ElementMap mapElem({
00241 { PlyElemEntity::NNP_UNKNOWN_ELEM, NameVector({ "unknonw" }) },
00242 { PlyElemEntity::NNP_VERTEX_ELEM, NameVector({ "vertex" }) },
00243 { PlyElemEntity::NNP_EDGE_ELEM, NameVector({ "edge" }) },
00244 { PlyElemEntity::NNP_FACE_ELEM, NameVector({ "face" }) },
00245 });
00246
00247
00248
00249 static const NameVector& PlyPropertyName(PlyEntity ent)
00250 {
00251 if (mapProp.find(ent) != mapProp.end())
00252 return mapProp[ent];
00253 return emptyVec;
00254 };
00255
00256
00257
00258 static const NameVector& PlyTypeName(PlyType ent)
00259 {
00260 if (mapType.find(ent) != mapType.end())
00261 return mapType[ent];
00262 return emptyVec;
00263 };
00264
00265
00266
00267 static const NameVector& PlyElementName(PlyElemEntity ent)
00268 {
00269 if (mapElem.find(ent) != mapElem.end())
00270 return mapElem[ent];
00271 return emptyVec;
00272 };
00273
00274
00275
00276 int checkEndianness()
00277 {
00278 unsigned int x = 1;
00279 char *c = (char*)&x;
00280 return (int)*c;
00281 };
00282
00283
00284 void adjustEndianess(unsigned char* buffer, int typeSize, int count)
00285 {
00286 for (int i = 0; i < count; i++)
00287 {
00288 int offset = i*typeSize;
00289 for (int j = 0; j < typeSize / 2; j++)
00290 {
00291 unsigned char temp = buffer[offset + j];
00292 buffer[offset + j] = buffer[offset + typeSize - 1 - j];
00293 buffer[offset + typeSize - 1 - j] = temp;
00294 }
00295 }
00296 }
00306 class PlyFile
00307 {
00308 private:
00309 std::fstream fileStream;
00310 char mode;
00312 int64_t bufferSize;
00313 int64_t bufferOffset;
00314 int64_t maxSize;
00315 char* buffer;
00317 public:
00318
00319 PlyFile();
00320
00321 ~PlyFile();
00322
00329 bool OpenFileToRead(const std::string &filename);
00330
00337 bool OpenFileToWrite(const std::string &filename);
00338
00346 bool NextHeaderLine(std::string &line, bool &last);
00347
00354 bool WriteHeaderLine(std::string &line);
00355
00363 bool ReadBinaryData(void *dest, int nByte);
00364
00371 template <typename T>
00372 bool ReadAsciiData(T &dest);
00373
00381 bool WriteBinaryData(void *src, int nByte);
00382
00389 template <typename T>
00390 bool WriteAsciiData(T &src);
00391
00397 void SetBufferSize(int64_t size);
00398
00402 void Flush();
00403 };
00404
00405
00406 PlyFile::PlyFile()
00407 {
00408 buffer = NULL;
00409 maxSize = 1000000;
00410 mode = -1;
00411 }
00412
00413
00414 PlyFile::~PlyFile()
00415 {
00416 Flush();
00417 if (buffer != NULL)
00418 delete[] buffer;
00419 if (fileStream.is_open())
00420 fileStream.close();
00421 }
00422
00423
00424 bool PlyFile::OpenFileToRead(const std::string& filename)
00425 {
00426 if (fileStream.is_open())
00427 fileStream.close();
00428 mode = 0;
00429 fileStream.open(filename, std::fstream::in | std::fstream::binary);
00430 if (fileStream.fail())
00431 return false;
00432 bufferOffset = 0;
00433 return true;
00434 }
00435
00436
00437 bool PlyFile::OpenFileToWrite(const std::string& filename)
00438 {
00439 if (fileStream.is_open())
00440 fileStream.close();
00441 mode = 1;
00442 fileStream.open(filename, std::fstream::out | std::fstream::binary);
00443 if (fileStream.fail())
00444 return false;
00445 bufferOffset = 0;
00446
00447
00448 return true;
00449 }
00450
00451
00452 bool PlyFile::NextHeaderLine(std::string& line, bool& last)
00453 {
00454 if (mode != 0)
00455 return false;
00456 std::getline(fileStream, line);
00457 std::transform(line.begin(), line.end(), line.begin(), ::tolower);
00458 last = false;
00459 if (line == "end_header")
00460 last = true;
00461 return true;
00462 }
00463
00464
00465 bool PlyFile::WriteHeaderLine(std::string& line)
00466 {
00467 if (mode != 1)
00468 return false;
00469 fileStream << line;
00470 return true;
00471 }
00472
00473
00474 bool PlyFile::ReadBinaryData(void* dest, int nByte)
00475 {
00476 if (mode != 0)
00477 return false;
00478 if (buffer == NULL)
00479 {
00480 buffer = new char[maxSize];
00481 fileStream.read(buffer, maxSize);
00482 bufferSize = fileStream.gcount();
00483 bufferOffset = 0;
00484 }
00485 else if (bufferOffset + nByte > bufferSize)
00486 {
00487 unsigned int lastByte = bufferSize - bufferOffset;
00488 memcpy(buffer, &buffer[bufferOffset], lastByte);
00489 fileStream.read(&buffer[lastByte], maxSize - lastByte);
00490 bufferSize = fileStream.gcount() + lastByte;
00491 bufferOffset = 0;
00492 }
00493 memcpy(dest, &buffer[bufferOffset], nByte);
00494 bufferOffset += nByte;
00495 return true;
00496 }
00497
00498
00499 template <typename T>
00500 bool PlyFile::ReadAsciiData(T& dest)
00501 {
00502 if (mode != 0)
00503 return false;
00504 fileStream >> dest;
00505 return true;
00506 }
00507
00508 bool PlyFile::WriteBinaryData(void* src, int nByte)
00509 {
00510 if (mode != 1)
00511 return false;
00512 if (buffer == NULL)
00513 {
00514 buffer = new char[maxSize];
00515 bufferSize = maxSize;
00516 bufferOffset = 0;
00517 }
00518 else if (bufferOffset + nByte > bufferSize)
00519 {
00520 fileStream.write(buffer, bufferOffset);
00521 bufferOffset = 0;
00522 }
00523 memcpy(&buffer[bufferOffset], src, nByte);
00524 bufferOffset += nByte;
00525 return true;
00526 }
00527
00528
00529 template <typename T>
00530 bool PlyFile::WriteAsciiData(T& src)
00531 {
00532 if (mode != 1)
00533 return false;
00534 fileStream << src;
00535 return true;
00536 }
00537
00538 void PlyFile::SetBufferSize(int64_t size)
00539 {
00540 maxSize = size;
00541 }
00542
00543
00544 void PlyFile::Flush()
00545 {
00546 if (mode == 1)
00547 fileStream.write(buffer, bufferOffset);
00548 }
00549
00550
00551
00552
00556 class PlyProperty
00557 {
00558 public:
00559
00560 std::string name;
00561 PlyType type;
00562 PlyEntity elem;
00563 bool validToWrite;
00571 PlyProperty(PlyType _t, PlyEntity _e) :type(_t), elem(_e), name(PlyPropertyName(_e)[0]), validToWrite(false){}
00572
00580 PlyProperty(PlyType _t, PlyEntity _e, std::string _n) :type(_t), elem(_e), name(_n), validToWrite(false){}
00581
00588 PlyProperty(PlyType _t, std::string _n) :type(_t), elem(PlyEntity::NNP_UNKNOWN_ENTITY), name(_n), validToWrite(false){}
00589
00595 const char* EntityStr();
00596
00602 const char* EntityName();
00603
00609 const char* TypeStr();
00610
00616 int TypeSize();
00617
00623 int CountValue();
00624
00630 bool IsSigned();
00631
00638 bool SkipAsciiPropertyInFile(PlyFile &file);
00639
00646 bool SkipBinaryPropertyInFile(PlyFile &file);
00647
00654 bool WriteHeader(PlyFile &file);
00655 };
00656
00657
00658 const char* PlyProperty::EntityStr()
00659 {
00660 switch (this->elem)
00661 {
00662 case NNP_UNKNOWN_ENTITY: return "NNP_UNKNOWN_ENTITY ";
00663 case NNP_PX: return "NNP_PX ";
00664 case NNP_PY: return "NNP_PY ";
00665 case NNP_PZ: return "NNP_PZ ";
00666 case NNP_PXYZ: return "NNP_PXYZ ";
00667 case NNP_NX: return "NNP_NX ";
00668 case NNP_NY: return "NNP_NY ";
00669 case NNP_NZ: return "NNP_NZ ";
00670 case NNP_NXYZ: return "NNP_NXYZ ";
00671 case NNP_CR: return "NNP_CR ";
00672 case NNP_CG: return "NNP_CG ";
00673 case NNP_CB: return "NNP_CB ";
00674 case NNP_CRGB: return "NNP_CRGB ";
00675 case NNP_CA: return "NNP_CA ";
00676 case NNP_CRGBA: return "NNP_CRGBA ";
00677 case NNP_DENSITY: return "NNP_DENSITY ";
00678 case NNP_SCALE: return "NNP_SCALE ";
00679 case NNP_QUALITY: return "NNP_QUALITY ";
00680 case NNP_REFLECTANCE: return "NNP_REFLECTANCE ";
00681 case NNP_TEXTUREU: return "NNP_TEXTUREU ";
00682 case NNP_TEXTUREV: return "NNP_TEXTUREV ";
00683 case NNP_TEXTURE2D: return "NNP_TEXTURE2D ";
00684 case NNP_TEXTUREW: return "NNP_TEXTUREW ";
00685 case NNP_TEXTURE3D: return "NNP_TEXTURE3D ";
00686 case NNP_TEXTUREINDEX: return "NNP_TEXTUREINDEX ";
00687 case NNP_BITFLAG: return "NNP_BITFLAG ";
00688 case NNP_K1: return "NNP_K1 ";
00689 case NNP_K2: return "NNP_K2 ";
00690 case NNP_KG: return "NNP_K ";
00691 case NNP_KH: return "NNP_H ";
00692 case NNP_K1DIR: return "NNP_K1DIR ";
00693 case NNP_K2DIR: return "NNP_K2DIR ";
00694 case NNP_EDGE_V1: return "NNP_EDGE_V1 ";
00695 case NNP_EDGE_V2: return "NNP_EDGE_V2 ";
00696 case NNP_FACE_VERTEX_LIST: return "NNP_FACE_VERTEX_LIST ";
00697 case NNP_FACE_WEDGE_COLOR: return "NNP_FACE_WEDGE_COLOR ";
00698 case NNP_FACE_WEDGE_NORMAL: return "NNP_FACE_WEDGE_NORMAL";
00699 case NNP_FACE_WEDGE_TEX: return "NNP_FACE_WEDGE_TEX ";
00700
00701 default: assert(0);
00702 break;
00703 }
00704 return 0;
00705 }
00706
00707
00708 const char* PlyProperty::EntityName()
00709 {
00710
00711 if (this->elem == PlyEntity::NNP_UNKNOWN_ENTITY)
00712 return (*this).name.c_str();
00713 #ifdef USE_NOSTANDARDPLY_OUTPUT
00714 if (this->elem == PlyEntity::NNP_SCALE)
00715 return PlyPropertyName(this->elem)[1].c_str();
00716 if (this->elem == PlyEntity::NNP_QUALITY)
00717 return PlyPropertyName(this->elem)[1].c_str();
00718 if (this->elem == PlyEntity::NNP_CR)
00719 return PlyPropertyName(this->elem)[1].c_str();
00720 if (this->elem == PlyEntity::NNP_CB)
00721 return PlyPropertyName(this->elem)[1].c_str();
00722 if (this->elem == PlyEntity::NNP_CG)
00723 return PlyPropertyName(this->elem)[1].c_str();
00724 if (this->elem == PlyEntity::NNP_CA)
00725 return PlyPropertyName(this->elem)[1].c_str();
00726 #endif
00727 const std::vector<std::string>& vect = PlyPropertyName(this->elem);
00728 if (vect.size() > 0)
00729 return vect[0].c_str();
00730 assert(0);
00731 return 0;
00732 }
00733
00734
00735 const char* PlyProperty::TypeStr()
00736 {
00737 switch (this->type)
00738 {
00739 case NNP_UNKNOWN_TYPE: return "NNP_UNKNOWN_TYPE ";
00740 case NNP_FLOAT32: return "NNP_FLOAT32 ";
00741 case NNP_FLOAT64: return "NNP_FLOAT64 ";
00742 case NNP_INT8: return "NNP_INT8 ";
00743 case NNP_INT16: return "NNP_INT16 ";
00744 case NNP_INT32: return "NNP_INT32 ";
00745 case NNP_UINT8: return "NNP_UINT8 ";
00746 case NNP_UINT16: return "NNP_UINT16 ";
00747 case NNP_UINT32: return "NNP_UINT32 ";
00748 case NNP_LIST_UINT8_UINT32: return "NNP_LIST_UINT8_UINT32 ";
00749 case NNP_LIST_INT8_UINT32: return "NNP_LIST_INT8_UINT32 ";
00750 case NNP_LIST_UINT8_INT32: return "NNP_LIST_UINT8_INT32 ";
00751 case NNP_LIST_INT8_INT32: return "NNP_LIST_INT8_INT32 ";
00752 case NNP_LIST_UINT8_FLOAT32: return "NNP_LIST_UINT8_FLOAT32 ";
00753 case NNP_LIST_INT8_FLOAT32: return "NNP_LIST_INT8_FLOAT32 ";
00754 case NNP_LIST_UINT8_FLOAT64: return "NNP_LIST_UINT8_FLOAT64 ";
00755 case NNP_LIST_INT8_FLOAT64: return "NNP_LIST_INT8_FLOAT64 ";
00756 case NNP_LIST_UINT8_UINT8: return "NNP_LIST_UINT8_UINT8 ";
00757 case NNP_LIST_INT8_UINT8: return "NNP_LIST_INT8_UINT8 ";
00758 case NNP_LIST_UINT8_INT8: return "NNP_LIST_UINT8_INT8 ";
00759 case NNP_LIST_INT8_INT8: return "NNP_LIST_INT8_INT8 ";
00760 case NNP_LIST_UINT8_UINT16: return "NNP_LIST_UINT8_UINT16 ";
00761 case NNP_LIST_INT8_UINT16: return "NNP_LIST_INT8_UINT16 ";
00762 case NNP_LIST_UINT8_INT16: return "NNP_LIST_UINT8_INT16 ";
00763 case NNP_LIST_INT8_INT16: return "NNP_LIST_INT8_INT16 ";
00764 default: assert(0);
00765 break;
00766 }
00767 return 0;
00768 }
00769
00770
00771 int PlyProperty::TypeSize()
00772 {
00773 switch (this->type)
00774 {
00775 case NNP_UNKNOWN_TYPE:
00776 return 0;
00777 case NNP_INT8:
00778 case NNP_UINT8:
00779 return sizeof(char);
00780 case NNP_INT16:
00781 case NNP_UINT16:
00782 return sizeof(short);
00783 case NNP_FLOAT32:
00784 case NNP_INT32:
00785 case NNP_UINT32:
00786 return sizeof(int);
00787 case NNP_FLOAT64:
00788 return sizeof(double);
00789 case NNP_LIST_UINT8_UINT32:
00790 case NNP_LIST_INT8_UINT32:
00791 case NNP_LIST_UINT8_INT32:
00792 case NNP_LIST_INT8_INT32:
00793 return sizeof(int);
00794 case NNP_LIST_UINT8_UINT16:
00795 case NNP_LIST_INT8_UINT16:
00796 case NNP_LIST_UINT8_INT16:
00797 case NNP_LIST_INT8_INT16:
00798 return sizeof(short);
00799 case NNP_LIST_UINT8_UINT8:
00800 case NNP_LIST_INT8_UINT8:
00801 case NNP_LIST_UINT8_INT8:
00802 case NNP_LIST_INT8_INT8:
00803 return sizeof(char);
00804 case NNP_LIST_UINT8_FLOAT32:
00805 case NNP_LIST_INT8_FLOAT32:
00806 return sizeof(float);
00807 case NNP_LIST_UINT8_FLOAT64:
00808 case NNP_LIST_INT8_FLOAT64:
00809 return sizeof(double);
00810 default: assert(0);
00811 break;
00812 }
00813 return 0;
00814 }
00815
00816
00817 bool PlyProperty::IsSigned()
00818 {
00819 switch (this->type)
00820 {
00821 case NNP_INT8:
00822 case NNP_INT16:
00823 case NNP_INT32:
00824 case NNP_FLOAT32:
00825 case NNP_FLOAT64:
00826 case NNP_LIST_INT8_UINT32:
00827 case NNP_LIST_INT8_INT32:
00828 case NNP_LIST_INT8_UINT16:
00829 case NNP_LIST_INT8_INT16:
00830 case NNP_LIST_INT8_UINT8:
00831 case NNP_LIST_INT8_INT8:
00832 case NNP_LIST_INT8_FLOAT32:
00833 case NNP_LIST_INT8_FLOAT64:
00834 return true;
00835 case NNP_UINT8:
00836 case NNP_UINT16:
00837 case NNP_UINT32:
00838 case NNP_LIST_UINT8_UINT32:
00839 case NNP_LIST_UINT8_INT32:
00840 case NNP_LIST_UINT8_UINT16:
00841 case NNP_LIST_UINT8_INT16:
00842 case NNP_LIST_UINT8_UINT8:
00843 case NNP_LIST_UINT8_INT8:
00844 case NNP_LIST_UINT8_FLOAT32:
00845 case NNP_LIST_UINT8_FLOAT64:
00846 return false;
00847 default:
00848 return false;
00849 }
00850 }
00851
00852
00853 int PlyProperty::CountValue()
00854 {
00855 if (this->elem == NNP_CRGB || this->elem == NNP_NXYZ || this->elem == NNP_PXYZ || this->elem == NNP_TEXTURE3D)
00856 return 3;
00857 else if (this->elem == NNP_CRGBA)
00858 return 4;
00859 else if (this->elem == NNP_TEXTURE2D)
00860 return 2;
00861 return 1;
00862 }
00863
00864
00865 bool PlyProperty::SkipAsciiPropertyInFile(PlyFile &file)
00866 {
00867 int count = CountValue();
00868 if (this->type >= NNP_LIST_UINT8_UINT32)
00869 file.ReadAsciiData(count);
00870 switch (type)
00871 {
00872 case NNP_INT8:
00873 case NNP_INT16:
00874 case NNP_INT32:
00875 case NNP_LIST_UINT8_INT32:
00876 case NNP_LIST_INT8_INT32:
00877 case NNP_LIST_UINT8_INT16:
00878 case NNP_LIST_INT8_INT16:
00879 case NNP_LIST_UINT8_INT8:
00880 case NNP_LIST_INT8_INT8:
00881 {
00882 int* temp = new int[count];
00883 for (int i = 0; i < count; i++)
00884 file.ReadAsciiData(temp[i]);
00885 delete[] temp;
00886 break;
00887 }
00888 case NNP_UINT8:
00889 case NNP_UINT16:
00890 case NNP_UINT32:
00891 case NNP_LIST_UINT8_UINT32:
00892 case NNP_LIST_INT8_UINT32:
00893 case NNP_LIST_UINT8_UINT16:
00894 case NNP_LIST_INT8_UINT16:
00895 case NNP_LIST_UINT8_UINT8:
00896 case NNP_LIST_INT8_UINT8:
00897 {
00898 unsigned int* temp = new unsigned int[count];
00899 for (int i = 0; i < count; i++)
00900 file.ReadAsciiData(temp[i]);
00901 delete[] temp;
00902 break;
00903 }
00904 case NNP_FLOAT32:
00905 case NNP_LIST_UINT8_FLOAT32:
00906 case NNP_LIST_INT8_FLOAT32:
00907 {
00908 float* temp = new float[count];
00909 for (int i = 0; i < count; i++)
00910 file.ReadAsciiData(temp[i]);
00911 delete[] temp;
00912 break;
00913 }
00914 case NNP_FLOAT64:
00915 case NNP_LIST_UINT8_FLOAT64:
00916 case NNP_LIST_INT8_FLOAT64:
00917 {
00918 double* temp = new double[count];
00919 for (int i = 0; i < count; i++)
00920 file.ReadAsciiData(temp[i]);
00921 delete[] temp;
00922 break;
00923 }
00924 }
00925 return true;
00926 }
00927
00928
00929 bool PlyProperty::SkipBinaryPropertyInFile(PlyFile& file)
00930 {
00931 unsigned char* temp;
00932 int count = CountValue();
00933 if (this->type >= NNP_LIST_UINT8_UINT32)
00934 {
00935 int size;
00936 if (this->IsSigned())
00937 {
00938 unsigned char cntList = 0;
00939 file.ReadBinaryData(&cntList, sizeof(char));
00940 size = this->TypeSize() * cntList;
00941 }
00942 else
00943 {
00944 char cntList = 0;
00945 file.ReadBinaryData(&cntList, sizeof(char));
00946 size = this->TypeSize() * cntList;
00947 }
00948 temp = new unsigned char[size];
00949 file.ReadBinaryData(temp, size);
00950 }
00951 else
00952 {
00953 int size = this->TypeSize()*count;
00954 temp = new unsigned char[size];
00955 file.ReadBinaryData(temp, size);
00956 }
00957 delete[] temp;
00958 return true;
00959 }
00960
00961
00962 bool PlyProperty::WriteHeader(PlyFile& file)
00963 {
00964 if (!validToWrite)
00965 return true;
00966 std::string name, type;
00967 type = PlyTypeName(this->type)[0];
00968 name = this->EntityName();
00969 std::vector<std::string> v;
00970 switch (this->elem)
00971 {
00972 case NNP_PXYZ:
00973 {
00974 v.push_back(PlyPropertyName(NNP_PX)[0]);
00975 v.push_back(PlyPropertyName(NNP_PY)[0]);
00976 v.push_back(PlyPropertyName(NNP_PZ)[0]);
00977 break;
00978 }
00979 case NNP_NXYZ:
00980 {
00981 v.push_back(PlyPropertyName(NNP_NX)[0]);
00982 v.push_back(PlyPropertyName(NNP_NY)[0]);
00983 v.push_back(PlyPropertyName(NNP_NZ)[0]);
00984 break;
00985 }
00986 case NNP_CRGB:
00987 {
00988 v.push_back(PlyPropertyName(NNP_CR)[0]);
00989 v.push_back(PlyPropertyName(NNP_CG)[0]);
00990 v.push_back(PlyPropertyName(NNP_CB)[0]);
00991 break;
00992 }
00993 case NNP_CRGBA:
00994 {
00995 v.push_back(PlyPropertyName(NNP_CR)[0]);
00996 v.push_back(PlyPropertyName(NNP_CG)[0]);
00997 v.push_back(PlyPropertyName(NNP_CB)[0]);
00998 v.push_back(PlyPropertyName(NNP_CA)[0]);
00999 break;
01000 }
01001 case NNP_TEXTURE2D:
01002 {
01003 v.push_back(PlyPropertyName(NNP_TEXTUREU)[0]);
01004 v.push_back(PlyPropertyName(NNP_TEXTUREV)[0]);
01005 break;
01006 }
01007 case NNP_TEXTURE3D:
01008 {
01009 v.push_back(PlyPropertyName(NNP_TEXTUREU)[0]);
01010 v.push_back(PlyPropertyName(NNP_TEXTUREV)[0]);
01011 v.push_back(PlyPropertyName(NNP_TEXTUREW)[0]);
01012 break;
01013 }
01014 default:
01015 v.push_back(name);
01016
01017 }
01018 for (int i = 0; i < v.size(); i++)
01019 {
01020 std::stringstream s;
01021 s << "property " << type << " " << v[i] << "\n";
01022 if (!file.WriteHeaderLine(s.str()))
01023 return false;
01024 }
01025 return true;
01026 }
01027
01028
01029
01030
01034 class PlyElement
01035 {
01036 public:
01037
01038 std::string name;
01039 PlyElemEntity plyElem;
01040 size_t cnt;
01041 std::vector<PlyProperty> propVec;
01042 bool validToWrite;
01047 PlyElement() :validToWrite(false){};
01048
01056 PlyElement(std::string& _name, std::vector<PlyProperty> &prop, size_t nElem) :name(_name), cnt(nElem), propVec(prop), plyElem(PlyElemEntity::NNP_UNKNOWN_ELEM), validToWrite(false){};
01057
01065 PlyElement(PlyElemEntity ent, std::vector<PlyProperty> &prop, size_t nElem) :name(PlyElementName(ent)[0]), cnt(nElem), propVec(prop), plyElem(ent), validToWrite(false){};
01066
01074 bool AddProperty(std::string &line);
01075
01083 bool InitFromHeader(std::string &elemStr, std::vector<std::string> &propStr);
01084
01091 bool WriteHeader(PlyFile &file);
01092
01099 bool SkipAsciiElementsInFile(PlyFile &file);
01100
01107 bool SkipBinaryElementsInFile(PlyFile &file);
01108
01115 bool Contains(NNP_ENTITY entity);
01116 };
01117
01118
01119 bool PlyElement::InitFromHeader(std::string &elemStr, std::vector<std::string> &propStr)
01120 {
01121 char* token;
01122 char* tempStr = &elemStr[0];
01123 token = strtok(tempStr, " \t");
01124 if (strstr(token, "element") == NULL)
01125 return false;
01126 token = strtok(0, " \t\n");
01127 name = std::string(token);
01128 plyElem = PlyElemEntity::NNP_UNKNOWN_ELEM;
01129 ElementMapIterator iter = mapElem.begin();
01130 bool found = false;
01131 while (iter != mapElem.end())
01132 {
01133 NameVector& v = (*iter).second;
01134 for (size_t i = 0; i < v.size(); i++)
01135 {
01136 if (v[i] == name)
01137 {
01138 found = true;
01139 break;
01140 }
01141 }
01142 if (found)
01143 {
01144 plyElem = (*iter).first;
01145 break;
01146 }
01147 iter++;
01148 }
01149 token = strtok(0, " \t\n");
01150 cnt = atoi(token);
01151 for (size_t i = 0; i < propStr.size(); i++)
01152 if (!AddProperty(propStr[i]))
01153 return false;
01154 unsigned int mask = 0;
01155 for (size_t i = 0; i < propVec.size(); i++)
01156 mask |= propVec[i].elem;
01157 std::vector<PlyProperty> compactPropVec;
01158 for (size_t i = 0; i < propVec.size(); i++)
01159 {
01160 switch (propVec[i].elem)
01161 {
01162 case NNP_NX:
01163 case NNP_NY:
01164 if ((mask & NNP_NXYZ) != NNP_NXYZ)
01165 compactPropVec.push_back(propVec[i]);
01166 break;
01167 case NNP_NZ:
01168 if ((mask & NNP_NXYZ) != NNP_NXYZ)
01169 compactPropVec.push_back(propVec[i]);
01170 else
01171 compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_NXYZ));
01172 break;
01173 case NNP_PX:
01174 case NNP_PY:
01175 if ((mask & NNP_PXYZ) != NNP_PXYZ)
01176 compactPropVec.push_back(propVec[i]);
01177 break;
01178 case NNP_PZ:
01179 if ((mask & NNP_PXYZ) != NNP_PXYZ)
01180 compactPropVec.push_back(propVec[i]);
01181 else
01182 compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_PXYZ));
01183 break;
01184 case NNP_CR:
01185 case NNP_CG:
01186 if (((mask & NNP_CRGB) != NNP_CRGB) && ((mask & NNP_CRGBA) != NNP_CRGBA))
01187 compactPropVec.push_back(propVec[i]);
01188 break;
01189 case NNP_CB:
01190 if (((mask & NNP_CRGB) != NNP_CRGB) & ((mask & NNP_CRGBA) != NNP_CRGBA))
01191 compactPropVec.push_back(propVec[i]);
01192 else if (((mask & NNP_CRGB) == NNP_CRGB) & ((mask & NNP_CRGBA) != NNP_CRGBA))
01193 compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_CRGB));
01194 break;
01195 case NNP_CA:
01196 if (((mask & NNP_CRGB) != NNP_CRGB) & ((mask & NNP_CRGBA) != NNP_CRGBA))
01197 compactPropVec.push_back(propVec[i]);
01198 else if ((mask & NNP_CRGBA) == NNP_CRGBA)
01199 compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_CRGBA));
01200 break;
01201 case NNP_TEXTUREU:
01202 if (((mask & NNP_TEXTURE2D) != NNP_TEXTURE2D) & ((mask & NNP_TEXTURE3D) != NNP_TEXTURE3D))
01203 compactPropVec.push_back(propVec[i]);
01204 break;
01205 case NNP_TEXTUREV:
01206 if (((mask & NNP_TEXTURE2D) != NNP_TEXTURE2D) & ((mask & NNP_TEXTURE3D) != NNP_TEXTURE3D))
01207 compactPropVec.push_back(propVec[i]);
01208 else if (((mask & NNP_TEXTURE2D) == NNP_TEXTURE2D) & ((mask & NNP_TEXTURE3D) != NNP_TEXTURE3D))
01209 compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_TEXTURE2D));
01210 break;
01211 case NNP_TEXTUREW:
01212 if (((mask & NNP_TEXTURE2D) != NNP_TEXTURE2D) & ((mask & NNP_TEXTURE3D) != NNP_TEXTURE3D))
01213 compactPropVec.push_back(propVec[i]);
01214 else if ((mask & NNP_TEXTURE3D) == NNP_TEXTURE3D)
01215 compactPropVec.push_back(PlyProperty(propVec[i].type, NNP_TEXTURE3D));
01216 break;
01217 default:
01218 compactPropVec.push_back(propVec[i]);
01219 break;
01220 }
01221 }
01222 propVec.clear();
01223 propVec = compactPropVec;
01224 return true;
01225 }
01226
01227
01228 bool PlyElement::WriteHeader(PlyFile &file)
01229 {
01230 if (!validToWrite || cnt == 0)
01231 return true;
01232 bool ok = true;
01233 std::stringstream temp;
01234 temp << "element " << name << " " << cnt << "\n";
01235 if (file.WriteHeaderLine(temp.str()))
01236 {
01237 for (int i = 0; i < propVec.size(); i++)
01238 ok = propVec[i].WriteHeader(file);
01239 }
01240 else
01241 return false;
01242 return ok;
01243 }
01244
01245
01246 bool PlyElement::SkipAsciiElementsInFile(PlyFile &file)
01247 {
01248 for (int i = 0; i < this->cnt; ++i)
01249 for (int j = 0; j < this->propVec.size(); ++j)
01250 this->propVec[j].SkipAsciiPropertyInFile(file);
01251 return true;
01252 }
01253
01254
01255 bool PlyElement::SkipBinaryElementsInFile(PlyFile &file)
01256 {
01257 for (int i = 0; i < this->cnt; ++i)
01258 for (int j = 0; j < this->propVec.size(); ++j)
01259 this->propVec[j].SkipBinaryPropertyInFile(file);
01260 return true;
01261 }
01262
01263
01264 bool PlyElement::AddProperty(std::string &line)
01265 {
01266 char* token;
01267 char* tempStr = &line[0];
01268 token = strtok(tempStr, " \t");
01269 if (strstr(token, "property") == NULL)
01270 return false;
01271 char* typeStr = strtok(0, " \t\n");
01272 char *ty1, *ty2;
01273 std::string type;
01274 type.append(typeStr);
01275 if (strcmp(typeStr, "list") == 0)
01276 {
01277 ty1 = strtok(0, " \t\n");
01278 ty2 = strtok(0, " \t\n");
01279 type.append(" ");
01280 type.append(ty1);
01281 type.append(" ");
01282 type.append(ty2);
01283 }
01284 PlyType plyType = PlyType::NNP_UNKNOWN_TYPE;
01285 TypeMapIterator iterType = mapType.begin();
01286 bool found = false;
01287 while (iterType != mapType.end())
01288 {
01289 NameVector& v = (*iterType).second;
01290 for (size_t i = 0; i < v.size(); i++)
01291 {
01292 if (v[i] == type)
01293 {
01294 found = true;
01295 break;
01296 }
01297 }
01298 if (found)
01299 {
01300 plyType = (*iterType).first;
01301 break;
01302 }
01303 iterType++;
01304 }
01305 if (plyType == PlyType::NNP_UNKNOWN_TYPE)
01306 return false;
01307 char* nameStr = strtok(0, " \t\n");
01308 PlyEntity plyEntity = PlyEntity::NNP_UNKNOWN_ENTITY;
01309 EntityMapIterator iterEnt = mapProp.begin();
01310 found = false;
01311 while (iterEnt != mapProp.end())
01312 {
01313 NameVector& v = (*iterEnt).second;
01314 for (size_t i = 0; i < v.size(); i++)
01315 {
01316 if (v[i] == nameStr)
01317 {
01318 found = true;
01319 break;
01320 }
01321 }
01322 if (found)
01323 {
01324 plyEntity = (*iterEnt).first;
01325 break;
01326 }
01327 iterEnt++;
01328 }
01329 if (plyEntity != PlyEntity::NNP_UNKNOWN_ENTITY)
01330 propVec.push_back(PlyProperty(plyType, plyEntity, nameStr));
01331 else
01332 propVec.push_back(PlyProperty(plyType, nameStr));
01333 return true;
01334 }
01335
01336
01337 bool PlyElement::Contains(PlyEntity entity)
01338 {
01339 for (int i = 0; i < propVec.size(); i++)
01340 {
01341 if (propVec[i].elem == entity)
01342 return true;
01343 }
01344 return false;
01345 }
01346
01347
01348
01349
01353 class Info
01354 {
01355
01356 public:
01357 ErrorCode errInfo;
01358 bool binary;
01359 std::vector<PlyElement> elemVec;
01360 bool bigEndian;
01361 std::string filename;
01362 std::vector<std::string> textureFile;
01367 Info();
01368
01374 Info(const std::string& filename);
01375
01382 bool LoadHeader(const std::string& filename);
01383
01390 bool WriteHeader(PlyFile& file);
01391
01397 void AddPlyElement(PlyElement& pe);
01398
01402 void Clear() { errInfo = NNP_OK; }
01403
01410 size_t GetElementCount(std::string& name);
01411
01418 size_t GetElementCount(PlyElemEntity e);
01419
01425 size_t GetVertexCount();
01426
01432 size_t GetFaceCount();
01433
01439 size_t GetEdgeCount();
01440
01447 PlyElement* GetElement(std::string& name);
01448
01455 PlyElement* GetElement(PlyElemEntity e);
01456
01462 PlyElement* GetVertexElement();
01463
01469 PlyElement* GetFaceElement();
01470
01476 PlyElement* GetEdgeElement();
01477
01478 };
01479
01480
01481 Info::Info()
01482 {
01483 this->binary = true;
01484 this->bigEndian = true;
01485 this->Clear();
01486 }
01487
01488
01489 Info::Info(const std::string& filename)
01490 {
01491 this->LoadHeader(filename);
01492 }
01493
01494
01495 bool Info::LoadHeader(const std::string& filename)
01496 {
01497 this->filename = filename;
01498 this->errInfo = NNP_OK;
01499 std::ifstream input(filename, std::ios::binary);
01500 if (!input.good())
01501 {
01502 this->errInfo = NNP_UNABLE_TO_OPEN;
01503 input.close();
01504 return false;
01505 }
01506 std::string buffer;
01507 std::getline(input, buffer);
01508 std::transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower);
01509 if (buffer != "ply")
01510 {
01511 this->errInfo = NNP_MISSING_HEADER;
01512 input.close();
01513 return false;
01514 }
01515 std::getline(input, buffer);
01516 std::transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower);
01517 std::size_t pos = buffer.find("format");
01518 if (pos == std::string::npos)
01519 {
01520 this->errInfo = NNP_MISSING_FORMAT;
01521 input.close();
01522 return false;
01523 }
01524 if (buffer.find("binary_lit") != std::string::npos)
01525 {
01526 this->binary = true;
01527 this->bigEndian = false;
01528 }
01529 else if (buffer.find("binary_big") != std::string::npos)
01530 {
01531 this->binary = true;
01532 this->bigEndian = true;
01533 }
01534 else if (buffer.find("ascii") != std::string::npos)
01535 {
01536 this->binary = false;
01537 this->bigEndian = false;
01538 }
01539 else
01540 {
01541 this->errInfo = NNP_MISSING_FORMAT;
01542 return false;
01543 }
01544 std::getline(input, buffer);
01545 std::transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower);
01546 while (buffer != "end_header")
01547 {
01548 if (buffer.find("element") != std::string::npos)
01549 {
01550 std::string elemStr = buffer;
01551 std::vector<std::string> propStr;
01552 do
01553 {
01554 std::getline(input, buffer);
01555 std::transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower);
01556 pos = buffer.find("property");
01557 if (pos != std::string::npos)
01558 propStr.push_back(buffer);
01559 } while (pos != std::string::npos);
01560 PlyElement pe;
01561 if (!pe.InitFromHeader(elemStr, propStr))
01562 {
01563 this->errInfo = NNP_INVALID_ELEMENT;
01564 input.close();
01565 return false;
01566 }
01567 elemVec.push_back(pe);
01568 }
01569 else
01570 {
01571 if (buffer.find("comment TextureFile"))
01572 textureFile.push_back(buffer.substr(21));
01573 std::getline(input, buffer);
01574 std::transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower);
01575 }
01576 }
01577 input.close();
01578 return true;
01579 }
01580
01581
01582 bool Info::WriteHeader(PlyFile& file)
01583 {
01584 bool ok = true;
01585 ok = file.WriteHeaderLine(std::string("ply\n"));
01586 if (this->binary)
01587 ok = file.WriteHeaderLine(std::string("format binary_little_endian 1.0\n"));
01588 else
01589 ok = file.WriteHeaderLine(std::string("format ascii 1.0\n"));
01590 ok = file.WriteHeaderLine(std::string("comment nanoply generated\n"));
01591 for (int i = 0; i < this->textureFile.size(); i++)
01592 ok = file.WriteHeaderLine(std::string("comment TextureName ") + this->textureFile[i] + "\n");
01593 for (int i = 0; i < this->elemVec.size(); i++)
01594 ok = this->elemVec[i].WriteHeader(file);
01595 ok = file.WriteHeaderLine(std::string("end_header\n"));
01596 return ok;
01597 }
01598
01599
01600 void Info::AddPlyElement(PlyElement& pe)
01601 {
01602 elemVec.push_back(pe);
01603 }
01604
01605
01606 size_t Info::GetElementCount(std::string& name)
01607 {
01608 PlyElement* pe = GetElement(name);
01609 if (pe != NULL)
01610 return pe->cnt;
01611 return -1;
01612 }
01613
01614
01615 size_t Info::GetElementCount(PlyElemEntity e)
01616 {
01617 PlyElement* pe = GetElement(e);
01618 if (pe != NULL)
01619 return pe->cnt;
01620 return -1;
01621 }
01622
01623
01624 size_t Info::GetVertexCount()
01625 {
01626 return GetElementCount(PlyElemEntity::NNP_VERTEX_ELEM);
01627 }
01628
01629
01630 size_t Info::GetFaceCount()
01631 {
01632 return GetElementCount(PlyElemEntity::NNP_FACE_ELEM);
01633 }
01634
01635
01636 size_t Info::GetEdgeCount()
01637 {
01638 return GetElementCount(PlyElemEntity::NNP_EDGE_ELEM);
01639 }
01640
01641
01642 PlyElement* Info::GetElement(std::string& name)
01643 {
01644 for (int i = 0; i < elemVec.size(); i++)
01645 {
01646 if (elemVec[i].name == name)
01647 return &elemVec[i];
01648 }
01649 return NULL;
01650 }
01651
01652
01653 PlyElement* Info::GetElement(PlyElemEntity e)
01654 {
01655 for (int i = 0; i < elemVec.size(); i++)
01656 {
01657 if (elemVec[i].plyElem == e)
01658 return &elemVec[i];
01659 }
01660 return NULL;
01661 }
01662
01663
01664 PlyElement* Info::GetVertexElement()
01665 {
01666 return GetElement(PlyElemEntity::NNP_VERTEX_ELEM);
01667 }
01668
01669
01670 PlyElement* Info::GetFaceElement()
01671 {
01672 return GetElement(PlyElemEntity::NNP_FACE_ELEM);
01673 }
01674
01675
01676 PlyElement* Info::GetEdgeElement()
01677 {
01678 return GetElement(PlyElemEntity::NNP_EDGE_ELEM);
01679 }
01680
01681
01682
01686 class DescriptorInterface
01687 {
01688
01689 public:
01690
01691 int64_t curPos;
01693 void *base;
01695 PlyEntity elem;
01697 std::string name;
01705 DescriptorInterface(PlyEntity _e, void *_b) :curPos(0), elem(_e), base(_b), name(PlyPropertyName(_e)[0]){};
01706
01713 DescriptorInterface(std::string& _s, void *_b) :curPos(0), elem(PlyEntity::NNP_UNKNOWN_ENTITY), name(_s), base(_b){};
01714
01718 virtual void Restart() = 0;
01719
01728 virtual bool ReadElemBinary(PlyFile &file, PlyProperty &prop, bool fixEndian) = 0;
01729
01737 virtual bool ReadElemAscii(PlyFile &file, PlyProperty &prop) = 0;
01738
01747 virtual bool WriteElemBinary(PlyFile &file, PlyProperty &prop, bool fixEndian) = 0;
01748
01756 virtual bool WriteElemAscii(PlyFile &file, PlyProperty &prop) = 0;
01757 };
01758
01759
01760
01764 class ElementDescriptor
01765 {
01766 public:
01767
01768 typedef std::vector<nanoply::DescriptorInterface*> PropertyDescriptor;
01769
01770 std::string name;
01771 PlyElemEntity elem;
01772 PropertyDescriptor dataDescriptor;
01779 ElementDescriptor(PlyElemEntity _e) : elem(_e), name(PlyElementName(_e)[0]){};
01780
01786 ElementDescriptor(std::string &_s) : elem(PlyElemEntity::NNP_UNKNOWN_ELEM), name(_s){};
01787
01796 bool ReadElemBinary(PlyFile &file, PlyElement &elem, bool fixEndian);
01797
01805 bool ReadElemAscii(PlyFile &file, PlyElement &elem);
01806
01815 bool WriteElemBinary(PlyFile &file, PlyElement &elem, bool fixEndian);
01816
01824 bool WriteElemAscii(PlyFile &file, PlyElement &elem);
01825
01832 void CheckDescriptor(PlyElement &elem);
01833
01834 private:
01835
01836 void ExtractDescriptor(PropertyDescriptor &descr, PlyElement &elem);
01837
01838 };
01839
01840
01841 void ElementDescriptor::ExtractDescriptor(PropertyDescriptor& descr, PlyElement &elem)
01842 {
01843 for (int j = 0; j < elem.propVec.size(); j++)
01844 {
01845 PlyProperty& prop = elem.propVec[j];
01846 int i = 0;
01847 for (; i < dataDescriptor.size(); i++)
01848 {
01849 if (dataDescriptor[i]->elem == prop.elem)
01850 {
01851 if (prop.elem != PlyEntity::NNP_UNKNOWN_ENTITY)
01852 {
01853 descr.push_back(dataDescriptor[i]);
01854 break;
01855 }
01856 else
01857 {
01858 std::string name1(dataDescriptor[i]->name);
01859 std::string name2(prop.name);
01860 std::transform(name1.begin(), name1.end(), name1.begin(), ::tolower);
01861 std::transform(name2.begin(), name2.end(), name2.begin(), ::tolower);
01862 if (name1 == name2)
01863 {
01864 descr.push_back(dataDescriptor[i]);
01865 break;
01866 }
01867 }
01868 }
01869 }
01870 if (i == dataDescriptor.size())
01871 descr.push_back(NULL);
01872 }
01873 }
01874
01875
01876 bool ElementDescriptor::ReadElemBinary(PlyFile &file, PlyElement &elem, bool fixEndian)
01877 {
01878 PropertyDescriptor descr;
01879 ExtractDescriptor(descr, elem);
01880 for (int i = 0; i < elem.cnt; i++)
01881 {
01882 for (int j = 0; j < elem.propVec.size(); j++)
01883 {
01884 PlyProperty& prop = elem.propVec[j];
01885 if (descr[j] != NULL)
01886 (*descr[j]).ReadElemBinary(file, prop, fixEndian);
01887 else
01888 prop.SkipBinaryPropertyInFile(file);
01889 }
01890 }
01891 return true;
01892 }
01893
01894
01895 bool ElementDescriptor::ReadElemAscii(PlyFile &file, PlyElement &elem)
01896 {
01897 PropertyDescriptor descr;
01898 ExtractDescriptor(descr, elem);
01899 for (int i = 0; i < elem.cnt; i++)
01900 {
01901 for (int j = 0; j < elem.propVec.size(); j++)
01902 {
01903 PlyProperty& prop = elem.propVec[j];
01904 if (descr[j] != NULL)
01905 (*descr[j]).ReadElemAscii(file, prop);
01906 else
01907 prop.SkipAsciiPropertyInFile(file);
01908 }
01909 }
01910 return true;
01911 }
01912
01913 bool ElementDescriptor::WriteElemBinary(PlyFile &file, PlyElement &elem, bool fixEndian)
01914 {
01915 PropertyDescriptor descr;
01916 ExtractDescriptor(descr, elem);
01917 for (int i = 0; i < elem.cnt; i++)
01918 {
01919 for (int j = 0; j < elem.propVec.size(); j++)
01920 {
01921 if (descr[j] != NULL)
01922 (*descr[j]).WriteElemBinary(file, elem.propVec[j], fixEndian);
01923 }
01924 }
01925 return true;
01926 }
01927
01928 bool ElementDescriptor::WriteElemAscii(PlyFile &file, PlyElement &elem)
01929 {
01930 PropertyDescriptor descr;
01931 ExtractDescriptor(descr, elem);
01932 for (int i = 0; i < elem.cnt; i++)
01933 {
01934 bool first = true;
01935 for (int j = 0; j < elem.propVec.size(); j++)
01936 {
01937 if (descr[j] != NULL)
01938 {
01939 if (!first)
01940 file.WriteAsciiData(std::string(" "));
01941 else
01942 first = false;
01943 (*descr[j]).WriteElemAscii(file, elem.propVec[j]);
01944 }
01945 }
01946 file.WriteAsciiData(std::string("\n"));
01947 }
01948 return true;
01949 }
01950
01951
01952 void ElementDescriptor::CheckDescriptor(PlyElement &elem)
01953 {
01954 if (elem.propVec.size() == 0)
01955 {
01956 elem.validToWrite = false;
01957 return;
01958 }
01959 elem.validToWrite = true;
01960 PropertyDescriptor descr;
01961 ExtractDescriptor(descr, elem);
01962 for (int j = 0; j < elem.propVec.size(); j++)
01963 {
01964 if (descr[j] != NULL)
01965 elem.propVec[j].validToWrite = true;
01966 }
01967 }
01968
01969
01970
01978 template<class CointainerType, int VectorSize, typename ScalarType>
01979 class DataDescriptor : public DescriptorInterface
01980 {
01981 public:
01982
01983 DataDescriptor();
01984
01991 DataDescriptor(PlyEntity _e, void *_b) :DescriptorInterface(_e, _b){};
01992
01999 DataDescriptor(std::string& _s, void *_b) :DescriptorInterface(_s, _b){};
02000
02001 void Restart();
02002
02003 bool ReadElemBinary(PlyFile &file, PlyProperty &prop, bool fixEndian);
02004
02005 bool ReadElemAscii(PlyFile &file, PlyProperty &prop);
02006
02007 bool WriteElemBinary(PlyFile &file, PlyProperty &prop, bool fixEndian);
02008
02009 bool WriteElemAscii(PlyFile &file, PlyProperty &prop);
02010
02011 private:
02012
02013 template<typename C>
02014 void ReadBinary(PlyFile &file, PlyProperty &prop, bool fixEndian);
02015
02016 template<typename C>
02017 void ReadAscii(PlyFile &file, PlyProperty &prop);
02018
02019 template<typename C>
02020 void WriteBinary(PlyFile &file, PlyProperty &prop, bool fixEndian);
02021
02022 template<typename C>
02023 void WriteAscii(PlyFile &file, PlyProperty &prop);
02024
02025 };
02026
02027
02028 template<class CointainerType, int VectorSize, typename ScalarType>
02029 void DataDescriptor<CointainerType, VectorSize, ScalarType>::Restart()
02030 {
02031 this->curPos = 0;
02032 }
02033
02034 template<class ContainerType, int VectorSize, typename ScalarType>
02035 template<typename C>
02036 void DataDescriptor<ContainerType, VectorSize, ScalarType>::ReadBinary(PlyFile &file, PlyProperty &prop, bool fixEndian)
02037 {
02038 unsigned char* buffer;
02039 int size;
02040 int count = prop.CountValue();
02041 int typeSize = prop.TypeSize();
02042 if (prop.type >= NNP_LIST_UINT8_UINT32)
02043 {
02044 if (prop.IsSigned())
02045 {
02046 char cntList = 0;
02047 file.ReadBinaryData(&cntList, sizeof(char));
02048 size = typeSize * cntList;
02049 count = cntList;
02050 }
02051 else
02052 {
02053 unsigned char cntList = 0;
02054 file.ReadBinaryData(&cntList, sizeof(char));
02055 size = typeSize * cntList;
02056 count = cntList;
02057 }
02058 }
02059 else
02060 size = typeSize * count;
02061 buffer = new unsigned char[size];
02062 file.ReadBinaryData(buffer, size);
02063
02064 if (typeSize > 1 && fixEndian)
02065 adjustEndianess(buffer, typeSize, count);
02066
02067 C* temp = (C*)buffer;
02068 float norm = 1.0f;
02069 if ((prop.elem == NNP_CRGB || prop.elem == NNP_CRGBA))
02070 {
02071 if (std::is_same<ScalarType, float>::value && std::is_same<C, unsigned char>::value)
02072 norm = 1.0f / 255.0f;
02073 else if (std::is_same<ScalarType, unsigned char>::value && std::is_same<C, float>::value)
02074 norm = 255.0f;
02075 }
02076 unsigned char* baseProp = (unsigned char*)base + this->curPos*sizeof(ContainerType);
02077 for (int i = 0; i < std::min(VectorSize, count); i++)
02078 *(ScalarType *)(baseProp + i*sizeof(ScalarType)) = ScalarType(temp[i] * norm);
02079 ++(this->curPos);
02080 delete[] buffer;
02081 }
02082
02083
02084 template<class ContainerType, int VectorSize, typename ScalarType>
02085 bool DataDescriptor<ContainerType, VectorSize, ScalarType>::ReadElemBinary(PlyFile &file, PlyProperty &prop, bool fixEndian)
02086 {
02087 if (prop.elem != elem)
02088 return false;
02089 switch (prop.type)
02090 {
02091 case NNP_LIST_INT8_INT8:
02092 case NNP_LIST_UINT8_INT8:
02093 case NNP_INT8: this->ReadBinary<char>(file, prop, fixEndian); break;
02094 case NNP_LIST_INT8_UINT8:
02095 case NNP_LIST_UINT8_UINT8:
02096 case NNP_UINT8: this->ReadBinary<unsigned char>(file, prop, fixEndian); break;
02097 case NNP_LIST_INT8_INT16:
02098 case NNP_LIST_UINT8_INT16:
02099 case NNP_INT16: this->ReadBinary<short>(file, prop, fixEndian); break;
02100 case NNP_LIST_INT8_UINT16:
02101 case NNP_LIST_UINT8_UINT16:
02102 case NNP_UINT16: this->ReadBinary<unsigned short>(file, prop, fixEndian); break;
02103 case NNP_LIST_INT8_FLOAT32:
02104 case NNP_LIST_UINT8_FLOAT32:
02105 case NNP_FLOAT32: this->ReadBinary<float>(file, prop, fixEndian); break;
02106 case NNP_LIST_UINT8_INT32:
02107 case NNP_LIST_INT8_INT32:
02108 case NNP_INT32: this->ReadBinary<int>(file, prop, fixEndian); break;
02109 case NNP_LIST_UINT8_UINT32:
02110 case NNP_LIST_INT8_UINT32:
02111 case NNP_UINT32: this->ReadBinary<unsigned int>(file, prop, fixEndian); break;
02112 case NNP_LIST_INT8_FLOAT64:
02113 case NNP_LIST_UINT8_FLOAT64:
02114 case NNP_FLOAT64: this->ReadBinary<double>(file, prop, fixEndian); break;
02115 }
02116 return true;
02117 }
02118
02119
02120
02121 template<class ContainerType, int VectorSize, typename ScalarType>
02122 template<typename C>
02123 void DataDescriptor<ContainerType, VectorSize, ScalarType>::ReadAscii(PlyFile &file, PlyProperty &prop)
02124 {
02125 int count = prop.CountValue();
02126 if (prop.type >= NNP_LIST_UINT8_UINT32)
02127 file.ReadAsciiData(count);
02128
02129 C* temp = new C[count];
02130 for (int i = 0; i < count; i++)
02131 file.ReadAsciiData(temp[i]);
02132
02133 float norm = 1.0f;
02134 if ((prop.elem == NNP_CRGB || prop.elem == NNP_CRGBA))
02135 {
02136 if (std::is_same<ScalarType, float>::value && prop.type == NNP_UINT8)
02137 norm = 1.0f / 255.0f;
02138 else if (std::is_same<ScalarType, unsigned char>::value && prop.type == NNP_FLOAT32)
02139 norm = 255.0f;
02140 }
02141 unsigned char* baseProp = (unsigned char*)base + this->curPos*sizeof(ContainerType);
02142 for (int i = 0; i < std::min(VectorSize, count); i++)
02143 *(ScalarType *)(baseProp + i*sizeof(ScalarType)) = ScalarType(temp[i] * norm);
02144
02145 delete[] temp;
02146 ++(this->curPos);
02147 }
02148
02149
02150
02151 template<class ContainerType, int VectorSize, typename ScalarType>
02152 bool DataDescriptor<ContainerType, VectorSize, ScalarType>::ReadElemAscii(PlyFile &file, PlyProperty &prop)
02153 {
02154 if (prop.elem != elem)
02155 return false;
02156 switch (prop.type)
02157 {
02158 case NNP_LIST_UINT8_INT8:
02159 case NNP_LIST_INT8_INT8:
02160 case NNP_INT8: this->ReadAscii<int>(file, prop); break;
02161 case NNP_LIST_UINT8_UINT8:
02162 case NNP_LIST_INT8_UINT8:
02163 case NNP_UINT8: this->ReadAscii<unsigned int>(file, prop); break;
02164 case NNP_LIST_UINT8_INT16:
02165 case NNP_LIST_INT8_INT16:
02166 case NNP_INT16: this->ReadAscii<short>(file, prop); break;
02167 case NNP_LIST_UINT8_UINT16:
02168 case NNP_LIST_INT8_UINT16:
02169 case NNP_UINT16: this->ReadAscii<unsigned short>(file, prop); break;
02170 case NNP_LIST_UINT8_FLOAT32:
02171 case NNP_LIST_INT8_FLOAT32:
02172 case NNP_FLOAT32: this->ReadAscii<float>(file, prop); break;
02173 case NNP_LIST_UINT8_INT32:
02174 case NNP_LIST_INT8_INT32:
02175 case NNP_INT32: this->ReadAscii<int>(file, prop); break;
02176 case NNP_LIST_UINT8_UINT32:
02177 case NNP_LIST_INT8_UINT32:
02178 case NNP_UINT32: this->ReadAscii<unsigned int>(file, prop); break;
02179 case NNP_LIST_UINT8_FLOAT64:
02180 case NNP_LIST_INT8_FLOAT64:
02181 case NNP_FLOAT64: this->ReadAscii<double>(file, prop); break;
02182 }
02183 return true;
02184 }
02185
02186
02187
02188 template<class ContainerType, int VectorSize, typename ScalarType>
02189 template<typename C>
02190 void DataDescriptor<ContainerType, VectorSize, ScalarType>::WriteBinary(PlyFile &file, PlyProperty &prop, bool fixEndian)
02191 {
02192 int count = prop.CountValue();
02193 C data[VectorSize];
02194 if (prop.type >= NNP_LIST_UINT8_UINT32)
02195 {
02196 if (prop.IsSigned())
02197 {
02198 char listSize = (char)VectorSize;
02199 file.WriteBinaryData(&listSize, 1);
02200 count = VectorSize;
02201 }
02202 else
02203 {
02204 unsigned char listSize = (unsigned char)VectorSize;
02205 file.WriteBinaryData(&listSize, 1);
02206 count = VectorSize;
02207 }
02208 }
02209
02210 float norm = 1.0f;
02211 if ((prop.elem == NNP_CRGB || prop.elem == NNP_CRGBA))
02212 {
02213 if (std::is_same<ScalarType, float>::value && std::is_same<C, unsigned char>::value)
02214 norm = 255.0f;
02215 else if (std::is_same<ScalarType, unsigned char>::value && std::is_same<C, float>::value)
02216 norm = 1.0f / 255.0f;
02217 }
02218
02219 C temp = 0;
02220 unsigned char* baseProp = (unsigned char*)base + this->curPos*sizeof(ContainerType);
02221 for (int i = 0; i < std::min(VectorSize, count); i++)
02222 data[i] = (C)((*(ScalarType*)(baseProp + i*sizeof(ScalarType))) * norm);
02223 if (sizeof(C) > 1 && fixEndian)
02224 adjustEndianess((unsigned char*)data, sizeof(C), std::min(VectorSize, count));
02225
02226 file.WriteBinaryData(data, sizeof(C)*std::min(VectorSize, count));
02227 for (int i = 0; i < (count - VectorSize); i++)
02228 file.WriteBinaryData(&temp, sizeof(C));
02229 ++(this->curPos);
02230 }
02231
02232
02233 template<class ContainerType, int VectorSize, typename ScalarType>
02234 bool DataDescriptor<ContainerType, VectorSize, ScalarType>::WriteElemBinary(PlyFile &file, PlyProperty &prop, bool fixEndian)
02235 {
02236 if (prop.elem != elem)
02237 return false;
02238 switch (prop.type)
02239 {
02240 case NNP_LIST_INT8_INT8:
02241 case NNP_LIST_UINT8_INT8:
02242 case NNP_INT8: this->WriteBinary<char>(file, prop, fixEndian); break;
02243 case NNP_LIST_INT8_UINT8:
02244 case NNP_LIST_UINT8_UINT8:
02245 case NNP_UINT8: this->WriteBinary<unsigned char>(file, prop, fixEndian); break;
02246 case NNP_LIST_INT8_INT16:
02247 case NNP_LIST_UINT8_INT16:
02248 case NNP_INT16: this->WriteBinary<short>(file, prop, fixEndian); break;
02249 case NNP_LIST_INT8_UINT16:
02250 case NNP_LIST_UINT8_UINT16:
02251 case NNP_UINT16: this->WriteBinary<unsigned short>(file, prop, fixEndian); break;
02252 case NNP_LIST_INT8_FLOAT32:
02253 case NNP_LIST_UINT8_FLOAT32:
02254 case NNP_FLOAT32: this->WriteBinary<float>(file, prop, fixEndian); break;
02255 case NNP_LIST_UINT8_INT32:
02256 case NNP_LIST_INT8_INT32:
02257 case NNP_INT32: this->WriteBinary<int>(file, prop, fixEndian); break;
02258 case NNP_LIST_UINT8_UINT32:
02259 case NNP_LIST_INT8_UINT32:
02260 case NNP_UINT32: this->WriteBinary<unsigned int>(file, prop, fixEndian); break;
02261 case NNP_LIST_INT8_FLOAT64:
02262 case NNP_LIST_UINT8_FLOAT64:
02263 case NNP_FLOAT64: this->WriteBinary<double>(file, prop, fixEndian); break;
02264 }
02265 return true;
02266 }
02267
02268
02269 template<class ContainerType, int VectorSize, typename ScalarType>
02270 template<typename C>
02271 void DataDescriptor<ContainerType, VectorSize, ScalarType>::WriteAscii(PlyFile &file, PlyProperty &prop)
02272 {
02273 int count = prop.CountValue();
02274 if (prop.type >= NNP_LIST_UINT8_UINT32)
02275 {
02276 if (prop.IsSigned())
02277 {
02278 int listSize = (int)VectorSize;
02279 file.WriteAsciiData(listSize);
02280 count = VectorSize;
02281 }
02282 else
02283 {
02284 unsigned int listSize = (unsigned int)VectorSize;
02285 file.WriteAsciiData(listSize);
02286 count = VectorSize;
02287 }
02288 file.WriteAsciiData(std::string(" "));
02289 }
02290
02291 float norm = 1.0;
02292 if ((prop.elem == NNP_CRGB || prop.elem == NNP_CRGBA))
02293 {
02294 if (std::is_same<ScalarType, float>::value && prop.type == NNP_UINT8)
02295 norm = 255.0f;
02296 else if (std::is_same<ScalarType, unsigned char>::value && prop.type == NNP_FLOAT32)
02297 norm = 1.0f / 255.0f;
02298 }
02299
02300 C data[VectorSize];
02301 unsigned char* baseProp = (unsigned char*)base + this->curPos*sizeof(ContainerType);
02302 for (int i = 0; i < std::min(VectorSize, count); i++)
02303 data[i] = (C)((*(ScalarType*)(baseProp + i*sizeof(ScalarType))) * norm);
02304 for (int i = 0; i < (count - VectorSize); i++)
02305 data[i] = 0;
02306
02307 for (int i = 0; i < count; i++)
02308 {
02309 file.WriteAsciiData(data[i]);
02310 if (i < count - 1)
02311 file.WriteAsciiData(std::string(" "));
02312 }
02313 ++(this->curPos);
02314 }
02315
02316
02317 template<class ContainerType, int VectorSize, typename ScalarType>
02318 bool DataDescriptor<ContainerType, VectorSize, ScalarType>::WriteElemAscii(PlyFile &file, PlyProperty& prop)
02319 {
02320 if (prop.elem != elem)
02321 return false;
02322 if (prop.elem == PlyEntity::NNP_UNKNOWN_ENTITY && prop.name != name)
02323 return false;
02324 switch (prop.type)
02325 {
02326 case NNP_LIST_UINT8_INT8:
02327 case NNP_LIST_INT8_INT8:
02328 case NNP_INT8: this->WriteAscii<int>(file, prop); break;
02329 case NNP_LIST_UINT8_UINT8:
02330 case NNP_LIST_INT8_UINT8:
02331 case NNP_UINT8: this->WriteAscii<unsigned int>(file, prop); break;
02332 case NNP_LIST_UINT8_INT16:
02333 case NNP_LIST_INT8_INT16:
02334 case NNP_INT16: this->WriteAscii<short>(file, prop); break;
02335 case NNP_LIST_UINT8_UINT16:
02336 case NNP_LIST_INT8_UINT16:
02337 case NNP_UINT16: this->WriteAscii<unsigned short>(file, prop); break;
02338 case NNP_LIST_UINT8_FLOAT32:
02339 case NNP_LIST_INT8_FLOAT32:
02340 case NNP_FLOAT32: this->WriteAscii<float>(file, prop); break;
02341 case NNP_LIST_UINT8_INT32:
02342 case NNP_LIST_INT8_INT32:
02343 case NNP_INT32: this->WriteAscii<int>(file, prop); break;
02344 case NNP_LIST_UINT8_UINT32:
02345 case NNP_LIST_INT8_UINT32:
02346 case NNP_UINT32: this->WriteAscii<unsigned int>(file, prop); break;
02347 case NNP_LIST_UINT8_FLOAT64:
02348 case NNP_LIST_INT8_FLOAT64:
02349 case NNP_FLOAT64: this->WriteAscii<double>(file, prop); break;
02350 }
02351 return true;
02352 }
02353
02354
02355
02356 template <size_t ActionType>
02357 inline bool ElemProcessing(ElementDescriptor& elemDescr, PlyElement &elem, PlyFile& file, bool fixEndian)
02358 {
02359 if ((elemDescr.elem != PlyElemEntity::NNP_UNKNOWN_ELEM && elemDescr.elem == elem.plyElem) ||
02360 (elemDescr.elem == PlyElemEntity::NNP_UNKNOWN_ELEM && elemDescr.name == elem.name))
02361 {
02362 if (ActionType == 0)
02363 elemDescr.ReadElemBinary(file, elem, fixEndian);
02364 else if (ActionType == 1)
02365 elemDescr.ReadElemAscii(file, elem);
02366 else if (ActionType == 2)
02367 elemDescr.WriteElemBinary(file, elem, fixEndian);
02368 else if (ActionType == 3)
02369 elemDescr.WriteElemAscii(file, elem);
02370 else if (ActionType == 4)
02371 elemDescr.CheckDescriptor(elem);
02372 return true;
02373 }
02374 return false;
02375 }
02376
02377 typedef std::vector<ElementDescriptor*> MeshDescriptor;
02378
02385 bool OpenModel(Info& info, MeshDescriptor& meshElements)
02386 {
02387 PlyFile file;
02388 if (!file.OpenFileToRead(info.filename))
02389 {
02390 info.errInfo = NNP_UNABLE_TO_OPEN;
02391 return false;
02392 }
02393 bool last;
02394 std::string line;
02395 do
02396 {
02397 file.NextHeaderLine(line, last);
02398 } while (!last);
02399 bool fixEndian = false;
02400 if (checkEndianness() == 1)
02401 {
02402 if (info.bigEndian)
02403 fixEndian = true;
02404 }
02405 else
02406 {
02407 if (!info.bigEndian)
02408 fixEndian = true;
02409 }
02410
02411 if (info.binary)
02412 {
02413 for (int i = 0; i < info.elemVec.size(); ++i)
02414 {
02415 PlyElement& pe = info.elemVec[i];
02416 int j = 0;
02417 for (; j < meshElements.size(); j++)
02418 if (ElemProcessing<0>(*meshElements[j], pe, file, false))
02419 break;
02420 if (j == meshElements.size())
02421 pe.SkipBinaryElementsInFile(file);
02422
02423
02424 }
02425 }
02426 else
02427 {
02428 for (int i = 0; i < info.elemVec.size(); ++i)
02429 {
02430 PlyElement& pe = info.elemVec[i];
02431 int j = 0;
02432 for (; j < meshElements.size(); j++)
02433 if (ElemProcessing<1>(*meshElements[j], pe, file, false))
02434 break;
02435 if (j == meshElements.size())
02436 pe.SkipAsciiElementsInFile(file);
02437
02438
02439 }
02440 }
02441 return true;
02442 }
02443
02444
02445
02453 bool SaveModel(std::string& filename, MeshDescriptor& meshElements, Info& info)
02454 {
02455 PlyFile file;
02456 if (!file.OpenFileToWrite(filename))
02457 {
02458 info.errInfo = NNP_UNABLE_TO_OPEN;
02459 return false;
02460 }
02461 for (int i = 0; i < info.elemVec.size(); ++i)
02462 {
02463 PlyElement& pe = info.elemVec[i];
02464 for (int j = 0; j < meshElements.size(); j++)
02465 if (ElemProcessing<4>(*meshElements[j], pe, file, false))
02466 break;
02467 }
02468 info.WriteHeader(file);
02469 bool fixEndian = false;
02470 if (checkEndianness() == 1)
02471 {
02472 if (info.bigEndian)
02473 fixEndian = true;
02474 }
02475 else
02476 {
02477 if (!info.bigEndian)
02478 fixEndian = true;
02479 }
02480
02481 if (info.binary)
02482 {
02483 for (int i = 0; i < info.elemVec.size(); ++i)
02484 {
02485 PlyElement& pe = info.elemVec[i];
02486 if (pe.validToWrite)
02487 {
02488 for (int j = 0; j < meshElements.size(); j++)
02489 if (ElemProcessing<2>(*meshElements[j], pe, file, false))
02490 break;
02491 }
02492 }
02493 }
02494 else
02495 {
02496 for (int i = 0; i < info.elemVec.size(); ++i)
02497 {
02498 PlyElement& pe = info.elemVec[i];
02499 if (pe.validToWrite)
02500 {
02501 for (int j = 0; j < meshElements.size(); j++)
02502 if (ElemProcessing<3>(*meshElements[j], pe, file, false))
02503 break;
02504 }
02505 }
02506 }
02507 file.Flush();
02508 return true;
02509 }
02510
02511
02512
02516 template < typename TupleType, size_t ActionType>
02517 inline bool TupleForEach(TupleType &tuple, PlyElement &elem, PlyFile& file, bool fixEndian, SizeT<ActionType> a)
02518 {
02519 return TupleForEach(tuple, elem, file, fixEndian, SizeT<std::tuple_size<TupleType>::value>(), a);
02520 }
02521
02522 template < typename TupleType, size_t ActionType>
02523 inline bool TupleForEach(TupleType &tuple, PlyElement &elem, PlyFile& file, bool fixEndian, SizeT<0> t, SizeT<ActionType> a) { return false; }
02524
02525 template < typename TupleType, size_t N, size_t ActionType>
02526 inline bool TupleForEach(TupleType &tuple, PlyElement &elem, PlyFile& file, bool fixEndian, SizeT<N> t, SizeT<ActionType> a)
02527 {
02528 typename std::tuple_element<N - 1, TupleType>::type &elemDescr = std::get<N - 1>(tuple);
02529 if ((elemDescr.elem != PlyElemEntity::NNP_UNKNOWN_ELEM && elemDescr.elem == elem.plyElem) ||
02530 (elemDescr.elem == PlyElemEntity::NNP_UNKNOWN_ELEM && elemDescr.name == elem.name))
02531 {
02532 if (ActionType == 0)
02533 elemDescr.ReadElemBinary(file, elem, fixEndian);
02534 else if (ActionType == 1)
02535 elemDescr.ReadElemAscii(file, elem);
02536 else if (ActionType == 2)
02537 elemDescr.WriteElemBinary(file, elem, fixEndian);
02538 else if (ActionType == 3)
02539 elemDescr.WriteElemAscii(file, elem);
02540 else if (ActionType == 4)
02541 elemDescr.CheckDescriptor(elem);
02542 return true;
02543 }
02544 return TupleForEach(tuple, elem, file, fixEndian, SizeT<N - 1>(), a);
02545 }
02550 }
02551 #endif // NANOPLY_HPP