From 6c2b26eab8a8c88e66e33728f32588f8300a8be2 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Fri, 5 Mar 2021 12:04:20 +0100 Subject: [PATCH] FilterMls uses new applyFilter call --- src/CMakeLists.txt | 2 +- src/meshlab.pro | 2 +- src/meshlabplugins/filter_mls/mlsplugin.cpp | 888 ++++++++++---------- src/meshlabplugins/filter_mls/mlsplugin.h | 9 +- 4 files changed, 456 insertions(+), 445 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 13e836c1f..98b1e6120 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -148,7 +148,7 @@ else() meshlabplugins/filter_layer meshlabplugins/filter_measure meshlabplugins/filter_meshing -# meshlabplugins/filter_mls + meshlabplugins/filter_mls # meshlabplugins/filter_mutualglobal # meshlabplugins/filter_mutualinfo # meshlabplugins/filter_plymc diff --git a/src/meshlab.pro b/src/meshlab.pro index be7a06445..ba0a3740c 100644 --- a/src/meshlab.pro +++ b/src/meshlab.pro @@ -69,7 +69,7 @@ SUBDIRS += \ #sub projects names filter_img_patch_param \ filter_isoparametrization \ filter_layer \ - #filter_mls \ + filter_mls \ #filter_mutualglobal \ #filter_mutualinfo \ #filter_plymc \ diff --git a/src/meshlabplugins/filter_mls/mlsplugin.cpp b/src/meshlabplugins/filter_mls/mlsplugin.cpp index 1112950c3..3b3f51891 100644 --- a/src/meshlabplugins/filter_mls/mlsplugin.cpp +++ b/src/meshlabplugins/filter_mls/mlsplugin.cpp @@ -52,119 +52,119 @@ typedef Histogram Histogramm; // - actionList with the corresponding actions. If you want to add icons to your filtering actions you can do here by construction the QActions accordingly enum { - CT_MEAN = 0, - CT_GAUSS = 1, - CT_K1 = 2, - CT_K2 = 3, - CT_APSS = 4 + CT_MEAN = 0, + CT_GAUSS = 1, + CT_K1 = 2, + CT_K2 = 3, + CT_APSS = 4 }; MlsPlugin::MlsPlugin() { - typeList - << FP_RIMLS_PROJECTION << FP_APSS_PROJECTION -// << FP_RIMLS_AFRONT << FP_APSS_AFRONT - << FP_RIMLS_MCUBE << FP_APSS_MCUBE - << FP_RIMLS_COLORIZE << FP_APSS_COLORIZE - << FP_RADIUS_FROM_DENSITY - << FP_SELECT_SMALL_COMPONENTS; + typeList + << FP_RIMLS_PROJECTION << FP_APSS_PROJECTION + // << FP_RIMLS_AFRONT << FP_APSS_AFRONT + << FP_RIMLS_MCUBE << FP_APSS_MCUBE + << FP_RIMLS_COLORIZE << FP_APSS_COLORIZE + << FP_RADIUS_FROM_DENSITY + << FP_SELECT_SMALL_COMPONENTS; -// initFilterList(this); - foreach(ActionIDType tt , types()) - actionList << new QAction(filterName(tt), this); + // initFilterList(this); + foreach(ActionIDType tt , types()) + actionList << new QAction(filterName(tt), this); } QString MlsPlugin::pluginName() const { - return "FilterMLS"; + return "FilterMLS"; } // ST() must return the very short string describing each filtering action // (this string is used also to define the menu entry) - QString MlsPlugin::filterName(ActionIDType filterId) const +QString MlsPlugin::filterName(ActionIDType filterId) const { - switch(filterId) { - case FP_APSS_PROJECTION : return QString("MLS projection (APSS)"); - case FP_RIMLS_PROJECTION : return QString("MLS projection (RIMLS)"); - case FP_APSS_AFRONT : return QString("MLS meshing/APSS Advancing Front"); - case FP_RIMLS_AFRONT : return QString("MLS meshing/RIMLS Advancing Front"); - case FP_APSS_MCUBE : return QString("Marching Cubes (APSS)"); - case FP_RIMLS_MCUBE : return QString("Marching Cubes (RIMLS)"); - case FP_APSS_COLORIZE : return QString("Colorize curvature (APSS)"); - case FP_RIMLS_COLORIZE : return QString("Colorize curvature (RIMLS)"); - case FP_RADIUS_FROM_DENSITY : return QString("Estimate radius from density"); - case FP_SELECT_SMALL_COMPONENTS : return QString("Select small disconnected component"); - default : assert(0); - } -return QString("Filter Unknown"); + switch(filterId) { + case FP_APSS_PROJECTION : return QString("MLS projection (APSS)"); + case FP_RIMLS_PROJECTION : return QString("MLS projection (RIMLS)"); + case FP_APSS_AFRONT : return QString("MLS meshing/APSS Advancing Front"); + case FP_RIMLS_AFRONT : return QString("MLS meshing/RIMLS Advancing Front"); + case FP_APSS_MCUBE : return QString("Marching Cubes (APSS)"); + case FP_RIMLS_MCUBE : return QString("Marching Cubes (RIMLS)"); + case FP_APSS_COLORIZE : return QString("Colorize curvature (APSS)"); + case FP_RIMLS_COLORIZE : return QString("Colorize curvature (RIMLS)"); + case FP_RADIUS_FROM_DENSITY : return QString("Estimate radius from density"); + case FP_SELECT_SMALL_COMPONENTS : return QString("Select small disconnected component"); + default : assert(0); + } + return QString("Filter Unknown"); } - FilterPlugin::FilterClass MlsPlugin::getClass(const QAction *a) const +FilterPlugin::FilterClass MlsPlugin::getClass(const QAction *a) const { - int filterId = ID(a); + int filterId = ID(a); - switch(filterId) { - case FP_APSS_PROJECTION : - case FP_RIMLS_PROJECTION : return FilterClass(FilterPlugin::PointSet + FilterPlugin::Smoothing); - case FP_APSS_AFRONT : - case FP_RIMLS_AFRONT : - case FP_APSS_MCUBE : - case FP_RIMLS_MCUBE : return FilterClass(FilterPlugin::PointSet | FilterPlugin::Remeshing); - case FP_APSS_COLORIZE : - case FP_RIMLS_COLORIZE : return FilterClass(FilterPlugin::PointSet | FilterPlugin::VertexColoring); - case FP_RADIUS_FROM_DENSITY : return FilterPlugin::PointSet; - case FP_SELECT_SMALL_COMPONENTS : return FilterPlugin::Selection; - } - assert(0); - return FilterPlugin::Generic; + switch(filterId) { + case FP_APSS_PROJECTION : + case FP_RIMLS_PROJECTION : return FilterClass(FilterPlugin::PointSet + FilterPlugin::Smoothing); + case FP_APSS_AFRONT : + case FP_RIMLS_AFRONT : + case FP_APSS_MCUBE : + case FP_RIMLS_MCUBE : return FilterClass(FilterPlugin::PointSet | FilterPlugin::Remeshing); + case FP_APSS_COLORIZE : + case FP_RIMLS_COLORIZE : return FilterClass(FilterPlugin::PointSet | FilterPlugin::VertexColoring); + case FP_RADIUS_FROM_DENSITY : return FilterPlugin::PointSet; + case FP_SELECT_SMALL_COMPONENTS : return FilterPlugin::Selection; + } + assert(0); + return FilterPlugin::Generic; } // Info() must return the longer string describing each filtering action // (this string is used in the About plugin dialog) - QString MlsPlugin::filterInfo(ActionIDType filterId) const +QString MlsPlugin::filterInfo(ActionIDType filterId) const { - QString str = ""; - if (filterId & _PROJECTION_) - { - str += "Project a mesh (or a point set) onto the MLS surface defined by itself or another point set.
"; - } + QString str = ""; + if (filterId & _PROJECTION_) + { + str += "Project a mesh (or a point set) onto the MLS surface defined by itself or another point set.
"; + } - if (filterId & _MCUBE_) - { - str += - "Extract the iso-surface (as a mesh) of a MLS surface defined by the current point set (or mesh)" + if (filterId & _MCUBE_) + { + str += + "Extract the iso-surface (as a mesh) of a MLS surface defined by the current point set (or mesh)" "using the marching cubes algorithm. The coarse extraction is followed by an accurate projection" "step onto the MLS, and an extra zero removal procedure.
"; - } + } - if (filterId & _COLORIZE_) - { - str += "Colorize the vertices of a mesh or point set using the curvature of the underlying surface.
"; - } + if (filterId & _COLORIZE_) + { + str += "Colorize the vertices of a mesh or point set using the curvature of the underlying surface.
"; + } - if (filterId & _APSS_) - { - str += - "
This is the algebraic point set surfaces (APSS) variant which is based on " + if (filterId & _APSS_) + { + str += + "
This is the algebraic point set surfaces (APSS) variant which is based on " "the local fitting of algebraic spheres. It requires points equipped with oriented normals.
" "For all the details about APSS see:
Guennebaud and Gross, 'Algebraic Point Set Surfaces', Siggraph 2007, and
" "Guennebaud et al., 'Dynamic Sampling and Rendering of APSS', Eurographics 2008"; - } + } - if (filterId & _RIMLS_) - { - str += - "
This is the Robust Implicit MLS (RIMLS) variant which is an extension of " + if (filterId & _RIMLS_) + { + str += + "
This is the Robust Implicit MLS (RIMLS) variant which is an extension of " "Implicit MLS preserving sharp features using non linear regression. For more details see:
" "Oztireli, Guennebaud and Gross, 'Feature Preserving Point Set Surfaces based on Non-Linear Kernel Regression' Eurographics 2009."; - } + } - if (filterId == FP_RADIUS_FROM_DENSITY) - str = "Estimate the local point spacing (aka radius) around each vertex using a basic estimate of the local density."; - else if (filterId == FP_SELECT_SMALL_COMPONENTS) - str = "Select the small disconnected components of a mesh."; + if (filterId == FP_RADIUS_FROM_DENSITY) + str = "Estimate the local point spacing (aka radius) around each vertex using a basic estimate of the local density."; + else if (filterId == FP_SELECT_SMALL_COMPONENTS) + str = "Select the small disconnected components of a mesh."; - return str; + return str; } @@ -177,444 +177,450 @@ return QString("Filter Unknown"); // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) void MlsPlugin::initParameterList(const QAction* action, MeshDocument& md, RichParameterList& parlst) { - int id = ID(action); - MeshModel *target = md.mm(); + int id = ID(action); + MeshModel *target = md.mm(); - if (id == FP_SELECT_SMALL_COMPONENTS) - { - parlst.addParam(RichFloat("NbFaceRatio", - 0.1f, - "Small component ratio", - "This ratio (between 0 and 1) defines the meaning of small as the threshold ratio between the number of faces" + if (id == FP_SELECT_SMALL_COMPONENTS) + { + parlst.addParam(RichFloat("NbFaceRatio", + 0.1f, + "Small component ratio", + "This ratio (between 0 and 1) defines the meaning of small as the threshold ratio between the number of faces" "of the largest component and the other ones. A larger value will select more components.")); - parlst.addParam(RichBool( "NonClosedOnly", - false, - "Select only non closed components", - "")); - return; - } - else if (id == FP_RADIUS_FROM_DENSITY) - { - parlst.addParam(RichInt("NbNeighbors", - 16, - "Number of neighbors", - "Number of neighbors used to estimate the local density. Larger values lead to smoother variations.")); - return; - } + parlst.addParam(RichBool( "NonClosedOnly", + false, + "Select only non closed components", + "")); + return; + } + else if (id == FP_RADIUS_FROM_DENSITY) + { + parlst.addParam(RichInt("NbNeighbors", + 16, + "Number of neighbors", + "Number of neighbors used to estimate the local density. Larger values lead to smoother variations.")); + return; + } - if ((id & _PROJECTION_)) - { - parlst.addParam(RichMesh( "ControlMesh", target,&md, "Point set", - "The point set (or mesh) which defines the MLS surface.")); - parlst.addParam(RichMesh( "ProxyMesh", target, &md, "Proxy Mesh", - "The mesh that will be projected/resampled onto the MLS surface.")); - } - if ((id & _PROJECTION_) || (id & _COLORIZE_)) - { - parlst.addParam(RichBool( "SelectionOnly", - target->cm.sfn>0, - "Selection only", - "If checked, only selected vertices will be projected.")); - } + if ((id & _PROJECTION_)) + { + parlst.addParam(RichMesh( "ControlMesh", target,&md, "Point set", + "The point set (or mesh) which defines the MLS surface.")); + parlst.addParam(RichMesh( "ProxyMesh", target, &md, "Proxy Mesh", + "The mesh that will be projected/resampled onto the MLS surface.")); + } + if ((id & _PROJECTION_) || (id & _COLORIZE_)) + { + parlst.addParam(RichBool( "SelectionOnly", + target->cm.sfn>0, + "Selection only", + "If checked, only selected vertices will be projected.")); + } - if ( (id & _APSS_) || (id & _RIMLS_) ) - { - parlst.addParam(RichFloat("FilterScale", - 2.0, - "MLS - Filter scale", - "Scale of the spatial low pass filter.\n" + if ( (id & _APSS_) || (id & _RIMLS_) ) + { + parlst.addParam(RichFloat("FilterScale", + 2.0, + "MLS - Filter scale", + "Scale of the spatial low pass filter.\n" "It is relative to the radius (local point spacing) of the vertices.")); - parlst.addParam(RichFloat("ProjectionAccuracy", - 1e-4f, - "Projection - Accuracy (adv)", - "Threshold value used to stop the projections.\n" + parlst.addParam(RichFloat("ProjectionAccuracy", + 1e-4f, + "Projection - Accuracy (adv)", + "Threshold value used to stop the projections.\n" "This value is scaled by the mean point spacing to get the actual threshold.")); - parlst.addParam(RichInt( "MaxProjectionIters", - 15, - "Projection - Max iterations (adv)", - "Max number of iterations for the projection.")); - } + parlst.addParam(RichInt( "MaxProjectionIters", + 15, + "Projection - Max iterations (adv)", + "Max number of iterations for the projection.")); + } - if (id & _APSS_) - { - parlst.addParam(RichFloat("SphericalParameter", - 1, - "MLS - Spherical parameter", - "Control the curvature of the fitted spheres: 0 is equivalent to a pure plane fit," + if (id & _APSS_) + { + parlst.addParam(RichFloat("SphericalParameter", + 1, + "MLS - Spherical parameter", + "Control the curvature of the fitted spheres: 0 is equivalent to a pure plane fit," "1 to a pure spherical fit, values between 0 and 1 gives intermediate results," "while other real values might give interesting results, but take care with extreme" "settings !")); - if (!(id & _COLORIZE_)) - parlst.addParam(RichBool( "AccurateNormal", - true, - "Accurate normals", - "If checked, use the accurate MLS gradient instead of the local approximation" + if (!(id & _COLORIZE_)) + parlst.addParam(RichBool( "AccurateNormal", + true, + "Accurate normals", + "If checked, use the accurate MLS gradient instead of the local approximation" "to compute the normals.")); - } + } - if (id & _RIMLS_) - { - parlst.addParam(RichFloat("SigmaN", - 0.75, - "MLS - Sharpness", - "Width of the filter used by the normal refitting weight." + if (id & _RIMLS_) + { + parlst.addParam(RichFloat("SigmaN", + 0.75, + "MLS - Sharpness", + "Width of the filter used by the normal refitting weight." "This weight function is a Gaussian on the distance between two unit vectors:" "the current gradient and the input normal. Therefore, typical value range between 0.5 (sharp) to 2 (smooth).")); - parlst.addParam(RichInt( "MaxRefittingIters", - 3, - "MLS - Max fitting iterations", - "Max number of fitting iterations. (0 or 1 is equivalent to the standard IMLS)")); - } + parlst.addParam(RichInt( "MaxRefittingIters", + 3, + "MLS - Max fitting iterations", + "Max number of fitting iterations. (0 or 1 is equivalent to the standard IMLS)")); + } - if (id & _PROJECTION_) - { - parlst.addParam(RichInt( "MaxSubdivisions", - 0, - "Refinement - Max subdivisions", - "Max number of subdivisions.")); - parlst.addParam(RichFloat("ThAngleInDegree", - 2, - "Refinement - Crease angle (degree)", - "Threshold angle between two faces controlling the refinement.")); - } + if (id & _PROJECTION_) + { + parlst.addParam(RichInt( "MaxSubdivisions", + 0, + "Refinement - Max subdivisions", + "Max number of subdivisions.")); + parlst.addParam(RichFloat("ThAngleInDegree", + 2, + "Refinement - Crease angle (degree)", + "Threshold angle between two faces controlling the refinement.")); + } - if (id & _AFRONT_) - { - } + if (id & _AFRONT_) + { + } - if ((id & _COLORIZE_)) - { - QStringList lst; - lst << "Mean" << "Gauss" << "K1" << "K2"; - if (id & _APSS_) - lst << "ApproxMean"; + if ((id & _COLORIZE_)) + { + QStringList lst; + lst << "Mean" << "Gauss" << "K1" << "K2"; + if (id & _APSS_) + lst << "ApproxMean"; - parlst.addParam(RichEnum("CurvatureType", CT_MEAN, - lst, - "Curvature type", - QString("The type of the curvature to plot.") - + ((id & _APSS_) ? "
ApproxMean uses the radius of the fitted sphere as an approximation of the mean curvature." : ""))); -// if ((id & _APSS_)) -// parlst.addParam(RichBool( "ApproxCurvature", -// false, -// "Approx mean curvature", -// "If checked, use the radius of the fitted sphere as an approximation of the mean curvature."); - } + parlst.addParam(RichEnum("CurvatureType", CT_MEAN, + lst, + "Curvature type", + QString("The type of the curvature to plot.") + + ((id & _APSS_) ? "
ApproxMean uses the radius of the fitted sphere as an approximation of the mean curvature." : ""))); + // if ((id & _APSS_)) + // parlst.addParam(RichBool( "ApproxCurvature", + // false, + // "Approx mean curvature", + // "If checked, use the radius of the fitted sphere as an approximation of the mean curvature."); + } - if (id & _MCUBE_) - { - parlst.addParam(RichInt( "Resolution", - 200, - "Grid Resolution", - "The resolution of the grid on which we run the marching cubes." + if (id & _MCUBE_) + { + parlst.addParam(RichInt( "Resolution", + 200, + "Grid Resolution", + "The resolution of the grid on which we run the marching cubes." "This marching cube is memory friendly, so you can safely set large values up to 1000 or even more.")); - } + } } - int MlsPlugin::getRequirements(const QAction *) +int MlsPlugin::getRequirements(const QAction *) { - return 0; + return 0; } /** Predicate functor for adaptive refinement according to crease angle. - * - */ + * + */ template struct EdgeAnglePredicate { - Scalar thCosAngle; - bool operator()(vcg::face::Pos ep) const - { - // FIXME why does the following fails: -// vcg::face::Pos op = ep; -// op.FlipF(); -// if (op.f) -// return vcg::Dot(ep.f->cN(), op.f->cN()) < thCosAngle; -// else -// return true; + Scalar thCosAngle; + bool operator()(vcg::face::Pos ep) const + { + // FIXME why does the following fails: + // vcg::face::Pos op = ep; + // op.FlipF(); + // if (op.f) + // return vcg::Dot(ep.f->cN(), op.f->cN()) < thCosAngle; + // else + // return true; - return (ep.F()->cN() * ep.FFlip()->cN()) < thCosAngle; - } + return (ep.F()->cN() * ep.FFlip()->cN()) < thCosAngle; + } }; /** compute the normal of a face as the average of its vertices */ template void UpdateFaceNormalFromVertex(MeshType& m) { - typedef typename MeshType::VertexType VertexType; - typedef typename VertexType::NormalType NormalType; - //typedef typename VertexType::ScalarType ScalarType; - typedef typename MeshType::FaceIterator FaceIterator; + typedef typename MeshType::VertexType VertexType; + typedef typename VertexType::NormalType NormalType; + //typedef typename VertexType::ScalarType ScalarType; + typedef typename MeshType::FaceIterator FaceIterator; - for (FaceIterator f=m.face.begin(); f!=m.face.end(); ++f) - { - NormalType n; - n.SetZero(); - for(int j=0; j<3; ++j) - n += f->V(j)->cN(); - n.Normalize(); - f->N() = n; - } + for (FaceIterator f=m.face.begin(); f!=m.face.end(); ++f) + { + NormalType n; + n.SetZero(); + for(int j=0; j<3; ++j) + n += f->V(j)->cN(); + n.Normalize(); + f->N() = n; + } } -bool MlsPlugin::applyFilter(const QAction* filter, MeshDocument& md, std::map&, unsigned int& /*postConditionMask*/, const RichParameterList& par, vcg::CallBackPos* cb) +std::map MlsPlugin::applyFilter( + const QAction* filter, + const RichParameterList& par, + MeshDocument& md, + unsigned int& /*postConditionMask*/, + vcg::CallBackPos* cb) { - int id = ID(filter); + std::map outValues; + int id = ID(filter); - if (id == FP_RADIUS_FROM_DENSITY) - { - md.mm()->updateDataMask(MeshModel::MM_VERTRADIUS); - APSS mls(md.mm()->cm); - mls.computeVertexRaddi(par.getInt("NbNeighbors")); - return true; - } - if (id == FP_SELECT_SMALL_COMPONENTS) - { - MeshModel* mesh = md.mm(); - mesh->updateDataMask(MeshModel::MM_FACEFACETOPO); - bool nonClosedOnly = par.getBool("NonClosedOnly"); - Scalarm ratio = par.getFloat("NbFaceRatio"); - vcg::tri::SmallComponent::Select(mesh->cm, ratio, nonClosedOnly); - return true; - } + if (id == FP_RADIUS_FROM_DENSITY) + { + md.mm()->updateDataMask(MeshModel::MM_VERTRADIUS); + APSS mls(md.mm()->cm); + mls.computeVertexRaddi(par.getInt("NbNeighbors")); + return outValues; + } + if (id == FP_SELECT_SMALL_COMPONENTS) + { + MeshModel* mesh = md.mm(); + mesh->updateDataMask(MeshModel::MM_FACEFACETOPO); + bool nonClosedOnly = par.getBool("NonClosedOnly"); + Scalarm ratio = par.getFloat("NbFaceRatio"); + vcg::tri::SmallComponent::Select(mesh->cm, ratio, nonClosedOnly); + return outValues; + } - // we are doing some MLS based stuff - { - if(md.mm()->cm.fn > 0) - { // if we start from a mesh, and it has unreferenced vertices - // normals are undefined on that vertices. - int delvert=tri::Clean::RemoveUnreferencedVertex(md.mm()->cm); - if(delvert) log( "Pre-MLS Cleaning: Removed %d unreferenced vertices",delvert); - } - tri::Allocator::CompactVertexVector(md.mm()->cm); + // we are doing some MLS based stuff + { + if(md.mm()->cm.fn > 0) + { // if we start from a mesh, and it has unreferenced vertices + // normals are undefined on that vertices. + int delvert=tri::Clean::RemoveUnreferencedVertex(md.mm()->cm); + if(delvert) log( "Pre-MLS Cleaning: Removed %d unreferenced vertices",delvert); + } + tri::Allocator::CompactVertexVector(md.mm()->cm); - // We require a per vertex radius so as a first thing check it - if(!md.mm()->hasDataMask(MeshModel::MM_VERTRADIUS)) - { - md.mm()->updateDataMask(MeshModel::MM_VERTRADIUS); - APSS mls(md.mm()->cm); - mls.computeVertexRaddi(); - log( "Mesh has no per vertex radius. Computed and added using default neighbourhood"); - } + // We require a per vertex radius so as a first thing check it + if(!md.mm()->hasDataMask(MeshModel::MM_VERTRADIUS)) + { + md.mm()->updateDataMask(MeshModel::MM_VERTRADIUS); + APSS mls(md.mm()->cm); + mls.computeVertexRaddi(); + log( "Mesh has no per vertex radius. Computed and added using default neighbourhood"); + } - MeshModel* pPoints = 0; - if (id & _PROJECTION_) - { - if (par.getMesh("ControlMesh") == par.getMesh("ProxyMesh")) - { - // clone the control mesh - MeshModel* ref = par.getMesh("ControlMesh"); - pPoints = md.addNewMesh("","TempMesh"); - pPoints->updateDataMask(ref); - vcg::tri::Append::Mesh(pPoints->cm, ref->cm); // the last true means "copy all vertices" - vcg::tri::UpdateBounding::Box(pPoints->cm); - pPoints->cm.Tr = ref->cm.Tr; - } - else - pPoints = par.getMesh("ControlMesh"); - } - else // for curvature - pPoints = md.mm(); + MeshModel* pPoints = 0; + if (id & _PROJECTION_) + { + if (par.getMesh("ControlMesh") == par.getMesh("ProxyMesh")) + { + // clone the control mesh + MeshModel* ref = par.getMesh("ControlMesh"); + pPoints = md.addNewMesh("","TempMesh"); + pPoints->updateDataMask(ref); + vcg::tri::Append::Mesh(pPoints->cm, ref->cm); // the last true means "copy all vertices" + vcg::tri::UpdateBounding::Box(pPoints->cm); + pPoints->cm.Tr = ref->cm.Tr; + } + else + pPoints = par.getMesh("ControlMesh"); + } + else // for curvature + pPoints = md.mm(); - // create the MLS surface - cb(1, "Create the MLS data structures..."); - MlsSurface* mls = 0; + // create the MLS surface + cb(1, "Create the MLS data structures..."); + MlsSurface* mls = 0; - RIMLS* rimls = 0; - APSS* apss = 0; + RIMLS* rimls = 0; + APSS* apss = 0; - if (id & _RIMLS_) - mls = rimls = new RIMLS(pPoints->cm); - else if (id & _APSS_) - mls = apss = new APSS(pPoints->cm); - else - { - assert(0); - } + if (id & _RIMLS_) + mls = rimls = new RIMLS(pPoints->cm); + else if (id & _APSS_) + mls = apss = new APSS(pPoints->cm); + else + { + assert(0); + } - mls->setFilterScale(par.getFloat("FilterScale")); - mls->setMaxProjectionIters(par.getInt("MaxProjectionIters")); - mls->setProjectionAccuracy(par.getFloat("ProjectionAccuracy")); + mls->setFilterScale(par.getFloat("FilterScale")); + mls->setMaxProjectionIters(par.getInt("MaxProjectionIters")); + mls->setProjectionAccuracy(par.getFloat("ProjectionAccuracy")); - if (rimls) - { - rimls->setMaxRefittingIters(par.getInt("MaxRefittingIters")); - //mls.setMinRefittingIters(par.getFloat("MinRefittingIters")); - rimls->setSigmaN(par.getFloat("SigmaN")); - } + if (rimls) + { + rimls->setMaxRefittingIters(par.getInt("MaxRefittingIters")); + //mls.setMinRefittingIters(par.getFloat("MinRefittingIters")); + rimls->setSigmaN(par.getFloat("SigmaN")); + } - if (apss) - { - apss->setSphericalParameter(par.getFloat("SphericalParameter")); - if (!(id & _COLORIZE_)) - apss->setGradientHint(par.getBool("AccurateNormal") ? GaelMls::MLS_DERIVATIVE_ACCURATE : GaelMls::MLS_DERIVATIVE_APPROX); - } + if (apss) + { + apss->setSphericalParameter(par.getFloat("SphericalParameter")); + if (!(id & _COLORIZE_)) + apss->setGradientHint(par.getBool("AccurateNormal") ? GaelMls::MLS_DERIVATIVE_ACCURATE : GaelMls::MLS_DERIVATIVE_APPROX); + } - MeshModel * mesh = 0; + MeshModel * mesh = 0; - if (id & _PROJECTION_) - { - mesh = par.getMesh("ProxyMesh"); - bool selectionOnly = par.getBool("SelectionOnly"); + if (id & _PROJECTION_) + { + mesh = par.getMesh("ProxyMesh"); + bool selectionOnly = par.getBool("SelectionOnly"); - if (selectionOnly) - vcg::tri::UpdateSelection::VertexFromFaceStrict(mesh->cm); - EdgeAnglePredicate edgePred; - edgePred.thCosAngle = cos(M_PI * par.getFloat("ThAngleInDegree")/180.); + if (selectionOnly) + vcg::tri::UpdateSelection::VertexFromFaceStrict(mesh->cm); + EdgeAnglePredicate edgePred; + edgePred.thCosAngle = cos(M_PI * par.getFloat("ThAngleInDegree")/180.); - int nbRefinements = par.getInt("MaxSubdivisions"); - for (int k=0; kupdateDataMask(MeshModel::MM_FACEFACETOPO); + int nbRefinements = par.getInt("MaxSubdivisions"); + for (int k=0; kupdateDataMask(MeshModel::MM_FACEFACETOPO); - vcg::tri::UpdateNormal::PerFace(mesh->cm); - vcg::tri::UpdateNormal::NormalizePerFace(mesh->cm); - //vcg::RefineE >(m.cm, vcg::MidPoint(), edgePred, false, cb); - vcg::tri::RefineOddEvenE, tri::EvenPointLoop > - (mesh->cm, tri::OddPointLoop(mesh->cm), tri::EvenPointLoop(), edgePred, selectionOnly, cb); - } - // project all vertices onto the MLS surface - for (unsigned int i = 0; i< mesh->cm.vert.size(); i++) - { - cb(1+98*i/mesh->cm.vert.size(), "MLS projection..."); + vcg::tri::UpdateNormal::PerFace(mesh->cm); + vcg::tri::UpdateNormal::NormalizePerFace(mesh->cm); + //vcg::RefineE >(m.cm, vcg::MidPoint(), edgePred, false, cb); + vcg::tri::RefineOddEvenE, tri::EvenPointLoop > + (mesh->cm, tri::OddPointLoop(mesh->cm), tri::EvenPointLoop(), edgePred, selectionOnly, cb); + } + // project all vertices onto the MLS surface + for (unsigned int i = 0; i< mesh->cm.vert.size(); i++) + { + cb(1+98*i/mesh->cm.vert.size(), "MLS projection..."); - if ( (!selectionOnly) || (mesh->cm.vert[i].IsS()) ) - mesh->cm.vert[i].P() = mls->project(mesh->cm.vert[i].P(), &mesh->cm.vert[i].N()); - } - } + if ( (!selectionOnly) || (mesh->cm.vert[i].IsS()) ) + mesh->cm.vert[i].P() = mls->project(mesh->cm.vert[i].P(), &mesh->cm.vert[i].N()); + } + } - log( "Successfully projected %i vertices", mesh->cm.vn); - } - else if (id & _COLORIZE_) - { - mesh = md.mm(); - mesh->updateDataMask(MeshModel::MM_VERTCOLOR); - mesh->updateDataMask(MeshModel::MM_VERTQUALITY); - mesh->updateDataMask(MeshModel::MM_VERTCURVDIR); + log( "Successfully projected %i vertices", mesh->cm.vn); + } + else if (id & _COLORIZE_) + { + mesh = md.mm(); + mesh->updateDataMask(MeshModel::MM_VERTCOLOR); + mesh->updateDataMask(MeshModel::MM_VERTQUALITY); + mesh->updateDataMask(MeshModel::MM_VERTCURVDIR); - bool selectionOnly = par.getBool("SelectionOnly"); - //bool approx = apss && par.getBool("ApproxCurvature"); - int ct = par.getEnum("CurvatureType"); + bool selectionOnly = par.getBool("SelectionOnly"); + //bool approx = apss && par.getBool("ApproxCurvature"); + int ct = par.getEnum("CurvatureType"); - uint size = mesh->cm.vert.size(); - //std::vector curvatures(size); - Scalarm minc=1e9, maxc=-1e9, minabsc=1e9; - Point3m grad; - Matrix33m hess; + uint size = mesh->cm.vert.size(); + //std::vector curvatures(size); + Scalarm minc=1e9, maxc=-1e9, minabsc=1e9; + Point3m grad; + Matrix33m hess; - // pass 1: computes curvatures and statistics - for (unsigned int i = 0; i< size; i++) - { - cb(1+98*i/pPoints->cm.vert.size(), "MLS colorization..."); + // pass 1: computes curvatures and statistics + for (unsigned int i = 0; i< size; i++) + { + cb(1+98*i/pPoints->cm.vert.size(), "MLS colorization..."); - if ( (!selectionOnly) || (pPoints->cm.vert[i].IsS()) ) - { - Point3m p = mls->project(mesh->cm.vert[i].P()); - Scalarm c = 0; + if ( (!selectionOnly) || (pPoints->cm.vert[i].IsS()) ) + { + Point3m p = mls->project(mesh->cm.vert[i].P()); + Scalarm c = 0; - if (ct==CT_APSS) - c = apss->approxMeanCurvature(p); - else - { - int errorMask; - grad = mls->gradient(p, &errorMask); - if (errorMask == MLS_OK && grad.Norm() > 1e-8) - { - hess = mls->hessian(p); - implicits::WeingartenMap W(grad,hess); + if (ct==CT_APSS) + c = apss->approxMeanCurvature(p); + else + { + int errorMask; + grad = mls->gradient(p, &errorMask); + if (errorMask == MLS_OK && grad.Norm() > 1e-8) + { + hess = mls->hessian(p); + implicits::WeingartenMap W(grad,hess); - mesh->cm.vert[i].PD1() = W.K1Dir(); - mesh->cm.vert[i].PD2() = W.K2Dir(); - mesh->cm.vert[i].K1() = W.K1(); - mesh->cm.vert[i].K2() = W.K2(); + mesh->cm.vert[i].PD1() = W.K1Dir(); + mesh->cm.vert[i].PD2() = W.K2Dir(); + mesh->cm.vert[i].K1() = W.K1(); + mesh->cm.vert[i].K2() = W.K2(); - switch(ct) - { - case CT_MEAN: c = W.MeanCurvature(); break; - case CT_GAUSS: c = W.GaussCurvature(); break; - case CT_K1: c = W.K1(); break; - case CT_K2: c = W.K2(); break; - default: assert(0 && "invalid curvature type"); - } - } - assert(!math::IsNAN(c) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); - } - mesh->cm.vert[i].Q() = c; - minc = std::min(c,minc); - maxc = std::max(c,maxc); - minabsc = std::min(std::abs(c),minabsc); - } - } - // pass 2: convert the curvature to color - cb(99, "Curvature to color..."); - Scalarm d = maxc-minc; - minc += 0.05*d; - maxc -= 0.05*d; + switch(ct) + { + case CT_MEAN: c = W.MeanCurvature(); break; + case CT_GAUSS: c = W.GaussCurvature(); break; + case CT_K1: c = W.K1(); break; + case CT_K2: c = W.K2(); break; + default: assert(0 && "invalid curvature type"); + } + } + assert(!math::IsNAN(c) && "You should never try to compute Histogram with Invalid Floating points numbers (NaN)"); + } + mesh->cm.vert[i].Q() = c; + minc = std::min(c,minc); + maxc = std::max(c,maxc); + minabsc = std::min(std::abs(c),minabsc); + } + } + // pass 2: convert the curvature to color + cb(99, "Curvature to color..."); + Scalarm d = maxc-minc; + minc += 0.05*d; + maxc -= 0.05*d; - Histogramm H; - vcg::tri::Stat::ComputePerVertexQualityHistogram(mesh->cm,H); - vcg::tri::UpdateColor::PerVertexQualityRamp(mesh->cm,H.Percentile(0.01f),H.Percentile(0.99f)); - } - // else if (id & _AFRONT_) - // { - // // create a new mesh - // mesh = md.addNewMesh("afront mesh"); - // vcg::tri::AdvancingMLS afront(mesh->cm, *mls); - // //afront.BuildMesh(cb); - // afront._SeedFace(); - // for (int i=0; i<20120; ++i) - // afront.AddFace(); - // Log(0, "Advancing front MLS meshing done."); - // } - else if (id & _MCUBE_) - { - // create a new mesh - mesh = md.addNewMesh("","mc_mesh"); + Histogramm H; + vcg::tri::Stat::ComputePerVertexQualityHistogram(mesh->cm,H); + vcg::tri::UpdateColor::PerVertexQualityRamp(mesh->cm,H.Percentile(0.01f),H.Percentile(0.99f)); + } + // else if (id & _AFRONT_) + // { + // // create a new mesh + // mesh = md.addNewMesh("afront mesh"); + // vcg::tri::AdvancingMLS afront(mesh->cm, *mls); + // //afront.BuildMesh(cb); + // afront._SeedFace(); + // for (int i=0; i<20120; ++i) + // afront.AddFace(); + // Log(0, "Advancing front MLS meshing done."); + // } + else if (id & _MCUBE_) + { + // create a new mesh + mesh = md.addNewMesh("","mc_mesh"); - typedef vcg::tri::MlsWalker > MlsWalker; - typedef vcg::tri::MarchingCubes MlsMarchingCubes; - MlsWalker walker; - walker.resolution = par.getInt("Resolution"); + typedef vcg::tri::MlsWalker > MlsWalker; + typedef vcg::tri::MarchingCubes MlsMarchingCubes; + MlsWalker walker; + walker.resolution = par.getInt("Resolution"); - // iso extraction - MlsMarchingCubes mc(mesh->cm, walker); - walker.BuildMesh(mesh->cm, *mls, mc, cb); + // iso extraction + MlsMarchingCubes mc(mesh->cm, walker); + walker.BuildMesh(mesh->cm, *mls, mc, cb); - // accurate projection - for (unsigned int i = 0; i< mesh->cm.vert.size(); i++) - { - cb(1+98*i/mesh->cm.vert.size(), "MLS projection..."); - mesh->cm.vert[i].P() = mls->project(mesh->cm.vert[i].P(), &mesh->cm.vert[i].N()); - } + // accurate projection + for (unsigned int i = 0; i< mesh->cm.vert.size(); i++) + { + cb(1+98*i/mesh->cm.vert.size(), "MLS projection..."); + mesh->cm.vert[i].P() = mls->project(mesh->cm.vert[i].P(), &mesh->cm.vert[i].N()); + } - // extra zero detection and removal - { - mesh->updateDataMask(MeshModel::MM_FACEFACETOPO ); - // selection... - vcg::tri::SmallComponent::Select(mesh->cm, 0.1f); - // deletion... - vcg::tri::SmallComponent::DeleteFaceVert(mesh->cm); - mesh->clearDataMask(MeshModel::MM_FACEFACETOPO); - } + // extra zero detection and removal + { + mesh->updateDataMask(MeshModel::MM_FACEFACETOPO ); + // selection... + vcg::tri::SmallComponent::Select(mesh->cm, 0.1f); + // deletion... + vcg::tri::SmallComponent::DeleteFaceVert(mesh->cm); + mesh->clearDataMask(MeshModel::MM_FACEFACETOPO); + } - log( "Marching cubes MLS meshing done."); - } + log( "Marching cubes MLS meshing done."); + } - delete mls; - if ( (id & _PROJECTION_) && par.getMesh("ControlMesh")!=pPoints) - { - md.delMesh(pPoints); - } + delete mls; + if ( (id & _PROJECTION_) && par.getMesh("ControlMesh")!=pPoints) + { + md.delMesh(pPoints); + } - if (mesh) - mesh->UpdateBoxAndNormals(); + if (mesh) + mesh->UpdateBoxAndNormals(); - } // end MLS based stuff + } // end MLS based stuff - return true; + return outValues; } MESHLAB_PLUGIN_NAME_EXPORTER(MlsPlugin) diff --git a/src/meshlabplugins/filter_mls/mlsplugin.h b/src/meshlabplugins/filter_mls/mlsplugin.h index 2f8086792..ec90a239b 100644 --- a/src/meshlabplugins/filter_mls/mlsplugin.h +++ b/src/meshlabplugins/filter_mls/mlsplugin.h @@ -67,8 +67,13 @@ public: virtual QString filterInfo(ActionIDType filter) const; FilterClass getClass(const QAction *a) const; virtual void initParameterList(const QAction*, MeshDocument &md, RichParameterList &parent); - virtual int getRequirements(const QAction* action); - virtual bool applyFilter(const QAction* filter, MeshDocument &m, std::map& outputValues, unsigned int& postConditionMask, const RichParameterList &parent, vcg::CallBackPos *cb) ; + virtual int getRequirements(const QAction* action); + std::map applyFilter( + const QAction* action, + const RichParameterList & parameters, + MeshDocument &md, + unsigned int& postConditionMask, + vcg::CallBackPos * cb); FILTER_ARITY filterArity(const QAction *) const {return SINGLE_MESH;} };