//! file="amma/Surf3d/VTRing/VTRing.hh" //! lib=VTRing //! userlevel=Default //! author="Andrew Stoddart" //! rcsid="$Id: VTRing.hh,v 1.39 1999/03/29 11:17:22 ees1cg Exp $" //! date="07/11/97" //! docentry="default.Andrew Stoddart" // ------------------------------------------------------------------------- // ********** VTRingC **************************************************** // ------------------------------------------------------------------------- #ifndef VTRing_HH #define VTRing_HH #include #include #include "amma/KwList.hh" #include "amma/Vector3d.hh" #include "amma/Polops.hh" // this can be removed if PoltoVTRing is taken out // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- /* Future Work - implement a local remove odddballs to speed up the decimation decimation will handle long thin strips badly */ // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- #define VTR_PI 3.1415926535897932 const int MAXV=4; enum EdgeCollapseT { HOPPEPASS, // 0= HOPPEFAIL2, // 1=fail on condition 2 of Hoppe HOPPEFAILFACE, // 2=Hoppe condition 1; extra shared verts HOPPEWHAT // 3=this should never happen! }; // HOPPE 2 is implemented in an over restrictive way. // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- typedef KIterC ItVertC; typedef KIterC ItItVertC; typedef KIterC ItTriC; typedef KIterC ItItTriC; typedef KIterC ItEdgeC ; typedef KIterC ItTEdgeC ; // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- // A useful representation of an edge struct TEdgeC { ItTriC it; int e; }; inline int operator==(TEdgeC &te1, TEdgeC &te2) {return te1.it==te2.it && te1.e==te2.e;} inline int operator!=(TEdgeC &te1, TEdgeC &te2) {return te1.it!=te2.it || te1.e!=te2.e;} // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- // // Remember that KList is a BIG object when using copy cons & = on VTVertexC // // ------------------------------------------------------------------------- // Markers // ------- // // A vertex, an edge and a face each have an integer id that can be used // by the user. A face also has a byte called used. // // VTRingC: "VTFaceC.used" is never used. // All 3 id's are used only by Print(), various Renumber*() and // for debug printouts // "VTVertexC.id" is used by // RenumberVerts() // SaveTri(), VTRingToPol // // // VTBoundC: "VTVertexC.id" is used by SaveTri() // //"VTEdgeC.id" is used by Print() // "VTFaceC.id" must be set to 0..ntfaces-1 // // VTBackTrackC: as for VTBoundC // "VTFaceC.id" is set to 0..ntfaces-1 // // // ------------------------------------------------------------------------- class VTVertexC { public: int id; Vector3dC vector; KListC ptris; // list of triangles using this vertex void * ptr; VTVertexC(); VTVertexC(Vector3dC v); VTVertexC(const VTVertexC & vert); VTVertexC & operator=(const VTVertexC & vert); ~VTVertexC(); void WriteVector(ofstream & of); // It is desirable to use slightly higher accuracy to output vectors // we use 8 decimal places rather than the 6 of Vector3dC }; // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- // The ptri[0] goes vert0->1 // The ptri[1] goes vert0<-1 // if valence == 1 then ptri[1] is null! class VTEdgeC { public: int valence; // number of triangles using this vertex int id; ItTriC ptris[2]; // list of triangles using this vertex ItVertC verts[2]; // list of vertices VTEdgeC(); VTEdgeC(const VTEdgeC & vert); VTEdgeC & operator=(const VTEdgeC & vert); ~VTEdgeC(); }; // ------------------------------------------------------------------------- // ------------------------------------------------------------------------- // NB: Edge i the the edge that joins vertex i to (i+1)%3 // class VTFaceC { public: int id; char used; ItVertC verts[MAXV]; // pointers to vertices forming triangle ItEdgeC edges[MAXV]; void * ptr; VTFaceC(); VTFaceC(ItVertC i, ItVertC j, ItVertC k); VTFaceC(ItVertC i, ItVertC j, ItVertC k, ItVertC l); VTFaceC(const VTFaceC & tri); VTFaceC & operator=(const VTFaceC & tri); ~VTFaceC(); }; // ------------------------------------------------------------------------- // ********** VTRingC **************************************************** // ------------------------------------------------------------------------- // .LP // This structure is intended to cope with CLOSED and OPEN surfaces // CLOSED - no boundary; OPEN with boundary // // CLOSED surfaces are easier and everything works for closed surfaces // The following dont work or havent been tested on OPEN surfaces // *AroundEdge - probably never needed // Edge Collapse // Face Collapse // // .LP // Each face has an inside and an outside. These are rendered differently. // The ordering of the vertices around an outward pointing normal // should be anti-clockwise. It cannot be guaranteed that an // imported input file satisfies this. // .LP // // This is a tricky data structure. It is recommended that only a small set // of editing operations are used. // // InsertVertex(Vector3dC v); // Insert3Face(ItVertC iv0, ItVertC iv1, ItVertC iv2); // DeleteVertex(ItVertC iv); // DeleteTriangle(ItTriC); // // The edge data structure may be deficient for boundary edges?? 0/1 // The data structure is not tested for open meshes. // // Collapse Edge lacks some important checks as described by Hoppe 93 page 23 // const int SORT_INTERVAL=20; // SHOULD BE REMOVED !!!!!!!! // ------------------------------------------------------------------------- class VTRingC { public: int nv; // 3 or 4 vertices per face KListC vlist; // list of vertices KListC elist; // list of edges KListC flist; // list of triangles public: // Constructors, destructor, assignment // ------------------------------------- VTRingC(int nverts=3); // Null Constructor VTRingC(char *fname, int nverts=3); // Constructor VTRingC(const VTRingC & vt); // Copy Constructor VTRingC & operator=(const VTRingC & vt); // Assignment ~VTRingC(); // Destructor VTRingC Copy(); // Deep Copy // Global Ops // ---------- void PrintPointers(); // Print out the list of vertices void Print(); // Print out the list of vertices void Renumber(int preserve_special=0); void RenumberVerts(); void RenumberEdges(); void RenumberFaces(int preserve_special=0); // Set handy_no to the ordinal number in list, 0..n-1 scheme void SaveTri(char * name); // write the data lists to a file void SaveMarkedFacesAsTri(char * fname); // saves all faces marked with 1 into file // the id for vertex is also used int LoadTri(char * name, int nverts); // reads the data list from a file, if error then return 0 else 1 void SaveBoundaryPoints(char * name = "bound.vec"); // save a list of all points on a boundary, .vec format // Topology Stuff // -------------- BooleanT Checks(BooleanT fixup, BooleanT trace=TRUE); // look at mesh and perform some checks; only works for 3 sided // uses renumber every thing int CountBoundaries(BooleanT trace=TRUE, int fill=0); // count the number of distinct boundaries // fill all holes with less than fill edges - no check for hole vs outer boundary! // uses RenumberEdges, now tested and working // BooleanT IsClosed(void); // returns TRUE if the surface is closed - a closed surface has all edges valence 2 void SplitSaveAll(); // splits into connected components and saves each in a separate file called split000-tri. void PutNeighInStack(KListC & stack, ItTriC it); // Used by MarkConnected(ItTriC it) void MarkConnected(ItTriC it); // Mark all adjacent faces id to 1, should set to != 1 beforehand // not a recursive algorithm void OldMarkConnected(ItTriC it); // Mark all adjacent faces id to 1 recursively, should set to != 1 beforehand int RemoveFragments(BooleanT trace=TRUE); // Removes all surfaces not connected to first face in flist // Insert and Delete operations // ---------------------------- public: ItVertC InsertVertex(Vector3dC v); // Insert a new vertex in VTRing vertex list (only) void Insert4Face(ItTriC it, ItVertC iv0, ItVertC iv1, ItVertC iv2, ItVertC iv3); void Insert3Face(ItTriC it, ItVertC iv0, ItVertC iv1, ItVertC iv2); ItTriC Insert4Face(ItVertC iv0, ItVertC iv1, ItVertC iv2, ItVertC iv3); ItTriC Insert3Face(ItVertC iv0, ItVertC iv1, ItVertC iv2); // One version creates a new face; the other overwrites the supplied face. // The face is setup to point to vertices and edges; and the edges and vertices // updated to point back at the face // No test for validity of Vertex iterator void DeleteVertex(ItVertC iv); // Deletes the vertex from VTRing list, deletes all triangles using this vertex // dangling vertices are deleted void DeleteTriangle(ItTriC it, int del_dangle, int del_tri=1); // Deletes the triangle from VTRing list, delete reference to it from vertices // Flag to delete 'dangling' vertices 1=delete, 0=dont delete // Flag to delete face or leave it to be overwritten later // Insert and Delete operations // ---------------------------- private: ItVertC MakeMidpoint(ItVertC iv0, ItVertC iv1); // Insert a new vertex midway between the supplied vertices ItEdgeC InsertEdge(ItVertC iv0, ItVertC iv1, ItTriC it); // Insert edge in VTRing edge list, tests to see if already there // and adds to it if so, otherwise new edge is created. // The order of v0, iv1 is significant void AddReferenceToFace(ItVertC iv, ItTriC it); // Add a reference to face it into the ptris list of iv ItTriC OldChangeVertex(ItTriC it, int i, ItVertC ivnew); void ChangeVertex(ItTriC it, int i, ItVertC ivnew); // A face refers to 3 or 4 vertices // Move pointer vertex[i] to point to a new vertex // Since it is done by delete & insert it is slow, but should do everything right // Dangling vertices are not deleted // This routine could probably be optimized // The old version completely deletes the old face and inserts a new one // The newer version keeps the face and hence id and ptr are unchanged; // however all edges are deleted and reinserted void RemoveEdge(ItVertC ie, ItVertC iv0, ItVertC iv1); // If valence 2 then remove reference, if 1 then delete edge; // should only be used when deleting a face // Note that this is ORDER DEPENDENT public: // Utilities // --------- int NumFacesOnVert(ItVertC & iv); // returns number of faces using this vertex // Utilities - boundary related // ---------------------------- ItEdgeC NextEdgeonBound(ItEdgeC ie); // Gets the next edge on the boundary; same sense as single tri BooleanT EdgeonBound(ItEdgeC ie); // returns 1 if edge is a boundary edge; very efficent!! int NBoundsOnVert(ItVertC iv); // Counts the number of boundary edges on the vertex - efficient // could be used to replace VertexonBound(ItVertC iv); BooleanT VertexonBound(ItVertC iv); // returns 1 if vertex is has a boundary edge // this is a fast but not very fast operation since it uses Cyclic(te) // avoid unnecessary use! BooleanT FaceonBound(ItTriC it); // returns 1 if face is has a boundary edge // Utilities - find it // ------------------- int FindEdge(ItEdgeC & ie, ItVertC iv0, ItVertC iv1); // returns ie given vertices, 1 for success, 0 failure void EdgesOf(ItVertC iv, ItTriC it, ItEdgeC & ieout, ItEdgeC & iein); // locates the edges of a vertex in a triangle int VnumOfVertinTri(const ItTriC & it, const ItVertC & iv, bool warn=true); // Given tri and vertex finds which number the vertex is in the tri int EnumOfEdgeinTriNoCheck(ItEdgeC ie, int i); // Given edge and i=0/1 returns the edge number 0/1/2 in the tri // Usage is deprecated since it does not perform a check for boundary case, // use instead TEfromEdge int InumOfTriinEdge(ItTriC it, int e); // Given tri and e=0/1/2 returns the tri number 0/1 in the edge // on a boundary this is always 0 BooleanT OtherTriOnEdge(TEdgeC & teother, const TEdgeC & te); // Locate other triangle using this edge, return FALSE if not found // i.e. edge is valence 1 TEdgeC GetFirstTEofVert(ItVertC iv); // Find the first TE leading from given vertex TEdgeC ForceTEfromEdge(ItEdgeC ie); // Convert edge iterator to TE with direction i=0 // this is always possible, but since i=1 on boundary doesnt work hence TEfromEdge BooleanT TEfromEdge(TEdgeC & te, ItEdgeC ie, int i); // Convert edge iterator to TE, note direction // returns TRUE if successful, failure occurs on surface boundarys ItEdgeC EdgefromTE(TEdgeC te); // Convert TE to edge iterator, note direction BooleanT CyclicTE(TEdgeC & te); // Move around to the next TE, returns FALSE if on boundary and does not change te BooleanT AntiCyclicTE(TEdgeC & te); // Move backwards to the next TE, returns FALSE if on boundary and does not change te KListC TEdgesAroundVert(TEdgeC te0, BooleanT & bound); KListC TEdgesAroundVert(ItVertC ivcent, BooleanT & bound); KListC VertsAroundVert(TEdgeC te0, BooleanT & bound, int & nprev); KListC VertsAroundVert(TEdgeC te0, BooleanT & bound); KListC VertsAroundVert(ItVertC ivcent, BooleanT & bound); // returns a list of vertices around a central VERTEX in order // bound is set to true if the vertex is on the boundary // the returned list starts with the first outward TEdgeC for boundary vertices // the TEdge list contains as many elements as there are triangles // the Verts list contains one MORE element // nprev records the number of TE's before te0 when the vertex is on the boundary KListC TEdgesAroundEdge(ItEdgeC iecent, int & mid); // returns a list of all edges around a central EDGE in order // for a list of all tris remove the last element // ***NB***: not implemented for boundary vertices (on edge) // list element 0 and mid correspond to the common tris, 0-indexed KListC VertsAroundEdge(ItEdgeC iecent, int & mid); // returns a list of vertices around a central EDGE in order // ***NB***: not implemented for boundary vertices (on edge) // list element 0 and mid correspond to the common vertices, 0-indexed KListC FacesOnEdge(ItEdgeC ie); // A list (NOT IN ORDER) of all the triangles that touch the specified // edge. This works for all edge configurations. // Nearest point to triangle // ------------------------- // Errors may arise for triangles with zero area, whether they have zero // perimeter or not. These errors result in a warning and a 'plausible' result // is returned based on using vertex 0. // This code is a DUPLICATION of code in IndTriC in Polops module // to increases modularity // The Vector3dC b contains the coordinates of the point in barycentric coords // // // double DistToTri(ItTriC it, const Vector3dC & p); // distance to nearest point on triangle double DistToTri(const Vector3dC & v0, const Vector3dC & v1, const Vector3dC & v2, const Vector3dC & p); // distance to nearest point on triangle void NearestBaryInside(const Vector3dC & v0, const Vector3dC & v1, const Vector3dC & v2, const Vector3dC & p, Vector3dC & b); // nearest point on triangle void NearestBaryInside(const Vector3dC & v0, const Vector3dC & v1, const Vector3dC & v2, const Vector3dC & p, Vector3dC & b, Vector3dC & nearest, double & dist); // nearest point on triangle void NearestBaryInside(ItTriC it, const Vector3dC & p, Vector3dC & b, Vector3dC & nearest, double & dist); // nearest point on triangle // Geometrical Utilities // --------------------- Vector3dC BoxMin(ItTriC it); Vector3dC BoxMin(void); // Minimum extent, face or whole surface Vector3dC BoxMax(ItTriC it); Vector3dC BoxMax(void); // Maximum extent, face or whole surface double EdgeAngle(ItEdgeC ie); // returns the angle between the two faces on the edge // - concave, + convex, 0 flat // boundary edge -> 0 Vector3dC FaceNormal(ItTriC it); // returns the outward pointing normal; 3 sided only. double FaceArea(ItTriC it); // returns the area; 3 sided only. Vector3dC FaceCentroid(ItTriC it); // returns the centroid Vector3dC EdgeVector(ItEdgeC ie); // returns the vector from v0 to v1 double EdgeLength(VTEdgeC & e); // Length of edge double EdgeLength(ItEdgeC ie); // Length of edge Vector3dC EdgeMidpoint(ItEdgeC ie); // Midpoint of edge double EdgeLength(ItTriC it, int edge); // Length of edge int FindLongest(ItTriC it); // Find the longest edge of this triangle // Sorting routines // ---------------- void SortEdgesByLength(BooleanT ascending=TRUE); // Sort, from shortest to longest void SortFacesByDiag(BooleanT ascending=TRUE); // Sort, from shortest to longest, meaningful for 4 sided only // Miscellaneous // ------------- PolopsC Make4Sided(void); // Take a 3 sided surface and make it into a 4 sided one // ---------------- // THREE SIDES ONLY // ---------------- // Oddballs // -------- void RemoveOddBalls(); // remove any odd situations that can be detected, eg Remove3TriVertex // for 4-face meshes, performs Remove4QuadVertex // Should also remove zero length edges !!!!!!!!!! ************ // repeats passing through all vertices until none left since // oddballs can be nested! // MINOR FLAW - delete vertex iterator BooleanT Remove3TriVertex(ItVertC iv); // remove a non-boundary vertex used by only 3 triangles, also detects case of // only 2 triangles for non-boundary vertex and gives a warning // returns TRUE if action was taken. // This routine can BREAK on a tetrahedron BooleanT Remove4QuadVertex(ItVertC iv); // remove a vertex that is only on 2 faces. // returns TRUE if action was taken. void DisAllowedVerts(BooleanT trace=TRUE, BooleanT fix=FALSE); // detects, reports and deletes any vertex with more than two boundary edges // contains a very slow step but shouldnt fail, these are RARE. // Adaptive algorithms - refinement // -------------------------------- void RefineLongest(int n, int sort=SORT_INTERVAL); // Subdivide n triangles with longest edge, resort every sort steps ItVertC Refine(TEdgeC te); // Subdivide triangle (on specified edge) and any others needed to maintain conforming ItVertC Refine(ItTriC it); // Subdivide triangle (on longest edge) and any others needed to maintain conforming void ProcessNonConform(TEdgeC te, ItVertC iv); // Take a given triangle with a new vertex on stated edge and make it // conforming - recursive! // Adaptive algorithms - edge collapse // ----------------------------------- void CollapseShortestEdges(int n, BooleanT trace=TRUE); //void CollapseShortestEdges(int n, int sort=SORT_INTERVAL); // Collapse the shortest n edges, if CollapseEdge fails the next // shortest edge is removed. A warning in printed, but it may be ignored. EdgeCollapseT CollapseEdgeAllowed(ItEdgeC ie); void CollapseEdge(ItEdgeC ie, ItVertC & iv_mid); void CollapseEdge(ItEdgeC ie); // Collapse the edge - valence = 1 or 2 EdgeCollapseT CollapseEdgeAllowed_1(TEdgeC te); void CollapseEdge_1(TEdgeC te, ItVertC & iv_mid, TEdgeC & teout); // Collapse the edge; valence 1 EdgeCollapseT CollapseEdgeAllowed_2(TEdgeC te); void CollapseEdge_2(TEdgeC te, ItVertC & iv_mid, TEdgeC & te_a, TEdgeC & te_b); // Collapse the edge; valence 2 // All routines return TRUE if edge collapsed, FALSE if it cannot be collapsed // ******* needs some heuristics to avoid special cases!!!! void ExpandTEdge(TEdgeC tein, TEdgeC & teout, ItVertC & iv0, ItVertC & iv1); // receive a TEdgeC with the ZERO vertex on the boundary, // split the vertex and return the new TEdgeC on the boundary. // ---------------- // FOUR SIDES ONLY // ---------------- double FaceDiag(TEdgeC & te); // returns the length of the shortest face diagonal; te.e is set to 0 or 1 acc shortest double FaceDiag(VTFaceC & tri); // returns the length of the shortest face diagonal double FaceDiag(VTFaceC & tri, int e); // returns the length of the face specified diagonal void CollapseShortestFaces(int n, int sort=SORT_INTERVAL); // BooleanT CollapseFaceAllowed(const TEdgeC & te); // Test to see if face collapse will be OK. void CollapseFace(TEdgeC te, ItVertC & ivnew, int del_dangle=1); // Do face collapse, assumes FaceCollapseAllowed passed // vertices te.e and te.e+2 will be merged to a new vertex void CollapseFaceToPoint(TEdgeC te, ItVertC ivnew, int del_dangle=1); // Do face collapse, linking ivnew as the new point. // assumes FaceCollapseAllowed passed // vertices te.e and te.e+2 will be merged to a new vertex void CollapseFaceToPoint(ItVertC iv1, ItVertC iv2, ItTriC it, ItVertC ivnew, int del_dangle); // Do face collapse, linking ivnew as the new point. // no checking is done. it is assumed that the points iv1 and iv2 of it // can be collapsed void ExpandFace(TEdgeC te1, TEdgeC te2, ItTriC &itnew, ItVertC iv1=NULL, ItVertC iv2=NULL); // inserts a new face by expanding edges "te1" and "te2". // New face returned in "itnew". ItVertC ExpandFaceNoDelete(TEdgeC te1, TEdgeC te2, ItTriC &itnew, ItVertC iv1=NULL, ItVertC iv2=NULL); // inserts a new face by expanding edges "te1" and "te2". // New face returned in "itnew". BooleanT ExpandFaceAllowed(TEdgeC te1, TEdgeC te2); // tests whether a new face can be created by expanding edges "te1" and // "te2" BooleanT ExpandFaceAllowed(ItTriC it, TEdgeC &te1, TEdgeC &te2); // returns TRUE if face "it" can be expanded. Also returns the best // TEdge pair to expand on (selection criteria is maximum minimum distance // bewteen outer vertices of edge pair). void ExpandFirstFaces(int num=1); // expands face for about first vertex in "vlist". // Keeps looking down "vlist" til a vertex that can be expanded is found. void ExpandFirstVerts(int num=1); // expands face for about first vertex in "vlist". // Keeps looking down "vlist" til a vertex that can be expanded is found. }; //----------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- VTRingC PolToVTRing(PolopsC pol, int nv=3); // Calling purify and Check are advised before calling this PolopsC VTRingToPol(VTRingC vt); // //----------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------- #define FOR_VLIST(it, list) \ for (ItVertC it=list.First(); list.IsElem(it); it=list.Next(it)) #define FOR_IVLIST(it, list) \ for (ItItVertC it=list.First(); list.IsElem(it); it=list.Next(it)) #define FOR_ELIST(it, list) \ for (ItEdgeC it=list.First(); list.IsElem(it); it=list.Next(it)) #define FOR_ITELIST(it, list) \ for (ItTEdgeC it=list.First(); list.IsElem(it); it=list.Next(it)) #define FOR_TLIST(it, list) \ for (ItTriC it=list.First(); list.IsElem(it); it=list.Next(it)) #define FOR_ITLIST(it, list) \ for (ItItTriC it=list.First(); list.IsElem(it); it=list.Next(it)) #endif //----------------------------------------------------------------------------------------- // End of include file VTRing.hh //-----------------------------------------------------------------------------------------