Commit 27a0566f authored by Kenneth Vanhoey's avatar Kenneth Vanhoey

Add decimation with color attributes ('Naive' version works, rest is todo)

parent 282195db
......@@ -39,14 +39,16 @@ namespace Decimation
enum ApproximatorType
{
A_QEM,
A_hQEM,
A_MidEdge,
A_HalfCollapse,
A_CornerCutting,
A_TangentPredict1,
A_TangentPredict2,
A_hColor
/*A_LightfieldHalf,
A_ColorNaive,
A_ColorQEMext,
// note: the following "h" prefix means that half-edges are prioritized instead of edges.
A_hHalfCollapse,
A_hQEM,
A_hLightfieldHalf/*,
A_LightfieldHalf_deprecated,
A_LightfieldFull_deprecated*/
} ;
......@@ -99,15 +101,17 @@ public:
Approximator(MAP& m, std::vector<VertexAttribute<T>* > va, Predictor<PFP, T> * predictor) :
ApproximatorGen<PFP>(m), m_predictor(predictor), m_attrV(va)
{
assert(m_attrV.size() > 0 || !"Approximator: no attributes provided") ;
m_approx.resize(m_attrV.size()) ;
m_detail.resize(m_attrV.size()) ;
m_app.resize(m_attrV.size()) ;
if (m_attrV.size() < 1)
std::cerr << "Approximator: no attributes provided" << std::endl ;
for (unsigned int i = 0 ; i < m_attrV.size() ; ++i)
{
if (!m_attrV[i]->isValid())
std::cerr << "Approximator Warning: attribute number " << i << " is not valid" << std::endl ;
std::stringstream aname ;
aname << "approx_" << m_attrV[i]->name() ;
m_approx[i] = this->m_map.template addAttribute<T, EDGE>(aname.str()) ;
......
......@@ -22,8 +22,8 @@
* *
*******************************************************************************/
#ifndef __LIGHTFIELD_APPROXIMATOR_H__
#define __LIGHTFIELD_APPROXIMATOR_H__
#ifndef __COLOR_APPROXIMATOR_H__
#define __COLOR_APPROXIMATOR_H__
#include "Algo/Decimation/approximator.h"
#include "Topology/generic/mapBrowser.h"
......@@ -38,7 +38,7 @@ namespace Decimation
{
template <typename PFP>
class Approximator_Color : public Approximator<PFP, typename PFP::VEC3>
class Approximator_ColorNaive : public Approximator<PFP, typename PFP::VEC3>
{
public:
typedef typename PFP::MAP MAP ;
......@@ -46,21 +46,29 @@ public:
typedef typename PFP::REAL REAL ;
protected:
VertexAttribute<VEC3> m_position ;
EdgeAttribute<VEC3> m_approxposition ;
VertexAttribute<VEC3> *m_color ;
public:
Approximator_Color(MAP& m, std::vector<VertexAttribute<VEC3>* >& attr, Predictor<PFP, VEC3>* pred = NULL) :
Approximator_ColorNaive(MAP& m, std::vector<VertexAttribute<VEC3>* >& attr, Predictor<PFP, VEC3>* pred = NULL) :
Approximator<PFP, VEC3>(m, attr, pred)
{
m_color = this->m_attrV[0] ;
assert((m_color->isValid() && m_color->name() == "color") || !"Approximator_Color: the approximated attribute is not valid or not named 'color'") ;
assert(m_color->isValid() || !"Approximator_ColorNaive: the approximated attribute is not valid") ;
m_position = this->m_map.template getAttribute<VEC3, VERTEX>("position") ;
assert(m_position.isValid() || !"Approximator_ColorNaive: the position attribute is not valid") ;
m_approxposition = this->m_map.template getAttribute<VEC3, EDGE>("approx_position") ;
assert(m_approxposition.isValid() || !"Approximator_ColorNaive: the approx_position attribute is not valid") ;
}
~Approximator_Color()
~Approximator_ColorNaive()
{}
ApproximatorType getType() const
{
return A_hColor ;
return A_ColorNaive ;
}
bool init()
......@@ -71,63 +79,42 @@ public:
void approximate(Dart d) ;
} ;
/*
template <typename PFP>
class Approximator_FrameHalf : public Approximator<PFP, typename PFP::VEC3>
class Approximator_ColorQEMext : public Approximator<PFP, typename PFP::VEC3>
{
public:
typedef typename PFP::MAP MAP ;
typedef typename PFP::VEC3 VEC3 ;
typedef typename PFP::REAL REAL ;
typedef typename PFP::VEC3 VEC3 ;
typedef Geom::Vector<6,REAL> VEC6 ;
protected:
VertexAttribute<QuadricNd<REAL,6> > m_quadric ;
VertexAttribute<VEC3> *m_position ;
VertexAttribute<VEC3> *m_color ;
public:
Approximator_FrameHalf(MAP& m, std::vector<VertexAttribute<VEC3> >& attr, Predictor<PFP, VEC3>* pred = NULL) :
Approximator_ColorQEMext(MAP& m, std::vector<VertexAttribute<VEC3>* >& attr, Predictor<PFP, VEC3>* pred = NULL) :
Approximator<PFP, VEC3>(m, attr, pred)
{}
~Approximator_FrameHalf()
{}
ApproximatorType getType() const
{
return A_LightfieldHalf ;
}
assert(attr.size() > 1 || !"Approximator_ColorQEMext: there are not sufficient attributes provided") ;
bool init()
{
return true ;
m_position = this->m_attrV[0] ;
m_color = this->m_attrV[1] ;
}
void approximate(Dart d) ;
} ;
template <typename PFP>
class Approximator_LightfieldCoefsHalf : public Approximator<PFP, typename PFP::VEC3>
{
public:
typedef typename PFP::MAP MAP ;
typedef typename PFP::VEC3 VEC3 ;
typedef typename PFP::REAL REAL ;
public:
Approximator_LightfieldCoefsHalf(MAP& m, std::vector<VertexAttribute<VEC3> >& attr, Predictor<PFP, VEC3>* pred = NULL) :
Approximator<PFP, VEC3>(m, attr, pred)
{}
~Approximator_LightfieldCoefsHalf()
~Approximator_ColorQEMext()
{}
ApproximatorType getType() const
{
return A_LightfieldHalf ;
return A_ColorQEMext ;
}
bool init()
{
return true ;
}
bool init() ;
void approximate(Dart d) ;
} ;
*/
} //namespace Decimation
} //namespace Algo
......
......@@ -32,17 +32,132 @@ namespace Decimation
{
/************************************************************************************
* COLOR METRIC *
* NAIVE COLOR METRIC *
************************************************************************************/
template <typename PFP>
void Approximator_Color<PFP>::approximate(Dart d)
void Approximator_ColorNaive<PFP>::approximate(Dart d)
{
Dart dd = this->m_map.phi1(d) ;
this->m_approx[0][d] = m_color->operator[](d) ;
this->m_approx[0][d] += m_color->operator[](dd) ;
this->m_approx[0][d] /= 2 ;
const VEC3& p1 = m_position.operator[](d) ;
const VEC3& p2 = m_position.operator[](dd) ;
const VEC3& p = m_approxposition.operator[](d) ;
const VEC3& edge = p2 - p1 ;
const REAL& ratio = std::max(std::min(((p - p1) * edge) / edge.norm2(),REAL(1)),REAL(0)) ;
this->m_approx[0][d] = m_color->operator[](d)*ratio + m_color->operator[](dd)*(1-ratio) ;
}
/************************************************************************************
* EXTENDED QUADRIC ERROR METRIC *
************************************************************************************/
template <typename PFP>
bool Approximator_ColorQEMext<PFP>::init()
{
m_quadric = this->m_map.template getAttribute<QuadricNd<REAL,6>, VERTEX>("QEMext-quadric") ;
if(this->m_predictor)
{
return false ;
}
return true ;
}
template <typename PFP>
void Approximator_ColorQEMext<PFP>::approximate(Dart d)
{
MAP& m = this->m_map ;
// get some darts
Dart dd = m.phi2(d) ;
QuadricNd<REAL,6> 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<REAL,6> 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<REAL,6> 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<REAL,6> quad ;
quad += q1 ; // compute the sum of the
quad += q2 ; // two vertices quadrics
VEC6 res ;
bool opt = quad.findOptimizedPos(res) ; // try to compute an optimized position for the contraction of this edge
if(!opt)
{
VEC6 p1, p2 ;
for (unsigned int i = 0 ; i < 3; ++i)
{
p1[i] = this->m_attrV[0]->operator[](d)[i] ; // let the new vertex lie
p1[i+3] = this->m_attrV[1]->operator[](d)[i] ; // on either one
p2[i] = this->m_attrV[0]->operator[](dd)[i] ; // of the two
p2[i+3] = this->m_attrV[1]->operator[](dd)[i] ; // endpoints
}
VEC6 p12 = (p1 + p2) / 2.0f ; // or the middle of the edge
REAL e1 = quad(p1) ;
REAL e2 = quad(p2) ;
REAL e12 = quad(p12) ;
REAL minerr = std::min(std::min(e1, e2), e12) ; // consider only the one for
if(minerr == e12)
res = p12 ; // which the error is minimal
else if(minerr == e1)
res = p1 ;
else
res = p2 ;
}
// copy res into m_approx
for (unsigned int i = 0 ; i < 3 ; ++i)
{
this->m_approx[0][d] = res[i] ;
this->m_approx[1][d] = res[i+3] ;
}
}
} //namespace Decimation
......
......@@ -29,7 +29,7 @@
#include "Algo/Decimation/halfEdgeSelector.h"
#include "Algo/Decimation/geometryApproximator.h"
#include "Algo/Decimation/colorPerVertexApproximator.h"
//#include "Algo/Decimation/lightfieldApproximator_deprecated.h"
#include "Algo/Decimation/lightfieldApproximator.h"
namespace CGoGN
{
......
......@@ -48,9 +48,6 @@ void decimate(
case A_QEM :
approximators.push_back(new Approximator_QEM<PFP>(map, v_pos)) ;
break ;
case A_hQEM :
approximators.push_back(new Approximator_QEMhalfEdge<PFP>(map, v_pos)) ;
break ;
case A_MidEdge :
approximators.push_back(new Approximator_MidEdge<PFP>(map, v_pos)) ;
break ;
......@@ -63,19 +60,57 @@ void decimate(
case A_TangentPredict2 :
approximators.push_back(new Approximator_MidEdge<PFP>(map, v_pos)) ;
break ;
case A_HalfCollapse :
case A_hHalfCollapse :
approximators.push_back(new Approximator_HalfCollapse<PFP>(map, v_pos)) ;
break ;
case A_hColor :
case A_ColorNaive :
{
// pos
approximators.push_back(new Approximator_HalfCollapse<PFP>(map, v_pos)) ;
approximators.push_back(new Approximator_QEM<PFP>(map, v_pos)) ;
// col
std::vector<VertexAttribute<typename PFP::VEC3>* > v_col ;
VertexAttribute<typename PFP::VEC3> colors = map.template getAttribute<typename PFP::VEC3, VERTEX>("color") ;
v_col.push_back(&colors) ;
approximators.push_back(new Approximator_Color<PFP>(map, v_col)) ;
break ;
approximators.push_back(new Approximator_ColorNaive<PFP>(map, v_col)) ;
}
break ;
case A_ColorQEMext :
{
// pos+col
std::vector<VertexAttribute<typename PFP::VEC3>* > v_poscol ;
v_poscol.push_back(&position) ; // pos
VertexAttribute<typename PFP::VEC3> colors = map.template getAttribute<typename PFP::VEC3, VERTEX>("color") ;
v_poscol.push_back(&colors) ; // col
approximators.push_back(new Approximator_ColorQEMext<PFP>(map, v_poscol)) ;
}
break;
case A_hQEM :
approximators.push_back(new Approximator_QEMhalfEdge<PFP>(map, v_pos)) ;
break ;
case A_hLightfieldHalf :
{
// pos
approximators.push_back(new Approximator_HalfCollapse<PFP>(map, v_pos)) ;
// frame
std::vector<VertexAttribute<typename PFP::VEC3>* > v_frame ;
VertexAttribute<typename PFP::VEC3> FT = map.template getAttribute<typename PFP::VEC3, VERTEX>("frameT") ;
VertexAttribute<typename PFP::VEC3> FB = map.template getAttribute<typename PFP::VEC3, VERTEX>("frameB") ;
VertexAttribute<typename PFP::VEC3> FN = map.template getAttribute<typename PFP::VEC3, VERTEX>("frameN") ;
v_frame.push_back(&FT) ;
v_frame.push_back(&FB) ;
v_frame.push_back(&FN) ;
approximators.push_back(new Approximator_FrameHalf<PFP>(map, v_frame)) ;
// TODO
// // function coefs
// std::vector<VertexAttribute<typename PFP::VEC3>* > v_coefs ;
// VertexAttribute<typename PFP::VEC3> coefs = map.template getAttribute<typename PFP::VEC3, VERTEX>("SLFcoefs_0") ;
// v_frame.push_back(&coefs) ;
// approximators.push_back(new Approximator_LFcoefs<PFP>(map, v_coefs)) ;
}
break ;
/*case A_LightfieldHalf:
approximators.push_back(new Approximator_HalfCollapse<PFP>(map, position)) ;
......@@ -177,14 +212,14 @@ void decimate(
case S_MinDetail :
selector = new EdgeSelector_MinDetail<PFP>(map, position, approximators, selected) ;
break ;
/*case S_hLightfield_deprecated :
selector = new HalfEdgeSelector_Lightfield_deprecated<PFP>(map, position, approximators, selected) ;
break ;*/
case S_ColorNaive :
selector = new EdgeSelector_ColorNaive<PFP>(map, position, approximators, selected) ;
break ;
case S_hQEMml :
selector = new HalfEdgeSelector_QEMml<PFP>(map, position, approximators, selected) ;
break ;
case S_hColor :
selector = new HalfEdgeSelector_Color<PFP>(map, position, approximators, selected) ;
case S_hLightfield :
selector = new HalfEdgeSelector_Lightfield<PFP>(map, position, approximators, selected) ;
break ;
}
......
......@@ -169,7 +169,8 @@ private:
public:
EdgeSelector_QEM(MAP& m, VertexAttribute<typename PFP::VEC3>& pos, std::vector<ApproximatorGen<PFP>*>& approx, const FunctorSelect& select) :
EdgeSelector<PFP>(m, pos, approx, select)
EdgeSelector<PFP>(m, pos, approx, select),
m_positionApproximator(NULL)
{
edgeInfo = m.template addAttribute<EdgeInfo, EDGE>("edgeInfo") ;
quadric = m.template addAttribute<Quadric<REAL>, VERTEX>("QEMquadric") ;
......@@ -218,7 +219,8 @@ private:
public:
EdgeSelector_QEMml(MAP& m, VertexAttribute<typename PFP::VEC3>& pos, std::vector<ApproximatorGen<PFP>*>& approx, const FunctorSelect& select) :
EdgeSelector<PFP>(m, pos, approx, select)
EdgeSelector<PFP>(m, pos, approx, select),
m_positionApproximator(NULL)
{
edgeInfo = m.template addAttribute<EdgeInfo, EDGE>("edgeInfo") ;
quadric = m.template addAttribute<Quadric<REAL>, VERTEX>("QEMquadric") ;
......@@ -275,7 +277,8 @@ private:
public:
EdgeSelector_Curvature(MAP& m, VertexAttribute<VEC3>& pos, std::vector<ApproximatorGen<PFP>*>& approx, const FunctorSelect& select) :
EdgeSelector<PFP>(m, pos, approx, select)
EdgeSelector<PFP>(m, pos, approx, select),
m_positionApproximator(NULL)
{
bb = Algo::Geometry::computeBoundingBox<PFP>(m, pos) ;
radius = bb.diagSize() * 0.003 ;
......@@ -360,7 +363,8 @@ private:
public:
EdgeSelector_MinDetail(MAP& m, VertexAttribute<typename PFP::VEC3>& pos, std::vector<ApproximatorGen<PFP>*>& approx, const FunctorSelect& select) :
EdgeSelector<PFP>(m, pos, approx, select)
EdgeSelector<PFP>(m, pos, approx, select),
m_positionApproximator(NULL)
{
edgeInfo = m.template addAttribute<EdgeInfo, EDGE>("edgeInfo") ;
}
......@@ -375,6 +379,66 @@ public:
void updateAfterCollapse(Dart d2, Dart dd2) ;
} ;
/*****************************************************************************************************************
* HALF-EDGE NAIVE COLOR METRIC (using QEMml) *
*****************************************************************************************************************/
template <typename PFP>
class EdgeSelector_ColorNaive : public EdgeSelector<PFP>
{
public:
typedef typename PFP::MAP MAP ;
typedef typename PFP::VEC3 VEC3 ;
typedef typename PFP::REAL REAL ;
private:
typedef struct
{
typename std::multimap<float,Dart>::iterator it ;
bool valid ;
static std::string CGoGNnameOfType() { return "ColorNaiveEdgeInfo" ; }
} ColorNaiveedgeInfo ;
typedef NoMathIOAttribute<ColorNaiveedgeInfo> EdgeInfo ;
EdgeAttribute<EdgeInfo> edgeInfo ;
VertexAttribute<VEC3> m_color ;
VertexAttribute<Quadric<REAL> > m_quadric ;
std::multimap<float,Dart> edges ;
typename std::multimap<float,Dart>::iterator cur ;
Approximator<PFP, typename PFP::VEC3>* m_positionApproximator ;
Approximator<PFP, typename PFP::VEC3>* m_colorApproximator ;
void initEdgeInfo(Dart d) ;
void updateEdgeInfo(Dart d, bool recompute) ;
void computeEdgeInfo(Dart d,EdgeInfo& einfo) ;
void recomputeQuadric(const Dart d, const bool recomputeNeighbors = false) ;
public:
EdgeSelector_ColorNaive(MAP& m, VertexAttribute<typename PFP::VEC3>& pos, std::vector<ApproximatorGen<PFP>*>& approx, const FunctorSelect& select = allDarts) :
EdgeSelector<PFP>(m, pos, approx, select),
m_positionApproximator(NULL),
m_colorApproximator(NULL)
{
edgeInfo = m.template addAttribute<EdgeInfo, EDGE>("edgeInfo") ;
m_quadric = m.template addAttribute<Quadric<REAL>, VERTEX>("QEMquadric") ;
m_color = m.template getAttribute<VEC3, VERTEX>("color") ;
assert(m_color.isValid() || !"EdgeSelector_ColorNaive: Color atrribute to select is not valid") ;
}
~EdgeSelector_ColorNaive()
{
this->m_map.removeAttribute(edgeInfo) ;
this->m_map.removeAttribute(m_quadric) ;
}
SelectorType getType() { return S_ColorNaive ; }
bool init() ;
bool nextEdge(Dart& d) ;
void updateBeforeCollapse(Dart d) ;
void updateAfterCollapse(Dart d2, Dart dd2) ;
} ;
} // namespace Decimation
} // namespace Algo
......
......@@ -735,7 +735,7 @@ bool EdgeSelector_Curvature<PFP>::init()
edges.clear() ;
CellMarker<EDGE> eMark(m) ;
CellMarker<VERTEX> eMark(m) ;
for(Dart d = m.begin(); d != m.end(); m.next(d))
{
if(!eMark.isMarked(d))
......@@ -1095,6 +1095,253 @@ void EdgeSelector_MinDetail<PFP>::computeEdgeInfo(Dart d, EdgeInfo& einfo)
einfo.valid = true ;
}
/************************************************************************************
* EDGESELECTOR COLOR PER VERTEX *
************************************************************************************/
template <typename PFP>
bool EdgeSelector_ColorNaive<PFP>::init()
{
MAP& m = this->m_map ;
// Verify availability of required approximators
char ok = 0 ;
for(typename std::vector<ApproximatorGen<PFP>*>::iterator it = this->m_approximators.begin();
it != this->m_approximators.end();
++it)
{
// constraint : 2 approximators in specific order
if(ok == 0 && (*it)->getApproximatedAttributeName(0) == "position")
{
m_positionApproximator = reinterpret_cast<Approximator<PFP, VEC3>* >(*it) ; // 1) position
// check incompatibilities
assert(m_positionApproximator->getType() != A_hQEM || !"Approximator(hQEM) and selector (ColorNaive) are not compatible") ;
assert(m_positionApproximator->getType() != A_hHalfCollapse || !"Approximator(hHalfCollapse) and selector (ColorNaive) are not compatible") ;
assert(m_positionApproximator->getType() != A_hLightfieldHalf || !"Approximator(hLightfieldHalf) and selector (ColorNaive) are not compatible") ;
++ok ;
}
else if( ok == 1 && (*it)->getApproximatedAttributeName(0) == "color")
{
m_colorApproximator = reinterpret_cast<Approximator<PFP, VEC3>* >(*it) ; // 2) color (needs position)
++ok ;
}
}
if(ok != 2)
return false ;
TraversorV<MAP> travV(m);
for(Dart dit = travV.begin() ; dit != travV.end() ; dit = travV.next())
{
Quadric<REAL> q ; // create one quadric
m_quadric[dit] = q ; // per vertex
}
// Compute quadric per vertex
TraversorF<MAP> 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<REAL> 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<MAP> 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 <typename PFP>
bool EdgeSelector_ColorNaive<PFP>::nextEdge(Dart& d)
{
if(cur == edges.end() || edges.empty())
return false ;
d = (*cur).second ;
return true ;