Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

701 lines
19 KiB

  1. /*
  2. ** Copyright 1994, Silicon Graphics, Inc.
  3. ** All Rights Reserved.
  4. **
  5. ** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6. ** the contents of this file may not be disclosed to third parties, copied or
  7. ** duplicated in any form, in whole or in part, without the prior written
  8. ** permission of Silicon Graphics, Inc.
  9. **
  10. ** RESTRICTED RIGHTS LEGEND:
  11. ** Use, duplication or disclosure by the Government is subject to restrictions
  12. ** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13. ** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14. ** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15. ** rights reserved under the Copyright Laws of the United States.
  16. **
  17. ** Author: Eric Veach, July 1994.
  18. */
  19. #include <assert.h>
  20. #include "mesh.h"
  21. #include "memalloc.h"
  22. #define TRUE 1
  23. #define FALSE 0
  24. /************************ Utility Routines ************************/
  25. /* Allocate and free half-edges in pairs for efficiency.
  26. * The *only* place that should use this fact is allocation/free.
  27. */
  28. typedef struct { GLUhalfEdge e, eSym; } EdgePair;
  29. /* MakeEdge creates a new pair of half-edges which form their own loop.
  30. * No vertex or face structures are allocated, but these must be assigned
  31. * before the current edge operation is completed.
  32. */
  33. static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
  34. {
  35. EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
  36. GLUhalfEdge *e = &pair->e;
  37. GLUhalfEdge *eSym = &pair->eSym;
  38. GLUhalfEdge *ePrev;
  39. /* Make sure eNext points to the first edge of the edge pair */
  40. if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
  41. /* Insert in circular doubly-linked list before eNext.
  42. * Note that the prev pointer is stored in Sym->next.
  43. */
  44. ePrev = eNext->Sym->next;
  45. eSym->next = ePrev;
  46. ePrev->Sym->next = e;
  47. e->next = eNext;
  48. eNext->Sym->next = eSym;
  49. e->Sym = eSym;
  50. e->Onext = e;
  51. e->Lnext = eSym;
  52. e->Org = NULL;
  53. e->Lface = NULL;
  54. e->winding = 0;
  55. e->activeRegion = NULL;
  56. eSym->Sym = e;
  57. eSym->Onext = eSym;
  58. eSym->Lnext = e;
  59. eSym->Org = NULL;
  60. eSym->Lface = NULL;
  61. eSym->winding = 0;
  62. eSym->activeRegion = NULL;
  63. return e;
  64. }
  65. /* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
  66. * CS348a notes (see mesh.h). Basically it modifies the mesh so that
  67. * a->Onext and b->Onext are exchanged. This can have various effects
  68. * depending on whether a and b belong to different face or vertex rings.
  69. * For more explanation see __gl_meshSplice() below.
  70. */
  71. static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
  72. {
  73. GLUhalfEdge *aOnext = a->Onext;
  74. GLUhalfEdge *bOnext = b->Onext;
  75. aOnext->Sym->Lnext = b;
  76. bOnext->Sym->Lnext = a;
  77. a->Onext = bOnext;
  78. b->Onext = aOnext;
  79. }
  80. /* MakeVertex( eOrig, vNext ) creates a new vertex and makes it the origin
  81. * of all edges in the vertex loop to which eOrig belongs. "vNext" gives
  82. * a place to insert the new vertex in the global vertex list. We insert
  83. * the new vertex *before* vNext so that algorithms which walk the vertex
  84. * list will not see the newly created vertices.
  85. */
  86. static void MakeVertex( GLUhalfEdge *eOrig, GLUvertex *vNext )
  87. {
  88. GLUvertex *vNew = (GLUvertex *)memAlloc( sizeof( GLUvertex ));
  89. GLUhalfEdge *e;
  90. GLUvertex *vPrev;
  91. /* insert in circular doubly-linked list before vNext */
  92. vPrev = vNext->prev;
  93. vNew->prev = vPrev;
  94. vPrev->next = vNew;
  95. vNew->next = vNext;
  96. vNext->prev = vNew;
  97. vNew->anEdge = eOrig;
  98. vNew->data = NULL;
  99. /* leave coords, s, t undefined */
  100. /* fix other edges on this vertex loop */
  101. e = eOrig;
  102. do {
  103. e->Org = vNew;
  104. e = e->Onext;
  105. } while( e != eOrig );
  106. }
  107. /* MakeFace( eOrig, fNext ) creates a new face and makes it the left face
  108. * of all edges in the face loop to which eOrig belongs. "fNext" gives
  109. * a place to insert the new face in the global face list. We insert
  110. * the new face *before* fNext so that algorithms which walk the face
  111. * list will not see the newly created faces.
  112. */
  113. static void MakeFace( GLUhalfEdge *eOrig, GLUface *fNext )
  114. {
  115. GLUface *fNew = (GLUface *)memAlloc( sizeof( GLUface ));
  116. GLUhalfEdge *e;
  117. GLUface *fPrev;
  118. /* insert in circular doubly-linked list before fNext */
  119. fPrev = fNext->prev;
  120. fNew->prev = fPrev;
  121. fPrev->next = fNew;
  122. fNew->next = fNext;
  123. fNext->prev = fNew;
  124. fNew->anEdge = eOrig;
  125. fNew->data = NULL;
  126. fNew->trail = NULL;
  127. fNew->marked = FALSE;
  128. /* The new face is marked "inside" if the old one was. This is a
  129. * convenience for the common case where a face has been split in two.
  130. */
  131. fNew->inside = fNext->inside;
  132. /* fix other edges on this face loop */
  133. e = eOrig;
  134. do {
  135. e->Lface = fNew;
  136. e = e->Lnext;
  137. } while( e != eOrig );
  138. }
  139. /* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
  140. * and removes from the global edge list.
  141. */
  142. static void KillEdge( GLUhalfEdge *eDel )
  143. {
  144. GLUhalfEdge *ePrev, *eNext;
  145. /* Half-edges are allocated in pairs, see EdgePair above */
  146. if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
  147. /* delete from circular doubly-linked list */
  148. eNext = eDel->next;
  149. ePrev = eDel->Sym->next;
  150. eNext->Sym->next = ePrev;
  151. ePrev->Sym->next = eNext;
  152. memFree( eDel );
  153. }
  154. /* KillVertex( vDel ) destroys a vertex and removes it from the global
  155. * vertex list. It updates the vertex loop to point to a given new vertex.
  156. */
  157. static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
  158. {
  159. GLUhalfEdge *e, *eStart = vDel->anEdge;
  160. GLUvertex *vPrev, *vNext;
  161. /* change the origin of all affected edges */
  162. e = eStart;
  163. do {
  164. e->Org = newOrg;
  165. e = e->Onext;
  166. } while( e != eStart );
  167. /* delete from circular doubly-linked list */
  168. vPrev = vDel->prev;
  169. vNext = vDel->next;
  170. vNext->prev = vPrev;
  171. vPrev->next = vNext;
  172. memFree( vDel );
  173. }
  174. /* KillFace( fDel ) destroys a face and removes it from the global face
  175. * list. It updates the face loop to point to a given new face.
  176. */
  177. static void KillFace( GLUface *fDel, GLUface *newLface )
  178. {
  179. GLUhalfEdge *e, *eStart = fDel->anEdge;
  180. GLUface *fPrev, *fNext;
  181. /* change the left face of all affected edges */
  182. e = eStart;
  183. do {
  184. e->Lface = newLface;
  185. e = e->Lnext;
  186. } while( e != eStart );
  187. /* delete from circular doubly-linked list */
  188. fPrev = fDel->prev;
  189. fNext = fDel->next;
  190. fNext->prev = fPrev;
  191. fPrev->next = fNext;
  192. memFree( fDel );
  193. }
  194. /****************** Basic Edge Operations **********************/
  195. /* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
  196. * The loop consists of the two new half-edges.
  197. */
  198. GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
  199. {
  200. GLUhalfEdge *e = MakeEdge( &mesh->eHead );
  201. MakeVertex( e, &mesh->vHead );
  202. MakeVertex( e->Sym, &mesh->vHead );
  203. MakeFace( e, &mesh->fHead );
  204. return e;
  205. }
  206. /* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
  207. * mesh connectivity and topology. It changes the mesh so that
  208. * eOrg->Onext <- OLD( eDst->Onext )
  209. * eDst->Onext <- OLD( eOrg->Onext )
  210. * where OLD(...) means the value before the meshSplice operation.
  211. *
  212. * This can have two effects on the vertex structure:
  213. * - if eOrg->Org != eDst->Org, the two vertices are merged together
  214. * - if eOrg->Org == eDst->Org, the origin is split into two vertices
  215. * In both cases, eDst->Org is changed and eOrg->Org is untouched.
  216. *
  217. * Similarly (and independently) for the face structure,
  218. * - if eOrg->Lface == eDst->Lface, one loop is split into two
  219. * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
  220. * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
  221. *
  222. * Some special cases:
  223. * If eDst == eOrg, the operation has no effect.
  224. * If eDst == eOrg->Lnext, the new face will have a single edge.
  225. * If eDst == eOrg->Lprev, the old face will have a single edge.
  226. * If eDst == eOrg->Onext, the new vertex will have a single edge.
  227. * If eDst == eOrg->Oprev, the old vertex will have a single edge.
  228. */
  229. void __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
  230. {
  231. int joiningLoops = FALSE;
  232. int joiningVertices = FALSE;
  233. if( eOrg == eDst ) return;
  234. if( eDst->Org != eOrg->Org ) {
  235. /* We are merging two disjoint vertices -- destroy eDst->Org */
  236. joiningVertices = TRUE;
  237. KillVertex( eDst->Org, eOrg->Org );
  238. }
  239. if( eDst->Lface != eOrg->Lface ) {
  240. /* We are connecting two disjoint loops -- destroy eDst->Lface */
  241. joiningLoops = TRUE;
  242. KillFace( eDst->Lface, eOrg->Lface );
  243. }
  244. /* Change the edge structure */
  245. Splice( eDst, eOrg );
  246. if( ! joiningVertices ) {
  247. /* We split one vertex into two -- the new vertex is eDst->Org.
  248. * Make sure the old vertex points to a valid half-edge.
  249. */
  250. MakeVertex( eDst, eOrg->Org );
  251. eOrg->Org->anEdge = eOrg;
  252. }
  253. if( ! joiningLoops ) {
  254. /* We split one loop into two -- the new loop is eDst->Lface.
  255. * Make sure the old face points to a valid half-edge.
  256. */
  257. MakeFace( eDst, eOrg->Lface );
  258. eOrg->Lface->anEdge = eOrg;
  259. }
  260. }
  261. /* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
  262. * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
  263. * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
  264. * the newly created loop will contain eDel->Dst. If the deletion of eDel
  265. * would create isolated vertices, those are deleted as well.
  266. *
  267. * This function could be implemented as two calls to __gl_meshSplice
  268. * plus a few calls to memFree, but this would allocate and delete
  269. * unnecessary vertices and faces.
  270. */
  271. void __gl_meshDelete( GLUhalfEdge *eDel )
  272. {
  273. GLUhalfEdge *eDelSym = eDel->Sym;
  274. int joiningLoops = FALSE;
  275. /* First step: disconnect the origin vertex eDel->Org. We make all
  276. * changes to get a consistent mesh in this "intermediate" state.
  277. */
  278. if( eDel->Lface != eDel->Rface ) {
  279. /* We are joining two loops into one -- remove the left face */
  280. joiningLoops = TRUE;
  281. KillFace( eDel->Lface, eDel->Rface );
  282. }
  283. if( eDel->Onext == eDel ) {
  284. KillVertex( eDel->Org, NULL );
  285. } else {
  286. /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
  287. eDel->Rface->anEdge = eDel->Oprev;
  288. eDel->Org->anEdge = eDel->Onext;
  289. Splice( eDel, eDel->Oprev );
  290. if( ! joiningLoops ) {
  291. /* We are splitting one loop into two -- create a new loop for eDel. */
  292. MakeFace( eDel, eDel->Lface );
  293. }
  294. }
  295. /* Claim: the mesh is now in a consistent state, except that eDel->Org
  296. * may have been deleted. Now we disconnect eDel->Dst.
  297. */
  298. if( eDelSym->Onext == eDelSym ) {
  299. KillVertex( eDelSym->Org, NULL );
  300. KillFace( eDelSym->Lface, NULL );
  301. } else {
  302. /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
  303. eDel->Lface->anEdge = eDelSym->Oprev;
  304. eDelSym->Org->anEdge = eDelSym->Onext;
  305. Splice( eDelSym, eDelSym->Oprev );
  306. }
  307. /* Any isolated vertices or faces have already been freed. */
  308. KillEdge( eDel );
  309. }
  310. /******************** Other Edge Operations **********************/
  311. /* All these routines can be implemented with the basic edge
  312. * operations above. They are provided for convenience and efficiency.
  313. */
  314. /* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
  315. * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
  316. * eOrg and eNew will have the same left face.
  317. */
  318. GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
  319. {
  320. GLUhalfEdge *eNew = MakeEdge( eOrg );
  321. GLUhalfEdge *eNewSym = eNew->Sym;
  322. /* Connect the new edge appropriately */
  323. Splice( eNew, eOrg->Lnext );
  324. /* Set the vertex and face information */
  325. eNew->Org = eOrg->Dst;
  326. MakeVertex( eNewSym, eNew->Org );
  327. eNew->Lface = eNewSym->Lface = eOrg->Lface;
  328. return eNew;
  329. }
  330. /* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
  331. * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
  332. * eOrg and eNew will have the same left face.
  333. */
  334. GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
  335. {
  336. GLUhalfEdge *eNew = __gl_meshAddEdgeVertex( eOrg )->Sym;
  337. /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
  338. Splice( eOrg->Sym, eOrg->Sym->Oprev );
  339. Splice( eOrg->Sym, eNew );
  340. /* Set the vertex and face information */
  341. eOrg->Dst = eNew->Org;
  342. eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
  343. eNew->Rface = eOrg->Rface;
  344. eNew->winding = eOrg->winding; /* copy old winding information */
  345. eNew->Sym->winding = eOrg->Sym->winding;
  346. return eNew;
  347. }
  348. /* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
  349. * to eDst->Org, and returns the corresponding half-edge eNew.
  350. * If eOrg->Lface == eDst->Lface, this splits one loop into two,
  351. * and the newly created loop is eNew->Lface. Otherwise, two disjoint
  352. * loops are merged into one, and the loop eDst->Lface is destroyed.
  353. *
  354. * If (eOrg == eDst), the new face will have only two edges.
  355. * If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
  356. * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
  357. */
  358. GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
  359. {
  360. GLUhalfEdge *eNew = MakeEdge( eOrg );
  361. GLUhalfEdge *eNewSym = eNew->Sym;
  362. int joiningLoops = FALSE;
  363. if( eDst->Lface != eOrg->Lface ) {
  364. /* We are connecting two disjoint loops -- destroy eDst->Lface */
  365. joiningLoops = TRUE;
  366. KillFace( eDst->Lface, eOrg->Lface );
  367. }
  368. /* Connect the new edge appropriately */
  369. Splice( eNew, eOrg->Lnext );
  370. Splice( eNewSym, eDst );
  371. /* Set the vertex and face information */
  372. eNew->Org = eOrg->Dst;
  373. eNewSym->Org = eDst->Org;
  374. eNew->Lface = eNewSym->Lface = eOrg->Lface;
  375. /* Make sure the old face points to a valid half-edge */
  376. eOrg->Lface->anEdge = eNewSym;
  377. if( ! joiningLoops ) {
  378. /* We split one loop into two -- the new loop is eNew->Lface */
  379. MakeFace( eNew, eOrg->Lface );
  380. }
  381. return eNew;
  382. }
  383. /******************** Other Operations **********************/
  384. /* __gl_meshZapFace( fZap ) destroys a face and removes it from the
  385. * global face list. All edges of fZap will have a NULL pointer as their
  386. * left face. Any edges which also have a NULL pointer as their right face
  387. * are deleted entirely (along with any isolated vertices this produces).
  388. * An entire mesh can be deleted by zapping its faces, one at a time,
  389. * in any order. Zapped faces cannot be used in further mesh operations!
  390. */
  391. void __gl_meshZapFace( GLUface *fZap )
  392. {
  393. GLUhalfEdge *eStart = fZap->anEdge;
  394. GLUhalfEdge *e, *eNext, *eSym;
  395. GLUface *fPrev, *fNext;
  396. /* walk around face, deleting edges whose right face is also NULL */
  397. eNext = eStart->Lnext;
  398. do {
  399. e = eNext;
  400. eNext = e->Lnext;
  401. e->Lface = NULL;
  402. if( e->Rface == NULL ) {
  403. /* delete the edge -- see __gl_MeshDelete above */
  404. if( e->Onext == e ) {
  405. KillVertex( e->Org, NULL );
  406. } else {
  407. /* Make sure that e->Org points to a valid half-edge */
  408. e->Org->anEdge = e->Onext;
  409. Splice( e, e->Oprev );
  410. }
  411. eSym = e->Sym;
  412. if( eSym->Onext == eSym ) {
  413. KillVertex( eSym->Org, NULL );
  414. } else {
  415. /* Make sure that eSym->Org points to a valid half-edge */
  416. eSym->Org->anEdge = eSym->Onext;
  417. Splice( eSym, eSym->Oprev );
  418. }
  419. KillEdge( e );
  420. }
  421. } while( e != eStart );
  422. /* delete from circular doubly-linked list */
  423. fPrev = fZap->prev;
  424. fNext = fZap->next;
  425. fNext->prev = fPrev;
  426. fPrev->next = fNext;
  427. memFree( fZap );
  428. }
  429. /* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
  430. * and no loops (what we usually call a "face").
  431. */
  432. GLUmesh *__gl_meshNewMesh( void )
  433. {
  434. GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
  435. GLUvertex *v = &mesh->vHead;
  436. GLUface *f = &mesh->fHead;
  437. GLUhalfEdge *e = &mesh->eHead;
  438. GLUhalfEdge *eSym = &mesh->eHeadSym;
  439. v->next = v->prev = v;
  440. v->anEdge = NULL;
  441. v->data = NULL;
  442. f->next = f->prev = f;
  443. f->anEdge = NULL;
  444. f->data = NULL;
  445. f->trail = NULL;
  446. f->marked = FALSE;
  447. f->inside = FALSE;
  448. e->next = e;
  449. e->Sym = eSym;
  450. e->Onext = NULL;
  451. e->Lnext = NULL;
  452. e->Org = NULL;
  453. e->Lface = NULL;
  454. e->winding = 0;
  455. e->activeRegion = NULL;
  456. eSym->next = eSym;
  457. eSym->Sym = e;
  458. eSym->Onext = NULL;
  459. eSym->Lnext = NULL;
  460. eSym->Org = NULL;
  461. eSym->Lface = NULL;
  462. eSym->winding = 0;
  463. eSym->activeRegion = NULL;
  464. return mesh;
  465. }
  466. /* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
  467. * both meshes, and returns the new mesh (the old meshes are destroyed).
  468. */
  469. GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
  470. {
  471. GLUface *f1 = &mesh1->fHead;
  472. GLUvertex *v1 = &mesh1->vHead;
  473. GLUhalfEdge *e1 = &mesh1->eHead;
  474. GLUface *f2 = &mesh2->fHead;
  475. GLUvertex *v2 = &mesh2->vHead;
  476. GLUhalfEdge *e2 = &mesh2->eHead;
  477. /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
  478. if( f2->next != f2 ) {
  479. f1->prev->next = f2->next;
  480. f2->next->prev = f1->prev;
  481. f2->prev->next = f1;
  482. f1->prev = f2->prev;
  483. }
  484. if( v2->next != v2 ) {
  485. v1->prev->next = v2->next;
  486. v2->next->prev = v1->prev;
  487. v2->prev->next = v1;
  488. v1->prev = v2->prev;
  489. }
  490. if( e2->next != e2 ) {
  491. e1->Sym->next->Sym->next = e2->next;
  492. e2->next->Sym->next = e1->Sym->next;
  493. e2->Sym->next->Sym->next = e1;
  494. e1->Sym->next = e2->Sym->next;
  495. }
  496. memFree( mesh2 );
  497. return mesh1;
  498. }
  499. #ifdef DELETE_BY_ZAPPING
  500. /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
  501. */
  502. void __gl_meshDeleteMesh( GLUmesh *mesh )
  503. {
  504. GLUface *fHead = &mesh->fHead;
  505. while( fHead->next != fHead ) {
  506. __gl_meshZapFace( fHead->next );
  507. }
  508. assert( mesh->vHead.next == &mesh->vHead );
  509. memFree( mesh );
  510. }
  511. #else
  512. /* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
  513. */
  514. void __gl_meshDeleteMesh( GLUmesh *mesh )
  515. {
  516. GLUface *f, *fNext;
  517. GLUvertex *v, *vNext;
  518. GLUhalfEdge *e, *eNext;
  519. for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
  520. fNext = f->next;
  521. memFree( f );
  522. }
  523. for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
  524. vNext = v->next;
  525. memFree( v );
  526. }
  527. for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
  528. /* One call frees both e and e->Sym (see EdgePair above) */
  529. eNext = e->next;
  530. memFree( e );
  531. }
  532. memFree( mesh );
  533. }
  534. #endif
  535. #ifndef NDEBUG
  536. /* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
  537. */
  538. void __gl_meshCheckMesh( GLUmesh *mesh )
  539. {
  540. GLUface *fHead = &mesh->fHead;
  541. GLUvertex *vHead = &mesh->vHead;
  542. GLUhalfEdge *eHead = &mesh->eHead;
  543. GLUface *f, *fPrev;
  544. GLUvertex *v, *vPrev;
  545. GLUhalfEdge *e, *ePrev;
  546. fPrev = fHead;
  547. for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
  548. assert( f->prev == fPrev );
  549. e = f->anEdge;
  550. do {
  551. assert( e->Sym != e );
  552. assert( e->Sym->Sym == e );
  553. assert( e->Lnext->Onext->Sym == e );
  554. assert( e->Onext->Sym->Lnext == e );
  555. assert( e->Lface == f );
  556. e = e->Lnext;
  557. } while( e != f->anEdge );
  558. }
  559. assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
  560. vPrev = vHead;
  561. for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
  562. assert( v->prev == vPrev );
  563. e = v->anEdge;
  564. do {
  565. assert( e->Sym != e );
  566. assert( e->Sym->Sym == e );
  567. assert( e->Lnext->Onext->Sym == e );
  568. assert( e->Onext->Sym->Lnext == e );
  569. assert( e->Org == v );
  570. e = e->Onext;
  571. } while( e != v->anEdge );
  572. }
  573. assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
  574. ePrev = eHead;
  575. for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
  576. assert( e->Sym->next == ePrev->Sym );
  577. assert( e->Sym != e );
  578. assert( e->Sym->Sym == e );
  579. assert( e->Org != NULL );
  580. assert( e->Dst != NULL );
  581. assert( e->Lnext->Onext->Sym == e );
  582. assert( e->Onext->Sym->Lnext == e );
  583. }
  584. assert( e->Sym->next == ePrev->Sym
  585. && e->Sym == &mesh->eHeadSym
  586. && e->Sym->Sym == e
  587. && e->Org == NULL && e->Dst == NULL
  588. && e->Lface == NULL && e->Rface == NULL );
  589. }
  590. #endif