23#ifndef VCL_IO_MESH_PLY_DETAIL_HEADER_H
24#define VCL_IO_MESH_PLY_DETAIL_HEADER_H
28#include <vclib/io/file_info.h>
29#include <vclib/io/read.h>
31#include <vclib/space/complex.h>
37namespace vcl::detail {
48 ply::Format mFormat = ply::UNKNOWN;
50 std::vector<PlyElement> mElements;
51 std::vector<std::string> mTextureFiles;
60 using iterator = std::vector<PlyElement>::const_iterator;
62 PlyHeader() =
default;
67 std::vector<std::string> textureFiles = std::vector<std::string>()) :
68 mValid(true), mFormat(format)
70 setInfo(info, textureFiles, format);
73 PlyHeader(std::istream& file,
const std::string& filename =
"")
78 std::getline(file, line);
79 removeCarriageReturn(line);
80 if (line.compare(0, 3,
"ply") == 0) {
82 bool firstElement =
true;
83 std::string headerLine;
86 Tokenizer spaceTokenizer =
87 readAndTokenizeNextNonEmptyLine(file);
89 Tokenizer::iterator token = spaceTokenizer.begin();
91 if (headerLine ==
"format") {
93 if (*token ==
"ascii")
96 *token ==
"binary_little_endian" ||
98 mFormat = ply::BINARY_LITTLE_ENDIAN;
99 else if (*token ==
"binary_big_endian")
100 mFormat = ply::BINARY_BIG_ENDIAN;
103 else if (headerLine ==
"comment") {
105 if (token != spaceTokenizer.end()) {
106 if (containsCaseInsensitive(*token,
"texture")) {
108 if (token != spaceTokenizer.end()) {
109 std::string textName = *token;
111 findCaseInsensitive(textName,
"<this>");
112 if (it != textName.end()) {
113 uint pos = it - textName.begin();
118 textName.substr(0, pos) + fn +
120 pos + 6, textName.size());
122 mTextureFiles.push_back(textName);
128 else if (headerLine ==
"element") {
133 if (element.type == ply::VERTEX)
134 mVertElemPos = mElements.size();
135 if (element.type == ply::FACE)
136 mFaceElemPos = mElements.size();
137 if (element.type == ply::EDGE)
138 mEdgeElemPos = mElements.size();
139 if (element.type == ply::TRISTRIP)
140 mTriStripElemPos = mElements.size();
141 mElements.push_back(element);
142 element = PlyElement();
144 element = readElement(spaceTokenizer);
145 firstElement =
false;
147 else if (headerLine ==
"property") {
148 PlyProperty p = readProperty(spaceTokenizer);
149 element.properties.push_back(p);
152 else if (headerLine ==
"end_header") {
153 if (element.type == ply::VERTEX)
154 mVertElemPos = mElements.size();
155 if (element.type == ply::FACE)
156 mFaceElemPos = mElements.size();
157 if (element.type == ply::EDGE)
158 mEdgeElemPos = mElements.size();
159 if (element.type == ply::TRISTRIP)
160 mTriStripElemPos = mElements.size();
161 mElements.push_back(element);
164 }
while (!error && headerLine !=
"end_header");
165 mValid = !error && hasVertices();
171 mFormat = ply::UNKNOWN;
173 mTextureFiles.clear();
182 bool isValid()
const {
return mValid; }
184 ply::Format format()
const {
return mFormat; }
186 MeshInfo getInfo()
const
193 for (
const PlyProperty& p : mElements[mVertElemPos].properties) {
197 case ply::z: mod.setPerVertexPosition();
break;
200 case ply::nz: mod.setPerVertexNormal();
break;
204 case ply::alpha: mod.setPerVertexColor();
break;
205 case ply::quality: mod.setPerVertexQuality();
break;
206 case ply::texture_u: mod.setPerVertexTexCoord();
break;
207 case ply::texnumber: mod.setPerVertexMaterialIndex();
break;
209 if (p.type <= ply::PropertyType::DOUBLE) {
210 mod.addPerVertexCustomComponent(
219 for (
const PlyProperty& p : mElements[mFaceElemPos].properties) {
221 case ply::vertex_indices:
222 mod.setPerFaceVertexReferences();
226 case ply::nz: mod.setPerFaceNormal();
break;
230 case ply::alpha: mod.setPerFaceColor();
break;
231 case ply::quality: mod.setPerFaceQuality();
break;
232 case ply::texnumber: mod.setPerFaceMaterialIndex();
break;
233 case ply::texcoord: mod.setPerFaceWedgeTexCoords();
break;
235 if (p.type <= ply::PropertyType::DOUBLE) {
236 mod.addPerFaceCustomComponent(
245 for (
const PlyProperty& p :
246 mElements[mTriStripElemPos].properties) {
248 case ply::vertex_indices:
249 mod.setPerFaceVertexReferences();
253 case ply::nz: mod.setPerFaceNormal();
break;
257 case ply::alpha: mod.setPerFaceColor();
break;
258 case ply::quality: mod.setPerFaceQuality();
break;
259 case ply::texcoord: mod.setPerFaceWedgeTexCoords();
break;
266 for (
const PlyProperty& p : mElements[mEdgeElemPos].properties) {
268 case ply::vertex_indices:
269 mod.setPerEdgeVertexReferences();
273 case ply::nz: mod.setPerEdgeNormal();
break;
277 case ply::alpha: mod.setPerEdgeColor();
break;
278 case ply::quality: mod.setPerEdgeQuality();
break;
283 if (mTextureFiles.size() > 0) {
289 bool hasVertices()
const {
return mVertElemPos !=
UINT_NULL; }
291 bool hasFaces()
const {
return mFaceElemPos !=
UINT_NULL; }
293 bool hasEdges()
const {
return mEdgeElemPos !=
UINT_NULL; }
295 bool hasTriStrips()
const {
return mTriStripElemPos !=
UINT_NULL; }
297 bool hasTextureFileNames()
const {
return mTextureFiles.
size() > 0; }
299 uint numberVertices()
const
301 assert(hasVertices());
302 return mElements[mVertElemPos].numberElements;
305 uint numberFaces()
const
308 return mElements[mFaceElemPos].numberElements;
311 uint numberEdges()
const
314 return mElements[mEdgeElemPos].numberElements;
317 uint numberTriStrips()
const
319 assert(hasTriStrips());
320 return mElements[mTriStripElemPos].numberElements;
323 uint numberTextureFileNames()
const {
return mTextureFiles.
size(); }
325 const std::list<PlyProperty>& vertexProperties()
const
327 assert(hasVertices());
328 return mElements[mVertElemPos].properties;
331 const std::list<PlyProperty>& faceProperties()
const
334 return mElements[mFaceElemPos].properties;
337 const std::list<PlyProperty>& edgeProperties()
const
340 return mElements[mEdgeElemPos].properties;
343 const std::list<PlyProperty>& triStripsProperties()
const
345 assert(hasTriStrips());
346 return mElements[mTriStripElemPos].properties;
349 const std::vector<std::string>& textureFileNames()
const
351 return mTextureFiles;
354 bool errorWhileLoading()
const {
return !mValid; }
356 void setNumberVertices(
unsigned long int nV)
358 assert(hasVertices());
359 mElements[mVertElemPos].numberElements = nV;
362 void setNumberFaces(
unsigned long int nF)
365 mElements[mFaceElemPos].numberElements = nF;
368 void setNumberEdges(
unsigned long int nE)
371 mElements[mEdgeElemPos].numberElements = nE;
374 void pushTextureFileName(
const std::string& tn)
376 mTextureFiles.push_back(tn);
380 const MeshInfo& info,
381 std::vector<std::string> textureFileNames = std::vector<std::string>(),
382 ply::Format format = ply::BINARY_LITTLE_ENDIAN)
387 mTextureFiles = textureFileNames;
388 if (info.hasVertices()) {
389 mVertElemPos = mElements.size();
391 vElem.type = ply::VERTEX;
392 if (info.hasPerVertexPosition()) {
393 PlyProperty px, py, pz;
395 px.type = info.perVertexPositionType();
397 py.type = info.perVertexPositionType();
399 pz.type = info.perVertexPositionType();
400 vElem.properties.push_back(px);
401 vElem.properties.push_back(py);
402 vElem.properties.push_back(pz);
404 if (info.hasPerVertexNormal()) {
405 PlyProperty vnx, vny, vnz;
407 vnx.type = info.perVertexNormalType();
409 vny.type = info.perVertexNormalType();
411 vnz.type = info.perVertexNormalType();
412 vElem.properties.push_back(vnx);
413 vElem.properties.push_back(vny);
414 vElem.properties.push_back(vnz);
416 if (info.hasPerVertexColor()) {
417 PlyProperty vcr, vcg, vcb, vca;
419 vcr.type = info.perVertexColorType();
420 vcg.name = ply::green;
421 vcg.type = info.perVertexColorType();
422 vcb.name = ply::blue;
423 vcb.type = info.perVertexColorType();
424 vca.name = ply::alpha;
425 vca.type = info.perVertexColorType();
426 vElem.properties.push_back(vcr);
427 vElem.properties.push_back(vcg);
428 vElem.properties.push_back(vcb);
429 vElem.properties.push_back(vca);
431 if (info.hasPerVertexQuality()) {
433 vs.name = ply::quality;
434 vs.type = info.perVertexQualityType();
435 vElem.properties.push_back(vs);
437 if (info.hasPerVertexTexCoord()) {
438 PlyProperty tcu, tcv;
439 tcu.name = ply::texture_u;
440 tcu.type = info.perVertexTexCoordType();
441 tcv.name = ply::texture_v;
442 tcv.type = info.perVertexTexCoordType();
443 vElem.properties.push_back(tcu);
444 vElem.properties.push_back(tcv);
446 if (info.hasPerVertexMaterialIndex()) {
448 tcn.name = ply::texnumber;
449 tcn.type = info.perVertexMaterialIndexType();
450 vElem.properties.push_back(tcn);
452 if (info.hasPerVertexCustomComponents()) {
453 for (
const auto& cc : info.perVertexCustomComponents()) {
454 if (cc.type <= PrimitiveType::DOUBLE) {
456 pp.name = ply::unknown;
457 pp.unknownPropertyName = cc.name;
459 vElem.properties.push_back(pp);
463 mElements.push_back(vElem);
465 if (info.hasFaces()) {
466 mFaceElemPos = mElements.size();
468 fElem.type = ply::FACE;
469 if (info.hasPerFaceVertexReferences()) {
472 vids.name = ply::vertex_indices;
473 vids.type = PrimitiveType::UINT;
474 vids.listSizeType = PrimitiveType::UCHAR;
475 fElem.properties.push_back(vids);
477 if (info.hasPerFaceNormal()) {
478 PlyProperty fnx, fny, fnz;
480 fnx.type = info.perFaceNormalType();
482 fny.type = info.perFaceNormalType();
484 fnz.type = info.perFaceNormalType();
485 fElem.properties.push_back(fnx);
486 fElem.properties.push_back(fny);
487 fElem.properties.push_back(fnz);
489 if (info.hasPerFaceColor()) {
490 PlyProperty fcr, fcg, fcb, fca;
492 fcr.type = info.perFaceColorType();
493 fcg.name = ply::green;
494 fcg.type = info.perFaceColorType();
495 fcb.name = ply::blue;
496 fcb.type = info.perFaceColorType();
497 fca.name = ply::alpha;
498 fca.type = info.perFaceColorType();
499 fElem.properties.push_back(fcr);
500 fElem.properties.push_back(fcg);
501 fElem.properties.push_back(fcb);
502 fElem.properties.push_back(fca);
504 if (info.hasPerFaceQuality()) {
506 fs.name = ply::quality;
507 fs.type = info.perFaceQualityType();
508 fElem.properties.push_back(fs);
510 if (info.hasPerFaceWedgeTexCoords()) {
513 tc.listSizeType = PrimitiveType::UCHAR;
514 tc.name = ply::texcoord;
515 tc.type = info.perFaceWedgeTexCoordsType();
516 fElem.properties.push_back(tc);
518 if (info.hasPerFaceMaterialIndex()) {
520 tn.name = ply::texnumber;
521 tn.type = info.perFaceMaterialIndexType();
522 fElem.properties.push_back(tn);
524 if (info.hasPerFaceCustomComponents()) {
525 for (
const auto& cc : info.perFaceCustomComponents()) {
526 if (cc.type <= PrimitiveType::DOUBLE) {
528 pp.name = ply::unknown;
529 pp.unknownPropertyName = cc.name;
531 fElem.properties.push_back(pp);
535 mElements.push_back(fElem);
537 if (info.hasEdges()) {
538 mEdgeElemPos = mElements.size();
540 eElem.type = ply::EDGE;
541 if (info.hasPerEdgeVertexReferences()) {
543 v1.name = ply::vertex1;
544 v1.type = PrimitiveType::UINT;
545 eElem.properties.push_back(v1);
547 v2.name = ply::vertex2;
548 v2.type = PrimitiveType::UINT;
549 eElem.properties.push_back(v2);
551 mElements.push_back(eElem);
555 std::string toString()
const
562 case ply::ASCII: s +=
"ascii 1.0\n";
break;
563 case ply::BINARY_BIG_ENDIAN: s +=
"binary_big_endian 1.0\n";
break;
564 default: s +=
"binary_little_endian 1.0\n";
break;
567 s +=
"comment Generated by vclib\n";
568 for (
const std::string& str : mTextureFiles) {
569 s +=
"comment TextureFile " + str +
"\n";
571 for (
const PlyElement& e : mElements) {
575 s +=
"vertex " + std::to_string(e.numberElements) +
"\n";
578 s +=
"face " + std::to_string(e.numberElements) +
"\n";
581 s +=
"edge " + std::to_string(e.numberElements) +
"\n";
584 s +=
"tristrips " + std::to_string(e.numberElements) +
"\n";
587 s +=
"material " + std::to_string(e.numberElements) +
"\n";
590 s += e.unknownElementType +
" " +
591 std::to_string(e.numberElements) +
"\n";
594 for (
const PlyProperty& p : e.properties) {
598 s += typeToString(p.listSizeType) +
" ";
600 s += typeToString(p.type) +
" ";
601 if (p.name == ply::unknown)
602 s += p.unknownPropertyName +
"\n";
604 s += nameToString(p.name) +
"\n";
612 void setFormat(ply::Format f) { mFormat = f; }
614 iterator begin()
const {
return mElements.begin(); }
616 iterator end()
const {
return mElements.end(); }
619 PlyElement readElement(
const Tokenizer& lineTokenizer)
const
622 Tokenizer::iterator token = lineTokenizer.begin();
623 std::string s = *(++token);
625 e.type = ply::VERTEX;
626 e.numberElements = std::stoi(*(++token));
628 else if (s ==
"face") {
630 e.numberElements = std::stoi(*(++token));
632 else if (s ==
"edge") {
634 e.numberElements = std::stoi(*(++token));
636 else if (s ==
"tristrips") {
637 e.type = ply::TRISTRIP;
638 e.numberElements = std::stoi(*(++token));
642 e.numberElements = std::stoi(*(++token));
643 e.unknownElementType = s;
648 PlyProperty readProperty(
const Tokenizer& lineTokenizer)
const
651 Tokenizer::iterator token = lineTokenizer.begin();
652 std::string type = *(++token);
653 if (type ==
"list") {
655 std::string typeSize = *(++token);
656 std::string typeData = *(++token);
657 std::string name = *(++token);
658 p.listSizeType = stringToType(typeSize);
659 p.type = stringToType(typeData);
660 p.name = stringToName(name);
661 if (p.name == ply::unknown)
662 p.unknownPropertyName = name;
666 std::string name = *(++token);
667 p.type = stringToType(type);
668 p.name = stringToName(name);
669 if (p.name == ply::unknown)
670 p.unknownPropertyName = name;
676 ply::PropertyName stringToName(
const std::string& name)
const
678 ply::PropertyName pn = ply::unknown;
699 if (name ==
"quality" || name ==
"scalar")
701 if (name ==
"texture_u" || name ==
"s" || name ==
"u")
703 if (name ==
"texture_v" || name ==
"t" || name ==
"v")
705 if (name ==
"texnumber")
707 if (name ==
"vertex_indices")
708 pn = ply::vertex_indices;
709 if (name ==
"texcoord")
711 if (name ==
"vertex1")
713 if (name ==
"vertex2")
719 ply::PropertyType stringToType(
const std::string& type)
const
721 ply::PropertyType pt = ply::PropertyType::UCHAR;
723 pt = ply::PropertyType::CHAR;
725 pt = ply::PropertyType::UCHAR;
727 pt = ply::PropertyType::SHORT;
728 if (type ==
"ushort")
729 pt = ply::PropertyType::USHORT;
731 pt = ply::PropertyType::INT;
733 pt = ply::PropertyType::UINT;
735 pt = ply::PropertyType::FLOAT;
736 if (type ==
"double")
737 pt = ply::PropertyType::DOUBLE;
741 std::string nameToString(ply::PropertyName n)
const
744 case ply::x:
return "x";
745 case ply::y:
return "y";
746 case ply::z:
return "z";
747 case ply::nx:
return "nx";
748 case ply::ny:
return "ny";
749 case ply::nz:
return "nz";
750 case ply::red:
return "red";
751 case ply::green:
return "green";
752 case ply::blue:
return "blue";
753 case ply::alpha:
return "alpha";
754 case ply::quality:
return "quality";
755 case ply::texture_u:
return "texture_u";
756 case ply::texture_v:
return "texture_v";
757 case ply::texnumber:
return "texnumber";
758 case ply::vertex_indices:
return "vertex_indices";
759 case ply::texcoord:
return "texcoord";
760 case ply::vertex1:
return "vertex1";
761 case ply::vertex2:
return "vertex2";
762 default:
return "unknown";
766 std::string typeToString(ply::PropertyType t)
const
769 case ply::PropertyType::CHAR:
return "char";
770 case ply::PropertyType::UCHAR:
return "uchar";
771 case ply::PropertyType::SHORT:
return "short";
772 case ply::PropertyType::USHORT:
return "ushort";
773 case ply::PropertyType::INT:
return "int";
774 case ply::PropertyType::UINT:
return "uint";
775 case ply::PropertyType::FLOAT:
return "float";
776 case ply::PropertyType::DOUBLE:
return "double";
777 case ply::PropertyType::NONE:
return "";
PointT size() const
Computes the size of the box.
Definition box.h:267
static std::string fileNameWithoutExtension(const std::string &fullpath)
Get the file name without extension of a file.
Definition file_info.h:220
PrimitiveType DataType
Enum used to describe the type of Data stored in a component.
Definition mesh_info.h:114
constexpr uint UINT_NULL
The UINT_NULL value represent a null value of uint that is the maximum value that can be represented ...
Definition base.h:48