Warning, /include/Geant4/tools/glutess/mesh is written in an unsupported language. File is not indexed.
0001 // see license file for original license.
0002
0003 #ifndef tools_glutess_mesh
0004 #define tools_glutess_mesh
0005
0006 #include "_glu"
0007
0008 typedef struct GLUmesh GLUmesh;
0009
0010 typedef struct GLUvertex GLUvertex;
0011 typedef struct GLUface GLUface;
0012 typedef struct GLUhalfEdge GLUhalfEdge;
0013
0014 typedef struct ActiveRegion ActiveRegion; /* Internal data */
0015
0016 /* The mesh structure is similar in spirit, notation, and operations
0017 * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
0018 * for the manipulation of general subdivisions and the computation of
0019 * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
0020 * For a simplified description, see the course notes for CS348a,
0021 * "Mathematical Foundations of Computer Graphics", available at the
0022 * Stanford bookstore (and taught during the fall quarter).
0023 * The implementation also borrows a tiny subset of the graph-based approach
0024 * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
0025 * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
0026 *
0027 * The fundamental data structure is the "half-edge". Two half-edges
0028 * go together to make an edge, but they point in opposite directions.
0029 * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
0030 * its origin vertex (Org), the face on its left side (Lface), and the
0031 * adjacent half-edges in the CCW direction around the origin vertex
0032 * (Onext) and around the left face (Lnext). There is also a "next"
0033 * pointer for the global edge list (see below).
0034 *
0035 * The notation used for mesh navigation:
0036 * Sym = the mate of a half-edge (same edge, but opposite direction)
0037 * Onext = edge CCW around origin vertex (keep same origin)
0038 * Dnext = edge CCW around destination vertex (keep same dest)
0039 * Lnext = edge CCW around left face (dest becomes new origin)
0040 * Rnext = edge CCW around right face (origin becomes new dest)
0041 *
0042 * "prev" means to substitute CW for CCW in the definitions above.
0043 *
0044 * The mesh keeps global lists of all vertices, faces, and edges,
0045 * stored as doubly-linked circular lists with a dummy header node.
0046 * The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
0047 *
0048 * The circular edge list is special; since half-edges always occur
0049 * in pairs (e and e->Sym), each half-edge stores a pointer in only
0050 * one direction. Starting at eHead and following the e->next pointers
0051 * will visit each *edge* once (ie. e or e->Sym, but not both).
0052 * e->Sym stores a pointer in the opposite direction, thus it is
0053 * always true that e->Sym->next->Sym->next == e.
0054 *
0055 * Each vertex has a pointer to next and previous vertices in the
0056 * circular list, and a pointer to a half-edge with this vertex as
0057 * the origin (NULL if this is the dummy header). There is also a
0058 * field "data" for client data.
0059 *
0060 * Each face has a pointer to the next and previous faces in the
0061 * circular list, and a pointer to a half-edge with this face as
0062 * the left face (NULL if this is the dummy header). There is also
0063 * a field "data" for client data.
0064 *
0065 * Note that what we call a "face" is really a loop; faces may consist
0066 * of more than one loop (ie. not simply connected), but there is no
0067 * record of this in the data structure. The mesh may consist of
0068 * several disconnected regions, so it may not be possible to visit
0069 * the entire mesh by starting at a half-edge and traversing the edge
0070 * structure.
0071 *
0072 * The mesh does NOT support isolated vertices; a vertex is deleted along
0073 * with its last edge. Similarly when two faces are merged, one of the
0074 * faces is deleted (see __gl_meshDelete below). For mesh operations,
0075 * all face (loop) and vertex pointers must not be NULL. However, once
0076 * mesh manipulation is finished, __gl_MeshZapFace can be used to delete
0077 * faces of the mesh, one at a time. All external faces can be "zapped"
0078 * before the mesh is returned to the client; then a NULL face indicates
0079 * a region which is not part of the output polygon.
0080 */
0081
0082 struct GLUvertex {
0083 GLUvertex *next; /* next vertex (never NULL) */
0084 GLUvertex *prev; /* previous vertex (never NULL) */
0085 GLUhalfEdge *anEdge; /* a half-edge with this origin */
0086 void *data; /* client's data */
0087
0088 /* Internal data (keep hidden) */
0089 GLUdouble coords[3]; /* vertex location in 3D */
0090 GLUdouble s, t; /* projection onto the sweep plane */
0091 long pqHandle; /* to allow deletion from priority queue */
0092 };
0093
0094 struct GLUface {
0095 GLUface *next; /* next face (never NULL) */
0096 GLUface *prev; /* previous face (never NULL) */
0097 GLUhalfEdge *anEdge; /* a half edge with this left face */
0098 void *data; /* room for client's data */
0099
0100 /* Internal data (keep hidden) */
0101 GLUface *trail; /* "stack" for conversion to strips */
0102 GLUboolean marked; /* flag for conversion to strips */
0103 GLUboolean inside; /* this face is in the polygon interior */
0104 };
0105
0106 struct GLUhalfEdge {
0107 GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */
0108 GLUhalfEdge *Sym; /* same edge, opposite direction */
0109 GLUhalfEdge *Onext; /* next edge CCW around origin */
0110 GLUhalfEdge *Lnext; /* next edge CCW around left face */
0111 GLUvertex *Org; /* origin vertex (Overtex too long) */
0112 GLUface *Lface; /* left face */
0113
0114 /* Internal data (keep hidden) */
0115 ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */
0116 int winding; /* change in winding number when crossing
0117 from the right face to the left face */
0118 };
0119
0120 #define Rface Sym->Lface
0121 #define Dst Sym->Org
0122
0123 #define Oprev Sym->Lnext
0124 #define Lprev Onext->Sym
0125 #define Dprev Lnext->Sym
0126 #define Rprev Sym->Onext
0127 #define Dnext Rprev->Sym /* 3 pointers */
0128 #define Rnext Oprev->Sym /* 3 pointers */
0129
0130
0131 struct GLUmesh {
0132 GLUvertex vHead; /* dummy header for vertex list */
0133 GLUface fHead; /* dummy header for face list */
0134 GLUhalfEdge eHead; /* dummy header for edge list */
0135 GLUhalfEdge eHeadSym; /* and its symmetric counterpart */
0136 };
0137
0138 /* The mesh operations below have three motivations: completeness,
0139 * convenience, and efficiency. The basic mesh operations are MakeEdge,
0140 * Splice, and Delete. All the other edge operations can be implemented
0141 * in terms of these. The other operations are provided for convenience
0142 * and/or efficiency.
0143 *
0144 * When a face is split or a vertex is added, they are inserted into the
0145 * global list *before* the existing vertex or face (ie. e->Org or e->Lface).
0146 * This makes it easier to process all vertices or faces in the global lists
0147 * without worrying about processing the same data twice. As a convenience,
0148 * when a face is split, the "inside" flag is copied from the old face.
0149 * Other internal data (v->data, v->activeRegion, f->data, f->marked,
0150 * f->trail, e->winding) is set to zero.
0151 *
0152 * ********************** Basic Edge Operations **************************
0153 *
0154 * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
0155 * The loop (face) consists of the two new half-edges.
0156 *
0157 * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
0158 * mesh connectivity and topology. It changes the mesh so that
0159 * eOrg->Onext <- OLD( eDst->Onext )
0160 * eDst->Onext <- OLD( eOrg->Onext )
0161 * where OLD(...) means the value before the meshSplice operation.
0162 *
0163 * This can have two effects on the vertex structure:
0164 * - if eOrg->Org != eDst->Org, the two vertices are merged together
0165 * - if eOrg->Org == eDst->Org, the origin is split into two vertices
0166 * In both cases, eDst->Org is changed and eOrg->Org is untouched.
0167 *
0168 * Similarly (and independently) for the face structure,
0169 * - if eOrg->Lface == eDst->Lface, one loop is split into two
0170 * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
0171 * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
0172 *
0173 * __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
0174 * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
0175 * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
0176 * the newly created loop will contain eDel->Dst. If the deletion of eDel
0177 * would create isolated vertices, those are deleted as well.
0178 *
0179 * ********************** Other Edge Operations **************************
0180 *
0181 * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
0182 * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
0183 * eOrg and eNew will have the same left face.
0184 *
0185 * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
0186 * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
0187 * eOrg and eNew will have the same left face.
0188 *
0189 * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
0190 * to eDst->Org, and returns the corresponding half-edge eNew.
0191 * If eOrg->Lface == eDst->Lface, this splits one loop into two,
0192 * and the newly created loop is eNew->Lface. Otherwise, two disjoint
0193 * loops are merged into one, and the loop eDst->Lface is destroyed.
0194 *
0195 * ************************ Other Operations *****************************
0196 *
0197 * __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
0198 * and no loops (what we usually call a "face").
0199 *
0200 * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
0201 * both meshes, and returns the new mesh (the old meshes are destroyed).
0202 *
0203 * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
0204 *
0205 * __gl_meshZapFace( fZap ) destroys a face and removes it from the
0206 * global face list. All edges of fZap will have a NULL pointer as their
0207 * left face. Any edges which also have a NULL pointer as their right face
0208 * are deleted entirely (along with any isolated vertices this produces).
0209 * An entire mesh can be deleted by zapping its faces, one at a time,
0210 * in any order. Zapped faces cannot be used in further mesh operations!
0211 *
0212 * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
0213 */
0214
0215 ////////////////////////////////////////////////////////
0216 /// inlined C code : ///////////////////////////////////
0217 ////////////////////////////////////////////////////////
0218
0219 //#include "gluos"
0220 #include <cstddef>
0221 #include <cassert>
0222 #include "memalloc"
0223
0224 inline/*static*/ GLUvertex *static_allocVertex()
0225 {
0226 return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
0227 }
0228
0229 inline/*static*/ GLUface *static_allocFace()
0230 {
0231 return (GLUface *)memAlloc( sizeof( GLUface ));
0232 }
0233
0234 /************************ Utility Routines ************************/
0235
0236 /* Allocate and free half-edges in pairs for efficiency.
0237 * The *only* place that should use this fact is allocation/free.
0238 */
0239 typedef struct { GLUhalfEdge e, eSym; } EdgePair;
0240
0241 /* MakeEdge creates a new pair of half-edges which form their own loop.
0242 * No vertex or face structures are allocated, but these must be assigned
0243 * before the current edge operation is completed.
0244 */
0245 inline/*static*/ GLUhalfEdge *static_MakeEdge( GLUhalfEdge *eNext )
0246 {
0247 GLUhalfEdge *e;
0248 GLUhalfEdge *eSym;
0249 GLUhalfEdge *ePrev;
0250 EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
0251 if (pair == NULL) return NULL;
0252
0253 e = &pair->e;
0254 eSym = &pair->eSym;
0255
0256 /* Make sure eNext points to the first edge of the edge pair */
0257 if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
0258
0259 /* Insert in circular doubly-linked list before eNext.
0260 * Note that the prev pointer is stored in Sym->next.
0261 */
0262 ePrev = eNext->Sym->next;
0263 eSym->next = ePrev;
0264 ePrev->Sym->next = e;
0265 e->next = eNext;
0266 eNext->Sym->next = eSym;
0267
0268 e->Sym = eSym;
0269 e->Onext = e;
0270 e->Lnext = eSym;
0271 e->Org = NULL;
0272 e->Lface = NULL;
0273 e->winding = 0;
0274 e->activeRegion = NULL;
0275
0276 eSym->Sym = e;
0277 eSym->Onext = eSym;
0278 eSym->Lnext = e;
0279 eSym->Org = NULL;
0280 eSym->Lface = NULL;
0281 eSym->winding = 0;
0282 eSym->activeRegion = NULL;
0283
0284 return e;
0285 }
0286
0287 /* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
0288 * CS348a notes (see mesh.h). Basically it modifies the mesh so that
0289 * a->Onext and b->Onext are exchanged. This can have various effects
0290 * depending on whether a and b belong to different face or vertex rings.
0291 * For more explanation see __gl_meshSplice() below.
0292 */
0293 inline/*static*/ void static_Splice( GLUhalfEdge *a, GLUhalfEdge *b )
0294 {
0295 GLUhalfEdge *aOnext = a->Onext;
0296 GLUhalfEdge *bOnext = b->Onext;
0297
0298 aOnext->Sym->Lnext = b;
0299 bOnext->Sym->Lnext = a;
0300 a->Onext = bOnext;
0301 b->Onext = aOnext;
0302 }
0303
0304 /* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
0305 * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
0306 * a place to insert the new vertex in the global vertex list. We insert
0307 * the new vertex *before* vNext so that algorithms which walk the vertex
0308 * list will not see the newly created vertices.
0309 */
0310 inline/*static*/ void static_MakeVertex( GLUvertex *newVertex,
0311 GLUhalfEdge *eOrig, GLUvertex *vNext )
0312 {
0313 GLUhalfEdge *e;
0314 GLUvertex *vPrev;
0315 GLUvertex *vNew = newVertex;
0316
0317 assert(vNew != NULL);
0318
0319 /* insert in circular doubly-linked list before vNext */
0320 vPrev = vNext->prev;
0321 vNew->prev = vPrev;
0322 vPrev->next = vNew;
0323 vNew->next = vNext;
0324 vNext->prev = vNew;
0325
0326 vNew->anEdge = eOrig;
0327 vNew->data = NULL;
0328 /* leave coords, s, t undefined */
0329
0330 /* fix other edges on this vertex loop */
0331 e = eOrig;
0332 do {
0333 e->Org = vNew;
0334 e = e->Onext;
0335 } while( e != eOrig );
0336 }
0337
0338 /* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
0339 * face of all edges in the face loop to which eOrig belongs. "fNext" gives
0340 * a place to insert the new face in the global face list. We insert
0341 * the new face *before* fNext so that algorithms which walk the face
0342 * list will not see the newly created faces.
0343 */
0344 inline/*static*/ void static_MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
0345 {
0346 GLUhalfEdge *e;
0347 GLUface *fPrev;
0348 GLUface *fNew = newFace;
0349
0350 assert(fNew != NULL);
0351
0352 /* insert in circular doubly-linked list before fNext */
0353 fPrev = fNext->prev;
0354 fNew->prev = fPrev;
0355 fPrev->next = fNew;
0356 fNew->next = fNext;
0357 fNext->prev = fNew;
0358
0359 fNew->anEdge = eOrig;
0360 fNew->data = NULL;
0361 fNew->trail = NULL;
0362 fNew->marked = TOOLS_GLU_FALSE;
0363
0364 /* The new face is marked "inside" if the old one was. This is a
0365 * convenience for the common case where a face has been split in two.
0366 */
0367 fNew->inside = fNext->inside;
0368
0369 /* fix other edges on this face loop */
0370 e = eOrig;
0371 do {
0372 e->Lface = fNew;
0373 e = e->Lnext;
0374 } while( e != eOrig );
0375 }
0376
0377 /* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
0378 * and removes from the global edge list.
0379 */
0380 inline/*static*/ void static_KillEdge( GLUhalfEdge *eDel )
0381 {
0382 GLUhalfEdge *ePrev, *eNext;
0383
0384 /* Half-edges are allocated in pairs, see EdgePair above */
0385 if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
0386
0387 /* delete from circular doubly-linked list */
0388 eNext = eDel->next;
0389 ePrev = eDel->Sym->next;
0390 eNext->Sym->next = ePrev;
0391 ePrev->Sym->next = eNext;
0392
0393 memFree( eDel );
0394 }
0395
0396
0397 /* KillVertex( vDel ) destroys a vertex and removes it from the global
0398 * vertex list. It updates the vertex loop to point to a given new vertex.
0399 */
0400 inline/*static*/ void static_KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
0401 {
0402 GLUhalfEdge *e, *eStart = vDel->anEdge;
0403 GLUvertex *vPrev, *vNext;
0404
0405 /* change the origin of all affected edges */
0406 e = eStart;
0407 do {
0408 e->Org = newOrg;
0409 e = e->Onext;
0410 } while( e != eStart );
0411
0412 /* delete from circular doubly-linked list */
0413 vPrev = vDel->prev;
0414 vNext = vDel->next;
0415 vNext->prev = vPrev;
0416 vPrev->next = vNext;
0417
0418 memFree( vDel );
0419 }
0420
0421 /* KillFace( fDel ) destroys a face and removes it from the global face
0422 * list. It updates the face loop to point to a given new face.
0423 */
0424 inline/*static*/ void static_KillFace( GLUface *fDel, GLUface *newLface )
0425 {
0426 GLUhalfEdge *e, *eStart = fDel->anEdge;
0427 GLUface *fPrev, *fNext;
0428
0429 /* change the left face of all affected edges */
0430 e = eStart;
0431 do {
0432 e->Lface = newLface;
0433 e = e->Lnext;
0434 } while( e != eStart );
0435
0436 /* delete from circular doubly-linked list */
0437 fPrev = fDel->prev;
0438 fNext = fDel->next;
0439 fNext->prev = fPrev;
0440 fPrev->next = fNext;
0441
0442 memFree( fDel );
0443 }
0444
0445
0446 /****************** Basic Edge Operations **********************/
0447
0448 /* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
0449 * The loop consists of the two new half-edges.
0450 */
0451 inline GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
0452 {
0453 GLUvertex *newVertex1= static_allocVertex();
0454 GLUvertex *newVertex2= static_allocVertex();
0455 GLUface *newFace= static_allocFace();
0456 GLUhalfEdge *e;
0457
0458 /* if any one is null then all get freed */
0459 if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
0460 if (newVertex1 != NULL) memFree(newVertex1);
0461 if (newVertex2 != NULL) memFree(newVertex2);
0462 if (newFace != NULL) memFree(newFace);
0463 return NULL;
0464 }
0465
0466 e = static_MakeEdge( &mesh->eHead );
0467 if (e == NULL) {
0468 memFree(newVertex1);
0469 memFree(newVertex2);
0470 memFree(newFace);
0471 return NULL;
0472 }
0473
0474 static_MakeVertex( newVertex1, e, &mesh->vHead );
0475 static_MakeVertex( newVertex2, e->Sym, &mesh->vHead );
0476 static_MakeFace( newFace, e, &mesh->fHead );
0477 return e;
0478 }
0479
0480
0481 /* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
0482 * mesh connectivity and topology. It changes the mesh so that
0483 * eOrg->Onext <- OLD( eDst->Onext )
0484 * eDst->Onext <- OLD( eOrg->Onext )
0485 * where OLD(...) means the value before the meshSplice operation.
0486 *
0487 * This can have two effects on the vertex structure:
0488 * - if eOrg->Org != eDst->Org, the two vertices are merged together
0489 * - if eOrg->Org == eDst->Org, the origin is split into two vertices
0490 * In both cases, eDst->Org is changed and eOrg->Org is untouched.
0491 *
0492 * Similarly (and independently) for the face structure,
0493 * - if eOrg->Lface == eDst->Lface, one loop is split into two
0494 * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
0495 * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
0496 *
0497 * Some special cases:
0498 * If eDst == eOrg, the operation has no effect.
0499 * If eDst == eOrg->Lnext, the new face will have a single edge.
0500 * If eDst == eOrg->Lprev, the old face will have a single edge.
0501 * If eDst == eOrg->Onext, the new vertex will have a single edge.
0502 * If eDst == eOrg->Oprev, the old vertex will have a single edge.
0503 */
0504 inline int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
0505 {
0506 int joiningLoops = TOOLS_GLU_FALSE;
0507 int joiningVertices = TOOLS_GLU_FALSE;
0508
0509 if( eOrg == eDst ) return 1;
0510
0511 if( eDst->Org != eOrg->Org ) {
0512 /* We are merging two disjoint vertices -- destroy eDst->Org */
0513 joiningVertices = TOOLS_GLU_TRUE;
0514 static_KillVertex( eDst->Org, eOrg->Org );
0515 }
0516 if( eDst->Lface != eOrg->Lface ) {
0517 /* We are connecting two disjoint loops -- destroy eDst->Lface */
0518 joiningLoops = TOOLS_GLU_TRUE;
0519 static_KillFace( eDst->Lface, eOrg->Lface );
0520 }
0521
0522 /* Change the edge structure */
0523 static_Splice( eDst, eOrg );
0524
0525 if( ! joiningVertices ) {
0526 GLUvertex *newVertex= static_allocVertex();
0527 if (newVertex == NULL) return 0;
0528
0529 /* We split one vertex into two -- the new vertex is eDst->Org.
0530 * Make sure the old vertex points to a valid half-edge.
0531 */
0532 static_MakeVertex( newVertex, eDst, eOrg->Org );
0533 eOrg->Org->anEdge = eOrg;
0534 }
0535 if( ! joiningLoops ) {
0536 GLUface *newFace= static_allocFace();
0537 if (newFace == NULL) return 0;
0538
0539 /* We split one loop into two -- the new loop is eDst->Lface.
0540 * Make sure the old face points to a valid half-edge.
0541 */
0542 static_MakeFace( newFace, eDst, eOrg->Lface );
0543 eOrg->Lface->anEdge = eOrg;
0544 }
0545
0546 return 1;
0547 }
0548
0549
0550 /* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
0551 * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
0552 * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
0553 * the newly created loop will contain eDel->Dst. If the deletion of eDel
0554 * would create isolated vertices, those are deleted as well.
0555 *
0556 * This function could be implemented as two calls to __gl_meshSplice
0557 * plus a few calls to memFree, but this would allocate and delete
0558 * unnecessary vertices and faces.
0559 */
0560 inline int __gl_meshDelete( GLUhalfEdge *eDel )
0561 {
0562 GLUhalfEdge *eDelSym = eDel->Sym;
0563 int joiningLoops = TOOLS_GLU_FALSE;
0564
0565 /* First step: disconnect the origin vertex eDel->Org. We make all
0566 * changes to get a consistent mesh in this "intermediate" state.
0567 */
0568 if( eDel->Lface != eDel->Rface ) {
0569 /* We are joining two loops into one -- remove the left face */
0570 joiningLoops = TOOLS_GLU_TRUE;
0571 static_KillFace( eDel->Lface, eDel->Rface );
0572 /* G.Barrand : note : Coverity says that there is a problem using eDel->Lface->anEdge in the below,
0573 but it appears that at the out of the upper static_KillFace() call (then here), eDel->Lface before
0574 (the pointer freeed) is not the same than after (then here). */
0575 }
0576
0577 if( eDel->Onext == eDel ) {
0578 static_KillVertex( eDel->Org, NULL );
0579 } else {
0580 /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
0581 eDel->Rface->anEdge = eDel->Oprev;
0582 eDel->Org->anEdge = eDel->Onext;
0583
0584 static_Splice( eDel, eDel->Oprev );
0585 if( ! joiningLoops ) {
0586 GLUface *newFace= static_allocFace();
0587 if (newFace == NULL) return 0;
0588
0589 /* We are splitting one loop into two -- create a new loop for eDel. */
0590 static_MakeFace( newFace, eDel, eDel->Lface );
0591 }
0592 }
0593
0594 /* Claim: the mesh is now in a consistent state, except that eDel->Org
0595 * may have been deleted. Now we disconnect eDel->Dst.
0596 */
0597 if( eDelSym->Onext == eDelSym ) {
0598 static_KillVertex( eDelSym->Org, NULL );
0599 static_KillFace( eDelSym->Lface, NULL );
0600 } else {
0601 /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
0602 eDel->Lface->anEdge = eDelSym->Oprev;
0603 eDelSym->Org->anEdge = eDelSym->Onext;
0604 static_Splice( eDelSym, eDelSym->Oprev );
0605 }
0606
0607 /* Any isolated vertices or faces have already been freed. */
0608 static_KillEdge( eDel );
0609
0610 return 1;
0611 }
0612
0613
0614 /******************** Other Edge Operations **********************/
0615
0616 /* All these routines can be implemented with the basic edge
0617 * operations above. They are provided for convenience and efficiency.
0618 */
0619
0620
0621 /* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
0622 * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
0623 * eOrg and eNew will have the same left face.
0624 */
0625 inline GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
0626 {
0627 GLUhalfEdge *eNewSym;
0628 GLUhalfEdge *eNew = static_MakeEdge( eOrg );
0629 if (eNew == NULL) return NULL;
0630
0631 eNewSym = eNew->Sym;
0632
0633 /* Connect the new edge appropriately */
0634 static_Splice( eNew, eOrg->Lnext );
0635
0636 /* Set the vertex and face information */
0637 eNew->Org = eOrg->Dst;
0638 {
0639 GLUvertex *newVertex= static_allocVertex();
0640 if (newVertex == NULL) return NULL;
0641
0642 static_MakeVertex( newVertex, eNewSym, eNew->Org );
0643 }
0644 eNew->Lface = eNewSym->Lface = eOrg->Lface;
0645
0646 return eNew;
0647 }
0648
0649
0650 /* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
0651 * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
0652 * eOrg and eNew will have the same left face.
0653 */
0654 inline GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
0655 {
0656 GLUhalfEdge *eNew;
0657 GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
0658 if (tempHalfEdge == NULL) return NULL;
0659
0660 eNew = tempHalfEdge->Sym;
0661
0662 /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
0663 static_Splice( eOrg->Sym, eOrg->Sym->Oprev );
0664 static_Splice( eOrg->Sym, eNew );
0665
0666 /* Set the vertex and face information */
0667 eOrg->Dst = eNew->Org;
0668 eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
0669 eNew->Rface = eOrg->Rface;
0670 eNew->winding = eOrg->winding; /* copy old winding information */
0671 eNew->Sym->winding = eOrg->Sym->winding;
0672
0673 return eNew;
0674 }
0675
0676
0677 /* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
0678 * to eDst->Org, and returns the corresponding half-edge eNew.
0679 * If eOrg->Lface == eDst->Lface, this splits one loop into two,
0680 * and the newly created loop is eNew->Lface. Otherwise, two disjoint
0681 * loops are merged into one, and the loop eDst->Lface is destroyed.
0682 *
0683 * If (eOrg == eDst), the new face will have only two edges.
0684 * If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
0685 * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
0686 */
0687 inline GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
0688 {
0689 GLUhalfEdge *eNewSym;
0690 int joiningLoops = TOOLS_GLU_FALSE;
0691 GLUhalfEdge *eNew = static_MakeEdge( eOrg );
0692 if (eNew == NULL) return NULL;
0693
0694 eNewSym = eNew->Sym;
0695
0696 if( eDst->Lface != eOrg->Lface ) {
0697 /* We are connecting two disjoint loops -- destroy eDst->Lface */
0698 joiningLoops = TOOLS_GLU_TRUE;
0699 static_KillFace( eDst->Lface, eOrg->Lface );
0700 }
0701
0702 /* Connect the new edge appropriately */
0703 static_Splice( eNew, eOrg->Lnext );
0704 static_Splice( eNewSym, eDst );
0705
0706 /* Set the vertex and face information */
0707 eNew->Org = eOrg->Dst;
0708 eNewSym->Org = eDst->Org;
0709 eNew->Lface = eNewSym->Lface = eOrg->Lface;
0710
0711 /* Make sure the old face points to a valid half-edge */
0712 eOrg->Lface->anEdge = eNewSym;
0713
0714 if( ! joiningLoops ) {
0715 GLUface *newFace= static_allocFace();
0716 if (newFace == NULL) return NULL;
0717
0718 /* We split one loop into two -- the new loop is eNew->Lface */
0719 static_MakeFace( newFace, eNew, eOrg->Lface );
0720 }
0721 return eNew;
0722 }
0723
0724
0725 /******************** Other Operations **********************/
0726
0727 /* __gl_meshZapFace( fZap ) destroys a face and removes it from the
0728 * global face list. All edges of fZap will have a NULL pointer as their
0729 * left face. Any edges which also have a NULL pointer as their right face
0730 * are deleted entirely (along with any isolated vertices this produces).
0731 * An entire mesh can be deleted by zapping its faces, one at a time,
0732 * in any order. Zapped faces cannot be used in further mesh operations!
0733 */
0734 inline void __gl_meshZapFace( GLUface *fZap )
0735 {
0736 GLUhalfEdge *eStart = fZap->anEdge;
0737 GLUhalfEdge *e, *eNext, *eSym;
0738 GLUface *fPrev, *fNext;
0739
0740 /* walk around face, deleting edges whose right face is also NULL */
0741 eNext = eStart->Lnext;
0742 do {
0743 e = eNext;
0744 eNext = e->Lnext;
0745
0746 e->Lface = NULL;
0747 if( e->Rface == NULL ) {
0748 /* delete the edge -- see __gl_MeshDelete above */
0749
0750 if( e->Onext == e ) {
0751 static_KillVertex( e->Org, NULL );
0752 } else {
0753 /* Make sure that e->Org points to a valid half-edge */
0754 e->Org->anEdge = e->Onext;
0755 static_Splice( e, e->Oprev );
0756 }
0757 eSym = e->Sym;
0758 if( eSym->Onext == eSym ) {
0759 static_KillVertex( eSym->Org, NULL );
0760 } else {
0761 /* Make sure that eSym->Org points to a valid half-edge */
0762 eSym->Org->anEdge = eSym->Onext;
0763 static_Splice( eSym, eSym->Oprev );
0764 }
0765 static_KillEdge( e );
0766 }
0767 } while( e != eStart );
0768
0769 /* delete from circular doubly-linked list */
0770 fPrev = fZap->prev;
0771 fNext = fZap->next;
0772 fNext->prev = fPrev;
0773 fPrev->next = fNext;
0774
0775 memFree( fZap );
0776 }
0777
0778
0779 /* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
0780 * and no loops (what we usually call a "face").
0781 */
0782 inline GLUmesh *__gl_meshNewMesh( void )
0783 {
0784 GLUvertex *v;
0785 GLUface *f;
0786 GLUhalfEdge *e;
0787 GLUhalfEdge *eSym;
0788 GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
0789 if (mesh == NULL) {
0790 return NULL;
0791 }
0792
0793 v = &mesh->vHead;
0794 f = &mesh->fHead;
0795 e = &mesh->eHead;
0796 eSym = &mesh->eHeadSym;
0797
0798 v->next = v->prev = v;
0799 v->anEdge = NULL;
0800 v->data = NULL;
0801
0802 f->next = f->prev = f;
0803 f->anEdge = NULL;
0804 f->data = NULL;
0805 f->trail = NULL;
0806 f->marked = TOOLS_GLU_FALSE;
0807 f->inside = TOOLS_GLU_FALSE;
0808
0809 e->next = e;
0810 e->Sym = eSym;
0811 e->Onext = NULL;
0812 e->Lnext = NULL;
0813 e->Org = NULL;
0814 e->Lface = NULL;
0815 e->winding = 0;
0816 e->activeRegion = NULL;
0817
0818 eSym->next = eSym;
0819 eSym->Sym = e;
0820 eSym->Onext = NULL;
0821 eSym->Lnext = NULL;
0822 eSym->Org = NULL;
0823 eSym->Lface = NULL;
0824 eSym->winding = 0;
0825 eSym->activeRegion = NULL;
0826
0827 return mesh;
0828 }
0829
0830
0831 /* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
0832 * both meshes, and returns the new mesh (the old meshes are destroyed).
0833 */
0834 inline GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
0835 {
0836 GLUface *f1 = &mesh1->fHead;
0837 GLUvertex *v1 = &mesh1->vHead;
0838 GLUhalfEdge *e1 = &mesh1->eHead;
0839 GLUface *f2 = &mesh2->fHead;
0840 GLUvertex *v2 = &mesh2->vHead;
0841 GLUhalfEdge *e2 = &mesh2->eHead;
0842
0843 /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
0844 if( f2->next != f2 ) {
0845 f1->prev->next = f2->next;
0846 f2->next->prev = f1->prev;
0847 f2->prev->next = f1;
0848 f1->prev = f2->prev;
0849 }
0850
0851 if( v2->next != v2 ) {
0852 v1->prev->next = v2->next;
0853 v2->next->prev = v1->prev;
0854 v2->prev->next = v1;
0855 v1->prev = v2->prev;
0856 }
0857
0858 if( e2->next != e2 ) {
0859 e1->Sym->next->Sym->next = e2->next;
0860 e2->next->Sym->next = e1->Sym->next;
0861 e2->Sym->next->Sym->next = e1;
0862 e1->Sym->next = e2->Sym->next;
0863 }
0864
0865 memFree( mesh2 );
0866 return mesh1;
0867 }
0868
0869
0870 #ifdef DELETE_BY_ZAPPING
0871
0872 /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
0873 */
0874 inline void __gl_meshDeleteMesh( GLUmesh *mesh )
0875 {
0876 GLUface *fHead = &mesh->fHead;
0877
0878 while( fHead->next != fHead ) {
0879 __gl_meshZapFace( fHead->next );
0880 }
0881 assert( mesh->vHead.next == &mesh->vHead );
0882
0883 memFree( mesh );
0884 }
0885
0886 #else
0887
0888 /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
0889 */
0890 inline void __gl_meshDeleteMesh( GLUmesh *mesh )
0891 {
0892 GLUface *f, *fNext;
0893 GLUvertex *v, *vNext;
0894 GLUhalfEdge *e, *eNext;
0895
0896 for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
0897 fNext = f->next;
0898 memFree( f );
0899 }
0900
0901 for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
0902 vNext = v->next;
0903 memFree( v );
0904 }
0905
0906 for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
0907 /* One call frees both e and e->Sym (see EdgePair above) */
0908 eNext = e->next;
0909 memFree( e );
0910 }
0911
0912 memFree( mesh );
0913 }
0914
0915 #endif
0916
0917 inline void __gl_meshCheckMesh( GLUmesh *mesh )
0918 {
0919 GLUface *fHead = &mesh->fHead;
0920 GLUvertex *vHead = &mesh->vHead;
0921 GLUhalfEdge *eHead = &mesh->eHead;
0922 GLUface *f, *fPrev;
0923 GLUvertex *v, *vPrev;
0924 GLUhalfEdge *e, *ePrev;
0925
0926 fPrev = fHead;
0927 for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
0928 assert( f->prev == fPrev );
0929 e = f->anEdge;
0930 do {
0931 assert( e->Sym != e );
0932 assert( e->Sym->Sym == e );
0933 assert( e->Lnext->Onext->Sym == e );
0934 assert( e->Onext->Sym->Lnext == e );
0935 assert( e->Lface == f );
0936 e = e->Lnext;
0937 } while( e != f->anEdge );
0938 }
0939 assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
0940
0941 vPrev = vHead;
0942 for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
0943 assert( v->prev == vPrev );
0944 e = v->anEdge;
0945 do {
0946 assert( e->Sym != e );
0947 assert( e->Sym->Sym == e );
0948 assert( e->Lnext->Onext->Sym == e );
0949 assert( e->Onext->Sym->Lnext == e );
0950 assert( e->Org == v );
0951 e = e->Onext;
0952 } while( e != v->anEdge );
0953 }
0954 assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
0955
0956 ePrev = eHead;
0957 for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
0958 assert( e->Sym->next == ePrev->Sym );
0959 assert( e->Sym != e );
0960 assert( e->Sym->Sym == e );
0961 assert( e->Org != NULL );
0962 assert( e->Dst != NULL );
0963 assert( e->Lnext->Onext->Sym == e );
0964 assert( e->Onext->Sym->Lnext == e );
0965 }
0966 assert( e->Sym->next == ePrev->Sym
0967 && e->Sym == &mesh->eHeadSym
0968 && e->Sym->Sym == e
0969 && e->Org == NULL && e->Dst == NULL
0970 && e->Lface == NULL && e->Rface == NULL );
0971 }
0972
0973 #endif