Visual Computing Library
Loading...
Searching...
No Matches
edge.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_EDGE_H
24#define VCL_LOAD_SAVE_PLY_DETAIL_EDGE_H
25
26#include "header.h"
27
28#include <vclib/io/write.h>
29#include <vclib/misc/tokenizer.h>
30
31namespace vcl::detail {
32
33template<EdgeMeshConcept MeshType, EdgeConcept EdgeType, typename Stream>
34void readPlyEdgeProperty(
35 Stream& file,
36 MeshType& mesh,
37 EdgeType& e,
38 PlyProperty p,
39 std::endian end = std::endian::little)
40{
41 bool hasBeenRead = false;
42 // loading vertex indices in case of list
43 if (p.name == ply::vertex_indices) {
44 std::vector<uint> vids; // contains the vertex ids of the actual edge
45 uint eSize = io::readPrimitiveType<uint>(file, p.listSizeType, end);
46 vids.resize(eSize);
47 for (uint i = 0; i < eSize; ++i) {
48 vids[i] = io::readPrimitiveType<size_t>(file, p.type, end);
49 if (vids[i] >= mesh.vertexNumber()) {
50 throw MalformedFileException(
51 "Bad vertex index for edge " + std::to_string(e.index()));
52 }
53 }
54 hasBeenRead = true;
55 e.setVertex(0u, vids[0]);
56 e.setVertex(1u, vids[1]);
57 }
58 if (p.name == ply::vertex1) { // loading vertex1 index
59 uint v0 = io::readPrimitiveType<uint>(file, p.type, end);
60 hasBeenRead = true;
61 e.setVertex(0u, v0);
62 }
63 if (p.name == ply::vertex2) { // loading vertex2 index
64 uint v1 = io::readPrimitiveType<uint>(file, p.type, end);
65 hasBeenRead = true;
66 e.setVertex(1u, v1);
67 }
68 // loading one of the normal components
69 if (p.name >= ply::nx && p.name <= ply::nz) {
70 if constexpr (HasPerEdgeNormal<MeshType>) {
71 if (isPerEdgeNormalAvailable(mesh)) {
72 using Scalar = EdgeType::NormalType::ScalarType;
73 int a = p.name - ply::nx;
74 Scalar n = io::readPrimitiveType<Scalar>(file, p.type, end);
75 hasBeenRead = true;
76 }
77 }
78 }
79 // loading one of the color components
80 if (p.name >= ply::red && p.name <= ply::alpha) {
81 if constexpr (HasPerFaceColor<MeshType>) {
82 if (isPerFaceColorAvailable(mesh)) {
83 int a = p.name - ply::red;
84 unsigned char c =
85 io::readPrimitiveType<unsigned char>(file, p.type, end);
86 hasBeenRead = true;
87 }
88 }
89 }
90 if (p.name == ply::quality) { // loading the quality component
91 if constexpr (HasPerFaceQuality<MeshType>) {
92 using QualityType = EdgeType::QualityType;
93 if (isPerFaceQualityAvailable(mesh)) {
94 QualityType s =
95 io::readPrimitiveType<QualityType>(file, p.type, end);
96 hasBeenRead = true;
97 }
98 }
99 }
100 if (p.name == ply::unknown) {
101 if constexpr (HasPerFaceCustomComponents<MeshType>) {
102 if (mesh.hasPerFaceCustomComponent(p.unknownPropertyName)) {
103 io::readCustomComponent(
104 file, e, p.unknownPropertyName, p.type, end);
105 hasBeenRead = true;
106 }
107 }
108 }
109 // if nothing has been read, it means that there is some data we don't know
110 // we still need to read and discard what we read
111 if (!hasBeenRead) {
112 if (p.list) {
113 uint s = io::readPrimitiveType<int>(file, p.listSizeType, end);
114 for (uint i = 0; i < s; ++i)
115 io::readPrimitiveType<int>(file, p.type, end);
116 }
117 else {
118 io::readPrimitiveType<int>(file, p.type, end);
119 }
120 }
121}
122
123template<EdgeConcept EdgeType, MeshConcept MeshType>
124void readPlyEdgeTxt(
125 std::istream& file,
126 EdgeType& e,
127 MeshType& mesh,
128 const std::list<PlyProperty>& edgeProperties)
129{
130 Tokenizer spaceTokenizer = readAndTokenizeNextNonEmptyLine(file);
131 Tokenizer::iterator token = spaceTokenizer.begin();
132 for (const PlyProperty& p : edgeProperties) {
133 if (token == spaceTokenizer.end()) {
134 throw MalformedFileException("Unexpected end of line.");
135 }
136 readPlyEdgeProperty(token, mesh, e, p);
137 }
138}
139
140template<EdgeConcept EdgeType, MeshConcept MeshType>
141void readPlyEdgeBin(
142 std::istream& file,
143 EdgeType& e,
144 MeshType& mesh,
145 const std::list<PlyProperty>& edgeProperties,
146 std::endian end)
147{
148 for (const PlyProperty& p : edgeProperties) {
149 readPlyEdgeProperty(file, mesh, e, p, end);
150 }
151}
152
153template<EdgeMeshConcept MeshType>
154void writePlyEdges(
155 std::ostream& file,
156 const PlyHeader& header,
157 const MeshType& mesh)
158{
159 using EdgeType = MeshType::EdgeType;
160
161 FileType format;
162 if (header.format() == ply::ASCII) {
163 format.isBinary = false;
164 }
165 else if (header.format() == ply::BINARY_BIG_ENDIAN) {
166 format.endian = std::endian::big;
167 }
168
169 // indices of vertices that do not consider deleted vertices
170 std::vector<uint> vIndices = mesh.vertexCompactIndices();
171
172 for (const EdgeType& e : mesh.edges()) {
173 for (const PlyProperty& p : header.edgeProperties()) {
174 bool hasBeenWritten = false;
175 if (p.name == ply::vertex1) {
176 io::writeProperty(
177 file, vIndices[mesh.index(e.vertex(0))], p.type, format);
178 hasBeenWritten = true;
179 }
180 if (p.name == ply::vertex2) {
181 io::writeProperty(
182 file, vIndices[mesh.index(e.vertex(1))], p.type, format);
183 hasBeenWritten = true;
184 }
185 if (p.name >= ply::nx && p.name <= ply::nz) {
186 if constexpr (HasPerEdgeNormal<MeshType>) {
187 io::writeProperty(
188 file, e.normal()[p.name - ply::nx], p.type, format);
189 hasBeenWritten = true;
190 }
191 }
192 if (p.name >= ply::red && p.name <= ply::alpha) {
193 if constexpr (HasPerEdgeColor<MeshType>) {
194 io::writeProperty(
195 file, e.color()[p.name - ply::red], p.type, format);
196 hasBeenWritten = true;
197 }
198 }
199 if (p.name == ply::quality) {
200 if constexpr (HasPerEdgeQuality<MeshType>) {
201 io::writeProperty(file, e.quality(), p.type, format);
202 hasBeenWritten = true;
203 }
204 }
205 if (!hasBeenWritten) {
206 // be sure to write something if the header declares some
207 // property that is not in the mesh
208 io::writeProperty(file, 0, p.type, format);
209 }
210 }
211 if (!format.isBinary)
212 file << std::endl;
213 }
214}
215
216template<EdgeMeshConcept MeshType, LoggerConcept LogType>
217void readPlyEdges(
218 std::istream& file,
219 const PlyHeader& header,
220 MeshType& m,
221 LogType& log)
222{
223 using EdgeType = MeshType::EdgeType;
224 m.reserveEdges(header.numberEdges());
225
226 log.startProgress("Reading edges", header.numberEdges());
227
228 for (uint eid = 0; eid < header.numberEdges(); ++eid) {
229 uint eeid = m.addEdge();
230 EdgeType& e = m.edge(eeid);
231 if (header.format() == ply::ASCII) {
232 detail::readPlyEdgeTxt(file, e, m, header.edgeProperties());
233 }
234 else {
235 std::endian end = header.format() == ply::BINARY_BIG_ENDIAN ?
236 std::endian::big :
237 std::endian::little;
238 detail::readPlyEdgeBin(file, e, m, header.edgeProperties(), end);
239 }
240
241 log.progress(eid);
242 }
243
244 log.endProgress();
245}
246
247} // namespace vcl::detail
248
249#endif // VCL_LOAD_SAVE_PLY_DETAIL_EDGE_H
bool isPerEdgeNormalAvailable(const MeshType &m)
Returns true if the Normal component is available (enabled) in the Edge element of the input mesh m.
Definition edge_requirements.h:330
bool isPerFaceQualityAvailable(const MeshType &m)
Returns true if the Quality component is available (enabled) in the Face element of the input mesh m.
Definition face_requirements.h:451
bool isPerFaceColorAvailable(const MeshType &m)
Returns true if the Color component is available (enabled) in the Face element of the input mesh m.
Definition face_requirements.h:214
constexpr detail::EdgesView edges
A view that allows to iterate overt the Edge elements of an object.
Definition edge.h:52