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;
208 if (p.type <= ply::PropertyType::DOUBLE) {
209 mod.addPerVertexCustomComponent(
218 for (
const PlyProperty& p : mElements[mFaceElemPos].properties) {
220 case ply::vertex_indices:
221 mod.setPerFaceVertexReferences();
225 case ply::nz: mod.setPerFaceNormal();
break;
229 case ply::alpha: mod.setPerFaceColor();
break;
230 case ply::quality: mod.setPerFaceQuality();
break;
231 case ply::texcoord: mod.setPerFaceWedgeTexCoords();
break;
233 if (p.type <= ply::PropertyType::DOUBLE) {
234 mod.addPerFaceCustomComponent(
243 for (
const PlyProperty& p :
244 mElements[mTriStripElemPos].properties) {
246 case ply::vertex_indices:
247 mod.setPerFaceVertexReferences();
251 case ply::nz: mod.setPerFaceNormal();
break;
255 case ply::alpha: mod.setPerFaceColor();
break;
256 case ply::quality: mod.setPerFaceQuality();
break;
257 case ply::texcoord: mod.setPerFaceWedgeTexCoords();
break;
264 for (
const PlyProperty& p : mElements[mEdgeElemPos].properties) {
266 case ply::vertex_indices:
267 mod.setPerEdgeVertexReferences();
271 case ply::nz: mod.setPerEdgeNormal();
break;
275 case ply::alpha: mod.setPerEdgeColor();
break;
276 case ply::quality: mod.setPerEdgeQuality();
break;
281 if (mTextureFiles.size() > 0) {
282 mod.setTextures(
true);
287 bool hasVertices()
const {
return mVertElemPos !=
UINT_NULL; }
289 bool hasFaces()
const {
return mFaceElemPos !=
UINT_NULL; }
291 bool hasEdges()
const {
return mEdgeElemPos !=
UINT_NULL; }
293 bool hasTriStrips()
const {
return mTriStripElemPos !=
UINT_NULL; }
295 bool hasTextureFileNames()
const {
return mTextureFiles.
size() > 0; }
297 uint numberVertices()
const
299 assert(hasVertices());
300 return mElements[mVertElemPos].numberElements;
303 uint numberFaces()
const
306 return mElements[mFaceElemPos].numberElements;
309 uint numberEdges()
const
312 return mElements[mEdgeElemPos].numberElements;
315 uint numberTriStrips()
const
317 assert(hasTriStrips());
318 return mElements[mTriStripElemPos].numberElements;
321 uint numberTextureFileNames()
const {
return mTextureFiles.
size(); }
323 const std::list<PlyProperty>& vertexProperties()
const
325 assert(hasVertices());
326 return mElements[mVertElemPos].properties;
329 const std::list<PlyProperty>& faceProperties()
const
332 return mElements[mFaceElemPos].properties;
335 const std::list<PlyProperty>& edgeProperties()
const
338 return mElements[mEdgeElemPos].properties;
341 const std::list<PlyProperty>& triStripsProperties()
const
343 assert(hasTriStrips());
344 return mElements[mTriStripElemPos].properties;
347 const std::vector<std::string>& textureFileNames()
const
349 return mTextureFiles;
352 bool errorWhileLoading()
const {
return !mValid; }
354 void setNumberVertices(
unsigned long int nV)
356 assert(hasVertices());
357 mElements[mVertElemPos].numberElements = nV;
360 void setNumberFaces(
unsigned long int nF)
363 mElements[mFaceElemPos].numberElements = nF;
366 void setNumberEdges(
unsigned long int nE)
369 mElements[mEdgeElemPos].numberElements = nE;
372 void pushTextureFileName(
const std::string& tn)
374 mTextureFiles.push_back(tn);
378 const MeshInfo& info,
379 std::vector<std::string> textureFileNames = std::vector<std::string>(),
380 ply::Format format = ply::BINARY_LITTLE_ENDIAN)
385 mTextureFiles = textureFileNames;
386 if (info.hasVertices()) {
387 mVertElemPos = mElements.size();
389 vElem.type = ply::VERTEX;
390 if (info.hasPerVertexPosition()) {
391 PlyProperty px, py, pz;
393 px.type = info.perVertexPositionType();
395 py.type = info.perVertexPositionType();
397 pz.type = info.perVertexPositionType();
398 vElem.properties.push_back(px);
399 vElem.properties.push_back(py);
400 vElem.properties.push_back(pz);
402 if (info.hasPerVertexNormal()) {
403 PlyProperty vnx, vny, vnz;
405 vnx.type = info.perVertexNormalType();
407 vny.type = info.perVertexNormalType();
409 vnz.type = info.perVertexNormalType();
410 vElem.properties.push_back(vnx);
411 vElem.properties.push_back(vny);
412 vElem.properties.push_back(vnz);
414 if (info.hasPerVertexColor()) {
415 PlyProperty vcr, vcg, vcb, vca;
417 vcr.type = info.perVertexColorType();
418 vcg.name = ply::green;
419 vcg.type = info.perVertexColorType();
420 vcb.name = ply::blue;
421 vcb.type = info.perVertexColorType();
422 vca.name = ply::alpha;
423 vca.type = info.perVertexColorType();
424 vElem.properties.push_back(vcr);
425 vElem.properties.push_back(vcg);
426 vElem.properties.push_back(vcb);
427 vElem.properties.push_back(vca);
429 if (info.hasPerVertexQuality()) {
431 vs.name = ply::quality;
432 vs.type = info.perVertexQualityType();
433 vElem.properties.push_back(vs);
435 if (info.hasPerVertexTexCoord()) {
436 PlyProperty tcu, tcv, tcn;
437 tcu.name = ply::texture_u;
438 tcu.type = info.perVertexTexCoordType();
439 tcv.name = ply::texture_v;
440 tcv.type = info.perVertexTexCoordType();
441 tcn.name = ply::texnumber;
442 tcn.type = PrimitiveType::USHORT;
443 vElem.properties.push_back(tcu);
444 vElem.properties.push_back(tcv);
445 vElem.properties.push_back(tcn);
447 if (info.hasPerVertexCustomComponents()) {
448 for (
const auto& cc : info.perVertexCustomComponents()) {
449 if (cc.type <= PrimitiveType::DOUBLE) {
451 pp.name = ply::unknown;
452 pp.unknownPropertyName = cc.name;
454 vElem.properties.push_back(pp);
458 mElements.push_back(vElem);
460 if (info.hasFaces()) {
461 mFaceElemPos = mElements.size();
463 fElem.type = ply::FACE;
464 if (info.hasPerFaceVertexReferences()) {
467 vids.name = ply::vertex_indices;
468 vids.type = PrimitiveType::UINT;
469 vids.listSizeType = PrimitiveType::UCHAR;
470 fElem.properties.push_back(vids);
472 if (info.hasPerFaceNormal()) {
473 PlyProperty fnx, fny, fnz;
475 fnx.type = info.perFaceNormalType();
477 fny.type = info.perFaceNormalType();
479 fnz.type = info.perFaceNormalType();
480 fElem.properties.push_back(fnx);
481 fElem.properties.push_back(fny);
482 fElem.properties.push_back(fnz);
484 if (info.hasPerFaceColor()) {
485 PlyProperty fcr, fcg, fcb, fca;
487 fcr.type = info.perFaceColorType();
488 fcg.name = ply::green;
489 fcg.type = info.perFaceColorType();
490 fcb.name = ply::blue;
491 fcb.type = info.perFaceColorType();
492 fca.name = ply::alpha;
493 fca.type = info.perFaceColorType();
494 fElem.properties.push_back(fcr);
495 fElem.properties.push_back(fcg);
496 fElem.properties.push_back(fcb);
497 fElem.properties.push_back(fca);
499 if (info.hasPerFaceQuality()) {
501 fs.name = ply::quality;
502 fs.type = (ply::PropertyType) info.perFaceQualityType();
503 fElem.properties.push_back(fs);
505 if (info.hasPerFaceWedgeTexCoords()) {
508 tc.listSizeType = PrimitiveType::UCHAR;
509 tc.name = ply::texcoord;
510 tc.type = (ply::PropertyType) info.perFaceWedgeTexCoordsType();
511 tn.name = ply::texnumber;
512 tn.type = PrimitiveType::USHORT;
513 fElem.properties.push_back(tc);
514 fElem.properties.push_back(tn);
516 if (info.hasPerFaceCustomComponents()) {
517 for (
const auto& cc : info.perFaceCustomComponents()) {
518 if (cc.type <= PrimitiveType::DOUBLE) {
520 pp.name = ply::unknown;
521 pp.unknownPropertyName = cc.name;
522 pp.type = (ply::PropertyType) cc.type;
523 fElem.properties.push_back(pp);
527 mElements.push_back(fElem);
529 if (info.hasEdges()) {
530 mEdgeElemPos = mElements.size();
532 eElem.type = ply::EDGE;
533 if (info.hasPerEdgeVertexReferences()) {
535 v1.name = ply::vertex1;
536 v1.type = PrimitiveType::UINT;
537 eElem.properties.push_back(v1);
539 v2.name = ply::vertex2;
540 v2.type = PrimitiveType::UINT;
541 eElem.properties.push_back(v2);
543 mElements.push_back(eElem);
547 std::string toString()
const
554 case ply::ASCII: s +=
"ascii 1.0\n";
break;
555 case ply::BINARY_BIG_ENDIAN: s +=
"binary_big_endian 1.0\n";
break;
556 default: s +=
"binary_little_endian 1.0\n";
break;
559 s +=
"comment Generated by vclib\n";
560 for (
const std::string& str : mTextureFiles) {
561 s +=
"comment TextureFile " + str +
"\n";
563 for (
const PlyElement& e : mElements) {
567 s +=
"vertex " + std::to_string(e.numberElements) +
"\n";
570 s +=
"face " + std::to_string(e.numberElements) +
"\n";
573 s +=
"edge " + std::to_string(e.numberElements) +
"\n";
576 s +=
"tristrips " + std::to_string(e.numberElements) +
"\n";
579 s +=
"material " + std::to_string(e.numberElements) +
"\n";
582 s += e.unknownElementType +
" " +
583 std::to_string(e.numberElements) +
"\n";
586 for (
const PlyProperty& p : e.properties) {
590 s += typeToString(p.listSizeType) +
" ";
592 s += typeToString(p.type) +
" ";
593 if (p.name == ply::unknown)
594 s += p.unknownPropertyName +
"\n";
596 s += nameToString(p.name) +
"\n";
604 void setFormat(ply::Format f) { mFormat = f; }
606 iterator begin()
const {
return mElements.begin(); }
608 iterator end()
const {
return mElements.end(); }
611 PlyElement readElement(
const Tokenizer& lineTokenizer)
const
614 Tokenizer::iterator token = lineTokenizer.begin();
615 std::string s = *(++token);
617 e.type = ply::VERTEX;
618 e.numberElements = std::stoi(*(++token));
620 else if (s ==
"face") {
622 e.numberElements = std::stoi(*(++token));
624 else if (s ==
"edge") {
626 e.numberElements = std::stoi(*(++token));
628 else if (s ==
"tristrips") {
629 e.type = ply::TRISTRIP;
630 e.numberElements = std::stoi(*(++token));
634 e.numberElements = std::stoi(*(++token));
635 e.unknownElementType = s;
640 PlyProperty readProperty(
const Tokenizer& lineTokenizer)
const
643 Tokenizer::iterator token = lineTokenizer.begin();
644 std::string type = *(++token);
645 if (type ==
"list") {
647 std::string typeSize = *(++token);
648 std::string typeData = *(++token);
649 std::string name = *(++token);
650 p.listSizeType = stringToType(typeSize);
651 p.type = stringToType(typeData);
652 p.name = stringToName(name);
653 if (p.name == ply::unknown)
654 p.unknownPropertyName = name;
658 std::string name = *(++token);
659 p.type = stringToType(type);
660 p.name = stringToName(name);
661 if (p.name == ply::unknown)
662 p.unknownPropertyName = name;
668 ply::PropertyName stringToName(
const std::string& name)
const
670 ply::PropertyName pn = ply::unknown;
691 if (name ==
"quality" || name ==
"scalar")
693 if (name ==
"texture_u" || name ==
"s" || name ==
"u")
695 if (name ==
"texture_v" || name ==
"t" || name ==
"v")
697 if (name ==
"texnumber")
699 if (name ==
"vertex_indices")
700 pn = ply::vertex_indices;
701 if (name ==
"texcoord")
703 if (name ==
"vertex1")
705 if (name ==
"vertex2")
711 ply::PropertyType stringToType(
const std::string& type)
const
713 ply::PropertyType pt = ply::PropertyType::UCHAR;
715 pt = ply::PropertyType::CHAR;
717 pt = ply::PropertyType::UCHAR;
719 pt = ply::PropertyType::SHORT;
720 if (type ==
"ushort")
721 pt = ply::PropertyType::USHORT;
723 pt = ply::PropertyType::INT;
725 pt = ply::PropertyType::UINT;
727 pt = ply::PropertyType::FLOAT;
728 if (type ==
"double")
729 pt = ply::PropertyType::DOUBLE;
733 std::string nameToString(ply::PropertyName n)
const
736 case ply::x:
return "x";
737 case ply::y:
return "y";
738 case ply::z:
return "z";
739 case ply::nx:
return "nx";
740 case ply::ny:
return "ny";
741 case ply::nz:
return "nz";
742 case ply::red:
return "red";
743 case ply::green:
return "green";
744 case ply::blue:
return "blue";
745 case ply::alpha:
return "alpha";
746 case ply::quality:
return "quality";
747 case ply::texture_u:
return "texture_u";
748 case ply::texture_v:
return "texture_v";
749 case ply::texnumber:
return "texnumber";
750 case ply::vertex_indices:
return "vertex_indices";
751 case ply::texcoord:
return "texcoord";
752 case ply::vertex1:
return "vertex1";
753 case ply::vertex2:
return "vertex2";
754 default:
return "unknown";
758 std::string typeToString(ply::PropertyType t)
const
761 case ply::PropertyType::CHAR:
return "char";
762 case ply::PropertyType::UCHAR:
return "uchar";
763 case ply::PropertyType::SHORT:
return "short";
764 case ply::PropertyType::USHORT:
return "ushort";
765 case ply::PropertyType::INT:
return "int";
766 case ply::PropertyType::UINT:
return "uint";
767 case ply::PropertyType::FLOAT:
return "float";
768 case ply::PropertyType::DOUBLE:
return "double";
769 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:113
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