Commit 3f03bce5 authored by Thery Sylvain's avatar Thery Sylvain

Merge branch 'master' of cgogn:~vanhoey/CGoGN

parents e61959de 23f82746
......@@ -202,6 +202,12 @@ void decimate(
case S_hLFexperimental:
selector = new HalfEdgeSelector_LFexperimental<PFP>(map, position, approximators, selected) ;
break ;
case S_hColorPerFace:
selector = new HalfEdgeSelector_ColorPerFace<PFP>(map, position, approximators, selected) ;
break ;
case S_hLFperFace:
selector = new HalfEdgeSelector_LFperFace<PFP>(map, position, approximators, selected) ;
break ;
}
for(typename std::vector<ApproximatorGen<PFP>*>::iterator it = approximators.begin(); it != approximators.end(); ++it)
......
......@@ -667,6 +667,198 @@ public:
}
} ;
/*****************************************************************************************************************
* HALF-EDGE COLOR PER FACE *
*****************************************************************************************************************/
template <typename PFP>
class HalfEdgeSelector_ColorPerFace : public EdgeSelector<PFP>
{
public:
typedef typename PFP::MAP MAP ;
typedef typename PFP::REAL REAL ;
typedef typename PFP::VEC3 VEC3 ;
private:
typedef struct
{
typename std::multimap<float,Dart>::iterator it ;
bool valid ;
static std::string CGoGNnameOfType() { return "ColorPerFaceHalfEdgeInfo" ; }
} QEMextColorHalfEdgeInfo ;
typedef NoMathIOAttribute<QEMextColorHalfEdgeInfo> HalfEdgeInfo ;
DartAttribute<HalfEdgeInfo> halfEdgeInfo ;
VertexAttribute<Utils::Quadric<REAL> > m_quadric ;
VertexAttribute<VEC3> m_pos, m_color ;
int m_approxindex_pos, m_attrindex_pos ;
int m_approxindex_color, m_attrindex_color ;
std::vector<Approximator<PFP, typename PFP::VEC3,DART>* > m_approx ;
std::multimap<float,Dart> halfEdges ;
typename std::multimap<float,Dart>::iterator cur ;
void initHalfEdgeInfo(Dart d) ;
void updateHalfEdgeInfo(Dart d) ;
void computeHalfEdgeInfo(Dart d, HalfEdgeInfo& einfo) ;
//void recomputeQuadric(const Dart d, const bool recomputeNeighbors = false) ;
void recomputeQuadric(const Dart d) ;
typename PFP::REAL computeExperimentalColorError(const Dart& v0, const Dart& v1) ;
public:
HalfEdgeSelector_ColorPerFace(MAP& m, VertexAttribute<typename PFP::VEC3>& pos, std::vector<ApproximatorGen<PFP>*>& approx, const FunctorSelect& select = allDarts) :
EdgeSelector<PFP>(m, pos, approx, select),
m_approxindex_pos(-1),
m_attrindex_pos(-1),
m_approxindex_color(-1),
m_attrindex_color(-1)
{
halfEdgeInfo = m.template addAttribute<HalfEdgeInfo, DART>("halfEdgeInfo") ;
m_quadric = m.template addAttribute<Utils::Quadric<REAL>, VERTEX>("QEMquadric") ;
}
~HalfEdgeSelector_ColorPerFace()
{
this->m_map.removeAttribute(m_quadric) ;
this->m_map.removeAttribute(halfEdgeInfo) ;
}
SelectorType getType() { return S_hColorPerFace ; }
bool init() ;
bool nextEdge(Dart& d) ;
void updateBeforeCollapse(Dart d) ;
void updateAfterCollapse(Dart d2, Dart dd2) ;
void updateWithoutCollapse() { }
void getEdgeErrors(EdgeAttribute<typename PFP::REAL> *errors)
{
assert(errors != NULL || !"EdgeSelector::setColorMap requires non null vertexattribute argument") ;
if (!errors->isValid())
std::cerr << "EdgeSelector::setColorMap requires valid edgeattribute argument" << std::endl ;
assert(halfEdgeInfo.isValid()) ;
TraversorE<typename PFP::MAP> travE(this->m_map) ;
for(Dart d = travE.begin() ; d != travE.end() ; d = travE.next())
{
(*errors)[d] = -1 ;
if (halfEdgeInfo[d].valid)
{
(*errors)[d] = halfEdgeInfo[d].it->first ;
}
Dart dd = this->m_map.phi2(d) ;
if (halfEdgeInfo[dd].valid && halfEdgeInfo[dd].it->first < (*errors)[d])
{
(*errors)[d] = halfEdgeInfo[dd].it->first ;
}
}
}
} ;
/*****************************************************************************************************************
* HALF-EDGE LF PER FACE *
*****************************************************************************************************************/
template <typename PFP>
class HalfEdgeSelector_LFperFace : public EdgeSelector<PFP>
{
public:
typedef typename PFP::MAP MAP ;
typedef typename PFP::REAL REAL ;
typedef typename PFP::VEC3 VEC3 ;
private:
typedef struct
{
typename std::multimap<float,Dart>::iterator it ;
bool valid ;
static std::string CGoGNnameOfType() { return "LightfieldPerFaceHalfEdgeInfo" ; }
} LightfieldHalfEdgeInfo ;
typedef NoMathIOAttribute<LightfieldHalfEdgeInfo> HalfEdgeInfo ;
DartAttribute<HalfEdgeInfo> halfEdgeInfo ;
VertexAttribute<Utils::Quadric<REAL> > m_quadric ;
VertexAttribute<REAL> m_visualImportance ;
VertexAttribute<VEC3> m_avgColor ;
int m_approxindex_pos, m_attrindex_pos ;
int m_approxindex_FT, m_attrindex_FT ;
int m_approxindex_FB, m_attrindex_FB ;
int m_approxindex_FN, m_attrindex_FN ;
std::vector<unsigned int> m_approxindex_HF, m_attrindex_HF ;
unsigned int m_K ;
std::vector<Approximator<PFP, typename PFP::VEC3,DART>* > m_approx ;
std::multimap<float,Dart> halfEdges ;
typename std::multimap<float,Dart>::iterator cur ;
void initHalfEdgeInfo(Dart d) ;
void updateHalfEdgeInfo(Dart d) ;
void computeHalfEdgeInfo(Dart d, HalfEdgeInfo& einfo) ;
void recomputeQuadric(const Dart d) ;
REAL computeLightfieldError(const Dart& v0, const Dart& v1) ;
REAL computeSquaredLightfieldDifference(const Dart& d1, const Dart& d2) ;
public:
HalfEdgeSelector_LFperFace(MAP& m, VertexAttribute<typename PFP::VEC3>& pos, std::vector<ApproximatorGen<PFP>*>& approx, const FunctorSelect& select = allDarts) :
EdgeSelector<PFP>(m, pos, approx, select),
m_approxindex_pos(-1),
m_attrindex_pos(-1),
m_approxindex_FT(-1),
m_attrindex_FT(-1),
m_approxindex_FB(-1),
m_attrindex_FB(-1),
m_approxindex_FN(-1),
m_attrindex_FN(-1),
m_K(0)
{
halfEdgeInfo = m.template addAttribute<HalfEdgeInfo, DART>("halfEdgeInfo") ;
m_quadric = m.template addAttribute<Utils::Quadric<REAL>, VERTEX>("QEMquadric") ;
m_avgColor = m.template getAttribute<typename PFP::VEC3, VERTEX>("color") ;
assert(m_avgColor.isValid()) ;
}
~HalfEdgeSelector_LFperFace()
{
this->m_map.removeAttribute(m_quadric) ;
this->m_map.removeAttribute(halfEdgeInfo) ;
}
SelectorType getType() { return S_hLFperFace ; }
bool init() ;
bool nextEdge(Dart& d) ;
void updateBeforeCollapse(Dart d) ;
void updateAfterCollapse(Dart d2, Dart dd2) ;
void updateWithoutCollapse() { }
void getEdgeErrors(EdgeAttribute<typename PFP::REAL> *errors)
{
assert(errors != NULL || !"EdgeSelector::setColorMap requires non null vertexattribute argument") ;
if (!errors->isValid())
std::cerr << "EdgeSelector::setColorMap requires valid edgeattribute argument" << std::endl ;
assert(halfEdgeInfo.isValid()) ;
TraversorE<typename PFP::MAP> travE(this->m_map) ;
for(Dart d = travE.begin() ; d != travE.end() ; d = travE.next())
{
(*errors)[d] = -1 ;
if (halfEdgeInfo[d].valid)
{
(*errors)[d] = halfEdgeInfo[d].it->first ;
}
Dart dd = this->m_map.phi2(d) ;
if (halfEdgeInfo[dd].valid && halfEdgeInfo[dd].it->first < (*errors)[d])
{
(*errors)[d] = halfEdgeInfo[dd].it->first ;
}
}
}
} ;
} // namespace Decimation
......
......@@ -2120,13 +2120,13 @@ void HalfEdgeSelector_ColorExperimental<PFP>::computeHalfEdgeInfo(Dart d, HalfEd
// New position
const VEC3& newPos = this->m_approx[m_approxindex_pos]->getApprox(d,m_attrindex_pos) ; // get newPos
// New normal
const VEC3& newColor = this->m_approx[m_approxindex_color]->getApprox(d,m_attrindex_color) ; // get new color
// const VEC3& newColor = this->m_approx[m_approxindex_color]->getApprox(d,m_attrindex_color) ; // get new color
const Dart& v0 = dd ;
const Dart& v1 = d ;
assert(newPos == m_pos[v1]) ;
assert(newColor == m_color[v1]) ;
assert( this->m_approx[m_approxindex_color]->getApprox(d,m_attrindex_color) == m_color[v1]) ;
// Compute errors
// Position
......@@ -2138,9 +2138,10 @@ void HalfEdgeSelector_ColorExperimental<PFP>::computeHalfEdgeInfo(Dart d, HalfEd
// sum of QEM metric and frame orientation difference
const REAL& err =
quadGeom(newPos) + // geom
computeExperimentalColorError(v0,v1) // color
10*computeExperimentalColorError(v0,v1) // color
;
//std::cout << quadGeom(newPos) / computeExperimentalColorError(v0,v1) << std::endl ;
//std::cout << quadGeom(newPos)/computeExperimentalColorError(v0,v1) << std::endl ;
// Check if errated values appear
if (err < -1e-6)
......@@ -2158,7 +2159,7 @@ HalfEdgeSelector_ColorExperimental<PFP>::computeExperimentalColorError(const Dar
{
MAP& m = this->m_map ;
Traversor2VF<MAP> tf(m,v0) ;
Traversor2VF<MAP> tf(m,v0) ; // all faces around vertex v0
const unsigned int& v1_vertexId = m.template getEmbedding<VERTEX>(v1) ;
const VEC3& P0 = m_pos[v0] ;
......@@ -2166,58 +2167,66 @@ HalfEdgeSelector_ColorExperimental<PFP>::computeExperimentalColorError(const Dar
const VEC3& c0 = m_color[v0] ;
const VEC3& c1 = m_color[v1] ;
REAL res = 0 ;
REAL res1 = 0, res2 = 0 ;
unsigned int count1 = 0, count2 = 0 ;
for (Dart fi = tf.begin() ; fi != tf.end() ; fi = tf.next())
{
const Dart& vi = m.phi1(fi) ;
const Dart& vj = m.phi_1(fi) ;
const VEC3& Pi = m_pos[vi] ;
const VEC3& Pj = m_pos[vj] ;
const VEC3& Pi = this->m_position[vi] ;
const VEC3& Pj = this->m_position[vj] ;
const VEC3& ci = m_color[vi] ;
const VEC3& cj = m_color[vj] ;
const VEC3 PiP0 = P0 - Pi ;
const VEC3 PjP0 = P0 - Pj ;
const VEC3 PiPj = Pj - Pi ;
const VEC3 Pi_P0 = P0 - Pi ;
//const VEC3 PjP0 = P0 - Pj ;
const VEC3 Pi_Pj = Pj - Pi ;
const REAL b = Pi_Pj.norm() ;
const VEC3 P0prim = Pi + (PiP0 * PiPj)*PiPj ;
const VEC3 P0P0prim = P0prim - P0 ;
const REAL h0 = P0P0prim.norm() ;
const VEC3 P0proj2D = Pi + (Pi_P0 * Pi_Pj)*Pi_Pj ;
const VEC3 P0_P0proj2D = P0proj2D - P0 ;
const REAL h0 = P0_P0proj2D.norm() ;
const VEC3 coldiff01 = c1 - c0 ;
res += coldiff01.norm() * PiPj.norm() * h0 / (6. * sqrt(3)) ;
res1 += coldiff01.norm() * b * h0 / (6. * sqrt(3)) ;
++count1 ;
// test if v1 is adjacent to this face
bool adjacent = false ;
Traversor2FV<MAP> tv(m,fi) ;
for (Dart v = tv.begin() ; v != tv.end() ; v = tv.next())
{
if (v1_vertexId == m.template getEmbedding<VERTEX>(v))
adjacent = true ;
adjacent |= v1_vertexId == m.template getEmbedding<VERTEX>(v) ;
}
// if v1 is not adjacent to this face
if (!adjacent)
{
const VEC3 PiP1 = P0 - Pi ;
const VEC3 PjP1 = P0 - Pj ;
const VEC3 P1proj3D = P1 ;
const VEC3 Pi_P1 = P1proj3D - Pi ;
//const VEC3 PjP1 = newP1 - Pj ;
const VEC3 P1prim = Pi + (PiP1 * PiPj)*PiPj ;
const VEC3 P1P1prim = P1prim - P1 ;
const REAL h1 = P1P1prim.norm() ;
const VEC3 P1proj2D = Pi + (Pi_P1 * Pi_Pj)*Pi_Pj ;
const VEC3 P1proj2D_P1proj3D = P1proj2D - P1proj3D ;
const REAL h1 = P1proj2D_P1proj3D.norm() ;
const VEC3 coldiff0i = ci - c0 ;
const VEC3 coldiff1i = ci - c1 ;
const VEC3 coldiff0j = cj - c0 ;
const VEC3 coldiff1j = cj - c1 ;
res += (coldiff0i.norm() + coldiff0j.norm() + coldiff1i.norm() + coldiff1j.norm()) * PiPj.norm() * std::fabs(h1 - h0) / (6. * sqrt(3)) ;
res2 += (coldiff0i.norm() + coldiff0j.norm() + coldiff1i.norm() + coldiff1j.norm())
* b * std::fabs(h1 - h0)
/ (12. * sqrt(3)) ;
++count2 ;
}
}
return res ;
assert(count1-2==count2) ;
return res1 / count1 + res2 / count2 ;
}
/************************************************************************************
......@@ -2510,7 +2519,7 @@ void HalfEdgeSelector_LFexperimental<PFP>::computeHalfEdgeInfo(Dart d, HalfEdgeI
// sum of QEM metric
const REAL& err =
quadGeom(newPos) + // geom
100*computeLightfieldError(v0,v1) // lf
1000*computeLightfieldError(v0,v1) // lf
;
//std::cout << computeLightfieldError(v0,v1) / quadGeom(newPos) << std::endl ;
......@@ -2536,7 +2545,8 @@ HalfEdgeSelector_LFexperimental<PFP>::computeLightfieldError(const Dart& v0, con
const VEC3& P0 = this->m_position[v0] ;
const VEC3& P1 = this->m_position[v1] ;
REAL res = 0 ;
REAL res1 = 0, res2 = 0 ;
unsigned int count = 0 ;
for (Dart fi = tf.begin() ; fi != tf.end() ; fi = tf.next())
{
const Dart& vi = m.phi1(fi) ;
......@@ -2545,16 +2555,17 @@ HalfEdgeSelector_LFexperimental<PFP>::computeLightfieldError(const Dart& v0, con
const VEC3& Pi = this->m_position[vi] ;
const VEC3& Pj = this->m_position[vj] ;
const VEC3 PiP0 = P0 - Pi ;
const VEC3 PjP0 = P0 - Pj ;
const VEC3 PiPj = Pj - Pi ;
const VEC3 Pi_P0 = P0 - Pi ;
//const VEC3 PjP0 = P0 - Pj ;
const VEC3 Pi_Pj = Pj - Pi ;
const REAL b = Pi_Pj.norm() ;
const VEC3 P0prim = Pi + (PiP0 * PiPj)*PiPj ;
const VEC3 P0P0prim = P0prim - P0 ;
const REAL h0 = P0P0prim.norm() ;
const VEC3 P0proj2D = Pi + (Pi_P0 * Pi_Pj)*Pi_Pj ;
const VEC3 P0_P0proj2D = P0proj2D - P0 ;
const REAL h0 = P0_P0proj2D.norm() ;
const REAL lfdiff01 = computeSquaredLightfieldDifference(v0,v1) ;
res += lfdiff01 * PiPj.norm() * h0 / 6. ;
res1 += lfdiff01 * b * h0 / (6.*sqrt(3)) ;
// test if v1 is adjacent to this face
bool adjacent = false ;
......@@ -2568,23 +2579,25 @@ HalfEdgeSelector_LFexperimental<PFP>::computeLightfieldError(const Dart& v0, con
// if v1 is not adjacent to this face
if (!adjacent)
{
const VEC3 PiP1 = P0 - Pi ;
const VEC3 PjP1 = P0 - Pj ;
const VEC3 P1proj3D = P1 ;
const VEC3 Pi_P1 = P1proj3D - Pi ;
//const VEC3 PjP1 = newP1 - Pj ;
const VEC3 P1prim = Pi + (PiP1 * PiPj)*PiPj ;
const VEC3 P1P1prim = P1prim - P1 ;
const REAL h1 = P1P1prim.norm() ;
const VEC3 P1proj2D = Pi + (Pi_P1 * Pi_Pj)*Pi_Pj ;
const VEC3 P1proj2D_P1proj3D = P1proj2D - P1proj3D ;
const REAL h1 = P1proj2D_P1proj3D.norm() ;
const REAL lfdiff0i = computeSquaredLightfieldDifference(vi,v0) ;
const REAL lfdiff1i = computeSquaredLightfieldDifference(vi,v1) ;
const REAL lfdiff0j = computeSquaredLightfieldDifference(vj,v0) ;
const REAL lfdiff1j = computeSquaredLightfieldDifference(vj,v1) ;
res += (lfdiff0i + lfdiff0j + lfdiff1i + lfdiff1j) * PiPj.norm() * std::fabs(h1 - h0) / 6. ;
res2 += (lfdiff0i + lfdiff0j + lfdiff1i + lfdiff1j) * b * std::fabs(h1 - h0) / (12.*sqrt(3)) ;
}
++count ;
}
return res ;
return res1 / count + res2 / (count-2) ;
}
template <typename PFP>
......@@ -2652,6 +2665,784 @@ typename PFP::REAL HalfEdgeSelector_LFexperimental<PFP>::computeSquaredLightfiel
}
/************************************************************************************
* COLOR PER FACE *
************************************************************************************/
template <typename PFP>
bool HalfEdgeSelector_ColorPerFace<PFP>::init()
{
MAP& m = this->m_map ;
// Verify availability of required approximators
unsigned int ok = 0 ;
for (unsigned int approxindex = 0 ; approxindex < this->m_approximators.size() ; ++approxindex)
{
assert(this->m_approximators[approxindex]->getType() == A_hQEM
|| this->m_approximators[approxindex]->getType() == A_hHalfCollapse
|| !"Approximator for selector (HalfEdgeSelector_ColorExperimental) must be of a half-edge approximator") ;
bool saved = false ;
for (unsigned int attrindex = 0 ; attrindex < this->m_approximators[approxindex]->getNbApproximated() ; ++ attrindex)
{
// constraint : 2 approximators in specific order
if(ok == 0 && this->m_approximators[approxindex]->getApproximatedAttributeName(attrindex) == "position")
{
++ok ;
m_approxindex_pos = approxindex ;
m_attrindex_pos = attrindex ;
m_pos = this->m_position ;
if (!saved)
{
m_approx.push_back(reinterpret_cast<Approximator<PFP, VEC3, DART>* >(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<typename PFP::VEC3, VERTEX>("color") ;
assert(m_color.isValid() || !"EdgeSelector_QEMextColor: color attribute is not valid") ;
if (!saved)
{
m_approx.push_back(reinterpret_cast<Approximator<PFP, VEC3, DART>* >(this->m_approximators[approxindex])) ;
saved = true ;
}
}
}
}
if(ok != 2)
return false ;
CellMarker<VERTEX> vMark(m) ;
for(Dart d = m.begin(); d != m.end(); m.next(d))
{
if(!vMark.isMarked(d))
{
Utils::Quadric<REAL> q ; // create one quadric
m_quadric[d] = q ; // per vertex
vMark.mark(d) ;
}
}
DartMarker mark(m) ;
for(Dart d = m.begin(); d != m.end(); m.next(d))
{
if(!mark.isMarked(d))
{
Dart d1 = m.phi1(d) ; // for each triangle,
Dart d_1 = m.phi_1(d) ; // initialize the quadric of the triangle
Utils::Quadric<REAL> q(this->m_position[d], this->m_position[d1], this->m_position[d_1]) ;
m_quadric[d] += 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
mark.markOrbit<FACE>(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 <typename PFP>
bool HalfEdgeSelector_ColorPerFace<PFP>::nextEdge(Dart& d)
{
if(cur == halfEdges.end() || halfEdges.empty())
return false ;
d = (*cur).second ;
return true ;
}
template <typename PFP>
void HalfEdgeSelector_ColorPerFace<PFP>::updateBeforeCollapse(Dart d)
{
MAP& m = this->m_map ;
const Dart& v0 = m.phi1(d) ;
Traversor2VVaE<MAP> tv(m,v0) ;
for (Dart v = tv.begin() ; v != tv.end() ; v = tv.next())
{
Traversor2VE<MAP> te(m,v) ;
for (Dart he = te.begin() ; he != te.end() ; he = te.next())
{
HalfEdgeInfo* edgeE = &(halfEdgeInfo[he]) ;
if(edgeE->valid)
{
edgeE->valid = false ;
halfEdges.erase(edgeE->it) ;
}
Dart de = m.phi2(he) ;
edgeE = &(halfEdgeInfo[de]) ;
if(edgeE->valid)
{
edgeE->valid = false ;
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 <typename PFP>
void HalfEdgeSelector_ColorPerFace<PFP>::recomputeQuadric(const Dart d)
{
Dart dFront,dBack ;
Dart dInit = d ;
// Init Front
dFront = dInit ;
m_quadric[d].zero() ;
do {
// Make step
dBack = this->m_map.phi1(dFront) ;
dFront = this->m_map.phi2_1(dFront) ;
if (this->m_map.phi2(dFront) != dFront) { // if dFront is no border
m_quadric[d] += Utils::Quadric<REAL>(this->m_position[d],this->m_position[dBack],this->m_position[this->m_map.phi1(dFront)]) ;
}
} while(dFront != dInit) ;
}
template <typename PFP>
void HalfEdgeSelector_ColorPerFace<PFP>::updateAfterCollapse(Dart d2, Dart dd2)
{
MAP& m = this->m_map ;
const Dart& v1 = d2 ;
recomputeQuadric(v1) ;
Traversor2VVaE<MAP> tv(m,v1) ;
for (Dart v = tv.begin() ; v != tv.end() ; v = tv.next())
{
recomputeQuadric(v) ;
}
for (Dart v = tv.begin() ; v != tv.end() ; v = tv.next())
{
Traversor2VE<MAP> te(m,v) ;
for (Dart e = te.begin() ; e != te.end() ; e = te.next())
{
updateHalfEdgeInfo(e) ;
updateHalfEdgeInfo(m.phi2(e)) ;
}
}
cur = halfEdges.begin() ; // set the current edge to the first one
}
template <typename PFP>
void HalfEdgeSelector_ColorPerFace<PFP>::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 <typename PFP>
void HalfEdgeSelector_ColorPerFace<PFP>::updateHalfEdgeInfo(Dart d)
{
MAP& m = this->m_map ;
HalfEdgeInfo& heinfo = halfEdgeInfo[d] ;
if(!heinfo.valid && m.edgeCanCollapse(d))
computeHalfEdgeInfo(d, heinfo) ;
}
template <typename PFP>
void HalfEdgeSelector_ColorPerFace<PFP>::computeHalfEdgeInfo(Dart d, HalfEdgeInfo& heinfo)
{
MAP& m = this->m_map ;
Dart dd = m.phi1(d) ;
Utils::Quadric<REAL> 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<ApproximatorGen<PFP>*>::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