nmg_mod.c

Go to the documentation of this file.
00001 /*                       N M G _ M O D . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1991-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup nmg */
00023 
00024 /*@{*/
00025 /** @file nmg_mod.c
00026  *  Routines for modifying n-Manifold Geometry data structures.
00027  *
00028  *  Authors -
00029  *      Lee A. Butler
00030  *      Michael John Muuss
00031  *
00032  *  Source -
00033  *      SECAD/VLD Computing Consortium, Bldg 394
00034  *      The U. S. Army Ballistic Research Laboratory
00035  *      Aberdeen Proving Ground, Maryland  21005-5066
00036  *
00037  */
00038 /*@}*/
00039 
00040 #ifndef lint
00041 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_mod.c,v 14.11 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00042 #endif
00043 
00044 #include "common.h"
00045 
00046 #include <stdlib.h>
00047 #include <stdio.h>
00048 #include <string.h>
00049 
00050 #include "machine.h"
00051 #include "vmath.h"
00052 #include "nmg.h"
00053 #include "raytrace.h"
00054 #include "nurb.h"
00055 
00056 
00057 /**
00058  *                      N M G _ M E R G E _ R E G I O N S
00059  */
00060 void
00061 nmg_merge_regions(struct nmgregion *r1, struct nmgregion *r2, const struct bn_tol *tol)
00062 {
00063         struct model *m;
00064 
00065         NMG_CK_REGION( r1 );
00066         NMG_CK_REGION( r2 );
00067         BN_CK_TOL( tol );
00068 
00069         m = r1->m_p;
00070         NMG_CK_MODEL( m );
00071 
00072         if( r2->m_p != m )
00073                 rt_bomb( "nmg_merge_regions: Tried to merge regions from different models!!" );
00074 
00075         /* move all of r2's faces into r1 */
00076         while( BU_LIST_NON_EMPTY( &r2->s_hd ) )
00077         {
00078                 struct shell *s;
00079 
00080                 s = BU_LIST_FIRST( shell, &r2->s_hd );
00081                 BU_LIST_DEQUEUE( &s->l );
00082                 s->r_p = r1;
00083                 BU_LIST_APPEND( &r1->s_hd, &s->l );
00084         }
00085 
00086         (void)nmg_kr( r2 );
00087         nmg_rebound( m, tol );
00088 }
00089 
00090 /************************************************************************
00091  *                                                                      *
00092  *                              SHELL Routines                          *
00093  *                                                                      *
00094  ************************************************************************/
00095 
00096 /**
00097  *                      N M G _ S H E L L _ C O P L A N A R _ F A C E _ M E R G E
00098  *
00099  *  A geometric routine to
00100  *  find all pairs of faces in a shell that have the same plane equation
00101  *  (to within the given tolerance), and combine them into a single face.
00102  *
00103  *  Note that this may result in some of the verticies being very slightly
00104  *  off the plane equation, but the geometry routines need to be prepared
00105  *  for this in any case.
00106  *  If the "simplify" flag is set, pairs of loops in the face that touch
00107  *  will be combined into a single loop where possible.
00108  *
00109  *  XXX Perhaps should be recast as "nmg_shell_shared_face_merge()", leaving
00110  *  XXX all the geometric calculations to the code in nmg_fuse.c ?
00111  */
00112 void
00113 nmg_shell_coplanar_face_merge(struct shell *s, const struct bn_tol *tol, const int simplify)
00114 {
00115         struct model    *m;
00116         int             len;
00117         char            *flags1;
00118         char            *flags2;
00119         struct faceuse  *fu1;
00120         struct faceuse  *fu2;
00121         struct face     *f1;
00122         struct face     *f2;
00123         struct face_g_plane     *fg1;
00124         struct face_g_plane     *fg2;
00125 
00126         NMG_CK_SHELL(s);
00127         m = nmg_find_model( &s->l.magic );
00128         len = sizeof(char) * m->maxindex * 2;
00129         flags1 = (char *)bu_calloc( sizeof(char), m->maxindex * 2,
00130                 "nmg_shell_coplanar_face_merge flags1[]" );
00131         flags2 = (char *)bu_calloc( sizeof(char), m->maxindex * 2,
00132                 "nmg_shell_coplanar_face_merge flags2[]" );
00133 
00134         /* Visit each face in the shell */
00135         for( BU_LIST_FOR( fu1, faceuse, &s->fu_hd ) )  {
00136                 plane_t         n1;
00137 
00138                 if( BU_LIST_NEXT_IS_HEAD(fu1, &s->fu_hd) )  break;
00139                 f1 = fu1->f_p;
00140                 NMG_CK_FACE(f1);
00141                 if( NMG_INDEX_TEST(flags1, f1) )  continue;
00142                 NMG_INDEX_SET(flags1, f1);
00143 
00144                 fg1 = f1->g.plane_p;
00145                 NMG_CK_FACE_G_PLANE(fg1);
00146                 NMG_GET_FU_PLANE( n1, fu1 );
00147 
00148                 /* For this face, visit all remaining faces in the shell. */
00149                 /* Don't revisit any faces already considered. */
00150                 bcopy( flags1, flags2, len );
00151                 for( fu2 = BU_LIST_NEXT(faceuse, &fu1->l);
00152                      BU_LIST_NOT_HEAD(fu2, &s->fu_hd);
00153                      fu2 = BU_LIST_NEXT(faceuse,&fu2->l)
00154                 )  {
00155                         register fastf_t        dist;
00156                         plane_t                 n2;
00157 
00158                         f2 = fu2->f_p;
00159                         NMG_CK_FACE(f2);
00160                         if( NMG_INDEX_TEST(flags2, f2) )  continue;
00161                         NMG_INDEX_SET(flags2, f2);
00162 
00163                         fg2 = f2->g.plane_p;
00164                         NMG_CK_FACE_G_PLANE(fg2);
00165 
00166                         if( fu2->fumate_p == fu1 || fu1->fumate_p == fu2 )
00167                                 rt_bomb("nmg_shell_coplanar_face_merge() mate confusion\n");
00168 
00169                         /* See if face geometry is shared & same direction */
00170                         if( fg1 != fg2 || f1->flip != f2->flip )  {
00171                                 /* If plane equations are different, done */
00172                                 NMG_GET_FU_PLANE( n2, fu2 );
00173 
00174                                 /* Compare distances from origin */
00175                                 dist = n1[3] - n2[3];
00176                                 if( !NEAR_ZERO(dist, tol->dist) ) continue;
00177 
00178                                 /*
00179                                  *  Compare angle between normals.
00180                                  *  Can't just use BN_VECT_ARE_PARALLEL here,
00181                                  *  because they must point in the same direction.
00182                                  */
00183                                 dist = VDOT( n1, n2 );
00184                                 if( !(dist >= tol->para) ) continue;
00185 
00186                                 if( nmg_ck_fu_verts( fu2, f1, tol ) )
00187                                         continue;
00188                         }
00189 
00190                         /*
00191                          * Plane equations are the same, within tolerance,
00192                          * or by shared fg topology.
00193                          * Move everything into fu1, and
00194                          * kill now empty faceuse, fumate, and face
00195                          */
00196                         {
00197                                 struct faceuse  *prev_fu;
00198                                 prev_fu = BU_LIST_PREV(faceuse, &fu2->l);
00199                                 /* The prev_fu can never be the head */
00200                                 if( BU_LIST_IS_HEAD(prev_fu, &s->fu_hd) )
00201                                         rt_bomb("prev is head?\n");
00202 
00203                                 nmg_jf( fu1, fu2 );
00204 
00205                                 fu2 = prev_fu;
00206                         }
00207 
00208                         /* There is now the option of simplifying the face,
00209                          * by removing unnecessary edges.
00210                          */
00211                         if( simplify )  {
00212                                 struct loopuse *lu;
00213 
00214                                 for (BU_LIST_FOR(lu, loopuse, &fu1->lu_hd))
00215                                         nmg_simplify_loop(lu);
00216                         }
00217                 }
00218         }
00219         bu_free( (char *)flags1, "nmg_shell_coplanar_face_merge flags1[]" );
00220         bu_free( (char *)flags2, "nmg_shell_coplanar_face_merge flags2[]" );
00221 
00222         nmg_shell_a( s, tol );
00223 
00224         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00225                 bu_log("nmg_shell_coplanar_face_merge(s=x%x, tol=x%x, simplify=%d)\n",
00226                         s, tol, simplify);
00227         }
00228 }
00229 
00230 /**
00231  *                      N M G _ S I M P L I F Y _ S H E L L
00232  *
00233  *  Simplify all the faces in this shell, where possible.
00234  *  Under some circumstances this may result in an empty shell as a result.
00235  *
00236  * Returns -
00237  *      0       If all was OK
00238  *      1       If shell is now empty
00239  */
00240 int
00241 nmg_simplify_shell(struct shell *s)
00242 {
00243         struct faceuse *fu;
00244         int ret_val;
00245 
00246         NMG_CK_SHELL(s);
00247 
00248         for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) {
00249                 if( nmg_simplify_face(fu) )  {
00250                         struct faceuse  *kfu = fu;
00251                         fu = BU_LIST_PREV( faceuse, &fu->l );
00252                         nmg_kfu( kfu );
00253                 }
00254         }
00255 
00256         ret_val = nmg_shell_is_empty(s);
00257 
00258         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00259                 bu_log("nmg_simplify_shell(s=x%x) returns %d\n", s , ret_val);
00260         }
00261 
00262         return( ret_val );
00263 }
00264 
00265 /**
00266  *                      N M G _ R M _ R E D U N D A N C I E S
00267  *
00268  *  Remove all redundant parts between the different "levels" of a shell.
00269  *  Remove wire loops that match face loops.
00270  *  Remove wire edges that match edges in wire loops or face loops.
00271  *  Remove lone vertices (stored as wire loops on a single vertex) that
00272  *  match vertices in a face loop, wire loop, or wire edge.
00273  */
00274 void
00275 nmg_rm_redundancies(struct shell *s, const struct bn_tol *tol)
00276 {
00277         struct faceuse  *fu;
00278         struct loopuse  *lu;
00279         struct edgeuse  *eu;
00280         struct vertexuse        *vu;
00281         long            magic1;
00282 
00283         NMG_CK_SHELL(s);
00284         BN_CK_TOL( tol );
00285 
00286         if( BU_LIST_NON_EMPTY( &s->fu_hd ) )  {
00287                 /* Compare wire loops -vs- loops in faces */
00288                 lu = BU_LIST_FIRST( loopuse, &s->lu_hd );
00289                 while( BU_LIST_NOT_HEAD( lu, &s->lu_hd ) )  {
00290                         register struct loopuse *nextlu;
00291                         NMG_CK_LOOPUSE(lu);
00292                         NMG_CK_LOOP(lu->l_p);
00293                         nextlu = BU_LIST_PNEXT( loopuse, lu );
00294                         if( nmg_is_loop_in_facelist( lu->l_p, &s->fu_hd ) )  {
00295                                 /* Dispose of wire loop (and mate)
00296                                  * which match face loop */
00297                                 if( nextlu == lu->lumate_p )
00298                                         nextlu = BU_LIST_PNEXT(loopuse, nextlu);
00299                                 nmg_klu( lu );
00300                         }
00301                         lu = nextlu;
00302                 }
00303 
00304                 /* Compare wire edges -vs- edges in loops in faces */
00305                 eu = BU_LIST_FIRST( edgeuse, &s->eu_hd );
00306                 while( BU_LIST_NOT_HEAD( eu, &s->eu_hd ) )  {
00307                         register struct edgeuse *nexteu;
00308                         NMG_CK_EDGEUSE(eu);
00309                         NMG_CK_EDGE(eu->e_p);
00310                         nexteu = BU_LIST_PNEXT( edgeuse, eu );
00311                         if( nmg_is_edge_in_facelist( eu->e_p, &s->fu_hd ) )  {
00312                                 /* Dispose of wire edge (and mate) */
00313                                 if( nexteu == eu->eumate_p )
00314                                         nexteu = BU_LIST_PNEXT(edgeuse, nexteu);
00315                                 (void)nmg_keu(eu);
00316                         }
00317                         eu = nexteu;
00318                 }
00319         }
00320 
00321         /* Compare wire edges -vs- edges in wire loops */
00322         eu = BU_LIST_FIRST( edgeuse, &s->eu_hd );
00323         while( BU_LIST_NOT_HEAD( eu, &s->eu_hd ) )  {
00324                 register struct edgeuse *nexteu;
00325                 NMG_CK_EDGEUSE(eu);
00326                 NMG_CK_EDGE(eu->e_p);
00327                 nexteu = BU_LIST_PNEXT( edgeuse, eu );
00328                 if( nmg_is_edge_in_looplist( eu->e_p, &s->lu_hd ) )  {
00329                         /* Kill edge use and mate */
00330                         if( nexteu == eu->eumate_p )
00331                                 nexteu = BU_LIST_PNEXT(edgeuse, nexteu);
00332                         (void)nmg_keu(eu);
00333                 }
00334                 eu = nexteu;
00335         }
00336 
00337         /* Compare lone vertices against everything else */
00338         /* Individual vertices are stored as wire loops on a single vertex */
00339         lu = BU_LIST_FIRST( loopuse, &s->lu_hd );
00340         while( BU_LIST_NOT_HEAD( lu, &s->lu_hd ) )  {
00341                 register struct loopuse *nextlu;
00342                 NMG_CK_LOOPUSE(lu);
00343                 nextlu = BU_LIST_PNEXT( loopuse, lu );
00344                 magic1 = BU_LIST_FIRST_MAGIC( &lu->down_hd );
00345                 if( magic1 != NMG_VERTEXUSE_MAGIC )  {
00346                         lu = nextlu;
00347                         continue;
00348                 }
00349                 vu = BU_LIST_PNEXT( vertexuse, &lu->down_hd );
00350                 NMG_CK_VERTEXUSE(vu);
00351                 NMG_CK_VERTEX(vu->v_p);
00352                 if( nmg_is_vertex_in_facelist( vu->v_p, &s->fu_hd ) ||
00353                     nmg_is_vertex_in_looplist( vu->v_p, &s->lu_hd,0 ) ||
00354                     nmg_is_vertex_in_edgelist( vu->v_p, &s->eu_hd ) )  {
00355                         /* Kill lu and mate */
00356                         if( nextlu == lu->lumate_p )
00357                                 nextlu = BU_LIST_PNEXT(loopuse, nextlu);
00358                         nmg_klu( lu );
00359                         lu = nextlu;
00360                         continue;
00361                 }
00362                 lu = nextlu;
00363         }
00364 
00365         /* There really shouldn't be a lone vertex by now */
00366         if( s->vu_p )  bu_log("nmg_rm_redundancies() lone vertex?\n");
00367 
00368         /* get rid of matching OT_SAME/OT_OPPOSITE loops in same faceuse */
00369         fu = BU_LIST_FIRST( faceuse, &s->fu_hd );
00370         while( BU_LIST_NOT_HEAD( &fu->l, &s->fu_hd ) )
00371         {
00372                 struct faceuse *next_fu;
00373                 int lu1_count;
00374                 int lu_count;
00375 
00376                 NMG_CK_FACEUSE( fu );
00377 
00378                 if( fu->orientation != OT_SAME )
00379                 {
00380                         fu = BU_LIST_NEXT( faceuse, &fu->l );
00381                         continue;
00382                 }
00383 
00384                 next_fu = BU_LIST_NEXT( faceuse, &fu->l );
00385                 if( next_fu == fu->fumate_p )
00386                         next_fu = BU_LIST_NEXT( faceuse, &next_fu->l );
00387 
00388                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
00389                 while( BU_LIST_NOT_HEAD( &lu->l, &fu->lu_hd ) )
00390                 {
00391                         struct loopuse *next_lu;
00392                         struct loopuse *lu1;
00393                         struct edgeuse *eu;
00394 
00395                         NMG_CK_LOOPUSE( lu );
00396 
00397                         next_lu = BU_LIST_NEXT( loopuse, &lu->l );
00398 
00399                         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
00400                         {
00401                                 lu = next_lu;
00402                                 continue;
00403                         }
00404 
00405                         /* count edges in lu */
00406                         lu_count = 0;
00407                         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
00408                                 lu_count++;
00409 
00410                         /* look for anther loopuse with opposite orientation */
00411                         lu1 = BU_LIST_FIRST( loopuse, &fu->lu_hd );
00412                         while( BU_LIST_NOT_HEAD( &lu1->l, &fu->lu_hd ) )
00413                         {
00414                                 struct loopuse *next_lu1;
00415 
00416                                 NMG_CK_LOOPUSE( lu1 );
00417 
00418                                 next_lu1 = BU_LIST_PNEXT( loopuse, &lu1->l );
00419 
00420                                 if( BU_LIST_FIRST_MAGIC( &lu1->down_hd ) != NMG_EDGEUSE_MAGIC )
00421                                 {
00422                                         lu1 = next_lu1;
00423                                         continue;
00424                                 }
00425 
00426                                 if( lu1 == lu )
00427                                 {
00428                                         lu1 = next_lu1;
00429                                         continue;
00430                                 }
00431 
00432                                 if( lu1->orientation == lu->orientation )
00433                                 {
00434                                         lu1 = next_lu1;
00435                                         continue;
00436                                 }
00437 
00438                                 /* count edges in lu1 */
00439                                 lu1_count = 0;
00440                                 for( BU_LIST_FOR( eu, edgeuse, &lu1->down_hd ) )
00441                                         lu1_count++;
00442 
00443                                 if( lu_count != lu1_count )
00444                                 {
00445                                         lu1 = next_lu1;
00446                                         continue;
00447                                 }
00448 
00449                                 if( nmg_classify_lu_lu( lu, lu1, tol ) != NMG_CLASS_AonBshared )
00450                                 {
00451                                         lu1 = next_lu1;
00452                                         continue;
00453                                 }
00454 
00455                                 /* lu and lu1 are identical, but with opposite orientations
00456                                  * kill them both
00457                                  */
00458 
00459                                 if( next_lu1 == lu )
00460                                         next_lu1 = BU_LIST_NEXT( loopuse, &next_lu1->l );
00461 
00462                                 if( next_lu == lu1 )
00463                                         next_lu = BU_LIST_NEXT( loopuse, &next_lu->l );
00464 
00465                                 (void)nmg_klu( lu );
00466                                 if( nmg_klu( lu1 ) )
00467                                 {
00468                                         /* faceuse is empty, kill it */
00469                                         if( nmg_kfu( fu ) )
00470                                         {
00471                                                 /* shell is empty, set "nexts" to get out */
00472                                                 next_fu = (struct faceuse *)(&s->fu_hd);
00473                                                 next_lu = (struct loopuse *)NULL;
00474                                         }
00475                                         else
00476                                         {
00477                                                 /* shell not empty, but fu is */
00478                                                 next_lu = (struct loopuse *)NULL;
00479                                         }
00480                                 }
00481                                 break;
00482                         }
00483 
00484                         if( !next_lu )
00485                                 break;
00486 
00487                         lu = next_lu;
00488                 }
00489                 fu = next_fu;
00490         }
00491 
00492         /* get rid of redundant loops in same fu (OT_SAME within an OT_SAME), etc. */
00493         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )
00494         {
00495                 NMG_CK_FACEUSE( fu );
00496 
00497                 if( fu->orientation != OT_SAME )
00498                         continue;
00499 
00500                 for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )
00501                 {
00502                         struct loopuse *lu1;
00503 
00504                         NMG_CK_LOOPUSE( lu );
00505 
00506                         /* look for another loop with same orientation */
00507                         lu1 = BU_LIST_FIRST( loopuse, &fu->lu_hd );
00508                         while( BU_LIST_NOT_HEAD( &lu1->l, &fu->lu_hd ) )
00509                         {
00510                                 struct loopuse *next_lu;
00511                                 struct loopuse *lu2;
00512                                 int found;
00513 
00514                                 NMG_CK_LOOPUSE( lu1 );
00515 
00516                                 next_lu = BU_LIST_PNEXT( loopuse, &lu1->l );
00517 
00518                                 if( lu1 == lu )
00519                                 {
00520                                         lu1 = next_lu;
00521                                         continue;
00522                                 }
00523 
00524                                 if( lu1->orientation != lu->orientation )
00525                                 {
00526                                         lu1 = next_lu;
00527                                         continue;
00528                                 }
00529 
00530                                 if( nmg_classify_lu_lu( lu1, lu, tol ) != NMG_CLASS_AinB )
00531                                 {
00532                                         lu1 = next_lu;
00533                                         continue;
00534                                 }
00535 
00536                                 /* lu1 is within lu and has same orientation.
00537                                  * Check if there is a loop with opposite
00538                                  * orientation between them.
00539                                  */
00540                                 found = 0;
00541                                 for( BU_LIST_FOR( lu2, loopuse, &fu->lu_hd ) )
00542                                 {
00543                                         int class1,class2;
00544 
00545                                         NMG_CK_LOOPUSE( lu2 );
00546 
00547                                         if( lu2 == lu || lu2 == lu1 )
00548                                                 continue;
00549 
00550                                         if( lu2->orientation == lu->orientation )
00551                                                 continue;
00552 
00553                                         class1 = nmg_classify_lu_lu( lu2, lu, tol );
00554                                         class2 = nmg_classify_lu_lu( lu1, lu2, tol );
00555 
00556                                         if( class1 == NMG_CLASS_AinB &&
00557                                             class2 == NMG_CLASS_AinB )
00558                                         {
00559                                                 found = 1;
00560                                                 break;
00561                                         }
00562                                 }
00563                                 if( !found )
00564                                 {
00565                                         /* lu1 is a redundant loop */
00566                                         (void) nmg_klu( lu1 );
00567                                 }
00568                                 lu1 = next_lu;
00569                         }
00570                 }
00571         }
00572 
00573         /* get rid of redundant loops in same fu where there are two identical
00574          * loops, but with opposite orientation
00575          */
00576         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )
00577         {
00578                 if( fu->orientation != OT_SAME )
00579                         continue;
00580 
00581                 for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )
00582                 {
00583                         struct loopuse *lu1;
00584 
00585                         if( lu->orientation != OT_SAME )
00586                                 continue;
00587 
00588                         lu1 = BU_LIST_FIRST( loopuse, &fu->lu_hd );
00589                         while( BU_LIST_NOT_HEAD( &lu1->l, &fu->lu_hd ) )
00590                         {
00591                                 int class;
00592                                 struct loopuse *next_lu;
00593 
00594                                 next_lu = BU_LIST_PNEXT( loopuse, &lu1->l );
00595 
00596                                 if( lu1 == lu || lu1->orientation != OT_OPPOSITE )
00597                                 {
00598                                         lu1 = next_lu;
00599                                         continue;
00600                                 }
00601 
00602                                 class = nmg_classify_lu_lu( lu, lu1, tol );
00603 
00604                                 if( class == NMG_CLASS_AonBshared )
00605                                 {
00606                                         nmg_klu( lu1 ); /* lu1 is redudndant */
00607                                 }
00608 
00609                                 lu1 = next_lu;
00610                         }
00611                 }
00612         }
00613 
00614         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00615                 bu_log("nmg_rm_redundancies(s=x%x)\n", s);
00616         }
00617 }
00618 
00619 /**
00620  *                      N M G _ S A N I T I Z E _ S _ L V
00621  *
00622  *      Remove those pesky little vertex-only loops of orientation "orient".
00623  *      Typically these will be OT_BOOLPLACE markers created in the
00624  *      process of doing intersections for the boolean operations.
00625  */
00626 void
00627 nmg_sanitize_s_lv(struct shell *s, int orient)
00628 {
00629         struct faceuse *fu;
00630         struct loopuse *lu;
00631         pointp_t pt;
00632 
00633         NMG_CK_SHELL(s);
00634 
00635         /* sanitize the loop lists in the faces of the shell */
00636         fu = BU_LIST_FIRST(faceuse, &s->fu_hd);
00637         while (BU_LIST_NOT_HEAD(fu, &s->fu_hd) ) {
00638 
00639                 /* all of those vertex-only/orient loops get deleted
00640                  */
00641                 lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
00642                 while (BU_LIST_NOT_HEAD(lu, &fu->lu_hd)) {
00643                         if (lu->orientation == orient) {
00644                                 lu = BU_LIST_PNEXT(loopuse,lu);
00645                                 nmg_klu(BU_LIST_PLAST(loopuse, lu));
00646                         } else if (lu->orientation == OT_UNSPEC &&
00647                             BU_LIST_FIRST_MAGIC(&lu->down_hd) ==
00648                             NMG_VERTEXUSE_MAGIC) {
00649                                 register struct vertexuse *vu;
00650                                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
00651                                 pt = vu->v_p->vg_p->coord;
00652                                 VPRINT("nmg_sanitize_s_lv() OT_UNSPEC at", pt);
00653                                 lu = BU_LIST_PNEXT(loopuse,lu);
00654                         } else {
00655                                 lu = BU_LIST_PNEXT(loopuse,lu);
00656                         }
00657                 }
00658 
00659                 /* step forward, avoiding re-processing our mate (which would
00660                  * have had it's loops processed with ours)
00661                  */
00662                 if (BU_LIST_PNEXT(faceuse, fu) == fu->fumate_p)
00663                         fu = BU_LIST_PNEXT_PNEXT(faceuse, fu);
00664                 else
00665                         fu = BU_LIST_PNEXT(faceuse, fu);
00666 
00667                 /* If previous faceuse has no more loops, kill it */
00668                 if (BU_LIST_IS_EMPTY( &(BU_LIST_PLAST(faceuse, fu))->lu_hd )) {
00669                         /* All of the loopuses of the previous face were
00670                          * BOOLPLACE's so the face will now go away
00671                          */
00672                         nmg_kfu(BU_LIST_PLAST(faceuse, fu));
00673                 }
00674         }
00675 
00676         /* Sanitize any wire/vertex loops in the shell */
00677         lu = BU_LIST_FIRST(loopuse, &s->lu_hd);
00678         while (BU_LIST_NOT_HEAD(lu, &s->lu_hd) ) {
00679                 if (lu->orientation == orient) {
00680                         lu = BU_LIST_PNEXT(loopuse,lu);
00681                         nmg_klu(BU_LIST_PLAST(loopuse, lu));
00682                 } else if (lu->orientation == OT_UNSPEC &&
00683                     BU_LIST_FIRST_MAGIC(&lu->down_hd) ==
00684                     NMG_VERTEXUSE_MAGIC) {
00685                         register struct vertexuse *vu;
00686                         vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
00687                         pt = vu->v_p->vg_p->coord;
00688                         VPRINT("nmg_sanitize_s_lv() OT_UNSPEC at", pt);
00689                         lu = BU_LIST_PNEXT(loopuse,lu);
00690                 } else {
00691                         lu = BU_LIST_PNEXT(loopuse,lu);
00692                 }
00693         }
00694 
00695         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00696                 bu_log("nmg_sanitize_s_lv(s=x%x, orient=%d)\n", s, orient);
00697         }
00698 }
00699 
00700 /**
00701  *                      N M G _ S _ S P L I T _ T O U C H I N G L O O P S
00702  *
00703  *  For every loop in a shell, invoke nmg_split_touchingloops() on it.
00704  *
00705  *  Needed before starting classification, to separate interior (touching)
00706  *  loop segments into true interior loops, so each can be processed
00707  *  separately.
00708  */
00709 void
00710 nmg_s_split_touchingloops(struct shell *s, const struct bn_tol *tol)
00711 {
00712         struct faceuse  *fu;
00713         struct loopuse  *lu;
00714 
00715         NMG_CK_SHELL(s);
00716         BN_CK_TOL(tol);
00717 
00718         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00719                 bu_log("nmg_s_split_touching_loops(s=x%x, tol=x%x) START\n", s, tol);
00720         }
00721 
00722         /* First, handle any splitting */
00723         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )  {
00724                 for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
00725                         (void)nmg_loop_split_at_touching_jaunt( lu, tol );
00726                         nmg_split_touchingloops( lu, tol );
00727                 }
00728         }
00729         for( BU_LIST_FOR( lu, loopuse, &s->lu_hd ) )  {
00730                 (void)nmg_loop_split_at_touching_jaunt( lu, tol );
00731                 nmg_split_touchingloops( lu, tol );
00732         }
00733 
00734         /* Second, reorient any split loop fragments */
00735         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )  {
00736                 for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
00737                         if( lu->orientation != OT_UNSPEC )  continue;
00738                         nmg_lu_reorient( lu );
00739                 }
00740         }
00741 
00742         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00743                 bu_log("nmg_s_split_touching_loops(s=x%x, tol=x%x) END\n", s, tol);
00744         }
00745 }
00746 
00747 /**
00748  *                      N M G _ S _ J O I N _ T O U C H I N G L O O P S
00749  *
00750  *  For every loop in a shell, invoke nmg_join_touchingloops() on it.
00751  */
00752 void
00753 nmg_s_join_touchingloops(struct shell *s, const struct bn_tol *tol)
00754 {
00755         struct faceuse  *fu;
00756         struct loopuse  *lu;
00757 
00758         NMG_CK_SHELL(s);
00759         BN_CK_TOL(tol);
00760 
00761         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00762                 bu_log("nmg_s_join_touching_loops(s=x%x, tol=x%x) START\n", s, tol);
00763         }
00764 
00765         /* First, handle any joining */
00766         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )  {
00767                 for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
00768                         nmg_join_touchingloops( lu );
00769                 }
00770         }
00771         for( BU_LIST_FOR( lu, loopuse, &s->lu_hd ) )  {
00772                 nmg_join_touchingloops( lu );
00773         }
00774 
00775         /* Second, reorient any disoriented loop fragments */
00776         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )  {
00777                 for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
00778                         if( lu->orientation != OT_UNSPEC )  continue;
00779                         nmg_lu_reorient( lu );
00780                 }
00781         }
00782 
00783         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00784                 bu_log("nmg_s_join_touching_loops(s=x%x, tol=x%x) END\n", s, tol);
00785         }
00786 }
00787 
00788 /**
00789  *                      N M G _ J S
00790  *
00791  *  Join two shells into one.
00792  *  This is mostly an up-pointer re-labeling activity, as it is left up to
00793  *  the caller to ensure that there are no non-explicit intersections.
00794  *
00795  *  Upon return, s2 will no longer exist.
00796  *
00797  *  The 'tol' arg is used strictly for printing purposes.
00798  */
00799 void
00800 nmg_js(register struct shell *s1, register struct shell *s2, const struct bn_tol *tol)
00801                                         /* destination */
00802                                         /* source */
00803 
00804 {
00805         struct faceuse  *fu2;
00806         struct faceuse  *nextfu;
00807         struct loopuse  *lu;
00808         struct loopuse  *nextlu;
00809         struct edgeuse  *eu;
00810         struct edgeuse  *nexteu;
00811         struct vertexuse *vu;
00812 
00813         NMG_CK_SHELL(s1);
00814         NMG_CK_SHELL(s2);
00815         BN_CK_TOL(tol);
00816 
00817         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00818                 bu_log("nmg_js(s1=x%x, s2=x%x) START\n", s1, s2);
00819         }
00820 
00821         if( rt_g.NMG_debug & DEBUG_VERIFY )
00822                 nmg_vshell( &s1->r_p->s_hd, s1->r_p );
00823 
00824         /*
00825          *  For each face in the shell, process all the loops in the face,
00826          *  and then handle the face and all loops as a unit.
00827          */
00828         fu2 = BU_LIST_FIRST( faceuse, &s2->fu_hd );
00829         while( BU_LIST_NOT_HEAD( fu2, &s2->fu_hd ) )  {
00830                 struct faceuse  *fu1;
00831 
00832                 nextfu = BU_LIST_PNEXT( faceuse, fu2 );
00833 
00834                 /* Faceuse mates will be handled at same time as OT_SAME fu */
00835                 if( fu2->orientation != OT_SAME )  {
00836                         fu2 = nextfu;
00837                         continue;
00838                 }
00839 
00840                 /* Consider this face */
00841                 NMG_CK_FACEUSE(fu2);
00842                 NMG_CK_FACE(fu2->f_p);
00843 
00844                 if( nextfu == fu2->fumate_p )
00845                         nextfu = BU_LIST_PNEXT(faceuse, nextfu);
00846 
00847                 /* If there is a face in the destination shell that
00848                  * shares face geometry with this face, then
00849                  * move all the loops into the other face,
00850                  * and eliminate this redundant face.
00851                  */
00852                 fu1 = nmg_find_fu_with_fg_in_s( s1, fu2 );
00853                 if( fu1 && fu1->orientation == OT_SAME )  {
00854                         if (rt_g.NMG_debug & DEBUG_BASIC)
00855                                 bu_log("nmg_js(): shared face_g_plane, doing nmg_jf()\n");
00856                         nmg_jf( fu1, fu2 );
00857                         /* fu2 pointer is invalid here */
00858                         fu2 = fu1;
00859                 } else {
00860                         nmg_mv_fu_between_shells( s1, s2, fu2 );
00861                 }
00862 
00863                 fu2 = nextfu;
00864         }
00865 #if 0
00866         if( rt_g.NMG_debug & DEBUG_VERIFY )
00867                 nmg_vshell( &s1->r_p->s_hd, s1->r_p );
00868 #endif
00869 
00870         /*
00871          *  For each loop in the shell, process.
00872          *  Each loop is either a wire-loop, or a vertex-with-self-loop.
00873          *  Both get the same treatment.
00874          */
00875         lu = BU_LIST_FIRST( loopuse, &s2->lu_hd );
00876         while( BU_LIST_NOT_HEAD( lu, &s2->lu_hd ) )  {
00877                 nextlu = BU_LIST_PNEXT( loopuse, lu );
00878 
00879                 NMG_CK_LOOPUSE(lu);
00880                 NMG_CK_LOOP( lu->l_p );
00881                 if( nextlu == lu->lumate_p )
00882                         nextlu = BU_LIST_PNEXT(loopuse, nextlu);
00883 
00884                 nmg_mv_lu_between_shells( s1, s2, lu );
00885                 lu = nextlu;
00886         }
00887 #if 0
00888         if( rt_g.NMG_debug & DEBUG_VERIFY )
00889                 nmg_vshell( &s1->r_p->s_hd, s1->r_p );
00890 #endif
00891 
00892         /*
00893          *  For each wire-edge in the shell, ...
00894          */
00895         eu = BU_LIST_FIRST( edgeuse, &s2->eu_hd );
00896         while( BU_LIST_NOT_HEAD( eu, &s2->eu_hd ) )  {
00897                 nexteu = BU_LIST_PNEXT( edgeuse, eu );
00898 
00899                 /* Consider this edge */
00900                 NMG_CK_EDGEUSE(eu);
00901                 NMG_CK_EDGE( eu->e_p );
00902                 if( nexteu == eu->eumate_p )
00903                         nexteu = BU_LIST_PNEXT(edgeuse, nexteu);
00904                 nmg_mv_eu_between_shells( s1, s2, eu );
00905                 eu = nexteu;
00906         }
00907 #if 0
00908         if( rt_g.NMG_debug & DEBUG_VERIFY )
00909                 nmg_vshell( &s1->r_p->s_hd, s1->r_p );
00910 #endif
00911 
00912         /*
00913          * Final case:  shell of a single vertexuse
00914          */
00915         if( (vu = s2->vu_p) )  {
00916                 NMG_CK_VERTEXUSE( vu );
00917                 NMG_CK_VERTEX( vu->v_p );
00918                 nmg_mv_vu_between_shells( s1, s2, vu );
00919                 s2->vu_p = (struct vertexuse *)0;       /* sanity */
00920         }
00921 
00922         if( BU_LIST_NON_EMPTY( &s2->fu_hd ) )  {
00923                 rt_bomb("nmg_js():  s2 still has faces!\n");
00924         }
00925         if( BU_LIST_NON_EMPTY( &s2->lu_hd ) )  {
00926                 rt_bomb("nmg_js():  s2 still has wire loops!\n");
00927         }
00928         if( BU_LIST_NON_EMPTY( &s2->eu_hd ) )  {
00929                 rt_bomb("nmg_js():  s2 still has wire edges!\n");
00930         }
00931         if(s2->vu_p) {
00932                 rt_bomb("nmg_js():  s2 still has verts!\n");
00933         }
00934 
00935         /* s2 is completely empty now, which is an invalid condition */
00936         nmg_ks( s2 );
00937 
00938         /* Some edges may need faceuse parity touched up. */
00939         nmg_s_radial_harmonize( s1, tol );
00940 
00941         if( rt_g.NMG_debug & DEBUG_VERIFY )
00942                 nmg_vshell( &s1->r_p->s_hd, s1->r_p );
00943 
00944         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00945                 bu_log("nmg_js(s1=x%x, s2=x%x) END\n", s1, s2);
00946         }
00947 }
00948 
00949 /**
00950  *                      N M G _ I N V E R T _ S H E L L
00951  *
00952  *  Reverse the surface normals, and invert the orientation state of
00953  *  all faceuses in a shell.
00954  *
00955  *  This turns the shell "inside out", such as might be needed for the
00956  *  right hand side term of a subtraction operation.
00957  *
00958  *  While this function is operating, the parity of faceuses radially
00959  *  around edgeuses is disrupted, hence this atomic interface to
00960  *  invert the shell.
00961  *
00962  *  The 'tol' argument is used strictly for printing.
00963  */
00964 void
00965 nmg_invert_shell(struct shell *s, const struct bn_tol *tol)
00966 {
00967         struct model    *m;
00968         struct faceuse  *fu;
00969         char            *tags;
00970 
00971         NMG_CK_SHELL(s);
00972         m = s->r_p->m_p;
00973         NMG_CK_MODEL(m);
00974         BN_CK_TOL(tol);
00975 
00976         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00977                 bu_log("nmg_invert_shell(x%x)\n", s);
00978         }
00979 
00980         /* Allocate map of faces visited */
00981         tags = bu_calloc( m->maxindex+1, 1, "nmg_invert_shell() tags[]" );
00982 
00983         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )  {
00984                 NMG_CK_FACEUSE(fu);
00985                 /* By tagging on faces, marks fu and fumate together */
00986                 if( NMG_INDEX_TEST( tags, fu->f_p ) )  continue;
00987                 NMG_INDEX_SET( tags, fu->f_p );
00988                 /* Process fu and fumate together */
00989                 nmg_reverse_face(fu);
00990         }
00991         bu_free( tags, "nmg_invert_shell() tags[]" );
00992 }
00993 
00994 /************************************************************************
00995  *                                                                      *
00996  *                              FACE Routines                           *
00997  *                                                                      *
00998  ************************************************************************/
00999 
01000 /**
01001  *                      N M G _ C M F A C E
01002  *
01003  *      Create a face with exactly one exterior loop (and no holes),
01004  *      given an array of pointers to struct vertex pointers.
01005  *      Intended to help create a "3-manifold" shell, where
01006  *      each edge has only two faces alongside of it.
01007  *      (Shades of winged edges!)
01008  *
01009  *      "verts" is an array of "n" pointers to pointers to (struct vertex).
01010  *      "s" is the parent shell for the new face.
01011  *
01012  *      The new face will consist of a single loop
01013  *      made from n edges between the n vertices.  Before an edge is created
01014  *      between a pair of verticies, we check to see if there is already an
01015  *      edge with exactly one edgeuse+mate (in this shell)
01016  *      that runs between the two verticies.
01017  *      If such an edge can be found, the newly created edgeuses will just
01018  *      use the existing edge.
01019  *      This means that no special call to nmg_gluefaces() is needed later.
01020  *
01021  *      If a pointer in verts is a pointer to a null vertex pointer, a new
01022  *      vertex is created.  In this way, new verticies can be created
01023  *      conveniently within a user's list of known verticies
01024  *
01025  *      verts           pointers to struct vertex           vertex structs
01026  *
01027  *      -------         --------
01028  *   0  |  +--|-------->|   +--|--------------------------> (struct vertex)
01029  *      -------         --------        ---------
01030  *   1  |  +--|------------------------>|   +---|---------> (struct vertex)
01031  *      -------         --------        ---------
01032  *   2  |  +--|-------->|   +--|--------------------------> (struct vertex)
01033  *      -------         --------
01034  *  ...
01035  *      -------                         ---------
01036  *   n  |  +--|------------------------>|   +---|---------> (struct vertex)
01037  *      -------                         ---------
01038  *
01039  *
01040  *      The vertices *must* be listed in "counter-clockwise" (CCW) order.
01041  *      This routine makes only topology, without reference to any geometry.
01042  *
01043  *      Note that this routine inserts new vertices (by edge use splitting)
01044  *      at the head of the loop, which reverses the order.
01045  *      Therefore, the caller's vertices are traversed in reverse order
01046  *      to counter this behavior, and
01047  *      to effect the proper vertex order in the final face loop.
01048  *
01049  *      Also note that this routine uses one level more of indirection
01050  *      in the verts[] array than nmg_cface().
01051  *
01052  *  Recent improvement: the lu's list of eu's traverses the
01053  *  verts[] array in order specified by the caller.  Imagine that.
01054  */
01055 struct faceuse *
01056 nmg_cmface(struct shell *s, struct vertex ***verts, int n)
01057 {
01058         struct faceuse *fu;
01059         struct edgeuse *eu, *eur, *euold = NULL;
01060         struct loopuse  *lu;
01061         struct vertexuse        *vu;
01062         int i;
01063 
01064         NMG_CK_SHELL(s);
01065 
01066         if (n < 1) {
01067                 bu_log("nmg_cmface(s=x%x, verts=x%x, n=%d.)\n",
01068                         s, verts, n );
01069                 rt_bomb("nmg_cmface() trying to make bogus face\n");
01070         }
01071 
01072         /* make sure verts points to some real storage */
01073         if (!verts) {
01074                 bu_log("nmg_cmface(s=x%x, verts=x%x, n=%d.) null pointer to array start\n",
01075                         s, verts, n );
01076                 rt_bomb("nmg_cmface\n");
01077         }
01078 
01079         /* validate each of the pointers in verts */
01080         for (i=0 ; i < n ; ++i) {
01081                 if (verts[i]) {
01082                         if (*verts[i]) {
01083                                 /* validate the vertex pointer */
01084                                 NMG_CK_VERTEX(*verts[i]);
01085                         }
01086                 } else {
01087                         bu_log("nmg_cmface(s=x%x, verts=x%x, n=%d.) verts[%d]=NULL\n",
01088                                 s, verts, n, i );
01089                         rt_bomb("nmg_cmface\n");
01090                 }
01091         }
01092 
01093         lu = nmg_mlv(&s->l.magic, *verts[0], OT_SAME);
01094         fu = nmg_mf(lu);
01095         fu->orientation = OT_SAME;
01096         fu->fumate_p->orientation = OT_OPPOSITE;
01097         vu = BU_LIST_FIRST( vertexuse, &lu->down_hd);
01098         NMG_CK_VERTEXUSE(vu);
01099         eu = nmg_meonvu(vu);
01100         NMG_CK_EDGEUSE(eu);
01101 
01102         if (!(*verts[0]))  {
01103                 NMG_CK_VERTEXUSE(eu->vu_p);
01104                 NMG_CK_VERTEX(eu->vu_p->v_p);
01105                 *verts[0] = eu->vu_p->v_p;
01106         }
01107 
01108         for (i = n-1 ; i > 0 ; i--) {
01109                 /* Get the edgeuse most recently created */
01110                 euold = BU_LIST_FIRST( edgeuse, &lu->down_hd );
01111                 NMG_CK_EDGEUSE(euold);
01112 
01113                 if (rt_g.NMG_debug & DEBUG_CMFACE)
01114                         bu_log("nmg_cmface() euold: %8x\n", euold);
01115 
01116                 /* look for pre-existing edge between these
01117                  * verticies
01118                  */
01119                 if (*verts[i]) {
01120                         /* look for an existing edge to share */
01121                         eur = nmg_findeu(*verts[(i+1)%n], *verts[i], s, euold, 1);
01122                         eu = nmg_eusplit(*verts[i], euold, 0);
01123                         if (eur) {
01124                                 nmg_je(eur, eu);
01125 
01126                                 if (rt_g.NMG_debug & DEBUG_CMFACE)
01127                                         bu_log("nmg_cmface() found another edgeuse (%8x) between %8x and %8x\n",
01128                                                 eur, *verts[(i+1)%n], *verts[i]);
01129                         } else {
01130                                 if (rt_g.NMG_debug & DEBUG_CMFACE)
01131                                     bu_log("nmg_cmface() didn't find edge from verts[%d]%8x to verts[%d]%8x\n",
01132                                         i+1, *verts[(i+1)%n], i, *verts[i]);
01133                         }
01134                 } else {
01135                         eu = nmg_eusplit(*verts[i], euold, 0);
01136                         *verts[i] = eu->vu_p->v_p;
01137 
01138                         if (rt_g.NMG_debug & DEBUG_CMFACE)  {
01139                                 bu_log("nmg_cmface() *verts[%d] was null, is now %8x\n",
01140                                         i, *verts[i]);
01141                         }
01142                 }
01143         }
01144 
01145         if( n > 1 )  {
01146                 if ((eur = nmg_findeu(*verts[0], *verts[1], s, euold, 1)))  {
01147                         nmg_je(eur, euold);
01148                 } else  {
01149                     if (rt_g.NMG_debug & DEBUG_CMFACE)
01150                         bu_log("nmg_cmface() didn't find edge from verts[%d]%8x to verts[%d]%8x\n",
01151                                 0, *verts[0], 1, *verts[1]);
01152                 }
01153         }
01154 
01155         if(rt_g.NMG_debug & DEBUG_BASIC)  {
01156                 /* Sanity check */
01157                 euold = BU_LIST_FIRST( edgeuse, &lu->down_hd );
01158                 NMG_CK_EDGEUSE(euold);
01159                 if( euold->vu_p->v_p != *verts[0] )  {
01160                         bu_log("ERROR nmg_cmface() lu first vert s/b x%x, was x%x\n",
01161                                 *verts[0], euold->vu_p->v_p );
01162                         for( i=0; i < n; i++ )  {
01163                                 bu_log("  *verts[%2d]=x%x, eu->vu_p->v_p=x%x\n",
01164                                         i, *verts[i], euold->vu_p->v_p);
01165                                 euold = BU_LIST_PNEXT_CIRC( edgeuse, &euold->l );
01166                         }
01167                         rt_bomb("nmg_cmface() bogus eu ordering\n");
01168                 }
01169         }
01170 
01171         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01172                 bu_log("nmg_cmface(s=x%x, verts[]=x%x, n=%d) fu=x%x\n",
01173                         s, verts, n, fu);
01174         }
01175         return (fu);
01176 }
01177 
01178 /**
01179  *                      N M G _ C F A C E
01180  *
01181  *      Create a loop within a face, given a list of vertices.
01182  *
01183  *      "verts" is an array of "n" pointers to (struct vertex).  "s" is the
01184  *      parent shell for the new face.  The face will consist of a single loop
01185  *      made from edges between the n vertices.
01186  *
01187  *      If verts is a null pointer (no vertex list), all vertices of the face
01188  *      will be new points.  Otherwise, verts is a pointer to a list of
01189  *      vertices to use in creating the face/loop.  Null entries within the
01190  *      list will cause a new vertex to be created for that point.  Such new
01191  *      vertices will be inserted into the list for return to the caller.
01192  *
01193  *      The vertices should be listed in
01194  *      "counter-clockwise" (CCW) order if this is an ordinary face (loop),
01195  *      and in "clockwise" (CW) order if this is an interior
01196  *      ("hole" or "subtracted") face (loop).
01197  *      This routine makes only topology, without reference to any geometry.
01198  *
01199  *      Note that this routine inserts new vertices (by edge use splitting)
01200  *      at the head of the loop, which reverses the order.
01201  *      Therefore, the caller's vertices are traversed in reverse order
01202  *      to counter this behavior, and
01203  *      to effect the proper vertex order in the final face loop.
01204  */
01205 struct faceuse *
01206 nmg_cface(struct shell *s, struct vertex **verts, int n)
01207 {
01208         struct faceuse *fu;
01209         struct edgeuse *eu;
01210         struct loopuse  *lu;
01211         struct vertexuse *vu;
01212         int i;
01213 
01214         NMG_CK_SHELL(s);
01215         if (n < 1) {
01216                 bu_log("nmg_cface(s=x%x, verts=x%x, n=%d.)\n",
01217                         s, verts, n );
01218                 rt_bomb("nmg_cface() trying to make bogus face\n");
01219         }
01220 
01221         if (verts) {
01222                 for (i=0 ; i < n ; ++i) {
01223                         if (verts[i]) {
01224                                 NMG_CK_VERTEX(verts[i]);
01225                         }
01226                 }
01227                 lu = nmg_mlv(&s->l.magic, verts[n-1], OT_SAME);
01228                 fu = nmg_mf(lu);
01229                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
01230                 eu = nmg_meonvu(vu);
01231 
01232                 if (!verts[n-1])
01233                         verts[n-1] = eu->vu_p->v_p;
01234 
01235                 for (i = n-2 ; i >= 0 ; i--) {
01236                         eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
01237                         eu = nmg_eusplit(verts[i], eu, 0);
01238                         if (!verts[i])
01239                                 verts[i] = eu->vu_p->v_p;
01240                 }
01241 
01242         } else {
01243                 lu = nmg_mlv(&s->l.magic, (struct vertex *)NULL, OT_SAME);
01244                 fu = nmg_mf(lu);
01245                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
01246                 eu = nmg_meonvu(vu);
01247                 while (--n) {
01248                         (void)nmg_eusplit((struct vertex *)NULL, eu, 0);
01249                 }
01250         }
01251         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01252                 bu_log("nmg_cface(s=x%x, verts[]=x%x, n=%d) fu=x%x\n",
01253                         s, verts, n, fu);
01254         }
01255         return (fu);
01256 }
01257 
01258 /**
01259  *                      N M G _ A D D _ L O O P _ T O _ F A C E
01260  *
01261  *      Create a new loop within a face, given a list of vertices.
01262  *      Modified version of nmg_cface().
01263  *
01264  *      "verts" is an array of "n" pointers to (struct vertex).  "s" is the
01265  *      parent shell for the new face.  The face will consist of a single loop
01266  *      made from edges between the n vertices.
01267  *
01268  *      If verts is a null pointer (no vertex list), all vertices of the face
01269  *      will be new points.  Otherwise, verts is a pointer to a list of
01270  *      vertices to use in creating the face/loop.  Null entries within the
01271  *      list will cause a new vertex to be created for that point.  Such new
01272  *      vertices will be inserted into the list for return to the caller.
01273  *
01274  *      The vertices should be listed in "counter-clockwise" (CCW) order if
01275  *      this is an ordinary face (loop), and in "clockwise" (CW) order if
01276  *      this is an interior ("hole" or "subtracted") face (loop).  This
01277  *      routine makes only topology, without reference to any geometry.
01278  *
01279  *      Note that this routine inserts new vertices (by edge use splitting)
01280  *      at the head of the loop, which reverses the order.  Therefore, the
01281  *      caller's vertices are traversed in reverse order to counter this
01282  *      behavior, and to effect the proper vertex order in the final face
01283  *      loop.
01284  */
01285 struct faceuse *
01286 nmg_add_loop_to_face(struct shell *s, struct faceuse *fu, struct vertex **verts, int n, int dir)
01287 {
01288         int i;
01289         struct edgeuse *eu;
01290         struct loopuse *lu;
01291         struct vertexuse *vu;
01292 
01293         NMG_CK_SHELL(s);
01294         if (n < 1) {
01295                 bu_log("nmg_add_loop_to_face(s=x%x, verts=x%x, n=%d.)\n",
01296                         s, verts, n );
01297                 rt_bomb("nmg_add_loop_to_face: request to make 0 faces\n");
01298         }
01299 
01300         if (verts) {
01301                 if (!fu) {
01302                         lu = nmg_mlv(&s->l.magic, verts[n-1], dir);
01303                         fu = nmg_mf(lu);
01304                 } else {
01305                         lu = nmg_mlv(&fu->l.magic, verts[n-1], dir);
01306                 }
01307                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
01308                 eu = nmg_meonvu(vu);
01309                 if (!verts[n-1])
01310                         verts[n-1] = eu->vu_p->v_p;
01311 
01312                 for (i = n-2 ; i >= 0 ; i--) {
01313                         eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
01314                         eu = nmg_eusplit(verts[i], eu, 0);
01315                         if (!verts[i])
01316                                 verts[i] = eu->vu_p->v_p;
01317                 }
01318         } else {
01319                 if (!fu) {
01320                         lu = nmg_mlv(&s->l.magic, (struct vertex *)NULL, dir);
01321                         fu = nmg_mf(lu);
01322                 } else {
01323                         lu = nmg_mlv(&fu->l.magic, (struct vertex *)NULL, dir);
01324                 }
01325                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
01326                 eu = nmg_meonvu(vu);
01327                 while (--n) {
01328                         (void)nmg_eusplit((struct vertex *)NULL, eu, 0);
01329                 }
01330         }
01331         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01332                 bu_log("nmg_add_loop_to_face(s=x%x, fu=x%x, verts[]=x%x, n=%d, %s) fu=x%x\n",
01333                         s, fu, verts, n,
01334                         nmg_orientation(dir) );
01335         }
01336         return (fu);
01337 }
01338 
01339 /**
01340  *                      N M G _ F U _ P L A N E E Q N
01341  *
01342  *  Given a convex face that has been constructed with edges listed in
01343  *  counter-clockwise (CCW) order, compute the surface normal and plane
01344  *  equation for this face.
01345  *
01346  *
01347  *                      D                   C
01348  *                      *-------------------*
01349  *                      |                   |
01350  *                      |   .<...........   |
01351  *         ^     N      |   .           ^   |     ^
01352  *         |      \     |   .  counter- .   |     |
01353  *         |       \    |   .   clock   .   |     |
01354  *         |C-B     \   |   .   wise    .   |     |C-B
01355  *         |         \  |   v           .   |     |
01356  *         |          \ |   ...........>.   |     |
01357  *                     \|                   |
01358  *                      *-------------------*
01359  *                      A                   B
01360  *                            <-----
01361  *                              A-B
01362  *
01363  *  If the vertices in the loop are given in the order A B C D
01364  *  (e.g., counter-clockwise),
01365  *  then the outward pointing surface normal can be computed as:
01366  *
01367  *              N = (C-B) x (A-B)
01368  *
01369  *  This is the "right hand rule".
01370  *  For reference, note that a vector which points "into" the loop
01371  *  can be subsequently found by taking the cross product of the
01372  *  surface normal and any edge vector, e.g.:
01373  *
01374  *              Left = N x (B-A)
01375  *      or      Left = N x (C-B)
01376  *
01377  *  This routine will skip on past edges that start and end on
01378  *  the same vertex, in an attempt to avoid trouble.
01379  *  However, the loop *must* be convex for this routine to work.
01380  *  Otherwise, the surface normal may be inadvertently reversed.
01381  *
01382  *  Returns -
01383  *      0       OK
01384  *      -1      failure
01385  */
01386 int
01387 nmg_fu_planeeqn(struct faceuse *fu, const struct bn_tol *tol)
01388 {
01389         struct edgeuse          *eu, *eu_final, *eu_next;
01390         struct loopuse          *lu;
01391         plane_t                 plane;
01392         struct vertex           *a, *b, *c;
01393         register int            both_equal;
01394 
01395         BN_CK_TOL(tol);
01396 
01397         NMG_CK_FACEUSE(fu);
01398         lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
01399         NMG_CK_LOOPUSE(lu);
01400 
01401         if( BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC )
01402         {
01403                 bu_log( "nmg_fu_planeeqn(): First loopuse does not contain edges\n" );
01404                 return(-1);
01405         }
01406         eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
01407         NMG_CK_EDGEUSE(eu);
01408         NMG_CK_VERTEXUSE(eu->vu_p);
01409         a = eu->vu_p->v_p;
01410         NMG_CK_VERTEX(a);
01411         NMG_CK_VERTEX_G(a->vg_p);
01412 
01413         eu_next = eu;
01414         do {
01415                 eu_next = BU_LIST_PNEXT_CIRC(edgeuse, eu_next);
01416                 NMG_CK_EDGEUSE(eu_next);
01417                 if( eu_next == eu )
01418                 {
01419                         bu_log( "nmg_fu_planeeqn(): First loopuse contains only one edgeuse\n" );
01420                         return -1;
01421                 }
01422                 NMG_CK_VERTEXUSE(eu_next->vu_p);
01423                 b = eu_next->vu_p->v_p;
01424                 NMG_CK_VERTEX(b);
01425                 NMG_CK_VERTEX_G(b->vg_p);
01426         } while( (b == a
01427                 || bn_pt3_pt3_equal(a->vg_p->coord, b->vg_p->coord, tol))
01428                 && eu_next->vu_p != eu->vu_p );
01429 
01430         eu_final = eu_next;
01431         do {
01432                 eu_final = BU_LIST_PNEXT_CIRC(edgeuse, eu_final);
01433                 NMG_CK_EDGEUSE(eu_final);
01434                 if( eu_final == eu )
01435                 {
01436                         bu_log( "nmg_fu_planeeqn(): Cannot find three distinct vertices\n" );
01437                         return -1;
01438                 }
01439                 NMG_CK_VERTEXUSE(eu_final->vu_p);
01440                 c = eu_final->vu_p->v_p;
01441                 NMG_CK_VERTEX(c);
01442                 NMG_CK_VERTEX_G(c->vg_p);
01443                 both_equal = (c == b) ||
01444                     bn_pt3_pt3_equal(a->vg_p->coord, c->vg_p->coord, tol) ||
01445                     bn_pt3_pt3_equal(b->vg_p->coord, c->vg_p->coord, tol);
01446         } while( (both_equal
01447                 || bn_3pts_collinear(a->vg_p->coord, b->vg_p->coord,
01448                         c->vg_p->coord, tol))
01449                 && eu_next->vu_p != eu->vu_p );
01450 
01451         if (bn_mk_plane_3pts(plane,
01452             a->vg_p->coord, b->vg_p->coord, c->vg_p->coord, tol) < 0 ) {
01453                 bu_log("nmg_fu_planeeqn(): bn_mk_plane_3pts failed on (%g,%g,%g) (%g,%g,%g) (%g,%g,%g)\n",
01454                         V3ARGS( a->vg_p->coord ),
01455                         V3ARGS( b->vg_p->coord ),
01456                         V3ARGS( c->vg_p->coord ) );
01457                 HPRINT("plane", plane);
01458                 return(-1);
01459         }
01460         if (plane[0] == 0.0 && plane[1] == 0.0 && plane[2] == 0.0) {
01461                 bu_log("nmg_fu_planeeqn():  Bad plane equation from bn_mk_plane_3pts\n" );
01462                 HPRINT("plane", plane);
01463                 return(-1);
01464         }
01465         nmg_face_g( fu, plane);
01466 
01467         /* Check and make sure all verts are within tol->dist of face */
01468         if( nmg_ck_fu_verts( fu, fu->f_p, tol ) != 0 )  {
01469                 bu_log("nmg_fu_planeeqn(fu=x%x) ERROR, verts are not within tol of face\n" , fu );
01470                 return -1;
01471         }
01472 
01473         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01474                 bu_log("nmg_fu_planeeqn(fu=x%x, tol=x%x)\n", fu, tol);
01475         }
01476         return(0);
01477 }
01478 
01479 /**
01480  *                      N M G _ G L U E F A C E S
01481  *
01482  *      given a shell containing "n" faces whose outward oriented faceuses are
01483  *      enumerated in "fulist", glue the edges of the faces together
01484  *      Most especially useful after using nmg_cface() several times to
01485  *      make faces which share vertex structures.
01486  *
01487  */
01488 void
01489 nmg_gluefaces(struct faceuse **fulist, int n, const struct bn_tol *tol)
01490 {
01491         struct shell    *s;
01492         struct loopuse  *lu;
01493         struct edgeuse  *eu;
01494         int             i;
01495         int             f_no;           /* Face number */
01496 
01497         NMG_CK_FACEUSE(fulist[0]);
01498         s = fulist[0]->s_p;
01499         NMG_CK_SHELL(s);
01500 
01501         /* First, perform some checks */
01502         for (i = 0 ; i < n ; ++i) {
01503                 register struct faceuse *fu;
01504 
01505                 fu = fulist[i];
01506                 NMG_CK_FACEUSE(fu);
01507                 if (fu->s_p != s) {
01508                         bu_log("nmg_gluefaces() in %s at %d. faceuses don't share parent\n",
01509                                 __FILE__, __LINE__);
01510                         rt_bomb("nmg_gluefaces\n");
01511                 }
01512         }
01513 
01514         for (i=0 ; i < n ; ++i) {
01515                 for( BU_LIST_FOR( lu , loopuse , &fulist[i]->lu_hd ) ) {
01516                         NMG_CK_LOOPUSE( lu );
01517 
01518                         if( BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC )
01519                                 continue;
01520 
01521                         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
01522                                 for( f_no = i+1; f_no < n; f_no++ )  {
01523                                         struct loopuse          *lu2;
01524                                         register struct edgeuse *eu2;
01525 
01526                                         for( BU_LIST_FOR( lu2 , loopuse , &fulist[f_no]->lu_hd ) ) {
01527                                                 NMG_CK_LOOPUSE( lu2 );
01528                                                 if( BU_LIST_FIRST_MAGIC(&lu2->down_hd) != NMG_EDGEUSE_MAGIC )
01529                                                         continue;
01530                                                 for( BU_LIST_FOR( eu2, edgeuse, &lu2->down_hd ) )  {
01531                                                         if (EDGESADJ(eu, eu2))
01532                                                                 nmg_radial_join_eu(eu, eu2, tol);
01533                                                 }
01534                                         }
01535                                 }
01536                         }
01537                 }
01538         }
01539 
01540         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01541                 bu_log("nmg_gluefaces(fulist=x%x, n=%d)\n", fulist, n);
01542         }
01543 }
01544 
01545 
01546 /**                     N M G _ S I M P L I F Y _ F A C E
01547  *
01548  *
01549  *      combine adjacent loops within a face which serve no apparent purpose
01550  *      by remaining separate and distinct.  Kill "wire-snakes" in face.
01551  *
01552  * Returns -
01553  *      0       If all was OK
01554  *      1       If faceuse is now empty
01555  */
01556 int
01557 nmg_simplify_face(struct faceuse *fu)
01558 {
01559         struct loopuse *lu;
01560         int ret_val;
01561 
01562         NMG_CK_FACEUSE(fu);
01563 
01564         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd))  {
01565                 nmg_simplify_loop(lu);
01566         }
01567 
01568         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd))  {
01569                 if( nmg_kill_snakes(lu) )  {
01570                         struct loopuse  *klu = lu;
01571                         lu = BU_LIST_PREV( loopuse, &lu->l );
01572                         nmg_klu(klu);
01573                 }
01574         }
01575 
01576         ret_val = BU_LIST_IS_EMPTY(&fu->lu_hd);
01577 
01578         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01579                 bu_log("nmg_simplify_face(fut=x%x) return=%d\n", fu, ret_val);
01580         }
01581 
01582         return( ret_val );
01583 }
01584 
01585 /**
01586  *                      N M G _ R E V E R S E _ F A C E
01587  *
01588  *
01589  *  This routine reverses the direction of the Normal vector which defines
01590  *  the plane of the face.
01591  *
01592  *  The OT_SAME faceuse becomes the OT_OPPOSITE faceuse, and vice versa.
01593  *  This preserves the convention that OT_SAME loopuses in the
01594  *  OT_SAME faceuse are counter-clockwise rotating about the surface normal.
01595  *
01596  *
01597  *           Before                     After
01598  *
01599  *
01600  * N      OT_SAME                 OT_OPPOSITE
01601  *  \   .<---------.            .<---------.
01602  *   \  |fu        ^            |fu        ^
01603  *    \ |  .------ | ->.        |  .------ | ->.
01604  *     \|  ^fumate |   |        |  ^fumate |   |
01605  *      |  |       |   |        |  |       |   |
01606  *      |  |       |   |        |  |       |   |
01607  *      V  |       |   |        V  |       |   |\
01608  *      .--------->.   |        .--------->.   | \
01609  *         |           V           |           V  \
01610  *         .<----------.           .<----------.   \
01611  *          OT_OPPOSITE              OT_SAME        \
01612  *                                                   N
01613  *
01614  *
01615  *  Also note that this reverses the same:opposite:opposite:same
01616  *  parity radially around each edge.  This can create parity errors
01617  *  until all faces of this shell have been processed.
01618  *
01619  *  Applications programmers should use nmg_invert_shell(),
01620  *  which does not have this problem.
01621  *  This routine is for internal use only.
01622  */
01623 void
01624 nmg_reverse_face(register struct faceuse *fu)
01625 {
01626         register struct faceuse *fumate;
01627 
01628         NMG_CK_FACEUSE(fu);
01629         fumate = fu->fumate_p;
01630         NMG_CK_FACEUSE(fumate);
01631         NMG_CK_FACE(fu->f_p);
01632         NMG_CK_FACE_G_EITHER(fu->f_p->g.magic_p);
01633 
01634         /* reverse face normal vector */
01635         fu->f_p->flip = !fu->f_p->flip;
01636 
01637         /* switch which face is "outside" face */
01638         if (fu->orientation == OT_SAME)  {
01639                 if (fumate->orientation != OT_OPPOSITE)  {
01640                         bu_log("nmg_reverse_face(fu=x%x) fu:SAME, fumate:%d\n",
01641                                 fu, fumate->orientation);
01642                         rt_bomb("nmg_reverse_face() orientation clash\n");
01643                 } else {
01644                         fu->orientation = OT_OPPOSITE;
01645                         fumate->orientation = OT_SAME;
01646                 }
01647         } else if (fu->orientation == OT_OPPOSITE) {
01648                 if (fumate->orientation != OT_SAME)  {
01649                         bu_log("nmg_reverse_face(fu=x%x) fu:OPPOSITE, fumate:%d\n",
01650                                 fu, fumate->orientation);
01651                         rt_bomb("nmg_reverse_face() orientation clash\n");
01652                 } else {
01653                         fu->orientation = OT_SAME;
01654                         fumate->orientation = OT_OPPOSITE;
01655                 }
01656         } else {
01657                 /* Unoriented face? */
01658                 bu_log("ERROR nmg_reverse_face(fu=x%x), orientation=%d.\n",
01659                         fu, fu->orientation );
01660         }
01661 
01662         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01663                 bu_log("nmg_reverse_face(fu=x%x) fumate=x%x\n", fu, fumate);
01664         }
01665 }
01666 
01667 #if 0
01668 /**
01669  * XXX Called in nmg_misc.c / nmg_reverse_face_and_radials()
01670  *                      N M G _ F A C E _ F I X _ R A D I A L _ P A R I T Y
01671  *
01672  *  Around an edge, consider all the edgeuses that belong to a single shell.
01673  *  The faceuses pertaining to those edgeuses must maintain the appropriate
01674  *  parity with their radial faceuses, so that OT_SAME is always radial to
01675  *  OT_SAME, and OT_OPPOSITE is always radial to OT_OPPOSITE.
01676  *
01677  *  If a radial edgeuse is encountered that belongs to *this* face, then
01678  *  it might not have been processed by this routine yet, and is ignored
01679  *  for the purposes of checking parity.
01680  *
01681  *  When moving faces between shells, sometimes this parity relationship
01682  *  needs to be fixed, which can be easily accomplished by exchanging
01683  *  the incorrect edgeuse with it's mate in the radial edge linkages.
01684  *
01685  *  XXX Note that this routine will not work right in the presence of
01686  *  XXX dangling faces.
01687  *
01688  *  Note that this routine can't be used incrementally, because
01689  *  after an odd number (like one) of faceuses have been "fixed",
01690  *  there is an inherrent parity error, which will cause wrong
01691  *  decisions to be made.  Therefore, *all* faces have to be moved from
01692  *  one shell to another before the radial parity can be "fixed".
01693  *  Even then, this isn't going to work right unless we are given
01694  *  a list of all the "suspect" faceuses, so the initial parity
01695  *  value can be properly established.
01696  *
01697  *  XXXX I am of the opinion this routine is neither useful nor correct
01698  *  XXXX in it's present form, except for limited special cases.
01699  *
01700  *  The 'tol' arg is used strictly for printing purposes.
01701  *
01702  *  Returns -
01703  *      count of number of edges fixed.
01704  */
01705 int
01706 nmg_face_fix_radial_parity( fu, tol )
01707 struct faceuse          *fu;
01708 const struct bn_tol     *tol;
01709 {
01710         struct loopuse *lu;
01711         struct edgeuse *eu;
01712         struct faceuse *fu2;
01713         struct shell    *s;
01714         long            count = 0;
01715 
01716         NMG_CK_FACEUSE( fu );
01717         s = fu->s_p;
01718         NMG_CK_SHELL(s);
01719         BN_CK_TOL(tol);
01720 
01721         /* Make sure we are now dealing with the OT_SAME faceuse */
01722         if( fu->orientation == OT_SAME )
01723                 fu2 = fu;
01724         else
01725                 fu2 = fu->fumate_p;
01726 
01727         for( BU_LIST_FOR( lu , loopuse , &fu2->lu_hd ) )  {
01728                 NMG_CK_LOOPUSE( lu );
01729 
01730                 /* skip loops of a single vertex */
01731                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
01732                         continue;
01733 
01734                 /*
01735                  *  Consider every edge of this loop.
01736                  *  Initial sequencing is:
01737                  *    before(radial), eu, eumate, after(radial)
01738                  */
01739                 for( BU_LIST_FOR( eu , edgeuse , &lu->down_hd ) )  {
01740                         struct edgeuse  *eumate;
01741                         struct edgeuse  *before;
01742                         struct edgeuse  *sbefore;       /* searched before */
01743                         struct edgeuse  *after;
01744 
01745                         eumate = eu->eumate_p;
01746                         before = eu->radial_p;
01747                         after = eumate->radial_p;
01748                         NMG_CK_EDGEUSE(eumate);
01749                         NMG_CK_EDGEUSE(before);
01750                         NMG_CK_EDGEUSE(after);
01751 
01752                         /* If no other edgeuses around edge, done. */
01753                         if( before == eumate )
01754                                 continue;
01755 
01756                         /*
01757                          *  Search in 'before' direction, until it's in
01758                          *  same shell.  Also ignore edgeuses from this FACE,
01759                          *  as they may not have been fixed yet.
01760                          */
01761                         for( sbefore = before;
01762                              sbefore != eu && sbefore != eumate;
01763                              sbefore = sbefore->eumate_p->radial_p
01764                         )  {
01765                                 struct faceuse  *bfu;
01766                                 if( nmg_find_s_of_eu(sbefore) != s )  continue;
01767 
01768                                 bfu = nmg_find_fu_of_eu(sbefore);
01769                                 /* If edgeuse isn't part of a faceuse, skip */
01770                                 if( !bfu )  continue;
01771                                 if( bfu->f_p == fu->f_p )  continue;
01772                                 /* Found a candidate */
01773                                 break;
01774                         }
01775 
01776                         /* If search found no others from this shell, done. */
01777                         if( sbefore == eu || sbefore == eumate )
01778                                 continue;
01779 
01780                         /*
01781                          *  'eu' is in an OT_SAME faceuse.
01782                          *  If the first faceuse in the 'before' direction
01783                          *  from this shell is OT_SAME, no fix is required.
01784                          */
01785                         if( sbefore->up.lu_p->up.fu_p->orientation == OT_SAME )
01786                                 continue;
01787 
01788 #if 0
01789 bu_log("sbefore eu=x%x, before=x%x, eu=x%x, eumate=x%x, after=x%x\n",
01790                         sbefore, before, eu, eumate, after );
01791 nmg_pr_fu_around_eu(eu, tol );
01792 #endif
01793                         /*
01794                          *  Rearrange order to be: before, eumate, eu, after.
01795                          *  NOTE: do NOT use sbefore here.
01796                          */
01797                         before->radial_p = eumate;
01798                         eumate->radial_p = before;
01799 
01800                         after->radial_p = eu;
01801                         eu->radial_p = after;
01802                         count++;
01803                         if( rt_g.NMG_debug & DEBUG_BASIC )  {
01804                                 bu_log("nmg_face_fix_radial_parity() exchanging eu=x%x & eumate=x%x on edge x%x\n",
01805                                         eu, eumate, eu->e_p);
01806                         }
01807 #if 0
01808                         /* Can't do this incrementally, it blows up after 1st "fix" */
01809                         if( rt_g.NMG_debug )  {
01810 nmg_pr_fu_around_eu(eu, tol );
01811                                 if( nmg_check_radial( eu, tol ) )
01812                                         rt_bomb("nmg_face_fix_radial_parity(): nmg_check_radial failed\n");
01813                         }
01814 #endif
01815                 }
01816         }
01817 
01818         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01819                 bu_log("nmg_face_fix_radial_parity(fu=x%x) returns %d\n", fu, count);
01820         }
01821 
01822         return count;
01823 }
01824 #endif
01825 
01826 /**
01827  *                      N M G _ M V _ F U _ B E T W E E N _ S H E L L S
01828  *
01829  *  Move faceuse from 'src' shell to 'dest' shell.
01830  */
01831 void
01832 nmg_mv_fu_between_shells(struct shell *dest, register struct shell *src, register struct faceuse *fu)
01833 {
01834         register struct faceuse *fumate;
01835 
01836         NMG_CK_FACEUSE(fu);
01837         fumate = fu->fumate_p;
01838         NMG_CK_FACEUSE(fumate);
01839 
01840         if (fu->s_p != src) {
01841                 bu_log("nmg_mv_fu_between_shells(dest=x%x, src=x%x, fu=x%x), fu->s_p=x%x isnt src shell\n",
01842                         dest, src, fu, fu->s_p );
01843                 rt_bomb("fu->s_p isnt source shell\n");
01844         }
01845         if (fumate->s_p != src) {
01846                 bu_log("nmg_mv_fu_between_shells(dest=x%x, src=x%x, fu=x%x), fumate->s_p=x%x isn't src shell\n",
01847                         dest, src, fu, fumate->s_p );
01848                 rt_bomb("fumate->s_p isnt source shell\n");
01849         }
01850 
01851         /* Remove fu from src shell */
01852         BU_LIST_DEQUEUE( &fu->l );
01853         if( BU_LIST_IS_EMPTY( &src->fu_hd ) )  {
01854                 /* This was the last fu in the list, bad news */
01855                 bu_log("nmg_mv_fu_between_shells(dest=x%x, src=x%x, fu=x%x), fumate=x%x not in src shell\n",
01856                         dest, src, fu, fumate );
01857                 rt_bomb("src shell emptied before finding fumate\n");
01858         }
01859 
01860         /* Remove fumate from src shell */
01861         BU_LIST_DEQUEUE( &fumate->l );
01862 
01863         /*
01864          * Add fu and fumate to dest shell,
01865          * preserving implicit OT_SAME, OT_OPPOSITE order
01866          */
01867         if( fu->orientation == OT_SAME )  {
01868                 BU_LIST_APPEND( &dest->fu_hd, &fu->l );
01869                 BU_LIST_APPEND( &fu->l, &fumate->l );
01870         } else {
01871                 BU_LIST_APPEND( &dest->fu_hd, &fumate->l );
01872                 BU_LIST_APPEND( &fumate->l, &fu->l );
01873         }
01874 
01875         fu->s_p = dest;
01876         fumate->s_p = dest;
01877 
01878         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01879                 bu_log("nmg_mv_fu_between_shells(dest=x%x, src=x%x, fu=x%x)\n", dest , src , fu);
01880         }
01881 }
01882 
01883 /**
01884  *                      N M G _ M O V E _ F U _ F U
01885  *
01886  *  Move everything from the source faceuse into the destination faceuse.
01887  *  Exists as a support routine for nmg_jf() only.
01888  */
01889 static void
01890 nmg_move_fu_fu(register struct faceuse *dest_fu, register struct faceuse *src_fu)
01891 {
01892         register struct loopuse *lu;
01893 
01894         NMG_CK_FACEUSE(dest_fu);
01895         NMG_CK_FACEUSE(src_fu);
01896 
01897         if( dest_fu->orientation != src_fu->orientation )
01898                 rt_bomb("nmg_move_fu_fu: differing orientations\n");
01899 
01900         /* Move all loopuses from src to dest faceuse */
01901         while( BU_LIST_WHILE( lu, loopuse, &src_fu->lu_hd ) )  {
01902                 BU_LIST_DEQUEUE( &(lu->l) );
01903                 BU_LIST_INSERT( &(dest_fu->lu_hd), &(lu->l) );
01904                 lu->up.fu_p = dest_fu;
01905         }
01906         /* The src_fu is invalid here, with an empty lu_hd list */
01907 
01908         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01909                 bu_log("nmg_move_fu_fu(dest_fu=x%x, src_fu=x%x)\n", dest_fu , src_fu);
01910         }
01911 }
01912 
01913 /**
01914  *                      N M G _ J F
01915  *
01916  *  Join two faces together by
01917  *  moving everything from the source faceuse and mate into the
01918  *  destination faceuse and mate, taking into account face orientations.
01919  *  The source face is destroyed by this operation.
01920  */
01921 void
01922 nmg_jf(register struct faceuse *dest_fu, register struct faceuse *src_fu)
01923 {
01924         NMG_CK_FACEUSE(dest_fu);
01925         NMG_CK_FACEUSE(src_fu);
01926 
01927         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01928                 bu_log("nmg_jf(dest_fu=x%x, src_fu=x%x)\n", dest_fu, src_fu);
01929         }
01930 
01931         if( src_fu->f_p == dest_fu->f_p )
01932                 rt_bomb("nmg_jf() src and dest faces are the same\n");
01933 
01934         if( dest_fu->orientation == src_fu->orientation )  {
01935                 nmg_move_fu_fu(dest_fu, src_fu);
01936                 nmg_move_fu_fu(dest_fu->fumate_p, src_fu->fumate_p);
01937         } else {
01938                 nmg_move_fu_fu(dest_fu, src_fu->fumate_p);
01939                 nmg_move_fu_fu(dest_fu->fumate_p, src_fu);
01940         }
01941         /* The src_fu is invalid here, having an empty lu_hd list */
01942         nmg_kfu(src_fu);
01943 
01944 }
01945 
01946 /**
01947  *                      N M G _ D U P _ F A C E
01948  *
01949  *  Construct a duplicate of a face into the shell 's'.
01950  *  The vertex geometry is copied from the source face into topologically
01951  *  distinct (new) vertex and vertex_g structs.
01952  *  They will start out being geometricly coincident, but it is anticipated
01953  *  that the caller will modify the geometry, e.g. as in an extrude operation.
01954  *
01955  *  It is the caller's responsibility to re-bound the new face after
01956  *  making any modifications.
01957  */
01958 struct faceuse *
01959 nmg_dup_face(struct faceuse *fu, struct shell *s)
01960 {
01961         struct loopuse *new_lu, *lu;
01962         struct faceuse *new_fu = (struct faceuse *)NULL;
01963         struct model    *m;
01964         struct model    *m_f;
01965         plane_t         pl;
01966         long            **trans_tbl;
01967         long            tbl_size;
01968 
01969         NMG_CK_FACEUSE(fu);
01970         NMG_CK_FACE(fu->f_p);
01971         NMG_CK_SHELL(s);
01972 
01973         /* allocate the table that holds the translations between existing
01974          * elements and the duplicates we will create.
01975          */
01976         m = nmg_find_model( (long *)s );
01977         tbl_size = m->maxindex;
01978 
01979         m_f = nmg_find_model( (long *)fu );
01980         if (m != m_f)
01981                 tbl_size += m_f->maxindex;
01982 
01983         /* Needs double space, because model will grow as dup proceeds */
01984         trans_tbl = (long **)bu_calloc(tbl_size*2, sizeof(long *),
01985                         "nmg_dup_face trans_tbl");
01986 
01987         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
01988                 if (rt_g.NMG_debug & DEBUG_BASIC)
01989                         bu_log("nmg_dup_face() duping %s loop...",
01990                                 nmg_orientation(lu->orientation));
01991                 if (new_fu) {
01992                         new_lu = nmg_dup_loop(lu, &new_fu->l.magic, trans_tbl);
01993                 } else {
01994                         new_lu = nmg_dup_loop(lu, &s->l.magic, trans_tbl);
01995                         new_fu = nmg_mf(new_lu);
01996 
01997                         /* since nmg_mf() FORCES the orientation of the
01998                          * initial loop to be OT_SAME, we need to re-set
01999                          * the orientation of new_lu if lu->orientation
02000                          * is not OT_SAME.  In general, the first loopuse on
02001                          * a faceuse's linked list will be OT_SAME, but
02002                          * in some circumstances (such as after booleans)
02003                          * the first loopuse MAY be OT_OPPOSITE
02004                          */
02005                         if (lu->orientation != OT_SAME) {
02006                                 new_lu->orientation = lu->orientation;
02007                                 new_lu->lumate_p->orientation =
02008                                         lu->lumate_p->orientation;
02009                         }
02010                 }
02011                 if (rt_g.NMG_debug & DEBUG_BASIC)
02012                         bu_log(".  Duped %s loop\n",
02013                                 nmg_orientation(new_lu->orientation));
02014         }
02015 
02016         /* Create duplicate, independently modifiable face geometry */
02017         switch (*fu->f_p->g.magic_p) {
02018         case NMG_FACE_G_PLANE_MAGIC:
02019                 NMG_GET_FU_PLANE( pl, fu );
02020                 nmg_face_g(new_fu, pl);
02021                 break;
02022         case NMG_FACE_G_SNURB_MAGIC:
02023                 {
02024                         struct face_g_snurb     *old = fu->f_p->g.snurb_p;
02025                         struct face_g_snurb     *new;
02026                         /* Create a new, duplicate snurb */
02027                         nmg_face_g_snurb(new_fu,
02028                                 old->order[0], old->order[1],
02029                                 old->u.k_size, old->v.k_size,
02030                                 NULL, NULL,
02031                                 old->s_size[0], old->s_size[1],
02032                                 old->pt_type,
02033                                 NULL );
02034                         new = new_fu->f_p->g.snurb_p;
02035                         /* Copy knots */
02036                         bcopy( old->u.knots, new->u.knots, old->u.k_size*sizeof(fastf_t) );
02037                         bcopy( old->v.knots, new->v.knots, old->v.k_size*sizeof(fastf_t) );
02038                         /* Copy mesh */
02039                         bcopy( old->ctl_points, new->ctl_points,
02040                                 old->s_size[0] * old->s_size[1] *
02041                                 RT_NURB_EXTRACT_COORDS(old->pt_type) *
02042                                 sizeof(fastf_t) );
02043                 }
02044         }
02045         new_fu->orientation = fu->orientation;
02046         new_fu->fumate_p->orientation = fu->fumate_p->orientation;
02047 
02048         bu_free((char *)trans_tbl, "nmg_dup_face trans_tbl");
02049 
02050         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02051                 bu_log("nmg_dup_face(fu=x%x, s=x%x) new_fu=x%x\n",
02052                         fu, s, new_fu);
02053         }
02054 
02055         return(new_fu);
02056 }
02057 
02058 /************************************************************************
02059  *                                                                      *
02060  *                              LOOP Routines                           *
02061  *                                                                      *
02062  ************************************************************************/
02063 
02064 /**
02065  *                      N M G _ J L
02066  *
02067  *  Join two loops together which share a common edge,
02068  *  such that both occurances of the common edge are deleted.
02069  *  This routine always leaves "lu" intact, and kills the loop
02070  *  radial to "eu" (after stealing all it's edges).
02071  *
02072  *  Either both loops must be of the same orientation, or then
02073  *  first loop must be OT_SAME, and the second loop must be OT_OPPOSITE.
02074  *  Joining OT_SAME & OT_OPPOSITE always gives an OT_SAME result.
02075  *              Above statment is not true!!!! I have added nmg_lu_reorient() -JRA
02076  *  Since "lu" must survive, it must be the OT_SAME one.
02077  */
02078 void
02079 nmg_jl(struct loopuse *lu, struct edgeuse *eu)
02080 {
02081         struct loopuse  *lu2;
02082         struct edgeuse  *eu_r;          /* use of shared edge in lu2 */
02083         struct edgeuse  *nexteu;
02084 
02085         NMG_CK_LOOPUSE(lu);
02086 
02087         NMG_CK_EDGEUSE(eu);
02088         NMG_CK_EDGEUSE(eu->eumate_p);
02089         eu_r = eu->radial_p;
02090         NMG_CK_EDGEUSE(eu_r);
02091         NMG_CK_EDGEUSE(eu_r->eumate_p);
02092 
02093         lu2 = eu_r->up.lu_p;
02094         NMG_CK_LOOPUSE(lu2);
02095 
02096         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02097                 bu_log("nmg_jl(lu=x%x, eu=x%x) lu2=x%x\n", lu, eu, lu2);
02098         }
02099 
02100         if (eu->up.lu_p != lu)
02101                 rt_bomb("nmg_jl: edgeuse is not child of loopuse?\n");
02102 
02103         if (lu2->l.magic != NMG_LOOPUSE_MAGIC)
02104                 rt_bomb("nmg_jl: radial edgeuse not part of loopuse\n");
02105 
02106         if (lu2 == lu)
02107                 rt_bomb("nmg_jl: trying to join a loop to itself\n");
02108 
02109         if (lu->up.magic_p != lu2->up.magic_p)
02110                 rt_bomb("nmg_jl: loopuses do not share parent\n");
02111 
02112         if (lu2->orientation != lu->orientation)  {
02113                 if( lu->orientation != OT_SAME || lu2->orientation != OT_OPPOSITE )  {
02114                         bu_log("nmg_jl: lu2 = %s, lu = %s\n",
02115                                 nmg_orientation(lu2->orientation),
02116                                 nmg_orientation(lu->orientation) );
02117                         rt_bomb("nmg_jl: can't join loops of different orientation!\n");
02118                 } else {
02119                         /* Consuming an OPPOSITE into a SAME is OK */
02120                 }
02121         }
02122 
02123         if (eu->radial_p->eumate_p->radial_p->eumate_p != eu ||
02124             eu->eumate_p->radial_p->eumate_p->radial_p != eu)
02125                 rt_bomb("nmg_jl: edgeuses must be sole uses of edge to join loops\n");
02126 
02127         /*
02128          * Remove all the edgeuses "ahead" of our radial and insert them
02129          * "behind" the current edgeuse.
02130          * Operates on lu and lu's mate simultaneously.
02131          */
02132         nexteu = BU_LIST_PNEXT_CIRC(edgeuse, eu_r);
02133         while (nexteu != eu_r) {
02134                 BU_LIST_DEQUEUE(&nexteu->l);
02135                 BU_LIST_INSERT(&eu->l, &nexteu->l);
02136                 nexteu->up.lu_p = eu->up.lu_p;
02137 
02138                 BU_LIST_DEQUEUE(&nexteu->eumate_p->l);
02139                 BU_LIST_APPEND(&eu->eumate_p->l, &nexteu->eumate_p->l);
02140                 nexteu->eumate_p->up.lu_p = eu->eumate_p->up.lu_p;
02141 
02142                 nexteu = BU_LIST_PNEXT_CIRC(edgeuse, eu_r);
02143         }
02144 
02145         /*
02146          * The other loop just has the one (shared) edgeuse left in it.
02147          * Delete the other loop (and it's mate).
02148          */
02149         nmg_klu(lu2);
02150 
02151         /*
02152          * Kill the one remaining use of the (formerly) "shared" edge in lu
02153          * and voila: one contiguous loop.
02154          */
02155         if( nmg_keu(eu) )  rt_bomb("nmg_jl() loop vanished?\n");
02156 
02157         nmg_lu_reorient( lu );
02158 }
02159 
02160 /**
02161  *                      N M G _ J O I N _ 2 L O O P S
02162  *
02163  *  Intended to join an interior and exterior loop together,
02164  *  by building a bridge between the two indicated vertices.
02165  *
02166  *  This routine can be used to join two exterior loops which do not
02167  *  overlap, and it can also be used to join an exterior loop with
02168  *  a loop of oposite orientation that lies entirely within it.
02169  *  This restriction is important, but not checked for.
02170  *
02171  *  If the two vertexuses reference distinct vertices, then two new
02172  *  edges are built to bridge the loops together.
02173  *  If the two vertexuses share the same vertex, then it is even easier.
02174  *
02175  *  Returns the replacement for vu2.
02176  */
02177 struct vertexuse *
02178 nmg_join_2loops(struct vertexuse *vu1, struct vertexuse *vu2)
02179 {
02180         struct edgeuse  *eu1, *eu2;
02181         struct edgeuse  *first_new_eu;
02182         struct edgeuse  *second_new_eu;
02183         struct edgeuse  *final_eu2;
02184         struct loopuse  *lu1, *lu2;
02185 
02186         NMG_CK_VERTEXUSE(vu1);
02187         NMG_CK_VERTEXUSE(vu2);
02188         eu1 = vu1->up.eu_p;
02189         eu2 = vu2->up.eu_p;
02190         NMG_CK_EDGEUSE(eu1);
02191         NMG_CK_EDGEUSE(eu2);
02192         lu1 = eu1->up.lu_p;
02193         lu2 = eu2->up.lu_p;
02194         NMG_CK_LOOPUSE(lu1);
02195         NMG_CK_LOOPUSE(lu2);
02196 
02197         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02198                 bu_log("nmg_join_2loops(vu1=x%x, vu2=x%x) lu1=x%x, lu2=x%x\n",
02199                         vu1, vu2, lu1, lu2 );
02200         }
02201 
02202         if( lu1 == lu2 || lu1->l_p == lu2->l_p )
02203                 rt_bomb("nmg_join_2loops: can't join loop to itself\n");
02204 
02205         if( lu1->up.fu_p != lu2->up.fu_p )
02206                 rt_bomb("nmg_join_2loops: can't join loops in different faces\n");
02207 
02208         if( vu1->v_p != vu2->v_p )  {
02209                 /*
02210                  *  Start by taking a jaunt from vu1 to vu2 and back.
02211                  */
02212 
02213                 /* insert 0 length edge, before eu1 */
02214                 first_new_eu = nmg_eins(eu1);
02215 
02216                 /* split the new edge, and connect it to vertex 2 */
02217                 second_new_eu = nmg_eusplit( vu2->v_p, first_new_eu, 0 );
02218                 first_new_eu = BU_LIST_PPREV_CIRC(edgeuse, second_new_eu);
02219 
02220                 /* Make the two new edgeuses share just one edge */
02221                 nmg_je( second_new_eu, first_new_eu );
02222 
02223                 /* first_new_eu is eu that enters shared vertex */
02224                 vu1 = second_new_eu->vu_p;
02225         } else {
02226                 second_new_eu = eu1;
02227                 first_new_eu = BU_LIST_PPREV_CIRC(edgeuse, second_new_eu);
02228                 NMG_CK_EDGEUSE(second_new_eu);
02229         }
02230         /* second_new_eu is eu that departs from shared vertex */
02231         vu2 = second_new_eu->vu_p;      /* replacement for original vu2 */
02232         if( vu1->v_p != vu2->v_p )  rt_bomb("nmg_join_2loops: jaunt failed\n");
02233 
02234         /*
02235          *  Gobble edges off of loop2 (starting with eu2),
02236          *  and insert them into loop1,
02237          *  between first_new_eu and second_new_eu.
02238          *  The final edge from loop 2 will then be followed by
02239          *  second_new_eu.
02240          */
02241         final_eu2 = BU_LIST_PPREV_CIRC(edgeuse, eu2 );
02242         while( BU_LIST_NON_EMPTY( &lu2->down_hd ) )  {
02243                 eu2 = BU_LIST_PNEXT_CIRC(edgeuse, final_eu2);
02244 
02245                 BU_LIST_DEQUEUE(&eu2->l);
02246                 BU_LIST_INSERT(&second_new_eu->l, &eu2->l);
02247                 eu2->up.lu_p = lu1;
02248 
02249                 BU_LIST_DEQUEUE(&eu2->eumate_p->l);
02250                 BU_LIST_APPEND(&second_new_eu->eumate_p->l, &eu2->eumate_p->l);
02251                 eu2->eumate_p->up.lu_p = lu1->lumate_p;
02252         }
02253 
02254         nmg_lu_reorient( lu1 );
02255 
02256         /* Kill entire (null) loop associated with lu2 */
02257         nmg_klu(lu2);
02258 
02259         return vu2;
02260 }
02261 
02262 /* XXX These should be included in nmg_join_2loops, or be called by it */
02263 /**
02264  *                      N M G _ J O I N _ S I N G V U _ L O O P
02265  *
02266  *  vu1 is in a regular loop, vu2 is in a loop of a single vertex
02267  *  A jaunt is taken from vu1 to vu2 and back to vu1, and the
02268  *  old loop at vu2 is destroyed.
02269  *  Return is the new vu that replaces vu2.
02270  */
02271 struct vertexuse *
02272 nmg_join_singvu_loop(struct vertexuse *vu1, struct vertexuse *vu2)
02273 {
02274         struct edgeuse  *eu1;
02275         struct edgeuse  *first_new_eu, *second_new_eu;
02276         struct loopuse  *lu2;
02277 
02278         NMG_CK_VERTEXUSE( vu1 );
02279         NMG_CK_VERTEXUSE( vu2 );
02280 
02281         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02282                 bu_log("nmg_join_singvu_loop(vu1=x%x, vu2=x%x) lu1=x%x, lu2=x%x\n",
02283                         vu1, vu2, vu1->up.lu_p, vu2->up.lu_p );
02284         }
02285 
02286         if( *vu2->up.magic_p != NMG_LOOPUSE_MAGIC ||
02287             *vu1->up.magic_p != NMG_EDGEUSE_MAGIC )  rt_bomb("nmg_join_singvu_loop bad args\n");
02288 
02289         if( vu1->v_p == vu2->v_p )  rt_bomb("nmg_join_singvu_loop same vertex\n");
02290 
02291         /* Take jaunt from vu1 to vu2 and back */
02292         eu1 = vu1->up.eu_p;
02293         NMG_CK_EDGEUSE(eu1);
02294 
02295         /* Insert 0 length edge */
02296         first_new_eu = nmg_eins(eu1);
02297         /* split the new edge, and connect it to vertex 2 */
02298         second_new_eu = nmg_eusplit( vu2->v_p, first_new_eu, 0 );
02299         first_new_eu = BU_LIST_PPREV_CIRC(edgeuse, second_new_eu);
02300         /* Make the two new edgeuses share just one edge */
02301         nmg_je( second_new_eu, first_new_eu );
02302 
02303         /* Kill loop lu2 associated with vu2 */
02304         lu2 = vu2->up.lu_p;
02305         NMG_CK_LOOPUSE(lu2);
02306         nmg_klu(lu2);
02307 
02308         return second_new_eu->vu_p;
02309 }
02310 
02311 /**
02312  *                      N M G _ J O I N _ 2 S I N G V U _ L O O P S
02313  *
02314  *  Both vertices are part of single vertex loops.
02315  *  Converts loop on vu1 into a real loop that connects them together,
02316  *  with a single edge (two edgeuses).
02317  *  Loop on vu2 is killed.
02318  *  Returns replacement vu for vu2.
02319  *  Does not change the orientation.
02320  */
02321 struct vertexuse *
02322 nmg_join_2singvu_loops(struct vertexuse *vu1, struct vertexuse *vu2)
02323 {
02324         struct edgeuse  *first_new_eu, *second_new_eu;
02325         struct loopuse  *lu1, *lu2;
02326 
02327         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02328                 bu_log("nmg_join_2singvu_loops(vu1=x%x, vu2=x%x) lu1=x%x, lu2=x%x\n",
02329                         vu1, vu2, vu1->up.lu_p, vu2->up.lu_p );
02330         }
02331 
02332         NMG_CK_VERTEXUSE( vu1 );
02333         NMG_CK_VERTEXUSE( vu2 );
02334 
02335         if( *vu2->up.magic_p != NMG_LOOPUSE_MAGIC ||
02336             *vu1->up.magic_p != NMG_LOOPUSE_MAGIC )  rt_bomb("nmg_join_2singvu_loops bad args\n");
02337 
02338         if( vu1->v_p == vu2->v_p )  rt_bomb("nmg_join_2singvu_loops same vertex\n");
02339 
02340         /* Take jaunt from vu1 to vu2 and back */
02341         /* Make a 0 length edge on vu1 */
02342         first_new_eu = nmg_meonvu(vu1);
02343         /* split the new edge, and connect it to vertex 2 */
02344         second_new_eu = nmg_eusplit( vu2->v_p, first_new_eu, 0 );
02345         first_new_eu = BU_LIST_PPREV_CIRC(edgeuse, second_new_eu);
02346         /* Make the two new edgeuses share just one edge */
02347         nmg_je( second_new_eu, first_new_eu );
02348 
02349         /* Kill loop lu2 associated with vu2 */
02350         lu2 = vu2->up.lu_p;
02351         NMG_CK_LOOPUSE(lu2);
02352         nmg_klu(lu2);
02353 
02354         lu1 = vu1->up.eu_p->up.lu_p;
02355         NMG_CK_LOOPUSE(lu1);
02356 
02357         return second_new_eu->vu_p;
02358 }
02359 
02360 /**                     N M G _ C U T _ L O O P
02361  *
02362  *      Divide a loop of edges between two vertexuses.
02363  *
02364  *      Make a new loop between the two vertexes, and split it and
02365  *      the loop of the vertexuses at the same time.
02366  *
02367  *
02368  *              BEFORE                                  AFTER
02369  *
02370  *
02371  *     Va    eu1  vu1           Vb             Va   eu1  vu1             Vb
02372  *      * <---------* <---------*               * <--------*  * <--------*
02373  *      |                                       |             |
02374  *      |                       ^               |          ^  |          ^
02375  *      |        Original       |               | Original |  |    New   |
02376  *      |          Loopuse      |               | Loopuse  |  |  Loopuse |
02377  *      V                       |               V          |  V /        |
02378  *                              |                          |   /         |
02379  *      *----------> *--------> *               *--------> *  *--------> *
02380  *     Vd            vu2 eu2    Vc             Vd             vu2  eu2   Vc
02381  *
02382  *  Returns the new loopuse pointer.  The new loopuse will contain "vu2"
02383  *  and the edgeuse associated with "vu2" as the FIRST edgeuse on the
02384  *  list of edgeuses.  The edgeuse for the new edge  (connecting
02385  *  the verticies indicated by vu1 and vu2) will be the LAST edgeuse on the
02386  *  new loopuse's list of edgeuses.
02387  *
02388  *  It is the caller's responsibility to re-bound the loops.
02389  *
02390  *  Both old and new loopuse will have orientation OT_UNSPEC.  It is the
02391  *  callers responsibility to determine what the orientations should be.
02392  *  This can be conveniently done with nmg_lu_reorient().
02393  *
02394  *  Here is a simple example of how the new loopuse might have a different
02395  *  orientation than the original one:
02396  *
02397  *
02398  *              F<----------------E
02399  *              |                 ^
02400  *              |                 |
02401  *              |      C--------->D
02402  *              |      ^          .
02403  *              |      |          .
02404  *              |      |          .
02405  *              |      B<---------A
02406  *              |                 ^
02407  *              v                 |
02408  *              G---------------->H
02409  *
02410  *  When nmg_cut_loop(A,D) is called, the new loop ABCD is clockwise,
02411  *  even though the original loop was counter-clockwise.
02412  *  There is no way to determine this without referring to the
02413  *  face normal and vertex geometry, which being a topology routine
02414  *  this routine shouldn't do.
02415  *
02416  *  Returns -
02417  *      NULL    Error
02418  *      lu      Loopuse of new loop, on success.
02419  */
02420 struct loopuse *
02421 nmg_cut_loop(struct vertexuse *vu1, struct vertexuse *vu2)
02422 {
02423         struct loopuse *lu, *oldlu;
02424         struct edgeuse *eu1, *eu2, *eunext, *neweu, *eu;
02425         struct model    *m;
02426         FILE            *fd;
02427         char            name[32];
02428         static int      i=0;
02429 
02430         NMG_CK_VERTEXUSE(vu1);
02431         NMG_CK_VERTEXUSE(vu2);
02432 
02433         eu1 = vu1->up.eu_p;
02434         eu2 = vu2->up.eu_p;
02435         NMG_CK_EDGEUSE(eu1);
02436         NMG_CK_EDGEUSE(eu2);
02437         oldlu = eu1->up.lu_p;
02438         NMG_CK_LOOPUSE(oldlu);
02439 
02440         if (eu2->up.lu_p != oldlu) {
02441                 rt_bomb("nmg_cut_loop() vertices not decendants of same loop\n");
02442         }
02443 
02444         if( vu1->v_p == vu2->v_p )  {
02445                 /* The loops touch, use a different routine */
02446                 lu = nmg_split_lu_at_vu( oldlu, vu1 );
02447                 goto out;
02448         }
02449 
02450         NMG_CK_FACEUSE(oldlu->up.fu_p);
02451         m = oldlu->up.fu_p->s_p->r_p->m_p;
02452         NMG_CK_MODEL(m);
02453 
02454         if (rt_g.NMG_debug & DEBUG_CUTLOOP) {
02455                 bu_log("\tnmg_cut_loop\n");
02456                 if (rt_g.NMG_debug & DEBUG_PLOTEM) {
02457                         long            *tab;
02458                         tab = (long *)bu_calloc( m->maxindex, sizeof(long),
02459                                 "nmg_cut_loop flag[] 1" );
02460 
02461                         (void)sprintf(name, "Before_cutloop%d.pl", ++i);
02462                         bu_log("nmg_cut_loop() plotting %s\n", name);
02463                         if ((fd = fopen(name, "w")) == (FILE *)NULL) {
02464                                 (void)perror(name);
02465                                 bu_bomb("unable to open file for writing");
02466                         }
02467 
02468                         nmg_pl_fu(fd, oldlu->up.fu_p, tab, 100, 100, 100);
02469                         nmg_pl_fu(fd, oldlu->up.fu_p->fumate_p, tab, 100, 100, 100);
02470                         (void)fclose(fd);
02471                         bu_free( (char *)tab, "nmg_cut_loop flag[] 1" );
02472                 }
02473         }
02474 
02475         /* make a new loop structure for the new loop & throw away
02476          * the vertexuse we don't need
02477          */
02478         lu = nmg_mlv(oldlu->up.magic_p, (struct vertex *)NULL, OT_UNSPEC );
02479         oldlu->orientation = oldlu->lumate_p->orientation = OT_UNSPEC;
02480 
02481         nmg_kvu(BU_LIST_FIRST(vertexuse, &lu->down_hd));
02482         nmg_kvu(BU_LIST_FIRST(vertexuse, &lu->lumate_p->down_hd));
02483         /* nmg_kvu() does BU_LIST_INIT() on down_hd */
02484         /* The loopuse is considered invalid until it gets some edges */
02485 
02486         /* move the edges into one of the uses of the new loop */
02487         for (eu = eu2 ; eu != eu1 ; eu = eunext) {
02488                 eunext = BU_LIST_PNEXT_CIRC(edgeuse, &eu->l);
02489 
02490                 BU_LIST_DEQUEUE(&eu->l);
02491                 BU_LIST_INSERT(&lu->down_hd, &eu->l);
02492                 BU_LIST_DEQUEUE(&eu->eumate_p->l);
02493                 BU_LIST_APPEND(&lu->lumate_p->down_hd, &eu->eumate_p->l);
02494                 eu->up.lu_p = lu;
02495                 eu->eumate_p->up.lu_p = lu->lumate_p;
02496         }
02497 
02498         /* make a wire edge in the shell to "cap off" the new loop */
02499         neweu = nmg_me(eu1->vu_p->v_p, eu2->vu_p->v_p, nmg_find_s_of_eu(eu1));
02500 
02501         /* move the new edgeuse into the new loopuse */
02502         BU_LIST_DEQUEUE(&neweu->l);
02503         BU_LIST_INSERT(&lu->down_hd, &neweu->l);
02504         neweu->up.lu_p = lu;
02505 
02506         /* move the new edgeuse mate into the new loopuse mate */
02507         BU_LIST_DEQUEUE(&neweu->eumate_p->l);
02508         BU_LIST_APPEND(&lu->lumate_p->down_hd, &neweu->eumate_p->l);
02509         neweu->eumate_p->up.lu_p = lu->lumate_p;
02510 
02511         /* now we go back and close up the loop we just ripped open */
02512         eunext = nmg_me(eu2->vu_p->v_p, eu1->vu_p->v_p, nmg_find_s_of_eu(eu1));
02513 
02514         BU_LIST_DEQUEUE(&eunext->l);
02515         BU_LIST_INSERT(&eu1->l, &eunext->l);
02516         BU_LIST_DEQUEUE(&eunext->eumate_p->l);
02517         BU_LIST_APPEND(&eu1->eumate_p->l, &eunext->eumate_p->l);
02518         eunext->up.lu_p = eu1->up.lu_p;
02519         eunext->eumate_p->up.lu_p = eu1->eumate_p->up.lu_p;
02520 
02521         /* make new edgeuses radial to each other, sharing the new edge */
02522         nmg_je(neweu, eunext);
02523 
02524         nmg_ck_lueu(oldlu, "oldlu");
02525         nmg_ck_lueu(lu, "lu");  /*LABLABLAB*/
02526 
02527 
02528         if (rt_g.NMG_debug & DEBUG_CUTLOOP && rt_g.NMG_debug & DEBUG_PLOTEM) {
02529                 long            *tab;
02530                 tab = (long *)bu_calloc( m->maxindex, sizeof(long),
02531                         "nmg_cut_loop flag[] 2" );
02532 
02533                 (void)sprintf(name, "After_cutloop%d.pl", i);
02534                 bu_log("nmg_cut_loop() plotting %s\n", name);
02535                 if ((fd = fopen(name, "w")) == (FILE *)NULL) {
02536                         (void)perror(name);
02537                         bu_bomb("unable to open file for writing");
02538                 }
02539 
02540                 nmg_pl_fu(fd, oldlu->up.fu_p, tab, 100, 100, 100);
02541                 nmg_pl_fu(fd, oldlu->up.fu_p->fumate_p, tab, 100, 100, 100);
02542                 (void)fclose(fd);
02543                 bu_free( (char *)tab, "nmg_cut_loop flag[] 2" );
02544         }
02545 out:
02546         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02547                 bu_log("nmg_cut_loop(vu1=x%x, vu2=x%x) old_lu=x%x, new_lu=x%x\n",
02548                         vu1, vu2, oldlu, lu );
02549         }
02550 
02551         return lu;
02552 }
02553 
02554 /**
02555  *                      N M G _ S P L I T _ L U _ A T _ V U
02556  *
02557  *  In a loop which has at least two distinct uses of a vertex,
02558  *  split off the edges from "split_vu" to the second occurance of
02559  *  the vertex into a new loop.
02560  *  It is the caller's responsibility to re-bound the loops.
02561  *
02562  *  The old and new loopuses will have orientation OT_UNSPEC.  It is the
02563  *  callers responsibility to determine what their orientations should be.
02564  *  This can be conveniently done with nmg_lu_reorient().
02565  *
02566  *  Here is an example:
02567  *
02568  *                    E<__________B <___________A
02569  *                    |           ^\            ^
02570  *                    |          /  \           |
02571  *                    |         /    \          |
02572  *                    |        /      v         |
02573  *                    |       D<_______C        |
02574  *                    v                         |
02575  *                    F________________________>G
02576  *
02577  *  When nmg_split_lu_at_vu(lu, B) is called, the old loopuse continues to
02578  *  be counter clockwise and OT_SAME, but the new loopuse BCD is now
02579  *  clockwise.  It needs to be marked OT_OPPOSITE.  Without referring
02580  *  to the geometry, this can't be determined.
02581  *
02582  *  Intended primarily for use by nmg_split_touchingloops().
02583  *
02584  *  Returns -
02585  *      NULL    Error
02586  *      lu      Loopuse of new loop, on success.
02587  */
02588 struct loopuse *
02589 nmg_split_lu_at_vu(struct loopuse *lu, struct vertexuse *split_vu)
02590 {
02591         struct edgeuse          *eu;
02592         struct vertexuse        *vu;
02593         struct loopuse          *newlu;
02594         struct loopuse          *newlumate;
02595         struct vertex           *split_v;
02596         int                     iteration;
02597 
02598         split_v = split_vu->v_p;
02599         NMG_CK_VERTEX(split_v);
02600 
02601         eu = split_vu->up.eu_p;
02602         NMG_CK_EDGEUSE(eu);
02603 
02604         if( eu->up.lu_p != lu )  {
02605                 /* Could not find indicated vertex */
02606                 newlu = (struct loopuse *)0;            /* FAIL */
02607                 goto out;
02608         }
02609 
02610         /* Make a new loop in the same face */
02611         lu->orientation = lu->lumate_p->orientation = OT_UNSPEC;
02612         newlu = nmg_mlv( lu->up.magic_p, (struct vertex *)NULL, OT_UNSPEC );
02613         NMG_CK_LOOPUSE(newlu);
02614         newlumate = newlu->lumate_p;
02615         NMG_CK_LOOPUSE(newlumate);
02616 
02617         /* Throw away unneeded lone vertexuse */
02618         nmg_kvu(BU_LIST_FIRST(vertexuse, &newlu->down_hd));
02619         nmg_kvu(BU_LIST_FIRST(vertexuse, &newlumate->down_hd));
02620         /* nmg_kvu() does BU_LIST_INIT() on down_hd */
02621 
02622         /* Move edges & mates into new loop until vertex is repeated */
02623         for( iteration=0; iteration < 10000; iteration++ )  {
02624                 struct edgeuse  *eunext;
02625                 eunext = BU_LIST_PNEXT_CIRC(edgeuse, &eu->l);
02626 
02627                 BU_LIST_DEQUEUE(&eu->l);
02628                 BU_LIST_INSERT(&newlu->down_hd, &eu->l);
02629                 BU_LIST_DEQUEUE(&eu->eumate_p->l);
02630                 BU_LIST_APPEND(&newlumate->down_hd, &eu->eumate_p->l);
02631 
02632                 /* Change edgeuse & mate up pointers */
02633                 eu->up.lu_p = newlu;
02634                 eu->eumate_p->up.lu_p = newlumate;
02635 
02636                 /* Advance to next edgeuse */
02637                 eu = eunext;
02638 
02639                 /* When split_v is encountered, stop */
02640                 vu = eu->vu_p;
02641                 NMG_CK_VERTEXUSE(vu);
02642                 if( vu->v_p == split_v )  break;
02643         }
02644         if( iteration >= 10000 )  rt_bomb("nmg_split_lu_at_vu:  infinite loop\n");
02645 out:
02646         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02647                 bu_log("nmg_split_lu_at_vu( lu=x%x, split_vu=x%x ) newlu=x%x\n",
02648                         lu, split_vu, newlu );
02649         }
02650         return newlu;
02651 }
02652 
02653 /**
02654  *                      N M G _ F I N D _ R E P E A T E D _ V _ I N _ L U
02655  *
02656  *  Given a vertexuse of an edgeuse in a loopuse, see if the vertex is
02657  *  used by at least one other vertexuse in that same loopuse.
02658  *
02659  *  Returns -
02660  *      vu      If this vertex appears elsewhere in the loopuse.
02661  *      NULL    If this is the only occurance of this vertex in the loopuse.
02662  *  XXX move to nmg_info.c
02663  */
02664 struct vertexuse *
02665 nmg_find_repeated_v_in_lu(struct vertexuse *vu)
02666 {
02667         struct vertexuse        *tvu;           /* vu to test */
02668         struct loopuse          *lu;
02669         struct vertex           *v;
02670 
02671         v = vu->v_p;
02672         NMG_CK_VERTEX(v);
02673 
02674         if( *vu->up.magic_p != NMG_EDGEUSE_MAGIC )
02675                 return (struct vertexuse *)0;
02676         if( *vu->up.eu_p->up.magic_p != NMG_LOOPUSE_MAGIC )
02677                 return (struct vertexuse *)0;
02678         lu = vu->up.eu_p->up.lu_p;
02679 
02680         /*
02681          *  For each vertexuse on vertex list,
02682          *  check to see if it points up to the this loop.
02683          *  If so, then there is a duplicated vertex.
02684          *  Ordinarily, the vertex list will be *very* short,
02685          *  so this strategy is likely to be faster than
02686          *  a table-based approach, for most cases.
02687          */
02688         for( BU_LIST_FOR( tvu, vertexuse, &v->vu_hd ) )  {
02689                 struct edgeuse          *teu;
02690                 struct loopuse          *tlu;
02691 
02692                 if( tvu == vu )  continue;
02693                 if( *tvu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
02694                 teu = tvu->up.eu_p;
02695                 NMG_CK_EDGEUSE(teu);
02696                 if( *teu->up.magic_p != NMG_LOOPUSE_MAGIC )  continue;
02697                 tlu = teu->up.lu_p;
02698                 NMG_CK_LOOPUSE(tlu);
02699                 if( tlu != lu )  continue;
02700                 /*
02701                  *  Repeated vertex exists.  Return (one) other use of it.
02702                  */
02703                 return tvu;
02704         }
02705         return (struct vertexuse *)0;
02706 }
02707 
02708 /**
02709  *                      N M G _ S P L I T _ T O U C H I N G L O O P S
02710  *
02711  *  Search through all the vertices in a loop.
02712  *  Whenever there are two distinct uses of one vertex in the loop,
02713  *  split off all the edges between them into a new loop.
02714  *
02715  *  Note that the call to nmg_split_lu_at_vu() will cause the split
02716  *  loopuses to be marked OT_UNSPEC.
02717  */
02718 void
02719 nmg_split_touchingloops(struct loopuse *lu, const struct bn_tol *tol)
02720 {
02721         struct edgeuse          *eu;
02722         struct vertexuse        *vu;
02723         struct loopuse          *newlu;
02724         struct vertexuse        *vu_save;
02725 
02726         NMG_CK_LOOPUSE(lu);
02727         BN_CK_TOL(tol);
02728         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02729                 bu_log("nmg_split_touchingloops( lu=x%x )\n", lu);
02730         }
02731 top:
02732         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
02733                 return;
02734 
02735         vu_save = (struct vertexuse *)NULL;
02736 
02737         /* For each edgeuse, get vertexuse and vertex */
02738         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
02739 
02740                 struct edgeuse *other_eu;
02741                 struct vertexuse *other_vu;
02742                 int vu_is_part_of_crack=0;
02743 
02744                 vu = eu->vu_p;
02745                 NMG_CK_VERTEXUSE(vu);
02746 
02747 #if 1
02748                 if( !nmg_find_repeated_v_in_lu( vu ) )  continue;
02749 
02750                 /* avoid splitting a crack if possible */
02751                 for( BU_LIST_FOR( other_vu, vertexuse, &vu->v_p->vu_hd ) )
02752                 {
02753                         if( nmg_find_lu_of_vu( other_vu ) != lu )
02754                                 continue;
02755                         if( *other_vu->up.magic_p != NMG_EDGEUSE_MAGIC )
02756                                 continue;
02757                         other_eu = other_vu->up.eu_p;
02758                         if( nmg_eu_is_part_of_crack( other_eu ) )
02759                         {
02760                                 vu_save = other_vu;
02761                                 vu_is_part_of_crack = 1;
02762                                 break;
02763                         }
02764                 }
02765 
02766                 if( vu_is_part_of_crack )
02767                         continue;
02768 
02769                 /*
02770                  *  Repeated vertex exists,
02771                  *  Split loop into two loops
02772                  */
02773                 newlu = nmg_split_lu_at_vu( lu, vu );
02774                 NMG_CK_LOOPUSE(newlu);
02775                 NMG_CK_LOOP(newlu->l_p);
02776                 nmg_loop_g(newlu->l_p, tol);
02777 
02778                 /* Ensure there are no duplications in new loop */
02779                 nmg_split_touchingloops(newlu, tol);
02780 
02781                 /* There is no telling where we will be in the
02782                  * remainder of original loop, check 'em all.
02783                  */
02784                 goto top;
02785         }
02786 
02787         if( vu_save )
02788         {
02789                 /* split loop at crack */
02790                 newlu = nmg_split_lu_at_vu( lu, vu_save );
02791                 NMG_CK_LOOPUSE(newlu);
02792                 NMG_CK_LOOP(newlu->l_p);
02793                 nmg_loop_g(newlu->l_p, tol);
02794 
02795                 /* Ensure there are no duplications in new loop */
02796                 nmg_split_touchingloops(newlu, tol);
02797 
02798                 /* There is no telling where we will be in the
02799                  * remainder of original loop, check 'em all.
02800                  */
02801                 goto top;
02802         }
02803 
02804 #else
02805                 v = vu->v_p;
02806                 NMG_CK_VERTEX(v);
02807 
02808                 /*
02809                  *  For each vertexuse on vertex list,
02810                  *  check to see if it points up to the this loop.
02811                  *  If so, then there is a duplicated vertex.
02812                  *  Ordinarily, the vertex list will be *very* short,
02813                  *  so this strategy is likely to be faster than
02814                  *  a table-based approach, for most cases.
02815                  */
02816                 for( BU_LIST_FOR( tvu, vertexuse, &v->vu_hd ) )  {
02817                         struct edgeuse          *teu;
02818                         struct loopuse          *tlu;
02819 
02820                         if( tvu == vu )  continue;
02821                         if( *tvu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
02822                         teu = tvu->up.eu_p;
02823                         NMG_CK_EDGEUSE(teu);
02824                         if( *teu->up.magic_p != NMG_LOOPUSE_MAGIC )  continue;
02825                         tlu = teu->up.lu_p;
02826                         NMG_CK_LOOPUSE(tlu);
02827                         if( tlu != lu )  continue;
02828                         /*
02829                          *  Repeated vertex exists,
02830                          *  Split loop into two loops
02831                          */
02832                         newlu = nmg_split_lu_at_vu( lu, vu );
02833                         NMG_CK_LOOPUSE(newlu);
02834                         NMG_CK_LOOP(newlu->l_p);
02835                         nmg_loop_g(newlu->l_p, tol);
02836 
02837                         /* Ensure there are no duplications in new loop */
02838                         nmg_split_touchingloops(newlu, tol);
02839 
02840                         /* There is no telling where we will be in the
02841                          * remainder of original loop, check 'em all.
02842                          */
02843                         goto top;
02844                 }
02845         }
02846 #endif
02847 }
02848 
02849 /**
02850  *                      N M G _ J O I N _ T O U C H I N G L O O P S
02851  *
02852  *  Search through all the vertices in a loopuse that belongs to a faceuse.
02853  *  Whenever another loopuse in the same faceuse refers to one of this
02854  *  loop's vertices, the two loops touch at (at least) that vertex.
02855  *  Join them together.
02856  *
02857  *  Return -
02858  *      count of loops joined (eliminated)
02859  */
02860 int
02861 nmg_join_touchingloops(struct loopuse *lu)
02862 {
02863         struct faceuse          *fu;
02864         struct edgeuse          *eu;
02865         struct vertexuse        *vu;
02866         struct vertex           *v;
02867         int                     count = 0;
02868 
02869         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02870                 bu_log("nmg_join_touchingloops( lu=x%x )\n", lu);
02871         }
02872         NMG_CK_LOOPUSE(lu);
02873         fu = lu->up.fu_p;
02874         NMG_CK_FACEUSE(fu);
02875 
02876 top:
02877         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
02878                 return count;
02879 
02880         /* For each edgeuse, get vertexuse and vertex */
02881         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
02882                 struct vertexuse        *tvu;
02883 
02884                 vu = eu->vu_p;
02885                 NMG_CK_VERTEXUSE(vu);
02886                 v = vu->v_p;
02887                 NMG_CK_VERTEX(v);
02888 
02889                 /*
02890                  *  For each vertexuse on vertex list,
02891                  *  check to see if it points up to an edgeuse in a
02892                  *  different loopuse in the same faceuse.
02893                  *  If so, we touch.
02894                  */
02895                 for( BU_LIST_FOR( tvu, vertexuse, &v->vu_hd ) )  {
02896                         struct edgeuse          *teu;
02897                         struct loopuse          *tlu;
02898 
02899                         if( tvu == vu )  continue;
02900                         if( *tvu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
02901                         teu = tvu->up.eu_p;
02902                         NMG_CK_EDGEUSE(teu);
02903                         if( *teu->up.magic_p != NMG_LOOPUSE_MAGIC )  continue;
02904                         tlu = teu->up.lu_p;
02905                         NMG_CK_LOOPUSE(tlu);
02906                         if( tlu == lu )  {
02907                                 /* We touch ourselves at another vu? */
02908 #if 0
02909                                 bu_log("INFO: nmg_join_touchingloops() lu=x%x touches itself at vu1=x%x, vu2=x%x, skipping\n",
02910                                         lu, vu, tvu );
02911 #endif
02912                                 continue;
02913                         }
02914                         if( *tlu->up.magic_p != NMG_FACEUSE_MAGIC )  continue;
02915                         if( tlu->up.fu_p != fu )  continue;     /* wrong faceuse */
02916                         /*
02917                          *  Loop 'lu' touches loop 'tlu' at this vertex,
02918                          *  join them.
02919                          *  XXX Is there any advantage to searching for
02920                          *  XXX a potential shared edge at this point?
02921                          *  XXX Call nmg_simplify_loop()?
02922                          */
02923                         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02924                                 bu_log("nmg_join_touchingloops(): lu=x%x, vu=x%x, tvu=x%x\n", lu, vu, tvu);
02925                         }
02926                         tvu = nmg_join_2loops( vu, tvu );
02927                         NMG_CK_VERTEXUSE(tvu);
02928                         count++;
02929                         goto top;
02930                 }
02931         }
02932         return count;
02933 }
02934 
02935 /* jaunt status flags used in the jaunt_status array */
02936 #define         JS_UNKNOWN              0
02937 #define         JS_SPLIT                1
02938 #define         JS_JAUNT                2
02939 #define         JS_TOUCHING_JAUNT       3
02940 
02941 /**     N M G _ G E T _ T O U C H I N G _ J A U N T S
02942  *
02943  * Create a table of EU's. Each EU will be the first EU in
02944  * a touching jaunt (edgeuses from vert A->B->A) where vertex B
02945  * appears elswhere in the loopuse lu.
02946  *
02947  * returns:
02948  *      count of touching jaunts found
02949  *
02950  * The passed pointer to an bu_ptbl structure may
02951  * not be initialized. If no touching jaunts are found,
02952  * it will still not be initialized upon return (to avoid
02953  * bu_malloc/bu_free pairs for loops with no touching
02954  * jaunts. The flag (need_init) lets this routine know
02955  * whether the ptbl structure has been initialized
02956  */
02957 
02958 int
02959 nmg_get_touching_jaunts(const struct loopuse *lu, struct bu_ptbl *tbl, int *need_init)
02960 {
02961         struct edgeuse *eu;
02962         int count=0;
02963 
02964         NMG_CK_LOOPUSE( lu );
02965 
02966         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
02967                 return( 0 );
02968 
02969         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02970         {
02971                 struct edgeuse *eu2,*eu3;
02972 
02973                 eu2 = BU_LIST_PNEXT_CIRC(edgeuse, &eu->l);
02974                 eu3 = BU_LIST_PNEXT_CIRC(edgeuse, &eu2->l);
02975 
02976                 /* If it's a 2 vertex crack, stop here */
02977                 if( eu->vu_p == eu3->vu_p )  break;
02978 
02979                 /* If not jaunt, move on */
02980                 if( eu->vu_p->v_p != eu3->vu_p->v_p )  continue;
02981 
02982                 /* It's a jaunt, see if tip touches same loop */
02983                 if( nmg_find_repeated_v_in_lu(eu2->vu_p) == (struct vertexuse *)NULL )
02984                         continue;
02985 
02986                 /* This is a touching jaunt, add it to the list */
02987                 if( *need_init )
02988                 {
02989                         bu_ptbl_init( tbl, 64, " tbl");
02990                         *need_init = 0;
02991                 }
02992 
02993                 bu_ptbl_ins( tbl, (long *)eu );
02994                 count++;
02995         }
02996 
02997         return( count );
02998 }
02999 
03000 /**     N M G _ C H E C K _ P R O P O S E D _ L O O P
03001  *
03002  * Support routine for nmg_loop_split_at_touching_jaunt().
03003  *
03004  * Follow the edgeuses in a proposed loop (that may later be created by nmg_split_lu_at_vu)
03005  * and predict the status of the jaunts in "jaunt_tbl". The jaunt_status array must be
03006  * initialized before this routine is called and this routine should be called twice
03007  * to account for both loops that will result from the application of nmg_split_lu_at_vu().
03008  *
03009  * input:
03010  *      start_eu - edgeuse that will be first in the proposed new loop
03011  *      jaunt_tbl - list of touching jaunts whose status in the resulting loops is desired.
03012  *      jaunt_no - which entry in the jaunt_tbl is being considered as a split location
03013  *      visit_count - array for counting the number of times a jaunt gets visited in the new loop
03014  *              This array just provides working space for the routine.
03015  *      which_loop - Flag:
03016  *              0 -> This is a proposed loop to be created  by nmg_split_lu_at_vu()
03017  *              1 -> This is the loop that will be remaining after nmg_split_lu_at_vu().
03018  *              when "which_loop" == 1, (*next_start_eu) must be set to the starting EU
03019  *              of the first loop (Used to find end of remaining loop).
03020  *
03021  * output:
03022  *      jaunt_status - status of each touching jaunt that appears in the jaunt_tbl
03023  *      next_start_eu - edgeuse that will be first in the next loop
03024  */
03025 
03026 static void
03027 nmg_check_proposed_loop(struct edgeuse *start_eu, struct edgeuse **next_start_eu, int *visit_count, int *jaunt_status, const struct bu_ptbl *jaunt_tbl, const int jaunt_no, const int which_loop)
03028 {
03029         struct edgeuse *loop_eu;
03030         struct edgeuse *last_eu;
03031         int j;
03032         int done=0;
03033 
03034         NMG_CK_EDGEUSE( start_eu );
03035         BU_CK_PTBL( jaunt_tbl );
03036 
03037         /* Initialize the count */
03038         for( j=0 ; j< BU_PTBL_END( jaunt_tbl ) ; j++ )
03039                 visit_count[j] = 0;
03040 
03041         /* walk through the proposed new loop, updating the visit_count and the jaunt status */
03042         last_eu = NULL;
03043         loop_eu = start_eu;
03044         while( !done )
03045         {
03046                 for( j=0 ; j<BU_PTBL_END( jaunt_tbl ) ; j++ )
03047                 {
03048                         struct edgeuse *jaunt_eu;
03049 
03050                         /* Don't worru about this jaunt */
03051                         if( j == jaunt_no )
03052                                 continue;
03053 
03054                         jaunt_eu = (struct edgeuse *)BU_PTBL_GET( jaunt_tbl, j );
03055                         NMG_CK_EDGEUSE( jaunt_eu );
03056 
03057                         /* if jaunt number j is included in this loop, update its status */
03058                         if( last_eu && last_eu == jaunt_eu )
03059                                 jaunt_status[j] = JS_JAUNT;
03060 
03061                         /* if this loop_eu has its vertex at the apex of one of
03062                          * the touching jaunts, increment the appropriate visit_count.
03063                          */
03064                         if( loop_eu->vu_p->v_p == jaunt_eu->eumate_p->vu_p->v_p )
03065                                 visit_count[j]++;
03066                 }
03067                 last_eu = loop_eu;
03068                 loop_eu = BU_LIST_PNEXT_CIRC(edgeuse, &loop_eu->l);
03069 
03070                 /* if "which_loop" is 0, use the nmg_split_lu_at_vu() terminate condition,
03071                  * otherwise, continue until we find (*next_start_eu)
03072                  */
03073                 if( !which_loop && loop_eu->vu_p->v_p == start_eu->vu_p->v_p )
03074                         done = 1;
03075                 else if( which_loop && loop_eu == (*next_start_eu) )
03076                         done = 1;
03077         }
03078         *next_start_eu = loop_eu;
03079 
03080 
03081         /* check all jaunts to see if they are still touching jaunts in the proposed loop */
03082         for( j=0 ; j<BU_PTBL_END( jaunt_tbl ) ; j++ )
03083         {
03084                 if( jaunt_status[j] == JS_JAUNT ) /* proposed loop contains this jaunt */
03085                 {
03086                         if( visit_count[j] > 1 )        /* it's still a touching jaunt */
03087                                 jaunt_status[j] = JS_TOUCHING_JAUNT;
03088                 }
03089         }
03090 
03091         /* if the first or last eu in the proposed loop is a jaunt eu, the proposed
03092          * loop will split the jaunt, so set its status to JS_SPLIT.
03093          */
03094         for( j=0 ; j<BU_PTBL_END( jaunt_tbl ) ; j++ )
03095         {
03096                 struct edgeuse *jaunt_eu;
03097                 struct edgeuse *jaunt_eu2;
03098 
03099                 jaunt_eu = (struct edgeuse *)BU_PTBL_GET( jaunt_tbl, j );
03100                 jaunt_eu2 = BU_LIST_PNEXT_CIRC( edgeuse, &jaunt_eu->l );
03101 
03102                 if( last_eu == jaunt_eu || start_eu == jaunt_eu2 )
03103                         jaunt_status[j] = JS_SPLIT;
03104         }
03105 
03106         return;
03107 }
03108 
03109 void
03110 nmg_kill_accordions(struct loopuse *lu)
03111 {
03112         struct edgeuse *eu;
03113         struct edgeuse *jaunt_eu1;
03114         struct edgeuse *jaunt_eu2 = NULL;
03115         struct edgeuse *jaunt_eu3;
03116 
03117         NMG_CK_LOOPUSE( lu );
03118 
03119         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
03120                 return;
03121 top:
03122         /* first look for a jaunt */
03123         jaunt_eu1 = (struct edgeuse *)NULL;
03124         jaunt_eu3 = (struct edgeuse *)NULL;
03125         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
03126         {
03127                 struct edgeuse *eu2;
03128 
03129                 eu2 = BU_LIST_PPREV_CIRC( edgeuse, &eu->l );
03130                 if( (eu2->vu_p->v_p == eu->eumate_p->vu_p->v_p) && (eu != eu2) )
03131                 {
03132                         struct edgeuse *eu3;
03133 
03134                         /* found a jaunt */
03135                         jaunt_eu1 = eu;
03136                         jaunt_eu2 = eu2;
03137 
03138                         /* look for a third eu between the same vertices */
03139                         jaunt_eu3 = (struct edgeuse *)NULL;
03140                         for( BU_LIST_FOR( eu3, edgeuse, &lu->down_hd ) )
03141                         {
03142                                 if( eu3 == jaunt_eu1 || eu3 == jaunt_eu2 )
03143                                         continue;
03144 
03145                                 if( NMG_ARE_EUS_ADJACENT( eu3, jaunt_eu1 ) )
03146                                 {
03147                                         jaunt_eu3 = eu3;
03148                                         break;
03149                                 }
03150                         }
03151                 }
03152                 if( jaunt_eu3 )
03153                         break;
03154         }
03155 
03156         if( !jaunt_eu3 )
03157                 return;
03158 
03159         if( jaunt_eu2 != jaunt_eu1->eumate_p )
03160         {
03161                 if ((rt_g.NMG_debug & DEBUG_BASIC) || (rt_g.NMG_debug & DEBUG_CUTLOOP))
03162                         bu_log( "Killing jaunt in accordion eu's x%x and x%x\n", jaunt_eu1, jaunt_eu2 );
03163                 (void)nmg_keu( jaunt_eu1 );
03164                 (void)nmg_keu( jaunt_eu2 );
03165         }
03166         else
03167         {
03168                 if ((rt_g.NMG_debug & DEBUG_BASIC) || (rt_g.NMG_debug & DEBUG_CUTLOOP))
03169                         bu_log( "Killing jaunt in accordion eu x%x\n", jaunt_eu1 );
03170                 (void)nmg_keu( jaunt_eu1 );
03171         }
03172 
03173         goto top;
03174 
03175 }
03176 
03177 /**
03178  *                      N M G _ L O O P _ S P L I T _ A T _ T O U C H I N G _ J A U N T
03179  *
03180  *  If a loop makes a "jaunt" (edgeuses from verts A->B->A), where the
03181  *  tip of the jaunt touches the same loop at a different vertexuse,
03182  *  cut the loop into two.
03183  *
03184  *  This produces a much more reasonable loop split than
03185  *  nmg_split_touchingloops(), which tends to peel off 2-edge "cracks"
03186  *  as it unravels the loop.
03187  *
03188  *  Note that any loops so split will be marked OT_UNSPEC.
03189  */
03190 int
03191 nmg_loop_split_at_touching_jaunt(struct loopuse *lu, const struct bn_tol *tol)
03192 {
03193         struct bu_ptbl          jaunt_tbl;
03194         struct loopuse          *new_lu;
03195         struct edgeuse          *eu;
03196         struct edgeuse          *eu2;
03197         int                     count=0;
03198         int                     jaunt_count;
03199         int                     jaunt_no;
03200         int                     need_init=1;
03201         int                     *visit_count;
03202         int                     *jaunt_status;
03203         int                     i;
03204 
03205         NMG_CK_LOOPUSE(lu);
03206         BN_CK_TOL(tol);
03207 
03208         if ((rt_g.NMG_debug & DEBUG_BASIC) || (rt_g.NMG_debug & DEBUG_CUTLOOP))  {
03209                 bu_log("nmg_loop_split_at_touching_jaunt( lu=x%x ) START\n", lu);
03210                 nmg_pr_lu_briefly( lu, "" );
03211         }
03212 
03213         /* first kill any accordion pleats */
03214         nmg_kill_accordions( lu );
03215 
03216         visit_count = (int *)NULL;
03217         jaunt_status = (int *)NULL;
03218 
03219 top:
03220         jaunt_count = nmg_get_touching_jaunts( lu, &jaunt_tbl, &need_init );
03221         if( rt_g.NMG_debug & DEBUG_CUTLOOP )
03222         {
03223                 bu_log( "nmg_loop_split_at_touching_jaunt: found %d touching jaunts in lu x%x\n", jaunt_count, lu );
03224                 if( jaunt_count )
03225                 {
03226                         for( i=0 ; i<BU_PTBL_END( &jaunt_tbl ) ; i++ )
03227                         {
03228                                 eu = (struct edgeuse *)BU_PTBL_GET( &jaunt_tbl, i );
03229                                 bu_log( "\tx%x\n" , eu );
03230                         }
03231                 }
03232         }
03233 
03234         if( jaunt_count < 0 )
03235         {
03236                 bu_log( "nmg_loop_split_at_touching_jaunt: nmg_get_touching_jaunts() returned %d for lu x%x\n", jaunt_count, lu );
03237                 rt_bomb( "nmg_loop_split_at_touching_jaunt: bad jaunt count\n" );
03238         }
03239 
03240         if( jaunt_count == 0 )
03241         {
03242                 if( visit_count )
03243                         bu_free( (char *)visit_count, "nmg_loop_split_at_touching_jaunt: visit_count[]\n" );
03244                 if( jaunt_status )
03245                         bu_free( (char *)jaunt_status, "nmg_loop_split_at_touching_jaunt: jaunt_status[]\n" );
03246                 if( !need_init )
03247                         bu_ptbl_free( &jaunt_tbl);
03248 
03249                 if ((rt_g.NMG_debug & DEBUG_BASIC) || (rt_g.NMG_debug & DEBUG_CUTLOOP))  {
03250                         bu_log("nmg_loop_split_at_touching_jaunt( lu=x%x ) END count=%d\n",
03251                                 lu, count);
03252                 }
03253                 return( count );
03254         }
03255 
03256         if( jaunt_count == 1 )
03257         {
03258                 /* just one jaunt, split it and return */
03259                 BU_CK_PTBL( &jaunt_tbl );
03260 
03261                 eu = (struct edgeuse *)BU_PTBL_GET( &jaunt_tbl, 0 );
03262                 NMG_CK_EDGEUSE( eu );
03263                 eu2 = BU_LIST_PNEXT_CIRC(edgeuse, &eu->l);
03264 
03265                 new_lu = nmg_split_lu_at_vu( lu, eu2->vu_p );
03266                 count++;
03267                 NMG_CK_LOOPUSE(new_lu);
03268                 NMG_CK_LOOP(new_lu->l_p);
03269                 nmg_loop_g(new_lu->l_p, tol);
03270 
03271                 bu_ptbl_free( &jaunt_tbl);
03272                 if( visit_count )
03273                         bu_free( (char *)visit_count, "nmg_loop_split_at_touching_jaunt: visit_count[]\n" );
03274                 if( jaunt_status )
03275                         bu_free( (char *)jaunt_status, "nmg_loop_split_at_touching_jaunt: jaunt_status[]\n" );
03276 
03277                 if ((rt_g.NMG_debug & DEBUG_BASIC) || (rt_g.NMG_debug & DEBUG_CUTLOOP))  {
03278                         bu_log("nmg_loop_split_at_touching_jaunt( lu=x%x ) END count=%d\n",
03279                                 lu, count);
03280                 }
03281                 return( count );
03282         }
03283 
03284         /* if we get here, there are at least two touching jaunts in the loop.
03285          * We need to select which order to split them to avoid converting the
03286          * touching jaunt into a crack. To do this, select one touching jaunt
03287          * as the location for splitting the loop. Follow the EU's as nmg_split_lu_at_vu()
03288          * would do and predict the status of ALL the touching jaunts (not just the one being
03289          * split). Both the new loop and the remains of the current loop must be checked
03290          * to determine the status of all the touching jaunts.
03291          * The original touching jaunts must either remain as touching jaunts in
03292          * one of the two resulting loops, or they must be split between the two
03293          * resulting loops. If any of the touching jaunts are predicted to have a status
03294          * other than split or still touching, then this is a bad choice for splitting
03295          * the loop. For example, a touching jaunt may be converted to a non-touching
03296          * jaunt by applying nmg_split_lu_at_vu() at the wrong vu and will later be
03297          * converted to a two edgeuse loop by nmg_split_touching_loops.
03298          */
03299         BU_CK_PTBL( &jaunt_tbl );
03300 
03301         if( visit_count )
03302                 bu_free( (char *)visit_count, "nmg_loop_split_at_touching_jaunt: visit_count[]\n" );
03303         if( jaunt_status )
03304                 bu_free( (char *)jaunt_status, "nmg_loop_split_at_touching_jaunt: jaunt_status[]\n" );
03305 
03306         visit_count = (int *)bu_calloc( BU_PTBL_END( &jaunt_tbl ), sizeof( int ),
03307                         "nmg_loop_split_at_touching_jaunt: visit_count[]" );
03308         jaunt_status = (int *)bu_calloc( BU_PTBL_END( &jaunt_tbl ), sizeof( int ),
03309                         "nmg_loop_split_at_touching_jaunt: jaunt_status[]" );
03310 
03311         /* consider each jaunt as a possible location for splitting the loop */
03312         for( jaunt_no=0 ; jaunt_no<BU_PTBL_END( &jaunt_tbl ) ; jaunt_no++ )
03313         {
03314                 struct edgeuse *start_eu1;      /* EU that will start a new loop upon split */
03315                 struct edgeuse *start_eu2;      /* EU that will start the remaining loop */
03316                 int do_split=1;                 /* flag: 1 -> this jaunt is a good choice for making the split */
03317 
03318                 /* initialize the status of each jaunt to unknown */
03319                 for( i=0 ; i<BU_PTBL_END( &jaunt_tbl ) ; i++ )
03320                         jaunt_status[i] = JS_UNKNOWN;
03321 
03322                 /* consider splitting lu at this touching jaunt */
03323                 eu = (struct edgeuse *)BU_PTBL_GET( &jaunt_tbl, jaunt_no );
03324                 NMG_CK_EDGEUSE( eu );
03325 
03326                 /* get new loop starting edgeuse */
03327                 start_eu1 = BU_LIST_PNEXT_CIRC(edgeuse, &eu->l);
03328 
03329                 if( rt_g.NMG_debug & DEBUG_CUTLOOP )
03330                 {
03331                         bu_log( "\tConsider splitting lu x%x at vu=x%x\n", lu, start_eu1->vu_p );
03332                         bu_log( "\t\t(jaunt number %d\n" , jaunt_no );
03333                 }
03334 
03335                 /* determine status of jaunts in the proposed new loop */
03336                 nmg_check_proposed_loop( start_eu1, &start_eu2, visit_count,
03337                         jaunt_status, &jaunt_tbl, jaunt_no, 0 );
03338 
03339                 /* Still need to check the loop that will be left if we do a split here */
03340                 nmg_check_proposed_loop( start_eu2, &start_eu1, visit_count,
03341                         jaunt_status, &jaunt_tbl, jaunt_no, 1 );
03342 
03343                 if( rt_g.NMG_debug & DEBUG_CUTLOOP )
03344                 {
03345                         for( i=0 ; i<BU_PTBL_END( &jaunt_tbl ) ; i++ )
03346                         {
03347                                 struct edgeuse *tmp_eu;
03348 
03349                                 tmp_eu = (struct edgeuse *)BU_PTBL_GET( &jaunt_tbl, i );
03350                                 bu_log( "\t\tpredicted status of jaunt at eu x%x is ", tmp_eu );
03351                                 switch( jaunt_status[i] )
03352                                 {
03353                                         case JS_UNKNOWN:
03354                                                 bu_log( "unknown\n" );
03355                                                 break;
03356                                         case JS_SPLIT:
03357                                                 bu_log( "split\n" );
03358                                                 break;
03359                                         case JS_JAUNT:
03360                                                 bu_log( "a jaunt\n" );
03361                                                 break;
03362                                         case JS_TOUCHING_JAUNT:
03363                                                 bu_log( "still a touching jaunt\n" );
03364                                                 break;
03365                                         default:
03366                                                 bu_log( "unrecognized status\n" );
03367                                                 break;
03368                                 }
03369                         }
03370                 }
03371 
03372                 /* check predicted status of all the touching jaunts,
03373                  * every one must be either split or still a touching jaunt.
03374                  * Any other status will create loops of two edgeuses!!!
03375                  */
03376                 for( i=0 ; i<BU_PTBL_END( &jaunt_tbl ) ; i++ )
03377                 {
03378                         if(jaunt_status[i] != JS_SPLIT && jaunt_status[i] != JS_TOUCHING_JAUNT )
03379                         {
03380                                 do_split = 0;
03381                                 break;
03382                         }
03383                 }
03384 
03385                 /* if splitting lu at this touching jaunt is not desirable, check the next one */
03386                 if( !do_split )
03387                 {
03388                         if( rt_g.NMG_debug & DEBUG_CUTLOOP )
03389                         {
03390                                 bu_log( "\t\tCannot split lu x%x at proposed vu\n" );
03391                         }
03392                         continue;
03393                 }
03394 
03395                 /* This touching jaunt passed all the tests, its reward is to be split */
03396                 eu2 = BU_LIST_PNEXT_CIRC(edgeuse, &eu->l);
03397 
03398                 new_lu = nmg_split_lu_at_vu( lu, eu2->vu_p );
03399 
03400                 if( rt_g.NMG_debug & DEBUG_CUTLOOP )
03401                 {
03402                         bu_log( "\tnmg_loop_split_at_touching_jaunt: splitting lu x%x at vu x%x\n", lu, eu2->vu_p );
03403                         bu_log( "\t\tnew_lu is x%x\n" , new_lu );
03404                 }
03405 
03406                 count++;
03407                 NMG_CK_LOOPUSE(new_lu);
03408                 NMG_CK_LOOP(new_lu->l_p);
03409                 nmg_loop_g(new_lu->l_p, tol);
03410                 bu_ptbl_reset( &jaunt_tbl);
03411 
03412                 /* recurse on the new loop */
03413                 count += nmg_loop_split_at_touching_jaunt( new_lu, tol );
03414 
03415                 /* continue with the remains of the current loop */
03416                 goto top;
03417         }
03418 
03419         /* If we ever get here, we have failed to find a way to split this loop!!!! */
03420         bu_log( "nmg_loop_split_at_touching_jaunt: Could not find a way to split lu x%x\n", lu );
03421         nmg_pr_lu_briefly( lu, " " );
03422         nmg_stash_model_to_file( "jaunt.g", nmg_find_model( &lu->l.magic ), "Can't split lu" );
03423         rt_bomb( "nmg_loop_split_at_touching_jaunt: Can't split lu\n" );
03424 
03425         /* This return will never execute, but the compilers like it */
03426         return( count );
03427 }
03428 
03429 /**                     N M G _ S I M P L I F Y _ L O O P
03430  *
03431  *      combine adjacent loops within the same parent that touch along
03432  *      a common edge into a single loop, with the edge eliminated.
03433  */
03434 void
03435 nmg_simplify_loop(struct loopuse *lu)
03436 {
03437         struct edgeuse *eu, *eu_r, *tmpeu;
03438 
03439         NMG_CK_LOOPUSE(lu);
03440         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03441                 bu_log("nmg_simplify_loop(lu=x%x)\n", lu);
03442         }
03443 
03444         if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC)
03445                 return;
03446 
03447         eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
03448         while (BU_LIST_NOT_HEAD(eu, &lu->down_hd) ) {
03449 
03450                 NMG_CK_EDGEUSE(eu);
03451 
03452                 eu_r = eu->radial_p;
03453                 NMG_CK_EDGEUSE(eu_r);
03454 
03455                 /* if the radial edge is part of a loop, and the loop of
03456                  * the other edge is a part of the same object (face)
03457                  * as the loop containing the current edge, and my
03458                  * edgeuse mate is radial to my radial`s edgeuse
03459                  * mate, and the radial edge is a part of a loop other
03460                  * than the one "eu" is a part of
03461                  * then this is a "worthless" edge between these two loops.
03462                  */
03463                 if (*eu_r->up.magic_p == NMG_LOOPUSE_MAGIC &&
03464                     eu_r->up.lu_p->up.magic_p == lu->up.magic_p &&
03465                     eu->eumate_p->radial_p == eu->radial_p->eumate_p &&
03466                     eu_r->up.lu_p != lu) {
03467 
03468                         if( eu_r->up.lu_p->orientation != lu->orientation &&
03469                            (lu->orientation != OT_SAME ||
03470                             eu_r->up.lu_p->orientation != OT_OPPOSITE) )  {
03471                                 /* Does not meet requirements of nmg_jl(),
03472                                  * skip it.
03473                                  */
03474                                 eu = BU_LIST_PNEXT(edgeuse, eu);
03475                                 continue;
03476                         }
03477 
03478                         /* save a pointer to where we've already been
03479                          * so that when eu becomes an invalid pointer, we
03480                          * still know where to pick up from.
03481                          */
03482                         tmpeu = BU_LIST_PLAST(edgeuse, eu);
03483 
03484                         nmg_jl(lu, eu);
03485 
03486                         /* Since all the new edges will have been appended
03487                          * after tmpeu, we can pick up processing with the
03488                          * edgeuse immediately after tmpeu
03489                          */
03490                         eu = tmpeu;
03491 
03492                         if (rt_g.NMG_debug &(DEBUG_PLOTEM|DEBUG_PL_ANIM) &&
03493                             *lu->up.magic_p == NMG_FACEUSE_MAGIC ) {
03494                                 static int fno=0;
03495 
03496                                 nmg_pl_2fu("After_joinloop%d.pl", fno++,
03497                                     lu->up.fu_p, lu->up.fu_p->fumate_p, 0);
03498 
03499                         }
03500                 }
03501                 eu = BU_LIST_PNEXT(edgeuse, eu);
03502         }
03503 }
03504 
03505 
03506 /**
03507  *                      N M G _ K I L L _ S N A K E S
03508  *
03509  *  Removes "snake" or "disconnected crack" edges from loopuse.
03510  *
03511  *  Returns -
03512  *      0       If all went well
03513  *      1       If the loopuse is now empty and needs to be killed.
03514  */
03515 int
03516 nmg_kill_snakes(struct loopuse *lu)
03517 {
03518         struct edgeuse *eu, *eu_r;
03519         struct vertexuse *vu;
03520         struct vertex *v;
03521 
03522         NMG_CK_LOOPUSE(lu);
03523         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03524                 bu_log("nmg_kill_snakes(lu=x%x)\n", lu);
03525         }
03526         if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC)
03527                 return 0;
03528 
03529         eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
03530         while (BU_LIST_NOT_HEAD(eu, &lu->down_hd) ) {
03531 
03532                 NMG_CK_EDGEUSE(eu);
03533 
03534                 eu_r = eu->radial_p;
03535                 NMG_CK_EDGEUSE(eu_r);
03536 
03537                 /* if the radial edge is a part of the same loop, and
03538                  * this edge is not used by anyplace else, and the radial edge
03539                  * is also the next edge, this MAY be the tail of a snake!
03540                  */
03541 
03542                 if (*eu_r->up.magic_p == NMG_LOOPUSE_MAGIC &&
03543                     eu_r->up.lu_p == eu->up.lu_p &&
03544                     eu->eumate_p->radial_p == eu->radial_p->eumate_p &&
03545                     BU_LIST_PNEXT_CIRC(edgeuse, eu) == eu_r) {
03546 
03547                         /* if there are no other uses of the vertex
03548                          * between these two edgeuses, then this is
03549                          * indeed the tail of a snake
03550                          */
03551                         v = eu->eumate_p->vu_p->v_p;
03552                         vu = BU_LIST_FIRST(vertexuse, &v->vu_hd);
03553                         while (BU_LIST_NOT_HEAD(vu, &v->vu_hd) &&
03554                               (vu->up.eu_p == eu->eumate_p ||
03555                                vu->up.eu_p == eu_r) )
03556                                 vu = BU_LIST_PNEXT(vertexuse, vu);
03557 
03558                         if (! BU_LIST_NOT_HEAD(vu, &v->vu_hd) ) {
03559                                 /* this is the tail of a snake! */
03560                                 (void)nmg_keu(eu_r);
03561                                 if( nmg_keu(eu) )  return 1; /* kill lu */
03562                                 if( BU_LIST_IS_EMPTY( &lu->down_hd ) )
03563                                         return 1;       /* loopuse is empty */
03564                                 eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
03565 
03566                                 if (rt_g.NMG_debug &(DEBUG_PLOTEM|DEBUG_PL_ANIM) &&
03567                                     *lu->up.magic_p == NMG_FACEUSE_MAGIC ) {
03568                                         static int fno=0;
03569 
03570                                         nmg_pl_2fu("After_joinloop%d.pl", fno++,
03571                                             lu->up.fu_p, lu->up.fu_p->fumate_p, 0);
03572 
03573                                 }
03574 
03575 
03576                         } else
03577                                 eu = BU_LIST_PNEXT(edgeuse, eu);
03578                 } else
03579                         eu = BU_LIST_PNEXT(edgeuse, eu);
03580         }
03581         return 0;       /* All is well, loop still has edges */
03582 }
03583 
03584 /**
03585  *                      N M G _ M V _ L U _ B E T W E E N _ S H E L L S
03586  *
03587  *  Move a wire-loopuse from one shell to another.
03588  *  Note that this routine can not be used on loops in faces.
03589  */
03590 void
03591 nmg_mv_lu_between_shells(struct shell *dest, register struct shell *src, register struct loopuse *lu)
03592 {
03593         register struct loopuse *lumate;
03594 
03595         NMG_CK_LOOPUSE(lu);
03596         lumate = lu->lumate_p;
03597         NMG_CK_LOOPUSE(lumate);
03598 
03599         if( lu->up.s_p != src )  {
03600                 bu_log("nmg_mv_lu_between_shells(dest=x%x, src=x%x, lu=x%x), lu->up.s_p=x%x isn't source shell\n",
03601                         dest, src, lu, lu->up.s_p );
03602                 rt_bomb("lu->up.s_p isn't source shell\n");
03603         }
03604         if( lumate->up.s_p != src )  {
03605                 bu_log("nmg_mv_lu_between_shells(dest=x%x, src=x%x, lu=x%x), lumate->up.s_p=x%x isn't source shell\n",
03606                         dest, src, lu, lumate->up.s_p );
03607                 rt_bomb("lumate->up.s_p isn't source shell\n");
03608         }
03609 
03610         /* Remove lu from src shell */
03611         BU_LIST_DEQUEUE( &lu->l );
03612         if( BU_LIST_IS_EMPTY( &src->lu_hd ) )  {
03613                 /* This was the last lu in the list */
03614                 bu_log("nmg_mv_lu_between_shells(dest=x%x, src=x%x, lu=x%x), lumate=x%x not in src shell\n",
03615                         dest, src, lu, lumate );
03616                 rt_bomb("src shell emptied before finding lumate\n");
03617         }
03618 
03619         /* Remove lumate from src shell */
03620         BU_LIST_DEQUEUE( &lumate->l );
03621 
03622         /* Add lu and lumate to dest shell */
03623         BU_LIST_APPEND( &dest->lu_hd, &lu->l );
03624         BU_LIST_APPEND( &lu->l, &lumate->l );
03625 
03626         lu->up.s_p = dest;
03627         lumate->up.s_p = dest;
03628 
03629         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03630                 bu_log("nmg_mv_lu_between_shells(dest=x%x, src=x%x, lu=x%x)\n",
03631                         dest , src , lu);
03632         }
03633 }
03634 
03635 /**
03636  *                      N M G _ M O V E L T O F
03637  *
03638  *      move first pair of shell wire loopuses out to become a genuine loop
03639  *      in an existing face.
03640  * XXX This routine is not used anywhere, and may not work.
03641  */
03642 void nmg_moveltof(struct faceuse *fu, struct shell *s)
03643 {
03644         struct loopuse  *lu1, *lu2;
03645 
03646         NMG_CK_SHELL(s);
03647         NMG_CK_FACEUSE(fu);
03648         if (fu->s_p != s) {
03649                 bu_log("nmg_moveltof() in %s at %d. Cannot move loop to face in another shell\n",
03650                     __FILE__, __LINE__);
03651         }
03652         lu1 = BU_LIST_FIRST(loopuse, &s->lu_hd);
03653         NMG_CK_LOOPUSE(lu1);
03654         BU_LIST_DEQUEUE( &lu1->l );
03655 
03656         lu2 = BU_LIST_FIRST(loopuse, &s->lu_hd);
03657         NMG_CK_LOOPUSE(lu2);
03658         BU_LIST_DEQUEUE( &lu2->l );
03659 
03660         BU_LIST_APPEND( &fu->lu_hd, &lu1->l );
03661         BU_LIST_APPEND( &fu->fumate_p->lu_hd, &lu2->l );
03662         /* XXX What about loopuse "up" pointers? */
03663 
03664         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03665                 bu_log("nmg_moveltof(fu=x%x, s=x%x)\n",
03666                         fu , s );
03667         }
03668 }
03669 
03670 /**
03671  *                      N M G _ D U P _ L O O P
03672  *
03673  *  A support routine for nmg_dup_face()
03674  *
03675  *  trans_tbl may be NULL.
03676  */
03677 struct loopuse *
03678 nmg_dup_loop(struct loopuse *lu, long int *parent, long int **trans_tbl)
03679 
03680                                 /* fu or shell ptr */
03681 
03682 {
03683         struct loopuse *new_lu = (struct loopuse *)NULL;
03684         struct vertexuse *new_vu = (struct vertexuse *)NULL;
03685         struct vertexuse *old_vu = (struct vertexuse *)NULL;
03686         struct vertex *old_v = (struct vertex *)NULL;
03687         struct vertex   *new_v;
03688         struct edgeuse *new_eu = (struct edgeuse *)NULL;
03689         struct edgeuse *tbl_eu = (struct edgeuse *)NULL;
03690         struct edgeuse *eu = (struct edgeuse *)NULL;
03691 
03692         NMG_CK_LOOPUSE(lu);
03693 
03694         /* if loop is just a vertex, that's simple to duplicate */
03695         if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) {
03696                 old_vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
03697                 old_v = old_vu->v_p;
03698 
03699                 /* Obtain new duplicate of old vertex.  May be null 1st time. */
03700                 if( trans_tbl )
03701                         new_v = NMG_INDEX_GETP(vertex, trans_tbl, old_v);
03702                 else
03703                         new_v = (struct vertex *)NULL;
03704                 new_lu = nmg_mlv(parent, new_v, lu->orientation);
03705                 if (new_lu->orientation != lu->orientation) {
03706                         bu_log("%s %d: I asked for a %s loop not a %s loop.\n",
03707                                 __FILE__, __LINE__,
03708                                 nmg_orientation(lu->orientation),
03709                                 nmg_orientation(new_lu->orientation));
03710                         rt_bomb("bombing\n");
03711                 }
03712                 if( new_v )  {
03713                         /* the new vertex already exists in the new model */
03714                         bu_log("nmg_dup_loop() existing vertex in new model\n");
03715                         return (struct loopuse *)NULL;
03716                 }
03717                 /* nmg_mlv made a new vertex */
03718                 bu_log("nmg_dup_loop() new vertex in new model\n");
03719 
03720                 new_vu = BU_LIST_FIRST(vertexuse, &new_lu->down_hd);
03721                 new_v = new_vu->v_p;
03722                 /* Give old_v entry a pointer to new_v */
03723                 if( trans_tbl )
03724                         NMG_INDEX_ASSIGN( trans_tbl, old_v, (long *)new_v );
03725                 if (old_v->vg_p) {
03726                         /* Build a different vertex_g with same coordinates */
03727                         nmg_vertex_gv(new_v, old_v->vg_p->coord);
03728                 }
03729                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
03730                         bu_log("nmg_dup_loop(lu=x%x, parent=x%x, trans_tbl=x%x) new_lu=x%x\n",
03731                                 lu , parent , trans_tbl , new_lu );
03732                 }
03733                 return new_lu;
03734         }
03735 
03736         /* This loop is an edge-loop.  This is a little more work
03737          * First order of business is to duplicate the vertex/edge makeup.
03738          */
03739         for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
03740 
03741                 NMG_CK_EDGEUSE(eu);
03742                 NMG_CK_VERTEXUSE(eu->vu_p);
03743                 NMG_CK_VERTEX(eu->vu_p->v_p);
03744                 old_v = eu->vu_p->v_p;
03745 
03746                 /* Obtain new duplicate of old vertex.  May be null 1st time. */
03747                 if( trans_tbl )
03748                         new_v = NMG_INDEX_GETP(vertex, trans_tbl, old_v);
03749                 else
03750                         new_v = (struct vertex *)NULL;
03751 
03752                 if (new_lu == (struct loopuse *)NULL) {
03753                         /* this is the first edge in the new loop */
03754                         new_lu = nmg_mlv(parent, new_v, lu->orientation);
03755                         if (new_lu->orientation != lu->orientation) {
03756                                 bu_log("%s %d: I asked for a %s loop not a %s loop.\n",
03757                                         __FILE__, __LINE__,
03758                                         nmg_orientation(lu->orientation),
03759                                         nmg_orientation(new_lu->orientation));
03760                                 rt_bomb("bombing\n");
03761                         }
03762 
03763                         new_vu = BU_LIST_FIRST(vertexuse, &new_lu->down_hd);
03764 
03765                         NMG_CK_VERTEXUSE(new_vu);
03766                         NMG_CK_VERTEX(new_vu->v_p);
03767 
03768                         if( !new_v && trans_tbl )  {
03769                                 /* Give old_v entry a pointer to new_v */
03770                                 NMG_INDEX_ASSIGN( trans_tbl, old_v,
03771                                         (long *)new_vu->v_p );
03772                         }
03773                         new_v = new_vu->v_p;
03774 
03775                         new_eu = nmg_meonvu(new_vu);
03776                 } else {
03777                         /* not the first edge in new loop */
03778                         new_eu = BU_LIST_LAST(edgeuse, &new_lu->down_hd);
03779                         NMG_CK_EDGEUSE(new_eu);
03780 
03781                         new_eu = nmg_eusplit(new_v, new_eu, 0);
03782                         new_vu = new_eu->vu_p;
03783 
03784                         if( !new_v && trans_tbl )  {
03785                                 /* Give old_v entry a pointer to new_v */
03786                                 NMG_INDEX_ASSIGN( trans_tbl, old_v,
03787                                         (long *)new_vu->v_p );
03788                         }
03789                         new_v = new_vu->v_p;
03790                 }
03791                 /* Build a different vertex_g with same coordinates */
03792                 if (old_v->vg_p) {
03793                         NMG_CK_VERTEX_G(old_v->vg_p);
03794                         nmg_vertex_gv(new_v, old_v->vg_p->coord);
03795                 }
03796 
03797                 /* Prepare to glue edges */
03798                 /* Use old_e as subscript, to get 1st new_eu (for new_e) */
03799                 /* Use old_eu to get mapped new_eu */
03800                 if( trans_tbl )
03801                         tbl_eu = NMG_INDEX_GETP(edgeuse, trans_tbl, eu->e_p );
03802                 else
03803                         tbl_eu = (struct edgeuse *)NULL;
03804                 if( !tbl_eu && trans_tbl )  {
03805                         /* Establishes map from old edge to new edge(+use) */
03806                         NMG_INDEX_ASSIGN( trans_tbl, eu->e_p, (long *)new_eu );
03807                 }
03808                 if( trans_tbl )
03809                         NMG_INDEX_ASSIGN( trans_tbl, eu, (long *)new_eu );
03810         }
03811 #if 0
03812 /* XXX untested */
03813         if( trans_tbl )
03814         {
03815                 /* All vertex structs are shared.  Make shared edges be shared */
03816                 for(BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
03817                         /* Use old_e as subscript, to get 1st new_eu (for new_e) */
03818                         /* Use old_eu to get mapped new_eu */
03819                         tbl_eu = NMG_INDEX_GETP(edgeuse, trans_tbl, eu->e_p );
03820                         new_eu = NMG_INDEX_GETP(edgeuse, trans_tbl, eu );
03821                         if( tbl_eu->e_p == new_eu->e_p )  continue;
03822 
03823                         /* new_eu isn't sharing edge with tbl_eu, join them */
03824                         /* XXX Is radial relationship preserved (enough)? */
03825                         nmg_je( tbl_eu, new_eu );
03826                 }
03827         }
03828 #endif
03829 
03830         /* Now that we've got all the right topology created and the
03831          * vertex geometries are in place we can create the edge geometries.
03832          * XXX This ought to be optional, as most callers will immediately
03833          * XXX change the vertex geometry anyway (e.g. by extrusion dist).
03834          */
03835         for(BU_LIST_FOR(new_eu, edgeuse, &new_lu->down_hd)) {
03836                 NMG_CK_EDGEUSE(new_eu);
03837                 NMG_CK_EDGE(new_eu->e_p);
03838                 if( new_eu->g.magic_p )  continue;
03839                 nmg_edge_g(new_eu);
03840         }
03841 
03842         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03843                 bu_log("nmg_dup_loop(lu=x%x(%s), parent=x%x, trans_tbl=x%x) new_lu=x%x(%s)\n",
03844                         lu, nmg_orientation(lu->orientation),
03845                         parent , trans_tbl , new_lu,
03846                         nmg_orientation(new_lu->orientation) );
03847         }
03848         return (new_lu);
03849 }
03850 
03851 /**
03852  *                      N M G _ S E T _ L U _ O R I E N T A T I O N
03853  *
03854  *  Set this loopuse and mate's orientation to be SAME or OPPOSITE
03855  *  from the orientation of the faceuse they each reside in.
03856  */
03857 void
03858 nmg_set_lu_orientation(struct loopuse *lu, int is_opposite)
03859 {
03860         NMG_CK_LOOPUSE(lu);
03861         NMG_CK_LOOPUSE(lu->lumate_p);
03862         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03863                 bu_log("nmg_set_lu_orientation(lu=x%x, %s)\n",
03864                         lu, is_opposite?"OT_OPPOSITE":"OT_SAME");
03865         }
03866         if( is_opposite )  {
03867                 /* Interior (crack) loop */
03868                 lu->orientation = OT_OPPOSITE;
03869                 lu->lumate_p->orientation = OT_OPPOSITE;
03870         } else {
03871                 /* Exterior loop */
03872                 lu->orientation = OT_SAME;
03873                 lu->lumate_p->orientation = OT_SAME;
03874         }
03875 }
03876 
03877 /**
03878  *                      N M G _ L U _ R E O R I E N T
03879  *
03880  *  Based upon a geometric calculation, reorient a loop and it's mate,
03881  *  if the stored orientation differs from the geometric one.
03882  *
03883  *  Note that the loopuse and it's mate have the same orientation;
03884  *  it's the faceuses that are normalward and anti-normalward.
03885  *  The loopuses either both agree with their faceuse, or both differ.
03886  */
03887 void
03888 nmg_lu_reorient(struct loopuse *lu)
03889 {
03890         struct faceuse  *fu;
03891         int     geom_orient;
03892         plane_t norm;
03893         plane_t lu_pl;
03894 
03895         NMG_CK_LOOPUSE(lu);
03896 
03897         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03898                 bu_log("nmg_lu_reorient(lu=x%x)\n", lu);
03899         }
03900 
03901         /* Don't harm the OT_BOOLPLACE self-loop marker vertices */
03902         if( lu->orientation == OT_BOOLPLACE &&
03903             BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC )
03904                 return;
03905 
03906         fu = lu->up.fu_p;
03907         NMG_CK_FACEUSE(fu);
03908         if( fu->orientation != OT_SAME )  {
03909                 lu = lu->lumate_p;
03910                 NMG_CK_LOOPUSE(lu);
03911                 fu = lu->up.fu_p;
03912                 NMG_CK_FACEUSE(fu);
03913                 if (rt_g.NMG_debug & DEBUG_BASIC)
03914                         bu_log("nmg_lu_reorient() selecting other fu=x%x, lu=x%x\n", fu, lu);
03915                 if( fu->orientation != OT_SAME )
03916                         rt_bomb("nmg_lu_reorient() no OT_SAME fu?\n");
03917         }
03918 
03919 
03920         /* Get OT_SAME faceuse's normal */
03921         NMG_GET_FU_PLANE( norm, fu );
03922         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03923                 PLPRINT("\tfu peqn", norm);
03924         }
03925 
03926         nmg_loop_plane_newell( lu, lu_pl );
03927 
03928         if( lu->orientation == OT_OPPOSITE )
03929                 HREVERSE( lu_pl, lu_pl );
03930 
03931         if( VDOT( lu_pl, norm ) < 0.0 )
03932                 geom_orient = OT_OPPOSITE;
03933         else
03934                 geom_orient = OT_SAME;
03935 
03936         if( lu->orientation == geom_orient )  return;
03937         if( rt_g.NMG_debug & DEBUG_BASIC )  {
03938                 bu_log("nmg_lu_reorient(x%x):  changing orientation: %s to %s\n",
03939                         lu, nmg_orientation(lu->orientation),
03940                         nmg_orientation(geom_orient) );
03941         }
03942 
03943         lu->orientation = geom_orient;
03944         lu->lumate_p->orientation = geom_orient;
03945 }
03946 
03947 /************************************************************************
03948  *                                                                      *
03949  *                              EDGE Routines                           *
03950  *                                                                      *
03951  ************************************************************************/
03952 
03953 /**
03954  *                      N M G _ E U S P L I T
03955  *
03956  *      Split an edgeuse by inserting a vertex into middle of the edgeuse.
03957  *
03958  *      Make a new edge, and a vertex.  If v is non-null it is taken as a
03959  *      pointer to an existing vertex to use as the start of the new edge.
03960  *      If v is null, then a new vertex is created for the begining of the
03961  *      new edge.
03962  *
03963  *      In either case, the new edge will exist as the "next" edgeuse after
03964  *      the edgeuse passed as a parameter.
03965  *
03966  *      Upon return, the new edgeuses (eu1 and mate) will not refer to any
03967  *      geometry, unless argument "share_geom" was non-zero.
03968  *
03969  *  Explicit return -
03970  *      edgeuse of new edge "eu1", starting at V and going to B.
03971  *
03972  *  List on entry -
03973  *
03974  *                     oldeu
03975  *                .------------->
03976  *               /
03977  *              A =============== B (edge)
03978  *                               /
03979  *                <-------------.
03980  *                    oldeumate
03981  *
03982  *  List on return -
03983  *
03984  *                   oldeu(cw)    eu1
03985  *                  .------->   .----->
03986  *                 /           /
03987  *         (edge) A ========= V ~~~~~~~ B (new edge)
03988  *                           /         /
03989  *                  <-------.   <-----.
03990  *                     mate      mate
03991  */
03992 struct edgeuse *
03993 nmg_eusplit(struct vertex *v, struct edgeuse *oldeu, int share_geom)
03994 {
03995         struct edgeuse  *eu1,
03996                         *eu2,
03997                         *oldeumate;
03998         struct shell *s = NULL;
03999         struct loopuse  *lu;
04000 
04001         NMG_CK_EDGEUSE(oldeu);
04002         if (v) {
04003                 NMG_CK_VERTEX(v);
04004         }
04005         oldeumate = oldeu->eumate_p;
04006         NMG_CK_EDGEUSE( oldeumate );
04007 
04008         /* if this edge has uses other than this edge and its mate, we must
04009          * separate these two edgeuses from the existing edge, and create
04010          * a new edge for them.  Then we can insert a new vertex in this
04011          * new edge without fear of damaging some other object.
04012          */
04013         if (oldeu->radial_p != oldeumate)
04014                 nmg_unglueedge(oldeu);
04015 
04016         if (*oldeu->up.magic_p == NMG_SHELL_MAGIC) {
04017                 s = oldeu->up.s_p;
04018                 NMG_CK_SHELL(s);
04019 
04020                 /*
04021                  *  Make an edge from the new vertex ("V") to vertex at
04022                  *  other end of the edge given ("B").
04023                  *  The new vertex "V" may be NULL, which will cause the
04024                  *  shell's lone vertex to be used, or a new one obtained.
04025                  *  New edges will be placed at head of shell's edge list.
04026                  */
04027                 eu1 = nmg_me(v, oldeumate->vu_p->v_p, s);
04028                 eu2 = eu1->eumate_p;
04029 
04030                 /*
04031                  *  The situation is now:
04032                  *
04033                  *      eu1                            oldeu
04034                  *  .----------->                 .------------->
04035                  * /                             /
04036                  *V ~~~~~~~~~~~~~ B (new edge)  A =============== B (edge)
04037                  *               /                               /
04038                  *  <-----------.                 <-------------.
04039                  *      eu2                           oldeumate
04040                  */
04041 
04042                 /* Make oldeumate start at "V", not "B" */
04043                 nmg_movevu(oldeumate->vu_p, eu1->vu_p->v_p);
04044 
04045                 /*
04046                  *  Enforce rigid ordering in shell's edge list:
04047                  *      oldeu, oldeumate, eu1, eu2
04048                  *  This is to keep edges & mates "close to each other".
04049                  */
04050                 if( BU_LIST_PNEXT(edgeuse, oldeu) != oldeumate )  {
04051                         BU_LIST_DEQUEUE( &oldeumate->l );
04052                         BU_LIST_APPEND( &oldeu->l, &oldeumate->l );
04053                 }
04054                 BU_LIST_DEQUEUE( &eu1->l );
04055                 BU_LIST_DEQUEUE( &eu2->l );
04056                 BU_LIST_APPEND( &oldeumate->l, &eu1->l );
04057                 BU_LIST_APPEND( &eu1->l, &eu2->l );
04058 
04059                 /*
04060                  *           oldeu(cw)    eu1
04061                  *          .------->   .----->
04062                  *         /           /
04063                  * (edge) A ========= V ~~~~~~~ B (new edge)
04064                  *                   /         /
04065                  *          <-------.   <-----.
04066                  *          oldeumate     eu2
04067                  */
04068                 if( share_geom )  {
04069                         /* Make eu1 share geom with oldeu, eu2 with oldeumate */
04070                         nmg_use_edge_g( eu1, oldeu->g.magic_p );
04071                         nmg_use_edge_g( eu2, oldeumate->g.magic_p );
04072                 } else {
04073                         /* Make eu2 use same geometry as oldeu */
04074                         nmg_use_edge_g( eu2, oldeu->g.magic_p );
04075                         /* Now release geometry from oldeumate;  new edge has no geom */
04076                         BU_LIST_DEQUEUE( &oldeumate->l2 );
04077                         nmg_keg( oldeumate );
04078                         BU_LIST_DEQUEUE( &eu1->l2 );
04079                         nmg_keg( eu1 );
04080                         BU_LIST_INIT( &oldeumate->l2 );
04081                         BU_LIST_INIT( &eu1->l2 );
04082                         oldeumate->l2.magic = NMG_EDGEUSE2_MAGIC;
04083                         eu1->l2.magic = NMG_EDGEUSE2_MAGIC;
04084                 }
04085                 goto out;
04086         }
04087         else if (*oldeu->up.magic_p != NMG_LOOPUSE_MAGIC) {
04088                 bu_log("nmg_eusplit() in %s at %d invalid edgeuse parent\n",
04089                         __FILE__, __LINE__);
04090                 rt_bomb("nmg_eusplit\n");
04091         }
04092 
04093         /* now we know we are in a loop */
04094 
04095         lu = oldeu->up.lu_p;
04096         NMG_CK_LOOPUSE(lu);
04097 
04098         /* get a parent shell pointer so we can make a new edge */
04099         if (*lu->up.magic_p == NMG_SHELL_MAGIC)
04100                 s = lu->up.s_p;
04101         else if (*lu->up.magic_p == NMG_FACEUSE_MAGIC)
04102                 s = lu->up.fu_p->s_p;
04103         else
04104                 rt_bomb("nmg_eusplit() bad lu->up\n");
04105         NMG_CK_SHELL(s);
04106 
04107         /* Make a new wire edge in the shell */
04108         if (v) {
04109                 /* An edge on the single vertex "V" */
04110                 eu1 = nmg_me(v, v, s);
04111                 eu2 = eu1->eumate_p;
04112         } else {
04113                 /* Form a wire edge between two new vertices */
04114                 eu1 = nmg_me((struct vertex *)NULL, (struct vertex *)NULL, s);
04115                 eu2 = eu1->eumate_p;
04116                 /* Make both ends of edge use same vertex.
04117                  * The second vertex is freed automaticly.
04118                  */
04119                 nmg_movevu(eu2->vu_p, eu1->vu_p->v_p);
04120         }
04121 
04122         /*
04123          *  The current situation is now:
04124          *
04125          *            eu1                                      oldeu
04126          *        .------------->                         .------------->
04127          *       /                                       /
04128          *      V ~~~~~~~~~~~~~~~ V (new edge)          A =============== B (edge)
04129          *                       /                                       /
04130          *        <-------------.                         <-------------.
04131          *            eu2                                     oldeumate
04132          *
04133          *  Goals:
04134          *  eu1 will become the mate to oldeumate on the existing edge.
04135          *  eu2 will become the mate of oldeu on the new edge.
04136          */
04137         BU_LIST_DEQUEUE( &eu1->l );
04138         BU_LIST_DEQUEUE( &eu2->l );
04139         BU_LIST_APPEND( &oldeu->l, &eu1->l );
04140         BU_LIST_APPEND( &oldeumate->l, &eu2->l );
04141 
04142         /*
04143          *  The situation is now:
04144          *
04145          *                     oldeu      eu1                   >>>loop>>>
04146          *                  .------->   .----->
04147          *                 /           /
04148          *         (edge) A ========= V ~~~~~~~ B (new edge)
04149          *                           /         /
04150          *                  <-------.   <-----.
04151          *                     eu2      oldeumate               <<<loop<<<
04152          */
04153 
04154         /* Copy parentage (loop affiliation) and orientation */
04155         eu1->up.magic_p = oldeu->up.magic_p;
04156         eu1->orientation = oldeu->orientation;
04157 
04158         eu2->up.magic_p = oldeumate->up.magic_p;
04159         eu2->orientation = oldeumate->orientation;
04160 
04161         /* Build mate relationship */
04162         eu1->eumate_p = oldeumate;
04163         oldeumate->eumate_p = eu1;
04164         eu2->eumate_p = oldeu;
04165         oldeu->eumate_p = eu2;
04166 
04167         /*  Build radial relationship.
04168          *  Simple only because this edge has no other uses.
04169          */
04170         eu1->radial_p = oldeumate;
04171         oldeumate->radial_p = eu1;
04172         eu2->radial_p = oldeu;
04173         oldeu->radial_p = eu2;
04174 
04175         /* Associate oldeumate with new edge, and eu2 with old edge. */
04176         oldeumate->e_p = eu1->e_p;
04177         eu2->e_p = oldeu->e_p;
04178 
04179         /* Ensure that edge points up to one of the proper edgeuses. */
04180         oldeumate->e_p->eu_p = oldeumate;
04181         eu2->e_p->eu_p = eu2;
04182 
04183         if( share_geom )  {
04184                 /* Make eu1 share same geometry as oldeu */
04185                 nmg_use_edge_g( eu1, oldeu->g.magic_p );
04186                 /* Make eu2 share same geometry as oldeumate */
04187                 nmg_use_edge_g( eu2, oldeumate->g.magic_p );
04188         } else {
04189                 /* Make eu2 use same geometry as oldeu */
04190                 nmg_use_edge_g( eu2, oldeu->g.magic_p );
04191                 /* Now release geometry from oldeumate;  new edge has no geom */
04192                 BU_LIST_DEQUEUE( &oldeumate->l2 );
04193                 nmg_keg( oldeumate );
04194                 BU_LIST_DEQUEUE( &eu1->l2 );
04195                 nmg_keg( eu1 );
04196                 BU_LIST_INIT( &oldeumate->l2 );
04197                 BU_LIST_INIT( &eu1->l2 );
04198                 oldeumate->l2.magic = NMG_EDGEUSE2_MAGIC;
04199                 eu1->l2.magic = NMG_EDGEUSE2_MAGIC;
04200         }
04201         if( oldeu->g.magic_p != oldeu->eumate_p->g.magic_p )  rt_bomb("nmg_eusplit() unshared geom\n");
04202 
04203 out:
04204         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04205                 bu_log("nmg_eusplit(v=x%x, eu=x%x, share=%d) new_eu=x%x, mate=x%x\n",
04206                         v, oldeu, share_geom,
04207                         eu1, eu1->eumate_p );
04208         }
04209         return(eu1);
04210 }
04211 
04212 /**
04213  *                      N M G _ E S P L I T
04214  *
04215  *      Split an edge by inserting a vertex into middle of *all* of the
04216  *      uses of this edge, and combine the new edgeuses together onto the
04217  *      new edge.
04218  *      A more powerful version of nmg_eusplit(), which does only one use.
04219  *
04220  *      Makes a new edge, and a vertex.  If v is non-null it is taken as a
04221  *      pointer to an existing vertex to use as the start of the new edge.
04222  *      If v is null, then a new vertex is created for the begining of the
04223  *      new edge.
04224  *
04225  *      In either case, the new edgeuse will exist as the "next" edgeuse
04226  *      after the edgeuse passed as a parameter.
04227  *
04228  *      Note that eu->e_p changes value upon return, because the old
04229  *      edge is incrementally replaced by two new ones.
04230  *
04231  *      Geometry will be preserved on eu and it's mates (by nmg_eusplit),
04232  *      if any.  ret_eu and mates will share that geometry if share_geom
04233  *      is set non-zero, otherwise they will have null geom pointers.
04234  *
04235  *  Explicit return -
04236  *      Pointer to the edgeuse which starts at the newly created
04237  *      vertex (V), and runs to B.
04238  *
04239  *  Implicit returns -
04240  *      ret_eu->vu_p->v_p gives the new vertex ("v", if non-null), and
04241  *      ret_eu->e_p is the new edge that runs from V to B.
04242  *
04243  *      The new vertex created will also be eu->eumate_p->vu_p->v_p.
04244  *
04245  *  Edge on entry -
04246  *
04247  *                      eu
04248  *                .------------->
04249  *               /
04250  *              A =============== B (edge)
04251  *                               /
04252  *                <-------------.
04253  *                  eu->eumate_p
04254  *
04255  *  Edge on return -
04256  *
04257  *                      eu        ret_eu
04258  *                  .------->   .--------->
04259  *                 /           /
04260  *      (newedge) A ========= V ~~~~~~~~~~~ B (new edge)
04261  *                           /             /
04262  *                  <-------.   <---------.
04263  *
04264  *  Note: to replicate the behavior of this routine in BRL-CAD Relase 4.0,
04265  *  call with share_geom=0.
04266  */
04267 struct edgeuse *
04268 nmg_esplit(struct vertex *v, struct edgeuse *eu, int share_geom)
04269                                 /* New vertex, to go in middle */
04270 
04271 
04272 {
04273         struct edge     *e;     /* eu->e_p */
04274         struct edgeuse  *teuX,  /* radial edgeuse of eu */
04275                         *teuY,  /* new edgeuse (next of teuX) */
04276                         *neu1, *neu2; /* new (split) edgeuses */
04277         int             notdone=1;
04278         struct vertex   *vA, *vB;       /* start and end of eu */
04279 
04280         neu1 = neu2 = (struct edgeuse *)NULL;
04281 
04282         NMG_CK_EDGEUSE(eu);
04283         e = eu->e_p;
04284         NMG_CK_EDGE(e);
04285 
04286         NMG_CK_VERTEXUSE(eu->vu_p);
04287         vA = eu->vu_p->v_p;
04288         NMG_CK_VERTEX(vA);
04289 
04290         NMG_CK_EDGEUSE(eu->eumate_p);
04291         NMG_CK_VERTEXUSE(eu->eumate_p->vu_p);
04292         vB = eu->eumate_p->vu_p->v_p;
04293         NMG_CK_VERTEX(vB);
04294 
04295         if( v && ( v == vA || v == vB ) )  {
04296                 bu_log("WARNING: nmg_esplit(v=x%x) vertex is already an edge vertex\n", v);
04297                 rt_bomb("nmg_esplit() new vertex is already an edge vertex\n");
04298         }
04299 
04300         /* one at a time, we peel out & split an edgeuse pair of this edge.
04301          * when we split an edge that didn't need to be peeled out, we know
04302          * we've split the last edge
04303          */
04304         do {
04305                 /* Peel two temporary edgeuses off the original edge */
04306                 teuX = eu->radial_p;
04307                 /* teuX runs from vA to vB */
04308                 teuY = nmg_eusplit(v, teuX, share_geom);
04309                 /* Now, teuX runs from vA to v, teuY runs from v to vB */
04310                 NMG_CK_EDGEUSE(teuX);
04311                 NMG_CK_EDGEUSE(teuY);
04312                 NMG_TEST_EDGEUSE(teuX);
04313                 NMG_TEST_EDGEUSE(teuY);
04314 
04315                 if (!v)  {
04316                         /* If "v" parameter was NULL and this is the
04317                          * first time through, take note of "v" where
04318                          * "e" was just split at.
04319                          */
04320                         v = teuY->vu_p->v_p;
04321                         NMG_CK_VERTEX(v);
04322                 }
04323 
04324                 if (teuY->e_p == e || teuX->e_p == e) notdone = 0;
04325 
04326                 /*  Are the two edgeuses going in same or opposite directions?
04327                  *  Join the newly created temporary edge (teuX, teuY)
04328                  *  with the new permanant edge (neu1, neu2).
04329                  *  On first pass, just take note of the new edge & edgeuses.
04330                  */
04331                 NMG_CK_VERTEX(teuX->vu_p->v_p);
04332                 if (teuX->vu_p->v_p == vA) {
04333                         if (neu1) {
04334                                 nmg_je(neu1, teuX);
04335                                 nmg_je(neu2, teuY);
04336                         }
04337                         neu1 = teuX->eumate_p;
04338                         neu2 = teuY->eumate_p;
04339                 } else if (teuX->vu_p->v_p == vB) {
04340                         if (neu1) {
04341                                 nmg_je(neu2, teuX);
04342                                 nmg_je(neu1, teuY);
04343                         }
04344                         neu2 = teuX->eumate_p;
04345                         neu1 = teuY->eumate_p;
04346                 } else {
04347                         bu_log("nmg_esplit(v=x%x, e=x%x)\n", v, e);
04348                         bu_log("nmg_esplit: teuX->vu_p->v_p=x%x, vA=x%x, vB=x%x\n", teuX->vu_p->v_p, vA, vB );
04349                         rt_bomb("nmg_esplit() teuX->vu_p->v_p is neither vA nor vB\n");
04350                 }
04351         } while (notdone);
04352         /* Here, "e" pointer is invalid -- it no longer exists */
04353 
04354         /* Find an edgeuse that runs from v to vB */
04355         if( neu2->vu_p->v_p == v && neu2->eumate_p->vu_p->v_p == vB )  {
04356                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
04357                         bu_log("nmg_esplit(v=x%x, eu=x%x, share=%d) neu2=x%x\n",
04358                                 v, eu, share_geom, neu2);
04359                 }
04360                 return neu2;
04361         }
04362         else if( neu1->vu_p->v_p == v && neu1->eumate_p->vu_p->v_p == vB )  {
04363                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
04364                         bu_log("nmg_esplit(v=x%x, eu=x%x, share=%d) neu1=x%x\n",
04365                                 v, eu, share_geom, neu1);
04366                 }
04367                 return neu1;
04368         }
04369 
04370         rt_bomb("nmg_esplit() unable to find eu starting at new v\n");
04371         /* NOTREACHED */
04372         return (struct edgeuse *)NULL;
04373 }
04374 
04375 /**
04376  *                      N M G _ E B R E A K
04377  *
04378  *  Like nmg_esplit(), split an edge into two parts.
04379  *  Ensure that both sets of edgeuses share the original edgeuse geometry.
04380  *  If the original edge had no edge geometry, then none is created here.
04381  *
04382  *  This is a simple compatability interface to nmg_esplit().
04383  *  The return is the return of nmg_esplit().
04384  */
04385 struct edgeuse *
04386 nmg_ebreak(struct vertex *v, struct edgeuse *eu)
04387                                         /* May be NULL */
04388 
04389 {
04390         struct edgeuse  *new_eu;
04391 
04392         NMG_CK_EDGEUSE(eu);
04393         if( eu->g.magic_p )  {
04394                 NMG_CK_EDGE_G_LSEG(eu->g.lseg_p);
04395         }
04396 
04397         new_eu = nmg_esplit(v, eu, 1);  /* Do the hard work */
04398         NMG_CK_EDGEUSE(eu);
04399         NMG_CK_EDGEUSE(new_eu);
04400 
04401         if( eu->e_p == new_eu->e_p )  rt_bomb("nmb_ebreak() same edges?\n");
04402 
04403         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04404                 bu_log("nmg_ebreak( v=x%x, eu=x%x ) new_eu=x%x\n",
04405                         v, eu, new_eu);
04406         }
04407         return new_eu;
04408 }
04409 
04410 /*
04411  *                      N M G _ E B R E A K E R
04412  *
04413  *  Like nmg_ebreak(), but with edge radial sorting when sharing occurs.
04414  *
04415  *  Use nmg_ebreak() to break an existing edge on a vertex, preserving edge
04416  *  geometry on both new edges.
04417  *  If the edge was broken on an existing vertex,
04418  *  search both old and new edgeuses to see if they need to be joined
04419  *  with an existing edgeuse that shared the same vertices.
04420  */
04421 struct edgeuse *
04422 nmg_ebreaker(struct vertex *v, struct edgeuse *eu, const struct bn_tol *tol)
04423                                                 /* May be NULL */
04424 
04425 
04426 {
04427         struct edgeuse  *new_eu;
04428         struct edgeuse  *oeu;
04429 
04430         NMG_CK_EDGEUSE(eu);
04431         BN_CK_TOL(tol);
04432 
04433 nmg_eu_radial_check( eu, nmg_find_s_of_eu(eu), tol );
04434         new_eu = nmg_ebreak(v, eu);
04435         if( v )  {
04436                 /*
04437                  *  This edge was broken on an existing vertex.
04438                  *  Search the whole model for other existing edges
04439                  *  that match the newly created edge fragments.
04440                  */
04441                 for(;;)  {
04442                         oeu = nmg_find_e( eu->vu_p->v_p,
04443                                 eu->eumate_p->vu_p->v_p,
04444                                 (struct shell *)NULL, eu->e_p );
04445                         if( !oeu ) break;
04446                         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04447                                 bu_log("nmg_ebreaker() joining eu=x%x to oeu=x%x\n",
04448                                         eu, oeu );
04449                         }
04450                         nmg_radial_join_eu( eu, oeu, tol );
04451                 }
04452 
04453                 for(;;)  {
04454                         oeu = nmg_find_e( new_eu->vu_p->v_p,
04455                                 new_eu->eumate_p->vu_p->v_p,
04456                                 (struct shell *)NULL, new_eu->e_p );
04457                         if( !oeu )  break;
04458                         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04459                                 bu_log("nmg_ebreaker() joining new_eu=x%x to oeu=x%x\n",
04460                                         new_eu, oeu );
04461                         }
04462                         nmg_radial_join_eu( new_eu, oeu, tol );
04463                 }
04464 /* XXX Will this catch it? */
04465 nmg_eu_radial_check( eu, nmg_find_s_of_eu(eu), tol );
04466 nmg_eu_radial_check( new_eu, nmg_find_s_of_eu(new_eu), tol );
04467 if( nmg_check_radial( eu, tol ) ) bu_log("ERROR ebreaker eu=x%x bad\n", eu);
04468 if( nmg_check_radial( new_eu, tol ) ) bu_log("ERROR ebreaker new_eu=x%x bad\n", new_eu);
04469         }
04470         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04471                 bu_log("nmg_ebreaker( v=x%x, eu=x%x ) new_eu=x%x\n", v, eu, new_eu);
04472         }
04473         return new_eu;
04474 }
04475 
04476 /**
04477  *                      N M G _ E 2 B R E A K
04478  *
04479  *  Given two edges that are known to intersect someplace other than
04480  *  at any of their endpoints, break both of them and
04481  *  insert a shared vertex.
04482  *  Return a pointer to the new vertex.
04483  */
04484 struct vertex *
04485 nmg_e2break(struct edgeuse *eu1, struct edgeuse *eu2)
04486 {
04487         struct vertex           *v;
04488         struct edgeuse          *new_eu;
04489 
04490         NMG_CK_EDGEUSE(eu1);
04491         NMG_CK_EDGEUSE(eu2);
04492 
04493         new_eu = nmg_ebreak( NULL, eu1 );
04494         v = new_eu->vu_p->v_p;
04495         NMG_CK_VERTEX(v);
04496         (void)nmg_ebreak( v, eu2 );
04497 
04498         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04499                 bu_log("nmg_e2break( eu1=x%x, eu2=x%x ) v=x%x\n", eu1, eu2, v);
04500         }
04501         return v;
04502 }
04503 /**
04504  *                      N M G _ U N B R E A K _ E D G E
04505  *
04506  *  Undoes the effect of an unwanted nmg_ebreak().
04507  *
04508  *  Eliminate the vertex between this edgeuse and the next edge,
04509  *  on all edgeuses radial to this edgeuse's edge.
04510  *  The edge geometry must be shared, and all uses of the vertex
04511  *  to be disposed of must originate from this edge pair.
04512  *  Also, the "non-B" ends of all edgeuses around e1 and e2 must
04513  *  terminate at either A or B.
04514  *
04515  *  XXX for t-NURBS, this should probably be re-stated as
04516  *  saying that all the edgeuses must share the same 2 edges, and that
04517  *  every eu1 needs to share geom with it's corresponding eu2,
04518  *  and similarly for the two mates.
04519  *
04520  *                   eu1          eu2
04521  *              *----------->*----------->*
04522  *              A.....e1.....B.....e2.....C
04523  *              *<-----------*<-----------*
04524  *                  eu1mate      eu2mate
04525  *
04526  *  If successful, the vertex B, the edge e2, and all the edgeuses
04527  *  radial to eu2 (including eu2) will have all been killed.
04528  *  The radial ordering around e1 will not change.
04529  *
04530  *                   eu1
04531  *              *------------------------>*
04532  *              A.....e1..................C
04533  *              *<------------------------*
04534  *                  eu1mate
04535  *
04536  *
04537  *  No new topology structures are created by this operation.
04538  *
04539  *  Returns -
04540  *      0       OK, edge unbroken
04541  *      <0      failure, nothing changed
04542  */
04543 int
04544 nmg_unbreak_edge(struct edgeuse *eu1_first)
04545 {
04546         struct edgeuse  *eu1;
04547         struct edgeuse  *eu2;
04548         struct edgeuse  *teu;
04549         struct edge     *e1;
04550         struct edge_g_lseg      *eg;
04551         struct vertexuse *vu;
04552         struct vertex   *vb = 0;
04553         struct vertex   *vc;
04554         struct vertex   *va;
04555         struct shell    *s1;
04556         int             ret = 0;
04557 
04558         NMG_CK_EDGEUSE( eu1_first );
04559         e1 = eu1_first->e_p;
04560         NMG_CK_EDGE( e1 );
04561 
04562         if( eu1_first->g.magic_p != eu1_first->eumate_p->g.magic_p )
04563                 rt_bomb("nmg_unbreak_edge() eu and mate don't share geometry\n");
04564 
04565         eg = eu1_first->g.lseg_p;
04566         if( !eg )  {
04567                 bu_log( "nmg_unbreak_edge: no geometry for edge1 x%x\n" , e1 );
04568                 ret = -1;
04569                 goto out;
04570         }
04571         NMG_CK_EDGE_G_LSEG(eg);
04572 
04573         /* If the edge geometry doesn't have at least four edgeuses, this
04574          * is not a candidate for unbreaking */
04575         if( bu_list_len( &eg->eu_hd2 ) < 2*2 )  {
04576                 ret = -2;
04577                 goto out;
04578         }
04579 
04580         s1 = nmg_find_s_of_eu(eu1_first);
04581         NMG_CK_SHELL(s1);
04582 
04583         eu1 = eu1_first;
04584         eu2 = BU_LIST_PNEXT_CIRC( edgeuse , eu1 );
04585         if( eu2->g.lseg_p != eg )  {
04586                 bu_log( "nmg_unbreak_edge: second eu geometry x%x does not match geometry x%x of edge1 x%x\n" ,
04587                         eu2->g.magic_p, eg, e1 );
04588                 ret = -3;
04589                 goto out;
04590         }
04591 
04592         va = eu1->vu_p->v_p;            /* start vertex (A) */
04593         vb = eu2->vu_p->v_p;            /* middle vertex (B) */
04594         vc = eu2->eumate_p->vu_p->v_p;  /* end vertex (C) */
04595 
04596         /* all uses of this vertex must be for this edge geometry, otherwise
04597          * it is not a candidate for deletion */
04598         for( BU_LIST_FOR( vu , vertexuse , &vb->vu_hd ) )  {
04599                 NMG_CK_VERTEXUSE(vu);
04600                 if( *(vu->up.magic_p) != NMG_EDGEUSE_MAGIC )  {
04601                         /* vertex is referred to by a self-loop */
04602                         if( vu->up.lu_p->orientation == OT_BOOLPLACE )  {
04603                                 /* This kind is transient, and safe to ignore */
04604                                 continue;
04605                         }
04606                         ret = -4;
04607                         goto out;
04608                 }
04609                 NMG_CK_EDGEUSE(vu->up.eu_p);
04610                 if( vu->up.eu_p->g.lseg_p != eg )  {
04611                         ret = -5;
04612                         goto out;
04613                 }
04614         }
04615 
04616         /* Visit all edgeuse pairs radial to eu1 (A--B) */
04617         teu = eu1;
04618         for(;;)  {
04619                 register struct edgeuse *teu2;
04620                 NMG_CK_EDGEUSE(teu);
04621                 if( teu->vu_p->v_p != va || teu->eumate_p->vu_p->v_p != vb )  {
04622                         ret = -6;
04623                         goto out;
04624                 }
04625                 /* We *may* encounter a teu2 not around eu2.  Seen in BigWedge */
04626                 teu2 = BU_LIST_PNEXT_CIRC( edgeuse, teu );
04627                 NMG_CK_EDGEUSE(teu2);
04628                 if( teu2->vu_p->v_p != vb || teu2->eumate_p->vu_p->v_p != vc )  {
04629                         ret = -7;
04630                         goto out;
04631                 }
04632                 teu = teu->eumate_p->radial_p;
04633                 if( teu == eu1 )  break;
04634         }
04635 
04636         /* Visit all edgeuse pairs radial to eu2 (B--C) */
04637         teu = eu2;
04638         for(;;)  {
04639                 NMG_CK_EDGEUSE(teu);
04640                 if( teu->vu_p->v_p != vb || teu->eumate_p->vu_p->v_p != vc )  {
04641                         ret = -8;
04642                         goto out;
04643                 }
04644                 teu = teu->eumate_p->radial_p;
04645                 if( teu == eu2 )  break;
04646         }
04647 
04648         /* All preconditions are met, begin the unbreak operation */
04649         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04650                 bu_log("nmg_unbreak_edge va=x%x, vb=x%x, vc=x%x\n",
04651                         va, vb, vc );
04652                 bu_log("nmg_unbreak_edge A:(%g, %g, %g), B:(%g, %g, %g), C:(%g, %g, %g)\n",
04653                         V3ARGS( va->vg_p->coord ),
04654                         V3ARGS( vb->vg_p->coord ),
04655                         V3ARGS( vc->vg_p->coord ) );
04656         }
04657 
04658         if( va == vc )
04659         {
04660                 /* bu_log( "nmg_unbreak_edge( eu=%x ): Trying to break a jaunt, va==vc (%x)\n", eu1_first, va ); */
04661                 ret = -9;
04662                 goto out;
04663         }
04664 
04665 
04666         /* visit all the edgeuse pairs radial to eu1 */
04667         for(;;)  {
04668                 /* Recheck initial conditions */
04669                 if( eu1->vu_p->v_p != va || eu1->eumate_p->vu_p->v_p != vb )  {
04670                         bu_log( "nmg_unbreak_edge: eu1 does not got to/from correct vertices, x%x, %x\n",
04671                                 eu1->vu_p->v_p, eu1->eumate_p->vu_p->v_p );
04672                         nmg_pr_eu_briefly( eu1, " " );
04673                         rt_bomb( "nmg_unbreak_edge 1\n" );
04674                 }
04675                 eu2 = BU_LIST_PNEXT_CIRC( edgeuse, eu1 );
04676                 NMG_CK_EDGEUSE(eu2);
04677                 if( eu2->g.lseg_p != eg )  {
04678                         rt_bomb("nmg_unbreak_edge:  eu2 geometry is wrong\n");
04679                 }
04680                 if( eu2->vu_p->v_p != vb || eu2->eumate_p->vu_p->v_p != vc )  {
04681                         bu_log( "nmg_unbreak_edge: about to kill eu2, but does not got to/from correct vertices, x%x, x%x\n",
04682                                 eu2->vu_p->v_p, eu2->eumate_p->vu_p->v_p );
04683                         nmg_pr_eu_briefly( eu2, " " );
04684                         rt_bomb( "nmg_unbreak_edge 3\n" );
04685                 }
04686 
04687                 /* revector eu1mate's start vertex from B to C */
04688                 nmg_movevu( eu1->eumate_p->vu_p , vc );
04689 
04690                 if( eu1->vu_p->v_p != va || eu1->eumate_p->vu_p->v_p != vc )  {
04691                         bu_log( "nmg_unbreak_edge: extended eu1 does not got to/from correct vertices, x%x, x%x\n",
04692                                 eu1->vu_p->v_p, eu1->eumate_p->vu_p->v_p );
04693                         nmg_pr_eu_briefly( eu1, " " );
04694                         rt_bomb( "nmg_unbreak_edge 2\n" );
04695                 }
04696 
04697                 if( eu2 != BU_LIST_PNEXT_CIRC( edgeuse, eu1 ) )
04698                         rt_bomb("nmg_unbreak_edge eu2 unexpected altered\n");
04699 
04700                 /* Now kill off the unnecessary eu2 associated w/ cur eu1 */
04701                 if( nmg_keu( eu2 ) )
04702                         rt_bomb( "nmg_unbreak_edge: edgeuse parent is now empty!!\n" );
04703 
04704                 if( eu1->vu_p->v_p != va || eu1->eumate_p->vu_p->v_p != vc )  {
04705                         bu_log( "nmg_unbreak_edge: unbroken eu1 (after eu2 killed) does not got to/from correct vertices, x%x, x%x\n",
04706                                 eu1->vu_p->v_p, eu1->eumate_p->vu_p->v_p );
04707                         nmg_pr_eu_briefly( eu1, " " );
04708                         rt_bomb( "nmg_unbreak_edge 4\n" );
04709                 }
04710                 eu1 = eu1->eumate_p->radial_p;
04711                 if( eu1 == eu1_first )  break;
04712         }
04713 out:
04714         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04715                 bu_log("nmg_unbreak_edge(eu=x%x, vb=x%x) ret = %d\n",
04716                         eu1_first, vb, ret);
04717         }
04718         return ret;
04719 }
04720 
04721 /**
04722  *                      N M G _ U N B R E A K _ S H E L L _ E D G E _ U N S A F E
04723  *
04724  *  Undoes the effect of an unwanted nmg_ebreak().
04725  *
04726  *      NOTE: THIS IS LIKELY TO PRODUCE AN ILLEGAL NMG STRUCTURE!!!!
04727  *      This routine is intended for use only when simplifying an NMG
04728  *      prior to output in another format (such as polygons). It will
04729  *      unbreak edges where nmg_unbreak_edge() will not!!!!!
04730  *
04731  *  Eliminate the vertex between this edgeuse and the next edge,
04732  *  on all edgeuses radial to this edgeuse's edge.
04733  *  The edge geometry must be shared, and all uses of the vertex, in the same shell,
04734  *  to be disposed of must originate from this edge pair.
04735  *  Also, the "non-B" ends of all edgeuses around e1 and e2 (in this shell) must
04736  *  terminate at either A or B.
04737  *
04738  *
04739  *                   eu1          eu2
04740  *              *----------->*----------->*
04741  *              A.....e1.....B.....e2.....C
04742  *              *<-----------*<-----------*
04743  *                  eu1mate      eu2mate
04744  *
04745  *  If successful, the vertex B, the edge e2, and all the edgeuses in the same shell
04746  *  radial to eu2 (including eu2) will have all been killed.
04747  *  The radial ordering around e1 will not change.
04748  *
04749  *                   eu1
04750  *              *------------------------>*
04751  *              A.....e1..................C
04752  *              *<------------------------*
04753  *                  eu1mate
04754  *
04755  *
04756  *  No new topology structures are created by this operation.
04757  *
04758  *  Returns -
04759  *      0       OK, edge unbroken
04760  *      <0      failure, nothing changed
04761  */
04762 int
04763 nmg_unbreak_shell_edge_unsafe(struct edgeuse *eu1_first)
04764 {
04765         struct edgeuse  *eu1;
04766         struct edgeuse  *eu2;
04767         struct edgeuse  *teu;
04768         struct edge     *e1;
04769         struct edge_g_lseg      *eg;
04770         struct vertexuse *vu;
04771         struct vertex   *vb = 0;
04772         struct vertex   *vc;
04773         struct vertex   *va;
04774         struct shell    *s1;
04775         int             ret = 0;
04776 
04777         NMG_CK_EDGEUSE( eu1_first );
04778         e1 = eu1_first->e_p;
04779         NMG_CK_EDGE( e1 );
04780 
04781         if( eu1_first->g.magic_p != eu1_first->eumate_p->g.magic_p )
04782         {
04783                 ret = -10;
04784                 goto out;
04785         }
04786 
04787         eg = eu1_first->g.lseg_p;
04788         if( !eg )  {
04789                 ret = -1;
04790                 goto out;
04791         }
04792         NMG_CK_EDGE_G_LSEG(eg);
04793 
04794         s1 = nmg_find_s_of_eu(eu1_first);
04795         NMG_CK_SHELL(s1);
04796 
04797         eu1 = eu1_first;
04798         eu2 = BU_LIST_PNEXT_CIRC( edgeuse , eu1 );
04799         if( eu2->g.lseg_p != eg )  {
04800                 bu_log( "nmg_unbreak_edge: second eu geometry x%x does not match geometry x%x of edge1 x%x\n" ,
04801                         eu2->g.magic_p, eg, e1 );
04802                 ret = -3;
04803                 goto out;
04804         }
04805 
04806         va = eu1->vu_p->v_p;            /* start vertex (A) */
04807         vb = eu2->vu_p->v_p;            /* middle vertex (B) */
04808         vc = eu2->eumate_p->vu_p->v_p;  /* end vertex (C) */
04809 
04810         /* all uses of this vertex (in shell s1) must be for this edge geometry, otherwise
04811          * it is not a candidate for deletion */
04812         for( BU_LIST_FOR( vu , vertexuse , &vb->vu_hd ) )  {
04813                 NMG_CK_VERTEXUSE(vu);
04814                 if( *(vu->up.magic_p) != NMG_EDGEUSE_MAGIC )  {
04815                         /* vertex is referred to by a self-loop */
04816                         if( vu->up.lu_p->orientation == OT_BOOLPLACE )  {
04817                                 /* This kind is transient, and safe to ignore */
04818                                 continue;
04819                         }
04820                         ret = -4;
04821                         goto out;
04822                 }
04823                 if( nmg_find_s_of_vu( vu ) != s1 )
04824                         continue;
04825                 NMG_CK_EDGEUSE(vu->up.eu_p);
04826                 if( vu->up.eu_p->g.lseg_p != eg )  {
04827                         ret = -5;
04828                         goto out;
04829                 }
04830         }
04831 
04832         /* Visit all edgeuse pairs radial to eu1 (A--B) */
04833         teu = eu1;
04834         for(;;)  {
04835                 register struct edgeuse *teu2;
04836                 NMG_CK_EDGEUSE(teu);
04837                 if( teu->vu_p->v_p != va || teu->eumate_p->vu_p->v_p != vb )  {
04838                         ret = -6;
04839                         goto out;
04840                 }
04841                 /* We *may* encounter a teu2 not around eu2.  Seen in BigWedge */
04842                 teu2 = BU_LIST_PNEXT_CIRC( edgeuse, teu );
04843                 NMG_CK_EDGEUSE(teu2);
04844                 if( teu2->vu_p->v_p != vb || teu2->eumate_p->vu_p->v_p != vc )  {
04845                         ret = -7;
04846                         goto out;
04847                 }
04848                 teu = teu->eumate_p->radial_p;
04849                 if( teu == eu1 )  break;
04850         }
04851 
04852         /* Visit all edgeuse pairs radial to eu2 (B--C) */
04853         teu = eu2;
04854         for(;;)  {
04855                 NMG_CK_EDGEUSE(teu);
04856                 if( teu->vu_p->v_p != vb || teu->eumate_p->vu_p->v_p != vc )  {
04857                         ret = -8;
04858                         goto out;
04859                 }
04860                 teu = teu->eumate_p->radial_p;
04861                 if( teu == eu2 )  break;
04862         }
04863 
04864         /* All preconditions are met, begin the unbreak operation */
04865         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04866                 bu_log("nmg_unbreak_edge va=x%x, vb=x%x, vc=x%x\n",
04867                         va, vb, vc );
04868                 bu_log("nmg_unbreak_edge A:(%g, %g, %g), B:(%g, %g, %g), C:(%g, %g, %g)\n",
04869                         V3ARGS( va->vg_p->coord ),
04870                         V3ARGS( vb->vg_p->coord ),
04871                         V3ARGS( vc->vg_p->coord ) );
04872         }
04873 
04874         if( va == vc )
04875         {
04876                 /* bu_log( "nmg_unbreak_edge( eu=%x ): Trying to break a jaunt, va==vc (%x)\n", eu1_first, va ); */
04877                 ret = -9;
04878                 goto out;
04879         }
04880 
04881 
04882         /* visit all the edgeuse pairs radial to eu1 */
04883         for(;;)  {
04884                 /* Recheck initial conditions */
04885                 if( eu1->vu_p->v_p != va || eu1->eumate_p->vu_p->v_p != vb )  {
04886                         bu_log( "nmg_unbreak_edge: eu1 does not got to/from correct vertices, x%x, %x\n",
04887                                 eu1->vu_p->v_p, eu1->eumate_p->vu_p->v_p );
04888                         nmg_pr_eu_briefly( eu1, " " );
04889                         rt_bomb( "nmg_unbreak_edge 1\n" );
04890                 }
04891                 eu2 = BU_LIST_PNEXT_CIRC( edgeuse, eu1 );
04892                 NMG_CK_EDGEUSE(eu2);
04893                 if( eu2->g.lseg_p != eg )  {
04894                         rt_bomb("nmg_unbreak_edge:  eu2 geometry is wrong\n");
04895                 }
04896                 if( eu2->vu_p->v_p != vb || eu2->eumate_p->vu_p->v_p != vc )  {
04897                         bu_log( "nmg_unbreak_edge: about to kill eu2, but does not got to/from correct vertices, x%x, x%x\n",
04898                                 eu2->vu_p->v_p, eu2->eumate_p->vu_p->v_p );
04899                         nmg_pr_eu_briefly( eu2, " " );
04900                         rt_bomb( "nmg_unbreak_edge 3\n" );
04901                 }
04902 
04903                 /* revector eu1mate's start vertex from B to C */
04904                 nmg_movevu( eu1->eumate_p->vu_p , vc );
04905 
04906                 if( eu1->vu_p->v_p != va || eu1->eumate_p->vu_p->v_p != vc )  {
04907                         bu_log( "nmg_unbreak_edge: extended eu1 does not got to/from correct vertices, x%x, x%x\n",
04908                                 eu1->vu_p->v_p, eu1->eumate_p->vu_p->v_p );
04909                         nmg_pr_eu_briefly( eu1, " " );
04910                         rt_bomb( "nmg_unbreak_edge 2\n" );
04911                 }
04912 
04913                 if( eu2 != BU_LIST_PNEXT_CIRC( edgeuse, eu1 ) )
04914                         rt_bomb("nmg_unbreak_edge eu2 unexpected altered\n");
04915 
04916                 /* Now kill off the unnecessary eu2 associated w/ cur eu1 */
04917                 if( nmg_keu( eu2 ) )
04918                         rt_bomb( "nmg_unbreak_edge: edgeuse parent is now empty!!\n" );
04919 
04920                 if( eu1->vu_p->v_p != va || eu1->eumate_p->vu_p->v_p != vc )  {
04921                         bu_log( "nmg_unbreak_edge: unbroken eu1 (after eu2 killed) does not got to/from correct vertices, x%x, x%x\n",
04922                                 eu1->vu_p->v_p, eu1->eumate_p->vu_p->v_p );
04923                         nmg_pr_eu_briefly( eu1, " " );
04924                         rt_bomb( "nmg_unbreak_edge 4\n" );
04925                 }
04926                 eu1 = eu1->eumate_p->radial_p;
04927                 if( eu1 == eu1_first )  break;
04928         }
04929 out:
04930         if (rt_g.NMG_debug & DEBUG_BASIC)  {
04931                 bu_log("nmg_unbreak_edge(eu=x%x, vb=x%x) ret = %d\n",
04932                         eu1_first, vb, ret);
04933         }
04934         return ret;
04935 }
04936 
04937 /**
04938  *                      N M G _ E I N S
04939  *
04940  *      Insert a new (zero length) edge at the begining of (ie, before)
04941  *      an existing edgeuse
04942  *      Perhaps this is what nmg_esplit and nmg_eusplit should have been like?
04943  *
04944  *      Before:
04945  *      .--A--> .--eu-->
04946  *               \
04947  *                >.
04948  *               /
04949  *        <-A'--. <-eu'-.
04950  *
04951  *
04952  *      After:
04953  *
04954  *               eu1     eu
04955  *      .--A--> .---> .--eu-->
04956  *               \   /
04957  *                >.<
04958  *               /   \
04959  *        <-A'--. <---. <-eu'--.
04960  *                eu2     eumate
04961  */
04962 struct edgeuse *
04963 nmg_eins(struct edgeuse *eu)
04964 {
04965         struct edgeuse  *eumate;
04966         struct edgeuse  *eu1, *eu2;
04967         struct shell    *s;
04968 
04969         NMG_CK_EDGEUSE(eu);
04970         eumate = eu->eumate_p;
04971         NMG_CK_EDGEUSE(eumate);
04972 
04973         if (*eu->up.magic_p == NMG_SHELL_MAGIC) {
04974                 s = eu->up.s_p;
04975                 NMG_CK_SHELL(s);
04976         }
04977         else {
04978                 struct loopuse *lu;
04979 
04980                 lu = eu->up.lu_p;
04981                 NMG_CK_LOOPUSE(lu);
04982                 if (*lu->up.magic_p == NMG_SHELL_MAGIC) {
04983                         s = lu->up.s_p;
04984                         NMG_CK_SHELL(s);
04985                 } else {
04986                         struct faceuse *fu;
04987                         fu = lu->up.fu_p;
04988                         NMG_CK_FACEUSE(fu);
04989                         s = fu->s_p;
04990                         NMG_CK_SHELL(s);
04991                 }
04992         }
04993 
04994         eu1 = nmg_me(eu->vu_p->v_p, eu->vu_p->v_p, s);
04995         eu2 = eu1->eumate_p;
04996 
04997         if (*eu->up.magic_p == NMG_LOOPUSE_MAGIC) {
04998                 BU_LIST_DEQUEUE( &eu1->l );
04999                 BU_LIST_DEQUEUE( &eu2->l );
05000 
05001                 BU_LIST_INSERT( &eu->l, &eu1->l );
05002                 BU_LIST_APPEND( &eumate->l, &eu2->l );
05003 
05004                 eu1->up.lu_p = eu->up.lu_p;
05005                 eu2->up.lu_p = eumate->up.lu_p;
05006         }
05007         else {
05008                 rt_bomb("nmg_eins() Cannot yet insert null edge in shell\n");
05009         }
05010         if (rt_g.NMG_debug & DEBUG_BASIC)  {
05011                 bu_log("nmg_eins(eu=x%x) eu1=x%x\n", eu, eu1);
05012         }
05013         return(eu1);
05014 }
05015 
05016 /**
05017  *                      N M G _ M V _ E U _ B E T W E E N _ S H E L L S
05018  *
05019  *  Move a wire edgeuse and it's mate from one shell to another.
05020  */
05021 void
05022 nmg_mv_eu_between_shells(struct shell *dest, register struct shell *src, register struct edgeuse *eu)
05023 {
05024         register struct edgeuse *eumate;
05025 
05026         NMG_CK_EDGEUSE(eu);
05027         eumate = eu->eumate_p;
05028         NMG_CK_EDGEUSE(eumate);
05029 
05030         if (eu->up.s_p != src) {
05031                 bu_log("nmg_mv_eu_between_shells(dest=x%x, src=x%x, eu=x%x), eu->up.s_p=x%x isnt src shell\n",
05032                         dest, src, eu, eu->up.s_p );
05033                 rt_bomb("eu->up.s_p isnt source shell\n");
05034         }
05035         if (eumate->up.s_p != src) {
05036                 bu_log("nmg_mv_eu_between_shells(dest=x%x, src=x%x, eu=x%x), eumate->up.s_p=x%x isn't src shell\n",
05037                         dest, src, eu, eumate->up.s_p );
05038                 rt_bomb("eumate->up.s_p isnt source shell\n");
05039         }
05040 
05041         /* Remove eu from src shell */
05042         BU_LIST_DEQUEUE( &eu->l );
05043         if( BU_LIST_IS_EMPTY( &src->eu_hd ) )  {
05044                 /* This was the last eu in the list, bad news */
05045                 bu_log("nmg_mv_eu_between_shells(dest=x%x, src=x%x, eu=x%x), eumate=x%x not in src shell\n",
05046                         dest, src, eu, eumate );
05047                 rt_bomb("src shell emptied before finding eumate\n");
05048         }
05049 
05050         /* Remove eumate from src shell */
05051         BU_LIST_DEQUEUE( &eumate->l );
05052 
05053         /* Add eu and eumate to dest shell */
05054         BU_LIST_APPEND( &dest->eu_hd, &eu->l );
05055         BU_LIST_APPEND( &eu->l, &eumate->l );
05056 
05057         eu->up.s_p = dest;
05058         eumate->up.s_p = dest;
05059 
05060         if (rt_g.NMG_debug & DEBUG_BASIC)  {
05061                 bu_log("nmg_mv_eu_between_shells( dest=x%x, src=x%x, eu=x%x ) new_eu=x%x\n",
05062                         dest, src, eu);
05063         }
05064 }
05065 
05066 /************************************************************************
05067  *                                                                      *
05068  *                              VERTEX Routines                         *
05069  *                                                                      *
05070  ************************************************************************/
05071 
05072 /**
05073  *                      N M G _ M V _ V U _ B E T W E E N _ S H E L L S
05074  *
05075  *  If this shell had a single vertexuse in it, move it to the other
05076  *  shell, but "promote" it to a "loop of a single vertex" along the way.
05077  */
05078 void
05079 nmg_mv_vu_between_shells(struct shell *dest, register struct shell *src, register struct vertexuse *vu)
05080 {
05081         NMG_CK_VERTEXUSE( vu );
05082         NMG_CK_VERTEX( vu->v_p );
05083 
05084         if (rt_g.NMG_debug & DEBUG_BASIC)  {
05085                 bu_log("nmg_mv_vu_between_shells( dest_s=x%x, src_s=x%x, vu=x%x )\n",
05086                         dest, src, vu);
05087         }
05088         (void) nmg_mlv( &(dest->l.magic), vu->v_p, OT_SAME );
05089         if (vu->v_p->vg_p) {
05090                 NMG_CK_VERTEX_G(vu->v_p->vg_p);
05091         }
05092         nmg_kvu( vu );
05093 }
05094 
05095 /*
05096  * Local Variables:
05097  * mode: C
05098  * tab-width: 8
05099  * c-basic-offset: 4
05100  * indent-tabs-mode: t
05101  * End:
05102  * ex: shiftwidth=4 tabstop=8
05103  */

Generated on Mon Sep 18 01:24:55 2006 for BRL-CAD by  doxygen 1.4.6