diff --git a/vcg/complex/tetramesh/edge_collapse.h b/vcg/complex/tetramesh/edge_collapse.h new file mode 100644 index 00000000..9ee93032 --- /dev/null +++ b/vcg/complex/tetramesh/edge_collapse.h @@ -0,0 +1,913 @@ +/**************************************************************************** +* 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 +#include +#include + + + +namespace vcg{ +namespace tetra{ + +/** \addtogroup tetramesh */ +/*@{*/ +/// This Class is used for the edge collapse +template +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 PosType; + /// The HEdgePos Loop type + typedef PosLoop PosLType; + /// The topology updater type + typedef vcg::tetra::UpdateTetraTopology Topology; + ///the normal updater type + typedef vcg::tetra::UpdateNormals UpdateNormals; + + + /// Default Constructor + EdgeCollapse() + { + }; + + ~EdgeCollapse() + { + }; + + private: + typedef pair 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] v0; + std::vector v1; + std::vector v0_U_v1; + std::vector no_E; + std::vector E; + std::vector indexE; + std::vector indexv0; + std::vector indexv1; + + void clear() + { + v0.clear(); + v1.clear(); + v0_U_v1.clear(); + no_E.clear(); + E.clear(); + } +}; + + + + + +static map & _EdgeMark(){ + static map em; + return em; +}; + +static map & _FaceMark(){ + static map 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 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::iterator ti; + for (ti=To_Del.begin();tiSetD(); + + //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(); + return n_deleted; +} + + +static void orMarkE(Edge E,char M) +{ + map::iterator EI; + EI=_EdgeMark().find(E); + if (EI==_EdgeMark().end()) + _EdgeMark().insert (pair(E,M)); + else + (*EI).second|=M; +} + +static bool isMarkedE(Edge E,char M) +{ + map::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::iterator FI; + FI=_FaceMark().find(F); + if (FI==_FaceMark().end()) + _FaceMark().insert (pair(F,M)); + else + (*FI).second|=M; +} + +static bool isMarkedF(Face F,char M) +{ + map::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)))) + { + FAIL::LKF(); + 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)))) + { + FAIL::LKE(); + 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); + FAIL::LKV(); + 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))); + + if (vcg::ComputeVolume(**ti)<=0) + { + FAIL::VOL(); + 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 VTi=VTIterator(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: + +/// clean everything +static void Reset(){ + _EdgeMark().clear(); + _FaceMark().clear(); + _Sets().clear(); + _DummyV().ClearFlags(); +} +///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)) + { + FAIL::BOR(); + 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(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 T=Tetra3(); + 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(*((Tetra3*)&*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 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 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 \ No newline at end of file diff --git a/vcg/complex/tetramesh/edge_split.h b/vcg/complex/tetramesh/edge_split.h new file mode 100644 index 00000000..d4e6c16d --- /dev/null +++ b/vcg/complex/tetramesh/edge_split.h @@ -0,0 +1,478 @@ +/**************************************************************************** +* 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 +#include +#include +#include +namespace vcg{ +namespace tetra{ + +/** \addtogroup tetramesh */ +/*@{*/ +/// This Class is used for split the edges + +template +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 PosType; + /// The topology updater type + typedef vcg::tetra::UpdateTetraTopology Topology; + /// The allocator type + typedef vcg::tetra::Allocator 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 All= Allocator(); + 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 \ No newline at end of file diff --git a/vcg/complex/tetramesh/update/topology.h b/vcg/complex/tetramesh/update/topology.h index aacd8eec..eb73cd05 100644 --- a/vcg/complex/tetramesh/update/topology.h +++ b/vcg/complex/tetramesh/update/topology.h @@ -223,6 +223,7 @@ static void ClearVTTopology(VertexContainer &vert,TetraContainer &tetra) TetraIterator t; for(t=tetra.begin();t!=tetra.end();++t) + if( ! (*t).IsD()) for(int j=0;j<4;++j) { (*t).TVp(j) = 0; @@ -235,6 +236,7 @@ static void ClearVTTopology(VertexContainer &vert,TetraContainer &tetra) static void DetachVTTopology(TetraType *t) { int i; + if( ! (*t).IsD()) for(i=0;i<4;i++) DetachVTTopology(t->V(i),t); } @@ -297,8 +299,6 @@ static void TestVTTopology(VertexContainer &vert,TetraContainer &tetra) { int i; for (VertexIterator vi=vert.begin();vi!=vert.end();vi++) - { - if (!(*vi).IsD()) { TetraType *nextT=vi->VTb(); @@ -311,7 +311,6 @@ static void TestVTTopology(VertexContainer &vert,TetraContainer &tetra) nextI=nextT->TVi(nextI); nextT=nextT->TVp(oldI); } - } } } @@ -329,8 +328,7 @@ static void TTTopology(VertexContainer &vert,TetraContainer &tetra) VertexType* v2; for (TetraIterator ti=tetra.begin();ti!=tetra.end();ti++) - { - if (!(*ti).IsD()) + if (!(*ti).IsD()) { (*ti).TTi(0)=0; (*ti).TTi(1)=1; @@ -364,8 +362,7 @@ static void TTTopology(VertexContainer &vert,TetraContainer &tetra) v2=(*ti).V(Tetra3::VofF(3,2)); VF.push_back(Facet(v0,v1,v2,&(*ti),3)); - } - } + } sort(VF.begin(),VF.end()); TetraType *t0; @@ -412,10 +409,9 @@ static void TestTTTopology(VertexContainer &vert,TetraContainer &tetra) { int i; for (TetraIterator ti=tetra.begin();ti!=tetra.end();ti++) - { + if ((!(*ti).IsD())) for (i=0;i<4;i++) { - if ((!(*ti).IsD())) { assert( ((((*ti).TTp(i))->TTp((*ti).TTi(i)))==&(*ti))); @@ -439,8 +435,6 @@ static void TestTTTopology(VertexContainer &vert,TetraContainer &tetra) assert ((v2==vo0)||(v2==vo1)||(v2==vo2)); } } - } - } ///test if all and only the exernal vertex are set of border @@ -507,6 +501,7 @@ static void setExternalVertices(VertexContainer &vert,TetraContainer &tetra) for (vi=vert.begin();viClearB(); for (tt=tetra.begin();tt