/******************************************************************************* * 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 * * * *******************************************************************************/ #include #include "Algo/Geometry/basic.h" #include "Algo/Decimation/geometryApproximator.h" namespace CGoGN { namespace Algo { namespace Decimation { /************************************************************************************ * MAP ORDER * ************************************************************************************/ template bool EdgeSelector_MapOrder::init() { cur = this->m_map.begin() ; return true ; } template bool EdgeSelector_MapOrder::nextEdge(Dart& d) { typename PFP::MAP& m = this->m_map ; if(cur == m.end()) return false ; d = cur ; return true ; } template void EdgeSelector_MapOrder::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::MAP& m = this->m_map ; cur = m.begin() ; while(!this->m_select(cur) || !m.edgeCanCollapse(cur)) { m.next(cur) ; if(cur == m.end()) break ; } } /************************************************************************************ * RANDOM * ************************************************************************************/ template bool EdgeSelector_Random::init() { typename PFP::MAP& m = this->m_map ; darts.reserve(m.getNbDarts()) ; darts.clear() ; for(Dart d = m.begin(); d != m.end(); m.next(d)) darts.push_back(d) ; srand(time(NULL)) ; int remains = darts.size() ; for(unsigned int i = 0; i < darts.size()-1; ++i) // generate the random permutation { int r = (rand() % remains) + i ; // swap ith and rth elements Dart tmp = darts[i] ; darts[i] = darts[r] ; darts[r] = tmp ; --remains ; } cur = 0 ; allSkipped = true ; return true ; } template bool EdgeSelector_Random::nextEdge(Dart& d) { if(cur == darts.size() && allSkipped) return false ; d = darts[cur] ; return true ; } template void EdgeSelector_Random::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::MAP& m = this->m_map ; allSkipped = false ; do { ++cur ; if(cur == darts.size()) { cur = 0 ; allSkipped = true ; } } while(!this->m_select(cur) || !m.edgeCanCollapse(darts[cur])) ; } template void EdgeSelector_Random::updateWithoutCollapse() { typename PFP::MAP& m = this->m_map ; allSkipped = false ; do { ++cur ; if(cur == darts.size()) { cur = 0 ; allSkipped = true ; } } while(!this->m_select(cur) || !m.edgeCanCollapse(darts[cur])) ; } /************************************************************************************ * EDGE LENGTH * ************************************************************************************/ template bool EdgeSelector_Length::init() { typename PFP::MAP& m = this->m_map ; edges.clear() ; CellMarker eMark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!eMark.isMarked(d)) { initEdgeInfo(d) ; eMark.mark(d) ; } } cur = edges.begin() ; // init the current edge to the first one return true ; } template bool EdgeSelector_Length::nextEdge(Dart& d) { if(cur == edges.end() || edges.empty()) return false ; d = (*cur).second ; return true ; } template void EdgeSelector_Length::updateBeforeCollapse(Dart d) { typename PFP::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 concerned edges 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) ; } } template void EdgeSelector_Length::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::MAP& m = this->m_map ; Dart vit = d2 ; do { updateEdgeInfo(m.phi1(vit), false) ; // 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 // treating differently : 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, false) ; updateEdgeInfo(m.phi1(vit2), false) ; vit2 = m.phi12(vit2) ; } while(vit2 != stop) ; } else updateEdgeInfo(vit, true) ; vit = m.phi2_1(vit) ; } while(vit != d2) ; cur = edges.begin() ; // set the current edge to the first one } template void EdgeSelector_Length::updateWithoutCollapse() { EdgeInfo& einfo = edgeInfo[(*cur).second] ; einfo.valid = false ; edges.erase(einfo.it) ; //edges.erase(cur) ; cur = edges.begin(); } template void EdgeSelector_Length::initEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo einfo ; if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; edgeInfo[d] = einfo ; } template void EdgeSelector_Length::updateEdgeInfo(Dart d, bool recompute) { typename PFP::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_Length::computeEdgeInfo(Dart d, EdgeInfo& einfo) { VEC3 vec = Algo::Geometry::vectorOutOfDart(this->m_map, d, this->m_position) ; einfo.it = edges.insert(std::make_pair(vec.norm2(), d)) ; einfo.valid = true ; } /************************************************************************************ * QUADRIC ERROR METRIC * ************************************************************************************/ template bool EdgeSelector_QEM::init() { typename PFP::MAP& m = this->m_map ; bool ok = false ; for(typename std::vector*>::iterator it = this->m_approximators.begin(); it != this->m_approximators.end() && !ok; ++it) { if((*it)->getApproximatedAttributeName() == "position") { assert((*it)->getType() != A_hQEM || !"Approximator(hQEM) and selector (EdgeSelector_QEM) are not compatible") ; assert((*it)->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (EdgeSelector_QEM) are not compatible") ; assert((*it)->getType() != A_Lightfield || !"Approximator(hLightfield) and selector (EdgeSelector_QEM) are not compatible") ; m_positionApproximator = reinterpret_cast* >(*it) ; ok = true ; } } if(!ok) return false ; edges.clear() ; CellMarker vMark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!vMark.isMarked(d)) { Utils::Quadric q ; // create one quadric quadric[d] = q ; // per vertex vMark.mark(d) ; } } DartMarker mark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!mark.isMarked(d)) { Dart d1 = m.phi1(d) ; // for each triangle, Dart d_1 = m.phi_1(d) ; // initialize the quadric of the triangle Utils::Quadric q(this->m_position[d], this->m_position[d1], this->m_position[d_1]) ; quadric[d] += q ; // and add the contribution of quadric[d1] += q ; // this quadric to the ones quadric[d_1] += q ; // of the 3 incident vertices mark.markOrbit(d) ; } } CellMarker eMark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!eMark.isMarked(d)) { initEdgeInfo(d) ; // init the edges with their optimal position eMark.mark(d) ; // 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_QEM::nextEdge(Dart& d) { if(cur == edges.end() || edges.empty()) return false ; d = (*cur).second ; return true ; } template void EdgeSelector_QEM::updateBeforeCollapse(Dart d) { typename PFP::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 concerned edges 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) ; } tmpQ.zero() ; // compute quadric for the new tmpQ += quadric[d] ; // vertex as the sum of those tmpQ += quadric[dd] ; // of the contracted vertices } template void EdgeSelector_QEM::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::MAP& m = this->m_map ; quadric[d2] = tmpQ ; Dart vit = d2 ; do { updateEdgeInfo(m.phi1(vit), false) ; // 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 // treating differently : 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, false) ; updateEdgeInfo(m.phi1(vit2), false) ; vit2 = m.phi12(vit2) ; } while(vit2 != stop) ; } else updateEdgeInfo(vit, true) ; vit = m.phi2_1(vit) ; } while(vit != d2) ; cur = edges.begin() ; // set the current edge to the first one } template void EdgeSelector_QEM::updateWithoutCollapse() { EdgeInfo& einfo = edgeInfo[(*cur).second] ; einfo.valid = false ; edges.erase(einfo.it) ; //edges.erase(cur) ; cur = edges.begin(); } template void EdgeSelector_QEM::initEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo einfo ; if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; edgeInfo[d] = einfo ; } template void EdgeSelector_QEM::updateEdgeInfo(Dart d, bool recompute) { typename PFP::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_QEM::computeEdgeInfo(Dart d, EdgeInfo& einfo) { typename PFP::MAP& m = this->m_map ; Dart dd = m.phi2(d) ; Utils::Quadric quad ; quad += quadric[d] ; // compute the sum of the quad += quadric[dd] ; // two vertices quadrics m_positionApproximator->approximate(d) ; REAL err = quad(m_positionApproximator->getApprox(d)) ; einfo.it = edges.insert(std::make_pair(err, d)) ; einfo.valid = true ; } /************************************************************************************ * QUADRIC ERROR METRIC (Memoryless version) * ************************************************************************************/ template bool EdgeSelector_QEMml::init() { typename PFP::MAP& m = this->m_map ; bool ok = false ; for(typename std::vector*>::iterator it = this->m_approximators.begin(); it != this->m_approximators.end() && !ok; ++it) { if((*it)->getApproximatedAttributeName() == "position") { assert((*it)->getType() != A_hQEM || !"Approximator(hQEM) and selector (EdgeSelector_QEMml) are not compatible") ; assert((*it)->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (EdgeSelector_QEMml) are not compatible") ; assert((*it)->getType() != A_Lightfield || !"Approximator(hLightfield) and selector (EdgeSelector_QEMml) are not compatible") ; m_positionApproximator = reinterpret_cast* >(*it) ; ok = true ; } } if(!ok) return false ; edges.clear() ; CellMarker vMark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!vMark.isMarked(d)) { Utils::Quadric q ; // create one quadric quadric[d] = q ; // per vertex vMark.mark(d) ; } } DartMarker mark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!mark.isMarked(d)) { Dart d1 = m.phi1(d) ; // for each triangle, Dart d_1 = m.phi_1(d) ; // initialize the quadric of the triangle Utils::Quadric q(this->m_position[d], this->m_position[d1], this->m_position[d_1]) ; quadric[d] += q ; // and add the contribution of quadric[d1] += q ; // this quadric to the ones quadric[d_1] += q ; // of the 3 incident vertices mark.markOrbit(d) ; } } CellMarker eMark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!eMark.isMarked(d)) { initEdgeInfo(d) ; // init the edges with their optimal position eMark.mark(d) ; // 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_QEMml::nextEdge(Dart& d) { if(cur == edges.end() || edges.empty()) return false ; d = (*cur).second ; return true ; } template void EdgeSelector_QEMml::updateBeforeCollapse(Dart d) { typename PFP::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 concerned edges 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_QEMml::recomputeQuadric(const Dart d, const bool recomputeNeighbors) { Dart dFront,dBack ; Dart dInit = d ; // Init Front dFront = dInit ; 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 quadric[d] += Utils::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_QEMml::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::MAP& m = this->m_map ; // for local vertex and neighbors 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_QEMml::updateWithoutCollapse() { EdgeInfo& einfo = edgeInfo[(*cur).second] ; einfo.valid = false ; edges.erase(einfo.it) ; //edges.erase(cur) ; cur = edges.begin(); } template void EdgeSelector_QEMml::initEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo einfo ; if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; edgeInfo[d] = einfo ; } template void EdgeSelector_QEMml::updateEdgeInfo(Dart d, bool recompute) { typename PFP::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_QEMml::computeEdgeInfo(Dart d, EdgeInfo& einfo) { typename PFP::MAP& m = this->m_map ; Dart dd = m.phi2(d) ; Utils::Quadric quad ; quad += quadric[d] ; // compute the sum of the quad += quadric[dd] ; // two vertices quadrics m_positionApproximator->approximate(d) ; REAL err = quad(m_positionApproximator->getApprox(d)) ; einfo.it = edges.insert(std::make_pair(err, d)) ; einfo.valid = true ; } /************************************************************************************ * Metric based on Face Normal and Area deviation * ************************************************************************************/ template bool EdgeSelector_NormalArea::init() { typename PFP::MAP& m = this->m_map ; bool ok = false ; for(typename std::vector*>::iterator it = this->m_approximators.begin(); it != this->m_approximators.end() && !ok; ++it) { if((*it)->getApproximatedAttributeName() == "position") { // assert((*it)->getType() == A_MidEdge || (*it)->getType() == A_NormalArea || !"Only MidEdge and NormalArea Approximator are valid") ; m_positionApproximator = reinterpret_cast* >(*it) ; ok = true ; } } if(!ok) return false ; edges.clear() ; TraversorE travE(m); for(Dart dit = travE.begin() ; dit != travE.end() ; dit = travE.next()) { computeEdgeMatrix(dit); // const VEC3 e = Algo::Geometry::vectorOutOfDart(m, dit, this->m_position) ; // edgeMatrix[dit].identity(); // edgeMatrix[dit] *= e.norm2(); // edgeMatrix[dit] -= Geom::transposed_vectors_mult(e,e) ; } for(Dart dit = travE.begin() ; dit != travE.end() ; dit = travE.next()) { initEdgeInfo(dit) ; // init "edgeInfo" and "edges" } cur = edges.begin() ; // init the current edge to the first one return true ; } template bool EdgeSelector_NormalArea::nextEdge(Dart& d) { if(cur == edges.end() || edges.empty()) return false ; d = (*cur).second ; return true ; } template void EdgeSelector_NormalArea::updateBeforeCollapse(Dart d) { typename PFP::MAP& m = this->m_map ; assert(!m.isBoundaryEdge(d)); EdgeInfo* edgeE = &(edgeInfo[d]) ; if(edgeE->valid) { edges.erase(edgeE->it) ; edgeE->valid = false; } edgeE = &(edgeInfo[m.phi1(d)]) ; if(edgeE->valid) // remove all { edges.erase(edgeE->it) ; edgeE->valid = false; } edgeE = &(edgeInfo[m.phi_1(d)]) ; // the concerned edges if(edgeE->valid) { edges.erase(edgeE->it) ; edgeE->valid = false; } // from the multimap Dart dd = m.phi2(d) ; edgeE = &(edgeInfo[m.phi1(dd)]) ; if(edgeE->valid) { edges.erase(edgeE->it) ; edgeE->valid = false; } edgeE = &(edgeInfo[m.phi_1(dd)]) ; if(edgeE->valid) { edges.erase(edgeE->it) ; edgeE->valid = false; } } template void EdgeSelector_NormalArea::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::MAP& m = this->m_map ; // update the edge matrices Traversor2VE te (m,d2); for(Dart dit = te.begin() ; dit != te.end() ; dit = te.next()) { computeEdgeMatrix(dit); } // update the multimap Traversor2VVaE tv (m,d2); CellMarker eMark (m); for(Dart dit = tv.begin() ; dit != tv.end() ; dit = tv.next()) { Traversor2VE te2 (m,dit); for(Dart dit2 = te2.begin() ; dit2 != te2.end() ; dit2 = te2.next()) { if (!eMark.isMarked(dit2)) { updateEdgeInfo(dit2) ; eMark.mark(dit2); } } } cur = edges.begin() ; // set the current edge to the first one } template void EdgeSelector_NormalArea::initEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo einfo ; if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; edgeInfo[d] = einfo ; } template void EdgeSelector_NormalArea::updateEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo& einfo = edgeInfo[d] ; if(einfo.valid) edges.erase(einfo.it) ; // remove the edge from the multimap if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; } template void EdgeSelector_NormalArea::computeEdgeInfo(Dart d, EdgeInfo& einfo) { typename PFP::MAP& m = this->m_map ; Dart dd = m.phi2(d); Geom::Matrix33f M1; // init zero included Geom::Matrix33f M2; // init zero included assert(! m.isBoundaryEdge(d)); Traversor2VF td (m,d); Dart it = td.begin(); it = td.next(); Dart it2 = td.next(); while( it2 != td.end()) { M1 += edgeMatrix[m.phi1(it)]; it = it2; it2 = td.next(); } Traversor2VF tdd (m,dd); it = tdd.begin(); it = tdd.next(); it2 = tdd.next(); while( it2 != tdd.end()) { M2 += edgeMatrix[m.phi1(it)]; it = it2; it2 = tdd.next(); } m_positionApproximator->approximate(d) ; const VEC3& a = m_positionApproximator->getApprox(d) ; const VEC3 av1 = a - this->m_position[d] ; const VEC3 av2 = a - this->m_position[dd] ; REAL err = av1 * (M1 * av1) + av2 * (M2 * av2); /* // TODO : test to normalize by area // TODO : not border-safe REAL area = 0.0; Traversor2EEaV ta (m,d); for (Dart dita = ta.begin(); dita != ta.end(); dita=ta.next()) { area += Algo::Geometry::triangleArea(m,dita,this->m_position); } err /= area ; // résultats sensiblment identiques à ceux sans pris en compte de l'aire. // err /= area*area ; // ca favorise la contraction des gros triangles : maillages très in-homogènes et qualité géométrique mauvaise */ einfo.it = edges.insert(std::make_pair(err, d)) ; einfo.valid = true ; } template void EdgeSelector_NormalArea::computeEdgeMatrix(Dart d) { const typename PFP::VEC3 e = Algo::Geometry::vectorOutOfDart(this->m_map, d, this->m_position) ; edgeMatrix[d].identity(); edgeMatrix[d] *= e.norm2(); edgeMatrix[d] -= Geom::transposed_vectors_mult(e,e) ; // TODO : test : try to normalize by area // edgeMatrix[d] /= e.norm2(); // pas d'amélioration significative par rapport à la version sans normalisation // edgeMatrix[d] /= e.norm2() * e.norm2(); // étonnament bon : sur certains maillages équivalant à la QEMml } /************************************************************************************ * CURVATURE * ************************************************************************************/ template bool EdgeSelector_Curvature::init() { typename PFP::MAP& m = this->m_map ; bool ok = false ; for(typename std::vector*>::iterator it = this->m_approximators.begin(); it != this->m_approximators.end() && !ok; ++it) { if((*it)->getApproximatedAttributeName() == "position") { assert((*it)->getType() != A_hQEM || !"Approximator(hQEM) and selector (EdgeSelector_Curvature) are not compatible") ; assert((*it)->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (EdgeSelector_Curvature) are not compatible") ; assert((*it)->getType() != A_Lightfield || !"Approximator(hLightfield) and selector (EdgeSelector_Curvature) are not compatible") ; m_positionApproximator = reinterpret_cast* >(*it) ; ok = true ; } } if(!ok) return false ; edges.clear() ; CellMarker eMark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!eMark.isMarked(d)) { initEdgeInfo(d) ; // init the edges with their optimal position eMark.mark(d) ; // 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_Curvature::nextEdge(Dart& d) { if(cur == edges.end() || edges.empty()) return false ; d = (*cur).second ; return true ; } template void EdgeSelector_Curvature::updateBeforeCollapse(Dart d) { typename PFP::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 concerned edges 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) ; } } template void EdgeSelector_Curvature::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::MAP& m = this->m_map ; normal[d2] = Algo::Geometry::vertexNormal(m, d2, this->m_position) ; Algo::Geometry::computeCurvatureVertex_NormalCycles(m, d2, radius, this->m_position, normal, edgeangle, kmax, kmin, Kmax, Kmin, Knormal) ; Dart vit = d2 ; do { Dart nVert = m.phi1(vit) ; normal[nVert] = Algo::Geometry::vertexNormal(m, nVert, this->m_position) ; Algo::Geometry::computeCurvatureVertex_NormalCycles(m, nVert, radius, this->m_position, normal, edgeangle, kmax, kmin, Kmax, Kmin, Knormal) ; updateEdgeInfo(m.phi1(vit), false) ; // 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 // treating differently : 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, false) ; updateEdgeInfo(m.phi1(vit2), false) ; vit2 = m.phi12(vit2) ; } while(vit2 != stop) ; } else updateEdgeInfo(vit, true) ; vit = m.phi2_1(vit) ; } while(vit != d2) ; cur = edges.begin() ; // set the current edge to the first one } template void EdgeSelector_Curvature::updateWithoutCollapse() { EdgeInfo& einfo = edgeInfo[(*cur).second] ; einfo.valid = false ; edges.erase(einfo.it) ; //edges.erase(cur) ; cur = edges.begin(); } template void EdgeSelector_Curvature::initEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo einfo ; if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; edgeInfo[d] = einfo ; } template void EdgeSelector_Curvature::updateEdgeInfo(Dart d, bool recompute) { typename PFP::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_Curvature::computeEdgeInfo(Dart d, EdgeInfo& einfo) { typename PFP::MAP& m = this->m_map ; Dart dd = m.phi2(d) ; unsigned int v1 = m.template getEmbedding(d) ; unsigned int v2 = m.template getEmbedding(dd) ; m_positionApproximator->approximate(d) ; // temporary edge collapse Dart d2 = m.phi2(m.phi_1(d)) ; Dart dd2 = m.phi2(m.phi_1(dd)) ; m.extractTrianglePair(d) ; unsigned int newV = m.template setOrbitEmbeddingOnNewCell(d2) ; this->m_position[newV] = m_positionApproximator->getApprox(d) ; // compute things on the coarse version of the mesh normal[newV] = Algo::Geometry::vertexNormal(m, d2, this->m_position) ; Algo::Geometry::computeCurvatureVertex_NormalCycles(m, d2, radius, this->m_position, normal, edgeangle, kmax, kmin, Kmax, Kmin, Knormal) ; // VEC3 norm = normal[newV] ; REAL mCurv = (kmax[newV] + kmin[newV]) / REAL(2) ; // VEC3 cDir1 = Kmax[newV] ; // vertex split to reset the initial connectivity and embeddings m.insertTrianglePair(d, d2, dd2) ; m.template setOrbitEmbedding(d, v1) ; m.template setOrbitEmbedding(dd, v2) ; REAL err = 0 ; // REAL norm_deviation_1 = REAL(1) / abs(norm * normal[v1]) ; // REAL norm_deviation_2 = REAL(1) / abs(norm * normal[v2]) ; // err += norm_deviation_1 + norm_deviation_2 ; REAL mCurv_deviation_1 = abs(mCurv - (kmax[v1] + kmin[v1] / REAL(2))) ; REAL mCurv_deviation_2 = abs(mCurv - (kmax[v2] + kmin[v2] / REAL(2))) ; err += mCurv_deviation_1 + mCurv_deviation_2 ; // REAL cDir1_deviation_1 = REAL(1) / abs(cDir1 * Kmax[v1]) ; // REAL cDir1_deviation_2 = REAL(1) / abs(cDir1 * Kmax[v2]) ; // err += cDir1_deviation_1 + cDir1_deviation_2 ; einfo.it = edges.insert(std::make_pair(err, d)) ; einfo.valid = true ; } /************************************************************************************ * CURVATURE TENSOR * ************************************************************************************/ template bool EdgeSelector_CurvatureTensor::init() { typename PFP::MAP& m = this->m_map ; bool ok = false ; for(typename std::vector*>::iterator it = this->m_approximators.begin(); it != this->m_approximators.end() && !ok; ++it) { if((*it)->getApproximatedAttributeName() == "position") { assert((*it)->getType() == A_MidEdge || !"Only MidEdge Approximator is valid") ; m_positionApproximator = reinterpret_cast* >(*it) ; ok = true ; } } if(!ok) return false ; edges.clear() ; TraversorE travE(m); // for(Dart dit = travE.begin() ; dit != travE.end() ; dit = travE.next()) // { // computeEdgeMatrix(dit); // } for(Dart dit = travE.begin() ; dit != travE.end() ; dit = travE.next()) { initEdgeInfo(dit) ; // init "edgeInfo" and "edges" } cur = edges.begin() ; // init the current edge to the first one return true ; } template bool EdgeSelector_CurvatureTensor::nextEdge(Dart& d) { if(cur == edges.end() || edges.empty()) return false ; d = (*cur).second ; return true ; } template void EdgeSelector_CurvatureTensor::updateBeforeCollapse(Dart d) { typename PFP::MAP& m = this->m_map ; assert(!m.isBoundaryEdge(d)); EdgeInfo* edgeE = &(edgeInfo[d]) ; if(edgeE->valid) { edges.erase(edgeE->it) ; edgeE->valid = false; } edgeE = &(edgeInfo[m.phi1(d)]) ; if(edgeE->valid) // remove all { edges.erase(edgeE->it) ; edgeE->valid = false; } edgeE = &(edgeInfo[m.phi_1(d)]) ; // the concerned edges if(edgeE->valid) { edges.erase(edgeE->it) ; edgeE->valid = false; } // from the multimap Dart dd = m.phi2(d) ; edgeE = &(edgeInfo[m.phi1(dd)]) ; if(edgeE->valid) { edges.erase(edgeE->it) ; edgeE->valid = false; } edgeE = &(edgeInfo[m.phi_1(dd)]) ; if(edgeE->valid) { edges.erase(edgeE->it) ; edgeE->valid = false; } } template void EdgeSelector_CurvatureTensor::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::MAP& m = this->m_map ; CellMarkerStore eMark (m); // update edge angles Traversor2VF tf (m,d2); for(Dart dit = tf.begin(); dit != tf.end(); dit = tf.next()) { Traversor2FE te (m,dit); for(Dart dit2 = te.begin(); dit2 != te.end(); dit2=te.next()) { if (!eMark.isMarked(dit2)) { edgeangle[dit2] = Algo::Geometry::computeAngleBetweenNormalsOnEdge(m, dit2, this->m_position) ; eMark.mark(dit2); } } } // update the multimap Traversor2VVaE tv (m,d2); eMark.unmarkAll(); for(Dart dit = tv.begin() ; dit != tv.end() ; dit = tv.next()) { Traversor2VE te2 (m,dit); for(Dart dit2 = te2.begin() ; dit2 != te2.end() ; dit2 = te2.next()) { if (!eMark.isMarked(dit2)) { updateEdgeInfo(dit2) ; eMark.mark(dit2); } } } cur = edges.begin() ; // set the current edge to the first one } template void EdgeSelector_CurvatureTensor::initEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo einfo ; if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; edgeInfo[d] = einfo ; } template void EdgeSelector_CurvatureTensor::updateEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo& einfo = edgeInfo[d] ; if(einfo.valid) edges.erase(einfo.it) ; // remove the edge from the multimap if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; } template void EdgeSelector_CurvatureTensor::computeEdgeInfo(Dart d, EdgeInfo& einfo) { typedef Geom::Matrix<3,3,REAL> MATRIX; // typedef Eigen::Matrix E_VEC3; typedef Eigen::Matrix E_MATRIX; typename PFP::MAP& m = this->m_map ; Dart dd = m.phi2(d) ; unsigned int v1 = m.template getEmbedding(d) ; unsigned int v2 = m.template getEmbedding(dd) ; m_positionApproximator->approximate(d) ; // compute tensor before collapse MATRIX tens1; Algo::Selection::Collector_OneRing_AroundEdge col1 (m); col1.collectAll(d); col1.computeNormalCyclesTensor(this->m_position,edgeangle,tens1); // edgeangle is up to date here tens1 *= col1.computeArea(this->m_position); // mean tensor * area = integral of the tensor Algo::Geometry::normalCycles_SortTensor(tens1); // temporary edge collapse Dart d2 = m.phi2(m.phi_1(d)) ; Dart dd2 = m.phi2(m.phi_1(dd)) ; m.extractTrianglePair(d) ; const unsigned int newV = m.template setOrbitEmbeddingOnNewCell(d2) ; this->m_position[newV] = m_positionApproximator->getApprox(d) ; // compute tensor after collapse MATRIX tens2; Algo::Selection::Collector_OneRing col2 (m); col2.collectAll(d); col2.computeNormalCyclesTensor(this->m_position,tens2); // edgeangle is not up to date here tens2 *= col2.computeArea(this->m_position); // mean tensor * area = integral of the tensor Algo::Geometry::normalCycles_SortTensor(tens2); // vertex split to reset the initial connectivity and embeddings m.insertTrianglePair(d, d2, dd2) ; m.template setOrbitEmbedding(d, v1) ; m.template setOrbitEmbedding(dd, v2) ; // compute err from the tensors tens1 -= tens2; Eigen::SelfAdjointEigenSolver solver (Utils::convertRef(tens1),Eigen::EigenvaluesOnly); const VEC3& e_val = Utils::convertRef(solver.eigenvalues()); REAL err = std::max(std::max(abs(e_val[0]), abs(e_val[1])) , abs(e_val[2])) ; // if (v1 % 5000 == 0) CGoGNout << e_val << CGoGNendl << err << CGoGNendl ; // update the priority queue and edgeinfo einfo.it = edges.insert(std::make_pair(err, d)) ; einfo.valid = true ; } /************************************************************************************ * MIN DETAIL * ************************************************************************************/ template bool EdgeSelector_MinDetail::init() { MAP& m = this->m_map ; bool ok = false ; for(typename std::vector*>::iterator it = this->m_approximators.begin(); it != this->m_approximators.end() && !ok; ++it) { if((*it)->getApproximatedAttributeName() == "position" && (*it)->getPredictor()) { assert((*it)->getType() != A_hQEM || !"Approximator(hQEM) and selector (EdgeSelector_MinDetail) are not compatible") ; assert((*it)->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (EdgeSelector_MinDetail) are not compatible") ; assert((*it)->getType() != A_Lightfield || !"Approximator(hLightfield) and selector (EdgeSelector_MinDetail) are not compatible") ; m_positionApproximator = reinterpret_cast* >(*it) ; ok = true ; } } if(!ok) return false ; edges.clear() ; TraversorE travE(m); for(Dart dit = travE.begin() ; dit != travE.end() ; dit = travE.next()) { initEdgeInfo(dit); } cur = edges.begin() ; // init the current edge to the first one return true ; } template bool EdgeSelector_MinDetail::nextEdge(Dart& d) { if(cur == edges.end() || edges.empty()) return false ; d = (*cur).second ; return true ; } template void EdgeSelector_MinDetail::updateBeforeCollapse(Dart d) { typename PFP::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 concerned edges 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) ; } } template void EdgeSelector_MinDetail::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::MAP& m = this->m_map ; Dart vit = d2 ; do { updateEdgeInfo(m.phi1(vit), false) ; // 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 // treating differently : 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, false) ; updateEdgeInfo(m.phi1(vit2), false) ; vit2 = m.phi12(vit2) ; } while(vit2 != stop) ; } else updateEdgeInfo(vit, true) ; vit = m.phi2_1(vit) ; } while(vit != d2) ; cur = edges.begin() ; // set the current edge to the first one } template void EdgeSelector_MinDetail::updateWithoutCollapse() { EdgeInfo& einfo = edgeInfo[(*cur).second] ; einfo.valid = false ; edges.erase(einfo.it) ; //edges.erase(cur) ; cur = edges.begin(); } template void EdgeSelector_MinDetail::initEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo einfo ; if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; edgeInfo[d] = einfo ; } template void EdgeSelector_MinDetail::updateEdgeInfo(Dart d, bool recompute) { typename PFP::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_MinDetail::computeEdgeInfo(Dart d, EdgeInfo& einfo) { // Dart dd = this->m_map.phi2(d) ; REAL err = REAL(0) ; // for(typename std::vector*>::iterator it = this->m_approximators.begin(); // it != this->m_approximators.end(); // ++it) // { // if((*it)->getPredictor()) // { // (*it)->approximate(d) ; // err += (*it)->detailMagnitude(d) ; // } // } m_positionApproximator->approximate(d) ; err = m_positionApproximator->getDetail(d).norm2() ; einfo.it = edges.insert(std::make_pair(err, d)) ; einfo.valid = true ; } /************************************************************************************ * EDGESELECTOR COLOR PER VERTEX * ************************************************************************************/ template bool EdgeSelector_ColorNaive::init() { typename PFP::MAP& m = this->m_map ; // Verify availability of required approximators unsigned int ok = 0 ; for (unsigned int approxindex = 0 ; approxindex < this->m_approximators.size() ; ++approxindex) { assert(this->m_approximators[approxindex]->getType() != A_hQEM || !"Approximator(hQEM) and selector (ColorNaive) are not compatible") ; assert(this->m_approximators[approxindex]->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (ColorNaive) are not compatible") ; assert(this->m_approximators[approxindex]->getType() != A_Lightfield || !"Approximator(hLightfield) and selector (ColorNaive) are not compatible") ; bool saved = false ; for (unsigned int attrindex = 0 ; attrindex < this->m_approximators[approxindex]->getNbApproximated() ; ++ attrindex) { // constraint : 2 approximators in specific order if(ok == 0 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == "position") { ++ok ; m_approxindex_pos = approxindex ; m_attrindex_pos = attrindex ; m_pos = this->m_position ; if (!saved) { m_approx.push_back(reinterpret_cast* >(this->m_approximators[approxindex])) ; saved = true ; } } else if(ok == 1 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == "color") { ++ok ; m_approxindex_color = approxindex ; m_attrindex_color = attrindex ; m_color = m.template getAttribute("color") ; assert(m_color.isValid() || !"EdgeSelector_ColorNaive: color attribute is not valid") ; if (!saved) { m_approx.push_back(reinterpret_cast* >(this->m_approximators[approxindex])) ; saved = true ; } } } } if(ok != 2) return false ; TraversorV travV(m); for(Dart dit = travV.begin() ; dit != travV.end() ; dit = travV.next()) { Utils::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 Utils::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) { typename PFP::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] += Utils::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) { typename PFP::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) { typename PFP::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) { typename PFP::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) { typename PFP::MAP& m = this->m_map ; Dart dd = m.phi1(d) ; // New position Utils::Quadric quad ; quad += m_quadric[d] ; // compute the sum of the quad += m_quadric[dd] ; // two vertices quadrics // compute all approximated attributes for(typename std::vector*>::iterator it = this->m_approximators.begin() ; it != this->m_approximators.end() ; ++it) { (*it)->approximate(d) ; } // get pos const VEC3& newPos = this->m_approx[m_approxindex_pos]->getApprox(d,m_attrindex_pos) ; // get newPos // get col const VEC3& newCol = this->m_approx[m_approxindex_color]->getApprox(d,m_attrindex_color) ; // get newPos // compute error VEC3 colDiff1 = newCol ; VEC3 colDiff2 = newCol ; colDiff1 -= m_color[d] ; colDiff2 -= m_color[dd] ; const VEC3& colDiff = colDiff1 + colDiff2 ; // sum of QEM metric and squared difference between new color and old colors REAL err = quad(newPos) + colDiff.norm() ; einfo.it = edges.insert(std::make_pair(err, d)) ; einfo.valid = true ; } /************************************************************************************ * EDGESELECTOR QEMext for Color * ************************************************************************************/ template bool EdgeSelector_QEMextColor::init() { typename PFP::MAP& m = this->m_map ; // Verify availability of required approximators unsigned int ok = 0 ; for (unsigned int approxindex = 0 ; approxindex < this->m_approximators.size() ; ++approxindex) { assert(this->m_approximators[approxindex]->getType() != A_hQEM || !"Approximator(hQEM) and selector (EdgeSelector_QEMextColor) are not compatible") ; assert(this->m_approximators[approxindex]->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (EdgeSelector_QEMextColor) are not compatible") ; assert(this->m_approximators[approxindex]->getType() != A_hLightfieldHalf || !"Approximator(hLightfieldHalf) and selector (EdgeSelector_QEMextColor) are not compatible") ; bool saved = false ; for (unsigned int attrindex = 0 ; attrindex < this->m_approximators[approxindex]->getNbApproximated() ; ++ attrindex) { // constraint : 2 approximators in specific order if(ok == 0 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == "position") { ++ok ; m_approxindex_pos = approxindex ; m_attrindex_pos = attrindex ; m_pos = this->m_position ; if (!saved) { m_approx.push_back(reinterpret_cast* >(this->m_approximators[approxindex])) ; saved = true ; } } else if(ok == 1 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == "color") { ++ok ; m_approxindex_color = approxindex ; m_attrindex_color = attrindex ; m_color = m.template getAttribute("color") ; assert(m_color.isValid() || !"EdgeSelector_QEMextColor: color attribute is not valid") ; if (!saved) { m_approx.push_back(reinterpret_cast* >(this->m_approximators[approxindex])) ; saved = true ; } } } } if(ok != 2) return false ; TraversorV travV(m); for(Dart dit = travV.begin() ; dit != travV.end() ; dit = travV.next()) { Utils::QuadricNd 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 VEC6 p0, p1, p2 ; for (unsigned int i = 0 ; i < 3 ; ++i) { p0[i] = this->m_position[dit][i] ; p0[i+3] = this->m_color[dit][i] ; p1[i] = this->m_position[d1][i] ; p1[i+3] = this->m_color[d1][i] ; p2[i] = this->m_position[d_1][i] ; p2[i+3] = this->m_color[d_1][i] ; } Utils::QuadricNd q(p0,p1,p2) ; 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 } edges.clear() ; 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_QEMextColor::nextEdge(Dart& d) { if(cur == edges.end() || edges.empty()) return false ; d = (*cur).second ; return true ; } template void EdgeSelector_QEMextColor::updateBeforeCollapse(Dart d) { typename PFP::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_QEMextColor::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 Dart d2 = this->m_map.phi2(dFront) ; VEC6 p0, p1, p2 ; for (unsigned int i = 0 ; i < 3 ; ++i) { p0[i] = this->m_position[d][i] ; p0[i+3] = this->m_color[d][i] ; p1[i] = this->m_position[d2][i] ; p1[i+3] = this->m_color[d2][i] ; p2[i] = this->m_position[dBack][i] ; p2[i+3] = this->m_color[dBack][i] ; } m_quadric[d] += Utils::QuadricNd(p0,p1,p2) ; } if (recomputeNeighbors) recomputeQuadric(dBack, false) ; } while(dFront != dInit) ; } template void EdgeSelector_QEMextColor::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::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_QEMextColor::initEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo einfo ; if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; edgeInfo[d] = einfo ; } template void EdgeSelector_QEMextColor::updateEdgeInfo(Dart d, bool recompute) { typename PFP::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_QEMextColor::computeEdgeInfo(Dart d, EdgeInfo& einfo) { typename PFP::MAP& m = this->m_map ; Dart dd = m.phi1(d) ; // New position Utils::QuadricNd quad ; quad += m_quadric[d] ; // compute the sum of the quad += m_quadric[dd] ; // two vertices quadrics // compute all approximated attributes for(typename std::vector*>::iterator it = this->m_approximators.begin() ; it != this->m_approximators.end() ; ++it) { (*it)->approximate(d) ; } // get pos const VEC3& newPos = this->m_approx[m_approxindex_pos]->getApprox(d,m_attrindex_pos) ; // get newPos // get col const VEC3& newCol = this->m_approx[m_approxindex_color]->getApprox(d,m_attrindex_color) ; // get newCol // compute error VEC6 newEmb ; for (unsigned int i = 0 ; i < 3 ; ++i) { newEmb[i] = newPos[i] ; newEmb[i+3] = newCol[i] ; } const REAL& err = quad(newEmb) ; // Check if errated values appear if (err < -1e-6) einfo.valid = false ; else { einfo.it = edges.insert(std::make_pair(std::max(err,REAL(0)), d)) ; einfo.valid = true ; } } /***************************************************************************************************************** * LIGHTFIELD QUADRIC ERROR METRIC * *****************************************************************************************************************/ template bool EdgeSelector_Lightfield::init() { typename PFP::MAP& m = this->m_map ; // Verify availability of required approximators unsigned int ok = 0 ; for (unsigned int approxindex = 0 ; approxindex < this->m_approximators.size() ; ++approxindex) { assert(this->m_approximators[approxindex]->getType() != A_hQEM || !"Approximator(hQEM) and selector (EdgeSelector_Lightfield) are not compatible") ; assert(this->m_approximators[approxindex]->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (EdgeSelector_Lightfield) are not compatible") ; assert(this->m_approximators[approxindex]->getType() != A_hLightfieldHalf || !"Approximator(hLightfieldHalf) and selector (EdgeSelector_Lightfield) are not compatible") ; unsigned int k = 0 ; bool saved = false ; for (unsigned int attrindex = 0 ; attrindex < this->m_approximators[approxindex]->getNbApproximated() ; ++ attrindex) { // constraint : 2 approximators in specific order if(ok == 0 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == "position") { ++ok ; m_approxindex_pos = approxindex ; m_attrindex_pos = attrindex ; m_pos = this->m_position ; if (!saved) { m_approx.push_back(reinterpret_cast* >(this->m_approximators[approxindex])) ; saved = true ; } } else if(ok == 1 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == "frameT") { ++ok ; // m_approxindex_FT = approxindex ; // m_attrindex_FT = attrindex ; m_frameT = m.template getAttribute("frameT") ; if (!saved) { m_approx.push_back(reinterpret_cast* >(this->m_approximators[approxindex])) ; assert(m_frameT.isValid() || !"EdgeSelector_QEMextColor: frameT attribute is not valid") ; saved = true ; } } else if(ok == 2 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == "frameB") { ++ok ; // m_approxindex_FB = approxindex ; // m_attrindex_FB = attrindex ; m_frameB = m.template getAttribute("frameB") ; assert(m_frameB.isValid() || !"EdgeSelector_QEMextColor: frameB attribute is not valid") ; if (!saved) { m_approx.push_back(reinterpret_cast* >(this->m_approximators[approxindex])) ; saved = true ; } } else if(ok == 3 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == "frameN") { ++ok ; m_approxindex_FN = approxindex ; m_attrindex_FN = attrindex ; m_frameN = m.template getAttribute("frameN") ; assert(m_frameN.isValid() || !"EdgeSelector_QEMextColor: frameN attribute is not valid") ; if (!saved) { m_approx.push_back(reinterpret_cast* >(this->m_approximators[approxindex])) ; saved = true ; } } else { std::stringstream s ; s << "PBcoefs" << k ; if(ok > 3 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == s.str().c_str()) { ++ok ; m_HF.push_back(m.template getAttribute(s.str().c_str())) ; if (m_HF[k++].isValid()) { m_approxindex_HF.push_back(approxindex) ; m_attrindex_HF.push_back(attrindex) ; if (!saved) { m_approx.push_back(reinterpret_cast* >(this->m_approximators[approxindex])) ; saved = true ; } } } } } m_K = k ; } if(ok < 5) return false ; TraversorV travV(m); for(Dart dit = travV.begin() ; dit != travV.end() ; dit = travV.next()) { Utils::Quadric q ; // create one quadric m_quadricGeom[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 Utils::Quadric q(this->m_position[dit], this->m_position[d1], this->m_position[d_1]) ; m_quadricGeom[dit] += q ; // and add the contribution of m_quadricGeom[d1] += q ; // this quadric to the ones m_quadricGeom[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_Lightfield::nextEdge(Dart& d) { if(cur == edges.end() || edges.empty()) return false ; d = (*cur).second ; return true ; } template void EdgeSelector_Lightfield::updateBeforeCollapse(Dart d) { typename PFP::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_Lightfield::recomputeQuadric(const Dart d, const bool recomputeNeighbors) { Dart dFront,dBack ; Dart dInit = d ; // Init Front dFront = dInit ; m_quadricGeom[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_quadricGeom[d] += Utils::Quadric(m_pos[d],m_pos[this->m_map.phi1(dFront)],m_pos[dBack]) ; } if (recomputeNeighbors) recomputeQuadric(dBack, false) ; } while(dFront != dInit) ; } template void EdgeSelector_Lightfield::updateAfterCollapse(Dart d2, Dart dd2) { typename PFP::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_Lightfield::initEdgeInfo(Dart d) { typename PFP::MAP& m = this->m_map ; EdgeInfo einfo ; if(m.edgeCanCollapse(d)) computeEdgeInfo(d, einfo) ; else einfo.valid = false ; edgeInfo[d] = einfo ; } template void EdgeSelector_Lightfield::updateEdgeInfo(Dart d, bool recompute) { typename PFP::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_Lightfield::computeEdgeInfo(Dart d, EdgeInfo& einfo) { typename PFP::MAP& m = this->m_map ; Dart dd = m.phi1(d) ; // New position Utils::Quadric quad ; quad += m_quadricGeom[d] ; // compute the sum of the quad += m_quadricGeom[dd] ; // two vertices quadrics // compute all approximated attributes for(typename std::vector*>::iterator it = this->m_approximators.begin() ; it != this->m_approximators.end() ; ++it) { (*it)->approximate(d) ; } // Get all approximated attributes // New position const VEC3& newPos = this->m_approx[m_approxindex_pos]->getApprox(d,m_attrindex_pos) ; // get newPos // New normal const VEC3& newFN = this->m_approx[m_approxindex_FN]->getApprox(d,m_attrindex_FN) ; // get new frameN // New function std::vector newHF ; newHF.resize(m_K) ; for (unsigned int k = 0 ; k < m_K ; ++k) newHF[k] = this->m_approx[m_approxindex_HF[k]]->getApprox(d,m_attrindex_HF[k]) ; // get newHFcoefsK // Compute errors // Position Utils::Quadric quadGeom ; quadGeom += m_quadricGeom[d] ; // compute the sum of the quadGeom += m_quadricGeom[dd] ; // two vertices quadrics // hemisphere difference error double scal1 = double(m_frameN[d] * newFN) ; double alpha1 = acos(std::max(std::min(scal1, double(1)),double(-1))) ; // for epsilon normalization of newFN errors // angle 2 double scal2 = double(m_frameN[dd] * newFN) ; double alpha2 = acos(std::max(std::min(scal2, double(1)),double(-1))) ; // for epsilon normalization of newFN errors double alpha = alpha1 + alpha2 ; assert(m_quadricHF.isValid() | !"EdgeSelector_Lightfield::computeEdgeInfo: quadricHF is not valid") ; Utils::QuadricHF quadHF = m_quadricHF[d] ; //std::cout << quadGeom(newPos) << " vs " << alpha/M_PI << " vs " << quadHF(newHF) << std::endl ; // sum of QEM metric and frame orientation difference const REAL& errG = quadGeom(newPos) ; // geom const REAL& errAngle = alpha / M_PI ; // frame const REAL& errLF = quadHF(newHF) ; // function coefficients // Check if errated values appear if (errG < -1e-6 || errAngle < -1e-6 || errLF < -1e-6) einfo.valid = false ; else { einfo.it = edges.insert(std::make_pair(std::max(errG + errAngle + errLF, REAL(0)), d)) ; einfo.valid = true ; } } } // namespace Decimation } // namespace Algo } // namespace CGoGN