/******************************************************************************* * 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) { MAP& m = this->m_map ; if(cur == m.end()) return false ; d = cur ; return true ; } template void EdgeSelector_MapOrder::updateAfterCollapse(Dart d2, Dart dd2) { 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() { 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) { 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() { 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) { 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) { 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::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_Length::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_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() { 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") { 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)) { 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 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) { 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) { 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::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_QEM::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_QEM::computeEdgeInfo(Dart d, EdgeInfo& einfo) { MAP& m = this->m_map ; Dart dd = m.phi2(d) ; 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() { 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") { 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)) { 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 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) { 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] += 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) { 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::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_QEMml::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_QEMml::computeEdgeInfo(Dart d, EdgeInfo& einfo) { MAP& m = this->m_map ; Dart dd = m.phi2(d) ; 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 ; } /************************************************************************************ * CURVATURE * ************************************************************************************/ template bool EdgeSelector_Curvature::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") { 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) { 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) { 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::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_Curvature::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_Curvature::computeEdgeInfo(Dart d, EdgeInfo& einfo) { 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 embedNewCell(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 embedOrbit(d, v1) ; m.template embedOrbit(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 ; } /************************************************************************************ * 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()) { 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) { 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) { 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::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_MinDetail::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_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() { 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 ; } /************************************************************************************ * EDGESELECTOR QEMext for Color * ************************************************************************************/ template bool EdgeSelector_QEMextColor::init() { MAP& m = this->m_map ; // Verify availability of required approximators bool ok = false ; for(typename std::vector*>::iterator it = this->m_approximators.begin(); it != this->m_approximators.end(); ++it) { // constraint : 2 approximators in specific order if((*it)->getApproximatedAttributeName(0) == "position" && (*it)->getApproximatedAttributeName(1) == "color") { m_poscolApproximator = reinterpret_cast* >(*it) ; // pos + col // check incompatibilities assert(m_poscolApproximator->getType() != A_hQEM || !"Approximator(hQEM) and selector (ColorNaive) are not compatible") ; assert(m_poscolApproximator->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (ColorNaive) are not compatible") ; assert(m_poscolApproximator->getType() != A_hLightfieldHalf || !"Approximator(hLightfieldHalf) and selector (ColorNaive) are not compatible") ; ok = true ; } } if(!ok) return false ; TraversorV travV(m); for(Dart dit = travV.begin() ; dit != travV.end() ; dit = travV.next()) { 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] ; } 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 } 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) { 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] += QuadricNd(p0,p1,p2) ; } if (recomputeNeighbors) recomputeQuadric(dBack, false) ; } while(dFront != dInit) ; } template void EdgeSelector_QEMextColor::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_QEMextColor::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_QEMextColor::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_QEMextColor::computeEdgeInfo(Dart d, EdgeInfo& einfo) { MAP& m = this->m_map ; Dart dd = m.phi1(d) ; // New position QuadricNd quad ; quad += m_quadric[d] ; // compute the sum of the quad += m_quadric[dd] ; // two vertices quadrics this->m_poscolApproximator->approximate(d) ; // sets newPos VEC3 newPos = this->m_poscolApproximator->getApprox(d,0) ; // get newPos VEC3 newCol = this->m_poscolApproximator->getApprox(d,1) ; // get newCol 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,0.), d)) ; einfo.valid = true ; } } } // namespace Decimation } // namespace Algo } // namespace CGoGN