mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-13 08:09:39 +00:00
"points cloud movement" takes two mesh parameters
This commit is contained in:
parent
d92495fdb4
commit
c5ca4f0023
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user