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