From f1d2fca0f3afc613a59654884cfda97201141fd2 Mon Sep 17 00:00:00 2001 From: Luigi Malomo malomo Date: Fri, 21 Feb 2014 14:46:46 +0000 Subject: [PATCH] refactored the code to use the vcg function. --- .../filter_harmonic/filter_harmonic.cpp | 184 ++---------------- .../filter_harmonic/filter_harmonic.h | 4 +- 2 files changed, 19 insertions(+), 169 deletions(-) diff --git a/src/plugins_experimental/filter_harmonic/filter_harmonic.cpp b/src/plugins_experimental/filter_harmonic/filter_harmonic.cpp index c16932a2a..845fa6561 100644 --- a/src/plugins_experimental/filter_harmonic/filter_harmonic.cpp +++ b/src/plugins_experimental/filter_harmonic/filter_harmonic.cpp @@ -23,9 +23,7 @@ #include "filter_harmonic.h" #include #include -#include - -#include +#include // Constructor usually performs only two simple tasks of filling the two lists // - typeList: with all the possible id of the filtering actions @@ -98,60 +96,6 @@ void FilterHarmonicPlugin::initParameterSet(QAction * action, MeshModel & m, Ric } } -enum WeightInfo -{ - Success = 0, - EdgeAlreadyVisited -}; - -// Function to compute the cotangent weighting function for an edge -// return Success if everything is fine; -// EdgeAlreadyVisited if the weight for the considered edge have been already computed and assigned; -template -WeightInfo ComputeWeight(const FaceType &f, int edge, ScalarType & weight) -{ - typedef typename FaceType::VertexType VertexType; - - assert(edge >= 0 && edge < 3); - - // get the adjacent face - const FaceType * fp = f.cFFp(edge); - - ScalarType cotA = 0; - ScalarType cotB = 0; - - // Get the edge (a pair of vertices) - VertexType * v0 = f.cV0(edge); - VertexType * v1 = f.cV1(edge); - - if (fp != NULL && - fp != &f) - { - // not a border edge - if (fp->IsV()) return EdgeAlreadyVisited; - - VertexType * vb = fp->cV2(f.cFFi(edge)); - ScalarType angleB = ComputeAngle(v0, vb, v1); - cotB = vcg::math::Cos(angleB) / vcg::math::Sin(angleB); - } - - VertexType * va = f.cV2(edge); - ScalarType angleA = ComputeAngle(v0, va, v1); - cotA = vcg::math::Cos(angleA) / vcg::math::Sin(angleA); - - weight = (cotA + cotB) / 2; - - return Success; -} - -template -ScalarType ComputeAngle(const VertexType * a, const VertexType * b, const VertexType * c) -{ - assert(a != NULL && b != NULL && c != NULL); - ScalarType angle = vcg::Angle(a->P() - b->P(), c->P() - b->P()); - return angle; -} - // The Real Core Function doing the actual mesh processing. bool FilterHarmonicPlugin::applyFilter(QAction * action, MeshDocument & md, RichParameterSet & par, vcg::CallBackPos * cb) { @@ -161,89 +105,25 @@ bool FilterHarmonicPlugin::applyFilter(QAction * action, MeshDocument & md, Rich { typedef vcg::GridStaticPtr VertexGrid; - typedef double CoeffScalar; // TODO, when moving the code to a class make it a template (CoeffScalar = double) + typedef double FieldScalar; + // double is fine typedef CMeshO::ScalarType ScalarType; typedef CMeshO::CoordType CoordType; typedef CMeshO::VertexType VertexType; typedef CMeshO::FaceType FaceType; - typedef Eigen::Triplet T; - typedef Eigen::SparseMatrix SpMat; //sparse matrix type of double - + cb(1, "Computing harmonic field..."); CMeshO & m = md.mm()->cm; vcg::tri::Allocator::CompactFaceVector(m); vcg::tri::Allocator::CompactVertexVector(m); - md.mm()->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK); + md.mm()->updateDataMask(MeshModel::MM_VERTMARK | MeshModel::MM_FACEFLAG); vcg::tri::UpdateBounding::Box(m); - vcg::tri::UpdateTopology::FaceFace(m); int n = m.VN(); - int fn = m.FN(); - - std::vector coeffs; // coefficients of the system - std::map sums; // row sum of the coefficient - - SpMat laplaceMat; // the system to be solved - laplaceMat.resize(n, n); - - cb(0, "Generating coefficients..."); - vcg::tri::UpdateFlags::FaceClearV(m); - // Iterate over the faces - for (size_t i = 0; i < m.face.size(); ++i) - { - CMeshO::FaceType & f = m.face[i]; - - if (f.IsD()) - { - assert(int(i) == fn); - break; // TODO FIX the indexing of vertices - } - - assert(!f.IsV()); - f.SetV(); - - // Generate coefficients for each edge - for (int idx = 0; idx < 3; ++idx) - { - CoeffScalar weight; - WeightInfo res = ComputeWeight(f, idx, weight); - - switch (res) - { - case EdgeAlreadyVisited : continue; - case Success : break; - default: assert(0); - } - -// if (weight < 0) weight = 0; // TODO check if negative weight may be an issue - - // Add the weight to the coefficients vector for both the vertices of the considered edge - size_t v0_idx = vcg::tri::Index(m, f.V0(idx)); - size_t v1_idx = vcg::tri::Index(m, f.V1(idx)); - - coeffs.push_back(T(v0_idx, v1_idx, -weight)); - coeffs.push_back(T(v1_idx, v0_idx, -weight)); - - // Add the weight to the row sum - sums[v0_idx] += weight; - sums[v1_idx] += weight; - } - - f.SetV(); - } - - // Fill the system matrix - cb(10, "Filling the system matrix..."); - laplaceMat.reserve(coeffs.size()); - for (std::map::const_iterator it = sums.begin(); it != sums.end(); ++it) - { - coeffs.push_back(T(it->first, it->first, it->second)); - } - laplaceMat.setFromTriplets(coeffs.begin(), coeffs.end()); // Get the two vertices with value set VertexGrid vg; @@ -263,57 +143,31 @@ bool FilterHarmonicPlugin::applyFilter(QAction * action, MeshDocument & md, Rich return false; } - size_t v0_idx = vcg::tri::Index(m, vp0); - size_t v1_idx = vcg::tri::Index(m, vp1); + vcg::tri::Harmonic::ConstraintVec constraints; + constraints.push_back(vcg::tri::Harmonic::Constraint(vp0, FieldScalar(par.getFloat("value1")))); + constraints.push_back(vcg::tri::Harmonic::Constraint(vp1, FieldScalar(par.getFloat("value2")))); - // Add penalty factor alpha - const CoeffScalar alpha = pow(10, 8); + CMeshO::PerVertexAttributeHandle handle = vcg::tri::Allocator::GetPerVertexAttribute(m, "harmonic"); - Eigen::Matrix b, x; // Unknown and known terms vectors - b.setZero(n); - b(v0_idx) = alpha * par.getFloat("value1"); - b(v1_idx) = alpha * par.getFloat("value2"); + bool ok = vcg::tri::Harmonic::ComputeScalarField(m, constraints, handle); - laplaceMat.coeffRef(v0_idx, v0_idx) += alpha; - laplaceMat.coeffRef(v1_idx, v1_idx) += alpha; - - // Solve system laplacianMat x = b - cb(20, "System matrix decomposition..."); - Eigen::SimplicialLDLT > solver; // TODO eventually use another solver - solver.compute(laplaceMat); - if(solver.info() != Eigen::Success) + if (!ok) { - // decomposition failed - this->errorMessage = "System matrix decomposition failed: "; - if (solver.info() == Eigen::NumericalIssue) - this->errorMessage += "numerical issue."; - else if (solver.info() == Eigen::NoConvergence) - this->errorMessage += "no convergence."; - else if (solver.info() == Eigen::InvalidInput) - this->errorMessage += "invalid input."; - - return false; - } - - cb(85, "Solving the system..."); - x = solver.solve(b); - if(solver.info() != Eigen::Success) - { - // solving failed - this->errorMessage = "System solving failed."; + this->errorMessage += "An error occurred."; return false; } // Colorize bands for the 0-1 interval if (par.getBool("colorize")) { + md.mm()->updateDataMask(MeshModel::MM_VERTCOLOR); float steps = 20.0f; for (size_t i = 0; int(i) < n; ++i) { - bool on = (int)(x[i]*steps)%2 == 1; + bool on = (int)(handle[i]*steps)%2 == 1; if (on) { - m.vert[i].C() = vcg::Color4b::ColorRamp(0,2,x[i]); + m.vert[i].C() = vcg::Color4b::ColorRamp(0,2,handle[i]); } else { @@ -322,12 +176,6 @@ bool FilterHarmonicPlugin::applyFilter(QAction * action, MeshDocument & md, Rich } } - // Set field value into vertex quality attribute - for (size_t i = 0; int(i) < n; ++i) - { - m.vert[i].Q() = x[i]; - } - cb(100, "Done."); return true; @@ -347,4 +195,4 @@ QString FilterHarmonicPlugin::filterScriptFunctionName( FilterIDType filterID ) return QString(); } -Q_EXPORT_PLUGIN(FilterHarmonicPlugin) +MESHLAB_PLUGIN_NAME_EXPORTER(FilterHarmonicPlugin) diff --git a/src/plugins_experimental/filter_harmonic/filter_harmonic.h b/src/plugins_experimental/filter_harmonic/filter_harmonic.h index cc86e3e25..760a79423 100644 --- a/src/plugins_experimental/filter_harmonic/filter_harmonic.h +++ b/src/plugins_experimental/filter_harmonic/filter_harmonic.h @@ -31,6 +31,7 @@ class QScriptEngine; class FilterHarmonicPlugin : public QObject, public MeshFilterInterface { Q_OBJECT + MESHLAB_PLUGIN_IID_EXPORTER(MESH_FILTER_INTERFACE_IID) Q_INTERFACES(MeshFilterInterface) public: @@ -41,7 +42,8 @@ public: FilterHarmonicPlugin(); virtual QString pluginName(void) const { return "FilterHarmonicPlugin"; } - int getPreConditions(QAction *) const { return MeshModel::MM_VERTFACETOPO | MeshModel::MM_FACEFACETOPO; } + int getPreConditions(QAction *) const { return MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACENUMBER; } + int getRequirements(QAction *) { return MeshModel::MM_FACEFACETOPO; } QString filterName(FilterIDType filter) const; QString filterInfo(FilterIDType filter) const; void initParameterSet(QAction *, MeshModel & /*m*/, RichParameterSet & /*parent*/);