From 27a0566feb2c80639f9ccb2cec769e04a2536cd0 Mon Sep 17 00:00:00 2001 From: Kenneth Vanhoey Date: Fri, 14 Sep 2012 17:30:34 +0200 Subject: [PATCH] Add decimation with color attributes ('Naive' version works, rest is todo) --- include/Algo/Decimation/approximator.h | 18 +- .../Decimation/colorPerVertexApproximator.h | 75 +++--- .../Decimation/colorPerVertexApproximator.hpp | 125 ++++++++- include/Algo/Decimation/decimation.h | 2 +- include/Algo/Decimation/decimation.hpp | 61 ++++- include/Algo/Decimation/edgeSelector.h | 72 ++++- include/Algo/Decimation/edgeSelector.hpp | 249 +++++++++++++++++- .../Algo/Decimation/geometryApproximator.h | 2 +- .../Algo/Decimation/geometryApproximator.hpp | 17 +- include/Algo/Decimation/halfEdgeSelector.h | 36 ++- include/Algo/Decimation/halfEdgeSelector.hpp | 73 ++--- .../Algo/Decimation/lightfieldApproximator.h | 119 +++++++++ .../Decimation/lightfieldApproximator.hpp | 50 ++++ include/Algo/Decimation/selector.h | 8 +- include/Algo/ProgressiveMesh/pmesh.hpp | 4 +- include/Utils/qem.h | 154 +++++++++++ 16 files changed, 932 insertions(+), 133 deletions(-) create mode 100644 include/Algo/Decimation/lightfieldApproximator.h create mode 100644 include/Algo/Decimation/lightfieldApproximator.hpp diff --git a/include/Algo/Decimation/approximator.h b/include/Algo/Decimation/approximator.h index 22f809f95..48026ad5d 100644 --- a/include/Algo/Decimation/approximator.h +++ b/include/Algo/Decimation/approximator.h @@ -39,14 +39,16 @@ namespace Decimation enum ApproximatorType { A_QEM, - A_hQEM, A_MidEdge, - A_HalfCollapse, A_CornerCutting, A_TangentPredict1, A_TangentPredict2, - A_hColor - /*A_LightfieldHalf, + A_ColorNaive, + A_ColorQEMext, + // note: the following "h" prefix means that half-edges are prioritized instead of edges. + A_hHalfCollapse, + A_hQEM, + A_hLightfieldHalf/*, A_LightfieldHalf_deprecated, A_LightfieldFull_deprecated*/ } ; @@ -99,15 +101,17 @@ public: Approximator(MAP& m, std::vector* > va, Predictor * predictor) : ApproximatorGen(m), m_predictor(predictor), m_attrV(va) { + assert(m_attrV.size() > 0 || !"Approximator: no attributes provided") ; + m_approx.resize(m_attrV.size()) ; m_detail.resize(m_attrV.size()) ; m_app.resize(m_attrV.size()) ; - if (m_attrV.size() < 1) - std::cerr << "Approximator: no attributes provided" << std::endl ; - for (unsigned int i = 0 ; i < m_attrV.size() ; ++i) { + if (!m_attrV[i]->isValid()) + std::cerr << "Approximator Warning: attribute number " << i << " is not valid" << std::endl ; + std::stringstream aname ; aname << "approx_" << m_attrV[i]->name() ; m_approx[i] = this->m_map.template addAttribute(aname.str()) ; diff --git a/include/Algo/Decimation/colorPerVertexApproximator.h b/include/Algo/Decimation/colorPerVertexApproximator.h index d1ff74104..6c09d02d5 100644 --- a/include/Algo/Decimation/colorPerVertexApproximator.h +++ b/include/Algo/Decimation/colorPerVertexApproximator.h @@ -22,8 +22,8 @@ * * *******************************************************************************/ -#ifndef __LIGHTFIELD_APPROXIMATOR_H__ -#define __LIGHTFIELD_APPROXIMATOR_H__ +#ifndef __COLOR_APPROXIMATOR_H__ +#define __COLOR_APPROXIMATOR_H__ #include "Algo/Decimation/approximator.h" #include "Topology/generic/mapBrowser.h" @@ -38,7 +38,7 @@ namespace Decimation { template -class Approximator_Color : public Approximator +class Approximator_ColorNaive : public Approximator { public: typedef typename PFP::MAP MAP ; @@ -46,21 +46,29 @@ public: typedef typename PFP::REAL REAL ; protected: + VertexAttribute m_position ; + EdgeAttribute m_approxposition ; VertexAttribute *m_color ; public: - Approximator_Color(MAP& m, std::vector* >& attr, Predictor* pred = NULL) : + Approximator_ColorNaive(MAP& m, std::vector* >& attr, Predictor* pred = NULL) : Approximator(m, attr, pred) { m_color = this->m_attrV[0] ; - assert((m_color->isValid() && m_color->name() == "color") || !"Approximator_Color: the approximated attribute is not valid or not named 'color'") ; + assert(m_color->isValid() || !"Approximator_ColorNaive: the approximated attribute is not valid") ; + + m_position = this->m_map.template getAttribute("position") ; + assert(m_position.isValid() || !"Approximator_ColorNaive: the position attribute is not valid") ; + + m_approxposition = this->m_map.template getAttribute("approx_position") ; + assert(m_approxposition.isValid() || !"Approximator_ColorNaive: the approx_position attribute is not valid") ; } - ~Approximator_Color() + ~Approximator_ColorNaive() {} ApproximatorType getType() const { - return A_hColor ; + return A_ColorNaive ; } bool init() @@ -71,63 +79,42 @@ public: void approximate(Dart d) ; } ; -/* template -class Approximator_FrameHalf : public Approximator +class Approximator_ColorQEMext : public Approximator { public: typedef typename PFP::MAP MAP ; - typedef typename PFP::VEC3 VEC3 ; typedef typename PFP::REAL REAL ; + typedef typename PFP::VEC3 VEC3 ; + typedef Geom::Vector<6,REAL> VEC6 ; + +protected: + VertexAttribute > m_quadric ; + VertexAttribute *m_position ; + VertexAttribute *m_color ; public: - Approximator_FrameHalf(MAP& m, std::vector >& attr, Predictor* pred = NULL) : + Approximator_ColorQEMext(MAP& m, std::vector* >& attr, Predictor* pred = NULL) : Approximator(m, attr, pred) - {} - ~Approximator_FrameHalf() - {} - - ApproximatorType getType() const { - return A_LightfieldHalf ; - } + assert(attr.size() > 1 || !"Approximator_ColorQEMext: there are not sufficient attributes provided") ; - bool init() - { - return true ; + m_position = this->m_attrV[0] ; + m_color = this->m_attrV[1] ; } - - void approximate(Dart d) ; -} ; - -template -class Approximator_LightfieldCoefsHalf : public Approximator -{ -public: - typedef typename PFP::MAP MAP ; - typedef typename PFP::VEC3 VEC3 ; - typedef typename PFP::REAL REAL ; - -public: - Approximator_LightfieldCoefsHalf(MAP& m, std::vector >& attr, Predictor* pred = NULL) : - Approximator(m, attr, pred) - {} - ~Approximator_LightfieldCoefsHalf() + ~Approximator_ColorQEMext() {} ApproximatorType getType() const { - return A_LightfieldHalf ; + return A_ColorQEMext ; } - bool init() - { - return true ; - } + bool init() ; void approximate(Dart d) ; } ; -*/ + } //namespace Decimation } //namespace Algo diff --git a/include/Algo/Decimation/colorPerVertexApproximator.hpp b/include/Algo/Decimation/colorPerVertexApproximator.hpp index 332db4132..d4e5d4f57 100644 --- a/include/Algo/Decimation/colorPerVertexApproximator.hpp +++ b/include/Algo/Decimation/colorPerVertexApproximator.hpp @@ -32,17 +32,132 @@ namespace Decimation { /************************************************************************************ - * COLOR METRIC * + * NAIVE COLOR METRIC * ************************************************************************************/ template -void Approximator_Color::approximate(Dart d) +void Approximator_ColorNaive::approximate(Dart d) { Dart dd = this->m_map.phi1(d) ; - this->m_approx[0][d] = m_color->operator[](d) ; - this->m_approx[0][d] += m_color->operator[](dd) ; - this->m_approx[0][d] /= 2 ; + const VEC3& p1 = m_position.operator[](d) ; + const VEC3& p2 = m_position.operator[](dd) ; + const VEC3& p = m_approxposition.operator[](d) ; + + const VEC3& edge = p2 - p1 ; + const REAL& ratio = std::max(std::min(((p - p1) * edge) / edge.norm2(),REAL(1)),REAL(0)) ; + + this->m_approx[0][d] = m_color->operator[](d)*ratio + m_color->operator[](dd)*(1-ratio) ; +} + +/************************************************************************************ + * EXTENDED QUADRIC ERROR METRIC * + ************************************************************************************/ +template +bool Approximator_ColorQEMext::init() +{ + m_quadric = this->m_map.template getAttribute, VERTEX>("QEMext-quadric") ; + + if(this->m_predictor) + { + return false ; + } + return true ; +} + +template +void Approximator_ColorQEMext::approximate(Dart d) +{ + MAP& m = this->m_map ; + + // get some darts + Dart dd = m.phi2(d) ; + + QuadricNd q1, q2 ; + if(!m_quadric.isValid()) // if the selector is not QEM, compute local error quadrics + { + // compute the error quadric associated to v1 + Dart it = d ; + do + { + VEC6 p0,p1,p2 ; + for (unsigned int i = 0 ; i < 3 ; ++i) + { + p0[i] = this->m_attrV[0]->operator[](it)[i] ; + p0[i+3] = this->m_attrV[1]->operator[](it)[i] ; + p1[i] = this->m_attrV[0]->operator[](m.phi1(it))[i] ; + p1[i+3] = this->m_attrV[1]->operator[](m.phi1(it))[i] ; + p2[i] = this->m_attrV[0]->operator[](m.phi_1(it))[i] ; + p2[i+3] = this->m_attrV[1]->operator[](m.phi_1(it))[i] ; + } + + QuadricNd q(p0,p1,p2) ; + q1 += q ; + it = m.phi2_1(it) ; + } while(it != d) ; + + // compute the error quadric associated to v2 + it = dd ; + do + { + VEC6 p0,p1,p2 ; + for (unsigned int i = 0 ; i < 3 ; ++i) + { + p0[i] = this->m_attrV[0]->operator[](it)[i] ; + p0[i+3] = this->m_attrV[1]->operator[](it)[i] ; + p1[i] = this->m_attrV[0]->operator[](m.phi1(it))[i] ; + p1[i+3] = this->m_attrV[1]->operator[](m.phi1(it))[i] ; + p2[i] = this->m_attrV[0]->operator[](m.phi_1(it))[i] ; + p2[i+3] = this->m_attrV[1]->operator[](m.phi_1(it))[i] ; + } + + QuadricNd q(p0,p1,p2) ; + q2 += q ; + it = m.phi2_1(it) ; + } while(it != dd) ; + } + else // if the selector is QEM, use the error quadrics computed by the selector + { + q1 = m_quadric[d] ; + q2 = m_quadric[dd] ; + } + + QuadricNd quad ; + quad += q1 ; // compute the sum of the + quad += q2 ; // two vertices quadrics + + VEC6 res ; + bool opt = quad.findOptimizedPos(res) ; // try to compute an optimized position for the contraction of this edge + if(!opt) + { + VEC6 p1, p2 ; + for (unsigned int i = 0 ; i < 3; ++i) + { + p1[i] = this->m_attrV[0]->operator[](d)[i] ; // let the new vertex lie + p1[i+3] = this->m_attrV[1]->operator[](d)[i] ; // on either one + p2[i] = this->m_attrV[0]->operator[](dd)[i] ; // of the two + p2[i+3] = this->m_attrV[1]->operator[](dd)[i] ; // endpoints + } + VEC6 p12 = (p1 + p2) / 2.0f ; // or the middle of the edge + + REAL e1 = quad(p1) ; + REAL e2 = quad(p2) ; + REAL e12 = quad(p12) ; + REAL minerr = std::min(std::min(e1, e2), e12) ; // consider only the one for + if(minerr == e12) + res = p12 ; // which the error is minimal + else if(minerr == e1) + res = p1 ; + else + res = p2 ; + } + + // copy res into m_approx + for (unsigned int i = 0 ; i < 3 ; ++i) + { + this->m_approx[0][d] = res[i] ; + this->m_approx[1][d] = res[i+3] ; + } } } //namespace Decimation diff --git a/include/Algo/Decimation/decimation.h b/include/Algo/Decimation/decimation.h index d959f749c..0aef4964b 100644 --- a/include/Algo/Decimation/decimation.h +++ b/include/Algo/Decimation/decimation.h @@ -29,7 +29,7 @@ #include "Algo/Decimation/halfEdgeSelector.h" #include "Algo/Decimation/geometryApproximator.h" #include "Algo/Decimation/colorPerVertexApproximator.h" -//#include "Algo/Decimation/lightfieldApproximator_deprecated.h" +#include "Algo/Decimation/lightfieldApproximator.h" namespace CGoGN { diff --git a/include/Algo/Decimation/decimation.hpp b/include/Algo/Decimation/decimation.hpp index b6340e13a..c35753175 100644 --- a/include/Algo/Decimation/decimation.hpp +++ b/include/Algo/Decimation/decimation.hpp @@ -48,9 +48,6 @@ void decimate( case A_QEM : approximators.push_back(new Approximator_QEM(map, v_pos)) ; break ; - case A_hQEM : - approximators.push_back(new Approximator_QEMhalfEdge(map, v_pos)) ; - break ; case A_MidEdge : approximators.push_back(new Approximator_MidEdge(map, v_pos)) ; break ; @@ -63,19 +60,57 @@ void decimate( case A_TangentPredict2 : approximators.push_back(new Approximator_MidEdge(map, v_pos)) ; break ; - case A_HalfCollapse : + case A_hHalfCollapse : approximators.push_back(new Approximator_HalfCollapse(map, v_pos)) ; break ; - case A_hColor : + case A_ColorNaive : + { // pos - approximators.push_back(new Approximator_HalfCollapse(map, v_pos)) ; + approximators.push_back(new Approximator_QEM(map, v_pos)) ; // col std::vector* > v_col ; VertexAttribute colors = map.template getAttribute("color") ; v_col.push_back(&colors) ; - approximators.push_back(new Approximator_Color(map, v_col)) ; - break ; + approximators.push_back(new Approximator_ColorNaive(map, v_col)) ; + } + break ; + case A_ColorQEMext : + { + // pos+col + std::vector* > v_poscol ; + v_poscol.push_back(&position) ; // pos + VertexAttribute colors = map.template getAttribute("color") ; + v_poscol.push_back(&colors) ; // col + approximators.push_back(new Approximator_ColorQEMext(map, v_poscol)) ; + } + break; + case A_hQEM : + approximators.push_back(new Approximator_QEMhalfEdge(map, v_pos)) ; + break ; + case A_hLightfieldHalf : + { + // pos + approximators.push_back(new Approximator_HalfCollapse(map, v_pos)) ; + + // frame + std::vector* > v_frame ; + VertexAttribute FT = map.template getAttribute("frameT") ; + VertexAttribute FB = map.template getAttribute("frameB") ; + VertexAttribute FN = map.template getAttribute("frameN") ; + v_frame.push_back(&FT) ; + v_frame.push_back(&FB) ; + v_frame.push_back(&FN) ; + approximators.push_back(new Approximator_FrameHalf(map, v_frame)) ; + +// TODO +// // function coefs +// std::vector* > v_coefs ; +// VertexAttribute coefs = map.template getAttribute("SLFcoefs_0") ; +// v_frame.push_back(&coefs) ; +// approximators.push_back(new Approximator_LFcoefs(map, v_coefs)) ; + } + break ; /*case A_LightfieldHalf: approximators.push_back(new Approximator_HalfCollapse(map, position)) ; @@ -177,14 +212,14 @@ void decimate( case S_MinDetail : selector = new EdgeSelector_MinDetail(map, position, approximators, selected) ; break ; - /*case S_hLightfield_deprecated : - selector = new HalfEdgeSelector_Lightfield_deprecated(map, position, approximators, selected) ; - break ;*/ + case S_ColorNaive : + selector = new EdgeSelector_ColorNaive(map, position, approximators, selected) ; + break ; case S_hQEMml : selector = new HalfEdgeSelector_QEMml(map, position, approximators, selected) ; break ; - case S_hColor : - selector = new HalfEdgeSelector_Color(map, position, approximators, selected) ; + case S_hLightfield : + selector = new HalfEdgeSelector_Lightfield(map, position, approximators, selected) ; break ; } diff --git a/include/Algo/Decimation/edgeSelector.h b/include/Algo/Decimation/edgeSelector.h index 4b007d37d..1039477b0 100644 --- a/include/Algo/Decimation/edgeSelector.h +++ b/include/Algo/Decimation/edgeSelector.h @@ -169,7 +169,8 @@ private: public: EdgeSelector_QEM(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { edgeInfo = m.template addAttribute("edgeInfo") ; quadric = m.template addAttribute, VERTEX>("QEMquadric") ; @@ -218,7 +219,8 @@ private: public: EdgeSelector_QEMml(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { edgeInfo = m.template addAttribute("edgeInfo") ; quadric = m.template addAttribute, VERTEX>("QEMquadric") ; @@ -275,7 +277,8 @@ private: public: EdgeSelector_Curvature(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { bb = Algo::Geometry::computeBoundingBox(m, pos) ; radius = bb.diagSize() * 0.003 ; @@ -360,7 +363,8 @@ private: public: EdgeSelector_MinDetail(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { edgeInfo = m.template addAttribute("edgeInfo") ; } @@ -375,6 +379,66 @@ public: void updateAfterCollapse(Dart d2, Dart dd2) ; } ; +/***************************************************************************************************************** + * HALF-EDGE NAIVE COLOR METRIC (using QEMml) * + *****************************************************************************************************************/ +template +class EdgeSelector_ColorNaive : public EdgeSelector +{ +public: + typedef typename PFP::MAP MAP ; + typedef typename PFP::VEC3 VEC3 ; + typedef typename PFP::REAL REAL ; + +private: + typedef struct + { + typename std::multimap::iterator it ; + bool valid ; + static std::string CGoGNnameOfType() { return "ColorNaiveEdgeInfo" ; } + } ColorNaiveedgeInfo ; + typedef NoMathIOAttribute EdgeInfo ; + + EdgeAttribute edgeInfo ; + VertexAttribute m_color ; + VertexAttribute > m_quadric ; + + std::multimap edges ; + typename std::multimap::iterator cur ; + + Approximator* m_positionApproximator ; + Approximator* m_colorApproximator ; + + void initEdgeInfo(Dart d) ; + void updateEdgeInfo(Dart d, bool recompute) ; + void computeEdgeInfo(Dart d,EdgeInfo& einfo) ; + void recomputeQuadric(const Dart d, const bool recomputeNeighbors = false) ; + +public: + EdgeSelector_ColorNaive(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL), + m_colorApproximator(NULL) + { + edgeInfo = m.template addAttribute("edgeInfo") ; + m_quadric = m.template addAttribute, VERTEX>("QEMquadric") ; + + m_color = m.template getAttribute("color") ; + assert(m_color.isValid() || !"EdgeSelector_ColorNaive: Color atrribute to select is not valid") ; + } + ~EdgeSelector_ColorNaive() + { + this->m_map.removeAttribute(edgeInfo) ; + this->m_map.removeAttribute(m_quadric) ; + } + SelectorType getType() { return S_ColorNaive ; } + bool init() ; + bool nextEdge(Dart& d) ; + void updateBeforeCollapse(Dart d) ; + void updateAfterCollapse(Dart d2, Dart dd2) ; +} ; + + } // namespace Decimation } // namespace Algo diff --git a/include/Algo/Decimation/edgeSelector.hpp b/include/Algo/Decimation/edgeSelector.hpp index a4af98926..f555ac9bb 100644 --- a/include/Algo/Decimation/edgeSelector.hpp +++ b/include/Algo/Decimation/edgeSelector.hpp @@ -735,7 +735,7 @@ bool EdgeSelector_Curvature::init() edges.clear() ; - CellMarker eMark(m) ; + CellMarker eMark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!eMark.isMarked(d)) @@ -1095,6 +1095,253 @@ void EdgeSelector_MinDetail::computeEdgeInfo(Dart d, EdgeInfo& einfo) einfo.valid = true ; } +/************************************************************************************ + * EDGESELECTOR COLOR PER VERTEX * + ************************************************************************************/ + +template +bool EdgeSelector_ColorNaive::init() +{ + MAP& m = this->m_map ; + + // Verify availability of required approximators + char ok = 0 ; + for(typename std::vector*>::iterator it = this->m_approximators.begin(); + it != this->m_approximators.end(); + ++it) + { + // constraint : 2 approximators in specific order + if(ok == 0 && (*it)->getApproximatedAttributeName(0) == "position") + { + m_positionApproximator = reinterpret_cast* >(*it) ; // 1) position + // check incompatibilities + assert(m_positionApproximator->getType() != A_hQEM || !"Approximator(hQEM) and selector (ColorNaive) are not compatible") ; + assert(m_positionApproximator->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (ColorNaive) are not compatible") ; + assert(m_positionApproximator->getType() != A_hLightfieldHalf || !"Approximator(hLightfieldHalf) and selector (ColorNaive) are not compatible") ; + + ++ok ; + } + else if( ok == 1 && (*it)->getApproximatedAttributeName(0) == "color") + { + m_colorApproximator = reinterpret_cast* >(*it) ; // 2) color (needs position) + ++ok ; + } + } + + if(ok != 2) + return false ; + + TraversorV travV(m); + for(Dart dit = travV.begin() ; dit != travV.end() ; dit = travV.next()) + { + Quadric q ; // create one quadric + m_quadric[dit] = q ; // per vertex + } + + // Compute quadric per vertex + TraversorF travF(m) ; + for(Dart dit = travF.begin() ; dit != travF.end() ; dit = travF.next()) // init QEM quadrics + { + Dart d1 = m.phi1(dit) ; // for each triangle, + Dart d_1 = m.phi_1(dit) ; // initialize the quadric of the triangle + Quadric q(this->m_position[dit], this->m_position[d1], this->m_position[d_1]) ; + m_quadric[dit] += q ; // and add the contribution of + m_quadric[d1] += q ; // this quadric to the ones + m_quadric[d_1] += q ; // of the 3 incident vertices + } + + TraversorE travE(m); + for(Dart dit = travE.begin() ; dit != travE.end() ; dit = travE.next()) + { + initEdgeInfo(dit) ; // init the edges with their optimal position + // and insert them in the multimap according to their error + } + + cur = edges.begin() ; // init the current edge to the first one + + return true ; +} + +template +bool EdgeSelector_ColorNaive::nextEdge(Dart& d) +{ + if(cur == edges.end() || edges.empty()) + return false ; + d = (*cur).second ; + return true ; +} + +template +void EdgeSelector_ColorNaive::updateBeforeCollapse(Dart d) +{ + MAP& m = this->m_map ; + + EdgeInfo& edgeE = edgeInfo[d] ; + if(edgeE.valid) + edges.erase(edgeE.it) ; + + edgeE = edgeInfo[m.phi1(d)] ; + if(edgeE.valid) // remove all + edges.erase(edgeE.it) ; + + edgeE = edgeInfo[m.phi_1(d)] ; // the edges that will disappear + if(edgeE.valid) + edges.erase(edgeE.it) ; + // from the multimap + Dart dd = m.phi2(d) ; + if(dd != d) + { + edgeE = edgeInfo[m.phi1(dd)] ; + if(edgeE.valid) + edges.erase(edgeE.it) ; + + edgeE = edgeInfo[m.phi_1(dd)] ; + if(edgeE.valid) + edges.erase(edgeE.it) ; + } +} + +/** + * Update quadric of a vertex + * Discards quadrics of d and assigns freshly calculated + * quadrics depending on the actual planes surrounding d + * @param dart d + */ +template +void EdgeSelector_ColorNaive::recomputeQuadric(const Dart d, const bool recomputeNeighbors) +{ + Dart dFront,dBack ; + Dart dInit = d ; + + // Init Front + dFront = dInit ; + + m_quadric[d].zero() ; + + do + { + // Make step + dBack = this->m_map.phi2(dFront) ; + dFront = this->m_map.phi2_1(dFront) ; + + if (dBack != dFront) + { // if dFront is no border + m_quadric[d] += Quadric(this->m_position[d],this->m_position[this->m_map.phi2(dFront)],this->m_position[dBack]) ; + } + if (recomputeNeighbors) + recomputeQuadric(dBack, false) ; + + } while(dFront != dInit) ; +} + +template +void EdgeSelector_ColorNaive::updateAfterCollapse(Dart d2, Dart dd2) +{ + MAP& m = this->m_map ; + + recomputeQuadric(d2, true) ; + + Dart vit = d2 ; + do + { + updateEdgeInfo(m.phi1(vit), true) ; // must recompute some edge infos in the + if(vit == d2 || vit == dd2) // neighborhood of the collapsed edge + initEdgeInfo(vit) ; // various optimizations are applied here by + else // treating differently : + updateEdgeInfo(vit, true) ; + + Dart vit2 = m.phi12(m.phi1(vit)) ; // - edges for which the criteria must be recomputed + Dart stop = m.phi2(vit) ; // - edges that must be re-embedded + do // - edges for which only the collapsibility must be re-tested + { + updateEdgeInfo(vit2, true) ; + updateEdgeInfo(m.phi1(vit2), false) ; + vit2 = m.phi12(vit2) ; + } while(vit2 != stop) ; + + vit = m.phi2_1(vit) ; + } while(vit != d2) ; + + cur = edges.begin() ; // set the current edge to the first one +} + +template +void EdgeSelector_ColorNaive::initEdgeInfo(Dart d) +{ + MAP& m = this->m_map ; + EdgeInfo einfo ; + if(m.edgeCanCollapse(d)) + computeEdgeInfo(d, einfo) ; + else + einfo.valid = false ; + edgeInfo[d] = einfo ; +} + +template +void EdgeSelector_ColorNaive::updateEdgeInfo(Dart d, bool recompute) +{ + MAP& m = this->m_map ; + EdgeInfo& einfo = edgeInfo[d] ; + if(recompute) + { + if(einfo.valid) + edges.erase(einfo.it) ; // remove the edge from the multimap + if(m.edgeCanCollapse(d)) + computeEdgeInfo(d, einfo) ; + else + einfo.valid = false ; + } + else + { + if(m.edgeCanCollapse(d)) + { // if the edge can be collapsed now + if(!einfo.valid) // but it was not before + computeEdgeInfo(d, einfo) ; + } + else + { // if the edge cannot be collapsed now + if(einfo.valid) // and it was before + { + edges.erase(einfo.it) ; + einfo.valid = false ; + } + } + } +} + +template +void EdgeSelector_ColorNaive::computeEdgeInfo(Dart d, EdgeInfo& einfo) +{ + MAP& m = this->m_map ; + Dart dd = m.phi1(d) ; + + // New position + Quadric quad ; + quad += m_quadric[d] ; // compute the sum of the + quad += m_quadric[dd] ; // two vertices quadrics + + this->m_positionApproximator->approximate(d) ; // sets newPos + VEC3 newPos = this->m_positionApproximator->getApprox(d) ; // get newPos + + // New color + this->m_colorApproximator->approximate(d) ; // sets new color + const VEC3& newColor = this->m_colorApproximator->getApprox(d) ; // get new color + + // Compute error + VEC3 colDiff1 = newColor ; + VEC3 colDiff2 = newColor ; + const VEC3& oldCol1 = m_color[d] ; + const VEC3& oldCol2 = m_color[dd] ; + colDiff1 -= oldCol1 ; + colDiff2 -= oldCol2 ; + + // sum of QEM metric and squared difference between new color and old colors + REAL err = quad(newPos) + colDiff1.norm() + colDiff2.norm() ; + + einfo.it = edges.insert(std::make_pair(err, d)) ; + einfo.valid = true ; +} + } // namespace Decimation } // namespace Algo diff --git a/include/Algo/Decimation/geometryApproximator.h b/include/Algo/Decimation/geometryApproximator.h index 2c2b00c59..9a6458815 100644 --- a/include/Algo/Decimation/geometryApproximator.h +++ b/include/Algo/Decimation/geometryApproximator.h @@ -119,7 +119,7 @@ public: } ~Approximator_HalfCollapse() {} - ApproximatorType getType() const { return A_HalfCollapse ; } + ApproximatorType getType() const { return A_hHalfCollapse ; } bool init() ; void approximate(Dart d) ; } ; diff --git a/include/Algo/Decimation/geometryApproximator.hpp b/include/Algo/Decimation/geometryApproximator.hpp index c7b3e8540..14706cbdc 100644 --- a/include/Algo/Decimation/geometryApproximator.hpp +++ b/include/Algo/Decimation/geometryApproximator.hpp @@ -34,7 +34,6 @@ namespace Decimation /************************************************************************************ * QUADRIC ERROR METRIC * ************************************************************************************/ - template bool Approximator_QEM::init() { @@ -83,21 +82,21 @@ void Approximator_QEM::approximate(Dart d) } Quadric quad ; - quad += q1 ; // compute the sum of the - quad += q2 ; // two vertices quadrics + quad += q1 ; // compute the sum of the + quad += q2 ; // two vertices quadrics VEC3 res ; - bool opt = quad.findOptimizedPos(res) ; // try to compute an optimized position for the contraction of this edge + bool opt = quad.findOptimizedPos(res) ; // try to compute an optimized position for the contraction of this edge if(!opt) { - VEC3 p1 = this->m_attrV[0]->operator[](d) ; // let the new vertex lie - VEC3 p2 = this->m_attrV[0]->operator[](dd) ; // on either one of the two endpoints - VEC3 p12 = (p1 + p2) / 2.0f ; // or the middle of the edge + VEC3 p1 = this->m_attrV[0]->operator[](d) ; // let the new vertex lie + VEC3 p2 = this->m_attrV[0]->operator[](dd) ; // on either one of the two endpoints + VEC3 p12 = (p1 + p2) / 2.0f ; // or the middle of the edge REAL e1 = quad(p1) ; REAL e2 = quad(p2) ; REAL e12 = quad(p12) ; - REAL minerr = std::min(std::min(e1, e2), e12) ; // consider only the one for - if(minerr == e12) this->m_approx[0][d] = p12 ; // which the error is minimal + REAL minerr = std::min(std::min(e1, e2), e12) ; // consider only the one for + if(minerr == e12) this->m_approx[0][d] = p12 ; // which the error is minimal else if(minerr == e1) this->m_approx[0][d] = p1 ; else this->m_approx[0][d] = p2 ; } diff --git a/include/Algo/Decimation/halfEdgeSelector.h b/include/Algo/Decimation/halfEdgeSelector.h index ffad61635..3f866f982 100644 --- a/include/Algo/Decimation/halfEdgeSelector.h +++ b/include/Algo/Decimation/halfEdgeSelector.h @@ -36,6 +36,9 @@ namespace Algo namespace Decimation { +/***************************************************************************************************************** + * HALF-EDGE MEMORYLESS QEM METRIC * + *****************************************************************************************************************/ template class HalfEdgeSelector_QEMml : public EdgeSelector { @@ -68,7 +71,8 @@ private: public: HalfEdgeSelector_QEMml(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { halfEdgeInfo = m.template addAttribute("halfEdgeInfo") ; quadric = m.template addAttribute, VERTEX>("QEMquadric") ; @@ -85,8 +89,11 @@ public: void updateAfterCollapse(Dart d2, Dart dd2) ; } ; +/***************************************************************************************************************** + * HALF-EDGE LIGHTFIELD METRIC * + *****************************************************************************************************************/ template -class HalfEdgeSelector_Color : public EdgeSelector +class HalfEdgeSelector_Lightfield : public EdgeSelector { public: typedef typename PFP::MAP MAP ; @@ -98,19 +105,20 @@ private: { typename std::multimap::iterator it ; bool valid ; - static std::string CGoGNnameOfType() { return "ColorHalfEdgeInfo" ; } + static std::string CGoGNnameOfType() { return "LightfieldHalfEdgeInfo" ; } } QEMhalfEdgeInfo ; typedef NoMathIOAttribute HalfEdgeInfo ; DartAttribute halfEdgeInfo ; - VertexAttribute m_color ; + VertexAttribute m_frameT, m_frameB, m_frameN ; VertexAttribute > m_quadric ; std::multimap halfEdges ; typename std::multimap::iterator cur ; Approximator* m_positionApproximator ; - Approximator* m_colorApproximator ; + Approximator* m_frameApproximator ; + // Approximator* m_lfcoefsApproximator ; void initHalfEdgeInfo(Dart d) ; void updateHalfEdgeInfo(Dart d, bool recompute) ; @@ -118,21 +126,27 @@ private: void recomputeQuadric(const Dart d, const bool recomputeNeighbors = false) ; public: - HalfEdgeSelector_Color(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : - EdgeSelector(m, pos, approx, select) + HalfEdgeSelector_Lightfield(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL), + m_frameApproximator(NULL) { halfEdgeInfo = m.template addAttribute("halfEdgeInfo") ; m_quadric = m.template addAttribute, VERTEX>("QEMquadric") ; - m_color = m.template getAttribute("color") ; - assert(m_color.isValid() || !"HalfEdgeSelector_Color: Color atrribute to select is not valid") ; + m_frameT = m.template getAttribute("frameT") ; + m_frameB = m.template getAttribute("frameB") ; + m_frameN = m.template getAttribute("frameN") ; + assert(m_frameT.isValid() || !"HalfEdgeSelector_Lightfield: frameT atrribute to select is not valid") ; + assert(m_frameB.isValid() || !"HalfEdgeSelector_Lightfield: frameT atrribute to select is not valid") ; + assert(m_frameN.isValid() || !"HalfEdgeSelector_Lightfield: frameT atrribute to select is not valid") ; } - ~HalfEdgeSelector_Color() + ~HalfEdgeSelector_Lightfield() { this->m_map.removeAttribute(halfEdgeInfo) ; this->m_map.removeAttribute(m_quadric) ; } - SelectorType getType() { return S_hColor ; } + SelectorType getType() { return S_hLightfield ; } bool init() ; bool nextEdge(Dart& d) ; void updateBeforeCollapse(Dart d) ; diff --git a/include/Algo/Decimation/halfEdgeSelector.hpp b/include/Algo/Decimation/halfEdgeSelector.hpp index 120c36125..78918719a 100644 --- a/include/Algo/Decimation/halfEdgeSelector.hpp +++ b/include/Algo/Decimation/halfEdgeSelector.hpp @@ -278,12 +278,12 @@ void HalfEdgeSelector_QEMml::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& hein } /************************************************************************************ - * HALFEDGESELECTOR COLOR PER VERTEX * + * HALFEDGESELECTOR LIGHTFIELD * ************************************************************************************/ - template -bool HalfEdgeSelector_Color::init() +bool HalfEdgeSelector_Lightfield::init() { + // TODO MAP& m = this->m_map ; // Verify availability of required approximators @@ -299,11 +299,14 @@ bool HalfEdgeSelector_Color::init() assert(m_positionApproximator->getType() != A_QEM) ; // A_QEM is not compatible for half-edge crit ++ok ; } - else if( ok == 1 && (*it)->getApproximatedAttributeName(0) == "color") - { - m_colorApproximator = reinterpret_cast* >(*it) ; // 2) color (needs position) - ++ok ; - } + else + if( ok == 1 && (*it)->getApproximatedAttributeName(0) == "frameT") + if( ok == 1 && (*it)->getApproximatedAttributeName(1) == "frameB") + if( ok == 1 && (*it)->getApproximatedAttributeName(2) == "frameN") + { + m_frameApproximator = reinterpret_cast* >(*it) ; // 2) frame (needs position) + ++ok ; + } } if(ok != 2) @@ -352,7 +355,7 @@ bool HalfEdgeSelector_Color::init() } template -bool HalfEdgeSelector_Color::nextEdge(Dart& d) +bool HalfEdgeSelector_Lightfield::nextEdge(Dart& d) { if(cur == halfEdges.end() || halfEdges.empty()) return false ; @@ -361,7 +364,7 @@ bool HalfEdgeSelector_Color::nextEdge(Dart& d) } template -void HalfEdgeSelector_Color::updateBeforeCollapse(Dart d) +void HalfEdgeSelector_Lightfield::updateBeforeCollapse(Dart d) { MAP& m = this->m_map ; @@ -401,8 +404,8 @@ void HalfEdgeSelector_Color::updateBeforeCollapse(Dart d) * @param dart d */ template -void HalfEdgeSelector_Color::recomputeQuadric(const Dart d, const bool recomputeNeighbors) -{ +void HalfEdgeSelector_Lightfield::recomputeQuadric(const Dart d, const bool recomputeNeighbors) +{ // TODO Dart dFront,dBack ; Dart dInit = d ; @@ -428,10 +431,11 @@ void HalfEdgeSelector_Color::recomputeQuadric(const Dart d, const bool reco } template -void HalfEdgeSelector_Color::updateAfterCollapse(Dart d2, Dart dd2) +void HalfEdgeSelector_Lightfield::updateAfterCollapse(Dart d2, Dart dd2) { MAP& m = this->m_map ; + // TODO recomputeQuadric(d2, true) ; Dart vit = d2 ; @@ -466,12 +470,11 @@ void HalfEdgeSelector_Color::updateAfterCollapse(Dart d2, Dart dd2) vit = m.phi2_1(vit) ; } while(vit != d2) ; - cur = halfEdges.begin() ; // set the current edge to the first one } template -void HalfEdgeSelector_Color::initHalfEdgeInfo(Dart d) +void HalfEdgeSelector_Lightfield::initHalfEdgeInfo(Dart d) { MAP& m = this->m_map ; HalfEdgeInfo heinfo ; @@ -484,7 +487,7 @@ void HalfEdgeSelector_Color::initHalfEdgeInfo(Dart d) } template -void HalfEdgeSelector_Color::updateHalfEdgeInfo(Dart d, bool recompute) +void HalfEdgeSelector_Lightfield::updateHalfEdgeInfo(Dart d, bool recompute) { MAP& m = this->m_map ; HalfEdgeInfo& heinfo = halfEdgeInfo[d] ; @@ -516,8 +519,8 @@ void HalfEdgeSelector_Color::updateHalfEdgeInfo(Dart d, bool recompute) } template -void HalfEdgeSelector_Color::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& heinfo) -{ +void HalfEdgeSelector_Lightfield::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& heinfo) +{ // TODO MAP& m = this->m_map ; Dart dd = m.phi1(d) ; @@ -530,26 +533,34 @@ void HalfEdgeSelector_Color::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& hein VEC3 newPos = this->m_positionApproximator->getApprox(d) ; // get newPos // New Frame - this->m_colorApproximator->approximate(d) ; // sets new color - VEC3 newColor = this->m_colorApproximator->getApprox(d) ; // get new color + this->m_frameApproximator->approximate(d) ; // sets new color + const VEC3& newFN = this->m_frameApproximator->getApprox(d,2) ; // get new frameN + + // Compute hemisphere difference error + double scal1 = abs(double(m_frameN[d] * newFN)) ; + scal1 = std::min(scal1, double(1)) ; // for epsilon normalization of newFN errors + double alpha = acos(scal1) ; - // Compute error - VEC3 colDiff1 = newColor ; - VEC3 colDiff2 = newColor ; - VEC3 oldCol1 = m_color[d] ; - VEC3 oldCol2 = m_color[dd] ; - colDiff1 -= oldCol1 ; - colDiff2 -= oldCol2 ; + double scal2 = abs(double(m_frameN[dd] * newFN)) ; + scal2 = std::min(scal2, double(1)) ; + alpha += acos(scal2) ; - // sum of QEM metric and squared difference between new color and old colors - REAL err = quad(newPos) + colDiff1.norm2() + colDiff2.norm2() ; - std::cout << quad(newPos) << " vs " << colDiff1.norm2() + colDiff2.norm2() << std::endl ; + // Sum of abs values works only if newFN is in-between the two old ones (interpolated). + // This avoids computation of the sign of alpha1 and alpha2. + + std::cout << quad(newPos) << " vs " << ((alpha <= M_PI/2.) ? sin(alpha)/2. : 1 - sin(alpha)/2.) << std::endl ; + + // sum of QEM metric and frame orientation difference + REAL err = + quad(newPos) // geom + + ((alpha <= M_PI/2.) ? sin(alpha)/2. : 1 - sin(alpha)/2.) // frame + //TODO // function coefficients + ; heinfo.it = halfEdges.insert(std::make_pair(err, d)) ; heinfo.valid = true ; } - ///************************************************************************************ // * HALFEDGESELECTOR LIGHTFIELD * // ************************************************************************************/ diff --git a/include/Algo/Decimation/lightfieldApproximator.h b/include/Algo/Decimation/lightfieldApproximator.h new file mode 100644 index 000000000..b6a020384 --- /dev/null +++ b/include/Algo/Decimation/lightfieldApproximator.h @@ -0,0 +1,119 @@ +/******************************************************************************* +* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * +* version 0.1 * +* Copyright (C) 2009-2012, IGG Team, LSIIT, University of Strasbourg * +* * +* This library is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by the * +* Free Software Foundation; either version 2.1 of the License, or (at your * +* option) any later version. * +* * +* This library 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 Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +* Web site: http://cgogn.unistra.fr/ * +* Contact information: cgogn@unistra.fr * +* * +*******************************************************************************/ + +#ifndef __LIGHTFIELD_APPROXIMATOR_H__ +#define __LIGHTFIELD_APPROXIMATOR_H__ + +#include "Algo/Decimation/approximator.h" +#include "Topology/generic/mapBrowser.h" + +namespace CGoGN +{ + +namespace Algo +{ + +namespace Decimation +{ + +template +class Approximator_FrameHalf : public Approximator +{ +public: + typedef typename PFP::MAP MAP ; + typedef typename PFP::VEC3 VEC3 ; + typedef typename PFP::REAL REAL ; + +protected: + VertexAttribute *m_frameT ; + VertexAttribute *m_frameB ; + VertexAttribute *m_frameN ; + +public: + Approximator_FrameHalf(MAP& m, std::vector* >& attr, Predictor* pred = NULL) : + Approximator(m, attr, pred) + { + if (this->m_attrV.size() < 1) + std::cerr << "Approximator_Frame: not enough attributes provided (only " << this->m_attrV.size() << " instead of 3)" << std::endl ; + + m_frameT = this->m_attrV[0] ; + m_frameB = this->m_attrV[1] ; + m_frameN = this->m_attrV[2] ; + assert(m_frameT->isValid() || !"Approximator_FrameHalf: the first approximated attribute is not valid") ; + assert(m_frameB->isValid() || !"Approximator_FrameHalf: the second approximated attribute is not valid") ; + assert(m_frameN->isValid() || !"Approximator_FrameHalf: the third approximated attribute is not valid") ; + } + ~Approximator_FrameHalf() + {} + + ApproximatorType getType() const + { + return A_hLightfieldHalf ; + } + + bool init() + { + return true ; + } + + void approximate(Dart d) ; +} ; +/* +template +class Approximator_LightfieldCoefsHalf : public Approximator +{ +public: + typedef typename PFP::MAP MAP ; + typedef typename PFP::VEC3 VEC3 ; + typedef typename PFP::REAL REAL ; + +public: + Approximator_LightfieldCoefsHalf(MAP& m, std::vector >& attr, Predictor* pred = NULL) : + Approximator(m, attr, pred) + {} + ~Approximator_LightfieldCoefsHalf() + {} + + ApproximatorType getType() const + { + return A_LightfieldHalf ; + } + + bool init() + { + return true ; + } + + void approximate(Dart d) ; +} ; +*/ +} //namespace Decimation + +} //namespace Algo + +} //namespace CGoGN + +#include "Algo/Decimation/lightfieldApproximator.hpp" + +#endif diff --git a/include/Algo/Decimation/lightfieldApproximator.hpp b/include/Algo/Decimation/lightfieldApproximator.hpp new file mode 100644 index 000000000..62d039d64 --- /dev/null +++ b/include/Algo/Decimation/lightfieldApproximator.hpp @@ -0,0 +1,50 @@ +/******************************************************************************* +* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * +* version 0.1 * +* Copyright (C) 2009-2012, IGG Team, LSIIT, University of Strasbourg * +* * +* This library is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by the * +* Free Software Foundation; either version 2.1 of the License, or (at your * +* option) any later version. * +* * +* This library 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 Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +* Web site: http://cgogn.unistra.fr/ * +* Contact information: cgogn@unistra.fr * +* * +*******************************************************************************/ + +namespace CGoGN +{ + +namespace Algo +{ + +namespace Decimation +{ + +/************************************************************************************ + * HALF-CONTRACTION FRAME APPROXIMATOR * + ************************************************************************************/ + +template +void Approximator_FrameHalf::approximate(Dart d) +{ + this->m_approx[0][d] = m_frameT->operator[](d) ; + this->m_approx[1][d] = m_frameB->operator[](d) ; + this->m_approx[2][d] = m_frameN->operator[](d) ; +} + +} //namespace Decimation + +} //namespace Algo + +} //namespace CGoGN diff --git a/include/Algo/Decimation/selector.h b/include/Algo/Decimation/selector.h index 9a33a9731..e1158b104 100644 --- a/include/Algo/Decimation/selector.h +++ b/include/Algo/Decimation/selector.h @@ -36,17 +36,17 @@ namespace Decimation enum SelectorType { - S_MapOrder, + S_MapOrder = 0, S_Random, S_EdgeLength, S_QEM, S_QEMml, S_MinDetail, S_Curvature, + S_ColorNaive, + // note: the following "h" prefix means that half-edges are prioritized instead of edges. S_hQEMml, - S_hColor, - //S_hLightfield_cst, - //S_hLightfield_deprecated + S_hLightfield } ; template class ApproximatorGen ; diff --git a/include/Algo/ProgressiveMesh/pmesh.hpp b/include/Algo/ProgressiveMesh/pmesh.hpp index 45d17d434..3032d5188 100644 --- a/include/Algo/ProgressiveMesh/pmesh.hpp +++ b/include/Algo/ProgressiveMesh/pmesh.hpp @@ -53,7 +53,7 @@ ProgressiveMesh::ProgressiveMesh( case Algo::Decimation::A_MidEdge : { m_approximators.push_back(new Algo::Decimation::Approximator_MidEdge(m_map, pos_v)) ; break ; } - case Algo::Decimation::A_HalfCollapse : { + case Algo::Decimation::A_hHalfCollapse : { Algo::Decimation::Predictor_HalfCollapse* pred = new Algo::Decimation::Predictor_HalfCollapse(m_map, positionsTable) ; m_predictors.push_back(pred) ; m_approximators.push_back(new Algo::Decimation::Approximator_HalfCollapse(m_map, pos_v, pred)) ; @@ -307,7 +307,7 @@ void ProgressiveMesh::refine() detailTransform = &invLocalFrame ; (*pit)->affectPredict(d) ; - if((*ait)->getType() == Algo::Decimation::A_HalfCollapse) + if((*ait)->getType() == Algo::Decimation::A_hHalfCollapse) { (*ait)->addDetail(dd, m_detailAmount, true, detailTransform) ; } diff --git a/include/Utils/qem.h b/include/Utils/qem.h index 86ae7d4d8..f258a3a4d 100644 --- a/include/Utils/qem.h +++ b/include/Utils/qem.h @@ -165,6 +165,160 @@ private: } } ; +template +class QuadricNd +{ +public: + static std::string CGoGNnameOfType() { return "QuadricNd" ; } + + typedef Geom::Vector VECN ; + typedef Geom::Vector VECNp ; + typedef Geom::Matrix MATRIXNN ; // double is crucial here ! + typedef Geom::Matrix MATRIXNpNp ; // double is crucial here ! + + QuadricNd() + { + Q.zero() ; + } + + QuadricNd(int i) + { + Q.zero() ; + } + + QuadricNd(const VECN& p1_r, const VECN& p2_r, const VECN& p3_r) + { + const Geom::Vector& p1 = p1_r ; + const Geom::Vector& p2 = p2_r ; + const Geom::Vector& p3 = p3_r ; + + Geom::Vector e1 = p2 - p1 ; e1.normalize() ; + Geom::Vector e2 = p3 - p1 - (e1*(p3-p1))*e1 ; e2.normalize() ; + + MATRIXNN A ; + A.identity() ; + A -= (Geom::transposed_vectors_mult(e1,e1) + Geom::transposed_vectors_mult(e2,e2)) ; + + const Geom::Vector& b = (p1*e1)*e1 + (p1*e2)*e2 - p1 ; + + const REAL& c = p1*p1 - pow((p1*e1),2) - pow((p1*e2),2) ; + + /* + * Build Q + * |-----------| + * Q = |- A - b -| + * |-----------| + * |- b^T - c -| + */ + Q.setSubMatrix(0,0,A) ; + Q.setSubVectorH(N,0,b) ; + Q.setSubVectorV(N,0,b) ; + Q(N,N) = c ; + } + + void zero() + { + Q.zero() ; + } + + void operator= (const QuadricNd& q) + { + Q = q.Q ; + } + QuadricNd& operator+= (const QuadricNd& q) + { + Q += q.Q ; + return *this ; + } + QuadricNd& operator -= (const QuadricNd& q) + { + Q -= q.Q ; + return *this ; + } + QuadricNd& operator *= (REAL v) + { + Q *= v ; + return *this ; + } + QuadricNd& operator /= (REAL v) + { + Q /= v ; + return *this ; + } + + REAL operator() (const VECNp& v) const + { + return evaluate(v) ; + } + + REAL operator() (const VECN& v) const + { + VECNp hv ; + for (unsigned int i = 0 ; i < N ; ++i) + hv[i] = v[i] ; + hv[N] = 1.0f ; + + return evaluate(hv) ; + } + + friend std::ostream& operator<<(std::ostream& out, const QuadricNd& q) + { + out << q.Q ; + return out ; + } + + friend std::istream& operator>>(std::istream& in, QuadricNd& q) + { + in >> q.Q ; + return in ; + } + + bool findOptimizedPos(VECN& v) + { + VECNp hv ; + bool b = optimize(hv) ; + if(b) + { + for (unsigned int i = 0 ; i < N ; ++i) + v[i] = hv[i] ; + } + return b ; + } + +private: + MATRIXNpNp Q ; + + REAL evaluate(const VECNp& v) const + { + // Double computation is crucial for stability + Geom::Vector Qv = Q * v ; + return v * Qv ; + } + + bool optimize(VECNp& v) const + { + if (std::isnan(Q(0,0))) + return false ; + + MATRIXNpNp Q2(Q) ; + for(unsigned int i = 0; i < N; ++i) + Q2(N,i) = 0.0f ; + Q2(N,N) = 1.0f ; + + MATRIXNpNp Qinv ; + REAL det = Q2.invert(Qinv) ; + + if(det > -1e-6 && det < 1e-6) + return false ; + + VECNp right(0) ; + right[N] = 1 ; // last element + v = Qinv * right ; + + return true; + } +} ; + //} // Utils -- GitLab