Openholo  v4.0
Open Source Digital Holographic Library
PLYparser.cpp
Go to the documentation of this file.
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install, copy or use the software.
7 //
8 //
9 // License Agreement
10 // For Open Source Digital Holographic Library
11 //
12 // Openholo library is free software;
13 // you can redistribute it and/or modify it under the terms of the BSD 2-Clause license.
14 //
15 // Copyright (C) 2017-2024, Korea Electronics Technology Institute. All rights reserved.
16 // E-mail : contact.openholo@gmail.com
17 // Web : http://www.openholo.org
18 //
19 // Redistribution and use in source and binary forms, with or without modification,
20 // are permitted provided that the following conditions are met:
21 //
22 // 1. Redistribution's of source code must retain the above copyright notice,
23 // this list of conditions and the following disclaimer.
24 //
25 // 2. Redistribution's in binary form must reproduce the above copyright notice,
26 // this list of conditions and the following disclaimer in the documentation
27 // and/or other materials provided with the distribution.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the copyright holder or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 // This software contains opensource software released under GNU Generic Public License,
41 // NVDIA Software License Agreement, or CUDA supplement to Software License Agreement.
42 // Check whether software you use contains licensed software.
43 //
44 //M*/
45 
46 #include "PLYparser.h"
47 #include "sys.h"
48 #include <typeinfo>
49 
51 {
52  PropertyTable.insert(std::make_pair(Type::INT8, std::make_pair(1, "char")));
53  PropertyTable.insert(std::make_pair(Type::UINT8, std::make_pair(1, "uchar")));
54  PropertyTable.insert(std::make_pair(Type::INT16, std::make_pair(2, "short")));
55  PropertyTable.insert(std::make_pair(Type::UINT16, std::make_pair(2, "ushort")));
56  PropertyTable.insert(std::make_pair(Type::INT32, std::make_pair(4, "int")));
57  PropertyTable.insert(std::make_pair(Type::UINT32, std::make_pair(4, "uint")));
58  PropertyTable.insert(std::make_pair(Type::FLOAT32, std::make_pair(4, "float")));
59  PropertyTable.insert(std::make_pair(Type::FLOAT64, std::make_pair(8, "double")));
60  PropertyTable.insert(std::make_pair(Type::INVALID, std::make_pair(0, "INVALID")));
61 }
62 
64 {
65 }
66 
67 PLYparser::PlyProperty::PlyProperty(std::istream &is)
68  : isList(false)
69 {
70  std::string type;
71  is >> type;
72  if (type == "list") {
73  std::string countType;
74  is >> countType >> type;
75  listType = PLYparser::propertyTypeFromString(countType);
76  isList = true;
77  }
78  propertyType = PLYparser::propertyTypeFromString(type);
79  is >> name;
80 }
81 
82 PLYparser::PlyProperty::PlyProperty(const Type type, const std::string &_name)
83  : propertyType(type), name(_name)
84 {
85 }
86 
87 PLYparser::PlyProperty::PlyProperty(const Type list_type, const Type prop_type, const std::string &_name, const ulonglong list_count)
88  : listType(list_type), propertyType(prop_type), name(_name), listCount(list_count), isList(true)
89 {
90 }
91 
92 PLYparser::PlyElement::PlyElement(std::istream &is)
93 {
94  is >> name >> size;
95 }
96 
97 PLYparser::PlyElement::PlyElement(const std::string &_name, const ulonglong count)
98  : name(_name), size(count)
99 {
100 }
101 
102 PLYparser::Type PLYparser::propertyTypeFromString(const std::string &t)
103 {
104  if (t == "int8" || t == "char") return Type::INT8;
105  else if (t == "uint8" || t == "uchar") return Type::UINT8;
106  else if (t == "int16" || t == "short") return Type::INT16;
107  else if (t == "uint16" || t == "ushort") return Type::UINT16;
108  else if (t == "int32" || t == "int") return Type::INT32;
109  else if (t == "uint32" || t == "uint") return Type::UINT32;
110  else if (t == "float32" || t == "float") return Type::FLOAT32;
111  else if (t == "float64" || t == "double" || t == "real") return Type::FLOAT64;
112  else return Type::INVALID;
113 }
114 
115 bool PLYparser::findIdxOfPropertiesAndElement(const std::vector<PlyElement> &elements, const std::string &elementKey, const std::string &propertyKeys, longlong &elementIdx, int &propertyIdx)
116 {
117  elementIdx = -1;
118  for (size_t i = 0; i < elements.size(); ++i) {
119  if (elements[i].name == elementKey) {
120  elementIdx = i;
121  break;
122  }
123  }
124 
125  if (elementIdx >= 0) {
126  const PlyElement &element = elements[elementIdx];
127 
128  propertyIdx = -1;
129  for (int j = 0; j < element.properties.size(); ++j) {
130  if (element.properties[j].name == propertyKeys) {
131  propertyIdx = j;
132  break;
133  }
134  }
135 
136  if (propertyIdx >= 0) return true;
137  else return false;
138  }
139  else return false;
140 }
141 
142 bool PLYparser::loadPLY(const std::string& fileName, ulonglong& n_points, Vertex** vertices)
143 {
144  std::string inputPath = fileName;
145  if ((fileName.find(".ply") == std::string::npos) && (fileName.find(".PLY") == std::string::npos))
146  inputPath.append(".ply");
147  std::ifstream File(inputPath, std::ios::in | std::ios::binary);
148 
149  int color_channels;
150  bool isBinary = false;
151  bool isBigEndian = false;
152  std::vector<PlyElement> elements;
153  std::vector<std::string> comments;
154  std::vector<std::string> objInfo;
155 
156  if (File.is_open()) {
157  //parse header
158  std::string line;
159  std::getline(File, line);
160  std::istringstream lineStr(line);
161  std::string token;
162  lineStr.clear();
163  lineStr >> token;
164 
165  if ((token != "ply") && (token != "PLY")) {
166  LOG("<FAILED> Wrong file ext: %s\n", token.c_str());
167  File.close();
168  return false;
169  }
170  else {
171  //parse PLY header
172  while (std::getline(File, line)) {
173  //std::istringstream lineStr(line);
174  lineStr.clear();
175  lineStr.str(line);
176  std::istream(lineStr.rdbuf()) >> token;
177 
178  if (token == "comment") {
179  comments.push_back((8 > 0) ? line.erase(0, 8) : line);
180  }
181  else if (token == "format") {
182  std::string str;
183  lineStr.clear();
184  lineStr >> str;
185  if (str == "binary_little_endian") isBinary = true;
186  else if (str == "binary_big_endian") isBinary = isBigEndian = true;
187  }
188  else if (token == "element") {
189  elements.emplace_back(lineStr);
190  }
191  else if (token == "property") {
192  if (!elements.size())
193  LOG("<FAILED> No Elements defined, file is malformed.\n");
194  elements.back().properties.emplace_back(lineStr);
195  }
196  else if (token == "obj_info") objInfo.push_back((9 > 0) ? line.erase(0, 9) : line);
197  else if (token == "end_header") break;
198  }
199 
200 #ifdef _DEBUG
201  //print comment list
202  for (auto cmt : comments) {
203  LOG("Comment : %s\n", cmt.c_str());
204  }
205 
206  //print element and property list
207  for (auto elmnt : elements) {
208  LOG("Element - %s : ( %lld )\n", elmnt.name.c_str(), elmnt.size);
209  for (auto Property : elmnt.properties) {
210  auto tmp = PropertyTable[Property.propertyType].second;
211  LOG("\tProperty : %s : ( %s )\n", Property.name.c_str(), PropertyTable[Property.propertyType].second.c_str());
212  }
213  }
214 #endif
215  longlong idxE_color = -1;
216  int idxP_channel = -1;
217  bool found_channel = findIdxOfPropertiesAndElement(elements, "color", "channel", idxE_color, idxP_channel);
218 
219  longlong idxE_vertex = -1;
220  int idxP_x = -1;
221  int idxP_y = -1;
222  int idxP_z = -1;
223  bool found_vertex = findIdxOfPropertiesAndElement(elements, "vertex", "x", idxE_vertex, idxP_x);
224  found_vertex = findIdxOfPropertiesAndElement(elements, "vertex", "y", idxE_vertex, idxP_y);
225  found_vertex = findIdxOfPropertiesAndElement(elements, "vertex", "z", idxE_vertex, idxP_z);
226  if (!found_vertex) {
227  LOG("<FAILED> File is not having vertices data.\n");
228  File.close();
229  return false;
230  }
231 
232  longlong idxE_face = -1;
233  int idxP_list = -1;
234  int idxP_red = -1;
235  int idxP_green = -1;
236  int idxP_blue = -1;
237  int idxP_alpha = -1;
238  bool found_face = findIdxOfPropertiesAndElement(elements, "face", "vertex_indices", idxE_face, idxP_list);
239  bool found_alpha = findIdxOfPropertiesAndElement(elements, "face", "alpha", idxE_face, idxP_alpha);
240  bool found_color = findIdxOfPropertiesAndElement(elements, "vertex", "red", idxE_vertex, idxP_red);
241  found_color = findIdxOfPropertiesAndElement(elements, "vertex", "green", idxE_vertex, idxP_green);
242  found_color = findIdxOfPropertiesAndElement(elements, "vertex", "blue", idxE_vertex, idxP_blue);
243 
244  if (!found_color) {
245  if (found_vertex) {
246  found_color = findIdxOfPropertiesAndElement(elements, "vertex", "diffuse_red", idxE_vertex, idxP_red);
247  found_color = findIdxOfPropertiesAndElement(elements, "vertex", "diffuse_green", idxE_vertex, idxP_green);
248  found_color = findIdxOfPropertiesAndElement(elements, "vertex", "diffuse_blue", idxE_vertex, idxP_blue);
249  }
250  if (!found_color && found_face) {
251  found_color = findIdxOfPropertiesAndElement(elements, "face", "red", idxE_face, idxP_red);
252  found_color = findIdxOfPropertiesAndElement(elements, "face", "green", idxE_face, idxP_green);
253  found_color = findIdxOfPropertiesAndElement(elements, "face", "blue", idxE_face, idxP_blue);
254 
255  }
256  }
257 
258  n_points = elements[idxE_vertex].size;
259 
260 
261  // Memory allocation
262  if (*vertices != nullptr)
263  {
264  delete[] *vertices;
265  *vertices = nullptr;
266  }
267 
268  *vertices = new Vertex[n_points];
269  std::memset(*vertices, 0, sizeof(Vertex) * n_points);
270 
271  int idxP_phase = -1;
272  bool isPhaseParse = findIdxOfPropertiesAndElement(elements, "vertex", "phase", idxE_vertex, idxP_phase);
273 
274  // BINARY
275  if (isBinary) {
276  //parse Point Cloud Data
277  for (size_t idxE = 0; idxE < elements.size(); ++idxE) {
278  // parse vertex
279  for (longlong e = 0; e < elements[idxE].size; ++e) {
280  //vertex data parsing
281  if (idxE == idxE_vertex) {
282  auto list = 0;
283  auto x = 0.0f;
284  auto y = 0.0f;
285  auto z = 0.0f;
286  auto red = 0;
287  auto green = 0;
288  auto blue = 0;
289  auto alpha = 0;
290  auto phase = 0.0f;
291  void* tmp = nullptr;
292 
293  //line Processing
294  for (int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
295 
296  if (idxP == idxP_x) tmp = &x;
297  else if (idxP == idxP_y) tmp = &y;
298  else if (idxP == idxP_z) tmp = &z;
299  else if (idxP == idxP_red) tmp = &red;
300  else if (idxP == idxP_green) tmp = &green;
301  else if (idxP == idxP_blue) tmp = &blue;
302  else if (idxP == idxP_phase && isPhaseParse) tmp = &phase;
303  else tmp = nullptr;
304  if (tmp != nullptr)
305  {
306  File.read((char*)tmp, PropertyTable[elements[idxE].properties[idxP].propertyType].first);
307  }
308  }
309 
310  (*vertices)[e].point.pos[_X] = x;
311  (*vertices)[e].point.pos[_Y] = y;
312  (*vertices)[e].point.pos[_Z] = z;
313 
314  if (!found_face)
315  {
316  (*vertices)[e].color.color[_R] = (Real)(red / 255.f);
317  (*vertices)[e].color.color[_G] = (Real)(green / 255.f);
318  (*vertices)[e].color.color[_B] = (Real)(blue / 255.f);
319  }
320  if (isPhaseParse) {
321  (*vertices)[e].phase = (Real)phase;
322  }
323  }
324  //face data parsing
325  else if (idxE == idxE_face) {
326  auto red = 0;
327  auto green = 0;
328  auto blue = 0;
329  auto alpha = 0;
330  void* tmp = nullptr;
331 
332  //line Processing
333  for (int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
334  // do not processing
335  if (elements[idxE].properties[idxP].isList) { // list type
336 
337  auto nCnt = 0;
338  File.read((char*)&nCnt, PropertyTable[elements[idxE].properties[idxP].listType].first);
339  int* pTest = new int[nCnt];
340  for (int i = 0; i < nCnt; ++i) {
341  File.read((char*)&pTest[i], PropertyTable[elements[idxE].properties[idxP].propertyType].first);
342  }
343  delete[] pTest;
344  }
345 
346  if (idxP == idxP_red) tmp = &red;
347  else if (idxP == idxP_green) tmp = &green;
348  else if (idxP == idxP_blue) tmp = &blue;
349  else if (idxP == idxP_alpha) tmp = &alpha;
350  else tmp = nullptr;
351  if (tmp != nullptr)
352  {
353  File.read((char*)tmp, PropertyTable[elements[idxE].properties[idxP].propertyType].first);
354  }
355 
356  (*vertices)[e].color.color[_R] = (Real)(red / 255.f);
357  (*vertices)[e].color.color[_G] = (Real)(green / 255.f);
358  (*vertices)[e].color.color[_B] = (Real)(blue / 255.f);
359  }
360  }
361  //color channel parsing
362  else if (found_channel && (idxE == idxE_color)) {
363  for (int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
364  File.read((char*)&color_channels, PropertyTable[elements[idxE].properties[idxP].propertyType].first);
365  }
366  }
367  }
368  }
369  }
370  // ASCII
371  else {
372  //parse Point Cloud Data
373  for (size_t idxE = 0; idxE < elements.size(); ++idxE) {
374  // parse vertex
375  for (longlong e = 0; e < elements[idxE].size; ++e) {
376 
377  std::getline(File, line);
378  lineStr.str(line);
379  std::string val;
380 
381  //color channel parsing
382  if (found_channel && (idxE == idxE_color)) {
383  lineStr.clear();
384  lineStr >> val;
385  color_channels = std::stoi(val);
386  }
387 
388  //vertex data parsing
389  if (idxE == idxE_vertex) {
390  Real x = 0.0;
391  Real y = 0.0;
392  Real z = 0.0;
393  auto red = 0;
394  auto green = 0;
395  auto blue = 0;
396  auto alpha = 0;
397  auto phase = 0.f;
398 
399  //line Processing
400  for (int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
401  lineStr.clear();
402 
403  lineStr >> val;
404 
405  if (idxP == idxP_x) x = std::stod(val);
406  else if (idxP == idxP_y) y = std::stod(val);
407  else if (idxP == idxP_z) z = std::stod(val);
408  else if (idxP == idxP_red) red = std::stoi(val);
409  else if (idxP == idxP_green) green = std::stoi(val);
410  else if (idxP == idxP_blue) blue = std::stoi(val);
411  else if (idxP == idxP_alpha) alpha = std::stoi(val);
412  else if ((idxP == idxP_phase) && isPhaseParse) phase = std::stod(val);
413  }
414 
415  (*vertices)[e].point.pos[_X] = x;
416  (*vertices)[e].point.pos[_Y] = y;
417  (*vertices)[e].point.pos[_Z] = z;
418 
419  if (!found_face)
420  {
421  (*vertices)[e].color.color[_R] = (Real)(red / 255.f);
422  (*vertices)[e].color.color[_G] = (Real)(green / 255.f);
423  (*vertices)[e].color.color[_B] = (Real)(blue / 255.f);
424  }
425  if (isPhaseParse) {
426  (*vertices)[e].phase = (Real)phase;
427  }
428  }
429  }
430  }
431  }
432  File.close();
433 
434  // post process
435  if (!found_channel) {
436  for (ulonglong i = 0; i < n_points; ++i) {
437  (*vertices)[i].color.color[_R] = 0.5;
438  (*vertices)[i].color.color[_G] = 0.5;
439  (*vertices)[i].color.color[_B] = 0.5;
440  }
441  }
442  return true;
443  }
444  }
445  else {
446  LOG("<FAILED> Loading ply file.\n");
447  return false;
448  }
449 }
450 
451 bool PLYparser::savePLY(const std::string& fileName, const ulonglong n_points, Vertex* vertices, bool isBinary)
452 {
453  if (vertices == nullptr) {
454  LOG("<FAILED> There is not data for saving ply file.\n");
455  return false;
456  }
457 
458  std::string outputPath = fileName;
459  if ((fileName.find(".ply") == std::string::npos) && (fileName.find(".PLY") == std::string::npos))
460  outputPath.append(".ply");
461  if (isBinary)
462  {
463  std::ofstream File(outputPath, std::ios::out | std::ios::trunc | std::ios::binary);
464 
465  if (File.is_open()) {
466  File << "ply\n";
467  File << "format ascii 1.0\n";
468  File << "comment Point Cloud Data Format in OpenHolo Library v" << _OPH_LIB_VERSION_MAJOR_ << "." << _OPH_LIB_VERSION_MINOR_ << "\n";
469  File << "element color 1\n";
470  File << "property int channel\n";
471  File << "element vertex " << n_points << std::endl;
472  File << "property float x\n";
473  File << "property float y\n";
474  File << "property float z\n";
475  File << "property uchar red\n";
476  File << "property uchar green\n";
477  File << "property uchar blue\n";
478  File << "property Real phase\n";
479  File << "end_header\n";
480  int color_channels = 3;
481  File.write(reinterpret_cast<char*>(&color_channels), sizeof(color_channels));
482 
483  for (ulonglong i = 0; i < n_points; ++i) {
484  float x = vertices[i].point.pos[_X];
485  float y = vertices[i].point.pos[_Y];
486  float z = vertices[i].point.pos[_Z];
487  char r = vertices[i].color.color[_R] * 255.f + 0.5f;
488  char g = vertices[i].color.color[_G] * 255.f + 0.5f;
489  char b = vertices[i].color.color[_B] * 255.f + 0.5f;
490  // Vertex Geometry
491  File.write(reinterpret_cast<char *>(&x), sizeof(x));
492  File.write(reinterpret_cast<char *>(&y), sizeof(y));
493  File.write(reinterpret_cast<char *>(&z), sizeof(z));
494  File.write(reinterpret_cast<char *>(&r), sizeof(r));
495  File.write(reinterpret_cast<char *>(&g), sizeof(g));
496  File.write(reinterpret_cast<char *>(&b), sizeof(b));
497  }
498  File.close();
499  return true;
500  }
501  }
502  else
503  {
504  std::ofstream File(outputPath, std::ios::out | std::ios::trunc);
505 
506  if (File.is_open()) {
507  File << "ply\n";
508  File << "format ascii 1.0\n";
509  File << "comment Point Cloud Data Format in OpenHolo Library v" << _OPH_LIB_VERSION_MAJOR_ << "." << _OPH_LIB_VERSION_MINOR_ << "\n";
510  File << "element color 1\n";
511  File << "property int channel\n";
512  File << "element vertex " << n_points << std::endl;
513  File << "property float x\n";
514  File << "property float y\n";
515  File << "property float z\n";
516  File << "property uchar red\n";
517  File << "property uchar green\n";
518  File << "property uchar blue\n";
519  File << "property Real phase\n";
520  File << "end_header\n";
521  int color_channels = 3;
522  File << color_channels << std::endl;
523 
524  for (ulonglong i = 0; i < n_points; ++i) {
525  // Vertex Geometry
526  File << std::fixed << vertices[i].point.pos[_X] << " " << vertices[i].point.pos[_Y] << " " << vertices[i].point.pos[_Z] << " ";
527  // Color
528  File << vertices[i].color.color[_R] * 255.f + 0.5f << " " << vertices[i].color.color[_G] * 255.f + 0.5f << " " << vertices[i].color.color[_B] * 255.f + 0.5f << " ";
529  // Phase
530  File << std::fixed << vertices[i].phase << std::endl;
531  }
532  File.close();
533  return true;
534  }
535  else {
536  LOG("<FAILED> Saving ply file.\n");
537  return false;
538  }
539  }
540  return false;
541 }
542 
543 bool PLYparser::loadPLY(const std::string& fileName, ulonglong& n_vertices, Face** faces)
544 {
545  std::string inputPath = fileName;
546  if ((inputPath.find(".ply") == std::string::npos) && (inputPath.find(".PLY") == std::string::npos))
547  inputPath.append(".ply");
548  std::ifstream File(inputPath, std::ios::in | std::ios::binary);
549 
550  int color_channels;
551  bool isBinary = false;
552  bool isBigEndian = false;
553  std::vector<PlyElement> elements;
554  std::vector<std::string> comments;
555  std::vector<std::string> objInfo;
556 
557  if (File.is_open()) {
558  //parse header
559  std::string line;
560  std::getline(File, line);
561  std::istringstream lineStr(line);
562  std::string token;
563  lineStr >> token;
564 
565  if ((token != "ply") && (token != "PLY")) {
566  LOG("<FAILED> Wrong file ext: %s\n", token.c_str());
567  File.close();
568  return false;
569  }
570  else {
571  //parse PLY header
572  while (std::getline(File, line)) {
573  lineStr.clear();
574  lineStr.str(line);
575  std::istream(lineStr.rdbuf()) >> token;
576 
577  if (token == "comment") comments.push_back((8 > 0) ? line.erase(0, 8) : line);
578  else if (token == "format") {
579  std::string str;
580  lineStr >> str;
581  if (str == "binary_little_endian") isBinary = true;
582  else if (str == "binary_big_endian") isBinary = isBigEndian = true;
583  }
584  else if (token == "element") elements.emplace_back(lineStr);
585  else if (token == "property") {
586  if (!elements.size())
587  LOG("<FAILED> No Elements defined, file is malformed.\n");
588  elements.back().properties.emplace_back(lineStr);
589  }
590  else if (token == "obj_info") objInfo.push_back((9 > 0) ? line.erase(0, 9) : line);
591  else if (token == "end_header") break;
592  }
593 #ifdef _DEBUG
594  //print comment list
595  for (auto cmt : comments) {
596  LOG("Comment : %s\n", cmt.c_str());
597  }
598 
599  //print element and property list
600  for (auto elmnt : elements) {
601  LOG("Element - %s : ( %lld )\n", elmnt.name.c_str(), elmnt.size);
602  for (auto Property : elmnt.properties) {
603  LOG("\tProperty : %s : ( %s )\n", Property.name.c_str(), PropertyTable[Property.propertyType].second);
604  }
605  }
606 #endif
607  longlong idxE_color = -1;
608  int idxP_channel = -1;
609  bool ok_channel = findIdxOfPropertiesAndElement(elements, "color", "channel", idxE_color, idxP_channel);
610 
611  longlong idxE_vertex = -1;
612  int idxP_face_idx = -1;
613  int idxP_x = -1;
614  int idxP_y = -1;
615  int idxP_z = -1;
616  bool ok_vertex = findIdxOfPropertiesAndElement(elements, "vertex", "face_idx", idxE_vertex, idxP_face_idx);
617  ok_vertex = findIdxOfPropertiesAndElement(elements, "vertex", "x", idxE_vertex, idxP_x);
618  ok_vertex = findIdxOfPropertiesAndElement(elements, "vertex", "y", idxE_vertex, idxP_y);
619  ok_vertex = findIdxOfPropertiesAndElement(elements, "vertex", "z", idxE_vertex, idxP_z);
620 
621  if (!ok_vertex) {
622  LOG("<FAILED> File is not having vertices data.\n");
623  File.close();
624  return false;
625  }
626 
627  int idxP_red = -1;
628  int idxP_green = -1;
629  int idxP_blue = -1;
630  int idxP_alpha = -1;
631  bool ok_color = findIdxOfPropertiesAndElement(elements, "vertex", "red", idxE_vertex, idxP_red);
632  ok_color = findIdxOfPropertiesAndElement(elements, "vertex", "green", idxE_vertex, idxP_green);
633  ok_color = findIdxOfPropertiesAndElement(elements, "vertex", "blue", idxE_vertex, idxP_blue);
634  if (!ok_color) {
635  ok_color = findIdxOfPropertiesAndElement(elements, "vertex", "diffuse_red", idxE_vertex, idxP_red);
636  ok_color = findIdxOfPropertiesAndElement(elements, "vertex", "diffuse_green", idxE_vertex, idxP_green);
637  ok_color = findIdxOfPropertiesAndElement(elements, "vertex", "diffuse_blue", idxE_vertex, idxP_blue);
638 
639  if (!ok_vertex) {
640  LOG("<FAILED> File is not having color data.\n");
641  File.close();
642  return false;
643  }
644  }
645 
646  n_vertices = elements[idxE_vertex].size;
647 
648  // Memory allocation
649  if (*faces != nullptr)
650  {
651  delete[] * faces;
652  *faces = nullptr;
653  }
654 
655 
656  *faces = new Face[n_vertices];
657  std::memset(*faces, 0, sizeof(Face) * n_vertices);
658 
659  // Binary Mode
660  if (isBinary)
661  {
662  // Elements Size
663  for (size_t idxE = 0; idxE < elements.size(); ++idxE) {
664  // Property Size
665  for (longlong e = 0; e < elements[idxE].size; ++e) {
666 
667  //color channel parsing
668  if (ok_channel && (idxE == idxE_color)) {
669  for (int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
670  int nSize = PropertyTable[elements[idxE].properties[idxP].propertyType].first;
671  void *tmp = &color_channels;
672  if (tmp != nullptr) {
673  File.read((char*)tmp, nSize);
674  }
675  }
676  }
677 
678  //vertex data parsing
679  if (idxE == idxE_vertex) {
680  auto face = 0;
681  auto x = 0.f;
682  auto y = 0.f;
683  auto z = 0.f;
684  auto red = 0.f;
685  auto green = 0.f;
686  auto blue = 0.f;
687  void *tmp = nullptr;
688 
689  //line Processing
690  for (int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
691 
692  if (idxP == idxP_face_idx) tmp = &face;
693  else if (idxP == idxP_x) tmp = &x;
694  else if (idxP == idxP_y) tmp = &y;
695  else if (idxP == idxP_z) tmp = &z;
696  else if (idxP == idxP_red) tmp = &red;
697  else if (idxP == idxP_green) tmp = &green;
698  else if (idxP == idxP_blue) tmp = &blue;
699 
700  if (tmp != nullptr)
701  {
702  File.read((char*)tmp, PropertyTable[elements[idxE].properties[idxP].propertyType].first);
703  }
704  }
705 
706  int div = e / 3;
707  int mod = e % 3;
708 
709  (*faces)[div].idx = face;
710  (*faces)[div].vertices[mod].point.pos[_X] = x;
711  (*faces)[div].vertices[mod].point.pos[_Y] = y;
712  (*faces)[div].vertices[mod].point.pos[_Z] = z;
713  (*faces)[div].vertices[mod].color.color[_R] = (Real)(red / 255.f);
714  (*faces)[div].vertices[mod].color.color[_G] = (Real)(green / 255.f);
715  (*faces)[div].vertices[mod].color.color[_B] = (Real)(blue / 255.f);
716  }
717  }
718  }
719 
720  }
721  // Text Mode
722  else
723  {
724  for (size_t idxE = 0; idxE < elements.size(); ++idxE) {
725 
726  // Parse element vertex
727  for (longlong e = 0; e < elements[idxE].size; ++e) {
728 
729  std::getline(File, line);
730  lineStr.clear();
731  lineStr.str(line);
732  std::string val;
733  if (ok_channel && (idxE == idxE_color)) {
734  lineStr >> val;
735  color_channels = std::stoi(val);
736  }
737 
738  //vertex data parsing
739  if (idxE == idxE_vertex) {
740  auto face = 0;
741  auto x = 0.f;
742  auto y = 0.f;
743  auto z = 0.f;
744  auto red = 0.f;
745  auto green = 0.f;
746  auto blue = 0.f;
747 
748  //line Processing
749  for (int p = 0; p < elements[idxE].properties.size(); ++p) {
750  lineStr.clear();
751  lineStr >> val;
752  if (p == idxP_face_idx) face = std::stoi(val);
753  if (p == idxP_x) x = std::stof(val);
754  else if (p == idxP_y) y = std::stof(val);
755  else if (p == idxP_z) z = std::stof(val);
756  else if (p == idxP_red) red = std::stoi(val);
757  else if (p == idxP_green) green = std::stoi(val);
758  else if (p == idxP_blue) blue = std::stoi(val);
759  }
760 
761  int div = e / 3;
762  int mod = e % 3;
763 
764  (*faces)[div].idx = div;
765  (*faces)[div].vertices[mod].point.pos[_X] = x;
766  (*faces)[div].vertices[mod].point.pos[_Y] = y;
767  (*faces)[div].vertices[mod].point.pos[_Z] = z;
768  (*faces)[div].vertices[mod].color.color[_R] = (Real)(red / 255.f);
769  (*faces)[div].vertices[mod].color.color[_G] = (Real)(green / 255.f);
770  (*faces)[div].vertices[mod].color.color[_B] = (Real)(blue / 255.f);
771  }
772  }
773  }
774  }
775 
776  File.close();
777 
778  return true;
779  }
780  }
781  else {
782  LOG("<FAILED> Loading ply file.\n");
783  return false;
784  }
785 }
786 
787 bool PLYparser::savePLY(const std::string& fileName, const ulonglong n_vertices, Face *faces, bool isBinary)
788 {
789  if (faces == nullptr) {
790  LOG("<FAILED> There is not data for saving ply file.\n");
791  return false;
792  }
793 
794  std::string outputPath = fileName;
795  if ((outputPath.find(".ply") == std::string::npos) && (outputPath.find(".PLY") == std::string::npos)) outputPath += ".ply";
796 
797  if (isBinary)
798  {
799  std::ofstream File(outputPath, std::ios::out | std::ios::trunc | std::ios::binary);
800 
801  if (File.is_open()) {
802  File << "ply\n";
803  File << "format ascii 1.0\n";
804  File << "comment Triangle Mesh Data Format in OpenHolo Library v" << _OPH_LIB_VERSION_MAJOR_ << "." << _OPH_LIB_VERSION_MINOR_ << "\n";
805  File << "element color 1\n";
806  File << "property int channel\n";
807  File << "element vertex " << n_vertices << std::endl;
808  File << "property uint face_idx\n";
809  File << "property float x\n";
810  File << "property float y\n";
811  File << "property float z\n";
812  File << "property uchar red\n";
813  File << "property uchar green\n";
814  File << "property uchar blue\n";
815  File << "end_header\n";
816  int color_channels = 3;
817 
818  File.write(reinterpret_cast<char*>(&color_channels), sizeof(color_channels));
819 
820  for (ulonglong i = 0; i < n_vertices; ++i) {
821 
822  int div = i / 3;
823  int mod = i % 3;
824 
825  uint face_idx = faces[div].idx;
826  float x = faces[div].vertices[mod].point.pos[_X];
827  float y = faces[div].vertices[mod].point.pos[_Y];
828  float z = faces[div].vertices[mod].point.pos[_Z];
829  char r = faces[div].vertices[mod].color.color[_R] * 255.f + 0.5f;
830  char g = faces[div].vertices[mod].color.color[_G] * 255.f + 0.5f;
831  char b = faces[div].vertices[mod].color.color[_B] * 255.f + 0.5f;
832 
833  // index
834  File.write(reinterpret_cast<char*>(&face_idx), sizeof(face_idx));
835 
836  // Vertex Geometry
837  File.write(reinterpret_cast<char*>(&x), sizeof(x));
838  File.write(reinterpret_cast<char*>(&y), sizeof(y));
839  File.write(reinterpret_cast<char*>(&z), sizeof(z));
840  File.write(reinterpret_cast<char*>(&r), sizeof(r));
841  File.write(reinterpret_cast<char*>(&g), sizeof(g));
842  File.write(reinterpret_cast<char*>(&b), sizeof(b));
843  }
844  File.close();
845  return true;
846  }
847  else {
848  LOG("<FAILED> Saving ply file.\n");
849  return false;
850  }
851  }
852  else
853  {
854  std::ofstream File(outputPath, std::ios::out | std::ios::trunc);
855 
856  if (File.is_open()) {
857  File << "ply\n";
858  File << "format ascii 1.0\n";
859  File << "comment Triangle Mesh Data Format in OpenHolo Library v" << _OPH_LIB_VERSION_MAJOR_ << "." << _OPH_LIB_VERSION_MINOR_ << "\n";
860  File << "element color 1\n";
861  File << "property int channel\n";
862  File << "element vertex " << n_vertices << std::endl;
863  File << "property uint face_idx\n";
864  File << "property float x\n";
865  File << "property float y\n";
866  File << "property float z\n";
867  File << "property uchar red\n";
868  File << "property uchar green\n";
869  File << "property uchar blue\n";
870  File << "end_header\n";
871  int color_channels = 3;
872  File << color_channels << std::endl;
873 
874  for (ulonglong i = 0; i < n_vertices; ++i) {
875  int div = i / 3;
876  int mod = i % 3;
877 
878  //Vertex Face Index
879  File << std::fixed << faces[div].idx << " ";
880 
881  //Vertex Geometry
882  File << std::fixed << faces[div].vertices[mod].point.pos[_X] << " " << faces[div].vertices[mod].point.pos[_Y] << " " << faces[div].vertices[mod].point.pos[_Z] << " ";
883 
884  //Color Amplitude
885  File << faces[div].vertices[mod].color.color[_R] * 255.f + 0.5f << " " << faces[div].vertices[mod].color.color[_G] * 255.f + 0.5f << " " << faces[div].vertices[mod].color.color[_B] * 255.f + 0.5f << " ";
886 
887  }
888  File.close();
889  return true;
890  }
891  else {
892  LOG("<FAILED> Saving ply file.\n");
893  return false;
894  }
895  }
896 }
Color color
Definition: struct.h:104
bool loadPLY(const std::string &fileName, ulonglong &n_points, Vertex **vertices)
Definition: PLYparser.cpp:142
Point point
Definition: struct.h:103
#define _B
Definition: define.h:116
bool savePLY(const std::string &fileName, const ulonglong n_points, Vertex *vertices, bool isBinary)
Definition: PLYparser.cpp:451
float Real
Definition: typedef.h:55
long long longlong
Definition: typedef.h:66
#define _Y
Definition: define.h:96
Real phase
Definition: struct.h:105
#define _OPH_LIB_VERSION_MAJOR_
Definition: include.h:49
unsigned long long ulonglong
Definition: typedef.h:67
#define _X
Definition: define.h:92
return true
Definition: Openholo.cpp:434
#define _R
Definition: define.h:108
ulonglong idx
Definition: struct.h:116
Vertex vertices[3]
Definition: struct.h:117
Definition: struct.h:102
Real pos[3]
Definition: struct.h:87
Definition: struct.h:115
#define _OPH_LIB_VERSION_MINOR_
Definition: include.h:50
#define _Z
Definition: define.h:100
Real color[3]
Definition: struct.h:95
unsigned int uint
Definition: typedef.h:62
#define _G
Definition: define.h:112