2011-04-01 18:25:49 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* VCGLib o o *
|
|
|
|
* Visual and Computer Graphics Library o o *
|
|
|
|
* _ O _ *
|
|
|
|
* Copyright(C) 2004 \/)\/ *
|
|
|
|
* Visual Computing Lab /\/| *
|
|
|
|
* ISTI - Italian National Research Council | *
|
|
|
|
* \ *
|
|
|
|
* All rights reserved. *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
|
|
|
* for more details. *
|
|
|
|
* *
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef __VCG_DECIMATION_TRICOLLAPSE
|
|
|
|
#define __VCG_DECIMATION_TRICOLLAPSE
|
|
|
|
|
2011-04-01 19:06:03 +02:00
|
|
|
#include<vcg/complex/algorithms/edge_collapse.h>
|
2011-04-01 18:25:49 +02:00
|
|
|
#include<vcg/simplex/face/pos.h>
|
2011-04-01 19:06:03 +02:00
|
|
|
#include<vcg/complex/algorithms/local_optimization.h>
|
2011-06-08 10:46:02 +02:00
|
|
|
#include<vcg/complex/algorithms/update/topology.h>
|
2011-04-01 18:25:49 +02:00
|
|
|
|
|
|
|
namespace vcg{
|
|
|
|
namespace tri{
|
|
|
|
|
|
|
|
/** \addtogroup trimesh */
|
|
|
|
/*@{*/
|
|
|
|
/// This Class is specialization of LocalModification for the edge collapse.
|
|
|
|
/// It wraps the atomic operation EdgeCollapse to be used in a optimizatin routine.
|
|
|
|
/// Note that it has knowledge of the heap of the class LocalOptimization because
|
|
|
|
/// it is responsible of updating it after a collapse has been performed;
|
|
|
|
/// This is the base class of all the specialized collapse classes like for example Quadric Edge Collapse.
|
|
|
|
/// Each derived class
|
|
|
|
|
2011-05-20 17:12:09 +02:00
|
|
|
template<class TriMeshType, class VertexPair, class MYTYPE>
|
|
|
|
class TriEdgeCollapse: public LocalOptimization<TriMeshType>::LocModType
|
2011-04-01 18:25:49 +02:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
/// static data to gather statistical information about the reasons of collapse failures
|
|
|
|
class FailStat {
|
|
|
|
public:
|
|
|
|
static int &Volume() {static int vol=0; return vol;}
|
|
|
|
static int &LinkConditionFace(){static int lkf=0; return lkf;}
|
|
|
|
static int &LinkConditionEdge(){static int lke=0; return lke;}
|
|
|
|
static int &LinkConditionVert(){static int lkv=0; return lkv;}
|
|
|
|
static int &OutOfDate() {static int ofd=0; return ofd;}
|
|
|
|
static int &Border() {static int bor=0; return bor;}
|
|
|
|
static void Init()
|
|
|
|
{
|
|
|
|
Volume() =0;
|
|
|
|
LinkConditionFace()=0;
|
|
|
|
LinkConditionEdge()=0;
|
|
|
|
LinkConditionVert()=0;
|
|
|
|
OutOfDate() =0;
|
|
|
|
Border() =0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
protected:
|
|
|
|
typedef typename TriMeshType::FaceType FaceType;
|
|
|
|
typedef typename TriMeshType::FaceType::VertexType VertexType;
|
2011-05-20 17:12:09 +02:00
|
|
|
// typedef typename VertexType::EdgeType EdgeType;
|
2011-04-01 18:25:49 +02:00
|
|
|
typedef typename FaceType::VertexType::CoordType CoordType;
|
|
|
|
typedef typename TriMeshType::VertexType::ScalarType ScalarType;
|
|
|
|
typedef typename LocalOptimization<TriMeshType>::HeapElem HeapElem;
|
|
|
|
typedef typename LocalOptimization<TriMeshType>::HeapType HeapType;
|
|
|
|
|
|
|
|
TriMeshType *mt;
|
|
|
|
///the pair to collapse
|
2011-05-20 17:12:09 +02:00
|
|
|
VertexPair pos;
|
2011-04-01 18:25:49 +02:00
|
|
|
|
|
|
|
///mark for up_dating
|
|
|
|
static int& GlobalMark(){ static int im=0; return im;}
|
|
|
|
|
|
|
|
///mark for up_dating
|
|
|
|
int localMark;
|
|
|
|
|
|
|
|
/// priority in the heap
|
|
|
|
ScalarType _priority;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/// Default Constructor
|
|
|
|
inline TriEdgeCollapse()
|
|
|
|
{}
|
|
|
|
///Constructor with postype
|
2011-05-20 17:12:09 +02:00
|
|
|
inline TriEdgeCollapse(const VertexPair &p, int mark, BaseParameterClass *pp)
|
2011-04-01 18:25:49 +02:00
|
|
|
{
|
|
|
|
localMark = mark;
|
|
|
|
pos=p;
|
2011-05-20 17:12:09 +02:00
|
|
|
_priority = ComputePriority(pp);
|
2011-04-01 18:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
~TriEdgeCollapse()
|
|
|
|
{}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2011-05-20 17:12:09 +02:00
|
|
|
inline ScalarType ComputePriority(BaseParameterClass *)
|
2011-04-01 18:25:49 +02:00
|
|
|
{
|
|
|
|
_priority = Distance(pos.V(0)->cP(),pos.V(1)->cP());
|
|
|
|
return _priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual const char *Info(TriMeshType &m) {
|
|
|
|
mt = &m;
|
|
|
|
static char buf[60];
|
|
|
|
sprintf(buf,"%i -> %i %g\n", int(pos.V(0)-&m.vert[0]), int(pos.V(1)-&m.vert[0]),-_priority);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2011-05-20 17:12:09 +02:00
|
|
|
inline void Execute(TriMeshType &m, BaseParameterClass *)
|
2011-04-01 18:25:49 +02:00
|
|
|
{
|
|
|
|
CoordType MidPoint=(pos.V(0)->P()+pos.V(1)->P())/2.0;
|
2011-05-20 17:12:09 +02:00
|
|
|
EdgeCollapser<TriMeshType,VertexPair>::Do(m, pos, MidPoint);
|
2011-04-01 18:25:49 +02:00
|
|
|
}
|
|
|
|
|
2011-05-20 17:12:09 +02:00
|
|
|
static bool IsSymmetric(BaseParameterClass *) { return true;}
|
2011-04-01 18:25:49 +02:00
|
|
|
|
|
|
|
// This function is called after an action to re-add in the heap elements whose priority could have been changed.
|
|
|
|
// in the plain case we just put again in the heap all the edges around the vertex resulting from the previous collapse: v[1].
|
|
|
|
// if the collapse is not symmetric you should add also backward edges (because v0->v1 collapse could be different from v1->v0)
|
|
|
|
|
2011-05-20 17:12:09 +02:00
|
|
|
inline void UpdateHeap(HeapType & h_ret, BaseParameterClass *pp)
|
2011-04-01 18:25:49 +02:00
|
|
|
{
|
2013-01-28 16:42:24 +01:00
|
|
|
GlobalMark()++;
|
|
|
|
VertexType *v[2];
|
|
|
|
v[0]= pos.V(0);v[1]=pos.V(1);
|
|
|
|
v[1]->IMark() = GlobalMark();
|
2011-04-01 18:25:49 +02:00
|
|
|
|
2013-01-28 16:42:24 +01:00
|
|
|
// First loop around the remaining vertex to unmark visited flags
|
2011-04-01 18:25:49 +02:00
|
|
|
vcg::face::VFIterator<FaceType> vfi(v[1]);
|
2013-01-28 16:42:24 +01:00
|
|
|
while (!vfi.End()){
|
|
|
|
vfi.V1()->ClearV();
|
|
|
|
vfi.V2()->ClearV();
|
|
|
|
++vfi;
|
|
|
|
}
|
2011-04-01 18:25:49 +02:00
|
|
|
|
|
|
|
// Second Loop: add all the outgoing edges around v[1]
|
|
|
|
// for each face add the two edges outgoing from v[1] and not visited.
|
|
|
|
vfi = face::VFIterator<FaceType>(v[1]);
|
|
|
|
while (!vfi.End())
|
|
|
|
{
|
2013-01-28 16:42:24 +01:00
|
|
|
assert(!vfi.F()->IsD());
|
|
|
|
if( !(vfi.V1()->IsV()) && (vfi.V1()->IsRW()))
|
|
|
|
{
|
|
|
|
vfi.V1()->SetV();
|
|
|
|
h_ret.push_back(HeapElem(new MYTYPE(VertexPair( vfi.V(),vfi.V1() ),GlobalMark(),pp)));
|
|
|
|
std::push_heap(h_ret.begin(),h_ret.end());
|
|
|
|
if(! this->IsSymmetric(pp)){
|
|
|
|
h_ret.push_back(HeapElem(new MYTYPE(VertexPair( vfi.V1(),vfi.V()),GlobalMark(),pp)));
|
2011-04-01 18:25:49 +02:00
|
|
|
std::push_heap(h_ret.begin(),h_ret.end());
|
|
|
|
}
|
2013-01-28 16:42:24 +01:00
|
|
|
}
|
|
|
|
if( !(vfi.V2()->IsV()) && (vfi.V2()->IsRW()))
|
|
|
|
{
|
|
|
|
vfi.V2()->SetV();
|
|
|
|
h_ret.push_back(HeapElem(new MYTYPE(VertexPair(vfi.F()->V(vfi.I()),vfi.F()->V2(vfi.I())),GlobalMark(),pp)));
|
|
|
|
std::push_heap(h_ret.begin(),h_ret.end());
|
|
|
|
if(! this->IsSymmetric(pp)){
|
|
|
|
h_ret.push_back(HeapElem(new MYTYPE(VertexPair (vfi.F()->V1(vfi.I()),vfi.F()->V(vfi.I())),GlobalMark(),pp)));
|
2011-04-01 18:25:49 +02:00
|
|
|
std::push_heap(h_ret.begin(),h_ret.end());
|
|
|
|
}
|
2013-01-28 16:42:24 +01:00
|
|
|
}
|
|
|
|
// if(vfi.V1()->IsRW() && vfi.V2()->IsRW() )
|
|
|
|
// {
|
|
|
|
// h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V1(),vfi.V2()),this->GlobalMark())));
|
|
|
|
// std::push_heap(h_ret.begin(),h_ret.end());
|
|
|
|
// if(IsSymmetric()){
|
|
|
|
// h_ret.push_back(HeapElem(new MYTYPE(EdgeType(vfi.V2(),vfi.V1()), this->GlobalMark())));
|
|
|
|
// std::push_heap(h_ret.begin(),h_ret.end());
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
++vfi;
|
|
|
|
} // end while
|
2011-04-01 18:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ModifierType IsOfType(){ return TriEdgeCollapseOp;}
|
|
|
|
|
2011-10-05 17:04:40 +02:00
|
|
|
inline bool IsFeasible(BaseParameterClass *){
|
2011-05-20 17:12:09 +02:00
|
|
|
return EdgeCollapser<TriMeshType,VertexPair>::LinkConditions(pos);
|
2011-04-01 18:25:49 +02:00
|
|
|
}
|
|
|
|
|
2011-05-20 17:12:09 +02:00
|
|
|
inline bool IsUpToDate() const
|
|
|
|
{
|
|
|
|
VertexType *v0=pos.cV(0);
|
|
|
|
VertexType *v1=pos.cV(1);
|
2011-04-01 18:25:49 +02:00
|
|
|
if( v0->IsD() || v1->IsD() ||
|
|
|
|
localMark < v0->IMark() ||
|
|
|
|
localMark < v1->IMark() )
|
|
|
|
{
|
|
|
|
++FailStat::OutOfDate();
|
|
|
|
return false;
|
2011-05-20 17:12:09 +02:00
|
|
|
}
|
|
|
|
return true;
|
2011-04-01 18:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual ScalarType Priority() const {
|
|
|
|
return _priority;
|
|
|
|
}
|
|
|
|
|
2011-05-20 17:12:09 +02:00
|
|
|
static void Init(TriMeshType &m, HeapType &h_ret, BaseParameterClass *pp)
|
|
|
|
{
|
|
|
|
vcg::tri::UpdateTopology<TriMeshType>::VertexFace(m);
|
|
|
|
h_ret.clear();
|
|
|
|
typename TriMeshType::FaceIterator fi;
|
|
|
|
for(fi = m.face.begin(); fi != m.face.end();++fi)
|
|
|
|
if(!(*fi).IsD()){
|
|
|
|
for (int j=0;j<3;j++)
|
2011-04-01 18:25:49 +02:00
|
|
|
{
|
2011-05-20 17:12:09 +02:00
|
|
|
VertexPair p((*fi).V0(j), (*fi).V1(j));
|
|
|
|
p.Sort();
|
|
|
|
h_ret.push_back(HeapElem(new MYTYPE(p, IMark(m),pp)));
|
2011-04-01 18:25:49 +02:00
|
|
|
//printf("Inserting in heap coll %3i ->%3i %f\n",p.V()-&m.vert[0],p.VFlip()-&m.vert[0],h_ret.back().locModPtr->Priority());
|
|
|
|
}
|
2011-05-20 17:12:09 +02:00
|
|
|
}
|
2011-04-01 18:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
}//end namespace tri
|
|
|
|
}//end namespace vcg
|
|
|
|
|
|
|
|
#endif
|