files moved to tetra_mesh path
This commit is contained in:
parent
cf20e1d0c1
commit
638dfc64fb
|
@ -1,901 +0,0 @@
|
||||||
/****************************************************************************
|
|
||||||
* 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_EDGE_COLLAPSE
|
|
||||||
#define __VCG_TETRA_EDGE_COLLAPSE
|
|
||||||
|
|
||||||
#include <vcg/space/tetra3.h>
|
|
||||||
#include <vcg/complex/tetramesh/update/topology.h>
|
|
||||||
#include <vcg/complex/tetramesh/update/normal.h>
|
|
||||||
|
|
||||||
namespace vcg{
|
|
||||||
namespace tetra{
|
|
||||||
|
|
||||||
/** \addtogroup tetramesh */
|
|
||||||
/*@{*/
|
|
||||||
/// This Class is used for the edge collapse
|
|
||||||
template <class TETRA_MESH_TYPE>
|
|
||||||
class EdgeCollapse
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// The tetrahedral mesh type
|
|
||||||
typedef typename TETRA_MESH_TYPE TetraMeshType;
|
|
||||||
/// The tetrahedron type
|
|
||||||
typedef typename TetraMeshType::TetraType TetraType;
|
|
||||||
/// The vertex type
|
|
||||||
typedef typename TetraType::VertexType VertexType;
|
|
||||||
/// The vertex iterator type
|
|
||||||
typedef typename TetraMeshType::VertexIterator VertexIterator;
|
|
||||||
/// The tetra iterator type
|
|
||||||
typedef typename TetraMeshType::TetraIterator TetraIterator;
|
|
||||||
/// The coordinate type
|
|
||||||
typedef typename TetraType::VertexType::CoordType CoordType;
|
|
||||||
/// The scalar type
|
|
||||||
typedef typename TetraMeshType::VertexType::ScalarType ScalarType;
|
|
||||||
///the container of tetrahedron type
|
|
||||||
typedef typename TetraMeshType::TetraContainer TetraContainer;
|
|
||||||
///the container of vertex type
|
|
||||||
typedef typename TetraMeshType::VertexContainer VertexContainer;
|
|
||||||
/// The HEdgePos type
|
|
||||||
typedef Pos<TetraType> PosType;
|
|
||||||
/// The HEdgePos Loop type
|
|
||||||
typedef PosLoop<TetraType> PosLType;
|
|
||||||
/// The topology updater type
|
|
||||||
typedef vcg::tetra::UpdateTetraTopology<VertexContainer,TetraContainer> Topology;
|
|
||||||
///the normal updater type
|
|
||||||
typedef vcg::tetra::UpdateNormals<TetraMeshType> UpdateNormals;
|
|
||||||
|
|
||||||
|
|
||||||
/// Default Constructor
|
|
||||||
EdgeCollapse()
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
~EdgeCollapse()
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef pair <int,int> FacePair;
|
|
||||||
struct Face
|
|
||||||
{
|
|
||||||
VertexType* v[3];
|
|
||||||
|
|
||||||
Face( VertexType* a, VertexType* b,VertexType* c)
|
|
||||||
{
|
|
||||||
assert((a!=b)&&(b!=c)&&(a!=c));
|
|
||||||
v[0]=a;
|
|
||||||
v[1]=b;
|
|
||||||
v[2]=c;
|
|
||||||
sort(v,v+3);
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool operator <(const Face & f) const
|
|
||||||
{
|
|
||||||
return ((v[0]==f.v[0])?((v[1]==f.v[1])?(v[2]<f.v[2]):(v[1]<f.v[1])):(v[0]<f.v[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool operator ==(const Face & f) const {
|
|
||||||
return ((v[0]==f.v[0])&&(v[1]==f.v[1])&&(v[2]==f.v[2]));
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Edge{
|
|
||||||
VertexType* v0;
|
|
||||||
VertexType* v1;
|
|
||||||
Edge( VertexType* a, VertexType* b){
|
|
||||||
assert(a!=b);
|
|
||||||
if(a<b)
|
|
||||||
{v0=a;v1=b;}
|
|
||||||
else
|
|
||||||
{v1=a;v0=b;}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool operator <(const Edge & e) const {
|
|
||||||
return (v0==e.v0)?(v1<e.v1):(v0<e.v0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool operator ==(const Edge & e) const {
|
|
||||||
return (v0==e.v0)&&(v1==e.v1);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
struct TetraSets
|
|
||||||
{
|
|
||||||
std::vector <TetraType*> v0;
|
|
||||||
std::vector <TetraType*> v1;
|
|
||||||
std::vector <TetraType*> v0_U_v1;
|
|
||||||
std::vector <TetraType*> no_E;
|
|
||||||
std::vector <TetraType*> E;
|
|
||||||
std::vector <char> indexE;
|
|
||||||
std::vector <char> indexv0;
|
|
||||||
std::vector <char> indexv1;
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
v0.clear();
|
|
||||||
v1.clear();
|
|
||||||
v0_U_v1.clear();
|
|
||||||
no_E.clear();
|
|
||||||
E.clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static map<Edge,char> & _EdgeMark(){
|
|
||||||
static map<Edge,char> em;
|
|
||||||
return em;
|
|
||||||
};
|
|
||||||
|
|
||||||
static map<Face,char> & _FaceMark(){
|
|
||||||
static map<Face,char> fm;
|
|
||||||
return fm;
|
|
||||||
}
|
|
||||||
|
|
||||||
static VertexType &_DummyV(){
|
|
||||||
static VertexType _dv;
|
|
||||||
return _dv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TetraSets &_Sets(){
|
|
||||||
static TetraSets _s;
|
|
||||||
return _s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///select the 2 faces that does not share the edge
|
|
||||||
static FacePair _FindNoEdgeFace(TetraType *t,int edge)
|
|
||||||
{
|
|
||||||
//as first I find the 2 faces on the opposite sides of the egde
|
|
||||||
int fa0=Tetra::FofE(edge,0);
|
|
||||||
int fa1=Tetra::FofE(edge,1);
|
|
||||||
|
|
||||||
//then find the faces that remain
|
|
||||||
int fa2=(fa0+1)%4;
|
|
||||||
while ((fa2==fa0)||(fa2==fa1))
|
|
||||||
{
|
|
||||||
fa2=(fa2+1)%4;
|
|
||||||
}
|
|
||||||
int fa3=(fa2+1)%4;
|
|
||||||
while ((fa3==fa0)||(fa3==fa1)||(fa3==fa2))
|
|
||||||
{
|
|
||||||
fa3=(fa3+1)%4;
|
|
||||||
}
|
|
||||||
return FacePair(fa2,fa3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
static void _AssertingVolume(TetraType *t)
|
|
||||||
{
|
|
||||||
assert(t->ComputeVolume() >0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
///collpse de edge specified by pos (the first vertex on edge remain)
|
|
||||||
static int _Collapse(PosType p,CoordType NewP)
|
|
||||||
{
|
|
||||||
int n_deleted=0;
|
|
||||||
vector<TetraType*> To_Del;
|
|
||||||
VertexType *Vrem=(p.T()->V(Tetra::VofE(p.E(),0)));
|
|
||||||
VertexType *Vdel=(p.T()->V(Tetra::VofE(p.E(),1)));
|
|
||||||
//Vrem->P()=(Vrem->P()*alfa)+(Vdel->P()*(1.f-alfa));
|
|
||||||
Vrem->P()=NewP;
|
|
||||||
PosLType pos(p.T(),p.F(),p.E(),p.V());
|
|
||||||
pos.Reset();
|
|
||||||
To_Del.reserve(40);
|
|
||||||
To_Del.clear();
|
|
||||||
while (!pos.LoopEnd())
|
|
||||||
{
|
|
||||||
//get the two faces that doesn't share the edge
|
|
||||||
FacePair fp=_FindNoEdgeFace(pos.T(),pos.E());
|
|
||||||
int fa0=fp.first;
|
|
||||||
int fa1=fp.second;
|
|
||||||
|
|
||||||
//now set the T-T topology on that faces
|
|
||||||
TetraType *tleft=pos.T()->TTp(fa0);
|
|
||||||
TetraType *tright=pos.T()->TTp(fa1);
|
|
||||||
int ileft=pos.T()->TTi(fa0);
|
|
||||||
int iright=pos.T()->TTi(fa1);
|
|
||||||
|
|
||||||
//in this case I cannot do the collapse
|
|
||||||
assert (!((pos.T()==tleft)&&(pos.T()==tright)));
|
|
||||||
|
|
||||||
//case no one is extern face
|
|
||||||
if ((!pos.T()->IsBorderF(fa0))&&(!pos.T()->IsBorderF(fa1)))
|
|
||||||
//connect the 2 tetrahedrons
|
|
||||||
Topology::_AttachTTTopology(tleft,ileft,tright,iright);
|
|
||||||
else
|
|
||||||
//case f2 is an extern face
|
|
||||||
if (pos.T()->IsBorderF(fa0))
|
|
||||||
{
|
|
||||||
tright->TTp(iright)=tright;
|
|
||||||
tright->TTi(iright)=iright;
|
|
||||||
}
|
|
||||||
|
|
||||||
else //case fa1 is an extern face
|
|
||||||
//if ((pos.T()->IsBorderF(fa3))
|
|
||||||
{
|
|
||||||
tleft->TTp(ileft)=tleft;
|
|
||||||
tleft->TTi(ileft)=ileft;
|
|
||||||
}
|
|
||||||
|
|
||||||
//end setting T-T topology
|
|
||||||
|
|
||||||
//setting the V-T topology
|
|
||||||
|
|
||||||
//i remove the tetrahedrons that have the edge
|
|
||||||
// to collapse
|
|
||||||
Topology::DetachVTTopology(pos.T());
|
|
||||||
//end setting the V-T topology
|
|
||||||
To_Del.push_back(pos.T());
|
|
||||||
pos.NextT();
|
|
||||||
|
|
||||||
n_deleted++;
|
|
||||||
// tm.tn--;
|
|
||||||
}
|
|
||||||
|
|
||||||
//delting old tetrahedrons
|
|
||||||
vector<TetraType*>::iterator ti;
|
|
||||||
for (ti=To_Del.begin();ti<To_Del.end();ti++)
|
|
||||||
(*ti)->SetD();
|
|
||||||
|
|
||||||
//now I cycle on the tetrahedron that had the old vertex
|
|
||||||
//reassegning the new one.
|
|
||||||
|
|
||||||
VTIterator< TetraType> VTi(Vdel->VTb(),Vdel->VTi());
|
|
||||||
while (!VTi.End())
|
|
||||||
{
|
|
||||||
TetraType *T_Change=VTi.Vt();
|
|
||||||
int index=VTi.Vi();
|
|
||||||
//VTi++;
|
|
||||||
//assegning the vertex that remain
|
|
||||||
T_Change->V(index)=Vrem;
|
|
||||||
Topology::DetachVTTopology(Vdel,T_Change);
|
|
||||||
Topology::InsertVTTopology(Vrem,index,T_Change);
|
|
||||||
//that's cause i restart everytime in the chain
|
|
||||||
//from the vertex
|
|
||||||
VTi.Vt()=Vdel->VTb();
|
|
||||||
VTi.Vi()=Vdel->VTi();
|
|
||||||
#ifdef _DEBUG
|
|
||||||
_AssertingVolume(T_Change);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
if (Vdel->IsB())
|
|
||||||
Vrem->SetB();
|
|
||||||
//set as deleted the vertex
|
|
||||||
Vdel->SetD();
|
|
||||||
// tm.vn--;
|
|
||||||
return n_deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void orMarkE(Edge E,char M)
|
|
||||||
{
|
|
||||||
map<Edge,char>::iterator EI;
|
|
||||||
EI=_EdgeMark().find(E);
|
|
||||||
if (EI==_EdgeMark().end())
|
|
||||||
_EdgeMark().insert (pair<Edge,char>(E,M));
|
|
||||||
else
|
|
||||||
(*EI).second|=M;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isMarkedE(Edge E,char M)
|
|
||||||
{
|
|
||||||
map<Edge,char>::iterator EI;
|
|
||||||
EI=_EdgeMark().find(E);
|
|
||||||
if (EI==_EdgeMark().end())
|
|
||||||
return false;
|
|
||||||
else return ((*EI).second & M);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void orMarkF(Face F,char M)
|
|
||||||
{
|
|
||||||
map<Face,char>::iterator FI;
|
|
||||||
FI=_FaceMark().find(F);
|
|
||||||
if (FI==_FaceMark().end())
|
|
||||||
_FaceMark().insert (pair<Face,char>(F,M));
|
|
||||||
else
|
|
||||||
(*FI).second|=M;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isMarkedF(Face F,char M)
|
|
||||||
{
|
|
||||||
map<Face,char>::iterator FI;
|
|
||||||
FI=_FaceMark().find(F);
|
|
||||||
if (FI==_FaceMark().end())
|
|
||||||
return false;
|
|
||||||
else return ((*FI).second & M);
|
|
||||||
}
|
|
||||||
|
|
||||||
///this structure is used to find the sets that are used in link conditions and more
|
|
||||||
|
|
||||||
///verify the link conditions on faces
|
|
||||||
static bool _LinkConditionsF(PosType pos)
|
|
||||||
{
|
|
||||||
const int LINK_V0 = 0x00000001;
|
|
||||||
const int LINK_EE = 0x00000002;
|
|
||||||
|
|
||||||
_EdgeMark().clear();
|
|
||||||
|
|
||||||
// Mark edges of ve0
|
|
||||||
vector< TetraType *>::iterator ti=_Sets().v0.begin();
|
|
||||||
vector< char >::iterator en=_Sets().indexv0.begin();
|
|
||||||
while (ti!=_Sets().v0.end())
|
|
||||||
{
|
|
||||||
//put dummy face
|
|
||||||
for (int f=0;f<3;f++)
|
|
||||||
{
|
|
||||||
int f_test=Tetra::FofV((*en),f);
|
|
||||||
if ((*ti)->IsBorderF(f_test))
|
|
||||||
{
|
|
||||||
orMarkF(Face((*ti)->V(Tetra::VofF(f_test,0)),(*ti)->V(Tetra::VofF(f_test,1)),&_DummyV()),LINK_V0);
|
|
||||||
orMarkF(Face((*ti)->V(Tetra::VofF(f_test,1)),(*ti)->V(Tetra::VofF(f_test,2)),&_DummyV()),LINK_V0);
|
|
||||||
orMarkF(Face((*ti)->V(Tetra::VofF(f_test,2)),(*ti)->V(Tetra::VofF(f_test,0)),&_DummyV()),LINK_V0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ti++;
|
|
||||||
en++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ti=_Sets().E.begin();
|
|
||||||
en=_Sets().indexE.begin();
|
|
||||||
//mark them as intersection
|
|
||||||
while (ti!=_Sets().E.end())
|
|
||||||
{
|
|
||||||
//faces on the edge
|
|
||||||
int f0=Tetra::FofE((*en),0);
|
|
||||||
int f1=Tetra::FofE((*en),1);
|
|
||||||
|
|
||||||
if ((*ti)->IsBorderF(f0))
|
|
||||||
{
|
|
||||||
orMarkF(Face((*ti)->V(Tetra::VofF(f0,0)),(*ti)->V(Tetra::VofF(f0,1)),&_DummyV()),LINK_EE);
|
|
||||||
orMarkF(Face((*ti)->V(Tetra::VofF(f0,1)),(*ti)->V(Tetra::VofF(f0,2)),&_DummyV()),LINK_EE);
|
|
||||||
orMarkF(Face((*ti)->V(Tetra::VofF(f0,2)),(*ti)->V(Tetra::VofF(f0,0)),&_DummyV()),LINK_EE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*ti)->IsBorderF(f1))
|
|
||||||
{
|
|
||||||
orMarkF(Face((*ti)->V(Tetra::VofF(f1,0)),(*ti)->V(Tetra::VofF(f1,1)),&_DummyV()),LINK_EE);
|
|
||||||
orMarkF(Face((*ti)->V(Tetra::VofF(f1,1)),(*ti)->V(Tetra::VofF(f1,2)),&_DummyV()),LINK_EE);
|
|
||||||
orMarkF(Face((*ti)->V(Tetra::VofF(f1,2)),(*ti)->V(Tetra::VofF(f1,0)),&_DummyV()),LINK_EE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ti++;
|
|
||||||
en++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//and at the end I verify if the intersection is equal to the star of the edge
|
|
||||||
ti=_Sets().v1.begin();
|
|
||||||
en=_Sets().indexv1.begin();
|
|
||||||
while (ti!=_Sets().v1.end())
|
|
||||||
{
|
|
||||||
|
|
||||||
//dummy edges control
|
|
||||||
for (int f=0;f<3;f++)
|
|
||||||
{
|
|
||||||
int f_test=Tetra::FofV((*en),f);
|
|
||||||
if ((*ti)->IsBorderF(f_test))
|
|
||||||
{
|
|
||||||
//control all the 3 edges
|
|
||||||
Face f_test0=Face((*ti)->V(Tetra::VofF(f_test,0)),(*ti)->V(Tetra::VofF(f_test,1)),&_DummyV());
|
|
||||||
Face f_test1=Face((*ti)->V(Tetra::VofF(f_test,1)),(*ti)->V(Tetra::VofF(f_test,2)),&_DummyV());
|
|
||||||
Face f_test2=Face((*ti)->V(Tetra::VofF(f_test,2)),(*ti)->V(Tetra::VofF(f_test,0)),&_DummyV());
|
|
||||||
if (((isMarkedF(f_test0,LINK_V0))&&(!isMarkedF(f_test0,LINK_EE)))||
|
|
||||||
((isMarkedF(f_test1,LINK_V0))&&(!isMarkedF(f_test1,LINK_EE)))||
|
|
||||||
((isMarkedF(f_test2,LINK_V0))&&(!isMarkedF(f_test2,LINK_EE))))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ti++;
|
|
||||||
en++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///verify the link conditions on edges
|
|
||||||
static bool _LinkConditionsE(PosType pos)
|
|
||||||
{
|
|
||||||
const int LINK_V0 = 0x00000001;
|
|
||||||
const int LINK_EE = 0x00000002;
|
|
||||||
|
|
||||||
_FaceMark().clear();
|
|
||||||
|
|
||||||
// Mark edges of ve0
|
|
||||||
vector< TetraType *>::iterator ti=_Sets().v0.begin();
|
|
||||||
vector< char >::iterator en=_Sets().indexv0.begin();
|
|
||||||
while (ti!=_Sets().v0.end())
|
|
||||||
{
|
|
||||||
//put dummy edge
|
|
||||||
for (int f=0;f<3;f++)
|
|
||||||
{
|
|
||||||
int f_test=Tetra::FofV((*en),f);
|
|
||||||
if ((*ti)->IsBorderF(f_test))
|
|
||||||
{
|
|
||||||
orMarkE(Edge((*ti)->V(Tetra::VofF(f_test,0)),&_DummyV()),LINK_V0);
|
|
||||||
orMarkE(Edge((*ti)->V(Tetra::VofF(f_test,1)),&_DummyV()),LINK_V0);
|
|
||||||
orMarkE(Edge((*ti)->V(Tetra::VofF(f_test,2)),&_DummyV()),LINK_V0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ti++;
|
|
||||||
en++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ti=_Sets().E.begin();
|
|
||||||
en=_Sets().indexE.begin();
|
|
||||||
//mark them as intersection
|
|
||||||
while (ti!=_Sets().E.end())
|
|
||||||
{
|
|
||||||
//faces on the edge
|
|
||||||
int f0=Tetra::FofE((*en),0);
|
|
||||||
int f1=Tetra::FofE((*en),1);
|
|
||||||
|
|
||||||
if ((*ti)->IsBorderF(f0))
|
|
||||||
{
|
|
||||||
orMarkE(Edge((*ti)->V(Tetra::VofF(f0,0)),&_DummyV()),LINK_EE);
|
|
||||||
orMarkE(Edge((*ti)->V(Tetra::VofF(f0,1)),&_DummyV()),LINK_EE);
|
|
||||||
orMarkE(Edge((*ti)->V(Tetra::VofF(f0,2)),&_DummyV()),LINK_EE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*ti)->IsBorderF(f1))
|
|
||||||
{
|
|
||||||
orMarkE(Edge((*ti)->V(Tetra::VofF(f1,0)),&_DummyV()),LINK_EE);
|
|
||||||
orMarkE(Edge((*ti)->V(Tetra::VofF(f1,1)),&_DummyV()),LINK_EE);
|
|
||||||
orMarkE(Edge((*ti)->V(Tetra::VofF(f1,2)),&_DummyV()),LINK_EE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ti++;
|
|
||||||
en++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//and at the end I verify if the intersection is equal to the star of the edge
|
|
||||||
ti=_Sets().v1.begin();
|
|
||||||
en=_Sets().indexv1.begin();
|
|
||||||
while (ti!=_Sets().v1.end())
|
|
||||||
{
|
|
||||||
|
|
||||||
//dummy edges control
|
|
||||||
for (int f=0;f<3;f++)
|
|
||||||
{
|
|
||||||
int f_test=Tetra::FofV((*en),f);
|
|
||||||
if ((*ti)->IsBorderF(f_test))
|
|
||||||
{
|
|
||||||
//control all the 3 edges
|
|
||||||
Edge e_test0=Edge((*ti)->V(Tetra::VofF(f_test,0)),&_DummyV());
|
|
||||||
Edge e_test1=Edge((*ti)->V(Tetra::VofF(f_test,1)),&_DummyV());
|
|
||||||
Edge e_test2=Edge((*ti)->V(Tetra::VofF(f_test,2)),&_DummyV());
|
|
||||||
if (((isMarkedE(e_test0,LINK_V0))&&(!isMarkedE(e_test0,LINK_EE)))||
|
|
||||||
((isMarkedE(e_test1,LINK_V0))&&(!isMarkedE(e_test1,LINK_EE)))||
|
|
||||||
((isMarkedE(e_test2,LINK_V0))&&(!isMarkedE(e_test2,LINK_EE))))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ti++;
|
|
||||||
en++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///verify the link conditions on vertices
|
|
||||||
static bool _LinkConditionsV()
|
|
||||||
{
|
|
||||||
const int LINK_V0 = VertexType::NewUserBit();
|
|
||||||
const int LINK_V1 = VertexType::NewUserBit();
|
|
||||||
const int LINK_EE = VertexType::NewUserBit();
|
|
||||||
|
|
||||||
const int NOT_LINKED = ~(LINK_V0 | LINK_V1 | LINK_EE);
|
|
||||||
_DummyV().Flags() &= NOT_LINKED;
|
|
||||||
|
|
||||||
VertexType *vt0;
|
|
||||||
VertexType *vt1;
|
|
||||||
VertexType *vt2;
|
|
||||||
VertexType *vt3;
|
|
||||||
|
|
||||||
|
|
||||||
vector< TetraType *>::iterator ti=_Sets().v0_U_v1.begin();
|
|
||||||
|
|
||||||
//reset all link flags
|
|
||||||
while (ti!=_Sets().v0_U_v1.end())
|
|
||||||
{
|
|
||||||
for(int i=0;i<4;i++)
|
|
||||||
(*ti)->V(i)->Flags() &= NOT_LINKED;
|
|
||||||
ti++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//also in the ones that appartain to the edge
|
|
||||||
vector< char >::iterator en;
|
|
||||||
ti=_Sets().E.begin();
|
|
||||||
en=_Sets().indexE.begin();
|
|
||||||
//reset all link flags for intersection and in the same
|
|
||||||
//time mark them as intersection
|
|
||||||
while (ti!=_Sets().E.end())
|
|
||||||
{
|
|
||||||
for(int i=0;i<4;i++)
|
|
||||||
{
|
|
||||||
(*ti)->V(i)->Flags() &= NOT_LINKED;
|
|
||||||
(*ti)->V(i)->Flags() |= LINK_EE;
|
|
||||||
}
|
|
||||||
|
|
||||||
//dummy vertex
|
|
||||||
|
|
||||||
//faces on the edge
|
|
||||||
int f0=Tetra::FofE((*en),0);
|
|
||||||
int f1=Tetra::FofE((*en),1);
|
|
||||||
|
|
||||||
if (((*ti)->IsBorderF(f0))||((*ti)->IsBorderF(f1)))
|
|
||||||
_DummyV().Flags() |= LINK_EE;
|
|
||||||
|
|
||||||
ti++;
|
|
||||||
en++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Mark vertices of ve0
|
|
||||||
ti=_Sets().v0.begin();
|
|
||||||
en=_Sets().indexv0.begin();
|
|
||||||
|
|
||||||
while (ti!=_Sets().v0.end())
|
|
||||||
{
|
|
||||||
for(int i=0;i<4;i++)
|
|
||||||
(*ti)->V(i)->Flags() |= LINK_V0;
|
|
||||||
|
|
||||||
//dummy faces on the vertex
|
|
||||||
int f0=Tetra::FofV((*en),0);
|
|
||||||
int f1=Tetra::FofV((*en),1);
|
|
||||||
int f2=Tetra::FofV((*en),2);
|
|
||||||
|
|
||||||
if (((*ti)->IsBorderF(f0))||((*ti)->IsBorderF(f1))||((*ti)->IsBorderF(f2)))
|
|
||||||
_DummyV().Flags() |= LINK_V0;
|
|
||||||
|
|
||||||
ti++;
|
|
||||||
en++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//and at the end I verify if the intersection is equal to the star of the edge
|
|
||||||
bool correct=true;
|
|
||||||
ti=_Sets().v1.begin();
|
|
||||||
en=_Sets().indexv1.begin();
|
|
||||||
|
|
||||||
while (ti!=_Sets().v1.end())
|
|
||||||
{
|
|
||||||
vt0=(*ti)->V(0);
|
|
||||||
vt1=(*ti)->V(1);
|
|
||||||
vt2=(*ti)->V(2);
|
|
||||||
vt3=(*ti)->V(3);
|
|
||||||
|
|
||||||
if ((vt0->Flags()& LINK_V0)&&(!(vt0->Flags()& LINK_EE)))
|
|
||||||
correct=false;
|
|
||||||
else
|
|
||||||
if ((vt1->Flags()& LINK_V0)&&(!(vt1->Flags()& LINK_EE)))
|
|
||||||
correct=false;
|
|
||||||
else
|
|
||||||
if ((vt2->Flags()& LINK_V0)&&(!(vt2->Flags()& LINK_EE)))
|
|
||||||
correct=false;
|
|
||||||
else
|
|
||||||
if ((vt3->Flags()& LINK_V0)&&(!(vt3->Flags()& LINK_EE)))
|
|
||||||
correct=false;
|
|
||||||
|
|
||||||
//dummy vertex control
|
|
||||||
int f0=Tetra::FofV((*en),0);
|
|
||||||
int f1=Tetra::FofV((*en),1);
|
|
||||||
int f2=Tetra::FofV((*en),2);
|
|
||||||
|
|
||||||
if (((*ti)->IsBorderF(f0))||((*ti)->IsBorderF(f1))||((*ti)->IsBorderF(f2)))
|
|
||||||
if ((_DummyV().Flags()& LINK_V0)&&(!(_DummyV().Flags()& LINK_EE)))
|
|
||||||
correct=false;
|
|
||||||
|
|
||||||
if (!correct)
|
|
||||||
{
|
|
||||||
VertexType::DeleteUserBit(LINK_EE);
|
|
||||||
VertexType::DeleteUserBit(LINK_V1);
|
|
||||||
VertexType::DeleteUserBit(LINK_V0);
|
|
||||||
return (false);
|
|
||||||
}
|
|
||||||
en++;
|
|
||||||
ti++;
|
|
||||||
}
|
|
||||||
VertexType::DeleteUserBit(LINK_EE);
|
|
||||||
VertexType::DeleteUserBit(LINK_V1);
|
|
||||||
VertexType::DeleteUserBit(LINK_V0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///verify the flip condition
|
|
||||||
static bool _FlipCondition(PosType pos,CoordType NewP)
|
|
||||||
{
|
|
||||||
int edge=pos.E();
|
|
||||||
VertexType *ve0=pos.T()->V(Tetra::VofE(edge,0));
|
|
||||||
VertexType *ve1=pos.T()->V(Tetra::VofE(edge,1));
|
|
||||||
CoordType oldpos0;
|
|
||||||
CoordType oldpos1;
|
|
||||||
//CoordType newpos=((ve0->P()*alfa)+(ve1->P()*(1.f-alfa)));
|
|
||||||
|
|
||||||
vector< TetraType *>::iterator ti=_Sets().no_E.begin();
|
|
||||||
|
|
||||||
//verification
|
|
||||||
oldpos0 = ve0->P();
|
|
||||||
oldpos1 = ve1->P();
|
|
||||||
|
|
||||||
//assegning new position
|
|
||||||
ve0->P() =NewP;
|
|
||||||
ve1->P() =NewP;
|
|
||||||
|
|
||||||
while (ti!=_Sets().no_E.end())
|
|
||||||
{
|
|
||||||
assert(!(*ti)->IsD());
|
|
||||||
assert((((*ti)->V(0)==ve0)||((*ti)->V(1)==ve0)||((*ti)->V(2)==ve0)||((*ti)->V(3)==ve0))^
|
|
||||||
(((*ti)->V(0)==ve1)||((*ti)->V(1)==ve1)||((*ti)->V(2)==ve1)||((*ti)->V(3)==ve1)));
|
|
||||||
|
|
||||||
/* Tetra3<ScalarType> T=Tetra3<ScalarType>();
|
|
||||||
T.P0(0)=(*ti)->V(0)->cP();
|
|
||||||
T.P1(0)=(*ti)->V(1)->cP();
|
|
||||||
T.P2(0)=(*ti)->V(2)->cP();
|
|
||||||
T.P3(0)=(*ti)->V(3)->cP();*/
|
|
||||||
//flip comes if volume is less or equal to zero
|
|
||||||
ScalarType tv = vcg::ComputeVolume(**ti);
|
|
||||||
if (vcg::ComputeVolume<TetraType>(**ti)<=0)
|
|
||||||
{
|
|
||||||
ve0->P()=oldpos0;
|
|
||||||
ve1->P()=oldpos1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ti++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//reset initial value
|
|
||||||
ve0->P()=oldpos0;
|
|
||||||
ve1->P()=oldpos1;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///update the normal of the modified tetrahedrons ond the normal of the vertex that remain after collapse
|
|
||||||
static void _InitTetrahedronValues(VertexType* v)
|
|
||||||
{
|
|
||||||
|
|
||||||
VTIterator<TetraType> VTi=VTIterator<TetraType>(v->VTb(),v->VTi());
|
|
||||||
while (!VTi.End())
|
|
||||||
{
|
|
||||||
if (TetraType::HasTetraQuality())
|
|
||||||
{
|
|
||||||
VTi.Vt()->ComputeAspectRatio();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TetraType::HasTetraNormal())
|
|
||||||
{
|
|
||||||
VTi.Vt()->ComputeNormal();
|
|
||||||
}
|
|
||||||
|
|
||||||
VTi++;
|
|
||||||
}
|
|
||||||
|
|
||||||
VTi.Vt()=v->VTb();
|
|
||||||
VTi.Vi()=v->VTi();
|
|
||||||
while (!VTi.End())
|
|
||||||
{
|
|
||||||
for (int i=0;i<4;i++)
|
|
||||||
{
|
|
||||||
if (VTi.Vt()->V(i)->IsB())
|
|
||||||
{
|
|
||||||
if (VertexType::HasNormal)
|
|
||||||
UpdateNormals::PerVertex(VTi.Vt()->V(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
++VTi;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
|
|
||||||
///Return the aspect Ratio media of the tetrahedrons
|
|
||||||
///that share the adge to collapse
|
|
||||||
static ScalarType AspectRatioCollapsed(PosType p)
|
|
||||||
{
|
|
||||||
PosL pos=PosL(p.T(),p.F(),p.E(),p.V());
|
|
||||||
pos.Reset();
|
|
||||||
int num=0;
|
|
||||||
ScalarType ratio_media=0.f;
|
|
||||||
while(!pos.end())
|
|
||||||
{
|
|
||||||
ratio_media+=pos.T()->AspectRatio();
|
|
||||||
pos.NextT();
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
ratio_media=ratio_media/num;
|
|
||||||
return (ratio_media);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///check the topologycal preserving conditions for the collapse indicated by pos
|
|
||||||
static bool CheckPreconditions(PosType pos,CoordType NewP)
|
|
||||||
{
|
|
||||||
VertexType *v0=pos.T()->V(Tetra::VofE(pos.E(),0));
|
|
||||||
VertexType *v1=pos.T()->V(Tetra::VofE(pos.E(),1));
|
|
||||||
//if the two vertices are of border and the edge is not a border edge
|
|
||||||
//we can do it.
|
|
||||||
bool border0=v0->IsB();
|
|
||||||
bool border1=v1->IsB();
|
|
||||||
bool bordere=Topology::IsExternEdge(pos.T(),pos.E());
|
|
||||||
|
|
||||||
//first case vertex external and edge internal
|
|
||||||
if ((border0 && border1)&&(!bordere))
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
//if both vertex are internal so is enougth to verify flip conditions
|
|
||||||
if ((!border0) && (!border1))
|
|
||||||
return (_FlipCondition(pos,NewP));
|
|
||||||
else
|
|
||||||
//if the edge is internal is enougth to verify link condition on vertex
|
|
||||||
if (!bordere)
|
|
||||||
return((_FlipCondition(pos,NewP))&&(_LinkConditionsV()));
|
|
||||||
else
|
|
||||||
//at the end if trh edge is on the border we must verify also with the complete test
|
|
||||||
return ((_FlipCondition(pos,NewP))&&(_LinkConditionsV())&&(_LinkConditionsE(pos))&&(_LinkConditionsF(pos)));
|
|
||||||
//return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
///return the sum of volumes of the union of stars on vertices (the original volume of tetrahedrons)
|
|
||||||
static ScalarType VolumeOriginal()
|
|
||||||
{
|
|
||||||
vector< TetraType *>::iterator ti=_Sets().v0_U_v1.begin();
|
|
||||||
ScalarType vol=0;
|
|
||||||
while (ti!=_Sets().v0_U_v1.end())
|
|
||||||
{
|
|
||||||
vol+=(*ti)->Volume();
|
|
||||||
ti++;
|
|
||||||
}
|
|
||||||
return vol;
|
|
||||||
}
|
|
||||||
|
|
||||||
///Calculate the volume on the vertex resulting after collapse...
|
|
||||||
static ScalarType VolumeSimulateCollapse(PosType Pos,CoordType newP)
|
|
||||||
{
|
|
||||||
VertexType *Vrem=(Pos.T()->V(Tetra::VofE(Pos.E(),0)));
|
|
||||||
VertexType *Vdel=(Pos.T()->V(Tetra::VofE(Pos.E(),1)));
|
|
||||||
|
|
||||||
if (Vrem!=Pos.T()->V(Pos.V()))
|
|
||||||
swap<VertexType*>(Vdel,Vrem);
|
|
||||||
|
|
||||||
ScalarType vol=0;
|
|
||||||
CoordType oldpos = Vrem->P();
|
|
||||||
|
|
||||||
//move vertex that remain in the new position
|
|
||||||
Vrem->P() = newP;
|
|
||||||
|
|
||||||
vector< TetraType *>::iterator ti=_Sets().no_E.begin();
|
|
||||||
|
|
||||||
while (ti!=_Sets().no_E.end())
|
|
||||||
{
|
|
||||||
/* Tetra3<ScalarType> T=Tetra3<ScalarType>();
|
|
||||||
T.P0(0)=(*ti)->V(0)->cP();
|
|
||||||
T.P1(0)=(*ti)->V(1)->cP();
|
|
||||||
T.P2(0)=(*ti)->V(2)->cP();
|
|
||||||
T.P3(0)=(*ti)->V(3)->cP();
|
|
||||||
|
|
||||||
vol+=T.ComputeVolume(); */
|
|
||||||
// vol+= vcg::ComputeVolume<TetraType>(*((Tetra3<ScalarType>*)&*ti));
|
|
||||||
|
|
||||||
vol+= vcg::ComputeVolume(**ti);
|
|
||||||
ti++;
|
|
||||||
}
|
|
||||||
Vrem->P()=oldpos;
|
|
||||||
return vol;
|
|
||||||
}
|
|
||||||
|
|
||||||
///finds sets used for all test in edge collapse
|
|
||||||
static void FindSets(vcg::tetra::Pos<TetraType> pos)
|
|
||||||
{
|
|
||||||
|
|
||||||
_Sets().clear();
|
|
||||||
int size=40;
|
|
||||||
_Sets().v0.reserve(size);
|
|
||||||
_Sets().indexv0.reserve(size);
|
|
||||||
_Sets().v1.reserve(size);
|
|
||||||
_Sets().indexv1.reserve(size);
|
|
||||||
_Sets().v0_U_v1.reserve(size*2);
|
|
||||||
_Sets().no_E.reserve(size*2);
|
|
||||||
_Sets().E.reserve(size);
|
|
||||||
_Sets().indexE.reserve(size);
|
|
||||||
|
|
||||||
int edge =pos.E();
|
|
||||||
|
|
||||||
VertexType *ve0=pos.T()->V(Tetra::VofE(edge,0));
|
|
||||||
VertexType *ve1=pos.T()->V(Tetra::VofE(edge,1));
|
|
||||||
|
|
||||||
// put all tetrahedrons in the first one vector and in the union
|
|
||||||
VTIterator<TetraType> vf0(ve0->VTb(),ve0->VTi());
|
|
||||||
while (!vf0.End())
|
|
||||||
{
|
|
||||||
//set of ve0
|
|
||||||
_Sets().v0.push_back(vf0.Vt());
|
|
||||||
_Sets().indexv0.push_back(vf0.Vi());
|
|
||||||
//set of union
|
|
||||||
_Sets().v0_U_v1.push_back(vf0.Vt());
|
|
||||||
//set of union minus intersection
|
|
||||||
if ((vf0.Vt()->V(0)!=ve1)&&(vf0.Vt()->V(1)!=ve1)&&(vf0.Vt()->V(2)!=ve1)&&(vf0.Vt()->V(3)!=ve1))
|
|
||||||
_Sets().no_E.push_back(vf0.Vt());
|
|
||||||
vf0++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//second vertex iteration
|
|
||||||
vf0.Vt()=ve1->VTb();
|
|
||||||
vf0.Vi()=ve1->VTi();
|
|
||||||
|
|
||||||
while (!vf0.End())
|
|
||||||
{
|
|
||||||
//set of ve1
|
|
||||||
_Sets().v1.push_back(vf0.Vt());
|
|
||||||
_Sets().indexv1.push_back(vf0.Vi());
|
|
||||||
//set of union
|
|
||||||
_Sets().v0_U_v1.push_back(vf0.Vt());
|
|
||||||
//set of union minus intersection
|
|
||||||
if ((vf0.Vt()->V(0)!=ve0)&&(vf0.Vt()->V(1)!=ve0)&&(vf0.Vt()->V(2)!=ve0)&&(vf0.Vt()->V(3)!=ve0))
|
|
||||||
_Sets().no_E.push_back(vf0.Vt());
|
|
||||||
vf0++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//erase duplicated tetrahedrons from the union set
|
|
||||||
sort(_Sets().v0_U_v1.begin(),_Sets().v0_U_v1.end());
|
|
||||||
unique(_Sets().v0_U_v1.begin(),_Sets().v0_U_v1.end());
|
|
||||||
|
|
||||||
//now compute the intersection
|
|
||||||
PosLType PL(pos.T(),pos.F(),pos.E(),pos.V());
|
|
||||||
|
|
||||||
//mark the vertex on the edge
|
|
||||||
while (!PL.LoopEnd())
|
|
||||||
{
|
|
||||||
_Sets().E.push_back(PL.T());
|
|
||||||
_Sets().indexE.push_back(PL.E());
|
|
||||||
PL.NextT();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
///do the collapse on the edge in postype p
|
|
||||||
static int DoCollapse(PosType p,CoordType newP)
|
|
||||||
{
|
|
||||||
VertexType *v=p.T()->V(p.V());
|
|
||||||
assert(p.T()->HasVTAdjacency());
|
|
||||||
int n_deleted = _Collapse(p,newP);
|
|
||||||
_InitTetrahedronValues(v);
|
|
||||||
return n_deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
}//end namespace
|
|
||||||
}//end namespace
|
|
||||||
#endif
|
|
|
@ -1,478 +0,0 @@
|
||||||
/****************************************************************************
|
|
||||||
* 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_EDGE_SPLIT
|
|
||||||
#define __VCG_TETRA_EDGE_SPLIT
|
|
||||||
|
|
||||||
#include <vcg/simplex/tetrahedron/pos.h>
|
|
||||||
#include <vcg/complex/tetramesh/allocate.h>
|
|
||||||
#include <vcg/complex/tetramesh/update/topology.h>
|
|
||||||
#include <vcg/space/tetra3.h>
|
|
||||||
namespace vcg{
|
|
||||||
namespace tetra{
|
|
||||||
|
|
||||||
/** \addtogroup tetramesh */
|
|
||||||
/*@{*/
|
|
||||||
/// This Class is used for split the edges
|
|
||||||
|
|
||||||
template <class TETRA_MESH_TYPE>
|
|
||||||
class EdgeSplit
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// The tetrahedral mesh type
|
|
||||||
typedef typename TETRA_MESH_TYPE TetraMeshType;
|
|
||||||
/// The tetrahedron type
|
|
||||||
typedef typename TetraMeshType::TetraType TetraType;
|
|
||||||
/// The vertex type
|
|
||||||
typedef typename TetraType::VertexType VertexType;
|
|
||||||
/// The vertex iterator type
|
|
||||||
typedef typename TetraMeshType::VertexIterator VertexIterator;
|
|
||||||
/// The tetra iterator type
|
|
||||||
typedef typename TetraMeshType::TetraIterator TetraIterator;
|
|
||||||
/// The coordinate type
|
|
||||||
typedef typename TetraType::VertexType::CoordType CoordType;
|
|
||||||
///the container of tetrahedron type
|
|
||||||
typedef typename TetraMeshType::TetraContainer TetraContainer;
|
|
||||||
///the container of vertex type
|
|
||||||
typedef typename TetraMeshType::VertexContainer VertexContainer;
|
|
||||||
/// The HEdgePos type
|
|
||||||
typedef PosLoop<TetraType> PosType;
|
|
||||||
/// The topology updater type
|
|
||||||
typedef vcg::tetra::UpdateTetraTopology<VertexContainer,TetraContainer> Topology;
|
|
||||||
/// The allocator type
|
|
||||||
typedef vcg::tetra::Allocator<TetraMeshType> TetraAllocator;
|
|
||||||
/// Default Constructor
|
|
||||||
EdgeSplit()
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
~EdgeSplit()
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
///the tetrahedron that must mark as Deleted after substitution
|
|
||||||
TetraType* _toDel[30];
|
|
||||||
///The number of tetrahedrons that are substituted
|
|
||||||
int _nT;
|
|
||||||
|
|
||||||
Topology _Topo;
|
|
||||||
|
|
||||||
///add a vertex into the edge at distance alfa ( 0<alfa<1) to the first vertex of the edge
|
|
||||||
|
|
||||||
VertexType* _AddVertexEdge(TetraMeshType &tm,const TetraType &t,const int &edge,const double &alfa)
|
|
||||||
{
|
|
||||||
VertexType *v0=(VertexType*)t.V(Tetra::VofE(edge,0));
|
|
||||||
VertexType *v1=(VertexType*)t.V(Tetra::VofE(edge,1));
|
|
||||||
Allocator<TetraMeshType> All= Allocator<TetraMeshType>();
|
|
||||||
VertexIterator vn=All.AddVertices(tm,1);
|
|
||||||
vn->Flags()=0;
|
|
||||||
vn->VTb()=NULL;
|
|
||||||
vn->VTi()=-1;
|
|
||||||
vn->P()=(v0->P()*alfa)+(v1->P()*(1.0f-alfa));
|
|
||||||
return (&(*vn));
|
|
||||||
}
|
|
||||||
|
|
||||||
///set the default v-t topology
|
|
||||||
void _SetDefultVTTopology(TetraType *t)
|
|
||||||
{
|
|
||||||
unsigned int j;
|
|
||||||
for (j=0;j<4;j++)
|
|
||||||
{
|
|
||||||
t->TVp(j) = NULL;
|
|
||||||
t->TVi(j) = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transform the vertex index according to rotation of the tetraedron
|
|
||||||
/// that trasform it in the basic case
|
|
||||||
static int _GetMapVertEdgeRot(const int &indexE,const int &indexV)
|
|
||||||
{
|
|
||||||
static int mapvertedgerot[12][4]={
|
|
||||||
{0,3,1,2},
|
|
||||||
{0,1,2,3},
|
|
||||||
{0,2,3,1},
|
|
||||||
{1,3,2,0},
|
|
||||||
{1,0,3,2},
|
|
||||||
{2,1,3,0},
|
|
||||||
|
|
||||||
{1,2,0,3},
|
|
||||||
{2,3,0,1},
|
|
||||||
{3,1,0,2},
|
|
||||||
{2,0,1,3},
|
|
||||||
{3,2,1,0},
|
|
||||||
{3,0,2,1},
|
|
||||||
};
|
|
||||||
assert ((indexE<12)&&(indexV<4));
|
|
||||||
return mapvertedgerot[indexE][indexV];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transform the face index according to rotation of the tetraedron
|
|
||||||
/// that trasform it in the basic case
|
|
||||||
static int _GetMapFaceEdgeRot(const int &indexE,const int &indexF)
|
|
||||||
{
|
|
||||||
static int mapfaceedgerot[12][4]={
|
|
||||||
{1,2,0,3},
|
|
||||||
{0,1,2,3},
|
|
||||||
{2,0,1,3},
|
|
||||||
{3,1,0,2},
|
|
||||||
{1,0,3,2},
|
|
||||||
{3,0,2,1},
|
|
||||||
|
|
||||||
{0,3,1,2},
|
|
||||||
{2,3,0,1},
|
|
||||||
{1,3,2,0},
|
|
||||||
{0,2,3,1},
|
|
||||||
{3,2,1,0},
|
|
||||||
{2,1,3,0},
|
|
||||||
};
|
|
||||||
assert ((indexE<12)&&(indexF<4));
|
|
||||||
return mapfaceedgerot[indexE][indexF];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the rotation sense during the loop on the edge to divide
|
|
||||||
/// according to rotation of the tetraedron that trasform it in the basic case
|
|
||||||
static int _GetDirRot(int indexE,int indexF)
|
|
||||||
{
|
|
||||||
static int mapfaceedgerot[12][4]={
|
|
||||||
{2,0,-1,-1},
|
|
||||||
{0,-1,2,-1},
|
|
||||||
{-1,2,0,-1},
|
|
||||||
{2,-1,-1,0},
|
|
||||||
{-1,0,-1,2},
|
|
||||||
{-1,-1,2,0},
|
|
||||||
|
|
||||||
{0,2,-1,-1},
|
|
||||||
{2,-1,0,-1},
|
|
||||||
{-1,0,2,-1},
|
|
||||||
{0,-1,-1,2},
|
|
||||||
{-1,2,-1,0},
|
|
||||||
{-1,-1,0,2},
|
|
||||||
};
|
|
||||||
|
|
||||||
assert ((indexE<12)&&(indexF<4));
|
|
||||||
return mapfaceedgerot[indexE][indexF];
|
|
||||||
}
|
|
||||||
|
|
||||||
///Built an Half edge on tetrahedron t using edge edge
|
|
||||||
PosType _FindPos(TetraType *t,int edge)
|
|
||||||
{
|
|
||||||
int face0=Tetra::FofE(edge,0);
|
|
||||||
int ve0=Tetra::VofE(edge,0);
|
|
||||||
PosType pos(t,face0,edge,ve0);
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
///Assert the right order of vertex that compose the tetrahedron
|
|
||||||
void _AssertOrder(TetraType *t,VertexType *v0,VertexType *v1,VertexType *v2,VertexType *v3)
|
|
||||||
{
|
|
||||||
assert(t->V(0)==v0);
|
|
||||||
assert(t->V(1)==v1);
|
|
||||||
assert(t->V(2)==v2);
|
|
||||||
assert(t->V(3)==v3);
|
|
||||||
}
|
|
||||||
|
|
||||||
///Connect trought Tetrahedron-Tetrahedron Topology t0 and t1 with faces i0 and i1
|
|
||||||
void _ConnectTTTopology(TetraType *t0,int i0,TetraType *t1,int i1)
|
|
||||||
{
|
|
||||||
assert((i0>=0)&&(i0<4));
|
|
||||||
assert((i1>=0)&&(i1<4));
|
|
||||||
assert((!t0->IsD())&&(!t1->IsD()));
|
|
||||||
t0->TTp(i0)=t1;
|
|
||||||
t0->TTi(i0)=i1;
|
|
||||||
t1->TTp(i1)=t0;
|
|
||||||
t1->TTi(i1)=i0;
|
|
||||||
assert( (((t0->TTp(i0))->TTp(t0->TTi(i0)))==t0));
|
|
||||||
assert( (((t1->TTp(i1))->TTp(t1->TTi(i1)))==t1));
|
|
||||||
}
|
|
||||||
|
|
||||||
///Divide the tetrahadron in pos in two tetrahedrons using the new vertex vnew
|
|
||||||
void _Divide(PosType pos,VertexType *vnew,TetraType *newtp0,TetraType *newtp1,bool invert)
|
|
||||||
{
|
|
||||||
int curredge=pos.E();
|
|
||||||
|
|
||||||
//control if the edge vertices arein the right order for the table
|
|
||||||
if (invert)
|
|
||||||
curredge+=6;
|
|
||||||
|
|
||||||
//find the new position to vertex according
|
|
||||||
int ie0=_GetMapVertEdgeRot(curredge,0);
|
|
||||||
int ie1=_GetMapVertEdgeRot(curredge,2);
|
|
||||||
int in0=_GetMapVertEdgeRot(curredge,1);
|
|
||||||
int in1=_GetMapVertEdgeRot(curredge,3);
|
|
||||||
|
|
||||||
//as first the ones that appartain to the selected curredge
|
|
||||||
VertexType *ve0=pos.T()->V(ie0);
|
|
||||||
VertexType *ve1=pos.T()->V(ie1);
|
|
||||||
|
|
||||||
//and after the others that will be in the cutting plane
|
|
||||||
VertexType *vn0=pos.T()->V(in0);
|
|
||||||
VertexType *vn1=pos.T()->V(in1);
|
|
||||||
|
|
||||||
newtp0->V(0)=ve0;
|
|
||||||
newtp0->V(1)=vn0;
|
|
||||||
newtp0->V(2)=vnew;
|
|
||||||
newtp0->V(3)=vn1;
|
|
||||||
|
|
||||||
newtp1->V(0)=vnew;
|
|
||||||
newtp1->V(1)=vn0;
|
|
||||||
newtp1->V(2)=ve1;
|
|
||||||
newtp1->V(3)=vn1;
|
|
||||||
|
|
||||||
//right order of the vertices
|
|
||||||
#ifdef _DEBUG
|
|
||||||
_AssertOrder(newtp0,ve0,vn0,vnew,vn1);
|
|
||||||
_AssertOrder(newtp1,vnew,vn0,ve1,vn1);
|
|
||||||
//end asserts
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _InvertRotation(PosType pos)
|
|
||||||
{
|
|
||||||
return (pos.V()!=Tetra::VofE(pos.E(),0));
|
|
||||||
}
|
|
||||||
|
|
||||||
///substitute the told tetrahedon on VT topology with newtp0 and newtp1 as created
|
|
||||||
void _SubstituteVTTopology(TetraType *told,TetraType *newtp0,TetraType *newtp1)
|
|
||||||
{
|
|
||||||
_SetDefultVTTopology(newtp0);
|
|
||||||
_SetDefultVTTopology(newtp1);
|
|
||||||
|
|
||||||
//detach the old tetrahedron from VTtopology
|
|
||||||
_Topo.DetachVTTopology(told);
|
|
||||||
//tetrahedron 0
|
|
||||||
_Topo.InsertVTTopology(newtp0);
|
|
||||||
//tetrahedron 1
|
|
||||||
_Topo.InsertVTTopology(newtp1);
|
|
||||||
}
|
|
||||||
|
|
||||||
///control if the connections between tetrahedron created have the right shared vertices
|
|
||||||
void _ControlConnection(TetraType *oldtp0,TetraType *newtp0)
|
|
||||||
{
|
|
||||||
VertexType *v00=oldtp0->V(0);
|
|
||||||
VertexType *v01=oldtp0->V(1);
|
|
||||||
VertexType *v02=oldtp0->V(2);
|
|
||||||
VertexType *v03=oldtp0->V(3);
|
|
||||||
|
|
||||||
VertexType *v10=newtp0->V(0);
|
|
||||||
VertexType *v11=newtp0->V(1);
|
|
||||||
VertexType *v12=newtp0->V(2);
|
|
||||||
VertexType *v13=newtp0->V(3);
|
|
||||||
|
|
||||||
assert(((v00==v10)&&(v02==v12))||((v00==v12)&&(v02==v10)));
|
|
||||||
assert(((v01==v13)&&(v03!=v11))||((v01!=v13)&&(v03==v11)));
|
|
||||||
}
|
|
||||||
|
|
||||||
///set as extern the 4 faces of the tetrahedron
|
|
||||||
void _SetDefaultTTExtern(TetraType *t)
|
|
||||||
{
|
|
||||||
for (int y=0;y<4;y++)
|
|
||||||
{
|
|
||||||
t->TTp(y)=t;
|
|
||||||
t->TTi(y)=y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///substitute in Tetra Tetra Topology the tetrahedron old_t with new_t in according
|
|
||||||
///to face and edge
|
|
||||||
|
|
||||||
void _SubstituteTTTopology(TetraType *old_t,TetraType *new_t,int edgerot,int face)
|
|
||||||
{
|
|
||||||
int indexface=_GetMapFaceEdgeRot(edgerot,face);
|
|
||||||
|
|
||||||
if (old_t->IsBorderF(indexface))
|
|
||||||
{
|
|
||||||
new_t->TTp(face)=new_t;
|
|
||||||
new_t->TTi(face)=face;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TetraType *tetrad=old_t->TTp(indexface);
|
|
||||||
int fad=old_t->TTi(indexface);
|
|
||||||
_ConnectTTTopology(new_t,face,tetrad,fad);
|
|
||||||
assert (!tetrad->IsD());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// sobstitute the old tetrahedrons that share the edge in pos with new ones
|
|
||||||
/// that share the vertex vnew that divide the old edge
|
|
||||||
|
|
||||||
void _AddNewTetrahedrons(TetraMeshType &tm,PosType pos,VertexType *vnew)
|
|
||||||
{
|
|
||||||
|
|
||||||
TetraType *oldtp0=NULL;
|
|
||||||
TetraType *oldtp1=NULL;
|
|
||||||
|
|
||||||
TetraType *newtp0;
|
|
||||||
TetraType *newtp1;
|
|
||||||
|
|
||||||
TetraType *firsttp0=NULL;
|
|
||||||
TetraType *firsttp1=NULL;
|
|
||||||
|
|
||||||
|
|
||||||
int curredge;
|
|
||||||
int direction=-1;
|
|
||||||
bool invert=false;
|
|
||||||
|
|
||||||
TetraAllocator All=TetraAllocator();
|
|
||||||
pos.Reset();
|
|
||||||
_nT=0;
|
|
||||||
|
|
||||||
while (!pos.LoopEnd())
|
|
||||||
{
|
|
||||||
assert(!pos.T()->IsD());
|
|
||||||
|
|
||||||
invert=_InvertRotation(pos);
|
|
||||||
|
|
||||||
//CREATE THE NEW TETRAHEDRONS
|
|
||||||
|
|
||||||
//create the new ones putting the veritices in the right order
|
|
||||||
TetraIterator ti=All.AddTetra(tm,2);
|
|
||||||
newtp0 = &(*ti);
|
|
||||||
ti++;
|
|
||||||
newtp1 = &(*ti);
|
|
||||||
|
|
||||||
|
|
||||||
_Divide(pos,vnew,newtp0,newtp1,invert);
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
if ((oldtp0!=NULL)&&(!pos.Jump()))
|
|
||||||
_ControlConnection(oldtp0,newtp0);
|
|
||||||
if ((oldtp1!=NULL)&&(!pos.Jump()))
|
|
||||||
_ControlConnection(oldtp1,newtp1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// SUBSTITUTE NEW TETRAHEDRONS ON VT TOPOLOGY
|
|
||||||
if (tm.HasVTTopology())
|
|
||||||
_SubstituteVTTopology(pos.T(),newtp0,newtp1);
|
|
||||||
|
|
||||||
|
|
||||||
//THEN SET THE T-T TOPOLOGY
|
|
||||||
|
|
||||||
_SetDefaultTTExtern(newtp0);
|
|
||||||
_SetDefaultTTExtern(newtp1);
|
|
||||||
|
|
||||||
curredge=pos.E();
|
|
||||||
if (invert)
|
|
||||||
curredge+=6;
|
|
||||||
|
|
||||||
//face3
|
|
||||||
_SubstituteTTTopology(pos.T(),newtp1,curredge,3);
|
|
||||||
|
|
||||||
//face1
|
|
||||||
_SubstituteTTTopology(pos.T(),newtp0,curredge,1);
|
|
||||||
|
|
||||||
//now I set t-t topology between themselfes
|
|
||||||
|
|
||||||
_ConnectTTTopology(newtp0,3,newtp1,1);
|
|
||||||
|
|
||||||
if (pos.Jump())
|
|
||||||
{
|
|
||||||
vnew->SetB();
|
|
||||||
oldtp0=NULL;
|
|
||||||
oldtp1=NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
direction=_GetDirRot(curredge,pos.F());
|
|
||||||
assert(direction!=-1);
|
|
||||||
//control the direction of moving
|
|
||||||
if ((oldtp0!=NULL)&&(oldtp1!=NULL))
|
|
||||||
{
|
|
||||||
//direction=_GetDirRot(oldtp0,newtp0);
|
|
||||||
|
|
||||||
//find direction of moving
|
|
||||||
if (direction==0)
|
|
||||||
{
|
|
||||||
_ConnectTTTopology(oldtp0,0,newtp0,2);
|
|
||||||
_ConnectTTTopology(oldtp1,0,newtp1,2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (direction==2)
|
|
||||||
{
|
|
||||||
_ConnectTTTopology(oldtp0,2,newtp0,0);
|
|
||||||
_ConnectTTTopology(oldtp1,2,newtp1,0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//assign if it is the first one
|
|
||||||
if (firsttp0==NULL)
|
|
||||||
firsttp0=newtp0;
|
|
||||||
if (firsttp1==NULL)
|
|
||||||
firsttp1=newtp1;
|
|
||||||
|
|
||||||
oldtp0=newtp0;
|
|
||||||
oldtp1=newtp1;
|
|
||||||
|
|
||||||
_toDel[_nT]=pos.T();
|
|
||||||
_nT++;
|
|
||||||
pos.NextT();
|
|
||||||
}
|
|
||||||
|
|
||||||
//at the end I finish the connections
|
|
||||||
if (!(pos.Jump())&&(direction==0)&&(firsttp0!=NULL)&&(firsttp1!=NULL)&&(oldtp0!=NULL)&&(oldtp1!=NULL))
|
|
||||||
{
|
|
||||||
_ConnectTTTopology(oldtp0,0,firsttp0,2);
|
|
||||||
_ConnectTTTopology(oldtp1,0,firsttp1,2);
|
|
||||||
}
|
|
||||||
else if (!(pos.Jump())&&(direction==2)&&(firsttp0!=NULL)&&(firsttp1!=NULL)&&(oldtp0!=NULL)&&(oldtp1!=NULL))
|
|
||||||
{
|
|
||||||
_ConnectTTTopology(oldtp0,2,firsttp0,0);
|
|
||||||
_ConnectTTTopology(oldtp1,2,firsttp1,0);
|
|
||||||
}
|
|
||||||
else if (pos.Jump())
|
|
||||||
vnew->SetB();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
///Mark as deleted the tetrahedron that must be substituted
|
|
||||||
void _DeleteOldTetra()
|
|
||||||
{
|
|
||||||
for (int i=0;i<_nT;i++)
|
|
||||||
_toDel[i]->SetD();
|
|
||||||
}
|
|
||||||
|
|
||||||
//=========================================================================
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// Split the edge with local remeshing
|
|
||||||
/// Tetrahedron-Tetrahedron topology is required
|
|
||||||
VertexType* DoSplit(TetraMeshType &tm,TetraType *t,int edge,double alfa)
|
|
||||||
{
|
|
||||||
assert(!t->IsD());
|
|
||||||
assert(tm.HasTTTopology());
|
|
||||||
assert((alfa>0)&&(alfa<1));
|
|
||||||
assert((edge>=0)&&(edge<6));
|
|
||||||
VertexType *vnew=_AddVertexEdge(tm,*t,edge,alfa);
|
|
||||||
_AddNewTetrahedrons(tm,_FindPos(t,edge),vnew);
|
|
||||||
_DeleteOldTetra();
|
|
||||||
return(vnew);
|
|
||||||
}
|
|
||||||
|
|
||||||
};//end class
|
|
||||||
|
|
||||||
}//end namespace tetra
|
|
||||||
}//end namespace vcg
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue