[an error occurred while processing this directive] | [an error occurred while processing this directive] | [an error occurred while processing this directive] |
Home | Message board |
I wrote this C++ code to maintain the dynamic sets of tetrahedra in my programs.
Vertex object is rather straightforward:
class CVertex { public: double X,Y,Z; // add your own members... }; typedef CVertex *CVertexPtr;
Tetrahedron object is also simple:
class CTetrahedron { public: CVertex *V[4]; CPtr P[4]; // ... }; Each tetrahedron can be wieved from one of twelve viewpoints: enum Rotation { abcd,acdb,adbc,badc,bcad,bdca, cabd,cbda,cdab,dacb,dbac,dcba };Superposition, as well as other operations with rotations, is implemented using a lookup table: inline Rotation operator*(Rotation a,Rotation b){ return Mult[b][a];}
Tetrahedron pointer is the main object type that is used to control all operations on tetrahedra.
class CPtr { public: CTetrahedron *P; Rotation R; CPtr(CTetrahedron* p=0,Rotation r=abcd):P(p),R(r){} // ... };Tetrahedron pointer class implements the functions to access the vertices and adjacent tetrahedra, and a bunch of rotation functions: CPtr operator*(Rotation r){ return CPtr(P,R*r);} CPtr Abcd(){ return *this;} // just to have the complete set... CPtr Acdb(){ return *this*acdb;} CPtr Adbc(){ return *this*adbc;} CPtr Badc(){ return *this*badc;} CPtr Bcad(){ return *this*bcad;} CPtr Bdca(){ return *this*bdca;} CPtr Cabd(){ return *this*cabd;} CPtr Cbda(){ return *this*cbda;} CPtr Cdab(){ return *this*cdab;} CPtr Dacb(){ return *this*dacb;} CPtr Dbac(){ return *this*dbac;} CPtr Dcba(){ return *this*dcba;}Accessing vertices in the correct order is done via the lookup table: CVertexPtr& operator[](int n){ return P->V[Vert[R][n]];} | |
Tetrahedra abcd and acbe are adjacent to each other |
Accessing adjacent tetrahedra is a bit more tricky.
Imagine, we need to assign bace to be adjacent to bcad,
A special helper class Adjacent pointer is used to perform these on-the-fly substitutions: class CPtr { // ... // type conversion from adjacent pointer: CPtr(CAdjPtr&A):P(A.Ptr.P->P[NAdj[A.Ptr.R]].P),R(A.Ptr.P->P[NAdj[A.Ptr.R]].R*TAdj[A.Ptr.R]){} // ... CAdjPtr Adj(){ return CAdjPtr(*this);} // ... }; class CAdjPtr { public: CPtr &Ptr; CAdjPtr(CPtr&p):Ptr(p){} void operator=(CPtr&p){ Ptr.P->P[NAdj[Ptr.R]].P=p.P; Ptr.P->P[NAdj[Ptr.R]].R=p.R*RAdj[Ptr.R];} // ... CPtr Adj(){ return Ptr;} // adjacent to my adjacent is myself! // ... };
Note, that there are two tables used in both type convertion and assignment operator:
Each rotation can be in unique way represented as X*A, where
Finally, to make the adjacent pointer look and feel exactly like a normal tetrahedron pointer in the expressions like P.Cabd().Dbac().Adj().Bcad() ...we redefine all tetrahedron pointer functions for the adjacent pointer in the following way: CVertexPtr& operator[](int n){ return CPtr(*this)[n];} CPtr Abcd(){ return CPtr(*this).Abcd();} // etc... Download complete code: tetrahedron1.h. Compile-time rotations Consider the expression: p1 = p.Acdb().Badc().Bcad(); // equivalent to p1 = p;It will take 3 table lookups during the run-time to calculate the new pointer. Can we do better? - This will require a bunch of additional helper classes: class CabcdPtr; class CacdbPtr; class CadbcPtr; class CbadcPtr; class CbcadPtr; class CbdcaPtr; class CcabdPtr; class CcbdaPtr; class CcdabPtr; class CdacbPtr; class CdbacPtr; class CdcbaPtr;Each helper class has the reference to the original pointer, and the set of rotation functions that are just type conversions to other helpers: class CacdbPtr { public: // the only member: CPtr &Ptr; // constructor: CacdbPtr(CPtr&p):Ptr(p){} // rotations: CacdbPtr Abcd(){ return Ptr;} CadbcPtr Acdb(){ return Ptr;} CabcdPtr Adbc(){ return Ptr;} CcabdPtr Badc(){ return Ptr;} CcdabPtr Bcad(){ return Ptr;} CcbdaPtr Bdca(){ return Ptr;} CdacbPtr Cabd(){ return Ptr;} CdcbaPtr Cbda(){ return Ptr;} CdbacPtr Cdab(){ return Ptr;} CbadcPtr Dacb(){ return Ptr;} CbcadPtr Dbac(){ return Ptr;} CbdcaPtr Dcba(){ return Ptr;} // other CPtr functions: CAdjPtr Adj(){ return CPtr(*this).Adj();} CVertexPtr& operator[](int n){ return CPtr(*this)[n];} };
Original pointer class gets new constructor from each helper class,
CPtr(CacdbPtr&A):P(A.Ptr.P),R(A.Ptr.R*acdb){} CacdbPtr Acdb(){ return *this;} // instead of CPtr Acdb(); The compiler will substitute the the expression discussed above by the series of inline functions: CacdbPtr CPtr::Acdb(); CcabdPtr CacdbPtr::Badc(); CabcdPtr CcabdPtr::Bcad(); CPtr::CPtr(CabcdPtr);thus, doing all rotations in compile time. Download complete code: tetrahedron2.h. |