expose mesh conversions in meshlab-common

This commit is contained in:
alemuntoni 2021-06-11 14:40:00 +02:00
parent 15b2cc51be
commit 89f2abd68d
8 changed files with 416 additions and 80 deletions

View File

@ -70,6 +70,7 @@ set(HEADERS
python/function_parameter.h
python/function_set.h
python/python_utils.h
utilities/eigen_mesh_conversions.h
utilities/file_format.h
utilities/load_save.h
globals.h
@ -111,6 +112,7 @@ set(SOURCES
python/function_parameter.cpp
python/function_set.cpp
python/python_utils.cpp
utilities/eigen_mesh_conversions.cpp
utilities/load_save.cpp
globals.cpp
GLExtensionsManager.cpp

View File

@ -70,6 +70,7 @@ HEADERS += \
python/function_parameter.h \
python/function_set.h \
python/python_utils.h \
utilities/eigen_mesh_conversions.h \
utilities/file_format.h \
utilities/load_save.h \
GLExtensionsManager.h \
@ -110,6 +111,7 @@ SOURCES += \
python/function_parameter.cpp \
python/function_set.cpp \
python/python_utils.cpp \
utilities/eigen_mesh_conversions.cpp \
utilities/load_save.cpp \
GLExtensionsManager.cpp \
filterscript.cpp \

View File

@ -0,0 +1,341 @@
/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005-2021 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include "eigen_mesh_conversions.h"
#include "../mlexception.h"
/**
* @brief Creates a CMeshO mesh from the data contained in the given matrices.
* The only matrix required to be non-empty is the 'vertices' matrix.
* Other matrices may be empty.
*
* If normals and quality matrices are give, their sizes must be coherent with
* the sizes of vertex and face matrices. If this requirement is not satisfied,
* a MLException will be thrown.
*
* @param vertices: #V*3 matrix of scalars (vertex coordinates)
* @param faces: #F*3 matrix of integers (vertex indices composing the faces)
* @param vertexNormals: #V*3 matrix of scalars (vertex normals)
* @param faceNormals: #F*3 matrix of scalars (face normals)
* @param vertexQuality: #V vector of scalars (vertex quality)
* @param faceQuality: #F vector of scalars (face quality)
* @return a CMeshO made of the given components
*/
CMeshO meshlab::meshFromMatrices(
const EigenMatrixX3m& vertices,
const Eigen::MatrixX3i& faces,
const EigenMatrixX3m& vertexNormals,
const EigenMatrixX3m& faceNormals,
const EigenVectorXm& vertexQuality,
const EigenVectorXm& faceQuality)
{
CMeshO m;
if (vertices.rows() > 0) {
//add vertices and their associated normals and quality if any
std::vector<CMeshO::VertexPointer> ivp(vertices.rows());
bool hasVNormals = vertexNormals.rows() > 0;
bool hasVQuality = vertexQuality.rows() > 0;
if (hasVNormals && (vertices.rows() != vertexNormals.rows())) {
throw MLException(
"Error while creating mesh: the number of vertex normals "
"is different from the number of vertices.");
}
if (hasVQuality && (vertices.rows() != vertexQuality.size())) {
throw MLException(
"Error while creating mesh: the number of vertex quality "
"values is different from the number of vertices.");
}
CMeshO::VertexIterator vi =
vcg::tri::Allocator<CMeshO>::AddVertices(m, vertices.rows());
for (unsigned int i = 0; i < vertices.rows(); ++i, ++vi) {
ivp[i] = &*vi;
vi->P() = CMeshO::CoordType(vertices(i,0), vertices(i,1), vertices(i,2));
if (hasVNormals) {
vi->N() = CMeshO::CoordType(
vertexNormals(i,0),
vertexNormals(i,1),
vertexNormals(i,2));
}
if (hasVQuality) {
vi->Q() = vertexQuality(i);
}
}
//add faces and their associated normals and quality if any
bool hasFNormals = faceNormals.rows() > 0;
bool hasFQuality = faceQuality.rows() > 0;
if (hasFNormals && (faces.rows() != faceNormals.rows())) {
throw MLException(
"Error while creating mesh: the number of face normals "
"is different from the number of faces.");
}
if (hasFQuality) {
if (faces.rows() != faceQuality.size()) {
throw MLException(
"Error while creating mesh: the number of face quality "
"values is different from the number of faces.");
}
m.face.EnableQuality();
}
CMeshO::FaceIterator fi =
vcg::tri::Allocator<CMeshO>::AddFaces(m, faces.rows());
for (unsigned int i = 0; i < faces.rows(); ++i, ++fi) {
for (unsigned int j = 0; j < 3; j++){
if ((unsigned int)faces(i,j) >= ivp.size()) {
throw MLException(
"Error while creating mesh: bad vertex index " +
QString::number(faces(i,j)) + " in face " +
QString::number(i) + "; vertex " + QString::number(j) + ".");
}
}
fi->V(0)=ivp[faces(i,0)];
fi->V(1)=ivp[faces(i,1)];
fi->V(2)=ivp[faces(i,2)];
if (hasFNormals){
fi->N() = CMeshO::CoordType(
faceNormals(i,0),
faceNormals(i,1),
faceNormals(i,2));
}
if (hasFQuality) {
fi->Q() = faceQuality(i);
}
}
if (!hasFNormals){
vcg::tri::UpdateNormal<CMeshO>::PerFace(m);
}
if (!hasVNormals){
vcg::tri::UpdateNormal<CMeshO>::PerVertex(m);
}
}
else {
throw MLException("Error while creating mesh: Vertex matrix is empty.");
}
return m;
}
/**
* @brief Get a #V*3 Eigen matrix of scalars containing the coordinates of the
* vertices of a CMeshO.
* The vertices in the mesh must be compact (no deleted vertices).
* If the mesh is not compact, a vcg::MissingCompactnessException will be thrown.
*
* @param mesh: input mesh
* @return #V*3 matrix of scalars (vertex coordinates)
*/
EigenMatrixX3m meshlab::vertexMatrix(const CMeshO& mesh)
{
vcg::tri::RequireVertexCompactness(mesh);
// create eigen matrix of vertices
EigenMatrixX3m vert(mesh.VN(), 3);
// copy vertices
for (int i = 0; i < mesh.VN(); i++){
for (int j = 0; j < 3; j++){
vert(i,j) = mesh.vert[i].cP()[j];
}
}
return vert;
}
/**
* @brief Get a #F*3 Eigen matrix of integers containing the vertex indices of
* a CMeshO.
* The faces in the mesh must be compact (no deleted faces).
* If the mesh is not compact, a vcg::MissingCompactnessException will be thrown.
*
* @param mesh: input mesh
* @return #F*3 matrix of integers (vertex indices composing the faces)
*/
Eigen::MatrixX3i meshlab::faceMatrix(const CMeshO& mesh)
{
vcg::tri::RequireFaceCompactness(mesh);
// create eigen matrix of faces
Eigen::MatrixXi faces(mesh.FN(), 3);
// copy faces
for (int i = 0; i < mesh.FN(); i++){
for (int j = 0; j < 3; j++){
faces(i,j) = (int)vcg::tri::Index(mesh,mesh.face[i].cV(j));
}
}
return faces;
}
EigenMatrixX3m meshlab::vertexNormalMatrix(const CMeshO& mesh)
{
vcg::tri::RequireVertexCompactness(mesh);
// create eigen matrix of vertex normals
EigenMatrixX3m vertexNormals(mesh.VN(), 3);
// per vertices normals
for (int i = 0; i < mesh.VN(); i++){
for (int j = 0; j < 3; j++){
vertexNormals(i,j) = mesh.vert[i].cN()[j];
}
}
return vertexNormals;
}
EigenMatrixX3m meshlab::faceNormalMatrix(const CMeshO& mesh)
{
vcg::tri::RequireFaceCompactness(mesh);
// create eigen matrix of face normals
EigenMatrixX3m faceNormals(mesh.FN(), 3);
// per face normals
for (int i = 0; i < mesh.FN(); i++){
for (int j = 0; j < 3; j++){
faceNormals(i,j) = mesh.face[i].cN()[j];
}
}
return faceNormals;
}
EigenMatrixX3m meshlab::vertexColorMatrix(const CMeshO& mesh)
{
vcg::tri::RequireVertexCompactness(mesh);
EigenMatrixX3m vertexColors(mesh.VN(), 4);
for (int i = 0; i < mesh.VN(); i++){
for (int j = 0; j < 4; j++){
vertexColors(i,j) = mesh.vert[i].C()[j] / 255.0;
}
}
return vertexColors;
}
EigenMatrixX3m meshlab::faceColorMatrix(const CMeshO& mesh)
{
vcg::tri::RequireFaceCompactness(mesh);
vcg::tri::RequirePerFaceColor(mesh);
EigenMatrixX3m faceColors(mesh.FN(), 4);
for (int i = 0; i < mesh.FN(); i++){
for (int j = 0; j < 4; j++){
faceColors(i,j) = mesh.face[i].C()[j] / 255.0;
}
}
return faceColors;
}
Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> meshlab::vertexColorArray(
const CMeshO& mesh)
{
vcg::tri::RequireVertexCompactness(mesh);
Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> vertexColors(mesh.VN());
for (int i = 0; i < mesh.VN(); i++){
vertexColors(i) =
vcg::Color4<unsigned char>::ToUnsignedA8R8G8B8(mesh.vert[i].C());
}
return vertexColors;
}
Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> meshlab::faceColorArray(
const CMeshO& mesh)
{
vcg::tri::RequireFaceCompactness(mesh);
vcg::tri::RequirePerFaceColor(mesh);
Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> faceColors(mesh.FN());
for (int i = 0; i < mesh.FN(); i++){
faceColors(i) =
vcg::Color4<unsigned char>::ToUnsignedA8R8G8B8(mesh.face[i].C());
}
return faceColors;
}
EigenVectorXm meshlab::vertexQualityArray(const CMeshO& mesh)
{
vcg::tri::RequireVertexCompactness(mesh);
vcg::tri::RequirePerVertexQuality(mesh);
EigenVectorXm qv(mesh.VN());
for (int i = 0; i < mesh.VN(); i++){
qv(i) = mesh.vert[i].cQ();
}
return qv;
}
EigenVectorXm meshlab::faceQualityArray(const CMeshO& mesh)
{
vcg::tri::RequireFaceCompactness(mesh);
vcg::tri::RequirePerFaceQuality(mesh);
EigenVectorXm qf(mesh.FN());
for (int i = 0; i < mesh.FN(); i++){
qf(i) = mesh.face[i].cQ();
}
return qf;
}
EigenMatrixX2m meshlab::vertexTexCoordMatrix(const CMeshO& mesh)
{
vcg::tri::RequireVertexCompactness(mesh);
vcg::tri::RequirePerVertexTexCoord(mesh);
EigenMatrixX2m uv (mesh.VN(), 2);
// per vertices uv
for (int i = 0; i < mesh.VN(); i++) {
uv(i,0) = mesh.vert[i].cT().U();
uv(i,1) = mesh.vert[i].cT().V();
}
return uv;
}
EigenMatrixX2m meshlab::wedgeTexCoordMatrix(const CMeshO& mesh)
{
vcg::tri::RequireFaceCompactness(mesh);
vcg::tri::RequirePerVertexTexCoord(mesh);
EigenMatrixX2m m(mesh.FN()*3, 2);
for (int i = 0; i < mesh.FN(); i++) {
int base = i * 3;
for (int j = 0; j < 3; j++){
m(base+j, 0) = mesh.face[i].WT(j).u();
m(base+j, 1) = mesh.face[i].WT(j).v();
}
}
return m;
}

View File

@ -0,0 +1,58 @@
/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005-2021 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#ifndef MESHLAB_EIGEN_MESH_CONVERSIONS_H
#define MESHLAB_EIGEN_MESH_CONVERSIONS_H
#include <Eigen/Core>
#include "../ml_document/cmesh.h"
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 3> EigenMatrixX3m;
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 2> EigenMatrixX2m;
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 1> EigenVectorXm;
namespace meshlab {
CMeshO meshFromMatrices(
const EigenMatrixX3m& vertices,
const Eigen::MatrixX3i& faces = Eigen::MatrixX3i(),
const EigenMatrixX3m& vertexNormals = EigenMatrixX3m(),
const EigenMatrixX3m& faceNormals = EigenMatrixX3m(),
const EigenVectorXm& vertexQuality = EigenVectorXm(),
const EigenVectorXm& faceQuality = EigenVectorXm());
EigenMatrixX3m vertexMatrix(const CMeshO& mesh);
Eigen::MatrixX3i faceMatrix(const CMeshO& mesh);
EigenMatrixX3m vertexNormalMatrix(const CMeshO& mesh);
EigenMatrixX3m faceNormalMatrix(const CMeshO& mesh);
EigenMatrixX3m vertexColorMatrix(const CMeshO& mesh);
EigenMatrixX3m faceColorMatrix(const CMeshO& mesh);
Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> vertexColorArray(const CMeshO& mesh);
Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> faceColorArray(const CMeshO& mesh);
EigenVectorXm vertexQualityArray(const CMeshO& mesh);
EigenVectorXm faceQualityArray(const CMeshO& mesh);
EigenMatrixX2m vertexTexCoordMatrix(const CMeshO& mesh);
EigenMatrixX2m wedgeTexCoordMatrix(const CMeshO& mesh);
}
#endif // MESHLAB_EIGEN_MESH_CONVERSIONS_H

View File

@ -2,7 +2,7 @@
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005-2020 \/)\/ *
* Copyright(C) 2005-2021 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *

View File

@ -2,7 +2,7 @@
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2005-2020 \/)\/ *
* Copyright(C) 2005-2021 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *

View File

@ -23,6 +23,8 @@
#include "filter_mesh_booleans.h"
#include <common/utilities/eigen_mesh_conversions.h>
#include <igl/copyleft/cgal/CSGTree.h>
/**
@ -294,68 +296,6 @@ std::map<std::string, QVariant> FilterMeshBooleans::applyFilter(
return std::map<std::string, QVariant>();
}
/**
* @brief Puts coords and triangle indices of m into V and F matrices
* @param m
* @param V
* @param F
*/
void FilterMeshBooleans::CMeshOToEigen(const CMeshO& m, Eigen::MatrixX3d& V, Eigen::MatrixX3i& F)
{
vcg::tri::RequireVertexCompactness(m);
vcg::tri::RequireFaceCompactness(m);
V.resize(m.VN(), 3);
for (int i = 0; i < m.VN(); i++){
for (int j = 0; j < 3; j++){
V(i,j) = m.vert[i].P()[j];
}
}
F.resize(m.FN(), 3);
for (int i = 0; i < m.FN(); i++){
for (int j = 0; j < 3; j++){
F(i,j) = (int) vcg::tri::Index(m,m.face[i].cV(j));
}
}
}
/**
* @brief Returns a CMeshO containing the triangle mesh contained in V and F
* @param V
* @param F
* @return
*/
CMeshO FilterMeshBooleans::EigenToCMeshO(const Eigen::MatrixX3d& V, const Eigen::MatrixX3i& F)
{
CMeshO m;
CMeshO::VertexIterator vi =
vcg::tri::Allocator<CMeshO>::AddVertices(m, V.rows());
std::vector<CMeshO::VertexPointer> ivp(V.rows());
for (unsigned int i = 0; i < V.rows(); ++i, ++vi) {
ivp[i] = &*vi;
vi->P() = CMeshO::CoordType(V(i,0), V(i,1), V(i,2));
}
CMeshO::FaceIterator fi =
vcg::tri::Allocator<CMeshO>::AddFaces(m, F.rows());
for (unsigned int i = 0; i < F.rows(); ++i, ++fi) {
for (unsigned int j = 0; j < 3; j++){
if ((unsigned int)F(i,j) >= ivp.size()) {
throw MLException(
"Error while creating mesh: bad vertex index " +
QString::number(F(i,j)) + " in face " +
QString::number(i) + "; vertex " + QString::number(j) + ".");
}
}
fi->V(0)=ivp[F(i,0)];
fi->V(1)=ivp[F(i,1)];
fi->V(2)=ivp[F(i,2)];
}
vcg::tri::UpdateNormal<CMeshO>::PerFace(m);
vcg::tri::UpdateNormal<CMeshO>::PerVertex(m);
return m;
}
/**
* @brief Executes the boolean operation between m1 and m2, and puts the result
* as a new mesh into md.
@ -394,13 +334,15 @@ void FilterMeshBooleans::booleanOperation(
throw MLException("Boolean Operation not found! Please report this issue on https://github.com/cnr-isti-vclab/meshlab/issues");
}
Eigen::MatrixX3d V1, V2, VR;
Eigen::MatrixX3i F1, F2, FR;
Eigen::VectorXi indices; //mapping indices for birth faces
//vcg to eigen meshes
CMeshOToEigen(m1.cm, V1, F1);
CMeshOToEigen(m2.cm, V2, F2);
EigenMatrixX3m V1 = meshlab::vertexMatrix(m1.cm);
Eigen::MatrixX3i F1 = meshlab::faceMatrix(m1.cm);
EigenMatrixX3m V2 = meshlab::vertexMatrix(m2.cm);
Eigen::MatrixX3i F2 = meshlab::faceMatrix(m2.cm);
EigenMatrixX3m VR;
Eigen::MatrixX3i FR;
Eigen::VectorXi indices; //mapping indices for birth faces
bool result = igl::copyleft::cgal::mesh_boolean(V1, F1, V2, F2, (igl::MeshBooleanType)op, VR, FR, indices);
@ -412,7 +354,7 @@ void FilterMeshBooleans::booleanOperation(
else {
//everything ok, create new mesh into md
MeshModel* mesh = md.addNewMesh("", name);
mesh->cm = EigenToCMeshO(VR, FR);
mesh->cm = meshlab::meshFromMatrices(VR, FR);
//if transfer option enabled
if (transfFaceColor || transfFaceQuality)

View File

@ -74,15 +74,6 @@ public:
vcg::CallBackPos * cb);
private:
//conversion functions
static void CMeshOToEigen(
const CMeshO& m,
Eigen::MatrixX3d& V,
Eigen::MatrixX3i& F);
static CMeshO EigenToCMeshO(
const Eigen::MatrixX3d& V,
const Eigen::MatrixX3i& F);
//generic boolean operation function
static void booleanOperation(
MeshDocument& md,