/******************************************************************************* * 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 { /************************************************************************************ * QUADRIC ERROR METRIC (Memoryless version) * ************************************************************************************/ template bool HalfEdgeSelector_QEMml::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") { assert((*it)->getType() == A_hQEM || (*it)->getType() == A_hHalfCollapse || (*it)->getType() != A_Lightfield || !"Approximator for selector (HalfEdgeSelector_QEMml) must be of a half-edge approximator") ; m_positionApproximator = reinterpret_cast* >(*it) ; ok = true ; } } if(!ok) return false ; 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) ; } } // Init multimap for each Half-edge halfEdges.clear() ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { initHalfEdgeInfo(d) ; // init the edges with their optimal info } // and insert them in the multimap according to their error cur = halfEdges.begin() ; // init the current edge to the first one return true ; } template bool HalfEdgeSelector_QEMml::nextEdge(Dart& d) { if(cur == halfEdges.end() || halfEdges.empty()) return false ; d = (*cur).second ; return true ; } template void HalfEdgeSelector_QEMml::updateBeforeCollapse(Dart d) { MAP& m = this->m_map ; HalfEdgeInfo& edgeE = halfEdgeInfo[d] ; if(edgeE.valid) halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi1(d)] ; if(edgeE.valid) // remove all halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi_1(d)] ; // the halfedges that will disappear if(edgeE.valid) halfEdges.erase(edgeE.it) ; // from the multimap Dart dd = m.phi2(d) ; assert(dd != d) ; if(dd != d) { edgeE = halfEdgeInfo[dd] ; if(edgeE.valid) halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi1(dd)] ; if(edgeE.valid) halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi_1(dd)] ; if(edgeE.valid) halfEdges.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 HalfEdgeSelector_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.phi1(dFront) ; dFront = this->m_map.phi2_1(dFront) ; if (this->m_map.phi2(dFront) != dFront) { // if dFront is no border quadric[d] += Utils::Quadric(this->m_position[d],this->m_position[dBack],this->m_position[this->m_map.phi1(dFront)]) ; } if (recomputeNeighbors) recomputeQuadric(dBack, false) ; } while(dFront != dInit) ; } template void HalfEdgeSelector_QEMml::updateAfterCollapse(Dart d2, Dart dd2) { MAP& m = this->m_map ; recomputeQuadric(d2, true) ; Dart vit = d2 ; do { updateHalfEdgeInfo(vit, true) ; Dart d = m.phi2(vit) ; if (d != vit) ; updateHalfEdgeInfo(d, true) ; updateHalfEdgeInfo(m.phi1(vit), true) ; d = m.phi2(m.phi1(vit)) ; if (d != m.phi1(vit)) ; updateHalfEdgeInfo(d, true) ; Dart stop = m.phi2(vit) ; assert (stop != vit) ; Dart vit2 = m.phi12(m.phi1(vit)) ; do { updateHalfEdgeInfo(vit2, true) ; d = m.phi2(vit2) ; if (d != vit2) ; updateHalfEdgeInfo(d, true) ; updateHalfEdgeInfo(m.phi1(vit2), false) ; d = m.phi2(m.phi1(vit2)) ; if (d != m.phi1(vit2)) ; updateHalfEdgeInfo(d, false) ; vit2 = m.phi12(vit2) ; } while (stop != vit2) ; vit = m.phi2_1(vit) ; } while(vit != d2) ; cur = halfEdges.begin() ; // set the current edge to the first one } template void HalfEdgeSelector_QEMml::initHalfEdgeInfo(Dart d) { MAP& m = this->m_map ; HalfEdgeInfo heinfo ; if(m.edgeCanCollapse(d)) computeHalfEdgeInfo(d, heinfo) ; else heinfo.valid = false ; halfEdgeInfo[d] = heinfo ; } template void HalfEdgeSelector_QEMml::updateHalfEdgeInfo(Dart d, bool recompute) { MAP& m = this->m_map ; HalfEdgeInfo& heinfo = halfEdgeInfo[d] ; if(recompute) { if(heinfo.valid) halfEdges.erase(heinfo.it) ; // remove the edge from the multimap if(m.edgeCanCollapse(d)) computeHalfEdgeInfo(d, heinfo) ; else heinfo.valid = false ; } else { if(m.edgeCanCollapse(d)) { // if the edge can be collapsed now if(!heinfo.valid) // but it was not before computeHalfEdgeInfo(d, heinfo) ; } else { // if the edge cannot be collapsed now if(heinfo.valid) // and it was before { halfEdges.erase(heinfo.it) ; heinfo.valid = false ; } } } } template void HalfEdgeSelector_QEMml::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& heinfo) { MAP& m = this->m_map ; Dart dd = m.phi1(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)) ; heinfo.it = halfEdges.insert(std::make_pair(err, d)) ; heinfo.valid = true ; } /************************************************************************************ * EDGESELECTOR QEMext for Color * ************************************************************************************/ template bool HalfEdgeSelector_QEMextColor::init() { 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 || this->m_approximators[approxindex]->getType() == A_hHalfCollapse || this->m_approximators[approxindex]->getType() != A_Lightfield || !"Approximator for selector (HalfEdgeSelector_QEMextColor) must be of a half-edge approximator") ; 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 } // Init multimap for each Half-edge halfEdges.clear() ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { initHalfEdgeInfo(d) ; // init the edges with their optimal info } // and insert them in the multimap according to their error cur = halfEdges.begin() ; // init the current edge to the first one return true ; } template bool HalfEdgeSelector_QEMextColor::nextEdge(Dart& d) { if(cur == halfEdges.end() || halfEdges.empty()) return false ; d = (*cur).second ; return true ; } template void HalfEdgeSelector_QEMextColor::updateBeforeCollapse(Dart d) { MAP& m = this->m_map ; HalfEdgeInfo& edgeE = halfEdgeInfo[d] ; if(edgeE.valid) halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi1(d)] ; if(edgeE.valid) // remove all halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi_1(d)] ; // the halfedges that will disappear if(edgeE.valid) halfEdges.erase(edgeE.it) ; // from the multimap Dart dd = m.phi2(d) ; assert(dd != d) ; if(dd != d) { edgeE = halfEdgeInfo[dd] ; if(edgeE.valid) halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi1(dd)] ; if(edgeE.valid) halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi_1(dd)] ; if(edgeE.valid) halfEdges.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 HalfEdgeSelector_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 HalfEdgeSelector_QEMextColor::updateAfterCollapse(Dart d2, Dart dd2) { MAP& m = this->m_map ; recomputeQuadric(d2, true) ; Dart vit = d2 ; do { updateHalfEdgeInfo(vit, true) ; Dart d = m.phi2(vit) ; if (d != vit) ; updateHalfEdgeInfo(d, true) ; updateHalfEdgeInfo(m.phi1(vit), true) ; d = m.phi2(m.phi1(vit)) ; if (d != m.phi1(vit)) ; updateHalfEdgeInfo(d, true) ; Dart stop = m.phi2(vit) ; assert (stop != vit) ; Dart vit2 = m.phi12(m.phi1(vit)) ; do { updateHalfEdgeInfo(vit2, true) ; d = m.phi2(vit2) ; if (d != vit2) ; updateHalfEdgeInfo(d, true) ; updateHalfEdgeInfo(m.phi1(vit2), false) ; d = m.phi2(m.phi1(vit2)) ; if (d != m.phi1(vit2)) ; updateHalfEdgeInfo(d, false) ; vit2 = m.phi12(vit2) ; } while (stop != vit2) ; vit = m.phi2_1(vit) ; } while(vit != d2) ; cur = halfEdges.begin() ; // set the current edge to the first one } template void HalfEdgeSelector_QEMextColor::initHalfEdgeInfo(Dart d) { MAP& m = this->m_map ; HalfEdgeInfo heinfo ; if(m.edgeCanCollapse(d)) computeHalfEdgeInfo(d, heinfo) ; else heinfo.valid = false ; halfEdgeInfo[d] = heinfo ; } template void HalfEdgeSelector_QEMextColor::updateHalfEdgeInfo(Dart d, bool recompute) { MAP& m = this->m_map ; HalfEdgeInfo& heinfo = halfEdgeInfo[d] ; if(recompute) { if(heinfo.valid) halfEdges.erase(heinfo.it) ; // remove the edge from the multimap if(m.edgeCanCollapse(d)) computeHalfEdgeInfo(d, heinfo) ; else heinfo.valid = false ; } else { if(m.edgeCanCollapse(d)) { // if the edge can be collapsed now if(!heinfo.valid) // but it was not before computeHalfEdgeInfo(d, heinfo) ; } else { // if the edge cannot be collapsed now if(heinfo.valid) // and it was before { halfEdges.erase(heinfo.it) ; heinfo.valid = false ; } } } } template void HalfEdgeSelector_QEMextColor::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& heinfo) { 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) heinfo.valid = false ; else { heinfo.it = this->halfEdges.insert(std::make_pair(std::max(err,REAL(0)), d)) ; heinfo.valid = true ; } } /************************************************************************************ * HALF EDGE LIGHTFIELD SELECTOR (using QEMml half-edge) * ************************************************************************************/ template bool HalfEdgeSelector_Lightfield::init() { 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 || this->m_approximators[approxindex]->getType() == A_hHalfCollapse || this->m_approximators[approxindex]->getType() != A_Lightfield || !"Approximator for selector (HalfEdgeSelector_Lightfield) must be of a half-edge approximator") ; 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 } // Init multimap for each Half-edge halfEdges.clear() ; TraversorE travE(m); for(Dart dit = travE.begin() ; dit != travE.end() ; dit = travE.next()) { initHalfEdgeInfo(dit) ; // init the edges with their optimal position // and insert them in the multimap according to their error } cur = halfEdges.begin() ; // init the current edge to the first one return true ; } template bool HalfEdgeSelector_Lightfield::nextEdge(Dart& d) { if(cur == halfEdges.end() || halfEdges.empty()) return false ; d = (*cur).second ; return true ; } template void HalfEdgeSelector_Lightfield::updateBeforeCollapse(Dart d) { MAP& m = this->m_map ; HalfEdgeInfo& edgeE = halfEdgeInfo[d] ; if(edgeE.valid) halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi1(d)] ; if(edgeE.valid) // remove all halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi_1(d)] ; // the halfedges that will disappear if(edgeE.valid) halfEdges.erase(edgeE.it) ; // from the multimap Dart dd = m.phi2(d) ; assert(dd != d) ; if(dd != d) { edgeE = halfEdgeInfo[dd] ; if(edgeE.valid) halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi1(dd)] ; if(edgeE.valid) halfEdges.erase(edgeE.it) ; edgeE = halfEdgeInfo[m.phi_1(dd)] ; if(edgeE.valid) halfEdges.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 HalfEdgeSelector_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 HalfEdgeSelector_Lightfield::updateAfterCollapse(Dart d2, Dart dd2) { MAP& m = this->m_map ; recomputeQuadric(d2, true) ; Dart vit = d2 ; do { updateHalfEdgeInfo(vit, true) ; Dart d = m.phi2(vit) ; if (d != vit) ; updateHalfEdgeInfo(d, true) ; updateHalfEdgeInfo(m.phi1(vit), true) ; d = m.phi2(m.phi1(vit)) ; if (d != m.phi1(vit)) ; updateHalfEdgeInfo(d, true) ; Dart stop = m.phi2(vit) ; assert (stop != vit) ; Dart vit2 = m.phi12(m.phi1(vit)) ; do { updateHalfEdgeInfo(vit2, true) ; d = m.phi2(vit2) ; if (d != vit2) ; updateHalfEdgeInfo(d, true) ; updateHalfEdgeInfo(m.phi1(vit2), false) ; d = m.phi2(m.phi1(vit2)) ; if (d != m.phi1(vit2)) ; updateHalfEdgeInfo(d, false) ; vit2 = m.phi12(vit2) ; } while (stop != vit2) ; vit = m.phi2_1(vit) ; } while(vit != d2) ; cur = halfEdges.begin() ; // set the current edge to the first one } template void HalfEdgeSelector_Lightfield::initHalfEdgeInfo(Dart d) { MAP& m = this->m_map ; HalfEdgeInfo heinfo ; if(m.edgeCanCollapse(d)) computeHalfEdgeInfo(d, heinfo) ; else heinfo.valid = false ; halfEdgeInfo[d] = heinfo ; } template void HalfEdgeSelector_Lightfield::updateHalfEdgeInfo(Dart d, bool recompute) { MAP& m = this->m_map ; HalfEdgeInfo& heinfo = halfEdgeInfo[d] ; if(recompute) { if(heinfo.valid) halfEdges.erase(heinfo.it) ; // remove the edge from the multimap if(m.edgeCanCollapse(d)) computeHalfEdgeInfo(d, heinfo) ; else heinfo.valid = false ; } else { if(m.edgeCanCollapse(d)) { // if the edge can be collapsed now if(!heinfo.valid) // but it was not before computeHalfEdgeInfo(d, heinfo) ; } else { // if the edge cannot be collapsed now if(heinfo.valid) // and it was before { halfEdges.erase(heinfo.it) ; heinfo.valid = false ; } } } } template void HalfEdgeSelector_Lightfield::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& heinfo) { 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 ; if (isnan(alpha)) std::cerr << "Nan: " << m_frameN[d] << " ; " << m_frameN[dd] << " ; " << newFN << std::endl ; assert(m_quadricHF.isValid() | !"EdgeSelector_Lightfield::computeEdgeInfo: quadricHF is not valid") ; Utils::QuadricHF quadHF = m_quadricHF[d] ; //std::cout << quadGeom(newPos) / (alpha/M_PI + quadHF(newHF)) << std::endl ; // sum of QEM metric and frame orientation difference const REAL& err = quadGeom(newPos) + // geom alpha / M_PI + // frame quadHF(newHF) // function coefficients ; // Check if errated values appear if (err < -1e-6) heinfo.valid = false ; else { heinfo.it = this->halfEdges.insert(std::make_pair(std::max(err,REAL(0)), d)) ; heinfo.valid = true ; } } } // namespace Decimation } // namespace Algo } // namespace CGoGN