nmg_inter.c

Go to the documentation of this file.
00001 /*                     N M G _ I N T E R . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1994-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup nmg */
00023 
00024 /*@{*/
00025 /** @file nmg_inter.c
00026  *  Routines to intersect two NMG regions.  When complete, all loops
00027  *  in each region have a single classification w.r.t. the other region,
00028  *  i.e. all geometric intersections of the two regions have explicit
00029  *  topological representations.
00030  *
00031  *  The intersector makes sure that all geometric intersections gets
00032  *  recorded with explicit geometry and topology that is shared between both
00033  *  regions. Primary examples of this are (a) the line of intersection
00034  *  between two planes (faces), and (b) the point of intersection where two
00035  *  edges cross.
00036  *
00037  *  Entities of one region that are INSIDE, but not ON the other region
00038  *  do not become shared during the intersection process.
00039  *
00040  *  All point -vs- point comparisons should be done in 3D, for consistency.
00041  *
00042  *  Method -
00043  *
00044  *      Find all the points of intersection between the two regions, and
00045  *      insert vertices at those points, breaking edges on those new
00046  *      vertices as appropriate.
00047  *
00048  *      Call the face cutter to construct and delete edges and loops
00049  *      along the line of intersection, as appropriate.
00050  *
00051  *      There are no "user interface" routines in here.
00052  *
00053  *  Authors -
00054  *      Michael John Muuss
00055  *      Lee A. Butler
00056  *
00057  *  Source -
00058  *      The U. S. Army Research Laboratory
00059  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00060  */
00061 /*@}*/
00062 
00063 #ifndef lint
00064 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_inter.c,v 14.13 2006/09/16 02:04:25 lbutler Exp $ (ARL)";
00065 #endif
00066 
00067 #include "common.h"
00068 
00069 #include <stddef.h>
00070 #include <stdio.h>
00071 #include <math.h>
00072 #include <string.h>
00073 
00074 #include "machine.h"
00075 #include "vmath.h"
00076 #include "nmg.h"
00077 #include "raytrace.h"
00078 #include "./debug.h"
00079 #include "plot3.h"
00080 
00081 #define ISECT_NONE      0
00082 #define ISECT_SHARED_V  1
00083 #define ISECT_SPLIT1    2
00084 #define ISECT_SPLIT2    4
00085 
00086 struct ee_2d_state {
00087         struct nmg_inter_struct *is;
00088         struct edgeuse  *eu;
00089         point_t start;
00090         point_t end;
00091         vect_t  dir;
00092 };
00093 
00094 
00095 static int      nmg_isect_edge2p_face2p BU_ARGS((struct nmg_inter_struct *is,
00096                         struct edgeuse *eu, struct faceuse *fu,
00097                         struct faceuse *eu_fu));
00098 
00099 
00100 static struct nmg_inter_struct  *nmg_hack_last_is;      /* see nmg_isect2d_final_cleanup() */
00101 
00102 /*
00103  */
00104 struct vertexuse *
00105 nmg_make_dualvu(struct vertex *v, struct faceuse *fu, const struct bn_tol *tol)
00106 {
00107         struct loopuse *lu;
00108         struct vertexuse *dualvu;
00109         struct edgeuse *new_eu;
00110 
00111         NMG_CK_VERTEX( v );
00112         NMG_CK_FACEUSE( fu );
00113         BN_CK_TOL( tol );
00114 
00115         if (rt_g.NMG_debug & DEBUG_POLYSECT)
00116                 bu_log( "nmg_make_dualvu( v=x%x, fu=x%x )\n", v, fu );
00117 
00118         /* check for existing vu */
00119         if(  (dualvu=nmg_find_v_in_face( v, fu ))  )
00120         {
00121                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
00122                         bu_log( "\tdualvu already exists (x%x)\n", dualvu );
00123                 return( dualvu );
00124         }
00125 
00126         new_eu = (struct edgeuse *)NULL;
00127 
00128         /* check if v lies within tolerance of an edge in face */
00129         if (rt_g.NMG_debug & DEBUG_POLYSECT)
00130                 bu_log( "\tLooking for an edge to split\n" );
00131         for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )
00132         {
00133                 struct edgeuse *eu;
00134 
00135                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
00136                         continue;
00137 
00138                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
00139                 {
00140                         int code;
00141                         fastf_t   dist;
00142                         point_t pca;
00143 
00144                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
00145                                 bu_log( "\tChecking eu x%x (%f %f %f) <-> (%f %f %f)\n",
00146                                         eu,
00147                                         V3ARGS( eu->vu_p->v_p->vg_p->coord ),
00148                                         V3ARGS( eu->eumate_p->vu_p->v_p->vg_p->coord ) );
00149 
00150                         code = bn_dist_pt3_lseg3( &dist, pca,
00151                                 eu->vu_p->v_p->vg_p->coord,
00152                                 eu->eumate_p->vu_p->v_p->vg_p->coord,
00153                                 v->vg_p->coord, tol );
00154 
00155                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
00156                                 bu_log( "bn_dist_pt3_lseg3 returns %d, dist=%f\n", code, dist );
00157 
00158                         if( code > 2 )
00159                                 continue;
00160 
00161                         /* v is within tolerance of eu */
00162                         if( code > 0 )
00163                                 continue;
00164 
00165                         /* split edge */
00166                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
00167                                 bu_log( "nmg_make_dualvu is splitting eu x%x at v x%x\n", eu, v );
00168                         new_eu = nmg_esplit( v, eu, 1 );
00169                 }
00170         }
00171 
00172         if( new_eu )
00173                 return( new_eu->vu_p );
00174 
00175         /* need a self loop  */
00176         lu = nmg_mlv( &fu->l.magic, v, OT_BOOLPLACE );
00177         if (rt_g.NMG_debug & DEBUG_POLYSECT)
00178                 bu_log( "nmg_make_dualvu is makeing a self_loop (lu=x%x, vu=x%x) for v=x%x\n", lu, BU_LIST_FIRST( vertexuse, &lu->down_hd ), v );
00179         nmg_loop_g( lu->l_p, tol );
00180         return( BU_LIST_FIRST( vertexuse, &lu->down_hd ) );
00181 }
00182 
00183 /**
00184  *                      N M G _ E N L I S T _ V U
00185  *
00186  *  Given a vu which represents a point of intersection between shells
00187  *  s1 and s2, insert it and it's dual into lists l1 and l2.
00188  *  First, determine whether the vu came from s1 or s2, and insert in
00189  *  the corresponding list.
00190  *
00191  *  Second, try and find a dual of that vertex
00192  *  in the other shell's faceuse (fu1 or fu2)
00193  *  (if the entity in the other shell is not a wire), and enlist the dual.
00194  *  If there is no dual, make a self-loop over there, and enlist that.
00195  *
00196  *  If 'dualvu' is provided, don't search, just use that.
00197  *
00198  *  While it is true that in most cases the calling routine will know
00199  *  which shell the vu came from, it's cheap to re-determine it here.
00200  *  This "all in one" packaging, which handles both lists automaticly
00201  *  is *vastly* superior to the previous version, which pushed 10-20
00202  *  lines of bookkeeping up into *every* place an intersection vu was
00203  *  created.
00204  *
00205  *  Returns a pointer to vu's dual.
00206  *
00207  *  "Join the Army, young vertexuse".
00208  */
00209 struct vertexuse *
00210 nmg_enlist_vu(struct nmg_inter_struct *is, const struct vertexuse *vu, struct vertexuse *dualvu, fastf_t dist)
00211 
00212 
00213                                                 /* vu's dual in other shell.  May be NULL */
00214                                                 /* distance along intersect ray for this vu */
00215 {
00216         struct shell            *sv;            /* shell of vu */
00217         struct loopuse          *lu;            /* lu of new self-loop */
00218         struct faceuse          *dualfu = (struct faceuse *)NULL; /* faceuse of vu's dual */
00219         struct shell            *duals = (struct shell *)NULL;  /* shell of vu's dual */
00220         struct faceuse          *fuv;           /* faceuse of vu */
00221 
00222         NMG_CK_INTER_STRUCT(is);
00223         NMG_CK_VERTEXUSE(vu);
00224         if(dualvu)  {
00225                 NMG_CK_VERTEXUSE(dualvu);
00226                 if( vu == dualvu )  rt_bomb("nmg_enlist_vu() vu == dualvu\n");
00227         }
00228 
00229         if( is->mag_len <= BU_PTBL_END( is->l1 ) || is->mag_len <= BU_PTBL_END( is->l2 ) )
00230                 bu_log( "Array for distances to vertexuses is too small (%d)\n" , is->mag_len );
00231 
00232 #if 0
00233         /* Check the geometry */
00234         if( bn_distsq_line3_pt3(is->pt, is->dir, vu->v_p->vg_p->coord) > is->tol.dist_sq )  {
00235                 bu_log("nmg_enlist_vu() WARNING: vu=x%x, v=x%x not within tolerance of intersect line\n",
00236                         vu, vu->v_p);
00237         }
00238 #endif
00239 
00240         sv = nmg_find_s_of_vu( vu );
00241         fuv = nmg_find_fu_of_vu( vu );
00242 
00243         /* First step:  add vu to corresponding list */
00244         if( sv == is->s1 )  {
00245                 bu_ptbl_ins_unique( is->l1, (long *)&vu->l.magic );
00246                 if( is->mag_len <= BU_PTBL_END( is->l1 ) )
00247                 {
00248                         if( is->mag_len )
00249                         {
00250                                 is->mag_len *= 2;
00251                                 is->mag1 = (fastf_t *)rt_realloc( (char *)is->mag1, is->mag_len*sizeof( fastf_t),
00252                                         "is->mag1" );
00253                                 is->mag2 = (fastf_t *)rt_realloc( (char *)is->mag2, is->mag_len*sizeof( fastf_t),
00254                                         "is->mag2" );
00255                         }
00256                         else
00257                         {
00258                                 is->mag_len = 2*(BU_PTBL_END( is->l1 ) + BU_PTBL_END( is->l2 ));
00259                                 is->mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag1" );
00260                                 is->mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag2" );
00261                         }
00262 
00263                 }
00264                 if( dist < MAX_FASTF )
00265                         is->mag1[bu_ptbl_locate( is->l1, (long *)&vu->l.magic )] = dist;
00266                 duals = is->s2;         /* other shell */
00267                 dualfu = is->fu2;
00268                 if( is->fu1 && is->fu1->s_p != is->s1 ) rt_bomb("nmg_enlist_vu() fu1/s1 mismatch\n");
00269                 if( fuv != is->fu1 )  {
00270                         bu_log("fuv=x%x, fu1=x%x, fu2=x%x\n", fuv, is->fu1, is->fu2);
00271                         bu_log( "\tvu=x%x (x%x)\n", vu, vu->v_p );
00272                         rt_bomb("nmg_enlist_vu() vu/fu1 mis-match\n");
00273                 }
00274         } else if( sv == is->s2 )  {
00275                 bu_ptbl_ins_unique( is->l2, (long *)&vu->l.magic );
00276                 if( is->mag_len <= BU_PTBL_END( is->l2 ) )
00277                 {
00278                         if( is->mag_len )
00279                         {
00280                                 is->mag_len *= 2;
00281                                 is->mag1 = (fastf_t *)rt_realloc( (char *)is->mag1, is->mag_len*sizeof( fastf_t),
00282                                         "is->mag1" );
00283                                 is->mag2 = (fastf_t *)rt_realloc( (char *)is->mag2, is->mag_len*sizeof( fastf_t),
00284                                         "is->mag2" );
00285                         }
00286                         else
00287                         {
00288                                 is->mag_len = 2*(BU_PTBL_END( is->l1 ) + BU_PTBL_END( is->l2 ));
00289                                 is->mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag1" );
00290                                 is->mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag2" );
00291                         }
00292 
00293                 }
00294                 if( dist < MAX_FASTF )
00295                         is->mag2[bu_ptbl_locate( is->l2, (long *)&vu->l.magic )] = dist;
00296                 duals = is->s1;         /* other shell */
00297                 dualfu = is->fu1;
00298                 if( is->fu2 && is->fu2->s_p != is->s2 ) rt_bomb("nmg_enlist_vu() fu2/s2 mismatch\n");
00299                 if( fuv != is->fu2 )  {
00300                         bu_log("fuv=x%x, fu1=x%x, fu2=x%x\n", fuv, is->fu1, is->fu2);
00301                         bu_log( "\tvu=x%x (x%x)\n", vu, vu->v_p );
00302                         rt_bomb("nmg_enlist_vu() vu/fu2 mis-match\n");
00303                 }
00304         } else {
00305                 bu_log("nmg_enlist_vu(vu=x%x,dv=x%x) sv=x%x, s1=x%x, s2=x%x\n",
00306                         vu, dualvu, sv, is->s1, is->s2 );
00307                 rt_bomb("nmg_enlist_vu: vu is not in s1 or s2\n");
00308         }
00309 
00310         if( dualvu )  {
00311                 if( vu->v_p != dualvu->v_p )  rt_bomb("nmg_enlist_vu() dual vu has different vertex\n");
00312                 if( nmg_find_s_of_vu(dualvu) != duals )  {
00313                         bu_log("nmg_enlist_vu(vu=x%x,dv=x%x) sv=x%x, s1=x%x, s2=x%x, sdual=x%x\n",
00314                                 vu, dualvu,
00315                                 sv, is->s1, is->s2, nmg_find_s_of_vu(dualvu) );
00316                         rt_bomb("nmg_enlist_vu() dual vu shell mis-match\n");
00317                 }
00318                 if( dualfu && nmg_find_fu_of_vu(dualvu) != dualfu) rt_bomb("nmg_enlist_vu() dual vu has wrong fu\n");
00319         }
00320 
00321         /* Second, search for vu's dual */
00322         if( dualfu )  {
00323                 NMG_CK_FACEUSE(dualfu);
00324                 if( dualfu->s_p != duals )  rt_bomb("nmg_enlist_vu() dual fu's shell is not dual's shell?\n");
00325                 if( !dualvu )
00326                         dualvu = nmg_make_dualvu( vu->v_p, dualfu, &(is->tol) );
00327                 else {
00328                         if( rt_g.NMG_debug & DEBUG_POLYSECT )  {
00329                                 bu_log("nmg_enlist_vu(vu=x%x,dv=x%x) re-using dualvu=x%x from dualfu=x%x\n",
00330                                         vu, dualvu,
00331                                         dualvu, dualfu);
00332                         }
00333                 }
00334         } else {
00335                 /* Must have come from a wire in other shell, make wire loop */
00336                 bu_log("\tvu=x%x, %s, fu1=x%x, fu2=x%x\n", vu, (sv==is->s1)?"shell 1":"shell 2", is->fu1, is->fu2);
00337                 bu_log("nmg_enlist_vu(): QUESTION: What do I search for wire intersections?  Making self-loop\n");
00338                 if( !dualvu && !(dualvu = nmg_find_v_in_shell( vu->v_p, duals, 0 )) )  {
00339                         /* Not found, make self-loop in dual shell */
00340                         lu = nmg_mlv( &duals->l.magic, vu->v_p, OT_BOOLPLACE );
00341                         nmg_loop_g( lu->l_p, &(is->tol) );
00342                         dualvu = BU_LIST_FIRST( vertexuse, &lu->down_hd );
00343                 } else {
00344                         if( rt_g.NMG_debug & DEBUG_POLYSECT )  {
00345                                 bu_log("nmg_enlist_vu(vu=x%x) re-using dualvu=x%x from dualshell=x%x\n",
00346                                         vu,
00347                                         dualvu, duals);
00348                         }
00349                 }
00350         }
00351         NMG_CK_VERTEXUSE(dualvu);
00352 
00353         /* Enlist the dual onto the other list */
00354         if( sv == is->s1 )  {
00355                 bu_ptbl_ins_unique( is->l2, (long *)&dualvu->l.magic );
00356                 if( is->mag_len <= BU_PTBL_END( is->l2 ) )
00357                 {
00358                         if( is->mag_len )
00359                         {
00360                                 is->mag_len *= 2;
00361                                 is->mag1 = (fastf_t *)rt_realloc( (char *)is->mag1, is->mag_len*sizeof( fastf_t),
00362                                         "is->mag1" );
00363                                 is->mag2 = (fastf_t *)rt_realloc( (char *)is->mag2, is->mag_len*sizeof( fastf_t),
00364                                         "is->mag2" );
00365                         }
00366                         else
00367                         {
00368                                 is->mag_len = 2*(BU_PTBL_END( is->l1 ) + BU_PTBL_END( is->l2 ));
00369                                 is->mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag1" );
00370                                 is->mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag2" );
00371                         }
00372 
00373                 }
00374                 if( dist < MAX_FASTF )
00375                         is->mag2[bu_ptbl_locate( is->l2, (long *)&dualvu->l.magic )] = dist;
00376         } else {
00377                 bu_ptbl_ins_unique( is->l1, (long *)&dualvu->l.magic );
00378                 if( is->mag_len <= BU_PTBL_END( is->l1 ) )
00379                 {
00380                         if( is->mag_len )
00381                         {
00382                                 is->mag_len *= 2;
00383                                 is->mag1 = (fastf_t *)rt_realloc( (char *)is->mag1, is->mag_len*sizeof( fastf_t),
00384                                         "is->mag1" );
00385                                 is->mag2 = (fastf_t *)rt_realloc( (char *)is->mag2, is->mag_len*sizeof( fastf_t),
00386                                         "is->mag2" );
00387                         }
00388                         else
00389                         {
00390                                 is->mag_len = 2*(BU_PTBL_END( is->l1 ) + BU_PTBL_END( is->l2 ));
00391                                 is->mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag1" );
00392                                 is->mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag2" );
00393                         }
00394 
00395                 }
00396                 if( dist < MAX_FASTF )
00397                         is->mag1[bu_ptbl_locate( is->l1, (long *)&dualvu->l.magic )] = dist;
00398         }
00399 
00400         if( rt_g.NMG_debug & DEBUG_POLYSECT )  {
00401                 bu_log("nmg_enlist_vu(vu=x%x,dv=x%x) v=x%x, dist=%g (%s) ret=x%x\n",
00402                         vu, dualvu, vu->v_p, dist,
00403                         (sv == is->s1) ? "shell 1" : "shell 2",
00404                         dualvu );
00405         }
00406 
00407         /* Some (expensive) centralized sanity checking */
00408         if( (rt_g.NMG_debug & DEBUG_VERIFY) && is->fu1 && is->fu2 )  {
00409                 nmg_ck_v_in_2fus(vu->v_p, is->fu1, is->fu2, &(is->tol));
00410         }
00411         return dualvu;
00412 }
00413 
00414 /**
00415  *                      N M G _ G E T _ 2 D _ V E R T E X
00416  *
00417  *  A "lazy evaluator" to obtain the 2D projection of a vertex.
00418  *  The lazy approach is not a luxury, since new (3D) vertices are created
00419  *  as the edge/edge intersection proceeds, and their 2D coordinates may
00420  *  be needed later on in the calculation.
00421  *  The alternative would be to store the 2D projection each time a
00422  *  new vertex is created, but that is likely to be a lot of bothersome
00423  *  code, where one omission would be deadly.
00424  *
00425  *  The return is a 3-tuple, with the Z coordinate set to 0.0 for safety.
00426  *  This is especially useful when the projected value is printed using
00427  *  one of the 3D print routines.
00428  *
00429  *  'assoc_use' is either a pointer to a faceuse, or an edgeuse.
00430  */
00431 static void
00432 nmg_get_2d_vertex(fastf_t *v2d, struct vertex *v, struct nmg_inter_struct *is, const long int *assoc_use)
00433                                         /* a 3-tuple */
00434 
00435 
00436                                         /* ptr to faceuse/edgeuse associated w/2d projection */
00437 {
00438         register fastf_t        *pt2d;
00439         point_t                 pt;
00440         struct vertex_g         *vg;
00441         long                    *this;
00442 
00443         NMG_CK_INTER_STRUCT(is);
00444         NMG_CK_VERTEX(v);
00445 
00446         /* If 2D preparations have not been made yet, do it now */
00447         if( !is->vert2d )  {
00448                 nmg_isect2d_prep( is, assoc_use );
00449         }
00450 
00451         if( *assoc_use == NMG_FACEUSE_MAGIC )  {
00452                 this = &((struct faceuse *)assoc_use)->f_p->l.magic;
00453                 if( this != is->twod )
00454                         goto bad;
00455         } else if ( *assoc_use == NMG_EDGEUSE_MAGIC )  {
00456                 this = &((struct edgeuse *)assoc_use)->e_p->magic;
00457                 if( this != is->twod )
00458                         goto bad;
00459         } else {
00460                 this = (long *)NULL;
00461 bad:
00462                 bu_log("nmg_get_2d_vertex(,assoc_use=%x %s) this=x%x %s, is->twod=%x %s\n",
00463                         assoc_use, bu_identify_magic(*assoc_use),
00464                         this, bu_identify_magic(*this),
00465                         is->twod, bu_identify_magic(*(is->twod)) );
00466                 rt_bomb("nmg_get_2d_vertex:  2d association mis-match\n");
00467         }
00468 
00469         if( !v->vg_p )  {
00470                 bu_log("nmg_get_2d_vertex: v=x%x, assoc_use=x%x, null vg_p\n",
00471                         v, assoc_use);
00472                 rt_bomb("nmg_get_2d_vertex:  vertex with no geometry!\n");
00473         }
00474         vg = v->vg_p;
00475         NMG_CK_VERTEX_G(vg);
00476         if( v->index >= is->maxindex )  {
00477                 struct model    *m;
00478                 int             oldmax;
00479                 register int    i;
00480 
00481                 oldmax = is->maxindex;
00482                 m = nmg_find_model(&v->magic);
00483                 NMG_CK_MODEL(m);
00484                 bu_log("nmg_get_2d_vertex:  v=x%x, v->index=%d, is->maxindex=%d, m->maxindex=%d\n",
00485                         v, v->index, is->maxindex, m->maxindex );
00486                 if( v->index >= m->maxindex )  {
00487                         /* Really off the end */
00488                         VPRINT("3d vertex", vg->coord);
00489                         rt_bomb("nmg_get_2d_vertex:  array overrun\n");
00490                 }
00491                 /* Need to extend array, it's grown. */
00492                 is->maxindex = m->maxindex * 4;
00493                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
00494                         bu_log("nmg_get_2d_vertex() extending vert2d array from %d to %d points (m max=%d)\n",
00495                                 oldmax, is->maxindex, m->maxindex);
00496                 }
00497                 is->vert2d = (fastf_t *)rt_realloc( (char *)is->vert2d,
00498                         is->maxindex * 3 * sizeof(fastf_t), "vert2d[]");
00499 
00500                 /* Clear out the new part of the 2D vertex array, setting flag in [2] to -1 */
00501                 for( i = (3*is->maxindex)-1-2; i >= oldmax*3; i -= 3 )  {
00502                         VSET( &is->vert2d[i], 0, 0, -1 );
00503                 }
00504         }
00505         pt2d = &is->vert2d[v->index*3];
00506         if( pt2d[2] == 0 )  {
00507                 /* Flag set.  Conversion is done.  Been here before */
00508                 v2d[0] = pt2d[0];
00509                 v2d[1] = pt2d[1];
00510                 v2d[2] = 0;
00511                 return;
00512         }
00513 
00514         MAT4X3PNT( pt, is->proj, vg->coord );
00515         v2d[0] = pt2d[0] = pt[0];
00516         v2d[1] = pt2d[1] = pt[1];
00517         v2d[2] = pt2d[2] = 0;           /* flag */
00518 
00519         if( !NEAR_ZERO( pt[2], is->tol.dist ) )  {
00520                 struct faceuse  *fu = (struct faceuse *)assoc_use;
00521                 plane_t n;
00522                 fastf_t dist;
00523                 NMG_GET_FU_PLANE( n, fu );
00524                 dist = DIST_PT_PLANE(vg->coord, n);
00525                 bu_log("nmg_get_2d_vertex ERROR #%d (%g %g %g) becomes (%g,%g)\n\t%g != zero, dist3d=%g, %g*tol\n",
00526                         v->index, V3ARGS(vg->coord), V3ARGS(pt),
00527                         dist, dist/is->tol.dist );
00528                 if( !NEAR_ZERO( dist, is->tol.dist ) &&
00529                     !NEAR_ZERO( pt[2], 10*is->tol.dist ) )  {
00530                         bu_log("nmg_get_2d_vertex(,assoc_use=%x) f=x%x, is->twod=%x\n",
00531                                 assoc_use, fu->f_p, is->twod);
00532                         PLPRINT("fu->f_p N", n);
00533                         rt_bomb("3D->2D point projection error\n");
00534                 }
00535         }
00536 
00537         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
00538                 bu_log("2d #%d (%g %g %g) becomes (%g,%g) %g\n",
00539                         v->index, V3ARGS(vg->coord), V3ARGS(pt) );
00540         }
00541 }
00542 
00543 /**
00544  *                      N M G _ I S E C T 2 D _ P R E P
00545  *
00546  *  To intersect two co-planar faces, project all vertices from those
00547  *  faces into 2D.
00548  *  At the moment, use a memory intensive strategy which allocates a
00549  *  (3d) point_t for each "index" item, and subscripts the resulting
00550  *  array by the vertices index number.
00551  *  Since additional vertices can be created as the intersection process
00552  *  operates, 2*maxindex items are originall allocated, as a (generous)
00553  *  upper bound on the amount of intersecting that might happen.
00554  *
00555  *  In the array, the third double of each projected vertex is set to -1 when
00556  *  that slot has not been filled yet, and 0 when it has been.
00557  */
00558 /* XXX Set this up so that it can take either an edge pointer
00559  * or a face pointer.  In case of edge, make edge_g_lseg->dir unit, and
00560  * rotate that to +X axis.  Make edge_g_lseg->pt be the origin.
00561  * This will allow the 2D routines to operate on wires.
00562  */
00563 void
00564 nmg_isect2d_prep(struct nmg_inter_struct *is, const long int *assoc_use)
00565 {
00566         struct model    *m;
00567         struct face_g_plane     *fg;
00568         vect_t          to;
00569         point_t         centroid;
00570         point_t         centroid_proj;
00571         plane_t         n;
00572         register int    i;
00573 
00574         NMG_CK_INTER_STRUCT(is);
00575 
00576         if( *assoc_use == NMG_FACEUSE_MAGIC )  {
00577                 if( &((struct faceuse *)assoc_use)->f_p->l.magic == is->twod )
00578                         return;         /* Already prepped */
00579         } else if( *assoc_use == NMG_EDGEUSE_MAGIC )  {
00580                 if( &((struct edgeuse *)assoc_use)->e_p->magic == is->twod )
00581                         return;         /* Already prepped */
00582         } else {
00583                 rt_bomb("nmg_isect2d_prep() bad assoc_use magic\n");
00584         }
00585 
00586         nmg_isect2d_cleanup(is);
00587         nmg_hack_last_is = is;
00588 
00589         m = nmg_find_model( assoc_use );
00590 
00591         is->maxindex = ( 2 * m->maxindex );
00592         is->vert2d = (fastf_t *)bu_malloc( is->maxindex * 3 * sizeof(fastf_t), "vert2d[]");
00593 
00594         if( *assoc_use == NMG_FACEUSE_MAGIC )  {
00595                 struct faceuse  *fu1 = (struct faceuse *)assoc_use;
00596                 struct face     *f1;
00597 
00598                 f1 = fu1->f_p;
00599                 fg = f1->g.plane_p;
00600                 NMG_CK_FACE_G_PLANE(fg);
00601                 is->twod = &f1->l.magic;
00602                 if( f1->flip )  {
00603                         VREVERSE( n, fg->N );
00604                         n[3] = -fg->N[3];
00605                 } else {
00606                         HMOVE( n, fg->N );
00607                 }
00608                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
00609                         bu_log("nmg_isect2d_prep(f=x%x) flip=%d\n", f1, f1->flip);
00610                         PLPRINT("N", n);
00611                 }
00612 
00613                 /*
00614                  *  Rotate so that f1's N vector points up +Z.
00615                  *  This places all 2D calcuations in the XY plane.
00616                  *  Translate so that f1's centroid becomes the 2D origin.
00617                  *  Reasoning:  no vertex should be favored by putting it at
00618                  *  the origin.  The "desirable" floating point space in the
00619                  *  vicinity of the origin should be used to best advantage,
00620                  *  by centering calculations around it.
00621                  */
00622                 VSET( to, 0, 0, 1 );
00623                 bn_mat_fromto( is->proj, n, to );
00624                 VADD2SCALE( centroid, f1->max_pt, f1->min_pt, 0.5 );
00625                 MAT4X3PNT( centroid_proj, is->proj, centroid );
00626                 centroid_proj[Z] = n[3];        /* pull dist from origin off newZ */
00627                 MAT_DELTAS_VEC_NEG( is->proj, centroid_proj );
00628         } else if( *assoc_use == NMG_EDGEUSE_MAGIC )  {
00629                 struct edgeuse  *eu1 = (struct edgeuse *)assoc_use;
00630                 struct edge     *e1;
00631                 struct edge_g_lseg      *eg;
00632 
00633                 bu_log("2d prep for edgeuse\n");
00634                 e1 = eu1->e_p;
00635                 NMG_CK_EDGE(e1);
00636                 eg = eu1->g.lseg_p;
00637                 NMG_CK_EDGE_G_LSEG(eg);
00638                 is->twod = &e1->magic;
00639 
00640                 /*
00641                  *  Rotate so that eg's eg_dir vector points up +X.
00642                  *  The choice of the other axes is arbitrary.
00643                  *  This ensures that all calculations happen on the XY plane.
00644                  *  Translate the edge start point to the origin.
00645                  */
00646                 VSET( to, 1, 0, 0 );
00647                 bn_mat_fromto( is->proj, eg->e_dir, to );
00648                 MAT_DELTAS_VEC_NEG( is->proj, eg->e_pt );
00649         } else {
00650                 rt_bomb("nmg_isect2d_prep() bad assoc_use magic\n");
00651         }
00652 
00653         /* Clear out the 2D vertex array, setting flag in [2] to -1 */
00654         for( i = (3*is->maxindex)-1-2; i >= 0; i -= 3 )  {
00655                 VSET( &is->vert2d[i], 0, 0, -1 );
00656         }
00657 }
00658 
00659 /**
00660  *                      N M G _ I S E C T 2 D _ C L E A N U P.
00661  *
00662  *  Common routine to zap 2d vertex cache, and release dynamic storage.
00663  */
00664 void
00665 nmg_isect2d_cleanup(struct nmg_inter_struct *is)
00666 {
00667         NMG_CK_INTER_STRUCT(is);
00668 
00669         nmg_hack_last_is = (struct nmg_inter_struct *)NULL;
00670 
00671         if( !is->vert2d )  return;
00672         bu_free( (char *)is->vert2d, "vert2d");
00673         is->vert2d = (fastf_t *)NULL;
00674         is->twod = (long *)NULL;
00675 }
00676 
00677 /**
00678  *                      N M G _ I S E C T 2 D _ F I N A L _ C L E A N U P
00679  *
00680  *  XXX Hack routine used for storage reclamation by G-JACK for
00681  *  XXX calculation of the reportcard without gobbling lots of memory
00682  *  XXX on rt_bomb() longjmp()s.
00683  *  Can be called by the longjmp handler with impunity.
00684  *  If a pointer to busy dynamic memory is still handy, it will be freed.
00685  *  If not, no harm done.
00686  */
00687 void
00688 nmg_isect2d_final_cleanup(void)
00689 {
00690         if( nmg_hack_last_is && nmg_hack_last_is->magic == NMG_INTER_STRUCT_MAGIC )
00691                 nmg_isect2d_cleanup( nmg_hack_last_is );
00692 }
00693 
00694 /**
00695  *                      N M G _ I S E C T _ V E R T 2 P _ F A C E 2 P
00696  *
00697  *  Handle the complete intersection of a vertex which lies on the
00698  *  plane of a face.  *every* intersection is performed.
00699  *
00700  *  If already part of the topology of the face, do nothing more.
00701  *  If it intersects one of the edges of the face, break the edge there.
00702  *  Otherwise, add a self-loop into the face as a marker.
00703  *
00704  *  All vertexuse pairs are enlisted on the intersection line.
00705  *  Assuming that there is one (is->l1 non null).
00706  *
00707  *  Called by -
00708  *      nmg_isect_3vertex_3face()
00709  *      nmg_isect_two_face2p()
00710  */
00711 void
00712 nmg_isect_vert2p_face2p(struct nmg_inter_struct *is, struct vertexuse *vu1, struct faceuse *fu2)
00713 {
00714         struct vertexuse        *vu2;
00715         struct loopuse   *lu2;
00716         pointp_t        pt;
00717         int             ret = 0;
00718 
00719         if (rt_g.NMG_debug & DEBUG_POLYSECT)
00720                 bu_log("nmg_isect_vert2p_face2p(, vu1=x%x, fu2=x%x)\n", vu1, fu2);
00721         NMG_CK_INTER_STRUCT(is);
00722         NMG_CK_VERTEXUSE(vu1);
00723         NMG_CK_FACEUSE(fu2);
00724 
00725         pt = vu1->v_p->vg_p->coord;
00726 
00727         /* Prep the 2D cache, if the face changed */
00728         nmg_isect2d_prep( is, &fu2->l.magic );
00729 
00730         /* For every edge and vert, check topo AND geometric intersection */
00731         for( BU_LIST_FOR( lu2, loopuse, &fu2->lu_hd ) )  {
00732                 struct edgeuse  *eu2;
00733 
00734                 NMG_CK_LOOPUSE(lu2);
00735                 if( BU_LIST_FIRST_MAGIC( &lu2->down_hd ) == NMG_VERTEXUSE_MAGIC )  {
00736                         vu2 = BU_LIST_FIRST( vertexuse, &lu2->down_hd );
00737                         if( vu1->v_p == vu2->v_p )  {
00738 
00739                                 if( is->l1 ) nmg_enlist_vu( is, vu1, vu2, MAX_FASTF );
00740                                 ret++;
00741                                 continue;
00742                         }
00743                         /* Use 3D comparisons for uniformity */
00744                         if( bn_pt3_pt3_equal( pt, vu2->v_p->vg_p->coord, &is->tol ) )  {
00745                                 /* Fuse the two verts together */
00746                                 nmg_jv( vu1->v_p, vu2->v_p );
00747                                 if( is->l1 ) nmg_enlist_vu( is, vu1, vu2, MAX_FASTF );
00748                                 ret++;
00749                                 continue;
00750                         }
00751                         continue;
00752                 }
00753                 for( BU_LIST_FOR( eu2, edgeuse, &lu2->down_hd ) )  {
00754                         struct edgeuse  *new_eu;
00755 
00756                         if( eu2->vu_p->v_p == vu1->v_p )  {
00757                                 if( is->l1 ) nmg_enlist_vu( is, vu1, eu2->vu_p, MAX_FASTF );
00758                                 ret++;
00759                                 continue;
00760                         }
00761 
00762                         new_eu = nmg_break_eu_on_v(eu2, vu1->v_p, fu2, is);
00763                         if ( new_eu )
00764                         {
00765                                 if( is->l1 ) nmg_enlist_vu( is, vu1, new_eu->vu_p, MAX_FASTF );
00766                                 ret++;
00767                                 continue;
00768                         }
00769                 }
00770         }
00771 
00772         if( ret == 0 )  {
00773                 /* The vertex lies in the face, but touches nothing.  Place marker */
00774                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
00775                         VPRINT("Making vertexloop", pt);
00776 
00777                 lu2 = nmg_mlv(&fu2->l.magic, vu1->v_p, OT_BOOLPLACE);
00778                 nmg_loop_g( lu2->l_p, &is->tol );
00779                 vu2 = BU_LIST_FIRST( vertexuse, &lu2->down_hd );
00780                 if(is->l1) nmg_enlist_vu( is, vu1, vu2, MAX_FASTF );
00781         }
00782 }
00783 
00784 /**
00785  *                      N M G _ I S E C T _ 3 V E R T E X _ 3 F A C E
00786  *
00787  *      intersect a vertex with a face (primarily for intersecting
00788  *      loops of a single vertex with a face).
00789  *
00790  *  XXX It would be useful to have one of the new vu's in fu returned
00791  *  XXX as a flag, so that nmg_find_v_in_face() wouldn't have to be called
00792  *  XXX to re-determine what was just done.
00793  */
00794 static void
00795 nmg_isect_3vertex_3face(struct nmg_inter_struct *is, struct vertexuse *vu, struct faceuse *fu)
00796 {
00797         struct vertexuse *vup;
00798         pointp_t pt;
00799         fastf_t dist;
00800         plane_t n;
00801 
00802         NMG_CK_INTER_STRUCT(is);
00803         NMG_CK_VERTEXUSE(vu);
00804         NMG_CK_VERTEX(vu->v_p);
00805         NMG_CK_FACEUSE(fu);
00806 
00807         if (rt_g.NMG_debug & DEBUG_POLYSECT)
00808                 bu_log("nmg_isect_3vertex_3face(, vu=x%x, fu=x%x) v=x%x\n", vu, fu, vu->v_p);
00809 
00810         /* check the topology first */
00811         vup=nmg_find_v_in_face(vu->v_p, fu);
00812         if (vup) {
00813                 if (rt_g.NMG_debug & DEBUG_POLYSECT) bu_log("\tvu lies in face (topology 1)\n");
00814                 (void)bu_ptbl_ins_unique(is->l1, &vu->l.magic);
00815                 (void)bu_ptbl_ins_unique(is->l2, &vup->l.magic);
00816                 return;
00817         }
00818 
00819 
00820         /* since the topology didn't tell us anything, we need to check with
00821          * the geometry
00822          */
00823         pt = vu->v_p->vg_p->coord;
00824         NMG_GET_FU_PLANE( n, fu );
00825         dist = DIST_PT_PLANE(pt, n);
00826 
00827         if ( !NEAR_ZERO(dist, is->tol.dist) )  {
00828                 if (rt_g.NMG_debug & DEBUG_POLYSECT) bu_log("\tvu not on face (geometry)\n");
00829                 return;
00830         }
00831 
00832         /*
00833          *  The point lies on the plane of the face, by geometry.
00834          *  This is now a 2-D problem.
00835          */
00836         (void)nmg_isect_vert2p_face2p( is, vu, fu );
00837 }
00838 
00839 /**
00840  *                      N M G _ B R E A K _ 3 E D G E _ A T _ P L A N E
00841  *
00842  *      Having decided that an edge(use) crosses a plane of intersection,
00843  *      stick a vertex at the point of intersection along the edge.
00844  *
00845  *  vu1_final in fu1 is BU_LIST_PNEXT_CIRC(edgeuse,eu1)->vu_p after return.
00846  *  vu2_final is the returned value, and is in fu2.
00847  *
00848  */
00849 static struct vertexuse *
00850 nmg_break_3edge_at_plane(const fastf_t *hit_pt, struct faceuse *fu2, struct nmg_inter_struct *is, struct edgeuse *eu1)
00851 
00852                                         /* The face that eu intersects */
00853 
00854                                         /* Edge to be broken (in fu1) */
00855 {
00856         struct vertexuse *vu1_final;
00857         struct vertexuse *vu2_final;    /* hit_pt's vu in fu2 */
00858         struct vertex   *v2;
00859         struct loopuse  *plu2;          /* "point" loopuse */
00860         struct edgeuse  *eu1forw;       /* New eu, after break, forw of eu1 */
00861         struct vertex   *v1;
00862         struct vertex   *v1mate;
00863         fastf_t         dist;
00864 
00865         NMG_CK_INTER_STRUCT(is);
00866         NMG_CK_EDGEUSE(eu1);
00867 
00868         v1 = eu1->vu_p->v_p;
00869         NMG_CK_VERTEX(v1);
00870         v1mate = eu1->eumate_p->vu_p->v_p;
00871         NMG_CK_VERTEX(v1mate);
00872 
00873         /* Intersection is between first and second vertex points.
00874          * Insert new vertex at intersection point.
00875          */
00876         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
00877                 bu_log("nmg_break_3edge_at_plane() Splitting %g, %g, %g <-> %g, %g, %g\n",
00878                         V3ARGS(v1->vg_p->coord),
00879                         V3ARGS(v1mate->vg_p->coord) );
00880                 VPRINT("\tAt point of intersection", hit_pt);
00881         }
00882 
00883         /* Double check for bad behavior */
00884         if( bn_pt3_pt3_equal( hit_pt, v1->vg_p->coord, &is->tol ) )
00885                 rt_bomb("nmg_break_3edge_at_plane() hit_pt equal to v1\n");
00886         if( bn_pt3_pt3_equal( hit_pt, v1mate->vg_p->coord, &is->tol ) )
00887                 rt_bomb("nmg_break_3edge_at_plane() hit_pt equal to v1mate\n");
00888 
00889         {
00890                 vect_t  va, vb;
00891                 VSUB2( va, hit_pt, eu1->vu_p->v_p->vg_p->coord  );
00892                 VSUB2( vb, eu1->eumate_p->vu_p->v_p->vg_p->coord, hit_pt );
00893                 VUNITIZE(va);
00894                 VUNITIZE(vb);
00895                 if( VDOT( va, vb ) <= 0.7071 )  {
00896                         rt_bomb("nmg_break_3edge_at_plane() eu1 changes direction?\n");
00897                 }
00898         }
00899         {
00900                 struct bn_tol   t2;
00901                 t2 = is->tol;   /* Struct copy */
00902 
00903                 t2.dist = is->tol.dist * 4;
00904                 t2.dist_sq = t2.dist * t2.dist;
00905                 dist = DIST_PT_PT(hit_pt, v1->vg_p->coord);
00906                 if( bn_pt3_pt3_equal( hit_pt, v1->vg_p->coord, &t2 ) )
00907                         bu_log("NOTICE: nmg_break_3edge_at_plane() hit_pt nearly equal to v1 %g*tol\n", dist/is->tol.dist);
00908                 dist = DIST_PT_PT(hit_pt, v1mate->vg_p->coord);
00909                 if( bn_pt3_pt3_equal( hit_pt, v1mate->vg_p->coord, &t2 ) )
00910                         bu_log("NOTICE: nmg_break_3edge_at_plane() hit_pt nearly equal to v1mate %g*tol\n", dist/is->tol.dist);
00911         }
00912 
00913         /* if we can't find the appropriate vertex in the
00914          * other face by a geometry search, build a new vertex.
00915          * Otherwise, re-use the existing one.
00916          * Can't just search other face, might miss relevant vert.
00917          */
00918         v2 = nmg_find_pt_in_model(fu2->s_p->r_p->m_p, hit_pt, &(is->tol));
00919         if (v2) {
00920                 /* the other face has a convenient vertex for us */
00921                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
00922                         bu_log("re-using vertex v=x%x from other shell\n", v2);
00923 
00924                 eu1forw = nmg_ebreaker(v2, eu1, &(is->tol));
00925                 vu1_final = eu1forw->vu_p;
00926                 vu2_final = nmg_enlist_vu( is, vu1_final, 0, MAX_FASTF );
00927         } else {
00928                 /* The other face has no vertex in this vicinity */
00929                 /* If hit_pt falls outside all the loops in fu2,
00930                  * then there is no need to break this edge.
00931                  * XXX It is probably cheaper to call nmg_isect_3vertex_3face()
00932                  * XXX here first, causing any ON cases to be resolved into
00933                  * XXX shared topology first (and also cutting fu2 edges NOW),
00934                  * XXX and then run the classifier to answer IN/OUT.
00935                  * This is expensive.  For getting started, tolerate it.
00936                  */
00937                 int     class;
00938                 class = nmg_class_pt_fu_except( hit_pt, fu2,
00939                         (struct loopuse *)NULL,
00940                         (void (*)())NULL, (void (*)())NULL, (char *)NULL, 0,
00941                         0, &is->tol );
00942                 if( class == NMG_CLASS_AoutB )  {
00943                         /* point outside face loop, no need to break eu1 */
00944 #if 0
00945 bu_log("%%%%%% point is outside face loop, no need to break eu1?\n");
00946                         return (struct vertexuse *)NULL;
00947 #endif
00948                         /* Can't optimize this break out -- need to have
00949                          * the new vertexuse on the line of intersection,
00950                          * to drive the state machine of the face cutter!
00951                          */
00952                 }
00953 
00954                 eu1forw = nmg_ebreaker((struct vertex *)NULL, eu1, &is->tol);
00955                 vu1_final = eu1forw->vu_p;
00956                 nmg_vertex_gv(vu1_final->v_p, hit_pt);
00957                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
00958                         bu_log("Made new vertex vu=x%x, v=x%x\n", vu1_final, vu1_final->v_p);
00959 
00960                 NMG_CK_VERTEX_G(eu1->vu_p->v_p->vg_p);
00961                 NMG_CK_VERTEX_G(eu1->eumate_p->vu_p->v_p->vg_p);
00962                 NMG_CK_VERTEX_G(eu1forw->vu_p->v_p->vg_p);
00963                 NMG_CK_VERTEX_G(eu1forw->eumate_p->vu_p->v_p->vg_p);
00964 
00965                 if (rt_g.NMG_debug & DEBUG_POLYSECT) {
00966                         register pointp_t p1 = eu1->vu_p->v_p->vg_p->coord;
00967                         register pointp_t p2 = eu1->eumate_p->vu_p->v_p->vg_p->coord;
00968 
00969                         bu_log("After split eu1 x%x= %g, %g, %g -> %g, %g, %g\n",
00970                                 eu1,
00971                                 V3ARGS(p1), V3ARGS(p2) );
00972                         p1 = eu1forw->vu_p->v_p->vg_p->coord;
00973                         p2 = eu1forw->eumate_p->vu_p->v_p->vg_p->coord;
00974                         bu_log("\teu1forw x%x = %g, %g, %g -> %g, %g, %g\n",
00975                                 eu1forw,
00976                                 V3ARGS(p1), V3ARGS(p2) );
00977                 }
00978 
00979                 switch(class)  {
00980                 case NMG_CLASS_AinB:
00981                         /* point inside a face loop, break edge */
00982                         break;
00983                 case NMG_CLASS_AonBshared:
00984                         /* point is on a loop boundary.  Break fu2 loop too? */
00985                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
00986                                 bu_log("%%%%%% point is on loop boundary.  Break fu2 loop too?\n");
00987                         nmg_isect_3vertex_3face( is, vu1_final, fu2 );
00988                         /* XXX should get new vu2 from isect_3vertex_3face! */
00989                         vu2_final = nmg_find_v_in_face( vu1_final->v_p, fu2 );
00990                         if( !vu2_final ) rt_bomb("%%%%%% missed!\n");
00991                         NMG_CK_VERTEXUSE(vu2_final);
00992                         nmg_enlist_vu( is, vu1_final, vu2_final, MAX_FASTF );
00993                         return vu2_final;
00994                 case NMG_CLASS_AoutB:
00995                         /* Can't optimize this, break edge anyway. */
00996                         break;
00997                 default:
00998                         rt_bomb("nmg_break_3edge_at_plane() bad classification return from nmg_class_pt_f()\n");
00999                 }
01000 
01001                 /* stick this vertex in the other shell
01002                  * and make sure it is in the other shell's
01003                  * list of vertices on the intersect line
01004                  */
01005                 plu2 = nmg_mlv(&fu2->l.magic, vu1_final->v_p, OT_BOOLPLACE);
01006                 vu2_final = BU_LIST_FIRST( vertexuse, &plu2->down_hd );
01007                 NMG_CK_VERTEXUSE(vu2_final);
01008                 nmg_loop_g(plu2->l_p, &is->tol);
01009 
01010                 if (rt_g.NMG_debug & DEBUG_POLYSECT) {
01011                         bu_log("Made vertexloop in other face. lu=x%x vu=x%x on v=x%x\n",
01012                                 plu2,
01013                                 vu2_final, vu2_final->v_p);
01014                 }
01015                 vu2_final = nmg_enlist_vu( is, vu1_final, vu2_final, MAX_FASTF );
01016         }
01017 
01018         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
01019                 register pointp_t       p1, p2;
01020                 p1 = eu1->vu_p->v_p->vg_p->coord;
01021                 p2 = eu1->eumate_p->vu_p->v_p->vg_p->coord;
01022                 bu_log("\tNow %g, %g, %g <-> %g, %g, %g\n",
01023                         V3ARGS(p1), V3ARGS(p2) );
01024                 p1 = eu1forw->vu_p->v_p->vg_p->coord;
01025                 p2 = eu1forw->eumate_p->vu_p->v_p->vg_p->coord;
01026                 bu_log("\tand %g, %g, %g <-> %g, %g, %g\n\n",
01027                         V3ARGS(p1), V3ARGS(p2) );
01028         }
01029         return vu2_final;
01030 }
01031 
01032 /**
01033  *                      N M G _ B R E A K _ E U _ O N _ V
01034  *
01035  *  The vertex 'v2' is known to lie in the plane of eu1's face.
01036  *  If v2 lies between the two endpoints of eu1, break eu1 and
01037  *  return the new edgeuse pointer.
01038  *
01039  *  If an edgeuse vertex is joined with v2, v2 remains as the survivor,
01040  *  as the caller is working on it explicitly, and the edgeuse vertices
01041  *  are dealt with implicitly (by dereferencing the eu pointers).
01042  *  Otherwise, we will invalidate our caller's v2 pointer.
01043  *
01044  *  Note that no "intersection line" stuff is done, the goal here is
01045  *  just to get the edge appropriately broken.
01046  *
01047  *  Either faceuse can be passed in, but it needs to be consistent with the
01048  *  faceuse used to establish the 2d vertex cache.
01049  *
01050  *  Returns -
01051  *      new_eu  if edge is broken
01052  *      0       otherwise
01053  */
01054 struct edgeuse *
01055 nmg_break_eu_on_v(struct edgeuse *eu1, struct vertex *v2, struct faceuse *fu, struct nmg_inter_struct *is)
01056 
01057 
01058                                 /* for plane equation of (either) face */
01059 
01060 {
01061         point_t         a;
01062         point_t         b;
01063         point_t         p;
01064         int             code;
01065         fastf_t         dist;
01066         struct vertex   *v1a;
01067         struct vertex   *v1b;
01068         struct edgeuse          *new_eu = (struct edgeuse *)0;
01069 
01070         NMG_CK_EDGEUSE(eu1);
01071         NMG_CK_VERTEX(v2);
01072         NMG_CK_FACEUSE(fu);
01073         NMG_CK_INTER_STRUCT(is);
01074 
01075         v1a = eu1->vu_p->v_p;
01076         v1b = BU_LIST_PNEXT_CIRC( edgeuse, eu1 )->vu_p->v_p;
01077 
01078         /* Check for already shared topology */
01079         if( v1a == v2 || v1b == v2 )  {
01080                 goto out;
01081         }
01082 
01083         /* Map to 2d */
01084         nmg_get_2d_vertex( a, v1a, is, &fu->l.magic );
01085         nmg_get_2d_vertex( b, v1b, is, &fu->l.magic );
01086         nmg_get_2d_vertex( p, v2, is, &fu->l.magic );
01087 
01088         dist = -INFINITY;
01089         code = bn_isect_pt2_lseg2( &dist, a, b, p, &(is->tol) );
01090 
01091         switch(code)  {
01092         case -2:
01093                 /* P outside AB */
01094                 break;
01095         default:
01096         case -1:
01097                 /* P not on line */
01098 #if 0
01099                 /* This can happen when v2 is a long way from the lseg */
01100                 V2PRINT("a", a);
01101                 V2PRINT("p", p);
01102                 V2PRINT("b", b);
01103                 VPRINT("A", v1a->vg_p->coord);
01104                 VPRINT("P", v2->vg_p->coord);
01105                 VPRINT("B", v1b->vg_p->coord);
01106                 rt_bomb("nmg_break_eu_on_v() P not on line?\n");
01107 #endif
01108                 break;
01109         case 1:
01110                 /* P is at A */
01111                 nmg_jv( v2, v1a );      /* v2 must be surviving vertex */
01112                 break;
01113         case 2:
01114                 /* P is at B */
01115                 nmg_jv( v2, v1b );      /* v2 must be surviving vertex */
01116                 break;
01117         case 3:
01118                 /* P is in the middle, break edge */
01119                 new_eu = nmg_ebreaker( v2, eu1, &is->tol );
01120                 if (rt_g.NMG_debug & DEBUG_POLYSECT) {
01121                         bu_log("nmg_break_eu_on_v() breaking eu=x%x on v=x%x, new_eu=x%x\n",
01122                                 eu1, v2, new_eu );
01123                 }
01124                 break;
01125         }
01126 
01127 out:
01128         return new_eu;
01129 }
01130 
01131 /**
01132  *                      N M G _ B R E A K _ E G _ O N _ V
01133  *
01134  *  Given a vertex 'v' which is already known to have geometry that lies
01135  *  on the line defined by 'eg', break all the edgeuses along 'eg'
01136  *  which cross 'v'.
01137  *
01138  *  Calculation is done in 1 dimension:  parametric distance along 'eg'.
01139  *  Edge direction vector needs to be made unit length so that tol->dist
01140  *  makes sense.
01141  */
01142 void
01143 nmg_break_eg_on_v(const struct edge_g_lseg *eg, struct vertex *v, const struct bn_tol *tol)
01144 {
01145         register struct edgeuse **eup;
01146         struct bu_ptbl  eutab;
01147         vect_t          dir;
01148         double          vdist;
01149 
01150         NMG_CK_EDGE_G_LSEG(eg);
01151         NMG_CK_VERTEX(v);
01152         BN_CK_TOL(tol);
01153 
01154         VMOVE( dir, eg->e_dir );
01155         VUNITIZE( dir );
01156         vdist = bn_dist_pt3_along_line3( eg->e_pt, dir, v->vg_p->coord );
01157 
01158         /* This has to be a table, because nmg_ebreaker() will
01159          * change the list on the fly, otherwise.
01160          */
01161         nmg_edgeuse_with_eg_tabulate( &eutab, eg );
01162 
01163         for( eup = (struct edgeuse **)BU_PTBL_LASTADDR(&eutab);
01164              eup >= (struct edgeuse **)BU_PTBL_BASEADDR(&eutab);
01165              eup--
01166         )  {
01167                 struct vertex   *va;
01168                 struct vertex   *vb;
01169                 double          a;
01170                 double          b;
01171                 struct edgeuse  *new_eu;
01172 
01173                 NMG_CK_EDGEUSE(*eup);
01174                 if( (*eup)->g.lseg_p != eg )  rt_bomb("nmg_break_eg_on_v() eu disowns eg\n");
01175 
01176                 va = (*eup)->vu_p->v_p;
01177                 vb = (*eup)->eumate_p->vu_p->v_p;
01178                 if( v == va || v == vb )  continue;
01179                 if( bn_pt3_pt3_equal( v->vg_p->coord, va->vg_p->coord, tol ) )  {
01180                         nmg_jv( v, va );
01181                         continue;
01182                 }
01183                 if( bn_pt3_pt3_equal( v->vg_p->coord, vb->vg_p->coord, tol ) )  {
01184                         nmg_jv( v, vb );
01185                         continue;
01186                 }
01187                 a = bn_dist_pt3_along_line3( eg->e_pt, dir, va->vg_p->coord );
01188                 b = bn_dist_pt3_along_line3( eg->e_pt, dir, vb->vg_p->coord );
01189                 if( NEAR_ZERO( a-vdist, tol->dist ) )  continue;
01190                 if( NEAR_ZERO( b-vdist, tol->dist ) )  continue;
01191                 if( !bn_between( a, vdist, b, tol ) )  continue;
01192                 new_eu = nmg_ebreaker( v, *eup, tol );
01193                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
01194                         bu_log("nmg_break_eg_on_v( eg=x%x, v=x%x ) new_eu=x%x\n",
01195                                 eg, v, new_eu );
01196                 }
01197         }
01198         bu_ptbl_free( &eutab);
01199 }
01200 
01201 /**
01202  *                      N M G _ I S E C T _ 2 C O L I N E A R _ E D G E 2 P
01203  *
01204  *  Perform edge mutual breaking only on two colinear edgeuses.
01205  *  This can result in 2 new edgeuses showing up in either loop (case A & D).
01206  *  The vertexuse lists are updated to have all participating vu's and
01207  *  their duals.
01208  *
01209  *  Two colinear line segments (eu1 and eu2, or just "1" and "2" in the
01210  *  diagram) can overlap each other in one of 9 configurations,
01211  *  labeled A through I:
01212  *
01213  *      A       B       C       D       E       F       G       H       I
01214  *
01215  *  vu1b,vu2b
01216  *      *       *         *       *     *         *     *         *     *=*
01217  *      1       1         2       2     1         2     1         2     1 2
01218  *      1=*     1         2     *=2     1=*     *=2     *         *     1 2
01219  *      1 2     *=*     *=*     1 2     1 2     1 2                     1 2
01220  *      1 2       2     1       1 2     1 2     1 2       *     *       1 2
01221  *      1=*       2     1       *=2     *=2     1=*       2     1       1 2
01222  *      1         *     *         2       2     1         *     *       1 2
01223  *      *                         *       *     *                       *=*
01224  *   vu1a,vu2a
01225  *
01226  *  To ensure nothing is missed, break every edgeuse on all 4 vertices.
01227  *  If a new edgeuse is created, add it to the list of edgeuses still to be
01228  *  broken.
01229  *  Brute force, but *certain* not to miss anything.
01230  *
01231  *  There is nothing to prevent eu1 and eu2 from being edgeuses in the same
01232  *  loop.  This creates interesting patterns if one is NEXT of the other,
01233  *  such as vu[1] == vu[2].  Just handle it gracefully.
01234  *
01235  *  Returns the number of edgeuses that resulted,
01236  *  which is always at least the original 2.
01237  *
01238  */
01239 int
01240 nmg_isect_2colinear_edge2p(struct edgeuse *eu1, struct edgeuse *eu2, struct faceuse *fu, struct nmg_inter_struct *is, struct bu_ptbl *l1, struct bu_ptbl *l2)
01241 
01242 
01243                                 /* for plane equation of (either) face */
01244 
01245                                 /* optional: list of new eu1 pieces */
01246                                 /* optional: list of new eu2 pieces */
01247 {
01248         struct edgeuse  *eu[10];
01249         struct vertexuse *vu[4];
01250         register int    i;
01251         register int    j;
01252         int             neu;    /* Number of edgeuses */
01253 
01254         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
01255                 bu_log("nmg_isect_2colinear_edge2p(eu1=x%x, eu2=x%x) START\n",
01256                         eu1, eu2);
01257         }
01258 
01259         NMG_CK_EDGEUSE(eu1);
01260         NMG_CK_EDGEUSE(eu2);
01261         NMG_CK_FACEUSE(fu);     /* Don't check it, just pass it on down. */
01262         NMG_CK_INTER_STRUCT(is);
01263         if( l1 )  BU_CK_PTBL(l1);
01264         if( l2 )  BU_CK_PTBL(l2);
01265 
01266         vu[0] = eu1->vu_p;
01267         vu[1] = BU_LIST_PNEXT_CIRC( edgeuse, eu1 )->vu_p;
01268         vu[2] = eu2->vu_p;
01269         vu[3] = BU_LIST_PNEXT_CIRC( edgeuse, eu2 )->vu_p;
01270 
01271         eu[0] = eu1;
01272         eu[1] = eu2;
01273         neu = 2;
01274 
01275         for( i=0; i < neu; i++ )  {
01276                 for( j=0; j<4; j++ )  {
01277                         eu[neu] = nmg_break_eu_on_v(eu[i],vu[j]->v_p,fu,is);
01278                         if( eu[neu] )  {
01279                                 nmg_enlist_vu( is, eu[neu]->vu_p, vu[j], MAX_FASTF );
01280                                 if( l1 && eu[neu]->e_p == eu1->e_p )
01281                                         bu_ptbl_ins_unique(l1, &eu[neu]->l.magic );
01282                                 else if( l2 && eu[neu]->e_p == eu2->e_p )
01283                                         bu_ptbl_ins_unique(l2, &eu[neu]->l.magic );
01284                                 neu++;
01285                         }
01286                 }
01287         }
01288 
01289         /* Now join 'em up */
01290         /*  This step should no longer be necessary, as nmg_ebreaker()
01291          *  from nmg_break_eu_on_v() should have already handled this. */
01292         for( i=0; i < neu-1; i++ )  {
01293                 for( j=i+1; j < neu; j++ )  {
01294                         if( !NMG_ARE_EUS_ADJACENT(eu[i],eu[j]) )  continue;
01295                         nmg_radial_join_eu( eu[i], eu[j], &(is->tol) );
01296                 }
01297         }
01298 
01299         /* Enlist all four of the original endpoints */
01300         for( i=0; i < 4; i++ )  {
01301                 for( j=0; j < 4; j++ )  {
01302                         if( i==j )  continue;
01303                         if( vu[i] == vu[j] ) continue;  /* Happens if eu2 follows eu1 in loop */
01304                         if( vu[i]->v_p == vu[j]->v_p )  {
01305                                 nmg_enlist_vu( is, vu[i], vu[j], MAX_FASTF );
01306                                 goto next_i;
01307                         }
01308                 }
01309                 /* No match, let subroutine hunt for dual */
01310                 nmg_enlist_vu( is, vu[i], 0, MAX_FASTF );
01311 next_i:         ;
01312         }
01313 
01314         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
01315                 bu_log("nmg_isect_2colinear_edge2p(eu1=x%x, eu2=x%x) ret #eu=%d\n",
01316                         eu1, eu2, neu);
01317         }
01318         return neu;
01319 }
01320 
01321 /**
01322  *                      N M G _ I S E C T _ E D G E 2 P _ E D G E 2 P
01323  *
01324  *  Actual 2d edge/edge intersector
01325  *
01326  *  One or both of the edges may be wire edges, i.e.
01327  *  either or both of the fu1 and fu2 args may be null.
01328  *  If so, the vert_list's are unimportant.
01329  *
01330  *  Returns a bit vector -
01331  *      ISECT_NONE      no intersection
01332  *      ISECT_SHARED_V  intersection was at (at least one) shared vertex
01333  *      ISECT_SPLIT1    eu1 was split at (geometric) intersection.
01334  *      ISECT_SPLIT2    eu2 was split at (geometric) intersection.
01335  */
01336 int
01337 nmg_isect_edge2p_edge2p(struct nmg_inter_struct *is, struct edgeuse *eu1, struct edgeuse *eu2, struct faceuse *fu1, struct faceuse *fu2)
01338 
01339 
01340 
01341                                         /* fu of eu1, for plane equation */
01342                                         /* fu of eu2, for error checks */
01343 {
01344         point_t         eu1_start;
01345         point_t         eu1_end;
01346         vect_t          eu1_dir;
01347         point_t         eu2_start;
01348         point_t         eu2_end;
01349         vect_t          eu2_dir;
01350         vect_t          dir3d;
01351         fastf_t         dist[2];
01352         int             status;
01353         point_t         hit_pt;
01354         struct vertexuse        *vu;
01355         struct vertexuse        *vu1a, *vu1b;
01356         struct vertexuse        *vu2a, *vu2b;
01357         struct model            *m;
01358         int             ret = 0;
01359 
01360         NMG_CK_INTER_STRUCT(is);
01361         NMG_CK_EDGEUSE(eu1);
01362         NMG_CK_EDGEUSE(eu2);
01363         m = nmg_find_model(&eu1->l.magic);
01364         NMG_CK_MODEL(m);
01365         /*
01366          * Important note:  don't use eu1->eumate_p->vu_p here,
01367          * because that vu is in the opposite orientation faceuse.
01368          * Putting those vu's on the intersection line makes for big trouble.
01369          */
01370         vu1a = eu1->vu_p;
01371         vu1b = BU_LIST_PNEXT_CIRC( edgeuse, eu1 )->vu_p;
01372         vu2a = eu2->vu_p;
01373         vu2b = BU_LIST_PNEXT_CIRC( edgeuse, eu2 )->vu_p;
01374         NMG_CK_VERTEXUSE(vu1a);
01375         NMG_CK_VERTEXUSE(vu1b);
01376         NMG_CK_VERTEXUSE(vu2a);
01377         NMG_CK_VERTEXUSE(vu2b);
01378 
01379         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
01380                 bu_log("nmg_isect_edge2p_edge2p(eu1=x%x, eu2=x%x) START\n\tfu1=x%x, fu2=x%x\n\tvu1a=%x vu1b=%x, vu2a=%x vu2b=%x\n\tv1a=%x v1b=%x,   v2a=%x v2b=%x\n",
01381                         eu1, eu2,
01382                         fu1, fu2,
01383                         vu1a, vu1b, vu2a, vu2b,
01384                         vu1a->v_p, vu1b->v_p, vu2a->v_p, vu2b->v_p );
01385         }
01386 
01387         /*
01388          *  Topology check.
01389          *  If both endpoints of both edges match, this is a trivial accept.
01390          */
01391         if( vu1a->v_p == vu2a->v_p && vu1b->v_p == vu2b->v_p )  {
01392                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01393                         bu_log("nmg_isect_edge2p_edge2p: shared edge topology, both ends\n");
01394                 nmg_radial_join_eu(eu1, eu2, &is->tol );
01395                 nmg_enlist_vu( is, vu1a, vu2a, MAX_FASTF );
01396                 nmg_enlist_vu( is, vu1b, vu2b, MAX_FASTF );
01397                 ret = ISECT_SHARED_V;
01398                 goto out;               /* vu1a, vu1b already listed */
01399         }
01400         if( vu1a->v_p == vu2b->v_p && vu1b->v_p == vu2a->v_p )  {
01401                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01402                         bu_log("nmg_isect_edge2p_edge2p: shared edge topology, both ends, reversed.\n");
01403                 nmg_radial_join_eu(eu1, eu2, &is->tol );
01404                 nmg_enlist_vu( is, vu1a, vu2b, MAX_FASTF );
01405                 nmg_enlist_vu( is, vu1b, vu2a, MAX_FASTF );
01406                 ret = ISECT_SHARED_V;
01407                 goto out;               /* vu1a, vu1b already listed */
01408         }
01409 
01410         /*
01411          *  The 3D line in is->pt and is->dir is prepared by the caller.
01412          *  is->pt is *not* one of the endpoints of this edge.
01413          *
01414          *  IMPORTANT NOTE:  The edge-ray used for the edge intersection
01415          *  calculations is colinear with the "intersection line",
01416          *  but the edge-ray starts at vu1a and points to vu1b,
01417          *  while the intersection line has to satisfy different constraints.
01418          *  Don't confuse the two!
01419          */
01420         nmg_get_2d_vertex( eu1_start, vu1a->v_p, is, &fu2->l.magic );   /* 2D line */
01421         nmg_get_2d_vertex( eu1_end, vu1b->v_p, is, &fu2->l.magic );
01422         VSUB2_2D( eu1_dir, eu1_end, eu1_start );
01423 
01424         nmg_get_2d_vertex( eu2_start, vu2a->v_p, is, &fu2->l.magic );
01425         nmg_get_2d_vertex( eu2_end, vu2b->v_p, is, &fu2->l.magic );
01426         VSUB2_2D( eu2_dir, eu2_end, eu2_start );
01427 
01428         dist[0] = dist[1] = 0;  /* for clean prints, below */
01429 
01430         /* The "proper" thing to do is intersect two line segments.
01431          * However, this means that none of the intersections of edge "line"
01432          * with the exterior of the loop are computed, and that
01433          * violates the strategy assumptions of the face-cutter.
01434          */
01435         /* To pick up ALL intersection points, the source edge is a line */
01436         status = bn_isect_line2_lseg2( dist, eu1_start, eu1_dir,
01437                         eu2_start, eu2_dir, &is->tol );
01438 
01439         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
01440                 bu_log("\tbn_isect_line2_lseg2()=%d, dist: %g, %g\n",
01441                         status, dist[0], dist[1] );
01442         }
01443 
01444         /*
01445          *  Whether geometry hits or misses, as long as not colinear, check topo.
01446          *  If one endpoint matches, and edges are not colinear,
01447          *  then accept the one shared vertex as the intersection point.
01448          *  Can't do this before geometry check, or we might miss the
01449          *  colinear condition, and not do the mutual intersection.
01450          */
01451         if( status != 0 &&
01452             (vu1a->v_p == vu2a->v_p || vu1a->v_p == vu2b->v_p ||
01453             vu1b->v_p == vu2a->v_p || vu1b->v_p == vu2b->v_p )
01454         )  {
01455                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01456                         bu_log("edge2p_edge2p: non-colinear edges share one vertex (topology)\n");
01457                 if( vu1a->v_p == vu2a->v_p )
01458                         nmg_enlist_vu( is, vu1a, vu2a, MAX_FASTF );
01459                 else if( vu1a->v_p == vu2b->v_p )
01460                         nmg_enlist_vu( is, vu1a, vu2b, MAX_FASTF );
01461 
01462                 if( vu1b->v_p == vu2a->v_p )
01463                         nmg_enlist_vu( is, vu1b, vu2a, MAX_FASTF );
01464                 else if( vu1b->v_p == vu2b->v_p )
01465                         nmg_enlist_vu( is, vu1b, vu2b, MAX_FASTF );
01466 
01467                 ret = ISECT_SHARED_V;
01468                 goto out;               /* vu1a, vu1b already listed */
01469         }
01470 
01471         if (status < 0)  {
01472                 ret = ISECT_NONE;       /* No geometric intersection */
01473                 goto topo;              /* Still need to list vu1a, vu2b */
01474         }
01475 
01476         if( status == 0 )  {
01477                 /* Lines are co-linear and on line of intersection. */
01478                 /* Perform full mutual intersection, and vu enlisting. */
01479                 if( nmg_isect_2colinear_edge2p( eu1, eu2, fu2, is, (struct bu_ptbl *)0, (struct bu_ptbl *)0 ) > 2 )  {
01480                         /* Can't tell which edgeuse(s) got split */
01481                         ret = ISECT_SPLIT1 | ISECT_SPLIT2;
01482                 } else {
01483                         /* XXX Can't tell if some sharing ensued.  Does it matter? */
01484                         /* No, not for the one place we are called. */
01485                         ret = ISECT_NONE;
01486                 }
01487                 goto out;               /* vu1a, vu1b listed by nmg_isect_2colinear_edge2p */
01488         }
01489 
01490         /* There is only one intersect point.  Break one or both edges. */
01491 
01492 
01493         /* The ray defined by the edgeuse line eu1 intersects the lseg eu2.
01494          * Tolerances have already been factored in.
01495          * The edge exists over values of 0 <= dist <= 1.
01496          */
01497         VSUB2( dir3d, vu1b->v_p->vg_p->coord, vu1a->v_p->vg_p->coord );
01498         VJOIN1( hit_pt, vu1a->v_p->vg_p->coord, dist[0], dir3d );
01499 
01500         if ( dist[0] == 0 )  {
01501                 /* First point of eu1 is on eu2, by geometry */
01502                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01503                         bu_log("\tvu=x%x vu1a is intersect point\n", vu1a);
01504                 if( dist[1] < 0 || dist[1] > 1 )  {
01505                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01506                                 bu_log("\teu1 line intersects eu2 outside vu2a...vu2b range, ignore.\n");
01507                         ret = ISECT_NONE;
01508                         goto topo;
01509                 }
01510 
01511                 /* Edges not colinear. Either join up with a matching vertex,
01512                  * or break eu2 on our vert.
01513                  */
01514                 if( dist[1] == 0 )  {
01515                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01516                                 bu_log("\tvu2a matches vu1a\n");
01517                         nmg_jv(vu1a->v_p, vu2a->v_p);
01518                         nmg_enlist_vu( is, vu1a, vu2a, MAX_FASTF );
01519                         ret = ISECT_SHARED_V;
01520                         goto topo;
01521                 }
01522                 if( dist[1] == 1 )  {
01523                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01524                                 bu_log("\tsecond point of eu2 matches vu1a\n");
01525                         nmg_jv(vu1a->v_p, vu2b->v_p);
01526                         nmg_enlist_vu( is, vu1a, vu2b, MAX_FASTF );
01527                         ret = ISECT_SHARED_V;
01528                         goto topo;
01529                 }
01530                 /* Break eu2 on our first vertex */
01531                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01532                         bu_log("\tbreaking eu2 on vu1a\n");
01533                 vu = nmg_ebreaker( vu1a->v_p, eu2, &is->tol )->vu_p;
01534                 nmg_enlist_vu( is, vu1a, vu, MAX_FASTF );
01535                 ret = ISECT_SPLIT2;     /* eu1 not broken, just touched */
01536                 goto topo;
01537         }
01538 
01539         if ( dist[0] == 1 )  {
01540                 /* Second point of eu1 is on eu2, by geometry */
01541                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01542                         bu_log("\tvu=x%x vu1b is intersect point\n", vu1b);
01543                 if( dist[1] < 0 || dist[1] > 1 )  {
01544                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01545                                 bu_log("\teu1 line intersects eu2 outside vu2a...vu2b range, ignore.\n");
01546                         ret = ISECT_NONE;
01547                         goto topo;
01548                 }
01549 
01550                 /* Edges not colinear. Either join up with a matching vertex,
01551                  * or break eu2 on our vert.
01552                  */
01553                 if( dist[1] == 0 )  {
01554                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01555                                 bu_log("\tvu2a matches vu1b\n");
01556                         nmg_jv(vu1b->v_p, vu2a->v_p);
01557                         nmg_enlist_vu( is, vu1b, vu2a, MAX_FASTF );
01558                         ret = ISECT_SHARED_V;
01559                         goto topo;
01560                 }
01561                 if( dist[1] == 1 )  {
01562                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01563                                 bu_log("\tsecond point of eu2 matches vu1b\n");
01564                         nmg_jv(vu1b->v_p, vu2b->v_p);
01565                         nmg_enlist_vu( is, vu1b, vu2b, MAX_FASTF );
01566                         ret = ISECT_SHARED_V;
01567                         goto topo;
01568                 }
01569                 /* Break eu2 on our second vertex */
01570                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01571                         bu_log("\tbreaking eu2 on vu1b\n");
01572                 vu = nmg_ebreaker( vu1b->v_p, eu2, &is->tol )->vu_p;
01573                 nmg_enlist_vu( is, vu1b, vu, MAX_FASTF );
01574                 ret = ISECT_SPLIT2;     /* eu1 not broken, just touched */
01575                 goto topo;
01576         }
01577 
01578         /*  eu2 intersect point is on eu1 line, but not between vertices.
01579          *  Since it crosses the line of intersection, it must be broken.
01580          */
01581         if( dist[0] < 0 || dist[0] > 1 )  {
01582                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01583                         bu_log("\tIntersect point on eu2 is outside vu1a...vu1b.  Break eu2 anyway.\n");
01584 
01585                 if( dist[1] == 0 )  {
01586                         nmg_enlist_vu( is, vu2a, 0, MAX_FASTF );
01587                         ret = ISECT_SHARED_V;           /* eu1 was not broken */
01588                         goto topo;
01589                 } else if( dist[1] == 1 )  {
01590                         nmg_enlist_vu( is, vu2b, 0, MAX_FASTF );
01591                         ret = ISECT_SHARED_V;           /* eu1 was not broken */
01592                         goto topo;
01593                 } else if( dist[1] > 0 && dist[1] < 1 )  {
01594                         /* Break eu2 somewhere in the middle */
01595                         struct vertexuse        *new_vu2;
01596                         struct vertex           *new_v2;
01597                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01598                                 VPRINT("\t\tBreaking eu2 at intersect point", hit_pt);
01599                         new_v2 = nmg_find_pt_in_model(m, hit_pt, &(is->tol) );
01600                         new_vu2 = nmg_ebreaker( new_v2, eu2, &is->tol )->vu_p;
01601                         if( !new_v2 )  {
01602                                 /* A new vertex was created, assign geom */
01603                                 nmg_vertex_gv( new_vu2->v_p, hit_pt );  /* 3d geom */
01604                         }
01605                         nmg_enlist_vu( is, new_vu2, 0, MAX_FASTF );
01606                         ret = ISECT_SPLIT2;     /* eu1 was not broken */
01607                         goto topo;
01608                 }
01609 
01610                 /* Hit point not on either eu1 or eu2, nothing to do */
01611                 ret = ISECT_NONE;
01612                 goto topo;
01613         }
01614 
01615         /* Intersection is in the middle of the reference edge (eu1) */
01616         /* dist[0] >= 0 && dist[0] <= 1 ) */
01617         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01618                 bu_log("\tintersect is in middle of eu1, breaking it\n");
01619 
01620         /* Edges not colinear. Either join up with a matching vertex,
01621          * or break eu2 on our vert.
01622          */
01623         if( dist[1] == 0 )  {
01624                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01625                         bu_log("\t\tintersect point is vu2a\n");
01626                 vu = nmg_ebreaker( vu2a->v_p, eu1, &is->tol )->vu_p;
01627                 nmg_enlist_vu( is, vu2a, vu, MAX_FASTF );
01628                 ret |= ISECT_SPLIT1;
01629                 goto topo;
01630         } else if( dist[1] == 1 )  {
01631                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01632                         bu_log("\t\tintersect point is vu2b\n");
01633                 vu = nmg_ebreaker( vu2b->v_p, eu1, &is->tol )->vu_p;
01634                 nmg_enlist_vu( is, vu2b, vu, MAX_FASTF );
01635                 ret |= ISECT_SPLIT1;
01636                 goto topo;
01637         } else if( dist[1] > 0 && dist[1] < 1 )  {
01638                 /* Intersection is in the middle of both, split edge */
01639                 struct vertex   *new_v;
01640                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01641                         VPRINT("\t\tBreaking both edges at intersect point", hit_pt);
01642                 ret = ISECT_SPLIT1 | ISECT_SPLIT2;
01643                 new_v = nmg_e2break( eu1, eu2 );
01644                 nmg_vertex_gv( new_v, hit_pt ); /* 3d geometry */
01645 
01646                 /* new_v is at far end of eu1 and eu2 */
01647                 if( eu1->eumate_p->vu_p->v_p != new_v ) rt_bomb("new_v 1\n");
01648                 if( eu2->eumate_p->vu_p->v_p != new_v ) rt_bomb("new_v 2\n");
01649                 /* Can't use eumate_p here, it's in wrong orientation face */
01650                 nmg_enlist_vu( is, BU_LIST_PNEXT_CIRC(edgeuse,eu1)->vu_p,
01651                         BU_LIST_PNEXT_CIRC(edgeuse,eu2)->vu_p, MAX_FASTF );
01652                 goto topo;
01653         } else {
01654                 /* Intersection is in middle of eu1, which lies on the
01655                  * line of intersection being computed, but is outside
01656                  * the endpoints of eu2.  There is no point in breaking
01657                  * eu1 here -- it does not connnect up with anything.
01658                  */
01659                 ret = ISECT_NONE;
01660                 goto topo;
01661         }
01662 
01663 topo:
01664         /*
01665          *  Listing of any vu's from eu2 will have been done above.
01666          *
01667          *  The *original* vu1a and vu1b (and their duals) MUST be
01668          *  forcibly listed on
01669          *  the intersection line, since eu1 lies ON the line!
01670          *
01671          *  This is done last, so that the intersection code (above) has
01672          *  the opportunity to create the duals.
01673          *  vu1a and vu1b don't have to have anything to do with eu2,
01674          *  hence the 2nd vu argument is unspecified (0).
01675          *  For our purposes here, we will be satisfied with *any* use
01676          *  of the same vertex in the other face.
01677          */
01678         nmg_enlist_vu( is, vu1a, 0, MAX_FASTF );
01679         nmg_enlist_vu( is, vu1b, 0, MAX_FASTF );
01680 out:
01681         /* By here, vu1a and vu1b MUST have been enlisted */
01682         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
01683                 bu_log("nmg_isect_edge2p_edge2p(eu1=x%x, eu2=x%x) END, ret=%d %s%s%s\n",
01684                         eu1, eu2, ret,
01685                         (ret&ISECT_SHARED_V)? "SHARED_V|" :
01686                                 ((ret==0) ? "NONE" : ""),
01687                         (ret&ISECT_SPLIT1)? "SPLIT1|" : "",
01688                         (ret&ISECT_SPLIT2)? "SPLIT2" : ""
01689                 );
01690         }
01691 
01692         return ret;
01693 }
01694 
01695 /**
01696  *                      N M G _ I S E C T _ W I R E E D G E 3 P _ F A C E 3 P
01697  *
01698  *  Intersect an edge eu1 with a faceuse fu2.
01699  *  eu1 may belong to fu1, or it may be a wire edge.
01700  *
01701  *  XXX It is not clear whether we need the caller to provide the
01702  *  line equation, or if we should just create it here.
01703  *  If done here, the start pt needs to be outside fu2 (fu1 also?)
01704  *
01705  *  Returns -
01706  *      0       If everything went well
01707  *      1       If vu[] list along the intersection line needs to be re-done.
01708  */
01709 static int
01710 nmg_isect_wireedge3p_face3p(struct nmg_inter_struct *is, struct edgeuse *eu1, struct faceuse *fu2)
01711 {
01712         struct vertexuse *vu1_final = (struct vertexuse *)NULL;
01713         struct vertexuse *vu2_final = (struct vertexuse *)NULL;
01714         struct vertex   *v1a;           /* vertex at start of eu1 */
01715         struct vertex   *v1b;           /* vertex at end of eu1 */
01716         point_t         hit_pt;
01717         vect_t          edge_vect;
01718         fastf_t         edge_len;       /* MAGNITUDE(edge_vect) */
01719         fastf_t         dist;           /* parametric dist to hit point */
01720         fastf_t         dist_to_plane;  /* distance to hit point, in mm */
01721         int             status;
01722         vect_t          start_pt;
01723         struct edgeuse  *eunext;
01724         struct faceuse  *fu1;           /* fu that contains eu1 */
01725         plane_t         n2;
01726         int             ret = 0;
01727 
01728         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01729                 bu_log("nmg_isect_wireedge3p_face3p(, eu1=x%x, fu2=x%x) START\n", eu1, fu2);
01730 
01731         NMG_CK_INTER_STRUCT(is);
01732         NMG_CK_EDGEUSE(eu1);
01733         NMG_CK_VERTEXUSE(eu1->vu_p);
01734         v1a = eu1->vu_p->v_p;
01735         NMG_CK_VERTEX(v1a);
01736         NMG_CK_VERTEX_G(v1a->vg_p);
01737 
01738         NMG_CK_EDGEUSE(eu1->eumate_p);
01739         NMG_CK_VERTEXUSE(eu1->eumate_p->vu_p);
01740         v1b = eu1->eumate_p->vu_p->v_p;
01741         NMG_CK_VERTEX(v1b);
01742         NMG_CK_VERTEX_G(v1b->vg_p);
01743 
01744         NMG_CK_FACEUSE(fu2);
01745         if( fu2->orientation != OT_SAME )  rt_bomb("nmg_isect_wireedge3p_face3p() fu2 not OT_SAME\n");
01746         fu1 = nmg_find_fu_of_eu(eu1);   /* May be NULL */
01747 
01748         /*
01749          *  Form a ray that starts at one vertex of the edgeuse
01750          *  and points to the other vertex.
01751          */
01752         VSUB2(edge_vect, v1b->vg_p->coord, v1a->vg_p->coord);
01753         edge_len = MAGNITUDE(edge_vect);
01754 
01755         VMOVE( start_pt, v1a->vg_p->coord );
01756 
01757         {
01758                 /* XXX HACK */
01759                 double  dot;
01760                 dot = fabs( VDOT( is->dir, edge_vect ) / edge_len ) - 1;
01761                 if( !NEAR_ZERO( dot, .01 ) )  {
01762                         bu_log("HACK HACK cough cough.  Resetting is->pt, is->dir\n");
01763                         VPRINT("old is->pt ", is->pt);
01764                         VPRINT("old is->dir", is->dir);
01765                         VMOVE( is->pt, start_pt );
01766                         VMOVE( is->dir, edge_vect );
01767                         VUNITIZE(is->dir);
01768                         VPRINT("new is->pt ", is->pt);
01769                         VPRINT("new is->dir", is->dir);
01770                 }
01771         }
01772 
01773         NMG_GET_FU_PLANE( n2, fu2 );
01774         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
01775                 bu_log("Testing (%g, %g, %g) -> (%g, %g, %g) dir=(%g, %g, %g)\n",
01776                         V3ARGS(start_pt),
01777                         V3ARGS(v1b->vg_p->coord),
01778                         V3ARGS(edge_vect) );
01779                 PLPRINT("\t", n2);
01780         }
01781 
01782         status = bn_isect_line3_plane(&dist, start_pt, edge_vect,
01783                 n2, &is->tol);
01784 
01785         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
01786             if (status >= 0)
01787                 bu_log("\tHit. bn_isect_line3_plane=%d, dist=%g (%e)\n",
01788                         status, dist, dist);
01789             else
01790                 bu_log("\tMiss. Boring status of bn_isect_line3_plane: %d\n",
01791                         status);
01792         }
01793         if( status == 0 )  {
01794                 struct nmg_inter_struct is2;
01795 
01796                 /*
01797                  *  Edge (ray) lies in the plane of the other face,
01798                  *  by geometry.  Drop into 2D code to handle all
01799                  *  possible intersections (there may be many),
01800                  *  and any cut/joins, then resume with the previous work.
01801                  */
01802                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
01803                         bu_log("nmg_isect_wireedge3p_face3p: edge lies ON face, using 2D code\n@ @ @ @ @ @ @ @ @ @ 2D CODE, START\n");
01804                         bu_log("  The status of the face/face intersect line, before 2d:\n");
01805                         nmg_pr_ptbl_vert_list( "l1", is->l1, is->mag1 );
01806                         nmg_pr_ptbl_vert_list( "l2", is->l2, is->mag2 );
01807                 }
01808 
01809                 is2 = *is;      /* make private copy */
01810                 is2.vert2d = 0; /* Don't use previously initialized stuff */
01811 
01812                 ret = nmg_isect_edge2p_face2p( &is2, eu1, fu2, fu1 );
01813 
01814                 nmg_isect2d_cleanup( &is2 );
01815 
01816                 /*
01817                  *  Because nmg_isect_edge2p_face2p() calls the face cutter,
01818                  *  vu's in lone lu's that are listed in the current l1 or
01819                  *  l2 lists may have been destroyed.  It's ret is ours.
01820                  */
01821 
01822                 /* Only do this if list is still OK */
01823                 if (rt_g.NMG_debug & DEBUG_POLYSECT && ret == 0)  {
01824                         bu_log("nmg_isect_wireedge3p_face3p: @ @ @ @ @ @ @ @ @ @ 2D CODE, END, resume 3d problem.\n");
01825                         bu_log("  The status of the face/face intersect line, so far:\n");
01826                         nmg_pr_ptbl_vert_list( "l1", is->l1, is->mag1 );
01827                         nmg_pr_ptbl_vert_list( "l2", is->l2, is->mag2 );
01828                 }
01829 
01830                 /* See if start vertex is now shared */
01831                 if ( (vu2_final=nmg_find_v_in_face(eu1->vu_p->v_p, fu2)) ) {
01832                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01833                                 bu_log("\tEdge start vertex lies on other face (2d topology).\n");
01834                         vu1_final = eu1->vu_p;
01835                         (void)bu_ptbl_ins_unique(is->l1, &vu1_final->l.magic);
01836                         (void)bu_ptbl_ins_unique(is->l2, &vu2_final->l.magic);
01837                 }
01838                 /* XXX HACK HACK -- shut off error checking */
01839                 vu1_final = vu2_final = (struct vertexuse *)NULL;
01840                 goto out;
01841         }
01842 
01843         /*
01844          *  We now know that the the edge does not lie +in+ the other face,
01845          *  so it will intersect the face in at most one point.
01846          *  Before looking at the results of the geometric calculation,
01847          *  check the topology.  If the topology says that starting vertex
01848          *  of this edgeuse is on the other face, that is the hit point.
01849          *  Enter the two vertexuses of that starting vertex in the list,
01850          *  and return.
01851          *
01852          *  XXX Lee wonders if there might be a benefit to violating the
01853          *  XXX "only ask geom question once" rule, and doing a geom
01854          *  XXX calculation here before the topology check.
01855          */
01856         if ( (vu2_final=nmg_find_v_in_face(v1a, fu2)) ) {
01857                 vu1_final = eu1->vu_p;
01858                 if (rt_g.NMG_debug & DEBUG_POLYSECT) {
01859                         bu_log("\tEdge start vertex lies on other face (topology).\n\tAdding vu1_final=x%x (v=x%x), vu2_final=x%x (v=x%x)\n",
01860                                 vu1_final, vu1_final->v_p,
01861                                 vu2_final, vu2_final->v_p);
01862                 }
01863                 (void)bu_ptbl_ins_unique(is->l1, &vu1_final->l.magic);
01864                 (void)bu_ptbl_ins_unique(is->l2, &vu2_final->l.magic);
01865                 goto out;
01866         }
01867 
01868         if (status < 0)  {
01869                 /*  Ray does not strike plane.
01870                  *  See if start point lies on plane.
01871                  */
01872                 dist = VDOT( start_pt, n2 ) - n2[3];
01873                 if( !NEAR_ZERO( dist, is->tol.dist ) )
01874                         goto out;               /* No geometric intersection */
01875 
01876                 /* XXX Does this ever happen, now that geom calc is done
01877                  * XXX above, and there is 2D handling as well?  Lets find out.
01878                  */
01879                 rt_bomb("nmg_isect_wireedge3p_face3p: Edge start vertex lies on other face (geometry)\n");
01880 
01881                 /* Start point lies on plane of other face */
01882                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01883                         bu_log("\tEdge start vertex lies on other face (geometry)\n");
01884                 dist = VSUB2DOT( v1a->vg_p->coord, start_pt, edge_vect )
01885                                 / edge_len;
01886         }
01887 
01888         /* The ray defined by the edgeuse intersects the plane
01889          * of the other face.  Check to see if the distance to
01890          * intersection is between limits of the endpoints of
01891          * this edge(use).
01892          * The edge exists over values of 0 <= dist <= 1, ie,
01893          * over values of 0 <= dist_to_plane <= edge_len.
01894          * The tolerance, an absolute distance, can only be compared
01895          * to other absolute distances like dist_to_plane & edge_len.
01896          * The vertices are "fattened" by +/- is->tol units.
01897          */
01898         dist_to_plane = edge_len * dist;
01899 
01900         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01901                 bu_log("\tedge_len=%g, dist=%g, dist_to_plane=%g\n",
01902                         edge_len, dist, dist_to_plane);
01903 
01904         if ( dist_to_plane < -is->tol.dist )  {
01905                 /* Hit is behind first point */
01906                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01907                         bu_log("\tplane behind first point\n");
01908                 goto out;
01909         }
01910 
01911         if ( dist_to_plane > edge_len + is->tol.dist) {
01912                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01913                         bu_log("\tplane beyond second point\n");
01914                 goto out;
01915         }
01916 
01917         VJOIN1( hit_pt, start_pt, dist, edge_vect );
01918 
01919         /* Check hit_pt against face/face intersection line */
01920         {
01921                 fastf_t ff_dist;
01922                 ff_dist = bn_dist_line3_pt3( is->pt, is->dir, hit_pt );
01923                 if( ff_dist > is->tol.dist )  {
01924                         bu_log("WARNING nmg_isect_wireedge3p_face3p() hit_pt off f/f line %g*tol (%e, tol=%e)\n",
01925                                 ff_dist/is->tol.dist,
01926                                 ff_dist, is->tol.dist);
01927                         /* XXX now what? */
01928                 }
01929         }
01930 
01931         /*
01932          * If the vertex on the other end of this edgeuse is on the face,
01933          * then make a linkage to an existing face vertex (if found),
01934          * and give up on this edge, knowing that we'll pick up the
01935          * intersection of the next edgeuse with the face later.
01936          */
01937         if ( dist_to_plane < is->tol.dist )  {
01938                 /* First point is on plane of face, by geometry */
01939                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01940                         bu_log("\tedge starts at plane intersect\n");
01941                 vu1_final = eu1->vu_p;
01942                 vu2_final = nmg_enlist_vu( is, vu1_final, 0, MAX_FASTF );
01943                 goto out;
01944         }
01945 
01946         if ( dist_to_plane < edge_len - is->tol.dist) {
01947                 /* Intersection is between first and second vertex points.
01948                  * Insert new vertex at intersection point.
01949                  */
01950                 vu2_final = nmg_break_3edge_at_plane(hit_pt, fu2, is, eu1);
01951                 if( vu2_final )
01952                         vu1_final = BU_LIST_PNEXT_CIRC(edgeuse,eu1)->vu_p;
01953                 goto out;
01954         }
01955 
01956 #if 0
01957         if ( dist_to_plane <= edge_len + is->tol.dist)
01958 #endif
01959         {
01960                 /* Second point is on plane of face, by geometry */
01961                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
01962                         bu_log("\tedge ends at plane intersect\n");
01963 
01964                 eunext = BU_LIST_PNEXT_CIRC(edgeuse,eu1);
01965                 NMG_CK_EDGEUSE(eunext);
01966                 if( eunext->vu_p->v_p != v1b )
01967                         rt_bomb("nmg_isect_wireedge3p_face3p: discontinuous eu loop\n");
01968 
01969                 vu1_final = eunext->vu_p;
01970                 vu2_final = nmg_enlist_vu( is, vu1_final, 0, MAX_FASTF );
01971                 goto out;
01972         }
01973 
01974 out:
01975         /* If vu's were added to list, run some quick checks here */
01976         if( vu1_final && vu2_final )  {
01977                 fastf_t dist;
01978 
01979                 if( vu1_final->v_p != vu2_final->v_p )  rt_bomb("nmg_isect_wireedge3p_face3p() vertex mis-match\n");
01980 
01981                 dist = bn_dist_line3_pt3( is->pt, is->dir,
01982                         vu1_final->v_p->vg_p->coord );
01983                 if( dist > 100*is->tol.dist )  {
01984                         bu_log("ERROR nmg_isect_wireedge3p_face3p() vu1=x%x point off line by %g > 100*dist_tol (%g)\n",
01985                                 vu1_final, dist, 100*is->tol.dist);
01986                         VPRINT("is->pt|", is->pt);
01987                         VPRINT("is->dir", is->dir);
01988                         VPRINT(" coord ", vu1_final->v_p->vg_p->coord );
01989                         rt_bomb("nmg_isect_wireedge3p_face3p()\n");
01990                 }
01991                 if( dist > is->tol.dist )  {
01992                         bu_log("WARNING nmg_isect_wireedge3p_face3p() vu1=x%x pt off line %g*tol (%e, tol=%e)\n",
01993                                 vu1_final, dist/is->tol.dist,
01994                                 dist, is->tol.dist);
01995                 }
01996         }
01997 
01998         if (rt_g.NMG_debug & DEBUG_POLYSECT)
01999                 bu_log("nmg_isect_wireedge3p_face3p(, eu1=x%x, fu2=x%x) ret=%d END\n", eu1, fu2, ret);
02000         return ret;
02001 }
02002 
02003 /**
02004  *                      N M G _ I S E C T _ W I R E L O O P 3 P _ F A C E 3 P
02005  *
02006  *      Intersect a single loop with another face.
02007  *      Note that it may be a wire loop.
02008  *
02009  *  Returns -
02010  *       0      everything is ok
02011  *      >0      vu[] list along intersection line needs to be re-done.
02012  */
02013 static int
02014 nmg_isect_wireloop3p_face3p(struct nmg_inter_struct *bs, struct loopuse *lu, struct faceuse *fu)
02015 {
02016         struct edgeuse  *eu;
02017         long            magic1;
02018         int             discards = 0;
02019 
02020         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
02021                 plane_t         n;
02022                 bu_log("nmg_isect_wireloop3p_face3p(, lu=x%x, fu=x%x) START\n", lu, fu);
02023                 NMG_GET_FU_PLANE( n, fu );
02024                 HPRINT("  fg N", n);
02025         }
02026 
02027         NMG_CK_INTER_STRUCT(bs);
02028         NMG_CK_LOOPUSE(lu);
02029         NMG_CK_LOOP(lu->l_p);
02030         NMG_CK_LOOP_G(lu->l_p->lg_p);
02031 
02032         NMG_CK_FACEUSE(fu);
02033 
02034         magic1 = BU_LIST_FIRST_MAGIC( &lu->down_hd );
02035         if (magic1 == NMG_VERTEXUSE_MAGIC) {
02036                 struct vertexuse        *vu = BU_LIST_FIRST(vertexuse,&lu->down_hd);
02037                 /* this is most likely a loop inserted when we split
02038                  * up fu2 wrt fu1 (we're now splitting fu1 wrt fu2)
02039                  */
02040                 nmg_isect_3vertex_3face(bs, vu, fu);
02041                 return 0;
02042         } else if (magic1 != NMG_EDGEUSE_MAGIC) {
02043                 rt_bomb("nmg_isect_wireloop3p_face3p() Unknown type of NMG loopuse\n");
02044         }
02045 
02046         /*  Process loop consisting of a list of edgeuses.
02047          *
02048          * By going backwards around the list we avoid
02049          * re-processing an edgeuse that was just created
02050          * by nmg_isect_wireedge3p_face3p.  This is because the edgeuses
02051          * point in the "next" direction, and when one of
02052          * them is split, it inserts a new edge AHEAD or
02053          * "nextward" of the current edgeuse.
02054          */
02055         for( eu = BU_LIST_LAST(edgeuse, &lu->down_hd );
02056              BU_LIST_NOT_HEAD(eu,&lu->down_hd);
02057              eu = BU_LIST_PLAST(edgeuse,eu) )  {
02058                 NMG_CK_EDGEUSE(eu);
02059 
02060                 if (eu->up.magic_p != &lu->l.magic) {
02061                         rt_bomb("nmg_isect_wireloop3p_face3p: edge does not share loop\n");
02062                 }
02063 
02064                 discards += nmg_isect_wireedge3p_face3p(bs, eu, fu);
02065 
02066                 nmg_ck_lueu(lu, "nmg_isect_wireloop3p_face3p");
02067         }
02068 
02069         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
02070                 bu_log("nmg_isect_wireloop3p_face3p(, lu=x%x, fu=x%x) END, discards=%d\n", lu, fu, discards);
02071         }
02072         return discards;
02073 }
02074 
02075 /**
02076  *                      N M G _ I S E C T _ C O N S T R U C T _ N I C E _ R A Y
02077  *
02078  *  Construct a nice ray for is->pt, is->dir
02079  *  which contains the line of intersection, is->on_eg.
02080  *
02081  *  See the comment in nmg_isect_two_generics_faces() for details
02082  *  on the constraints on this ray, and the algorithm.
02083  *
02084  *  XXX Danger?
02085  *  The ray -vs- RPP check is being done in 3D.
02086  *  It really ought to be done in 2D, to ensure that
02087  *  long edge lines on nearly axis-aligned faces don't
02088  *  get discarded prematurely!
02089  *  XXX Can't just comment out the code, I think the selection
02090  *  XXX of is->pt is significant:
02091  *      1)  All intersections are at positive distances on the ray,
02092  *      2)  dir cross N will point "left".
02093  *
02094  *  Returns -
02095  *      0       OK
02096  *      1       ray misses fu2 bounding box
02097  */
02098 int
02099 nmg_isect_construct_nice_ray(struct nmg_inter_struct *is, struct faceuse *fu2)
02100 {
02101         struct xray             line;
02102         vect_t                  invdir;
02103 
02104         NMG_CK_INTER_STRUCT(is);
02105         NMG_CK_FACEUSE(fu2);
02106 
02107         VMOVE( line.r_pt, is->on_eg->e_pt );                    /* 3D line */
02108         VMOVE( line.r_dir, is->on_eg->e_dir );
02109         VUNITIZE( line.r_dir );
02110         VINVDIR( invdir, line.r_dir );
02111 
02112         /* nmg_loop_g() makes sure there are no 0-thickness faces */
02113         if( !rt_in_rpp( &line, invdir, fu2->f_p->min_pt, fu2->f_p->max_pt ) )  {
02114                 /* The edge ray missed the face RPP, nothing to do. */
02115                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
02116                         VPRINT("r_pt ", line.r_pt);
02117                         VPRINT("r_dir", line.r_dir);
02118                         VPRINT("fu2 min", fu2->f_p->min_pt);
02119                         VPRINT("fu2 max", fu2->f_p->max_pt);
02120                         bu_log("r_min=%g, r_max=%g\n", line.r_min, line.r_max);
02121                         bu_log("nmg_isect_construct_nice_ray() edge ray missed face bounding RPP, ret=1\n");
02122                 }
02123                 return 1;       /* Missed */
02124         }
02125         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
02126                 VPRINT("fu2 min", fu2->f_p->min_pt);
02127                 VPRINT("fu2 max", fu2->f_p->max_pt);
02128                 bu_log("r_min=%g, r_max=%g\n", line.r_min, line.r_max);
02129         }
02130         /* Start point will lie at min or max dist, outside of face RPP */
02131         VJOIN1( is->pt, line.r_pt, line.r_min, line.r_dir );
02132         if( line.r_min > line.r_max )  {
02133                 /* Direction is heading the wrong way, flip it */
02134                 VREVERSE( is->dir, line.r_dir );
02135                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
02136                         bu_log("flipping dir\n");
02137         } else {
02138                 VMOVE( is->dir, line.r_dir );
02139         }
02140         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
02141                 VPRINT("r_pt ", line.r_pt);
02142                 VPRINT("r_dir", line.r_dir);
02143                 VPRINT("->pt ", is->pt);
02144                 VPRINT("->dir", is->dir);
02145                 bu_log("nmg_isect_construct_nice_ray() ret=0\n");
02146         }
02147         return 0;
02148 }
02149 
02150 /**
02151  *                      N M G _ I S E C T _ E D G E 2 P _ F A C E 2 P
02152  *
02153  *  Given one (2D) edge (eu1) lying in the plane of another face (fu2),
02154  *  intersect with all the other edges of that face.
02155  *  The line of intersection is defined by the geometry of this edgeuse.
02156  *  Therefore, all edgeuses in fu1 which share edge geometry are,
02157  *  by definition, ON the intersection line.  We process all edgeuses
02158  *  which share geometry at once, followed by cutjoin operation.
02159  *  It is up to the caller not to recall for the other edgeuses of this edge_g.
02160  *
02161  *  XXX eu1 may be a wire edge, in which case there is no fu1 face!
02162  *
02163  *  Note that this routine completely conducts the
02164  *  intersection operation, so that edges may come and go, loops
02165  *  may join or split, each time it is called.
02166  *  This imposes special requirements on handling the march through
02167  *  the linked lists in this routine.
02168  *
02169  *  This also means that much of argument "is" is changed each call.
02170  *
02171  *  It further means that vu's in lone lu's found along the edge
02172  *  "intersection line" here may get merged in, causing the lu to
02173  *  be killed, and the vu, which is listed in the 3D (calling)
02174  *  routine's l1/l2 list, is now invalid.
02175  *
02176  *  NOTE-
02177  *  Since this routine calls the face cutter, *all* points of intersection
02178  *  along the line, for *both* faces, need to be found.
02179  *  Otherwise, the parity requirements of the face cutter will be violated.
02180  *  This means that eu1 needs to be intersected with all of fu1 also,
02181  *  including itself (so that the vu's at the ends of eu1 are listed).
02182  *
02183  *  Returns -
02184  *      0       Topology is completely shared (or no sharing).  l1/l2 valid.
02185  *      >0      Caller needs to invalidate his l1/l2 list.
02186  */
02187 static int
02188 nmg_isect_edge2p_face2p(struct nmg_inter_struct *is, struct edgeuse *eu1, struct faceuse *fu2, struct faceuse *fu1)
02189 
02190                                         /* edge to be intersected w/fu2 */
02191                                         /* face to be intersected w/eu1 */
02192                                         /* fu that eu1 is from */
02193 {
02194         struct bu_ptbl vert_list1, vert_list2;
02195         fastf_t         *mag1,      *mag2;
02196         struct vertexuse        *vu1;
02197         struct vertexuse        *vu2;
02198         struct edgeuse          *fu2_eu;        /* use of edge in fu2 */
02199         int                     total_splits = 0;
02200         int                     ret = 0;
02201         struct bu_ptbl          eu1_list;
02202         struct bu_ptbl          eu2_list;
02203 
02204         NMG_CK_INTER_STRUCT(is);
02205         NMG_CK_EDGEUSE(eu1);
02206         NMG_CK_FACEUSE(fu2);
02207         if(fu1) NMG_CK_FACEUSE(fu1);     /* fu1 may be null */
02208 
02209         if (rt_g.NMG_debug & DEBUG_POLYSECT)
02210                 bu_log("nmg_isect_edge2p_face2p(eu1=x%x, fu2=x%x, fu1=x%x) START\n", eu1, fu2, fu1);
02211 
02212         if( fu2->orientation != OT_SAME )  rt_bomb("nmg_isect_edge2p_face2p() fu2 not OT_SAME\n");
02213         if( fu1 && fu1->orientation != OT_SAME )  rt_bomb("nmg_isect_edge2p_face2p() fu1 not OT_SAME\n");
02214 
02215         mag1 = (fastf_t *)NULL;
02216         mag2 = (fastf_t *)NULL;
02217 
02218         /*  See if an edge exists in other face that connects these 2 verts */
02219         fu2_eu = nmg_find_eu_in_face( eu1->vu_p->v_p, eu1->eumate_p->vu_p->v_p,
02220             fu2, (const struct edgeuse *)NULL, 0 );
02221         if( fu2_eu != (struct edgeuse *)NULL )  {
02222                 /* There is an edge in other face that joins these 2 verts. */
02223                 NMG_CK_EDGEUSE(fu2_eu);
02224                 if( fu2_eu->e_p != eu1->e_p )  {
02225                         /* Not the same edge, fuse! */
02226                         bu_log("nmg_isect_edge2p_face2p() fusing unshared shared edge\n");
02227                         nmg_radial_join_eu( eu1, fu2_eu, &is->tol );
02228                 }
02229                 /* Topology is completely shared */
02230                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
02231                         bu_log("nmg_isect_edge2p_face2p() topology is shared\n");
02232                 ret = 0;
02233                 goto do_ret;
02234         }
02235 
02236         (void)bu_ptbl(&vert_list1, BU_PTBL_INIT,(long *)NULL);
02237         (void)bu_ptbl(&vert_list2, BU_PTBL_INIT,(long *)NULL);
02238         (void)bu_ptbl(&eu1_list, BU_PTBL_INIT,(long *)NULL);
02239         (void)bu_ptbl(&eu2_list, BU_PTBL_INIT,(long *)NULL);
02240 
02241         NMG_CK_EDGE_G_LSEG(eu1->g.lseg_p);
02242         is->on_eg = eu1->g.lseg_p;
02243         is->l1 = &vert_list1;
02244         is->l2 = &vert_list2;
02245         is->s1 = nmg_find_s_of_eu(eu1);         /* may be wire edge */
02246         is->s2 = fu2->s_p;
02247         is->fu1 = fu1;
02248         is->fu2 = fu2;
02249 
02250         if ( fu1 && rt_g.NMG_debug & (DEBUG_POLYSECT|DEBUG_FCUT|DEBUG_MESH)
02251             && rt_g.NMG_debug & DEBUG_PLOTEM) {
02252                 nmg_pl_2fu( "Iface%d.pl", 0, fu2, fu1, 0 );
02253         }
02254 
02255         vu1 = eu1->vu_p;
02256         vu2 = BU_LIST_PNEXT_CIRC( edgeuse, eu1 )->vu_p;
02257         if( vu1->v_p == vu2->v_p )  {
02258                 bu_log("nmg_isect_edge2p_face2p(eu1=x%x) skipping 0-len edge (topology)\n", eu1);
02259                 /* Call nmg_k0eu() ? */
02260                 goto out;
02261         }
02262 
02263         /*
02264          *  Construct the ray which contains the line of intersection,
02265          *  i.e. the line that contains the edge "eu1" (is->on_eg).
02266          */
02267         if( nmg_isect_construct_nice_ray( is, fu2 ) )  goto out;
02268 
02269         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
02270                 nmg_fu_touchingloops(fu2);
02271                 if(fu1)nmg_fu_touchingloops(fu1);
02272                 nmg_region_v_unique( is->s1->r_p, &is->tol );
02273                 nmg_region_v_unique( is->s2->r_p, &is->tol );
02274         }
02275 
02276         /* Build list of all edgeuses in eu1/fu1 and fu2 */
02277         if( fu1 )  {
02278                 nmg_edgeuse_tabulate( &eu1_list, &fu1->l.magic );
02279         } else {
02280                 nmg_edgeuse_tabulate( &eu1_list, &eu1->l.magic );
02281         }
02282         nmg_edgeuse_tabulate( &eu2_list, &fu2->l.magic );
02283 
02284         is->mag_len = 2 * (BU_PTBL_END( &eu1_list ) + BU_PTBL_END( &eu2_list ) );
02285         mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "mag1" );
02286         mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "mag2" );
02287 
02288         is->mag1 = mag1;
02289         is->mag2 = mag2;
02290 
02291         /* Run infinite line containing eu1 through fu2 */
02292         total_splits = 1;
02293         nmg_isect_line2_face2pNEW( is, fu2, fu1, &eu2_list, &eu1_list );
02294 
02295         /* If eu1 is a wire, there is no fu1 to run line through. */
02296         if( fu1 )  {
02297                 /* We are intersecting with ourself */
02298                 nmg_isect_line2_face2pNEW( is, fu1, fu2, &eu1_list, &eu2_list );
02299         }
02300         if (rt_g.NMG_debug & DEBUG_POLYSECT )
02301                 bu_log("nmg_isect_edge2p_face2p(): total_splits=%d\n", total_splits);
02302 
02303         if( total_splits <= 0 )  goto out;
02304 
02305         if (rt_g.NMG_debug & DEBUG_FCUT) {
02306                 bu_log("nmg_isect_edge2p_face2p(eu1=x%x, fu2=x%x) vert_lists C:\n", eu1, fu2 );
02307                 nmg_pr_ptbl_vert_list( "vert_list1", &vert_list1, mag1 );
02308                 nmg_pr_ptbl_vert_list( "vert_list2", &vert_list2, mag2 );
02309         }
02310 #if 0
02311         nmg_purge_unwanted_intersection_points(&vert_list1, mag1, fu2, &is->tol);
02312         if(fu1)nmg_purge_unwanted_intersection_points(&vert_list2, mag2, fu1, &is->tol);
02313 #endif
02314         if (rt_g.NMG_debug & DEBUG_FCUT) {
02315                 bu_log("nmg_isect_edge2p_face2p(eu1=x%x, fu2=x%x) vert_lists D:\n", eu1, fu2 );
02316                 nmg_pr_ptbl_vert_list( "vert_list1", &vert_list1, mag1 );
02317                 nmg_pr_ptbl_vert_list( "vert_list2", &vert_list2, mag2 );
02318         }
02319 
02320         if (vert_list1.end == 0 && vert_list2.end == 0) goto out;
02321 
02322         /* Invoke the face cutter to snip and join loops along isect line */
02323         is->on_eg = nmg_face_cutjoin(&vert_list1, &vert_list2, mag1, mag2, fu1, fu2, is->pt, is->dir, is->on_eg, &is->tol);
02324         ret = 1;                /* face cutter was called. */
02325 
02326 out:
02327         (void)bu_ptbl_free(&vert_list1);
02328         (void)bu_ptbl_free(&vert_list2);
02329         (void)bu_ptbl_free(&eu1_list);
02330         (void)bu_ptbl_free(&eu2_list);
02331         if( mag1 )
02332                 bu_free( (char *)mag1, "nmg_isect_edge2p_face2p: mag1" );
02333         if( mag2 )
02334                 bu_free( (char *)mag2, "nmg_isect_edge2p_face2p: mag2" );
02335 
02336 do_ret:
02337         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
02338                 bu_log("nmg_isect_edge2p_face2p(eu1=x%x, fu2=x%x) ret=%d\n",
02339                         eu1, fu2, ret);
02340         }
02341         return ret;
02342 }
02343 
02344 /*
02345  */
02346 void
02347 nmg_enlist_one_vu(struct nmg_inter_struct *is, const struct vertexuse *vu, fastf_t dist)
02348 
02349 
02350                                                 /* distance along intersect ray for this vu */
02351 {
02352         struct shell            *sv;            /* shell of vu */
02353 
02354         NMG_CK_INTER_STRUCT(is);
02355         NMG_CK_VERTEXUSE(vu);
02356 
02357         if( is->mag_len <= BU_PTBL_END( is->l1 ) || is->mag_len <= BU_PTBL_END( is->l2 ) )
02358                 bu_log( "Array for distances to vertexuses is too small (%d)\n" , is->mag_len );
02359 
02360         sv = nmg_find_s_of_vu( vu );
02361 
02362         /* First step:  add vu to corresponding list */
02363         if( sv == is->s1 )  {
02364                 bu_ptbl_ins_unique( is->l1, (long *)&vu->l.magic );
02365                 if( is->mag_len <= BU_PTBL_END( is->l1 ) )
02366                 {
02367                         if( is->mag_len )
02368                         {
02369                                 is->mag_len *= 2;
02370                                 is->mag1 = (fastf_t *)rt_realloc( (char *)is->mag1, is->mag_len*sizeof( fastf_t),
02371                                         "is->mag1" );
02372                                 is->mag2 = (fastf_t *)rt_realloc( (char *)is->mag2, is->mag_len*sizeof( fastf_t),
02373                                         "is->mag2" );
02374                         }
02375                         else
02376                         {
02377                                 is->mag_len = 2*(BU_PTBL_END( is->l1 ) + BU_PTBL_END( is->l2 ));
02378                                 is->mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag1" );
02379                                 is->mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag2" );
02380                         }
02381 
02382                 }
02383                 if( dist < MAX_FASTF )
02384                         is->mag1[bu_ptbl_locate( is->l1, (long *)&vu->l.magic )] = dist;
02385         } else if( sv == is->s2 )  {
02386                 bu_ptbl_ins_unique( is->l2, (long *)&vu->l.magic );
02387                 if( is->mag_len <= BU_PTBL_END( is->l2 ) )
02388                 {
02389                         if( is->mag_len )
02390                         {
02391                                 is->mag_len *= 2;
02392                                 is->mag1 = (fastf_t *)rt_realloc( (char *)is->mag1, is->mag_len*sizeof( fastf_t),
02393                                         "is->mag1" );
02394                                 is->mag2 = (fastf_t *)rt_realloc( (char *)is->mag2, is->mag_len*sizeof( fastf_t),
02395                                         "is->mag2" );
02396                         }
02397                         else
02398                         {
02399                                 is->mag_len = 2*(BU_PTBL_END( is->l1 ) + BU_PTBL_END( is->l2 ));
02400                                 is->mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag1" );
02401                                 is->mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "is->mag2" );
02402                         }
02403 
02404                 }
02405                 if( dist < MAX_FASTF )
02406                         is->mag2[bu_ptbl_locate( is->l2, (long *)&vu->l.magic )] = dist;
02407         } else {
02408                 bu_log("nmg_enlist_one_vu(vu=x%x) sv=x%x, s1=x%x, s2=x%x\n",
02409                         vu, sv, is->s1, is->s2 );
02410                 rt_bomb("nmg_enlist_one_vu: vu is not in s1 or s2\n");
02411         }
02412 
02413         if( rt_g.NMG_debug & DEBUG_POLYSECT )  {
02414                 bu_log("nmg_enlist_one_vu(vu=x%x) v=x%x, dist=%g (%s)\n",
02415                         vu, vu->v_p, dist,
02416                         (sv == is->s1) ? "shell 1" : "shell 2" );
02417         }
02418 
02419         /* Some (expensive) centralized sanity checking */
02420         if( (rt_g.NMG_debug & DEBUG_VERIFY) && is->fu1 && is->fu2 )  {
02421                 nmg_ck_v_in_2fus(vu->v_p, is->fu1, is->fu2, &(is->tol));
02422         }
02423 }
02424 
02425 static void
02426 nmg_coplanar_face_vertex_fuse(struct faceuse *fu1, struct faceuse *fu2, struct bn_tol *tol)
02427 {
02428         struct bu_ptbl fu1_verts;
02429         struct bu_ptbl fu2_verts;
02430         int i, j;
02431         vect_t norm;
02432 
02433         NMG_CK_FACEUSE( fu1 );
02434         NMG_CK_FACEUSE( fu2 );
02435         BN_CK_TOL( tol );
02436 
02437         NMG_GET_FU_NORMAL( norm, fu1 );
02438 
02439         nmg_vertex_tabulate( &fu1_verts, &fu1->l.magic );
02440         nmg_vertex_tabulate( &fu2_verts, &fu2->l.magic );
02441 
02442         for( i=0 ; i<BU_PTBL_END( &fu1_verts ) ; i++ )
02443         {
02444                 struct vertex *v1;
02445 
02446                 v1 = (struct vertex *)BU_PTBL_GET( &fu1_verts, i );
02447 
02448                 for( j=0 ; j<BU_PTBL_END( &fu2_verts ) ; j++ )
02449                 {
02450                         struct vertex *v2;
02451                         vect_t diff;
02452                         vect_t diff_unit;
02453                         fastf_t len_sq, inv_len;
02454                         fastf_t dot;
02455 
02456                         v2 = (struct vertex *)BU_PTBL_GET( &fu2_verts, j );
02457 
02458                         if( v1 == v2 )
02459                                 continue;
02460 
02461                         VSUB2( diff, v1->vg_p->coord, v2->vg_p->coord );
02462                         len_sq = MAGSQ( diff );
02463                         if( len_sq > 4.0*tol->dist_sq )
02464                                 continue;
02465 
02466                         inv_len = 1.0 / sqrt( len_sq );
02467 
02468                         VSCALE( diff_unit, diff, inv_len );
02469 
02470                         dot = VDOT( norm, diff_unit );
02471                         if( BN_VECT_ARE_PARALLEL( dot, tol ) )
02472                         {
02473                                 /* fuse these two vertices */
02474                                 nmg_jv( v2, v1 );
02475                                 break;
02476                         }
02477                 }
02478         }
02479 }
02480 
02481 static void
02482 nmg_isect_two_face2p_jra(struct nmg_inter_struct *is, struct faceuse *fu1, struct faceuse *fu2)
02483 {
02484         struct model *m;
02485         struct loopuse *lu;
02486         struct bu_ptbl eu1_list;
02487         struct bu_ptbl eu2_list;
02488         struct bu_ptbl v_list;
02489         struct bu_ptbl vert_list1,vert_list2;
02490         fastf_t *mag1,*mag2;
02491         int i,j;
02492 
02493         NMG_CK_FACEUSE( fu1 );
02494         NMG_CK_FACEUSE( fu2 );
02495         NMG_CK_INTER_STRUCT(is);
02496 
02497         if (rt_g.NMG_debug & DEBUG_POLYSECT)
02498                 bu_log( "nmg_isect_two)face2p_jra: fu1=x%x, fu2=x%x\n" );
02499 
02500         nmg_coplanar_face_vertex_fuse( fu1, fu2, &is->tol );
02501 
02502         m = nmg_find_model( &fu1->l.magic );
02503         NMG_CK_MODEL( m );
02504 
02505         nmg_edgeuse_tabulate( &eu1_list, &fu1->l.magic );
02506         nmg_edgeuse_tabulate( &eu2_list, &fu2->l.magic );
02507 
02508         is->mag_len = 2 * (BU_PTBL_END( &eu1_list ) + BU_PTBL_END( &eu2_list ) );
02509         mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "mag1" );
02510         mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "mag2" );
02511 
02512         for( i=0 ; i<is->mag_len ; i++ )
02513         {
02514                 mag1[i] = MAX_FASTF;
02515                 mag2[i] = MAX_FASTF;
02516         }
02517 
02518 
02519         is->s1 = fu1->s_p;
02520         is->s2 = fu2->s_p;
02521         is->fu1 = fu1;
02522         is->fu2 = fu2;
02523         is->mag1 = mag1;
02524         is->mag2 = mag2;
02525 
02526         /* First split all edgeuses that intersect */
02527         for( i=0 ; i<BU_PTBL_END( &eu1_list ) ; i++ )
02528         {
02529                 struct edgeuse *eu1;
02530                 struct vertex_g *vg1a,*vg1b;
02531                 vect_t vt1_3d;
02532 
02533                 eu1 = (struct edgeuse *)BU_PTBL_GET( &eu1_list, i );
02534                 NMG_CK_EDGEUSE( eu1 );
02535 
02536                 vg1a = eu1->vu_p->v_p->vg_p;
02537                 NMG_CK_VERTEX_G( vg1a );
02538                 vg1b = eu1->eumate_p->vu_p->v_p->vg_p;
02539                 NMG_CK_VERTEX_G( vg1b );
02540 
02541                 VSUB2( vt1_3d, vg1b->coord, vg1a->coord );
02542 #if 0
02543                 nmg_get_2d_vertex( pt1a, eu1->vu_p->v_p, is, (long *)fu1 );
02544                 nmg_get_2d_vertex( pt1b, eu1->eumate_p->vu_p->v_p, is, (long *)fu1 );
02545                 VSUB2( vt1, pt1b, pt1a );
02546 #endif
02547                 for( j=0 ; j<BU_PTBL_END( &eu2_list ) ; j++ )
02548                 {
02549                         struct edgeuse *eu2;
02550                         struct vertex_g *vg2a, *vg2b;
02551                         int code;
02552                         vect_t vt2_3d;
02553                         fastf_t dist[2];
02554                         point_t hit_pt;
02555                         int hit_no;
02556                         int hit_count;
02557 
02558                         eu2 = (struct edgeuse *)BU_PTBL_GET( &eu2_list, j );
02559                         NMG_CK_EDGEUSE( eu2 );
02560 #if 0
02561                         nmg_get_2d_vertex( pt2a, eu2->vu_p->v_p, is, (long *)fu1 );
02562                         nmg_get_2d_vertex( pt2b, eu2->eumate_p->vu_p->v_p, is, (long *)fu1 );
02563                         VSUB2( vt2, pt2b, pt2a );
02564 #endif
02565                         vg2a = eu2->vu_p->v_p->vg_p;
02566                         vg2b = eu2->eumate_p->vu_p->v_p->vg_p;
02567                         VSUB2( vt2_3d, vg2b->coord, vg2a->coord );
02568 #if 0
02569                         code = bn_isect_lseg2_lseg2( dist, pt1a, vt1,
02570                                 pt2a, vt2, &is->tol );
02571 #else
02572                         code = bn_isect_lseg3_lseg3( dist, vg1a->coord, vt1_3d,
02573                                 vg2a->coord, vt2_3d, &is->tol );
02574 #endif
02575 
02576                         if( code < 0 )
02577                                 continue;
02578 
02579                         if( code == 0 )
02580                         {
02581                                 hit_count = 2;
02582                                 if( dist[0] < dist[1] )
02583                                 {
02584                                         fastf_t tmp;
02585 
02586                                         tmp = dist[0];
02587                                         dist[0] = dist[1];
02588                                         dist[1] = tmp;
02589                                 }
02590                         }
02591                         else
02592                                 hit_count = 1;
02593 
02594                         for( hit_no=0 ; hit_no < hit_count ; hit_no++ )
02595                         {
02596                                 struct edgeuse *new_eu;
02597                                 struct vertex *hitv;
02598                                 struct vertexuse *hit_vu = NULL;
02599 
02600                                 if( dist[hit_no] < 0.0 || dist[hit_no] > 1.0 )
02601                                         continue;
02602 
02603                                 hitv = (struct vertex *)NULL;
02604 
02605                                 if( dist[hit_no] == 0.0 )
02606                                 {
02607                                         hit_vu = eu1->vu_p;
02608                                         hitv = hit_vu->v_p;
02609                                         VMOVE( hit_pt, hitv->vg_p->coord );
02610                                 }
02611                                 else if( dist[hit_no] == 1.0 )
02612                                 {
02613                                         hit_vu = eu1->eumate_p->vu_p;
02614                                         hitv = hit_vu->v_p;
02615                                         VMOVE( hit_pt, hitv->vg_p->coord );
02616                                 }
02617                                 else
02618                                         VJOIN1( hit_pt, vg1a->coord , dist[hit_no], vt1_3d )
02619 
02620                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
02621                                         bu_log( "eus x%x and x%x intersect #%d at (%f %f %f)\n",
02622                                                 eu1, eu2, hit_no, V3ARGS( hit_pt ) );
02623 
02624                                 if( !hit_vu )
02625                                         hit_vu = nmg_find_pt_in_face( fu2, hit_pt, &is->tol );
02626 
02627                                 if( !hit_vu )
02628                                         hitv = nmg_find_pt_in_model( nmg_find_model( &fu1->l.magic ), hit_pt, &is->tol );
02629 
02630                                 if (rt_g.NMG_debug & DEBUG_POLYSECT && hitv)
02631                                         bu_log( "Found vertex (x%x) at hit_pt\n", hitv );
02632 
02633                                 if( hitv != eu1->vu_p->v_p && hitv != eu1->eumate_p->vu_p->v_p )
02634                                 {
02635                                         struct edgeuse *next_eu, *prev_eu;
02636 
02637                                         next_eu = BU_LIST_PNEXT_CIRC( edgeuse, &eu1->l );
02638                                         prev_eu = BU_LIST_PPREV_CIRC( edgeuse, &eu1->l );
02639 
02640                                         if( hitv != prev_eu->vu_p->v_p && hitv != next_eu->eumate_p->vu_p->v_p )
02641                                         {
02642                                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
02643                                                         bu_log( "Splitting eu1 x%x\n", eu1 );
02644                                                 new_eu = nmg_esplit( hitv, eu1, 1 );
02645                                                 hitv = new_eu->vu_p->v_p;
02646                                                 if( !hitv->vg_p )
02647                                                         nmg_vertex_gv( hitv, hit_pt );
02648                                                 vg1b = eu1->eumate_p->vu_p->v_p->vg_p;
02649                                                 VSUB2( vt1_3d, vg1b->coord, vg1a->coord );
02650 #if 0
02651                                                 bu_ptbl_ins( &eu1_list, (long *)new_eu );
02652                                                 nmg_get_2d_vertex( pt1b, eu1->eumate_p->vu_p->v_p, is, (long *)fu1 );
02653                                                 VSUB2( vt1, pt1b, pt1a );
02654 #endif
02655                                         }
02656                                 }
02657                                 if( code == 1 && hitv != eu2->vu_p->v_p && hitv != eu2->eumate_p->vu_p->v_p )
02658                                 {
02659                                         struct edgeuse *next_eu, *prev_eu;
02660 
02661                                         next_eu = BU_LIST_PNEXT_CIRC( edgeuse, &eu2->l );
02662                                         prev_eu = BU_LIST_PPREV_CIRC( edgeuse, &eu2->l );
02663 
02664                                         if( hitv != prev_eu->vu_p->v_p && hitv != next_eu->eumate_p->vu_p->v_p )
02665                                         {
02666                                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
02667                                                 {
02668                                                         vect_t tmp1, tmp2;
02669                                                         VSUB2( tmp1, hit_pt, eu2->vu_p->v_p->vg_p->coord )
02670                                                         VSUB2( tmp2, hit_pt, eu2->eumate_p->vu_p->v_p->vg_p->coord )
02671                                                         bu_log( "Splitting eu2 x%x\n",  eu2 );
02672                                                         bu_log( "Distance to hit_pt = %g from vu1, %g from vu2\n",
02673                                                                 MAGNITUDE( tmp1 ), MAGNITUDE( tmp2 ) );
02674                                                 }
02675                                                 new_eu = nmg_esplit( hitv, eu2, 1 );
02676                                                 hitv = new_eu->vu_p->v_p;
02677                                                 if( !hitv->vg_p )
02678                                                         nmg_vertex_gv( hitv, hit_pt );
02679                                                 bu_ptbl_ins( &eu2_list, (long *)new_eu );
02680                                         }
02681                                 }
02682 
02683                                 if( hitv )
02684                                         (void)nmg_break_all_es_on_v( &m->magic, hitv, &is->tol );
02685                         }
02686                 }
02687         }
02688 
02689         bu_ptbl_free( &eu1_list);
02690         bu_ptbl_free( &eu2_list);
02691 
02692         /* Make sure every vertex in fu1 has dual in fu2
02693          * (if they overlap)
02694          */
02695         nmg_vertex_tabulate( &v_list, &fu1->l.magic );
02696 
02697         for( i=0 ; i<BU_PTBL_END( &v_list ) ; i++ )
02698         {
02699                 struct vertex *v;
02700                 int class;
02701 
02702                 v = (struct vertex *)BU_PTBL_GET( &v_list, i );
02703                 NMG_CK_VERTEX( v );
02704 
02705                 if( nmg_find_v_in_face( v, fu2 ) )
02706                         continue;
02707 
02708                 /* Check if this vertex is within other FU */
02709                 class = nmg_class_pt_fu_except( v->vg_p->coord, fu2, NULL, NULL, NULL,
02710                         (char *)NULL, 0, 0, &is->tol );
02711 
02712                 if( class == NMG_CLASS_AinB )
02713                 {
02714                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
02715                                 bu_log( "Making dualvu of vertex x%x in fu2 x%x\n", v, fu2 );
02716                         (void)nmg_make_dualvu( v, fu2, &is->tol );
02717                 }
02718         }
02719         bu_ptbl_reset( &v_list);
02720 
02721         /* same for fu2  */
02722         nmg_vertex_tabulate( &v_list, &fu2->l.magic );
02723 
02724         for( i=0 ; i<BU_PTBL_END( &v_list ) ; i++ )
02725         {
02726                 struct vertex *v;
02727                 int class;
02728 
02729                 v = (struct vertex *)BU_PTBL_GET( &v_list, i );
02730                 NMG_CK_VERTEX( v );
02731 
02732                 if( nmg_find_v_in_face( v, fu1 ) )
02733                         continue;
02734 
02735                 /* Check if this vertex is within other FU */
02736                 class = nmg_class_pt_fu_except( v->vg_p->coord, fu1, NULL, NULL, NULL,
02737                         (char *)NULL, 0, 0, &is->tol );
02738 
02739                 if( class == NMG_CLASS_AinB )
02740                 {
02741                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
02742                                 bu_log( "Making dualvu of vertex x%x in fu1 x%x\n", v, fu1 );
02743                         (void)nmg_make_dualvu( v, fu1, &is->tol );
02744                 }
02745         }
02746 
02747         bu_ptbl_free( &v_list);
02748 
02749         bu_ptbl_init( &vert_list1, 64, " &vert_list1");
02750         bu_ptbl_init( &vert_list2, 64, " &vert_list2");
02751         is->l1 = &vert_list1;
02752         is->l2 = &vert_list2;
02753 
02754         for( BU_LIST_FOR( lu, loopuse, &fu1->lu_hd ) )
02755         {
02756                 struct edgeuse *eu;
02757 
02758                 NMG_CK_LOOPUSE( lu );
02759 
02760                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
02761                         continue;
02762 
02763                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02764                 {
02765                         struct vertexuse *vu;
02766                         struct vertex *v1,*v2;
02767 
02768                         NMG_CK_EDGEUSE( eu );
02769 
02770                         v1 = eu->vu_p->v_p;
02771                         NMG_CK_VERTEX( v1 );
02772                         v2 = eu->eumate_p->vu_p->v_p;
02773                         NMG_CK_VERTEX( v2 );
02774 
02775                         if( !nmg_find_v_in_face( v1, fu2 ) ||
02776                                 !nmg_find_v_in_face( v2, fu2 ) )
02777                                 continue;
02778 
02779                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
02780                                 bu_log( "Making EU x%x an intersect line for face cutting\n", eu );
02781 
02782                         for( BU_LIST_FOR( vu, vertexuse, &v1->vu_hd ) )
02783                         {
02784                                 struct faceuse *fu;
02785 
02786                                 fu = nmg_find_fu_of_vu( vu );
02787 
02788                                 if( fu == fu2 )
02789                                         nmg_enlist_one_vu( is, vu, 0.0 );
02790                         }
02791 
02792                         for( BU_LIST_FOR( vu, vertexuse, &v2->vu_hd ) )
02793                         {
02794                                 struct faceuse *fu;
02795 
02796                                 fu = nmg_find_fu_of_vu( vu );
02797 
02798                                 if( fu == fu2 )
02799                                         nmg_enlist_one_vu( is, vu, 1.0 );
02800                         }
02801 
02802                         /* Now do face cutting */
02803                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
02804                                 bu_log( "Calling face cutter for fu2 x%x\n", fu2 );
02805                         nmg_fcut_face_2d( is->l2, is->mag2, fu2, fu1, &is->tol );
02806 
02807                         bu_ptbl_reset( is->l1);
02808                         bu_ptbl_reset( is->l2);
02809                 }
02810         }
02811 
02812         for( BU_LIST_FOR( lu, loopuse, &fu2->lu_hd ) )
02813         {
02814                 struct edgeuse *eu;
02815 
02816                 NMG_CK_LOOPUSE( lu );
02817 
02818                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
02819                         continue;
02820 
02821                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02822                 {
02823                         struct vertexuse *vu;
02824                         struct vertex *v1,*v2;
02825 
02826                         NMG_CK_EDGEUSE( eu );
02827 
02828                         v1 = eu->vu_p->v_p;
02829                         NMG_CK_VERTEX( v1 );
02830                         v2 = eu->eumate_p->vu_p->v_p;
02831                         NMG_CK_VERTEX( v2 );
02832 
02833                         if( !nmg_find_v_in_face( v1, fu1 ) ||
02834                                 !nmg_find_v_in_face( v2, fu1 ) )
02835                                 continue;
02836 
02837                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
02838                                 bu_log( "Making EU x%x an intersect line for face cutting\n", eu );
02839 
02840                         for( BU_LIST_FOR( vu, vertexuse, &v1->vu_hd ) )
02841                         {
02842                                 struct faceuse *fu;
02843 
02844                                 fu = nmg_find_fu_of_vu( vu );
02845 
02846                                 if( fu == fu1 )
02847                                         nmg_enlist_one_vu( is, vu, 0.0 );
02848                         }
02849 
02850                         for( BU_LIST_FOR( vu, vertexuse, &v2->vu_hd ) )
02851                         {
02852                                 struct faceuse *fu;
02853 
02854                                 fu = nmg_find_fu_of_vu( vu );
02855 
02856                                 if( fu == fu1 )
02857                                         nmg_enlist_one_vu( is, vu, 1.0 );
02858                         }
02859 
02860                         /* Now do face cutting */
02861                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
02862                                 bu_log( "Calling face cutter for fu1 x%x\n", fu1 );
02863                         nmg_fcut_face_2d( is->l1, is->mag1, fu1, fu2, &is->tol );
02864 
02865                         bu_ptbl_reset( is->l1);
02866                         bu_ptbl_reset( is->l2);
02867                 }
02868         }
02869         if( mag1 )
02870                 bu_free( (char *)mag1, "mag1" );
02871         if( mag2 )
02872                 bu_free( (char *)mag2, "mag2" );
02873 
02874         bu_ptbl_free( is->l1);
02875         bu_ptbl_free( is->l2);
02876 }
02877 
02878 /**
02879  *                      N M G _ I S E C T _ T W O _ F A C E 2 P
02880  *
02881  *  Manage the mutual intersection of two 3-D coplanar planar faces.
02882  *
02883  *  The big challenge in this routine comes from the fact that
02884  *  loopuses can come and go as the facecutter operates.
02885  *  Thus, after a call to nmg_isect_edge2p_face2p(), the current
02886  *  loopuse structure may be invalid.
02887  *  The intersection operations being performed here never delete
02888  *  edgeuses, only split existing ones and add new ones.
02889  *  It might reduce complexity to unbreak edges in here, but that
02890  *  would violate the assumption of edgeuses not vanishing.
02891  *
02892  *  Called by -
02893  *      nmg_isect_two_generic_faces()
02894  *
02895  *  Call tree -
02896  *      nmg_isect_vert2p_face2p()
02897  *      nmg_isect_edge2p_face2p()
02898  *              nmg_isect_vert2p_face2p()
02899  *              nmg_isect_line2_face2p()
02900  *              nmg_purge_unwanted_intersection_points()
02901  *              nmg_face_cutjoin()
02902  */
02903 #if 0
02904 static void
02905 nmg_isect_two_face2p( is, fu1, fu2 )
02906 struct nmg_inter_struct *is;
02907 struct faceuse          *fu1, *fu2;
02908 {
02909         struct model            *m;
02910         struct loopuse          *lu;
02911         struct edgeuse          *eu;
02912         struct vertexuse        *vu;
02913         unsigned char           *tags;
02914         int                     tagsize;
02915 
02916         NMG_CK_INTER_STRUCT(is);
02917         NMG_CK_FACEUSE(fu1);
02918         NMG_CK_FACEUSE(fu2);
02919         m = fu1->s_p->r_p->m_p;
02920         NMG_CK_MODEL(m);
02921 
02922         is->l1 = 0;
02923         is->l2 = 0;
02924         is->fu1 = fu1;
02925         is->fu2 = fu2;
02926 
02927         if (rt_g.NMG_debug & DEBUG_POLYSECT)
02928                 bu_log("nmg_isect_two_face2p(fu1=x%x, fu2=x%x) START\n", fu1, fu2);
02929 
02930         /* Allocate map of edgegeom's visited */
02931         tagsize = 4 * m->maxindex+1;
02932         tags = (unsigned char *)bu_calloc( tagsize, 1, "nmg_isect_two_face2p() tags[]" );
02933 
02934 /* XXX A vastly better strategy would be to build a list of vu's and eu's,
02935  * XXX and then intersect them with the other face.
02936  * XXX loopuses can come and go as loops get cutjoin'ed, but at this
02937  * XXX stage edgeuses are created, but never deleted.
02938  * XXX This way, the process should converge in 2 interations, rather than N.
02939  */
02940 
02941         /* For every edge in f1, intersect with f2, incl. cutjoin */
02942         bzero( (char *)tags, tagsize );
02943 f1_again:
02944         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
02945                 nmg_fu_touchingloops(fu1);
02946                 nmg_fu_touchingloops(fu2);
02947                 nmg_region_v_unique( fu1->s_p->r_p, &is->tol );
02948                 nmg_region_v_unique( fu2->s_p->r_p, &is->tol );
02949         }
02950         for( BU_LIST_FOR( lu, loopuse, &fu1->lu_hd ) )  {
02951                 NMG_CK_LOOPUSE(lu);
02952                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC )  {
02953                         is->l1 = 0;
02954                         is->l2 = 0;
02955                         vu = BU_LIST_FIRST( vertexuse, &lu->down_hd );
02956                         if( !NMG_INDEX_FIRST_TIME(tags, vu->v_p) )  continue;
02957                         nmg_isect_vert2p_face2p( is, vu, fu2 );
02958                         continue;
02959                 }
02960                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
02961                         struct edge_g_lseg      *eg;
02962 
02963                         NMG_CK_EDGEUSE(eu);
02964                         eg = eu->g.lseg_p;
02965                         /* If this eu's eg has been seen before, skip on. */
02966                         if( eg && !NMG_INDEX_FIRST_TIME(tags, eg) )  continue;
02967 
02968                         if( nmg_isect_edge2p_face2p( is, eu, fu2, fu1 ) )  {
02969                                 /* Face topologies have changed */
02970                                 /* This loop might have been joined into another loopuse! */
02971                                 /* XXX Might want to unbreak edges? */
02972                                 goto f1_again;
02973                         }
02974                 }
02975         }
02976 
02977         /* Zap 2d cache, we are switching faces now */
02978         nmg_isect2d_cleanup(is);
02979 
02980         /* For every edge in f2, intersect with f1, incl. cutjoin */
02981         bzero( (char *)tags, tagsize );
02982 f2_again:
02983         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
02984                 nmg_fu_touchingloops(fu1);
02985                 nmg_fu_touchingloops(fu2);
02986                 nmg_region_v_unique( fu1->s_p->r_p, &is->tol );
02987                 nmg_region_v_unique( fu2->s_p->r_p, &is->tol );
02988         }
02989         for( BU_LIST_FOR( lu, loopuse, &fu2->lu_hd ) )  {
02990                 NMG_CK_LOOPUSE(lu);
02991                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC )  {
02992                         is->l1 = 0;
02993                         is->l2 = 0;
02994                         vu = BU_LIST_FIRST( vertexuse, &lu->down_hd );
02995                         if( !NMG_INDEX_FIRST_TIME(tags, vu->v_p) )  continue;
02996                         nmg_isect_vert2p_face2p( is, vu, fu1 );
02997                         continue;
02998                 }
02999                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
03000                         struct edge_g_lseg      *eg;
03001 
03002                         NMG_CK_EDGEUSE(eu);
03003                         eg = eu->g.lseg_p;
03004                         /* If this eu's eg has been seen before, skip on. */
03005                         if( eg && !NMG_INDEX_FIRST_TIME(tags, eg) )  continue;
03006 
03007                         if( nmg_isect_edge2p_face2p( is, eu, fu1, fu2 ) )  {
03008                                 /* Face topologies have changed */
03009                                 goto f2_again;
03010                         }
03011                 }
03012         }
03013         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
03014                 nmg_fu_touchingloops(fu1);
03015                 nmg_fu_touchingloops(fu2);
03016                 nmg_region_v_unique( fu1->s_p->r_p, &is->tol );
03017                 nmg_region_v_unique( fu2->s_p->r_p, &is->tol );
03018         }
03019         bu_free( (char *)tags, "tags[]" );
03020         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03021                 bu_log("nmg_isect_two_face2p(fu1=x%x, fu2=x%x) END\n", fu1, fu2);
03022 }
03023 #endif
03024 /**
03025  *                      N M G _ I S E C T _ L I N E 2 _ E D G E 2 P
03026  *
03027  *  A parallel to nmg_isect_edge2p_edge2p().
03028  *
03029  *  Intersect the line with eu1, from fu1.
03030  *  The resulting vu's are added to "list", not is->l1 or is->l2.
03031  *  fu2 is the "other" face on this intersect line, and is used only
03032  *  when searching for existing vertex structs suitable for re-use.
03033  *
03034  *  Returns -
03035  *      Number of times edge is broken (0 or 1).
03036  */
03037 int
03038 nmg_isect_line2_edge2p(struct nmg_inter_struct *is, struct bu_ptbl *list, struct edgeuse *eu1, struct faceuse *fu1, struct faceuse *fu2)
03039 {
03040         point_t         eu1_start;      /* 2D */
03041         point_t         eu1_end;        /* 2D */
03042         vect_t          eu1_dir;        /* 2D */
03043         fastf_t         dist[2];
03044         int             status;
03045         point_t         hit_pt;         /* 3D */
03046         struct vertexuse        *vu1a, *vu1b;
03047         int                     ret = 0;
03048 
03049         NMG_CK_INTER_STRUCT(is);
03050         BU_CK_PTBL(list);
03051         NMG_CK_EDGEUSE(eu1);
03052         NMG_CK_FACEUSE(fu1);
03053         NMG_CK_FACEUSE(fu2);
03054 
03055         /*
03056          * Important note:  don't use eu1->eumate_p->vu_p here,
03057          * because that vu is in the opposite orientation faceuse.
03058          * Putting those vu's on the intersection line makes for big trouble.
03059          */
03060         vu1a = eu1->vu_p;
03061         vu1b = BU_LIST_PNEXT_CIRC( edgeuse, eu1 )->vu_p;
03062         NMG_CK_VERTEXUSE(vu1a);
03063         NMG_CK_VERTEXUSE(vu1b);
03064 
03065         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
03066                 bu_log("nmg_isect_line2_edge2p(eu1=x%x, fu1=x%x)\n\tvu1a=%x vu1b=%x\n\tv2a=%x v2b=%x\n",
03067                         eu1, fu1,
03068                         vu1a, vu1b,
03069                         vu1a->v_p, vu1b->v_p );
03070         }
03071 
03072         /*
03073          *  The 3D line in is->pt and is->dir is prepared by the caller.
03074          */
03075         nmg_get_2d_vertex( eu1_start, vu1a->v_p, is, &fu1->l.magic );
03076         nmg_get_2d_vertex( eu1_end, vu1b->v_p, is, &fu1->l.magic );
03077         VSUB2_2D( eu1_dir, eu1_end, eu1_start );
03078 
03079         dist[0] = dist[1] = 0;  /* for clean prints, below */
03080 
03081         /* Intersect the line with the edge, in 2D */
03082         status = bn_isect_line2_lseg2( dist, is->pt2d, is->dir2d,
03083                         eu1_start, eu1_dir, &is->tol );
03084 
03085         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
03086                 bu_log("\tbn_isect_line2_lseg2()=%d, dist: %g, %g\n",
03087                         status, dist[0], dist[1] );
03088         }
03089 
03090         if (status < 0)  goto out;      /* No geometric intersection */
03091 
03092         if( status == 0 )  {
03093                 /*
03094                  *  The edge is colinear with the line.
03095                  *  List both vertexuse structures, and return.
03096                  */
03097                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03098                         bu_log("\t\tedge colinear with isect line.  Listing vu1a, vu1b\n");
03099                 nmg_enlist_vu(is, vu1a, 0, MAX_FASTF);
03100                 nmg_enlist_vu(is, vu1b, 0, MAX_FASTF);
03101                 ret = 0;
03102                 goto out;
03103         }
03104 
03105         /* There is only one intersect point.  Break the edge there. */
03106 
03107         VJOIN1( hit_pt, is->pt, dist[0], is->dir );     /* 3D hit */
03108 
03109         /* Edges not colinear. Either list a vertex,
03110          * or break eu1.
03111          */
03112         if( status == 1 || dist[1] == 0 )  {
03113                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03114                         bu_log("\t\tintersect point is vu1a\n");
03115                 if( !bn_pt3_pt3_equal(hit_pt, vu1a->v_p->vg_p->coord, &(is->tol) ) )
03116                         rt_bomb("vu1a does not match calculated point\n");
03117                 nmg_enlist_vu(is, vu1a, 0, MAX_FASTF);
03118                 ret = 0;
03119         } else if( status == 2 || dist[1] == 1 )  {
03120                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03121                         bu_log("\t\tintersect point is vu1b\n");
03122                 if( !bn_pt3_pt3_equal(hit_pt, vu1b->v_p->vg_p->coord, &(is->tol) ) )
03123                         rt_bomb("vu1b does not match calculated point\n");
03124                 nmg_enlist_vu(is, vu1b, 0, MAX_FASTF);
03125                 ret = 0;
03126         } else {
03127                 /* Intersection is in the middle of eu1, split edge */
03128                 struct vertexuse        *vu1_final;
03129                 struct vertex           *new_v;
03130                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
03131                         fastf_t dist;
03132                         int     code;
03133                         bu_log("\t2D: pt2d=(%g, %g), dir2d=(%g, %g)\n",
03134                                 is->pt2d[X], is->pt2d[Y],
03135                                 is->dir2d[X], is->dir2d[Y] );
03136                         bu_log("\t2D: eu1_start=(%g, %g), eu1_dir=(%g, %g)\n",
03137                                 eu1_start[X], eu1_start[Y],
03138                                 eu1_dir[X], eu1_dir[Y] );
03139                         VPRINT("\t3D: is->pt ", is->pt);
03140                         VPRINT("\t3D: is->dir", is->dir);
03141                         bu_log("\t2d: Breaking eu1 at isect.\n");
03142                         VPRINT("  vu1a", vu1a->v_p->vg_p->coord);
03143                         VPRINT("hit_pt", hit_pt);
03144                         VPRINT("  vu1b", vu1b->v_p->vg_p->coord);
03145                         /* XXX Perform a (not-so) quick check */
03146                         code = bn_isect_pt_lseg( &dist, vu1a->v_p->vg_p->coord,
03147                                 vu1b->v_p->vg_p->coord,
03148                                 hit_pt, &(is->tol) );
03149                         bu_log("\tbn_isect_pt_lseg() dist=%g, ret=%d\n", dist, code);
03150                         if( code < 0 )  rt_bomb("3D point not on 3D lseg\n");
03151 
03152                         /* Ensure that the 3D hit_pt is between the end pts */
03153 if( !bn_between(vu1a->v_p->vg_p->coord[X], hit_pt[X], vu1b->v_p->vg_p->coord[X], &(is->tol)) ||
03154     !bn_between(vu1a->v_p->vg_p->coord[Y], hit_pt[Y], vu1b->v_p->vg_p->coord[Y], &(is->tol)) ||
03155     !bn_between(vu1a->v_p->vg_p->coord[Z], hit_pt[Z], vu1b->v_p->vg_p->coord[Z], &(is->tol)) )  {
03156         VPRINT("vu1a", vu1a->v_p->vg_p->coord);
03157         VPRINT("hitp", hit_pt);
03158         VPRINT("vu1b", vu1b->v_p->vg_p->coord);
03159         rt_bomb("nmg_isect_line2_edge2p() hit point not between edge verts!\n");
03160 }
03161 
03162                 }
03163 
03164                 /* if we can't find the appropriate vertex
03165                  * by a geometry search, build a new vertex.
03166                  * Otherwise, re-use the existing one.
03167                  * Can't just search other face, might miss relevant vert.
03168                  */
03169                 new_v = nmg_find_pt_in_model(fu2->s_p->r_p->m_p, hit_pt, &(is->tol));
03170                 vu1_final = nmg_ebreaker(new_v, eu1, &is->tol)->vu_p;
03171                 ret = 1;
03172                 if( !new_v )  {
03173                         nmg_vertex_gv( vu1_final->v_p, hit_pt );        /* 3d geom */
03174                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03175                                 bu_log("\t\tmaking new vertex vu=x%x v=x%x\n",
03176                                         vu1_final, vu1_final->v_p);
03177                 } else {
03178                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03179                                 bu_log("\t\tre-using vertex v=x%x vu=x%x\n", new_v, vu1_final);
03180                 }
03181                 nmg_enlist_vu(is, vu1_final, 0, MAX_FASTF);
03182 
03183                 nmg_ck_face_worthless_edges( fu1 );
03184         }
03185 
03186 out:
03187         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03188                 bu_log("nmg_isect_line2_edge2p(eu1=x%x, fu1=x%x) END ret=%d\n", eu1, fu1, ret);
03189         return ret;
03190 }
03191 
03192 /**
03193  *                      N M G _ I S E C T _ L I N E 2 _ V E R T E X 2
03194  *
03195  *  If this lone vertex lies along the intersect line, then add it to
03196  *  the lists.
03197  *
03198  *  Called from nmg_isect_line2_face2p().
03199  */
03200 void
03201 nmg_isect_line2_vertex2(struct nmg_inter_struct *is, struct vertexuse *vu1, struct faceuse *fu1)
03202 {
03203 
03204         NMG_CK_INTER_STRUCT(is);
03205         NMG_CK_VERTEXUSE(vu1);
03206         NMG_CK_FACEUSE(fu1);
03207 
03208         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03209                 bu_log("nmg_isect_line2_vertex2(vu=x%x)\n", vu1);
03210 
03211         /* Needs to be a 3D comparison */
03212         if( bn_distsq_line3_pt3( is->pt, is->dir, vu1->v_p->vg_p->coord ) > is->tol.dist_sq )
03213                 return;
03214 
03215         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03216                 bu_log("nmg_isect_line2_vertex2(vu=x%x) line hits vertex v=x%x\n", vu1, vu1->v_p);
03217 
03218         nmg_enlist_vu( is, vu1, 0, MAX_FASTF );
03219 }
03220 
03221 /**
03222  *
03223  *  Given two pointer tables filled with edgeuses representing two differentt
03224  *  edge geometry lines, see if there is a common vertex of intersection.
03225  *  If so, enlist the intersection.
03226  *
03227  *  Returns -
03228  *      1       intersection found
03229  *      0       no intersection
03230  */
03231 int
03232 nmg_isect_two_ptbls(struct nmg_inter_struct *is, const struct bu_ptbl *t1, const struct bu_ptbl *t2)
03233 {
03234         const struct edgeuse    **eu1;
03235         const struct edgeuse    **eu2;
03236         struct vertexuse        *vu1a;
03237         struct vertexuse        *vu1b;
03238 
03239         NMG_CK_INTER_STRUCT(is);
03240         BU_CK_PTBL(t1);
03241 
03242         for( eu1 = (const struct edgeuse **)BU_PTBL_LASTADDR(t1);
03243              eu1 >= (const struct edgeuse **)BU_PTBL_BASEADDR(t1); eu1--
03244         )  {
03245                 struct vertex   *v1a;
03246                 struct vertex   *v1b;
03247 
03248                 vu1a = (*eu1)->vu_p;
03249                 vu1b = BU_LIST_PNEXT_CIRC( edgeuse, (*eu1) )->vu_p;
03250                 NMG_CK_VERTEXUSE(vu1a);
03251                 NMG_CK_VERTEXUSE(vu1b);
03252                 v1a = vu1a->v_p;
03253                 v1b = vu1b->v_p;
03254 
03255                 for( eu2 = (const struct edgeuse **)BU_PTBL_LASTADDR(t2);
03256                      eu2 >= (const struct edgeuse **)BU_PTBL_BASEADDR(t2); eu2--
03257                 )  {
03258                         register struct vertexuse       *vu2a;
03259                         register struct vertexuse       *vu2b;
03260 
03261                         vu2a = (*eu2)->vu_p;
03262                         vu2b = BU_LIST_PNEXT_CIRC( edgeuse, (*eu2) )->vu_p;
03263                         NMG_CK_VERTEXUSE(vu2a);
03264                         NMG_CK_VERTEXUSE(vu2b);
03265 
03266                         if( v1a == vu2a->v_p )  {
03267                                 vu1b = vu2a;
03268                                 goto enlist;
03269                         }
03270                         if( v1a == vu2b->v_p )  {
03271                                 vu1b = vu2b;
03272                                 goto enlist;
03273                         }
03274                         if( v1b == vu2a->v_p )  {
03275                                 vu1a = vu1b;
03276                                 vu1b = vu2a;
03277                                 goto enlist;
03278                         }
03279                         if( v1b == vu2b->v_p )  {
03280                                 vu1a = vu1b;
03281                                 vu1b = vu2b;
03282                                 goto enlist;
03283                         }
03284                 }
03285         }
03286         return 0;
03287 enlist:
03288         /* Two vu's are now vu1a, vu1b */
03289         if( nmg_find_s_of_vu(vu1a) == nmg_find_s_of_vu(vu1b) )  {
03290                 vu1b = 0;
03291         }
03292 
03293         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
03294                 bu_log("nmg_isect_two_ptbls() intersection! vu=x%x, vu_dual=x%x\n",
03295                         vu1a, vu1b );
03296         }
03297         nmg_enlist_vu( is, vu1a, vu1b, MAX_FASTF );
03298         return 1;
03299 }
03300 
03301 /**
03302  *                      N M G _ F I N D _ E G _ O N _ L I N E
03303  *
03304  *  Do a geometric search to find an edge_g_lseg on the given line.
03305  *  If the fuser did it's job, there should be only one.
03306  */
03307 struct edge_g_lseg *
03308 nmg_find_eg_on_line(const long int *magic_p, const fastf_t *pt, const fastf_t *dir, const struct bn_tol *tol)
03309 {
03310         struct bu_ptbl  eutab;
03311         struct edgeuse  **eup;
03312         struct edge_g_lseg      *ret = (struct edge_g_lseg *)NULL;
03313         vect_t          dir1, dir2;
03314 
03315         BN_CK_TOL(tol);
03316 
03317         nmg_edgeuse_on_line_tabulate( &eutab, magic_p, pt, dir, tol );
03318 
03319         for( eup = (struct edgeuse **)BU_PTBL_LASTADDR(&eutab);
03320              eup >= (struct edgeuse **)BU_PTBL_BASEADDR(&eutab); eup--
03321         )  {
03322                 if( !ret )  {
03323                         /* No edge_g_lseg found yet, use this one. */
03324                         ret = (*eup)->g.lseg_p;
03325                         continue;
03326                 }
03327                 if( (*eup)->g.lseg_p == ret ) continue; /* OK */
03328 
03329                 /* Found 2 different edge_g_lseg, pick best one */
03330                 VMOVE( dir1, ret->e_dir );
03331                 VUNITIZE(dir1);
03332                 VMOVE( dir2, (*eup)->g.lseg_p->e_dir );
03333                 VUNITIZE(dir2);
03334                 if( fabs(VDOT(dir1,dir)) > fabs(VDOT(dir2,dir)) )  {
03335                         /* ret is better, do nothing */
03336                 } else {
03337                         /* *eup is better, take it instead */
03338                         ret = (*eup)->g.lseg_p;
03339                 }
03340                 bu_log("nmg_find_eg_on_line() 2 different eg's, taking better one.\n");
03341         }
03342         (void)bu_ptbl_free( &eutab);
03343         if( rt_g.NMG_debug & DEBUG_POLYSECT) {
03344                 bu_log("rt_find_eg_on_line( x%x ) ret=x%x\n", magic_p, ret);
03345         }
03346         return ret;
03347 }
03348 
03349 /**
03350  *                      N M G _ K 0 E U
03351  *
03352  *  Kill all 0-length edgeuses that start and end on this vertex.
03353  *
03354  *  Returns -
03355  *      0       If none were found
03356  *      count   Number of 0-length edgeuses killed (not counting mates)
03357  */
03358 int
03359 nmg_k0eu(struct vertex *v)
03360 {
03361         struct edgeuse          *eu;
03362         struct vertexuse        *vu;
03363         int                     count = 0;
03364 
03365         NMG_CK_VERTEX(v);
03366 top:
03367         for( BU_LIST_FOR( vu, vertexuse, &v->vu_hd ) )  {
03368                 NMG_CK_VERTEXUSE(vu);
03369                 if( *vu->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
03370                 eu = vu->up.eu_p;
03371                 NMG_CK_EDGEUSE(eu);
03372                 if( eu->eumate_p->vu_p->v_p != v )  continue;
03373                 bu_log("nmg_k0eu(v=x%x) killing 0-len eu=x%x, mate=x%x\n",
03374                         v, eu, eu->eumate_p);
03375 nmg_pr_eu_briefly(eu, 0);
03376 nmg_pr_eu_briefly(eu->eumate_p, 0);
03377                 if( nmg_keu(eu) )  {
03378                         bu_log("nmg_k0eu() WARNING: parent now has no edgeuses\n");
03379                         /* XXX Now what? */
03380                 }
03381                 count++;
03382                 goto top;       /* vu_hd list is altered by nmg_keu() */
03383         }
03384         return count;
03385 }
03386 
03387 /**
03388  *                      N M G _ R E P A I R _ V _ N E A R _ V
03389  *
03390  *  Attempt to join two vertices which both claim to be the intersection
03391  *  of two lines.  If they are close enough, repair the damage.
03392  *
03393  *  Returns -
03394  *      hit_v   If repair succeeds.  vertex 'v' is now invalid.
03395  *      NULL    If repair fails.
03396  *              If 'bomb' is non-zero, rt_bomb() is called.
03397  */
03398 struct vertex *
03399 nmg_repair_v_near_v(struct vertex *hit_v, struct vertex *v, const struct edge_g_lseg *eg1, const struct edge_g_lseg *eg2, int bomb, const struct bn_tol *tol)
03400 
03401 
03402                                                         /* edge_g_lseg of hit_v */
03403                                                         /* edge_g_lseg of v */
03404 
03405 
03406 {
03407         NMG_CK_VERTEX(hit_v);
03408         NMG_CK_VERTEX(v);
03409         if(eg1) NMG_CK_EDGE_G_LSEG(eg1);        /* eg1 may be NULL */
03410         NMG_CK_EDGE_G_LSEG(eg2);
03411         BN_CK_TOL(tol);
03412 
03413         bu_log("nmg_repair_v_near_v(hit_v=x%x, v=x%x)\n", hit_v, v );
03414 
03415         VPRINT("v  ", v->vg_p->coord);
03416         VPRINT("hit", hit_v->vg_p->coord);
03417         bu_log("dist v-hit=%g, equal=%d\n",
03418                 bn_dist_pt3_pt3(v->vg_p->coord, hit_v->vg_p->coord),
03419                 bn_pt3_pt3_equal(v->vg_p->coord, hit_v->vg_p->coord, tol)
03420             );
03421         if( eg1 )  {
03422                 if( bn_2line3_colinear( eg1->e_pt, eg1->e_dir, eg2->e_pt, eg2->e_dir, 1e5, tol ) )
03423                         rt_bomb("ERROR: nmg_repair_v_near_v() eg1 and eg2 are colinear!\n");
03424                 bu_log("eg1: line/ vu dist=%g, hit dist=%g\n",
03425                         bn_dist_line3_pt3( eg1->e_pt, eg1->e_dir, v->vg_p->coord ),
03426                         bn_dist_line3_pt3( eg1->e_pt, eg1->e_dir, hit_v->vg_p->coord ) );
03427                 bu_log("eg2: line/ vu dist=%g, hit dist=%g\n",
03428                         bn_dist_line3_pt3( eg2->e_pt, eg2->e_dir, v->vg_p->coord ),
03429                         bn_dist_line3_pt3( eg2->e_pt, eg2->e_dir, hit_v->vg_p->coord ) );
03430                 nmg_pr_eg(&eg1->l.magic, 0);
03431                 nmg_pr_eg(&eg2->l.magic, 0);
03432         }
03433 
03434         if( bn_dist_pt3_pt3(v->vg_p->coord,
03435               hit_v->vg_p->coord) < 10 * tol->dist )  {
03436                 struct edgeuse  *eu0;
03437                 bu_log("NOTICE: The intersection of two lines has resulted in 2 different intersect points\n");
03438                 bu_log("  Since the two points are 'close', they are being fused.\n");
03439 
03440                 /* See if there is an edge between them */
03441                 eu0 = nmg_findeu(hit_v, v, (struct shell *)NULL,
03442                         (struct edgeuse *)NULL, 0);
03443                 if( eu0 )  {
03444                         bu_log("DANGER: a 0-length edge is being created eu0=x%x\n", eu0);
03445                 }
03446 
03447                 nmg_jv(hit_v, v);
03448                 (void)nmg_k0eu(hit_v);
03449                 goto out;
03450         }
03451         /* Separation is too great */
03452 /**     if( bomb ) **/
03453                 rt_bomb("nmg_repair_v_near_v() separation is too great to repair.\n");
03454         hit_v = (struct vertex *)NULL;
03455 out:
03456         bu_log("nmg_repair_v_near_v(v=x%x) ret=x%x\n", v, hit_v);
03457         return hit_v;
03458 }
03459 
03460 /**
03461  *  Search all edgeuses referring to this vu's vertex.
03462  *  If the vertex is used by edges on both eg1 and eg2, then it's a "hit"
03463  *  between the two edge geometries.
03464  *  If a new hit happens at a different vertex from a previous hit,
03465  *  that is a fatal error.
03466  *
03467  *  This routine exists only as a support routine for nmg_common_v_2eg().
03468  *
03469  * XXX This is a lame name.
03470  */
03471 struct vertex *
03472 nmg_search_v_eg(const struct edgeuse *eu, int second, const struct edge_g_lseg *eg1, const struct edge_g_lseg *eg2, register struct vertex *hit_v, const struct bn_tol *tol)
03473 
03474                                                 /* 2nd vu on eu, not 1st */
03475 
03476 
03477                                                 /* often will be NULL */
03478 
03479 {
03480         struct vertex                   *v;
03481         register struct vertexuse       *vu1;
03482         register struct edgeuse         *seen1 = (struct edgeuse *)NULL;
03483         register struct edgeuse         *seen2 = (struct edgeuse *)NULL;
03484 
03485         NMG_CK_EDGEUSE(eu);
03486         NMG_CK_EDGE_G_LSEG(eg1);
03487         NMG_CK_EDGE_G_LSEG(eg2);
03488         BN_CK_TOL(tol);
03489 
03490         if( second )  {
03491                 v = BU_LIST_PNEXT_CIRC(edgeuse, eu)->vu_p->v_p;
03492                 if( v != eu->eumate_p->vu_p->v_p )
03493                         rt_bomb("nmg_search_v_eg() next vu not mate's vu?\n");
03494         } else {
03495                 v = eu->vu_p->v_p;
03496         }
03497         NMG_CK_VERTEX(v);
03498 
03499         if( eu->g.lseg_p != eg1 )  rt_bomb("nmg_search_v_eg() eu not on eg1\n");
03500 
03501         /* vu lies on eg1 by topology.  Check this assertion. */
03502         if( bn_distsq_line3_pt3( eg1->e_pt, eg1->e_dir, v->vg_p->coord ) > tol->dist_sq )  {
03503                 VPRINT("v", v->vg_p->coord);
03504                 nmg_pr_eu( eu, (char *)NULL );
03505                 nmg_pr_eg( &eg1->l.magic, 0 );
03506                 rt_bomb("nmg_search_v_eg() eu vertex not on eg line\n");
03507         }
03508 
03509         /* This loop accounts for 30% of the runtime of a boolean! */
03510         for( BU_LIST_FOR( vu1, vertexuse, &v->vu_hd ) )  {
03511                 register struct edgeuse *eu1;
03512 
03513                 if( *vu1->up.magic_p != NMG_EDGEUSE_MAGIC )  continue;
03514                 eu1 = vu1->up.eu_p;
03515                 if( eu1->g.lseg_p == eg1 )  seen1 = eu1;
03516                 if( eu1->g.lseg_p == eg2 )  seen2 = eu1;
03517                 if( !seen1 || !seen2 )  continue;
03518 
03519                 /* Both edge_g's have been seen at 'v', this is a hit. */
03520                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
03521                         bu_log("  seen1=x%x, seen2=x%x, hit_v=x%x, v=x%x\n",
03522                                 seen1, seen2, hit_v, v);
03523                 }
03524                 if( !hit_v )   {
03525                         hit_v = v;
03526                         break;
03527                 }
03528 
03529                 /* Is it a different vertex than hit_v? */
03530                 if( hit_v == v )  break;
03531 
03532                 /* Different vertices, this "can't happen" */
03533                 bu_log("ERROR seen1=x%x, seen2=x%x, hit_v=x%x != v=x%x\n",
03534                         seen1, seen2, hit_v, v);
03535                 if( nmg_repair_v_near_v( hit_v, v, eg1, eg2, 0, tol ) )
03536                         break;
03537 
03538                 rt_bomb("nmg_search_v_eg() two different vertices for intersect point?\n");
03539         }
03540         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
03541                 bu_log("nmg_search_v_eg(eu=x%x, %d, eg1=x%x, eg2=x%x) ret=x%x\n",
03542                         eu, second, eg1, eg2, hit_v);
03543         }
03544         return hit_v;
03545 }
03546 
03547 /**
03548  *                      N M G _ C O M M O N _ V _ 2 E G
03549  *
03550  *  Perform a topology search for a common vertex between two edge geometry
03551  *  lines.
03552  */
03553 struct vertex *
03554 nmg_common_v_2eg(struct edge_g_lseg *eg1, struct edge_g_lseg *eg2, const struct bn_tol *tol)
03555 {
03556         struct edgeuse          *eu1;
03557         struct vertex           *hit_v = (struct vertex *)NULL;
03558         struct bu_list          *midway;        /* &eu->l2, midway into edgeuse */
03559 
03560         NMG_CK_EDGE_G_LSEG(eg1);
03561         NMG_CK_EDGE_G_LSEG(eg2);
03562         BN_CK_TOL(tol);
03563 
03564         if( eg1 == eg2 )
03565                 rt_bomb("nmg_common_v_2eg() eg1 and eg2 are colinear\n");
03566 
03567         /* Scan all edgeuses in the model that use eg1 */
03568         for( BU_LIST_FOR( midway, bu_list, &eg1->eu_hd2 ) )  {
03569                 NMG_CKMAG(midway, NMG_EDGEUSE2_MAGIC, "edgeuse2 [l2]");
03570                 eu1 = BU_LIST_MAIN_PTR( edgeuse, midway, l2 );
03571                 NMG_CK_EDGEUSE(eu1);
03572                 if( eu1->g.lseg_p != eg1 )  rt_bomb("nmg_common_v_2eg() eu disavows eg\n");
03573                 /* Both verts of eu1 lie on line eg1 */
03574                 hit_v = nmg_search_v_eg( eu1, 0, eg1, eg2, hit_v, tol );
03575                 hit_v = nmg_search_v_eg( eu1, 1, eg1, eg2, hit_v, tol );
03576         }
03577         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
03578                 bu_log("nmg_common_v_2eg(eg1=x%x, eg2=x%x) hit_v=x%x\n",
03579                         eg1, eg2, hit_v);
03580         }
03581         return hit_v;
03582 }
03583 
03584 #define VDIST( a, b )   sqrt( (a[X]-b[X])*(a[X]-b[X]) + (a[Y]-b[Y])*(a[Y]-b[Y]) + (a[Z]-b[Z])*(a[Z]-b[Z]) )
03585 #define VDIST_SQ( a, b )        ( (a[X]-b[X])*(a[X]-b[X]) + (a[Y]-b[Y])*(a[Y]-b[Y]) + (a[Z]-b[Z])*(a[Z]-b[Z]) )
03586 
03587 int
03588 nmg_is_vertex_on_inter(struct vertex *v, struct faceuse *fu1, struct faceuse *fu2, struct nmg_inter_struct *is)
03589 {
03590         struct vertex_g *vg;
03591         plane_t pl1,pl2;
03592         int code;
03593         fastf_t dist;
03594 
03595         NMG_CK_VERTEX( v );
03596         NMG_CK_FACEUSE( fu1 );
03597         NMG_CK_FACEUSE( fu2 );
03598         NMG_CK_INTER_STRUCT(is);
03599 
03600         if( nmg_find_v_in_face( v, fu1 ) && nmg_find_v_in_face( v, fu2 ) )
03601                 return( 1 );
03602 
03603         NMG_GET_FU_PLANE( pl1, fu1 );
03604         NMG_GET_FU_PLANE( pl2, fu2 );
03605 
03606         vg = v->vg_p;
03607         NMG_CK_VERTEX_G( vg );
03608 
03609         /* check if vertex is in plane of fu's  */
03610         dist = fabs( DIST_PT_PLANE( vg->coord, pl1 ) );
03611         if( dist > is->tol.dist )
03612                 return( 0 );
03613         dist = fabs( DIST_PT_PLANE( vg->coord, pl2 ) );
03614         if( dist > is->tol.dist )
03615                 return( 0 );
03616 
03617         /* check if it is on intersection line */
03618         if( bn_distsq_line3_pt3( is->pt, is->dir, vg->coord ) > is->tol.dist_sq )
03619                 return( 0 );
03620 
03621         /* check if it is within fu's */
03622         code = nmg_class_pt_fu_except( vg->coord, fu1, (struct loopuse *)NULL,
03623                 (void (*)())NULL, (void (*)())NULL, (char *)NULL, 0, 0, &is->tol );
03624         if( code != NMG_CLASS_AinB )
03625                 return( 0 );
03626 
03627         code = nmg_class_pt_fu_except( vg->coord, fu2, (struct loopuse *)NULL,
03628                 (void (*)())NULL, (void (*)())NULL, (char *)NULL, 0, 0, &is->tol );
03629         if( code != NMG_CLASS_AinB )
03630                 return( 0 );
03631 
03632         return( 1 );
03633 }
03634 
03635 void
03636 nmg_isect_eu_verts(struct edgeuse *eu, struct vertex_g *vg1, struct vertex_g *vg2, struct bu_ptbl *verts, struct bu_ptbl *inters, const struct bn_tol *tol)
03637 {
03638         int i;
03639         struct vertex *v1,*v2;
03640 
03641         NMG_CK_EDGEUSE( eu );
03642         NMG_CK_VERTEX_G( vg1 );
03643         NMG_CK_VERTEX_G( vg2 );
03644         BU_CK_PTBL( verts );
03645         BU_CK_PTBL( inters );
03646         BN_CK_TOL( tol );
03647 
03648         v1 = eu->vu_p->v_p;
03649         v2 = eu->eumate_p->vu_p->v_p;
03650 
03651         for( i=0 ; i<BU_PTBL_END( verts ) ; i++ )
03652         {
03653                 struct vertex *v;
03654                 fastf_t dist;
03655                 point_t pca;
03656                 int code;
03657 
03658                 v = (struct vertex *)BU_PTBL_GET( verts, i );
03659                 if( v == v1 || v == v2 )
03660                 {
03661                         bu_ptbl_ins_unique( inters, (long *)v );
03662                         continue;
03663                 }
03664 
03665                 code = bn_dist_pt3_lseg3( &dist, pca, vg1->coord,
03666                                 vg2->coord, v->vg_p->coord, tol );
03667 
03668                 if( code )
03669                         continue;
03670 
03671                 bu_ptbl_ins_unique( inters, (long *)v );
03672         }
03673 
03674         return;
03675 }
03676 
03677 void
03678 nmg_isect_eu_eu(struct edgeuse *eu1, struct vertex_g *vg1a, struct vertex_g *vg1b, fastf_t *dir1, struct edgeuse *eu2, struct bu_ptbl *verts, struct bu_ptbl *inters, const struct bn_tol *tol)
03679 {
03680         struct model *m;
03681         struct vertex_g *vg2a,*vg2b;
03682         vect_t dir2;
03683         fastf_t dist[2];
03684         int code;
03685         point_t hit_pt;
03686         vect_t diff;
03687 
03688         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03689                 bu_log( "nmg_isect_eu_eu( eu1=x%x, eu2=x%x )\n", eu1, eu2 );
03690 
03691         NMG_CK_EDGEUSE( eu1 );
03692         NMG_CK_VERTEX_G( vg1a );
03693         NMG_CK_VERTEX_G( vg1b );
03694         NMG_CK_EDGEUSE( eu2 );
03695         BN_CK_TOL( tol );
03696         BU_CK_PTBL( inters );
03697         BU_CK_PTBL( verts );
03698 
03699         m = nmg_find_model( &eu1->l.magic );
03700         NMG_CK_MODEL( m );
03701 
03702         vg2a = eu2->vu_p->v_p->vg_p;
03703         NMG_CK_VERTEX_G( vg2a );
03704 
03705         vg2b = eu2->eumate_p->vu_p->v_p->vg_p;
03706         NMG_CK_VERTEX_G( vg2b );
03707 
03708         VSUB2( dir2, vg2b->coord, vg2a->coord );
03709 
03710         code = bn_isect_lseg3_lseg3( dist, vg1a->coord, dir1, vg2a->coord, dir2, tol );
03711 
03712         if( code < 0 )
03713         {
03714                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03715                         bu_log( "\tnmg_isect_eu_eu: No intersection\n" );
03716                 return;
03717         }
03718 
03719         if( code == 1 )
03720         {
03721                 point_t hit_pt1,hit_pt2;
03722                 struct vertex *v=(struct vertex *)NULL;
03723                 struct edgeuse *new_eu;
03724 
03725                 /* normal intersection (one point ) */
03726 
03727                 if( eu1->vu_p->v_p == eu2->vu_p->v_p ||
03728                     eu1->vu_p->v_p == eu2->eumate_p->vu_p->v_p ||
03729                     eu1->eumate_p->vu_p->v_p == eu2->vu_p->v_p ||
03730                     eu1->eumate_p->vu_p->v_p == eu2->eumate_p->vu_p->v_p )
03731                         return;
03732 
03733                 if( dist[0] == 0.0 || dist[0] == 1.0 )
03734                         return;
03735 
03736                 if( dist[1] == 0.0 )
03737                 {
03738                         bu_ptbl_ins_unique( inters, (long *)eu2->vu_p->v_p );
03739                         return;
03740                 }
03741                 if( dist[1] == 1.0 )
03742                 {
03743                         bu_ptbl_ins_unique( inters, (long *)eu2->eumate_p->vu_p->v_p );
03744                         return;
03745                 }
03746 
03747                 VJOIN1( hit_pt1, vg1a->coord, dist[0], dir1 );
03748                 VJOIN1( hit_pt2, vg2a->coord, dist[1], dir2 );
03749 
03750                 VBLEND2( hit_pt, 0.5, hit_pt1, 0.5, hit_pt2 );
03751 
03752                 v = nmg_find_pt_in_model( m, hit_pt, tol );
03753 
03754                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03755                 {
03756                         bu_log( "nmg_isect_eu_eu: intersection at (%g %g %g)\n", V3ARGS( hit_pt ) );
03757                         bu_log( "splitting eu x%x at v=x%x\n", eu2, v );
03758                 }
03759                 new_eu = nmg_esplit( v, eu2, 1 );
03760                 if( !v )
03761                 {
03762                         v = new_eu->vu_p->v_p;
03763                         nmg_vertex_gv( v, hit_pt );
03764                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03765                                 bu_log( "\tcreated new vertex x%x\n", v );
03766                 }
03767                 bu_ptbl_ins_unique( inters, (long *)v );
03768                 bu_ptbl_ins_unique( verts, (long *)v );
03769                 return;
03770         }
03771 
03772         /* code == 0, could be two intersection points
03773          * But there should be no vertex creation here
03774          */
03775 
03776         VSUB2( diff, vg2a->coord, vg1a->coord );
03777         if( VDOT( diff, dir1 ) > 0.0 )
03778         {
03779                 VSUB2( diff, vg1b->coord, vg2a->coord );
03780                 if( VDOT( diff, dir1 ) > 0.0 )
03781                         bu_ptbl_ins_unique( inters, (long *)eu2->vu_p->v_p );
03782         }
03783 
03784         VSUB2( diff, vg2b->coord, vg1a->coord );
03785         if( VDOT( diff, dir1 ) > 0.0 )
03786         {
03787                 VSUB2( diff, vg1b->coord, vg2b->coord );
03788                 if( VDOT( diff, dir1 ) > 0.0 )
03789                         bu_ptbl_ins_unique( inters, (long *)eu2->eumate_p->vu_p->v_p );
03790         }
03791 }
03792 
03793 void
03794 nmg_isect_eu_fu(struct nmg_inter_struct *is, struct bu_ptbl *verts, struct edgeuse *eu, struct faceuse *fu)
03795 {
03796         struct model *m;
03797         struct vertex_g *vg1,*vg2;
03798         struct loopuse *lu;
03799         plane_t pl;
03800         fastf_t dist;
03801         fastf_t eu_len;
03802         fastf_t one_over_len;
03803         point_t hit_pt;
03804         vect_t edir;
03805         vect_t dir;
03806         struct bu_ptbl inters;
03807         fastf_t *inter_dist;
03808         int i;
03809 
03810         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03811                 bu_log( "nmg_isect_eu_fu: eu=x%x, fu=x%x START\n", eu, fu );
03812 
03813         NMG_CK_INTER_STRUCT( is );
03814         NMG_CK_FACEUSE( fu );
03815         NMG_CK_EDGEUSE( eu );
03816         BU_CK_PTBL( verts );
03817 
03818         if( nmg_find_fu_of_eu( eu ) == fu )
03819         {
03820                 bu_log( "nmg_isect_eu_fu() called with eu (x%x) from its own fu (x%x)\n",eu , fu );
03821                 rt_bomb( "nmg_isect_eu_fu() called with eu from its own fu" );
03822         }
03823 
03824         m = nmg_find_model( &fu->l.magic );
03825         NMG_CK_MODEL( m );
03826         if( nmg_find_model( &eu->l.magic ) != m )
03827         {
03828                 bu_log( "nmg_isect_eu_fu() called with EU (x%x) from model (x%x)\n", eu, nmg_find_model( &eu->l.magic ) );
03829                 bu_log( "\tand FU (x%x) from model (x%x)\n", fu, m );
03830                 rt_bomb( "nmg_isect_eu_fu() called with EU and FU from different models" );
03831         }
03832 
03833         vg1 = eu->vu_p->v_p->vg_p;
03834         NMG_CK_VERTEX_G( vg1 );
03835         vg2 = eu->eumate_p->vu_p->v_p->vg_p;
03836         NMG_CK_VERTEX_G( vg2 );
03837 
03838         VSUB2( dir, vg2->coord, vg1->coord );
03839         VMOVE( edir, dir );
03840         eu_len = MAGNITUDE( dir );
03841         if( eu_len < is->tol.dist || eu_len < SMALL_FASTF )
03842         {
03843                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03844                         bu_log( "\tnmg_isec_eu_fu: 0 length edge\n" );
03845                 return;
03846         }
03847 
03848         one_over_len = 1.0/eu_len;
03849         VSCALE( dir, dir, one_over_len );
03850 
03851         NMG_GET_FU_PLANE( pl, fu );
03852         /* check if edge line intersects plane of fu */
03853         if( bn_isect_line3_plane( &dist, vg1->coord, dir, pl, &is->tol ) < 1 )
03854         {
03855                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03856                         bu_log( "\tnmg_isec_eu_fu: no intersection\n" );
03857                 return;
03858         }
03859 #if 0
03860         /* make sure intersection is within limits of eu */
03861         if( dist < (-is->tol.dist) || dist > eu_len+is->tol.dist )
03862         {
03863                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03864                         bu_log( "\tnmg_isec_eu_fu: intersection beyond ends of EU\n" );
03865                 return;
03866         }
03867 
03868         if( dist <= is->tol.dist )
03869         {
03870                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03871                         bu_log( "\tintersection at eu_vu_p\n" );
03872                 (void)nmg_make_dualvu( eu->vu_p->v_p, fu, &is->tol );
03873                 return;
03874         }
03875 
03876         if( dist >= eu_len - is->tol.dist )
03877         {
03878                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03879                         bu_log( "\tintersection at eu->eumate_p->vu_p\n" );
03880                 (void)nmg_make_dualvu( eu->eumate_p->vu_p->v_p, fu, &is->tol );
03881                 return;
03882         }
03883 #endif
03884         VJOIN1( hit_pt, vg1->coord, dist, dir );
03885 
03886         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03887                 bu_log( "\tintersection point at (%g %g %g)\n", V3ARGS( hit_pt ) );
03888 
03889         /* create a list of intersection vertices */
03890         bu_ptbl_init( &inters, 64, " &inters");
03891 
03892         /* add vertices from fu to list */
03893         nmg_isect_eu_verts( eu, vg1, vg2, verts, &inters, &is->tol );
03894 
03895         /* break FU EU's that intersect our eu, and put vertices on list */
03896         for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )
03897         {
03898                 struct edgeuse *eu_fu;
03899 
03900                 NMG_CK_LOOPUSE( lu );
03901 
03902                 /* vertices of FU are handled above */
03903                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
03904                         continue;
03905 
03906                 for( BU_LIST_FOR( eu_fu, edgeuse, &lu->down_hd ) )
03907                 {
03908                         NMG_CK_EDGEUSE( eu_fu );
03909 
03910                         nmg_isect_eu_eu( eu, vg1, vg2, edir, eu_fu, verts, &inters, &is->tol );
03911 
03912                 }
03913         }
03914 
03915         /* Now break eu at every vertex in the "inters" list */
03916 
03917         if( BU_PTBL_END( &inters ) == 0 )
03918         {
03919                 struct vertex *v=(struct vertex *)NULL;
03920                 int class;
03921                 fastf_t dist_to_plane;
03922 
03923                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03924                         bu_log( "\tNo intersection points found\n" );
03925 
03926                 /* check if EU endpoints are within tolerance of FU
03927                  * If so, the endpoint is the intersection and nothing to do
03928                  */
03929                 dist_to_plane = DIST_PT_PLANE( vg1->coord, pl );
03930                 if( dist_to_plane < 0.0 )
03931                         dist_to_plane = (-dist_to_plane);
03932                 if( dist_to_plane <= is->tol.dist )
03933                 {
03934                         /* check if hit point is within fu */
03935                         class = nmg_class_pt_fu_except( vg1->coord, fu, (struct loopuse *)NULL,
03936                                 0, 0, (char *)NULL, 0, 0, &is->tol );
03937                         if( class != NMG_CLASS_AinB )
03938                                 goto out;
03939 
03940                         v = eu->vu_p->v_p;
03941                         if( v && !nmg_find_v_in_face( v, fu ) )
03942                         {
03943                                 struct vertexuse *new_vu;
03944 
03945                                 new_vu = nmg_make_dualvu( v, fu, &is->tol );
03946                                 bu_ptbl_ins_unique( verts, (long *)new_vu->v_p );
03947                         }
03948                         goto out;
03949                 }
03950 
03951                 dist_to_plane = DIST_PT_PLANE( vg2->coord, pl );
03952                 if( dist_to_plane < 0.0 )
03953                         dist_to_plane = (-dist_to_plane);
03954                 if( dist_to_plane <= is->tol.dist )
03955                 {
03956                         /* check if hit point is within fu */
03957                         class = nmg_class_pt_fu_except( vg2->coord, fu, (struct loopuse *)NULL,
03958                                 0, 0, (char *)NULL, 0, 0, &is->tol );
03959                         if( class != NMG_CLASS_AinB )
03960                                 goto out;
03961 
03962                         v = eu->eumate_p->vu_p->v_p;
03963                         if( v && !nmg_find_v_in_face( v, fu ) )
03964                         {
03965                                 struct vertexuse *new_vu;
03966 
03967                                 new_vu = nmg_make_dualvu( v, fu, &is->tol );
03968                                 bu_ptbl_ins_unique( verts, (long *)new_vu->v_p );
03969                         }
03970                         goto out;
03971                 }
03972 
03973                 /* no vertices found, we might need to create a self loop */
03974 
03975                 /* make sure intersection is within limits of eu */
03976                 if( dist < (-is->tol.dist) || dist > eu_len+is->tol.dist )
03977                 {
03978                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
03979                                 bu_log( "\tnmg_isec_eu_fu: intersection beyond ends of EU\n" );
03980                         goto out;
03981                 }
03982 
03983                 /* check if hit_point is within tolerance of an end of eu */
03984                 if( VDIST_SQ( hit_pt, vg1->coord ) <= is->tol.dist_sq )
03985                 {
03986                         v = eu->vu_p->v_p;
03987                         VMOVE( hit_pt, vg1->coord );
03988                 }
03989                 else if( VDIST_SQ( hit_pt, vg2->coord ) <= is->tol.dist_sq )
03990                 {
03991                         v = eu->eumate_p->vu_p->v_p;
03992                         VMOVE( hit_pt, vg2->coord );
03993                 }
03994 
03995                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
03996                 {
03997                         bu_log( "\tHit point is not within tolerance of eu endpoints\n" );
03998                         bu_log( "\t\thit_pt=( %g %g %g ), eu=(%g %g %g)<->(%g %g %g)\n",
03999                                 V3ARGS( hit_pt), V3ARGS( vg1->coord ), V3ARGS( vg2->coord ) );
04000                 }
04001 
04002                 /* check if hit point is within fu */
04003                 class = nmg_class_pt_fu_except( hit_pt, fu, (struct loopuse *)NULL,
04004                         0, 0, (char *)NULL, 0, 0, &is->tol );
04005 
04006                 if( class == NMG_CLASS_AinB )
04007                 {
04008                         struct edgeuse *new_eu;
04009 
04010                         /* may need to split eu */
04011                         if( !v )
04012                                 v = nmg_find_pt_in_model( m, hit_pt, &is->tol );
04013                         if( v != eu->vu_p->v_p && v != eu->eumate_p->vu_p->v_p )
04014                         {
04015                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
04016                                         bu_log( "\tsplitting eu (x%x) at hit_pt (v=x%x)\n", eu, v );
04017 
04018                                 new_eu = nmg_esplit( v, eu, 1 );
04019                                 if( !v )
04020                                 {
04021                                         v = new_eu->vu_p->v_p;
04022                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04023                                                 bu_log( "\tnew vertex at hit point is x%x\n", v );
04024                                         nmg_vertex_gv( v, hit_pt );
04025                                 }
04026                         }
04027 
04028                         if( v && !nmg_find_v_in_face( v, fu ) )
04029                         {
04030                                 struct vertexuse *new_vu;
04031 
04032                                 new_vu = nmg_make_dualvu( v, fu, &is->tol );
04033                                 bu_ptbl_ins_unique( verts, (long *)new_vu->v_p );
04034                         }
04035 
04036                 }
04037                 goto out;
04038         }
04039 
04040         if( BU_PTBL_END( &inters ) == 1 )
04041         {
04042                 struct vertex *v;
04043 
04044                 /* only one vertex, just split */
04045                 v = (struct vertex *)BU_PTBL_GET( &inters, 0 );
04046                 NMG_CK_VERTEX( v );
04047 
04048                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
04049                         bu_log( "Only one intersect vertex (x%x), just split all EU's at (x%x)\n", v, eu );
04050 
04051                 if( v == eu->vu_p->v_p || v == eu->eumate_p->vu_p->v_p )
04052                         goto out;
04053 
04054                 (void)nmg_break_all_es_on_v( &m->magic, v, &is->tol );
04055 
04056                 goto out;
04057         }
04058 
04059         /* must do them in order from furthest to nearest */
04060         inter_dist = (fastf_t *)bu_calloc( BU_PTBL_END( &inters ), sizeof( fastf_t ),
04061                 "nmg_isect_eu_fu: inter_dist" );
04062 
04063         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04064                 bu_log( "%d intersect vertices along eu (x%x)\n", BU_PTBL_END( &inters ), eu );
04065 
04066         for( i=0 ; i<BU_PTBL_END( &inters ) ; i++ )
04067         {
04068                 struct vertex *v;
04069                 struct vertex_g *vg;
04070                 vect_t diff;
04071 
04072                 v = (struct vertex *)BU_PTBL_GET( &inters, i );
04073                 NMG_CK_VERTEX( v );
04074                 vg = v->vg_p;
04075                 NMG_CK_VERTEX_G( vg );
04076 
04077                 VSUB2( diff, vg->coord, vg1->coord );
04078                 if( VDOT( diff, dir ) < 0.0 )
04079                         rt_bomb( "nmg_isect_eu_fu: intersection point not on eu\n" );
04080 
04081                 inter_dist[i] = MAGSQ( diff );
04082         }
04083 
04084         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04085         {
04086                 bu_log( "Intersect vertices along eu x%x:\n", eu );
04087                 for( i=0 ; i<BU_PTBL_END( &inters ) ; i++ )
04088                         bu_log( "%d x%x %g\n", i+1, BU_PTBL_GET( &inters, i ), inter_dist[i] );
04089         }
04090 
04091         while( 1 )
04092         {
04093                 struct vertex *v;
04094                 fastf_t max_dist;
04095                 int index_at_max;
04096 
04097                 max_dist = (-1.0);
04098                 index_at_max = (-1);
04099 
04100                 for( i=0 ; i<BU_PTBL_END( &inters ) ; i++ )
04101                 {
04102                         if( inter_dist[i] > max_dist )
04103                         {
04104                                 max_dist = inter_dist[i];
04105                                 index_at_max = i;
04106                         }
04107                 }
04108 
04109                 if( index_at_max < 0 )
04110                         break;
04111 
04112                 v = (struct vertex *)BU_PTBL_GET( &inters, index_at_max );
04113                 NMG_CK_VERTEX( v );
04114 
04115                 if( v != eu->vu_p->v_p && v != eu->eumate_p->vu_p->v_p )
04116                 {
04117                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04118                                 bu_log( "Breaking edges at vertex #%d, dist=%g, v=x%x\n", i+1, inter_dist[i], v );
04119                         (void)nmg_break_all_es_on_v( &m->magic, v, &is->tol );
04120                 }
04121 
04122                 inter_dist[index_at_max] = (-10.0);
04123         }
04124 
04125         bu_free( (char *)inter_dist, "nmg_isect_eu_fu: inter_dist" );
04126 
04127 out:
04128         bu_ptbl_free( &inters);
04129 
04130         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04131                 bu_log( "nmg_isect_eu_fu: eu=x%x, fu=x%x END\n", eu, fu );
04132 
04133 }
04134 
04135 void
04136 nmg_isect_fu_jra(struct nmg_inter_struct *is, struct faceuse *fu1, struct faceuse *fu2, struct bu_ptbl *eu1_list, struct bu_ptbl *eu2_list)
04137 {
04138         struct model *m;
04139         struct bu_ptbl verts1,verts2;
04140         struct loopuse *lu;
04141         int i;
04142 
04143         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04144                 bu_log( "nmg_isect_fu_jra( fu1=x%x, fu2=x%x ) START\n", fu1, fu2 );
04145 
04146         NMG_CK_INTER_STRUCT(is);
04147         NMG_CK_FACEUSE(fu1);
04148         NMG_CK_FACEUSE(fu2);
04149         BU_CK_PTBL(eu1_list);
04150         BU_CK_PTBL(eu2_list);
04151 
04152         m = nmg_find_model( &fu1->l.magic );
04153         NMG_CK_MODEL( m );
04154 
04155         nmg_vertex_tabulate( &verts2, &fu2->l.magic );
04156 
04157         /* Intersect fu1 edgeuses */
04158         for( BU_LIST_FOR( lu, loopuse, &fu1->lu_hd ) )
04159         {
04160                 struct edgeuse *eu;
04161 
04162                 NMG_CK_LOOPUSE( lu );
04163 
04164                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
04165                         continue;
04166 
04167                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
04168                 {
04169                         NMG_CK_EDGEUSE( eu );
04170 
04171                         nmg_isect_eu_fu( is, &verts2, eu, fu2 );
04172                 }
04173         }
04174 
04175         bu_ptbl_free( &verts2);
04176         nmg_vertex_tabulate( &verts1, &fu1->l.magic );
04177 
04178         /* now intersect fu2 edgeuses */
04179         for( BU_LIST_FOR( lu, loopuse, &fu2->lu_hd ) )
04180         {
04181                 struct edgeuse *eu;
04182 
04183                 NMG_CK_LOOPUSE( lu );
04184 
04185                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
04186                         continue;
04187 
04188                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
04189                 {
04190                         NMG_CK_EDGEUSE( eu );
04191 
04192                         nmg_isect_eu_fu( is, &verts1, eu, fu1 );
04193                 }
04194         }
04195 
04196         /* check for existing vertices along intersection */
04197         bu_ptbl_free( &verts1);
04198 
04199         /* XXXX this is the second time this tabulate is being done,
04200          * but for now it's safer this way
04201          */
04202         nmg_vertex_tabulate( &verts1, &fu1->l.magic );
04203         nmg_vertex_tabulate( &verts2, &fu2->l.magic );
04204 
04205         /* merge the two lists */
04206         for( i=0 ; i<BU_PTBL_END( &verts2 ) ; i++ )
04207         {
04208                 struct vertex *v;
04209 
04210                 v = (struct vertex *)BU_PTBL_GET( &verts2, i );
04211                 NMG_CK_VERTEX( v );
04212 
04213                 bu_ptbl_ins_unique( &verts1, (long *)v );
04214         }
04215         bu_ptbl_free( &verts2);
04216 
04217         for( i=0 ; i< BU_PTBL_END( &verts1 ) ; i++ )
04218         {
04219                 struct vertex *v;
04220                 struct vertexuse *vu;
04221                 fastf_t dist;
04222 
04223                 v = (struct vertex *)BU_PTBL_GET( &verts1, i );
04224                 NMG_CK_VERTEX( v );
04225 
04226                 if( !nmg_is_vertex_on_inter( v, fu1, fu2, is ) )
04227                         continue;
04228 
04229                 /* calculate distance along intersect ray */
04230                 dist = VDIST( is->pt, v->vg_p->coord );
04231 
04232                 /* this vertex is on the intersection line
04233                  * add all uses from fu1 and fu2 to intersection list
04234                  */
04235                 for( BU_LIST_FOR( vu, vertexuse, &v->vu_hd ) )
04236                 {
04237                         struct faceuse *fu_tmp;
04238 
04239                         fu_tmp = nmg_find_fu_of_vu( vu );
04240                         if( fu_tmp == fu1 || fu_tmp == fu2 )
04241                         {
04242                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
04243                                         bu_log( "\tenlisting vu x%x (x%x) from fu (x%x)\n", vu, v, fu_tmp );
04244                                 nmg_enlist_one_vu( is, vu, dist );
04245                         }
04246                 }
04247         }
04248 
04249         bu_ptbl_free( &verts1);
04250 
04251         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04252                 bu_log( "nmg_isect_fu_jra( fu1=x%x, fu2=x%x ) END\n", fu1, fu2 );
04253 }
04254 
04255 /**
04256  *                      N M G _ I S E C T _ L I N E 2 _ F A C E 2 P
04257  *
04258  * HEART
04259  *
04260  *  For each distinct edge_g_lseg LINE on the face (composed of potentially many
04261  *  edgeuses and many different edges), intersect with the edge_g_lseg LINE
04262  *  which represents the face/face intersection line.
04263  *
04264  *  Note that the geometric intersection of the two faces is
04265  *  stored in is->pt and is->dir.
04266  *  If is->on_eg is set, it is the callers' responsibility to make sure
04267  *  it is not much different than the original geometric one.
04268  *
04269  *  Go to great pains to ensure that two non-colinear lines intersect
04270  *  at either 0 or 1 points, and no more.
04271  *
04272  *  Called from -
04273  *      nmg_isect_edge2p_face2p()
04274  *      nmg_isect_two_face3p()
04275  */
04276 void
04277 nmg_isect_line2_face2pNEW(struct nmg_inter_struct *is, struct faceuse *fu1, struct faceuse *fu2, struct bu_ptbl *eu1_list, struct bu_ptbl *eu2_list)
04278 {
04279         struct bu_ptbl          eg_list;
04280         struct edge_g_lseg      **eg1;
04281         struct edgeuse          *eu1;
04282         struct edgeuse          *eu2;
04283         fastf_t                 dist[2];
04284         int                     code;
04285         point_t                 eg_pt2d;        /* 2D */
04286         vect_t                  eg_dir2d;       /* 2D */
04287         struct loopuse          *lu1;
04288         point_t                 hit3d;
04289         point_t                 hit2d;          /* 2D */
04290         struct edgeuse          *new_eu;
04291         int                     eu1_index;
04292         int                     eu2_index;
04293         int                     class;
04294 
04295         NMG_CK_INTER_STRUCT(is);
04296         NMG_CK_FACEUSE(fu1);
04297         NMG_CK_FACEUSE(fu2);
04298         BU_CK_PTBL(eu1_list);
04299         BU_CK_PTBL(eu2_list);
04300 
04301         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04302                 bu_log("nmg_isect_line2_face2pNEW(, fu1=x%x, fu2=x%x) on_eg=x%x\n", fu1, fu2, is->on_eg);
04303 
04304         /* Project the intersect line into 2D.  Build matrix first. */
04305         nmg_isect2d_prep( is, &fu1->l.magic );
04306         /* XXX Need subroutine for this!! */
04307         MAT4X3PNT( is->pt2d, is->proj, is->pt );
04308         MAT4X3VEC( is->dir2d, is->proj, is->dir );
04309 
04310 re_tabulate:
04311         /* Build list of all edge_g_lseg's in fu1 */
04312         /* XXX This could be more cheaply done by cooking down eu1_list */
04313         nmg_edge_g_tabulate( &eg_list, &fu1->l.magic );
04314 
04315         /* Process each distinct line in the face fu1 */
04316         for( eg1 = (struct edge_g_lseg **)BU_PTBL_LASTADDR(&eg_list);
04317              eg1 >= (struct edge_g_lseg **)BU_PTBL_BASEADDR(&eg_list); eg1--
04318         )  {
04319                 struct vertex           *hit_v = (struct vertex *)NULL;
04320 
04321                 NMG_CK_EDGE_G_LSEG(*eg1);
04322 
04323                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04324                         bu_log( "\tChecking eg=x%x\n", *eg1 );
04325                 }
04326 
04327                 if( *eg1 == is->on_eg )  {
04328 #if 0
04329 colinear:
04330                         /*
04331                          *  This edge_g is known to be ON the face/face line.
04332                          *  Intersect all pairs of edgeuses, and enlist
04333                          *  every vertexuse along the edge.
04334                          *  Because the list can grow, scan in upwards direction.
04335                          */
04336                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04337                                 bu_log("\tThis edge_geom generated the line.  Enlisting.\n");
04338                         }
04339                         for( eu1_index=0; eu1_index < BU_PTBL_END(eu1_list); eu1_index++ )  {
04340                                 eu1 = (struct edgeuse *)BU_PTBL_GET(eu1_list, eu1_index);
04341                                 NMG_CK_EDGEUSE(eu1);
04342                                 if( eu1->g.lseg_p != is->on_eg )  continue;
04343                                 /* eu1 is from fu1 */
04344 
04345                                 for( eu2_index=0; eu2_index < BU_PTBL_END(eu2_list); eu2_index++ )  {
04346                                         eu2 = (struct edgeuse *)BU_PTBL_GET(eu2_list, eu2_index);
04347                                         NMG_CK_EDGEUSE(eu2);
04348 
04349                                         if( eu2->g.lseg_p != is->on_eg )  continue;
04350                                         /*
04351                                          *  eu2 is from fu2.
04352                                          *  Perform intersection.
04353                                          *  New edgeuses are added to lists.
04354                                          */
04355                                         (void)nmg_isect_2colinear_edge2p( eu1, eu2,
04356                                                 fu1, is, eu1_list, eu2_list);
04357                                 }
04358 
04359                                 /* For the case where only 1 face is involved */
04360                                 nmg_enlist_vu(is, eu1->vu_p, 0, MAX_FASTF );
04361                                 nmg_enlist_vu(is, BU_LIST_PNEXT_CIRC(edgeuse, eu1)->vu_p, 0, MAX_FASTF );
04362                         }
04363                         continue;
04364 #else
04365                         fastf_t  dist;
04366                         point_t pca;
04367                         struct edgeuse *eu_end;
04368                         struct vertex_g *vg;
04369                         plane_t pl1,pl2;
04370 
04371 colinear:
04372                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04373                                 bu_log("\tThis edge_geom generated the line.  Enlisting.\n");
04374                         }
04375 
04376                         NMG_GET_FU_PLANE( pl1, is->fu1 );
04377                         NMG_GET_FU_PLANE( pl2, is->fu2 );
04378                         for( eu1_index=0; eu1_index < BU_PTBL_END(eu1_list); eu1_index++ )
04379                         {
04380                                 eu1 = (struct edgeuse *)BU_PTBL_GET(eu1_list, eu1_index);
04381                                 NMG_CK_EDGEUSE(eu1);
04382                                 if( eu1->g.lseg_p != is->on_eg )  continue;
04383                                 /* eu1 is from fu1 */
04384 
04385                                 vg = eu1->vu_p->v_p->vg_p;
04386                                 NMG_CK_VERTEX_G( vg );
04387                                 (void)rt_dist_pt3_line3( &dist, pca, is->pt, is->dir, vg->coord, &(is->tol) );
04388                                 if( dist <= is->tol.dist )
04389                                 {
04390                                         /* vertex is on intersection line */
04391 
04392                                         if( DIST_PT_PLANE( vg->coord, pl2 ) <= is->tol.dist )
04393                                         {
04394                                                 /* and in plane of fu2 */
04395                                                 if( nmg_class_pt_fu_except( vg->coord, fu2, (struct loopuse *)NULL, NULL, NULL, (char *)NULL, 0, 0, &(is->tol) ) != NMG_CLASS_AoutB )
04396                                                 {
04397                                                         /* and within fu2 */
04398                                                         dist = VDIST( is->pt, vg->coord );
04399                                                         nmg_enlist_vu( is, eu1->vu_p, 0, dist );
04400                                                 }
04401                                         }
04402                                 }
04403                                 eu_end = BU_LIST_PNEXT_CIRC( edgeuse, &eu1->l );
04404                                 vg = eu_end->vu_p->v_p->vg_p;
04405                                 NMG_CK_VERTEX_G( vg );
04406                                 code = rt_dist_pt3_line3( &dist, pca, is->pt, is->dir, eu_end->vu_p->v_p->vg_p->coord, &(is->tol) );
04407                                 if( dist <= is->tol.dist )
04408                                 {
04409                                         /* vertex is on intersection line */
04410 
04411                                         if( DIST_PT_PLANE( vg->coord, pl2 ) <= is->tol.dist )
04412                                         {
04413                                                 /* and in plane of fu2 */
04414                                                 if( nmg_class_pt_fu_except( vg->coord, fu2, (struct loopuse *)NULL, NULL, NULL, (char *)NULL, 0, 0, &(is->tol) ) != NMG_CLASS_AoutB )
04415                                                 {
04416                                                         /* and within fu2 */
04417                                                         dist = VDIST( is->pt, vg->coord );
04418                                                         nmg_enlist_vu( is, eu_end->vu_p, 0, dist );
04419                                                 }
04420                                         }
04421                                 }
04422                         }
04423 
04424                         for( eu2_index=0; eu2_index < BU_PTBL_END(eu2_list); eu2_index++ )
04425                         {
04426                                 eu2 = (struct edgeuse *)BU_PTBL_GET(eu2_list, eu2_index);
04427                                 NMG_CK_EDGEUSE(eu2);
04428 
04429                                 if( eu2->g.lseg_p != is->on_eg )  continue;
04430                                 /*  eu2 is from fu2 */
04431 
04432                                 vg = eu2->vu_p->v_p->vg_p;
04433                                 NMG_CK_VERTEX_G( vg );
04434                                 code = rt_dist_pt3_line3( &dist, pca, is->pt, is->dir, vg->coord, &(is->tol) );
04435                                 if( dist <= is->tol.dist )
04436                                 {
04437                                         /* vertex is on intersection line */
04438 
04439                                         if( DIST_PT_PLANE( vg->coord, pl1 ) <= is->tol.dist )
04440                                         {
04441                                                 /* and in plane of fu1 */
04442                                                 if( nmg_class_pt_fu_except( vg->coord, fu1, (struct loopuse *)NULL, NULL, NULL, (char *)NULL, 0, 0, &(is->tol) ) != NMG_CLASS_AoutB )
04443                                                 {
04444                                                         /* and within fu1 */
04445                                                         dist = VDIST( is->pt, vg->coord );
04446                                                         nmg_enlist_vu( is, eu2->vu_p, 0, dist );
04447                                                 }
04448                                         }
04449                                 }
04450                                 eu_end = BU_LIST_PNEXT_CIRC( edgeuse, &eu2->l );
04451                                 vg = eu_end->vu_p->v_p->vg_p;
04452                                 NMG_CK_VERTEX_G( vg );
04453                                 code = rt_dist_pt3_line3( &dist, pca, is->pt, is->dir, eu_end->vu_p->v_p->vg_p->coord, &(is->tol) );
04454                                 if( dist <= is->tol.dist )
04455                                 {
04456                                         /* vertex is on intersection line */
04457 
04458                                         if( DIST_PT_PLANE( vg->coord, pl1 ) <= is->tol.dist )
04459                                         {
04460                                                 /* and in plane of fu1 */
04461                                                 if( nmg_class_pt_fu_except( vg->coord, fu1, (struct loopuse *)NULL, NULL, NULL, (char *)NULL, 0, 0, &(is->tol) ) != NMG_CLASS_AoutB )
04462                                                 {
04463                                                         /* and within fu1 */
04464                                                         dist = VDIST( is->pt, vg->coord );
04465                                                         nmg_enlist_vu( is, eu_end->vu_p, 0, dist );
04466                                                 }
04467                                         }
04468                                 }
04469                         }
04470                         continue;
04471 #endif
04472                 }
04473 
04474                 /*
04475                  *  eg1 is now known to be NOT colinear with on_eg.
04476                  *  From here on, only 0 or 1 points of intersection are possible.
04477                  */
04478 
04479                 /*  The 3D line in is->pt and is->dir is prepared by our caller. */
04480                 MAT4X3PNT( eg_pt2d, is->proj, (*eg1)->e_pt );
04481                 MAT4X3VEC( eg_dir2d, is->proj, (*eg1)->e_dir );
04482 
04483                 /* Calculate 2D geometric intersection, but don't look at answer yet */
04484                 dist[0] = dist[1] = -INFINITY;
04485                 code = bn_isect_line2_line2( dist, is->pt2d, is->dir2d,
04486                         eg_pt2d, eg_dir2d, &(is->tol) );
04487 
04488                 /* Do this check before topology search */
04489                 if( code == 0 )  {
04490                         /* Geometry says lines are colinear.  Egads!  This can't be! */
04491                         if( is->on_eg )  {
04492                                 bu_log("nmg_isect_line2_face2pNEW() edge_g not shared, geometry says lines are colinear.\n");
04493                                 goto fixup;
04494                         }
04495                         /* on_eg wasn't set, use it and continue on */
04496                         if( rt_g.NMG_debug & DEBUG_POLYSECT )
04497                                 bu_log("NOTICE: setting on_eg to eg1 and continuing with colinear case.\n");
04498                         is->on_eg = (*eg1);
04499                         goto colinear;
04500                 }
04501 
04502                 /* Double check */
04503                 if( is->on_eg && bn_2line3_colinear(
04504                     (*eg1)->e_pt, (*eg1)->e_dir,
04505                     is->on_eg->e_pt, is->on_eg->e_dir, 1e5, &(is->tol) ) )  {
04506 fixup:
04507                         nmg_pr_eg(&(*eg1)->l.magic, 0);
04508                         nmg_pr_eg(&is->on_eg->l.magic, 0);
04509                         bu_log("nmg_isect_line2_face2pNEW() eg1 colinear to on_eg?\n");
04510 #if 0
04511                         /* XXX See if this helps. */
04512                         nmg_model_fuse( nmg_find_model(&fu1->l.magic), &(is->tol) );
04513                         rt_bomb("nmg_isect_line2_face2pNEW() eg1 colinear to on_eg?\n");
04514 #else
04515                         /* fuse eg1 with on_eg, handle as colinear */
04516                         bu_log("fusing eg1 with on_eg, handling as colinear\n");
04517                         nmg_jeg( is->on_eg, *eg1 );
04518                         goto colinear;
04519 #endif
04520                 }
04521 
04522                 /* If on_eg was specified, do a search for topology intersection */
04523                 if( is->on_eg && !hit_v )  {
04524                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04525                                 bu_log("non-colinear.  Searching for topological intersection between on_eg and eg1\n");
04526                         }
04527                         /* See if any vu along eg1 is used by edge from on_eg */
04528                         hit_v = nmg_common_v_2eg( *eg1, is->on_eg, &(is->tol) );
04529                         /*
04530                          *  Note that while eg1 contains an eu from fu1,
04531                          *  the intersection vertex just found may occur
04532                          *  well outside *either* faceuse, but lie on some
04533                          *  other face that shares this face geometry.
04534                          */
04535                         if(hit_v) {
04536                                 fastf_t dist1,dist2;
04537                                 plane_t n1, n2;
04538 
04539                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04540                                         static int num=0;
04541                                         char buf[128];
04542                                         FILE *fp;
04543                                         sprintf(buf, "Itopo%d.pl", num++);
04544                                         if( (fp=fopen(buf,"w")) != NULL )  {
04545                                                 pl_color(fp, 255, 0, 0);
04546                                                 pdv_3ray( fp, is->on_eg->e_pt, is->on_eg->e_dir, 1.0 );
04547                                                 pdv_3cont( fp, hit_v->vg_p->coord );
04548                                                 pl_color(fp, 255,255, 0);
04549                                                 pdv_3ray( fp, (*eg1)->e_pt, (*eg1)->e_dir, 1.0 );
04550                                                 pdv_3cont( fp, hit_v->vg_p->coord );
04551                                                 fclose(fp);
04552                                                 bu_log("overlay %s red is on_eg, yellow is eg1\n", buf);
04553                                         } else perror(buf);
04554                                         bu_log("\tTopology intersection.  hit_v=x%x (%g, %g, %g)\n",
04555                                                 hit_v,
04556                                                 V3ARGS(hit_v->vg_p->coord) );
04557                                 }
04558 
04559                                 /*
04560                                  *  If the hit point is outside BOTH faces
04561                                  *  bounding RPP, then it can be ignored.
04562                                  *  Otherwise, it is needed for generating
04563                                  *  accurate state transitions in the
04564                                  *  face cutter.
04565                                  */
04566                                 if( !V3PT_IN_RPP( hit_v->vg_p->coord, fu1->f_p->min_pt, fu1->f_p->max_pt ) &&
04567                                     !V3PT_IN_RPP( hit_v->vg_p->coord, fu2->f_p->min_pt, fu2->f_p->max_pt )
04568                                 )  {
04569                                         /* Lines intersect outside bounds of both faces. */
04570                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04571                                                 VPRINT("\t\tisect pt outside fu1 & fu2 RPP:", hit_v->vg_p->coord );
04572                                                 bu_log("\t\tfu1 RPP: ( %g %g %g ) <-> ( %g %g %g )\n",
04573                                                         V3ARGS( fu1->f_p->min_pt ), V3ARGS( fu1->f_p->max_pt ) );
04574                                                 bu_log("\t\tfu2 RPP: ( %g %g %g ) <-> ( %g %g %g )\n",
04575                                                         V3ARGS( fu2->f_p->min_pt ), V3ARGS( fu2->f_p->max_pt ) );
04576                                         }
04577                                         continue;
04578                                 }
04579 
04580                                 /*
04581                                  *  Geometry check.
04582                                  *  Since on_eg is the line of intersection
04583                                  *  between fu1 and fu2, and since eg1
04584                                  *  lies in the plane of fu1,
04585                                  *  and since hit_v lies on eg1
04586                                  *  at the point where eg1 intersects on_eg,
04587                                  *  it's pretty hard to see how hit_v
04588                                  *  could fail to lie in the plane of fu2.
04589                                  *
04590                                  *  However, in BigWedge r1 (m14.r) this
04591                                  *  case occurs:  hit_v is off f2 by -60mm!
04592                                  *  These two fu's don't overlap at all.
04593                                  *
04594                                  *  Rather than letting nmg_ck_v_in_2fus()
04595                                  *  blow it's mind over this, catch it here
04596                                  *  and discard the point.
04597                                  *  (Hopefully the RPP checks above will have
04598                                  *  already discarded it).
04599                                  */
04600                                 NMG_GET_FU_PLANE(n1, fu1);
04601                                 NMG_GET_FU_PLANE(n2, fu2);
04602                                 dist1 = DIST_PT_PLANE( hit_v->vg_p->coord , n1 );
04603                                 dist2 = DIST_PT_PLANE( hit_v->vg_p->coord , n2 );
04604 
04605                                 if( !NEAR_ZERO( dist1 , is->tol.dist ) || !NEAR_ZERO( dist2 , is->tol.dist ) )  {
04606                                         continue;
04607                                 }
04608                                 if( (class=nmg_class_pt_fu_except( hit_v->vg_p->coord, fu1, (struct loopuse *)NULL, NULL, NULL, (char *)NULL, 0, 0, &(is->tol) )) == NMG_CLASS_AoutB )
04609                                 {
04610                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04611                                         {
04612                                                 VPRINT("\t\tisect pt outside face fu1 (nmg_class_pt_fu_except):", hit_v->vg_p->coord );
04613                                         }
04614                                         continue;
04615                                 }
04616                                 else if( (class=nmg_class_pt_fu_except( hit_v->vg_p->coord, fu2, (struct loopuse *)NULL, NULL, NULL, (char *)NULL, 0, 0, &(is->tol) )) == NMG_CLASS_AoutB )
04617                                 {
04618                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04619                                         {
04620                                                 VPRINT("\t\tisect pt outside face fu2 (nmg_class_pt_fu_except):", hit_v->vg_p->coord );
04621                                         }
04622                                         continue;
04623                                 }
04624                                 /* Ignore further geometry checking, isect is good.
04625                                  * Head right to searching for vertexuses
04626                                  */
04627                                 goto force_isect;
04628                         }
04629                 }
04630 
04631                 /* Now compare results of topology and geometry calculations */
04632 
04633                 if( code < 0 )  {
04634                         /* Geometry says lines are parallel, no intersection */
04635                         if( hit_v )  {
04636                                 bu_log("NOTICE: geom/topo mis-match, enlisting topo vu, hit_v=x%x\n", hit_v);
04637                                 VPRINT("hit_v", hit_v->vg_p->coord);
04638                                 nmg_pr_eg(&(*eg1)->l.magic, 0);
04639                                 nmg_pr_eg(&is->on_eg->l.magic, 0);
04640                                 bu_log(" dist to eg1=%e, dist to on_eg=%e\n",
04641                                         bn_dist_line3_pt3((*eg1)->e_pt, (*eg1)->e_dir, hit_v->vg_p->coord),
04642                                         bn_dist_line3_pt3(is->on_eg->e_pt, is->on_eg->e_dir, hit_v->vg_p->coord) );
04643                                 VPRINT("is->pt2d ", is->pt2d);
04644                                 VPRINT("is->dir2d", is->dir2d);
04645                                 VPRINT("eg_pt2d  ", eg_pt2d);
04646                                 VPRINT("eg_dir2d ", eg_dir2d);
04647                                 bu_log(" 3d line isect, code=%d\n",
04648                                         bn_isect_line3_line3( &dist[0], &dist[1],
04649                                                 is->pt, is->dir,
04650                                                 (*eg1)->e_pt,
04651                                                 (*eg1)->e_dir,
04652                                                 &(is->tol)
04653                                         ) );
04654                                 goto force_isect;
04655                         }
04656                         continue;
04657                 }
04658                 /* Geometry says 2 lines intersect at a point */
04659                 VJOIN1( hit3d, is->pt, dist[0], is->dir );
04660                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04661                         VPRINT("\t2 lines intersect at", hit3d);
04662                 }
04663 #if 1
04664                 if( !V3PT_IN_RPP( hit3d, fu1->f_p->min_pt, fu1->f_p->max_pt ) )  {
04665                         /* Lines intersect outside bounds of this face. */
04666                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04667                                 VPRINT("\t\tisect pt outside fu1 face RPP:", hit3d );
04668                                 bu_log("\t\tface RPP: ( %g %g %g ) <-> ( %g %g %g )\n",
04669                                         V3ARGS( fu1->f_p->min_pt ), V3ARGS( fu1->f_p->max_pt ) );
04670                         }
04671                         continue;
04672                 }
04673 
04674                 if( (class=nmg_class_pt_fu_except( hit3d, fu1, (struct loopuse *)NULL, NULL, NULL, (char *)NULL, 0, 0, &(is->tol) )) == NMG_CLASS_AoutB )
04675                 {
04676                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04677                         {
04678                                 VPRINT("\t\tisect pt outside face fu1 (nmg_class_pt_fu_except):", hit3d );
04679                         }
04680                         continue;
04681                 }
04682                 else if( (class=nmg_class_pt_fu_except( hit3d, fu2, (struct loopuse *)NULL, NULL, NULL, (char *)NULL, 0, 0, &(is->tol) )) == NMG_CLASS_AoutB )
04683                 {
04684                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
04685                         {
04686                                 VPRINT("\t\tisect pt outside face fu2 (nmg_class_pt_fu_except):", hit3d );
04687                         }
04688                         continue;
04689                 }
04690                 else if(rt_g.NMG_debug & DEBUG_POLYSECT)
04691                 {
04692                         bu_log( "\t\tnmg_class_pt_fu_except(fu1) returns %s\n", nmg_class_name(class) );
04693                 }
04694 #endif
04695                 VJOIN1_2D( hit2d, is->pt2d, dist[0], is->dir2d );
04696 
04697                 /* Consistency check between geometry, and hit_v. */
04698                 if( hit_v )  {
04699 force_isect:
04700                         /* Force things to be consistent, use geom from hit_v */
04701                         VMOVE(hit3d, hit_v->vg_p->coord);
04702                         nmg_get_2d_vertex( hit2d, hit_v, is, &fu1->l.magic );
04703                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04704                                 bu_log("hit_v=x%x\n", hit_v);
04705                                 VPRINT("hit3d", hit3d);
04706                                 V2PRINT("hit2d", hit2d);
04707                         }
04708                 }
04709 
04710 eu_search:
04711                 /*  Search all eu's on eg1 for vu's to enlist.
04712                  *  There may be many, and the list may grow.
04713                  */
04714                 for( eu1_index=0; eu1_index < BU_PTBL_END(eu1_list); eu1_index++ )  {
04715                         struct vertexuse        *vu1a, *vu1b;
04716                         struct vertexuse        *vu1_midpt;
04717                         fastf_t                 ldist;
04718                         point_t                 eu1_pt2d;       /* 2D */
04719                         point_t                 eu1_end2d;      /* 2D */
04720                         double                  tmp_dist_sq;
04721 
04722                         eu1 = (struct edgeuse *)BU_PTBL_GET(eu1_list, eu1_index);
04723 
04724                         /* This EU may have been killed by nmg_repair_v_near_v() */
04725                         if( eu1->l.magic != NMG_EDGEUSE_MAGIC )
04726                                 continue;
04727 
04728                         NMG_CK_EDGEUSE(eu1);
04729 
04730                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04731                                 bu_log( "\tChecking eu x%x\n", eu1 );
04732                         }
04733 
04734                         if( eu1->g.lseg_p != *eg1 )
04735                         {
04736                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04737                                         bu_log( "\t\teg x%x is not eg1=x%x\n", eu1->g.lseg_p, *eg1 );
04738                                 }
04739                                 continue;
04740                         }
04741                         vu1a = eu1->vu_p;
04742                         vu1b = BU_LIST_PNEXT_CIRC( edgeuse, eu1 )->vu_p;
04743 
04744                         /* First, a topology check of both endpoints */
04745                         if( vu1a->v_p == hit_v )  {
04746 hit_a:
04747                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04748                                         bu_log("\tlisting intersect point at vu1a=x%x\n", vu1a);
04749                                 }
04750                                 /* Note that the distance dist[0] may not actually
04751                                  * be the exact distance to vu1a, but it is the distance
04752                                  * to the actual intersection point. This is an
04753                                  * attempt to get the correct ordering of vertices
04754                                  * on the intersection list, since using the
04755                                  * actual distance can get them reversed when
04756                                  * a VU is chosen over the actual interection
04757                                  * point.
04758                                  */
04759                                 nmg_enlist_vu(is, vu1a, 0, dist[0]);
04760                         }
04761                         if( vu1b->v_p == hit_v )  {
04762 hit_b:
04763                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04764                                         bu_log("\tlisting intersect point at vu1b=x%x\n", vu1b);
04765                                 }
04766                                 /* see above note about dist[0] */
04767                                 nmg_enlist_vu(is, vu1b, 0, dist[0]);
04768                         }
04769                         if( vu1a->v_p == hit_v || vu1b->v_p == hit_v )  continue;
04770 
04771                         /*  Second, a geometry check on the edgeuse ENDPOINTS
04772                          *  -vs- the line segment.  This is 3D, for consistency
04773                          *  with comparisons elsewhere.
04774                          */
04775                         tmp_dist_sq = bn_distsq_line3_pt3( is->pt, is->dir, vu1a->v_p->vg_p->coord );
04776                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04777                                 bu_log( "\tvu1a is sqrt(%g) from the intersect line\n" , tmp_dist_sq );
04778                         }
04779                         if( tmp_dist_sq <= is->tol.dist_sq  )  {
04780                                 if( !hit_v )  {
04781                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04782                                                 bu_log( "\tnmg_isect_line2_face2pNEW: using nearby vu1a vertex x%x from eu x%x\n", vu1a->v_p, eu1 );
04783                                         }
04784                                         hit_v = vu1a->v_p;
04785                                         goto hit_a;
04786                                 }
04787                                 if( hit_v == vu1a->v_p )  goto hit_a;
04788 #if 0
04789                                 nmg_repair_v_near_v( hit_v, vu1a->v_p,
04790                                         is->on_eg, *eg1, 1, &(is->tol) );
04791                                 bu_ptbl_free( &eg_list);
04792                                 goto re_tabulate;
04793 #else
04794                                 /* Fall through to bn_isect_pt2_lseg2() */
04795 #endif
04796                         }
04797                         tmp_dist_sq = bn_distsq_line3_pt3( is->pt, is->dir, vu1b->v_p->vg_p->coord );
04798                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04799                                 bu_log( "\tvu1b is sqrt(%g) from the intersect line\n" , tmp_dist_sq );
04800                         }
04801                         if(tmp_dist_sq <= is->tol.dist_sq )  {
04802                                 if( !hit_v )  {
04803                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04804                                                 bu_log( "\tnmg_isect_line2_face2pNEW: using nearby vu1b vertex x%x from eu x%x\n", vu1b->v_p, eu1 );
04805                                         }
04806                                         hit_v = vu1b->v_p;
04807                                         goto hit_b;
04808                                 }
04809                                 if( hit_v == vu1b->v_p )  goto hit_b;
04810 #if 0
04811                                 nmg_repair_v_near_v( hit_v, vu1b->v_p,
04812                                         is->on_eg, *eg1, 1, &(is->tol) );
04813                                 bu_ptbl_free( &eg_list);
04814                                 goto re_tabulate;
04815 #else
04816                                 /* Fall through to bn_isect_pt2_lseg2() */
04817 #endif
04818                         }
04819 
04820                         /* Third, a geometry check of the HITPT -vs- the line segment */
04821                         nmg_get_2d_vertex( eu1_pt2d, vu1a->v_p, is, &fu1->l.magic );
04822                         nmg_get_2d_vertex( eu1_end2d, vu1b->v_p, is, &fu1->l.magic );
04823                         ldist = 0;
04824                         code = bn_isect_pt2_lseg2( &ldist, eu1_pt2d, eu1_end2d, hit2d, &(is->tol) );
04825                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04826                                 bu_log("\tbn_isect_pt2_lseg2() returned %d, ldist=%g\n", code, ldist);
04827                         }
04828                         switch(code)  {
04829                         case -2:
04830                                 continue;       /* outside lseg AB pts */
04831                         default:
04832                         case -1:
04833                                 continue;       /* Point not on lseg */
04834                         case 1:
04835                                 /* Point is at A (vu1a) by geometry */
04836                                 if( hit_v && hit_v != vu1a->v_p )  {
04837                                         nmg_repair_v_near_v( hit_v, vu1a->v_p,
04838                                                 is->on_eg, *eg1, 1, &(is->tol) );
04839                                         bu_ptbl_free( &eg_list);
04840                                         goto re_tabulate;
04841                                 }
04842                                 hit_v = vu1a->v_p;
04843                                 if (rt_g.NMG_debug & DEBUG_POLYSECT) bu_log("\thit_v = x%x (vu1a)\n", hit_v);
04844                                 goto hit_a;
04845                         case 2:
04846                                 /* Point is at B (vu1b) by geometry */
04847                                 if( hit_v && hit_v != vu1b->v_p )  {
04848                                         nmg_repair_v_near_v( hit_v, vu1b->v_p,
04849                                                 is->on_eg, *eg1, 1, &(is->tol) );
04850                                         bu_ptbl_free( &eg_list);
04851                                         goto re_tabulate;
04852                                 }
04853                                 hit_v = vu1b->v_p;
04854                                 if (rt_g.NMG_debug & DEBUG_POLYSECT) bu_log("\thit_v = x%x (vu1b)\n", hit_v);
04855                                 goto hit_b;
04856                         case 3:
04857                                 /* Point hits the line segment amidships!  Split edge!
04858                                  * If we don't have a hit vertex yet,
04859                                  * search for one in whole model.
04860                                  */
04861                                 if( !hit_v )  {
04862                                         hit_v = nmg_find_pt_in_model(fu1->s_p->r_p->m_p,
04863                                                 hit3d, &(is->tol));
04864                                         if( hit_v == vu1a->v_p || hit_v == vu1b->v_p )
04865                                                 rt_bomb("About to make 0-length edge!\n");
04866                                 }
04867                                 new_eu = nmg_ebreaker(hit_v, eu1, &is->tol);
04868                                 bu_ptbl_ins_unique( eu1_list, &new_eu->l.magic );
04869                                 /* "eu1" must now be considered invalid */
04870                                 vu1_midpt = new_eu->vu_p;
04871                                 if( !hit_v )  {
04872                                         hit_v = vu1_midpt->v_p;
04873                                         nmg_vertex_gv( hit_v, hit3d );
04874                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04875                                                 bu_log("\tmaking new vertex vu=x%x hit_v=x%x\n",
04876                                                         vu1_midpt, hit_v);
04877                                         }
04878                                         /*  Before we loose track of the fact
04879                                          *  that this vertex lies on *both*
04880                                          *  lines, break any edges in the
04881                                          *  intersection line that cross it.
04882                                          */
04883                                         if( is->on_eg )  {
04884                                                 nmg_break_eg_on_v( is->on_eg,
04885                                                         hit_v, &(is->tol) );
04886                                         }
04887                                 } else {
04888                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04889                                                 bu_log("\tre-using hit_v=x%x, vu=x%x\n", hit_v, vu1_midpt);
04890                                         }
04891                                         if( hit_v != vu1_midpt->v_p )  rt_bomb("hit_v changed?\n");
04892                                 }
04893                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04894                                         bu_log( "Faceuses after nmg_ebreaker() call\n") ;
04895                                         bu_log( "fu1:\n" );
04896                                         nmg_pr_fu_briefly( fu1 , "\t" );
04897                                         bu_log( "fu2:\n" );
04898                                         nmg_pr_fu_briefly( fu2 , "\t" );
04899                                 }
04900                                 nmg_enlist_vu(is, vu1_midpt, 0, dist[0]);
04901                                 /* Neither old nor new edgeuse need further handling */
04902                                 /* Because "eu1" is now invalid, restart loop. */
04903                                 goto eu_search;
04904                         }
04905                 }
04906         }
04907 
04908         /* Don't forget to do self loops with no edges */
04909         for( BU_LIST_FOR( lu1, loopuse, &fu1->lu_hd ) )  {
04910                 struct vertexuse        *vu1;
04911 
04912                 if( BU_LIST_FIRST_MAGIC( &lu1->down_hd ) != NMG_VERTEXUSE_MAGIC )  continue;
04913 
04914                 /* Intersect line with lone vertex vu1 */
04915                 vu1 = BU_LIST_FIRST( vertexuse, &lu1->down_hd );
04916                 NMG_CK_VERTEXUSE(vu1);
04917 
04918                 /* Needs to be a 3D comparison */
04919                 if( bn_distsq_line3_pt3( is->pt, is->dir,
04920                       vu1->v_p->vg_p->coord ) > is->tol.dist_sq )
04921                         continue;
04922 
04923                 if (rt_g.NMG_debug & DEBUG_POLYSECT)  {
04924                         bu_log("\tself-loop vu=x%x lies on line of intersection\n", vu1 );
04925                 }
04926 
04927                 /* Break all edgeuses in the model on line on_eg, at vu1 */
04928                 if( is->on_eg )  {
04929                         nmg_break_eg_on_v( is->on_eg, vu1->v_p, &(is->tol) );
04930                         nmg_enlist_vu(is, vu1, 0, MAX_FASTF );
04931                 }
04932 
04933 #if 1
04934                 /* This can probably be removed */
04935                 /* recent OLD WAY: */
04936                 /*  To prevent an OT_BOOLPLACE from being overlooked,
04937                  *  break *both* sets of eu's
04938                  */
04939 
04940                 /* Break all edges from fu1 list */
04941                 for( eu1_index=0; eu1_index < BU_PTBL_END(eu1_list); eu1_index++ )  {
04942                         eu1 = (struct edgeuse *)BU_PTBL_GET(eu1_list, eu1_index);
04943 
04944                         /* This EU may have been killed by nmg_repair_v_near_v() */
04945                         if( eu1->l.magic != NMG_EDGEUSE_MAGIC )
04946                                 continue;
04947 
04948                         NMG_CK_EDGEUSE(eu1);
04949                         if( eu1->g.lseg_p != is->on_eg )  continue;
04950                         /* eu1 is from fu1 and on the intersection line */
04951                         new_eu = nmg_break_eu_on_v( eu1, vu1->v_p, fu1, is );
04952                         if( !new_eu )  continue;
04953                         bu_ptbl_ins_unique( eu1_list, &new_eu->l.magic );
04954                         nmg_enlist_vu(is, new_eu->vu_p, 0, MAX_FASTF );
04955                 }
04956 
04957                 /* Break all edges from fu2 list */
04958                 for( eu2_index=0; eu2_index < BU_PTBL_END(eu2_list); eu2_index++ )  {
04959                         eu2 = (struct edgeuse *)BU_PTBL_GET(eu2_list, eu2_index);
04960 
04961                         /* This EU may have been killed by nmg_repair_v_near_v() */
04962                         if( eu2->l.magic != NMG_EDGEUSE_MAGIC )
04963                                 continue;
04964 
04965                         NMG_CK_EDGEUSE(eu2);
04966                         if( eu2->g.lseg_p != is->on_eg )  continue;
04967                         /* eu2 is from fu2 and on the intersection line */
04968                         new_eu = nmg_break_eu_on_v( eu2, vu1->v_p, fu1, is );
04969                         if( !new_eu )  continue;
04970                         bu_ptbl_ins_unique( eu2_list, &new_eu->l.magic );
04971                         nmg_enlist_vu(is, new_eu->vu_p, 0, MAX_FASTF );
04972                 }
04973 #endif
04974         }
04975 
04976         bu_ptbl_free( &eg_list);
04977 }
04978 
04979 /* XXX move to nmg_info.c */
04980 /*
04981  *                      N M G _ I S _ E U _ O N _ L I N E 3
04982  */
04983 int
04984 nmg_is_eu_on_line3(const struct edgeuse *eu, const fastf_t *pt, const fastf_t *dir, const struct bn_tol *tol)
04985 {
04986         struct edge_g_lseg      *eg;
04987 
04988         NMG_CK_EDGEUSE(eu);
04989         BN_CK_TOL(tol);
04990 
04991         eg = eu->g.lseg_p;
04992         NMG_CK_EDGE_G_LSEG(eg);
04993 
04994         /* Ensure direction vectors are generally parallel */
04995         /* These are not unit vectors */
04996         /* tol->para and RT_DOT_TOL are too tight a tolerance.  0.1 is 5 degrees */
04997         if( fabs(VDOT(eg->e_dir, dir)) <
04998             0.9 * MAGNITUDE(eg->e_dir) * MAGNITUDE(dir)  )  return 0;
04999 
05000         /* Ensure that vertices on edge are within tol of line */
05001         if( bn_distsq_line3_pt3( eg->e_pt, eg->e_dir,
05002             eu->vu_p->v_p->vg_p->coord ) > tol->dist_sq )  return 0;
05003         if( bn_distsq_line3_pt3( eg->e_pt, eg->e_dir,
05004             eu->eumate_p->vu_p->v_p->vg_p->coord ) > tol->dist_sq )  return 0;
05005 
05006         return 1;
05007 }
05008 
05009 /* XXX Move to nmg_info.c */
05010 /**
05011  *                      N M G _ F I N D _ E G _ B E T W E E N _ 2 F G
05012  *
05013  *  Perform a topology search to determine if two face geometries (specified
05014  *  by their faceuses) share an edge geometry in common.
05015  *  The edge_g is returned, even if there are no existing uses of it
05016  *  in *either* fu1 or fu2.  It still represents the intersection line
05017  *  between the two face geometries, found topologically.
05018  *
05019  *  If there are multiple edgeuses in common, ensure that they all refer
05020  *  to the same edge_g geometry structure.  The intersection of two planes
05021  *  (non-coplanar) must be a single line.
05022  *
05023  *  Calling this routine when the two faces share face geometry
05024  *  is illegal.
05025  *
05026  *  NULL is returned if no common edge geometry could be found.
05027  */
05028 struct edge_g_lseg *
05029 nmg_find_eg_between_2fg(const struct faceuse *ofu1, const struct faceuse *fu2, const struct bn_tol *tol)
05030 {
05031         const struct faceuse    *fu1;
05032         const struct loopuse    *lu1;
05033         const struct face_g_plane       *fg1;
05034         const struct face_g_plane       *fg2;
05035         const struct face       *f1;
05036         struct edgeuse          *ret = (struct edgeuse *)NULL;
05037         int                     coincident;
05038 
05039         NMG_CK_FACEUSE(ofu1);
05040         NMG_CK_FACEUSE(fu2);
05041         BN_CK_TOL(tol);
05042 
05043         fg1 = ofu1->f_p->g.plane_p;
05044         fg2 = fu2->f_p->g.plane_p;
05045         NMG_CK_FACE_G_PLANE(fg1);
05046         NMG_CK_FACE_G_PLANE(fg2);
05047 
05048         if( fg1 == fg2 )  rt_bomb("nmg_find_eg_between_2fg() face_g_plane shared, infinitely many results\n");
05049 
05050         if (rt_g.NMG_debug & DEBUG_BASIC)  {
05051                 nmg_pr_fus_in_fg( &fg1->magic );
05052                 nmg_pr_fus_in_fg( &fg2->magic );
05053         }
05054 
05055         /* For all faces using fg1 */
05056         for( BU_LIST_FOR( f1, face, &fg1->f_hd ) )  {
05057                 NMG_CK_FACE(f1);
05058 
05059                 /* Arbitrarily pick one of the two fu's using f1 */
05060                 fu1 = f1->fu_p;
05061                 NMG_CK_FACEUSE(fu1);
05062 
05063                 for( BU_LIST_FOR( lu1, loopuse, &fu1->lu_hd ) )  {
05064                         const struct edgeuse    *eu1;
05065                         NMG_CK_LOOPUSE(lu1);
05066                         if( BU_LIST_FIRST_MAGIC(&lu1->down_hd) == NMG_VERTEXUSE_MAGIC )
05067                                 continue;
05068                         if (rt_g.NMG_debug & DEBUG_BASIC)  {
05069                                 bu_log(" visiting lu1=x%x, fu1=x%x, fg1=x%x\n",
05070                                         lu1, fu1, fg1 );
05071                         }
05072 restart:
05073                         for( BU_LIST_FOR( eu1, edgeuse, &lu1->down_hd ) )  {
05074                                 struct edgeuse *eur;
05075 
05076                                 NMG_CK_EDGEUSE(eu1);
05077                                 /* Walk radially around the edge */
05078                                 for(
05079                                     eur = eu1->radial_p;
05080                                     eur != eu1->eumate_p;
05081                                     eur = eur->eumate_p->radial_p
05082                                 )  {
05083                                         const struct faceuse    *tfu;
05084 
05085                                         if (*eur->up.magic_p != NMG_LOOPUSE_MAGIC ) continue;
05086                                         if( *eur->up.lu_p->up.magic_p != NMG_FACEUSE_MAGIC )  continue;
05087                                         tfu = eur->up.lu_p->up.fu_p;
05088                                         if( tfu->f_p->g.plane_p != fg2 )  continue;
05089                                         NMG_CK_EDGE_G_EITHER( eur->g.lseg_p );
05090 
05091                                         /* Found the other face on this edge! */
05092                                         if (rt_g.NMG_debug & DEBUG_BASIC)  {
05093                                                 bu_log(" Found shared edge, eur=x%x, eg=x%x\n", eur, eur->g.lseg_p );
05094                                                 nmg_pr_eu_briefly( eur, (char *)NULL );
05095                                                 nmg_pr_eu_briefly( eur->eumate_p, (char *)NULL );
05096                                                 nmg_pr_eg( eur->g.magic_p, 0 );
05097                                                 nmg_pr_fu_around_eu( eur, tol );
05098                                         }
05099 
05100                                         if( !ret )  {
05101                                                 /* First common edge found */
05102                                                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
05103                                                         nmg_pl_lu_around_eu(eur);
05104                                                 }
05105                                                 ret = eur;
05106                                                 continue;
05107                                         }
05108 
05109                                         /* Previous edge found, check edge_g */
05110                                         if( eur->g.lseg_p == ret->g.lseg_p )  continue;
05111 
05112                                         /* Edge geometry differs. vu's same? */
05113                                         if( NMG_ARE_EUS_ADJACENT(eur, ret) )  {
05114                                                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
05115                                                         bu_log("nmg_find_eg_between_2fg() joining edges eur=x%x, ret=x%x\n",
05116                                                                 eur, ret );
05117                                                 }
05118                                                 nmg_radial_join_eu(ret, eur, tol);
05119                                                 goto restart;
05120                                         }
05121 
05122                                         /* This condition "shouldn't happen" */
05123                                         bu_log("eur=x%x, eg_p=x%x;  ret=x%x, eg_p=x%x\n",
05124                                                 eur, eur->g.lseg_p,
05125                                                 ret, ret->g.lseg_p);
05126                                         nmg_pr_eg( eur->g.magic_p, 0 );
05127                                         nmg_pr_eg( ret->g.magic_p, 0 );
05128                                         nmg_pr_eu_endpoints( eur, 0 );
05129                                         nmg_pr_eu_endpoints( ret, 0 );
05130 
05131                                         coincident = nmg_2edgeuse_g_coincident( eur, ret, tol );
05132                                         if( coincident )  {
05133                                                 /* Change eur to use ret's eg */
05134                                                 bu_log("nmg_find_eg_between_2fg() belatedly fusing e1=x%x, eg1=x%x, e2=x%x, eg2=x%x\n",
05135                                                         eur->e_p, eur->g.lseg_p,
05136                                                         ret->e_p, ret->g.lseg_p );
05137                                                 nmg_jeg( ret->g.lseg_p, eur->g.lseg_p );
05138                                                 /* See if there are any others. */
05139                                                 nmg_model_fuse( nmg_find_model(&eur->l.magic), tol );
05140                                         } else {
05141                                                 rt_bomb("nmg_find_eg_between_2fg() 2 faces intersect with differing edge geometries?\n");
05142                                         }
05143                                         goto restart;
05144                                 }
05145                         }
05146                 }
05147         }
05148         if (rt_g.NMG_debug & DEBUG_BASIC)  {
05149                 bu_log("nmg_find_eg_between_2fg(fu1=x%x, fu2=x%x) edge_g=x%x\n",
05150                         ofu1, fu2, ret ? ret->g.lseg_p : 0);
05151         }
05152         if( ret )
05153                 return ret->g.lseg_p;
05154         return (struct edge_g_lseg *)NULL;
05155 }
05156 
05157 /* XXX Move to nmg_info.c */
05158 /**
05159  *                      N M G _ D O E S _ F U _ U S E _ E G
05160  *
05161  *  See if any edgeuse in the given faceuse
05162  *  lies on the indicated edge geometry (edge_g).
05163  *  This is a topology check only.
05164  *
05165  *  Returns -
05166  *      NULL    No
05167  *      eu      Yes, here is one edgeuse that does.  There may be more.
05168  */
05169 struct edgeuse *
05170 nmg_does_fu_use_eg(const struct faceuse *fu1, const long int *eg)
05171 {
05172         const struct loopuse    *lu1;
05173         register struct edgeuse *eu1;
05174 
05175         NMG_CK_FACEUSE(fu1);
05176         NMG_CK_EDGE_G_EITHER(eg);
05177 
05178         for( BU_LIST_FOR( lu1, loopuse, &fu1->lu_hd ) )  {
05179                 NMG_CK_LOOPUSE(lu1);
05180                 if( BU_LIST_FIRST_MAGIC(&lu1->down_hd) == NMG_VERTEXUSE_MAGIC )
05181                         continue;
05182                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
05183                         bu_log(" visiting lu1=x%x, fu1=x%x\n",
05184                                 lu1, fu1 );
05185                 }
05186                 for( BU_LIST_FOR( eu1, edgeuse, &lu1->down_hd ) )  {
05187                         if( eu1->g.magic_p == eg )  goto out;
05188                 }
05189         }
05190         eu1 = (struct edgeuse *)NULL;
05191 out:
05192         if (rt_g.NMG_debug & DEBUG_BASIC)  {
05193                 bu_log("nmg_does_fu_use_eg(fu1=x%x, eg=x%x) eu1=x%x\n",
05194                         fu1, eg, eu1 );
05195         }
05196         return eu1;
05197 }
05198 
05199 /* XXX move to plane.c */
05200 /**
05201  *                      R T _ L I N E _ O N _ P L A N E
05202  *
05203  *  Returns -
05204  *      1       line is on plane, within tol
05205  *      0       line does not lie on the plane
05206  */
05207 int
05208 rt_line_on_plane(const fastf_t *pt, const fastf_t *dir, const fastf_t *plane, const struct bn_tol *tol)
05209 {
05210         vect_t  unitdir;
05211         fastf_t dist;
05212 
05213         BN_CK_TOL(tol);
05214 
05215         dist = DIST_PT_PLANE( pt, plane );
05216         if( !NEAR_ZERO( dist, tol->dist ) )  return 0;
05217 
05218         VMOVE( unitdir, dir );
05219         VUNITIZE( unitdir );
05220 /* XXX This is *way* too tight TOO_STRICT */
05221         if( fabs(VDOT(unitdir, plane)) >= tol->para )  {
05222                 /* Vectors are parallel */
05223                 /* ray parallel to plane, and point is on it */
05224                 return 1;
05225         }
05226         return 0;
05227 }
05228 
05229 /**
05230  *                      N M G _ I S E C T _ T W O _ F A C E 3 P
05231  *
05232  *  Handle the complete mutual intersection of
05233  *  two 3-D non-coplanar planar faces,
05234  *  including cutjoin and meshing.
05235  *
05236  *  The line of intersection has already been computed.
05237  *  Handle as two 2-D line/face intersection problems
05238  *
05239  *  This is the HEART of the intersection code.
05240  */
05241 static void
05242 nmg_isect_two_face3p(struct nmg_inter_struct *is, struct faceuse *fu1, struct faceuse *fu2)
05243 {
05244         struct bu_ptbl vert_list1, vert_list2;
05245         struct bu_ptbl          eu1_list;       /* all eu's in fu1 */
05246         struct bu_ptbl          eu2_list;       /* all eu's in fu2 */
05247         fastf_t                 *mag1=(fastf_t *)NULL;
05248         fastf_t                 *mag2=(fastf_t *)NULL;
05249         int                     i;
05250 
05251         NMG_CK_INTER_STRUCT(is);
05252         NMG_CK_FACEUSE(fu1);
05253         NMG_CK_FACEUSE(fu2);
05254 
05255         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
05256                 bu_log("nmg_isect_two_face3p( fu1=x%x, fu2=x%x )  START12\n", fu1, fu2);
05257                 VPRINT("isect ray is->pt ", is->pt);
05258                 VPRINT("isect ray is->dir", is->dir);
05259         }
05260 
05261         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
05262                 nmg_vfu( &fu1->s_p->fu_hd, fu1->s_p );
05263                 nmg_vfu( &fu2->s_p->fu_hd, fu2->s_p );
05264                 nmg_fu_touchingloops(fu1);
05265                 nmg_fu_touchingloops(fu2);
05266         }
05267 
05268         /* Verify that line is within tolerance of both planes */
05269 #if TOO_STRICT
05270         NMG_GET_FU_PLANE(n1, fu1);
05271         if( !rt_line_on_plane( is->pt, is->dir, n1, &(is->tol) ) )
05272                 bu_log("WARNING: intersect line not on plane of fu1\n");
05273         NMG_GET_FU_PLANE(n2, fu2);
05274         if( !rt_line_on_plane( is->pt, is->dir, n2, &(is->tol) ) )
05275                 bu_log("WARNING: intersect line not on plane of fu2\n");
05276 #endif
05277 
05278         if (rt_g.NMG_debug & (DEBUG_POLYSECT|DEBUG_FCUT|DEBUG_MESH)
05279             && rt_g.NMG_debug & DEBUG_PLOTEM) {
05280                 nmg_pl_2fu( "Iface%d.pl", 0, fu1, fu2, 0 );
05281         }
05282 #if 0
05283         /* Topology search */
05284         /* See if 2 faces share an edge already.  If so, get edge_geom line */
05285         if( (is->on_eg = nmg_find_eg_between_2fg(fu1, fu2, &(is->tol))) )  {
05286                 NMG_CK_EDGE_G_LSEG(is->on_eg);
05287 #if TOO_STRICT
05288                 /* Verify that this edge_g is with tol of both planes */
05289                 if( !rt_line_on_plane( is->on_eg->e_pt, is->on_eg->e_dir, n1, &(is->tol) ) )  {
05290                         bu_log("WARNING: shared on_eg not on plane of fu1, omitting.\n");
05291                         is->on_eg = NULL;
05292                 } else if( !rt_line_on_plane( is->on_eg->e_pt, is->on_eg->e_dir, n2, &(is->tol) ) )  {
05293                         bu_log("WARNING: shared on_eg not on plane of fu2, omitting.\n");
05294                         is->on_eg = NULL;
05295                 }
05296 #endif
05297                 /*
05298                  *  There is a topological edge_g in common between
05299                  *  the two face geometries.
05300                  *  The intersection still needs to be done, because
05301                  *  there might be partial sharing due to the fuser,
05302                  *  but a full intersection may not have been performed
05303                  *  on both faceuses yet.
05304                  */
05305                 /* Check angle first */
05306                 VMOVE( unit_e_dir, is->on_eg->e_dir );
05307                 VUNITIZE( unit_e_dir );
05308                 dot = VDOT(is->dir, unit_e_dir);
05309                 if( fabs(dot) < is->tol.para && /* not parallel */
05310                     !bn_2line3_colinear(
05311                     is->pt, is->dir,
05312                     is->on_eg->e_pt, unit_e_dir, 1000.0, &(is->tol) ) )  {
05313                         ang = acos(fabs(dot));
05314                         bu_log("WARNING nmg_isect_two_face3p() is->pt and on_eg lines differ by %g deg. (shared topo)\n",
05315                                 ang * bn_radtodeg );
05316                 }
05317                 /* Take geometry from the known shared edge is->on_eg */
05318                 nmg_isect_construct_nice_ray( is, fu2 );
05319         }
05320         if( !is->on_eg )  {
05321                 /* Geometry search */
05322                 if( !(is->on_eg = nmg_find_eg_on_line( &fu1->l.magic, is->pt, is->dir, &(is->tol) ) ) )  {
05323                         is->on_eg = nmg_find_eg_on_line( &fu2->l.magic, is->pt, is->dir, &(is->tol) );
05324                 }
05325                 if( is->on_eg )  {
05326                         /* Check angle */
05327                         VMOVE( unit_e_dir, is->on_eg->e_dir );
05328                         VUNITIZE( unit_e_dir );
05329                         dot = VDOT(is->dir, unit_e_dir);
05330                         if( fabs(dot) < is->tol.para && /* not parallel */
05331                             !bn_2line3_colinear(
05332                             is->pt, is->dir,
05333                             is->on_eg->e_pt, unit_e_dir, 1000.0, &(is->tol) ) )  {
05334                                 ang = acos(fabs(dot));
05335                                 bu_log("WARNING nmg_isect_two_face3p() is->pt and on_eg lines differ by %g deg. (geom search)\n",
05336                                         ang * bn_radtodeg );
05337                                 if( ang * bn_radtodeg > 1.0 )  {
05338                                         /* Forget about this shared topology */
05339                                         bu_log("nmg_isect_two_face3p() line direction mismatch (geom), clearing on_eg.\n");
05340                                         is->on_eg = (struct edge_g_lseg *)NULL;
05341                                 }
05342                         }
05343                 }
05344         }
05345         if( is->on_eg )  {
05346                 if( rt_g.NMG_debug & DEBUG_POLYSECT) {
05347                         VPRINT("is->on_eg->e_pt ", is->on_eg->e_pt);
05348                         VPRINT("is->on_eg->e_dir", is->on_eg->e_dir);
05349                 }
05350         }
05351 #endif
05352         (void)bu_ptbl(&vert_list1, BU_PTBL_INIT,(long *)NULL);
05353         (void)bu_ptbl(&vert_list2, BU_PTBL_INIT,(long *)NULL);
05354 
05355         /* Build list of all edgeuses in fu1 and fu2 */
05356         nmg_edgeuse_tabulate( &eu1_list, &fu1->l.magic );
05357         nmg_edgeuse_tabulate( &eu2_list, &fu2->l.magic );
05358 
05359         is->mag_len = 2 * (BU_PTBL_END( &eu1_list ) + BU_PTBL_END( &eu2_list ) );
05360         mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "mag1" );
05361         mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "mag2" );
05362 
05363         for( i=0 ; i<is->mag_len ; i++ )
05364         {
05365                 mag1[i] = MAX_FASTF;
05366                 mag2[i] = MAX_FASTF;
05367         }
05368 
05369 
05370         is->l1 = &vert_list1;
05371         is->l2 = &vert_list2;
05372         is->s1 = fu1->s_p;
05373         is->s2 = fu2->s_p;
05374         is->fu1 = fu1;
05375         is->fu2 = fu2;
05376         is->mag1 = mag1;
05377         is->mag2 = mag2;
05378 #if 0
05379         /*  Intersect the line with everything in fu1.
05380          *  Note any colinear edgeuses in fu2 for potential sharing.
05381          */
05382         nmg_isect_line2_face2pNEW(is, fu1, fu2, &eu1_list, &eu2_list);
05383 
05384         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
05385                 nmg_fu_touchingloops(fu1);
05386                 nmg_fu_touchingloops(fu2);
05387                 nmg_vfu( &fu1->s_p->fu_hd, fu1->s_p );
05388                 nmg_vfu( &fu2->s_p->fu_hd, fu2->s_p );
05389         }
05390 
05391         /*
05392          *  Now intersect the line with the other face.
05393          */
05394         if (rt_g.NMG_debug & DEBUG_FCUT) {
05395                 bu_log("nmg_isect_two_face3p(fu1=x%x, fu2=x%x) vert_lists A:\n", fu1, fu2);
05396                 nmg_pr_ptbl_vert_list( "vert_list1", &vert_list1, mag1 );
05397                 nmg_pr_ptbl_vert_list( "vert_list2", &vert_list2, mag2 );
05398         }
05399 
05400         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
05401                 bu_log("nmg_isect_two_face3p( fu1=x%x, fu2=x%x )  START21\n", fu1, fu2);
05402         }
05403 #endif
05404 
05405         /*
05406          *  Now do the intersection with the other face.
05407          */
05408         is->l2 = &vert_list1;
05409         is->l1 = &vert_list2;
05410         is->s2 = fu1->s_p;
05411         is->s1 = fu2->s_p;
05412         is->fu2 = fu1;
05413         is->fu1 = fu2;
05414         is->mag1 = mag2;
05415         is->mag2 = mag1;
05416 /*      nmg_isect_line2_face2pNEW(is, fu2, fu1, &eu2_list, &eu1_list); */
05417         is->on_eg = (struct edge_g_lseg *)NULL;
05418         nmg_isect_fu_jra(is, fu1, fu2, &eu1_list, &eu2_list);
05419 
05420         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
05421                 nmg_fu_touchingloops(fu1);
05422                 nmg_fu_touchingloops(fu2);
05423                 nmg_vfu( &fu1->s_p->fu_hd, fu1->s_p );
05424                 nmg_vfu( &fu2->s_p->fu_hd, fu2->s_p );
05425         }
05426 #if 0
05427         nmg_purge_unwanted_intersection_points(&vert_list1, mag1, fu2, &is->tol);
05428         nmg_purge_unwanted_intersection_points(&vert_list2, mag2, fu1, &is->tol);
05429 #endif
05430         if (rt_g.NMG_debug & DEBUG_FCUT) {
05431                 bu_log("nmg_isect_two_face3p(fu1=x%x, fu2=x%x) vert_lists B:\n", fu1, fu2);
05432                 nmg_pr_ptbl_vert_list( "vert_list1", &vert_list1, mag1 );
05433                 nmg_pr_ptbl_vert_list( "vert_list2", &vert_list2, mag2 );
05434         }
05435 
05436         if (vert_list1.end == 0 && vert_list2.end == 0) {
05437                 /* there were no intersections */
05438                 goto out;
05439         }
05440 
05441         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
05442                 bu_log("nmg_isect_two_face3p( fu1=x%x, fu2=x%x )  MIDDLE\n", fu1, fu2);
05443         }
05444 
05445         is->on_eg = nmg_face_cutjoin(&vert_list1, &vert_list2, mag1, mag2, fu1, fu2, is->pt, is->dir, is->on_eg, &is->tol);
05446 
05447         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
05448                 nmg_fu_touchingloops(fu1);
05449                 nmg_fu_touchingloops(fu2);
05450                 nmg_region_v_unique( fu1->s_p->r_p, &is->tol );
05451                 nmg_region_v_unique( fu2->s_p->r_p, &is->tol );
05452                 nmg_vfu( &fu1->s_p->fu_hd, fu1->s_p );
05453                 nmg_vfu( &fu2->s_p->fu_hd, fu2->s_p );
05454         }
05455 
05456         nmg_mesh_faces(fu1, fu2, &is->tol);
05457         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
05458                 nmg_fu_touchingloops(fu1);
05459                 nmg_fu_touchingloops(fu2);
05460         }
05461 
05462 #if 0
05463         nmg_show_broken_classifier_stuff((long *)fu1, (long **)NULL, 1, 0);
05464         nmg_show_broken_classifier_stuff((long *)fu2, (long **)NULL, 1, 0);
05465 #endif
05466 
05467 out:
05468         (void)bu_ptbl_free(&vert_list1);
05469         (void)bu_ptbl_free(&vert_list2);
05470         (void)bu_ptbl_free(&eu1_list);
05471         (void)bu_ptbl_free(&eu2_list);
05472         if( mag1 )
05473                 bu_free( (char *)mag1, "nmg_isect_two_face3p: mag1" );
05474         if( mag2 )
05475                 bu_free( (char *)mag2, "nmg_isect_two_face3p: mag2" );
05476 
05477 
05478         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
05479                 nmg_vfu( &fu1->s_p->fu_hd, fu1->s_p );
05480                 nmg_vfu( &fu2->s_p->fu_hd, fu2->s_p );
05481         }
05482         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
05483                 bu_log("nmg_isect_two_face3p( fu1=x%x, fu2=x%x )  END\n", fu1, fu2);
05484                 VPRINT("isect ray is->pt ", is->pt);
05485                 VPRINT("isect ray is->dir", is->dir);
05486         }
05487 }
05488 
05489 void
05490 nmg_cut_lu_into_coplanar_and_non(struct loopuse *lu, fastf_t *pl, struct nmg_inter_struct *is)
05491 {
05492         struct model *m;
05493         struct edgeuse *eu;
05494         struct vertex_g *vg2;
05495         struct vertex *vcut1,*vcut2;
05496         struct  bu_ptbl cut_list;
05497         fastf_t dist,dist2;
05498         int class1,class2;
05499         int in=0;
05500         int on=0;
05501         int out=0;
05502         int i;
05503 
05504         if (rt_g.NMG_debug & DEBUG_POLYSECT)
05505                 bu_log( "nmg_cut_lu_into_coplanar_and_non( lu=x%x, pl=%g %g %g %g )\n", lu, V4ARGS( pl ) );
05506 
05507         NMG_CK_LOOPUSE( lu );
05508         NMG_CK_INTER_STRUCT( is );
05509 
05510         m = nmg_find_model( &is->fu1->l.magic );
05511 
05512         /* check if this loop even needs to be considered */
05513         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
05514                 return;
05515 
05516         bu_ptbl_init( &cut_list, 64, " &cut_list");
05517 
05518         eu = BU_LIST_FIRST( edgeuse, &lu->down_hd );
05519         vg2 = eu->vu_p->v_p->vg_p;
05520         NMG_CK_VERTEX_G( vg2 );
05521         dist2 = DIST_PT_PLANE( vg2->coord, pl );
05522         if( dist2 > is->tol.dist )
05523         {
05524                 class2 = NMG_CLASS_AoutB;
05525                 out++;
05526         }
05527         else if( dist2 < (-is->tol.dist) )
05528         {
05529                 class2 = NMG_CLASS_AinB;
05530                 in++;
05531         }
05532         else
05533         {
05534                 class2 = NMG_CLASS_AonBshared;
05535                 on++;
05536         }
05537 
05538         vcut1 = (struct vertex *)NULL;
05539         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
05540         {
05541                 class1 = class2;
05542 
05543                 vg2 = eu->eumate_p->vu_p->v_p->vg_p;
05544                 dist2 = DIST_PT_PLANE( vg2->coord, pl );
05545 
05546                 if( dist2 > is->tol.dist )
05547                 {
05548                         class2 = NMG_CLASS_AoutB;
05549                         out++;
05550                 }
05551                 else if( dist2 < (-is->tol.dist) )
05552                 {
05553                         class2 = NMG_CLASS_AinB;
05554                         in++;
05555                 }
05556                 else
05557                 {
05558                         class2 = NMG_CLASS_AonBshared;
05559                         on++;
05560                 }
05561 
05562                 if( class1 == NMG_CLASS_AonBshared && class2 != class1 )
05563                 {
05564                         if( !vcut1 )
05565                         {
05566                                 vcut1 = eu->vu_p->v_p;
05567                         }
05568                         else if( vcut1 != eu->vu_p->v_p )
05569                         {
05570                                 bu_ptbl_ins( &cut_list, (long *)vcut1 );
05571                                 bu_ptbl_ins( &cut_list, (long *)eu->vu_p->v_p );
05572                                 vcut1 = (struct vertex *)NULL;
05573                         }
05574                 }
05575                 else if( class2 == NMG_CLASS_AonBshared && class1 != class2 )
05576                 {
05577                         if( !vcut1 )
05578                         {
05579                                 vcut1 = eu->eumate_p->vu_p->v_p;
05580                         }
05581                         else if( vcut1 != eu->eumate_p->vu_p->v_p )
05582                         {
05583                                 bu_ptbl_ins( &cut_list, (long *)vcut1 );
05584                                 bu_ptbl_ins( &cut_list, (long *)eu->eumate_p->vu_p->v_p );
05585                                 vcut1 = (struct vertex *)NULL;
05586                         }
05587                 }
05588         }
05589 
05590         if (rt_g.NMG_debug & DEBUG_POLYSECT)
05591         {
05592                 bu_log( "\t pl=( %g %g %g %g )\n", V4ARGS( pl ) );
05593                 bu_log( "\tcut_lists=%d, on=%d, in=%d, out=%d\n", BU_PTBL_END( &cut_list ),on,in,out );
05594                 if( BU_PTBL_END( &cut_list ) )
05595                 {
05596                         bu_log( "\tcut_lists:\n" );
05597                         for( i=0 ; i<BU_PTBL_END( &cut_list ) ; i++ )
05598                         {
05599                                 struct vertex *v;
05600 
05601                                 v = (struct vertex *)BU_PTBL_GET( &cut_list, i );
05602                                 bu_log( "\t\t%d, x%x\n", i+1, v );
05603                         }
05604                 }
05605         }
05606 
05607         if( !on )
05608                 return;
05609 
05610         if( BU_PTBL_END( &cut_list ) < 2 )
05611         {
05612                 bu_ptbl_free( &cut_list);
05613 
05614                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
05615                         bu_log( "No loops need cutting\n" );
05616                 return;
05617         }
05618 
05619         if( nmg_loop_is_a_crack( lu ) )
05620         {
05621                 struct bu_ptbl lus;
05622 
05623                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
05624                         bu_log( "Loop is a crack\n" );
05625 
05626                 i = 0;
05627                 while( i < BU_PTBL_END( &cut_list ) )
05628                 {
05629                         struct vertexuse *vu;
05630 
05631                         vcut1 = (struct vertex *)BU_PTBL_GET( &cut_list, i );
05632                         for( BU_LIST_FOR( vu, vertexuse, &vcut1->vu_hd ) )
05633                         {
05634                                 if( nmg_find_lu_of_vu( vu ) != lu )
05635                                         continue;
05636 
05637                                 eu = vu->up.eu_p;
05638                                 if( NMG_ARE_EUS_ADJACENT( eu, BU_LIST_PNEXT_CIRC( edgeuse, &eu->l ) ) )
05639                                 {
05640                                         i--;
05641                                         bu_ptbl_rm( &cut_list, (long *)vcut1 );
05642                                 }
05643                                 else if( NMG_ARE_EUS_ADJACENT( eu, BU_LIST_PPREV_CIRC( edgeuse, &eu->l ) ) )
05644                                 {
05645                                         i--;
05646                                         bu_ptbl_rm( &cut_list, (long *)vcut1 );
05647                                 }
05648                         }
05649                         i++;
05650                 }
05651 
05652                 if( BU_PTBL_END( &cut_list ) == 0 )
05653                 {
05654                         bu_ptbl_free( &cut_list);
05655 
05656                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
05657                                 bu_log( "no loops need cutting\n" );
05658                         return;
05659                 }
05660 
05661                 bu_ptbl_init( &lus, 64, " &lus");
05662                 bu_ptbl_ins( &lus, (long *)lu );
05663                 for( i=0 ; i<BU_PTBL_END( &cut_list ) ; i++ )
05664                 {
05665                         int j;
05666 
05667                         vcut1 = (struct vertex *)BU_PTBL_GET( &cut_list, i );
05668 
05669                         for( j=0 ; j<BU_PTBL_END( &lus ) ; j++ )
05670                         {
05671                                 int did_split=0;
05672                                 struct loopuse *lu1;
05673                                 struct vertexuse *vu1;
05674                                 struct loopuse *new_lu;
05675 
05676                                 lu1 = (struct loopuse *)BU_PTBL_GET( &lus, j );
05677 
05678                                 for( BU_LIST_FOR( vu1, vertexuse, &vcut1->vu_hd ) )
05679                                 {
05680                                         if( nmg_find_lu_of_vu( vu1 ) == lu1 )
05681                                         {
05682                                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
05683                                                         bu_log( "Splitting lu x%x at vu x%x\n", lu1, vu1 );
05684                                                 new_lu = nmg_split_lu_at_vu( lu1, vu1 );
05685                                                 nmg_lu_reorient( lu1 );
05686                                                 nmg_lu_reorient( new_lu );
05687                                                 nmg_loop_g( new_lu->l_p, &is->tol );
05688                                                 nmg_loop_g( lu1->l_p, &is->tol );
05689                                                 bu_ptbl_ins( &lus, (long *)new_lu );
05690                                                 did_split = 1;
05691                                                 break;
05692                                         }
05693                                 }
05694                                 if( did_split )
05695                                         break;
05696                         }
05697                 }
05698                 bu_ptbl_free( &lus);
05699                 bu_ptbl_free( &cut_list);
05700                 return;
05701         }
05702 
05703         if( BU_PTBL_END( &cut_list )%2 )
05704         {
05705                 bu_log( "Uneven number (%d) of vertices on cut list\n" , BU_PTBL_END( &cut_list ) );
05706                 rt_bomb( "Uneven number of vertices on cut list" );
05707         }
05708 
05709         /* Sort vertices on cut list into some order */
05710         if( BU_PTBL_END( &cut_list ) > 2 )
05711         {
05712                 struct vertex *v1=(struct vertex *)NULL;
05713                 struct vertex *v2=(struct vertex *)NULL;
05714                 struct vertex *end1 = NULL, *end2 = NULL;
05715                 fastf_t max_dist = 0.0;
05716                 vect_t diff;
05717                 fastf_t *dist_array;
05718                 int done;
05719 
05720                 /* find longest distance between two vertices */
05721                 for( i=0 ; i<BU_PTBL_END( &cut_list ) ; i++ )
05722                 {
05723                         int j;
05724 
05725                         v1 = (struct vertex *)BU_PTBL_GET( &cut_list, i );
05726 
05727                         for( j=i ; j<BU_PTBL_END( &cut_list ) ; j++ )
05728                         {
05729                                 fastf_t tmp_dist;
05730 
05731                                 v2 = (struct vertex *)BU_PTBL_GET( &cut_list, j );
05732                                 VSUB2( diff, v1->vg_p->coord, v2->vg_p->coord )
05733                                 tmp_dist = MAGSQ( diff );
05734                                 if( tmp_dist > max_dist )
05735                                 {
05736                                         max_dist = tmp_dist;
05737                                         end1 = v1;
05738                                         end2 = v2;
05739                                 }
05740                         }
05741                 }
05742                 if( !end1 || !end2 )
05743                 {
05744                         bu_log( "nmg_cut_lu_into_coplanar_and_non: Cannot find endpoints\n" );
05745                         rt_bomb( "nmg_cut_lu_into_coplanar_and_non: Cannot find endpoints\n" );
05746                 }
05747 
05748                 /* create array of distances (SQ) along the line from end1 to end2 */
05749                 dist_array = (fastf_t *)bu_calloc( sizeof( fastf_t ), BU_PTBL_END( &cut_list ), "distance array" );
05750                 for( i=0 ; i<BU_PTBL_END( &cut_list ) ; i++ )
05751                 {
05752                         v1 = (struct vertex *)BU_PTBL_GET( &cut_list, i );
05753                         if( v1 == end1 )
05754                         {
05755                                 dist_array[i] = 0.0;
05756                                 continue;
05757                         }
05758                         if( v1 == end2 )
05759                         {
05760                                 dist_array[i] = max_dist;
05761                                 continue;
05762                         }
05763 
05764                         VSUB2( diff, v1->vg_p->coord, end1->vg_p->coord )
05765                         dist_array[i] = MAGSQ( diff );
05766                 }
05767 
05768                 /* sort vertices according to distance array */
05769                 done = 0;
05770                 while( !done )
05771                 {
05772                         fastf_t tmp_dist;
05773                         long *tmp_v;
05774 
05775                         done = 1;
05776                         for( i=1 ; i<BU_PTBL_END( &cut_list ) ; i++ )
05777                         {
05778                                 if( dist_array[i-1] <= dist_array[i] )
05779                                         continue;
05780 
05781                                 /* swap distances in array */
05782                                 tmp_dist = dist_array[i];
05783                                 dist_array[i] = dist_array[i-1];
05784                                 dist_array[i-1] = tmp_dist;
05785 
05786                                 /* swap vertices */
05787                                 tmp_v = cut_list.buffer[i];
05788                                 cut_list.buffer[i] = cut_list.buffer[i-1];
05789                                 cut_list.buffer[i-1] = tmp_v;
05790 
05791                                 done = 0;
05792                         }
05793                 }
05794 
05795                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
05796                 {
05797                         bu_log( "After sorting:\n" );
05798                         for( i=0 ; i<BU_PTBL_END( &cut_list ) ; i++ )
05799                                 bu_log( "v=x%x, dist=%g\n", BU_PTBL_GET( &cut_list, i ), dist_array[i] );
05800                 }
05801 
05802                 bu_free( (char *)dist_array, "distance array" );
05803         }
05804 
05805         for( i=0 ; i<BU_PTBL_END( &cut_list ) ; i += 2 )
05806         {
05807                 struct loopuse *lu1;
05808                 struct vertexuse *vu;
05809                 vect_t dir;
05810                 point_t hit_pt;
05811                 struct vertex *hit_v;
05812                 struct vertexuse *hit_vu;
05813                 struct edgeuse *new_eu;
05814                 fastf_t len;
05815                 fastf_t inv_len;
05816                 int skip=0;
05817 
05818                 vcut1 = (struct vertex *)BU_PTBL_GET( &cut_list, i );
05819                 vcut2 = (struct vertex *)BU_PTBL_GET( &cut_list, i+1 );
05820 
05821                 if( vcut1 == vcut2 )
05822                         continue;
05823 
05824                 /* make sure these are not the ends of an edge of lu */
05825                 for( BU_LIST_FOR( vu, vertexuse, &vcut1->vu_hd ) )
05826                 {
05827                         if( nmg_find_lu_of_vu( vu ) != lu )
05828                                 continue;
05829 
05830                         eu = vu->up.eu_p;
05831                         if( eu->eumate_p->vu_p->v_p == vcut2 )
05832                         {
05833                                 /* already an edge here */
05834                                 skip = 1;
05835                                 break;
05836                         }
05837                 }
05838                 if( skip )
05839                         continue;
05840 
05841                 /* need to cut face along line from vcut1 to vcut2 */
05842                 VMOVE( is->pt, vcut1->vg_p->coord );
05843                 VSUB2( dir, vcut2->vg_p->coord, vcut1->vg_p->coord );
05844                 len = MAGNITUDE( dir );
05845                 if( len <= is->tol.dist )
05846                         continue;
05847 
05848                 inv_len = 1.0/len;
05849                 VSCALE( is->dir, dir, inv_len );
05850 
05851                 /* add vertexuses to intersect list */
05852                 bu_ptbl_reset( is->l1);
05853 
05854                 /* add uses of vcut1 */
05855                 for( BU_LIST_FOR( vu, vertexuse, &vcut1->vu_hd ) )
05856                 {
05857                         if( nmg_find_fu_of_vu( vu ) == is->fu1 )
05858                                 nmg_enlist_one_vu( is, vu, 0.0 );
05859                 }
05860 
05861                 /* add uses of vcut2 */
05862                 for( BU_LIST_FOR( vu, vertexuse, &vcut2->vu_hd ) )
05863                 {
05864                         if( nmg_find_fu_of_vu( vu ) == is->fu1 )
05865                                 nmg_enlist_one_vu( is, vu, len );
05866                 }
05867 
05868                 /* look for other edges that may intersect this line */
05869                 for( BU_LIST_FOR( lu1, loopuse, &is->fu1->lu_hd ) )
05870                 {
05871                         struct edgeuse *eu1;
05872 
05873                         NMG_CK_LOOPUSE( lu1 );
05874 
05875                         if( BU_LIST_FIRST_MAGIC( &lu1->down_hd ) != NMG_EDGEUSE_MAGIC )
05876                                 continue;
05877 
05878                         for( BU_LIST_FOR( eu1, edgeuse, &lu1->down_hd ) )
05879                         {
05880                                 int code;
05881                                 fastf_t dists[2];
05882                                 vect_t dir2;
05883 
05884                                 NMG_CK_EDGEUSE( eu1 );
05885 
05886                                 VSUB2( dir2, eu1->eumate_p->vu_p->v_p->vg_p->coord, eu1->vu_p->v_p->vg_p->coord );
05887                                 code = bn_isect_lseg3_lseg3( dists, is->pt, dir,
05888                                         eu1->vu_p->v_p->vg_p->coord, dir2, &is->tol );
05889                                 if( code < 0 )
05890                                         continue;
05891 
05892                                 if( code == 0 )
05893                                 {
05894                                         if( dists[0] > 0.0 && dists[0] < 1.0 )
05895                                         {
05896                                                 dist = dists[0]*len;
05897                                                 for( BU_LIST_FOR( vu, vertexuse, &eu1->vu_p->v_p->vu_hd ) )
05898                                                 {
05899                                                         if( nmg_find_fu_of_vu( vu ) == is->fu1 )
05900                                                                 nmg_enlist_one_vu( is, vu, dist );
05901                                                 }
05902                                         }
05903                                         if( dists[1] > 0.0 && dists[1] < 1.0 )
05904                                         {
05905                                                 dist = dists[1]*len;
05906                                                 for( BU_LIST_FOR( vu, vertexuse, &eu1->eumate_p->vu_p->v_p->vu_hd ) )
05907                                                 {
05908                                                         if( nmg_find_fu_of_vu( vu ) == is->fu1 )
05909                                                                 nmg_enlist_one_vu( is, vu, len );
05910                                                 }
05911                                         }
05912                                         continue;
05913                                 }
05914 
05915                                 /* normal intersection, may need to split eu1 */
05916                                 if( dists[0] <= 0.0 || dists[0] >= 1.0 )
05917                                         continue;
05918 
05919                                 if( dists[1] <= 0.0 || dists[1] >= 1.0 )
05920                                         continue;
05921 
05922                                 VJOIN1( hit_pt, is->pt, dists[0], dir );
05923                                 hit_vu = (struct vertexuse *)NULL;
05924                                 hit_v = (struct vertex *)NULL;
05925 
05926                                 hit_vu = nmg_find_pt_in_face( is->fu1, hit_pt, &is->tol );
05927                                 if( hit_vu )
05928                                         hit_v = hit_vu->v_p;
05929 
05930                                 if( !hit_v )
05931                                         hit_v = nmg_find_pt_in_model( m, hit_pt, &is->tol );
05932                                 new_eu = nmg_esplit( hit_v, eu1, 1 );
05933                                 hit_v = new_eu->vu_p->v_p;
05934                                 if( !hit_v->vg_p )
05935                                         nmg_vertex_gv( hit_v, hit_pt );
05936 
05937                                 /* add uses of hit_v to intersection list */
05938                                 dist = dists[0]*len;
05939                                 for( BU_LIST_FOR( vu, vertexuse, &hit_v->vu_hd ) )
05940                                 {
05941                                         if( nmg_find_fu_of_vu( vu ) == is->fu1 )
05942                                                 nmg_enlist_one_vu( is, vu, dist );
05943                                 }
05944                         }
05945                 }
05946 
05947                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
05948                         bu_log( "nmg_cut_lu_into_coplanar_and_non: calling face cutter\n" );
05949                 bu_ptbl_reset( is->l2);
05950                 (void)nmg_face_cutjoin( is->l1, is->l2, is->mag1, is->mag2, is->fu1,
05951                         is->fu2, is->pt, is->dir, is->on_eg, &is->tol);
05952 
05953                 vcut1 = (struct vertex *)NULL;
05954                 vcut2 = (struct vertex *)NULL;
05955         }
05956 
05957         bu_ptbl_free( &cut_list);
05958 }
05959 
05960 static void
05961 nmg_isect_coplanar_edges(struct nmg_inter_struct *is, struct bu_ptbl *eu1_list, struct bu_ptbl *eu2_list)
05962 {
05963         struct model *m;
05964         struct loopuse *lu;
05965         struct bu_ptbl v_list;
05966         int i,j;
05967         plane_t pl1,pl2;
05968 
05969         if (rt_g.NMG_debug & DEBUG_POLYSECT)
05970                 bu_log( "nmg_isect_coplanar_edges START\n" );
05971 
05972         NMG_CK_INTER_STRUCT( is );
05973         BU_CK_PTBL( eu1_list );
05974         BU_CK_PTBL( eu2_list );
05975 
05976         m = nmg_find_model( &is->fu1->l.magic );
05977 
05978         NMG_GET_FU_PLANE( pl1, is->fu1 );
05979         NMG_GET_FU_PLANE( pl2, is->fu2 );
05980 
05981         if (rt_g.NMG_debug & DEBUG_POLYSECT)
05982         {
05983                 bu_log( "pl1 = %g %g %g %g\n", V4ARGS( pl1 ) );
05984                 bu_log( "pl2 = %g %g %g %g\n", V4ARGS( pl2 ) );
05985         }
05986 
05987         /* First split all edgeuses that intersect */
05988         for( i=0 ; i<BU_PTBL_END( eu1_list ) ; i++ )
05989         {
05990                 struct edgeuse *eu1;
05991                 double len_vt1;
05992                 vect_t vt1;
05993                 struct vertex_g *vg1a,*vg1b;
05994 
05995                 eu1 = (struct edgeuse *)BU_PTBL_GET( eu1_list, i );
05996                 NMG_CK_EDGEUSE( eu1 );
05997 
05998                 vg1a = eu1->vu_p->v_p->vg_p;
05999                 NMG_CK_VERTEX_G( vg1a );
06000                 vg1b = eu1->eumate_p->vu_p->v_p->vg_p;
06001                 NMG_CK_VERTEX_G( vg1b );
06002 
06003                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
06004                         bu_log( "Considering EU x%x (%g %g %g) <-> (%g %g %g)\n",
06005                                 eu1, V3ARGS( vg1a->coord ), V3ARGS( vg1b->coord ) );
06006 
06007 #if 0
06008                 /* only consider edges in the plane of the other face */
06009                 if( !NEAR_ZERO( DIST_PT_PLANE( vg1a->coord, pl2 ), is->tol.dist ) )
06010                 {
06011                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06012                                 bu_log( "\tvg1a is not in other plane (%g)\n", DIST_PT_PLANE( vg1a->coord, pl2 ) );
06013                         continue;
06014                 }
06015                 if( !NEAR_ZERO( DIST_PT_PLANE( vg1b->coord, pl2 ), is->tol.dist ) )
06016                 {
06017                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06018                                 bu_log( "\tvg1b is not in other plane (%g)\n", DIST_PT_PLANE( vg1b->coord, pl2 ) );
06019                         continue;
06020                 }
06021 #endif
06022 
06023                 VSUB2( vt1, vg1b->coord, vg1a->coord );
06024                 len_vt1 = MAGNITUDE( vt1 );
06025                 VSCALE( vt1, vt1, 1.0/len_vt1 );
06026 
06027                 for( j=0 ; j<BU_PTBL_END( eu2_list ) ; j++ )
06028                 {
06029                         struct edgeuse *eu2;
06030                         struct vertex_g *vg2a,*vg2b;
06031                         int code;
06032                         vect_t vt2;
06033                         double len_vt2;
06034                         fastf_t dist[2];
06035                         point_t hit_pt;
06036                         int hit_no;
06037                         int hit_count;
06038                         struct vertex *hitv;
06039                         struct vertexuse *hit_vu;
06040 
06041                         eu2 = (struct edgeuse *)BU_PTBL_GET( eu2_list, j );
06042                         NMG_CK_EDGEUSE( eu2 );
06043 
06044                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06045                                 bu_log( "\tConsidering EU2 x%x (%g %g %g) <-> (%g %g %g)\n",
06046                                         eu2, V3ARGS( eu2->vu_p->v_p->vg_p->coord ), V3ARGS( eu2->eumate_p->vu_p->v_p->vg_p->coord ) );
06047 #if 0
06048                         /* only consider edges in the plane of the other face */
06049                         if( !NEAR_ZERO( DIST_PT_PLANE( eu2->vu_p->v_p->vg_p->coord, pl1 ), is->tol.dist ) )
06050                         {
06051                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
06052                                         bu_log( "\t\tEU2 start pt not in other plane (%g)\n",
06053                                                 DIST_PT_PLANE( eu2->vu_p->v_p->vg_p->coord, pl1 ) );
06054                                 continue;
06055                         }
06056                         if( !NEAR_ZERO( DIST_PT_PLANE( eu2->eumate_p->vu_p->v_p->vg_p->coord, pl1 ), is->tol.dist ) )
06057                         {
06058                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
06059                                         bu_log( "\t\tEU2 end pt not in other plane (%g)\n",
06060                                                 DIST_PT_PLANE( eu2->eumate_p->vu_p->v_p->vg_p->coord, pl1 ) );
06061                                 continue;
06062                         }
06063 #endif
06064 
06065                         /* if these edges are radial, nothing to do */
06066                         if( eu1->vu_p->v_p == eu2->vu_p->v_p &&
06067                                 eu1->eumate_p->vu_p->v_p == eu2->eumate_p->vu_p->v_p )
06068                                         continue;
06069 
06070                         if( eu1->vu_p->v_p == eu2->eumate_p->vu_p->v_p &&
06071                                 eu1->eumate_p->vu_p->v_p == eu2->vu_p->v_p )
06072                                         continue;
06073 
06074                         vg2a = eu2->vu_p->v_p->vg_p;
06075                         NMG_CK_VERTEX_G( vg2a );
06076                         vg2b = eu2->eumate_p->vu_p->v_p->vg_p;
06077                         NMG_CK_VERTEX_G( vg2b );
06078                         VSUB2( vt2, vg2b->coord, vg2a->coord  );
06079                         len_vt2 = MAGNITUDE( vt2 );
06080                         VSCALE( vt2, vt2, 1.0/len_vt2 );
06081 
06082                         code = rt_dist_line3_line3( dist, vg1a->coord, vt1,
06083                                 vg2a->coord, vt2, &is->tol );
06084 
06085                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06086                                 bu_log( "\tcode = %d\n", code );
06087 
06088                         if( code == (-2) || code == 1 )
06089                                 continue;
06090 
06091                         if( code == (-1) )
06092                         {
06093                                 fastf_t tmp;
06094                                 vect_t tmp_vect;
06095                                 fastf_t dist1[2];
06096 
06097                                 hit_count = 0;
06098 
06099                                 /* lines are colinear */
06100                                 VSUB2( tmp_vect, vg2a->coord, vg1a->coord );
06101                                 dist1[0] = VDOT( tmp_vect, vt1 );
06102                                 if( NEAR_ZERO( dist1[0], is->tol.dist ) )
06103                                         dist1[0] = 0.0;
06104                                 else if( NEAR_ZERO( dist1[0] - len_vt1, is->tol.dist ) )
06105                                         dist1[0] = len_vt1;
06106                                 VSUB2( tmp_vect, vg2b->coord, vg1a->coord );
06107                                 dist1[1] = VDOT( tmp_vect, vt1 );
06108                                 if( NEAR_ZERO( dist1[1], is->tol.dist ) )
06109                                         dist1[1] = 0.0;
06110                                 else if( NEAR_ZERO( dist1[1] - len_vt1, is->tol.dist ) )
06111                                         dist1[1] = len_vt1;
06112 
06113                                 if( (dist1[0] >= 0.0 && dist1[0] <= len_vt1 ) )
06114                                 {
06115                                         dist[hit_count] = dist1[0];
06116                                         hit_count++;
06117                                 }
06118                                 if ( (dist1[1] >= 0.0 && dist1[1] <= len_vt1 ) )
06119                                 {
06120                                         dist[hit_count] = dist1[1];
06121                                         hit_count++;
06122                                 }
06123 
06124                                 if( hit_count == 0 )
06125                                         continue;
06126 
06127                                 if( hit_count == 2 && dist[0] < dist[1] )
06128                                 {
06129                                         tmp = dist[0];
06130                                         dist[0] = dist[1];
06131                                         dist[1] = tmp;
06132                                 }
06133                         }
06134                         else
06135                         {
06136                                 if( NEAR_ZERO( dist[0], is->tol.dist ) )
06137                                         dist[0] = 0.0;
06138                                 else if( NEAR_ZERO( dist[0] - len_vt1, is->tol.dist ) )
06139                                         dist[0] = len_vt1;
06140                                 if( NEAR_ZERO( dist[1], is->tol.dist ) )
06141                                         dist[1] = 0.0;
06142                                 else if( NEAR_ZERO( dist[1] - len_vt2, is->tol.dist ) )
06143                                         dist[1] = len_vt2;
06144                                 if( dist[0] < 0.0 || dist[0] > len_vt1 )
06145                                         continue;
06146                                 if( dist[1] < 0.0 || dist[1] > len_vt2 )
06147                                         continue;
06148                                 hit_count = 1;
06149                         }
06150 
06151                         for( hit_no=0 ; hit_no < hit_count ; hit_no++ )
06152                         {
06153                                 struct edgeuse *new_eu;
06154 
06155                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
06156                                         bu_log( "\tdist[%d] = %g\n", hit_no, dist[hit_no] );
06157 
06158                                 hitv = (struct vertex *)NULL;
06159                                 hit_vu = (struct vertexuse *)NULL;
06160 
06161                                 if( dist[hit_no] == 0.0 )
06162                                 {
06163                                         hit_vu = eu1->vu_p;
06164                                         hitv = hit_vu->v_p;
06165                                         VMOVE( hit_pt, hitv->vg_p->coord );
06166                                 }
06167                                 else if( dist[hit_no] == len_vt1 )
06168                                 {
06169                                         hit_vu = eu1->eumate_p->vu_p;
06170                                         hitv = hit_vu->v_p;
06171                                         VMOVE( hit_pt, hitv->vg_p->coord );
06172                                 }
06173                                 else
06174                                         VJOIN1( hit_pt, vg1a->coord , dist[hit_no], vt1 )
06175 
06176                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
06177                                         bu_log( "eus x%x and x%x intersect #%d at (%g %g %g)\n",
06178                                                 eu1, eu2, hit_no, V3ARGS( hit_pt ) );
06179 
06180                                 if( !hit_vu )
06181                                         hit_vu = nmg_find_pt_in_face( is->fu2, hit_pt, &is->tol );
06182 
06183                                 if( !hit_vu )
06184                                         hitv = nmg_find_pt_in_model( nmg_find_model( &is->fu1->l.magic ), hit_pt, &is->tol );
06185                                 else
06186                                         hitv = hit_vu->v_p;
06187 
06188                                 if (rt_g.NMG_debug & DEBUG_POLYSECT && hitv)
06189                                         bu_log( "Found vertex (x%x) at hit_pt\n", hitv );
06190 
06191                                 if( hitv != eu1->vu_p->v_p && hitv != eu1->eumate_p->vu_p->v_p )
06192                                 {
06193                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06194                                                 bu_log( "Splitting eu1 x%x\n", eu1 );
06195                                         new_eu = nmg_esplit( hitv, eu1, 1 );
06196                                         hitv = new_eu->vu_p->v_p;
06197                                         if( !hitv->vg_p )
06198                                                 nmg_vertex_gv( hitv, hit_pt );
06199                                         vg1b = eu1->eumate_p->vu_p->v_p->vg_p;
06200                                         VSUB2( vt1, vg1b->coord, vg1a->coord );
06201                                         len_vt1 = MAGNITUDE( vt1 );
06202                                         VSCALE( vt1, vt1, 1.0/len_vt1 );
06203                                         bu_ptbl_ins( eu1_list, (long *)new_eu );
06204                                 }
06205                                 if( code == 0 && hitv != eu2->vu_p->v_p && hitv != eu2->eumate_p->vu_p->v_p )
06206                                 {
06207                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06208                                                 bu_log( "Splitting eu2 x%x at hitv = x%x\n",  eu2, hitv );
06209                                         new_eu = nmg_esplit( hitv, eu2, 1 );
06210                                         hitv = new_eu->vu_p->v_p;
06211                                         if( !hitv->vg_p )
06212                                                 nmg_vertex_gv( hitv, hit_pt );
06213                                         bu_ptbl_ins( eu2_list, (long *)new_eu );
06214                                 }
06215 
06216                                 if( hitv )
06217                                         (void)nmg_break_all_es_on_v( &m->magic, hitv, &is->tol );
06218                         }
06219                 }
06220         }
06221 
06222         bu_ptbl_free( eu1_list);
06223         bu_ptbl_free( eu2_list);
06224 
06225         /* Make sure every vertex in fu1 has dual in fu2
06226          * (if they overlap)
06227          */
06228         nmg_vertex_tabulate( &v_list, &is->fu1->l.magic );
06229 
06230         for( i=0 ; i<BU_PTBL_END( &v_list ) ; i++ )
06231         {
06232                 struct vertex *v;
06233                 int class;
06234 
06235                 v = (struct vertex *)BU_PTBL_GET( &v_list, i );
06236                 NMG_CK_VERTEX( v );
06237 
06238                 if( nmg_find_v_in_face( v, is->fu2 ) )
06239                         continue;
06240 
06241                 /* Check if this vertex is within other FU */
06242                 if( !NEAR_ZERO( DIST_PT_PLANE( v->vg_p->coord, pl2 ), is->tol.dist ) )
06243                         continue;
06244 
06245                 class = nmg_class_pt_fu_except( v->vg_p->coord, is->fu2, NULL, NULL, NULL,
06246                         (char *)NULL, 0, 0, &is->tol );
06247 
06248                 if( class == NMG_CLASS_AinB )
06249                 {
06250                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06251                                 bu_log( "Making dualvu of vertex x%x in is->fu2 x%x\n", v, is->fu2 );
06252                         (void)nmg_make_dualvu( v, is->fu2, &is->tol );
06253                 }
06254         }
06255         bu_ptbl_reset( &v_list);
06256 
06257         /* same for fu2  */
06258         nmg_vertex_tabulate( &v_list, &is->fu2->l.magic );
06259 
06260         for( i=0 ; i<BU_PTBL_END( &v_list ) ; i++ )
06261         {
06262                 struct vertex *v;
06263                 int class;
06264 
06265                 v = (struct vertex *)BU_PTBL_GET( &v_list, i );
06266                 NMG_CK_VERTEX( v );
06267 
06268                 if( nmg_find_v_in_face( v, is->fu1 ) )
06269                         continue;
06270 
06271                 /* Check if this vertex is within other FU */
06272                 if( !NEAR_ZERO( DIST_PT_PLANE( v->vg_p->coord, pl1 ), is->tol.dist ) )
06273                         continue;
06274 
06275                 class = nmg_class_pt_fu_except( v->vg_p->coord, is->fu1, NULL, NULL, NULL,
06276                         (char *)NULL, 0, 0, &is->tol );
06277 
06278                 if( class == NMG_CLASS_AinB )
06279                 {
06280                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06281                                 bu_log( "Making dualvu of vertex x%x in fu1 x%x\n", v, is->fu1 );
06282                         (void)nmg_make_dualvu( v, is->fu1, &is->tol );
06283                 }
06284         }
06285 
06286         bu_ptbl_free( &v_list);
06287 
06288         bu_ptbl_reset( is->l1);
06289         bu_ptbl_reset( is->l2);
06290 
06291         for( BU_LIST_FOR( lu, loopuse, &is->fu1->lu_hd ) )
06292         {
06293                 struct edgeuse *eu;
06294 
06295                 NMG_CK_LOOPUSE( lu );
06296 
06297                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
06298                         continue;
06299 
06300                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
06301                 {
06302                         struct vertexuse *vu;
06303                         struct vertex *v1,*v2;
06304 
06305                         NMG_CK_EDGEUSE( eu );
06306 
06307                         v1 = eu->vu_p->v_p;
06308                         NMG_CK_VERTEX( v1 );
06309                         v2 = eu->eumate_p->vu_p->v_p;
06310                         NMG_CK_VERTEX( v2 );
06311 
06312                         if( !NEAR_ZERO( DIST_PT_PLANE( v1->vg_p->coord, pl2), is->tol.dist ) )
06313                                 continue;
06314                         if( !NEAR_ZERO( DIST_PT_PLANE( v2->vg_p->coord, pl2), is->tol.dist ) )
06315                                 continue;
06316 
06317                         if( !nmg_find_v_in_face( v1, is->fu2 ) ||
06318                                 !nmg_find_v_in_face( v2, is->fu2 ) )
06319                                 continue;
06320 
06321                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06322                                 bu_log( "Making EU x%x an intersect line for face cutting\n", eu );
06323 
06324                         for( BU_LIST_FOR( vu, vertexuse, &v1->vu_hd ) )
06325                         {
06326                                 struct faceuse *fu;
06327 
06328                                 fu = nmg_find_fu_of_vu( vu );
06329 
06330                                 if( fu == is->fu2 )
06331                                         nmg_enlist_one_vu( is, vu, 0.0 );
06332                         }
06333 
06334                         for( BU_LIST_FOR( vu, vertexuse, &v2->vu_hd ) )
06335                         {
06336                                 struct faceuse *fu;
06337 
06338                                 fu = nmg_find_fu_of_vu( vu );
06339 
06340                                 if( fu == is->fu2 )
06341                                         nmg_enlist_one_vu( is, vu, 1.0 );
06342                         }
06343 
06344                         /* Now do face cutting */
06345                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06346                                 bu_log( "Calling face cutter for fu2 x%x\n", is->fu2 );
06347                         nmg_fcut_face_2d( is->l2, is->mag2, is->fu2, is->fu1, &is->tol );
06348 
06349                         bu_ptbl_reset( is->l1);
06350                         bu_ptbl_reset( is->l2);
06351                 }
06352         }
06353 
06354         for( BU_LIST_FOR( lu, loopuse, &is->fu2->lu_hd ) )
06355         {
06356                 struct edgeuse *eu;
06357 
06358                 NMG_CK_LOOPUSE( lu );
06359 
06360                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
06361                         continue;
06362 
06363                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
06364                 {
06365                         struct vertexuse *vu;
06366                         struct vertex *v1,*v2;
06367 
06368                         NMG_CK_EDGEUSE( eu );
06369 
06370                         v1 = eu->vu_p->v_p;
06371                         NMG_CK_VERTEX( v1 );
06372                         v2 = eu->eumate_p->vu_p->v_p;
06373                         NMG_CK_VERTEX( v2 );
06374 
06375                         if( !NEAR_ZERO( DIST_PT_PLANE( v1->vg_p->coord, pl1), is->tol.dist ) )
06376                                 continue;
06377                         if( !NEAR_ZERO( DIST_PT_PLANE( v2->vg_p->coord, pl1), is->tol.dist ) )
06378                                 continue;
06379 
06380                         if( !nmg_find_v_in_face( v1, is->fu1 ) ||
06381                                 !nmg_find_v_in_face( v2, is->fu1 ) )
06382                                 continue;
06383 
06384                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06385                                 bu_log( "Making EU x%x an intersect line for face cutting\n", eu );
06386 
06387                         for( BU_LIST_FOR( vu, vertexuse, &v1->vu_hd ) )
06388                         {
06389                                 struct faceuse *fu;
06390 
06391                                 fu = nmg_find_fu_of_vu( vu );
06392 
06393                                 if( fu == is->fu1 )
06394                                         nmg_enlist_one_vu( is, vu, 0.0 );
06395                         }
06396 
06397                         for( BU_LIST_FOR( vu, vertexuse, &v2->vu_hd ) )
06398                         {
06399                                 struct faceuse *fu;
06400 
06401                                 fu = nmg_find_fu_of_vu( vu );
06402 
06403                                 if( fu == is->fu1 )
06404                                         nmg_enlist_one_vu( is, vu, 1.0 );
06405                         }
06406 
06407                         /* Now do face cutting */
06408                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06409                                 bu_log( "Calling face cutter for fu1 x%x\n", is->fu1 );
06410                         nmg_fcut_face_2d( is->l1, is->mag1, is->fu1, is->fu2, &is->tol );
06411 
06412                         bu_ptbl_reset( is->l1);
06413                         bu_ptbl_reset( is->l2);
06414                 }
06415         }
06416 }
06417 
06418 #if 0
06419 static void
06420 jra_save_fu_data( fu1, fu2, pl1, pl2 )
06421 struct faceuse *fu1,*fu2;
06422 plane_t pl1,pl2;
06423 {
06424         NMG_CK_FACEUSE( fu1 );
06425         NMG_CK_FACEUSE( fu2 );
06426 
06427         bu_log( "STARTDATA\n" );
06428         bu_log( "%f %f %f %f\n", V4ARGS( pl1 ) );
06429         bu_log( "%f %f %f %f\n", V4ARGS( pl2 ) );
06430         nmg_pr_fu_briefly( fu1, "" );
06431         nmg_pr_fu_briefly( fu2, "" );
06432         bu_log( "ENDDATA\n" );
06433 }
06434 #endif
06435 #define MAX_FACES       200
06436 void
06437 nmg_check_radial_angles(char *str, struct shell *s, const struct bn_tol *tol)
06438 {
06439         struct bu_ptbl edges;
06440         vect_t xvec,yvec,zvec;
06441         int i,j;
06442         double angle[MAX_FACES];
06443         struct faceuse *fus[MAX_FACES];
06444         int face_count;
06445         int increasing;
06446 
06447         NMG_CK_SHELL( s );
06448         BN_CK_TOL( tol );
06449 
06450         bu_ptbl_init( &edges, 64, " &edges");
06451         nmg_edge_tabulate( &edges, &s->l.magic );
06452 
06453         for( i=0 ; i<BU_PTBL_END( &edges ) ; i++ )
06454         {
06455                 struct edge *e;
06456                 struct edgeuse *eu_start;
06457                 struct edgeuse *eu;
06458                 struct faceuse *fu;
06459                 int start;
06460 
06461                 e = (struct edge *)BU_PTBL_GET( &edges,  i );
06462                 NMG_CK_EDGE( e );
06463 
06464                 eu_start = e->eu_p;
06465                 NMG_CK_EDGEUSE( eu_start );
06466 
06467                 eu = eu_start;
06468                 do
06469                 {
06470                         fu = nmg_find_fu_of_eu( eu );
06471                 } while( !fu && eu != eu_start );
06472 
06473                 if( !fu )
06474                         continue;
06475 
06476                 eu_start = eu;
06477                 if( nmg_find_eu_leftvec( xvec, eu ) )
06478                         rt_bomb( "nmg_check_radial_angles() eu not part of a face!!" );
06479 
06480                 VSUB2( zvec, eu->eumate_p->vu_p->v_p->vg_p->coord, eu->vu_p->v_p->vg_p->coord );
06481                 VUNITIZE( zvec );
06482                 VCROSS( yvec, zvec, xvec );
06483 
06484                 face_count = 0;
06485 
06486                 eu = eu_start;
06487                 do
06488                 {
06489                         fu = nmg_find_fu_of_eu( eu );
06490                         if( fu )
06491                         {
06492                                 if( face_count >= MAX_FACES )
06493                                 {
06494                                         bu_log( "Too many faces in nmg_check_radial_angles (%d)\n", face_count );
06495                                         rt_bomb( "Too many faces in nmg_check_radial_angles\n" );
06496                                 }
06497                                 angle[face_count] = nmg_measure_fu_angle( eu, xvec, yvec, zvec );
06498                                 fus[face_count] = fu;
06499                                 face_count++;
06500                         }
06501                         eu = eu->eumate_p->radial_p;
06502                 } while( eu != eu_start );
06503 
06504                 /* list of angles should be monotonically increasing or decreasing */
06505                 increasing =  (-1);
06506                 start = 1;
06507                 for( j=2 ; j<=face_count ; j++ )
06508                 {
06509                         if( angle[j] == 0.0 || angle[j] == bn_twopi )
06510                                 continue;
06511                         if( angle[j] == angle[j-1] )
06512                                 continue;
06513                         else if( angle[j] > angle[j-1] )
06514                         {
06515                                 start = j;
06516                                 increasing = 1;
06517                                 break;
06518                         }
06519                         else
06520                         {
06521                                 start = j;
06522                                 increasing = 0;
06523                                 break;
06524                         }
06525                 }
06526 
06527                 if( increasing == (-1 ) )
06528                         continue;
06529 
06530                 for( j=start+1 ; j<face_count ; j++ )
06531                 {
06532                         if( (increasing && angle[j] < angle[j-1]) ||
06533                             (!increasing && angle[j] > angle[j-1]) )
06534                         {
06535                                 bu_log( str );
06536                                 bu_log( "nmg_check_radial_angles(): angles not monotonically increasing or decreasing\n" );
06537                                 bu_log( "start=%d, increasing = %d\n", start, increasing );
06538                                 bu_log( "\tfaces around eu x%x\n", eu_start );
06539                                 for( j=0 ; j<face_count ; j++ )
06540                                         bu_log( "\t\tfu=x%x, angle=%g\n", fus[j], angle[j]*180.0/bn_pi );
06541                                 rt_bomb( "nmg_check_radial_angles(): angles not monotonically increasing or decreasing\n" );
06542                         }
06543                 }
06544         }
06545         bu_ptbl_free( &edges);
06546 }
06547 
06548 /**                     N M G _ I S E C T _ N E A R L Y _ C O P L A N A R _ F A C E S
06549  *
06550  *      The two faceuses passed are expected to be parallel and distinct or coplanar
06551  *      according to bn_isect_2planes(). Also, some (but not all) of the vertices in
06552  *      one faceuse are within tolerance of the other faceuse. This case is singled
06553  *      out in nmg_isect_two_generic_faces().
06554  *
06555  *      The algorithm is:
06556  *              1. split any edges that pass from beyond tolerance on one side
06557  *                 of the other faceuse to beyond tolerance on the other side.
06558  *              2. cut all loops in each faceuse such that the resulting loops are
06559  *                 either entirely within tolerance of the other faceuse, or share
06560  *                 only one "line of intersection" with the other faceuse.
06561  *              3. intersect coplanar loops same as done in nmg_isect_two_face2p_jra().
06562  */
06563 static void
06564 nmg_isect_nearly_coplanar_faces(struct nmg_inter_struct *is, struct faceuse *fu1, struct faceuse *fu2)
06565 {
06566         int i;
06567         struct model *m;
06568         struct edgeuse *eu;
06569         struct loopuse *lu;
06570         struct bu_ptbl loops;
06571         plane_t pl1;
06572         plane_t pl2;
06573         fastf_t *mag1,*mag2;
06574         struct bu_ptbl eu1_list;
06575         struct bu_ptbl vert_list1;
06576         struct bu_ptbl eu2_list;
06577         struct bu_ptbl vert_list2;
06578         struct bu_ptbl verts;
06579 
06580         NMG_CK_FACEUSE( fu1 );
06581         NMG_CK_FACEUSE( fu2 );
06582         NMG_CK_INTER_STRUCT(is);
06583 
06584         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06585                 bu_log( "nmg_isect_nearly_coplanar_faces( fu1=x%x, fu2=x%x )\n", fu1, fu2 );
06586 
06587         m = nmg_find_model( &fu1->l.magic );
06588         NMG_CK_MODEL( m );
06589 
06590         NMG_GET_FU_PLANE( pl1, fu1 );
06591         NMG_GET_FU_PLANE( pl2, fu2 );
06592 
06593 #if 0
06594         jra_save_fu_data( fu1, fu2, pl1, pl2 );
06595 #endif
06596 
06597         nmg_edgeuse_tabulate( &eu1_list, &fu1->l.magic );
06598         nmg_edgeuse_tabulate( &eu2_list, &fu2->l.magic );
06599 
06600         is->mag_len = 2 * (BU_PTBL_END( &eu1_list ) + BU_PTBL_END( &eu2_list ) );
06601         mag1 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "mag1" );
06602         mag2 = (fastf_t *)bu_calloc( is->mag_len, sizeof( fastf_t ), "mag2" );
06603 
06604         for( i=0 ; i<is->mag_len ; i++ )
06605         {
06606                 mag1[i] = MAX_FASTF;
06607                 mag2[i] = MAX_FASTF;
06608         }
06609 
06610         bu_ptbl_init( &vert_list1, 64, " &vert_list1");
06611         bu_ptbl_init( &vert_list2, 64, " &vert_list2");
06612 
06613         is->s1 = fu1->s_p;
06614         is->s2 = fu2->s_p;
06615         is->fu1 = fu1;
06616         is->fu2 = fu2;
06617         is->l1 = &vert_list1;
06618         is->l2 = &vert_list2;
06619         is->mag1 = mag1;
06620         is->mag2 = mag2;
06621         is->on_eg = (struct edge_g_lseg *)NULL;
06622 
06623         /* split any edges that pass through the plane of the other faceuse */
06624         for( BU_LIST_FOR( lu, loopuse, &fu1->lu_hd ) )
06625         {
06626                 NMG_CK_LOOPUSE( lu );
06627                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
06628                         continue;
06629 
06630                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
06631                 {
06632                         int code;
06633                         int class1,class2;
06634                         fastf_t dist;
06635                         struct vertex_g *vg1,*vg2;
06636                         vect_t dir;
06637                         point_t hit_pt;
06638                         struct vertexuse *hit_vu;
06639                         struct vertex *hit_v=(struct vertex *)NULL;
06640                         struct edgeuse *new_eu;
06641 
06642                         NMG_CK_EDGEUSE( eu );
06643 
06644                         vg1 = eu->vu_p->v_p->vg_p;
06645                         vg2 = eu->eumate_p->vu_p->v_p->vg_p;
06646 
06647                         dist = DIST_PT_PLANE( vg1->coord, pl2 );
06648                         if( dist > is->tol.dist )
06649                                 class1 = NMG_CLASS_AoutB;
06650                         else if( dist < (-is->tol.dist ) )
06651                                 class1 = NMG_CLASS_AinB;
06652                         else
06653                                 class1 = NMG_CLASS_AonBshared;
06654 
06655                         dist = DIST_PT_PLANE( vg2->coord, pl2 );
06656                         if( dist > is->tol.dist )
06657                                 class2 = NMG_CLASS_AoutB;
06658                         else if( dist < (-is->tol.dist ) )
06659                                 class2 = NMG_CLASS_AinB;
06660                         else
06661                                 class2 = NMG_CLASS_AonBshared;
06662 
06663                         if( class1 == class2 )
06664                                 continue;
06665 
06666                         if( class1 == NMG_CLASS_AonBshared || class2 == NMG_CLASS_AonBshared )
06667                                 continue;
06668 
06669                         /* need to split this edge at plane pl2 */
06670                         VSUB2( dir, vg2->coord, vg1->coord )
06671 
06672                         code = bn_isect_line3_plane( &dist, vg1->coord, dir, pl2, &is->tol );
06673                         if( code < 1 )
06674                         {
06675                                 bu_log( "nmg_isect_nearly_coplanar_faces: EU (x%x) goes from %s to %s\n",
06676                                         eu, nmg_class_name( class1 ), nmg_class_name( class2 ) );
06677                                 bu_log( "But bn_isect_line3_plane() returns %d\n", code );
06678                                 bu_log( "pl2 = ( %g %g %g %g )\n", V4ARGS( pl2 ) );
06679                                 nmg_pr_lu_briefly( lu, "" );
06680                                 rt_bomb( "nmg_isect_nearly_coplanar_faces: BAD EU" );
06681                         }
06682 
06683                         if( dist <= 0.0 || dist >= 1.0 )
06684                         {
06685                                 bu_log( "nmg_isect_nearly_coplanar_faces: EU (x%x) goes from %s to %s\n",
06686                                         eu, nmg_class_name( class1 ), nmg_class_name( class2 ) );
06687                                 bu_log( "But bn_isect_line3_plane() returns %d and dist=%g\n", code, dist );
06688                                 bu_log( "pl2 = ( %g %g %g %g )\n", V4ARGS( pl2 ) );
06689                                 nmg_pr_lu_briefly( lu, "" );
06690                                 rt_bomb( "nmg_isect_nearly_coplanar_faces: BAD EU" );
06691                         }
06692 
06693                         VJOIN1( hit_pt, vg1->coord, dist, dir );
06694 
06695                         hit_vu = nmg_find_pt_in_face( fu2, hit_pt, &is->tol );
06696                         if( !hit_vu )
06697                                 hit_v = nmg_find_pt_in_model( m, hit_pt, &is->tol );
06698                         else
06699                                 hit_v = hit_vu->v_p;
06700 
06701                         new_eu = nmg_esplit( hit_v, eu, 1 );
06702                         hit_v = new_eu->vu_p->v_p;
06703                         if( !hit_v->vg_p )
06704                                 nmg_vertex_gv( hit_v, hit_pt );
06705 
06706                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06707                         {
06708                                 bu_log( "nmg_cut_lu_into_coplanar_and_non:\n" );
06709                                 bu_log( "\tsplitting eu x%x at v=x%x (%g %g %g)\n",
06710                                         eu, hit_v, V3ARGS( hit_v->vg_p->coord ) );
06711                         }
06712 
06713                 }
06714         }
06715 
06716         /* get a list of all the loops in this faceuse */
06717         bu_ptbl_init( &loops, 64, " &loops");
06718         for( BU_LIST_FOR( lu, loopuse, &fu1->lu_hd ) )
06719                 bu_ptbl( &loops,  BU_PTBL_INS, (long *)lu );
06720 
06721         /* cut each loop so that every loop ends up either entirely on the other
06722          * face, or with only a "line of intersection" in common
06723          */
06724         for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ )
06725         {
06726                 lu = (struct loopuse *)BU_PTBL_GET( &loops, i );
06727                 NMG_CK_LOOPUSE( lu );
06728 
06729                 nmg_cut_lu_into_coplanar_and_non( lu, pl2, is );
06730         }
06731 
06732         /* same for fu2 */
06733         for( BU_LIST_FOR( lu, loopuse, &fu2->lu_hd ) )
06734         {
06735                 NMG_CK_LOOPUSE( lu );
06736                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
06737                         continue;
06738 
06739                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
06740                 {
06741                         int code;
06742                         int class1,class2;
06743                         fastf_t dist;
06744                         struct vertex_g *vg1,*vg2;
06745                         vect_t dir;
06746                         point_t hit_pt;
06747                         struct vertexuse *hit_vu;
06748                         struct vertex *hit_v=(struct vertex *)NULL;
06749                         struct edgeuse *new_eu;
06750 
06751                         NMG_CK_EDGEUSE( eu );
06752 
06753                         vg1 = eu->vu_p->v_p->vg_p;
06754                         vg2 = eu->eumate_p->vu_p->v_p->vg_p;
06755 
06756                         dist = DIST_PT_PLANE( vg1->coord, pl1 );
06757                         if( dist > is->tol.dist )
06758                                 class1 = NMG_CLASS_AoutB;
06759                         else if( dist < (-is->tol.dist ) )
06760                                 class1 = NMG_CLASS_AinB;
06761                         else
06762                                 class1 = NMG_CLASS_AonBshared;
06763 
06764                         dist = DIST_PT_PLANE( vg2->coord, pl1 );
06765                         if( dist > is->tol.dist )
06766                                 class2 = NMG_CLASS_AoutB;
06767                         else if( dist < (-is->tol.dist ) )
06768                                 class2 = NMG_CLASS_AinB;
06769                         else
06770                                 class2 = NMG_CLASS_AonBshared;
06771 
06772                         if( class1 == class2 )
06773                                 continue;
06774 
06775                         if( class1 == NMG_CLASS_AonBshared || class2 == NMG_CLASS_AonBshared )
06776                                 continue;
06777 
06778                         /* need to split this edge at plane pl1 */
06779                         VSUB2( dir, vg2->coord, vg1->coord )
06780 
06781                         code = bn_isect_line3_plane( &dist, vg1->coord, dir, pl1, &is->tol );
06782                         if( code < 1 )
06783                         {
06784                                 bu_log( "nmg_isect_nearly_coplanar_faces: EU (x%x) goes from %s to %s\n",
06785                                         eu, nmg_class_name( class1 ), nmg_class_name( class2 ) );
06786                                 bu_log( "But bn_isect_line3_plane() returns %d\n", code );
06787                                 bu_log( "pl1 = ( %g %g %g %g )\n", V4ARGS( pl1 ) );
06788                                 nmg_pr_lu_briefly( lu, "" );
06789                                 rt_bomb( "nmg_isect_nearly_coplanar_faces: BAD EU" );
06790                         }
06791 
06792                         if( dist <= 0.0 || dist >= 1.0 )
06793                         {
06794                                 bu_log( "nmg_isect_nearly_coplanar_faces: EU (x%x) goes from %s to %s\n",
06795                                         eu, nmg_class_name( class1 ), nmg_class_name( class2 ) );
06796                                 bu_log( "But bn_isect_line3_plane() returns %d and dist=%g\n", code, dist );
06797                                 bu_log( "pl1 = ( %g %g %g %g )\n", V4ARGS( pl1 ) );
06798                                 nmg_pr_lu_briefly( lu, "" );
06799                                 rt_bomb( "nmg_isect_nearly_coplanar_faces: BAD EU" );
06800                         }
06801                         VJOIN1( hit_pt, vg1->coord, dist, dir );
06802 
06803                         hit_vu = nmg_find_pt_in_face( fu2, hit_pt, &is->tol );
06804                         if( !hit_vu )
06805                                 hit_v = nmg_find_pt_in_model( m, hit_pt, &is->tol );
06806                         else
06807                                 hit_v = hit_vu->v_p;
06808 
06809                         new_eu = nmg_esplit( hit_v, eu, 1 );
06810                         hit_v = new_eu->vu_p->v_p;
06811                         if( !hit_v->vg_p )
06812                                 nmg_vertex_gv( hit_v, hit_pt );
06813                 }
06814         }
06815 
06816         /* get a list of all the loops in this faceuse */
06817         bu_ptbl_reset( &loops);
06818         for( BU_LIST_FOR( lu, loopuse, &fu2->lu_hd ) )
06819                 bu_ptbl( &loops,  BU_PTBL_INS, (long *)lu );
06820 
06821         /* cut each loop so that every loop ends up either entirely on the other
06822          * face, or with only a "line of intersection" in common
06823          */
06824         for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ )
06825         {
06826                 lu = (struct loopuse *)BU_PTBL_GET( &loops, i );
06827                 NMG_CK_LOOPUSE( lu );
06828 
06829                 nmg_cut_lu_into_coplanar_and_non( lu, pl1, is );
06830         }
06831 
06832         /* Need to break edges in faces on vertices that may lie on new edges formed by cuts */
06833         nmg_vertex_tabulate( &verts, &m->magic );
06834         /* split new edges in fu1 */
06835         for( BU_LIST_FOR( lu, loopuse, &fu1->lu_hd ) )
06836         {
06837                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
06838                         continue;
06839 
06840                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
06841                 {
06842                         if( bu_ptbl_locate( &eu1_list, (long *)eu ) != (-1) )
06843                                 continue;
06844 
06845                         /* this is a new edgeuse, check if it should be split */
06846                         for( i=0 ; i<BU_PTBL_END( &verts ) ; i++ )
06847                         {
06848                                 struct vertex *v;
06849                                 int code;
06850                                 fastf_t dist[2];
06851                                 point_t pca;
06852 
06853                                 v = (struct vertex *)BU_PTBL_GET( &verts , i );
06854 
06855                                 if( v == eu->vu_p->v_p )
06856                                         continue;
06857 
06858                                 if( v == eu->eumate_p->vu_p->v_p )
06859                                         continue;
06860 
06861                                 code = bn_dist_pt3_lseg3( dist, pca, eu->vu_p->v_p->vg_p->coord,
06862                                         eu->eumate_p->vu_p->v_p->vg_p->coord, v->vg_p->coord, &is->tol );
06863 
06864                                 if( code > 2 )
06865                                         continue;
06866 
06867                                 if( code == 1 )
06868                                         bu_log( "nmg_isect_nearly_coplanar_faces: vertices should have been fused x%x and x%x\n", v, eu->vu_p->v_p );
06869                                 else if( code == 2 )
06870                                         bu_log( "nmg_isect_nearly_coplanar_faces: vertices should have been fused x%x and x%x\n", v, eu->eumate_p->vu_p->v_p );
06871                                 else
06872                                 {
06873                                         /* need to split EU at V */
06874                                         (void)nmg_esplit( v, eu, 1 );
06875                                 }
06876                         }
06877                 }
06878         }
06879 
06880         /* split new edges in fu2 */
06881         for( BU_LIST_FOR( lu, loopuse, &fu2->lu_hd ) )
06882         {
06883                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
06884                         continue;
06885 
06886                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
06887                 {
06888                         if( bu_ptbl_locate( &eu1_list, (long *)eu ) != (-1) )
06889                                 continue;
06890 
06891                         /* this is a new edgeuse, check if it should be split */
06892                         for( i=0 ; i<BU_PTBL_END( &verts ) ; i++ )
06893                         {
06894                                 struct vertex *v;
06895                                 int code;
06896                                 fastf_t dist[2];
06897                                 point_t pca;
06898 
06899                                 v = (struct vertex *)BU_PTBL_GET( &verts , i );
06900 
06901                                 if( v == eu->vu_p->v_p )
06902                                         continue;
06903 
06904                                 if( v == eu->eumate_p->vu_p->v_p )
06905                                         continue;
06906 
06907                                 code = bn_dist_pt3_lseg3( dist, pca, eu->vu_p->v_p->vg_p->coord,
06908                                         eu->eumate_p->vu_p->v_p->vg_p->coord, v->vg_p->coord, &is->tol );
06909 
06910                                 if( code > 2 )
06911                                         continue;
06912 
06913                                 if( code == 1 )
06914                                         bu_log( "nmg_isect_nearly_coplanar_faces: vertices should have been fused x%x and x%x\n", v, eu->vu_p->v_p );
06915                                 else if( code == 2 )
06916                                         bu_log( "nmg_isect_nearly_coplanar_faces: vertices should have been fused x%x and x%x\n", v, eu->eumate_p->vu_p->v_p );
06917                                 else
06918                                 {
06919                                         /* need to split EU at V */
06920                                         (void)nmg_esplit( v, eu, 1 );
06921                                 }
06922                         }
06923                 }
06924         }
06925 
06926         bu_ptbl_free( &loops);
06927         bu_ptbl_free( &verts);
06928 
06929         if (rt_g.NMG_debug & DEBUG_POLYSECT)
06930         {
06931                 plane_t pl1,pl2;
06932                 fastf_t dist;
06933 
06934                 bu_log( "After splitting loops into coplanar and non:\n" );
06935                 nmg_pr_fu_briefly( fu1, "" );
06936                 nmg_pr_fu_briefly( fu2, "" );
06937 
06938                 NMG_GET_FU_PLANE( pl1, fu1 );
06939                 NMG_GET_FU_PLANE( pl2, fu2 );
06940 
06941                 for( BU_LIST_FOR( lu, loopuse, &fu1->lu_hd ) )
06942                 {
06943                         int in=0,on=0,out=0;
06944 
06945                         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
06946                         {
06947                                 struct vertex_g *vg;
06948 
06949                                 vg = eu->vu_p->v_p->vg_p;
06950 
06951                                 dist = DIST_PT_PLANE( vg->coord, pl2 );
06952 
06953                                 if( dist > is->tol.dist )
06954                                         out++;
06955                                 else if( dist < (-is->tol.dist ))
06956                                         in++;
06957                                 else
06958                                         on++;
06959                         }
06960 
06961                         if( in && out )
06962                                 bu_log( "lu x%x is in and out of fu x%x\n", lu, fu2 );
06963                         else if( in )
06964                                 bu_log( "lu x%x is inside of fu x%x\n", lu, fu2 );
06965                         else if( out )
06966                                 bu_log( "lu x%x is outside of fu x%x\n", lu, fu2 );
06967                         else if( on )
06968                                 bu_log( "lu x%x is on of fu x%x\n", lu, fu2 );
06969                         else
06970                                 bu_log( "Can't figure lu x%x w.r.t fu x%x, on=%d, in=%d, out=%d\n",
06971                                         lu, fu2, on,in,out);
06972                 }
06973 
06974                 for( BU_LIST_FOR( lu, loopuse, &fu2->lu_hd ) )
06975                 {
06976                         int in=0,on=0,out=0;
06977 
06978                         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
06979                         {
06980                                 struct vertex_g *vg;
06981 
06982                                 vg = eu->vu_p->v_p->vg_p;
06983 
06984                                 dist = DIST_PT_PLANE( vg->coord, pl1 );
06985 
06986                                 if( dist > is->tol.dist )
06987                                         out++;
06988                                 else if( dist < (-is->tol.dist ))
06989                                         in++;
06990                                 else
06991                                         on++;
06992                         }
06993 
06994                         if( in && out )
06995                                 bu_log( "lu x%x is in and out of fu x%x\n", lu, fu1 );
06996                         else if( in )
06997                                 bu_log( "lu x%x is inside of fu x%x\n", lu, fu1 );
06998                         else if( out )
06999                                 bu_log( "lu x%x is outside of fu x%x\n", lu, fu1 );
07000                         else if( on )
07001                                 bu_log( "lu x%x is on of fu x%x\n", lu, fu1 );
07002                         else
07003                                 bu_log( "Can't figure lu x%x w.r.t fu x%x, on=%d, in=%d, out=%d\n",
07004                                         lu, fu1, on,in,out);
07005                 }
07006         }
07007 
07008         /* now intersect only EU's that lie in the plane of the other faceuse */
07009         bu_ptbl_reset( &eu1_list);
07010         bu_ptbl_reset( &eu2_list);
07011         nmg_edgeuse_tabulate( &eu1_list, &fu1->l.magic );
07012         nmg_edgeuse_tabulate( &eu2_list, &fu2->l.magic );
07013         nmg_isect_coplanar_edges( is, &eu1_list, &eu2_list );
07014 
07015         if( mag1 )
07016                 bu_free( (char *)mag1, "mag1" );
07017         if( mag2 )
07018                 bu_free( (char *)mag2, "mag2" );
07019 
07020         bu_ptbl_free( is->l1);
07021         bu_ptbl_free( is->l2);
07022 
07023         if (rt_g.NMG_debug & DEBUG_POLYSECT)
07024         {
07025                 plane_t pl1,pl2;
07026                 fastf_t dist;
07027 
07028                 bu_log( "After intersection nearly coplanar faces:\n" );
07029                 nmg_pr_fu_briefly( fu1, "" );
07030                 nmg_pr_fu_briefly( fu2, "" );
07031 
07032                 NMG_GET_FU_PLANE( pl1, fu1 );
07033                 NMG_GET_FU_PLANE( pl2, fu2 );
07034 
07035                 for( BU_LIST_FOR( lu, loopuse, &fu1->lu_hd ) )
07036                 {
07037                         int in=0,on=0,out=0;
07038 
07039                         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
07040                         {
07041                                 struct vertex_g *vg;
07042 
07043                                 vg = eu->vu_p->v_p->vg_p;
07044 
07045                                 dist = DIST_PT_PLANE( vg->coord, pl2 );
07046 
07047                                 if( dist > is->tol.dist )
07048                                         out++;
07049                                 else if( dist < (-is->tol.dist ))
07050                                         in++;
07051                                 else
07052                                         on++;
07053                         }
07054 
07055                         if( in && out )
07056                                 bu_log( "lu x%x is in and out of fu x%x\n", lu, fu2 );
07057                         else if( in )
07058                                 bu_log( "lu x%x is inside of fu x%x\n", lu, fu2 );
07059                         else if( out )
07060                                 bu_log( "lu x%x is outside of fu x%x\n", lu, fu2 );
07061                         else if( on )
07062                                 bu_log( "lu x%x is on of fu x%x\n", lu, fu2 );
07063                         else
07064                                 bu_log( "Can't figure lu x%x w.r.t fu x%x, on=%d, in=%d, out=%d\n",
07065                                         lu, fu2, on,in,out);
07066                 }
07067 
07068                 for( BU_LIST_FOR( lu, loopuse, &fu2->lu_hd ) )
07069                 {
07070                         int in=0,on=0,out=0;
07071 
07072                         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
07073                         {
07074                                 struct vertex_g *vg;
07075 
07076                                 vg = eu->vu_p->v_p->vg_p;
07077 
07078                                 dist = DIST_PT_PLANE( vg->coord, pl1 );
07079 
07080                                 if( dist > is->tol.dist )
07081                                         out++;
07082                                 else if( dist < (-is->tol.dist ))
07083                                         in++;
07084                                 else
07085                                         on++;
07086                         }
07087 
07088                         if( in && out )
07089                                 bu_log( "lu x%x is in and out of fu x%x\n", lu, fu1 );
07090                         else if( in )
07091                                 bu_log( "lu x%x is inside of fu x%x\n", lu, fu1 );
07092                         else if( out )
07093                                 bu_log( "lu x%x is outside of fu x%x\n", lu, fu1 );
07094                         else if( on )
07095                                 bu_log( "lu x%x is on of fu x%x\n", lu, fu1 );
07096                         else
07097                                 bu_log( "Can't figure lu x%x w.r.t fu x%x, on=%d, in=%d, out=%d\n",
07098                                         lu, fu1, on,in,out);
07099                 }
07100         }
07101 
07102 }
07103 
07104 /**                     N M G _ F A C E S _ C A N _ B E _ I N T E R S E C T E D
07105  *
07106  *      Check if two faceuses can be intersected normally, by looking at the line
07107  *      of intersection and determining if the vertices from each face are all
07108  *      above the other face on one side of the intersection line and below it
07109  *      on the other side of the interection line.
07110  *
07111  *      return:
07112  *              1 - faceuses meet criteria and can be intersected normally
07113  *              0 - must use nmg_isect_nearly_coplanar_faces
07114  */
07115 int
07116 nmg_faces_can_be_intersected(struct nmg_inter_struct *bs, const struct faceuse *fu1, const struct faceuse *fu2, const struct bn_tol *tol)
07117 {
07118         plane_t pl1,pl2;
07119         point_t min_pt;
07120         struct face *f1,*f2;
07121         double dir_len_sq;
07122         double one_over_dir_len;
07123         plane_t tmp_pl;
07124         vect_t left;
07125         struct bu_ptbl verts;
07126         int on_line, above_left, below_left, on_left, above_right, below_right, on_right;
07127         int i;
07128 
07129         NMG_CK_FACEUSE( fu1 );
07130         NMG_CK_FACEUSE( fu2 );
07131         BN_CK_TOL( tol );
07132 
07133         NMG_GET_FU_PLANE( pl1, fu1 );
07134         NMG_GET_FU_PLANE( pl2, fu2 );
07135 
07136         f1 = fu1->f_p;
07137         f2 = fu2->f_p;
07138 
07139         NMG_CK_FACE( f1 );
07140         NMG_CK_FACE( f2 );
07141 
07142         VMOVE(min_pt, f1->min_pt);
07143         VMIN(min_pt, f2->min_pt);
07144 
07145         VCROSS( bs->dir, pl1, pl2 );
07146         dir_len_sq = MAGSQ( bs->dir );
07147         if( dir_len_sq <= SMALL_FASTF )
07148                 return( 0 );
07149 
07150         one_over_dir_len = 1.0/sqrt( dir_len_sq );
07151         VSCALE( bs->dir, bs->dir, one_over_dir_len );
07152         VMOVE( tmp_pl, bs->dir );
07153         tmp_pl[3] = VDOT( tmp_pl, min_pt );
07154 
07155         if( bn_mkpoint_3planes( bs->pt, tmp_pl, pl1, pl2 ) )
07156                 return( 0 );
07157 
07158         VCROSS( left, pl1, bs->dir );
07159 
07160         /* check vertices from fu1 versus plane of fu2 */
07161         nmg_vertex_tabulate( &verts, &fu1->l.magic );
07162         on_line = 0;
07163         above_left = 0;
07164         below_left = 0;
07165         on_left = 0;
07166         above_right = 0;
07167         below_right = 0;
07168         on_right = 0;
07169         for( i=0 ; i<BU_PTBL_END( &verts ) ; i++ )
07170         {
07171                 struct vertex *v;
07172                 point_t pca;
07173                 fastf_t dist;
07174                 int code;
07175                 vect_t to_v;
07176 
07177                 v = (struct vertex *)BU_PTBL_GET( &verts, i );
07178 
07179                 code = rt_dist_pt3_line3( &dist, pca, bs->pt, bs->dir, v->vg_p->coord, tol );
07180 
07181                 if( code == 0 || code == 1 )
07182                 {
07183                         on_line++;
07184                         continue;
07185                 }
07186 
07187                 VSUB2( to_v, v->vg_p->coord, pca );
07188                 dist = DIST_PT_PLANE( v->vg_p->coord, pl2 );
07189                 if( VDOT( to_v, left ) > 0.0 )
07190                 {
07191                         /* left of intersection line */
07192                         if( dist > tol->dist )
07193                                 above_left++;
07194                         else if( dist < (-tol->dist) )
07195                                 below_left++;
07196                         else
07197                                 on_left++;
07198                 }
07199                 else
07200                 {
07201                         /* right of intersction line */
07202                         if( dist > tol->dist )
07203                                 above_right++;
07204                         else if( dist < (-tol->dist) )
07205                                 below_right++;
07206                         else
07207                                 on_right++;
07208                 }
07209         }
07210         bu_ptbl_free( &verts);
07211 
07212         if( above_left && below_left )
07213                 return( 0 );
07214         if( on_left )
07215                 return( 0 );
07216         if( above_right && below_right )
07217                 return( 0 );
07218         if( on_right )
07219                 return( 0 );
07220 
07221         /* check vertices from fu2 versus plane of fu1 */
07222         nmg_vertex_tabulate( &verts, &fu2->l.magic );
07223         on_line = 0;
07224         above_left = 0;
07225         below_left = 0;
07226         on_left = 0;
07227         above_right = 0;
07228         below_right = 0;
07229         on_right = 0;
07230         for( i=0 ; i<BU_PTBL_END( &verts ) ; i++ )
07231         {
07232                 struct vertex *v;
07233                 point_t pca;
07234                 fastf_t dist;
07235                 int code;
07236                 vect_t to_v;
07237 
07238                 v = (struct vertex *)BU_PTBL_GET( &verts, i );
07239 
07240                 code = rt_dist_pt3_line3( &dist, pca, bs->pt, bs->dir, v->vg_p->coord, tol );
07241 
07242                 if( code == 0 || code == 1 )
07243                 {
07244                         on_line++;
07245                         continue;
07246                 }
07247 
07248                 VSUB2( to_v, v->vg_p->coord, pca );
07249                 dist = DIST_PT_PLANE( v->vg_p->coord, pl1 );
07250                 if( VDOT( to_v, left ) > 0.0 )
07251                 {
07252                         /* left of intersection line */
07253                         if( dist > tol->dist )
07254                                 above_left++;
07255                         else if( dist < (-tol->dist) )
07256                                 below_left++;
07257                         else
07258                                 on_left++;
07259                 }
07260                 else
07261                 {
07262                         /* right of intersction line */
07263                         if( dist > tol->dist )
07264                                 above_right++;
07265                         else if( dist < (-tol->dist) )
07266                                 below_right++;
07267                         else
07268                                 on_right++;
07269                 }
07270         }
07271         bu_ptbl_free( &verts);
07272 
07273         if( above_left && below_left )
07274                 return( 0 );
07275         if( on_left )
07276                 return( 0 );
07277         if( above_right && below_right )
07278                 return( 0 );
07279         if( on_right )
07280                 return( 0 );
07281 
07282         return( 1 );
07283 }
07284 
07285 /**
07286  *                      N M G _ I S E C T _ T W O _ G E N E R I C _ F A C E S
07287  *
07288  *      Intersect a pair of faces
07289  */
07290 void
07291 nmg_isect_two_generic_faces(struct faceuse *fu1, struct faceuse *fu2, const struct bn_tol *tol)
07292 {
07293         struct nmg_inter_struct bs;
07294         plane_t         pl1, pl2;
07295         struct face     *f1;
07296         struct face     *f2;
07297         point_t         min_pt;
07298         int             status;
07299         int             i;
07300 
07301         BN_CK_TOL(tol);
07302         bs.magic = NMG_INTER_STRUCT_MAGIC;
07303         bs.vert2d = (fastf_t *)NULL;
07304         bs.tol = *tol;          /* struct copy */
07305 
07306         NMG_CK_FACEUSE(fu1);
07307         f1 = fu1->f_p;
07308         NMG_CK_FACE(f1);
07309         NMG_CK_FACE_G_PLANE(f1->g.plane_p);
07310 
07311         NMG_CK_FACEUSE(fu2);
07312         f2 = fu2->f_p;
07313         NMG_CK_FACE(f2);
07314         NMG_CK_FACE_G_PLANE(f2->g.plane_p);
07315 
07316         NMG_GET_FU_PLANE( pl1, fu1 );
07317         NMG_GET_FU_PLANE( pl2, fu2 );
07318 
07319         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
07320                 bu_log("\nnmg_isect_two_generic_faces(fu1=x%x, fu2=x%x)\n", fu1, fu2);
07321 
07322                 bu_log("Planes\t%gx + %gy + %gz = %g\n\t%gx + %gy + %gz = %g\n",
07323                         pl1[0], pl1[1], pl1[2], pl1[3],
07324                         pl2[0], pl2[1], pl2[2], pl2[3]);
07325                 bu_log( "Cosine of angle between planes = %g\n" , VDOT( pl1 , pl2 ) );
07326                 bu_log( "fu1:\n" );
07327                 nmg_pr_fu_briefly( fu1 , "\t" );
07328                 bu_log( "fu2:\n" );
07329                 nmg_pr_fu_briefly( fu2 , "\t" );
07330 nmg_fu_touchingloops(fu1);
07331 nmg_fu_touchingloops(fu2);
07332         }
07333 
07334         status = 10;
07335         if( f1->g.plane_p == f2->g.plane_p )  {
07336                 if (rt_g.NMG_debug & DEBUG_POLYSECT) {
07337                         bu_log("co-planar faces (shared fg)\n");
07338                 }
07339                 status = (-1);
07340         }
07341 
07342         if ( !V3RPP_OVERLAP_TOL(f2->min_pt, f2->max_pt,
07343             f1->min_pt, f1->max_pt, &bs.tol) )  return;
07344 
07345         /*
07346          *  The extents of face1 overlap the extents of face2.
07347          *  Construct a ray which contains the line of intersection.
07348          *  There are two choices for direction, and an infinite number
07349          *  of candidate points.
07350          *
07351          *  The correct choice of this ray is very important, so that:
07352          *      1)  All intersections are at positive distances on the ray,
07353          *      2)  dir cross N will point "left".
07354          *
07355          *  These two conditions can be satisfied by intersecting the
07356          *  line with the face's bounding RPP.  This will give two
07357          *  points A and B, where A is closer to the min point of the RPP
07358          *  and B is closer to the max point of the RPP.
07359          *  Let bs.pt be A, and let bs.dir point from A towards B.
07360          *  This choice will satisfy both constraints, above.
07361          *
07362          *  NOTE:  These conditions must be enforced in the 2D code, also.
07363          */
07364         VMOVE(min_pt, f1->min_pt);
07365         VMIN(min_pt, f2->min_pt);
07366         if( status == 10 )
07367         {
07368                 status = bn_isect_2planes( bs.pt, bs.dir, pl1, pl2,
07369                         min_pt, tol );
07370 
07371                 if (rt_g.NMG_debug & DEBUG_POLYSECT) {
07372                         bu_log( "\tnmg_isect_two_generic_faces: intersect ray start (%f , %f , %f )\n\t\tin direction (%f , %f , %f )\n",
07373                                 bs.pt[X],
07374                                 bs.pt[Y],
07375                                 bs.pt[Z],
07376                                 bs.dir[X],
07377                                 bs.dir[Y],
07378                                 bs.dir[Z] );
07379                 }
07380         }
07381 
07382         switch( status )  {
07383         case 0:
07384                 if( fu1->f_p->g.plane_p == fu2->f_p->g.plane_p )  {
07385                         rt_bomb("nmg_isect_two_generic_faces: co-planar faces not detected\n");
07386                 }
07387                 /* All is well */
07388                 bs.coplanar = 0;
07389                 nmg_isect_two_face3p( &bs, fu1, fu2 );
07390                 break;
07391         case -1:
07392         case -2:
07393                 /* co-planar faces */
07394                 {
07395                         int coplanar1=0;
07396                         int coplanar2=0;
07397                         int coplanar=0;
07398                         int parallel=0;
07399                         fastf_t max_dist1;
07400                         fastf_t min_dist1;
07401                         fastf_t max_dist2;
07402                         fastf_t min_dist2;
07403                         fastf_t dist;
07404                         struct bu_ptbl verts;
07405 
07406                         if( f1->g.plane_p == f2->g.plane_p )
07407                                 goto cplanar;
07408 
07409                         /* are these face really coplanar??? */
07410 
07411                         min_dist1 = MAX_FASTF;
07412                         max_dist1 = (-MAX_FASTF);
07413                         min_dist2 = MAX_FASTF;
07414                         max_dist2 = (-MAX_FASTF);
07415                         nmg_vertex_tabulate( &verts, &fu1->l.magic );
07416                         for( i=0 ; i<BU_PTBL_END( &verts ) ; i++ )
07417                         {
07418                                 struct vertex *v;
07419 
07420                                 v = (struct vertex *)BU_PTBL_GET( &verts, i );
07421                                 dist = DIST_PT_PLANE( v->vg_p->coord, pl2 );
07422                                 if( dist > max_dist1 )
07423                                         max_dist1 = dist;
07424                                 if( dist < min_dist1 )
07425                                         min_dist1 = dist;
07426                         }
07427                         bu_ptbl_free( &verts);
07428 
07429                         if( min_dist1 > tol->dist )
07430                         {
07431                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
07432                                 {
07433                                         bu_log( "nmg_isect_two_generic_faces: bn_isect_2planes() says faces are coplanar.\n" );
07434                                         bu_log( "\tbut all vertices of fu1 (x%x) are at least %gmm above plane of fu2 (x%x)\n",
07435                                                 fu1, min_dist1, fu2 );
07436                                 }
07437                                 parallel = 1;
07438                         }
07439                         else if( max_dist1 < (-tol->dist ) )
07440                         {
07441                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
07442                                 {
07443                                         bu_log( "nmg_isect_two_generic_faces: bn_isect_2planes() says faces are coplanar.\n" );
07444                                         bu_log( "\tbut all vertices of fu1 (x%x) are at least %gmm below plane of fu2 (x%x)\n",
07445                                                 fu1, -max_dist1, fu2 );
07446                                 }
07447                                 parallel =  1;
07448                         }
07449                         else if( max_dist1 <= tol->dist && min_dist1 >= (-tol->dist) )
07450                         {
07451                                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
07452                                         bu_log( "nmg_isect_two_generic_faces: coplanar faces don't share face geometry, intersecting anyway\n" );
07453                                 coplanar1 = 1;
07454                         }
07455 
07456                         if( !parallel )
07457                         {
07458                                 /* Nothing determined so far, try looking at vertices in the other face */
07459                                 nmg_vertex_tabulate( &verts, &fu2->l.magic );
07460                                 for( i=0 ; i<BU_PTBL_END( &verts ) ; i++ )
07461                                 {
07462                                         struct vertex *v;
07463 
07464                                         v = (struct vertex *)BU_PTBL_GET( &verts, i );
07465                                         dist = DIST_PT_PLANE( v->vg_p->coord, pl1 );
07466                                         if( dist > max_dist2 )
07467                                                 max_dist2 = dist;
07468                                         if( dist < min_dist2 )
07469                                                 min_dist2 = dist;
07470                                 }
07471                                 bu_ptbl_free( &verts);
07472 
07473                                 if( min_dist2 > tol->dist )
07474                                 {
07475                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
07476                                         {
07477                                                 bu_log( "nmg_isect_two_generic_faces: bn_isect_2planes() says faces are coplanar.\n" );
07478                                                 bu_log( "\tbut all vertices of fu2 (x%x) are at least %gmm above plane of fu1 (x%x)\n",
07479                                                         fu2, min_dist2, fu1 );
07480                                         }
07481                                         parallel = 1;
07482                                 }
07483                                 else if( max_dist2 < (-tol->dist ) )
07484                                 {
07485                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
07486                                         {
07487                                                 bu_log( "nmg_isect_two_generic_faces: bn_isect_2planes() says faces are coplanar.\n" );
07488                                                 bu_log( "\tbut all vertices of fu2 (x%x) are at least %gmm below plane of fu1 (x%x)\n",
07489                                                         fu2, -max_dist2, fu1 );
07490                                         }
07491                                         parallel = 1;
07492                                 }
07493                                 else if( max_dist2 <= tol->dist && min_dist2 >= (-tol->dist) )
07494                                 {
07495                                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
07496                                                 bu_log( "nmg_isect_two_generic_faces: coplanar faces don't share face geometry, intersecting anyway\n" );
07497                                         coplanar2 = 1;
07498                                 }
07499                         }
07500 
07501                         if (rt_g.NMG_debug & DEBUG_POLYSECT)
07502                         {
07503                                 bu_log( "nmg_isect_two_generic_faces: FUs x%x and x%x do not share face geometry\n", fu1, fu2 );
07504                                 bu_log( "\tbut bn_isect_2planes() says they are coplanar or parallel\n" );
07505                                 bu_log( "max_dist1 = %g, min_dist1 = %g\n", max_dist1, min_dist1 );
07506                                 bu_log( "max_dist2 = %g, min_dist2 = %g\n", max_dist2, min_dist2 );
07507                         }
07508 
07509                         if( coplanar1 && coplanar2 )
07510                                 coplanar = 1;
07511 
07512                         if( coplanar )
07513                         {
07514 cplanar:
07515                                 bs.coplanar = 1;
07516                                 nmg_isect_two_face2p_jra( &bs, fu1, fu2 );
07517                                 break;
07518                         }
07519                         else if( parallel )
07520                                 break;
07521                         else
07522                         {
07523                                 if( nmg_faces_can_be_intersected( &bs, fu1, fu2, tol ) )
07524                                 {
07525                                         bs.coplanar = 0;
07526                                         nmg_isect_two_face3p( &bs, fu1, fu2 );
07527                                 }
07528                                 else
07529                                         nmg_isect_nearly_coplanar_faces( &bs, fu1, fu2 );
07530                         }
07531                 }
07532                 break;
07533         default:
07534                 /* internal error */
07535                 bu_log("ERROR nmg_isect_two_generic_faces() unable to find plane intersection\n");
07536                 break;
07537         }
07538 
07539         nmg_isect2d_cleanup( &bs );
07540 #if 0
07541         /*      TOO EARLY, These are needed for identifying shared vertices */
07542         /* Eliminate any OT_BOOLPLACE self-loops now. */
07543         nmg_sanitize_fu( fu1 );
07544         nmg_sanitize_fu( fu2 );
07545 #endif
07546         /* Eliminate stray vertices that were added along edges in this step */
07547         (void)nmg_unbreak_region_edges( &fu1->l.magic );
07548         (void)nmg_unbreak_region_edges( &fu2->l.magic );
07549 
07550         if ( fu1 && rt_g.NMG_debug & (DEBUG_POLYSECT|DEBUG_FCUT|DEBUG_MESH)
07551             && rt_g.NMG_debug & DEBUG_PLOTEM) {
07552                 static int nshell = 1;
07553                 char    name[32];
07554                 FILE    *fp;
07555 
07556 
07557                 /* Both at once */
07558                 nmg_pl_2fu( "Iface%d.pl", 0, fu2, fu1, 0 );
07559 
07560                 /* Each in it's own file */
07561                 nmg_face_plot( fu1 );
07562                 nmg_face_plot( fu2 );
07563 
07564                 sprintf(name, "shellA%d.pl", nshell);
07565                 if( (fp = fopen(name, "w")) != NULL )  {
07566                         bu_log("overlay %s\n", name);
07567                         nmg_pl_s( fp, fu1->s_p );
07568                         fclose(fp);
07569                 }
07570 
07571                 sprintf(name, "shellB%d.pl", nshell++);
07572                 if( (fp = fopen(name, "w")) != NULL )  {
07573                         bu_log("overlay %s\n", name);
07574                         nmg_pl_s( fp, fu2->s_p );
07575                         fclose(fp);
07576                 }
07577 
07578 #if 0
07579                 /* This should really be controlled by it's own bit. */
07580                 sprintf(name, "model%d.g", nshell);
07581                 nmg_stash_model_to_file( name, m, "After 2d isect" );
07582                 nshell++;
07583 #endif
07584         }
07585 
07586         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
07587 nmg_region_v_unique( fu1->s_p->r_p, &bs.tol );
07588 nmg_region_v_unique( fu2->s_p->r_p, &bs.tol );
07589 nmg_fu_touchingloops(fu1);
07590 nmg_fu_touchingloops(fu2);
07591 nmg_ck_face_worthless_edges( fu1 );
07592 nmg_ck_face_worthless_edges( fu2 );
07593         }
07594 }
07595 
07596 /**
07597  *                      N M G _ I S E C T _ E D G E 3 P _ E D G E 3 P
07598  *
07599  *  Intersect one edge with another.  At least one is a wire edge;
07600  *  thus there is no face context or intersection line.
07601  *  If the edges are non-colinear, there will be at most one point of isect.
07602  *  If the edges are colinear, there may be two.
07603  *
07604  *  Called from nmg_isect_edge3p_shell()
07605  */
07606 static void
07607 nmg_isect_edge3p_edge3p(struct nmg_inter_struct *is, struct edgeuse *eu1, struct edgeuse *eu2)
07608 {
07609         struct vertexuse        *vu1a;
07610         struct vertexuse        *vu1b;
07611         struct vertexuse        *vu2a;
07612         struct vertexuse        *vu2b;
07613         vect_t                  eu1_dir;
07614         vect_t                  eu2_dir;
07615         fastf_t                 dist[2];
07616         int                     status;
07617         struct vertex           *new_v;
07618         point_t                 hit_pt;
07619 
07620         NMG_CK_INTER_STRUCT(is);
07621         NMG_CK_EDGEUSE(eu1);
07622         NMG_CK_EDGEUSE(eu2);
07623 
07624         vu1a = eu1->vu_p;
07625         vu1b = BU_LIST_PNEXT_CIRC( edgeuse, eu1 )->vu_p;
07626         vu2a = eu2->vu_p;
07627         vu2b = BU_LIST_PNEXT_CIRC( edgeuse, eu2 )->vu_p;
07628         NMG_CK_VERTEXUSE(vu1a);
07629         NMG_CK_VERTEXUSE(vu1b);
07630         NMG_CK_VERTEXUSE(vu2a);
07631         NMG_CK_VERTEXUSE(vu2b);
07632 
07633         if (rt_g.NMG_debug & DEBUG_POLYSECT)
07634                 bu_log("nmg_isect_edge3p_edge3p(eu1=x%x, eu2=x%x)\n\tvu1a=%x vu1b=%x, vu2a=%x vu2b=%x\n\tv1a=%x v1b=%x,   v2a=%x v2b=%x\n",
07635                         eu1, eu2,
07636                         vu1a, vu1b, vu2a, vu2b,
07637                         vu1a->v_p, vu1b->v_p, vu2a->v_p, vu2b->v_p );
07638 
07639         /*
07640          *  Topology check.
07641          *  If both endpoints of both edges match, this is a trivial accept.
07642          */
07643         if( (vu1a->v_p == vu2a->v_p && vu1b->v_p == vu2b->v_p) ||
07644             (vu1a->v_p == vu2b->v_p && vu1b->v_p == vu2a->v_p) )  {
07645                 if (rt_g.NMG_debug & DEBUG_POLYSECT)
07646                         bu_log("nmg_isect_edge3p_edge3p: shared edge topology, both ends\n");
07647                 if( eu1->e_p != eu2->e_p )
07648                         nmg_radial_join_eu(eu1, eu2, &is->tol );
07649                 return;
07650         }
07651         VSUB2( eu1_dir, vu1b->v_p->vg_p->coord, vu1a->v_p->vg_p->coord );
07652         VSUB2( eu2_dir, vu2b->v_p->vg_p->coord, vu2a->v_p->vg_p->coord );
07653 
07654         dist[0] = dist[1] = 0;  /* for clean prints, below */
07655 
07656         status = bn_isect_lseg3_lseg3( dist,
07657                         vu1a->v_p->vg_p->coord, eu1_dir,
07658                         vu2a->v_p->vg_p->coord, eu2_dir, &is->tol );
07659 
07660         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
07661                 bu_log("\trt_isect_line3_lseg3()=%d, dist: %g, %g\n",
07662                         status, dist[0], dist[1] );
07663         }
07664 
07665         if( status < 0 )  {
07666                 /* missed */
07667                 return;
07668         }
07669 
07670         if( status == 0 )  {
07671                 /* lines are colinear */
07672                 bu_log("nmg_isect_edge3p_edge3p() colinear case.  Untested waters.\n");
07673                 /* Initialize 2D vertex cache with EDGE info. */
07674                 nmg_isect2d_prep( is, &eu1->l.magic );
07675                 /* 3rd arg has to be a faceuse.  Tried to send it eu1->e_p */
07676                 /* XXX This will rt_bomb() when faceuse is checked. */
07677                 (void)nmg_isect_2colinear_edge2p( eu1, eu2, (struct faceuse *)NULL, is, (struct bu_ptbl *)0, (struct bu_ptbl *)0 );
07678                 return;
07679         }
07680 
07681         /* XXX There is an intersection point.  This could just be
07682          * reformulated as a 2D problem here, and passed off to
07683          * the 2D routine that this was based on.
07684          */
07685 
07686         /* dist[0] is distance along eu1 */
07687         if( dist[0] == 0 )  {
07688                 /* Hit is at vu1a */
07689                 if( dist[1] == 0 )  {
07690                         /* Hit is at vu2a */
07691                         nmg_jv( vu1a->v_p, vu2a->v_p );
07692                         return;
07693                 } else if( dist[1] == 1 )  {
07694                         /* Hit is at vu2b */
07695                         nmg_jv( vu1a->v_p, vu2b->v_p );
07696                         return;
07697                 }
07698                 /* Break eu2 on vu1a */
07699                 nmg_ebreaker( vu1a->v_p, eu2, &is->tol );
07700                 return;
07701         } else if( dist[0] == 1 )  {
07702                 /* Hit is at vu1b */
07703                 if( dist[1] == 0 )  {
07704                         /* Hit is at vu2a */
07705                         nmg_jv( vu1b->v_p, vu2a->v_p );
07706                         return;
07707                 } else if( dist[1] == 1 )  {
07708                         /* Hit is at vu2b */
07709                         nmg_jv( vu1b->v_p, vu2b->v_p );
07710                         return;
07711                 }
07712                 /* Break eu2 on vu1b */
07713                 nmg_ebreaker( vu1b->v_p, eu2, &is->tol );
07714                 return;
07715         } else {
07716                 /* Hit on eu1 is between vu1a and vu1b */
07717                 if( dist[1] < 0 || dist[1] > 1 )  return;       /* Don't bother breaking eu1, it doesn't touch eu2. */
07718 
07719                 if( dist[1] == 0 )  {
07720                         /* Hit is at vu2a */
07721                         nmg_ebreaker( vu2a->v_p, eu1, &is->tol );
07722                         return;
07723                 } else if( dist[1] == 1 )  {
07724                         /* Hit is at vu2b */
07725                         nmg_ebreaker( vu2b->v_p, eu1, &is->tol );
07726                         return;
07727                 }
07728                 /* Hit is amidships on both eu1 and eu2. */
07729                 new_v = nmg_e2break( eu1, eu2 );
07730 
07731                 VJOIN1( hit_pt, vu2a->v_p->vg_p->coord, dist[1], eu2_dir );
07732                 nmg_vertex_gv(new_v, hit_pt);
07733         }
07734 }
07735 
07736 /**
07737  *                      N M G _ I S E C T _ V E R T E X 3 _ E D G E 3 P
07738  *
07739  *  Intersect a lone vertex from s1 with a single edge from s2.
07740  */
07741 static void
07742 nmg_isect_vertex3_edge3p(struct nmg_inter_struct *is, struct vertexuse *vu1, struct edgeuse *eu2)
07743 {
07744         fastf_t         dist;
07745         int             code;
07746         struct vertexuse        *vu2 = (struct vertexuse *)NULL;
07747 
07748         NMG_CK_INTER_STRUCT(is);
07749         NMG_CK_VERTEXUSE(vu1);
07750         NMG_CK_EDGEUSE(eu2);
07751 
07752         code = bn_isect_pt_lseg( &dist, eu2->vu_p->v_p->vg_p->coord,
07753                 eu2->vu_p->v_p->vg_p->coord,
07754                 vu1->v_p->vg_p->coord, &is->tol );
07755 
07756         if( code < 0 )  return;         /* Not on line */
07757         switch( code )  {
07758         case 1:
07759                 /* Hit is at A */
07760                 vu2 = eu2->vu_p;
07761                 break;
07762         case 2:
07763                 /* Hit is at B */
07764                 vu2 = BU_LIST_NEXT( edgeuse, &eu2->l)->vu_p;
07765                 break;
07766         case 3:
07767                 /* Hit is in the span AB somewhere, break edge */
07768                 vu2 = nmg_ebreaker( vu1->v_p, eu2, &is->tol )->vu_p;
07769                 break;
07770         default:
07771                 rt_bomb("nmg_isect_vertex3_edge3p()\n");
07772         }
07773         /* Make sure verts are shared at hit point. They _should_ already be. */
07774         nmg_jv( vu1->v_p, vu2->v_p );
07775         (void)bu_ptbl_ins_unique(is->l1, &vu1->l.magic);
07776         (void)bu_ptbl_ins_unique(is->l2, &vu2->l.magic);
07777 }
07778 
07779 /**
07780  *                      N M G _ I S E C T _ E D G E 3 P _ S H E L L
07781  *
07782  *  Intersect one edge with all of another shell.
07783  *  There is no face context for this edge, because
07784  *
07785  *  At present, this routine is used for only one purpose:
07786  *      1)  Handling wire edge -vs- shell intersection
07787  *
07788  *  The edge will be fully intersected with the shell, potentially
07789  *  getting trimmed down in the process as crossings of s2 are found.
07790  *  The caller is responsible for re-calling with the extra edgeuses.
07791  *
07792  *  If both vertices of eu1 are on s2 (the other shell), and
07793  *  there is no edge in s2 between them, we need to determine
07794  *  whether this is an interior or exterior edge, and
07795  *  perhaps add a loop into s2 connecting those two verts.
07796  *
07797  *  We can't use the face cutter, because s2 has no
07798  *  appropriate face containing this edge.
07799  *
07800  *  If this edge is split, we have to
07801  *  trust nmg_ebreak() to insert new eu's ahead in the eu list,
07802  *  so caller will see them.
07803  *
07804  *  Lots of junk will be put on the vert_list's in 'is';  the caller
07805  *  should just free the lists without using them.
07806  *
07807  *  Called by nmg_crackshells().
07808  */
07809 static void
07810 nmg_isect_edge3p_shell(struct nmg_inter_struct *is, struct edgeuse *eu1, struct shell *s2)
07811 {
07812         struct faceuse  *fu2;
07813         struct loopuse  *lu2;
07814         struct edgeuse  *eu2;
07815         struct vertexuse *vu2;
07816         point_t         midpt;
07817 
07818         NMG_CK_INTER_STRUCT(is);
07819         NMG_CK_EDGEUSE(eu1);
07820         NMG_CK_SHELL(s2);
07821 
07822         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
07823                 bu_log("nmg_isect_edge3p_shell(, eu1=x%x, s2=x%x) START\n",
07824                         eu1, s2 );
07825         }
07826 
07827         if ( (eu2 = nmg_find_matching_eu_in_s( eu1, s2 )) )  {
07828                 /* XXX Is the fact that s2 has a corresponding edge good enough? */
07829                 nmg_radial_join_eu( eu1, eu2, &is->tol );
07830                 return;
07831         }
07832 
07833         /* Note the ray that contains this edge.  For debug in nmg_isect_wireedge3p_face3p() */
07834         VMOVE( is->pt, eu1->vu_p->v_p->vg_p->coord );
07835         VSUB2( is->dir, eu1->eumate_p->vu_p->v_p->vg_p->coord, is->pt );
07836         VUNITIZE( is->dir );
07837 
07838         /* Check eu1 of s1 against all faces in s2 */
07839         for( BU_LIST_FOR( fu2, faceuse, &s2->fu_hd ) )  {
07840                 NMG_CK_FACEUSE(fu2);
07841                 if( fu2->orientation != OT_SAME )  continue;
07842                 is->fu2 = fu2;
07843 
07844                 /* We aren't interested in the vert_list's, ignore return */
07845                 (void)nmg_isect_wireedge3p_face3p( is, eu1, fu2 );
07846         }
07847 
07848         /* Check eu1 of s1 against all wire loops in s2 */
07849         is->fu2 = (struct faceuse *)NULL;
07850         for( BU_LIST_FOR( lu2, loopuse, &s2->lu_hd ) )  {
07851                 NMG_CK_LOOPUSE(lu2);
07852                 /* Really, it's just a bunch of wire edges, in a loop. */
07853                 if( BU_LIST_FIRST_MAGIC( &lu2->down_hd ) == NMG_VERTEXUSE_MAGIC)  {
07854                         /* XXX Can there be lone-vertex wire loops here? */
07855                         vu2 = BU_LIST_FIRST( vertexuse, &lu2->down_hd );
07856                         NMG_CK_VERTEXUSE(vu2);
07857                         nmg_isect_vertex3_edge3p( is, vu2, eu1 );
07858                         continue;
07859                 }
07860                 for( BU_LIST_FOR( eu2, edgeuse, &lu2->down_hd ) )  {
07861                         NMG_CK_EDGEUSE(eu2);
07862                         nmg_isect_edge3p_edge3p( is, eu1, eu2 );
07863                 }
07864         }
07865 
07866         /* Check eu1 of s1 against all wire edges in s2 */
07867         for( BU_LIST_FOR( eu2, edgeuse, &s2->eu_hd ) )  {
07868                 NMG_CK_EDGEUSE(eu2);
07869                 nmg_isect_edge3p_edge3p( is, eu1, eu2 );
07870         }
07871 
07872         /* Check eu1 of s1 against vert of s2 */
07873         if( s2->vu_p )  {
07874                 nmg_isect_vertex3_edge3p( is, s2->vu_p, eu1 );
07875         }
07876 
07877         /*
07878          *  The edge has been fully intersected with the other shell.
07879          *  It may have been trimmed in the process;  the caller is
07880          *  responsible for re-calling us with the extra edgeuses.
07881          *  If both vertices of eu1 are on s2 (the other shell), and
07882          *  there is no edge in s2 between them, we need to determine
07883          *  whether this is an interior or exterior edge, and
07884          *  perhaps add a loop into s2 connecting those two verts.
07885          */
07886         if ((eu2 = nmg_find_matching_eu_in_s( eu1, s2 )) )  {
07887                 /* We can't fuse wire edges */
07888                 goto out;
07889         }
07890         /*  Can't use the face cutter, because s2 has no associated face!
07891          *  Call the geometric classifier on the midpoint.
07892          *  If it's INSIDE or ON the other shell, add a wire loop
07893          *  that connects the two vertices.
07894          */
07895         VADD2SCALE( midpt, eu1->vu_p->v_p->vg_p->coord,
07896                 eu1->eumate_p->vu_p->v_p->vg_p->coord,  0.5 );
07897         if( nmg_class_pt_s( midpt, s2, 0, &is->tol ) == NMG_CLASS_AoutB )
07898                 goto out;               /* Nothing more to do */
07899 
07900         /* Add a wire loop in s2 connecting the two vertices */
07901         lu2 = nmg_mlv( &s2->l.magic, eu1->vu_p->v_p, OT_UNSPEC );
07902         NMG_CK_LOOPUSE(lu2);
07903         {
07904                 struct edgeuse  *neu1, *neu2;
07905 
07906                 neu1 = nmg_meonvu( BU_LIST_FIRST( vertexuse, &lu2->down_hd ) );
07907                 neu2 = nmg_eusplit( eu1->eumate_p->vu_p->v_p, neu1, 0 );
07908                 NMG_CK_EDGEUSE(eu1);
07909                 /* Attach both new edges in s2 to original edge in s1 */
07910                 nmg_use_edge_g( neu1, eu1->g.magic_p );
07911                 nmg_use_edge_g( neu2, eu1->g.magic_p );
07912                 nmg_radial_join_eu( eu1, neu2, &is->tol );
07913                 nmg_radial_join_eu( eu1, neu1, &is->tol );
07914 }
07915         nmg_loop_g(lu2->l_p, &is->tol);
07916         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
07917                 bu_log("nmg_isect_edge3p_shell(, eu1=x%x, s2=x%x) Added wire lu=x%x\n",
07918                         eu1, s2, lu2 );
07919         }
07920 
07921 out:
07922         if (rt_g.NMG_debug & DEBUG_POLYSECT) {
07923                 bu_log("nmg_isect_edge3p_shell(, eu1=x%x, s2=x%x) END\n",
07924                         eu1, s2 );
07925         }
07926         return;
07927 }
07928 
07929 /**
07930  *                      N M G _ C R A C K S H E L L S
07931  *
07932  *      Split the components of two shells wherever they may intersect,
07933  *      in preparation for performing boolean operations on the shells.
07934  */
07935 void
07936 nmg_crackshells(struct shell *s1, struct shell *s2, const struct bn_tol *tol)
07937 {
07938         struct bu_ptbl          vert_list1, vert_list2;
07939         struct nmg_inter_struct is;
07940         struct shell_a  *sa1, *sa2;
07941         struct face     *f1;
07942         struct faceuse  *fu1, *fu2;
07943         struct loopuse  *lu1;
07944         struct loopuse  *lu2;
07945         struct edgeuse  *eu1;
07946         struct edgeuse  *eu2;
07947         char            *flags;
07948         int             flag_len;
07949 
07950         if (rt_g.NMG_debug & DEBUG_POLYSECT)
07951                 bu_log("nmg_crackshells(s1=x%x, s2=x%x)\n", s1, s2);
07952 
07953         BN_CK_TOL(tol);
07954         NMG_CK_SHELL(s1);
07955         sa1 = s1->sa_p;
07956         NMG_CK_SHELL_A(sa1);
07957 
07958         NMG_CK_SHELL(s2);
07959         sa2 = s2->sa_p;
07960         NMG_CK_SHELL_A(sa2);
07961 
07962         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
07963                 nmg_ck_vs_in_region( s1->r_p, tol );
07964                 nmg_ck_vs_in_region( s2->r_p, tol );
07965         }
07966 
07967         /* All the non-face/face isect subroutines need are tol, l1, and l2 */
07968         is.magic = NMG_INTER_STRUCT_MAGIC;
07969         is.vert2d = (fastf_t *)NULL;
07970         is.tol = *tol;          /* struct copy */
07971         is.l1 = &vert_list1;
07972         is.l2 = &vert_list2;
07973         is.s1 = s1;
07974         is.s2 = s2;
07975         is.fu1 = (struct faceuse *)NULL;
07976         is.fu2 = (struct faceuse *)NULL;
07977         (void)bu_ptbl_init(&vert_list1, 64, "&vert_list1");
07978         (void)bu_ptbl_init(&vert_list2, 64, "&vert_list2");
07979 
07980         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
07981                 nmg_vshell( &s1->r_p->s_hd, s1->r_p );
07982                 nmg_vshell( &s2->r_p->s_hd, s2->r_p );
07983         }
07984 
07985         /* See if shells overlap */
07986         if ( ! V3RPP_OVERLAP_TOL(sa1->min_pt, sa1->max_pt,
07987             sa2->min_pt, sa2->max_pt, tol) )
07988                 return;
07989 
07990         /* XXX This is dangerous:  maxindex will grow rapidly! */
07991         flag_len = s1->r_p->m_p->maxindex * 10;
07992         flags = (char *)bu_calloc( flag_len, sizeof(char),
07993                 "nmg_crackshells flags[]" );
07994 
07995         /*
07996          *  Check each of the faces in shell 1 to see
07997          *  if they overlap the extent of shell 2
07998          */
07999         for( BU_LIST_FOR( fu1, faceuse, &s1->fu_hd ) )  {
08000                 if( s1->r_p->m_p->maxindex >= flag_len )  rt_bomb("nmg_crackshells() flag_len overrun\n");
08001                 NMG_CK_FACEUSE(fu1);
08002                 f1 = fu1->f_p;
08003                 NMG_CK_FACE(f1);
08004 
08005                 if( fu1->orientation != OT_SAME )  continue;
08006                 if( NMG_INDEX_IS_SET(flags, f1) )  continue;
08007                 NMG_CK_FACE_G_PLANE(f1->g.plane_p);
08008 
08009                 /* See if face f1 overlaps shell2 */
08010                 if( ! V3RPP_OVERLAP_TOL(sa2->min_pt, sa2->max_pt,
08011                     f1->min_pt, f1->max_pt, tol) )
08012                         continue;
08013 
08014                 is.fu1 = fu1;
08015 
08016                 /*
08017                  *  Now, check the face f1 from shell 1
08018                  *  against each of the faces of shell 2
08019                  */
08020                 for( BU_LIST_FOR( fu2, faceuse, &s2->fu_hd ) )  {
08021                         NMG_CK_FACEUSE(fu2);
08022                         NMG_CK_FACE(fu2->f_p);
08023                         if( fu2->orientation != OT_SAME )  continue;
08024 
08025                         is.fu2 = fu2;
08026                         nmg_isect_two_generic_faces(fu1, fu2, tol);
08027                 }
08028 
08029                 /*
08030                  *  Because the rest of the shell elements are wires,
08031                  *  there is no need to invoke the face cutter;
08032                  *  calculating the intersection points (vertices)
08033                  *  is sufficient.
08034                  *  XXX Is this true?  What about a wire edge cutting
08035                  *  XXX clean across fu1?  fu1 ought to be cut!
08036                  *
08037                  *  If coplanar, need to cut face.
08038                  *  If non-coplanar, can only hit at one point.
08039                  */
08040                 is.fu2 = (struct faceuse *)NULL;
08041 
08042                 /* Check f1 from s1 against wire loops of s2 */
08043                 for( BU_LIST_FOR( lu2, loopuse, &s2->lu_hd ) )  {
08044                         NMG_CK_LOOPUSE(lu2);
08045                         /* Not interested in vert_list here */
08046                         (void)nmg_isect_wireloop3p_face3p( &is, lu2, fu1 );
08047                 }
08048 
08049                 /* Check f1 from s1 against wire edges of s2 */
08050                 for( BU_LIST_FOR( eu2, edgeuse, &s2->eu_hd ) )  {
08051                         NMG_CK_EDGEUSE(eu2);
08052 
08053                         nmg_isect_wireedge3p_face3p( &is, eu2, fu1 );
08054                 }
08055 
08056                 /* Check f1 from s1 against lone vert of s2 */
08057                 if( s2->vu_p )  {
08058                         nmg_isect_3vertex_3face( &is, s2->vu_p, fu1 );
08059                 }
08060 
08061                 NMG_INDEX_SET(flags, f1);
08062 
08063                 if( rt_g.NMG_debug & DEBUG_VERIFY )  {
08064                         nmg_vshell( &s1->r_p->s_hd, s1->r_p );
08065                         nmg_vshell( &s2->r_p->s_hd, s2->r_p );
08066                 }
08067         }
08068 
08069         /*  Check each wire loop of shell 1 against non-faces of shell 2. */
08070         is.fu1 = (struct faceuse *)NULL;
08071         is.fu2 = (struct faceuse *)NULL;
08072         for( BU_LIST_FOR( lu1, loopuse, &s1->lu_hd ) )  {
08073                 NMG_CK_LOOPUSE( lu1 );
08074                 /* XXX Can there be lone-vertex loops here? (yes, need an intersector) */
08075                 if( BU_LIST_FIRST_MAGIC( &lu1->down_hd ) != NMG_EDGEUSE_MAGIC )
08076                         continue;
08077                 /* Really, it's just a bunch of wire edges, in a loop. */
08078                 for( BU_LIST_FOR( eu1, edgeuse, &lu1->down_hd ) )  {
08079                         NMG_CK_EDGEUSE(eu1);
08080                         /* Check eu1 against all of shell 2 */
08081                         nmg_isect_edge3p_shell( &is, eu1, s2 );
08082                 }
08083         }
08084 
08085         /*  Check each wire edge of shell 1 against all of shell 2. */
08086         for( BU_LIST_FOR( eu1, edgeuse, &s1->eu_hd ) )  {
08087                 NMG_CK_EDGEUSE( eu1 );
08088                 nmg_isect_edge3p_shell( &is, eu1, s2 );
08089         }
08090 
08091         /* Check each lone vert of s1 against shell 2 */
08092         if( s1->vu_p )  {
08093                 /* Check vert of s1 against all faceuses in s2 */
08094                 for( BU_LIST_FOR( fu2, faceuse, &s2->fu_hd ) )  {
08095                         NMG_CK_FACEUSE(fu2);
08096                         if( fu2->orientation != OT_SAME )  continue;
08097                         nmg_isect_3vertex_3face( &is, s1->vu_p, fu2 );
08098                 }
08099                 /* Check vert of s1 against all wire loops of s2 */
08100                 for( BU_LIST_FOR( lu2, loopuse, &s2->lu_hd ) )  {
08101                         NMG_CK_LOOPUSE(lu2);
08102                         /* Really, it's just a bunch of wire edges, in a loop. */
08103                         /* XXX Can there be lone-vertex loops here? */
08104                         for( BU_LIST_FOR( eu2, edgeuse, &lu2->down_hd ) )  {
08105                                 NMG_CK_EDGEUSE(eu2);
08106                                 nmg_isect_vertex3_edge3p( &is, s1->vu_p, eu2 );
08107                         }
08108                 }
08109                 /* Check vert of s1 against all wire edges of s2 */
08110                 for( BU_LIST_FOR( eu2, edgeuse, &s2->eu_hd ) )  {
08111                         NMG_CK_EDGEUSE(eu2);
08112                         nmg_isect_vertex3_edge3p( &is, s1->vu_p, eu2 );
08113                 }
08114 
08115                 /* Check vert of s1 against vert of s2 */
08116                 /* Unnecessary: already done by vertex fuser */
08117         }
08118         if( s1->r_p->m_p->maxindex >= flag_len )  rt_bomb("nmg_crackshells() flag_len overrun by end\n");
08119 
08120         /* Release storage from bogus isect line */
08121         (void)bu_ptbl_free(&vert_list1);
08122         (void)bu_ptbl_free(&vert_list2);
08123 
08124         bu_free( (char *)flags, "nmg_crackshells flags[]" );
08125 
08126         /* Eliminate stray vertices that were added along edges in this step */
08127         (void)nmg_unbreak_region_edges( &s1->l.magic );
08128         (void)nmg_unbreak_region_edges( &s2->l.magic );
08129 #if 0
08130                 /* TOO EARLY!!! These are needed to identify shared vertices */
08131         /* clean things up now that the intersections have been built */
08132         nmg_sanitize_s_lv(s1, OT_BOOLPLACE);
08133         nmg_sanitize_s_lv(s2, OT_BOOLPLACE);
08134 #endif
08135         nmg_isect2d_cleanup(&is);
08136 
08137         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
08138                 nmg_vshell( &s1->r_p->s_hd, s1->r_p );
08139                 nmg_vshell( &s2->r_p->s_hd, s2->r_p );
08140 nmg_ck_vs_in_region( s1->r_p, tol );
08141 nmg_ck_vs_in_region( s2->r_p, tol );
08142         }
08143 }
08144 
08145 /**
08146  *                      N M G _ F U _ T O U C H I N G L O O P S
08147  */
08148 int
08149 nmg_fu_touchingloops(const struct faceuse *fu)
08150 {
08151         const struct loopuse    *lu;
08152         const struct vertexuse  *vu;
08153 
08154         NMG_CK_FACEUSE(fu);
08155         for (BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
08156                 NMG_CK_LOOPUSE(lu);
08157                 if ((vu = nmg_loop_touches_self( lu )) )  {
08158                         NMG_CK_VERTEXUSE(vu);
08159 #if 0
08160                         /* Right now, this routine is used for debugging ONLY,
08161                          * so if this condition exists, die.
08162                          * However, note that this condition happens a lot
08163                          * for valid reasons, too.
08164                          */
08165                         bu_log("nmg_fu_touchingloops(lu=x%x, vu=x%x, v=x%x)\n",
08166                                 lu, vu, vu->v_p );
08167                         nmg_pr_lu_briefly(lu,0);
08168                         rt_bomb("nmg_fu_touchingloops()\n");
08169 #else
08170                         /* Perhaps log something here? */
08171 #endif
08172                         return 1;
08173                 }
08174         }
08175         return 0;
08176 }
08177 
08178 /*
08179  * Local Variables:
08180  * mode: C
08181  * tab-width: 8
08182  * c-basic-offset: 4
08183  * indent-tabs-mode: t
08184  * End:
08185  * ex: shiftwidth=4 tabstop=8
08186  */

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