23#ifndef VCL_LOAD_SAVE_PLY_DETAIL_VERTEX_H
24#define VCL_LOAD_SAVE_PLY_DETAIL_VERTEX_H
28#include <vclib/concepts/mesh/per_vertex.h>
29#include <vclib/exceptions/io.h>
30#include <vclib/io/read.h>
31#include <vclib/io/write.h>
32#include <vclib/mesh/requirements.h>
33#include <vclib/misc/tokenizer.h>
35namespace vcl::detail {
37template<MeshConcept MeshType, VertexConcept VertexType,
typename Stream>
38void readPlyVertexProperty(
43 std::endian end = std::endian::little)
45 bool hasBeenRead =
false;
46 if (p.name >= ply::x && p.name <= ply::z) {
47 using Scalar = VertexType::CoordType::ScalarType;
48 int a = p.name - ply::x;
49 v.coord()[a] = io::readPrimitiveType<Scalar>(file, p.type, end);
52 if (p.name >= ply::nx && p.name <= ply::nz) {
53 if constexpr (HasPerVertexNormal<MeshType>) {
54 if (isPerVertexNormalAvailable(mesh)) {
55 using Scalar = VertexType::NormalType::ScalarType;
56 int a = p.name - ply::nx;
58 io::readPrimitiveType<Scalar>(file, p.type, end);
63 if (p.name >= ply::red && p.name <= ply::alpha) {
64 if constexpr (HasPerVertexColor<MeshType>) {
65 if (isPerVertexColorAvailable(mesh)) {
66 int a = p.name - ply::red;
68 io::readPrimitiveType<unsigned char>(file, p.type, end);
73 if (p.name == ply::quality) {
74 if constexpr (HasPerVertexQuality<MeshType>) {
75 using QualityType = VertexType::QualityType;
76 if (isPerVertexQualityAvailable(mesh)) {
78 io::readPrimitiveType<QualityType>(file, p.type, end);
83 if (p.name >= ply::texture_u && p.name <= ply::texture_v) {
84 if constexpr (HasPerVertexTexCoord<MeshType>) {
85 using Scalar = VertexType::TexCoordType::ScalarType;
86 if (isPerVertexTexCoordAvailable(mesh)) {
87 int a = p.name - ply::texture_u;
89 io::readPrimitiveType<Scalar>(file, p.type, end);
94 if (p.name == ply::texnumber) {
95 if constexpr (HasPerVertexTexCoord<MeshType>) {
96 if (isPerVertexTexCoordAvailable(mesh)) {
97 v.texCoord().index() =
98 io::readPrimitiveType<ushort>(file, p.type, end);
103 if (p.name == ply::unknown) {
104 if constexpr (HasPerVertexCustomComponents<MeshType>) {
105 if (mesh.hasPerVertexCustomComponent(p.unknownPropertyName)) {
106 io::readCustomComponent(
107 file, v, p.unknownPropertyName, p.type, end);
114 uint s = io::readPrimitiveType<int>(file, p.listSizeType);
115 for (uint i = 0; i < s; ++i)
116 io::readPrimitiveType<int>(file, p.type, end);
119 io::readPrimitiveType<int>(file, p.type, end);
124template<VertexConcept VertexType, MeshConcept MeshType>
125void readPlyVertexTxt(
129 const std::list<PlyProperty>& vertexProperties)
131 Tokenizer spaceTokenizer = readAndTokenizeNextNonEmptyLine(file);
132 Tokenizer::iterator token = spaceTokenizer.begin();
133 for (
const PlyProperty& p : vertexProperties) {
134 if (token == spaceTokenizer.end()) {
135 throw MalformedFileException(
"Unexpected end of line.");
137 readPlyVertexProperty(token, mesh, v, p);
141template<VertexConcept VertexType, MeshConcept MeshType>
142void readPlyVertexBin(
146 const std::list<PlyProperty>& vertexProperties,
149 for (
const PlyProperty& p : vertexProperties) {
150 readPlyVertexProperty(file, mesh, v, p, end);
154template<MeshConcept MeshType>
155void writePlyVertices(
157 const PlyHeader& header,
158 const MeshType& mesh)
160 using VertexType = MeshType::VertexType;
163 if (header.format() == ply::ASCII) {
164 format.isBinary =
false;
166 else if (header.format() == ply::BINARY_BIG_ENDIAN) {
167 format.endian = std::endian::big;
170 for (
const VertexType& v : mesh.
vertices()) {
171 for (
const PlyProperty& p : header.vertexProperties()) {
172 bool hasBeenWritten =
false;
173 if (p.name >= ply::x && p.name <= ply::z) {
175 file, v.coord()[p.name - ply::x], p.type, format);
176 hasBeenWritten =
true;
178 if (p.name >= ply::nx && p.name <= ply::nz) {
179 if constexpr (HasPerVertexNormal<MeshType>) {
181 file, v.normal()[p.name - ply::nx], p.type, format);
182 hasBeenWritten =
true;
185 if (p.name >= ply::red && p.name <= ply::alpha) {
186 if constexpr (HasPerVertexColor<MeshType>) {
188 file, v.color()[p.name - ply::red], p.type, format);
189 hasBeenWritten =
true;
192 if (p.name == ply::quality) {
193 if constexpr (HasPerVertexQuality<MeshType>) {
194 io::writeProperty(file, v.quality(), p.type, format);
195 hasBeenWritten =
true;
198 if (p.name >= ply::texture_u && p.name <= ply::texture_v) {
199 if constexpr (HasPerVertexTexCoord<MeshType>) {
200 const uint a = p.name - ply::texture_u;
201 io::writeProperty(file, v.texCoord()[a], p.type, format);
202 hasBeenWritten =
true;
205 if (p.name == ply::texnumber) {
206 if constexpr (HasPerVertexTexCoord<MeshType>) {
208 file, v.texCoord().index(), p.type, format);
209 hasBeenWritten =
true;
212 if (p.name == ply::unknown) {
213 if constexpr (HasPerVertexCustomComponents<MeshType>) {
214 if (mesh.hasPerVertexCustomComponent(
215 p.unknownPropertyName)) {
216 io::writeCustomComponent(
217 file, v, p.unknownPropertyName, p.type, format);
218 hasBeenWritten =
true;
222 if (!hasBeenWritten) {
225 io::writeProperty(file, 0, p.type, format);
228 if (!format.isBinary)
233template<MeshConcept MeshType, LoggerConcept LogType>
236 const PlyHeader& header,
240 m.addVertices(header.numberVertices());
242 log.startProgress(
"Reading vertices", header.numberVertices());
244 for (uint vid = 0; vid < header.numberVertices(); ++vid) {
245 auto& v = m.vertex(vid);
246 if (header.format() == ply::ASCII) {
247 detail::readPlyVertexTxt(file, v, m, header.vertexProperties());
250 std::endian end = header.format() == ply::BINARY_BIG_ENDIAN ?
253 detail::readPlyVertexBin(
254 file, v, m, header.vertexProperties(), end);
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:60