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")));
67 PLYparser::PlyProperty::PlyProperty(std::istream &is)
73 std::string countType;
74 is >> countType >> type;
75 listType = PLYparser::propertyTypeFromString(countType);
78 propertyType = PLYparser::propertyTypeFromString(type);
82 PLYparser::PlyProperty::PlyProperty(
const Type type,
const std::string &_name)
83 : propertyType(type),
name(_name)
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)
92 PLYparser::PlyElement::PlyElement(std::istream &is)
97 PLYparser::PlyElement::PlyElement(
const std::string &_name,
const ulonglong count)
98 :
name(_name), size(count)
102 PLYparser::Type PLYparser::propertyTypeFromString(
const std::string &t)
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;
115 bool PLYparser::findIdxOfPropertiesAndElement(
const std::vector<PlyElement> &elements,
const std::string &elementKey,
const std::string &propertyKeys,
longlong &elementIdx,
int &propertyIdx)
118 for (
size_t i = 0; i < elements.size(); ++i) {
119 if (elements[i].
name == elementKey) {
125 if (elementIdx >= 0) {
126 const PlyElement &element = elements[elementIdx];
129 for (
int j = 0; j < element.properties.size(); ++j) {
130 if (element.properties[j].name == propertyKeys) {
136 if (propertyIdx >= 0)
return true;
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);
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;
156 if (File.is_open()) {
159 std::getline(File, line);
160 std::istringstream lineStr(line);
165 if ((token !=
"ply") && (token !=
"PLY")) {
166 LOG(
"<FAILED> Wrong file ext: %s\n", token.c_str());
172 while (std::getline(File, line)) {
176 std::istream(lineStr.rdbuf()) >> token;
178 if (token ==
"comment") {
179 comments.push_back((8 > 0) ? line.erase(0, 8) : line);
181 else if (token ==
"format") {
185 if (str ==
"binary_little_endian") isBinary =
true;
186 else if (str ==
"binary_big_endian") isBinary = isBigEndian =
true;
188 else if (token ==
"element") {
189 elements.emplace_back(lineStr);
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);
196 else if (token ==
"obj_info") objInfo.push_back((9 > 0) ? line.erase(0, 9) : line);
197 else if (token ==
"end_header")
break;
202 for (
auto cmt : comments) {
203 LOG(
"Comment : %s\n", cmt.c_str());
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());
216 int idxP_channel = -1;
217 bool found_channel = findIdxOfPropertiesAndElement(elements,
"color",
"channel", idxE_color, idxP_channel);
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);
227 LOG(
"<FAILED> File is not having vertices data.\n");
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);
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);
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);
258 n_points = elements[idxE_vertex].size;
262 if (*vertices !=
nullptr)
268 *vertices =
new Vertex[n_points];
269 std::memset(*vertices, 0,
sizeof(
Vertex) * n_points);
272 bool isPhaseParse = findIdxOfPropertiesAndElement(elements,
"vertex",
"phase", idxE_vertex, idxP_phase);
277 for (
size_t idxE = 0; idxE < elements.size(); ++idxE) {
279 for (
longlong e = 0; e < elements[idxE].size; ++e) {
281 if (idxE == idxE_vertex) {
294 for (
int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
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;
306 File.read((
char*)tmp, PropertyTable[elements[idxE].properties[idxP].propertyType].first);
310 (*vertices)[e].point.pos[
_X] = x;
311 (*vertices)[e].point.pos[
_Y] = y;
312 (*vertices)[e].point.pos[
_Z] = z;
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);
321 (*vertices)[e].phase = (
Real)phase;
325 else if (idxE == idxE_face) {
333 for (
int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
335 if (elements[idxE].properties[idxP].isList) {
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);
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 = α
353 File.read((
char*)tmp, PropertyTable[elements[idxE].properties[idxP].propertyType].first);
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);
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);
373 for (
size_t idxE = 0; idxE < elements.size(); ++idxE) {
375 for (
longlong e = 0; e < elements[idxE].size; ++e) {
377 std::getline(File, line);
382 if (found_channel && (idxE == idxE_color)) {
385 color_channels = std::stoi(val);
389 if (idxE == idxE_vertex) {
400 for (
int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
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);
415 (*vertices)[e].point.pos[
_X] = x;
416 (*vertices)[e].point.pos[
_Y] = y;
417 (*vertices)[e].point.pos[
_Z] = z;
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);
426 (*vertices)[e].phase = (
Real)phase;
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;
446 LOG(
"<FAILED> Loading ply file.\n");
453 if (vertices ==
nullptr) {
454 LOG(
"<FAILED> There is not data for saving ply file.\n");
458 std::string outputPath = fileName;
459 if ((fileName.find(
".ply") == std::string::npos) && (fileName.find(
".PLY") == std::string::npos))
460 outputPath.append(
".ply");
463 std::ofstream File(outputPath, std::ios::out | std::ios::trunc | std::ios::binary);
465 if (File.is_open()) {
467 File <<
"format ascii 1.0\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));
483 for (
ulonglong i = 0; i < n_points; ++i) {
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));
504 std::ofstream File(outputPath, std::ios::out | std::ios::trunc);
506 if (File.is_open()) {
508 File <<
"format ascii 1.0\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;
524 for (
ulonglong i = 0; i < n_points; ++i) {
530 File << std::fixed << vertices[i].
phase << std::endl;
536 LOG(
"<FAILED> Saving ply file.\n");
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);
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;
557 if (File.is_open()) {
560 std::getline(File, line);
561 std::istringstream lineStr(line);
565 if ((token !=
"ply") && (token !=
"PLY")) {
566 LOG(
"<FAILED> Wrong file ext: %s\n", token.c_str());
572 while (std::getline(File, line)) {
575 std::istream(lineStr.rdbuf()) >> token;
577 if (token ==
"comment") comments.push_back((8 > 0) ? line.erase(0, 8) : line);
578 else if (token ==
"format") {
581 if (str ==
"binary_little_endian") isBinary =
true;
582 else if (str ==
"binary_big_endian") isBinary = isBigEndian =
true;
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);
590 else if (token ==
"obj_info") objInfo.push_back((9 > 0) ? line.erase(0, 9) : line);
591 else if (token ==
"end_header")
break;
595 for (
auto cmt : comments) {
596 LOG(
"Comment : %s\n", cmt.c_str());
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);
608 int idxP_channel = -1;
609 bool ok_channel = findIdxOfPropertiesAndElement(elements,
"color",
"channel", idxE_color, idxP_channel);
612 int idxP_face_idx = -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);
622 LOG(
"<FAILED> File is not having vertices data.\n");
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);
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);
640 LOG(
"<FAILED> File is not having color data.\n");
646 n_vertices = elements[idxE_vertex].size;
649 if (*faces !=
nullptr)
656 *faces =
new Face[n_vertices];
657 std::memset(*faces, 0,
sizeof(
Face) * n_vertices);
663 for (
size_t idxE = 0; idxE < elements.size(); ++idxE) {
665 for (
longlong e = 0; e < elements[idxE].size; ++e) {
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);
679 if (idxE == idxE_vertex) {
690 for (
int idxP = 0; idxP < elements[idxE].properties.size(); ++idxP) {
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;
702 File.read((
char*)tmp, PropertyTable[elements[idxE].properties[idxP].propertyType].first);
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);
724 for (
size_t idxE = 0; idxE < elements.size(); ++idxE) {
727 for (
longlong e = 0; e < elements[idxE].size; ++e) {
729 std::getline(File, line);
733 if (ok_channel && (idxE == idxE_color)) {
735 color_channels = std::stoi(val);
739 if (idxE == idxE_vertex) {
749 for (
int p = 0; p < elements[idxE].properties.size(); ++p) {
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);
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);
782 LOG(
"<FAILED> Loading ply file.\n");
789 if (faces ==
nullptr) {
790 LOG(
"<FAILED> There is not data for saving ply file.\n");
794 std::string outputPath = fileName;
795 if ((outputPath.find(
".ply") == std::string::npos) && (outputPath.find(
".PLY") == std::string::npos)) outputPath +=
".ply";
799 std::ofstream File(outputPath, std::ios::out | std::ios::trunc | std::ios::binary);
801 if (File.is_open()) {
803 File <<
"format ascii 1.0\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;
818 File.write(reinterpret_cast<char*>(&color_channels),
sizeof(color_channels));
820 for (
ulonglong i = 0; i < n_vertices; ++i) {
825 uint face_idx = faces[div].
idx;
834 File.write(reinterpret_cast<char*>(&face_idx),
sizeof(face_idx));
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));
848 LOG(
"<FAILED> Saving ply file.\n");
854 std::ofstream File(outputPath, std::ios::out | std::ios::trunc);
856 if (File.is_open()) {
858 File <<
"format ascii 1.0\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;
874 for (
ulonglong i = 0; i < n_vertices; ++i) {
879 File << std::fixed << faces[div].
idx <<
" ";
892 LOG(
"<FAILED> Saving ply file.\n");
bool loadPLY(const std::string &fileName, ulonglong &n_points, Vertex **vertices)
bool savePLY(const std::string &fileName, const ulonglong n_points, Vertex *vertices, bool isBinary)
unsigned long long ulonglong
#define _OPH_LIB_VERSION_MINOR_
#define _OPH_LIB_VERSION_MAJOR_