Visual Computing Library
Loading...
Searching...
No Matches
import_matrix.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_ALGORITHMS_MESH_IMPORT_EXPORT_IMPORT_MATRIX_H
24#define VCL_ALGORITHMS_MESH_IMPORT_EXPORT_IMPORT_MATRIX_H
25
26#include <vclib/concepts/space/matrix.h>
27#include <vclib/exceptions.h>
28#include <vclib/mesh/requirements.h>
29#include <vclib/space/core/polygon.h>
30
44namespace vcl {
45
46namespace detail {
47
48template<MatrixConcept FMatrix>
49std::vector<uint> faceVertIndices(const FMatrix& faces, uint f)
50{
51 std::vector<uint> fVerts;
52
53 uint j = 0;
54 while (j < faces.cols() && faces(f, j) != -1 && faces(f, j) != UINT_NULL)
55 fVerts.push_back(faces(f, j));
56
57 return fVerts;
58}
59
60template<uint ELEM_ID, MeshConcept MeshType, MatrixConcept NMatrix>
61void importElementNormalsFromMatrix(MeshType& mesh, const NMatrix& normals)
62{
63 // The type of the normal of the element
64 using NormalType = MeshType::template ElementType<ELEM_ID>::NormalType;
65
66 if (normals.cols() != 3)
67 throw WrongSizeException(
68 "The input " + elementEnumString<ELEM_ID>() +
69 " normal matrix must have 3 columns");
70
71 // matrix rows must be equal to the number of elements of the given type
72 if (normals.rows() != mesh.template number<ELEM_ID>())
73 throw WrongSizeException(
74 "The input normal matrix must have the same number of rows "
75 "as the number of " +
76 elementEnumString<ELEM_ID>() + " element in the mesh");
77
78 enableIfPerElementComponentOptional<ELEM_ID, CompId::NORMAL>(mesh);
79 requirePerElementComponent<ELEM_ID, CompId::NORMAL>(mesh);
80
81 uint i = 0;
82 for (auto& e : mesh.template elements<ELEM_ID>()) {
83 e.normal() = NormalType(normals(i, 0), normals(i, 1), normals(i, 2));
84 i++;
85 }
86}
87
88template<uint ELEM_ID, MeshConcept MeshType, MatrixConcept CMatrix>
89void importElementColorsFromMatrix(MeshType& mesh, const CMatrix& colors)
90{
91 using MatrixScalar = CMatrix::Scalar;
92
93 if (colors.cols() != 3 && colors.cols() != 4)
94 throw WrongSizeException(
95 "The input " + elementEnumString<ELEM_ID>() +
96 " color matrix must have 3 or 4 columns");
97
98 // matrix rows must be equal to the number of elements of the given type
99 if (colors.rows() != mesh.template number<ELEM_ID>())
100 throw WrongSizeException(
101 "The input color matrix must have the same number of rows "
102 "as the number of " +
103 elementEnumString<ELEM_ID>() + " element in the mesh");
104
105 enableIfPerElementComponentOptional<ELEM_ID, CompId::COLOR>(mesh);
106 requirePerElementComponent<ELEM_ID, CompId::COLOR>(mesh);
107
108 uint i = 0;
109 for (auto& e : mesh.template elements<ELEM_ID>()) {
110 // Matrix has colors in range 0-255
111 if constexpr (std::integral<MatrixScalar>) {
112 if (colors.cols() == 3) {
113 e.color() = Color(colors(i, 0), colors(i, 1), colors(i, 2));
114 }
115 else {
116 e.color() = Color(
117 colors(i, 0), colors(i, 1), colors(i, 2), colors(i, 3));
118 }
119 }
120 else { // Matrix has colors in range 0-1
121 if (colors.cols() == 3) {
122 e.color() = Color(
123 colors(i, 0) * 255, colors(i, 1) * 255, colors(i, 2) * 255);
124 }
125 else {
126 e.color() = Color(
127 colors(i, 0) * 255,
128 colors(i, 1) * 255,
129 colors(i, 2) * 255,
130 colors(i, 3) * 255);
131 }
132 }
133
134 i++;
135 }
136}
137
138} // namespace detail
139
175template<
176 MeshConcept MeshType,
177 MatrixConcept VMatrix,
178 MatrixConcept VNMatrix = Eigen::MatrixX3d>
179MeshType pointCloudMeshFromMatrices(
180 const VMatrix& vertices,
181 const VNMatrix& vertexNormals = VNMatrix())
182{
183 MeshType mesh;
184
185 importMeshFromMatrices(
186 mesh,
187 vertices,
188 Eigen::MatrixX3i(),
189 Eigen::MatrixX2i(),
190 vertexNormals,
191 Eigen::MatrixX3d());
192
193 return mesh;
194}
195
241template<
242 MeshConcept MeshType,
243 MatrixConcept VMatrix,
244 MatrixConcept FMatrix = Eigen::MatrixX3i,
245 MatrixConcept VNMatrix = Eigen::MatrixX3d,
246 MatrixConcept FNMatrix = Eigen::MatrixX3d>
247MeshType meshFromMatrices(
248 const VMatrix& vertices,
249 const FMatrix& faces = FMatrix(),
250 const VNMatrix& vertexNormals = VNMatrix(),
251 const FNMatrix& faceNormals = FNMatrix())
252{
253 MeshType mesh;
254
255 importMeshFromMatrices(
256 mesh, vertices, faces, Eigen::MatrixX2i(), vertexNormals, faceNormals);
257
258 return mesh;
259}
260
319template<
320 MeshConcept MeshType,
321 MatrixConcept VMatrix,
322 MatrixConcept FMatrix = Eigen::MatrixX3i,
323 MatrixConcept EMatrix = Eigen::MatrixX2i,
324 MatrixConcept VNMatrix = Eigen::MatrixX3d,
325 MatrixConcept FNMatrix = Eigen::MatrixX3d>
326void importMeshFromMatrices(
327 MeshType& mesh,
328 const VMatrix& vertices,
329 const FMatrix& faces = FMatrix(),
330 const EMatrix& edges = EMatrix(),
331 const VNMatrix& vertexNormals = VNMatrix(),
332 const FNMatrix& faceNormals = FNMatrix())
333{
334 mesh.clear();
335 mesh.disableAllOptionalComponents();
336
337 importVerticesFromMatrix(mesh, vertices);
338
339 if constexpr (HasPerVertexNormal<MeshType>) {
340 if (vertexNormals.rows() > 0) {
341 importVertexNormalsFromMatrix(mesh, vertexNormals);
342 }
343 }
344
345 if constexpr (HasFaces<MeshType>) {
346 if (faces.rows() > 0)
347 importFacesFromMatrix(mesh, faces);
348
349 if constexpr (HasPerFaceNormal<MeshType>) {
350 if (faceNormals.rows() > 0) {
351 importFaceNormalsFromMatrix(mesh, faceNormals);
352 }
353 }
354 }
355
356 if constexpr (HasEdges<MeshType>) {
357 if (edges.rows() > 0)
358 importEdgesFromMatrix(mesh, edges);
359 }
360}
361
400template<MeshConcept MeshType, MatrixConcept VMatrix>
401void importVerticesFromMatrix(
402 MeshType& mesh,
403 const VMatrix& vertices,
404 bool clearBeforeSet = true)
405{
406 using CoordType = MeshType::VertexType::CoordType;
407
408 if (vertices.cols() != 3)
409 throw WrongSizeException("The input vertex matrix must have 3 columns");
410
411 if (clearBeforeSet) {
412 mesh.clearVertices();
413 mesh.resizeVertices(vertices.rows());
414 }
415 else {
416 if (vertices.rows() != mesh.vertexNumber()) {
417 throw WrongSizeException(
418 "The input vertex matrix has a different number of rows than "
419 "the number of vertices of the mesh");
420 }
421 }
422
423 uint i = 0;
424 for (auto& v : mesh.vertices()) {
425 v.coord() = CoordType(vertices(i, 0), vertices(i, 1), vertices(i, 2));
426 i++;
427 }
428}
429
430template<FaceMeshConcept MeshType, MatrixConcept FMatrix>
431void importFacesFromMatrix(
432 MeshType& mesh,
433 const FMatrix& faces,
434 bool clearBeforeSet = true)
435{
436 if (clearBeforeSet) {
437 mesh.clearFaces();
438 mesh.resizeFaces(faces.rows());
439 }
440 else {
441 if (faces.rows() != mesh.faceNumber()) {
442 throw WrongSizeException(
443 "The input face matrix has a different number of rows "
444 "than the number of faces of the mesh.");
445 }
446 }
447
448 if constexpr (HasPolygons<MeshType>) {
449 uint i = 0;
450 for (auto& f : mesh.faces()) {
451 uint vertexNumber = 0;
452
453 // count the number of vertices of the face
454 while (vertexNumber < faces.cols() &&
455 faces(i, vertexNumber) != -1 &&
456 faces(i, vertexNumber) != UINT_NULL)
457 vertexNumber++;
458
459 f.resizeVertices(vertexNumber);
460
461 for (uint j = 0; j < vertexNumber; ++j)
462 f.setVertex(j, faces(i, j));
463 ++i;
464 }
465 }
466 else { // the vertex number of mesh faces is fixed
467 using FaceType = MeshType::FaceType;
468
469 constexpr int VN = FaceType::VERTEX_NUMBER;
470 if (faces.cols() == VN) { // faces of matrix and mesh have same size
471 uint i = 0;
472 for (auto& f : mesh.faces()) {
473 for (uint j = 0; j < VN; ++j)
474 f.setVertex(j, faces(i, j));
475 ++i;
476 }
477 }
478 else { // faces of matrix and mesh have different sizes
479 // matrix cols is higher than 3 (polygons), but we have a triangle
480 // mesh and we can triangulate the faces
481 if constexpr (VN == 3) {
482 if (!clearBeforeSet) {
483 throw WrongSizeException(
484 "Cannot import the input face matrix into the mesh "
485 "without clearing the face container first "
486 "(need to perform a triangulation to import polygons "
487 "in a triangle mesh, and this operation that does not "
488 "guarantee a predefined number of faces is required).");
489 }
490 mesh.reserveFaces(faces.rows());
491 for (uint i = 0; i < faces.rows(); ++i) {
492 std::vector<uint> fVertIndices =
493 detail::faceVertIndices(faces, i);
494
495 addTriangleFacesFromPolygon(mesh, fVertIndices);
496 }
497 }
498 else {
499 // no triangulation available because VN != 3, we don't
500 // know how to import the faces and we throw an exception
501 throw WrongSizeException(
502 "The input face matrix has a different number of columns "
503 "than the number of vertices of the mesh faces.");
504 }
505 }
506 }
507}
508
509template<EdgeMeshConcept MeshType, MatrixConcept EMatrix>
510void importEdgesFromMatrix(
511 MeshType& mesh,
512 const EMatrix& edges,
513 bool clearBeforeSet = true)
514{
515 if (edges.cols() != 2)
516 throw WrongSizeException("The input edge matrix must have 2 columns");
517
518 if (clearBeforeSet) {
519 mesh.clearEdges();
520 mesh.resizeEdges(edges.rows());
521 }
522 else {
523 if (edges.rows() != mesh.edgeNumber()) {
524 throw WrongSizeException(
525 "The input edge matrix has a different number of rows than "
526 "the number of edges of the mesh");
527 }
528 }
529
530 uint i = 0;
531 for (auto& e : mesh.edges()) {
532 e.setVertex(0, edges(i, 0));
533 e.setVertex(1, edges(i, 1));
534 i++;
535 }
536}
537
538template<MeshConcept MeshType, MatrixConcept VNMatrix>
539void importVertexNormalsFromMatrix(
540 MeshType& mesh,
541 const VNMatrix& vertexNormals)
542{
543 detail::importElementNormalsFromMatrix<ElemId::VERTEX>(mesh, vertexNormals);
544}
545
546template<FaceMeshConcept MeshType, MatrixConcept FNMatrix>
547void importFaceNormalsFromMatrix(MeshType& mesh, const FNMatrix& faceNormals)
548{
549 detail::importElementNormalsFromMatrix<ElemId::FACE>(mesh, faceNormals);
550}
551
552template<MeshConcept MeshType, MatrixConcept VCMatrix>
553void importVertexColorsFromMatrix(MeshType& mesh, const VCMatrix& vertexColors)
554{
555 detail::importElementColorsFromMatrix<ElemId::VERTEX>(mesh, vertexColors);
556}
557
558template<FaceMeshConcept MeshType, MatrixConcept FCMatrix>
559void importFaceColorsFromMatrix(MeshType& mesh, const FCMatrix& faceColors)
560{
561 detail::importElementColorsFromMatrix<ElemId::FACE>(mesh, faceColors);
562}
563
564template<EdgeMeshConcept MeshType, MatrixConcept ECMatrix>
565void importEdgeColorsFromMatrix(MeshType& mesh, const ECMatrix& edgeColors)
566{
567 detail::importElementColorsFromMatrix<ElemId::EDGE>(mesh, edgeColors);
568}
569
570} // namespace vcl
571
572#endif // VCL_ALGORITHMS_MESH_IMPORT_EXPORT_IMPORT_MATRIX_H
constexpr uint UINT_NULL
The UINT_NULL value represent a null value of uint that is the maximum value that can be represented ...
Definition base.h:48
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:52
constexpr detail::EdgesView edges
A view that allows to iterate overt the Edge elements of an object.
Definition edge.h:52
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:60