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
|
---|