"points cloud movement" takes two mesh parameters

This commit is contained in:
alemuntoni 2021-10-07 16:19:39 +02:00
parent d92495fdb4
commit c5ca4f0023
4 changed files with 513 additions and 490 deletions

View File

@ -1,45 +1,44 @@
/****************************************************************************
* MeshLab o o *
* An extendible mesh processor o o *
* _ O _ *
* Copyright(C) 2005, 2006 \/)\/ *
* 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. *
* *
****************************************************************************/
/*****************************************************************************
* MeshLab o o *
* An extendible mesh processor 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 "filter_dirt.h"
#include "particle.h"
#include "dirt_utils.h"
#include "particle.h"
#include <vcg/space/color4.h>
#include <vcg/math/random_generator.h>
#include <vcg/complex/algorithms/closest.h>
#include <vcg/space/index/spatial_hashing.h>
#include <vcg/complex/algorithms/stat.h>
#include <vcg/complex/algorithms/update/topology.h>
#include <vcg/space/box2.h>
#include <vcg/math/base.h>
#include <vcg/complex/algorithms/clean.h>
#include <vcg/complex/algorithms/stat.h>
#include <vcg/complex/algorithms/smooth.h>
#include <vcg/complex/algorithms/update/color.h>
#include <vcg/complex/algorithms/update/bounding.h>
#include <vcg/complex/algorithms/update/normal.h>
#include <vcg/complex/algorithms/closest.h>
#include <vcg/complex/algorithms/point_sampling.h>
#include <vcg/complex/algorithms/smooth.h>
#include <vcg/complex/algorithms/stat.h>
#include <vcg/complex/algorithms/update/bounding.h>
#include <vcg/complex/algorithms/update/color.h>
#include <vcg/complex/algorithms/update/normal.h>
#include <vcg/complex/algorithms/update/topology.h>
#include <vcg/math/base.h>
#include <vcg/math/random_generator.h>
#include <vcg/space/box2.h>
#include <vcg/space/color4.h>
#include <vcg/space/index/spatial_hashing.h>
#include <vcg/space/triangle3.h>
#include <vector>
@ -49,12 +48,9 @@ using namespace tri;
FilterDirt::FilterDirt()
{
typeList = {
FP_DIRT,
FP_CLOUD_MOVEMENT
};
typeList = {FP_DIRT, FP_CLOUD_MOVEMENT};
for(ActionIDType tt: types())
for (ActionIDType tt : types())
actionList.push_back(new QAction(filterName(tt), this));
}
@ -66,17 +62,17 @@ QString FilterDirt::pluginName() const
QString FilterDirt::filterName(ActionIDType filterId) const
{
switch (filterId) {
case FP_DIRT:{
case FP_DIRT: {
return QString("Dust Accumulation");
break;
}
case FP_CLOUD_MOVEMENT:
{
case FP_CLOUD_MOVEMENT: {
return QString("Points Cloud Movement");
break;
}
default:{
assert(0); return QString("error");
default: {
assert(0);
return QString("error");
break;
}
}
@ -85,162 +81,214 @@ QString FilterDirt::filterName(ActionIDType filterId) const
QString FilterDirt::filterInfo(ActionIDType filterId) const
{
switch (filterId) {
case FP_DIRT:{
return QString("Simulate dust accumulation over the mesh generating a cloud of points lying on the current mesh");
case FP_DIRT:
return QString(
"Simulate dust accumulation over the mesh generating a cloud of points lying on the "
"current mesh");
break;
}
case FP_CLOUD_MOVEMENT:{
return QString("Simulate the movement of a points cloud over a mesh");
case FP_CLOUD_MOVEMENT:
return QString("Simulate the movement of a point cloud over a mesh");
break;
}
default:
assert(0); return QString("error");
assert(0);
return QString("error");
break;
}
}
RichParameterList FilterDirt::initParameterList(const QAction* filter, const MeshDocument & /*md*/)
RichParameterList FilterDirt::initParameterList(const QAction* filter, const MeshDocument& md)
{
RichParameterList par;
switch(ID(filter)){
case FP_DIRT:{
par.addParam(RichDirection("dust_dir", Point3m(0, 1, 0), "Direction", "Direction of the dust source"));
par.addParam(RichInt("nparticles", 3, "max particles x face", "Max Number of Dust Particles to Generate Per Face"));
par.addParam(RichFloat("slippiness", 1.0f, "s", "The surface slippines(large s means less sticky)"));
par.addParam(RichFloat("adhesion", 0.2f, "k", "Factor to model the general adhesion"));
par.addParam(RichBool("draw_texture", false, "Draw Dust", "create a new texture saved in dirt_texture.png"));
// par.addParam(RichBool("colorize_mesh",false,"Map to Color","Color the mesh with colors based on the movement of the particle"));
break;
const MeshModel* pc = md.mm();
const MeshModel* target = md.mm();
if (md.mm()->cm.FN() == 0) { // point cloud looks ok
// looking for the target mesh different that the current one
for (const MeshModel& t : md.meshIterator()) {
if (&t != md.mm() && t.cm.FN() > 0) {
target = &t;
break;
}
}
}
case FP_CLOUD_MOVEMENT:{
else { // target mesh looks ok
// looking for the point cloud mesh different that the current one
for (const MeshModel& t : md.meshIterator()) {
if (&t != md.mm() && t.cm.FN() == 0) {
pc = &t;
break;
}
}
}
switch (ID(filter)) {
case FP_DIRT:
par.addParam(RichDirection(
"dust_dir", Point3m(0, 1, 0), "Direction", "Direction of the dust source"));
par.addParam(RichInt(
"nparticles",
3,
"max particles x face",
"Max Number of Dust Particles to Generate Per Face"));
par.addParam(
RichFloat("slippiness", 1.0f, "s", "The surface slippines(large s means less sticky)"));
par.addParam(RichFloat("adhesion", 0.2f, "k", "Factor to model the general adhesion"));
par.addParam(RichBool(
"draw_texture", false, "Draw Dust", "create a new texture saved in dirt_texture.png"));
// par.addParam(RichBool("colorize_mesh",false,"Map to Color","Color the mesh with colors
// based on the movement of the particle"));
break;
case FP_CLOUD_MOVEMENT:
par.addParam(RichMesh(
"point_cloud",
pc->id(),
&md,
"Point cloud",
"The point cloud that will be moved over the target mesh."));
par.addParam(RichMesh(
"target_mesh",
target->id(),
&md,
"Target mesh",
"Target mesh on which the point cloud will be moved."));
par.addParam(RichDirection("gravity_dir", Point3m(0, -1, 0), "g", "Direction of gravity"));
par.addParam(RichDirection("force_dir", Point3m(0, 0, 0), "force", "Direction of the force acting on the points cloud"));
par.addParam(RichDirection(
"force_dir",
Point3m(0, 0, 0),
"force",
"Direction of the force acting on the points cloud"));
par.addParam(RichInt("steps", 1, "s", "Simulation Steps"));
par.addParam(RichDynamicFloat("adhesion", 1.0f, 0.0f, 1.0f, "adhesion", "Factor to model the general adhesion."));
par.addParam(RichDynamicFloat(
"adhesion", 1.0f, 0.0f, 1.0f, "adhesion", "Factor to model the general adhesion."));
par.addParam(RichFloat("velocity", 0, "v", "Initial velocity of the particle"));
par.addParam(RichFloat("mass", 1, "m", "Mass of the particle"));
par.addParam(RichBool("colorize_mesh", false, "Map to Color", "Color the mesh with colors based on the movement of the particle"));
par.addParam(RichBool(
"colorize_mesh",
false,
"Map to Color",
"Color the mesh with colors based on the movement of the particle"));
break;
}
default:{
break;
}
default: break;
}
return par;
}
int FilterDirt::getRequirements(const QAction * /*action*/)
int FilterDirt::getRequirements(const QAction* /*action*/)
{
return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTCOLOR |MeshModel::MM_FACECOLOR;
return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTCOLOR | MeshModel::MM_FACECOLOR;
}
std::map<std::string, QVariant> FilterDirt::applyFilter(const QAction *filter, const RichParameterList &par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos *cb){
switch(ID(filter)){
case FP_DIRT:{
std::map<std::string, QVariant> FilterDirt::applyFilter(
const QAction* filter,
const RichParameterList& par,
MeshDocument& md,
unsigned int& /*postConditionMask*/,
vcg::CallBackPos* cb)
{
switch (ID(filter)) {
case FP_DIRT: {
/*Get Parameters*/
Point3m dir=par.getPoint3m("dust_dir");
Scalarm s=par.getFloat("slippiness");
Scalarm k=par.getFloat("adhesion");
bool draw=par.getBool("draw_texture");
//bool colorize=par.getBool("colorize_mesh");
int n_p=par.getInt("nparticles");
Point3m dir = par.getPoint3m("dust_dir");
Scalarm s = par.getFloat("slippiness");
Scalarm k = par.getFloat("adhesion");
bool draw = par.getBool("draw_texture");
// bool colorize=par.getBool("colorize_mesh");
int n_p = par.getInt("nparticles");
MeshModel* currMM=md.mm();
MeshModel* currMM = md.mm();
if (currMM->cm.fn==0) {
throw MLException("This filter requires a mesh with some faces, it does not work on PointSet");
if (currMM->cm.fn == 0) {
throw MLException(
"This filter requires a mesh with some faces, it does not work on PointSet");
}
if(draw && !tri::HasPerWedgeTexCoord(currMM->cm)){
if (draw && !tri::HasPerWedgeTexCoord(currMM->cm)) {
throw MLException("Current Mesh does not have per Wedge Tex Coordinates");
}
vector<Point3m> dust_points;
prepareMesh(currMM);
if(cb) (*cb)(10,"Computing Dust Amount...");
if (cb)
(*cb)(10, "Computing Dust Amount...");
ComputeNormalDustAmount(currMM,dir,k,s);
if(cb) (*cb)(30,"Computing Mesh Exposure...");
ComputeNormalDustAmount(currMM, dir, k, s);
if (cb)
(*cb)(30, "Computing Mesh Exposure...");
ComputeSurfaceExposure(currMM,1,1);
ComputeSurfaceExposure(currMM, 1, 1);
if(cb) (*cb)(50,"Generating Particles...");
if (cb)
(*cb)(50, "Generating Particles...");
GenerateParticles(currMM, dust_points,/*dust_particles,*/n_p, 0.6f);
MeshModel* dmm=md.addNewMesh("","dust_mesh",true);
GenerateParticles(currMM, dust_points, /*dust_particles,*/ n_p, 0.6f);
MeshModel* dmm = md.addNewMesh("", "dust_mesh", true);
dmm->cm.Clear();
tri::Allocator<CMeshO>::AddVertices(dmm->cm,dust_points.size());
CMeshO::VertexIterator vi;
vector<Point3m>::iterator dvi=dust_points.begin();
if(cb) (*cb)(70,"Creating cloud Mesh...");
for(vi=dmm->cm.vert.begin();vi!=dmm->cm.vert.end();++vi){
vi->P()=(*dvi);
tri::Allocator<CMeshO>::AddVertices(dmm->cm, dust_points.size());
CMeshO::VertexIterator vi;
vector<Point3m>::iterator dvi = dust_points.begin();
if (cb)
(*cb)(70, "Creating cloud Mesh...");
for (vi = dmm->cm.vert.begin(); vi != dmm->cm.vert.end(); ++vi) {
vi->P() = (*dvi);
++dvi;
}
if(draw) DrawDust(currMM,dmm);
//if(colorize) ColorizeMesh(currMM);
if (draw)
DrawDust(currMM, dmm);
// if(colorize) ColorizeMesh(currMM);
break;
}
case FP_CLOUD_MOVEMENT:{
if(md.meshNumber()!=2){
throw MLException("This filter requires two mesh");
case FP_CLOUD_MOVEMENT: {
MeshModel* base_mesh = md.getMesh(par.getMeshId("target_mesh"));
if (base_mesh->cm.fn == 0) {
throw MLException("The filter requires that the target mesh has some faces");
}
MeshModel* base_mesh=md.getMesh(0);
if(base_mesh->cm.fn==0){
throw MLException("The filter requires that the first mesh has some faces");
MeshModel* cloud_mesh = md.getMesh(par.getMeshId("point_cloud"));
if (cloud_mesh->cm.fn != 0) {
throw MLException("The filter requires that the point cloud has zero faces");
}
MeshModel* cloud_mesh=md.getMesh(1);
if(cloud_mesh->cm.fn!=0){
throw MLException("The filter requires that the second mesh is a Point Set");
}
//Get Parameters
Point3m dir=par.getPoint3m("force_dir");
Point3m g=par.getPoint3m("gravity_dir");
Scalarm adhesion =par.getDynamicFloat("adhesion");
Scalarm l=base_mesh->cm.bbox.Diag()*0.01; //mm()->cm.bbox.Diag();
Scalarm v=par.getFloat("velocity");
Scalarm m=par.getFloat("mass");
int s=par.getInt("steps");
bool colorize=par.getBool("colorize_mesh");
if(!HasPerVertexAttribute(cloud_mesh->cm,"ParticleInfo")){
// Get Parameters
Point3m dir = par.getPoint3m("force_dir");
Point3m g = par.getPoint3m("gravity_dir");
Scalarm adhesion = par.getDynamicFloat("adhesion");
Scalarm l = base_mesh->cm.bbox.Diag() * 0.01; // mm()->cm.bbox.Diag();
Scalarm v = par.getFloat("velocity");
Scalarm m = par.getFloat("mass");
int s = par.getInt("steps");
bool colorize = par.getBool("colorize_mesh");
if (!HasPerVertexAttribute(cloud_mesh->cm, "ParticleInfo")) {
prepareMesh(base_mesh);
//Associate every point to a mesh and a Particle to every point
associateParticles(base_mesh,cloud_mesh,m,v,g);
// Associate every point to a mesh and a Particle to every point
associateParticles(base_mesh, cloud_mesh, m, v, g);
}
//Move Cloud Mesh
float frac=100/s;
for(int i=0;i<s;i++){
MoveCloudMeshForward(cloud_mesh,base_mesh,g,dir,l,adhesion,1,1);
if(cb) (*cb)(i*frac,"Moving...");
// Move Cloud Mesh
float frac = 100 / s;
for (int i = 0; i < s; i++) {
MoveCloudMeshForward(cloud_mesh, base_mesh, g, dir, l, adhesion, 1, 1);
if (cb)
(*cb)(i * frac, "Moving...");
}
if(colorize) ColorizeMesh(base_mesh);
if (colorize)
ColorizeMesh(base_mesh);
break;
}
default:{
default: {
wrongActionCalled(filter);
break;
}
}
return std::map<std::string, QVariant>();
}//End applyFilter
} // End applyFilter
int FilterDirt::postCondition(const QAction *a) const
int FilterDirt::postCondition(const QAction* a) const
{
switch (ID(a)){
switch (ID(a)) {
case FP_DIRT: return MeshModel::MM_ALL;
case FP_CLOUD_MOVEMENT: return MeshModel::MM_ALL;
default: assert(0);
@ -248,12 +296,12 @@ int FilterDirt::postCondition(const QAction *a) const
return MeshModel::MM_ALL;
}
FilterPlugin::FilterClass FilterDirt::getClass(const QAction *filter) const
FilterPlugin::FilterClass FilterDirt::getClass(const QAction* filter) const
{
switch (ID(filter)) {
case FP_DIRT:return FilterPlugin::Sampling;
case FP_CLOUD_MOVEMENT:return FilterPlugin::Remeshing;
default:assert(0);
switch (ID(filter)) {
case FP_DIRT: return FilterPlugin::Sampling;
case FP_CLOUD_MOVEMENT: return FilterPlugin::Remeshing;
default: assert(0);
}
return FilterPlugin::Generic;
}

View File

@ -1,75 +1,66 @@
/****************************************************************************
* MeshLab o o *
* A versatile mesh processing toolbox o o *
* _ O _ *
* Copyright(C) 2007 \/)\/ *
* 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. *
* *
****************************************************************************/
/*****************************************************************************
* 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 FILTERDIRTPLUGIN_H
#define FILTERDIRTPLUGIN_H
#include <QObject>
#include <QStringList>
#include <QString>
#include <QStringList>
#include <common/plugins/interfaces/filter_plugin.h>
#include<vector>
#include<vcg/complex/complex.h>
//#include "muParser.h"
#include <vcg/complex/complex.h>
#include <vector>
using namespace vcg;
//using namespace mu;
class FilterDirt : public QObject, public FilterPlugin
{
Q_OBJECT
MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_IID)
Q_INTERFACES(FilterPlugin)
protected:
double x,y,z,nx,ny,nz,r,g,b,q,rad;
//double x0,y0,z0,x1,y1,z1,x2,y2,z2,nx0,ny0,nz0,nx1,ny1,nz1,nx2,ny2,nz2,r0,g0,b0,r1,g1,b1,r2,g2,b2,q0,q1,q2;
double v,f,v0i,v1i,v2i;
std::vector<std::string> v_attrNames;
std::vector<double> v_attrValue;
//std::vector<std::string> f_attrNames;
//std:: vector<double> f_attrValue;
std::vector<CMeshO::PerVertexAttributeHandle<float> > vhandlers;
//std::vector<CMeshO::PerFaceAttributeHandle<float> > fhandlers;
public:
enum {FP_DIRT,FP_CLOUD_MOVEMENT} ;
enum { FP_DIRT, FP_CLOUD_MOVEMENT };
FilterDirt();
~FilterDirt(){};
~FilterDirt() {};
QString pluginName() const;
QString pluginName() const;
virtual QString filterName(ActionIDType filter) const;
virtual QString filterInfo(ActionIDType filter) const;
virtual int getRequirements(const QAction*);
virtual bool autoDialog(QAction *) {return true;}
virtual int getRequirements(const QAction*);
virtual bool autoDialog(QAction*) { return true; }
// virtual void initParameterSet(QAction* filter,MeshModel &,RichParameterSet &){};
RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/);
std::map<std::string, QVariant> applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb);
virtual int postCondition(const QAction*) const;
virtual FilterClass getClass (const QAction *) const;
FilterArity filterArity(const QAction*) const {return SINGLE_MESH;}
RichParameterList initParameterList(const QAction*, const MeshDocument& /*m*/);
std::map<std::string, QVariant> applyFilter(
const QAction* action,
const RichParameterList& /*parent*/,
MeshDocument& md,
unsigned int& postConditionMask,
vcg::CallBackPos* cb);
virtual int postCondition(const QAction*) const;
virtual FilterClass getClass(const QAction*) const;
FilterArity filterArity(const QAction*) const { return SINGLE_MESH; }
};
#endif

View File

@ -1,25 +1,25 @@
/****************************************************************************
* 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. *
* *
****************************************************************************/
/*****************************************************************************
* 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 "filter_mesh_booleans.h"
@ -32,17 +32,14 @@
* Constructor usually performs only two simple tasks of filling the two lists
* - typeList: with all the possible id of the filtering actions
* - actionList with the corresponding actions.
* If you want to add icons to your filtering actions you can do here by construction the QActions accordingly
* If you want to add icons to your filtering actions you can do here by construction the QActions
* accordingly
*/
FilterMeshBooleans::FilterMeshBooleans()
{
typeList = {
MESH_INTERSECTION,
MESH_UNION,
MESH_DIFFERENCE,
MESH_XOR};
typeList = {MESH_INTERSECTION, MESH_UNION, MESH_DIFFERENCE, MESH_XOR};
for(const ActionIDType& tt : typeList)
for (const ActionIDType& tt : typeList)
actionList.push_back(new QAction(filterName(tt), this));
}
@ -64,22 +61,15 @@ QString FilterMeshBooleans::vendor() const
*/
QString FilterMeshBooleans::filterName(ActionIDType filterId) const
{
switch(filterId) {
case MESH_INTERSECTION :
return "Mesh Boolean: Intersection";
case MESH_UNION:
return "Mesh Boolean: Union";
case MESH_DIFFERENCE:
return "Mesh Boolean: Difference";
case MESH_XOR:
return "Mesh Boolean: Symmetric Difference (XOR)";
default :
assert(0);
return "";
switch (filterId) {
case MESH_INTERSECTION: return "Mesh Boolean: Intersection";
case MESH_UNION: return "Mesh Boolean: Union";
case MESH_DIFFERENCE: return "Mesh Boolean: Difference";
case MESH_XOR: return "Mesh Boolean: Symmetric Difference (XOR)";
default: assert(0); return "";
}
}
/**
* @brief // Info() must return the longer string describing each filtering action
* (this string is used in the About plugin dialog)
@ -95,18 +85,12 @@ QString FilterMeshBooleans::filterInfo(ActionIDType filterId) const
"The implementation refers to the following paper:<br>"
"<i>Qingnan Zhou, Eitan Grinspun, Denis Zorin, Alec Jacobson</i>,<br>"
"<b>\"Mesh Arrangements for Solid Geometry\"</b><br>";
switch(filterId) {
case MESH_INTERSECTION :
return description.arg("intersection");
case MESH_UNION:
return description.arg("union");
case MESH_DIFFERENCE:
return description.arg("difference");
case MESH_XOR:
return description.arg("symmetric difference (XOR)");
default :
assert(0);
return "Unknown Filter";
switch (filterId) {
case MESH_INTERSECTION: return description.arg("intersection");
case MESH_UNION: return description.arg("union");
case MESH_DIFFERENCE: return description.arg("difference");
case MESH_XOR: return description.arg("symmetric difference (XOR)");
default: assert(0); return "Unknown Filter";
}
}
@ -117,17 +101,16 @@ QString FilterMeshBooleans::filterInfo(ActionIDType filterId) const
* @param a: the action of the filter
* @return the class od the filter
*/
FilterMeshBooleans::FilterClass FilterMeshBooleans::getClass(const QAction *a) const
FilterMeshBooleans::FilterClass FilterMeshBooleans::getClass(const QAction* a) const
{
switch(ID(a)) {
case MESH_INTERSECTION :
switch (ID(a)) {
case MESH_INTERSECTION:
case MESH_UNION:
case MESH_DIFFERENCE:
case MESH_XOR:
return FilterPlugin::FilterClass(FilterPlugin::FilterClass(FilterPlugin::Layer + FilterPlugin::Remeshing));
default :
assert(0);
return FilterPlugin::Generic;
return FilterPlugin::FilterClass(
FilterPlugin::FilterClass(FilterPlugin::Layer + FilterPlugin::Remeshing));
default: assert(0); return FilterPlugin::Generic;
}
}
@ -144,7 +127,7 @@ FilterPlugin::FilterArity FilterMeshBooleans::filterArity(const QAction*) const
* @brief FilterSamplePlugin::getPreConditions
* @return
*/
//int FilterMeshBooleans::getPreConditions(const QAction*) const
// int FilterMeshBooleans::getPreConditions(const QAction*) const
//{
// return MeshModel::MM_NONE;
//}
@ -153,37 +136,36 @@ FilterPlugin::FilterArity FilterMeshBooleans::filterArity(const QAction*) const
* @brief FilterSamplePlugin::postCondition
* @return
*/
//int FilterMeshBooleans::postCondition(const QAction*) const
// int FilterMeshBooleans::postCondition(const QAction*) const
//{
// return MeshModel::MM_VERTCOORD | MeshModel::MM_FACENORMAL | MeshModel::MM_VERTNORMAL;
//}
/**
* @brief This function define the needed parameters for each filter. Return true if the filter has some parameters
* it is called every time, so you can set the default value of parameters according to the mesh
* For each parameter you need to define,
* @brief This function define the needed parameters for each filter. Return true if the filter has
* some parameters it is called every time, so you can set the default value of parameters according
* to the mesh For each parameter you need to define,
* - the name of the parameter,
* - the default value
* - the string shown in the dialog
* - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog)
* - a possibly long string describing the meaning of that parameter (shown as a popup help in the
* dialog)
* @param action
* @param m
* @param parlst
*/
RichParameterList FilterMeshBooleans::initParameterList(
const QAction *action,
const MeshDocument& md)
RichParameterList
FilterMeshBooleans::initParameterList(const QAction* action, const MeshDocument& md)
{
RichParameterList parlst;
switch(ID(action)) {
case MESH_INTERSECTION :
switch (ID(action)) {
case MESH_INTERSECTION:
case MESH_UNION:
case MESH_DIFFERENCE:
case MESH_XOR:
{
const MeshModel *target = md.mm();
//looking for a second mesh different that the current one
for (const MeshModel& t : md.meshIterator()){
case MESH_XOR: {
const MeshModel* target = md.mm();
// looking for a second mesh different that the current one
for (const MeshModel& t : md.meshIterator()) {
if (&t != md.mm()) {
target = &t;
break;
@ -191,35 +173,47 @@ RichParameterList FilterMeshBooleans::initParameterList(
}
parlst.addParam(RichMesh(
"first_mesh", md.mm()->id(), &md, "First Mesh",
"The first operand of the boolean operation"));
"first_mesh",
md.mm()->id(),
&md,
"First Mesh",
"The first operand of the boolean operation"));
parlst.addParam(RichMesh(
"second_mesh", target->id(), &md, "Second Mesh",
"The second operand of the boolean operation"));
"second_mesh",
target->id(),
&md,
"Second Mesh",
"The second operand of the boolean operation"));
parlst.addParam(RichBool(
"transfer_face_color", false,
"Transfer face color", "Save the color of the birth face to the faces of resulting mesh."));
"transfer_face_color",
false,
"Transfer face color",
"Save the color of the birth face to the faces of resulting mesh."));
parlst.addParam(RichBool(
"transfer_face_quality", false,
"Transfer face quality", "Save the quality of the birth face to the faces of resulting mesh."));
"transfer_face_quality",
false,
"Transfer face quality",
"Save the quality of the birth face to the faces of resulting mesh."));
parlst.addParam(RichBool(
"transfer_vert_color", false,
"Transfer vertex color",
"Save the color of the birth vertex to the faces of resulting mesh. For newly created vertices, "
"a simple average of the neighbours is computed."));
"transfer_vert_color",
false,
"Transfer vertex color",
"Save the color of the birth vertex to the faces of resulting mesh. For newly created "
"vertices, "
"a simple average of the neighbours is computed."));
parlst.addParam(RichBool(
"transfer_vert_quality", false,
"Transfer vertex quality",
"Save the quality of the birth vertex to the faces of resulting mesh. For newly created vertices, "
"a simple average of the neighbours is computed."));
}
break;
default :
assert(0);
"transfer_vert_quality",
false,
"Transfer vertex quality",
"Save the quality of the birth vertex to the faces of resulting mesh. For newly "
"created vertices, "
"a simple average of the neighbours is computed."));
} break;
default: assert(0);
}
return parlst;
}
@ -233,65 +227,63 @@ RichParameterList FilterMeshBooleans::initParameterList(
* @return true if the filter has been applied correctly, false otherwise
*/
std::map<std::string, QVariant> FilterMeshBooleans::applyFilter(
const QAction * action,
const RichParameterList & par,
MeshDocument &md,
unsigned int& /*postConditionMask*/,
vcg::CallBackPos *)
const QAction* action,
const RichParameterList& par,
MeshDocument& md,
unsigned int& /*postConditionMask*/,
vcg::CallBackPos*)
{
bool transfFaceQuality = par.getBool("transfer_face_quality");
bool transfFaceColor = par.getBool("transfer_face_color");
bool transfFaceColor = par.getBool("transfer_face_color");
bool transfVertQuality = par.getBool("transfer_vert_quality");
bool transfVertColor = par.getBool("transfer_vert_color");
bool transfVertColor = par.getBool("transfer_vert_color");
switch(ID(action)) {
case MESH_INTERSECTION :
switch (ID(action)) {
case MESH_INTERSECTION:
booleanOperation(
md,
*md.getMesh(par.getMeshId("first_mesh")),
*md.getMesh(par.getMeshId("second_mesh")),
igl::MESH_BOOLEAN_TYPE_INTERSECT,
transfFaceQuality,
transfFaceColor,
transfVertQuality,
transfVertColor);
md,
*md.getMesh(par.getMeshId("first_mesh")),
*md.getMesh(par.getMeshId("second_mesh")),
igl::MESH_BOOLEAN_TYPE_INTERSECT,
transfFaceQuality,
transfFaceColor,
transfVertQuality,
transfVertColor);
break;
case MESH_UNION:
booleanOperation(
md,
*md.getMesh(par.getMeshId("first_mesh")),
*md.getMesh(par.getMeshId("second_mesh")),
igl::MESH_BOOLEAN_TYPE_UNION,
transfFaceQuality,
transfFaceColor,
transfVertQuality,
transfVertColor);
md,
*md.getMesh(par.getMeshId("first_mesh")),
*md.getMesh(par.getMeshId("second_mesh")),
igl::MESH_BOOLEAN_TYPE_UNION,
transfFaceQuality,
transfFaceColor,
transfVertQuality,
transfVertColor);
break;
case MESH_DIFFERENCE:
booleanOperation(
md,
*md.getMesh(par.getMeshId("first_mesh")),
*md.getMesh(par.getMeshId("second_mesh")),
igl::MESH_BOOLEAN_TYPE_MINUS,
transfFaceQuality,
transfFaceColor,
transfVertQuality,
transfVertColor);
md,
*md.getMesh(par.getMeshId("first_mesh")),
*md.getMesh(par.getMeshId("second_mesh")),
igl::MESH_BOOLEAN_TYPE_MINUS,
transfFaceQuality,
transfFaceColor,
transfVertQuality,
transfVertColor);
break;
case MESH_XOR:
booleanOperation(
md,
*md.getMesh(par.getMeshId("first_mesh")),
*md.getMesh(par.getMeshId("second_mesh")),
igl::MESH_BOOLEAN_TYPE_XOR,
transfFaceQuality,
transfFaceColor,
transfVertQuality,
transfVertColor);
md,
*md.getMesh(par.getMeshId("first_mesh")),
*md.getMesh(par.getMeshId("second_mesh")),
igl::MESH_BOOLEAN_TYPE_XOR,
transfFaceQuality,
transfFaceColor,
transfVertQuality,
transfVertColor);
break;
default :
wrongActionCalled(action);
default: wrongActionCalled(action);
}
return std::map<std::string, QVariant>();
}
@ -307,56 +299,51 @@ std::map<std::string, QVariant> FilterMeshBooleans::applyFilter(
* @param transfColor: if true, face color will be transferred in the res mesh
*/
void FilterMeshBooleans::booleanOperation(
MeshDocument& md,
const MeshModel& m1,
const MeshModel& m2,
int op,
bool transfFaceQuality,
bool transfFaceColor,
bool transfVertQuality,
bool transfVertColor)
MeshDocument& md,
const MeshModel& m1,
const MeshModel& m2,
int op,
bool transfFaceQuality,
bool transfFaceColor,
bool transfVertQuality,
bool transfVertColor)
{
QString name;
switch (op) {
case igl::MESH_BOOLEAN_TYPE_INTERSECT:
name = "intersection";
break;
case igl::MESH_BOOLEAN_TYPE_MINUS:
name = "difference";
break;
case igl::MESH_BOOLEAN_TYPE_XOR:
name = "xor";
break;
case igl::MESH_BOOLEAN_TYPE_UNION:
name = "union";
break;
case igl::MESH_BOOLEAN_TYPE_INTERSECT: name = "intersection"; break;
case igl::MESH_BOOLEAN_TYPE_MINUS: name = "difference"; break;
case igl::MESH_BOOLEAN_TYPE_XOR: name = "xor"; break;
case igl::MESH_BOOLEAN_TYPE_UNION: name = "union"; break;
default:
throw MLException("Boolean Operation not found! Please report this issue on https://github.com/cnr-isti-vclab/meshlab/issues");
throw MLException(
"Boolean Operation not found! Please report this issue on "
"https://github.com/cnr-isti-vclab/meshlab/issues");
}
//vcg to eigen meshes
EigenMatrixX3m V1 = meshlab::vertexMatrix(m1.cm);
// vcg to eigen meshes
EigenMatrixX3m V1 = meshlab::vertexMatrix(m1.cm);
Eigen::MatrixX3i F1 = meshlab::faceMatrix(m1.cm);
EigenMatrixX3m V2 = meshlab::vertexMatrix(m2.cm);
EigenMatrixX3m V2 = meshlab::vertexMatrix(m2.cm);
Eigen::MatrixX3i F2 = meshlab::faceMatrix(m2.cm);
EigenMatrixX3m VR;
EigenMatrixX3m VR;
Eigen::MatrixX3i FR;
Eigen::VectorXi indices; //mapping indices for birth faces
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);
bool result = igl::copyleft::cgal::mesh_boolean(
V1, F1, V2, F2, (igl::MeshBooleanType) op, VR, FR, indices);
if (!result){
if (!result) {
throw MLException(
"Mesh inputs must induce a piecewise constant winding number field.<br>"
"Make sure that both the input mesh are watertight (closed).");
}
else {
//everything ok, create new mesh into md
// everything ok, create new mesh into md
MeshModel* mesh = md.addNewMesh("", name);
mesh->cm = meshlab::meshFromMatrices(VR, FR);
mesh->cm = meshlab::meshFromMatrices(VR, FR);
//if transfer option enabled
// if transfer option enabled
if (transfFaceColor || transfFaceQuality)
transferFaceAttributes(*mesh, indices, m1, m2, transfFaceQuality, transfFaceColor);
if (transfVertColor || transfVertQuality)
@ -381,16 +368,16 @@ void FilterMeshBooleans::booleanOperation(
* @param color: if true, face color will be transferred
*/
void FilterMeshBooleans::transferFaceAttributes(
MeshModel& res,
const Eigen::VectorXi& faceIndices,
const MeshModel& m1,
const MeshModel& m2,
bool quality,
bool color)
MeshModel& res,
const Eigen::VectorXi& faceIndices,
const MeshModel& m1,
const MeshModel& m2,
bool quality,
bool color)
{
//checking if m1 and m2 have quality and color
// checking if m1 and m2 have quality and color
bool m1HasQuality = true, m1HasColor = true, m2HasQuality = true, m2HasColor = true;
if (quality){
if (quality) {
res.updateDataMask(MeshModel::MM_FACEQUALITY);
if (!m1.hasDataMask(MeshModel::MM_FACEQUALITY))
m1HasQuality = false;
@ -405,20 +392,20 @@ void FilterMeshBooleans::transferFaceAttributes(
m2HasColor = false;
}
//for each index in the birth faces vector
for (unsigned int i = 0; i < faceIndices.size(); ++i){
bool fromM1 = true;
// for each index in the birth faces vector
for (unsigned int i = 0; i < faceIndices.size(); ++i) {
bool fromM1 = true;
unsigned int mIndex = faceIndices[i];
//if the index is >= FN of m1, it means that the index is of m2
if (faceIndices[i] >= m1.cm.FN()){
// if the index is >= FN of m1, it means that the index is of m2
if (faceIndices[i] >= m1.cm.FN()) {
fromM1 = false;
mIndex -= m1.cm.FN();
}
//if we need to transfer quality
if (quality){
Scalarm q = 0; //default quality value
// if we need to transfer quality
if (quality) {
Scalarm q = 0; // default quality value
if (fromM1 && m1HasQuality)
q = m1.cm.face[mIndex].Q();
if (!fromM1 && m2HasQuality)
@ -426,9 +413,9 @@ void FilterMeshBooleans::transferFaceAttributes(
res.cm.face[i].Q() = q;
}
//if we need to transfer color
// if we need to transfer color
if (color) {
vcg::Color4b c(128, 128, 128, 255); //default color value
vcg::Color4b c(128, 128, 128, 255); // default color value
if (fromM1 && m1HasColor)
c = m1.cm.face[mIndex].C();
if (!fromM1 && m2HasColor)
@ -455,19 +442,19 @@ void FilterMeshBooleans::transferFaceAttributes(
* @param color: if true, vertex color will be transferred
*/
void FilterMeshBooleans::transferVertexAttributes(
MeshModel& res,
const Eigen::VectorXi& faceIndices,
const MeshModel& m1,
const MeshModel& m2,
bool quality,
bool color)
MeshModel& res,
const Eigen::VectorXi& faceIndices,
const MeshModel& m1,
const MeshModel& m2,
bool quality,
bool color)
{
res.updateDataMask(MeshModel::MM_VERTFACETOPO);
vcg::tri::UpdateTopology<CMeshO>::VertexFace(res.cm);
//checking if m1 and m2 have quality and color
// checking if m1 and m2 have quality and color
bool m1HasQuality = true, m1HasColor = true, m2HasQuality = true, m2HasColor = true;
if (quality){
if (quality) {
res.updateDataMask(MeshModel::MM_VERTQUALITY);
if (!m1.hasDataMask(MeshModel::MM_VERTQUALITY))
m1HasQuality = false;
@ -482,34 +469,34 @@ void FilterMeshBooleans::transferVertexAttributes(
m2HasColor = false;
}
//vertIndices construction
// vertIndices construction
Eigen::VectorXi vertIndices(res.cm.VN());
vertIndices.setConstant(-1);
for (unsigned int i = 0; i < faceIndices.size(); ++i){
bool fromM1 = true;
for (unsigned int i = 0; i < faceIndices.size(); ++i) {
bool fromM1 = true;
unsigned int mIndex = faceIndices[i];
//if the index is >= FN of m1, it means that the index is of m2
if (faceIndices[i] >= m1.cm.FN()){
// if the index is >= FN of m1, it means that the index is of m2
if (faceIndices[i] >= m1.cm.FN()) {
fromM1 = false;
mIndex -= m1.cm.FN();
}
CMeshO::ConstFacePointer fBirth;
CMeshO::FacePointer fRes = &(res.cm.face[i]);
CMeshO::FacePointer fRes = &(res.cm.face[i]);
if (fromM1)
fBirth = &(m1.cm.face[mIndex]);
else
fBirth = &(m2.cm.face[mIndex]);
for (unsigned int j = 0; j < 3; ++j){
for (unsigned int j = 0; j < 3; ++j) {
CMeshO::VertexPointer vp = fRes->V(j);
unsigned int vi = vcg::tri::Index(res.cm, vp);
if (vertIndices[vi] == -1){
//look if there is an equal vertex in fBirth
for (unsigned k = 0; k < 3; ++k){
if (fRes->V(j)->P() == fBirth->V(k)->P()){
unsigned int vi = vcg::tri::Index(res.cm, vp);
if (vertIndices[vi] == -1) {
// look if there is an equal vertex in fBirth
for (unsigned k = 0; k < 3; ++k) {
if (fRes->V(j)->P() == fBirth->V(k)->P()) {
unsigned int birthVertIndex;
if (fromM1)
birthVertIndex = vcg::tri::Index(m1.cm, fBirth->V(k));
@ -522,13 +509,13 @@ void FilterMeshBooleans::transferVertexAttributes(
}
}
//update birth vertices
for (unsigned int i = 0; i < vertIndices.size(); ++i){
// update birth vertices
for (unsigned int i = 0; i < vertIndices.size(); ++i) {
bool fromM1 = false;
bool fromM2 = false;
int mIndex = vertIndices[i];
if (vertIndices[i] >= m1.cm.VN()){
if (vertIndices[i] >= m1.cm.VN()) {
fromM2 = true;
mIndex -= m1.cm.VN();
}
@ -536,9 +523,9 @@ void FilterMeshBooleans::transferVertexAttributes(
fromM1 = true;
}
//if we need to transfer quality
if (quality){
Scalarm q = 0; //default quality value
// if we need to transfer quality
if (quality) {
Scalarm q = 0; // default quality value
if (fromM1 && m1HasQuality)
q = m1.cm.vert[mIndex].Q();
if (!fromM1 && m2HasQuality)
@ -546,9 +533,9 @@ void FilterMeshBooleans::transferVertexAttributes(
res.cm.vert[i].Q() = q;
}
//if we need to transfer color
// if we need to transfer color
if (color) {
vcg::Color4b c(128, 128, 128, 255); //default color value
vcg::Color4b c(128, 128, 128, 255); // default color value
if (fromM1 && m1HasColor)
c = m1.cm.vert[mIndex].C();
if (fromM2 && m2HasColor)
@ -557,43 +544,44 @@ void FilterMeshBooleans::transferVertexAttributes(
}
}
//update newly created vertices
for (unsigned int i = 0; i < vertIndices.size(); ++i){
if (vertIndices[i] == -1){
//base values
unsigned int avgr=0, avgg=0, avgb=0, avga=0;
Scalarm avgq=0;
// update newly created vertices
for (unsigned int i = 0; i < vertIndices.size(); ++i) {
if (vertIndices[i] == -1) {
// base values
unsigned int avgr = 0, avgg = 0, avgb = 0, avga = 0;
Scalarm avgq = 0;
unsigned int nAdjs = 0;
CMeshO::VertexPointer vp = &res.cm.vert[i];
CMeshO::VertexPointer vp = &res.cm.vert[i];
vcg::face::VFIterator<CMeshO::FaceType> fadjit(vp);
//for each incident face fadj to vp
for (; !fadjit.End(); ++fadjit){
for (unsigned int j = 0; j < 3; j++){
//get each vertex to f
// for each incident face fadj to vp
for (; !fadjit.End(); ++fadjit) {
for (unsigned int j = 0; j < 3; j++) {
// get each vertex to f
CMeshO::VertexPointer vadj = fadjit.F()->V(j);
unsigned int vi = vcg::tri::Index(res.cm, vadj);
//if the vertex is not i and it is not newly created
unsigned int vi = vcg::tri::Index(res.cm, vadj);
// if the vertex is not i and it is not newly created
if (vi != i && vertIndices[vi] != -1) {
nAdjs++;
//if we need to transfer color
// if we need to transfer color
if (color) {
avgr += res.cm.vert[vi].C()[0];
avgg += res.cm.vert[vi].C()[1];
avgb += res.cm.vert[vi].C()[2];
avga += res.cm.vert[vi].C()[3];
}
if (quality){
if (quality) {
avgq += res.cm.vert[vi].Q();
}
}
}
}
if (nAdjs != 0){
if (nAdjs != 0) {
if (color) {
res.cm.vert[i].C() = vcg::Color4b(avgr/nAdjs, avgg/nAdjs, avgb/nAdjs, avga/nAdjs);
res.cm.vert[i].C() =
vcg::Color4b(avgr / nAdjs, avgg / nAdjs, avgb / nAdjs, avga / nAdjs);
}
if (quality){
if (quality) {
res.cm.vert[i].Q() = avgq / nAdjs;
}
}

View File

@ -1,25 +1,25 @@
/****************************************************************************
* 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. *
* *
****************************************************************************/
/*****************************************************************************
* 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_FILTER_MESH_BOOLEANS_H
#define MESHLAB_FILTER_MESH_BOOLEANS_H
@ -47,59 +47,55 @@ class FilterMeshBooleans : public QObject, public FilterPlugin
Q_INTERFACES(FilterPlugin)
public:
//enum used to give an ID to every filter implemented in the plugin
enum FileterIds {
MESH_INTERSECTION,
MESH_UNION,
MESH_DIFFERENCE,
MESH_XOR};
// enum used to give an ID to every filter implemented in the plugin
enum FileterIds { MESH_INTERSECTION, MESH_UNION, MESH_DIFFERENCE, MESH_XOR };
FilterMeshBooleans();
QString pluginName() const;
QString vendor() const;
QString filterName(ActionIDType filter) const;
QString filterInfo(ActionIDType filter) const;
QString filterName(ActionIDType filter) const;
QString filterInfo(ActionIDType filter) const;
FilterClass getClass(const QAction* a) const;
FilterArity filterArity(const QAction*) const;
//int getPreConditions(const QAction *) const;
//int postCondition(const QAction* ) const;
RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/);
// int getPreConditions(const QAction *) const;
// int postCondition(const QAction* ) const;
RichParameterList initParameterList(const QAction*, const MeshDocument& /*m*/);
std::map<std::string, QVariant> applyFilter(
const QAction* action,
const RichParameterList & params,
MeshDocument &md,
unsigned int& postConditionMask,
vcg::CallBackPos * cb);
const QAction* action,
const RichParameterList& params,
MeshDocument& md,
unsigned int& postConditionMask,
vcg::CallBackPos* cb);
private:
//generic boolean operation function
// generic boolean operation function
static void booleanOperation(
MeshDocument& md,
const MeshModel& m1,
const MeshModel& m2,
int op,
bool transfFaceQuality,
bool transfFaceColor,
bool transfVertQuality,
bool transfVertColor);
MeshDocument& md,
const MeshModel& m1,
const MeshModel& m2,
int op,
bool transfFaceQuality,
bool transfFaceColor,
bool transfVertQuality,
bool transfVertColor);
//transfer functions
// transfer functions
static void transferFaceAttributes(
MeshModel& res,
const Eigen::VectorXi& faceIndices,
const MeshModel& m1,
const MeshModel& m2,
bool quality,
bool color);
MeshModel& res,
const Eigen::VectorXi& faceIndices,
const MeshModel& m1,
const MeshModel& m2,
bool quality,
bool color);
static void transferVertexAttributes(
MeshModel& res,
const Eigen::VectorXi& faceIndices,
const MeshModel& m1,
const MeshModel& m2,
bool quality,
bool color);
MeshModel& res,
const Eigen::VectorXi& faceIndices,
const MeshModel& m1,
const MeshModel& m2,
bool quality,
bool color);
};
#endif //MESHLAB_FILTER_MESH_BOOLEANS_H
#endif // MESHLAB_FILTER_MESH_BOOLEANS_H