From c718bce40220f3073d185a28b5360efeb4b93e89 Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Wed, 17 Jul 2013 22:43:43 +0000 Subject: [PATCH] Various changes and refactoring during the exam code review --- .../filter_decompose/filter_decomposer.cpp | 75 ++++++++------- src/fgt/filter_decompose/graph_builder.h | 92 ++++++++++++------- 2 files changed, 98 insertions(+), 69 deletions(-) diff --git a/src/fgt/filter_decompose/filter_decomposer.cpp b/src/fgt/filter_decompose/filter_decomposer.cpp index c337249ae..d92f9adc7 100644 --- a/src/fgt/filter_decompose/filter_decomposer.cpp +++ b/src/fgt/filter_decompose/filter_decomposer.cpp @@ -8,7 +8,7 @@ * \ * * All rights reserved. * * * -* This program is free software; you can redistribute it and/or modify * +* 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. * @@ -36,20 +36,23 @@ struct CutUsedTypes : public vcg::UsedTypes< vcg::Use ::AsVertexTyp class CutVertex : public vcg::Vertex{}; class CutFace : public vcg::Face {}; -class CutEdge : public vcg::Edge{}; +class CutEdge : public vcg::Edge{}; class CutMesh : public vcg::tri::TriMesh< std::vector, std::vector , std::vector > {}; typedef vcg::GridStaticPtr TriMeshGrid; - -class WeightFunctor : FunctorType +template +class WeightFunctor { + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::FacePointer FacePointer; + private: float _ambient_weight, _dihedral_weight, _elength_weight, _geodesic_weight, _max1, _max2, _maxq, _geomin, _geomax; - CutFace::FacePointer _start,_end; - typename CutMesh:: template PerFaceAttributeHandle _gfH1, _gfH2; + FacePointer _start,_end; + typename MeshType:: template PerFaceAttributeHandle _gfH1, _gfH2; double _totmax; public: - WeightFunctor(float aow, float dw, float geodesic, float elength, CutFace::FacePointer start, CutFace::FacePointer end, typename CutMesh:: template PerFaceAttributeHandle gfH1, typename CutMesh:: template PerFaceAttributeHandle gfH2, float max1, float max2, float geomin, float geomax, float maxq) + WeightFunctor(float aow, float dw, float geodesic, float elength, FacePointer start, FacePointer end, typename MeshType:: template PerFaceAttributeHandle gfH1, typename MeshType:: template PerFaceAttributeHandle gfH2, float max1, float max2, float geomin, float geomax, float maxq) { if(max1<0 || max2<0 || maxq<0 || elength<0 || start==NULL || end==NULL ||aow<0 || dw<0 || geodesic <0 || geomin<0 || geomax<0) @@ -69,6 +72,13 @@ public: _ambient_weight = aow; _dihedral_weight = dw; _geodesic_weight = geodesic; + qDebug("_max1 %f _max2 %f",_max1,_max2); + qDebug("_geomin %f _geomax %f",_geomin,_geomax); + qDebug("_totmax %f",_totmax); + qDebug("_elength_weight %f",_elength_weight); + qDebug("_ambient_weight %f",_ambient_weight); + qDebug("_dihedral_weight %f",_dihedral_weight); + qDebug("_geodesic_weight %f",_geodesic_weight); } /* Computes the weight W of the edge f1->f2 using the float parameters as coefficients for the expression: @@ -94,8 +104,8 @@ public: //sub-weights are normalized using previously computed max values return ((_elength_weight * vcg::Norm(pos.V()->P() - pos.VFlip()->P())) + (_geodesic_weight * GeodesicDistance(pos)) - + (_ambient_weight * (pos.f->Q()/_maxq)) - + (_dihedral_weight * ((M_PI + vcg::face::DihedralAngleRad(*(pos.f), pos.E()))/2*M_PI))); + + (_ambient_weight * (pos.f->Q() + pos.FFlip()->Q())/(2.0f*_maxq)) + + (_dihedral_weight * ( (M_PI + vcg::face::DihedralAngleRad(*(pos.f), pos.E())) / (2*M_PI))) ); } double GeodesicDistance(const vcg::face::Pos pos) @@ -104,27 +114,30 @@ public: //the value _totmax is returned, which makes sure the final weight will be high //and the edge won't be considered for a minimumcut. //this is useful to avoid trivial cuts. - if(_gfH1[pos.f] <= _max1*_geomin || _gfH1[pos.f] >= _max1*_geomax) - return _totmax; - if(_gfH2[pos.f] <= _max2*_geomin || _gfH2[pos.f] >= _max2*_geomax) - return _totmax; - return (std::pow(_gfH1[pos.f], 1.2f) + std::pow(_gfH2[pos.f], 1.2f))/_totmax; + float dist = (_gfH1[pos.f] + _gfH1[pos.FFlip()])/2.0f; + assert(dist<=_max1); + if(dist <= _gfH1[_end]*_geomin || dist >= _gfH1[_end]*_geomax) + return std::numeric_limits::max(); +// if(_gfH2[pos.f] <= _max2*_geomin || _gfH2[pos.f] >= _max2*_geomax) +// return _totmax; +// return (std::pow(_gfH1[pos.f], 1.2f) + std::pow(_gfH2[pos.f], 1.2f))/_totmax; + return dist/_max1; } }; -// Constructor usually performs only two simple tasks of filling the two lists +// 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 -ExtraSamplePlugin::ExtraSamplePlugin() -{ +ExtraSamplePlugin::ExtraSamplePlugin() +{ typeList << FP_DECOMPOSER; foreach(FilterIDType tt , types()) actionList << new QAction(filterName(tt), this); } -// ST() must return the very short string describing each filtering action +// ST() must return the very short string describing each filtering action // (this string is used also to define the menu entry) QString ExtraSamplePlugin::filterName(FilterIDType filterId) const { @@ -135,7 +148,7 @@ QString ExtraSamplePlugin::filterName(FilterIDType filterId) const return QString(); } -// Info() must return the longer string describing each filtering action +// Info() must return the longer string describing each filtering action // (this string is used in the About plugin dialog) QString ExtraSamplePlugin::filterInfo(FilterIDType filterId) const { @@ -147,8 +160,8 @@ QString ExtraSamplePlugin::filterInfo(FilterIDType filterId) const } -// The FilterClass describes in which generic class of filters it fits. -// This choice affect the submenu in which each filter will be placed +// The FilterClass describes in which generic class of filters it fits. +// This choice affect the submenu in which each filter will be placed // More than a single class can be choosen. ExtraSamplePlugin::FilterClass ExtraSamplePlugin::getClass(QAction *a) { @@ -162,14 +175,14 @@ ExtraSamplePlugin::FilterClass ExtraSamplePlugin::getClass(QAction *a) // 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 string shown in the dialog +// For each parameter you need to define, +// - the name of the parameter, +// - the string shown in the dialog // - the default value // - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) //farsi passare due Point3f sulla mesh dai quali risalire alle facce sorgente/pozzo -void ExtraSamplePlugin::initParameterSet(QAction *action,MeshModel &m, RichParameterSet & parlst) +void ExtraSamplePlugin::initParameterSet(QAction *action,MeshModel &m, RichParameterSet & parlst) { switch(ID(action)) { case FP_DECOMPOSER : @@ -197,15 +210,9 @@ bool ExtraSamplePlugin::applyFilter(QAction *action, MeshDocument &md, RichParam CMeshO &m = md.mm()->cm; CutMesh cm; vcg::tri::Append::MeshCopy(cm,m); - vcg::tri::RequireFFAdjacency(cm); - vcg::tri::RequireVFAdjacency(cm); - vcg::tri::RequirePerFaceQuality(cm); - vcg::tri::RequirePerFaceNormal(cm); - vcg::tri::Allocator::CompactFaceVector(cm); - vcg::tri::Allocator::CompactVertexVector(cm); + vcg::tri::Allocator::CompactEveryVector(cm); vcg::tri::UpdateTopology::FaceFace(cm); vcg::tri::UpdateTopology::VertexFace(cm); - vcg::tri::UpdateTopology::AllocateEdge(cm); vcg::tri::UpdateNormal::PerFace(cm); //Get Parameters @@ -269,9 +276,9 @@ bool ExtraSamplePlugin::applyFilter(QAction *action, MeshDocument &md, RichParam max2=gfH2[fit]; } //this functor will be used to compute edge weights on the dual graph - WeightFunctor wf(ambient, dihedral, geodesic, elength, startFace, endFace, gfH1, gfH2, max1, max2, geomin, geomax, maxq); + WeightFunctor wf(ambient, dihedral, geodesic, elength, startFace, endFace, gfH1, gfH2, max1, max2, geomin, geomax, maxq); //start actual computation - vcg::tri::GraphBuilder::Compute(cm, wf, startFace, endFace); + vcg::tri::GraphBuilder >::Compute(cm, wf, startFace, endFace); vcg::tri::Allocator::DeletePerFaceAttribute(cm,gfH1); vcg::tri::Allocator::DeletePerFaceAttribute(cm,gfH2); vcg::tri::Append::MeshCopy(m,cm); diff --git a/src/fgt/filter_decompose/graph_builder.h b/src/fgt/filter_decompose/graph_builder.h index 112662421..44443df3b 100644 --- a/src/fgt/filter_decompose/graph_builder.h +++ b/src/fgt/filter_decompose/graph_builder.h @@ -30,8 +30,9 @@ public: { assert(startFace!=NULL && endFace!=NULL && !startFace->IsD() && !endFace->IsD()); Graph *g = GraphBuilder::BuildGraph(m, wf, startFace, endFace); - g->maxflow(); - GraphBuilder::ColorFaces(m, *g); + double flowVal = g->maxflow(); + qDebug("Flow %f",flowVal); + GraphBuilder::ColorFaces(m, *g, startFace, endFace); assert(vcg::tri::HasPerFaceAttribute(m,"NodeID")); vcg::tri::Allocator::DeletePerFaceAttribute(m,"NodeID"); delete g; @@ -44,7 +45,8 @@ public: */ static Graph * BuildGraph(MeshType &m, FunctorType &wf, FacePointer startFace, FacePointer endFace) { - vcg::tri::UpdateFlags::Clear(m); + vcg::tri::UpdateFlags::FaceClearV(m); + tri::Allocator::CompactEveryVector(m); Graph *g = new Graph(); std::vector faceVec; @@ -71,38 +73,57 @@ public: faceVec.push_back(startFace); startFace->SetV(); - FacePointer curFace; - // continue adding nodes to the graph - while(!faceVec.empty()){ - curFace = faceVec.back(); - faceVec.pop_back(); - if(!curFace->IsD()){ - curFace->SetV(); - for (int i=0; i<3; i++) - { - if(curFace->FFp(i)!=curFace && !curFace->FFp(i)->IsD()) - { - if(!curFace->FFp(i)->IsV()) - faceVec.push_back(curFace->FFp(i)); - - //if the attribute is still NULL then i haven't considered the face yet - //so i can add a node for it and add it to the vector - if(nfH[curFace->FFp(i)] == NULL) - nfH[curFace->FFp(i)] = g->add_node(); - - // add edges (in the dual graph) between adjacent faces - // an edge is added in both directions with "cap" and "rev_cap"=0 flow capacities - // the reverse edge will be added when curFace->FFp(i) will be popped from the stack - PosType pf(curFace, i); - //using the functor operator () to compute edge capability - double cap = wf(pf); - assert(cap>=0); - g->add_edge(nfH[curFace], nfH[curFace->FFp(i)], cap, 0); - } - } - } + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) + { + if(nfH[fi] == NULL) + nfH[fi] = g->add_node(); } + for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) + { + for (int i=0; i<3; i++) + { + if(!face::IsBorder(*fi,i)) + { + PosType pf(&*fi, i); + //using the functor operator () to compute edge capability + double cap = wf(pf); + assert(cap>=0); + g->add_edge(nfH[fi], nfH[fi->FFp(i)], cap, 0); + } + } + } + + // continue adding nodes to the graph +// while(!faceVec.empty()){ +// FacePointer curFace = faceVec.back(); +// faceVec.pop_back(); + +// curFace->SetV(); +// for (int i=0; i<3; i++) +// { +// if(!face::IsBorder(*curFace,i)) +// { +// if(!curFace->FFp(i)->IsV()) +// faceVec.push_back(curFace->FFp(i)); + +// //if the attribute is still NULL then i haven't considered the face yet +// //so i can add a node for it and add it to the vector +// if(nfH[curFace->FFp(i)] == NULL) +// nfH[curFace->FFp(i)] = g->add_node(); + +// // add edges (in the dual graph) between adjacent faces +// // an edge is added in both directions with "cap" and "rev_cap"=0 flow capacities +// // the reverse edge will be added when curFace->FFp(i) will be popped from the stack +// PosType pf(curFace, i); +// //using the functor operator () to compute edge capability +// double cap = wf(pf); +// assert(cap>=0); +// g->add_edge(nfH[curFace], nfH[curFace->FFp(i)], cap, 0); +// } +// } +// } + return g; } @@ -110,7 +131,7 @@ public: Red-coloring Source faces and Green-coloring Sink faces */ - static void ColorFaces(MeshType &m, Graph &g){ + static void ColorFaces(MeshType &m, Graph &g, FacePointer startFace, FacePointer endFace){ assert(vcg::tri::HasPerFaceAttribute(m,"NodeID")); @@ -127,8 +148,9 @@ public: } else if(g.what_segment(nfH[fit]) == Graph::SINK) fit->C()=Color4b::Green; - } + if(&*fit == startFace) fit->C()= Color4b::White; + if(&*fit == endFace) fit->C()= Color4b::Black; } } };