Visual Computing Library  devel
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_IO_MESH_PLY_DETAIL_VERTEX_H
24#define VCL_IO_MESH_PLY_DETAIL_VERTEX_H
25
26#include "header.h"
27
28#include <vclib/io/read.h>
29#include <vclib/io/write.h>
30
31#include <vclib/mesh.h>
32
33namespace vcl::detail {
34
35template<MeshConcept MeshType, VertexConcept VertexType, typename Stream>
36void readPlyVertexProperty(
37 Stream& file,
38 MeshType& mesh,
39 VertexType& v,
40 PlyProperty p,
41 std::endian end = std::endian::little)
42{
43 bool hasBeenRead = false;
44 if (p.name >= ply::x && p.name <= ply::z) {
45 using Scalar = VertexType::PositionType::ScalarType;
46 int a = p.name - ply::x;
47 v.position()[a] = io::readPrimitiveType<Scalar>(file, p.type, end);
48 hasBeenRead = true;
49 }
50 if (p.name >= ply::nx && p.name <= ply::nz) {
51 if constexpr (HasPerVertexNormal<MeshType>) {
52 if (isPerVertexNormalAvailable(mesh)) {
53 using Scalar = VertexType::NormalType::ScalarType;
54 int a = p.name - ply::nx;
55 v.normal()[a] =
56 io::readPrimitiveType<Scalar>(file, p.type, end);
57 hasBeenRead = true;
58 }
59 }
60 }
61 if (p.name >= ply::red && p.name <= ply::alpha) {
62 if constexpr (HasPerVertexColor<MeshType>) {
63 if (isPerVertexColorAvailable(mesh)) {
64 int a = p.name - ply::red;
65 v.color()[a] =
66 io::readPrimitiveType<unsigned char>(file, p.type, end);
67 hasBeenRead = true;
68 }
69 }
70 }
71 if (p.name == ply::quality) {
72 if constexpr (HasPerVertexQuality<MeshType>) {
73 using QualityType = VertexType::QualityType;
74 if (isPerVertexQualityAvailable(mesh)) {
75 v.quality() =
76 io::readPrimitiveType<QualityType>(file, p.type, end);
77 hasBeenRead = true;
78 }
79 }
80 }
81 if (p.name >= ply::texture_u && p.name <= ply::texture_v) {
82 if constexpr (HasPerVertexTexCoord<MeshType>) {
83 using Scalar = VertexType::TexCoordType::ScalarType;
84 if (isPerVertexTexCoordAvailable(mesh)) {
85 int a = p.name - ply::texture_u;
86 v.texCoord()[a] =
87 io::readPrimitiveType<Scalar>(file, p.type, end);
88 hasBeenRead = true;
89 }
90 }
91 }
92 if (p.name == ply::texnumber) {
93 if constexpr (HasPerVertexTexCoord<MeshType>) {
94 if (isPerVertexTexCoordAvailable(mesh)) {
95 v.texCoord().index() =
96 io::readPrimitiveType<ushort>(file, p.type, end);
97 hasBeenRead = true;
98 }
99 }
100 }
101 if (p.name == ply::unknown) {
102 if constexpr (HasPerVertexCustomComponents<MeshType>) {
103 if (mesh.hasPerVertexCustomComponent(p.unknownPropertyName)) {
104 io::readCustomComponent(
105 file, v, p.unknownPropertyName, p.type, end);
106 hasBeenRead = true;
107 }
108 }
109 }
110 if (!hasBeenRead) {
111 if (p.list) {
112 uint s = io::readPrimitiveType<int>(file, p.listSizeType);
113 for (uint i = 0; i < s; ++i)
114 io::readPrimitiveType<int>(file, p.type, end);
115 }
116 else {
117 io::readPrimitiveType<int>(file, p.type, end);
118 }
119 }
120}
121
122template<VertexConcept VertexType, MeshConcept MeshType>
123void readPlyVertexTxt(
124 std::istream& file,
125 VertexType& v,
126 MeshType& mesh,
127 const std::list<PlyProperty>& vertexProperties)
128{
129 Tokenizer spaceTokenizer = readAndTokenizeNextNonEmptyLine(file);
130 Tokenizer::iterator token = spaceTokenizer.begin();
131 for (const PlyProperty& p : vertexProperties) {
132 if (token == spaceTokenizer.end()) {
133 throw MalformedFileException("Unexpected end of line.");
134 }
135 readPlyVertexProperty(token, mesh, v, p);
136 }
137}
138
139template<VertexConcept VertexType, MeshConcept MeshType>
140void readPlyVertexBin(
141 std::istream& file,
142 VertexType& v,
143 MeshType& mesh,
144 const std::list<PlyProperty>& vertexProperties,
145 std::endian end)
146{
147 for (const PlyProperty& p : vertexProperties) {
148 readPlyVertexProperty(file, mesh, v, p, end);
149 }
150}
151
152template<MeshConcept MeshType>
153void writePlyVertices(
154 std::ostream& file,
155 const PlyHeader& header,
156 const MeshType& mesh)
157{
158 using VertexType = MeshType::VertexType;
159
160 FileType format;
161 if (header.format() == ply::ASCII) {
162 format.isBinary = false;
163 }
164 else if (header.format() == ply::BINARY_BIG_ENDIAN) {
165 format.endian = std::endian::big;
166 }
167
168 for (const VertexType& v : mesh.vertices()) {
169 for (const PlyProperty& p : header.vertexProperties()) {
170 bool hasBeenWritten = false;
171 if (p.name >= ply::x && p.name <= ply::z) {
172 io::writeProperty(
173 file, v.position()[p.name - ply::x], p.type, format);
174 hasBeenWritten = true;
175 }
176 if (p.name >= ply::nx && p.name <= ply::nz) {
177 if constexpr (HasPerVertexNormal<MeshType>) {
178 io::writeProperty(
179 file, v.normal()[p.name - ply::nx], p.type, format);
180 hasBeenWritten = true;
181 }
182 }
183 if (p.name >= ply::red && p.name <= ply::alpha) {
184 if constexpr (HasPerVertexColor<MeshType>) {
185 io::writeProperty(
186 file, v.color()[p.name - ply::red], p.type, format);
187 hasBeenWritten = true;
188 }
189 }
190 if (p.name == ply::quality) {
191 if constexpr (HasPerVertexQuality<MeshType>) {
192 io::writeProperty(file, v.quality(), p.type, format);
193 hasBeenWritten = true;
194 }
195 }
196 if (p.name >= ply::texture_u && p.name <= ply::texture_v) {
197 if constexpr (HasPerVertexTexCoord<MeshType>) {
198 const uint a = p.name - ply::texture_u;
199 io::writeProperty(file, v.texCoord()[a], p.type, format);
200 hasBeenWritten = true;
201 }
202 }
203 if (p.name == ply::texnumber) {
204 if constexpr (HasPerVertexTexCoord<MeshType>) {
205 io::writeProperty(
206 file, v.texCoord().index(), p.type, format);
207 hasBeenWritten = true;
208 }
209 }
210 if (p.name == ply::unknown) {
211 if constexpr (HasPerVertexCustomComponents<MeshType>) {
212 if (mesh.hasPerVertexCustomComponent(
213 p.unknownPropertyName)) {
214 io::writeCustomComponent(
215 file, v, p.unknownPropertyName, p.type, format);
216 hasBeenWritten = true;
217 }
218 }
219 }
220 if (!hasBeenWritten) {
221 // be sure to write something if the header declares some
222 // property that is not in the mesh
223 io::writeProperty(file, 0, p.type, format);
224 }
225 }
226 if (!format.isBinary)
227 file << std::endl;
228 }
229}
230
231template<MeshConcept MeshType, LoggerConcept LogType>
232void readPlyVertices(
233 std::istream& file,
234 const PlyHeader& header,
235 MeshType& m,
236 LogType& log)
237{
238 m.addVertices(header.numberVertices());
239
240 log.startProgress("Reading vertices", header.numberVertices());
241
242 for (uint vid = 0; vid < header.numberVertices(); ++vid) {
243 auto& v = m.vertex(vid);
244 if (header.format() == ply::ASCII) {
245 detail::readPlyVertexTxt(file, v, m, header.vertexProperties());
246 }
247 else {
248 std::endian end = header.format() == ply::BINARY_BIG_ENDIAN ?
249 std::endian::big :
250 std::endian::little;
251 detail::readPlyVertexBin(
252 file, v, m, header.vertexProperties(), end);
253 }
254 log.progress(vid);
255 }
256 log.endProgress();
257}
258
259} // namespace vcl::detail
260
261#endif // VCL_IO_MESH_PLY_DETAIL_VERTEX_H
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:92