| 1 | /* $Id: mesh.c,v 1.1 2000-02-09 08:47:34 jeroen Exp $ */
|
|---|
| 2 | /*
|
|---|
| 3 | ** License Applicability. Except to the extent portions of this file are
|
|---|
| 4 | ** made subject to an alternative license as permitted in the SGI Free
|
|---|
| 5 | ** Software License B, Version 1.0 (the "License"), the contents of this
|
|---|
| 6 | ** file are subject only to the provisions of the License. You may not use
|
|---|
| 7 | ** this file except in compliance with the License. You may obtain a copy
|
|---|
| 8 | ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
|
|---|
| 9 | ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
|
|---|
| 10 | **
|
|---|
| 11 | ** http://oss.sgi.com/projects/FreeB
|
|---|
| 12 | **
|
|---|
| 13 | ** Note that, as provided in the License, the Software is distributed on an
|
|---|
| 14 | ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
|
|---|
| 15 | ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
|
|---|
| 16 | ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
|
|---|
| 17 | ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
|
|---|
| 18 | **
|
|---|
| 19 | ** Original Code. The Original Code is: OpenGL Sample Implementation,
|
|---|
| 20 | ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
|
|---|
| 21 | ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
|
|---|
| 22 | ** Copyright in any portions created by third parties is as indicated
|
|---|
| 23 | ** elsewhere herein. All Rights Reserved.
|
|---|
| 24 | **
|
|---|
| 25 | ** Additional Notice Provisions: The application programming interfaces
|
|---|
| 26 | ** established by SGI in conjunction with the Original Code are The
|
|---|
| 27 | ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
|
|---|
| 28 | ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
|
|---|
| 29 | ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
|
|---|
| 30 | ** Window System(R) (Version 1.3), released October 19, 1998. This software
|
|---|
| 31 | ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
|
|---|
| 32 | ** published by SGI, but has not been independently verified as being
|
|---|
| 33 | ** compliant with the OpenGL(R) version 1.2.1 Specification.
|
|---|
| 34 | **
|
|---|
| 35 | */
|
|---|
| 36 | /*
|
|---|
| 37 | ** Author: Eric Veach, July 1994.
|
|---|
| 38 | **
|
|---|
| 39 | ** $Date: 2000-02-09 08:47:34 $ $Revision: 1.1 $
|
|---|
| 40 | ** $Header: /home/ktk/tmp/odin/2007/netlabs.cvs/odin32/src/opengl/glu/tess/mesh.c,v 1.1 2000-02-09 08:47:34 jeroen Exp $
|
|---|
| 41 | */
|
|---|
| 42 |
|
|---|
| 43 | #include "gluos.h"
|
|---|
| 44 | #include <stddef.h>
|
|---|
| 45 | #include <assert.h>
|
|---|
| 46 | #include "mesh.h"
|
|---|
| 47 | #include "memalloc.h"
|
|---|
| 48 |
|
|---|
| 49 | #define TRUE 1
|
|---|
| 50 | #define FALSE 0
|
|---|
| 51 |
|
|---|
| 52 | static GLUvertex *allocVertex()
|
|---|
| 53 | {
|
|---|
| 54 | return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
|
|---|
| 55 | }
|
|---|
| 56 |
|
|---|
| 57 | static GLUface *allocFace()
|
|---|
| 58 | {
|
|---|
| 59 | return (GLUface *)memAlloc( sizeof( GLUface ));
|
|---|
| 60 | }
|
|---|
| 61 |
|
|---|
| 62 | /************************ Utility Routines ************************/
|
|---|
| 63 |
|
|---|
| 64 | /* Allocate and free half-edges in pairs for efficiency.
|
|---|
| 65 | * The *only* place that should use this fact is allocation/free.
|
|---|
| 66 | */
|
|---|
| 67 | typedef struct { GLUhalfEdge e, eSym; } EdgePair;
|
|---|
| 68 |
|
|---|
| 69 | /* MakeEdge creates a new pair of half-edges which form their own loop.
|
|---|
| 70 | * No vertex or face structures are allocated, but these must be assigned
|
|---|
| 71 | * before the current edge operation is completed.
|
|---|
| 72 | */
|
|---|
| 73 | static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
|
|---|
| 74 | {
|
|---|
| 75 | GLUhalfEdge *e;
|
|---|
| 76 | GLUhalfEdge *eSym;
|
|---|
| 77 | GLUhalfEdge *ePrev;
|
|---|
| 78 | EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
|
|---|
| 79 | if (pair == NULL) return NULL;
|
|---|
| 80 |
|
|---|
| 81 | e = &pair->e;
|
|---|
| 82 | eSym = &pair->eSym;
|
|---|
| 83 |
|
|---|
| 84 | /* Make sure eNext points to the first edge of the edge pair */
|
|---|
| 85 | if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
|
|---|
| 86 |
|
|---|
| 87 | /* Insert in circular doubly-linked list before eNext.
|
|---|
| 88 | * Note that the prev pointer is stored in Sym->next.
|
|---|
| 89 | */
|
|---|
| 90 | ePrev = eNext->Sym->next;
|
|---|
| 91 | eSym->next = ePrev;
|
|---|
| 92 | ePrev->Sym->next = e;
|
|---|
| 93 | e->next = eNext;
|
|---|
| 94 | eNext->Sym->next = eSym;
|
|---|
| 95 |
|
|---|
| 96 | e->Sym = eSym;
|
|---|
| 97 | e->Onext = e;
|
|---|
| 98 | e->Lnext = eSym;
|
|---|
| 99 | e->Org = NULL;
|
|---|
| 100 | e->Lface = NULL;
|
|---|
| 101 | e->winding = 0;
|
|---|
| 102 | e->activeRegion = NULL;
|
|---|
| 103 |
|
|---|
| 104 | eSym->Sym = e;
|
|---|
| 105 | eSym->Onext = eSym;
|
|---|
| 106 | eSym->Lnext = e;
|
|---|
| 107 | eSym->Org = NULL;
|
|---|
| 108 | eSym->Lface = NULL;
|
|---|
| 109 | eSym->winding = 0;
|
|---|
| 110 | eSym->activeRegion = NULL;
|
|---|
| 111 |
|
|---|
| 112 | return e;
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | /* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
|
|---|
| 116 | * CS348a notes (see mesh.h). Basically it modifies the mesh so that
|
|---|
| 117 | * a->Onext and b->Onext are exchanged. This can have various effects
|
|---|
| 118 | * depending on whether a and b belong to different face or vertex rings.
|
|---|
| 119 | * For more explanation see __gl_meshSplice() below.
|
|---|
| 120 | */
|
|---|
| 121 | static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
|
|---|
| 122 | {
|
|---|
| 123 | GLUhalfEdge *aOnext = a->Onext;
|
|---|
| 124 | GLUhalfEdge *bOnext = b->Onext;
|
|---|
| 125 |
|
|---|
| 126 | aOnext->Sym->Lnext = b;
|
|---|
| 127 | bOnext->Sym->Lnext = a;
|
|---|
| 128 | a->Onext = bOnext;
|
|---|
| 129 | b->Onext = aOnext;
|
|---|
| 130 | }
|
|---|
| 131 |
|
|---|
| 132 | /* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
|
|---|
| 133 | * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
|
|---|
| 134 | * a place to insert the new vertex in the global vertex list. We insert
|
|---|
| 135 | * the new vertex *before* vNext so that algorithms which walk the vertex
|
|---|
| 136 | * list will not see the newly created vertices.
|
|---|
| 137 | */
|
|---|
| 138 | static void MakeVertex( GLUvertex *newVertex,
|
|---|
| 139 | GLUhalfEdge *eOrig, GLUvertex *vNext )
|
|---|
| 140 | {
|
|---|
| 141 | GLUhalfEdge *e;
|
|---|
| 142 | GLUvertex *vPrev;
|
|---|
| 143 | GLUvertex *vNew = newVertex;
|
|---|
| 144 |
|
|---|
| 145 | assert(vNew != NULL);
|
|---|
| 146 |
|
|---|
| 147 | /* insert in circular doubly-linked list before vNext */
|
|---|
| 148 | vPrev = vNext->prev;
|
|---|
| 149 | vNew->prev = vPrev;
|
|---|
| 150 | vPrev->next = vNew;
|
|---|
| 151 | vNew->next = vNext;
|
|---|
| 152 | vNext->prev = vNew;
|
|---|
| 153 |
|
|---|
| 154 | vNew->anEdge = eOrig;
|
|---|
| 155 | vNew->data = NULL;
|
|---|
| 156 | /* leave coords, s, t undefined */
|
|---|
| 157 |
|
|---|
| 158 | /* fix other edges on this vertex loop */
|
|---|
| 159 | e = eOrig;
|
|---|
| 160 | do {
|
|---|
| 161 | e->Org = vNew;
|
|---|
| 162 | e = e->Onext;
|
|---|
| 163 | } while( e != eOrig );
|
|---|
| 164 | }
|
|---|
| 165 |
|
|---|
| 166 | /* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
|
|---|
| 167 | * face of all edges in the face loop to which eOrig belongs. "fNext" gives
|
|---|
| 168 | * a place to insert the new face in the global face list. We insert
|
|---|
| 169 | * the new face *before* fNext so that algorithms which walk the face
|
|---|
| 170 | * list will not see the newly created faces.
|
|---|
| 171 | */
|
|---|
| 172 | static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
|
|---|
| 173 | {
|
|---|
| 174 | GLUhalfEdge *e;
|
|---|
| 175 | GLUface *fPrev;
|
|---|
| 176 | GLUface *fNew = newFace;
|
|---|
| 177 |
|
|---|
| 178 | assert(fNew != NULL);
|
|---|
| 179 |
|
|---|
| 180 | /* insert in circular doubly-linked list before fNext */
|
|---|
| 181 | fPrev = fNext->prev;
|
|---|
| 182 | fNew->prev = fPrev;
|
|---|
| 183 | fPrev->next = fNew;
|
|---|
| 184 | fNew->next = fNext;
|
|---|
| 185 | fNext->prev = fNew;
|
|---|
| 186 |
|
|---|
| 187 | fNew->anEdge = eOrig;
|
|---|
| 188 | fNew->data = NULL;
|
|---|
| 189 | fNew->trail = NULL;
|
|---|
| 190 | fNew->marked = FALSE;
|
|---|
| 191 |
|
|---|
| 192 | /* The new face is marked "inside" if the old one was. This is a
|
|---|
| 193 | * convenience for the common case where a face has been split in two.
|
|---|
| 194 | */
|
|---|
| 195 | fNew->inside = fNext->inside;
|
|---|
| 196 |
|
|---|
| 197 | /* fix other edges on this face loop */
|
|---|
| 198 | e = eOrig;
|
|---|
| 199 | do {
|
|---|
| 200 | e->Lface = fNew;
|
|---|
| 201 | e = e->Lnext;
|
|---|
| 202 | } while( e != eOrig );
|
|---|
| 203 | }
|
|---|
| 204 |
|
|---|
| 205 | /* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
|
|---|
| 206 | * and removes from the global edge list.
|
|---|
| 207 | */
|
|---|
| 208 | static void KillEdge( GLUhalfEdge *eDel )
|
|---|
| 209 | {
|
|---|
| 210 | GLUhalfEdge *ePrev, *eNext;
|
|---|
| 211 |
|
|---|
| 212 | /* Half-edges are allocated in pairs, see EdgePair above */
|
|---|
| 213 | if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
|
|---|
| 214 |
|
|---|
| 215 | /* delete from circular doubly-linked list */
|
|---|
| 216 | eNext = eDel->next;
|
|---|
| 217 | ePrev = eDel->Sym->next;
|
|---|
| 218 | eNext->Sym->next = ePrev;
|
|---|
| 219 | ePrev->Sym->next = eNext;
|
|---|
| 220 |
|
|---|
| 221 | memFree( eDel );
|
|---|
| 222 | }
|
|---|
| 223 |
|
|---|
| 224 |
|
|---|
| 225 | /* KillVertex( vDel ) destroys a vertex and removes it from the global
|
|---|
| 226 | * vertex list. It updates the vertex loop to point to a given new vertex.
|
|---|
| 227 | */
|
|---|
| 228 | static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
|
|---|
| 229 | {
|
|---|
| 230 | GLUhalfEdge *e, *eStart = vDel->anEdge;
|
|---|
| 231 | GLUvertex *vPrev, *vNext;
|
|---|
| 232 |
|
|---|
| 233 | /* change the origin of all affected edges */
|
|---|
| 234 | e = eStart;
|
|---|
| 235 | do {
|
|---|
| 236 | e->Org = newOrg;
|
|---|
| 237 | e = e->Onext;
|
|---|
| 238 | } while( e != eStart );
|
|---|
| 239 |
|
|---|
| 240 | /* delete from circular doubly-linked list */
|
|---|
| 241 | vPrev = vDel->prev;
|
|---|
| 242 | vNext = vDel->next;
|
|---|
| 243 | vNext->prev = vPrev;
|
|---|
| 244 | vPrev->next = vNext;
|
|---|
| 245 |
|
|---|
| 246 | memFree( vDel );
|
|---|
| 247 | }
|
|---|
| 248 |
|
|---|
| 249 | /* KillFace( fDel ) destroys a face and removes it from the global face
|
|---|
| 250 | * list. It updates the face loop to point to a given new face.
|
|---|
| 251 | */
|
|---|
| 252 | static void KillFace( GLUface *fDel, GLUface *newLface )
|
|---|
| 253 | {
|
|---|
| 254 | GLUhalfEdge *e, *eStart = fDel->anEdge;
|
|---|
| 255 | GLUface *fPrev, *fNext;
|
|---|
| 256 |
|
|---|
| 257 | /* change the left face of all affected edges */
|
|---|
| 258 | e = eStart;
|
|---|
| 259 | do {
|
|---|
| 260 | e->Lface = newLface;
|
|---|
| 261 | e = e->Lnext;
|
|---|
| 262 | } while( e != eStart );
|
|---|
| 263 |
|
|---|
| 264 | /* delete from circular doubly-linked list */
|
|---|
| 265 | fPrev = fDel->prev;
|
|---|
| 266 | fNext = fDel->next;
|
|---|
| 267 | fNext->prev = fPrev;
|
|---|
| 268 | fPrev->next = fNext;
|
|---|
| 269 |
|
|---|
| 270 | memFree( fDel );
|
|---|
| 271 | }
|
|---|
| 272 |
|
|---|
| 273 |
|
|---|
| 274 | /****************** Basic Edge Operations **********************/
|
|---|
| 275 |
|
|---|
| 276 | /* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
|
|---|
| 277 | * The loop consists of the two new half-edges.
|
|---|
| 278 | */
|
|---|
| 279 | GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
|
|---|
| 280 | {
|
|---|
| 281 | GLUvertex *newVertex1= allocVertex();
|
|---|
| 282 | GLUvertex *newVertex2= allocVertex();
|
|---|
| 283 | GLUface *newFace= allocFace();
|
|---|
| 284 | GLUhalfEdge *e;
|
|---|
| 285 |
|
|---|
| 286 | /* if any one is null then all get freed */
|
|---|
| 287 | if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
|
|---|
| 288 | if (newVertex1 != NULL) memFree(newVertex1);
|
|---|
| 289 | if (newVertex2 != NULL) memFree(newVertex2);
|
|---|
| 290 | if (newFace != NULL) memFree(newFace);
|
|---|
| 291 | return NULL;
|
|---|
| 292 | }
|
|---|
| 293 |
|
|---|
| 294 | e = MakeEdge( &mesh->eHead );
|
|---|
| 295 | if (e == NULL) return NULL;
|
|---|
| 296 |
|
|---|
| 297 | MakeVertex( newVertex1, e, &mesh->vHead );
|
|---|
| 298 | MakeVertex( newVertex2, e->Sym, &mesh->vHead );
|
|---|
| 299 | MakeFace( newFace, e, &mesh->fHead );
|
|---|
| 300 | return e;
|
|---|
| 301 | }
|
|---|
| 302 |
|
|---|
| 303 |
|
|---|
| 304 | /* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
|
|---|
| 305 | * mesh connectivity and topology. It changes the mesh so that
|
|---|
| 306 | * eOrg->Onext <- OLD( eDst->Onext )
|
|---|
| 307 | * eDst->Onext <- OLD( eOrg->Onext )
|
|---|
| 308 | * where OLD(...) means the value before the meshSplice operation.
|
|---|
| 309 | *
|
|---|
| 310 | * This can have two effects on the vertex structure:
|
|---|
| 311 | * - if eOrg->Org != eDst->Org, the two vertices are merged together
|
|---|
| 312 | * - if eOrg->Org == eDst->Org, the origin is split into two vertices
|
|---|
| 313 | * In both cases, eDst->Org is changed and eOrg->Org is untouched.
|
|---|
| 314 | *
|
|---|
| 315 | * Similarly (and independently) for the face structure,
|
|---|
| 316 | * - if eOrg->Lface == eDst->Lface, one loop is split into two
|
|---|
| 317 | * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
|
|---|
| 318 | * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
|
|---|
| 319 | *
|
|---|
| 320 | * Some special cases:
|
|---|
| 321 | * If eDst == eOrg, the operation has no effect.
|
|---|
| 322 | * If eDst == eOrg->Lnext, the new face will have a single edge.
|
|---|
| 323 | * If eDst == eOrg->Lprev, the old face will have a single edge.
|
|---|
| 324 | * If eDst == eOrg->Onext, the new vertex will have a single edge.
|
|---|
| 325 | * If eDst == eOrg->Oprev, the old vertex will have a single edge.
|
|---|
| 326 | */
|
|---|
| 327 | int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
|
|---|
| 328 | {
|
|---|
| 329 | int joiningLoops = FALSE;
|
|---|
| 330 | int joiningVertices = FALSE;
|
|---|
| 331 |
|
|---|
| 332 | if( eOrg == eDst ) return 1;
|
|---|
| 333 |
|
|---|
| 334 | if( eDst->Org != eOrg->Org ) {
|
|---|
| 335 | /* We are merging two disjoint vertices -- destroy eDst->Org */
|
|---|
| 336 | joiningVertices = TRUE;
|
|---|
| 337 | KillVertex( eDst->Org, eOrg->Org );
|
|---|
| 338 | }
|
|---|
| 339 | if( eDst->Lface != eOrg->Lface ) {
|
|---|
| 340 | /* We are connecting two disjoint loops -- destroy eDst->Lface */
|
|---|
| 341 | joiningLoops = TRUE;
|
|---|
| 342 | KillFace( eDst->Lface, eOrg->Lface );
|
|---|
| 343 | }
|
|---|
| 344 |
|
|---|
| 345 | /* Change the edge structure */
|
|---|
| 346 | Splice( eDst, eOrg );
|
|---|
| 347 |
|
|---|
| 348 | if( ! joiningVertices ) {
|
|---|
| 349 | GLUvertex *newVertex= allocVertex();
|
|---|
| 350 | if (newVertex == NULL) return 0;
|
|---|
| 351 |
|
|---|
| 352 | /* We split one vertex into two -- the new vertex is eDst->Org.
|
|---|
| 353 | * Make sure the old vertex points to a valid half-edge.
|
|---|
| 354 | */
|
|---|
| 355 | MakeVertex( newVertex, eDst, eOrg->Org );
|
|---|
| 356 | eOrg->Org->anEdge = eOrg;
|
|---|
| 357 | }
|
|---|
| 358 | if( ! joiningLoops ) {
|
|---|
| 359 | GLUface *newFace= allocFace();
|
|---|
| 360 | if (newFace == NULL) return 0;
|
|---|
| 361 |
|
|---|
| 362 | /* We split one loop into two -- the new loop is eDst->Lface.
|
|---|
| 363 | * Make sure the old face points to a valid half-edge.
|
|---|
| 364 | */
|
|---|
| 365 | MakeFace( newFace, eDst, eOrg->Lface );
|
|---|
| 366 | eOrg->Lface->anEdge = eOrg;
|
|---|
| 367 | }
|
|---|
| 368 |
|
|---|
| 369 | return 1;
|
|---|
| 370 | }
|
|---|
| 371 |
|
|---|
| 372 |
|
|---|
| 373 | /* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
|
|---|
| 374 | * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
|
|---|
| 375 | * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
|
|---|
| 376 | * the newly created loop will contain eDel->Dst. If the deletion of eDel
|
|---|
| 377 | * would create isolated vertices, those are deleted as well.
|
|---|
| 378 | *
|
|---|
| 379 | * This function could be implemented as two calls to __gl_meshSplice
|
|---|
| 380 | * plus a few calls to memFree, but this would allocate and delete
|
|---|
| 381 | * unnecessary vertices and faces.
|
|---|
| 382 | */
|
|---|
| 383 | int __gl_meshDelete( GLUhalfEdge *eDel )
|
|---|
| 384 | {
|
|---|
| 385 | GLUhalfEdge *eDelSym = eDel->Sym;
|
|---|
| 386 | int joiningLoops = FALSE;
|
|---|
| 387 |
|
|---|
| 388 | /* First step: disconnect the origin vertex eDel->Org. We make all
|
|---|
| 389 | * changes to get a consistent mesh in this "intermediate" state.
|
|---|
| 390 | */
|
|---|
| 391 | if( eDel->Lface != eDel->Rface ) {
|
|---|
| 392 | /* We are joining two loops into one -- remove the left face */
|
|---|
| 393 | joiningLoops = TRUE;
|
|---|
| 394 | KillFace( eDel->Lface, eDel->Rface );
|
|---|
| 395 | }
|
|---|
| 396 |
|
|---|
| 397 | if( eDel->Onext == eDel ) {
|
|---|
| 398 | KillVertex( eDel->Org, NULL );
|
|---|
| 399 | } else {
|
|---|
| 400 | /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
|
|---|
| 401 | eDel->Rface->anEdge = eDel->Oprev;
|
|---|
| 402 | eDel->Org->anEdge = eDel->Onext;
|
|---|
| 403 |
|
|---|
| 404 | Splice( eDel, eDel->Oprev );
|
|---|
| 405 | if( ! joiningLoops ) {
|
|---|
| 406 | GLUface *newFace= allocFace();
|
|---|
| 407 | if (newFace == NULL) return 0;
|
|---|
| 408 |
|
|---|
| 409 | /* We are splitting one loop into two -- create a new loop for eDel. */
|
|---|
| 410 | MakeFace( newFace, eDel, eDel->Lface );
|
|---|
| 411 | }
|
|---|
| 412 | }
|
|---|
| 413 |
|
|---|
| 414 | /* Claim: the mesh is now in a consistent state, except that eDel->Org
|
|---|
| 415 | * may have been deleted. Now we disconnect eDel->Dst.
|
|---|
| 416 | */
|
|---|
| 417 | if( eDelSym->Onext == eDelSym ) {
|
|---|
| 418 | KillVertex( eDelSym->Org, NULL );
|
|---|
| 419 | KillFace( eDelSym->Lface, NULL );
|
|---|
| 420 | } else {
|
|---|
| 421 | /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
|
|---|
| 422 | eDel->Lface->anEdge = eDelSym->Oprev;
|
|---|
| 423 | eDelSym->Org->anEdge = eDelSym->Onext;
|
|---|
| 424 | Splice( eDelSym, eDelSym->Oprev );
|
|---|
| 425 | }
|
|---|
| 426 |
|
|---|
| 427 | /* Any isolated vertices or faces have already been freed. */
|
|---|
| 428 | KillEdge( eDel );
|
|---|
| 429 |
|
|---|
| 430 | return 1;
|
|---|
| 431 | }
|
|---|
| 432 |
|
|---|
| 433 |
|
|---|
| 434 | /******************** Other Edge Operations **********************/
|
|---|
| 435 |
|
|---|
| 436 | /* All these routines can be implemented with the basic edge
|
|---|
| 437 | * operations above. They are provided for convenience and efficiency.
|
|---|
| 438 | */
|
|---|
| 439 |
|
|---|
| 440 |
|
|---|
| 441 | /* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
|
|---|
| 442 | * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
|
|---|
| 443 | * eOrg and eNew will have the same left face.
|
|---|
| 444 | */
|
|---|
| 445 | GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
|
|---|
| 446 | {
|
|---|
| 447 | GLUhalfEdge *eNewSym;
|
|---|
| 448 | GLUhalfEdge *eNew = MakeEdge( eOrg );
|
|---|
| 449 | if (eNew == NULL) return NULL;
|
|---|
| 450 |
|
|---|
| 451 | eNewSym = eNew->Sym;
|
|---|
| 452 |
|
|---|
| 453 | /* Connect the new edge appropriately */
|
|---|
| 454 | Splice( eNew, eOrg->Lnext );
|
|---|
| 455 |
|
|---|
| 456 | /* Set the vertex and face information */
|
|---|
| 457 | eNew->Org = eOrg->Dst;
|
|---|
| 458 | {
|
|---|
| 459 | GLUvertex *newVertex= allocVertex();
|
|---|
| 460 | if (newVertex == NULL) return NULL;
|
|---|
| 461 |
|
|---|
| 462 | MakeVertex( newVertex, eNewSym, eNew->Org );
|
|---|
| 463 | }
|
|---|
| 464 | eNew->Lface = eNewSym->Lface = eOrg->Lface;
|
|---|
| 465 |
|
|---|
| 466 | return eNew;
|
|---|
| 467 | }
|
|---|
| 468 |
|
|---|
| 469 |
|
|---|
| 470 | /* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
|
|---|
| 471 | * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
|
|---|
| 472 | * eOrg and eNew will have the same left face.
|
|---|
| 473 | */
|
|---|
| 474 | GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
|
|---|
| 475 | {
|
|---|
| 476 | GLUhalfEdge *eNew;
|
|---|
| 477 | GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
|
|---|
| 478 | if (tempHalfEdge == NULL) return NULL;
|
|---|
| 479 |
|
|---|
| 480 | eNew = tempHalfEdge->Sym;
|
|---|
| 481 |
|
|---|
| 482 | /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
|
|---|
| 483 | Splice( eOrg->Sym, eOrg->Sym->Oprev );
|
|---|
| 484 | Splice( eOrg->Sym, eNew );
|
|---|
| 485 |
|
|---|
| 486 | /* Set the vertex and face information */
|
|---|
| 487 | eOrg->Dst = eNew->Org;
|
|---|
| 488 | eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
|
|---|
| 489 | eNew->Rface = eOrg->Rface;
|
|---|
| 490 | eNew->winding = eOrg->winding; /* copy old winding information */
|
|---|
| 491 | eNew->Sym->winding = eOrg->Sym->winding;
|
|---|
| 492 |
|
|---|
| 493 | return eNew;
|
|---|
| 494 | }
|
|---|
| 495 |
|
|---|
| 496 |
|
|---|
| 497 | /* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
|
|---|
| 498 | * to eDst->Org, and returns the corresponding half-edge eNew.
|
|---|
| 499 | * If eOrg->Lface == eDst->Lface, this splits one loop into two,
|
|---|
| 500 | * and the newly created loop is eNew->Lface. Otherwise, two disjoint
|
|---|
| 501 | * loops are merged into one, and the loop eDst->Lface is destroyed.
|
|---|
| 502 | *
|
|---|
| 503 | * If (eOrg == eDst), the new face will have only two edges.
|
|---|
| 504 | * If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
|
|---|
| 505 | * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
|
|---|
| 506 | */
|
|---|
| 507 | GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
|
|---|
| 508 | {
|
|---|
| 509 | GLUhalfEdge *eNewSym;
|
|---|
| 510 | int joiningLoops = FALSE;
|
|---|
| 511 | GLUhalfEdge *eNew = MakeEdge( eOrg );
|
|---|
| 512 | if (eNew == NULL) return NULL;
|
|---|
| 513 |
|
|---|
| 514 | eNewSym = eNew->Sym;
|
|---|
| 515 |
|
|---|
| 516 | if( eDst->Lface != eOrg->Lface ) {
|
|---|
| 517 | /* We are connecting two disjoint loops -- destroy eDst->Lface */
|
|---|
| 518 | joiningLoops = TRUE;
|
|---|
| 519 | KillFace( eDst->Lface, eOrg->Lface );
|
|---|
| 520 | }
|
|---|
| 521 |
|
|---|
| 522 | /* Connect the new edge appropriately */
|
|---|
| 523 | Splice( eNew, eOrg->Lnext );
|
|---|
| 524 | Splice( eNewSym, eDst );
|
|---|
| 525 |
|
|---|
| 526 | /* Set the vertex and face information */
|
|---|
| 527 | eNew->Org = eOrg->Dst;
|
|---|
| 528 | eNewSym->Org = eDst->Org;
|
|---|
| 529 | eNew->Lface = eNewSym->Lface = eOrg->Lface;
|
|---|
| 530 |
|
|---|
| 531 | /* Make sure the old face points to a valid half-edge */
|
|---|
| 532 | eOrg->Lface->anEdge = eNewSym;
|
|---|
| 533 |
|
|---|
| 534 | if( ! joiningLoops ) {
|
|---|
| 535 | GLUface *newFace= allocFace();
|
|---|
| 536 | if (newFace == NULL) return NULL;
|
|---|
| 537 |
|
|---|
| 538 | /* We split one loop into two -- the new loop is eNew->Lface */
|
|---|
| 539 | MakeFace( newFace, eNew, eOrg->Lface );
|
|---|
| 540 | }
|
|---|
| 541 | return eNew;
|
|---|
| 542 | }
|
|---|
| 543 |
|
|---|
| 544 |
|
|---|
| 545 | /******************** Other Operations **********************/
|
|---|
| 546 |
|
|---|
| 547 | /* __gl_meshZapFace( fZap ) destroys a face and removes it from the
|
|---|
| 548 | * global face list. All edges of fZap will have a NULL pointer as their
|
|---|
| 549 | * left face. Any edges which also have a NULL pointer as their right face
|
|---|
| 550 | * are deleted entirely (along with any isolated vertices this produces).
|
|---|
| 551 | * An entire mesh can be deleted by zapping its faces, one at a time,
|
|---|
| 552 | * in any order. Zapped faces cannot be used in further mesh operations!
|
|---|
| 553 | */
|
|---|
| 554 | void __gl_meshZapFace( GLUface *fZap )
|
|---|
| 555 | {
|
|---|
| 556 | GLUhalfEdge *eStart = fZap->anEdge;
|
|---|
| 557 | GLUhalfEdge *e, *eNext, *eSym;
|
|---|
| 558 | GLUface *fPrev, *fNext;
|
|---|
| 559 |
|
|---|
| 560 | /* walk around face, deleting edges whose right face is also NULL */
|
|---|
| 561 | eNext = eStart->Lnext;
|
|---|
| 562 | do {
|
|---|
| 563 | e = eNext;
|
|---|
| 564 | eNext = e->Lnext;
|
|---|
| 565 |
|
|---|
| 566 | e->Lface = NULL;
|
|---|
| 567 | if( e->Rface == NULL ) {
|
|---|
| 568 | /* delete the edge -- see __gl_MeshDelete above */
|
|---|
| 569 |
|
|---|
| 570 | if( e->Onext == e ) {
|
|---|
| 571 | KillVertex( e->Org, NULL );
|
|---|
| 572 | } else {
|
|---|
| 573 | /* Make sure that e->Org points to a valid half-edge */
|
|---|
| 574 | e->Org->anEdge = e->Onext;
|
|---|
| 575 | Splice( e, e->Oprev );
|
|---|
| 576 | }
|
|---|
| 577 | eSym = e->Sym;
|
|---|
| 578 | if( eSym->Onext == eSym ) {
|
|---|
| 579 | KillVertex( eSym->Org, NULL );
|
|---|
| 580 | } else {
|
|---|
| 581 | /* Make sure that eSym->Org points to a valid half-edge */
|
|---|
| 582 | eSym->Org->anEdge = eSym->Onext;
|
|---|
| 583 | Splice( eSym, eSym->Oprev );
|
|---|
| 584 | }
|
|---|
| 585 | KillEdge( e );
|
|---|
| 586 | }
|
|---|
| 587 | } while( e != eStart );
|
|---|
| 588 |
|
|---|
| 589 | /* delete from circular doubly-linked list */
|
|---|
| 590 | fPrev = fZap->prev;
|
|---|
| 591 | fNext = fZap->next;
|
|---|
| 592 | fNext->prev = fPrev;
|
|---|
| 593 | fPrev->next = fNext;
|
|---|
| 594 |
|
|---|
| 595 | memFree( fZap );
|
|---|
| 596 | }
|
|---|
| 597 |
|
|---|
| 598 |
|
|---|
| 599 | /* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
|
|---|
| 600 | * and no loops (what we usually call a "face").
|
|---|
| 601 | */
|
|---|
| 602 | GLUmesh *__gl_meshNewMesh( void )
|
|---|
| 603 | {
|
|---|
| 604 | GLUvertex *v;
|
|---|
| 605 | GLUface *f;
|
|---|
| 606 | GLUhalfEdge *e;
|
|---|
| 607 | GLUhalfEdge *eSym;
|
|---|
| 608 | GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
|
|---|
| 609 | if (mesh == NULL) {
|
|---|
| 610 | return NULL;
|
|---|
| 611 | }
|
|---|
| 612 |
|
|---|
| 613 | v = &mesh->vHead;
|
|---|
| 614 | f = &mesh->fHead;
|
|---|
| 615 | e = &mesh->eHead;
|
|---|
| 616 | eSym = &mesh->eHeadSym;
|
|---|
| 617 |
|
|---|
| 618 | v->next = v->prev = v;
|
|---|
| 619 | v->anEdge = NULL;
|
|---|
| 620 | v->data = NULL;
|
|---|
| 621 |
|
|---|
| 622 | f->next = f->prev = f;
|
|---|
| 623 | f->anEdge = NULL;
|
|---|
| 624 | f->data = NULL;
|
|---|
| 625 | f->trail = NULL;
|
|---|
| 626 | f->marked = FALSE;
|
|---|
| 627 | f->inside = FALSE;
|
|---|
| 628 |
|
|---|
| 629 | e->next = e;
|
|---|
| 630 | e->Sym = eSym;
|
|---|
| 631 | e->Onext = NULL;
|
|---|
| 632 | e->Lnext = NULL;
|
|---|
| 633 | e->Org = NULL;
|
|---|
| 634 | e->Lface = NULL;
|
|---|
| 635 | e->winding = 0;
|
|---|
| 636 | e->activeRegion = NULL;
|
|---|
| 637 |
|
|---|
| 638 | eSym->next = eSym;
|
|---|
| 639 | eSym->Sym = e;
|
|---|
| 640 | eSym->Onext = NULL;
|
|---|
| 641 | eSym->Lnext = NULL;
|
|---|
| 642 | eSym->Org = NULL;
|
|---|
| 643 | eSym->Lface = NULL;
|
|---|
| 644 | eSym->winding = 0;
|
|---|
| 645 | eSym->activeRegion = NULL;
|
|---|
| 646 |
|
|---|
| 647 | return mesh;
|
|---|
| 648 | }
|
|---|
| 649 |
|
|---|
| 650 |
|
|---|
| 651 | /* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
|
|---|
| 652 | * both meshes, and returns the new mesh (the old meshes are destroyed).
|
|---|
| 653 | */
|
|---|
| 654 | GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
|
|---|
| 655 | {
|
|---|
| 656 | GLUface *f1 = &mesh1->fHead;
|
|---|
| 657 | GLUvertex *v1 = &mesh1->vHead;
|
|---|
| 658 | GLUhalfEdge *e1 = &mesh1->eHead;
|
|---|
| 659 | GLUface *f2 = &mesh2->fHead;
|
|---|
| 660 | GLUvertex *v2 = &mesh2->vHead;
|
|---|
| 661 | GLUhalfEdge *e2 = &mesh2->eHead;
|
|---|
| 662 |
|
|---|
| 663 | /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
|
|---|
| 664 | if( f2->next != f2 ) {
|
|---|
| 665 | f1->prev->next = f2->next;
|
|---|
| 666 | f2->next->prev = f1->prev;
|
|---|
| 667 | f2->prev->next = f1;
|
|---|
| 668 | f1->prev = f2->prev;
|
|---|
| 669 | }
|
|---|
| 670 |
|
|---|
| 671 | if( v2->next != v2 ) {
|
|---|
| 672 | v1->prev->next = v2->next;
|
|---|
| 673 | v2->next->prev = v1->prev;
|
|---|
| 674 | v2->prev->next = v1;
|
|---|
| 675 | v1->prev = v2->prev;
|
|---|
| 676 | }
|
|---|
| 677 |
|
|---|
| 678 | if( e2->next != e2 ) {
|
|---|
| 679 | e1->Sym->next->Sym->next = e2->next;
|
|---|
| 680 | e2->next->Sym->next = e1->Sym->next;
|
|---|
| 681 | e2->Sym->next->Sym->next = e1;
|
|---|
| 682 | e1->Sym->next = e2->Sym->next;
|
|---|
| 683 | }
|
|---|
| 684 |
|
|---|
| 685 | memFree( mesh2 );
|
|---|
| 686 | return mesh1;
|
|---|
| 687 | }
|
|---|
| 688 |
|
|---|
| 689 |
|
|---|
| 690 | #ifdef DELETE_BY_ZAPPING
|
|---|
| 691 |
|
|---|
| 692 | /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
|
|---|
| 693 | */
|
|---|
| 694 | void __gl_meshDeleteMesh( GLUmesh *mesh )
|
|---|
| 695 | {
|
|---|
| 696 | GLUface *fHead = &mesh->fHead;
|
|---|
| 697 |
|
|---|
| 698 | while( fHead->next != fHead ) {
|
|---|
| 699 | __gl_meshZapFace( fHead->next );
|
|---|
| 700 | }
|
|---|
| 701 | assert( mesh->vHead.next == &mesh->vHead );
|
|---|
| 702 |
|
|---|
| 703 | memFree( mesh );
|
|---|
| 704 | }
|
|---|
| 705 |
|
|---|
| 706 | #else
|
|---|
| 707 |
|
|---|
| 708 | /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
|
|---|
| 709 | */
|
|---|
| 710 | void __gl_meshDeleteMesh( GLUmesh *mesh )
|
|---|
| 711 | {
|
|---|
| 712 | GLUface *f, *fNext;
|
|---|
| 713 | GLUvertex *v, *vNext;
|
|---|
| 714 | GLUhalfEdge *e, *eNext;
|
|---|
| 715 |
|
|---|
| 716 | for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
|
|---|
| 717 | fNext = f->next;
|
|---|
| 718 | memFree( f );
|
|---|
| 719 | }
|
|---|
| 720 |
|
|---|
| 721 | for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
|
|---|
| 722 | vNext = v->next;
|
|---|
| 723 | memFree( v );
|
|---|
| 724 | }
|
|---|
| 725 |
|
|---|
| 726 | for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
|
|---|
| 727 | /* One call frees both e and e->Sym (see EdgePair above) */
|
|---|
| 728 | eNext = e->next;
|
|---|
| 729 | memFree( e );
|
|---|
| 730 | }
|
|---|
| 731 |
|
|---|
| 732 | memFree( mesh );
|
|---|
| 733 | }
|
|---|
| 734 |
|
|---|
| 735 | #endif
|
|---|
| 736 |
|
|---|
| 737 | #ifndef NDEBUG
|
|---|
| 738 |
|
|---|
| 739 | /* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
|
|---|
| 740 | */
|
|---|
| 741 | void __gl_meshCheckMesh( GLUmesh *mesh )
|
|---|
| 742 | {
|
|---|
| 743 | GLUface *fHead = &mesh->fHead;
|
|---|
| 744 | GLUvertex *vHead = &mesh->vHead;
|
|---|
| 745 | GLUhalfEdge *eHead = &mesh->eHead;
|
|---|
| 746 | GLUface *f, *fPrev;
|
|---|
| 747 | GLUvertex *v, *vPrev;
|
|---|
| 748 | GLUhalfEdge *e, *ePrev;
|
|---|
| 749 |
|
|---|
| 750 | fPrev = fHead;
|
|---|
| 751 | for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
|
|---|
| 752 | assert( f->prev == fPrev );
|
|---|
| 753 | e = f->anEdge;
|
|---|
| 754 | do {
|
|---|
| 755 | assert( e->Sym != e );
|
|---|
| 756 | assert( e->Sym->Sym == e );
|
|---|
| 757 | assert( e->Lnext->Onext->Sym == e );
|
|---|
| 758 | assert( e->Onext->Sym->Lnext == e );
|
|---|
| 759 | assert( e->Lface == f );
|
|---|
| 760 | e = e->Lnext;
|
|---|
| 761 | } while( e != f->anEdge );
|
|---|
| 762 | }
|
|---|
| 763 | assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
|
|---|
| 764 |
|
|---|
| 765 | vPrev = vHead;
|
|---|
| 766 | for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
|
|---|
| 767 | assert( v->prev == vPrev );
|
|---|
| 768 | e = v->anEdge;
|
|---|
| 769 | do {
|
|---|
| 770 | assert( e->Sym != e );
|
|---|
| 771 | assert( e->Sym->Sym == e );
|
|---|
| 772 | assert( e->Lnext->Onext->Sym == e );
|
|---|
| 773 | assert( e->Onext->Sym->Lnext == e );
|
|---|
| 774 | assert( e->Org == v );
|
|---|
| 775 | e = e->Onext;
|
|---|
| 776 | } while( e != v->anEdge );
|
|---|
| 777 | }
|
|---|
| 778 | assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
|
|---|
| 779 |
|
|---|
| 780 | ePrev = eHead;
|
|---|
| 781 | for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
|
|---|
| 782 | assert( e->Sym->next == ePrev->Sym );
|
|---|
| 783 | assert( e->Sym != e );
|
|---|
| 784 | assert( e->Sym->Sym == e );
|
|---|
| 785 | assert( e->Org != NULL );
|
|---|
| 786 | assert( e->Dst != NULL );
|
|---|
| 787 | assert( e->Lnext->Onext->Sym == e );
|
|---|
| 788 | assert( e->Onext->Sym->Lnext == e );
|
|---|
| 789 | }
|
|---|
| 790 | assert( e->Sym->next == ePrev->Sym
|
|---|
| 791 | && e->Sym == &mesh->eHeadSym
|
|---|
| 792 | && e->Sym->Sym == e
|
|---|
| 793 | && e->Org == NULL && e->Dst == NULL
|
|---|
| 794 | && e->Lface == NULL && e->Rface == NULL );
|
|---|
| 795 | }
|
|---|
| 796 |
|
|---|
| 797 | #endif
|
|---|