diff --git a/README_ECLIPSE.TXT b/README_ECLIPSE.TXT index c28b5dbe3482a1a98b59b809d329dcea20808cd4..58e6c0effaa65b5291e59342a92182fdd8ec3538 100644 --- a/README_ECLIPSE.TXT +++ b/README_ECLIPSE.TXT @@ -1,6 +1,6 @@ -Pour utiliser Eclipse (testé avec la version Helios, Galileo & Indigo) -English version bellow + *** English version below *** +Pour utiliser Eclipse (testé avec la version Helios, Galileo, Indigo & Juno) * Configurer un projet dans Eclipse : - Faire un nouveau projet C++ - Choisir Makefile project -> Empty Project @@ -31,8 +31,8 @@ Projet X -> Properties -> Project references : cocher le projet dont il dépend. Afin d'éviter qu'Eclipse ne rejette les syntaxes Qt (les includes de Qt, les Q_OBJECT, les callbacks) : - Télécharger le plugin Qt "eclipse-integration" http://qt.nokia.com/developer/eclipse-integration/ - Décompresser l'archive et copier son contenu dans le répertoire d'installation d'Eclipse (plugins et features) - - Relancer Eclipse au moins une fois avec l'option --clean (relecture des répertoires locaux) -Normalement, dans Window->Preferences de Eclipse, Qt apparait dans le menu. + - Relancer Eclipse au moins une fois avec l'option "-clean" (relecture des répertoires locaux) +Normalement, dans Window --> Preferences de Eclipse, Qt apparait dans le menu. - Y ajouter le répertoire de Qt (/usr/bin sur Debian/Ubuntu) et le répertoire d'include (/usr/include/qt4). Ensuite, pour chaque projet, ajouter les includes suivants dans Properties -> C/C++ general -> Paths and Symbols parmi les includes de C++ : @@ -63,7 +63,7 @@ Dans Preferences -> Shaders Preferences, on peut désormais configurer certaines ENGLISH VERSION ========================================================================================= -To use Eclipse (tested with version Helios, Galileo & Indigo) +To use Eclipse (tested with version Helios, Galileoi, Indigo & Juno) * Setting up a project in Eclipse: - Make a new C + + project @@ -84,18 +84,18 @@ In the project properties: Tutorial: Build / Apps / Tutorial (compiles tutorials) etc. .. -This added to the directory of CGoGN a .project. and .cproject files. +This adds a .project. and .cproject files to the CGoGN directory. - * Inter-dependencies projects and autocompletion -If the project X depends on another project, then: + * Project inter-dependencies and autocompletion +If project X depends on another project, then: Project X -> Properties -> Project references: check the project which it depends. * Qt dependencies: -To avoid Eclipse rejects the Qt syntax (the Qt includes the Q_OBJECT, callbacks): +To avoid Eclipse rejecting the Qt syntax (includes, Q_OBJECT, callbacks): - Download the Qt plugin "eclipse-integration" http://qt.nokia.com/developer/eclipse-integration/ - Unzip the archive and copy its contents into the installation directory of Eclipse (plugins and features) - - Restart Eclipse at least once with the - clean (proofreading local directories) -Normally in Window-> Preferences of Eclipse, Qt appears in the menu. + - Restart Eclipse at least once with the "-clean" (proofreading local directories) +Normally in Window --> Preferences of Eclipse, Qt appears in the menu. - Add the Qt directory (/ usr / bin on Debian / Ubuntu) and the directory include (/ usr/include/qt4). Then, for each project, add the following includes in Properties -> C / C + + general -> Paths and Symbols among the C + + includes: diff --git a/include/Algo/Decimation/approximator.h b/include/Algo/Decimation/approximator.h index a2443aa79f585c0f7722990ce6684f77af89f6fe..f4bcb8bcb116784d607521bace92c014434e067f 100644 --- a/include/Algo/Decimation/approximator.h +++ b/include/Algo/Decimation/approximator.h @@ -39,14 +39,17 @@ namespace Decimation enum ApproximatorType { A_QEM, - A_QEMhalfEdge, A_MidEdge, - A_HalfCollapse, A_CornerCutting, A_TangentPredict1, A_TangentPredict2, - A_LightfieldHalf, - A_LightfieldFull + A_ColorNaive, + A_ColorQEMext, + A_Lightfield, + // note: the following "h" prefix means that half-edges are prioritized instead of edges. + A_hHalfCollapse, + A_hQEM + // A_hLightfieldHalf, } ; template @@ -65,8 +68,10 @@ public: {} virtual ~ApproximatorGen() {} - virtual const std::string& getApproximatedAttributeName() const = 0 ; + virtual const std::string& getApproximatedAttributeName(unsigned int index = 0) const = 0 ; +// virtual std::vector getApproximatedAttributeNames() const = 0 ; virtual ApproximatorType getType() const = 0 ; + virtual unsigned int getNbApproximated() const = 0 ; virtual bool init() = 0 ; virtual void approximate(Dart d) = 0 ; virtual void saveApprox(Dart d) = 0 ; @@ -87,52 +92,95 @@ public: protected: Predictor* m_predictor ; - VertexAttribute& m_attrV ; // vertex attribute to be approximated - EdgeAttribute m_approx ; // attribute to store approximation result - EdgeAttribute m_detail ; // attribute to store detail information for reconstruction - T m_app ; + std::vector* > m_attrV ; // vertex attributes to be approximated + std::vector > m_approx ; // attributes to store approximation result + std::vector > m_detail ; // attributes to store detail information for reconstruction + std::vector m_app ; public: - Approximator(MAP& m, VertexAttribute& a, Predictor* predictor) : - ApproximatorGen(m), m_predictor(predictor), m_attrV(a) + Approximator(MAP& m, std::vector* > va, Predictor * predictor) : + ApproximatorGen(m), m_predictor(predictor), m_attrV(va) { - std::stringstream aname ; - aname << "approx_" << m_attrV.name() ; - m_approx = this->m_map.template addAttribute(aname.str()) ; - - if(m_predictor) // if a predictor is associated to the approximator - { // create an attribute to store the detail needed for reconstruction - std::stringstream dname ; - dname << "detail_" << m_attrV.name() ; - m_detail = this->m_map.template addAttribute(dname.str()) ; + const unsigned int& size = m_attrV.size() ; + assert(size > 0 || !"Approximator: no attributes provided") ; + + m_approx.resize(size) ; + m_detail.resize(size) ; + m_app.resize(size) ; + + for (unsigned int i = 0 ; i < size ; ++i) + { + if (!m_attrV[i]->isValid()) + std::cerr << "Approximator Warning: attribute number " << i << " is not valid" << std::endl ; + + std::stringstream aname ; + aname << "approx_" << m_attrV[i]->name() ; + m_approx[i] = this->m_map.template addAttribute(aname.str()) ; + + if(m_predictor) // if predictors are associated to the approximator + { // create attributes to store the details needed for reconstruction + std::stringstream dname ; + dname << "detail_" << m_attrV[i]->name() ; + m_detail[i] = this->m_map.template addAttribute(dname.str()) ; + } } } virtual ~Approximator() { - this->m_map.template removeAttribute(m_approx) ; - if(m_predictor) - this->m_map.template removeAttribute(m_detail) ; + for (unsigned int i = 0 ; i < m_attrV.size() ; ++i) + { + this->m_map.template removeAttribute(m_approx[i]) ; + if(m_predictor) + this->m_map.template removeAttribute(m_detail[i]) ; + } + } + + const std::string& getApproximatedAttributeName(unsigned int index = 0) const + { + return m_attrV[index]->name() ; } - const std::string& getApproximatedAttributeName() const +// std::vector getApproximatedAttributeNames() const +// { +// std::vector names ; +// names.resize(m_attrV.size()) ; +// for (unsigned int i = 0 ; i < m_attrV.size() ; ++i) +// names[i] = m_attrV[i]->name() ; +// +// return names ; +// } + + unsigned int getNbApproximated() const { - return m_attrV.name() ; + return m_attrV.size() ; } void saveApprox(Dart d) { - m_app = m_approx[d] ; + for (unsigned int i = 0 ; i < m_attrV.size() ; ++i) + m_app[i] = m_approx[i][d] ; } void affectApprox(Dart d) { - m_attrV[d] = m_app ; + for (unsigned int i = 0 ; i < m_attrV.size() ; ++i) + m_attrV[i]->operator[](d) = m_app[i] ; + } + + const T& getApprox(Dart d, unsigned int index = 0) const + { + return m_approx[index][d] ; } - const T& getApprox(Dart d) const + std::vector getAllApprox(Dart d) const { - return m_approx[d] ; + std::vector res ; + res.resize(m_attrV.size()) ; + for (unsigned int i = 0 ; i < m_attrV.size() ; ++i) + res[i] = m_approx[i][d] ; + + return res ; } const Predictor* getPredictor() const @@ -140,18 +188,38 @@ public: return m_predictor ; } - const T& getDetail(Dart d) const + const T& getDetail(Dart d, unsigned int index = 0) const + { + assert(m_predictor || !"Trying to get detail on a non-predictive scheme") ; + return m_detail[index][d] ; + } + + std::vector getAllDetail(Dart d) const { assert(m_predictor || !"Trying to get detail on a non-predictive scheme") ; - return m_detail[d] ; + + std::vector res ; + res.resize(m_attrV.size()) ; + for (unsigned int i = 0 ; i < m_attrV.size() ; ++i) + res[i] = m_detail[i][d] ; + return res ; + } + + void setDetail(Dart d, unsigned int index, T& val) + { + assert(m_predictor || !"Trying to set detail on a non-predictive scheme") ; + m_detail[index][d] = val ; } - void setDetail(Dart d, T& val) + void setDetail(Dart d, std::vector& val) { assert(m_predictor || !"Trying to set detail on a non-predictive scheme") ; - m_detail[d] = val ; + + for (unsigned int i = 0 ; i < m_attrV.size() ; ++i) + m_detail[index][d] = val[i] ; } + // // TODO works only for vector types !! // REAL detailMagnitude(Dart d) // { @@ -162,13 +230,17 @@ public: void addDetail(Dart d, double amount, bool sign, typename PFP::MATRIX33* detailTransform) { assert(m_predictor || !"Trying to add detail on a non-predictive scheme") ; - T det = m_detail[d] ; - if(detailTransform) - det = (*detailTransform) * det ; - det *= amount ; - if(!sign) - det *= REAL(-1) ; - m_attrV[d] += det ; + + for (unsigned int i = 0 ; i < m_attrV.size() ; ++i) + { + T det = m_detail[i][d] ; + if(detailTransform) + det = (*detailTransform) * det ; + det *= amount ; + if(!sign) + det *= REAL(-1) ; + m_attrV[i]->operator[](d) += det ; + } } } ; diff --git a/include/Algo/Decimation/colorPerVertexApproximator.h b/include/Algo/Decimation/colorPerVertexApproximator.h new file mode 100644 index 0000000000000000000000000000000000000000..62f47bcf32d4902fbe8d7ea6f1d07e82b8d89b1e --- /dev/null +++ b/include/Algo/Decimation/colorPerVertexApproximator.h @@ -0,0 +1,129 @@ +/******************************************************************************* +* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * +* version 0.1 * +* Copyright (C) 2009-2012, IGG Team, LSIIT, University of Strasbourg * +* * +* This library is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by the * +* Free Software Foundation; either version 2.1 of the License, or (at your * +* option) any later version. * +* * +* This library is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +* Web site: http://cgogn.unistra.fr/ * +* Contact information: cgogn@unistra.fr * +* * +*******************************************************************************/ + +#ifndef __COLOR_APPROXIMATOR_H__ +#define __COLOR_APPROXIMATOR_H__ + +#include "Algo/Decimation/approximator.h" +#include "Topology/generic/mapBrowser.h" + +namespace CGoGN +{ + +namespace Algo +{ + +namespace Decimation +{ + +template +class Approximator_ColorNaive : public Approximator +{ +public: + typedef typename PFP::MAP MAP ; + typedef typename PFP::VEC3 VEC3 ; + typedef typename PFP::REAL REAL ; + +protected: + VertexAttribute m_position ; + EdgeAttribute m_approxposition ; + + VertexAttribute *m_color ; + +public: + Approximator_ColorNaive(MAP& m, std::vector* >& attr, Predictor* pred = NULL) : + Approximator(m, attr, pred) + { + m_color = this->m_attrV[0] ; + } + ~Approximator_ColorNaive() + {} + + ApproximatorType getType() const + { + return A_ColorNaive ; + } + + bool init() + { + assert(m_color->isValid() || !"Approximator_ColorNaive: the approximated attribute is not valid") ; + + m_position = this->m_map.template getAttribute("position") ; + assert(m_position.isValid() || !"Approximator_ColorNaive::init: the position attribute is not valid") ; + + m_approxposition = this->m_map.template getAttribute("approx_position") ; + assert(m_approxposition.isValid() || !"Approximator_ColorNaive::init: the approx_position attribute is not valid") ; + + return m_color->isValid() && m_position.isValid() && m_approxposition.isValid() ; + } + + void approximate(Dart d) ; +} ; + +template +class Approximator_ColorQEMext : public Approximator +{ +public: + typedef typename PFP::MAP MAP ; + typedef typename PFP::REAL REAL ; + typedef typename PFP::VEC3 VEC3 ; + typedef Geom::Vector<6,REAL> VEC6 ; + +protected: + VertexAttribute > m_quadric ; + VertexAttribute *m_position ; + VertexAttribute *m_color ; + +public: + Approximator_ColorQEMext(MAP& m, std::vector* >& attr, Predictor* pred = NULL) : + Approximator(m, attr, pred) + { + assert(attr.size() > 1 || !"Approximator_ColorQEMext: there are not sufficient attributes provided") ; + + m_position = this->m_attrV[0] ; + m_color = this->m_attrV[1] ; + } + + ~Approximator_ColorQEMext() + {} + + ApproximatorType getType() const + { + return A_ColorQEMext ; + } + + bool init() ; + + void approximate(Dart d) ; +} ; + +} //namespace Decimation + +} //namespace Algo + +} //namespace CGoGN + +#include "Algo/Decimation/colorPerVertexApproximator.hpp" + +#endif diff --git a/include/Algo/Decimation/colorPerVertexApproximator.hpp b/include/Algo/Decimation/colorPerVertexApproximator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2764f7f30daeb11ab94c8568a83563521716475a --- /dev/null +++ b/include/Algo/Decimation/colorPerVertexApproximator.hpp @@ -0,0 +1,169 @@ +/******************************************************************************* +* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps * +* version 0.1 * +* Copyright (C) 2009-2012, IGG Team, LSIIT, University of Strasbourg * +* * +* This library is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by the * +* Free Software Foundation; either version 2.1 of the License, or (at your * +* option) any later version. * +* * +* This library is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +* Web site: http://cgogn.unistra.fr/ * +* Contact information: cgogn@unistra.fr * +* * +*******************************************************************************/ + +namespace CGoGN +{ + +namespace Algo +{ + +namespace Decimation +{ + +/************************************************************************************ + * NAIVE COLOR METRIC * + ************************************************************************************/ + +template +void Approximator_ColorNaive::approximate(Dart d) +{ + Dart dd = this->m_map.phi1(d) ; + + const VEC3& p1 = m_position.operator[](d) ; + const VEC3& p2 = m_position.operator[](dd) ; + const VEC3& p = m_approxposition.operator[](d) ; + + const VEC3& edge = p2 - p1 ; + const REAL& ratio = std::max(std::min(((p - p1) * edge) / edge.norm2(),REAL(1)),REAL(0)) ; + + this->m_approx[0][d] = m_color->operator[](d)*ratio + m_color->operator[](dd)*(1-ratio) ; +} + +/************************************************************************************ + * EXTENDED QUADRIC ERROR METRIC * + ************************************************************************************/ +template +bool Approximator_ColorQEMext::init() +{ + m_quadric = this->m_map.template getAttribute, VERTEX>("QEMext-quadric") ; + // Does not require to be valid (if it is not, altenatives will be used). + + if(this->m_predictor) + { + return false ; + } + + return m_position->isValid() && m_color->isValid() ; +} + +template +void Approximator_ColorQEMext::approximate(Dart d) +{ + MAP& m = this->m_map ; + + // get some darts + Dart dd = m.phi2(d) ; + + QuadricNd q1, q2 ; + if(!m_quadric.isValid()) // if the selector is not QEM, compute local error quadrics + { + // compute the error quadric associated to v1 + Dart it = d ; + do + { + VEC6 p0,p1,p2 ; + for (unsigned int i = 0 ; i < 3 ; ++i) + { + p0[i] = this->m_attrV[0]->operator[](it)[i] ; + p0[i+3] = this->m_attrV[1]->operator[](it)[i] ; + p1[i] = this->m_attrV[0]->operator[](m.phi1(it))[i] ; + p1[i+3] = this->m_attrV[1]->operator[](m.phi1(it))[i] ; + p2[i] = this->m_attrV[0]->operator[](m.phi_1(it))[i] ; + p2[i+3] = this->m_attrV[1]->operator[](m.phi_1(it))[i] ; + } + + QuadricNd q(p0,p1,p2) ; + q1 += q ; + it = m.phi2_1(it) ; + } while(it != d) ; + + // compute the error quadric associated to v2 + it = dd ; + do + { + VEC6 p0,p1,p2 ; + for (unsigned int i = 0 ; i < 3 ; ++i) + { + p0[i] = this->m_attrV[0]->operator[](it)[i] ; + p0[i+3] = this->m_attrV[1]->operator[](it)[i] ; + p1[i] = this->m_attrV[0]->operator[](m.phi1(it))[i] ; + p1[i+3] = this->m_attrV[1]->operator[](m.phi1(it))[i] ; + p2[i] = this->m_attrV[0]->operator[](m.phi_1(it))[i] ; + p2[i+3] = this->m_attrV[1]->operator[](m.phi_1(it))[i] ; + } + + QuadricNd q(p0,p1,p2) ; + q2 += q ; + it = m.phi2_1(it) ; + } while(it != dd) ; + } + else // if the selector is QEM, use the error quadrics computed by the selector + { + q1 = m_quadric[d] ; + q2 = m_quadric[dd] ; + } + + QuadricNd quad ; + quad += q1 ; // compute the sum of the + quad += q2 ; // two vertices quadrics + + VEC6 res ; + bool opt = quad.findOptimizedVec(res) ; // try to compute an optimized position for the contraction of this edge + if(!opt) + { + VEC6 p1, p2 ; + for (unsigned int i = 0 ; i < 3; ++i) + { + p1[i] = this->m_attrV[0]->operator[](d)[i] ; // let the new vertex lie + p1[i+3] = this->m_attrV[1]->operator[](d)[i] ; // on either one + p2[i] = this->m_attrV[0]->operator[](dd)[i] ; // of the two + p2[i+3] = this->m_attrV[1]->operator[](dd)[i] ; // endpoints + } + VEC6 p12 = (p1 + p2) / 2.0f ; // or the middle of the edge + + REAL e1 = quad(p1) ; + REAL e2 = quad(p2) ; + REAL e12 = quad(p12) ; + REAL minerr = std::min(std::min(e1, e2), e12) ; // consider only the one for + if(minerr == e12) + res = p12 ; // which the error is minimal + else if(minerr == e1) + res = p1 ; + else + res = p2 ; + } + + // copy res into m_approx + for (unsigned int i = 0 ; i < 3 ; ++i) + { + this->m_approx[0][d][i] = res[i] ; + this->m_approx[1][d][i] = res[i+3] ; + } +} + +} //namespace Decimation + +} //namespace Algo + +} //namespace CGoGN diff --git a/include/Algo/Decimation/decimation.h b/include/Algo/Decimation/decimation.h index d38937b76f2273f940e51de801ce77c89c4c5f32..402bcc12b0f26ed19241a4d97b6ea348cb2876da 100644 --- a/include/Algo/Decimation/decimation.h +++ b/include/Algo/Decimation/decimation.h @@ -28,6 +28,7 @@ #include "Algo/Decimation/edgeSelector.h" #include "Algo/Decimation/halfEdgeSelector.h" #include "Algo/Decimation/geometryApproximator.h" +#include "Algo/Decimation/colorPerVertexApproximator.h" #include "Algo/Decimation/lightfieldApproximator.h" namespace CGoGN @@ -44,9 +45,10 @@ void decimate( typename PFP::MAP& map, SelectorType s, ApproximatorType a, - VertexAttribute& position, + std::vector *>& position, unsigned int nbWantedVertices, - const FunctorSelect& selected = allDarts + const FunctorSelect& selected = allDarts, + void (*callback_wrapper)(void*, const void*) = NULL, void *callback_object = NULL ) ; } //namespace Decimation diff --git a/include/Algo/Decimation/decimation.hpp b/include/Algo/Decimation/decimation.hpp index 6cbc490a08dfbabb0feb626f64c1de7a4507b100..3ae5365aa8e0ab8666cdbc653bc66b315bdc9957 100644 --- a/include/Algo/Decimation/decimation.hpp +++ b/include/Algo/Decimation/decimation.hpp @@ -34,75 +34,106 @@ namespace Decimation template void decimate( typename PFP::MAP& map, SelectorType s, ApproximatorType a, - VertexAttribute& position, unsigned int nbWantedVertices, const FunctorSelect& selected + std::vector* >& attribs, unsigned int nbWantedVertices, const FunctorSelect& selected, + void (*callback_wrapper)(void*, const void*), void* callback_object ) { + assert(attribs.size() >= 1 || !"Decimate: not enough attribs provided") ; + assert(attribs[0]->name() == "position" || !"Decimate: first attribute is not position") ; + VertexAttribute position = *(attribs[0]) ; + std::vector*> approximators ; EdgeSelector* selector = NULL ; + std::vector* > *v_approx = NULL ; + switch(a) { case A_QEM : - approximators.push_back(new Approximator_QEM(map, position)) ; - break ; - case A_QEMhalfEdge : - approximators.push_back(new Approximator_QEMhalfEdge(map, position)) ; + approximators.push_back(new Approximator_QEM(map, attribs)) ; break ; case A_MidEdge : - approximators.push_back(new Approximator_MidEdge(map, position)) ; + approximators.push_back(new Approximator_MidEdge(map, attribs)) ; break ; case A_CornerCutting : - approximators.push_back(new Approximator_CornerCutting(map, position)) ; + approximators.push_back(new Approximator_CornerCutting(map, attribs)) ; break ; case A_TangentPredict1 : - approximators.push_back(new Approximator_MidEdge(map, position)) ; + approximators.push_back(new Approximator_MidEdge(map, attribs)) ; break ; case A_TangentPredict2 : - approximators.push_back(new Approximator_MidEdge(map, position)) ; + approximators.push_back(new Approximator_MidEdge(map, attribs)) ; break ; - case A_HalfCollapse : - approximators.push_back(new Approximator_HalfCollapse(map, position)) ; + case A_hHalfCollapse : + approximators.push_back(new Approximator_HalfCollapse(map, attribs)) ; break ; - case A_LightfieldFull : + case A_ColorNaive : { - approximators.push_back(new Approximator_QEMhalfEdge(map, position)) ; - /* - PFP::TVEC3 frame[3] ; - frame[0] = map.template getAttribute("frame_T") ; // Tangent - frame[1] = map.template getAttribute("frame_B") ; // Bitangent - frame[2] = map.template getAttribute("frame_N") ; // Normal - for (unsigned int i = 0 ; i < 3 ; ++i) - if (!frame[i].isValid()) { - CGoGNerr << "In function decimate : frame[" << i << "] is not valid" << CGoGNendl ; - } - - VertexAttribute colorPTM[6] ; - colorPTM[0] = map.template getAttribute("colorPTM_a") ; - colorPTM[1] = map.template getAttribute("colorPTM_b") ; - colorPTM[2] = map.template getAttribute("colorPTM_c") ; - colorPTM[3] = map.template getAttribute("colorPTM_d") ; - colorPTM[4] = map.template getAttribute("colorPTM_e") ; - colorPTM[5] = map.template getAttribute("colorPTM_f") ; - for (unsigned int i = 0 ; i < 6 ; ++i) - if (!colorPTM[i].isValid()) { - CGoGNerr << "In function decimate : colorPTM[" << i << "] is not valid" << CGoGNendl ; - } - */ - VertexAttribute > frame = map.template getAttribute, VERTEX>("frame") ; - VertexAttribute > RGBfunctions = map.template getAttribute, VERTEX>("colorPTM") ; - approximators.push_back(new Approximator_Frame(map, frame)) ; - approximators.push_back(new Approximator_RGBfunctions(map, RGBfunctions)) ; - break ; + v_approx = new std::vector* >[2] ; + + // pos + v_approx[0].push_back(attribs[0]) ; + approximators.push_back(new Approximator_QEM(map, v_approx[0])) ; + + // col + assert(attribs.size() >= 2 || !"Decimate: A_ColorNaive --> not enough attribs provided") ; + v_approx[1].push_back(attribs[1]) ; + approximators.push_back(new Approximator_ColorNaive(map, v_approx[1])) ; } - case A_LightfieldHalf : + break ; + case A_ColorQEMext : { - approximators.push_back(new Approximator_HalfCollapse(map, position)) ; - VertexAttribute > frame = map.template getAttribute, VERTEX>("frame") ; - VertexAttribute > RGBfunctions = map.template getAttribute, VERTEX>("colorPTM") ; - approximators.push_back(new Approximator_FrameHalf(map, frame)) ; - approximators.push_back(new Approximator_RGBfunctionsHalf(map, RGBfunctions)) ; - break ; + // pos + col + assert(attribs.size() >= 2 || !"Decimate: A_ColorQEMext --> not enough attribs provided") ; + approximators.push_back(new Approximator_ColorQEMext(map, attribs)) ; } + break; + case A_hQEM : + // pos + approximators.push_back(new Approximator_QEMhalfEdge(map, attribs)) ; + break ; +// case A_hLightfieldHalf: +// { +// v_approx = new std::vector* >[3] ; +// +// // pos +// v_approx[0].push_back(attribs[0]) ; +// approximators.push_back(new Approximator_HalfCollapse(map, v_approx[0])) ; +// +// // frame +// assert(attribs.size() >= 4 || !"Decimate: A_LightfieldHalf --> not enough attribs provided") ; +// for (unsigned int i = 0 ; i < 3 ; ++i) +// v_approx[1].push_back(attribs[i+1]) ; +// approximators.push_back(new Approximator_FrameHalf(map, v_approx[1])) ; +// +// // hemifunction +// assert(attribs.size() >= 5 || !"Decimate: A_LightfieldHalf --> not enough attribs provided") ; +// for (unsigned int i = 0 ; i < attribs.size() - 4 ; ++i) +// v_approx[2].push_back(attribs[i+4]) ; +// approximators.push_back(new Approximator_LightfieldCoefsHalf(map, v_approx[2])) ; +// } +// break ; + case A_Lightfield : + { + v_approx = new std::vector* >[3] ; + + // pos + v_approx[0].push_back(attribs[0]) ; + approximators.push_back(new Approximator_QEM(map, v_approx[0])) ; + + // frame + assert(attribs.size() >= 4 || !"Decimate: A_Lightfield --> not enough attribs provided") ; + for (unsigned int i = 0 ; i < 3 ; ++i) + v_approx[1].push_back(attribs[i+1]) ; + approximators.push_back(new Approximator_FrameInterpolation(map, v_approx[1])) ; + + // hemifunction + assert(attribs.size() >= 5 || !"Decimate: A_Lightfield --> not enough attribs provided") ; + for (unsigned int i = 0 ; i < attribs.size() - 4 ; ++i) + v_approx[2].push_back(attribs[i+4]) ; + approximators.push_back(new Approximator_HemiFuncCoefs(map, v_approx[2])) ; + } + break ; } switch(s) @@ -128,19 +159,35 @@ void decimate( case S_MinDetail : selector = new EdgeSelector_MinDetail(map, position, approximators, selected) ; break ; - case S_hLightfield : - selector = new HalfEdgeSelector_Lightfield(map, position, approximators, selected) ; + case S_ColorNaive : + selector = new EdgeSelector_ColorNaive(map, position, approximators, selected) ; + break ; + case S_QEMextColor : + selector = new EdgeSelector_QEMextColor(map, position, approximators, selected) ; break ; case S_hQEMml : selector = new HalfEdgeSelector_QEMml(map, position, approximators, selected) ; break ; + case S_Lightfield : + selector = new EdgeSelector_Lightfield(map, position, approximators, selected) ; + break ; } for(typename std::vector*>::iterator it = approximators.begin(); it != approximators.end(); ++it) (*it)->init() ; if(!selector->init()) + { + delete selector ; + + for(typename std::vector*>::iterator it = approximators.begin(); it != approximators.end(); ++it) + delete (*it) ; + + delete[] v_approx ; + return ; + } + unsigned int nbVertices = map.template getNbOrbits() ; bool finished = false ; @@ -148,11 +195,8 @@ void decimate( while(!finished) { -// CGoGNout << "Countdown : " ; -// CGoGNout << std::setprecision(8) << (nbVertices - nbWantedVertices) << "\r" << CGoGNflush ; - - if(!selector->nextEdge(d)) { -// CGoGNout << CGoGNendl << "out" << CGoGNendl ; + if(!selector->nextEdge(d)) + { break ; } @@ -176,15 +220,22 @@ void decimate( selector->updateAfterCollapse(d2, dd2) ;// update selector - if(nbVertices <= nbWantedVertices) { + if(nbVertices <= nbWantedVertices) + { finished = true ; -// CGoGNout << CGoGNendl << "done" << CGoGNendl ; } + + // Progress bar support + if (callback_wrapper != NULL && callback_object != NULL) + callback_wrapper(callback_object, &nbVertices) ; } delete selector ; + for(typename std::vector*>::iterator it = approximators.begin(); it != approximators.end(); ++it) delete (*it) ; + + delete[] v_approx ; } } //namespace Decimation diff --git a/include/Algo/Decimation/edgeSelector.h b/include/Algo/Decimation/edgeSelector.h index a2a57c4b2443213a7e75015de15467b0b0478c9c..d6be8cc12436e6d4d4dda72396db399cebe81d01 100644 --- a/include/Algo/Decimation/edgeSelector.h +++ b/include/Algo/Decimation/edgeSelector.h @@ -84,7 +84,9 @@ private: public: EdgeSelector_Random(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + cur(0), + allSkipped(false) {} ~EdgeSelector_Random() {} @@ -175,7 +177,8 @@ private: public: EdgeSelector_QEM(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { edgeInfo = m.template addAttribute("edgeInfo") ; quadric = m.template addAttribute, VERTEX>("QEMquadric") ; @@ -226,7 +229,8 @@ private: public: EdgeSelector_QEMml(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { edgeInfo = m.template addAttribute("edgeInfo") ; quadric = m.template addAttribute, VERTEX>("QEMquadric") ; @@ -285,7 +289,8 @@ private: public: EdgeSelector_Curvature(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { bb = Algo::Geometry::computeBoundingBox(m, pos) ; radius = bb.diagSize() * 0.003 ; @@ -372,7 +377,8 @@ private: public: EdgeSelector_MinDetail(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { edgeInfo = m.template addAttribute("edgeInfo") ; } @@ -389,6 +395,193 @@ public: bool nextEdgeWithoutUpdates(Dart& d) { } } ; +/***************************************************************************************************************** + * EDGE NAIVE COLOR METRIC (using QEMml) * + *****************************************************************************************************************/ +template +class EdgeSelector_ColorNaive : public EdgeSelector +{ +public: + typedef typename PFP::MAP MAP ; + typedef typename PFP::VEC3 VEC3 ; + typedef typename PFP::REAL REAL ; + +private: + typedef struct + { + typename std::multimap::iterator it ; + bool valid ; + static std::string CGoGNnameOfType() { return "ColorNaiveEdgeInfo" ; } + } ColorNaiveedgeInfo ; + typedef NoMathIOAttribute EdgeInfo ; + + EdgeAttribute edgeInfo ; + VertexAttribute > m_quadric ; + + VertexAttribute m_pos, m_color ; + int m_approxindex_pos, m_attrindex_pos ; + int m_approxindex_color, m_attrindex_color ; + + std::vector* > m_approx ; + + std::multimap edges ; + typename std::multimap::iterator cur ; + + void initEdgeInfo(Dart d) ; + void updateEdgeInfo(Dart d, bool recompute) ; + void computeEdgeInfo(Dart d,EdgeInfo& einfo) ; + void recomputeQuadric(const Dart d, const bool recomputeNeighbors = false) ; + +public: + EdgeSelector_ColorNaive(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : + EdgeSelector(m, pos, approx, select), + m_approxindex_pos(-1), + m_attrindex_pos(-1), + m_approxindex_color(-1), + m_attrindex_color(-1) + { + edgeInfo = m.template addAttribute("edgeInfo") ; + m_quadric = m.template addAttribute, VERTEX>("QEMquadric") ; + } + ~EdgeSelector_ColorNaive() + { + this->m_map.removeAttribute(edgeInfo) ; + this->m_map.removeAttribute(m_quadric) ; + } + SelectorType getType() { return S_ColorNaive ; } + bool init() ; + bool nextEdge(Dart& d) ; + void updateBeforeCollapse(Dart d) ; + void updateAfterCollapse(Dart d2, Dart dd2) ; +} ; + +/***************************************************************************************************************** + * QEM extended to color metric * + *****************************************************************************************************************/ +template +class EdgeSelector_QEMextColor : public EdgeSelector +{ +public: + typedef typename PFP::MAP MAP ; + typedef typename PFP::REAL REAL ; + typedef typename PFP::VEC3 VEC3 ; + typedef typename Geom::Vector<6,REAL> VEC6 ; + +private: + typedef struct + { + typename std::multimap::iterator it ; + bool valid ; + static std::string CGoGNnameOfType() { return "QEMextColorEdgeInfo" ; } + } QEMextColorEdgeInfo ; + typedef NoMathIOAttribute EdgeInfo ; + + EdgeAttribute edgeInfo ; + VertexAttribute > m_quadric ; + + VertexAttribute m_pos, m_color ; + int m_approxindex_pos, m_attrindex_pos ; + int m_approxindex_color, m_attrindex_color ; + + std::vector* > m_approx ; + + std::multimap edges ; + typename std::multimap::iterator cur ; + + void initEdgeInfo(Dart d) ; + void updateEdgeInfo(Dart d, bool recompute) ; + void computeEdgeInfo(Dart d,EdgeInfo& einfo) ; + void recomputeQuadric(const Dart d, const bool recomputeNeighbors = false) ; + +public: + EdgeSelector_QEMextColor(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : + EdgeSelector(m, pos, approx, select), + m_approxindex_pos(-1), + m_attrindex_pos(-1), + m_approxindex_color(-1), + m_attrindex_color(-1) + { + edgeInfo = m.template addAttribute("edgeInfo") ; + m_quadric = m.template addAttribute, VERTEX>("QEMext-quadric") ; + } + ~EdgeSelector_QEMextColor() + { + this->m_map.removeAttribute(edgeInfo) ; + this->m_map.removeAttribute(m_quadric) ; + } + SelectorType getType() { return S_QEMextColor ; } + bool init() ; + bool nextEdge(Dart& d) ; + void updateBeforeCollapse(Dart d) ; + void updateAfterCollapse(Dart d2, Dart dd2) ; +} ; + +/***************************************************************************************************************** + * LIGHTFIELD QUADRIC ERROR METRIC * + *****************************************************************************************************************/ +template +class EdgeSelector_Lightfield : public EdgeSelector +{ +public: + typedef typename PFP::MAP MAP ; + typedef typename PFP::REAL REAL ; + typedef typename PFP::VEC3 VEC3 ; + typedef typename Geom::Vector<6,REAL> VEC6 ; + +private: + typedef struct + { + typename std::multimap::iterator it ; + bool valid ; + static std::string CGoGNnameOfType() { return "QEMextColorEdgeInfo" ; } + } QEMextColorEdgeInfo ; + typedef NoMathIOAttribute EdgeInfo ; + + EdgeAttribute edgeInfo ; + + VertexAttribute m_pos, m_frameT, m_frameB, m_frameN ; + //VertexAttribute *m_HF ; + int m_approxindex_pos, m_attrindex_pos ; + int m_approxindex_FN, m_attrindex_FN ; + + VertexAttribute > m_quadricGeom ; + VertexAttribute > m_quadricHF ; + + std::vector* > m_approx ; + + std::multimap edges ; + typename std::multimap::iterator cur ; + + void initEdgeInfo(Dart d) ; + void updateEdgeInfo(Dart d, bool recompute) ; + void computeEdgeInfo(Dart d,EdgeInfo& einfo) ; + void recomputeQuadric(const Dart d, const bool recomputeNeighbors = false) ; + +public: + EdgeSelector_Lightfield(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : + EdgeSelector(m, pos, approx, select), + m_approxindex_pos(-1), + m_attrindex_pos(-1), + m_approxindex_FN(-1), + m_attrindex_FN(-1) + { + edgeInfo = m.template addAttribute("edgeInfo") ; + m_quadricGeom = m.template addAttribute, VERTEX>("QEMquadric") ; + m_quadricHF = m.template addAttribute, VERTEX>("HFquadric") ; + } + ~EdgeSelector_Lightfield() + { + this->m_map.removeAttribute(edgeInfo) ; + this->m_map.removeAttribute(m_quadricGeom) ; + this->m_map.removeAttribute(m_quadricHF) ; + } + SelectorType getType() { return S_Lightfield ; } + bool init() ; + bool nextEdge(Dart& d) ; + void updateBeforeCollapse(Dart d) ; + void updateAfterCollapse(Dart d2, Dart dd2) ; +} ; + } // namespace Decimation } // namespace Algo diff --git a/include/Algo/Decimation/edgeSelector.hpp b/include/Algo/Decimation/edgeSelector.hpp index e5a1d0be0d4d409b1b3ee6ed96c3df44d879b07d..3723f67d89b384e29c682b0f6add9f9bd0aa55b6 100644 --- a/include/Algo/Decimation/edgeSelector.hpp +++ b/include/Algo/Decimation/edgeSelector.hpp @@ -473,7 +473,7 @@ void EdgeSelector_QEM::computeEdgeInfo(Dart d, EdgeInfo& einfo) m_positionApproximator->approximate(d) ; - REAL err = std::max(REAL(0),REAL(quad(m_positionApproximator->getApprox(d)))) ; + REAL err = quad(m_positionApproximator->getApprox(d)) ; einfo.it = edges.insert(std::make_pair(err, d)) ; einfo.valid = true ; @@ -749,7 +749,7 @@ bool EdgeSelector_Curvature::init() edges.clear() ; - CellMarker eMark(m) ; + CellMarker eMark(m) ; for(Dart d = m.begin(); d != m.end(); m.next(d)) { if(!eMark.isMarked(d)) @@ -1088,7 +1088,7 @@ void EdgeSelector_MinDetail::updateEdgeInfo(Dart d, bool recompute) template void EdgeSelector_MinDetail::computeEdgeInfo(Dart d, EdgeInfo& einfo) { - Dart dd = this->m_map.phi2(d) ; + // Dart dd = this->m_map.phi2(d) ; REAL err = REAL(0) ; // for(typename std::vector*>::iterator it = this->m_approximators.begin(); @@ -1109,6 +1109,891 @@ void EdgeSelector_MinDetail::computeEdgeInfo(Dart d, EdgeInfo& einfo) einfo.valid = true ; } +/************************************************************************************ + * EDGESELECTOR COLOR PER VERTEX * + ************************************************************************************/ + +template +bool EdgeSelector_ColorNaive::init() +{ + MAP& m = this->m_map ; + + assert(this->m_approximators[0]->getType() != A_hQEM || !"Approximator(hQEM) and selector (ColorNaive) are not compatible") ; + assert(this->m_approximators[0]->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (ColorNaive) are not compatible") ; + assert(this->m_approximators[0]->getType() != A_Lightfield || !"Approximator(hLightfield) and selector (ColorNaive) are not compatible") ; + + // Verify availability of required approximators + unsigned int ok = 0 ; + for (unsigned int approxindex = 0 ; approxindex < this->m_approximators.size() ; ++approxindex) + { + 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()) + { + 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 + + // 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() +{ + MAP& m = this->m_map ; + + assert(this->m_approximators[0]->getType() != A_hQEM || !"Approximator(hQEM) and selector (ColorNaive) are not compatible") ; + assert(this->m_approximators[0]->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (ColorNaive) are not compatible") ; + + // Verify availability of required approximators + unsigned int ok = 0 ; + for (unsigned int approxindex = 0 ; approxindex < this->m_approximators.size() ; ++approxindex) + { + 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()) + { + 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 + + // 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 + 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() +{ + MAP& m = this->m_map ; + + assert(this->m_approximators[0]->getType() != A_hQEM || !"Approximator(hQEM) and selector (ColorNaive) are not compatible") ; + assert(this->m_approximators[0]->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (ColorNaive) are not compatible") ; + + // Verify availability of required approximators + unsigned int ok = 0 ; + for (unsigned int approxindex = 0 ; approxindex < this->m_approximators.size() ; ++approxindex) + { + 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 ; + } + } + } + } + + if(ok != 4) + return false ; + + TraversorV travV(m); + for(Dart dit = travV.begin() ; dit != travV.end() ; dit = travV.next()) + { + 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 + + 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) +{ + 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 ; +//todo + // 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] += 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) +{ + MAP& m = this->m_map ; + //todo + 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) +{ + 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) +{ + 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) +{ + MAP& m = this->m_map ; + Dart dd = m.phi1(d) ; + + // New position + 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 + // todo const VEC3& hfcoefs0 = this->m_approximators[m_approxindex_hf]->getApprox(d,m_attrindex_hf[0]) ; // get newHFcoefs0 + // todo const VEC3& hfcoefs1 = this->m_approximators[m_approxindex_hf]->getApprox(d,m_attrindex_hf[1]) ; // get newHFcoefs1 + // todo const VEC3& hfcoefs2 = this->m_approximators[m_approxindex_hf]->getApprox(d,m_attrindex_hf[2]) ; // get newHFcoefs2 + // ... + // todo const VEC3& hfcoefsK = this->m_approximators[m_approxindex_hf]->getApprox(d,m_attrindex_hf[K]) ; // get newHFcoefsK + + // Compute errors + // Position + Quadric quadGeom ; + quadGeom += m_quadricGeom[d] ; // compute the sum of the + quadGeom += m_quadricGeom[dd] ; // two vertices quadrics + + // hemisphere difference error + double scal1 = abs(double(m_frameN[d] * newFN)) ; + scal1 = std::min(scal1, double(1)) ; // for epsilon normalization of newFN errors + // angle 2 + double scal2 = abs(double(m_frameN[dd] * newFN)) ; + scal2 = std::min(scal2, double(1)) ; + // Important: sum of abs values works only if newFN is in-between the two old ones (interpolated). + // This avoids computation of the sign of alpha1 and alpha2. + double alpha = acos(scal1 + scal2) ; + + std::cout << quadGeom(newPos) << " vs " << alpha/M_PI << std::endl ; + // sum of QEM metric and frame orientation difference + const REAL& err = + quadGeom(newPos) // geom + + alpha / M_PI // frame + // todo+ quadHF(newHF) // function coefficients + ; + + // 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 ; + } +} + } // namespace Decimation } // namespace Algo diff --git a/include/Algo/Decimation/geometryApproximator.h b/include/Algo/Decimation/geometryApproximator.h index 8793560203856fc0c864177a40168b84f416ef2b..9a64588153557941d969926177df5bbc88ab2b7f 100644 --- a/include/Algo/Decimation/geometryApproximator.h +++ b/include/Algo/Decimation/geometryApproximator.h @@ -48,9 +48,11 @@ protected: VertexAttribute > m_quadric ; public: - Approximator_QEM(MAP& m, VertexAttribute& pos, Predictor* pred = NULL) : + Approximator_QEM(MAP& m, std::vector* > pos, Predictor* pred = NULL) : Approximator(m, pos, pred) - {} + { + assert(pos.size() > 0 || !"Approximator_QEM: attribute vector is empty") ; + } ~Approximator_QEM() {} ApproximatorType getType() const { return A_QEM ; } @@ -70,12 +72,14 @@ protected: VertexAttribute > m_quadric ; public: - Approximator_QEMhalfEdge(MAP& m, VertexAttribute& pos, Predictor* pred = NULL) : + Approximator_QEMhalfEdge(MAP& m, std::vector* > pos, Predictor* pred = NULL) : Approximator(m, pos, pred) - {} + { + assert(pos.size() > 0 || !"Approximator_QEMhalfEdge: attribute vector is empty") ; + } ~Approximator_QEMhalfEdge() {} - ApproximatorType getType() const { return A_QEMhalfEdge ; } + ApproximatorType getType() const { return A_hQEM ; } bool init() ; void approximate(Dart d) ; } ; @@ -88,9 +92,11 @@ public: typedef typename PFP::VEC3 VEC3 ; typedef typename PFP::REAL REAL ; - Approximator_MidEdge(MAP& m, VertexAttribute& pos, Predictor* pred = NULL) : + Approximator_MidEdge(MAP& m, std::vector* > pos, Predictor* pred = NULL) : Approximator(m, pos, pred) - {} + { + assert(pos.size() > 0 || !"Approximator_MidEdge: attribute vector is empty") ; + } ~Approximator_MidEdge() {} ApproximatorType getType() const { return A_MidEdge ; } @@ -106,12 +112,14 @@ public: typedef typename PFP::VEC3 VEC3 ; typedef typename PFP::REAL REAL ; - Approximator_HalfCollapse(MAP& m, VertexAttribute& pos, Predictor* pred = NULL) : + Approximator_HalfCollapse(MAP& m, std::vector* > pos, Predictor* pred = NULL) : Approximator(m, pos, pred) - {} + { + assert(pos.size() > 0 || !"Approximator_HalfCollapse: attribute vector is empty") ; + } ~Approximator_HalfCollapse() {} - ApproximatorType getType() const { return A_HalfCollapse ; } + ApproximatorType getType() const { return A_hHalfCollapse ; } bool init() ; void approximate(Dart d) ; } ; @@ -124,9 +132,11 @@ public: typedef typename PFP::VEC3 VEC3 ; typedef typename PFP::REAL REAL ; - Approximator_CornerCutting(MAP& m, VertexAttribute& pos, Predictor* pred = NULL) : + Approximator_CornerCutting(MAP& m, std::vector* > pos, Predictor* pred = NULL) : Approximator(m, pos, pred) - {} + { + assert(pos.size() > 0 || !"Approximator_CornerCutting: attribute vector is empty") ; + } ~Approximator_CornerCutting() {} ApproximatorType getType() const { return A_CornerCutting ; } diff --git a/include/Algo/Decimation/geometryApproximator.hpp b/include/Algo/Decimation/geometryApproximator.hpp index 3745af590f53b9a8638daf650093e6410fe0aa8e..c9aa30e8b575bda92124bead4d0324af12ebf9e6 100644 --- a/include/Algo/Decimation/geometryApproximator.hpp +++ b/include/Algo/Decimation/geometryApproximator.hpp @@ -34,11 +34,11 @@ namespace Decimation /************************************************************************************ * QUADRIC ERROR METRIC * ************************************************************************************/ - template bool Approximator_QEM::init() { m_quadric = this->m_map.template getAttribute, VERTEX>("QEMquadric") ; + // Does not require to be valid (if it is not, altenatives will be used). if(this->m_predictor) { @@ -62,7 +62,7 @@ void Approximator_QEM::approximate(Dart d) Dart it = d ; do { - Quadric q(this->m_attrV[it], this->m_attrV[m.phi1(it)], this->m_attrV[m.phi_1(it)]) ; + Quadric q(this->m_attrV[0]->operator[](it), this->m_attrV[0]->operator[](m.phi1(it)), this->m_attrV[0]->operator[](m.phi_1(it))) ; q1 += q ; it = m.phi2_1(it) ; } while(it != d) ; @@ -71,7 +71,7 @@ void Approximator_QEM::approximate(Dart d) it = dd ; do { - Quadric q(this->m_attrV[it], this->m_attrV[m.phi1(it)], this->m_attrV[m.phi_1(it)]) ; + Quadric q(this->m_attrV[0]->operator[](it), this->m_attrV[0]->operator[](m.phi1(it)), this->m_attrV[0]->operator[](m.phi_1(it))) ; q2 += q ; it = m.phi2_1(it) ; } while(it != dd) ; @@ -83,26 +83,26 @@ void Approximator_QEM::approximate(Dart d) } Quadric quad ; - quad += q1 ; // compute the sum of the - quad += q2 ; // two vertices quadrics + quad += q1 ; // compute the sum of the + quad += q2 ; // two vertices quadrics VEC3 res ; - bool opt = quad.findOptimizedPos(res) ; // try to compute an optimized position for the contraction of this edge + bool opt = quad.findOptimizedPos(res) ; // try to compute an optimized position for the contraction of this edge if(!opt) { - VEC3 p1 = this->m_attrV[d] ; // let the new vertex lie - VEC3 p2 = this->m_attrV[dd] ; // on either one of the two endpoints - VEC3 p12 = (p1 + p2) / 2.0f ; // or the middle of the edge + VEC3 p1 = this->m_attrV[0]->operator[](d) ; // let the new vertex lie + VEC3 p2 = this->m_attrV[0]->operator[](dd) ; // on either one of the two endpoints + VEC3 p12 = (p1 + p2) / 2.0f ; // or the middle of the edge REAL e1 = quad(p1) ; REAL e2 = quad(p2) ; REAL e12 = quad(p12) ; - REAL minerr = std::min(std::min(e1, e2), e12) ; // consider only the one for - if(minerr == e12) this->m_approx[d] = p12 ; // which the error is minimal - else if(minerr == e1) this->m_approx[d] = p1 ; - else this->m_approx[d] = p2 ; + REAL minerr = std::min(std::min(e1, e2), e12) ; // consider only the one for + if(minerr == e12) this->m_approx[0][d] = p12 ; // which the error is minimal + else if(minerr == e1) this->m_approx[0][d] = p1 ; + else this->m_approx[0][d] = p2 ; } else - this->m_approx[d] = res ; + this->m_approx[0][d] = res ; } /************************************************************************************ @@ -136,7 +136,7 @@ void Approximator_QEMhalfEdge::approximate(Dart d) Dart it = d ; do { - Quadric q(this->m_attrV[it], this->m_attrV[m.phi1(it)], this->m_attrV[m.phi_1(it)]) ; + Quadric q(this->m_attrV[0]->operator[](it), this->m_attrV[0]->operator[](m.phi1(it)), this->m_attrV[0]->operator[](m.phi_1(it))) ; q1 += q ; it = m.phi2_1(it) ; } while(it != d) ; @@ -145,7 +145,7 @@ void Approximator_QEMhalfEdge::approximate(Dart d) it = dd ; do { - Quadric q(this->m_attrV[it], this->m_attrV[m.phi1(it)], this->m_attrV[m.phi_1(it)]) ; + Quadric q(this->m_attrV[0]->operator[](it), this->m_attrV[0]->operator[](m.phi1(it)), this->m_attrV[0]->operator[](m.phi_1(it))) ; q2 += q ; it = m.phi2_1(it) ; } while(it != dd) ; @@ -163,9 +163,9 @@ void Approximator_QEMhalfEdge::approximate(Dart d) VEC3 res ; bool opt = quad.findOptimizedPos(res) ; // try to compute an optimized position for the contraction of this edge if(!opt) - this->m_approx[d] = this->m_attrV[d] ; + this->m_approx[0][d] = this->m_attrV[0]->operator[](d) ; else - this->m_approx[d] = res ; + this->m_approx[0][d] = res ; } /************************************************************************************ @@ -195,11 +195,11 @@ void Approximator_MidEdge::approximate(Dart d) Dart dd = m.phi2(d) ; // get the contracted edge vertices positions - VEC3 v1 = this->m_attrV[d] ; - VEC3 v2 = this->m_attrV[dd] ; + VEC3 v1 = this->m_attrV[0]->operator[](d) ; + VEC3 v2 = this->m_attrV[0]->operator[](dd) ; // Compute the approximated position - this->m_approx[d] = (v1 + v2) / REAL(2) ; + this->m_approx[0][d] = (v1 + v2) / REAL(2) ; if(this->m_predictor) { @@ -207,16 +207,16 @@ void Approximator_MidEdge::approximate(Dart d) Dart d2 = m.phi2(m.phi_1(d)) ; Dart dd2 = m.phi2(m.phi_1(dd)) ; - // VEC3 v2 = this->m_attrV[dd] ; + // VEC3 v2 = this->m_attrV[0]->operator[](dd) ; // temporary edge collapse m.extractTrianglePair(d) ; unsigned int newV = m.template embedNewCell(d2) ; - this->m_attrV[newV] = this->m_approx[d] ; + this->m_attrV[0]->operator[](newV) = this->m_approx[0][d] ; // compute the detail vector this->m_predictor->predict(d2, dd2) ; - this->m_detail[d] = v1 - this->m_predictor->getPredict(0) ; + this->m_detail[0][d] = v1 - this->m_predictor->getPredict(0) ; // vertex split to reset the initial connectivity and embeddings m.insertTrianglePair(d, d2, dd2) ; @@ -247,7 +247,8 @@ void Approximator_HalfCollapse::approximate(Dart d) { MAP& m = this->m_map ; - this->m_approx[d] = this->m_attrV[d] ; + for (unsigned int i = 0 ; i < this->m_attrV.size() ; ++i) + this->m_approx[i][d] = this->m_attrV[i]->operator[](d) ; if(this->m_predictor) { @@ -255,16 +256,22 @@ void Approximator_HalfCollapse::approximate(Dart d) Dart d2 = m.phi2(m.phi_1(d)) ; Dart dd2 = m.phi2(m.phi_1(dd)) ; - VEC3 v2 = this->m_attrV[dd] ; + VEC3 v2 = this->m_attrV[0]->operator[](dd) ; // temporary edge collapse m.extractTrianglePair(d) ; unsigned int newV = m.template embedNewCell(d2) ; - this->m_attrV[newV] = this->m_approx[d] ; + for (unsigned int i = 0 ; i < this->m_attrV.size() ; ++i) + { + this->m_attrV[i]->operator[](newV) = this->m_approx[i][d] ; + } // compute the detail vector this->m_predictor->predict(d2, dd2) ; - this->m_detail[d] = v2 - this->m_predictor->getPredict(1) ; + for (unsigned int i = 0 ; i < this->m_attrV.size() ; ++i) + { + this->m_detail[i][d] = v2 - this->m_predictor->getPredict(1) ; + } // vertex split to reset the initial connectivity and embeddings m.insertTrianglePair(d, d2, dd2) ; @@ -303,8 +310,8 @@ void Approximator_CornerCutting::approximate(Dart d) Dart dd2 = m.phi2(m.phi_1(dd)) ; // get the contracted edge vertices positions - VEC3 v1 = this->m_attrV[d] ; - VEC3 v2 = this->m_attrV[dd] ; + VEC3 v1 = this->m_attrV[0]->operator[](d) ; + VEC3 v2 = this->m_attrV[0]->operator[](dd) ; // compute the alpha value according to vertices valences REAL k1 = 0 ; @@ -329,7 +336,7 @@ void Approximator_CornerCutting::approximate(Dart d) it = d2 ; do { - m1 += this->m_attrV[m.phi1(it)] ; + m1 += this->m_attrV[0]->operator[](m.phi1(it)); it = m.phi2_1(it) ; ++count ; } while (it != d) ; @@ -341,7 +348,7 @@ void Approximator_CornerCutting::approximate(Dart d) it = dd2 ; do { - m2 += this->m_attrV[m.phi1(it)] ; + m2 += this->m_attrV[0]->operator[](m.phi1(it)); it = m.phi2_1(it) ; ++count ; } while (it != dd) ; @@ -353,11 +360,11 @@ void Approximator_CornerCutting::approximate(Dart d) VEC3 a2 = ( REAL(1) / (REAL(1) - alpha) ) * ( v2 - (alpha * m2) ) ; // Compute the final approximated position - this->m_approx[d] = (a1 + a2) / REAL(2) ; + this->m_approx[0][d] = (a1 + a2) / REAL(2) ; if(this->m_predictor) { - this->m_detail[d] = (REAL(1) - alpha) * ( (a1 - a2) / REAL(2) ) ; + this->m_detail[0][d] = (REAL(1) - alpha) * ( (a1 - a2) / REAL(2) ) ; } } diff --git a/include/Algo/Decimation/geometryPredictor.hpp b/include/Algo/Decimation/geometryPredictor.hpp index 021c8f8940b8dffe325efa5756fcc82c68745942..ad6b2ca400a7a2486ab8396fea9fd7e2061f0ce0 100644 --- a/include/Algo/Decimation/geometryPredictor.hpp +++ b/include/Algo/Decimation/geometryPredictor.hpp @@ -43,8 +43,8 @@ void Predictor_HalfCollapse::predict(Dart d2, Dart dd2) this->m_predict.clear() ; // get some darts - Dart d1 = m.phi2(d2) ; - Dart dd1 = m.phi2(dd2) ; + // Dart d1 = m.phi2(d2) ; + // Dart dd1 = m.phi2(dd2) ; REAL k2 = REAL(1) ; VEC3 s2_1(0) ; @@ -75,8 +75,8 @@ typename PFP::REAL Predictor_CornerCutting::autoAlpha(Dart d2, Dart dd2) MAP& m = this->m_map ; // get some darts - Dart d1 = m.phi2(d2) ; - Dart dd1 = m.phi2(dd2) ; + // Dart d1 = m.phi2(d2) ; + // Dart dd1 = m.phi2(dd2) ; REAL k1 = 2 ; // compute the alpha REAL k2 = 2 ; // value according to @@ -102,8 +102,8 @@ void Predictor_CornerCutting::predict(Dart d2, Dart dd2) this->m_predict.clear() ; // get some darts - Dart d1 = m.phi2(d2) ; - Dart dd1 = m.phi2(dd2) ; + // Dart d1 = m.phi2(d2) ; + // Dart dd1 = m.phi2(dd2) ; REAL alpha = autoAlpha(d2, dd2) ; diff --git a/include/Algo/Decimation/halfEdgeSelector.h b/include/Algo/Decimation/halfEdgeSelector.h index 26794b0d99784de86c7b739e58e1f11157835d7f..270eb32d6be3b4461b7bf1052961eefef35962e9 100644 --- a/include/Algo/Decimation/halfEdgeSelector.h +++ b/include/Algo/Decimation/halfEdgeSelector.h @@ -36,6 +36,9 @@ namespace Algo namespace Decimation { +/***************************************************************************************************************** + * HALF-EDGE MEMORYLESS QEM METRIC * + *****************************************************************************************************************/ template class HalfEdgeSelector_QEMml : public EdgeSelector { @@ -68,7 +71,8 @@ private: public: HalfEdgeSelector_QEMml(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : - EdgeSelector(m, pos, approx, select) + EdgeSelector(m, pos, approx, select), + m_positionApproximator(NULL) { halfEdgeInfo = m.template addAttribute("halfEdgeInfo") ; quadric = m.template addAttribute, VERTEX>("QEMquadric") ; @@ -85,8 +89,80 @@ public: void updateAfterCollapse(Dart d2, Dart dd2) ; } ; -template -class HalfEdgeSelector_Lightfield : public EdgeSelector +///***************************************************************************************************************** +// * HALF-EDGE LIGHTFIELD METRIC * +// *****************************************************************************************************************/ +//template +//class HalfEdgeSelector_Lightfield : public EdgeSelector +//{ +//public: +// typedef typename PFP::MAP MAP ; +// typedef typename PFP::VEC3 VEC3 ; +// typedef typename PFP::REAL REAL ; +// +//private: +// typedef struct +// { +// typename std::multimap::iterator it ; +// bool valid ; +// static std::string CGoGNnameOfType() { return "LightfieldHalfEdgeInfo" ; } +// } QEMhalfEdgeInfo ; +// typedef NoMathIOAttribute HalfEdgeInfo ; +// +// DartAttribute halfEdgeInfo ; +// +// VertexAttribute m_pos, m_frameT, m_frameB, m_frameN ; +// //VertexAttribute *m_HF ; +// int m_approxindex_pos, m_attrindex_pos ; +// int m_approxindex_FN, m_attrindex_FN ; +// +// VertexAttribute > m_quadricGeom ; +// VertexAttribute > m_quadricHF ; +// +// std::multimap halfEdges ; +// typename std::multimap::iterator cur ; +// +// std::vector* > m_approx ; +// +// void initHalfEdgeInfo(Dart d) ; +// void updateHalfEdgeInfo(Dart d, bool recompute) ; +// void computeHalfEdgeInfo(Dart d, HalfEdgeInfo& einfo) ; +// void recomputeQuadric(const Dart d, const bool recomputeNeighbors = false) ; +// +//public: +// HalfEdgeSelector_Lightfield(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : +// EdgeSelector(m, pos, approx, select), +//// m_positionApproximator(NULL), +//// m_frameApproximator(NULL), +//// m_hfcoefsApproximator(NULL), +//// m_pos(NULL), +//// m_frameB(NULL), +//// m_frameN(NULL), +//// m_frameT(NULL), +// m_approxindex_pos(-1), +// m_attrindex_pos(-1), +// m_approxindex_FN(-1), +// m_attrindex_FN(-1) +// { +// halfEdgeInfo = m.template addAttribute("halfEdgeInfo") ; +// m_quadricGeom = m.template addAttribute, VERTEX>("QEMquadric") ; +// m_quadricHF = m.template addAttribute, VERTEX>("HFquadric") ; +// } +// ~HalfEdgeSelector_Lightfield() +// { +// this->m_map.removeAttribute(halfEdgeInfo) ; +// this->m_map.removeAttribute(m_quadricGeom) ; +// this->m_map.removeAttribute(m_quadricHF) ; +// } +// SelectorType getType() { return S_hLightfield ; } +// bool init() ; +// bool nextEdge(Dart& d) ; +// void updateBeforeCollapse(Dart d) ; +// void updateAfterCollapse(Dart d2, Dart dd2) ; +//} ; + +/*template +class HalfEdgeSelector_Lightfield_deprecated : public EdgeSelector { public: typedef typename PFP::MAP MAP ; @@ -101,7 +177,7 @@ private: { typename std::multimap::iterator it ; bool valid ; - static std::string CGoGNnameOfType() { return "LightfieldHalfEdgeInfo" ; } + static std::string CGoGNnameOfType() { return "LightfieldHalfEdgeInfo_deprecated" ; } } LightfieldHalfEdgeInfo ; typedef NoMathIOAttribute HalfEdgeInfo ; @@ -124,7 +200,7 @@ private: void recomputeQuadric(const Dart d, const bool recomputeNeighbors) ; public: - HalfEdgeSelector_Lightfield(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : + HalfEdgeSelector_Lightfield_deprecated(MAP& m, VertexAttribute& pos, std::vector*>& approx, const FunctorSelect& select = allDarts) : EdgeSelector(m, pos, approx, select) { m_frame = m.template getAttribute("frame") ; @@ -133,20 +209,20 @@ public: quadric = m.template addAttribute, VERTEX>("QEMquadric") ; quadricRGBfunctions = m.template addAttribute, EDGE>("quadricRGBfunctions") ; } - ~HalfEdgeSelector_Lightfield() + ~HalfEdgeSelector_Lightfield_deprecated() { this->m_map.removeAttribute(quadric) ; this->m_map.removeAttribute(quadricRGBfunctions) ; this->m_map.removeAttribute(halfEdgeInfo) ; } - SelectorType getType() { return S_hLightfield ; } + SelectorType getType() { return S_hLightfield_deprecated ; } bool init() ; bool nextEdge(Dart& d) ; void updateBeforeCollapse(Dart d) ; void updateAfterCollapse(Dart d2, Dart dd2) ; } ; -/* +/ * template class EdgeSelector_Lightfield : public EdgeSelector { diff --git a/include/Algo/Decimation/halfEdgeSelector.hpp b/include/Algo/Decimation/halfEdgeSelector.hpp index 904f5b6e8addda2413234c02e638c04e8ad4b350..845a260546fc072a3443c59db6bc97658ea62496 100644 --- a/include/Algo/Decimation/halfEdgeSelector.hpp +++ b/include/Algo/Decimation/halfEdgeSelector.hpp @@ -277,528 +277,863 @@ void HalfEdgeSelector_QEMml::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& hein heinfo.valid = true ; } -/************************************************************************************ - * HALFEDGESELECTOR LIGHTFIELD * - ************************************************************************************/ - -template -bool HalfEdgeSelector_Lightfield::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 : 3 approximators in specific order - if(ok == 0 && (*it)->getApproximatedAttributeName() == "position") - { - m_positionApproximator = reinterpret_cast* >(*it) ; // 1) position - assert(m_positionApproximator->getType() != A_QEM) ; // A_QEM is not compatible for half-edge crit - ++ok ; - } - else if( ok == 1 && (*it)->getApproximatedAttributeName() == "frame") - { - m_frameApproximator = reinterpret_cast* >(*it) ; // 2) frame (needs position) - ++ok ; - } - else if(ok == 2 && (*it)->getApproximatedAttributeName() == "colorPTM") - { - m_RGBfunctionsApproximator = reinterpret_cast* >(*it) ; // 3) functions (needs frame) - ++ok ; - } - } - - if(ok != 3) - return false ; - - // Set quadric per vertex - 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) ; - } - } - - // Compute quadric per vertex - DartMarker mark(m) ; - - for(Dart d = m.begin(); d != m.end(); m.next(d)) // init QEM quadrics - { - 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) ; - } - } - - // 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_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) ; - 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 ; - - quadric[d].zero() ; - - do { - // Make step - dBack = this->m_map.phi1(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.phi1(dFront)],this->m_position[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 - Quadric quad ; - quad += quadric[d] ; // compute the sum of the - quad += quadric[dd] ; // two vertices quadrics - - this->m_positionApproximator->approximate(d) ; // sets newPos - VEC3 newPos = this->m_positionApproximator->getApprox(d) ; // get newPos - - // New Frame - this->m_frameApproximator->approximate(d) ; // sets newF - MATRIX33 newFrame = this->m_frameApproximator->getApprox(d) ; // get newF - - VEC3 n1,n2 ; - if (! m_frame[d].getSubVectorH(2,0,n1)) { // get the normals - CGoGNout << "EdgeSelector_LightField::computeEdgeInfo --> getSubVectorH 1 failed " << CGoGNendl; - exit(2) ; - } - if (!m_frame[dd].getSubVectorH(2,0,n2)) { // of the two vertices - CGoGNout << "EdgeSelector_LightField::computeEdgeInfo --> getSubVectorH 2 failed " << CGoGNendl; - exit(3) ; - } - - // New function - this->m_RGBfunctionsApproximator->approximate(d) ; // sets quadricRGBf and newRGBf - MATRIX36 newRGBf = this->m_RGBfunctionsApproximator->getApprox(d) ; // get newRGBf - - // Compute error - REAL err = quad(newPos) + (2 * acos (n1 * n2)) + quadricRGBfunctions[d](newRGBf) ; - - heinfo.it = halfEdges.insert(std::make_pair(err, d)) ; - heinfo.valid = true ; -} - -/************************************************************************************ - * EDGESELECTOR LIGHTFIELD * - ************************************************************************************ - -template -bool EdgeSelector_Lightfield::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 : 3 approximators in specific order - if(ok == 0 && (*it)->getApproximatedAttributeName() == "position") - { - m_positionApproximator = reinterpret_cast* >(*it) ; // 1) position - ++ok ; - } - else if( ok == 1 && (*it)->getApproximatedAttributeName() == "frame") - { - m_frameApproximator = reinterpret_cast* >(*it) ; // 2) frame (needs position) - ++ok ; - } - else if(ok == 2 && (*it)->getApproximatedAttributeName() == "colorPTM") - { - m_RGBfunctionsApproximator = reinterpret_cast* >(*it) ; // 3) functions (needs frame) - ++ok ; - } - } - - if(ok != 3) - 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)) // init QEM quadrics - { - 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 info - 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_Lightfield::nextEdge(Dart& d) -{ - if(cur == edges.end() || edges.empty()) - return false ; - d = (*cur).second ; - return true ; -} - -template -void EdgeSelector_Lightfield::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_Lightfield::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_Lightfield::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_Lightfield::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_Lightfield::computeEdgeInfo(Dart d, EdgeInfo& einfo) -{ - MAP& m = this->m_map ; - Dart dd = m.phi2(d) ; - - // New position - Quadric quad ; - quad += quadric[d] ; // compute the sum of the - quad += quadric[dd] ; // two vertices quadrics - - this->m_positionApproximator->approximate(d) ; // sets newPos - VEC3 newPos = this->m_positionApproximator->getApprox(d) ; // get newPos - - // New Frame - this->m_frameApproximator->approximate(d) ; // sets newF - MATRIX33 newFrame = this->m_frameApproximator->getApprox(d) ; // get newF - - VEC3 n1,n2 ; - if (! m_frame[d].getSubVectorH(2,0,n1)) { // get the normals - CGoGNout << "EdgeSelector_LightField::computeEdgeInfo --> getSubVectorH 1 failed " << CGoGNendl; - exit(2) ; - } - if (!m_frame[dd].getSubVectorH(2,0,n2)) { // of the two vertices - CGoGNout << "EdgeSelector_LightField::computeEdgeInfo --> getSubVectorH 2 failed " << CGoGNendl; - exit(3) ; - } - - // New function - this->m_RGBfunctionsApproximator->approximate(d) ; // sets quadricRGBf and newRGBf - MATRIX36 newRGBf = this->m_RGBfunctionsApproximator->getApprox(d) ; // get newRGBf - - QuadricRGBfunctions quadRGBf = quadricRGBfunctions[d]; // get quadricRGBf - - // Compute error - REAL err = quad(newPos) + (2 * acos (n1 * n2)) + quadRGBf(newRGBf) ; -// REAL t1 = quad(newPos) ; -// REAL t2 = (2 * acos (n1 * n2)) ; -// REAL t3 = quadRGBf(newRGBf) ; - - einfo.it = edges.insert(std::make_pair(err, d)) ; - einfo.valid = true ; -}*/ +///************************************************************************************ +// * HALFEDGESELECTOR LIGHTFIELD * +// ************************************************************************************/ +//template +//bool HalfEdgeSelector_Lightfield::init() +//{ +// // TODO +// 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) +// { +// 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 ; +// } +// } +// } +// } +// +// if(ok != 4) +// return false ; +// +// // Set quadric per vertex +// CellMarker vMark(m) ; +// for(Dart d = m.begin(); d != m.end(); m.next(d)) +// { +// if(!vMark.isMarked(d)) +// { +// Quadric q ; // create one quadric +// m_quadricGeom[d] = q ; // per vertex +// vMark.mark(d) ; +// } +// } +// +// // Compute quadric per vertex +// DartMarker mark(m) ; +// +// for(Dart d = m.begin(); d != m.end(); m.next(d)) // init QEM quadrics +// { +// 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]) ; +// m_quadricGeom[d] += 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 +// 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_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) ; +// 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) +//{ // TODO +// Dart dFront,dBack ; +// Dart dInit = d ; +// +// // Init Front +// dFront = dInit ; +// +// m_quadricGeom[d].zero() ; +// +// do +// { +// // Make step +// dBack = this->m_map.phi1(dFront) ; +// dFront = this->m_map.phi2_1(dFront) ; +// +// if (dBack != dFront) +// { // if dFront is no border +// m_quadricGeom[d] += 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 ; +// +// // TODO +// 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) ; +// +// // 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 +// // todo const VEC3& hfcoefs0 = this->m_approximators[m_approxindex_hf]->getApprox(d,m_attrindex_hf[0]) ; // get newHFcoefs0 +// // todo const VEC3& hfcoefs1 = this->m_approximators[m_approxindex_hf]->getApprox(d,m_attrindex_hf[1]) ; // get newHFcoefs1 +// // todo const VEC3& hfcoefs2 = this->m_approximators[m_approxindex_hf]->getApprox(d,m_attrindex_hf[2]) ; // get newHFcoefs2 +// // ... +// // todo const VEC3& hfcoefsK = this->m_approximators[m_approxindex_hf]->getApprox(d,m_attrindex_hf[K]) ; // get newHFcoefsK +// +// // Compute errors +// // Position +// Quadric quadGeom ; +// quadGeom += m_quadricGeom[d] ; // compute the sum of the +// quadGeom += m_quadricGeom[dd] ; // two vertices quadrics +// +// // hemisphere difference error +// double scal1 = abs(double(m_frameN[d] * newFN)) ; +// scal1 = std::min(scal1, double(1)) ; // for epsilon normalization of newFN errors +// // angle 2 +// double scal2 = abs(double(m_frameN[dd] * newFN)) ; +// scal2 = std::min(scal2, double(1)) ; +// // Important: sum of abs values works only if newFN is in-between the two old ones (interpolated). +// // This avoids computation of the sign of alpha1 and alpha2. +// double alpha = acos(scal1 + scal2) ; +// +// std::cout << quadGeom(newPos) << " vs " << alpha/M_PI << std::endl ; +// // sum of QEM metric and frame orientation difference +// REAL err = +// quadGeom(newPos) // geom +// + alpha / M_PI // frame +// // todo+ quadHF(newHF) // function coefficients +// ; +// +// heinfo.it = halfEdges.insert(std::make_pair(err, d)) ; +// heinfo.valid = true ; +//} + +///************************************************************************************ +// * HALFEDGESELECTOR LIGHTFIELD * +// ************************************************************************************/ +// +//template +//bool HalfEdgeSelector_Lightfield_deprecated::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 : 3 approximators in specific order +// if(ok == 0 && (*it)->getApproximatedAttributeName() == "position") +// { +// m_positionApproximator = reinterpret_cast* >(*it) ; // 1) position +// assert(m_positionApproximator->getType() != A_QEM) ; // A_QEM is not compatible for half-edge crit +// ++ok ; +// } +// else if( ok == 1 && (*it)->getApproximatedAttributeName() == "frame") +// { +// m_frameApproximator = reinterpret_cast* >(*it) ; // 2) frame (needs position) +// ++ok ; +// } +// else if(ok == 2 && (*it)->getApproximatedAttributeName() == "colorPTM") +// { +// m_RGBfunctionsApproximator = reinterpret_cast* >(*it) ; // 3) functions (needs frame) +// ++ok ; +// } +// } +// +// if(ok != 3) +// return false ; +// +// // Set quadric per vertex +// 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) ; +// } +// } +// +// // Compute quadric per vertex +// DartMarker mark(m) ; +// +// for(Dart d = m.begin(); d != m.end(); m.next(d)) // init QEM quadrics +// { +// 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) ; +// } +// } +// +// // 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_Lightfield_deprecated::nextEdge(Dart& d) +//{ +// if(cur == halfEdges.end() || halfEdges.empty()) +// return false ; +// d = (*cur).second ; +// return true ; +//} +// +//template +//void HalfEdgeSelector_Lightfield_deprecated::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) ; +// 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_deprecated::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 (dBack != dFront) { // if dFront is no border +// quadric[d] += Quadric(this->m_position[d],this->m_position[this->m_map.phi1(dFront)],this->m_position[dBack]) ; +// } +// if (recomputeNeighbors) +// recomputeQuadric(dBack, false) ; +// +// } while(dFront != dInit) ; +//} +// +//template +//void HalfEdgeSelector_Lightfield_deprecated::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_deprecated::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_deprecated::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_deprecated::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& heinfo) +//{ +// MAP& m = this->m_map ; +// Dart dd = m.phi1(d) ; +// +// // New position +// Quadric quad ; +// quad += quadric[d] ; // compute the sum of the +// quad += quadric[dd] ; // two vertices quadrics +// +// this->m_positionApproximator->approximate(d) ; // sets newPos +// VEC3 newPos = this->m_positionApproximator->getApprox(d) ; // get newPos +// +// // New Frame +// this->m_frameApproximator->approximate(d) ; // sets newF +// MATRIX33 newFrame = this->m_frameApproximator->getApprox(d) ; // get newF +// +// VEC3 n1,n2 ; +// if (! m_frame[d].getSubVectorH(2,0,n1)) { // get the normals +// CGoGNout << "EdgeSelector_LightField::computeEdgeInfo --> getSubVectorH 1 failed " << CGoGNendl; +// exit(2) ; +// } +// if (!m_frame[dd].getSubVectorH(2,0,n2)) { // of the two vertices +// CGoGNout << "EdgeSelector_LightField::computeEdgeInfo --> getSubVectorH 2 failed " << CGoGNendl; +// exit(3) ; +// } +// +// // New function +// this->m_RGBfunctionsApproximator->approximate(d) ; // sets quadricRGBf and newRGBf +// MATRIX36 newRGBf = this->m_RGBfunctionsApproximator->getApprox(d) ; // get newRGBf +// +// // Compute error +// REAL err = quad(newPos) + (2 * acos (n1 * n2)) + quadricRGBfunctions[d](newRGBf) ; +// +// heinfo.it = halfEdges.insert(std::make_pair(err, d)) ; +// heinfo.valid = true ; +//} +// +///************************************************************************************ +// * EDGESELECTOR LIGHTFIELD * +// ************************************************************************************ +// +//template +//bool EdgeSelector_Lightfield::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 : 3 approximators in specific order +// if(ok == 0 && (*it)->getApproximatedAttributeName() == "position") +// { +// m_positionApproximator = reinterpret_cast* >(*it) ; // 1) position +// ++ok ; +// } +// else if( ok == 1 && (*it)->getApproximatedAttributeName() == "frame") +// { +// m_frameApproximator = reinterpret_cast* >(*it) ; // 2) frame (needs position) +// ++ok ; +// } +// else if(ok == 2 && (*it)->getApproximatedAttributeName() == "colorPTM") +// { +// m_RGBfunctionsApproximator = reinterpret_cast* >(*it) ; // 3) functions (needs frame) +// ++ok ; +// } +// } +// +// if(ok != 3) +// 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)) // init QEM quadrics +// { +// 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 info +// 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_Lightfield::nextEdge(Dart& d) +//{ +// if(cur == edges.end() || edges.empty()) +// return false ; +// d = (*cur).second ; +// return true ; +//} +// +//template +//void EdgeSelector_Lightfield::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_Lightfield::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_Lightfield::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_Lightfield::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_Lightfield::computeEdgeInfo(Dart d, EdgeInfo& einfo) +//{ +// MAP& m = this->m_map ; +// Dart dd = m.phi2(d) ; +// +// // New position +// Quadric quad ; +// quad += quadric[d] ; // compute the sum of the +// quad += quadric[dd] ; // two vertices quadrics +// +// this->m_positionApproximator->approximate(d) ; // sets newPos +// VEC3 newPos = this->m_positionApproximator->getApprox(d) ; // get newPos +// +// // New Frame +// this->m_frameApproximator->approximate(d) ; // sets newF +// MATRIX33 newFrame = this->m_frameApproximator->getApprox(d) ; // get newF +// +// VEC3 n1,n2 ; +// if (! m_frame[d].getSubVectorH(2,0,n1)) { // get the normals +// CGoGNout << "EdgeSelector_LightField::computeEdgeInfo --> getSubVectorH 1 failed " << CGoGNendl; +// exit(2) ; +// } +// if (!m_frame[dd].getSubVectorH(2,0,n2)) { // of the two vertices +// CGoGNout << "EdgeSelector_LightField::computeEdgeInfo --> getSubVectorH 2 failed " << CGoGNendl; +// exit(3) ; +// } +// +// // New function +// this->m_RGBfunctionsApproximator->approximate(d) ; // sets quadricRGBf and newRGBf +// MATRIX36 newRGBf = this->m_RGBfunctionsApproximator->getApprox(d) ; // get newRGBf +// +// QuadricRGBfunctions quadRGBf = quadricRGBfunctions[d]; // get quadricRGBf +// +// // Compute error +// REAL err = quad(newPos) + (2 * acos (n1 * n2)) + quadRGBf(newRGBf) ; +//// REAL t1 = quad(newPos) ; +//// REAL t2 = (2 * acos (n1 * n2)) ; +//// REAL t3 = quadRGBf(newRGBf) ; +// +// einfo.it = edges.insert(std::make_pair(err, d)) ; +// einfo.valid = true ; +//}*/ } // namespace Decimation diff --git a/include/Algo/Decimation/lightfieldApproximator.h b/include/Algo/Decimation/lightfieldApproximator.h index 7839ba824d95ff04724e7acdde677cbdf9c43aeb..0a22b6a1f18f2e77cdec4ba849cba82fb3b2dd5c 100644 --- a/include/Algo/Decimation/lightfieldApproximator.h +++ b/include/Algo/Decimation/lightfieldApproximator.h @@ -38,107 +38,190 @@ namespace Decimation { template -class Approximator_FrameHalf : public Approximator > +class Approximator_FrameInterpolation : public Approximator { public: typedef typename PFP::MAP MAP ; typedef typename PFP::VEC3 VEC3 ; typedef typename PFP::REAL REAL ; - typedef Geom::Matrix<3,3,REAL> MATRIX33 ; - typedef Geom::Matrix<3,6,REAL> MATRIX36 ; +protected: + VertexAttribute m_position ; + EdgeAttribute m_approxposition ; + + VertexAttribute *m_frameT ; + VertexAttribute *m_frameB ; + VertexAttribute *m_frameN ; public: - Approximator_FrameHalf(MAP& m, VertexAttribute& frame, Predictor* pred = NULL) : - Approximator(m, frame, pred) + Approximator_FrameInterpolation(MAP& m, std::vector* >& attr, Predictor* pred = NULL) : + Approximator(m, attr, pred), + m_frameT(NULL), + m_frameB(NULL), + m_frameN(NULL) + { + if (this->m_attrV.size() < 3) + std::cerr << "Approximator_FrameInterpolation: not enough attributes provided (only " << this->m_attrV.size() << " instead of 3)" << std::endl ; + + m_frameT = this->m_attrV[0] ; + m_frameB = this->m_attrV[1] ; + m_frameN = this->m_attrV[2] ; + } + + ~Approximator_FrameInterpolation() {} - ~Approximator_FrameHalf() - {} - ApproximatorType getType() const { return A_LightfieldHalf ; } - bool init() { return true ; } ; - void approximate(Dart d) ; -} ; -template -class Approximator_RGBfunctionsHalf : public Approximator > -{ -public: - typedef typename PFP::MAP MAP ; - typedef typename PFP::VEC3 VEC3 ; - typedef typename PFP::REAL REAL ; + ApproximatorType getType() const + { + return A_Lightfield ; + } - typedef Geom::Matrix<3,3,REAL> MATRIX33 ; - typedef Geom::Matrix<3,6,REAL> MATRIX36 ; + bool init() + { + assert(m_frameT->isValid() || !"Approximator_FrameInterpolation: the first approximated attribute is not valid") ; + assert(m_frameB->isValid() || !"Approximator_FrameInterpolation: the second approximated attribute is not valid") ; + assert(m_frameN->isValid() || !"Approximator_FrameInterpolation: the third approximated attribute is not valid") ; -protected: - VertexAttribute m_frame ; - EdgeAttribute m_approxFrame ; - EdgeAttribute > m_quadricRGBfunctions ; + m_position = this->m_map.template getAttribute("position") ; + assert(m_position.isValid() || !"Approximator_FrameInterpolation::init: the position attribute is not valid") ; + + m_approxposition = this->m_map.template getAttribute("approx_position") ; + assert(m_approxposition.isValid() || !"Approximator_FrameInterpolation::init: the approx_position attribute is not valid") ; + + return m_frameT->isValid() && m_frameB->isValid() && m_frameN->isValid() && m_position.isValid() && m_approxposition.isValid() ; + } -public: - Approximator_RGBfunctionsHalf(MAP& m, VertexAttribute& rgbfunctions, Predictor* pred = NULL) : - Approximator(m, rgbfunctions, pred) - { } - ~Approximator_RGBfunctionsHalf () - {} - ApproximatorType getType() const { return A_LightfieldHalf ; } - bool init() ; void approximate(Dart d) ; } ; template -class Approximator_Frame : public Approximator > +class Approximator_HemiFuncCoefs: public Approximator { public: typedef typename PFP::MAP MAP ; typedef typename PFP::VEC3 VEC3 ; typedef typename PFP::REAL REAL ; - typedef Geom::Matrix<3,3,REAL> MATRIX33 ; - typedef Geom::Matrix<3,6,REAL> MATRIX36 ; - -protected: - VertexAttribute m_position ; - EdgeAttribute m_approxPosition ; + unsigned int m_nbCoefs ; + unsigned int m_HFtype ; -public: - Approximator_Frame(MAP& m, VertexAttribute& frame, Predictor* pred = NULL) : - Approximator(m, frame, pred) - {} - ~Approximator_Frame() - {} - ApproximatorType getType() const { return A_LightfieldFull ; } - bool init() ; - void approximate(Dart d) ; -} ; + VertexAttribute m_frameT ; + VertexAttribute m_frameB ; + VertexAttribute m_frameN ; -template -class Approximator_RGBfunctions : public Approximator > -{ -public: - typedef typename PFP::MAP MAP ; - typedef typename PFP::VEC3 VEC3 ; - typedef typename PFP::REAL REAL ; + EdgeAttribute m_newFrameT ; + EdgeAttribute m_newFrameB ; + EdgeAttribute m_newFrameN ; - typedef Geom::Matrix<3,3,REAL> MATRIX33 ; - typedef Geom::Matrix<3,6,REAL> MATRIX36 ; + std::vector* > m_coefs ; -protected: - VertexAttribute m_frame ; - EdgeAttribute m_approxFrame ; - EdgeAttribute > m_quadricRGBfunctions ; + VertexAttribute > m_quadricHF ; public: - Approximator_RGBfunctions(MAP& m, VertexAttribute& rgbfunctions, Predictor* pred = NULL) : - Approximator(m, rgbfunctions, pred) - { } - ~Approximator_RGBfunctions() + Approximator_HemiFuncCoefs(MAP& m, std::vector* >& attr, Predictor* pred = NULL) : + Approximator(m, attr, pred), + m_nbCoefs(0), + m_HFtype(0) // SH = 0 + { + // check name of number 0 + if (this->m_attrV[0]->name().find("SH") != std::string::npos) + m_HFtype = 1 ; + + unsigned int i ; + for (i = 1 ; i < 200 ; ++i) + { + // check if number i is present + if ((this->m_attrV.size() <= i) || this->m_attrV[i]->name().find("coefs") == std::string::npos) + break ; + + m_coefs.push_back(this->m_attrV[i]) ; + } + m_nbCoefs = i - 1 ; + } + ~Approximator_HemiFuncCoefs() {} - ApproximatorType getType() const { return A_LightfieldFull ; } + + ApproximatorType getType() const + { + return A_Lightfield ; + } + bool init() ; + void approximate(Dart d) ; } ; +//template +//class Approximator_FrameHalf : public Approximator +//{ +//public: +// typedef typename PFP::MAP MAP ; +// typedef typename PFP::VEC3 VEC3 ; +// typedef typename PFP::REAL REAL ; +// +//protected: +// VertexAttribute *m_frameT ; +// VertexAttribute *m_frameB ; +// VertexAttribute *m_frameN ; +// +//public: +// Approximator_FrameHalf(MAP& m, std::vector* >& attr, Predictor* pred = NULL) : +// Approximator(m, attr, pred) +// { +// if (this->m_attrV.size() < 3) +// std::cerr << "Approximator_Frame: not enough attributes provided (only " << this->m_attrV.size() << " instead of 3)" << std::endl ; +// +// m_frameT = this->m_attrV[0] ; +// m_frameB = this->m_attrV[1] ; +// m_frameN = this->m_attrV[2] ; +// assert(m_frameT->isValid() || !"Approximator_FrameHalf: the first approximated attribute is not valid") ; +// assert(m_frameB->isValid() || !"Approximator_FrameHalf: the second approximated attribute is not valid") ; +// assert(m_frameN->isValid() || !"Approximator_FrameHalf: the third approximated attribute is not valid") ; +// } +// ~Approximator_FrameHalf() +// {} +// +// ApproximatorType getType() const +// { +// return A_hLightfieldHalf ; +// } +// +// bool init() +// { +// return true ; +// } +// +// void approximate(Dart d) ; +//} ; +// +//template +//class Approximator_LightfieldCoefsHalf : public Approximator +//{ +//public: +// typedef typename PFP::MAP MAP ; +// typedef typename PFP::VEC3 VEC3 ; +// typedef typename PFP::REAL REAL ; +// +//public: +// Approximator_LightfieldCoefsHalf(MAP& m, std::vector >& attr, Predictor* pred = NULL) : +// Approximator(m, attr, pred) +// {} +// ~Approximator_LightfieldCoefsHalf() +// {} +// +// ApproximatorType getType() const +// { +// return A_hLightfieldHalf ; +// } +// +// bool init() +// { +// return true ; +// } +// +// void approximate(Dart d) ; +//} ; + } //namespace Decimation } //namespace Algo diff --git a/include/Algo/Decimation/lightfieldApproximator.hpp b/include/Algo/Decimation/lightfieldApproximator.hpp index 9631e1461041bb68151b4cc54c20409c1979e829..4380667c8ecb5f19568ff975774a20f599c7f18a 100644 --- a/include/Algo/Decimation/lightfieldApproximator.hpp +++ b/include/Algo/Decimation/lightfieldApproximator.hpp @@ -32,254 +32,151 @@ namespace Decimation { /************************************************************************************ - * LIGHTFIELD QUADRIC METRIC : frame * + * FRAME INTERPOLATION APPROXIMATOR * ************************************************************************************/ template -void Approximator_FrameHalf::approximate(Dart d) +void Approximator_FrameInterpolation::approximate(Dart d) { - this->m_approx[d] = this->m_attrV[d] ; -} - -/************************************************************************************ - * LIGHTFIELD QUADRIC METRIC : functions * - ************************************************************************************/ - -template -bool Approximator_RGBfunctionsHalf::init() -{ - // get actual frames and hypothetical approximated frames - m_frame = this->m_map.template getAttribute("frame") ; - m_approxFrame = this->m_map.template getAttribute("approx_frame") ; - m_quadricRGBfunctions = this->m_map.template getAttribute, EDGE>("quadricRGBfunctions") ; - - MapBrowserLinked mb(this->m_map) ; - this->m_map.template foreach_orbit(mb) ; + const Dart dd = this->m_map.phi2(d) ; - // create quadric embedding for computing and set them to 0 - for (Dart d = mb.begin() ; d != mb.end() ; mb.next(d)) - m_quadricRGBfunctions[d].zero() ; - - // Check on embeddings - if (!m_frame.isValid() || !m_approxFrame.isValid() || !m_quadricRGBfunctions.isValid()) + // if QEM placed new vertex at one of the previous : place same frame + if (this->m_approxposition[d] == this->m_position[d]) // new Position is position of vertex d { - CGoGNerr << "Approximator_RGBfunctions::init() --> No approxPosition or no quadricRGBfunctions specified" << CGoGNendl ; - return false ; + for (unsigned int i = 0 ; i < 3 ; ++i) + this->m_approx[i][d] = this->m_attrV[i]->operator[](d) ; } - - return true ; -} - -template -void Approximator_RGBfunctionsHalf::approximate(Dart d) -{ - MAP& m = this->m_map ; - Dart dd = m.phi2(d) ; // get the two vertices - - // Approximation - this->m_approx[d] = this->m_attrV[d] ; - - // Compute quadrics for error evaluation - // get hypothetical local frames - VEC3 i,n ; - - m_approxFrame[d].getSubVectorH(0,0,i) ; - m_approxFrame[d].getSubVectorH(2,0,n) ; - - // Get previous local frames - VEC3 n1,n2,i1,i2,j1,j2 ; - - m_frame[d].getSubVectorH(0,0,i1) ; - m_frame[dd].getSubVectorH(0,0,i2) ; - - m_frame[d].getSubVectorH(1,0,j1) ; - m_frame[dd].getSubVectorH(1,0,j2) ; - - m_frame[d].getSubVectorH(2,0,n1) ; - m_frame[dd].getSubVectorH(2,0,n2) ; - - // Compute j1' and j2' - VEC3 j1pr = n1 ^ i ; - j1pr.normalize() ; - VEC3 j2pr = n2 ^ i ; - j2pr.normalize() ; - - // Rotation dans sens trigo dans le plan tangent autour de n (i1->i) -// REAL gamma1 = ((j1 * i) > 0 ? 1 : -1) * acos( std::max(std::min(1.0f, i1 * i ), -1.0f)) ; // angle positif ssi - REAL gamma2 = ((j2 * i) > 0 ? 1 : -1) * acos( std::max(std::min(1.0f, i2 * i ), -1.0f)) ; // -PI/2 < angle(i,j1) < PI/2 ssi i*j1 > 0 - // Rotation dans le sens trigo autour de l'axe i (n1->n) -// REAL phi2_1 = ((n * j1pr) > 0 ? -1 : 1) * acos( std::max(std::min(1.0f, n * n1), -1.0f) ) ; // angle positif ssi - REAL alpha2 = ((n * j2pr) > 0 ? -1 : 1) * acos( std::max(std::min(1.0f, n * n2), -1.0f) ) ; // PI/2 < angle(j1',n) < -PI/2 ssi j1'*n < 0 - -// assert (-0.01 < gamma1 && gamma1 < 0.01) ; -// assert (-0.01 < phi2_1 && phi2_1 < 0.01) ; - REAL gamma1 = REAL(0) ; - REAL phi2_1 = REAL(0) ; - - // Create and sum quadrics - m_quadricRGBfunctions[d] += QuadricRGBfunctions(this->m_attrV[d], gamma1, phi2_1) ; - m_quadricRGBfunctions[d] += QuadricRGBfunctions(this->m_attrV[dd], gamma2, alpha2) ; -} - -/************************************************************************************ - * LIGHTFIELD QUADRIC METRIC : frame * - ************************************************************************************/ - -template -bool Approximator_Frame::init() -{ - m_position = this->m_map.template getAttribute("position") ; - m_approxPosition = this->m_map.template getAttribute("approx_position") ; - - if (!m_position.isValid() || !m_approxPosition.isValid()) + else if (this->m_approxposition[d] == this->m_position[dd]) // new Position is position of vertex dd { - CGoGNerr << "Approximator_Frame::init() --> No approxPosition or no quadricRGBfunctions specified" << CGoGNendl ; - return false ; + for (unsigned int i = 0 ; i < 3 ; ++i) + this->m_approx[i][d] = this->m_attrV[i]->operator[](dd) ; } - return true ; -} - -template -void Approximator_Frame::approximate(Dart d) -{ - MAP& m = this->m_map ; - Dart dd = m.phi2(d) ; // get 2 vertices - - // if QEM placed new vertex at one of the previous : place same frame - if (this->m_approxPosition[d] == this->m_position[d]) // new Position is position of vertex d - this->m_approx[d] = this->m_attrV[d] ; - else if (this->m_approxPosition[d] == this->m_position[dd]) // new Position is position of vertex dd - this->m_approx[d] = this->m_attrV[dd] ; - else { + else + { // Create two segments : v0-v1 and v0-v - VEC3 segment = this->m_position[dd] ; - segment -= this->m_position[d] ; + VEC3 v0v1 = this->m_position[dd] ; + v0v1 -= this->m_position[d] ; - VEC3 segmentNew = m_approxPosition[d] ; - segmentNew -= this->m_position[d] ; + VEC3 v0v = this->m_approxposition[d] ; + v0v -= this->m_position[d] ; // Orthogonal projection of v0-v onto v0-v1 : get coefficient t - REAL t = (segment * segmentNew) / segment.norm() ; + REAL t = (v0v1 * v0v) / v0v1.norm() ; t = std::max (std::min (t , REAL(1)) , REAL(0) ) ; // clamp it to [0,1] - VEC3 n1, n2 ; - this->m_attrV[d].getSubVectorH(2, 0, n1) ; // get normal n1 - this->m_attrV[dd].getSubVectorH(2, 0, n2) ; // get normal n2 + const VEC3& normal1 = this->m_attrV[2]->operator[](d) ; + const VEC3& normal2 = this->m_attrV[2]->operator[](dd) ; - VEC3 newN = slerp(n1,n2,t) ; // spherical interpolation + VEC3 newN = slerp(normal1,normal2,t) ; // spherical interpolation newN.normalize() ; - VEC3 newI = n2 ^ n1 ; // i is perpendicular to newNormal - newI.normalize() ; + VEC3 newT = normal2 ^ normal1 ; // i is perpendicular to newNormal + newT.normalize() ; - VEC3 newJ = newN ^ newI ; // (i,j,n) is a direct frame - newJ.normalize() ; + VEC3 newB = newN ^ newT ; // (i,j,n) is a direct frame + newB.normalize() ; // save into m_approx - if (!this->m_approx[d].setSubVectorH(0,0,newI) || - !this->m_approx[d].setSubVectorH(1,0,newJ) || - !this->m_approx[d].setSubVectorH(2,0,newN) ) - assert(!"Approximator_Frame::approximate") ; + this->m_approx[0][d] = newT ; + this->m_approx[1][d] = newB ; + this->m_approx[2][d] = newN ; } - } /************************************************************************************ - * LIGHTFIELD QUADRIC METRIC : functions * + * HEMIFUNCTION COEFS APPROXIMATOR * ************************************************************************************/ template -bool Approximator_RGBfunctions::init() +bool Approximator_HemiFuncCoefs::init() { - // get actual frames and hypothetical approximated frames - m_frame = this->m_map.template getAttribute("frame") ; - m_approxFrame = this->m_map.template getAttribute("approx_frame") ; - m_quadricRGBfunctions = this->m_map.template getAttribute, EDGE>("quadricRGBfunctions") ; + // get frames + m_frameT = this->m_map.template getAttribute("frameT") ; + m_frameB = this->m_map.template getAttribute("frameB") ; + m_frameN = this->m_map.template getAttribute("frameN") ; - MapBrowserLinked mb(this->m_map) ; - this->m_map.template foreach_orbit(mb) ; + assert((m_frameT.isValid() && m_frameB.isValid() && m_frameN.isValid()) || !"Frame embeddings are not set") ; - // create quadric embedding for computing and set them to 0 - for (Dart d = mb.begin() ; d != mb.end() ; mb.next(d)) - m_quadricRGBfunctions[d].zero() ; + m_newFrameT = this->m_map.template getAttribute("approx_frameT") ; + m_newFrameB = this->m_map.template getAttribute("approx_frameB") ; + m_newFrameN = this->m_map.template getAttribute("approx_frameN") ; - // Check on embeddings - if (!m_frame.isValid() || !m_approxFrame.isValid() || !m_quadricRGBfunctions.isValid()) + assert((m_newFrameT.isValid() && m_newFrameB.isValid() && m_frameN.isValid()) + || !"New frame embeddings are not set") ; + + // get quadric + m_quadricHF = this->m_map.template getAttribute, VERTEX>("HFquadric") ; + // Does not require to be valid (if it is not, altenatives will be used). + + if(this->m_predictor) { - CGoGNerr << "Approximator_RGBfunctions::init() --> No approxPosition or no quadricRGBfunctions specified" << CGoGNendl ; return false ; } - return true ; + + return m_frameT.isValid() && m_frameB.isValid() && m_frameN.isValid() && m_newFrameT.isValid() && m_newFrameB.isValid() && m_newFrameN.isValid() && (m_nbCoefs > 0) ; } template -void Approximator_RGBfunctions::approximate(Dart d) +void Approximator_HemiFuncCoefs::approximate(Dart d) { - MAP& m = this->m_map ; - Dart dd = m.phi1(d) ; // get the two vertices - - // get hypothetical local frames - VEC3 i,n ; + const Dart& dd = this->m_map.phi1(d) ; - m_approxFrame[d].getSubVectorH(0,0,i) ; - m_approxFrame[d].getSubVectorH(2,0,n) ; - - // Get previous local frames - VEC3 n1,n2,i1,i2,j1,j2 ; - - m_frame[d].getSubVectorH(0,0,i1) ; - m_frame[dd].getSubVectorH(0,0,i2) ; - - m_frame[d].getSubVectorH(1,0,j1) ; - m_frame[dd].getSubVectorH(1,0,j2) ; - - m_frame[d].getSubVectorH(2,0,n1) ; - m_frame[dd].getSubVectorH(2,0,n2) ; - - // Compute j1' and j2' - VEC3 j1pr = n1 ^ i ; - j1pr.normalize() ; - VEC3 j2pr = n2 ^ i ; - j2pr.normalize() ; - - // Rotation dans sens trigo dans le plan tangent autour de n (i1->i) - REAL gamma1 = ((j1 * i) > 0 ? 1 : -1) * acos( std::max(std::min(1.0f, i1 * i ), -1.0f)) ; // angle positif ssi - REAL gamma2 = ((j2 * i) > 0 ? 1 : -1) * acos( std::max(std::min(1.0f, i2 * i ), -1.0f)) ; // -PI/2 < angle(i,j1) < PI/2 ssi i*j1 > 0 - // Rotation dans le sens trigo autour de l'axe i (n1->n) - REAL phi2_1 = ((n * j1pr) > 0 ? -1 : 1) * acos( std::max(std::min(1.0f, n * n1), -1.0f) ) ; // angle positif ssi - REAL alpha2 = ((n * j2pr) > 0 ? -1 : 1) * acos( std::max(std::min(1.0f, n * n2), -1.0f) ) ; // PI/2 < angle(j1',n) < -PI/2 ssi j1'*n < 0 - -// assert (-3.15 < gamma1 && gamma1 <= 3.15) ; -// assert (-3.15 < gamma2 && gamma2 <= 3.15) ; -// assert (-3.15 < phi2_1 && phi2_1 <= 3.15) ; -// assert (-3.15 < alpha2 && alpha2 <= 3.15) ; - -// MATRIX36 &f1 = this->m_attrV[d] ; -// MATRIX36 &f2 = this->m_attrV[dd] ; - - // Create and sum quadrics - m_quadricRGBfunctions[d].zero() ; - m_quadricRGBfunctions[d] += QuadricRGBfunctions(this->m_attrV[d], gamma1, phi2_1) ; - m_quadricRGBfunctions[d] += QuadricRGBfunctions(this->m_attrV[dd], gamma2, alpha2) ; + QuadricHF q ; + if (m_quadricHF.isValid()) // if the selector does provide a quadricHF + { + q = m_quadricHF[d] ; + q += m_quadricHF[dd] ; + } + else // the selector does not provide a quadricHF + { + // get coefs of v1 and v2 + std::vector coefs1, coefs2 ; + coefs1.resize(m_nbCoefs) ; coefs2.resize(m_nbCoefs) ; + for (unsigned int i = 0 ; i < m_nbCoefs ; ++i) + { + coefs1[i] = m_coefs[i]->operator[](d) ; + coefs2[i] = m_coefs[i]->operator[](dd) ; + } + + const VEC3& T = m_newFrameT[d] ; + const VEC3& T1 = m_frameT[d] ; + const VEC3& T2 = m_frameT[dd] ; + const VEC3& B1 = m_newFrameB[d] ; + const VEC3& B2 = m_newFrameB[d] ; + const VEC3& N = m_frameN[d] ; + const VEC3& N1 = m_newFrameN[d] ; + const VEC3& N2 = m_newFrameN[dd] ; + + assert(T * (N1 ^ N2) > 0.99 || !"T is not an intersection of the two tangent planes") ; + + // Compute D1' and D2' + VEC3 B1prime = N1 ^ T ; + B1prime.normalize() ; + VEC3 B2prime = N2 ^ T ; + B2prime.normalize() ; + + // Rotation dans sens trigo dans le plan tangent autour de N (T1 --> T) + const REAL gamma1 = ((B1 * T) > 0 ? 1 : -1) * acos( std::max(std::min(1.0f, T1 * T ), -1.0f)) ; // angle positif ssi + const REAL gamma2 = ((B2 * T) > 0 ? 1 : -1) * acos( std::max(std::min(1.0f, T2 * T ), -1.0f)) ; // -PI/2 < angle(i,j1) < PI/2 ssi i*j1 > 0 + // Rotation dans le sens trigo autour de l'axe T (N1 --> N) + const REAL alpha1 = ((N * B1prime) > 0 ? -1 : 1) * acos( std::max(std::min(1.0f, N * N1), -1.0f) ) ; // angle positif ssi + const REAL alpha2 = ((N * B2prime) > 0 ? -1 : 1) * acos( std::max(std::min(1.0f, N * N2), -1.0f) ) ; // PI/2 < angle(j1',n) < -PI/2 ssi j1'*n < 0 + + // Create and sum quadrics + q = QuadricHF(coefs1, gamma1, alpha1) ; + q += QuadricHF(coefs2, gamma2, alpha2) ; + } + std::vector coefs ; // Compute new function - if (! m_quadricRGBfunctions[d].findOptimizedRGBfunctions(this->m_approx[d])) { - this->m_approx[d] = this->m_attrV[d]; // if fail take first one - } -// MATRIX36 &newF = this->m_approx[d] ; -// CGoGNout << "Approx of : " <m_attrV[d] << CGoGNendl ; -// CGoGNout << "gamma1 : " << gamma1 << CGoGNendl ; -// CGoGNout << "Frame2 : " << m_frame[dd] << CGoGNendl ; -// CGoGNout << "Function2 : "<< this->m_attrV[dd] << CGoGNendl ; -// CGoGNout << "gamma2 : " << gamma2 << CGoGNendl ; -// CGoGNout << "is " << CGoGNendl ; -// CGoGNout << "Frame :" << m_approxFrame[d] << CGoGNendl ; -// CGoGNout << "Function : " << this->m_approx[d] << CGoGNendl ; -// CGoGNout << CGoGNendl ; + bool opt = q.findOptimizedCoefs(coefs) ; + // copy result + for (unsigned int i = 0 ; i < m_nbCoefs ; ++i) + this->m_approx[i][d] = opt ? (m_coefs[i]->operator[](d) + m_coefs[i]->operator[](dd))/2 : m_coefs[i]->operator[](d) ; // if fail take first one + assert(false || !"TODO: what todo when fail") ; } + } //namespace Decimation } //namespace Algo diff --git a/include/Algo/Decimation/selector.h b/include/Algo/Decimation/selector.h index e39d77ad50470b74eae20526a09c843bea12cc09..73376d032b9b24b981939882f519ec27cf915071 100644 --- a/include/Algo/Decimation/selector.h +++ b/include/Algo/Decimation/selector.h @@ -36,15 +36,18 @@ namespace Decimation enum SelectorType { - S_MapOrder, + S_MapOrder = 0, S_Random, S_EdgeLength, S_QEM, S_QEMml, S_MinDetail, S_Curvature, - S_hQEMml, - S_hLightfield + S_ColorNaive, + S_QEMextColor, + S_Lightfield, + // note: the following "h" prefix means that half-edges are prioritized instead of edges. + S_hQEMml } ; template class ApproximatorGen ; diff --git a/include/Algo/Export/export.hpp b/include/Algo/Export/export.hpp index c901216f9cc94c48ace03bec1046a683237478e3..5c36e524769b42f04665b375a4ed9c8995a02b59 100644 --- a/include/Algo/Export/export.hpp +++ b/include/Algo/Export/export.hpp @@ -259,9 +259,9 @@ bool exportPLYnew(typename PFP::MAP& map, const std::vectorname().compare("color") == 0) // vertex color property { - out << "property " << nameOfTypePly((*(*attrHandler))[0][0]) << " red" << std::endl ; - out << "property " << nameOfTypePly((*(*attrHandler))[0][1]) << " green" << std::endl ; - out << "property " << nameOfTypePly((*(*attrHandler))[0][2]) << " blue" << std::endl ; + out << "property " << nameOfTypePly((*(*attrHandler))[0][0]) << " r" << std::endl ; + out << "property " << nameOfTypePly((*(*attrHandler))[0][1]) << " g" << std::endl ; + out << "property " << nameOfTypePly((*(*attrHandler))[0][2]) << " b" << std::endl ; } else // other vertex properties { diff --git a/include/Algo/Import/import2tablesSurface.hpp b/include/Algo/Import/import2tablesSurface.hpp index 30522b49a10b70fe23d5b890c80d9328a5d335e6..793d4f473791525b4da3f3faf05230b1288decd5 100644 --- a/include/Algo/Import/import2tablesSurface.hpp +++ b/include/Algo/Import/import2tablesSurface.hpp @@ -614,7 +614,7 @@ bool MeshTablesSurface::importPly(const std::string& filename, std::vector< unsigned int id = container.insertLine(); positions[id] = pos; - if (pid.hasColors()) + if (pid.hasColorsUint8()) { Geom::Vector<3, unsigned char> col ; pid.vertexColorUint8(i, col) ; @@ -624,6 +624,16 @@ bool MeshTablesSurface::importPly(const std::string& filename, std::vector< colors[id] /= 255.0 ; } + if (pid.hasColorsFloat32()) + { + Geom::Vector<3, float> col ; + pid.vertexColorFloat32(i, col) ; + colors[id][0] = col[0] ; + colors[id][1] = col[1] ; + colors[id][2] = col[2] ; + } + + verticesID.push_back(id); } diff --git a/include/Algo/ProgressiveMesh/pmesh.h b/include/Algo/ProgressiveMesh/pmesh.h index 73a77abbd1dd0babd259ec4b47da5affd7b33c04..7fdd4191624c8707b5d32ffc513991456100549a 100644 --- a/include/Algo/ProgressiveMesh/pmesh.h +++ b/include/Algo/ProgressiveMesh/pmesh.h @@ -31,7 +31,7 @@ #include "Algo/Decimation/edgeSelector.h" #include "Algo/Decimation/geometryApproximator.h" #include "Algo/Decimation/geometryPredictor.h" -#include "Algo/Decimation/lightfieldApproximator.h" +#include "Algo/Decimation/colorPerVertexApproximator.h" #include "Utils/quantization.h" diff --git a/include/Algo/ProgressiveMesh/pmesh.hpp b/include/Algo/ProgressiveMesh/pmesh.hpp index 1579520ccf83863201636c3a6e38b587f7fc3e34..3032d5188d21c7b57b9fffb757a87a6d0a6cf6d4 100644 --- a/include/Algo/ProgressiveMesh/pmesh.hpp +++ b/include/Algo/ProgressiveMesh/pmesh.hpp @@ -42,33 +42,36 @@ ProgressiveMesh::ProgressiveMesh( m_map(map), positionsTable(position), inactiveMarker(inactive), dartSelect(inactiveMarker) { CGoGNout << " creating approximator and predictor.." << CGoGNflush ; + + std::vector* > pos_v ; + pos_v.push_back(&positionsTable) ; switch(a) { case Algo::Decimation::A_QEM : { - m_approximators.push_back(new Algo::Decimation::Approximator_QEM(m_map, positionsTable)) ; + m_approximators.push_back(new Algo::Decimation::Approximator_QEM(m_map, pos_v)) ; break ; } case Algo::Decimation::A_MidEdge : { - m_approximators.push_back(new Algo::Decimation::Approximator_MidEdge(m_map, positionsTable)) ; + m_approximators.push_back(new Algo::Decimation::Approximator_MidEdge(m_map, pos_v)) ; break ; } - case Algo::Decimation::A_HalfCollapse : { + case Algo::Decimation::A_hHalfCollapse : { Algo::Decimation::Predictor_HalfCollapse* pred = new Algo::Decimation::Predictor_HalfCollapse(m_map, positionsTable) ; m_predictors.push_back(pred) ; - m_approximators.push_back(new Algo::Decimation::Approximator_HalfCollapse(m_map, positionsTable, pred)) ; + m_approximators.push_back(new Algo::Decimation::Approximator_HalfCollapse(m_map, pos_v, pred)) ; break ; } case Algo::Decimation::A_CornerCutting : { Algo::Decimation::Predictor_CornerCutting* pred = new Algo::Decimation::Predictor_CornerCutting(m_map, positionsTable) ; m_predictors.push_back(pred) ; - m_approximators.push_back(new Algo::Decimation::Approximator_CornerCutting(m_map, positionsTable, pred)) ; + m_approximators.push_back(new Algo::Decimation::Approximator_CornerCutting(m_map, pos_v, pred)) ; break ; } case Algo::Decimation::A_TangentPredict1 : { Algo::Decimation::Predictor_TangentPredict1* pred = new Algo::Decimation::Predictor_TangentPredict1(m_map, positionsTable) ; m_predictors.push_back(pred) ; - m_approximators.push_back(new Algo::Decimation::Approximator_MidEdge(m_map, positionsTable, pred)) ; + m_approximators.push_back(new Algo::Decimation::Approximator_MidEdge(m_map, pos_v, pred)) ; break ; } case Algo::Decimation::A_TangentPredict2 : { Algo::Decimation::Predictor_TangentPredict2* pred = new Algo::Decimation::Predictor_TangentPredict2(m_map, positionsTable) ; m_predictors.push_back(pred) ; - m_approximators.push_back(new Algo::Decimation::Approximator_MidEdge(m_map, positionsTable, pred)) ; + m_approximators.push_back(new Algo::Decimation::Approximator_MidEdge(m_map, pos_v, pred)) ; break ; } } CGoGNout << "..done" << CGoGNendl ; @@ -230,8 +233,8 @@ void ProgressiveMesh::coarsen() VSplit* vs = m_splits[m_cur] ; // get the split node ++m_cur ; - Dart d = vs->getEdge() ; - Dart dd = m_map.phi2(d) ; // get some darts + // Dart d = vs->getEdge() ; + // Dart dd = m_map.phi2(d) ; // get some darts Dart d2 = vs->getLeftEdge() ; Dart dd2 = vs->getRightEdge() ; @@ -304,7 +307,7 @@ void ProgressiveMesh::refine() detailTransform = &invLocalFrame ; (*pit)->affectPredict(d) ; - if((*ait)->getType() == Algo::Decimation::A_HalfCollapse) + if((*ait)->getType() == Algo::Decimation::A_hHalfCollapse) { (*ait)->addDetail(dd, m_detailAmount, true, detailTransform) ; } @@ -429,7 +432,7 @@ void ProgressiveMesh::initQuantization() gotoLevel(nbSplits()) ; originalDetailVectors.resize(m_splits.size()) ; for(unsigned int i = 0; i < m_splits.size(); ++i) - originalDetailVectors[i] = m_positionApproximator->getDetail(m_splits[i]->getEdge()) ; + originalDetailVectors[i] = m_positionApproximator->getDetail(m_splits[i]->getEdge(),0) ; q = new Quantization(originalDetailVectors) ; quantizationInitialized = true ; CGoGNout << " Differential Entropy -> " << q->getDifferentialEntropy() << CGoGNendl ; @@ -446,7 +449,7 @@ void ProgressiveMesh::quantizeDetailVectors(unsigned int nbClasses) std::vector resultat; q->vectorQuantizationNbRegions(nbClasses, resultat) ; for(unsigned int i = 0; i < m_splits.size(); ++i) - m_positionApproximator->setDetail(m_splits[i]->getEdge(), resultat[i]) ; + m_positionApproximator->setDetail(m_splits[i]->getEdge(), 0, resultat[i]) ; quantizationApplied = true ; gotoLevel(0) ; CGoGNout << "Discrete Entropy -> " << q->getDiscreteEntropy() << " (codebook size : " << q->getNbCodeVectors() << ")" << CGoGNendl ; diff --git a/include/Geometry/matrix.hpp b/include/Geometry/matrix.hpp index 29093a5936246145f8b1420266901035086acd15..ba078da2b4399c41f865d82ade241c7d7f34db18 100644 --- a/include/Geometry/matrix.hpp +++ b/include/Geometry/matrix.hpp @@ -444,7 +444,7 @@ Vector operator*(const Vector& v, const Matrix& m) Vector res (0); for(unsigned int i = 0; i < M; ++i) for(unsigned int j = 0; j < N; ++j) - res[j] += m(i,j) * v[i] ; + res[j] += v[i] * m(i,j) ; return res ; } diff --git a/include/Utils/qem.h b/include/Utils/qem.h index 50a8dfcbfa6f41370be2a82e80adc8eab1fa65b6..22bbfaaac8393df2f9b92532409048c4d947e807 100644 --- a/include/Utils/qem.h +++ b/include/Utils/qem.h @@ -32,15 +32,23 @@ #include "Geometry/matrix.h" #include "Geometry/plane_3d.h" +// GSL includes +#include +#include + +namespace CGoGN { + +//namespace Utils { + template class Quadric { public: static std::string CGoGNnameOfType() { return "Quadric" ; } - typedef CGoGN::Geom::Vector<3,REAL> VEC3 ; - typedef CGoGN::Geom::Vector<4,REAL> VEC4 ; - typedef CGoGN::Geom::Matrix<4,4,REAL> MATRIX44 ; + typedef Geom::Vector<3,REAL> VEC3 ; + typedef Geom::Vector<4,REAL> VEC4 ; + typedef Geom::Matrix<4,4,double> MATRIX44 ; // double is crucial here ! Quadric() { @@ -55,28 +63,11 @@ public: Quadric(VEC3& p1, VEC3& p2, VEC3& p3) { // compute the equation of the plane of the 3 points - CGoGN::Geom::Plane3D p(p1, p2, p3) ; - VEC3& n = p.normal() ; - float a = n[0] ; - float b = n[1] ; - float c = n[2] ; - float d = p.d() ; - // set the matrix associated with this plane - A.set(1) ; - for(int i = 0; i < 4; ++i) - { - for(int j = 0; j < 4; ++j) - { - if(i==0) A(i,j) *= a ; - if(j==0) A(i,j) *= a ; - if(i==1) A(i,j) *= b ; - if(j==1) A(i,j) *= b ; - if(i==2) A(i,j) *= c ; - if(j==2) A(i,j) *= c ; - if(i==3) A(i,j) *= d ; - if(j==3) A(i,j) *= d ; - } - } + Geom::Plane3D plane(p1, p2, p3) ; + const VEC3& n = plane.normal() ; + + Geom::Vector<4,double> p = Geom::Vector<4,double>(n[0],n[1],n[2],plane.d()) ; + A = Geom::transposed_vectors_mult(p,p) ; } void zero() @@ -148,9 +139,10 @@ public: private: MATRIX44 A ; - float evaluate(const VEC4& v) const + REAL evaluate(const VEC4& v) const { - VEC4 Av = A * v ; + // Double computation is crucial for stability + Geom::Vector<4, double> Av = A * v ; return v * Av ; } @@ -177,4 +169,326 @@ private: } } ; +template +class QuadricNd +{ +public: + static std::string CGoGNnameOfType() { return "QuadricNd" ; } + + typedef Geom::Vector VECN ; + typedef Geom::Vector VECNp ; + + QuadricNd() + { + A.zero() ; + b.zero() ; + c = 0 ; + } + + QuadricNd(int i) + { + A.zero() ; + b.zero() ; + c = 0 ; + } + + QuadricNd(const VECN& p1_r, const VECN& p2_r, const VECN& p3_r) + { + const Geom::Vector& p1 = p1_r ; + const Geom::Vector& p2 = p2_r ; + const Geom::Vector& p3 = p3_r ; + + Geom::Vector e1 = p2 - p1 ; e1.normalize() ; + Geom::Vector e2 = (p3 - p1) - (e1*(p3-p1))*e1 ; e2.normalize() ; + + A.identity() ; + A -= Geom::transposed_vectors_mult(e1,e1) + Geom::transposed_vectors_mult(e2,e2) ; + + b = (p1*e1)*e1 + (p1*e2)*e2 - p1 ; + + c = p1*p1 - pow((p1*e1),2) - pow((p1*e2),2) ; + } + + void zero() + { + A.zero() ; + b.zero() ; + c = 0 ; + } + + void operator= (const QuadricNd& q) + { + A = q.A ; + b = q.b ; + c = q.c ; + } + QuadricNd& operator+= (const QuadricNd& q) + { + A += q.A ; + b += q.b ; + c += q.c ; + return *this ; + } + + QuadricNd& operator -= (const QuadricNd& q) + { + A -= q.A ; + b -= q.b ; + c -= q.c ; + return *this ; + } + + QuadricNd& operator *= (REAL v) + { + A *= v ; + b *= v ; + c *= v ; + return *this ; + } + QuadricNd& operator /= (REAL v) + { + A /= v ; + b /= v ; + c /= v ; + return *this ; + } + + REAL operator() (const VECNp& v) const + { + VECN hv ; + for (unsigned int i = 0 ; i < N ; ++i) + hv[i] = v[i] ; + + return evaluate(v) ; + } + + REAL operator() (const VECN& v) const + { + return evaluate(v) ; + } + + friend std::ostream& operator<<(std::ostream& out, const QuadricNd& q) + { + out << "(" << q.A << ", " << q.b << ", " << q.c << ")" ; + return out ; + } + + friend std::istream& operator>>(std::istream& in, QuadricNd& q) + { + in >> q.A ; + in >> q.b ; + in >> q.c ; + return in ; + } + + bool findOptimizedVec(VECN& v) + { + return optimize(v) ; + } + +private: + // Double computation is crucial for stability + Geom::Matrix A ; + Geom::Vector b ; + double c ; + + REAL evaluate(const VECN& v) const + { + Geom::Vector v_d = v ; + return v_d*A*v_d + 2.*(b*v_d) + c ; + } + + bool optimize(VECN& v) const + { + if (std::isnan(A(0,0))) + return false ; + + Geom::Matrix Ainv ; + double det = A.invert(Ainv) ; + + if(det > -1e-6 && det < 1e-6) + return false ; + + v.zero() ; + v -= Ainv * b ; + + return true ; + } +} ; + +template +class QuadricHF +{ +public: + static std::string CGoGNnameOfType() { return "QuadricHF" ; } + + typedef Geom::Vector<3,REAL> VEC3 ; + + QuadricHF() + { + m_A = gsl_matrix_alloc(0,0) ; + m_b = gsl_vector_alloc(0) ; + m_c = 0 ; + } + + QuadricHF(int i): + m_A(NULL), + m_b(NULL), + m_c(0) + { + m_A = gsl_matrix_calloc(i, i) ; + m_b = gsl_vector_calloc(i) ; + m_c = 0 ; + } + + QuadricHF(const std::vector& coefs, const REAL& gamma, const REAL& alpha) + { + m_A = gsl_matrix_calloc(coefs.size(), coefs.size()) ; + m_b = gsl_vector_calloc(coefs.size()) ; + m_c = 0 ; + // TODO : build A, b and c + assert(false || !"todo") ; + } + + ~QuadricHF() + { + gsl_matrix_free(m_A) ; + gsl_vector_free(m_b) ; + } + + void zero() + { + gsl_matrix_set_zero(m_A) ; + gsl_vector_set_zero(m_b) ; + m_c = 0 ; + } + + QuadricHF& operator= (const QuadricHF& q) + { + m_A = gsl_matrix_alloc(q.m_A->size1,q.m_A->size1) ; + gsl_matrix_memcpy(m_A,q.m_A) ; + + m_b = gsl_vector_alloc(m_b->size) ; + gsl_vector_memcpy(m_b,q.m_b) ; + + m_c = q.m_c ; + + return *this ; + } + + QuadricHF& operator+= (const QuadricHF& q) + { + assert(((m_A->size1 == q.m_A->size1) && (m_A->size2 == q.m_A->size2) && m_b->size == q.m_b->size) || !"Incompatible add of matrices") ; + if ((m_A->size1 == q.m_A->size1) && (m_A->size2 == q.m_A->size2) && (m_b->size == q.m_b->size)) + return *this ; + + gsl_matrix_add(m_A,q.m_A) ; + gsl_vector_add(m_b,q.m_b) ; + m_c += q.m_c ; + + return *this ; + } + + QuadricHF& operator -= (const QuadricHF& q) + { + assert(((m_A->size1 == q.m_A->size1) && (m_A->size2 == q.m_A->size2) && m_b->size == q.m_b->size) || !"Incompatible add of matrices") ; + if ((m_A->size1 == q.m_A->size1) && (m_A->size2 == q.m_A->size2) && (m_b->size == q.m_b->size)) + return *this ; + + gsl_matrix_sub(m_A,q.m_A) ; + gsl_vector_sub(m_b,q.m_b) ; + m_c -= q.m_c ; + + return *this ; + } + + QuadricHF& operator *= (const REAL& v) + { + gsl_matrix_scale(m_A,v) ; + gsl_vector_scale(m_b,v) ; + m_c *= v ; + + return *this ; + } + QuadricHF& operator /= (const REAL& v) + { + const REAL& inv = 1. / v ; + + (*this) *= inv ; + + return *this ; + } + +// REAL operator() (const VECNp& v) const +// { +// VECN hv ; +// for (unsigned int i = 0 ; i < 3 ; ++i) +// hv[i] = v[i] ; +// +// return evaluate(v) ; +// } + + REAL operator() (const std::vector& coefs) const + { + return evaluate(coefs) ; + } + + friend std::ostream& operator<<(std::ostream& out, const QuadricHF& q) + { + // TODO out << "(" << q.m_A << ", " << q.m_b << ", " << q.m_c << ")" ; + return out ; + } + + friend std::istream& operator>>(std::istream& in, QuadricHF& q) + { + // TODO +// in >> q.A ; +// in >> q.b ; +// in >> q.c ; + return in ; + } + + bool findOptimizedCoefs(std::vector& coefs) + { + return optimize(coefs) ; + } + +private: + // Double computation is crucial for stability + gsl_matrix *m_A ; + gsl_vector *m_b ; + double m_c ; + + REAL evaluate(const std::vector& coefs) const + { + // TODO +// Geom::Vector<3, double> v_d = v ; +// return v_d*A*v_d + 2.*(b*v_d) + c ; + } + + bool optimize(std::vector& coefs) const + { + coefs.reserve(m_b->size) ; + + // TODO +/* if (std::isnan(A(0,0))) + return false ; + + Geom::Matrix<3,3,double> Ainv ; + double det = A.invert(Ainv) ; + + if(det > -1e-6 && det < 1e-6) + return false ; + + v.zero() ; + v -= Ainv * b ; +*/ + return true ; + } +} ; + +//} // Utils + +} // CGOGN + #endif