Visual Computing Library
Loading...
Searching...
No Matches
vertex.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_LOAD_SAVE_PLY_DETAIL_VERTEX_H
24#define VCL_LOAD_SAVE_PLY_DETAIL_VERTEX_H
25
26#include "header.h"
27
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>
34
35namespace vcl::detail {
36
37template<MeshConcept MeshType, VertexConcept VertexType, typename Stream>
38void readPlyVertexProperty(
39 Stream& file,
40 MeshType& mesh,
41 VertexType& v,
42 PlyProperty p,
43 std::endian end = std::endian::little)
44{
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);
50 hasBeenRead = true;
51 }
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;
57 v.normal()[a] =
58 io::readPrimitiveType<Scalar>(file, p.type, end);
59 hasBeenRead = true;
60 }
61 }
62 }
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;
67 v.color()[a] =
68 io::readPrimitiveType<unsigned char>(file, p.type, end);
69 hasBeenRead = true;
70 }
71 }
72 }
73 if (p.name == ply::quality) {
74 if constexpr (HasPerVertexQuality<MeshType>) {
75 using QualityType = VertexType::QualityType;
76 if (isPerVertexQualityAvailable(mesh)) {
77 v.quality() =
78 io::readPrimitiveType<QualityType>(file, p.type, end);
79 hasBeenRead = true;
80 }
81 }
82 }
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;
88 v.texCoord()[a] =
89 io::readPrimitiveType<Scalar>(file, p.type, end);
90 hasBeenRead = true;
91 }
92 }
93 }
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);
99 hasBeenRead = true;
100 }
101 }
102 }
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);
108 hasBeenRead = true;
109 }
110 }
111 }
112 if (!hasBeenRead) {
113 if (p.list) {
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);
117 }
118 else {
119 io::readPrimitiveType<int>(file, p.type, end);
120 }
121 }
122}
123
124template<VertexConcept VertexType, MeshConcept MeshType>
125void readPlyVertexTxt(
126 std::istream& file,
127 VertexType& v,
128 MeshType& mesh,
129 const std::list<PlyProperty>& vertexProperties)
130{
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.");
136 }
137 readPlyVertexProperty(token, mesh, v, p);
138 }
139}
140
141template<VertexConcept VertexType, MeshConcept MeshType>
142void readPlyVertexBin(
143 std::istream& file,
144 VertexType& v,
145 MeshType& mesh,
146 const std::list<PlyProperty>& vertexProperties,
147 std::endian end)
148{
149 for (const PlyProperty& p : vertexProperties) {
150 readPlyVertexProperty(file, mesh, v, p, end);
151 }
152}
153
154template<MeshConcept MeshType>
155void writePlyVertices(
156 std::ostream& file,
157 const PlyHeader& header,
158 const MeshType& mesh)
159{
160 using VertexType = MeshType::VertexType;
161
162 FileType format;
163 if (header.format() == ply::ASCII) {
164 format.isBinary = false;
165 }
166 else if (header.format() == ply::BINARY_BIG_ENDIAN) {
167 format.endian = std::endian::big;
168 }
169
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) {
174 io::writeProperty(
175 file, v.coord()[p.name - ply::x], p.type, format);
176 hasBeenWritten = true;
177 }
178 if (p.name >= ply::nx && p.name <= ply::nz) {
179 if constexpr (HasPerVertexNormal<MeshType>) {
180 io::writeProperty(
181 file, v.normal()[p.name - ply::nx], p.type, format);
182 hasBeenWritten = true;
183 }
184 }
185 if (p.name >= ply::red && p.name <= ply::alpha) {
186 if constexpr (HasPerVertexColor<MeshType>) {
187 io::writeProperty(
188 file, v.color()[p.name - ply::red], p.type, format);
189 hasBeenWritten = true;
190 }
191 }
192 if (p.name == ply::quality) {
193 if constexpr (HasPerVertexQuality<MeshType>) {
194 io::writeProperty(file, v.quality(), p.type, format);
195 hasBeenWritten = true;
196 }
197 }
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;
203 }
204 }
205 if (p.name == ply::texnumber) {
206 if constexpr (HasPerVertexTexCoord<MeshType>) {
207 io::writeProperty(
208 file, v.texCoord().index(), p.type, format);
209 hasBeenWritten = true;
210 }
211 }
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;
219 }
220 }
221 }
222 if (!hasBeenWritten) {
223 // be sure to write something if the header declares some
224 // property that is not in the mesh
225 io::writeProperty(file, 0, p.type, format);
226 }
227 }
228 if (!format.isBinary)
229 file << std::endl;
230 }
231}
232
233template<MeshConcept MeshType, LoggerConcept LogType>
234void readPlyVertices(
235 std::istream& file,
236 const PlyHeader& header,
237 MeshType& m,
238 LogType& log)
239{
240 m.addVertices(header.numberVertices());
241
242 log.startProgress("Reading vertices", header.numberVertices());
243
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());
248 }
249 else {
250 std::endian end = header.format() == ply::BINARY_BIG_ENDIAN ?
251 std::endian::big :
252 std::endian::little;
253 detail::readPlyVertexBin(
254 file, v, m, header.vertexProperties(), end);
255 }
256 log.progress(vid);
257 }
258 log.endProgress();
259}
260
261} // namespace vcl::detail
262
263#endif // VCL_LOAD_SAVE_PLY_DETAIL_VERTEX_H
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:60