nmg_info.c

Go to the documentation of this file.
00001 /*                      N M G _ I N F O . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1993-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 /** @addtogroup nmg */
00022 
00023 /*@{*/
00024 /** @file nmg_info.c
00025  *  A companion module to nmg_mod.c which contains routines to
00026  *  answer questions about n-Manifold Geometry data structures.
00027  *  None of these routines will modify the NMG structures in any way.
00028  *
00029  *  Authors -
00030  *      Michael John Muuss
00031  *      Lee A. Butler
00032  *
00033  *  Source -
00034  *      The U. S. Army Research Laboratory
00035  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00036  */
00037 /*@}*/
00038 
00039 #ifndef lint
00040 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_info.c,v 14.14 2006/09/16 02:04:25 lbutler Exp $ (ARL)";
00041 #endif
00042 
00043 #include "common.h"
00044 
00045 #include <stdlib.h>
00046 #include <stddef.h>
00047 #include <stdio.h>
00048 #ifdef HAVE_STRING_H
00049 #  include <string.h>
00050 #else
00051 #  include <strings.h>
00052 #endif
00053 #include <math.h>
00054 
00055 #include "machine.h"
00056 #include "vmath.h"
00057 #include "nmg.h"
00058 #include "raytrace.h"
00059 
00060 /************************************************************************
00061  *                                                                      *
00062  *                              MODEL Routines                          *
00063  *                                                                      *
00064  ************************************************************************/
00065 
00066 /**
00067  *                      N M G _ F I N D _ M O D E L
00068  *
00069  *  Given a pointer to the magic number in any NMG data structure,
00070  *  return a pointer to the model structure that contains that NMG item.
00071  *
00072  *  The reason for the register variable is to leave the argument variable
00073  *  unmodified;  this may aid debugging in event of a core dump.
00074  */
00075 struct model *
00076 nmg_find_model(const long int *magic_p_arg)
00077 {
00078         register const long     *magic_p = magic_p_arg;
00079 
00080 top:
00081         if( magic_p == (long *)0 )  {
00082                 bu_log("nmg_find_model(x%x) enountered null pointer\n",
00083                         magic_p_arg );
00084                 rt_bomb("nmg_find_model() null pointer\n");
00085                 /* NOTREACHED */
00086         }
00087 
00088         switch( *magic_p )  {
00089         case NMG_MODEL_MAGIC:
00090                 return( (struct model *)magic_p );
00091         case NMG_REGION_MAGIC:
00092                 return( ((struct nmgregion *)magic_p)->m_p );
00093         case NMG_SHELL_MAGIC:
00094                 return( ((struct shell *)magic_p)->r_p->m_p );
00095         case NMG_FACEUSE_MAGIC:
00096                 magic_p = &((struct faceuse *)magic_p)->s_p->l.magic;
00097                 goto top;
00098         case NMG_FACE_MAGIC:
00099                 magic_p = &((struct face *)magic_p)->fu_p->l.magic;
00100                 goto top;
00101         case NMG_LOOP_MAGIC:
00102                 magic_p = ((struct loop *)magic_p)->lu_p->up.magic_p;
00103                 goto top;
00104         case NMG_LOOPUSE_MAGIC:
00105                 magic_p = ((struct loopuse *)magic_p)->up.magic_p;
00106                 goto top;
00107         case NMG_EDGE_MAGIC:
00108                 magic_p = ((struct edge *)magic_p)->eu_p->up.magic_p;
00109                 goto top;
00110         case NMG_EDGEUSE_MAGIC:
00111                 magic_p = ((struct edgeuse *)magic_p)->up.magic_p;
00112                 goto top;
00113         case NMG_VERTEX_MAGIC:
00114                 magic_p = &(BU_LIST_FIRST(vertexuse,
00115                         &((struct vertex *)magic_p)->vu_hd)->l.magic);
00116                 goto top;
00117         case NMG_VERTEXUSE_MAGIC:
00118                 magic_p = ((struct vertexuse *)magic_p)->up.magic_p;
00119                 goto top;
00120 
00121         default:
00122                 bu_log("nmg_find_model() can't get model for magic=x%x (%s)\n",
00123                         *magic_p, bu_identify_magic( *magic_p ) );
00124                 rt_bomb("nmg_find_model() failure\n");
00125         }
00126         return( (struct model *)NULL );
00127 }
00128 
00129 void
00130 nmg_model_bb(fastf_t *min_pt, fastf_t *max_pt, const struct model *m)
00131 {
00132         struct nmgregion *r;
00133         register int i;
00134 
00135         NMG_CK_MODEL(m);
00136 
00137         min_pt[0] = min_pt[1] = min_pt[2] = MAX_FASTF;
00138         max_pt[0] = max_pt[1] = max_pt[2] = -MAX_FASTF;
00139 
00140         for (BU_LIST_FOR(r, nmgregion, &m->r_hd)) {
00141                 NMG_CK_REGION(r);
00142                 NMG_CK_REGION_A(r->ra_p);
00143 
00144                 for (i=0 ; i < 3 ; i++) {
00145                         if (min_pt[i] > r->ra_p->min_pt[i])
00146                                 min_pt[i] = r->ra_p->min_pt[i];
00147                         if (max_pt[i] < r->ra_p->max_pt[i])
00148                                 max_pt[i] = r->ra_p->max_pt[i];
00149                 }
00150         }
00151 }
00152 
00153 /************************************************************************
00154  *                                                                      *
00155  *                              SHELL Routines                          *
00156  *                                                                      *
00157  ************************************************************************/
00158 
00159 /**
00160  *                      N M G _ S H E L L _ I S _ E M P T Y
00161  *
00162  *  See if this is an invalid shell
00163  *  i.e., one that has absolutely nothing in it,
00164  *  not even a lone vertexuse.
00165  *
00166  *  Returns -
00167  *      1       yes, it is completely empty
00168  *      0       no, not empty
00169  */
00170 int
00171 nmg_shell_is_empty(register const struct shell *s)
00172 {
00173 
00174         NMG_CK_SHELL(s);
00175 
00176         if( BU_LIST_NON_EMPTY( &s->fu_hd ) )  return 0;
00177         if( BU_LIST_NON_EMPTY( &s->lu_hd ) )  return 0;
00178         if( BU_LIST_NON_EMPTY( &s->eu_hd ) )  return 0;
00179         if( s->vu_p )  return 0;
00180         return 1;
00181 }
00182 
00183 /**                             N M G _ F I N D _ S _ O F _ L U
00184  *
00185  *      return parent shell for loopuse
00186  *      formerly nmg_lups().
00187  */
00188 struct shell *
00189 nmg_find_s_of_lu(const struct loopuse *lu)
00190 {
00191         if (*lu->up.magic_p == NMG_SHELL_MAGIC) return(lu->up.s_p);
00192         else if (*lu->up.magic_p != NMG_FACEUSE_MAGIC)
00193                 rt_bomb("nmg_find_s_of_lu() bad parent for loopuse\n");
00194 
00195         return(lu->up.fu_p->s_p);
00196 }
00197 
00198 /**                             N M G _ F I N D _ S _ O F _ E U
00199  *
00200  *      return parent shell of edgeuse
00201  *      formerly nmg_eups().
00202  */
00203 struct shell *
00204 nmg_find_s_of_eu(const struct edgeuse *eu)
00205 {
00206         if (*eu->up.magic_p == NMG_SHELL_MAGIC) return(eu->up.s_p);
00207         else if (*eu->up.magic_p != NMG_LOOPUSE_MAGIC)
00208                 rt_bomb("nmg_find_s_of_eu() bad parent for edgeuse\n");
00209 
00210         return(nmg_find_s_of_lu(eu->up.lu_p));
00211 }
00212 
00213 /**
00214  *                      N M G _ F I N D _ S _ O F _ V U
00215  *
00216  *  Return parent shell of vertexuse
00217  */
00218 struct shell *
00219 nmg_find_s_of_vu(const struct vertexuse *vu)
00220 {
00221         NMG_CK_VERTEXUSE(vu);
00222 
00223         if( *vu->up.magic_p == NMG_LOOPUSE_MAGIC )
00224                 return nmg_find_s_of_lu( vu->up.lu_p );
00225         return nmg_find_s_of_eu( vu->up.eu_p );
00226 }
00227 
00228 /************************************************************************
00229  *                                                                      *
00230  *                              FACE Routines                           *
00231  *                                                                      *
00232  ************************************************************************/
00233 
00234 /**
00235  *                      N M G _ F I N D _ F U _ O F _ E U
00236  *
00237  *      return a pointer to the faceuse that is the super-parent of this
00238  *      edgeuse.  If edgeuse has no grandparent faceuse, return NULL.
00239  */
00240 struct faceuse *
00241 nmg_find_fu_of_eu(const struct edgeuse *eu)
00242 {
00243         NMG_CK_EDGEUSE(eu);
00244 
00245         if (*eu->up.magic_p == NMG_LOOPUSE_MAGIC &&
00246                 *eu->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC)
00247                         return eu->up.lu_p->up.fu_p;
00248 
00249         return (struct faceuse *)NULL;
00250 }
00251 
00252 /**
00253  *                      N M G _ F I N D _ F U _ O F _ L U
00254  */
00255 struct faceuse *
00256 nmg_find_fu_of_lu(const struct loopuse *lu)
00257 {
00258         switch (*lu->up.magic_p) {
00259         case NMG_FACEUSE_MAGIC:
00260                 return lu->up.fu_p;
00261         case NMG_SHELL_MAGIC:
00262                 return (struct faceuse *)NULL;
00263         default:
00264             bu_log("Error at %s %d:\nInvalid loopuse parent magic (0x%x %d)\n",
00265                 __FILE__, __LINE__, *lu->up.magic_p, *lu->up.magic_p);
00266             rt_bomb("nmg_find_fu_of_lu() giving up on loopuse");
00267         }
00268         return (struct faceuse *)NULL;
00269 }
00270 
00271 
00272 /**     N M G _ F I N D _ F U _ O F _ V U
00273  *
00274  *      return a pointer to the parent faceuse of the vertexuse
00275  *      or a null pointer if vu is not a child of a faceuse.
00276  */
00277 struct faceuse *
00278 nmg_find_fu_of_vu(const struct vertexuse *vu)
00279 {
00280         NMG_CK_VERTEXUSE(vu);
00281 
00282         switch (*vu->up.magic_p) {
00283         case NMG_LOOPUSE_MAGIC:
00284                 return nmg_find_fu_of_lu( vu->up.lu_p );
00285         case NMG_SHELL_MAGIC:
00286                 if (rt_g.NMG_debug & DEBUG_BASIC) bu_log("nmg_find_fu_of_vu(vu=x%x) vertexuse is child of shell, can't find faceuse\n", vu);
00287                 return ((struct faceuse *)NULL);
00288         case NMG_EDGEUSE_MAGIC:
00289                 switch (*vu->up.eu_p->up.magic_p) {
00290                 case NMG_LOOPUSE_MAGIC:
00291                         return nmg_find_fu_of_lu( vu->up.eu_p->up.lu_p );
00292                 case NMG_SHELL_MAGIC:
00293                         if (rt_g.NMG_debug & DEBUG_BASIC) bu_log("nmg_find_fu_of_vu(vu=x%x) vertexuse is child of shell/edgeuse, can't find faceuse\n", vu);
00294                         return ((struct faceuse *)NULL);
00295                 }
00296                 bu_log("Error at %s %d:\nInvalid loopuse parent magic 0x%x\n",
00297                         __FILE__, __LINE__, *vu->up.lu_p->up.magic_p);
00298                 abort();
00299                 break;
00300         default:
00301                 bu_log("Error at %s %d:\nInvalid vertexuse parent magic 0x%x\n",
00302                         __FILE__, __LINE__,
00303                         *vu->up.magic_p);
00304                 abort();
00305                 break;
00306         }
00307         bu_log("How did I get here %s %d?\n", __FILE__, __LINE__);
00308         rt_bomb("nmg_find_fu_of_vu()\n");
00309         return ((struct faceuse *)NULL);
00310 }
00311 /**
00312  *                      N M G _ F I N D _ F U _ W I T H _ F G _ I N _ S
00313  *
00314  *  Find a faceuse in shell s1 that shares the face_g_plane structure with
00315  *  fu2 and has the same orientation.
00316  *  This may be an OT_OPPOSITE faceuse, depending on orientation.
00317  *  Returns NULL if no such faceuse can be found in s1.
00318  *  fu2 may be in s1, or in some other shell.
00319  */
00320 struct faceuse *
00321 nmg_find_fu_with_fg_in_s(const struct shell *s1, const struct faceuse *fu2)
00322 {
00323         struct faceuse          *fu1;
00324         struct face             *f2;
00325         register struct face_g_plane    *fg2;
00326 
00327         NMG_CK_SHELL(s1);
00328         NMG_CK_FACEUSE(fu2);
00329 
00330         f2 = fu2->f_p;
00331         NMG_CK_FACE(f2);
00332         fg2 = f2->g.plane_p;
00333         NMG_CK_FACE_G_PLANE(fg2);
00334 
00335         for( BU_LIST_FOR( fu1, faceuse, &s1->fu_hd ) )  {
00336                 register struct face    *f1;
00337                 register struct face_g_plane    *fg1;
00338                 int                     flip1, flip2;
00339 
00340                 NMG_CK_FACEUSE(fu1);
00341                 f1 = fu1->f_p;
00342                 NMG_CK_FACE(f1);
00343                 fg1 = fu1->f_p->g.plane_p;
00344                 NMG_CK_FACE_G_PLANE(fg1);
00345 
00346                 if( fg1 != fg2 )  continue;
00347 
00348                 if( fu1 == fu2 || fu1->fumate_p == fu2 )  continue;
00349 
00350                 /* Face geometry matches, select fu1 or it's mate */
00351                 flip1 = (fu1->orientation != OT_SAME) != (f1->flip != 0);
00352                 flip2 = (fu2->orientation != OT_SAME) != (f2->flip != 0);
00353                 if( flip1 == flip2 )  return fu1;
00354                 return fu1->fumate_p;
00355         }
00356         return (struct faceuse *)NULL;
00357 }
00358 
00359 /**
00360  *                      N M G _ M E A S U R E _ F U _ A N G L E
00361  *
00362  *  Return the angle in radians from the interior portion of the faceuse
00363  *  associated with edgeuse 'eu', measured in the coordinate system
00364  *  defined by xvec and yvec, which are known to be perpendicular to
00365  *  each other, and to the edge vector.
00366  *
00367  *  This is done by finding the "left-ward" vector for the edge in the
00368  *  face, which points into the interior of the face, and measuring
00369  *  the angle it forms relative to xvec and yvec.
00370  *
00371  *  Wire edges are indicated by always returning angle of -pi.
00372  *  That will be the only case for negative returns.
00373  */
00374 double
00375 nmg_measure_fu_angle(const struct edgeuse *eu, const fastf_t *xvec, const fastf_t *yvec, const fastf_t *zvec)
00376 {
00377         vect_t                  left;
00378         double                  ret;
00379 
00380         NMG_CK_EDGEUSE(eu);
00381         if( *eu->up.magic_p != NMG_LOOPUSE_MAGIC )  return -bn_pi;
00382 
00383         if( nmg_find_eu_leftvec( left, eu ) < 0 )  return -bn_pi;
00384 
00385         ret = bn_angle_measure( left, xvec, yvec );
00386         return ret;
00387 }
00388 
00389 /************************************************************************
00390  *                                                                      *
00391  *                              LOOP Routines                           *
00392  *                                                                      *
00393  ************************************************************************/
00394 
00395 /**
00396  *                      N M G _ F I N D _ L U _ O F _ V U
00397  */
00398 struct loopuse *
00399 nmg_find_lu_of_vu(const struct vertexuse *vu)
00400 {
00401         NMG_CK_VERTEXUSE( vu );
00402         if ( *vu->up.magic_p == NMG_LOOPUSE_MAGIC )
00403                 return vu->up.lu_p;
00404 
00405         if ( *vu->up.magic_p == NMG_SHELL_MAGIC )
00406                 return (struct loopuse *)NULL;
00407 
00408         NMG_CK_EDGEUSE( vu->up.eu_p );
00409 
00410         if ( *vu->up.eu_p->up.magic_p == NMG_SHELL_MAGIC )
00411                 return (struct loopuse *)NULL;
00412 
00413         NMG_CK_LOOPUSE( vu->up.eu_p->up.lu_p );
00414 
00415         return vu->up.eu_p->up.lu_p;
00416 }
00417 
00418 /**
00419  *                      N M G _ L O O P _ I S _ A _ C R A C K
00420  *
00421  *  A "crack" is defined as a loop which has no area.
00422  *
00423  *  Example of a non-trivial "crack" loop:
00424  *
00425  *                       <---- eu4 -----
00426  *                     C ############### D
00427  *                   | # ^ ---- eu3 --->
00428  *                   | # |
00429  *                 eu5 # eu2
00430  *                   | # |
00431  *        <--- eu6 --V # |
00432  *      A ############ B
00433  *        --- eu1 ---->
00434  *
00435  *
00436  *  Returns -
00437  *       0      Loop is not a "crack"
00438  *      !0      Loop *is* a "crack"
00439  */
00440 int
00441 nmg_loop_is_a_crack(const struct loopuse *lu)
00442 {
00443         struct edgeuse  *cur_eu;
00444         struct edgeuse  *cur_eumate;
00445         struct vertexuse *cur_vu;
00446         struct vertex   *cur_v;
00447         struct vertexuse *next_vu;
00448         struct vertex   *next_v;
00449         struct faceuse  *fu;
00450         struct vertexuse *test_vu;
00451         struct edgeuse  *test_eu;
00452         struct loopuse  *test_lu;
00453         int             ret = 0;
00454 
00455         NMG_CK_LOOPUSE(lu);
00456         if( *lu->up.magic_p != NMG_FACEUSE_MAGIC )  {
00457                 if (rt_g.NMG_debug & DEBUG_BASIC)  bu_log("lu up is not faceuse\n");
00458                 ret = 0;
00459                 goto out;
00460         }
00461         fu = lu->up.fu_p;
00462         NMG_CK_FACEUSE(fu);
00463 
00464         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )  {
00465                 if (rt_g.NMG_debug & DEBUG_BASIC)  bu_log("lu down is not edgeuse\n");
00466                 ret = 0;
00467                 goto out;
00468         }
00469 
00470         /*
00471          *  For every edgeuse, see if there is another edgeuse from 'lu',
00472          *  radial around this edge, which is not this edgeuse's mate.
00473          */
00474         for( BU_LIST_FOR( cur_eu, edgeuse, &lu->down_hd ) )  {
00475                 NMG_CK_EDGEUSE(cur_eu);
00476                 cur_eumate = cur_eu->eumate_p;
00477                 NMG_CK_EDGEUSE(cur_eumate);
00478                 cur_vu = cur_eu->vu_p;
00479                 NMG_CK_VERTEXUSE(cur_vu);
00480                 cur_v = cur_vu->v_p;
00481                 NMG_CK_VERTEX(cur_v);
00482 
00483                 next_vu = cur_eumate->vu_p;
00484                 NMG_CK_VERTEXUSE(next_vu);
00485                 next_v = next_vu->v_p;
00486                 NMG_CK_VERTEX(next_v);
00487                 /* XXX It might be more efficient to walk the radial list */
00488                 /* See if the next vertex has an edge pointing back to cur_v */
00489                 for( BU_LIST_FOR( test_vu, vertexuse, &next_v->vu_hd ) )  {
00490                         if( *test_vu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
00491                         test_eu = test_vu->up.eu_p;
00492                         NMG_CK_EDGEUSE(test_eu);
00493                         if( test_eu == cur_eu )  continue;      /* skip self */
00494                         if( test_eu == cur_eumate )  continue;  /* skip mates */
00495                         if( *test_eu->up.magic_p != NMG_LOOPUSE_MAGIC )  continue;
00496                         test_lu = test_eu->up.lu_p;
00497                         if( test_lu != lu )  continue;
00498                         /* Check departing edgeuse's NEXT vertex */
00499                         if( test_eu->eumate_p->vu_p->v_p == cur_v )  goto match;
00500                 }
00501                 /* No path back, this can't be a crack, abort */
00502                 ret = 0;
00503                 goto out;
00504 
00505                 /* One edgeuse matched, all the others have to as well */
00506 match:          ;
00507         }
00508         ret = 1;
00509 out:
00510         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00511                 bu_log("nmg_loop_is_a_crack(lu=x%x) ret=%d\n", lu, ret );
00512         }
00513         return ret;
00514 }
00515 
00516 /**
00517  *                      N M G _ L O O P _ I S _ C C W
00518  *
00519  *  Determine if loop proceeds counterclockwise (CCW) around the
00520  *  provided normal vector (which may be either the face normal,
00521  *  or the anti-normal).
00522  *
00523  *  Returns -
00524  *      +1      Loop is CCW, should be exterior loop.
00525  *      -1      Loop is CW, should be interior loop.
00526  *       0      Unable to tell, error.
00527  *
00528  */
00529 int
00530 nmg_loop_is_ccw(const struct loopuse *lu, const fastf_t *norm, const struct bn_tol *tol)
00531 {
00532         fastf_t area;
00533         fastf_t dot;
00534         plane_t pl;
00535         int ret;
00536 
00537         area = nmg_loop_plane_area( lu, pl );
00538 
00539         if( area <= 0.0 )
00540         {
00541                 if( RT_G_DEBUG & DEBUG_MATH )
00542                 {
00543                         bu_log( "nmg_loop_is_ccw: Loop has no area\n" );
00544                         nmg_pr_lu_briefly( lu, " " );
00545                 }
00546                 ret = 0;
00547                 goto out;
00548         }
00549 
00550         if( NEAR_ZERO( area, tol->dist_sq ) )
00551         {
00552                 if( RT_G_DEBUG & DEBUG_MATH )
00553                 {
00554                         bu_log( "nmg_loop_is_ccw: Loop area (%g) is less than tol->dist_sq (%g)\n", area, tol->dist_sq );
00555                         nmg_pr_lu_briefly( lu, " " );
00556                 }
00557                 ret = 0;
00558                 goto out;
00559         }
00560 
00561         dot = VDOT( norm, pl );
00562 
00563         if( NEAR_ZERO( dot, tol->perp ) )
00564         {
00565                 if( RT_G_DEBUG & DEBUG_MATH )
00566                 {
00567                         bu_log( "nmg_loop_is_ccw: normal ( %g %g %g ) is in plane of loop ( %g %g %g %g ), dot = %g\n",
00568                                 V3ARGS( norm ), V4ARGS( pl ), dot );
00569                         nmg_pr_lu_briefly( lu, " " );
00570                 }
00571                 ret = 0;
00572                 goto out;
00573         }
00574 
00575         if( dot < 0.0 )
00576                 ret = (-1 );
00577         else
00578                 ret = 1;
00579 
00580 out:
00581         if (rt_g.NMG_debug & DEBUG_BASIC)
00582                 bu_log( "nmg_loop_is_ccw(lu=x%x) ret=%d\n" , lu, ret );
00583 
00584         return( ret );
00585 }
00586 
00587 /**
00588  *                      N M G _ L O O P _ T O U C H E S _ S E L F
00589  *
00590  *  Search through all the vertices in a loop.
00591  *  If there are two distinct uses of one vertex in the loop,
00592  *  return true.
00593  *  This is useful for detecting "accordian pleats"
00594  *  unexpectedly showing up in a loop.
00595  *  Derrived from nmg_split_touchingloops().
00596  *
00597  *  Returns -
00598  *      vu      Yes, the loop touches itself at least once, at this vu.
00599  *      0       No, the loop does not touch itself.
00600  */
00601 const struct vertexuse *
00602 nmg_loop_touches_self(const struct loopuse *lu)
00603 {
00604         const struct edgeuse    *eu;
00605         const struct vertexuse  *vu;
00606         const struct vertex     *v;
00607 
00608         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
00609                 return (const struct vertexuse *)0;
00610 
00611         /* For each edgeuse, get vertexuse and vertex */
00612         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
00613                 const struct vertexuse  *tvu;
00614 
00615                 vu = eu->vu_p;
00616                 NMG_CK_VERTEXUSE(vu);
00617                 v = vu->v_p;
00618                 NMG_CK_VERTEX(v);
00619 
00620                 /*
00621                  *  For each vertexuse on vertex list,
00622                  *  check to see if it points up to the this loop.
00623                  *  If so, then there is a duplicated vertex.
00624                  *  Ordinarily, the vertex list will be *very* short,
00625                  *  so this strategy is likely to be faster than
00626                  *  a table-based approach, for most cases.
00627                  */
00628                 for( BU_LIST_FOR( tvu, vertexuse, &v->vu_hd ) )  {
00629                         const struct edgeuse            *teu;
00630                         const struct loopuse            *tlu;
00631 
00632                         if( tvu == vu )  continue;
00633                         /*
00634                          *  Inline expansion of:
00635                          *      if(nmg_find_lu_of_vu(tvu) != lu) continue;
00636                          */
00637                         if( *tvu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
00638                         teu = tvu->up.eu_p;
00639                         NMG_CK_EDGEUSE(teu);
00640                         if( *teu->up.magic_p != NMG_LOOPUSE_MAGIC )  continue;
00641                         tlu = teu->up.lu_p;
00642                         NMG_CK_LOOPUSE(tlu);
00643                         if( tlu != lu )  continue;
00644                         /*
00645                          *  Repeated vertex exists.
00646                          */
00647                         return vu;
00648                 }
00649         }
00650         return (const struct vertexuse *)0;
00651 }
00652 
00653 /************************************************************************
00654  *                                                                      *
00655  *                              EDGE Routines                           *
00656  *                                                                      *
00657  ************************************************************************/
00658 
00659 /**
00660  *                      N M G _ F I N D _ M A T C H I N G _ E U _ I N _ S
00661  *
00662  *  If shell s2 has an edge that connects the same vertices as eu1 connects,
00663  *  return the matching edgeuse in s2.
00664  *  This routine works properly regardless of whether eu1 is in s2 or not.
00665  *  A convenient wrapper for nmg_findeu().
00666  */
00667 struct edgeuse *
00668 nmg_find_matching_eu_in_s(const struct edgeuse *eu1, const struct shell *s2)
00669 {
00670         const struct vertexuse  *vu1a, *vu1b;
00671         struct edgeuse          *eu2;
00672 
00673         NMG_CK_EDGEUSE(eu1);
00674         NMG_CK_SHELL(s2);
00675 
00676         vu1a = eu1->vu_p;
00677         vu1b = BU_LIST_PNEXT_CIRC( edgeuse, eu1 )->vu_p;
00678         NMG_CK_VERTEXUSE(vu1a);
00679         NMG_CK_VERTEXUSE(vu1b);
00680         if( (nmg_find_v_in_shell( vu1a->v_p, s2, 1 )) == (struct vertexuse *)NULL )
00681                 return (struct edgeuse *)NULL;
00682         if( (nmg_find_v_in_shell( vu1b->v_p, s2, 1 )) == (struct vertexuse *)NULL )
00683                 return (struct edgeuse *)NULL;
00684 
00685         /* Both vertices have vu's of eu's in s2 */
00686 
00687         eu2 = nmg_findeu( vu1a->v_p, vu1b->v_p, s2, eu1, 0 );
00688         return eu2;             /* May be NULL if no edgeuse found */
00689 }
00690 
00691 /**
00692  *                      N M G _ F I N D E U
00693  *
00694  *  Find an edgeuse in a shell between a given pair of vertex structs.
00695  *
00696  *  If a given shell "s" is specified, then only edgeuses in that shell
00697  *  will be considered, otherwise all edgeuses in the model are fair game.
00698  *
00699  *  If a particular edgeuse "eup" is specified, then that edgeuse
00700  *  and it's mate will not be returned as a match.
00701  *
00702  *  If "dangling_only" is true, then an edgeuse will be matched only if
00703  *  there are no other edgeuses on the edge, i.e. the radial edgeuse is
00704  *  the same as the mate edgeuse.
00705  *
00706  *  Returns -
00707  *      edgeuse*        Edgeuse which matches the criteria
00708  *      NULL            Unable to find matching edgeuse
00709  */
00710 struct edgeuse *
00711 nmg_findeu(const struct vertex *v1, const struct vertex *v2, const struct shell *s, const struct edgeuse *eup, int dangling_only)
00712 {
00713         register const struct vertexuse *vu;
00714         register const struct edgeuse   *eu;
00715         const struct edgeuse            *eup_mate;
00716         int                             eup_orientation;
00717 
00718         NMG_CK_VERTEX(v1);
00719         NMG_CK_VERTEX(v2);
00720         if(s) NMG_CK_SHELL(s);
00721 
00722         if(eup)  {
00723                 struct faceuse  *fu;
00724                 NMG_CK_EDGEUSE(eup);
00725                 eup_mate = eup->eumate_p;
00726                 NMG_CK_EDGEUSE(eup_mate);
00727                 if( (fu = nmg_find_fu_of_eu(eup)) )
00728                         eup_orientation = fu->orientation;
00729                 else
00730                         eup_orientation = OT_SAME;
00731         } else {
00732                 eup_mate = eup;                 /* NULL */
00733                 eup_orientation = OT_SAME;
00734         }
00735 
00736         if (rt_g.NMG_debug & DEBUG_FINDEU)
00737                 bu_log("nmg_findeu() seeking eu!=%8x/%8x between (%8x, %8x) %s\n",
00738                         eup, eup_mate, v1, v2,
00739                         dangling_only ? "[dangling]" : "[any]" );
00740 
00741         for( BU_LIST_FOR( vu, vertexuse, &v1->vu_hd ) )  {
00742                 NMG_CK_VERTEXUSE(vu);
00743                 if (!vu->up.magic_p)
00744                         rt_bomb("nmg_findeu() vertexuse in vu_hd list has null parent\n");
00745 
00746                 /* Ignore self-loops and lone shell verts */
00747                 if (*vu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
00748                 eu = vu->up.eu_p;
00749 
00750                 /* Ignore edgeuses which don't run between the right verts */
00751                 if( eu->eumate_p->vu_p->v_p != v2 )  continue;
00752 
00753                 if (rt_g.NMG_debug & DEBUG_FINDEU )  {
00754                         bu_log("nmg_findeu: check eu=%8x vertex=(%8x, %8x)\n",
00755                                 eu, eu->vu_p->v_p,
00756                                 eu->eumate_p->vu_p->v_p);
00757                 }
00758 
00759                 /* Ignore the edgeuse to be excluded */
00760                 if( eu == eup || eu->eumate_p == eup )  {
00761                         if (rt_g.NMG_debug & DEBUG_FINDEU )
00762                                 bu_log("\tIgnoring -- excluded edgeuse\n");
00763                         continue;
00764                 }
00765 
00766                 /* See if this edgeuse is in the proper shell */
00767                 if( s && nmg_find_s_of_eu(eu) != s )  {
00768                         if (rt_g.NMG_debug & DEBUG_FINDEU)
00769                                 bu_log("\tIgnoring x%x -- eu in wrong shell s=%x\n", eu, eu->up.s_p);
00770                         continue;
00771                 }
00772 
00773                 /* If it's not a dangling edge, skip on */
00774                 if( dangling_only && eu->eumate_p != eu->radial_p) {
00775                         if (rt_g.NMG_debug & DEBUG_FINDEU)  {
00776                                 bu_log("\tIgnoring %8x/%8x (radial=x%x)\n",
00777                                         eu, eu->eumate_p,
00778                                         eu->radial_p );
00779                         }
00780                         continue;
00781                 }
00782 
00783                 if (rt_g.NMG_debug & DEBUG_FINDEU)
00784                         bu_log("\tFound %8x/%8x\n", eu, eu->eumate_p);
00785 
00786                 if ( *eu->up.magic_p == NMG_LOOPUSE_MAGIC &&
00787                      *eu->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC &&
00788                      eup_orientation != eu->up.lu_p->up.fu_p->orientation)
00789                         eu = eu->eumate_p;      /* Take other orient */
00790                 goto out;
00791         }
00792         eu = (struct edgeuse *)NULL;
00793 out:
00794         if (rt_g.NMG_debug & (DEBUG_BASIC|DEBUG_FINDEU))
00795                 bu_log("nmg_findeu() returns x%x\n", eu);
00796 
00797         return (struct edgeuse *)eu;
00798 }
00799 
00800 /**
00801  *                      N M G _ F I N D _ E U _ I N _ F A C E
00802  *
00803  *  An analog to nmg_findeu(), only restricted to searching a faceuse,
00804  *  rather than to a whole shell.
00805  */
00806 struct edgeuse *
00807 nmg_find_eu_in_face(const struct vertex *v1, const struct vertex *v2, const struct faceuse *fu, const struct edgeuse *eup, int dangling_only)
00808 {
00809         register const struct vertexuse *vu;
00810         register const struct edgeuse   *eu;
00811         const struct edgeuse            *eup_mate;
00812         int                             eup_orientation;
00813 
00814         NMG_CK_VERTEX(v1);
00815         NMG_CK_VERTEX(v2);
00816         if(fu) NMG_CK_FACEUSE(fu);
00817 
00818         if(eup)  {
00819                 struct faceuse  *fu;
00820                 NMG_CK_EDGEUSE(eup);
00821                 eup_mate = eup->eumate_p;
00822                 NMG_CK_EDGEUSE(eup_mate);
00823                 if( (fu = nmg_find_fu_of_eu(eup)) )
00824                         eup_orientation = fu->orientation;
00825                 else
00826                         eup_orientation = OT_SAME;
00827         } else {
00828                 eup_mate = eup;                 /* NULL */
00829                 eup_orientation = OT_SAME;
00830         }
00831 
00832         if (rt_g.NMG_debug & DEBUG_FINDEU)
00833                 bu_log("nmg_find_eu_in_face() seeking eu!=%8x/%8x between (%8x, %8x) %s\n",
00834                         eup, eup_mate, v1, v2,
00835                         dangling_only ? "[dangling]" : "[any]" );
00836 
00837         for( BU_LIST_FOR( vu, vertexuse, &v1->vu_hd ) )  {
00838                 NMG_CK_VERTEXUSE(vu);
00839                 if (!vu->up.magic_p)
00840                         rt_bomb("nmg_find_eu_in_face() vertexuse in vu_hd list has null parent\n");
00841 
00842                 /* Ignore self-loops and lone shell verts */
00843                 if (*vu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
00844                 eu = vu->up.eu_p;
00845 
00846                 /* Ignore edgeuses which don't run between the right verts */
00847                 if( eu->eumate_p->vu_p->v_p != v2 )  continue;
00848 
00849                 if (rt_g.NMG_debug & DEBUG_FINDEU )  {
00850                         bu_log("nmg_find_eu_in_face: check eu=%8x vertex=(%8x, %8x)\n",
00851                                 eu, eu->vu_p->v_p,
00852                                 eu->eumate_p->vu_p->v_p);
00853                 }
00854 
00855                 /* Ignore the edgeuse to be excluded */
00856                 if( eu == eup || eu->eumate_p == eup )  {
00857                         if (rt_g.NMG_debug & DEBUG_FINDEU )
00858                                 bu_log("\tIgnoring -- excluded edgeuse\n");
00859                         continue;
00860                 }
00861 
00862                 /* See if this edgeuse is in the proper faceuse */
00863                 if( fu && nmg_find_fu_of_eu(eu) != fu )  {
00864                         if (rt_g.NMG_debug & DEBUG_FINDEU)
00865                                 bu_log("\tIgnoring x%x -- eu not in faceuse\n", eu);
00866                         continue;
00867                 }
00868 
00869                 /* If it's not a dangling edge, skip on */
00870                 if( dangling_only && eu->eumate_p != eu->radial_p) {
00871                         if (rt_g.NMG_debug & DEBUG_FINDEU)  {
00872                                 bu_log("\tIgnoring %8x/%8x (radial=x%x)\n",
00873                                         eu, eu->eumate_p,
00874                                         eu->radial_p );
00875                         }
00876                         continue;
00877                 }
00878 
00879                 if (rt_g.NMG_debug & DEBUG_FINDEU)
00880                         bu_log("\tFound %8x/%8x\n", eu, eu->eumate_p);
00881 
00882                 if ( *eu->up.magic_p == NMG_LOOPUSE_MAGIC &&
00883                      *eu->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC &&
00884                      eup_orientation != eu->up.lu_p->up.fu_p->orientation)
00885                         eu = eu->eumate_p;      /* Take other orient */
00886                 goto out;
00887         }
00888         eu = (struct edgeuse *)NULL;
00889 out:
00890         if (rt_g.NMG_debug & (DEBUG_BASIC|DEBUG_FINDEU))
00891                 bu_log("nmg_find_eu_in_face() returns x%x\n", eu);
00892 
00893         return (struct edgeuse *)eu;
00894 }
00895 
00896 /**
00897  *                      N M G _ F I N D _ E
00898  *
00899  *  Find an edge between a given pair of vertices.
00900  *
00901  *  If a given shell "s" is specified, then only edges in that shell
00902  *  will be considered, otherwise all edges in the model are fair game.
00903  *
00904  *  If a particular edge "ep" is specified, then that edge
00905  *  will not be returned as a match.
00906  *
00907  *  Returns -
00908  *      edgeuse*        Edgeuse of an edge which matches the criteria
00909  *      NULL            Unable to find matching edge
00910  */
00911 struct edgeuse *
00912 nmg_find_e(const struct vertex *v1, const struct vertex *v2, const struct shell *s, const struct edge *ep)
00913 {
00914         register const struct vertexuse *vu;
00915         register const struct edgeuse   *eu;
00916 
00917         NMG_CK_VERTEX(v1);
00918         NMG_CK_VERTEX(v2);
00919         if(s) NMG_CK_SHELL(s);
00920 
00921         if (rt_g.NMG_debug & DEBUG_FINDEU)  {
00922                 bu_log("nmg_find_e() seeking e!=%8x between (%8x, %8x)\n",
00923                         ep, v1, v2 );
00924         }
00925 
00926         for( BU_LIST_FOR( vu, vertexuse, &v1->vu_hd ) )  {
00927                 NMG_CK_VERTEXUSE(vu);
00928                 if (!vu->up.magic_p)
00929                         rt_bomb("nmg_find_e() vertexuse in vu_hd list has null parent\n");
00930 
00931                 /* Ignore self-loops and lone shell verts */
00932                 if (*vu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
00933                 eu = vu->up.eu_p;
00934 
00935                 /* Ignore edgeuses which don't run between the right verts */
00936                 /* We know that this eu starts at v1 */
00937                 if( eu->eumate_p->vu_p->v_p != v2 )  continue;
00938 
00939                 if (rt_g.NMG_debug & DEBUG_FINDEU )  {
00940                         bu_log("nmg_find_e: check eu=%8x vertex=(%8x, %8x)\n",
00941                                 eu, eu->vu_p->v_p,
00942                                 eu->eumate_p->vu_p->v_p);
00943                 }
00944 
00945                 /* Ignore the edge to be excluded */
00946                 if( eu->e_p == ep )  {
00947                         if (rt_g.NMG_debug & DEBUG_FINDEU )
00948                                 bu_log("\tIgnoring -- excluded edge\n");
00949                         continue;
00950                 }
00951 
00952                 /* See if this edgeuse is in the proper shell */
00953                 if( s && nmg_find_s_of_eu(eu) != s )  {
00954                         if (rt_g.NMG_debug & DEBUG_FINDEU)
00955                                 bu_log("\tIgnoring x%x -- eu in wrong shell s=%x\n", eu, eu->up.s_p);
00956                         continue;
00957                 }
00958 
00959                 if (rt_g.NMG_debug & DEBUG_FINDEU)
00960                         bu_log("\tFound %8x/%8x\n", eu, eu->eumate_p);
00961 
00962                 if ( *eu->up.magic_p == NMG_LOOPUSE_MAGIC &&
00963                      *eu->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC &&
00964                      eu->up.lu_p->up.fu_p->orientation != OT_SAME )  {
00965                         eu = eu->eumate_p;      /* Take other orient */
00966                 }
00967                 goto out;
00968         }
00969         eu = (struct edgeuse *)NULL;
00970 out:
00971         if (rt_g.NMG_debug & (DEBUG_BASIC|DEBUG_FINDEU))
00972                 bu_log("nmg_find_e() returns x%x\n", eu);
00973 
00974         return (struct edgeuse *)eu;
00975 }
00976 
00977 /**
00978  *                      N M G _ F I N D _ E U _ O F _ V U
00979  *
00980  *  Return a pointer to the edgeuse which is the parent of this vertexuse.
00981  *
00982  *  A simple helper routine, which replaces the amazingly bad sequence of:
00983  *      nmg_find_eu_with_vu_in_lu( nmg_find_lu_of_vu(vu), vu )
00984  *  that was being used in several places.
00985  */
00986 struct edgeuse *
00987 nmg_find_eu_of_vu(const struct vertexuse *vu)
00988 {
00989         NMG_CK_VERTEXUSE(vu);
00990         if( *vu->up.magic_p != NMG_EDGEUSE_MAGIC )
00991                 return (struct edgeuse *)NULL;
00992         return vu->up.eu_p;
00993 }
00994 
00995 /**
00996  *                      N M G _ F I N D _ E U _ W I T H _ V U _ I N _ L U
00997  *
00998  *  Find an edgeuse starting at a given vertexuse within a loopuse.
00999  */
01000 struct edgeuse *
01001 nmg_find_eu_with_vu_in_lu(const struct loopuse *lu, const struct vertexuse *vu)
01002 {
01003         register struct edgeuse *eu;
01004 
01005         NMG_CK_LOOPUSE(lu);
01006         NMG_CK_VERTEXUSE(vu);
01007         if( BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC )
01008                 rt_bomb("nmg_find_eu_with_vu_in_lu: loop has no edges!\n");
01009         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
01010                 NMG_CK_EDGEUSE(eu);
01011                 if( eu->vu_p == vu )  return eu;
01012         }
01013         rt_bomb("nmg_find_eu_with_vu_in_lu:  Unable to find vu!\n");
01014         /* NOTREACHED */
01015         return((struct edgeuse *)NULL);
01016 }
01017 
01018 /**                             N M G _ F A C E R A D I A L
01019  *
01020  *      Looking radially around an edge, find another edge in the same
01021  *      face as the current edge. (this could be the mate to the current edge)
01022  */
01023 const struct edgeuse *
01024 nmg_faceradial(const struct edgeuse *eu)
01025 {
01026         const struct faceuse *fu;
01027         const struct edgeuse *eur;
01028 
01029         NMG_CK_EDGEUSE(eu);
01030         NMG_CK_LOOPUSE(eu->up.lu_p);
01031         fu = eu->up.lu_p->up.fu_p;
01032         NMG_CK_FACEUSE(fu);
01033 
01034         eur = eu->radial_p;
01035 
01036         while (*eur->up.magic_p != NMG_LOOPUSE_MAGIC ||
01037             *eur->up.lu_p->up.magic_p != NMG_FACEUSE_MAGIC ||
01038             eur->up.lu_p->up.fu_p->f_p != fu->f_p)
01039                 eur = eur->eumate_p->radial_p;
01040 
01041         return(eur);
01042 }
01043 
01044 
01045 /**
01046  *                      N M G _ R A D I A L _ F A C E _ E D G E _ I N _ S H E L L
01047  *
01048  *      looking radially around an edge, find another edge which is a part
01049  *      of a face in the same shell
01050  */
01051 const struct edgeuse *
01052 nmg_radial_face_edge_in_shell(const struct edgeuse *eu)
01053 {
01054         const struct edgeuse *eur;
01055         const struct shell      *s;
01056 
01057         NMG_CK_EDGEUSE(eu);
01058         s = nmg_find_s_of_eu(eu);
01059 
01060         eur = eu->radial_p;
01061         NMG_CK_EDGEUSE(eur);
01062 
01063         while (eur != eu->eumate_p) {
01064                 if (*eur->up.magic_p == NMG_LOOPUSE_MAGIC &&
01065                     *eur->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC &&
01066                     eur->up.lu_p->up.fu_p->s_p == s) {
01067                         break; /* found another face in shell */
01068                 } else {
01069                         eur = eur->eumate_p->radial_p;
01070                         NMG_CK_EDGEUSE(eur);
01071                 }
01072         }
01073         return(eur);
01074 }
01075 
01076 /**
01077  *                      N M G _ F I N D _ E D G E _ B E T W E E N _ 2 F U
01078  *
01079  *  Perform a topology search to determine if two faces (specified by
01080  *  their faceuses) share an edge in common.  If so, return an edgeuse
01081  *  in fu1 of that edge.
01082  *
01083  *  If there are multiple edgeuses in common, ensure that they all refer
01084  *  to the same edge_g_lseg geometry structure.  The intersection of two planes
01085  *  (non-coplanar) must be a single line.
01086  *
01087  *  Calling this routine when the two faces share face geometry
01088  *  and have more than one edge in common gives
01089  *  a NULL return, as there is no unique answer.
01090  *
01091  *  NULL is also returned if no common edge could be found.
01092  */
01093 const struct edgeuse *
01094 nmg_find_edge_between_2fu(const struct faceuse *fu1, const struct faceuse *fu2, const struct bn_tol *tol)
01095 {
01096         const struct loopuse    *lu1;
01097         const struct edgeuse    *ret = (const struct edgeuse *)NULL;
01098         int                     coincident;
01099 
01100         NMG_CK_FACEUSE(fu1);
01101         NMG_CK_FACEUSE(fu2);
01102         BN_CK_TOL(tol);
01103 
01104         for( BU_LIST_FOR( lu1, loopuse, &fu1->lu_hd ) )  {
01105                 const struct edgeuse    *eu1;
01106                 NMG_CK_LOOPUSE(lu1);
01107                 if( BU_LIST_FIRST_MAGIC(&lu1->down_hd) == NMG_VERTEXUSE_MAGIC )
01108                         continue;
01109                 for( BU_LIST_FOR( eu1, edgeuse, &lu1->down_hd ) )  {
01110                         const struct edgeuse *eur;
01111 
01112                         NMG_CK_EDGEUSE(eu1);
01113                         /* Walk radially around the edge */
01114                         eur = eu1->radial_p;
01115                         NMG_CK_EDGEUSE(eur);
01116 
01117                         while (eur != eu1->eumate_p) {
01118                                 if (*eur->up.magic_p == NMG_LOOPUSE_MAGIC &&
01119                                     *eur->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC &&
01120                                     eur->up.lu_p->up.fu_p->f_p == fu2->f_p) {
01121                                         /* Found the other face on this edge! */
01122                                         if( !ret )  {
01123                                                 /* First common edge found */
01124                                                 if( eur->up.lu_p->up.fu_p == fu2)  {
01125                                                         ret = eur;
01126                                                 } else {
01127                                                         ret = eur->eumate_p;
01128                                                 }
01129                                         } else {
01130                                                 /* Previous edge found, check edge_g_lseg */
01131                                                 if( eur->g.lseg_p != ret->g.lseg_p )  {
01132                                                         bu_log("eur=x%x, eg_p=x%x;  ret=x%x, eg_p=x%x\n",
01133                                                                 eur, eur->g.lseg_p,
01134                                                                 ret, ret->g.lseg_p );
01135                                                         nmg_pr_eg( eur->g.magic_p, 0 );
01136                                                         nmg_pr_eg( ret->g.magic_p, 0 );
01137                                                         nmg_pr_eu_endpoints( eur, 0 );
01138                                                         nmg_pr_eu_endpoints( ret, 0 );
01139 
01140                                                         coincident = nmg_2edgeuse_g_coincident( eur, ret, tol );
01141                                                         if( coincident )  {
01142                                                                 /* Change eur to use ret's eg */
01143                                                                 bu_log("nmg_find_edge_between_2fu() belatedly fusing e1=x%x, eg1=x%x, e2=x%x, eg2=x%x\n",
01144                                                                         eur->e_p, eur->g.lseg_p,
01145                                                                         ret->e_p, ret->g.lseg_p );
01146                                                                 nmg_jeg( ret->g.lseg_p, eur->g.lseg_p );
01147                                                                 /* See if there are any others. */
01148                                                                 nmg_model_fuse( nmg_find_model(&eur->l.magic), tol );
01149                                                         } else {
01150                                                                 rt_bomb("nmg_find_edge_between_2fu() 2 faces intersect with differing edge geometries?\n");
01151                                                         }
01152                                                 }
01153                                         }
01154                                 }
01155                                 /* Advance to next */
01156                                 eur = eur->eumate_p->radial_p;
01157                                 NMG_CK_EDGEUSE(eur);
01158                         }
01159                 }
01160         }
01161         if (rt_g.NMG_debug & DEBUG_BASIC)  bu_log("nmg_find_edge_between_2fu(fu1=x%x, fu2=x%x) edgeuse=x%x\n", fu1, fu2, ret);
01162         return ret;
01163 
01164 }
01165 
01166 /**
01167  *  Support for nmg_find_e_nearest_pt2().
01168  */
01169 struct fen2d_state {
01170         char            *visited;       /* array of edges already visited */
01171         fastf_t         mindist;        /* current min dist */
01172         struct edge     *ep;            /* closest edge */
01173         mat_t           mat;
01174         point_t         pt2;
01175         const struct bn_tol     *tol;
01176 };
01177 
01178 static void
01179 nmg_find_e_pt2_handler(long int *lp, genptr_t state, int first)
01180 {
01181         register struct fen2d_state     *sp = (struct fen2d_state *)state;
01182         register struct edge            *e = (struct edge *)lp;
01183         fastf_t                         dist_sq;
01184         point_t                         a2, b2;
01185         struct vertex                   *va, *vb;
01186         point_t                         pca;
01187         int                             code;
01188 
01189         BN_CK_TOL(sp->tol);
01190         NMG_CK_EDGE(e);
01191 
01192         /* If this edge has been processed before, do nothing more */
01193         if( !NMG_INDEX_FIRST_TIME(sp->visited, e) )  return;
01194 
01195         va = e->eu_p->vu_p->v_p;
01196         vb = e->eu_p->eumate_p->vu_p->v_p;
01197         NMG_CK_VERTEX(va);
01198         NMG_CK_VERTEX(vb);
01199 
01200         MAT4X3PNT( a2, sp->mat, va->vg_p->coord );
01201         MAT4X3PNT( b2, sp->mat, vb->vg_p->coord );
01202 
01203         code = bn_dist_pt2_lseg2( &dist_sq, pca, a2, b2, sp->pt2, sp->tol );
01204 
01205         if( code == 0 )  dist_sq = 0;
01206 
01207         if( dist_sq < sp->mindist )  {
01208                 sp->mindist = dist_sq;
01209                 sp->ep = e;
01210         }
01211 }
01212 
01213 /**
01214  *                      N M G _ F I N D _ E _ N E A R E S T _ P T 2
01215  *
01216  *  A geometric search routine to find the edge that is neaest to
01217  *  the given point, when all edges are projected into 2D using
01218  *  the matrix 'mat'.
01219  *  Useful for finding the edge nearest a mouse click, for example.
01220  */
01221 struct edge *
01222 nmg_find_e_nearest_pt2(long int *magic_p, const fastf_t *pt2, const fastf_t *mat, const struct bn_tol *tol)
01223 
01224                                 /* 2d point */
01225                                 /* 3d to 3d xform */
01226 
01227 {
01228         struct model                    *m;
01229         struct fen2d_state              st;
01230         static const struct nmg_visit_handlers htab = {NULL, NULL, NULL, NULL, NULL,
01231                                                        NULL, NULL, NULL, NULL, NULL,
01232                                                        NULL, NULL, NULL, NULL, NULL,
01233                                                        NULL, NULL, NULL, nmg_find_e_pt2_handler, NULL,
01234                                                        NULL, NULL, NULL, NULL, NULL};
01235         /* htab.vis_edge = nmg_find_e_pt2_handler; */
01236 
01237         BN_CK_TOL(tol);
01238         m = nmg_find_model( magic_p );
01239         NMG_CK_MODEL(m);
01240 
01241         st.visited = (char *)bu_calloc(m->maxindex+1, sizeof(char), "visited[]");
01242         st.mindist = INFINITY;
01243         VMOVE( st.pt2, pt2 );
01244         MAT_COPY( st.mat, mat );
01245         st.ep = (struct edge *)NULL;
01246         st.tol = tol;
01247 
01248         nmg_visit( magic_p, &htab, (genptr_t)&st );
01249 
01250         bu_free( (char *)st.visited, "visited[]" );
01251 
01252         if( st.ep )  {
01253                 NMG_CK_EDGE(st.ep);
01254                 return st.ep;
01255         }
01256         return (struct edge *)NULL;
01257 }
01258 
01259 /**
01260  *                      N M G _ E U _ 2 V E C S _ P E R P
01261  *
01262  *  Given an edgeuse, return two arbitrary unit-length vectors which
01263  *  are perpendicular to each other and to the edgeuse, such that
01264  *  they can be considered the +X and +Y axis, and the edgeuse is +Z.
01265  *  That is, X cross Y = Z.
01266  *
01267  *  Useful for erecting a coordinate system around an edge suitable
01268  *  for measuring the angles of other edges and faces with.
01269  */
01270 void
01271 nmg_eu_2vecs_perp(fastf_t *xvec, fastf_t *yvec, fastf_t *zvec, const struct edgeuse *eu, const struct bn_tol *tol)
01272 {
01273         const struct vertex     *v1, *v2;
01274         fastf_t                 len;
01275 
01276         NMG_CK_EDGEUSE(eu);
01277         v1 = eu->vu_p->v_p;
01278         NMG_CK_VERTEX(v1);
01279         v2 = eu->eumate_p->vu_p->v_p;
01280         NMG_CK_VERTEX(v2);
01281         if( v1 == v2 )  rt_bomb("nmg_eu_2vecs_perp() start&end vertex of edge are the same!\n");
01282         BN_CK_TOL(tol);
01283 
01284         NMG_CK_VERTEX_G(v1->vg_p);
01285         NMG_CK_VERTEX_G(v2->vg_p);
01286         VSUB2( zvec, v2->vg_p->coord, v1->vg_p->coord );
01287         len = MAGNITUDE(zvec);
01288         /* See if v1 == v2, within tol */
01289         if( len < tol->dist )  rt_bomb("nmg_eu_2vecs_perp(): 0-length edge (geometry)\n");
01290         len = 1 / len;
01291         VSCALE( zvec, zvec, len );
01292 
01293         bn_vec_perp( xvec, zvec );
01294         VCROSS( yvec, zvec, xvec );
01295 }
01296 
01297 /**
01298  *                      N M G _ F I N D _ E U _ L E F T V E C
01299  *
01300  *  Given an edgeuse, if it is part of a faceuse, return the inward pointing
01301  *  "left" vector which points into the interior of this loop, and
01302  *  lies in the plane of the face. The left vector is unitized.
01303  *
01304  *  This routine depends on the vertex ordering in an OT_SAME loopuse being
01305  *  properly CCW for exterior loops, and CW for interior (hole) loops.
01306  *
01307  *  Returns -
01308  *      -1      if edgeuse is not part of a faceuse.
01309  *       0      if left vector successfully computed into caller's array.
01310  */
01311 int
01312 nmg_find_eu_leftvec(fastf_t *left, const struct edgeuse *eu)
01313 {
01314         const struct loopuse    *lu;
01315         const struct faceuse    *fu;
01316         vect_t                  Norm;
01317         vect_t                  edgevect;
01318         fastf_t                 dot;
01319         struct vertex_g         *vg1;
01320         struct vertex_g         *vg2;
01321         fastf_t                 edge_len_sq;
01322         fastf_t                 sin_sq;
01323 
01324         NMG_CK_EDGEUSE(eu);
01325         if( *eu->up.magic_p != NMG_LOOPUSE_MAGIC )  return -1;
01326         lu = eu->up.lu_p;
01327         NMG_CK_LOOPUSE(lu);
01328         if( *lu->up.magic_p != NMG_FACEUSE_MAGIC )  return -1;
01329         fu = lu->up.fu_p;
01330         NMG_CK_FACEUSE(fu);
01331         NMG_CK_FACE(fu->f_p);
01332         NMG_CK_FACE_G_PLANE(fu->f_p->g.plane_p);
01333 
01334         vg1 = eu->vu_p->v_p->vg_p;
01335         vg2 = eu->eumate_p->vu_p->v_p->vg_p;
01336 
01337         /* Get unit length Normal vector for edgeuse's faceuse */
01338         NMG_GET_FU_NORMAL( Norm, fu );
01339 
01340         VSUB2( edgevect, vg2->coord, vg1->coord );
01341         edge_len_sq = MAGSQ( edgevect );
01342 
01343         dot = VDOT( edgevect, Norm );
01344         sin_sq = 1.0 - (dot * dot / edge_len_sq);
01345 
01346         if( NEAR_ZERO( sin_sq, 0.000001) )      /* we don't have a tol structure available XXX */
01347         {
01348                 const struct edgeuse *eu_next;
01349                 const struct edgeuse *eu_prev;
01350                 vect_t next_left;
01351                 vect_t prev_left;
01352                 vect_t other_edge;
01353                 int other_edge_is_parallel=1;
01354 
01355                 bu_log( "WARNING: eu x%x (%f %f %f) parallel to normal (%f %f %f)\n", eu, V3ARGS( edgevect ), V3ARGS( Norm ) );
01356 
01357                 eu_next = eu;
01358                 while( other_edge_is_parallel )
01359                 {
01360                         eu_next = BU_LIST_PNEXT_CIRC( edgeuse, &eu_next->l );
01361                         if( eu_next == eu )
01362                                 break;
01363                         if( NMG_ARE_EUS_ADJACENT( eu, eu_next ) )
01364                                 continue;
01365                         VSUB2( other_edge, eu_next->eumate_p->vu_p->v_p->vg_p->coord,
01366                                 eu_next->vu_p->v_p->vg_p->coord );
01367                         VUNITIZE( other_edge );
01368                         dot = 1.0 - fabs( VDOT( other_edge, Norm ) );
01369                         if( dot < .5 )
01370                                 other_edge_is_parallel = 0;
01371                 }
01372                 if( other_edge_is_parallel )
01373                 {
01374                         bu_log( "Cannot find edge (starting eu =x%x) that is not parallel to face normal!!!\n", eu );
01375                         nmg_pr_fu_briefly( fu, (char *)NULL );
01376                         rt_bomb( "Cannot find edge that is not parallel to face normal!!!\n" );
01377                 }
01378 
01379                 VCROSS( next_left, Norm, other_edge );
01380                 VUNITIZE( next_left );
01381 
01382                 eu_prev = eu;
01383                 other_edge_is_parallel = 1;
01384                 while( other_edge_is_parallel )
01385                 {
01386                         eu_prev = BU_LIST_PPREV_CIRC( edgeuse, &eu_prev->l );
01387                         if( eu_prev == eu )
01388                                 break;
01389                         if( NMG_ARE_EUS_ADJACENT( eu, eu_prev ) )
01390                                 continue;
01391                         VSUB2( other_edge, eu_prev->eumate_p->vu_p->v_p->vg_p->coord,
01392                                 eu_prev->vu_p->v_p->vg_p->coord );
01393                         VUNITIZE( other_edge );
01394                         dot = 1.0 - fabs( VDOT( other_edge, Norm ) );
01395                         if( dot < .5 )
01396                                 other_edge_is_parallel = 0;
01397                 }
01398                 if( other_edge_is_parallel )
01399                 {
01400                         bu_log( "Cannot find edge (starting eu =x%x) that is not parallel to face normal!!!\n", eu );
01401                         nmg_pr_fu_briefly( fu, (char *)NULL );
01402                         rt_bomb( "Cannot find edge that is not parallel to face normal!!!\n" );
01403                 }
01404 
01405                 VCROSS( prev_left, Norm, other_edge );
01406                 VUNITIZE( prev_left );
01407 
01408                 VBLEND2( left, 0.5, next_left, 0.5, prev_left );
01409                 VUNITIZE( left );
01410 #if 0
01411                 bu_log( "\t eu_prev (%g %g %g)<->(%g %g %g)\n",
01412                         V3ARGS( eu_prev->vu_p->v_p->vg_p->coord ),
01413                         V3ARGS( eu_prev->eumate_p->vu_p->v_p->vg_p->coord ) );
01414                 bu_log( "\t eu_next (%g %g %g)<->(%g %g %g)\n",
01415                         V3ARGS( eu_next->vu_p->v_p->vg_p->coord ),
01416                         V3ARGS( eu_next->eumate_p->vu_p->v_p->vg_p->coord ) );
01417                 bu_log( "\tprev_left=(%g %g %g), next_left=(%g %g %g)\n", V3ARGS( prev_left ), V3ARGS( next_left ) );
01418                 bu_log( "\tUnitized left=(%f %f %f)\n", V3ARGS( left ) );
01419 
01420                 nmg_pr_fu_briefly( fu, "" );
01421 #endif
01422                 return 0;
01423         }
01424 
01425         VCROSS( left, Norm, edgevect );
01426         if (rt_g.NMG_debug & DEBUG_MESH_EU ) {
01427                 vect_t edge_unit;
01428                 vect_t norm_x_edge;
01429 
01430                 VMOVE( edge_unit, edgevect );
01431                 VUNITIZE( edge_unit );
01432                 VCROSS( norm_x_edge, Norm, edge_unit );
01433                 bu_log( "for eu x%x from fu x%x v1=x%x, v2=x%x:\n", eu, fu, eu->vu_p->v_p, eu->eumate_p->vu_p->v_p );
01434                 bu_log( "\t(%.10f %.10f %.10f) <-> (%.10f %.10f %.10f)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ), V3ARGS( eu->eumate_p->vu_p->v_p->vg_p->coord ) );
01435                 bu_log( "\tedge dot norm = %.10f\n", VDOT( edge_unit, Norm ) );
01436                 bu_log( "\tnorm X edge = (%.10f %.10f %.10f)\n", V3ARGS( norm_x_edge ) );
01437                 bu_log( "\tnorm=(%.10f %.10f %.10f), edgevect=(%.10f %.10f %.10f), left=(%.10f %.10f %.10f )\n",
01438                         V3ARGS( Norm ), V3ARGS( edgevect ), V3ARGS( left ) );
01439         }
01440         VUNITIZE( left );
01441         if (rt_g.NMG_debug & DEBUG_MESH_EU ) {
01442                 bu_log( "\tUnitized left=(%f %f %f)\n", V3ARGS( left ) );
01443         }
01444         return 0;
01445 }
01446 
01447 /**
01448  *              N M G _ F I N D _ E U _ L E F T _ N O N _ U N I T
01449  *
01450  *  Given an edgeuse, if it is part of a faceuse, return the inward pointing
01451  *  "left" vector which points into the interior of this loop, and
01452  *  lies in the plane of the face. The left vector is not unitized.
01453  *
01454  *  This routine depends on the vertex ordering in an OT_SAME loopuse being
01455  *  properly CCW for exterior loops, and CW for interior (hole) loops.
01456  *
01457  *  Returns -
01458  *      -1      if edgeuse is not part of a faceuse.
01459  *       0      if left vector successfully computed into caller's array.
01460  */
01461 int
01462 nmg_find_eu_left_non_unit(fastf_t *left, const struct edgeuse *eu)
01463 {
01464         const struct loopuse    *lu;
01465         const struct faceuse    *fu;
01466         vect_t                  Norm;
01467         vect_t                  edgevect;
01468         pointp_t                p1,p2;
01469 
01470         NMG_CK_EDGEUSE(eu);
01471         if( *eu->up.magic_p != NMG_LOOPUSE_MAGIC )  return -1;
01472         lu = eu->up.lu_p;
01473         if( *lu->up.magic_p != NMG_FACEUSE_MAGIC )  return -1;
01474         fu = lu->up.fu_p;
01475 
01476         /* Get unit length Normal vector for edgeuse's faceuse */
01477         NMG_GET_FU_NORMAL( Norm, fu );
01478 
01479         /* Get vector in direction of edge */
01480         p1 = eu->vu_p->v_p->vg_p->coord;
01481         p2 = eu->eumate_p->vu_p->v_p->vg_p->coord;
01482         VSUB2( edgevect, p2, p1 );
01483 
01484         /* left vector is cross-product of face normal and edge direction */
01485         VCROSS( left, Norm, edgevect );
01486         return 0;
01487 }
01488 /**
01489  *                      N M G _ F I N D _ O T _ S A M E _ E U _ O F _ E
01490  *
01491  *  If there is an edgeuse of an OT_SAME faceuse on this edge, return it.
01492  *  Only return a wire edgeuse if that is all there is.
01493  *  Useful for selecting a "good" edgeuse to pass to nmg_eu_2vecs_perp().
01494  */
01495 struct edgeuse *
01496 nmg_find_ot_same_eu_of_e(const struct edge *e)
01497 {
01498         register struct edgeuse *eu1;
01499         register struct edgeuse *eu;
01500         struct faceuse          *fu;
01501 
01502         NMG_CK_EDGE(e);
01503         eu = eu1 = e->eu_p;
01504         do  {
01505                 fu = nmg_find_fu_of_eu(eu);
01506                 if( fu && fu->orientation == OT_SAME )  return eu;
01507 
01508                 fu = nmg_find_fu_of_eu(eu->eumate_p);
01509                 if( fu && fu->orientation == OT_SAME )  return eu->eumate_p;
01510                 eu = eu->radial_p->eumate_p;
01511         } while( eu != eu1 );
01512         return eu1;             /* All wire */
01513 }
01514 
01515 /************************************************************************
01516  *                                                                      *
01517  *                              VERTEX Routines                         *
01518  *                                                                      *
01519  ************************************************************************/
01520 
01521 /**
01522  *                      N M G _ F I N D _ V _ I N _ F A C E
01523  *
01524  *      Perform a topological search to
01525  *      determine if the given vertex is contained in the given faceuse.
01526  *      If it is, return a pointer to the vertexuse which was found in the
01527  *      faceuse.
01528  *
01529  *  Returns NULL if not found.
01530  */
01531 struct vertexuse *
01532 nmg_find_v_in_face(const struct vertex *v, const struct faceuse *fu)
01533 {
01534         struct vertexuse *vu;
01535         struct edgeuse *eu;
01536         struct loopuse *lu;
01537 
01538         NMG_CK_VERTEX(v);
01539 
01540         for( BU_LIST_FOR( vu, vertexuse, &v->vu_hd ) )  {
01541                 NMG_CK_VERTEXUSE(vu);
01542                 if (*vu->up.magic_p == NMG_EDGEUSE_MAGIC) {
01543                         eu = vu->up.eu_p;
01544                         if (*eu->up.magic_p == NMG_LOOPUSE_MAGIC) {
01545                                 lu = eu->up.lu_p;
01546                                 if (*lu->up.magic_p == NMG_FACEUSE_MAGIC && lu->up.fu_p == fu)
01547                                         return(vu);
01548                         }
01549 
01550                 } else if (*vu->up.magic_p == NMG_LOOPUSE_MAGIC) {
01551                         lu = vu->up.lu_p;
01552                         if (*lu->up.magic_p == NMG_FACEUSE_MAGIC && lu->up.fu_p == fu)
01553                                 return(vu);
01554                 }
01555         }
01556         return((struct vertexuse *)NULL);
01557 }
01558 
01559 /**
01560  *                      N M G _ F I N D _ V _ I N _ S H E L L
01561  *
01562  *  Search shell "s" for a vertexuse that refers to vertex "v".
01563  *  For efficiency, the search is done on the uses of "v".
01564  *
01565  *  If "edges_only" is set, only a vertexuse from an edgeuse will
01566  *  be returned, otherwise, vu's from self-loops and lone-shell-vu's
01567  *  are also candidates.
01568  */
01569 struct vertexuse *
01570 nmg_find_v_in_shell(const struct vertex *v, const struct shell *s, int edges_only)
01571 {
01572         struct vertexuse        *vu;
01573 
01574         for( BU_LIST_FOR( vu, vertexuse, &v->vu_hd ) )  {
01575                 NMG_CK_VERTEXUSE(vu);
01576 
01577                 if( *vu->up.magic_p == NMG_LOOPUSE_MAGIC )  {
01578                         if( edges_only )  continue;
01579                         if( nmg_find_s_of_lu( vu->up.lu_p ) == s )
01580                                 return vu;
01581                         continue;
01582                 }
01583                 if( *vu->up.magic_p == NMG_SHELL_MAGIC )  {
01584                         if( edges_only )  continue;
01585                         if( vu->up.s_p == s )
01586                                 return vu;
01587                         continue;
01588                 }
01589                 if( *vu->up.magic_p != NMG_EDGEUSE_MAGIC )
01590                         rt_bomb("nmg_find_v_in_shell(): bad vu up ptr\n");
01591 
01592                 /* vu is being used by an edgeuse */
01593                 if( nmg_find_s_of_eu( vu->up.eu_p ) == s )
01594                         return vu;
01595         }
01596         return (struct vertexuse *)NULL;
01597 }
01598 
01599 /**
01600  *                      N M G _ F I N D _ P T _ I N _ L U
01601  *
01602  *  Conduct a geometric search for a vertex in loopuse 'lu' which is
01603  *  "identical" to the given point, within the specified tolerance.
01604  *  The loopuse may be part of a face, or it may be wires.
01605  *
01606  *  Returns -
01607  *      NULL                    No vertex matched
01608  *      (struct vertexuse *)    A matching vertexuse from that loopuse.
01609  */
01610 struct vertexuse *
01611 nmg_find_pt_in_lu(const struct loopuse *lu, const fastf_t *pt, const struct bn_tol *tol)
01612 {
01613         struct edgeuse          *eu;
01614         vect_t                  delta;
01615         struct vertex           *v;
01616         register struct vertex_g *vg;
01617         int                     magic1;
01618 
01619         magic1 = BU_LIST_FIRST_MAGIC( &lu->down_hd );
01620         if (magic1 == NMG_VERTEXUSE_MAGIC) {
01621                 struct vertexuse        *vu;
01622                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
01623                 v = vu->v_p;
01624                 NMG_CK_VERTEX(v);
01625                 if( !(vg = v->vg_p) )
01626                         return ((struct vertexuse *)NULL);
01627                 NMG_CK_VERTEX_G(vg);
01628                 VSUB2(delta, vg->coord, pt);
01629                 if ( MAGSQ(delta) <= tol->dist_sq)
01630                         return(vu);
01631                 return ((struct vertexuse *)NULL);
01632         }
01633         if (magic1 != NMG_EDGEUSE_MAGIC) {
01634                 rt_bomb("nmg_find_pt_in_lu() Bogus child of loop\n");
01635         }
01636 
01637         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
01638                 v = eu->vu_p->v_p;
01639                 NMG_CK_VERTEX(v);
01640                 if( !(vg = v->vg_p) )  continue;
01641                 NMG_CK_VERTEX_G(vg);
01642                 VSUB2(delta, vg->coord, pt);
01643                 if ( MAGSQ(delta) <= tol->dist_sq)
01644                         return(eu->vu_p);
01645         }
01646         return ((struct vertexuse *)NULL);
01647 
01648 }
01649 
01650 /**
01651  *                      N M G _ F I N D _ P T _ I N _ F A C E
01652  *
01653  *  Conduct a geometric search for a vertex in face 'fu' which is
01654  *  "identical" to the given point, within the specified tolerance.
01655  *
01656  *  Returns -
01657  *      NULL                    No vertex matched
01658  *      (struct vertexuse *)    A matching vertexuse from that face.
01659  */
01660 struct vertexuse *
01661 nmg_find_pt_in_face(const struct faceuse *fu, const fastf_t *pt, const struct bn_tol *tol)
01662 {
01663         register struct loopuse *lu;
01664         struct vertexuse        *vu;
01665 
01666         NMG_CK_FACEUSE(fu);
01667         BN_CK_TOL(tol);
01668 
01669         for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
01670                 NMG_CK_LOOPUSE(lu);
01671                 if( (vu = nmg_find_pt_in_lu(lu, pt, tol)) )
01672                         return vu;
01673         }
01674         return ((struct vertexuse *)NULL);
01675 }
01676 
01677 /**
01678  *                      N M G _ F I N D _ P T _ I N _ S H E L L
01679  *
01680  *  Given a point in 3-space and a shell pointer, try to find a vertex
01681  *  anywhere in the shell which is within sqrt(tol_sq) distance of
01682  *  the given point.
01683  *
01684  *  The algorithm is a brute force, and should be used sparingly.
01685  *  Mike Gigante's NUgrid technique would work well here, if
01686  *  searching was going to be needed for more than a few points.
01687  *
01688  *  Returns -
01689  *      pointer to vertex with matching geometry
01690  *      NULL
01691  *
01692  *  XXX Why does this return a vertex, while it's helpers return a vertexuse?
01693  */
01694 struct vertex *
01695 nmg_find_pt_in_shell(const struct shell *s, const fastf_t *pt, const struct bn_tol *tol)
01696 {
01697         const struct faceuse    *fu;
01698         const struct loopuse    *lu;
01699         const struct edgeuse    *eu;
01700         const struct vertexuse  *vu;
01701         struct vertex           *v;
01702         const struct vertex_g   *vg;
01703         vect_t          delta;
01704 
01705         NMG_CK_SHELL(s);
01706         BN_CK_TOL(tol);
01707 
01708         fu = BU_LIST_FIRST(faceuse, &s->fu_hd);
01709         while (BU_LIST_NOT_HEAD(fu, &s->fu_hd) ) {
01710                 /* Shell has faces */
01711                 NMG_CK_FACEUSE(fu);
01712                 if( (vu = nmg_find_pt_in_face( fu, pt, tol )) )
01713                         return(vu->v_p);
01714 
01715                 if (BU_LIST_PNEXT(faceuse, fu) == fu->fumate_p)
01716                         fu = BU_LIST_PNEXT_PNEXT(faceuse, fu);
01717                 else
01718                         fu = BU_LIST_PNEXT(faceuse, fu);
01719         }
01720 
01721         /* Wire loopuses */
01722         lu = BU_LIST_FIRST(loopuse, &s->lu_hd);
01723         while (BU_LIST_NOT_HEAD(lu, &s->lu_hd) ) {
01724                 NMG_CK_LOOPUSE(lu);
01725                 if( (vu = nmg_find_pt_in_lu(lu, pt, tol)) )
01726                         return vu->v_p;
01727 
01728                 if (BU_LIST_PNEXT(loopuse, lu) == lu->lumate_p)
01729                         lu = BU_LIST_PNEXT_PNEXT(loopuse, lu);
01730                 else
01731                         lu = BU_LIST_PNEXT(loopuse, lu);
01732         }
01733 
01734         /* Wire edgeuses */
01735         for (BU_LIST_FOR(eu, edgeuse, &s->eu_hd)) {
01736                 NMG_CK_EDGEUSE(eu);
01737                 NMG_CK_VERTEXUSE(eu->vu_p);
01738                 v = eu->vu_p->v_p;
01739                 NMG_CK_VERTEX(v);
01740                 if( (vg = v->vg_p) )  {
01741                         NMG_CK_VERTEX_G(vg);
01742                         VSUB2( delta, vg->coord, pt );
01743                         if( MAGSQ(delta) <= tol->dist_sq )
01744                                 return(v);
01745                 }
01746         }
01747 
01748         /* Lone vertexuse */
01749         if (s->vu_p) {
01750                 NMG_CK_VERTEXUSE(s->vu_p);
01751                 v = s->vu_p->v_p;
01752                 NMG_CK_VERTEX(v);
01753                 if( (vg = v->vg_p) )  {
01754                         NMG_CK_VERTEX_G( vg );
01755                         VSUB2( delta, vg->coord, pt );
01756                         if( MAGSQ(delta) <= tol->dist_sq )
01757                                 return(v);
01758                 }
01759         }
01760         return( (struct vertex *)0 );
01761 }
01762 
01763 /**
01764  *                      N M G _ F I N D _ P T _ I N _ M O D E L
01765  *
01766  *  Brute force search of the entire model to find a vertex that
01767  *  matches this point.
01768  *  XXX Shouldn't this return the _closest_ match, not just the
01769  *  XXX first match within tolerance?
01770  */
01771 struct vertex *
01772 nmg_find_pt_in_model(const struct model *m, const fastf_t *pt, const struct bn_tol *tol)
01773 {
01774         struct nmgregion        *r;
01775         struct shell            *s;
01776         struct vertex           *v;
01777 
01778         NMG_CK_MODEL(m);
01779         BN_CK_TOL(tol);
01780 
01781         for( BU_LIST_FOR( r, nmgregion, &m->r_hd ) )  {
01782                 NMG_CK_REGION(r);
01783                 for( BU_LIST_FOR( s, shell, &r->s_hd ) )  {
01784                         NMG_CK_SHELL(s);
01785                         if( (v = nmg_find_pt_in_shell( s, pt, tol )) )  {
01786                                 NMG_CK_VERTEX(v);
01787                                 return v;
01788                         }
01789                 }
01790         }
01791         return (struct vertex *)NULL;
01792 }
01793 
01794 /**
01795  *                      N M G _ I S _ V E R T E X _ I N _ E D G E L I S T
01796  *
01797  *  Returns -
01798  *      1       If found
01799  *      0       If not found
01800  */
01801 int
01802 nmg_is_vertex_in_edgelist(register const struct vertex *v, const struct bu_list *hd)
01803 {
01804         register const struct edgeuse   *eu;
01805 
01806         NMG_CK_VERTEX(v);
01807         for( BU_LIST_FOR( eu, edgeuse, hd ) )  {
01808                 NMG_CK_EDGEUSE(eu);
01809                 NMG_CK_VERTEXUSE(eu->vu_p);
01810                 NMG_CK_VERTEX(eu->vu_p->v_p);
01811                 if( eu->vu_p->v_p == v )  return(1);
01812         }
01813         return(0);
01814 }
01815 
01816 /**
01817  *                      N M G _ I S _ V E R T E X _ I N _ L O O P L I S T
01818  *
01819  *  Returns -
01820  *      1       If found
01821  *      0       If not found
01822  */
01823 int
01824 nmg_is_vertex_in_looplist(register const struct vertex *v, const struct bu_list *hd, int singletons)
01825 {
01826         register const struct loopuse   *lu;
01827         long                    magic1;
01828 
01829         NMG_CK_VERTEX(v);
01830         for( BU_LIST_FOR( lu, loopuse, hd ) )  {
01831                 NMG_CK_LOOPUSE(lu);
01832                 magic1 = BU_LIST_FIRST_MAGIC( &lu->down_hd );
01833                 if( magic1 == NMG_VERTEXUSE_MAGIC )  {
01834                         register const struct vertexuse *vu;
01835                         if( !singletons )  continue;
01836                         vu = BU_LIST_FIRST(vertexuse, &lu->down_hd );
01837                         NMG_CK_VERTEXUSE(vu);
01838                         NMG_CK_VERTEX(vu->v_p);
01839                         if( vu->v_p == v )  return(1);
01840                 } else if( magic1 == NMG_EDGEUSE_MAGIC )  {
01841                         if( nmg_is_vertex_in_edgelist( v, &lu->down_hd ) )
01842                                 return(1);
01843                 } else {
01844                         rt_bomb("nmg_is_vertex_in_loopuse() bad magic\n");
01845                 }
01846         }
01847         return(0);
01848 }
01849 
01850 /**
01851  *                      N M G _ I S _ V E R T E X _ I N _ F A C E
01852  *
01853  *  Returns -
01854  *      vu      One use of vertex 'v' in face 'f'.
01855  *      NULL    If there are no uses of 'v' in 'f'.
01856  */
01857 struct vertexuse *
01858 nmg_is_vertex_in_face(const struct vertex *v, const struct face *f)
01859 {
01860         struct vertexuse        *vu;
01861 
01862         NMG_CK_VERTEX(v);
01863         NMG_CK_FACE(f);
01864 
01865         for( BU_LIST_FOR( vu, vertexuse, &v->vu_hd ) )  {
01866                 register const struct edgeuse   *eu;
01867                 register const struct loopuse   *lu;
01868                 register const struct faceuse   *fu;
01869 
01870                 if( *vu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
01871                 if( *(eu = vu->up.eu_p)->up.magic_p != NMG_LOOPUSE_MAGIC )  continue;
01872                 lu = eu->up.lu_p;
01873                 if( *lu->up.magic_p != NMG_FACEUSE_MAGIC )  continue;
01874                 fu = lu->up.fu_p;
01875                 if( fu->f_p != f )  continue;
01876                 return vu;
01877         }
01878         return (struct vertexuse *)NULL;
01879 }
01880 
01881 /**
01882  *      N M G _ I S _ V E R T E X _ A _ S E L F L O O P _ I N _ S H E L L
01883  *
01884  *  Check to see if a given vertex is used within a shell
01885  *  by a wire loopuse which is a loop of a single vertex.
01886  *  The search could either be by the shell lu_hd, or the vu_hd.
01887  *
01888  *  Returns -
01889  *      0       vertex is not part of that kind of loop in the shell.
01890  *      1       vertex is part of a selfloop in the given shell.
01891  */
01892 int
01893 nmg_is_vertex_a_selfloop_in_shell(const struct vertex *v, const struct shell *s)
01894 {
01895         const struct vertexuse *vu;
01896 
01897         NMG_CK_VERTEX(v);
01898         NMG_CK_SHELL(s);
01899 
01900         /* try to find the vertex in a loopuse of this shell */
01901         for (BU_LIST_FOR(vu, vertexuse, &v->vu_hd)) {
01902                 register const struct loopuse   *lu;
01903                 NMG_CK_VERTEXUSE(vu);
01904                 if (*vu->up.magic_p != NMG_LOOPUSE_MAGIC )  continue;
01905                 lu = vu->up.lu_p;
01906                 NMG_CK_LOOPUSE(lu);
01907                 if( *lu->up.magic_p != NMG_SHELL_MAGIC )  continue;
01908                 NMG_CK_SHELL(lu->up.s_p);
01909                 if( lu->up.s_p == s)
01910                         return 1;
01911         }
01912         return 0;
01913 }
01914 
01915 /**
01916  *                      N M G _ I S _ V E R T E X _ I N _ F A C E L I S T
01917  *
01918  *  Returns -
01919  *      1       If found
01920  *      0       If not found
01921  */
01922 int
01923 nmg_is_vertex_in_facelist(register const struct vertex *v, const struct bu_list *hd)
01924 {
01925         register const struct faceuse   *fu;
01926 
01927         NMG_CK_VERTEX(v);
01928         for( BU_LIST_FOR( fu, faceuse, hd ) )  {
01929                 NMG_CK_FACEUSE(fu);
01930                 if( nmg_is_vertex_in_looplist( v, &fu->lu_hd, 1 ) )
01931                         return(1);
01932         }
01933         return(0);
01934 }
01935 
01936 /**
01937  *                      N M G _ I S _ E D G E _ I N _ E D G E L I S T
01938  *
01939  *  Returns -
01940  *      1       If found
01941  *      0       If not found
01942  */
01943 int
01944 nmg_is_edge_in_edgelist(const struct edge *e, const struct bu_list *hd)
01945 {
01946         register const struct edgeuse   *eu;
01947 
01948         NMG_CK_EDGE(e);
01949         for( BU_LIST_FOR( eu, edgeuse, hd ) )  {
01950                 NMG_CK_EDGEUSE(eu);
01951                 NMG_CK_EDGE(eu->e_p);
01952                 if( e == eu->e_p )  return(1);
01953         }
01954         return(0);
01955 }
01956 
01957 /**
01958  *                      N M G _ I S _ E D G E _ I N _ L O O P L I S T
01959  *
01960  *  Returns -
01961  *      1       If found
01962  *      0       If not found
01963  */
01964 int
01965 nmg_is_edge_in_looplist(const struct edge *e, const struct bu_list *hd)
01966 {
01967         register const struct loopuse   *lu;
01968         long                    magic1;
01969 
01970         NMG_CK_EDGE(e);
01971         for( BU_LIST_FOR( lu, loopuse, hd ) )  {
01972                 NMG_CK_LOOPUSE(lu);
01973                 magic1 = BU_LIST_FIRST_MAGIC( &lu->down_hd );
01974                 if( magic1 == NMG_VERTEXUSE_MAGIC )  {
01975                         /* Loop of a single vertex does not have an edge */
01976                         continue;
01977                 } else if( magic1 == NMG_EDGEUSE_MAGIC )  {
01978                         if( nmg_is_edge_in_edgelist( e, &lu->down_hd ) )
01979                                 return(1);
01980                 } else {
01981                         rt_bomb("nmg_is_edge_in_loopuse() bad magic\n");
01982                 }
01983         }
01984         return(0);
01985 }
01986 
01987 /**
01988  *                      N M G _ I S _ E D G E _ I N _ F A C E L I S T
01989  *
01990  *  Returns -
01991  *      1       If found
01992  *      0       If not found
01993  */
01994 int
01995 nmg_is_edge_in_facelist(const struct edge *e, const struct bu_list *hd)
01996 {
01997         register const struct faceuse   *fu;
01998 
01999         NMG_CK_EDGE(e);
02000         for( BU_LIST_FOR( fu, faceuse, hd ) )  {
02001                 NMG_CK_FACEUSE(fu);
02002                 if( nmg_is_edge_in_looplist( e, &fu->lu_hd ) )
02003                         return(1);
02004         }
02005         return(0);
02006 }
02007 
02008 /**
02009  *                      N M G _ I S _ L O O P _ I N _ F A C E L I S T
02010  *
02011  *  Returns -
02012  *      1       If found
02013  *      0       If not found
02014  */
02015 int
02016 nmg_is_loop_in_facelist(const struct loop *l, const struct bu_list *fu_hd)
02017 {
02018         register const struct faceuse   *fu;
02019         register const struct loopuse   *lu;
02020 
02021         NMG_CK_LOOP(l);
02022         for( BU_LIST_FOR( fu, faceuse, fu_hd ) )  {
02023                 NMG_CK_FACEUSE(fu);
02024                 for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
02025                         NMG_CK_LOOPUSE(lu);
02026                         NMG_CK_LOOP(lu->l_p);
02027                         if( l == lu->l_p )  return(1);
02028                 }
02029         }
02030         return(0);
02031 }
02032 
02033 /************************************************************************
02034  *                                                                      *
02035  *                              Tabulation Routines                     *
02036  *                                                                      *
02037  ************************************************************************/
02038 
02039 struct vf_state {
02040         char            *visited;
02041         struct bu_ptbl  *tabl;
02042 };
02043 
02044 /**
02045  *                      N M G _ 2 R V F _ H A N D L E R
02046  *
02047  *  A private support routine for nmg_vertex_tabulate().
02048  *  Having just visited a vertex, if this is the first time,
02049  *  add it to the bu_ptbl array.
02050  */
02051 static void
02052 nmg_2rvf_handler(long int *vp, genptr_t state, int first)
02053 {
02054         register struct vf_state *sp = (struct vf_state *)state;
02055         register struct vertex  *v = (struct vertex *)vp;
02056 
02057         NMG_CK_VERTEX(v);
02058         /* If this vertex has been processed before, do nothing more */
02059         if( !NMG_INDEX_FIRST_TIME(sp->visited, v) )  return;
02060 
02061         bu_ptbl_ins( sp->tabl, vp );
02062 }
02063 
02064 /**
02065  *                      N M G _ V E R T E X _ T A B U L A T E
02066  *
02067  *  Given a pointer to any nmg data structure,
02068  *  build an bu_ptbl list which has every vertex
02069  *  pointer from there on "down" in the model, each one listed exactly once.
02070  */
02071 void
02072 nmg_vertex_tabulate(struct bu_ptbl *tab, const long int *magic_p)
02073 {
02074         struct model            *m;
02075         struct vf_state         st;
02076         static const struct nmg_visit_handlers  handlers = {NULL, NULL, NULL, NULL, NULL,
02077                                                             NULL, NULL, NULL, NULL, NULL,
02078                                                             NULL, NULL, NULL, NULL, NULL,
02079                                                             NULL, NULL, NULL, NULL, NULL,
02080                                                             NULL, NULL, NULL, nmg_2rvf_handler, NULL};
02081         /* handlers.vertex = nmg_2rvf_handler; */
02082 
02083         m = nmg_find_model( magic_p );
02084         NMG_CK_MODEL(m);
02085 
02086         st.visited = (char *)bu_calloc(m->maxindex+1, sizeof(char), "visited[]");
02087         st.tabl = tab;
02088 
02089         (void)bu_ptbl_init( tab, 64, " tab");
02090 
02091         nmg_visit( magic_p, &handlers, (genptr_t)&st );
02092 
02093         bu_free( (char *)st.visited, "visited[]");
02094 }
02095 
02096 /**
02097  *                      N M G _ V E R T _ A _ H A N D L E R
02098  *
02099  *  A private support routine for nmg_vertexuse_normal_tabulate().
02100  *  Having just visited a vertexuse-a, if this is the first time,
02101  *  add it to the bu_ptbl array.
02102  */
02103 static void
02104 nmg_vert_a_handler(long int *vp, genptr_t state, int first)
02105 {
02106         register struct vf_state *sp = (struct vf_state *)state;
02107         register struct vertexuse_a_plane       *va;
02108 
02109         if( *vp != NMG_VERTEXUSE_A_PLANE_MAGIC )
02110                 return;
02111 
02112         va = (struct vertexuse_a_plane *)vp;
02113         /* If this vertex normal has been processed before, do nothing more */
02114         if( !NMG_INDEX_FIRST_TIME(sp->visited, va) )  return;
02115 
02116         bu_ptbl_ins( sp->tabl, vp );
02117 }
02118 
02119 /**
02120  *                      N M G _ V E R T E X U S E_ N O R M A L _ T A B U L A T E
02121  *
02122  *  Given a pointer to any nmg data structure,
02123  *  build an bu_ptbl list which has every vertexuse normal
02124  *  pointer from there on "down" in the model, each one listed exactly once.
02125  */
02126 void
02127 nmg_vertexuse_normal_tabulate(struct bu_ptbl *tab, const long int *magic_p)
02128 {
02129         struct model            *m;
02130         struct vf_state         st;
02131         static const struct nmg_visit_handlers  handlers = {NULL, NULL, NULL, NULL, NULL,
02132                                                             NULL, NULL, NULL, NULL, NULL,
02133                                                             NULL, NULL, NULL, NULL, NULL,
02134                                                             NULL, NULL, NULL, NULL, NULL,
02135                                                             NULL, NULL, nmg_vert_a_handler, NULL, NULL};
02136         /* handlers.vis_vertexuse_a = nmg_vert_a_handler; */
02137 
02138         m = nmg_find_model( magic_p );
02139         NMG_CK_MODEL(m);
02140 
02141         st.visited = (char *)bu_calloc(m->maxindex+1, sizeof(char), "visited[]");
02142         st.tabl = tab;
02143 
02144         (void)bu_ptbl_init( tab, 64, " tab");
02145 
02146         nmg_visit( magic_p, &handlers, (genptr_t)&st );
02147 
02148         bu_free( (char *)st.visited, "visited[]");
02149 }
02150 
02151 /**
02152  *                      N M G _ 2 E D G E U S E _ H A N D L E R
02153  *
02154  *  A private support routine for nmg_edgeuse_tabulate().
02155  *  Having just visited a edgeuse, if this is the first time,
02156  *  add it to the bu_ptbl array.
02157  */
02158 static void
02159 nmg_2edgeuse_handler(long int *eup, genptr_t state, int first)
02160 {
02161         register struct vf_state *sp = (struct vf_state *)state;
02162         register struct edgeuse *eu = (struct edgeuse *)eup;
02163 
02164         NMG_CK_EDGEUSE(eu);
02165         /* If this edgeuse has been processed before, do nothing more */
02166         if( !NMG_INDEX_FIRST_TIME(sp->visited, eu) )  return;
02167 
02168         bu_ptbl_ins( sp->tabl, eup );
02169 }
02170 
02171 /**
02172  *                      N M G _ E D G E U S E _ T A B U L A T E
02173  *
02174  *  Given a pointer to any nmg data structure,
02175  *  build an bu_ptbl list which has every edgeuse
02176  *  pointer from there on "down" in the model, each one listed exactly once.
02177  */
02178 void
02179 nmg_edgeuse_tabulate(struct bu_ptbl *tab, const long int *magic_p)
02180 {
02181         struct model            *m;
02182         struct vf_state         st;
02183         static const struct nmg_visit_handlers  handlers = {NULL, NULL, NULL, NULL, NULL,
02184                                                             NULL, NULL, NULL, NULL, NULL,
02185                                                             NULL, NULL, NULL, NULL, NULL,
02186                                                             NULL, nmg_2edgeuse_handler, NULL, NULL, NULL,
02187                                                             NULL, NULL, NULL, NULL, NULL};
02188         /* handlers.bef_edgeuse = nmg_2edgeuse_handler; */
02189 
02190         m = nmg_find_model( magic_p );
02191         NMG_CK_MODEL(m);
02192 
02193         st.visited = (char *)bu_calloc(m->maxindex+1, sizeof(char), "visited[]");
02194         st.tabl = tab;
02195 
02196         (void)bu_ptbl_init( tab, 64, " tab");
02197 
02198         nmg_visit( magic_p, &handlers, (genptr_t)&st );
02199 
02200         bu_free( (char *)st.visited, "visited[]");
02201 }
02202 
02203 /**
02204  *                      N M G _ 2 E D G E _ H A N D L E R
02205  *
02206  *  A private support routine for nmg_edge_tabulate().
02207  *  Having just visited a edge, if this is the first time,
02208  *  add it to the bu_ptbl array.
02209  */
02210 static void
02211 nmg_2edge_handler(long int *ep, genptr_t state, int first)
02212 {
02213         register struct vf_state *sp = (struct vf_state *)state;
02214         register struct edge    *e = (struct edge *)ep;
02215 
02216         NMG_CK_EDGE(e);
02217         /* If this edge has been processed before, do nothing more */
02218         if( !NMG_INDEX_FIRST_TIME(sp->visited, e) )  return;
02219 
02220         bu_ptbl_ins( sp->tabl, ep );
02221 }
02222 
02223 /**
02224  *                      N M G _ E D G E _ T A B U L A T E
02225  *
02226  *  Given a pointer to any nmg data structure,
02227  *  build an bu_ptbl list which has every edge
02228  *  pointer from there on "down" in the model, each one listed exactly once.
02229  */
02230 void
02231 nmg_edge_tabulate(struct bu_ptbl *tab, const long int *magic_p)
02232 {
02233         struct model            *m;
02234         struct vf_state         st;
02235         static const struct nmg_visit_handlers  handlers = {NULL, NULL, NULL, NULL, NULL,
02236                                                             NULL, NULL, NULL, NULL, NULL,
02237                                                             NULL, NULL, NULL, NULL, NULL,
02238                                                             NULL, NULL, NULL, nmg_2edge_handler, NULL,
02239                                                             NULL, NULL, NULL, NULL, NULL};
02240         /* handlers.vis_edge = nmg_2edge_handler; */
02241 
02242         m = nmg_find_model( magic_p );
02243         NMG_CK_MODEL(m);
02244 
02245         st.visited = (char *)bu_calloc(m->maxindex+1, sizeof(char), "visited[]");
02246         st.tabl = tab;
02247 
02248         (void)bu_ptbl_init( tab, 64, " tab");
02249 
02250         nmg_visit( magic_p, &handlers, (genptr_t)&st );
02251 
02252         bu_free( (char *)st.visited, "visited[]");
02253 }
02254 
02255 /**
02256  *                      N M G _ E D G E _ G _ H A N D L E R
02257  *
02258  *  A private support routine for nmg_edge_g_tabulate().
02259  *  Having just visited an edge_g_lseg, if this is the first time,
02260  *  add it to the bu_ptbl array.
02261  */
02262 static void
02263 nmg_edge_g_handler(long int *ep, genptr_t state, int first)
02264 {
02265         register struct vf_state *sp = (struct vf_state *)state;
02266 
02267         NMG_CK_EDGE_G_EITHER(ep);
02268 
02269         /* If this edge has been processed before, do nothing more */
02270         switch( *ep )  {
02271         case NMG_EDGE_G_LSEG_MAGIC:
02272                 if( !NMG_INDEX_FIRST_TIME(sp->visited, ((struct edge_g_lseg *)ep)) )
02273                         return;
02274                 break;
02275         case NMG_EDGE_G_CNURB_MAGIC:
02276                 if( !NMG_INDEX_FIRST_TIME(sp->visited, ((struct edge_g_cnurb *)ep)) )
02277                         return;
02278                 break;
02279         }
02280 
02281         bu_ptbl_ins( sp->tabl, ep );
02282 }
02283 
02284 /**
02285  *                      N M G _ E D G E _ G _ T A B U L A T E
02286  *
02287  *  Given a pointer to any nmg data structure,
02288  *  build an bu_ptbl list which has every edge
02289  *  pointer from there on "down" in the model, each one listed exactly once.
02290  */
02291 void
02292 nmg_edge_g_tabulate(struct bu_ptbl *tab, const long int *magic_p)
02293 {
02294         struct model            *m;
02295         struct vf_state         st;
02296         static const struct nmg_visit_handlers  handlers = {NULL, NULL, NULL, NULL, NULL,
02297                                                             NULL, NULL, NULL, NULL, NULL,
02298                                                             NULL, NULL, NULL, NULL, NULL,
02299                                                             NULL, NULL, NULL, NULL, nmg_edge_g_handler,
02300                                                             NULL, NULL, NULL, NULL, NULL};
02301         /* handlers.vis_edge_g = nmg_edge_g_handler; */
02302 
02303         m = nmg_find_model( magic_p );
02304         NMG_CK_MODEL(m);
02305 
02306         st.visited = (char *)bu_calloc(m->maxindex+1, sizeof(char), "visited[]");
02307         st.tabl = tab;
02308 
02309         (void)bu_ptbl_init( tab, 64, " tab");
02310 
02311         nmg_visit( magic_p, &handlers, (genptr_t)&st );
02312 
02313         bu_free( (char *)st.visited, "visited[]");
02314 }
02315 
02316 /**
02317  *                      N M G _ 2 F A C E _ H A N D L E R
02318  *
02319  *  A private support routine for nmg_face_tabulate().
02320  *  Having just visited a face, if this is the first time,
02321  *  add it to the bu_ptbl array.
02322  */
02323 static void
02324 nmg_2face_handler(long int *fp, genptr_t state, int first)
02325 {
02326         register struct vf_state *sp = (struct vf_state *)state;
02327         register struct face    *f = (struct face *)fp;
02328 
02329         NMG_CK_FACE(f);
02330         /* If this face has been processed before, do nothing more */
02331         if( !NMG_INDEX_FIRST_TIME(sp->visited, f) )  return;
02332 
02333         bu_ptbl_ins( sp->tabl, fp );
02334 }
02335 
02336 /**
02337  *                      N M G _ F A C E _ T A B U L A T E
02338  *
02339  *  Given a pointer to any nmg data structure,
02340  *  build an bu_ptbl list which has every face
02341  *  pointer from there on "down" in the model, each one listed exactly once.
02342  */
02343 void
02344 nmg_face_tabulate(struct bu_ptbl *tab, const long int *magic_p)
02345 {
02346         struct model            *m;
02347         struct vf_state         st;
02348         static const struct nmg_visit_handlers  handlers = {NULL, NULL, NULL, NULL, NULL,
02349                                                             NULL, NULL, NULL, NULL, NULL,
02350                                                             nmg_2face_handler, NULL, NULL, NULL, NULL,
02351                                                             NULL, NULL, NULL, NULL, NULL,
02352                                                             NULL, NULL, NULL, NULL, NULL};
02353         /* handlers.vis_face = nmg_2face_handler; */
02354 
02355         m = nmg_find_model( magic_p );
02356         NMG_CK_MODEL(m);
02357 
02358         st.visited = (char *)bu_calloc(m->maxindex+1, sizeof(char), "visited[]");
02359         st.tabl = tab;
02360 
02361         (void)bu_ptbl_init( tab, 64, " tab");
02362 
02363         nmg_visit( magic_p, &handlers, (genptr_t)&st );
02364 
02365         bu_free( (char *)st.visited, "visited[]");
02366 }
02367 
02368 /**
02369  *                      N M G _ E D G E U S E _ W I T H _ E G _ T A B U L A T E
02370  *
02371  *  Build an bu_ptbl list which cites every edgeuse
02372  *  pointer that uses edge geometry "eg".
02373  */
02374 void
02375 nmg_edgeuse_with_eg_tabulate(struct bu_ptbl *tab, const struct edge_g_lseg *eg)
02376 
02377                                         /* can also be edge_g_cnurb */
02378 {
02379         struct bu_list  *midway;        /* &eu->l2, midway into edgeuse */
02380         struct edgeuse  *eu;
02381 
02382         NMG_CK_EDGE_G_EITHER(eg);
02383         (void)bu_ptbl_init( tab, 64, " tab");
02384 
02385         for( BU_LIST_FOR( midway, bu_list, &eg->eu_hd2 ) )  {
02386                 NMG_CKMAG(midway, NMG_EDGEUSE2_MAGIC, "edgeuse2 [l2]");
02387                 eu = BU_LIST_MAIN_PTR( edgeuse, midway, l2 );
02388                 NMG_CK_EDGEUSE(eu);
02389                 if( eu->g.lseg_p != eg )  rt_bomb("nmg_edgeuse_with_eg_tabulate() eu disavows eg\n");
02390                 bu_ptbl_ins_unique( tab, (long *)eu );
02391         }
02392 }
02393 
02394 struct edge_line_state {
02395         char                    *visited;
02396         struct bu_ptbl          *tabl;
02397         point_t                 pt;
02398         vect_t                  dir;
02399         struct bn_tol           tol;
02400 };
02401 
02402 /**
02403  *                      N M G _ L I N E _ H A N D L E R
02404  *
02405  *  A private support routine for nmg_edgeuse_on_line_tabulate.
02406  *  Having just visited an edgeuse, if this is the first time,
02407  *  and both vertices of this edgeuse lie within tol of the line,
02408  *  add it to the bu_ptbl array.
02409  */
02410 static void
02411 nmg_line_handler(long int *longp, genptr_t state, int first)
02412 {
02413         register struct edge_line_state *sp = (struct edge_line_state *)state;
02414         register struct edgeuse *eu = (struct edgeuse *)longp;
02415 
02416         NMG_CK_EDGEUSE(eu);
02417         /* If this edgeuse has been processed before, do nothing more */
02418         if( !NMG_INDEX_FIRST_TIME(sp->visited, eu) )  return;
02419 
02420         /*  If the lines are not generally parallel, don't bother with
02421          *  checking the endpoints.  This helps reject very short edges
02422          *  which are colinear only by virtue of being very small.
02423          */
02424         BN_CK_TOL(&sp->tol);
02425         NMG_CK_EDGE_G_LSEG(eu->g.lseg_p);
02426 
02427         /* sp->tol.para and RT_DOT_TOL are too tight. 0.1 is 5 degrees */
02428         /* These are not unit vectors. */
02429         if( fabs( VDOT( eu->g.lseg_p->e_dir, sp->dir ) ) <
02430             0.9 * MAGNITUDE(eu->g.lseg_p->e_dir) * MAGNITUDE(sp->dir) )
02431                 return;
02432 
02433         if( bn_distsq_line3_pt3( sp->pt, sp->dir, eu->vu_p->v_p->vg_p->coord )
02434             > sp->tol.dist_sq )
02435                 return;
02436         if( bn_distsq_line3_pt3( sp->pt, sp->dir, eu->eumate_p->vu_p->v_p->vg_p->coord )
02437             > sp->tol.dist_sq )
02438                 return;
02439 
02440         /* Both points are within tolerance, add edgeuse to the list */
02441         bu_ptbl_ins( sp->tabl, longp );
02442 }
02443 
02444 /**
02445  *                      N M G _ E D G E U S E _ O N _ L I N E _ T A B U L A T E
02446  *
02447  *  Given a pointer to any nmg data structure,
02448  *  build an bu_ptbl list which cites every edgeuse
02449  *  pointer from there on "down" in the model
02450  *  that has both vertices within tolerance of the given line.
02451  *
02452  *  XXX This routine is a potential source of major trouble.
02453  *  XXX If there are "nearby" edges that "should" be on the list but
02454  *  XXX don't make it, then the intersection calculations might
02455  *  XXX miss important intersections.
02456  *  As an admittedly grubby workaround, use 10X the distance tol here,
02457  *  just to get more candidates onto the list.
02458  *  The caller will have to wrestle with the added fuzz.
02459  */
02460 void
02461 nmg_edgeuse_on_line_tabulate(struct bu_ptbl *tab, const long int *magic_p, const fastf_t *pt, const fastf_t *dir, const struct bn_tol *tol)
02462 {
02463         struct model            *m;
02464         struct edge_line_state          st;
02465         static const struct nmg_visit_handlers  handlers = {NULL, NULL, NULL, NULL, NULL,
02466                                                             NULL, NULL, NULL, NULL, NULL,
02467                                                             NULL, NULL, NULL, NULL, NULL,
02468                                                             NULL, nmg_line_handler, NULL, NULL, NULL,
02469                                                             NULL, NULL, NULL, NULL, NULL};
02470         /* handlers.bef_edgeuse = nmg_line_handler; */
02471 
02472         m = nmg_find_model( magic_p );
02473         NMG_CK_MODEL(m);
02474         BN_CK_TOL(tol);
02475 
02476         st.visited = (char *)bu_calloc(m->maxindex+1, sizeof(char), "visited[]");
02477         st.tabl = tab;
02478         VMOVE( st.pt, pt );
02479         VMOVE( st.dir, dir );
02480 
02481         st.tol = *tol;                                  /* struct copy */
02482 #if 0
02483         /* Use larger tolerance */
02484         st.tol.dist = 10 * tol->dist;
02485         st.tol.dist_sq = st.tol.dist * st.tol.dist;
02486 #endif
02487 
02488         (void)bu_ptbl_init( tab, 64, " tab");
02489 
02490         nmg_visit( magic_p, &handlers, (genptr_t)&st );
02491 
02492         bu_free( (char *)st.visited, "visited[]");
02493 }
02494 
02495 struct e_and_v_state  {
02496         char            *visited;
02497         struct bu_ptbl  *edges;
02498         struct bu_ptbl  *verts;
02499 };
02500 
02501 /**
02502  *                      N M G _ E _ H A N D L E R
02503  *
02504  *  A private support routine for nmg_e_and_v_tabulate().
02505  *
02506  *  Note that an edgeUSE is put on the list, to save one memory dereference
02507  *  in the eventual application.
02508  */
02509 static void
02510 nmg_e_handler(long int *longp, genptr_t state, int first)
02511 {
02512         register struct e_and_v_state   *sp = (struct e_and_v_state *)state;
02513         register struct edge            *e  = (struct edge *)longp;
02514 
02515         NMG_CK_EDGE(e);
02516         /* If this edge has been processed before, do nothing more */
02517         if( !NMG_INDEX_FIRST_TIME(sp->visited, e) )  return;
02518 
02519         /* Add to list */
02520         bu_ptbl_ins( sp->edges, (long *)e->eu_p );
02521 }
02522 
02523 /**
02524  *                      N M G _ V _ H A N D L E R
02525  *
02526  *  A private support routine for nmg_e_and_v_tabulate().
02527  */
02528 static void
02529 nmg_v_handler(long int *longp, genptr_t state, int first)
02530 {
02531         register struct e_and_v_state   *sp = (struct e_and_v_state *)state;
02532         register struct vertex          *v  = (struct vertex *)longp;
02533 
02534         NMG_CK_VERTEX(v);
02535         /* If this vertex has been processed before, do nothing more */
02536         if( !NMG_INDEX_FIRST_TIME(sp->visited, v) )  return;
02537 
02538         /* Add to list */
02539         bu_ptbl_ins( sp->verts, longp );
02540 }
02541 
02542 /**
02543  *                      N M G _ E _ A N D _ V _ T A B U L A T E
02544  *
02545  *  Build lists of all edges (represented by one edgeuse on that edge)
02546  *  and all vertices found underneath the
02547  *  NMG entity indicated by magic_p.
02548  */
02549 void
02550 nmg_e_and_v_tabulate(struct bu_ptbl *eutab, struct bu_ptbl *vtab, const long int *magic_p)
02551 {
02552         struct model                    *m;
02553         struct e_and_v_state            st;
02554         static const struct nmg_visit_handlers  handlers = {NULL, NULL, NULL, NULL, NULL,
02555                                                             NULL, NULL, NULL, NULL, NULL,
02556                                                             NULL, NULL, NULL, NULL, NULL,
02557                                                             NULL, NULL, NULL, nmg_e_handler, NULL,
02558                                                             NULL, NULL, NULL, nmg_v_handler, NULL};
02559         /* handlers.vis_edge = nmg_e_handler; */
02560         /* handlers.vis_vertex = nmg_v_handler; */
02561 
02562         m = nmg_find_model( magic_p );
02563         NMG_CK_MODEL(m);
02564 
02565         st.visited = (char *)bu_calloc(m->maxindex+1, sizeof(char), "visited[]");
02566         st.edges = eutab;
02567         st.verts = vtab;
02568 
02569         (void)bu_ptbl_init( eutab, 64, " eutab");
02570         (void)bu_ptbl_init( vtab, 64, " vtab");
02571 
02572         nmg_visit( magic_p, &handlers, (genptr_t)&st );
02573 
02574         bu_free( (char *)st.visited, "visited[]");
02575 }
02576 
02577 /**
02578  *                      N M G _ 2 E D G E U S E _ G _ C O I N C I D E N T
02579  *
02580  *  Given two edgeuses, determine if they share the same edge geometry,
02581  *  either topologically, or within tolerance.
02582  *
02583  *  Returns -
02584  *      0       two edge geometries are not coincident
02585  *      1       edges geometries are everywhere coincident.
02586  *              (For linear edge_g_lseg, the 2 are the same line, within tol.)
02587  */
02588 int
02589 nmg_2edgeuse_g_coincident(const struct edgeuse *eu1, const struct edgeuse *eu2, const struct bn_tol *tol)
02590 {
02591         struct edge_g_lseg      *eg1;
02592         struct edge_g_lseg      *eg2;
02593 
02594         NMG_CK_EDGEUSE(eu1);
02595         NMG_CK_EDGEUSE(eu2);
02596         BN_CK_TOL(tol);
02597 
02598         eg1 = eu1->g.lseg_p;
02599         eg2 = eu2->g.lseg_p;
02600         NMG_CK_EDGE_G_LSEG(eg1);
02601         NMG_CK_EDGE_G_LSEG(eg2);
02602 
02603         if( eg1 == eg2 )  return 1;
02604 
02605         /* Ensure direction vectors are generally parallel */
02606         /* These are not unit vectors */
02607         /* tol->para and RT_DOT_TOL are too tight a tolerance.  0.1 is 5 degrees */
02608         if( fabs(VDOT(eg1->e_dir, eg2->e_dir)) <
02609             0.9 * MAGNITUDE(eg1->e_dir) * MAGNITUDE(eg2->e_dir)  )  return 0;
02610 
02611         /* Ensure that vertices on edge 2 are within tol of e1 */
02612         if( bn_distsq_line3_pt3( eg1->e_pt, eg1->e_dir,
02613             eu2->vu_p->v_p->vg_p->coord ) > tol->dist_sq )  goto trouble;
02614         if( bn_distsq_line3_pt3( eg1->e_pt, eg1->e_dir,
02615             eu2->eumate_p->vu_p->v_p->vg_p->coord ) > tol->dist_sq )  goto trouble;
02616 
02617         /* Ensure that vertices of both edges are within tol of other eg */
02618         if( bn_distsq_line3_pt3( eg2->e_pt, eg2->e_dir,
02619             eu1->vu_p->v_p->vg_p->coord ) > tol->dist_sq )  goto trouble;
02620         if( bn_distsq_line3_pt3( eg2->e_pt, eg2->e_dir,
02621             eu1->eumate_p->vu_p->v_p->vg_p->coord ) > tol->dist_sq )  goto trouble;
02622 
02623         /* Perhaps check for ultra-short edges (< 10*tol->dist)? */
02624 
02625         /* Do not use bn_isect_line3_line3() -- it's MUCH too strict */
02626 
02627         return 1;
02628 trouble:
02629         if( !bn_2line3_colinear( eg1->e_pt, eg1->e_dir, eg2->e_pt, eg2->e_dir,
02630              1e5, tol ) )
02631                 return 0;
02632 
02633         /* XXX debug */
02634         nmg_pr_eg( &eg1->l.magic, 0 );
02635         nmg_pr_eg( &eg2->l.magic, 0 );
02636         bu_log("nmg_2edgeuse_g_coincident() lines colinear, vertex check fails, calling colinear anyway.\n");
02637         return 1;
02638 }
02639 
02640 /*
02641  * Local Variables:
02642  * mode: C
02643  * tab-width: 8
02644  * c-basic-offset: 4
02645  * indent-tabs-mode: t
02646  * End:
02647  * ex: shiftwidth=4 tabstop=8
02648  */

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