2004-06-08 17:24:58 +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. *
|
|
|
|
* *
|
|
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
|
|
History
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifndef __VCG_TETRA_TRI_COLLAPSE
|
|
|
|
#define __VCG_TETRA_TRI_COLLAPSE
|
|
|
|
|
|
|
|
|
2004-09-09 15:02:12 +02:00
|
|
|
#include<vcg/simplex/face/pos.h>
|
|
|
|
#include<vcg/simplex/face/topology.h>
|
2004-06-08 17:24:58 +02:00
|
|
|
#include<map>
|
|
|
|
|
|
|
|
/** \addtogroup trimesh */
|
|
|
|
/*@{*/
|
2004-09-28 11:58:47 +02:00
|
|
|
/** This a static utlity class for the edge collapse.
|
|
|
|
It provides a common set of useful function for actually making an edge collapse over a trimesh. See also
|
|
|
|
**/
|
2004-06-08 17:24:58 +02:00
|
|
|
namespace vcg{
|
|
|
|
namespace tri{
|
|
|
|
|
|
|
|
template <class TRI_MESH_TYPE>
|
|
|
|
class EdgeCollapse
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
/// The tetrahedral mesh type
|
2004-09-08 17:13:03 +02:00
|
|
|
typedef TRI_MESH_TYPE TriMeshType;
|
2004-06-08 17:24:58 +02:00
|
|
|
/// The tetrahedron type
|
|
|
|
typedef typename TriMeshType::FaceType FaceType;
|
|
|
|
/// The vertex type
|
|
|
|
typedef typename FaceType::VertexType VertexType;
|
|
|
|
/// The vertex iterator type
|
|
|
|
typedef typename TriMeshType::VertexIterator VertexIterator;
|
|
|
|
/// The tetra iterator type
|
2004-07-15 13:36:13 +02:00
|
|
|
typedef typename TriMeshType::FaceIterator FaceIterator;
|
2004-06-08 17:24:58 +02:00
|
|
|
/// The coordinate type
|
|
|
|
typedef typename FaceType::VertexType::CoordType CoordType;
|
|
|
|
/// The scalar type
|
|
|
|
typedef typename TriMeshType::VertexType::ScalarType ScalarType;
|
|
|
|
///the container of tetrahedron type
|
|
|
|
typedef typename TriMeshType::FaceContainer FaceContainer;
|
|
|
|
///the container of vertex type
|
2004-06-15 18:15:18 +02:00
|
|
|
typedef typename TriMeshType::VertContainer VertContainer;
|
2004-07-15 13:36:13 +02:00
|
|
|
///half edge type
|
|
|
|
typedef typename vcg::face::Pos<FaceType> PosType;
|
|
|
|
/// vector of pos
|
|
|
|
typedef typename std::vector<PosType> PosVec;
|
|
|
|
///of VFIterator
|
|
|
|
typedef typename vcg::face::VFIterator<FaceType> VFI;
|
|
|
|
/// vector of VFIterator
|
|
|
|
typedef typename std::vector<vcg::face::VFIterator<FaceType> > VFIVec;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Default Constructor
|
2004-06-08 17:24:58 +02:00
|
|
|
EdgeCollapse()
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
~EdgeCollapse()
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct Edge{
|
|
|
|
VertexType* v0,v1;
|
2004-06-15 18:15:18 +02:00
|
|
|
Edge( const VertexType*& a,const VertexType*& b){
|
2004-06-08 17:24:58 +02:00
|
|
|
assert(a!=b);
|
|
|
|
if(a<b)
|
|
|
|
{v0=a;v1=b;}
|
|
|
|
else
|
|
|
|
{v1=a;v0=b;}
|
|
|
|
}
|
|
|
|
|
2004-06-15 18:15:18 +02:00
|
|
|
const bool operator <(const Edge & e) const {
|
2004-06-08 17:24:58 +02:00
|
|
|
return (v0==e.v0)?(v1<e.v1):(v0<e.v0);
|
|
|
|
}
|
|
|
|
|
2004-06-15 18:15:18 +02:00
|
|
|
const bool operator ==(const Edge & e) const {
|
2004-06-08 17:24:58 +02:00
|
|
|
return (v0==e.v0)&&(v1==e.v1);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2004-07-15 13:36:13 +02:00
|
|
|
static VFIVec & AV0(){static VFIVec av0; return av0;}
|
|
|
|
static VFIVec & AV1(){static VFIVec av1; return av1;}
|
|
|
|
static VFIVec & AV01(){static VFIVec av01; return av01;}
|
|
|
|
|
|
|
|
|
|
|
|
void FindSets(PosType p)
|
|
|
|
{
|
|
|
|
VertexType * v0 = p.V(0);
|
|
|
|
VertexType * v1 = p.V(1);
|
|
|
|
|
2004-10-12 17:43:26 +02:00
|
|
|
AV0().clear(); // Facce incidenti in v0
|
|
|
|
AV1().clear(); // Facce incidenti in v1
|
2004-07-15 13:36:13 +02:00
|
|
|
AV01().clear(); // Facce incidenti in v0 e v1
|
|
|
|
|
|
|
|
VFI x;
|
|
|
|
|
2004-07-27 11:46:15 +02:00
|
|
|
for( x.f = v0->VFp(), x.z = v0->VFi(); x.f!=0; ++x)
|
2004-07-15 13:36:13 +02:00
|
|
|
{
|
|
|
|
int zv1 = -1;
|
|
|
|
|
|
|
|
for(int j=0;j<3;++j)
|
|
|
|
if( x.f->V(j)==&*v1 ) {
|
|
|
|
zv1 = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(zv1==-1) AV0().push_back( x ); // la faccia x.f non ha il vertice v1 => e' incidente solo in v0
|
|
|
|
else AV01().push_back( x );
|
2004-06-08 17:24:58 +02:00
|
|
|
}
|
|
|
|
|
2004-07-27 11:46:15 +02:00
|
|
|
for( x.f = v1->VFp(), x.z = v1->VFi(); x.f!=0; ++x )
|
2004-07-15 13:36:13 +02:00
|
|
|
{
|
|
|
|
int zv0 = -1;
|
|
|
|
|
|
|
|
for(int j=0;j<3;++j)
|
|
|
|
if( x.f->V(j)==&*v0 ) {
|
|
|
|
zv0 = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(zv0==-1) AV1().push_back( x ); // la faccia x.f non ha il vertice v1 => e' incidente solo in v0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LinkConditions(PosType pos){
|
|
|
|
|
|
|
|
const int ADJ_1 = TriMeshType::VertexType::NewBitFlag();
|
|
|
|
const int ADJ_E = TriMeshType::VertexType::NewBitFlag();
|
|
|
|
//enum {ADJ_1= MeshType::VertexType::USER0,
|
|
|
|
// ADJ_E= MeshType::VertexType::USER0<<1} ;
|
2004-09-08 17:13:03 +02:00
|
|
|
// const int ALLADJ = ADJ_1|ADJ_E;
|
2004-07-15 13:36:13 +02:00
|
|
|
const int NOTALLADJ = ~(ADJ_1 | ADJ_E | TriMeshType::VertexType::VISITED);
|
|
|
|
const int NOTALLADJ1 = ~(ADJ_E | TriMeshType::VertexType::VISITED);
|
|
|
|
|
|
|
|
//EdgePosB<MeshType::face_type::face_base> x;
|
2004-09-08 17:13:03 +02:00
|
|
|
typename vcg::face::VFIterator<FaceType> x;
|
2004-06-08 17:24:58 +02:00
|
|
|
// Clear visited and adj flag for all vertices adj to v0;
|
2004-07-27 11:46:15 +02:00
|
|
|
for(x.f = pos.V(0)->VFp(), x.z = pos.V(0)->VFi(); x.f!=0; ++x ) {
|
2004-07-15 13:36:13 +02:00
|
|
|
x.f->V1(x.z)->Flags() &= NOTALLADJ;
|
|
|
|
x.f->V2(x.z)->Flags() &= NOTALLADJ;
|
|
|
|
}
|
|
|
|
// Clear visited flag for all vertices adj to v1 and set them adj1 to v1;
|
2004-07-27 11:46:15 +02:00
|
|
|
for(x.f = pos.V(1)->VFp(), x.z = pos.V(1)->VFi(); x.f!=0; ++x ) {
|
2004-07-15 13:36:13 +02:00
|
|
|
x.f->V1(x.z)->Flags() &= NOTALLADJ1;
|
|
|
|
x.f->V2(x.z)->Flags() &= NOTALLADJ1;
|
|
|
|
}
|
|
|
|
// Mark vertices adj to v1 as ADJ_1 and adj1 to v1;
|
2004-07-27 11:46:15 +02:00
|
|
|
for(x.f = pos.V(1)->VFp(), x.z = pos.V(1)->VFi(); x.f!=0; ++x ) {
|
2004-07-15 13:36:13 +02:00
|
|
|
if(x.f->V1(x.z)==pos.V(0)) x.f->V2(x.z)->Flags() |= ADJ_E | ADJ_1;
|
|
|
|
else x.f->V2(x.z)->Flags() |= ADJ_1;
|
|
|
|
if(x.f->V2(x.z)==pos.V(0)) x.f->V1(x.z)->Flags() |= ADJ_E | ADJ_1;
|
|
|
|
else x.f->V1(x.z)->Flags() |= ADJ_1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// compute the number of:
|
|
|
|
int adj01=0; // vertices adjacents to both v0 and v1
|
|
|
|
int adje=0; // vertices adjacents to an egde (usually 2)
|
2004-07-27 11:46:15 +02:00
|
|
|
for(x.f = pos.V(0)->VFp(), x.z = pos.V(0)->VFi(); x.f!=0; ++x ) {
|
2004-07-15 13:36:13 +02:00
|
|
|
if(!x.f->V1(x.z)->IsV()) {
|
|
|
|
x.f->V1(x.z)->SetV();
|
|
|
|
if(x.f->V1(x.z)->Flags()&ADJ_1) ++adj01;
|
|
|
|
if(x.f->V1(x.z)->Flags()&ADJ_E) ++adje;
|
|
|
|
}
|
|
|
|
if(!x.f->V2(x.z)->IsV()) {
|
|
|
|
x.f->V2(x.z)->SetV();
|
|
|
|
if(x.f->V2(x.z)->Flags()&ADJ_1) ++adj01;
|
|
|
|
if(x.f->V2(x.z)->Flags()&ADJ_E) ++adje;
|
|
|
|
}
|
2004-06-08 17:24:58 +02:00
|
|
|
}
|
|
|
|
|
2004-07-15 13:36:13 +02:00
|
|
|
//bool val=TopoCheck2();
|
|
|
|
//if(val != (adj01==adje)) printf("Wrong topo %i %i\n",adj01,adje);
|
|
|
|
TriMeshType::VertexType::DeleteBitFlag(ADJ_E);
|
|
|
|
TriMeshType::VertexType::DeleteBitFlag(ADJ_1);
|
2004-06-08 17:24:58 +02:00
|
|
|
|
2004-07-15 13:36:13 +02:00
|
|
|
return (adj01==adje);
|
2004-06-08 17:24:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-15 13:36:13 +02:00
|
|
|
|
|
|
|
int DoCollapse(PosType & c, Point3<ScalarType> p)
|
|
|
|
{
|
2004-09-07 17:41:57 +02:00
|
|
|
FindSets(c);
|
2004-09-08 17:13:03 +02:00
|
|
|
typename VFIVec::iterator i;
|
2004-07-15 13:36:13 +02:00
|
|
|
int n_face_del =0 ;
|
2004-09-07 17:41:57 +02:00
|
|
|
|
|
|
|
//set Face Face topology
|
|
|
|
if (TriMeshType::HasFFTopology())
|
|
|
|
{
|
|
|
|
int e0=c.z;
|
|
|
|
int e1=c.f->FFi(c.z); //opposite edge
|
|
|
|
|
|
|
|
FaceType *f0=c.f;
|
|
|
|
FaceType *f1=f0->FFp(c.z);
|
|
|
|
|
|
|
|
//take right indexes
|
|
|
|
FaceType *f00=f0->FFp((e0+1)%3);
|
|
|
|
FaceType *f01=f0->FFp((e0+2)%3);
|
|
|
|
int If00=f0->FFi((e0+1)%3);
|
|
|
|
int If01=f0->FFi((e0+2)%3);
|
|
|
|
|
|
|
|
//then attach faces
|
|
|
|
f00->FFp(If00)=f01;
|
|
|
|
f00->FFi(If00)=If01;
|
|
|
|
f01->FFp(If01)=f00;
|
|
|
|
f01->FFi(If01)=If00;
|
|
|
|
|
|
|
|
//and the ones of face f1
|
|
|
|
|
|
|
|
f00=f1->FFp((e1+1)%3);
|
|
|
|
f01=f1->FFp((e1+2)%3);
|
|
|
|
If00=f1->FFi((e1+1)%3);
|
|
|
|
If01=f1->FFi((e1+2)%3);
|
|
|
|
|
|
|
|
//and attach faces
|
|
|
|
f00->FFp(If00)=f01;
|
|
|
|
f00->FFi(If00)=If01;
|
|
|
|
f01->FFp(If01)=f00;
|
|
|
|
f01->FFi(If01)=If00;
|
|
|
|
}
|
|
|
|
|
2004-07-15 13:36:13 +02:00
|
|
|
for(i=AV01().begin();i!=AV01().end();++i)
|
|
|
|
{
|
2004-10-12 17:43:26 +02:00
|
|
|
FaceType & f = *((*i).f);
|
|
|
|
assert(f.V((*i).z) == c.V(0));
|
2004-07-15 13:36:13 +02:00
|
|
|
|
2004-10-12 17:43:26 +02:00
|
|
|
vcg::face::VFDetach(f,(*i).z);
|
|
|
|
vcg::face::VFDetach(f,((*i).z+1)%3);
|
|
|
|
vcg::face::VFDetach(f,((*i).z+2)%3);
|
|
|
|
f.SetD();
|
2004-07-15 13:36:13 +02:00
|
|
|
n_face_del++;
|
|
|
|
}
|
|
|
|
|
2004-09-07 17:41:57 +02:00
|
|
|
//set Vertex Face topology
|
2004-07-15 13:36:13 +02:00
|
|
|
for(i=AV0().begin();i!=AV0().end();++i)
|
|
|
|
{
|
|
|
|
(*i).f->V((*i).z) = c.V(1); // In tutte le facce incidenti in v0, si sostituisce v0 con v1
|
|
|
|
(*i).f->VFp((*i).z) = (*i).f->V((*i).z)->VFp(); // e appendo la lista di facce incidenti in v1 a questa faccia
|
|
|
|
(*i).f->VFi((*i).z) = (*i).f->V((*i).z)->VFi();
|
|
|
|
(*i).f->V((*i).z)->VFp() = (*i).f;
|
|
|
|
(*i).f->V((*i).z)->VFi() = (*i).z;
|
2004-10-12 17:43:26 +02:00
|
|
|
vcg::Quality((*i).f->P(0),(*i).f->P(1),(*i).f->P(2));
|
2004-07-15 13:36:13 +02:00
|
|
|
}
|
2004-09-07 17:41:57 +02:00
|
|
|
|
|
|
|
/*TriMeshType::VertexType nv;*/
|
2004-07-15 13:36:13 +02:00
|
|
|
//* c.v[1]->Merge(*c.v[0]);
|
|
|
|
c.V(0)->SetD();
|
2004-09-07 17:41:57 +02:00
|
|
|
c.V(1)->P()=p;
|
2004-07-15 13:36:13 +02:00
|
|
|
return n_face_del;
|
|
|
|
}
|
|
|
|
|
2004-06-08 17:24:58 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2004-09-08 17:13:03 +02:00
|
|
|
#endif
|