23#ifndef VCL_IO_MESH_PLY_DETAIL_FACE_H
24#define VCL_IO_MESH_PLY_DETAIL_FACE_H
28#include <vclib/io/file_type.h>
29#include <vclib/io/read.h>
30#include <vclib/io/write.h>
32#include <vclib/algorithms/mesh.h>
33#include <vclib/mesh.h>
35namespace vcl::detail {
37template<FaceMeshConcept MeshType, FaceConcept FaceType>
38void writePlyFaceIndices(
42 const std::vector<uint>& vIndices,
46 using VertexType = MeshType::VertexType;
48 uint fsize = f.vertexNumber();
49 io::writeProperty(file, fsize, p.listSizeType, format);
50 for (
const VertexType* v : f.
vertices()) {
51 io::writeProperty(file, vIndices[m.index(v)], p.type, format);
55template<FaceMeshConcept MeshType, FaceConcept FaceType>
56void setPlyFaceIndices(FaceType& f, MeshType& m,
const std::vector<uint>& vids)
58 bool splitFace =
false;
60 if constexpr (FaceType::VERTEX_NUMBER < 0) {
62 f.resizeVertices(vids.size());
64 else if (FaceType::VERTEX_NUMBER != vids.size()) {
73 for (uint i = 0; i < f.vertexNumber(); ++i) {
74 if (vids[i] >= m.vertexNumber()) {
75 throw MalformedFileException(
76 "Bad vertex index for face " + std::to_string(f.index()));
78 f.setVertex(i, vids[i]);
82 addTriangleFacesFromPolygon(m, f, vids);
86template<FaceMeshConcept MeshType, FaceConcept FaceType,
typename Scalar>
87void setPlyFaceWedgeTexCoords(
90 const std::vector<uint>& vids,
91 const std::vector<std::pair<Scalar, Scalar>>& wedges)
93 bool splitFace =
false;
94 if (FaceType::VERTEX_NUMBER > 0 && FaceType::VERTEX_NUMBER != wedges.size())
97 for (uint i = 0; i < wedges.size(); ++i) {
98 f.wedgeTexCoord(i).u() = wedges[i].first;
99 f.wedgeTexCoord(i).v() = wedges[i].second;
104 for (uint ff = m.index(f); ff < m.faceNumber(); ++ff) {
106 for (uint i = 0; i < m.face(ff).vertexNumber(); ++i) {
108 uint vid = m.index(m.face(ff).vertex(i));
109 auto it = std::find(vids.begin(), vids.end(), vid);
110 if (it == vids.end()) {
113 throw MalformedFileException(
114 "Bad vertex index for face " + std::to_string(ff));
117 uint p = it - vids.begin();
118 m.face(ff).wedgeTexCoord(i).u() = wedges[p].first;
119 m.face(ff).wedgeTexCoord(i).v() = wedges[p].second;
125template<FaceMeshConcept MeshType, FaceConcept FaceType,
typename Stream>
126void readPlyFaceProperty(
131 MeshInfo& loadedInfo,
132 std::endian end = std::endian::little)
134 bool hasBeenRead =
false;
135 std::vector<uint> vids;
136 if (p.name == ply::vertex_indices) {
137 uint fSize = io::readPrimitiveType<uint>(file, p.listSizeType, end);
138 loadedInfo.updateMeshType(fSize);
140 for (uint i = 0; i < fSize; ++i) {
141 vids[i] = io::readPrimitiveType<size_t>(file, p.type, end);
145 setPlyFaceIndices(f, mesh, vids);
147 if (p.name == ply::texcoord) {
148 if constexpr (HasPerFaceWedgeTexCoords<MeshType>) {
150 using Scalar = FaceType::WedgeTexCoordType::ScalarType;
152 io::readPrimitiveType<uint>(file, p.listSizeType, end);
153 uint fSize = uvSize / 2;
154 std::vector<std::pair<Scalar, Scalar>> wedges(fSize);
155 for (uint i = 0; i < fSize; ++i) {
156 Scalar u = io::readPrimitiveType<Scalar>(file, p.type, end);
157 Scalar v = io::readPrimitiveType<Scalar>(file, p.type, end);
159 wedges[i].second = v;
162 setPlyFaceWedgeTexCoords(f, mesh, vids, wedges);
167 if (p.name == ply::texnumber) {
168 if constexpr (HasPerFaceWedgeTexCoords<MeshType>) {
170 uint n = io::readPrimitiveType<uint>(file, p.type, end);
174 for (uint ff = mesh.index(f); ff < mesh.faceNumber(); ++ff) {
175 mesh.face(ff).textureIndex() = n;
181 if (p.name >= ply::nx && p.name <= ply::nz) {
182 if constexpr (HasPerFaceNormal<MeshType>) {
184 using Scalar = FaceType::NormalType::ScalarType;
185 int a = p.name - ply::nx;
186 Scalar n = io::readPrimitiveType<Scalar>(file, p.type, end);
190 for (uint ff = mesh.index(f); ff < mesh.faceNumber(); ++ff) {
191 mesh.face(ff).normal()[a] = n;
197 if (p.name >= ply::red && p.name <= ply::alpha) {
198 if constexpr (HasPerFaceColor<MeshType>) {
200 int a = p.name - ply::red;
202 io::readPrimitiveType<unsigned char>(file, p.type, end);
206 for (uint ff = mesh.index(f); ff < mesh.faceNumber(); ++ff) {
207 mesh.face(ff).color()[a] = c;
212 if (p.name == ply::quality) {
213 if constexpr (HasPerFaceQuality<MeshType>) {
214 using QualityType = FaceType::QualityType;
217 io::readPrimitiveType<QualityType>(file, p.type, end);
221 for (uint ff = mesh.index(f); ff < mesh.faceNumber(); ++ff) {
222 mesh.face(ff).quality() = s;
227 if (p.name == ply::unknown) {
228 if constexpr (HasPerFaceCustomComponents<MeshType>) {
229 if (mesh.hasPerFaceCustomComponent(p.unknownPropertyName)) {
230 io::readCustomComponent(
231 file, f, p.unknownPropertyName, p.type, end);
240 uint s = io::readPrimitiveType<int>(file, p.listSizeType, end);
241 for (uint i = 0; i < s; ++i)
242 io::readPrimitiveType<int>(file, p.type, end);
245 io::readPrimitiveType<int>(file, p.type, end);
250template<FaceConcept FaceType, MeshConcept MeshType>
255 MeshInfo& loadedInfo,
256 const std::list<PlyProperty>& faceProperties)
258 Tokenizer spaceTokenizer = readAndTokenizeNextNonEmptyLine(file);
259 Tokenizer::iterator token = spaceTokenizer.begin();
260 for (
const PlyProperty& p : faceProperties) {
261 if (token == spaceTokenizer.end()) {
262 throw MalformedFileException(
"Unexpected end of line.");
264 readPlyFaceProperty(token, mesh, f, p, loadedInfo);
268template<FaceConcept FaceType, MeshConcept MeshType>
273 MeshInfo& loadedInfo,
274 const std::list<PlyProperty>& faceProperties,
277 for (
const PlyProperty& p : faceProperties) {
278 readPlyFaceProperty(file, mesh, f, p, loadedInfo, end);
282template<FaceMeshConcept MeshType>
285 const PlyHeader& header,
286 const MeshType& mesh)
288 using FaceType = MeshType::FaceType;
291 if (header.format() == ply::ASCII) {
292 format.isBinary =
false;
294 else if (header.format() == ply::BINARY_BIG_ENDIAN) {
295 format.endian = std::endian::big;
299 std::vector<uint> vIndices = mesh.vertexCompactIndices();
301 for (
const FaceType& f : mesh.
faces()) {
302 for (
const PlyProperty& p : header.faceProperties()) {
303 bool hasBeenWritten =
false;
304 if (p.name == ply::vertex_indices) {
305 detail::writePlyFaceIndices(file, p, mesh, vIndices, f, format);
306 hasBeenWritten =
true;
308 if (p.name >= ply::nx && p.name <= ply::nz) {
309 if constexpr (HasPerFaceNormal<MeshType>) {
311 file, f.normal()[p.name - ply::nx], p.type, format);
312 hasBeenWritten =
true;
315 if (p.name >= ply::red && p.name <= ply::alpha) {
316 if constexpr (HasPerFaceColor<MeshType>) {
318 file, f.color()[p.name - ply::red], p.type, format);
319 hasBeenWritten =
true;
322 if (p.name == ply::quality) {
323 if constexpr (HasPerFaceQuality<MeshType>) {
324 io::writeProperty(file, f.quality(), p.type, format);
325 hasBeenWritten =
true;
328 if (p.name == ply::texcoord) {
329 if constexpr (HasPerFaceWedgeTexCoords<MeshType>) {
331 file, f.vertexNumber() * 2, p.listSizeType, format);
332 for (
const auto& tc : f.wedgeTexCoords()) {
333 io::writeProperty(file, tc.u(), p.type, format);
334 io::writeProperty(file, tc.v(), p.type, format);
336 hasBeenWritten =
true;
339 if (p.name == ply::texnumber) {
340 if constexpr (HasPerFaceWedgeTexCoords<MeshType>) {
341 io::writeProperty(file, f.textureIndex(), p.type, format);
342 hasBeenWritten =
true;
345 if (p.name == ply::unknown) {
346 if constexpr (HasPerFaceCustomComponents<MeshType>) {
347 if (mesh.hasPerFaceCustomComponent(p.unknownPropertyName)) {
348 io::writeCustomComponent(
349 file, f, p.unknownPropertyName, p.type, format);
350 hasBeenWritten =
true;
354 if (!hasBeenWritten) {
357 io::writeProperty(file, 0, p.type, format);
360 if (!format.isBinary)
365template<FaceMeshConcept MeshType, LoggerConcept LogType>
368 const PlyHeader& header,
370 MeshInfo& loadedInfo,
373 using FaceType = MeshType::FaceType;
374 mesh.reserveFaces(header.numberFaces());
376 log.startProgress(
"Reading faces", header.numberFaces());
378 for (uint fid = 0; fid < header.numberFaces(); ++fid) {
379 uint ffid = mesh.addFace();
380 FaceType& f = mesh.face(ffid);
381 if (header.format() == ply::ASCII) {
382 detail::readPlyFaceTxt(
383 file, f, mesh, loadedInfo, header.faceProperties());
386 std::endian end = header.format() == ply::BINARY_BIG_ENDIAN ?
389 detail::readPlyFaceBin(
390 file, f, mesh, loadedInfo, header.faceProperties(), end);
bool isPerFaceWedgeTexCoordsAvailable(const MeshType &m)
Returns true if the WedgeTexCoords component is available (enabled) in the Face element of the input ...
Definition face_requirements.h:833
bool isPerFaceNormalAvailable(const MeshType &m)
Returns true if the Normal component is available (enabled) in the Face element of the input mesh m.
Definition face_requirements.h:592
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:713
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:476
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:84
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:92