nmg_fcut.c

Go to the documentation of this file.
00001 #define PLOT_BOTH_FACES 1
00002 
00003 
00004 /** @addtogroup  nmg */
00005 
00006 /*@{*/
00007 /** @file nmg_fcut.c
00008  *  After two faces have been intersected, cut or join loops crossed
00009  *  by the line of intersection.  (Formerly nmg_comb.c)
00010  *
00011  *  The main external routine here is nmg_face_cutjoin().
00012  *
00013  *  The line of intersection ("ray") will divide the face into two sets
00014  *  of loops.
00015  *  No one loop may cross the ray after this routine is finished.
00016  *  (Current optimization may remove this property).
00017  *
00018  *  Intersection points of significance to the other face but not yet
00019  *  part of the current face's geometry are denoted by a vu on the ray
00020  *  list, which points to a loop of a single vertex.  These points
00021  *  need to be incorporated into the final face.
00022  *
00023  *  Authors -
00024  *      Michael John Muuss
00025  *      Lee A. Butler
00026  *
00027  *  Source -
00028  *      The U. S. Army Research Laboratory
00029  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00030  */
00031 /*@}*/
00032 
00033 #ifndef lint
00034 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_fcut.c,v 14.8 2006/09/16 02:04:25 lbutler Exp $ (ARL)";
00035 #endif
00036 
00037 #include "common.h"
00038 
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041 #include <string.h>
00042 #include <math.h>
00043 #include "machine.h"
00044 #include "vmath.h"
00045 #include "nmg.h"
00046 #include "raytrace.h"
00047 
00048 
00049 
00050 /* States of the state machine */
00051 #define NMG_STATE_ERROR         0
00052 #define NMG_STATE_OUT           1
00053 #define NMG_STATE_ON_L          2
00054 #define NMG_STATE_ON_R          3
00055 #define NMG_STATE_ON_B          4
00056 #define NMG_STATE_ON_N          5
00057 #define NMG_STATE_IN            6
00058 static const char *nmg_state_names[] = {
00059         "*ERROR*",
00060         "out",
00061         "on_L",
00062         "on_R",
00063         "on_both",              /* "hole" crack */
00064         "on_neither",           /* "non-hole" crack */
00065         "in",
00066         "TOOBIG"
00067 };
00068 
00069 #define NMG_E_ASSESSMENT_LEFT           0
00070 #define NMG_E_ASSESSMENT_RIGHT          1
00071 #define NMG_E_ASSESSMENT_ON_FORW        2
00072 #define NMG_E_ASSESSMENT_ON_REV         3
00073 #define NMG_E_ASSESSMENT_ERROR          4       /* risky */
00074 
00075 #define NMG_V_ASSESSMENT_LONE           16
00076 #define NMG_V_ASSESSMENT_ERROR          17
00077 #define NMG_V_COMB(_p,_n)       (((_p)<<2)|(_n))
00078 
00079 /* Extract previous and next assessments from combined version */
00080 #define NMG_V_ASSESSMENT_PREV(_a)       (((_a)>>2)&3)
00081 #define NMG_V_ASSESSMENT_NEXT(_a)       ((_a)&3)
00082 
00083 static const char *nmg_v_assessment_names[32] = {
00084         "Left,Left",
00085         "Left,Right",
00086         "Left,On_Forw",
00087         "Left,On_Rev",
00088         "Right,Left",
00089         "Right,Right",
00090         "Right,On_Forw",
00091         "Right,On_Rev",
00092         "On_Forw,Left",
00093         "On_Forw,Right",
00094         "On_Forw,On_Forw",
00095         "On_Forw,On_Rev",
00096         "On_Rev,Left",
00097         "On_Rev,Right",
00098         "On_Rev,On_Forw",
00099         "On_Rev,On_Rev",
00100         "LONE_V",               /* 16 */
00101         "V_ERROR",              /* 17 */
00102         "?18",
00103         "?19",
00104         "?20",
00105         "?21",
00106         "?22",
00107         "?23",
00108         "?24",
00109         "?25",
00110         "?26",
00111         "?27",
00112         "?28",
00113         "?29",
00114         "?30",
00115         "?31"
00116 };
00117 #define NMG_LEFT_LEFT   NMG_V_COMB(NMG_E_ASSESSMENT_LEFT,NMG_E_ASSESSMENT_LEFT)
00118 #define NMG_LEFT_RIGHT  NMG_V_COMB(NMG_E_ASSESSMENT_LEFT,NMG_E_ASSESSMENT_RIGHT)
00119 #define NMG_LEFT_ON_FORW NMG_V_COMB(NMG_E_ASSESSMENT_LEFT,NMG_E_ASSESSMENT_ON_FORW)
00120 #define NMG_LEFT_ON_REV NMG_V_COMB(NMG_E_ASSESSMENT_LEFT,NMG_E_ASSESSMENT_ON_REV)
00121 #define NMG_RIGHT_LEFT  NMG_V_COMB(NMG_E_ASSESSMENT_RIGHT,NMG_E_ASSESSMENT_LEFT)
00122 #define NMG_RIGHT_RIGHT NMG_V_COMB(NMG_E_ASSESSMENT_RIGHT,NMG_E_ASSESSMENT_RIGHT)
00123 #define NMG_RIGHT_ON_FORW NMG_V_COMB(NMG_E_ASSESSMENT_RIGHT,NMG_E_ASSESSMENT_ON_FORW)
00124 #define NMG_RIGHT_ON_REV NMG_V_COMB(NMG_E_ASSESSMENT_RIGHT,NMG_E_ASSESSMENT_ON_REV)
00125 #define NMG_ON_FORW_LEFT NMG_V_COMB(NMG_E_ASSESSMENT_ON_FORW,NMG_E_ASSESSMENT_LEFT)
00126 #define NMG_ON_FORW_RIGHT NMG_V_COMB(NMG_E_ASSESSMENT_ON_FORW,NMG_E_ASSESSMENT_RIGHT)
00127 #define NMG_ON_FORW_ON_FORW NMG_V_COMB(NMG_E_ASSESSMENT_ON_FORW,NMG_E_ASSESSMENT_ON_FORW)
00128 #define NMG_ON_FORW_ON_REV NMG_V_COMB(NMG_E_ASSESSMENT_ON_FORW,NMG_E_ASSESSMENT_ON_REV)
00129 #define NMG_ON_REV_LEFT NMG_V_COMB(NMG_E_ASSESSMENT_ON_REV,NMG_E_ASSESSMENT_LEFT)
00130 #define NMG_ON_REV_RIGHT NMG_V_COMB(NMG_E_ASSESSMENT_ON_REV,NMG_E_ASSESSMENT_RIGHT)
00131 #define NMG_ON_REV_ON_FORW NMG_V_COMB(NMG_E_ASSESSMENT_ON_REV,NMG_E_ASSESSMENT_ON_FORW)
00132 #define NMG_ON_REV_ON_REV NMG_V_COMB(NMG_E_ASSESSMENT_ON_REV,NMG_E_ASSESSMENT_ON_REV)
00133 #define NMG_LONE        NMG_V_ASSESSMENT_LONE
00134 
00135 static const char *nmg_e_assessment_names[6] = {
00136         "LEFT",
00137         "RIGHT",
00138         "ON_FORW",
00139         "ON_REV",
00140         "E_ERROR",
00141         "E_5?"
00142 };
00143 
00144 /*
00145  *  Action entries for the state transition tables
00146  */
00147 #define NMG_ACTION_ERROR                0
00148 #define NMG_ACTION_NONE                 1
00149 #define NMG_ACTION_NONE_OPTIM           2
00150 #define NMG_ACTION_VFY_EXT              3
00151 #define NMG_ACTION_VFY_MULTI            4
00152 #define NMG_ACTION_LONE_V_ESPLIT        5
00153 #define NMG_ACTION_LONE_V_JAUNT         6
00154 #define NMG_ACTION_CUTJOIN              7
00155 static const char *action_names[] = {
00156         "*ERROR*",
00157         "NONE",
00158         "NONE_OPTIM",
00159         "VFY_EXT",
00160         "VFY_MULTI",
00161         "LONE_V_ESPLIT",
00162         "LONE_V_JAUNT",
00163         "CUTJOIN",
00164         "*TOOBIG*"
00165 };
00166 
00167 /* The "ray" here is the intersection line between two faces */
00168 struct nmg_ray_state {
00169         long                    magic;
00170         struct vertexuse        **vu;           /* ptr to vu array */
00171         int                     nvu;            /* len of vu[] */
00172         point_t                 pt;             /* The ray */
00173         vect_t                  dir;
00174         struct edge_g_lseg              *eg_p;          /* Edge geom of the ray */
00175         struct shell            *sA;
00176         struct shell            *sB;
00177         struct faceuse          *fu1;
00178         struct faceuse          *fu2;
00179         vect_t                  left;           /* points left of ray, on face */
00180         int                     state;          /* current (old) state */
00181         int                     last_action;    /* last action taken */
00182         vect_t                  ang_x_dir;      /* x axis for angle measure */
00183         vect_t                  ang_y_dir;      /* y axis for angle measure */
00184         const struct bn_tol     *tol;
00185 };
00186 #define NMG_RAYSTATE_MAGIC      0x54322345
00187 #define NMG_CK_RAYSTATE(_p)     NMG_CKMAG(_p, NMG_RAYSTATE_MAGIC, "nmg_ray_state")
00188 
00189 struct loop_cuts {
00190         struct loopuse *lu;
00191         struct vertexuse *vu1;
00192         struct vertexuse *vu2;
00193 };
00194 int
00195 nmg_face_state_transition(struct nmg_ray_state  *rs,
00196                           int                   pos,
00197                           int                   multi,
00198                           int                   other_rs_state);
00199 
00200 /**
00201  *                      P T B L _ V S O R T
00202  *
00203  *  Sort list of hit points (vertexuse's) in fu1 on plane of fu2,
00204  *  by increasing distance, vertex ptr, and vu ptr.
00205  *  Eliminate duplications of vu at same distance.
00206  *  (Actually, a given vu should show up at exactly 1 distance!)
00207  *  The line of intersection is pt + t * dir.
00208  *
00209  *  For now, a bubble-sort is used, because the list should not have more
00210  *  than a few hundred entries on it.
00211  */
00212 static void ptbl_vsort(struct bu_ptbl *b, struct faceuse *fu1, struct faceuse *fu2, fastf_t *pt, fastf_t *dir, fastf_t *mag, fastf_t dist_tol)
00213                                 /* table of vertexuses on intercept line */
00214                                 /* unused? */
00215                                 /* unused? */
00216 
00217 
00218 
00219 
00220 {
00221         register struct vertexuse       **vu;
00222         register int i, j;
00223 
00224         vu = (struct vertexuse **)b->buffer;
00225 
00226         if( rt_g.NMG_debug )  {
00227                 /* Ensure that distance from points to ray is reasonable */
00228                 for(i = 0 ; i < b->end ; ++i) {
00229                         fastf_t         dist;
00230 
00231                         NMG_CK_VERTEXUSE(vu[i]);
00232                         dist = bn_dist_line3_pt3( pt, dir, vu[i]->v_p->vg_p->coord );
00233                         if( dist > dist_tol )  {
00234                                 bu_log("WARNING ptbl_vsort() vu=x%x point off line by %e %g*tol, tol=%e\n",
00235                                         vu[i], dist,
00236                                         dist/dist_tol, dist_tol);
00237                                 if(rt_g.NMG_debug&DEBUG_VU_SORT)  {
00238                                         VPRINT("  vu", vu[i]->v_p->vg_p->coord);
00239                                         VPRINT("  pt", pt);
00240                                         VPRINT(" dir", dir);
00241                                 }
00242                         }
00243                         if( dist > 100*dist_tol )  {
00244                                 bu_log("ERROR ptbl_vsort() vu=x%x point off line by %g > 100*dist_tol\n",
00245                                         vu[i], dist);
00246                                 rt_bomb("ptbl_vsort()\n");
00247                         }
00248                 }
00249         }
00250 
00251         /* check vertexuses and compute distance from start of line */
00252         for(i = 0 ; i < b->end ; ++i) {
00253                 vect_t          vect;
00254                 NMG_CK_VERTEXUSE(vu[i]);
00255 
00256                 if( mag[i] == MAX_FASTF )
00257                 {
00258                         VSUB2(vect, vu[i]->v_p->vg_p->coord, pt);
00259                         mag[i] = VDOT( vect, dir );
00260                 }
00261 
00262                 /* Find previous vu's at "same" distance, within dist_tol */
00263                 for( j = 0; j < i; j++ )  {
00264                         register fastf_t        tmag;
00265 
00266                         tmag = mag[i] - mag[j];
00267                         if( tmag < -dist_tol )  continue;
00268                         if( tmag > dist_tol )  continue;
00269                         /* Nearly equal at same vertex */
00270                         if( mag[i] != mag[j] &&
00271                             vu[i]->v_p == vu[j]->v_p )  {
00272         bu_log("ptbl_vsort: forcing vu=x%x & vu=x%x mag equal\n", vu[i], vu[j]);
00273                                 mag[j] = mag[i]; /* force equal */
00274                         }
00275                 }
00276         }
00277 
00278         for(i=0 ; i < b->end - 1 ; ++i) {
00279                 for (j=i+1; j < b->end ; ++j) {
00280 
00281                         if( mag[i] < mag[j] )  continue;
00282                         if( mag[i] == mag[j] )  {
00283                                 if( vu[i]->v_p < vu[j]->v_p )  continue;
00284                                 if( vu[i]->v_p == vu[j]->v_p )  {
00285                                         if( vu[i] < vu[j] )  continue;
00286                                         if( vu[i] == vu[j] )  {
00287                                                 int     last = b->end - 1;
00288                                                 /* vu duplication, eliminate! */
00289         bu_log("ptbl_vsort: vu duplication eliminated\n");
00290                                                 if( j >= last )  {
00291                                                         /* j is last element */
00292                                                         b->end--;
00293                                                         break;
00294                                                 }
00295                                                 /* rewrite j with last element */
00296                                                 vu[j] = vu[last];
00297                                                 mag[j] = mag[last];
00298                                                 b->end--;
00299                                                 /* Repeat this index */
00300                                                 j--;
00301                                                 continue;
00302                                         }
00303                                         /* vu[i] > vu[j], fall through */
00304                                 }
00305                                 /* vu[i]->v_p > vu[j]->v_p, fall through */
00306                         }
00307                         /* mag[i] > mag[j] */
00308 
00309                         /* exchange [i] and [j] */
00310                         {
00311                                 register struct vertexuse *tvu;
00312                                 tvu = vu[i];
00313                                 vu[i] = vu[j];
00314                                 vu[j] = tvu;
00315                         }
00316 
00317                         {
00318                                 register fastf_t        tmag;
00319                                 tmag = mag[i];
00320                                 mag[i] = mag[j];
00321                                 mag[j] = tmag;
00322                         }
00323                 }
00324         }
00325 }
00326 
00327 /**
00328  *                      N M G _ C K _ V U _ P T B L
00329  *
00330  *  As an automatic check for the intersector failing to find
00331  *  all intersections, check all the vertices on the intersection line.
00332  *  For each one, find all the other uses in this faceuse, and
00333  *  if they are not also listed on the line, they were overlooked.
00334  *
00335  *  This does not catch _all_ possible mistakes, but does catch some.
00336  */
00337 int
00338 nmg_ck_vu_ptbl(struct bu_ptbl *p, struct faceuse *fu)
00339 {
00340         struct vertex           *v;
00341         struct vertexuse        *vu;
00342         struct vertexuse        *tvu;
00343         struct faceuse          *tfu;
00344         int                     i;
00345         int                     ret = 0;
00346 
00347         BU_CK_PTBL(p);
00348         NMG_CK_FACEUSE(fu);
00349 
00350 top:
00351         for( i=0; i < BU_PTBL_END(p); i++ )  {
00352                 vu = (struct vertexuse *)BU_PTBL_GET(p, i);
00353                 NMG_CK_VERTEXUSE(vu);
00354                 v = vu->v_p;
00355                 NMG_CK_VERTEX(v);
00356                 tfu = nmg_find_fu_of_vu(vu);
00357                 if( tfu != fu )  {
00358                         bu_log("ERROR: vu=x%x v=x%x up_fu=x%x != arg_fu=x%x\n",
00359                                 vu, v, tfu, fu );
00360                         rt_bomb("nmg_ck_vu_ptbl() intersect list is confused about which face it belongs to.\n");
00361                 }
00362                 for( BU_LIST_FOR( tvu, vertexuse, &v->vu_hd ) )  {
00363                         NMG_CK_VERTEXUSE(tvu);
00364                         if( tvu == vu )  continue;
00365                         if( (tfu = nmg_find_fu_of_vu( tvu )) == (struct faceuse *)NULL )
00366                                 continue;
00367                         if( tfu != fu )  continue;
00368                         /* tvu is in fu.  Is tvu on the line? */
00369                         if( bu_ptbl_locate(p, &tvu->l.magic ) >= 0 )  continue;
00370                         /* No, not on list */
00371                         bu_log("ERROR: vu=x%x v=x%x %s=x%x is on isect line, tvu=x%x %s=x%x isn't.\n",
00372                                 vu, v,
00373                                 bu_identify_magic( *vu->up.magic_p ),
00374                                 vu->up.magic_p,
00375                                 tvu,
00376                                 bu_identify_magic( *tvu->up.magic_p ),
00377                                 tvu->up.magic_p );
00378                         /* XXX bomb here? */
00379                         nmg_pr_ptbl( "intersect line vu table", p, 1 );
00380                         rt_bomb("nmg_ck_vu_ptbl() missing vertexuse\n");
00381 /* XXXXXXXXXXXXXXXXXXXXXXXX Horrible temporizing measure */
00382                         /* Another strategy:  add it in! */
00383                         (void)bu_ptbl_ins( p, &tvu->l.magic );
00384                         ret++;
00385                         goto top;
00386                 }
00387         }
00388         if(ret)bu_log("nmg_ck_vu_ptbl() ret=%d\n", ret);
00389         return ret;
00390 }
00391 
00392 /**
00393  *                      N M G _ V U _ A N G L E _ M E A S U R E
00394  *
00395  *  Given a vertexuse from a loop which lies in a plane,
00396  *  compute the vector 'vec' from the previous vertex to this one.
00397  *  Using two perpendicular vectors (x_dir and y_dir) which both lie
00398  *  in the plane of the loop, return the angle (in radians) of 'vec'
00399  *  from x_dir, going CCW around the perpendicular x_dir CROSS y_dir.
00400  *
00401  *  x_dir is -ray_dir
00402  *  y_dir points right.
00403  *
00404  *  Returns -
00405  *      vec == x_dir returns 0,
00406  *      vec == y_dir returns pi/2,
00407  *      vec == -x_dir returns pi,
00408  *      vec == -y_dir returns 3*pi/2.
00409  *      0.0 if unable to compute 'vec'
00410  */
00411 double
00412 nmg_vu_angle_measure(struct vertexuse *vu, fastf_t *x_dir, fastf_t *y_dir, int assessment, int in)
00413 
00414 
00415 
00416 
00417                                 /* 1 = inbound edge, 0 = outbound edge */
00418 {
00419         struct loopuse  *lu;
00420         struct edgeuse  *this_eu;
00421         struct edgeuse  *prev_eu;
00422         vect_t          vec;
00423         fastf_t         ang;
00424         int             this_ass;
00425 
00426         NMG_CK_VERTEXUSE( vu );
00427         if( *vu->up.magic_p == NMG_LOOPUSE_MAGIC )  {
00428                 return 0;               /* Unable to compute 'vec' */
00429         }
00430 
00431         /*
00432          *  For consistency, if entry edge is ON the ray,
00433          *  force the angles to be exact, don't compute them.
00434          */
00435         if( in )
00436                 this_ass = NMG_V_ASSESSMENT_PREV( assessment );
00437         else
00438                 this_ass = NMG_V_ASSESSMENT_NEXT( assessment );
00439         if( this_ass == NMG_E_ASSESSMENT_ON_FORW )  {
00440                 if( in )  ang = 0;      /* zero angle */
00441                 else    ang = bn_pi;    /* 180 degrees */
00442                 if(rt_g.NMG_debug&DEBUG_VU_SORT)
00443                         bu_log("nmg_vu_angle_measure:  NMG_E_ASSESSMENT_ON_FORW, ang=%g\n", ang);
00444                 return ang;
00445         }
00446         if( this_ass == NMG_E_ASSESSMENT_ON_REV )  {
00447                 if( in )  ang = bn_pi;  /* 180 degrees */
00448                 else    ang = 0;        /* zero angle */
00449                 if(rt_g.NMG_debug&DEBUG_VU_SORT)
00450                         bu_log("nmg_vu_angle_measure:  NMG_E_ASSESSMENT_ON_REV, ang=%g\n", ang);
00451                 return ang;
00452         }
00453 
00454         /*
00455          *  Compute the angle
00456          */
00457         lu = nmg_find_lu_of_vu(vu);
00458         NMG_CK_LOOPUSE(lu);
00459         this_eu = nmg_find_eu_with_vu_in_lu( lu, vu );
00460         prev_eu = this_eu;
00461         do {
00462                 prev_eu = in ? BU_LIST_PPREV_CIRC( edgeuse, prev_eu ) :
00463                         BU_LIST_PNEXT_CIRC( edgeuse, prev_eu );
00464                 if( prev_eu == this_eu )  {
00465                         if(rt_g.NMG_debug&DEBUG_VU_SORT)
00466                                 bu_log("nmg_vu_angle_measure: prev eu is this eu, ang=0\n");
00467                         return 0;       /* Unable to compute 'vec' */
00468                 }
00469                 /* Skip any edges that stay on this vertex */
00470         } while( prev_eu->vu_p->v_p == this_eu->vu_p->v_p );
00471 
00472         /* in==1 Get vec for inbound edge, but pointing away from vert. */
00473         /* in==0 "prev" is really next, so this is departing vec */
00474         VSUB2( vec, prev_eu->vu_p->v_p->vg_p->coord, vu->v_p->vg_p->coord );
00475 
00476         ang = bn_angle_measure( vec, x_dir, y_dir );
00477         if(rt_g.NMG_debug&DEBUG_VU_SORT)
00478                 bu_log("nmg_vu_angle_measure:  measured angle=%e\n", ang*bn_radtodeg);
00479 
00480         /*
00481          *  Since the entry edge is not on the ray, ensure the
00482          *  angles are not exactly 0 or pi.
00483          */
00484 #define RADIAN_TWEEK    1.0e-14 /* low bits of double prec., re: 6.28... */
00485         if( ang == 0 )  {
00486                 if( this_ass == NMG_E_ASSESSMENT_RIGHT )  {
00487                         ang = RADIAN_TWEEK;
00488                 } else {
00489                         /* Assuming NMG_E_ASSESSMENT_LEFT */
00490                         ang = bn_twopi - RADIAN_TWEEK;
00491                 }
00492         } else if( ang == bn_pi )  {
00493                 if( this_ass == NMG_E_ASSESSMENT_RIGHT )  {
00494                         ang = bn_pi - RADIAN_TWEEK;
00495                 } else {
00496                         ang = bn_pi + RADIAN_TWEEK;
00497                 }
00498         }
00499 
00500         /*
00501          *  Also, ensure computed angle and topological assessment agree
00502          *  about which side of the ray this edge is on.
00503          */
00504         if( ang > bn_pi )  {
00505                 if( this_ass != NMG_E_ASSESSMENT_LEFT )  {
00506                         bu_log("*** ERROR topology/geometry conflict, ang=%e, ass=%s\n",
00507                                 ang*bn_radtodeg,
00508                                 nmg_e_assessment_names[this_ass] );
00509                 }
00510         } else if( ang < bn_pi )  {
00511                 if( this_ass != NMG_E_ASSESSMENT_RIGHT )  {
00512                         bu_log("*** ERROR topology/geometry conflict, ang=%e, ass=%s\n",
00513                                 ang*bn_radtodeg,
00514                                 nmg_e_assessment_names[this_ass] );
00515                 }
00516         }
00517         if(rt_g.NMG_debug&DEBUG_VU_SORT)
00518                 bu_log("  final ang=%g (%e), vec=(%g,%g,%g)\n", ang*bn_radtodeg, ang*bn_radtodeg, V3ARGS(vec) );
00519         return ang;
00520 }
00521 
00522 /**
00523  *                      N M G _ I S _ V _ O N _ R S _ L I S T
00524  */
00525 int
00526 nmg_is_v_on_rs_list(const struct nmg_ray_state *rs, const struct vertex *v)
00527 {
00528         register int    i;
00529 
00530         NMG_CK_VERTEX(v);
00531         for( i=rs->nvu-1; i >= 0; i-- )  {
00532                 if( !rs->vu[i] )  continue;
00533                 if( rs->vu[i]->v_p == v )  return i;
00534         }
00535         return -1;
00536 }
00537 
00538 /**
00539  *                      N M G _ A S S E S S _ E U
00540  *
00541  *  The current vertex (eu->vu_p) is on the line of intersection.
00542  *  Assess the indicated edge, to see if it lies on the line of
00543  *  intersection, or departs towards the left or right.
00544  *
00545  *  There is no need to look more than one edge forward or backward.
00546  *  Even if there are edges which loop around to the same vertex
00547  *  (with a different vertexuse), that (0-length) edge is ON the ray.
00548  */
00549 int
00550 nmg_assess_eu(struct edgeuse *eu, int forw, struct nmg_ray_state *rs, int pos)
00551 {
00552         struct vertex           *v;
00553         struct vertex           *otherv = (struct vertex *)0;
00554         struct edgeuse          *othereu;
00555         vect_t                  heading;
00556         int                     ret;
00557         register int            i;
00558 
00559         NMG_CK_EDGEUSE(eu);
00560         NMG_CK_RAYSTATE(rs);
00561         BN_CK_TOL(rs->tol);
00562         v = eu->vu_p->v_p;
00563         NMG_CK_VERTEX(v);
00564         othereu = eu;
00565         if( forw )  {
00566                 othereu = BU_LIST_PNEXT_CIRC( edgeuse, othereu );
00567         } else {
00568                 othereu = BU_LIST_PPREV_CIRC( edgeuse, othereu );
00569         }
00570         if( othereu == eu )  {
00571                 /* Back to where search started */
00572                 if(rt_g.NMG_debug) nmg_pr_eu(eu, NULL);
00573                 rt_bomb("nmg_assess_eu() no edges leave the vertex!\n");
00574         }
00575         otherv = othereu->vu_p->v_p;
00576         if( otherv == v )  {
00577                 /* Edge stays on this vertex -- can't tell if forw or rev! */
00578                 if(rt_g.NMG_debug) nmg_pr_eu(eu, NULL);
00579                 rt_bomb("nmg_assess_eu() edge runs from&to same vertex!\n");
00580         }
00581 
00582         /*  If the other vertex is mentioned anywhere on the ray's vu list,
00583          *  then the edge is "on" the ray.
00584          *  Match against vertex (rather than vertexuse) because cut/join
00585          *  operations may have changed the particular vertexuse pointer.
00586          */
00587         if( (i = nmg_is_v_on_rs_list(rs, otherv)) > -1 )  {
00588                 struct vertex   *farv;
00589                 struct edgeuse  *fareu;
00590                 int             start, end;
00591 
00592                 fareu = othereu;
00593 again:
00594                 /* Edge's far end is ON the ray.  Which way does it go? */
00595                 if(rt_g.NMG_debug&DEBUG_FCUT)
00596                         bu_log("eu ON ray: vu[%d]=x%x, other:vu[%d]=x%x\n",
00597                                 pos, rs->vu[pos], i, otherv );
00598 
00599                 /*
00600                  *  As an attempt at fixing the ON/ON vertexuse problem,
00601                  *  look further forw/back along the edgeuse list,
00602                  *  as long as it shares the same edge geometry.
00603                  *  If not on list, use *that* vertex to assess left/right.
00604                  */
00605                 if( forw )  {
00606                         fareu = BU_LIST_PNEXT_CIRC( edgeuse, fareu );
00607                 } else {
00608                         fareu = BU_LIST_PPREV_CIRC( edgeuse, fareu );
00609                 }
00610                 if( fareu == eu )  goto really_on;      /* All eu's are ON! */
00611                 if( fareu->g.lseg_p != eu->g.lseg_p )  goto really_on;
00612                 farv = fareu->vu_p->v_p;
00613                 if(rt_g.NMG_debug&DEBUG_FCUT)
00614                         bu_log("nmg_assess_eu() farv = x%x, on_index=%d\n", farv, nmg_is_v_on_rs_list(rs, farv) );
00615                 if( nmg_is_v_on_rs_list(rs, farv) > -1 )  {
00616                         /* farv is ON list, try going further back */
00617                         goto again;
00618                 }
00619                 /* farv is not ON list, assess _it_ */
00620                 /* XXX Need to remove othervu from the list! */
00621                 otherv = farv;
00622                 if(rt_g.NMG_debug&DEBUG_FCUT)
00623                         bu_log("nmg_assess_eu() assessing farv\n");
00624                 goto left_right;
00625 
00626                 /* Compute edge vector, for purposes of orienting answer */
00627 really_on:
00628 #if 0
00629                 if( forw )  {
00630                         /* Edge goes from v to otherv */
00631                         VSUB2( heading, otherv->vg_p->coord, v->vg_p->coord );
00632                 } else {
00633                         /* Edge goes from otherv to v */
00634                         VSUB2( heading, v->vg_p->coord, otherv->vg_p->coord );
00635                 }
00636                 if( MAGSQ(heading) < SMALL_FASTF )  rt_bomb("nmg_assess_eu() null heading\n");
00637                 if( MAGSQ(heading) < rs->tol->dist_sq )  rt_bomb("nmg_assess_eu() edge len < dist tol\n");
00638                 if( VDOT( heading, rs->dir ) < 0 )  {
00639                         ret = NMG_E_ASSESSMENT_ON_REV;
00640                 } else {
00641                         ret = NMG_E_ASSESSMENT_ON_FORW;
00642                 }
00643 
00644                 if( i > pos )  {
00645                         start = pos+1;
00646                         end = i;
00647                 } else {
00648                         start = i+1;
00649                         end = pos;
00650                 }
00651 #else
00652                 /*
00653                  *  There are 2 ways of determining the assessment:
00654                  *  edge direction DOT ray direction, above, and
00655                  *  comparing the subscripts of the two vertexuses
00656                  *  (which translates to comparing dists along ray).
00657                  */
00658                 if( i > pos )  {
00659                         if( forw )
00660                                 ret = NMG_E_ASSESSMENT_ON_FORW;
00661                         else
00662                                 ret = NMG_E_ASSESSMENT_ON_REV;
00663                         start = pos+1;
00664                         end = i;
00665                 } else {
00666                         /* i < pos  (They can't be equal) */
00667                         if( forw )
00668                                 ret = NMG_E_ASSESSMENT_ON_REV;
00669                         else
00670                                 ret = NMG_E_ASSESSMENT_ON_FORW;
00671                         start = i+1;
00672                         end = pos;
00673                 }
00674 #endif
00675                 /*
00676                  *  Verify that any other vertexuses on the intersect line
00677                  *  along the ON edge are uses of one of the two edge
00678                  *  endpoints.  Otherwise, something awful has happened.
00679                  */
00680                 for( i=start; i<end; i++ )  {
00681                         int     j;
00682                         if( !rs->vu[i] )  continue;
00683                         if( rs->vu[i]->v_p == v ||
00684                             rs->vu[i]->v_p == otherv )
00685                                 continue;
00686                         if(rt_g.NMG_debug&DEBUG_FCUT)  {
00687                                 bu_log("In edge interval (%d,%d), ON vertexuse [%d] = x%x appears?\n",
00688                                         start-1, end, i, rs->vu[i] );
00689                                 for( j=start-1; j<=end; j++ )  {
00690                                         if( !rs->vu[i] )  continue;
00691                                         bu_log(" %d ", j);
00692                                         nmg_pr_vu_briefly( rs->vu[j], (char *)0 );
00693                                 }
00694                                 bu_log("nmg_assess_eu():  ON vertexuse in middle of edge?\n");
00695                         }
00696                         /* Leave it for nmg_onon_fix() to fix */
00697                         ret = NMG_E_ASSESSMENT_ERROR;
00698                         return -i;      /* Special flag to nmg_onon_fix() */
00699                 }
00700                 goto out;
00701         }
00702 
00703         /*
00704          *  Since other vertex does not lie anywhere on line of intersection,
00705          *  the edge must lie to one side or the other of the ray.
00706          *  Check vector from v to otherv against "left" vector.
00707          */
00708 left_right:
00709         VSUB2( heading, otherv->vg_p->coord, v->vg_p->coord );
00710         if( MAGSQ(heading) < SMALL_FASTF )  rt_bomb("nmg_assess_eu() null heading 2\n");
00711         if( VDOT( heading, rs->left ) < 0 )  {
00712                 ret = NMG_E_ASSESSMENT_RIGHT;
00713         } else {
00714                 ret = NMG_E_ASSESSMENT_LEFT;
00715         }
00716 out:
00717         if(rt_g.NMG_debug&DEBUG_FCUT)  {
00718                 bu_log("nmg_assess_eu(x%x, fw=%d, pos=%d) v=x%x otherv=x%x: %s\n",
00719                         eu, forw, pos, v, otherv,
00720                         nmg_e_assessment_names[ret] );
00721                 bu_log(" v(%g, %g, %g) other(%g, %g, %g)\n",
00722                         V3ARGS(v->vg_p->coord), V3ARGS(otherv->vg_p->coord) );
00723                 bu_log(" rs->left(%g, %g, %g) heading(%g, %g, %g)\n",
00724                         V3ARGS(rs->left), V3ARGS(heading) );
00725         }
00726         return ret;
00727 }
00728 
00729 /**
00730  *                      N M G _ A S S E S S _ V U
00731  */
00732 int
00733 nmg_assess_vu(struct nmg_ray_state *rs, int pos)
00734 {
00735         struct vertexuse        *vu;
00736         struct loopuse  *lu;
00737         struct edgeuse  *this_eu;
00738         int             next_ass;
00739         int             prev_ass;
00740         int             ass;
00741 
00742         NMG_CK_RAYSTATE(rs);
00743         vu = rs->vu[pos];
00744         NMG_CK_VERTEXUSE( vu );
00745         if( *vu->up.magic_p == NMG_LOOPUSE_MAGIC )  {
00746                 return NMG_V_ASSESSMENT_LONE;
00747         }
00748         if( (lu = nmg_find_lu_of_vu(vu)) == (struct loopuse *)0 )
00749                 rt_bomb("nmg_assess_vu: no lu\n");
00750         this_eu = nmg_find_eu_with_vu_in_lu( lu, vu );
00751         /* Couldn't this have been this_eu = vu->up.eu_p ? */
00752         if( this_eu != vu->up.eu_p )  bu_log("nmg_assess_vu() eu mis-match? x%x x%x\n", this_eu, vu->up.eu_p);
00753         prev_ass = nmg_assess_eu( this_eu, 0, rs, pos );
00754         next_ass = nmg_assess_eu( this_eu, 1, rs, pos );
00755         if( prev_ass < 0 || next_ass < 0 )  {
00756                 ass = NMG_V_ASSESSMENT_ERROR;
00757         } else {
00758                 ass = NMG_V_COMB( prev_ass, next_ass );
00759         }
00760 
00761         /*
00762          *  If the vu assessment is
00763          *  NMG_ON_REV_ON_FORW or NMG_ON_FORW_ON_REV,
00764          *  ensure that other end of both eu's is same vertex.
00765          *  If not, it's an intersector error, and will confuse our caller.
00766          */
00767         if( ass==NMG_ON_REV_ON_FORW || ass==NMG_ON_FORW_ON_REV )  {
00768                 struct edgeuse  *prev;
00769                 struct edgeuse  *next;
00770                 prev = BU_LIST_PPREV_CIRC( edgeuse, this_eu );
00771                 next = BU_LIST_PNEXT_CIRC( edgeuse, this_eu );
00772                 if( prev->vu_p->v_p != next->vu_p->v_p )  {
00773                         bu_log("nmg_assess_vu() %s, v=x%x, prev_v=x%x, next_v=x%x\n",
00774                                 nmg_v_assessment_names[ass],
00775                                 this_eu->vu_p->v_p,
00776                                 prev->vu_p->v_p, next->vu_p->v_p );
00777                         bu_log("nmg_assess_vu() ON/ON edgeuse ends on different vertices.\n");
00778                         VPRINT("vu  ", this_eu->vu_p->v_p->vg_p->coord);
00779                         VPRINT("prev", prev->vu_p->v_p->vg_p->coord);
00780                         VPRINT("next", next->vu_p->v_p->vg_p->coord);
00781 
00782                         /* See how far off the line they are */
00783                         bu_log("vu dist=%e, next dist=%e, tol=%e\n",
00784                         bn_dist_line3_pt3( rs->pt, rs->dir, this_eu->vu_p->v_p->vg_p->coord ),
00785                         bn_dist_line3_pt3( rs->pt, rs->dir, prev->vu_p->v_p->vg_p->coord ),
00786                                 rs->tol->dist );
00787 #if 0
00788                         /* It's too late for this now. */
00789                         if( nmg_break_long_edges( nmg_find_s_of_eu(this_eu), rs->tol ) > 0 )
00790                                 bu_log("\tnmg_break_long_edges succeeded\n");
00791 #endif
00792                         rt_bomb("nmg_assess_vu() ON/ON edgeuse ends on different vertices.\n");
00793                 }
00794         }
00795         if(rt_g.NMG_debug&DEBUG_FCUT)  {
00796                 bu_log("nmg_assess_vu() vu[%d]=x%x, v=x%x: %s\n",
00797                         pos, vu, vu->v_p, nmg_v_assessment_names[ass] );
00798         }
00799         return ass;
00800 }
00801 
00802 struct nmg_vu_stuff {
00803         struct vertexuse        *vu;
00804         int                     loop_index;
00805         struct nmg_loop_stuff   *lsp;
00806         fastf_t                 in_vu_angle;
00807         fastf_t                 out_vu_angle;
00808         fastf_t                 min_vu_dot;
00809         fastf_t                 lo_ang;         /* small if RIGHT, large if LEFT */
00810         fastf_t                 hi_ang;
00811         int                     seq;            /* seq # after lsp->min_vu */
00812         int                     wedge_class;    /* WEDGE_LEFT, etc */
00813 };
00814 struct nmg_loop_stuff {
00815         struct loopuse          *lu;
00816         fastf_t                 min_dot;
00817         struct vertexuse        *min_vu;
00818         int                     n_vu_in_loop;   /* # ray vu's in this loop */
00819 };
00820 
00821 #define WEDGE_LEFT      0
00822 #define WEDGE_CROSS     1
00823 #define WEDGE_RIGHT     2
00824 #define WEDGE_ON        3
00825 #define WEDGECLASS2STR(_cl)     nmg_wedgeclass_string[(_cl)]
00826 static const char *nmg_wedgeclass_string[] = {
00827         "LEFT",
00828         "CROSS",
00829         "RIGHT",
00830         "ON",
00831         "???"
00832 };
00833 
00834 /**
00835  *                      N M G _ P R _ V U _ S T U F F
00836  */
00837 void
00838 nmg_pr_vu_stuff(const struct nmg_vu_stuff *vs)
00839 {
00840         bu_log("nmg_pr_vu_stuff(x%x) vu=x%x, loop_index=%d, lsp=x%x\n",
00841                 vs, vs->vu, vs->loop_index, vs->lsp);
00842         bu_log(" in_vu_angle=%g, out_vu_angle=%g, min_vu_dot=%g\n",
00843                 vs->in_vu_angle, vs->out_vu_angle, vs->min_vu_dot);
00844         bu_log(" lo_ang=%g, hi_ang=%g, seq=%d, wedge_class=%s\n",
00845                 vs->lo_ang, vs->hi_ang, vs->seq,
00846                 WEDGECLASS2STR(vs->wedge_class) );
00847 }
00848 
00849 /**
00850  *                      N M G _ W E D G E _ C L A S S
00851  *
00852  *  0 degrees is to the rear (ON_REV), 90 degrees is to the RIGHT,
00853  *  180 is ON_FORW, 270 is to the LEFT.
00854  *  Determine if the given wedge is entirely to the left or right of
00855  *  the ray, or if it crosses.
00856  *
00857  *  "halfway X" (ha, hb) have these properties:
00858  *      < 0     ( ==> X < 180 ) RIGHT
00859  *      > 0     ( ==> X > 180 ) LEFT
00860  *      ==0     ( ==> X == 180 ) ON_FORW
00861  *
00862  *  Returns -
00863  *      WEDGE_LEFT
00864  *      WEDGE_CROSSING
00865  *      WEDGE_RIGHT
00866  *      WEDGE_ON
00867  */
00868 int
00869 nmg_wedge_class(int ass, double a, double b)
00870                                 /* assessment of two edges forming wedge */
00871 
00872 
00873 {
00874         double  ha, hb;
00875         register int    ret;
00876 
00877         ha = a - 180;
00878         hb = b - 180;
00879 
00880         if( ass == NMG_V_COMB(NMG_E_ASSESSMENT_ON_FORW, NMG_E_ASSESSMENT_ON_FORW) )  {
00881                 ret = WEDGE_ON;
00882                 goto out;
00883         }
00884         if( ass == NMG_V_COMB(NMG_E_ASSESSMENT_ON_REV, NMG_E_ASSESSMENT_ON_REV) )  {
00885                 ret = WEDGE_ON;
00886                 goto out;
00887         }
00888 
00889         if( NEAR_ZERO( ha, .01 ) )  {
00890                 /* A is on the ray, within tol */
00891                 if( NEAR_ZERO( hb, .01 ) )  {
00892                         /* B is on the ray, within tol */
00893                         /* This is a 0-angle wedge entering & leaving.
00894                          * This is not WEDGE_ON
00895                          * Call it WEDGE_CROSS.
00896                          */
00897                         if(rt_g.NMG_debug&DEBUG_VU_SORT)
00898                                 bu_log("nmg_wedge_class() 0-angle wedge\n");
00899                         ret = WEDGE_CROSS;
00900                         goto out;
00901                 }
00902                 if( hb < 0 )  {
00903                         ret = WEDGE_RIGHT;
00904                         goto out;
00905                 }
00906                 ret = WEDGE_LEFT;
00907                 goto out;
00908         }
00909         if( ha < 0 )  {
00910                 /* A is to the right */
00911                 if( hb <= 0 )  {
00912                         ret = WEDGE_RIGHT;
00913                         goto out;
00914                 }
00915                 ret = WEDGE_CROSS;
00916                 goto out;
00917         }
00918         /* ha is > 0, A is to the left */
00919         if( NEAR_ZERO( hb, .01 ) )  {
00920                 /* A is left, B is ON_FORW (180) */
00921                 ret = WEDGE_LEFT;
00922                 goto out;
00923         }
00924         if( hb >= 0 )  {
00925                 /* A is left, B is LEFT */
00926                 ret = WEDGE_LEFT;
00927                 goto out;
00928         }
00929         /* A is left, B is RIGHT */
00930         ret = WEDGE_CROSS;
00931 out:
00932         if(rt_g.NMG_debug&DEBUG_VU_SORT)  {
00933                 bu_log("nmg_wedge_class(%g,%g) = %s\n",
00934                         a, b, WEDGECLASS2STR(ret) );
00935         }
00936         return ret;
00937 }
00938 
00939 static const char *nmg_wedge2_string[] = {
00940         "WEDGE2_OVERLAP",
00941         "WEDGE2_NO_OVERLAP",
00942         "WEDGE2_AB_IN_CD",
00943         "WEDGE2_CD_IN_AB",
00944         "WEDGE2_IDENTICAL",
00945         "WEDGE2_TOUCH_AT_BC",
00946         "WEDGE2_TOUCH_AT_DA",
00947         "WEDGE2_???"
00948 };
00949 #define WEDGE2_TO_STRING(_class2)       (nmg_wedge2_string[(_class2)+2])
00950 
00951 #define WEDGE2_OVERLAP          -2
00952 #define WEDGE2_NO_OVERLAP       -1
00953 #define WEDGE2_AB_IN_CD         0
00954 #define WEDGE2_CD_IN_AB         1
00955 #define WEDGE2_IDENTICAL        2
00956 #define WEDGE2_TOUCH_AT_BC      3
00957 #define WEDGE2_TOUCH_AT_DA      4
00958 
00959 /**
00960  *                      N M G _ C O M P A R E _ 2 _W E D G E S
00961  *
00962  *  Returns -
00963  *      WEDGE2_OVERLAP          AB partially overlaps CD (error)
00964  *      WEDGE2_NO_OVERLAP       AB does not overlap CD
00965  *      WEDGE2_AB_IN_CD         AB is inside CD
00966  *      WEDGE2_CD_IN_AB         CD is inside AB
00967  *      WEDGE2_IDENTICAL        AB == CD
00968  *      WEDGE2_TOUCH_AT_BC      AB touches CD at BC, but does not overlap
00969  *      WEDGE2_TOUCH_AT_DA      CD touches AB at DA, but does not overlap
00970  */
00971 static int
00972 nmg_compare_2_wedges(double a, double b, double c, double d)
00973 {
00974         double  t;
00975         int     a_in_cd = 0;
00976         int     b_in_cd = 0;
00977         int     c_in_ab = 0;
00978         int     d_in_ab = 0;
00979         int     a_eq_b = 0;
00980         int     a_eq_c = 0;
00981         int     a_eq_d = 0;
00982         int     b_eq_c = 0;
00983         int     b_eq_d = 0;
00984         int     c_eq_d = 0;
00985         int     ret;
00986 
00987 #define WEDGE_ANG_TOL   0.001   /* XXX Angular tolerance, in degrees */
00988 #define ANG_SMASH(_a)   {\
00989         if( _a <= WEDGE_ANG_TOL )  _a = 0; \
00990         else if( NEAR_ZERO( _a - 180, WEDGE_ANG_TOL ) )  _a = 180; \
00991         else if( _a >= 360 - WEDGE_ANG_TOL )  _a = 360; }
00992 
00993         ANG_SMASH(a);
00994         ANG_SMASH(b);
00995         ANG_SMASH(c);
00996         ANG_SMASH(d);
00997 
00998         /* Ensure A < B */
00999         if( a > b )  {
01000                 t = a;
01001                 a = b;
01002                 b = t;
01003         }
01004         /* Ensure that C < D */
01005         if( c > d )  {
01006                 t = c;
01007                 c = d;
01008                 d = t;
01009         }
01010 
01011         if( NEAR_ZERO( a-b, WEDGE_ANG_TOL ) )  a_eq_b = 1;
01012         if( NEAR_ZERO( a-c, WEDGE_ANG_TOL ) )  a_eq_c = 1;
01013         if( NEAR_ZERO( a-d, WEDGE_ANG_TOL ) )  a_eq_d = 1;
01014         if( NEAR_ZERO( b-c, WEDGE_ANG_TOL ) )  b_eq_c = 1;
01015         if( NEAR_ZERO( b-d, WEDGE_ANG_TOL ) )  b_eq_d = 1;
01016         if( NEAR_ZERO( c-d, WEDGE_ANG_TOL ) )  c_eq_d = 1;
01017 
01018         /*
01019          *  Test for TOUCHing wedges must come before INside test,
01020          *  so that zero-angle wedges that touch a non-zero angle wedge,
01021          *  will be properly recognized.  e.g. AB=(0,0) CD=(0,180).
01022          */
01023         if( b_eq_c )  {
01024                 /* Wedges touch along B-C junction */
01025                 if( a_eq_d )
01026                         ret = WEDGE2_IDENTICAL; /* two zero-angle wedges */
01027                 else
01028                         ret = WEDGE2_TOUCH_AT_BC;
01029                 goto out;
01030         }
01031 
01032         if( a_eq_d )  {
01033                 /* We know c <= d, d==a, a <= b */
01034                 if( b_eq_c )  {
01035                         ret = WEDGE2_IDENTICAL;
01036                         goto out;
01037                 }
01038                 if( a_eq_b )  {
01039                         ret = WEDGE2_AB_IN_CD;
01040                 } else if( c_eq_d )  {
01041                         ret = WEDGE2_CD_IN_AB;
01042                 } else {
01043                         ret = WEDGE2_TOUCH_AT_DA;
01044                 }
01045                 goto out;
01046         }
01047 
01048         if( a_eq_c )  {
01049                 if( b_eq_d )  {
01050                         ret = WEDGE2_IDENTICAL;
01051                         goto out;
01052                 }
01053                 /* We already know that A <= B, from sort above */
01054                 if( b < d )  ret = WEDGE2_AB_IN_CD;
01055                 else  ret = WEDGE2_CD_IN_AB;
01056                 goto out;
01057         }
01058 
01059         if( b_eq_d )  {
01060                 /* a != c, because of previous IF statement */
01061                 if( a < c )  ret = WEDGE2_CD_IN_AB;
01062                 else  ret = WEDGE2_AB_IN_CD;
01063                 goto out;
01064         }
01065 
01066         /* See if c < a,b < d */
01067         if( c <= a && a <= d )  a_in_cd = 1;
01068         if( c <= b && b <= d )  b_in_cd = 1;
01069         /* See if a < c,d < b */
01070         if( a < c && c < b )  c_in_ab = 1;
01071         if( a < d && d < b )  d_in_ab = 1;
01072 
01073         if( a_in_cd && b_in_cd )  {
01074                 if( c_in_ab || d_in_ab )  {
01075                         ret = WEDGE2_OVERLAP;   /* ERROR */
01076                         goto out;
01077                 }
01078                 ret = WEDGE2_AB_IN_CD;
01079                 goto out;
01080         }
01081         if( c_in_ab && d_in_ab )  {
01082                 if( a_in_cd || b_in_cd )  {
01083                         ret = WEDGE2_OVERLAP;   /* ERROR */
01084                         goto out;
01085                 }
01086                 ret = WEDGE2_CD_IN_AB;
01087                 goto out;
01088         }
01089         if( a_in_cd + b_in_cd + c_in_ab + d_in_ab <= 0 )  {
01090                 ret = WEDGE2_NO_OVERLAP;
01091                 goto out;
01092         }
01093         ret = WEDGE2_OVERLAP;                   /* ERROR */
01094 out:
01095         if(rt_g.NMG_debug&DEBUG_VU_SORT)  {
01096                 bu_log(" a_in_cd=%d, b_in_cd=%d, c_in_ab=%d, d_in_ab=%d\n",
01097                         a_in_cd, b_in_cd, c_in_ab, d_in_ab );
01098                 bu_log("nmg_compare_2_wedges(%g,%g, %g,%g) = %d %s\n",
01099                         a, b, c, d, ret, WEDGE2_TO_STRING(ret) );
01100         }
01101         if(ret <= WEDGE2_OVERLAP )  {
01102                 bu_log("nmg_compare_2_wedges(%g,%g, %g,%g) ERROR!\n", a, b, c, d);
01103                 rt_bomb("nmg_compare_2_wedges() ERROR\n");
01104         }
01105         return ret;
01106 }
01107 
01108 /**
01109  *                      N M G _ F I N D _ V U _ I N _ W E D G E
01110  *
01111  *  Find the VU which is inside (or on) the given wedge,
01112  *  fitting as tightly to the given wedge as possible,
01113  *  and with the lowest value of lo_ang possible.
01114  *  XXX how to do tie-breaking for the two coincident ones where
01115  *  XXX two loops come together.
01116  *
01117  *  lo_ang < hi_ang on RIGHT side of intersection line
01118  *  lo_ang > hi_ang on LEFT side of intersection line
01119  *
01120  *  There are three wedges involved here:
01121  *      the original one, from lo to hi,
01122  *      the current best "candidate" so far,
01123  *      and "this", the current one being considered.
01124  */
01125 static int
01126 nmg_find_vu_in_wedge(struct nmg_vu_stuff *vs, int start, int end, double lo_ang, double hi_ang, int wclass, int *skip_array)
01127 
01128                         /* vu index of coincident range */
01129 
01130 
01131 
01132 
01133 
01134 {
01135         register int    i;
01136         double  cand_lo;
01137         double  cand_hi;
01138         int     candidate;
01139 
01140         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01141                 bu_log("nmg_find_vu_in_wedge(start=%d,end=%d, lo=%g, hi=%g) START\n",
01142                         start, end, lo_ang, hi_ang);
01143 
01144         candidate = -1;
01145         cand_lo = lo_ang;
01146         cand_hi = hi_ang;
01147 
01148         /* Consider all the candidates */
01149         for( i=start; i < end; i++ )  {
01150                 int     this_wrt_orig;
01151                 int     this_wrt_cand;
01152 
01153                 NMG_CK_VERTEXUSE( vs[i].vu );
01154                 if( skip_array[i] )  {
01155                         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01156                                 bu_log("Skipping index %d\n", i);
01157                         continue;
01158                 }
01159 
01160                 /* Ignore wedges crossing, or on other side of line */
01161                 if( vs[i].wedge_class != wclass && vs[i].wedge_class != WEDGE_ON )  {
01162                         if(rt_g.NMG_debug&DEBUG_VU_SORT)  {
01163                                 bu_log("Seeking wedge_class=%s, [%d] has wedge_class %s\n",
01164                                         WEDGECLASS2STR(wclass), i, WEDGECLASS2STR(vs[i].wedge_class) );
01165                         }
01166                         continue;
01167                 }
01168 
01169                 if( vs[i].wedge_class == WEDGE_ON )  {
01170                         /* Ensure that comparisons will work */
01171                         if( wclass == WEDGE_RIGHT )  {
01172                                 vs[i].lo_ang = 0;
01173                                 vs[i].hi_ang = 180;
01174                         } else {
01175                                 vs[i].lo_ang = 360;
01176                                 vs[i].hi_ang = 180;
01177                         }
01178                 }
01179 
01180                 this_wrt_orig = nmg_compare_2_wedges(
01181                         vs[i].lo_ang, vs[i].hi_ang,
01182                         lo_ang, hi_ang );
01183                 switch( this_wrt_orig )  {
01184                 case WEDGE2_AB_IN_CD:
01185                         break;
01186                 case WEDGE2_IDENTICAL:
01187                         candidate = i;
01188                         goto out;
01189                 default:
01190                         continue;       /* not inside wedge */
01191                 }
01192 
01193                 if( candidate < 0 ) {
01194                         /* This wedge AB is inside original wedge.
01195                          * If candidate is -1, use AB as candidate.
01196                          */
01197                         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01198                                 bu_log("Initial candidate %d selected\n", i);
01199                         candidate = i;
01200                         cand_lo = vs[i].lo_ang;
01201                         cand_hi = vs[i].hi_ang;
01202                         continue;
01203                 }
01204 
01205                 this_wrt_cand = nmg_compare_2_wedges(
01206                         vs[i].lo_ang, vs[i].hi_ang,
01207                         cand_lo, cand_hi );
01208                 switch( this_wrt_cand )  {
01209                 case WEDGE2_CD_IN_AB:
01210                         /* This wedge AB contains candidate wedge CD, therefore
01211                          * this wedge is closer to original wedge */
01212                         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01213                                 bu_log("This candidate %d is closer\n", i);
01214                         candidate = i;
01215                         cand_lo = vs[i].lo_ang;
01216                         cand_hi = vs[i].hi_ang;
01217                         break;
01218                 case WEDGE2_NO_OVERLAP:
01219                         /* No overlap, but both are inside.  Take lower angle */
01220                         if( vs[i].lo_ang < cand_lo )  {
01221                         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01222                                 bu_log("Taking lower angle %d\n", i);
01223                                 candidate = i;
01224                                 cand_lo = vs[i].lo_ang;
01225                                 cand_hi = vs[i].hi_ang;
01226                         }
01227                         break;
01228                 default:
01229                         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01230                                 bu_log("Continuing with search\n");
01231                         continue;
01232                 }
01233         }
01234 out:
01235         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01236                 bu_log("nmg_find_vu_in_wedge(start=%d,end=%d, lo=%g, hi=%g) END candidate=%d\n",
01237                         start, end, lo_ang, hi_ang,
01238                         candidate);
01239         return candidate;       /* is -1 if none found */
01240 }
01241 
01242 /**
01243  *                      N M G _ I S _ W E D G E _ B E F O R E _ C R O S S
01244  *
01245  *  Determine if the 'wedge' vu, which is either a LEFT or RIGHT wedge,
01246  *  should be processed before or after the 'cross' vu, which is a
01247  *  CROSS wedge.
01248  *
01249  *  Returns -
01250  *      1       if wedge should be processed before cross
01251  *      0       if cross should be processed before wedge
01252  */
01253 static int
01254 nmg_is_wedge_before_cross(const struct nmg_vu_stuff *wedge, const struct nmg_vu_stuff *cross)
01255 {
01256         int     class2;
01257         int     ret = -1;
01258 
01259         if( cross->wedge_class != WEDGE_CROSS || wedge->wedge_class == WEDGE_CROSS )
01260                 rt_bomb("nmg_is_wedge_before_cross() bad input\n");
01261 
01262         /* LEFT/RIGHT Wedge is (AB), CROSS wedge is (CD) */
01263         class2 = nmg_compare_2_wedges( wedge->lo_ang, wedge->hi_ang,
01264                 cross->lo_ang, cross->hi_ang );
01265 
01266         switch(class2)  {
01267         default:
01268                 bu_log("nmg_is_wedge_before_cross() class2=%s\n",
01269                         WEDGE2_TO_STRING(class2) );
01270                 rt_bomb("nmg_is_wedge_before_cross(): bad wedge comparison\n");
01271         case WEDGE2_NO_OVERLAP:
01272                 /* wedge is not inside cross, cross is not inside wedge. */
01273                 /* Do wedge first */
01274                 ret = 1;
01275                 break;
01276         case WEDGE2_TOUCH_AT_BC:
01277                 /* Should only happen when wedge is WEDGE_RIGHT */
01278                 if( wedge->wedge_class != WEDGE_RIGHT )
01279                         rt_bomb("WEDGE not RIGHT with WEDGE2_TOUCH_AT_BC?\n");
01280                 ret = 1;
01281                 break;
01282         case WEDGE2_TOUCH_AT_DA:
01283                 /* Should only happen when wedge is WEDGE_LEFT */
01284                 if( wedge->wedge_class != WEDGE_LEFT )
01285                         rt_bomb("WEDGE not LEFT with WEDGE2_TOUCH_AT_DA?\n");
01286                 ret = 1;
01287                 break;
01288         case WEDGE2_AB_IN_CD:
01289                 /* 'wedge' is inside the 'cross' wedge, do it second. */
01290                 ret = 0;
01291                 break;
01292         }
01293         if(rt_g.NMG_debug&DEBUG_VU_SORT)  {
01294                 bu_log("nmg_is_wedge_before_cross() class2=%s, ret=%d\n",
01295                         WEDGE2_TO_STRING(class2), ret );
01296         }
01297         return ret;
01298 }
01299 
01300 /**
01301  *                      N M G _ F A C E _ V U _ C O M P A R E
01302  *
01303  *  Support routine for nmg_face_coincident_vu_sort(), via qsort().
01304  *
01305  *  It is important to note that an edge on the LEFT side of the ray
01306  *  will have a "lo" angle which is numerically LARGER than the "hi" angle.
01307  *  However, all are measured in the usual units:
01308  *  0 = ON_REV, 90 = RIGHT, 180 = ON_FORW, 270 = LEFT.
01309  *
01310  *  Returns -
01311  *      -1      when A < B
01312  *       0      when A == B
01313  *      +1      when A > B
01314  */
01315 #define A_LT_B          {ret = -1; goto out;}
01316 #define AB_EQUAL        {ret = 0; goto out;}
01317 #define A_GT_B          {ret = 1; goto out;}
01318 static int
01319 nmg_face_vu_compare(const void *aa, const void *bb)
01320 #if __STDC__
01321 
01322 
01323 #else
01324 
01325 
01326 #endif
01327 {
01328         register const struct nmg_vu_stuff *a = (const struct nmg_vu_stuff *)aa;
01329         register const struct nmg_vu_stuff *b = (const struct nmg_vu_stuff *)bb;
01330         register double diff;
01331         int     lo_equal = 0;
01332         int     hi_equal = 0;
01333         register int    ret = 0;
01334 
01335         lo_equal = NEAR_ZERO( a->lo_ang - b->lo_ang, WEDGE_ANG_TOL );
01336         hi_equal = NEAR_ZERO( a->hi_ang - b->hi_ang, WEDGE_ANG_TOL );
01337         /* If both have the same assessment & angles match, => tie */
01338         if( a->wedge_class == b->wedge_class && lo_equal && hi_equal ) {
01339                 /* Break the tie */
01340 tie_break:
01341                 if( a->loop_index == b->loop_index )  {
01342                         /* Within a loop, sort by vu sequence number */
01343                         if( a->seq < b->seq )  A_LT_B;
01344                         if( a->seq == b->seq )  AB_EQUAL;
01345                         A_GT_B;
01346                 }
01347                 /* Select smallest inbound angle */
01348                 diff = a->in_vu_angle - b->in_vu_angle;
01349                 if( NEAR_ZERO( diff, WEDGE_ANG_TOL ) )  {
01350                         /* Gak, this really means trouble! */
01351                         bu_log("nmg_face_vu_compare(): two loops (single vertex) have same in_vu_angle%g?\n",
01352                                 a->in_vu_angle);
01353                         nmg_pr_vu_stuff(a);
01354                         nmg_pr_vu_stuff(b);
01355                         rt_bomb("nmg_face_vu_compare():  can't decide\n");
01356                         AB_EQUAL;
01357                 }
01358                 if( diff < 0 )  A_LT_B;
01359                 A_GT_B;
01360         }
01361         switch( a->wedge_class )  {
01362         case WEDGE_ON:
01363                 switch( b->wedge_class )  {
01364                 case WEDGE_ON:
01365                         goto tie_break;
01366                 default:
01367                         nmg_pr_vu_stuff(a);
01368                         nmg_pr_vu_stuff(b);
01369                         rt_bomb("nmg_face_vu_compare() WEDGE_ON 1?\n");
01370                 }
01371                 break;
01372         case WEDGE_LEFT:
01373                 switch( b->wedge_class )  {
01374                 case WEDGE_LEFT:
01375                         if( lo_equal )  {
01376                                 /* hi_equal case handled above */
01377                                 if( a->hi_ang < b->hi_ang ) A_LT_B;
01378                                 A_GT_B;
01379                         }
01380                         if( a->lo_ang > b->lo_ang )  A_LT_B;
01381                         A_GT_B;
01382                 case WEDGE_CROSS:
01383                         /* A is LEFT, B is CROSS */
01384                         if( nmg_is_wedge_before_cross( a, b ) )  A_LT_B;
01385                         A_GT_B;
01386                 case WEDGE_RIGHT:
01387                         diff = 360 - a->lo_ang;/* CW version of left angle */
01388                         if( b->lo_ang <= diff )  A_GT_B;
01389                         A_LT_B;
01390                 case WEDGE_ON:
01391                         nmg_pr_vu_stuff(a);
01392                         nmg_pr_vu_stuff(b);
01393                         rt_bomb("nmg_face_vu_compare() WEDGE_ON 2?\n");
01394                 }
01395         case WEDGE_CROSS:
01396                 switch( b->wedge_class )  {
01397                 case WEDGE_LEFT:
01398                         /* A (AB) is CROSS, (CD) is LEFT */
01399                         if( nmg_is_wedge_before_cross( b, a ) )  A_GT_B;
01400                         A_LT_B;
01401                 case WEDGE_CROSS:
01402                         if( lo_equal )  {
01403                                 if( a->hi_ang > b->hi_ang )  A_LT_B;
01404                                 A_GT_B;
01405                         }
01406                         if( a->lo_ang < b->lo_ang )  A_LT_B;
01407                         A_GT_B;
01408                 case WEDGE_RIGHT:
01409                         /* A is CROSS, B is RIGHT */
01410                         if( nmg_is_wedge_before_cross( b, a ) )  A_GT_B;
01411                         A_LT_B;
01412                 case WEDGE_ON:
01413                         nmg_pr_vu_stuff(a);
01414                         nmg_pr_vu_stuff(b);
01415                         rt_bomb("nmg_face_vu_compare() WEDGE_ON 3?\n");
01416                 }
01417         case WEDGE_RIGHT:
01418                 switch( b->wedge_class )  {
01419                 case WEDGE_LEFT:
01420                         diff = 360 - b->lo_ang;/* CW version of left angle */
01421                         if( a->lo_ang <= diff )  A_LT_B;
01422                         A_GT_B;
01423                 case WEDGE_CROSS:
01424                         /* A is RIGHT, B is CROSS */
01425                         if( nmg_is_wedge_before_cross( a, b ) )  A_LT_B;
01426                         A_GT_B;
01427                 case WEDGE_RIGHT:
01428                         if( lo_equal )  {
01429                                 if( a->hi_ang < b->hi_ang )  A_GT_B;
01430                                 A_LT_B;
01431                         }
01432                         if( a->lo_ang < b->lo_ang )  A_LT_B;
01433                         A_GT_B;
01434                 case WEDGE_ON:
01435                         nmg_pr_vu_stuff(a);
01436                         nmg_pr_vu_stuff(b);
01437                         rt_bomb("nmg_face_vu_compare() WEDGE_ON 4?\n");
01438                 }
01439         }
01440 out:
01441         if(rt_g.NMG_debug&DEBUG_VU_SORT)  {
01442                 bu_log("nmg_face_vu_compare(vu=x%x, vu=x%x) %s %s, %s\n",
01443                         a->vu, b->vu,
01444                         WEDGECLASS2STR(a->wedge_class),
01445                         WEDGECLASS2STR(b->wedge_class),
01446                         ret==(-1) ? "A<B" : (ret==0 ? "A==B" : "A>B") );
01447         }
01448         return ret;
01449 }
01450 
01451 /**
01452  *                      N M G _ F A C E _ V U _ D O T
01453  *
01454  *  For the purpose of computing the dot product of the edges around
01455  *  this vertexuse and the ray direction vector, the edge vectors should
01456  *  both be pointing inwards to the vertex,
01457  *  rather than in the edge direction, so that it is possible to sort
01458  *  the vertexuse's into sequence by "angle" along the ray direction,
01459  *  starting with the vertexuse that the ray first encounters.
01460  */
01461 static void
01462 nmg_face_vu_dot(struct nmg_vu_stuff *vsp, struct loopuse *lu, const struct nmg_ray_state *rs, int ass)
01463 {
01464         struct edgeuse  *this_eu;
01465         struct edgeuse  *othereu;
01466         vect_t          vec;
01467         fastf_t         dot;
01468         struct vertexuse        *vu;
01469         int             this;
01470 
01471         NMG_CK_RAYSTATE(rs);
01472         vu = vsp->vu;
01473         NMG_CK_VERTEXUSE(vu);
01474         NMG_CK_LOOPUSE(lu);
01475         this_eu = nmg_find_eu_with_vu_in_lu( lu, vu );
01476 
01477         /* First, consider the edge inbound into this vertex */
01478         this = NMG_V_ASSESSMENT_PREV(ass);
01479         if( this == NMG_E_ASSESSMENT_ON_REV )  {
01480                 vsp->min_vu_dot = -1;           /* straight back */
01481         } else if( this == NMG_E_ASSESSMENT_ON_FORW )  {
01482                 vsp->min_vu_dot = 1;            /* straight forw */
01483         } else {
01484                 othereu = BU_LIST_PPREV_CIRC( edgeuse, this_eu );
01485                 if( vu->v_p != othereu->vu_p->v_p )  {
01486                         /* Vector from othereu to this_eu */
01487                         VSUB2( vec, vu->v_p->vg_p->coord,
01488                                 othereu->vu_p->v_p->vg_p->coord );
01489                         VUNITIZE(vec);
01490                         vsp->min_vu_dot = VDOT( vec, rs->dir );
01491                 } else {
01492                         vsp->min_vu_dot = 99;           /* larger than +1 */
01493                 }
01494         }
01495 
01496         /* Second, consider the edge outbound from this vertex (forw) */
01497         this = NMG_V_ASSESSMENT_NEXT(ass);
01498         if( this == NMG_E_ASSESSMENT_ON_REV )  {
01499                 dot = -1;               /* straight back */
01500                 if( dot < vsp->min_vu_dot )  vsp->min_vu_dot = dot;
01501         } else if( this == NMG_E_ASSESSMENT_ON_FORW )  {
01502                 dot = 1;                /* straight forw */
01503                 if( dot < vsp->min_vu_dot )  vsp->min_vu_dot = dot;
01504         } else {
01505                 othereu = BU_LIST_PNEXT_CIRC( edgeuse, this_eu );
01506                 if( vu->v_p != othereu->vu_p->v_p )  {
01507                         /* Vector from othereu to this_eu */
01508                         VSUB2( vec, vu->v_p->vg_p->coord,
01509                                 othereu->vu_p->v_p->vg_p->coord );
01510                         VUNITIZE(vec);
01511                         dot = VDOT( vec, rs->dir );
01512                         if( dot < vsp->min_vu_dot )  {
01513                                 vsp->min_vu_dot = dot;
01514                         }
01515                 }
01516         }
01517 }
01518 
01519 /**
01520  *                      N M G _ S P E C I A L _ W E D G E _ P R O C E S S I N G
01521  *
01522  *  If one loop gets cut, then unwind the whole call stack, and reassess
01523  *  where things stand.  (The caller needs to re-call in that case).
01524  *
01525  *  The goal here is to get rid of nested wedges.
01526  *  To do that, join loops wherever possible, cut them sparingly.
01527  *
01528  *  Returns -
01529  *      0       Nothing needed changing, OK to proceed with vertex sorting.
01530  *      1       Loops were cut or joined, need to reclassify everything
01531  *              at this vertexuse.
01532  */
01533 static int
01534 nmg_special_wedge_processing(struct nmg_vu_stuff *vs, int start, int end, double lo_ang, double hi_ang, int wclass, int *exclude, const struct bn_tol *tol)
01535 
01536                         /* vu index of coincident range */
01537 
01538 
01539 
01540 
01541 
01542 
01543 {
01544         register int    i;
01545         int             outer_wedge;
01546         int             inner_wedge;
01547         int             class2;
01548         struct loopuse  *outer_lu;
01549         struct loopuse  *inner_lu;
01550         int             not_these[128];
01551 
01552         BN_CK_TOL(tol);
01553 
01554         if(rt_g.NMG_debug&DEBUG_VU_SORT)  {
01555                 char                    buf[128];
01556                 FILE                    *fp;
01557                 struct model            *m;
01558                 long                    *b;
01559                 struct bn_vlblock       *vbp;
01560                 static int              num = 0;
01561 
01562                 bu_log("nmg_special_wedge_processing(start=%d,end=%d, lo=%g, hi=%g, wclass=%s)\n",
01563                         start, end, lo_ang, hi_ang,
01564                         WEDGECLASS2STR(wclass) );
01565                 VPRINT("\tvertex", vs[start].vu->v_p->vg_p->coord);
01566 
01567                 /* Plot all the loops that touch here. */
01568                 m = nmg_find_model((long *)vs[start].vu);
01569                 b = (long *)bu_calloc( m->maxindex, sizeof(long), "nmg_special_wedge_processing flag[]" );
01570                 vbp = rt_vlblock_init();
01571                 for( i=start; i < end; i++ )  {
01572                         struct loopuse  *lu;
01573                         lu = nmg_find_lu_of_vu(vs[i].vu);
01574                         bu_log("\tvu[%d]=x%x, lu=x%x\n", i, vs[i].vu, lu);
01575                         nmg_vlblock_lu(vbp, lu, b, 255, 0, 0, 0, 0 );
01576                 }
01577                 for( i=start; i < end; i++ )  {
01578                         struct loopuse  *lu;
01579                         lu = nmg_find_lu_of_vu(vs[i].vu);
01580                         nmg_pr_lu_briefly(lu,0);
01581                 }
01582                 sprintf(buf, "wedge%d.pl", num++);
01583                 fp = fopen(buf, "w");
01584                 rt_plot_vlblock( fp, vbp );
01585                 fclose(fp);
01586                 bu_log("wrote %s\n", buf);
01587                 bu_free( (char *)b, "nmg_special_wedge_processing flag[]" );
01588                 rt_vlblock_free(vbp);
01589         }
01590 
01591         if( end-start >= 128 )  rt_bomb("nmg_special_wedge_processing: array overflow\n");
01592         if( !exclude )  {
01593                 bzero( (char *)not_these, sizeof(not_these) );
01594                 exclude = not_these;
01595         }
01596 
01597 again:
01598         /* May be many "outer" wedges to iterate over this side of line */
01599         outer_wedge = nmg_find_vu_in_wedge( vs, start, end,
01600                 lo_ang, hi_ang, wclass, exclude );
01601         if( outer_wedge <= -1 )  return 0;      /* No wedges to process */
01602 
01603         exclude[outer_wedge] = 1;       /* Don't return this wedge again */
01604 
01605         /* There is at least one wedge on this side of the line */
01606         outer_lu = nmg_find_lu_of_vu( vs[outer_wedge].vu );
01607         NMG_CK_LOOPUSE(outer_lu);
01608 
01609 again_inner:
01610         inner_wedge = nmg_find_vu_in_wedge( vs, start, end,
01611                 vs[outer_wedge].lo_ang, vs[outer_wedge].hi_ang,
01612                 wclass, exclude );
01613         if( inner_wedge <= -1 )  {
01614                 /*
01615                  *  See if there is another outer wedge that starts where
01616                  *  outer_wedge left off.
01617                  *  exclude[outer_wedge] is already set.
01618                  */
01619                 goto again;
01620         }
01621         if( inner_wedge == outer_wedge )  rt_bomb("nmg_special_wedge_processing() identical vu selections?\n");
01622 
01623         class2 = nmg_compare_2_wedges( vs[outer_wedge].lo_ang, vs[outer_wedge].hi_ang,
01624                 vs[inner_wedge].lo_ang, vs[inner_wedge].hi_ang );
01625         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01626                 bu_log("+++nmg_special_wedge_processing() outer=%d, inner=%d, class2=%s\n", outer_wedge, inner_wedge, WEDGE2_TO_STRING(class2) );
01627 
01628         inner_lu = nmg_find_lu_of_vu( vs[inner_wedge].vu );
01629         NMG_CK_LOOPUSE(inner_lu);
01630 
01631         if( outer_lu == inner_lu )  {
01632                 struct loopuse  *new_lu;
01633                 if( class2 == WEDGE2_IDENTICAL &&
01634                     NEAR_ZERO( vs[inner_wedge].hi_ang - vs[inner_wedge].lo_ang, WEDGE_ANG_TOL )
01635                     )  {
01636 #if 0
01637 rt_g.NMG_debug |= DEBUG_VU_SORT|DEBUG_FCUT;
01638 #endif
01639                         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01640                                 bu_log("nmg_special_wedge_processing:  inner and outer wedges from same loop, WEDGE2_IDENTICAL & 0deg spread, already in final form.\n");
01641                         exclude[inner_wedge] = 1;       /* Don't return this wedge again */
01642                         /* Don't need to recurse only because this is a crack */
01643                         goto again_inner;
01644                 }
01645                 if(rt_g.NMG_debug&DEBUG_VU_SORT)
01646                         bu_log("nmg_special_wedge_processing:  inner and outer wedges from same loop, cutting loop\n");
01647                 new_lu = nmg_cut_loop( vs[outer_wedge].vu, vs[inner_wedge].vu );
01648                 NMG_CK_LOOPUSE(new_lu);
01649                 NMG_CK_LOOPUSE(inner_lu);
01650                 nmg_loop_g( inner_lu->l_p, tol );
01651                 nmg_loop_g( new_lu->l_p, tol );
01652                 nmg_lu_reorient(inner_lu);
01653                 nmg_lu_reorient(new_lu);
01654                 return 1;               /* cutjoin was done */
01655         }
01656 
01657         /* XXX Or they could be WEDGE2_IDENTICAL */
01658         /* XXX If WEDGE2_IDENTICAL, could we join and then simplify? */
01659         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01660                 bu_log("wedge at vu[%d] is inside wedge at vu[%d]\n", inner_wedge, outer_wedge);
01661 
01662         if( outer_lu->orientation == inner_lu->orientation )  {
01663                 /*
01664                  *  Two loops meet at this vu.  Joining them will impose
01665                  *  a natural edgeuse ordering onto the vu's.
01666                  */
01667                 if(rt_g.NMG_debug&DEBUG_VU_SORT)
01668                         bu_log("joining loops\n");
01669                 vs[inner_wedge].vu = nmg_join_2loops( vs[outer_wedge].vu,
01670                         vs[inner_wedge].vu );
01671                 nmg_loop_g( outer_lu->l_p, tol );
01672                 return 1;               /* cutjoin was done */
01673         }
01674 
01675         /* Recurse on inner wedge */
01676         if( nmg_special_wedge_processing( vs, start, end,
01677             vs[inner_wedge].lo_ang, vs[inner_wedge].hi_ang, wclass, exclude, tol ) )
01678                 return 1;       /* An inner wedge was cut */
01679 
01680         /*
01681          *  Inner and outer are different loopuses,
01682          *  have different orientations,
01683          *  and have nothing complex inside the wedge of the inner loop.
01684          *  Join inner and outer loops here, to impose a proper vu ordering.
01685          */
01686         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01687                 bu_log("Inner wedge is simple, join inner and outer loops.\n");
01688 
01689         vs[inner_wedge].vu = nmg_join_2loops( vs[outer_wedge].vu,
01690                 vs[inner_wedge].vu );
01691         nmg_loop_g( outer_lu->l_p, tol );
01692         return 1;               /* cutjoin was done */
01693 }
01694 
01695 /**
01696  *                      N M G _ F A C E _ C O I N C I D E N T _ V U _ S O R T
01697  *
01698  *  Given co-incident vertexuses (same distance along the ray),
01699  *  sort them into the "proper" order for driving the state machine.
01700  */
01701 int
01702 nmg_face_coincident_vu_sort(struct nmg_ray_state *rs, int start, int end)
01703 
01704                                         /* first index */
01705                                         /* last index + 1 */
01706 {
01707         int             num;
01708         struct nmg_vu_stuff     *vs;
01709         struct nmg_loop_stuff *ls;
01710         int             nloop;
01711         unsigned        nvu;
01712         int             i;
01713         struct loopuse  *lu;
01714         int             ass;
01715         int             l;
01716         int             retries = 0;
01717 
01718         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01719                 bu_log("nmg_face_coincident_vu_sort(, %d, %d) START\n", start, end);
01720 
01721         NMG_CK_RAYSTATE(rs);
01722 
01723         num = end - start;
01724         vs = (struct nmg_vu_stuff *)bu_malloc( sizeof(struct nmg_vu_stuff)*num,
01725                 "nmg_vu_stuff" );
01726         ls = (struct nmg_loop_stuff *)bu_malloc( sizeof(struct nmg_loop_stuff)*num,
01727                 "nmg_loop_stuff" );
01728 
01729 top:
01730 #if 0
01731         if( retries > 20 )  rt_g.NMG_debug |= DEBUG_VU_SORT;
01732 #endif
01733         if( retries++ > 24 )  rt_bomb("nmg_face_coincident_vu_sort() infinite loop\n");
01734         /* Assess each vu, create list of loopuses, find max angles */
01735         nloop = 0;
01736         nvu = 0;
01737         for( i = end-1; i >= start; i-- )  {
01738                 lu = nmg_find_lu_of_vu( rs->vu[i] );
01739                 NMG_CK_LOOPUSE(lu);
01740                 ass = nmg_assess_vu( rs, i );
01741                 if(rt_g.NMG_debug&DEBUG_VU_SORT)
01742                    bu_log("vu[%d]=x%x v=x%x assessment=%s\n",
01743                         i, rs->vu[i], rs->vu[i]->v_p, nmg_v_assessment_names[ass] );
01744                 /*  Ignore lone vertices, unless that is all that there is,
01745                  *  in which case, let just one through.  (return 'start+1');
01746                  */
01747                 if( *(rs->vu[i]->up.magic_p) == NMG_LOOPUSE_MAGIC )  {
01748                         if( nvu > 0 || i > start )  {
01749                                 /* Drop this loop of a single vertex in sanitize() */
01750                                 lu->orientation =
01751                                   lu->lumate_p->orientation = OT_BOOLPLACE;
01752                                 /* "continue" keeps vu from being added to vs[] */
01753                                 continue;
01754                         }
01755                 }
01756 
01757                 vs[nvu].vu = rs->vu[i];
01758                 vs[nvu].seq = -1;               /* Not assigned yet */
01759 
01760                 /* x_dir is -dir, y_dir is -left */
01761                 vs[nvu].in_vu_angle = nmg_vu_angle_measure( rs->vu[i],
01762                         rs->ang_x_dir, rs->ang_y_dir, ass, 1 ) * bn_radtodeg;
01763                 vs[nvu].out_vu_angle = nmg_vu_angle_measure( rs->vu[i],
01764                         rs->ang_x_dir, rs->ang_y_dir, ass, 0 ) * bn_radtodeg;
01765 
01766                 /* Special case for LEFT & ON combos */
01767                 if( ass == NMG_V_COMB(NMG_E_ASSESSMENT_ON_FORW, NMG_E_ASSESSMENT_LEFT) )
01768                         vs[nvu].in_vu_angle = 360;
01769                 else if( ass == NMG_V_COMB(NMG_E_ASSESSMENT_LEFT, NMG_E_ASSESSMENT_ON_REV) )
01770                         vs[nvu].out_vu_angle = 360;
01771 
01772                 vs[nvu].wedge_class = nmg_wedge_class( ass, vs[nvu].in_vu_angle, vs[nvu].out_vu_angle );
01773                 if(rt_g.NMG_debug&DEBUG_VU_SORT) bu_log("nmg_wedge_class = %d %s\n", vs[nvu].wedge_class, WEDGECLASS2STR(vs[nvu].wedge_class));
01774                 /* Sort the angles (Don't forget to sort for CROSS case too) */
01775                 if( (vs[nvu].wedge_class == WEDGE_LEFT && vs[nvu].in_vu_angle > vs[nvu].out_vu_angle) ||
01776                     (vs[nvu].wedge_class != WEDGE_LEFT && vs[nvu].in_vu_angle < vs[nvu].out_vu_angle) )  {
01777                         vs[nvu].lo_ang = vs[nvu].in_vu_angle;
01778                         vs[nvu].hi_ang = vs[nvu].out_vu_angle;
01779                 } else {
01780                         vs[nvu].lo_ang = vs[nvu].out_vu_angle;
01781                         vs[nvu].hi_ang = vs[nvu].in_vu_angle;
01782                 }
01783 
01784                 /* Check entering and departing edgeuse angle w.r.t. ray */
01785                 /* This is already done once in nmg_assess_vu();  reuse? */
01786                 /* Computes vs[nvu].min_vu_dot */
01787                 nmg_face_vu_dot( &vs[nvu], lu, rs, ass );
01788 
01789                 /* Search for loopuse table entry */
01790                 for( l = 0; l < nloop; l++ )  {
01791                         if( ls[l].lu == lu )  goto got_loop;
01792                 }
01793                 /* didn't find loopuse in table, add to table */
01794                 l = nloop++;
01795                 ls[l].lu = lu;
01796                 ls[l].n_vu_in_loop = 0;
01797                 ls[l].min_dot = 99;             /* > +1 */
01798 got_loop:
01799                 ls[l].n_vu_in_loop++;
01800                 vs[nvu].loop_index = l;
01801                 vs[nvu].lsp = &ls[l];
01802                 if( vs[nvu].min_vu_dot < ls[l].min_dot )  {
01803                         ls[l].min_dot = vs[nvu].min_vu_dot;
01804                         ls[l].min_vu = vs[nvu].vu;
01805                 }
01806                 nvu++;
01807         }
01808 
01809         /*
01810          *  For each loop which has more than one vertexuse present on the
01811          *  ray, start at the vu which has the smallest angle off the ray,
01812          *  and walk the edges of the loop, marking off the vu sequence for
01813          *  those vu's on the ray (those vu's found in vs[].vu).
01814          */
01815         for( l=0; l < nloop; l++ )  {
01816                 register struct edgeuse *eu;
01817                 struct edgeuse  *first_eu;
01818                 int             seq = 0;
01819 
01820                 if( ls[l].n_vu_in_loop <= 1 )  continue;
01821 
01822                 first_eu = nmg_find_eu_with_vu_in_lu( ls[l].lu, ls[l].min_vu );
01823                 eu = first_eu;
01824                 do {
01825                         register struct vertexuse *vu = eu->vu_p;
01826                         NMG_CK_VERTEXUSE(vu);
01827                         for( i=0; i < nvu; i++ )  {
01828                                 if( vs[i].vu == vu )  {
01829                                         vs[i].seq = seq++;
01830                                         break;
01831                                 }
01832                         }
01833                         eu = BU_LIST_PNEXT_CIRC(edgeuse,eu);
01834                 } while( eu != first_eu );
01835         }
01836 
01837         /* For loops with >1 crossings here, determine proper VU ordering on that loop */
01838         /* XXX */
01839 
01840         /* Here is where the special wedge-breaking code goes */
01841         if( nmg_special_wedge_processing( vs, 0, nvu, 0.0, 180.0, WEDGE_RIGHT, (int *)0, rs->tol ) )  {
01842                 if(rt_g.NMG_debug&DEBUG_VU_SORT)
01843                         bu_log("*** nmg_face_coincident_vu_sort(, %d, %d) restarting after 0--180 wedge\n", start, end);
01844                 goto top;
01845         }
01846         /* XXX reclass on/on edges from WEDGE_RIGHT to WEDGE_LEFT here? */
01847         if( nmg_special_wedge_processing( vs, 0, nvu, 360.0, 180.0, WEDGE_LEFT, (int *)0, rs->tol ) ) {
01848                 if(rt_g.NMG_debug&DEBUG_VU_SORT)
01849                         bu_log("*** nmg_face_coincident_vu_sort(, %d, %d) restarting after 180-360 wedge\n", start, end);
01850                 goto top;
01851         }
01852 
01853         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01854         {
01855                 bu_log("Loop table (before sort):\n");
01856                 for( l=0; l < nloop; l++ )  {
01857                         bu_log("  index=%d, lu=x%x, min_dot=%g, #vu=%d\n",
01858                                 l, ls[l].lu, ls[l].min_dot,
01859                                 ls[l].n_vu_in_loop );
01860                 }
01861         }
01862 
01863         /* Sort the vertexuse table into appropriate order */
01864         qsort( (genptr_t)vs, (unsigned)nvu, (unsigned)sizeof(*vs),
01865                 nmg_face_vu_compare );
01866 
01867         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01868         {
01869                 bu_log("Vertexuse table (after sort):\n");
01870                 for( i=0; i < nvu; i++ )  {
01871                         bu_log("  x%x, l=%d, in/o=(%g, %g), lo/hi=(%g,%g), %s, sq=%d\n",
01872                                 vs[i].vu, vs[i].loop_index,
01873                                 vs[i].in_vu_angle, vs[i].out_vu_angle,
01874                                 vs[i].lo_ang, vs[i].hi_ang,
01875                                 WEDGECLASS2STR(vs[i].wedge_class),
01876                                 vs[i].seq );
01877                 }
01878         }
01879 
01880         /* Copy new vu's back to main array */
01881 #if 0
01882         /* XXX I'm not sure if this is right or not */
01883         if( rs->state == NMG_STATE_IN )  {
01884                 /*
01885                  *  If the state is IN, then need to traverse the vertexuse's
01886                  *  in the opposite order.
01887                  *  All the sorting is done from the point of view of
01888                  *  being in OUT state.
01889                  */
01890                 if(rt_g.NMG_debug&DEBUG_VU_SORT)
01891                         bu_log("Reversed processing order, state=IN.\n");
01892                 for( i=0; i < nvu; i++ )  {
01893                         rs->vu[start+i] = vs[nvu-1-i].vu;
01894                 }
01895         } else
01896 #endif
01897         {
01898                 for( i=0; i < nvu; i++ )  {
01899                         rs->vu[start+i] = vs[i].vu;
01900                 }
01901         }
01902         if(rt_g.NMG_debug&DEBUG_VU_SORT)  {
01903                 for( i=0; i < nvu; i++ )  {
01904                         bu_log(" vu[%d]=x%x, v=x%x\n",
01905                                 start+i, rs->vu[start+i], rs->vu[start+i]->v_p );
01906                 }
01907         }
01908 
01909         bu_free( (char *)vs, "nmg_vu_stuff");
01910         bu_free( (char *)ls, "nmg_loop_stuff");
01911 
01912         if(rt_g.NMG_debug&DEBUG_VU_SORT)
01913                 bu_log("nmg_face_coincident_vu_sort(, %d, %d) END, ret=%d\n", start, end, start+nvu);
01914 
01915         return start+nvu;
01916 }
01917 
01918 /**
01919  *                      N M G _ S A N I T I Z E _ F U
01920  *
01921  *  Eliminate any OT_BOOLPLACE self-loops that remain behind in this face.
01922  */
01923 void
01924 nmg_sanitize_fu(struct faceuse *fu)
01925 {
01926         struct loopuse  *lu;
01927         struct loopuse  *lunext;
01928 
01929         NMG_CK_FACEUSE(fu);
01930 
01931         lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
01932         while( BU_LIST_NOT_HEAD(lu, &fu->lu_hd) )  {
01933                 NMG_CK_LOOPUSE(lu);
01934                 lunext = BU_LIST_PNEXT(loopuse,lu);
01935                 if( lu->orientation == OT_BOOLPLACE )  {
01936                         /* XXX What to do with return code? */
01937                         if( nmg_klu(lu) )  rt_bomb("nmg_sanitize_fu() nmg_klu() emptied face?\n");
01938                 }
01939                 lu = lunext;
01940         }
01941 }
01942 
01943 /**
01944  *                      N M G _ F A C E _ R S _ I N I T
01945  *
01946  *  Set up nmg_ray_state structure.
01947  *  "left" is a vector that lies in the plane of the face
01948  *  which contains the loops being operated on.
01949  *  It points in the direction "left" of the ray, such that the first
01950  *  OT_SAME loop in the first OT_SAME fact that it crosses will cross
01951  *  the ray in a left-to-right manner consistent with the CCW loop rule.
01952  *  There are some special conditions placed on the "dir" argument to
01953  *  make this happen;  see the comments in nmg_inter.c for details, or
01954  *  Mike's notes "The 'Left' Vector Choice" dated 27-Aug-93, page 1.
01955  */
01956 void
01957 nmg_face_rs_init(struct nmg_ray_state *rs, struct bu_ptbl *b, struct faceuse *fu1, struct faceuse *fu2, fastf_t *pt, fastf_t *dir, struct edge_g_lseg *eg, const struct bn_tol *tol)
01958 
01959                                 /* table of vertexuses in fu1 on intercept line */
01960                                 /* face being worked */
01961                                 /* for plane equation */
01962 
01963 
01964                                         /* may be null.  Geom of isect line. */
01965 
01966 {
01967         plane_t n1;
01968 
01969         BN_CK_TOL(tol);
01970         BU_CK_PTBL(b);
01971         NMG_CK_FACEUSE(fu1);
01972         NMG_CK_FACEUSE(fu2);
01973         if(eg)  NMG_CK_EDGE_G_LSEG(eg);
01974 
01975         bzero( (char *)rs, sizeof(*rs) );
01976         rs->magic = NMG_RAYSTATE_MAGIC;
01977         rs->tol = tol;
01978         rs->vu = (struct vertexuse **)b->buffer;
01979         rs->nvu = b->end;
01980         rs->eg_p = eg;
01981         rs->sA = fu1->s_p;
01982         rs->sB = fu2->s_p;
01983         rs->fu1 = fu1;
01984         rs->fu2 = fu2;
01985         VMOVE( rs->pt, pt );
01986         VMOVE( rs->dir, dir );
01987         NMG_GET_FU_PLANE( n1, fu1 );
01988         VCROSS( rs->left, n1, dir );
01989         VUNITIZE( rs->left );
01990         switch( fu1->orientation )  {
01991         case OT_SAME:
01992                 break;
01993         case OT_OPPOSITE:
01994                 VREVERSE(rs->left, rs->left);
01995                 break;
01996         default:
01997                 rt_bomb("nmg_face_rs_init: bad orientation\n");
01998         }
01999         if(rt_g.NMG_debug&DEBUG_FCUT)  {
02000                 struct loopuse *lu;
02001                 struct edgeuse *eu;
02002                 struct vertexuse *vu;
02003                 int i;
02004 
02005                 bu_log("\tfu->orientation=%s\n", nmg_orientation(fu1->orientation) );
02006                 HPRINT("\tfg N", n1);
02007                 VPRINT("\t  pt", pt);
02008                 VPRINT("\t dir", dir);
02009                 VPRINT("\tleft", rs->left);
02010                 bu_log( "\tvertexuses in fu that are on lintersect line:\n" );
02011                 for( i=0 ; i<BU_PTBL_END( b ) ; i++ )
02012                 {
02013                         vu = (struct vertexuse *)BU_PTBL_GET( b , i );
02014                         nmg_pr_vu_briefly( vu , "\t  " );
02015                 }
02016                 bu_log( "\tLoopuse in fu (x%x):\n" , fu1 );
02017                 for( BU_LIST_FOR( lu , loopuse , &fu1->lu_hd ) )
02018                 {
02019                         bu_log( "\tLOOPUSE x%x:\n" , lu );
02020                         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC )
02021                         {
02022                                 vu = BU_LIST_FIRST( vertexuse, &lu->down_hd );
02023                                 nmg_pr_vu_briefly( vu , "\tVertex Loop: " );
02024                         }
02025                         else
02026                         {
02027                                 for( BU_LIST_FOR( eu , edgeuse , &lu->down_hd ) )
02028                                 {
02029                                         struct edgeuse *eu_next;
02030                                         vect_t eu_dir;
02031                                         fastf_t eu_len;
02032                                         double inv_len;
02033 
02034                                         nmg_pr_eu_briefly( eu , "\t\t" );
02035                                         eu_next = BU_LIST_PNEXT_CIRC( edgeuse , eu );
02036                                         VSUB2( eu_dir , eu_next->vu_p->v_p->vg_p->coord , eu->vu_p->v_p->vg_p->coord );
02037                                         eu_len = MAGNITUDE( eu_dir );
02038                                         if( eu_len < VDIVIDE_TOL )
02039                                                 inv_len = 0.0;
02040                                         else
02041                                                 inv_len = 1.0/eu_len;
02042                                         for( i=0 ; i<3 ; i++ )
02043                                                 eu_dir[i] = eu_dir[i] * inv_len;
02044                                         bu_log( "\t\t\teu_dir = ( %g , %g , %g ), length = %g\n", V3ARGS( eu_dir ) , eu_len );
02045                                 }
02046                         }
02047                 }
02048         }
02049         rs->state = NMG_STATE_OUT;
02050 
02051         /* For measuring angle CCW around plane from -dir */
02052         VREVERSE( rs->ang_x_dir, dir );
02053         VREVERSE( rs->ang_y_dir, rs->left );
02054 }
02055 
02056 /**
02057  *                      N M G _ F A C E _ N E X T _ V U _ I N T E R V A L
02058  *
02059  *  Handle the extent of coincident vertexuses at this distance.
02060  *  ptbl_vsort() will have forced all the distances to be
02061  *  exactly equal if they are within tolerance of each other.
02062  *
02063  *  Two cases:  lone vertexuse, and range of vertexuses.
02064  *
02065  *  Return value is where next interval starts.
02066  */
02067 HIDDEN int
02068 nmg_face_next_vu_interval(struct nmg_ray_state *rs, int cur, fastf_t *mag, int other_rs_state)
02069 {
02070         int     j;
02071         int     k;
02072         int     m;
02073         struct vertex   *v;
02074 
02075         NMG_CK_RAYSTATE(rs);
02076         BN_CK_TOL(rs->tol);
02077         if(rs->eg_p) NMG_CK_EDGE_G_LSEG(rs->eg_p);
02078 
02079         if( cur == rs->nvu-1 || mag[cur+1] != mag[cur] )  {
02080                 /* Single vertexuse at this dist */
02081                 if(rt_g.NMG_debug&DEBUG_FCUT)
02082                         bu_log("nmg_face_next_vu_interval() fu=x%x, single vertexuse at index %d\n", rs->fu1, cur);
02083                 nmg_face_state_transition( rs, cur, 0, other_rs_state );
02084 #if PLOT_BOTH_FACES
02085                 nmg_2face_plot( rs->fu1, rs->fu2 );
02086 #else
02087                 nmg_face_plot( rs->fu1 );
02088 #endif
02089                 return cur+1;
02090         }
02091 
02092         /* Find range of vertexuses at this distance */
02093         v = rs->vu[cur]->v_p;
02094         for( j = cur+1; j < rs->nvu; j++ )  {
02095                 /* If distance along the ray changes, start a new interval */
02096                 if( mag[j] != mag[cur] )  break;
02097 #if 0
02098                 /* If vertex changes, it starts a new interval */
02099                 /* XXX Note that they will be sorted by pointer addres. */
02100                 /* XXX This might cause inconsistencies later */
02101                 if( rs->vu[j]->v_p != v )  break;
02102 #endif
02103         }
02104 
02105         /* vu Interval runs from [cur] to [j-1] inclusive */
02106         if(rt_g.NMG_debug&DEBUG_FCUT)
02107                 bu_log("nmg_face_next_vu_interval() fu=x%x vu's on list interval [%d] to [%d] equal\n", rs->fu1, cur, j-1 );
02108 
02109         /* Ensure that all vu's point to same vertex */
02110         for( k = cur+1; k < j; k++ )  {
02111                 if( rs->vu[k]->v_p == v )  continue;
02112                 /* Trouble.  Print out the interval and die */
02113                 bu_log("At k=%d, vertex changed from v=x%x!\n", k, v);
02114                 bu_log("pt_equality=%d\n", bn_pt3_pt3_equal(v->vg_p->coord,
02115                         rs->vu[k]->v_p->vg_p->coord, rs->tol ) );
02116                 for( k = cur; k < j; k++ )  {
02117                         bu_log("  %d vu=%8x v=%8x mag=%g\n", k,
02118                                 rs->vu[k], rs->vu[k]->v_p, mag[k] );
02119                         NMG_CK_VERTEX_G(rs->vu[k]->v_p->vg_p);
02120                         VPRINT("\tpt", rs->vu[k]->v_p->vg_p->coord);
02121                 }
02122                 rt_bomb("nmg_face_combine: vu block with differing vertices\n");
02123         }
02124         /* All vu's point to the same vertex, sort them */
02125         m = nmg_face_coincident_vu_sort( rs, cur, j );
02126 
02127         /* Process vu list, up to cutoff index 'm', which can be less than j */
02128         for( k = cur; k < m; k++ )  {
02129                 nmg_face_state_transition( rs, k, 1, other_rs_state );
02130 #if PLOT_BOTH_FACES
02131                 nmg_2face_plot( rs->fu1, rs->fu2 );
02132 #else
02133                 nmg_face_plot( rs->fu1 );
02134 #endif
02135         }
02136         rs->vu[j-1] = rs->vu[m-1]; /* for next iteration's lookback */
02137         if(rt_g.NMG_debug&DEBUG_FCUT)
02138                 bu_log("nmg_face_next_vu_interval() vu[%d] set to x%x\n", j-1, rs->vu[j-1] );
02139         return j;
02140 }
02141 
02142 #define VAVERAGE( a, b, c )     { \
02143         (a)[X] = ((b)[X] + (c)[X]) * 0.5;\
02144         (a)[Y] = ((b)[Y] + (c)[Y]) * 0.5;\
02145         (a)[Z] = ((b)[Z] + (c)[Z]) * 0.5;\
02146         }
02147 /**
02148  *                      N M G _ E D G E _ G E O M _ I S E C T _ L I N E
02149  *
02150  *  Force the geometry structure for a given edge to be that of
02151  *  the intersection line between the two faces.
02152  *
02153  *  Note that sometimes a vertex can appear to lie on more than one
02154  *  line.  It is important to refer to geometry here, to make sure
02155  *  that the edgeuse is not mistakenly fused to the wrong edge geometry.
02156  *
02157  *  XXX This has the byproduct that not all edgeuses "on" the line
02158  *  XXX of intersection will share rs->eg_p.
02159  *
02160  *  See the comments in nmg_radial_join_eu() for the rationale.
02161  */
02162 void
02163 nmg_edge_geom_isect_line(struct edgeuse *eu, struct nmg_ray_state *rs, const char *reason)
02164 {
02165         register struct edge_g_lseg     *eg;
02166 
02167         NMG_CK_EDGEUSE(eu);
02168         NMG_CK_RAYSTATE(rs);
02169         if(eu->g.lseg_p) NMG_CK_EDGE_G_LSEG(eu->g.lseg_p);
02170         if(rs->eg_p) NMG_CK_EDGE_G_LSEG(rs->eg_p);
02171 
02172         if(rt_g.NMG_debug&DEBUG_FCUT)  {
02173                 bu_log("nmg_edge_geom_isect_line(eu=x%x, %s)\n eu->g=x%x, rs->eg=x%x at START\n",
02174                         eu, reason,
02175                         eu->g.magic_p, rs->eg_p);
02176         }
02177         if( !eu->g.magic_p )  {
02178                 /* This edgeuse has No edge geometry so far.
02179                  * It may be a new edge formed by a CUTJOIN operation.
02180                  */
02181                 if( !rs->eg_p )  {
02182                         nmg_edge_g( eu );
02183                         eg = eu->g.lseg_p;
02184                         NMG_CK_EDGE_G_LSEG(eg);
02185                         VMOVE( eg->e_pt, rs->pt );
02186                         VMOVE( eg->e_dir, rs->dir );
02187                         rs->eg_p = eg;
02188                 } else {
02189                         NMG_CK_EDGE_G_LSEG(rs->eg_p);
02190                         nmg_use_edge_g( eu, (long *)rs->eg_p );
02191                 }
02192                 goto out;
02193         }
02194         /* Edge has edge geometry */
02195         if( eu->g.lseg_p == rs->eg_p )  return; /* nothing changes */
02196         if( !rs->eg_p )  {
02197                 /* This is first edge_g found on isect line, remember it */
02198                 eg = eu->g.lseg_p;
02199                 NMG_CK_EDGE_G_LSEG(eg);
02200                 rs->eg_p = eg;
02201                 goto out;
02202         }
02203 
02204         /*
02205          * Edge has an edge geometry struct, different from that of isect line.
02206          * Force all uses of this edge geom to take on isect line's geometry.
02207          * Everywhere eu->g.lseg_p is seen, replace with rs->eg_p.
02208          *
02209          *  XXX This is DUBIOUS, as the angle might be very different.
02210          */
02211         nmg_jeg( rs->eg_p, eu->g.lseg_p );
02212 out:
02213         NMG_CK_EDGE_G_LSEG(rs->eg_p);
02214         if(rt_g.NMG_debug&DEBUG_FCUT)  {
02215                 bu_log("nmg_edge_geom_isect_line(eu=x%x) g=x%x, rs->eg=x%x at END\n",
02216                         eu, eu->g.magic_p, rs->eg_p);
02217         }
02218 }
02219 
02220 static struct bu_ptbl *
02221 find_loop_to_cut(int *index1, int *index2, int prior_start, int prior_end, int next_start, int next_end, fastf_t *mid_pt, struct nmg_ray_state *rs)
02222 {
02223         struct loopuse *lu1,*lu2;
02224         struct vertexuse *vu1 = (struct vertexuse *)NULL;
02225         struct vertexuse *vu2 = (struct vertexuse *)NULL;
02226         struct loopuse *match_lu=(struct loopuse *)NULL;
02227         struct loopuse *prior_lu,*next_lu;
02228         struct bu_ptbl *cuts=(struct bu_ptbl *)NULL;
02229         struct loop_cuts *lcut;
02230         int count=0;
02231         int i,j,k;
02232         int done=0;
02233 
02234         if(rt_g.NMG_debug&DEBUG_FCUT)
02235                 bu_log( "find_loop_to_cut: prior_start=%d, prior_end=%d, next_start=%d, next_end=%d, rs=x%x\n",
02236                         prior_start, prior_end, next_start, next_end, rs );
02237 
02238         NMG_CK_RAYSTATE(rs);
02239 
02240         /* check if any coincident VU's can give us a loop to cut */
02241         while( !done )
02242         {
02243                 done = 1;
02244                 count++;
02245                 if( count > 100 )
02246                 {
02247                         bu_log( "find_loop_to_cut: infinite loop\n" );
02248                         bu_log( "prior_start = %d, prior_end = %d, next_start = %d next_nd = %d\n",
02249                                 prior_start, prior_end, next_start, next_end );
02250                         bu_log( "mid_point = ( %f %f %f )\n", V3ARGS( mid_pt ) );
02251                         for( i=0 ; i<rs->nvu ; i++ )
02252                                 bu_log( "\t%d x%x\n", i, rs->vu[i] );
02253                         rt_bomb( "find_loop_to_cut: infinite loop" );
02254                 }
02255                 for( i=prior_start ; i < prior_end ; i++ )
02256                 {
02257                         int class_pt;
02258 
02259                         prior_lu = nmg_find_lu_of_vu( rs->vu[i] );
02260                         class_pt = NMG_CLASS_Unknown;
02261                         for( j=next_start ; j < next_end ; j++ )
02262                         {
02263                                 next_lu = nmg_find_lu_of_vu( rs->vu[j] );
02264                                 if( prior_lu == next_lu )
02265                                 {
02266                                         int class_lu;
02267 
02268                                         if( !match_lu )
02269                                         {
02270                                                 match_lu = next_lu;
02271                                                 cuts = (struct bu_ptbl *)bu_malloc( sizeof( struct bu_ptbl ), "cuts" );
02272                                                 bu_ptbl_init( cuts, 64, " cuts");
02273                                                 lcut = (struct loop_cuts *)bu_malloc( sizeof( struct loop_cuts ), "lcut" );
02274                                                 lcut->lu = match_lu;
02275                                                 bu_ptbl_ins( cuts, (long *)lcut );
02276                                                 continue;
02277                                         }
02278 
02279                                         if( match_lu == next_lu )
02280                                                 continue;
02281 
02282                                         if( class_pt == NMG_CLASS_Unknown )
02283                                         {
02284                                                 class_pt = nmg_class_pt_lu_except( mid_pt,
02285                                                         match_lu, (struct edge *)NULL, rs->tol );
02286                                                 if( match_lu->orientation == OT_OPPOSITE )
02287                                                 {
02288                                                         if( class_pt == NMG_CLASS_AinB )
02289                                                                 class_pt = NMG_CLASS_AoutB;
02290                                                         else if( class_pt == NMG_CLASS_AoutB )
02291                                                                 class_pt = NMG_CLASS_AinB;
02292                                                 }
02293                                         }
02294                                         class_lu = nmg_classify_lu_lu( next_lu, match_lu, rs->tol );
02295 
02296                                         if( class_lu == class_pt ||
02297                                                 class_lu == NMG_CLASS_AonBshared )
02298                                         {
02299                                                 int found=0;
02300 
02301                                                 match_lu = next_lu;
02302                                                 for( k=0 ; k<BU_PTBL_END( cuts ) ; k++ )
02303                                                 {
02304                                                         lcut = (struct loop_cuts *)BU_PTBL_GET( cuts , k );
02305                                                         if( lcut->lu == match_lu )
02306                                                         {
02307                                                                 found = 1;
02308                                                                 break;
02309                                                         }
02310                                                 }
02311                                                 if( !found )
02312                                                 {
02313                                                         done = 0;
02314                                                         lcut = (struct loop_cuts *)bu_malloc( sizeof( struct loop_cuts ), "lcut" );
02315                                                         lcut->lu = match_lu;
02316                                                         bu_ptbl_ins( cuts, (long *)lcut );
02317                                                 }
02318                                         }
02319                                 }
02320                         }
02321                 }
02322         }
02323 
02324         if( cuts )
02325         {
02326                 for( k=0 ; k<BU_PTBL_END( cuts ) ; k++ )
02327                 {
02328                         lcut = (struct loop_cuts *)BU_PTBL_GET( cuts, k );
02329                         match_lu = lcut->lu;
02330 
02331                         if(rt_g.NMG_debug&DEBUG_FCUT)
02332                                 bu_log( "\tfind_loop_to_cut: matching lu's = x%x\n", match_lu );
02333                         lu1 = match_lu;
02334                         for( i=prior_start ; i < prior_end ; i++ )
02335                         {
02336                                 if( nmg_find_lu_of_vu( rs->vu[i] ) == lu1 )
02337                                 {
02338                                         *index1 = i;
02339                                         vu1 = rs->vu[i];
02340                                         lcut->vu1 = vu1;
02341                                         break;
02342                                 }
02343                         }
02344                         lu2 = match_lu;
02345                         for( i=next_start ; i < next_end ; i++ )
02346                         {
02347                                 if( nmg_find_lu_of_vu( rs->vu[i] ) == lu2 )
02348                                 {
02349                                         *index2 = i;
02350                                         vu2 = rs->vu[i];
02351                                         lcut->vu2 = vu2;
02352                                         break;
02353                                 }
02354                         }
02355                 }
02356         }
02357         else
02358         {
02359                 if(rt_g.NMG_debug&DEBUG_FCUT)
02360                         bu_log( "\tfind_loop_to_cut returning 0\n" );
02361                 return( (struct bu_ptbl *)NULL );
02362         }
02363 
02364         for( k=0 ; k<BU_PTBL_END( cuts ) ; k++ )
02365         {
02366                 lcut = (struct loop_cuts *)BU_PTBL_GET( cuts, k );
02367                 lu1 = lcut->lu;
02368                 lu2 = lu1;
02369 
02370                 /* Check if there is more than one VU from lu2 */
02371                 count = 0;
02372                 for( i=next_start ; i<next_end ; i++ )
02373                 {
02374                         if( nmg_find_lu_of_vu( rs->vu[i] ) == lu2 )
02375                                 count++;
02376                 }
02377 
02378                 if( count > 1 )
02379                 {
02380                         struct vertexuse *vu_best;
02381                         fastf_t vu_angle;
02382                         vect_t x_dir,y_dir;
02383                         vect_t norm;
02384 
02385                         if(rt_g.NMG_debug&DEBUG_FCUT)
02386                                 bu_log( "\tfind_loop_to_cut: %d VU's from lu x%x\n", count, lu2 );
02387 
02388                         /* need to select correct VU */
02389                         vu_angle = (-bn_pi);
02390                         vu_best = (struct vertexuse *)NULL;
02391 
02392                         VSUB2( x_dir, vu2->v_p->vg_p->coord, vu1->v_p->vg_p->coord );
02393                         VUNITIZE( x_dir );
02394                         NMG_GET_FU_NORMAL( norm, rs->fu1 );
02395 
02396                         VCROSS( y_dir, norm, x_dir );
02397                         VUNITIZE( y_dir );
02398 
02399                         if(rt_g.NMG_debug&DEBUG_FCUT)
02400                                 bu_log( "\tx_dir=(%g %g %g), y_dir=(%g %g %g)\n",
02401                                         V3ARGS( x_dir ), V3ARGS( y_dir ) );
02402 
02403                         for( i=next_start ; i<next_end ; i++ )
02404                         {
02405                                 struct edgeuse *eu;
02406                                 fastf_t angle;
02407                                 vect_t eu_dir;
02408 
02409 
02410                                 if( nmg_find_lu_of_vu( rs->vu[i] ) != lu2 )
02411                                         continue;
02412 
02413                                 if( *(rs->vu[i]->up.magic_p) != NMG_EDGEUSE_MAGIC )
02414                                 {
02415                                         bu_log( "nmg_fcut_face: VU (x%x) is not from an EU\n", rs->vu[i] );
02416                                         rt_bomb( "nmg_fcut_face: VU is not from an EU" );
02417                                 }
02418 
02419                                 /* calculate angle this EU will make with edgeuse
02420                                  * that will be created by the cut/join
02421                                  */
02422                                 eu = rs->vu[i]->up.eu_p;
02423                                 VSUB2( eu_dir, eu->eumate_p->vu_p->v_p->vg_p->coord, eu->vu_p->v_p->vg_p->coord );
02424                                 angle = atan2( VDOT( y_dir,eu_dir ), VDOT( x_dir, eu_dir ) );
02425 
02426                                 if(rt_g.NMG_debug&DEBUG_FCUT)
02427                                         bu_log( "\tangle for eu x%x (vu=x%x, #%d) is %g\n",
02428                                                 eu, rs->vu[i], i, angle );
02429 
02430                                 /* select max angle */
02431                                 if( angle > vu_angle )
02432                                 {
02433                                         if(rt_g.NMG_debug&DEBUG_FCUT)
02434                                                 bu_log( "\t\tabove is the new best VU\n" );
02435                                         vu_angle = angle;
02436                                         vu_best = rs->vu[i];
02437                                         *index2 = i;
02438                                 }
02439                         }
02440 
02441                         if( vu_best )
02442                         {
02443                                 vu2 = vu_best;
02444                                 lcut->vu2 = vu2;
02445                         }
02446 
02447                         if(rt_g.NMG_debug&DEBUG_FCUT)
02448                                 bu_log( "\tfind_loop_to_cut: selecting VU2 x%x\n", vu2 );
02449                 }
02450 
02451                 /* Check for duplicate cuts (cutting two different loops across same two vertices) */
02452                 if( BU_PTBL_END( cuts ) > 1 )
02453                 {
02454                         for( i=0 ; i<BU_PTBL_END( cuts ) ; i++ )
02455                         {
02456                                 struct loop_cuts *lcut1, *lcut2;
02457                                 int class1, class2;
02458 
02459                                 lcut1 = (struct loop_cuts *)BU_PTBL_GET( cuts, i );
02460                                 for( j=i+1 ; j<BU_PTBL_END( cuts ) ; j++ )
02461                                 {
02462                                         lcut2 = (struct loop_cuts *)BU_PTBL_GET( cuts, j );
02463 
02464                                         if( lcut1->vu1->v_p != lcut2->vu1->v_p ||
02465                                             lcut1->vu2->v_p != lcut2->vu2->v_p )
02466                                                 continue;
02467 
02468                                         /* lcut1 and lcut2 are the same cut, choose one loop to cut */
02469                                         if( lcut1->lu->orientation == OT_OPPOSITE &&
02470                                                 lcut2->lu->orientation == OT_OPPOSITE )
02471                                         {
02472                                                 bu_log( "find_loop_to_cut: Two OT_OPPOSITE loops to be cut?? x%x and x%x\n",
02473                                                         lcut1->lu, lcut2->lu );
02474                                                 bu_bomb( "find_loop_to_cut: Two OT_OPPOSITE loops to be cut??\n" );
02475                                         }
02476                                         if( lcut1->lu->orientation == OT_OPPOSITE )
02477                                         {
02478                                                 /* don't cut an OT_OPPOSITE loop */
02479                                                 bu_ptbl_rm( cuts, (long *)lcut1 );
02480                                                 break;
02481                                         }
02482                                         if( lcut2->lu->orientation == OT_OPPOSITE )
02483                                         {
02484                                                 /* don't cut an OT_OPPOSITE loop */
02485                                                 bu_ptbl_rm( cuts, (long *)lcut2 );
02486                                                 break;
02487                                         }
02488                                         class1 = nmg_class_pt_lu_except( mid_pt, lcut1->lu,
02489                                                 (struct edge *)NULL, rs->tol );
02490                                         class2 = nmg_class_pt_lu_except( mid_pt, lcut2->lu,
02491                                                 (struct edge *)NULL, rs->tol );
02492 
02493                                         if( class1 == NMG_CLASS_AoutB && class2 == NMG_CLASS_AoutB )
02494                                         {
02495                                                 bu_log( "find_loop_to_cut: mid point is outside both loops??? x%x and x%x pt=(%g %g %g)\n",
02496                                                         lcut1->lu, lcut2->lu, V3ARGS( mid_pt ) );
02497                                                 bu_bomb( "find_loop_to_cut: mid point is outside both loops???\n" );
02498                                         }
02499 
02500                                         if( class1 == NMG_CLASS_AoutB )
02501                                         {
02502                                                 /* Don't cut this loop (cut is outside loop) */
02503                                                 bu_ptbl_rm( cuts, (long *)lcut1 );
02504                                                 break;
02505                                         }
02506                                         if( class2 == NMG_CLASS_AoutB )
02507                                         {
02508                                                 /* Don't cut this loop (cut is outside loop) */
02509                                                 bu_ptbl_rm( cuts, (long *)lcut2 );
02510                                                 break;
02511                                         }
02512                                 }
02513                         }
02514                 }
02515 
02516                 /* Check if there is more than one VU from lu1 */
02517                 count = 0;
02518                 for( i=prior_start ; i<prior_end ; i++ )
02519                 {
02520                         if( nmg_find_lu_of_vu( rs->vu[i] ) == lu1 )
02521                                 count++;
02522                 }
02523 
02524                 if( count > 1 )
02525                 {
02526                         struct vertexuse *vu_best;
02527 
02528                         fastf_t vu_angle;
02529                         vect_t x_dir,y_dir;
02530                         vect_t norm;
02531 
02532                         if(rt_g.NMG_debug&DEBUG_FCUT)
02533                                 bu_log( "\tfind_loop_to_cut: %d VU's from lu x%x\n", count, lu1 );
02534 
02535                         /* need to select correct VU */
02536                         vu_angle = (-bn_pi);
02537                         vu_best = (struct vertexuse *)NULL;
02538 
02539                         VSUB2( x_dir, vu1->v_p->vg_p->coord, vu2->v_p->vg_p->coord );
02540                         VUNITIZE( x_dir );
02541                         NMG_GET_FU_NORMAL( norm, rs->fu1 );
02542 
02543                         VCROSS( y_dir, norm, x_dir );
02544                         VUNITIZE( y_dir );
02545 
02546                         if(rt_g.NMG_debug&DEBUG_FCUT)
02547                                 bu_log( "\tx_dir=(%g %g %g), y_dir=(%g %g %g)\n",
02548                                         V3ARGS( x_dir ), V3ARGS( y_dir ) );
02549 
02550                         for( i=prior_start ; i<prior_end ; i++ )
02551                         {
02552                                 struct edgeuse *eu;
02553                                 fastf_t angle;
02554                                 vect_t eu_dir;
02555 
02556                                 if( nmg_find_lu_of_vu( rs->vu[i] ) != lu1 )
02557                                         continue;
02558 
02559                                 if( *(rs->vu[i]->up.magic_p) != NMG_EDGEUSE_MAGIC )
02560                                 {
02561                                         bu_log( "nmg_fcut_face: VU (x%x) is not from an EU\n", rs->vu[i] );
02562                                         rt_bomb( "nmg_fcut_face: VU is not from an EU" );
02563                                 }
02564 
02565                                 /* calculate angle this EU will make with edgeuse
02566                                  * that will be created by the cut/join
02567                                  */
02568                                 eu = rs->vu[i]->up.eu_p;
02569                                 VSUB2( eu_dir, eu->eumate_p->vu_p->v_p->vg_p->coord, eu->vu_p->v_p->vg_p->coord );
02570                                 angle = atan2( VDOT( y_dir,eu_dir ), VDOT( x_dir, eu_dir ) );
02571 
02572                                 if(rt_g.NMG_debug&DEBUG_FCUT)
02573                                         bu_log( "\tangle for eu x%x (vu=x%x, #%d) is %g\n",
02574                                                 eu, rs->vu[i], i, angle );
02575 
02576                                 /* select max angle */
02577                                 if( angle > vu_angle )
02578                                 {
02579                                         if(rt_g.NMG_debug&DEBUG_FCUT)
02580                                                 bu_log( "\t\tabove is the new best VU\n" );
02581                                         vu_angle = angle;
02582 
02583                                         vu_best = rs->vu[i];
02584                                         *index1 = i;
02585                                 }
02586                         }
02587 
02588                         if( vu_best )
02589                         {
02590                                 vu1 = vu_best;
02591                                 lcut->vu1 = vu1;
02592                         }
02593 
02594                         if(rt_g.NMG_debug&DEBUG_FCUT)
02595                                 bu_log( "\tfind_loop_to_cut: selecting VU1 x%x\n", vu1 );
02596                 }
02597         }
02598 
02599         if(rt_g.NMG_debug&DEBUG_FCUT)
02600                 bu_log( "\tfind_loop_to_cut: returning %d cuts (index1=%d, index2=%d)\n",
02601                                 BU_PTBL_END( cuts ), *index1, *index2 );
02602 
02603         return( cuts );
02604 }
02605 
02606 static fastf_t
02607 nmg_eu_angle(struct edgeuse *eu, struct vertex *vp)
02608 {
02609         struct faceuse *fu;
02610         struct vertex_g *vg1,*vg2;
02611         vect_t norm;
02612         vect_t x_dir;
02613         vect_t y_dir;
02614         vect_t eu_dir;
02615         fastf_t angle;
02616 
02617         NMG_CK_EDGEUSE( eu );
02618         NMG_CK_VERTEX( vp );
02619 
02620         fu = nmg_find_fu_of_eu( eu );
02621         NMG_CK_FACEUSE( fu );
02622         NMG_GET_FU_NORMAL( norm, fu );
02623 
02624         vg1 = eu->vu_p->v_p->vg_p;
02625         vg2 = eu->eumate_p->vu_p->v_p->vg_p;
02626 
02627         VSUB2( x_dir, vg1->coord, vp->vg_p->coord );
02628         VUNITIZE( x_dir );
02629         VCROSS( y_dir, norm, x_dir );
02630         VUNITIZE( y_dir );
02631 
02632         VSUB2( eu_dir, vg2->coord, vg1->coord );
02633         angle = atan2( VDOT( eu_dir, y_dir ), VDOT( eu_dir, x_dir ) );
02634 
02635         return( angle );
02636 }
02637 
02638 static int
02639 find_best_vu(int start, int end, struct vertex *other_vp, struct nmg_ray_state *rs)
02640 {
02641         struct edgeuse *eu;
02642         struct vertexuse *best_vu;
02643         struct loopuse *best_lu;
02644         fastf_t best_angle;
02645         int best_index;
02646         int other_is_in_best = -42;
02647         int class;
02648         int i;
02649 
02650         if(rt_g.NMG_debug&DEBUG_FCUT)
02651                 bu_log( "find_best_vu: start=%d, end=%d, other_vp=x%x, rs=x%x\n",
02652                                 start,end,other_vp, rs );
02653 
02654         NMG_CK_VERTEX( other_vp );
02655         NMG_CK_RAYSTATE(rs);
02656 
02657         if( start == end-1 )
02658         {
02659                 if(rt_g.NMG_debug&DEBUG_FCUT)
02660                         bu_log( "\tfind_best_vu returning %d\n", start );
02661 
02662                 return( start );
02663         }
02664 
02665         best_vu = rs->vu[start];
02666         best_lu = nmg_find_lu_of_vu( best_vu );
02667         best_index = start;
02668         eu = best_vu->up.eu_p;
02669         best_angle = nmg_eu_angle( eu, other_vp );
02670 
02671         if( BU_LIST_FIRST_MAGIC( &best_lu->down_hd ) == NMG_VERTEXUSE_MAGIC )
02672         {
02673                 other_is_in_best = 0;
02674         }
02675         else if( nmg_loop_is_a_crack( best_lu ) )
02676         {
02677                 other_is_in_best = 0;
02678         }
02679         else
02680         {
02681                 class = nmg_class_pt_lu_except( other_vp->vg_p->coord, best_lu, (struct edge *)NULL, rs->tol );
02682 
02683                 if( (class == NMG_CLASS_AinB && best_lu->orientation == OT_SAME) ||
02684                     (class == NMG_CLASS_AoutB && best_lu->orientation == OT_OPPOSITE) )
02685                         other_is_in_best = 1;
02686                 else if( class == NMG_CLASS_AonBshared )
02687                 {
02688                         bu_log( "find_best_vu: There is a loop to cut, lu=x%x\n", best_lu );
02689                         rt_bomb( "find_best_vu: There is a loop to cut" );
02690                 }
02691                 else
02692                         other_is_in_best = 0;
02693         }
02694 
02695         if(rt_g.NMG_debug&DEBUG_FCUT)
02696                 bu_log( "\tfind_best_vu: first choice is index=%d, vu=x%x, lu=x%x, other_is_in_best=%d\n",
02697                                 best_index, best_vu, best_lu, other_is_in_best );
02698 
02699         for( i=start+1 ; i<end ; i++ )
02700         {
02701                 struct loopuse *lu;
02702 
02703                 lu = nmg_find_lu_of_vu( rs->vu[i] );
02704                 if( lu != best_lu )
02705                 {
02706                         class = nmg_classify_lu_lu( lu, best_lu, rs->tol );
02707                         if(rt_g.NMG_debug&DEBUG_FCUT)
02708                         {
02709                                 bu_log( "lu x%x is %s\n", lu , nmg_orientation( lu->orientation ) );
02710                                 bu_log( "best_lu x%x is %s\n", best_lu , nmg_orientation( best_lu->orientation ) );
02711                                 bu_log( "lu x%x is %s w.r.t lu x%x\n",
02712                                         lu, nmg_class_name( class ), best_lu );
02713                         }
02714 
02715                         if( other_is_in_best )
02716                         {
02717                                 if( class == NMG_CLASS_AinB || (class == NMG_CLASS_AonBshared && lu->orientation == OT_SAME) )
02718                                 {
02719 
02720                                         best_vu = rs->vu[i];
02721                                         best_lu = lu;
02722                                         best_index = i;
02723 
02724                                         if(rt_g.NMG_debug&DEBUG_FCUT)
02725                                                 bu_log( "\tfind_best_vu: better choice (inside) - index=%d, vu=x%x, lu=x%x, other_is_in_best=%d\n",
02726                                                         best_index, best_vu, best_lu, other_is_in_best );
02727                                         /* other_is_in_best can't change */
02728                                 }
02729                         }
02730                         else
02731                         {
02732                                 if( class == NMG_CLASS_AoutB || (class == NMG_CLASS_AonBshared && lu->orientation == OT_OPPOSITE) )
02733                                 {
02734                                         best_vu = rs->vu[i];
02735                                         best_lu = lu;
02736                                         best_index = i;
02737 
02738                                         /* other_is_in_best may change */
02739                                         if( BU_LIST_FIRST_MAGIC( &best_lu->down_hd ) == NMG_VERTEXUSE_MAGIC )
02740                                         {
02741                                                 other_is_in_best = 0;
02742                                         }
02743                                         else if( nmg_loop_is_a_crack( best_lu ) )
02744                                         {
02745                                                 other_is_in_best = 0;
02746                                         }
02747                                         else
02748                                         {
02749                                                 class = nmg_class_pt_lu_except( other_vp->vg_p->coord,
02750                                                         best_lu, (struct edge *)NULL, rs->tol );
02751 
02752                                                 if( (class == NMG_CLASS_AinB && best_lu->orientation == OT_SAME) ||
02753                                                     (class == NMG_CLASS_AoutB && best_lu->orientation == OT_OPPOSITE) )
02754                                                         other_is_in_best = 1;
02755                                                 else if( class == NMG_CLASS_AonBshared )
02756                                                 {
02757                                                         bu_log( "find_best_vu: There is a loop to cut, lu=x%x\n",
02758                                                                 best_lu );
02759                                                         rt_bomb( "find_best_vu: There is a loop to cut" );
02760                                                 }
02761                                                 else
02762                                                         other_is_in_best = 0;
02763                                         }
02764                                         if(rt_g.NMG_debug&DEBUG_FCUT)
02765                                                 bu_log( "\tfind_best_vu: better choice (outside) - index=%d, vu=x%x, lu=x%x, other_is_in_best=%d\n",
02766                                                         best_index, best_vu, best_lu, other_is_in_best );
02767                                 }
02768                         }
02769                 }
02770                 else
02771                 {
02772                         struct edgeuse *eu;
02773                         fastf_t angle;
02774                         /* need to choose based on eu directions */
02775 
02776                         eu = rs->vu[i]->up.eu_p;
02777                         NMG_CK_EDGEUSE( eu );
02778                         angle = nmg_eu_angle( eu, other_vp );
02779 
02780                         if(rt_g.NMG_debug&DEBUG_FCUT)
02781                                 bu_log( "best_angle = %f, eu=x%x, eu_angle=%f\n",
02782                                         best_angle, eu, angle );
02783                         if( angle > best_angle )
02784                         {
02785                                 best_angle = angle;
02786                                 best_vu = rs->vu[i];
02787                                 best_lu = nmg_find_lu_of_vu( best_vu );
02788                                 best_index = i;
02789                         }
02790                 }
02791         }
02792 
02793         return( best_index );
02794 }
02795 
02796 HIDDEN void
02797 nmg_fcut_face(struct nmg_ray_state *rs)
02798 {
02799         register int    cur;
02800         struct vertexuse *vu1,*vu2;
02801         struct loopuse *new_lu;
02802         struct edgeuse *new_eu1;
02803         struct edgeuse *old_eu;
02804         struct vertex *prev_v;
02805         struct bu_ptbl *cuts;
02806         int prior_start;
02807         int cut_no;
02808 
02809         NMG_CK_RAYSTATE(rs);
02810         BN_CK_TOL(rs->tol);
02811 
02812         if(rt_g.NMG_debug&DEBUG_FCUT)
02813                 bu_log("nmg_face_combine()\n");
02814 
02815         if(rs->eg_p) NMG_CK_EDGE_G_LSEG(rs->eg_p);
02816 
02817 #if PLOT_BOTH_FACES
02818         nmg_2face_plot( rs->fu1, rs->fu2 );
02819 #else
02820         nmg_face_plot( rs->fu1 );
02821         nmg_face_plot( rs->fu2 );
02822 #endif
02823 
02824         if(rt_g.NMG_debug&DEBUG_FCUT)
02825         {
02826                 bu_log( "rs->fu1 = x%x\n", rs->fu1 );
02827                 bu_log( "rs->fu2 = x%x\n", rs->fu2 );
02828                 nmg_pr_fu_briefly( rs->fu1, "" );
02829                 bu_log( "%d vertices on intersect line\n", rs->nvu );
02830                 for( cur=0 ; cur<rs->nvu ; cur++ )
02831                 bu_log( "\tvu=x%x, v=x%x, lu=x%x\n", rs->vu[cur], rs->vu[cur]->v_p, nmg_find_lu_of_vu( rs->vu[cur] ) );
02832         }
02833 
02834 
02835         if( rs->nvu < 2 )
02836                 return;
02837 
02838         prev_v = (struct vertex *)NULL;
02839         prior_start = 0;
02840         while( 1 )
02841         {
02842                 struct edgeuse *eu_tmp;
02843                 struct loopuse *lu1 = (struct loopuse *)NULL;
02844                 struct loopuse *lu2 = (struct loopuse *)NULL;
02845                 point_t mid_pt;
02846                 int class;
02847                 int orient1 = 0;
02848                 int orient2 = 0;
02849                 int prior_end;
02850                 int next_start,next_end;
02851                 int i;
02852                 int index1,index2;
02853 
02854                 while( rs->vu[prior_start]->v_p == prev_v )
02855                         prior_start++;
02856 
02857                 vu1 = rs->vu[prior_start];
02858                 prior_end = prior_start;
02859 
02860                 prev_v = vu1->v_p;
02861 
02862                 while( ++prior_end < rs->nvu && rs->vu[prior_end]->v_p == vu1->v_p );
02863 
02864                 next_start = prior_end;
02865 
02866                 if( next_start >= rs->nvu )
02867                         break;          /* all done */
02868 
02869                 vu2 = rs->vu[next_start];
02870                 next_end = next_start;
02871                 while( ++next_end < rs->nvu && rs->vu[next_end]->v_p == vu2->v_p );
02872 
02873                 if(rt_g.NMG_debug&DEBUG_FCUT)
02874                 {
02875                         bu_log( "rs->fu1 = x%x\n", rs->fu1 );
02876                         bu_log( "rs->fu2 = x%x\n", rs->fu2 );
02877                         bu_log( "prior_start=%d. prior_end=%d, next_start=%d, next_end=%d\n",
02878                                 prior_start, prior_end, next_start, next_end );
02879                         bu_log( "%d vertices on intersect line\n", rs->nvu );
02880                         for( cur=0 ; cur<rs->nvu ; cur++ )
02881                         bu_log( "\tvu=x%x, v=x%x, lu=x%x\n", rs->vu[cur], rs->vu[cur]->v_p, nmg_find_lu_of_vu( rs->vu[cur] ) );
02882                 }
02883 
02884                 /* look for an EU in this face that connects vu1 and vu2 */
02885                 if( nmg_find_eu_in_face( vu1->v_p, vu2->v_p, rs->fu1,
02886                         (struct edgeuse *)NULL, 0 ) )
02887                 {
02888                         if(rt_g.NMG_debug&DEBUG_FCUT)
02889                                 bu_log( "Already an edge here\n" );
02890                         continue;
02891                 }
02892 
02893                 if( nmg_find_eu_in_face( vu1->v_p, vu2->v_p, rs->fu1->fumate_p,
02894                         (struct edgeuse *)NULL, 0 ) )
02895                 {
02896                         if(rt_g.NMG_debug&DEBUG_FCUT)
02897                                 bu_log( "Already an edge here\n" );
02898                         continue;
02899                 }
02900 
02901                 /* we know that fu1 does not contain an edge connecting vu1 and vu2,
02902                  * Now check if the midpoint is inside or outside fu1.
02903                  * Note that ON fu1 is not an option at this point
02904                  */
02905                 VAVERAGE( mid_pt, vu1->v_p->vg_p->coord, vu2->v_p->vg_p->coord )
02906                 class = nmg_class_pt_fu_except( mid_pt, rs->fu1, (struct loopuse *)NULL,
02907                         (void (*)())NULL, (void (*)())NULL, (char *)NULL, 0, 1, rs->tol );
02908 
02909                 if(rt_g.NMG_debug&DEBUG_FCUT)
02910                 {
02911                         bu_log( "vu1=x%x (%g %g %g ), vu2=x%x (%g %g %g)\n",
02912                                 vu1, V3ARGS( vu1->v_p->vg_p->coord ),
02913                                 vu2, V3ARGS( vu2->v_p->vg_p->coord ) );
02914                         bu_log( "\tmid_pt = (%g %g %g)\n", V3ARGS( mid_pt ) );
02915                         bu_log( "class for mid point is %s\n", nmg_class_name(class) );
02916                 }
02917 
02918                 if( class == NMG_CLASS_AoutB )
02919                         continue;
02920 
02921                 /* Check if mid-point is in fu2. If fu2 is disjoint loops, this point
02922                  * may be outside fu2, and we don't want to cut fu1 here.
02923                  */
02924                 class = nmg_class_pt_fu_except( mid_pt, rs->fu2, (struct loopuse *)NULL,
02925                         (void (*)())NULL, (void (*)())NULL, (char *)NULL, 0, 0, rs->tol );
02926 
02927                 if( class == NMG_CLASS_AoutB )
02928                         continue;
02929 
02930                 /* See if there is an edge joining the 2 vertices already, this
02931                  * will be used for radial join later */
02932                 old_eu = nmg_findeu( vu1->v_p, vu2->v_p, (struct shell *)NULL,
02933                         (struct edgeuse *)NULL, 0);
02934 
02935 
02936                 cuts = find_loop_to_cut( &index1, &index2, prior_start, prior_end,
02937                                        next_start, next_end, mid_pt, rs );
02938                 if( cuts == (struct bu_ptbl *)NULL )
02939 #if 0
02940                 {
02941                         vu1 = rs->vu[index1];
02942                         vu2 = rs->vu[index2];
02943                         lu1 = nmg_find_lu_of_vu( vu1 );
02944                         lu2 = nmg_find_lu_of_vu( vu2 );
02945                         orient1 = lu1->orientation;
02946                         orient2 = lu2->orientation;
02947 
02948                 }
02949                 else
02950 #endif
02951                 {
02952                         index1 = find_best_vu( prior_start, prior_end, vu2->v_p, rs );
02953                         index2 = find_best_vu( next_start, next_end, vu1->v_p, rs );
02954                         vu1 = rs->vu[index1];
02955                         vu2 = rs->vu[index2];
02956                         lu1 = nmg_find_lu_of_vu( vu1 );
02957                         lu2 = nmg_find_lu_of_vu( vu2 );
02958                         orient1 = lu1->orientation;
02959                         orient2 = lu2->orientation;
02960                 }
02961 
02962                 if( cuts )
02963                 {
02964                         for( cut_no=0 ; cut_no<BU_PTBL_END( cuts ) ; cut_no++ )
02965                         {
02966                                 struct loop_cuts *lcut;
02967 
02968                                 if(rt_g.NMG_debug&DEBUG_FCUT)
02969                                         bu_log( "\tcut loop (#%d of %d)\n", cut_no, BU_PTBL_END( cuts ) );
02970 
02971                                 lcut = (struct loop_cuts *)BU_PTBL_GET( cuts, cut_no );
02972 
02973                                 vu1 = lcut->vu1;
02974                                 vu2 = lcut->vu2;
02975                                 lu1 = lcut->lu;
02976 
02977                                 new_lu = nmg_cut_loop( vu1, vu2 );
02978                                 new_eu1 = BU_LIST_LAST( edgeuse, &new_lu->down_hd );
02979 
02980                                 NMG_CK_EDGEUSE( new_eu1 );
02981 
02982                                 /* make intersection edges real */
02983                                 new_eu1->e_p->is_real = 1;
02984 
02985                                 nmg_loop_g( lu1->l_p, rs->tol );
02986                                 nmg_loop_g( new_lu->l_p, rs->tol );
02987 
02988                                 nmg_lu_reorient( lu1 );
02989                                 nmg_lu_reorient( new_lu );
02990 
02991                                 if(rt_g.NMG_debug&DEBUG_FCUT)
02992                                 {
02993                                         bu_log( "\t\t new_eu = x%x\n", new_eu1 );
02994                                         nmg_pr_fu_briefly( rs->fu1, "" );
02995                                 }
02996 #if 0
02997                                 /* Fuse new edge to intersect line, old edge */
02998                                 nmg_edge_geom_isect_line( new_eu1, rs, "CUTJOIN, new edge after loop cut" );
02999 #endif
03000                                 if( old_eu ) nmg_radial_join_eu( old_eu, new_eu1, rs->tol );
03001 
03002                                 /* A new VU has been added to vu2->v_p, add it to the rs->vu[]
03003                                  * array by overwriting the last use of vu1->v_p
03004                                  */
03005 
03006                                 eu_tmp = vu1->up.eu_p;
03007                                 eu_tmp = BU_LIST_PPREV_CIRC( edgeuse, &eu_tmp->l );
03008                                 if( eu_tmp->vu_p->v_p != vu2->v_p )
03009                                 {
03010                                         bu_log( "nmg_fcut_face: eu (x%x) has wrong vertex (x%x) should be (x%x)\n", eu_tmp, eu_tmp->vu_p->v_p, vu2->v_p );
03011                                         rt_bomb( "nmg_fcut_face: eu has wrong vertex" );
03012                                 }
03013 
03014                                 rs->vu[prior_end-1-cut_no] = eu_tmp->vu_p;
03015                         }
03016                         bu_ptbl_free( cuts);
03017                         bu_free( (char *)cuts, "cuts" );
03018 
03019                         continue;
03020                 }
03021 
03022                 if( BU_LIST_FIRST_MAGIC( &lu1->down_hd ) == NMG_VERTEXUSE_MAGIC &&
03023                     BU_LIST_FIRST_MAGIC( &lu2->down_hd ) == NMG_VERTEXUSE_MAGIC )
03024 
03025                 {
03026                         struct vertexuse *new_vu2;
03027 
03028                         new_vu2 = nmg_join_2singvu_loops( vu1, vu2 );
03029                         new_eu1 = new_vu2->up.eu_p;
03030                         NMG_CK_EDGEUSE( new_eu1 );
03031 
03032                         /* make intersection edges real */
03033                         new_eu1->e_p->is_real = 1;
03034 
03035                         nmg_loop_g( lu1->l_p, rs->tol );
03036                         lu1->orientation = OT_SAME;
03037                         lu1->lumate_p->orientation = OT_SAME;
03038 
03039                         if(rt_g.NMG_debug&DEBUG_FCUT)
03040                         {
03041                                 bu_log( "\tjoin 2 singvu loops\n" );
03042                                 nmg_pr_fu_briefly( rs->fu1, "" );
03043                         }
03044 #if 0
03045                         /* Fuse new edge to intersect line, old edge */
03046                         nmg_edge_geom_isect_line( new_eu1, rs, "CUTJOIN, new edge after loop cut" );
03047 #endif
03048                         if( old_eu )  nmg_radial_join_eu( old_eu, new_eu1, rs->tol );
03049 
03050                         /* vu2 has been killed, replace it in rs->vu[] */
03051 
03052                         for( i=next_start ; i<next_end ; i++ )
03053                         {
03054                                 if( rs->vu[i] == vu2 )
03055                                 {
03056                                         rs->vu[i] = new_vu2;
03057                                         break;
03058                                 }
03059                         }
03060 
03061                         continue;
03062                 }
03063 
03064                 if( BU_LIST_FIRST_MAGIC( &lu1->down_hd ) == NMG_VERTEXUSE_MAGIC &&
03065                     BU_LIST_FIRST_MAGIC( &lu2->down_hd ) == NMG_EDGEUSE_MAGIC )
03066                 {
03067                         struct vertexuse *new_vu1;
03068 
03069                         new_vu1 = nmg_join_singvu_loop( vu2, vu1 );
03070                         new_eu1 = new_vu1->up.eu_p;
03071                         NMG_CK_EDGEUSE( new_eu1 );
03072 
03073                         /* make intersection edges real */
03074                         new_eu1->e_p->is_real = 1;
03075 
03076                         nmg_loop_g( lu2->l_p, rs->tol );
03077                         lu2->orientation = orient2;
03078                         lu2->lumate_p->orientation = orient2;
03079 
03080                         if(rt_g.NMG_debug&DEBUG_FCUT)
03081                         {
03082                                 bu_log( "\tjoin loops vu1 (x%x) is sing vu loop\n", vu1 );
03083                                 nmg_pr_fu_briefly( rs->fu1, "" );
03084                         }
03085 #if 0
03086                         /* Fuse new edge to intersect line, old edge */
03087                         nmg_edge_geom_isect_line( new_eu1, rs, "CUTJOIN, new edge after loop cut" );
03088 
03089 #endif
03090                         if( old_eu )  nmg_radial_join_eu( old_eu, new_eu1, rs->tol );
03091 
03092                         /* A new VU has been added to vu2->v_p, add it to the rs->vu[]
03093                          * array by overwriting the last use of vu1->v_p
03094                          */
03095 
03096                         eu_tmp = new_vu1->up.eu_p;
03097                         eu_tmp = BU_LIST_PPREV_CIRC( edgeuse, &eu_tmp->l );
03098                         if( eu_tmp->vu_p->v_p != vu2->v_p )
03099                         {
03100                                 bu_log( "nmg_fcut_face: eu (x%x) has wrong vertex (x%x) should be (x%x)\n", eu_tmp, eu_tmp->vu_p->v_p, vu2->v_p );
03101                                 rt_bomb( "nmg_fcut_face: eu has wrong vertex" );
03102                         }
03103 
03104                         rs->vu[prior_end-1] = eu_tmp->vu_p;
03105                         continue;
03106                 }
03107 
03108                 if( BU_LIST_FIRST_MAGIC( &lu1->down_hd ) == NMG_EDGEUSE_MAGIC &&
03109                     BU_LIST_FIRST_MAGIC( &lu2->down_hd ) == NMG_VERTEXUSE_MAGIC )
03110                 {
03111                         struct vertexuse *new_vu2;
03112 
03113                         new_vu2 = nmg_join_singvu_loop( vu1, vu2 );
03114                         new_eu1 = new_vu2->up.eu_p;
03115                         NMG_CK_EDGEUSE( new_eu1 );
03116 
03117                         /* make intersection edges real */
03118                         new_eu1->e_p->is_real = 1;
03119 
03120                         nmg_loop_g( lu1->l_p, rs->tol );
03121                         lu1->orientation = orient1;
03122                         lu1->lumate_p->orientation = orient1;
03123 
03124                         if(rt_g.NMG_debug&DEBUG_FCUT)
03125                         {
03126                                 bu_log( "\tjoin loops vu2 (x%x) is sing vu loop\n", vu2 );
03127                                 nmg_pr_fu_briefly( rs->fu1, "" );
03128                         }
03129 #if 0
03130                         /* Fuse new edge to intersect line, old edge */
03131                         nmg_edge_geom_isect_line( new_eu1, rs, "CUTJOIN, new edge after loop cut" );
03132 #endif
03133 
03134                         if( old_eu )  nmg_radial_join_eu( old_eu, new_eu1, rs->tol );
03135 
03136                         /* vu2 has been killed, replace it in rs->vu[] */
03137 
03138                         for( i=next_start ; i<next_end ; i++ )
03139                         {
03140                                 if( rs->vu[i] == vu2 )
03141                                 {
03142                                         rs->vu[i] = new_vu2;
03143                                         break;
03144                                 }
03145                         }
03146 
03147                         continue;
03148                 }
03149 
03150                 if( lu1 != lu2 )
03151                 {
03152                         struct vertexuse *new_vu2;
03153 
03154                         new_vu2 = nmg_join_2loops( vu1, vu2 );
03155                         new_eu1 = new_vu2->up.eu_p;
03156                         NMG_CK_EDGEUSE( new_eu1 );
03157 
03158                         /* make intersection edges real */
03159                         new_eu1->e_p->is_real = 1;
03160 
03161                         nmg_loop_g( lu1->l_p, rs->tol );
03162 
03163                         if(rt_g.NMG_debug&DEBUG_FCUT)
03164                         {
03165                                 bu_log( "\t join 2 loops\n" );
03166                                 bu_log( "\t\tvu2 (x%x) replaced with new_vu2 x%x\n", vu2, new_vu2 );
03167                                 nmg_pr_fu_briefly( rs->fu1, "" );
03168                         }
03169 
03170 #if 0
03171                         /* Fuse new edge to intersect line, old edge */
03172                         nmg_edge_geom_isect_line( new_eu1, rs, "CUTJOIN, new edge after loop cut" );
03173 #endif
03174 
03175                         if( old_eu )  nmg_radial_join_eu( old_eu, new_eu1, rs->tol );
03176 
03177                         /* a new use of vu2->v_p has been created add it to the list by
03178                          * overwriting a use of the previous vertex
03179                          */
03180                         rs->vu[prior_end - 1] = new_vu2;
03181 
03182                         continue;
03183                 }
03184 
03185                 bu_log( "ERROR in face cutter: something should have been cut!!\n" );
03186                 bu_log( "vu1=x%x, vu2=x%x\n", vu1, vu2 );
03187                 nmg_pr_fu_briefly( rs->fu1, "" );
03188                 rt_bomb( "ERROR: face cutter didn't cut anything" );
03189         }
03190 
03191         if(rt_g.NMG_debug&DEBUG_FCUT)
03192                 nmg_pr_fu_briefly( rs->fu1, "" );
03193 }
03194 
03195 HIDDEN void
03196 nmg_face_combine_jra(struct nmg_ray_state *rs1, fastf_t *mag1, struct nmg_ray_state *rs2, fastf_t *mag2)
03197 {
03198         nmg_fcut_face( rs1 );
03199         nmg_fcut_face( rs2 );
03200 
03201 }
03202 
03203 /**
03204  *                      N M G _ F A C E _ C O M B I N E
03205  *
03206  *      collapse loops,vertices within face fu1 (relative to fu2)
03207  *
03208  */
03209 HIDDEN void
03210 nmg_face_combineX(struct nmg_ray_state *rs1, fastf_t *mag1, struct nmg_ray_state *rs2, fastf_t *mag2)
03211 {
03212         register int    cur1, cur2;
03213         register int    nxt1, nxt2;
03214 
03215         NMG_CK_RAYSTATE(rs1);
03216         NMG_CK_RAYSTATE(rs2);
03217         BN_CK_TOL(rs1->tol);
03218         BN_CK_TOL(rs2->tol);
03219 
03220         if(rt_g.NMG_debug&DEBUG_FCUT)
03221                 bu_log("nmg_face_combine()\n");
03222 
03223         if(rs1->eg_p) NMG_CK_EDGE_G_LSEG(rs1->eg_p);
03224         if(rs2->eg_p) NMG_CK_EDGE_G_LSEG(rs2->eg_p);
03225 
03226 #if PLOT_BOTH_FACES
03227         nmg_2face_plot( rs1->fu1, rs1->fu2 );
03228 #else
03229         nmg_face_plot( rs1->fu1 );
03230         nmg_face_plot( rs1->fu2 );
03231 #endif
03232 
03233         /*  Handle next block of coincident vertexuses.
03234          *  Sometimes only one list has a block in it.
03235          */
03236         cur1 = cur2 = 0;
03237         for( ; cur1 < rs1->nvu && cur2 < rs2->nvu; cur1=nxt1, cur2=nxt2 )  {
03238                 int     old_rs1_state = rs1->state;
03239 
03240                 if(rt_g.NMG_debug&DEBUG_FCUT)
03241                         bu_log("\nnmg_face_combineX() vu block, index1=%d, index2=%d\n", cur1, cur2);
03242 
03243                 if( mag1[cur1] < mag2[cur2] )  {
03244                         if(rt_g.NMG_debug&DEBUG_FCUT)
03245                                 bu_log("\nnmg_face_combineX() doing index1 block (at end)\n");
03246                         nxt1 = nmg_face_next_vu_interval( rs1, cur1, mag1, rs2->state );
03247                         nxt2 = cur2;
03248                         if(rs1->eg_p) NMG_CK_EDGE_G_LSEG(rs1->eg_p);
03249                         if(rs2->eg_p) NMG_CK_EDGE_G_LSEG(rs2->eg_p);
03250                         if( !rs2->eg_p )  rs2->eg_p = rs1->eg_p;
03251                 } else if( mag1[cur1] > mag2[cur2] )  {
03252                         if(rt_g.NMG_debug&DEBUG_FCUT)
03253                                 bu_log("\nnmg_face_combineX() doing index2 block (at end)\n");
03254                         nxt1 = cur1;
03255                         nxt2 = nmg_face_next_vu_interval( rs2, cur2, mag2, old_rs1_state );
03256                         if(rs1->eg_p) NMG_CK_EDGE_G_LSEG(rs1->eg_p);
03257                         if(rs2->eg_p) NMG_CK_EDGE_G_LSEG(rs2->eg_p);
03258                         if( !rs1->eg_p )  rs1->eg_p = rs2->eg_p;
03259                 } else {
03260                         struct vertexuse        *vu1;
03261                         struct vertexuse        *vu2;
03262                         vu1 = rs1->vu[cur1];
03263                         vu2 = rs2->vu[cur2];
03264                         NMG_CK_VERTEXUSE(vu1);
03265                         NMG_CK_VERTEXUSE(vu2);
03266                         if( vu1->v_p != vu2->v_p )  {
03267                                 bu_log("cur1=%d, cur2=%d, v1=x%x, v2=x%x\n",
03268                                         cur1, cur2, vu1->v_p, vu2->v_p);
03269                                 rt_bomb("nmg_face_combineX: vertex lists scrambled");
03270                         }
03271                         if(rt_g.NMG_debug&DEBUG_FCUT)
03272                                 bu_log("\nnmg_face_combineX() doing index1 block\n");
03273                         nxt1 = nmg_face_next_vu_interval( rs1, cur1, mag1, rs2->state );
03274                         if(rs1->eg_p) NMG_CK_EDGE_G_LSEG(rs1->eg_p);
03275                         if(rs2->eg_p) NMG_CK_EDGE_G_LSEG(rs2->eg_p);
03276                         if( !rs2->eg_p )  rs2->eg_p = rs1->eg_p;
03277 
03278                         if(rt_g.NMG_debug&DEBUG_FCUT)
03279                                 bu_log("\nnmg_face_combineX() doing index2 block\n");
03280                         nxt2 = nmg_face_next_vu_interval( rs2, cur2, mag2, old_rs1_state );
03281                         if(rs1->eg_p) NMG_CK_EDGE_G_LSEG(rs1->eg_p);
03282                         if(rs2->eg_p) NMG_CK_EDGE_G_LSEG(rs2->eg_p);
03283                         if( !rs1->eg_p )  rs1->eg_p = rs2->eg_p;
03284                 }
03285                 if(rs1->eg_p) NMG_CK_EDGE_G_LSEG(rs1->eg_p);
03286                 if(rs2->eg_p) NMG_CK_EDGE_G_LSEG(rs2->eg_p);
03287         }
03288 
03289         /*
03290          *  Here, one list is exhausted, but the other may not be.
03291          *  Press on until both are.
03292          */
03293         for( ; cur1 < rs1->nvu; cur1 = nxt1 )  {
03294                 nxt1 = nmg_face_next_vu_interval( rs1, cur1, mag1, rs2->state );
03295         }
03296         if( !rs2->eg_p )  rs2->eg_p = rs1->eg_p;
03297         if(rs1->eg_p) NMG_CK_EDGE_G_LSEG(rs1->eg_p);
03298         if(rs2->eg_p) NMG_CK_EDGE_G_LSEG(rs2->eg_p);
03299 
03300         for( ; cur2 < rs2->nvu; cur2 = nxt2 )  {
03301                 nxt2 = nmg_face_next_vu_interval( rs2, cur2, mag2, rs1->state );
03302         }
03303         if( !rs1->eg_p )  rs1->eg_p = rs2->eg_p;
03304         if(rs1->eg_p) NMG_CK_EDGE_G_LSEG(rs1->eg_p);
03305         if(rs2->eg_p) NMG_CK_EDGE_G_LSEG(rs2->eg_p);
03306 
03307         if( rs1->state != NMG_STATE_OUT || rs2->state != NMG_STATE_OUT )  {
03308                 bu_log("ERROR nmg_face_combine() ended in state '%s'/'%s'?\n",
03309                         nmg_state_names[rs1->state],
03310                         nmg_state_names[rs2->state] );
03311                 bu_log("cur1 = %d of %d, cur2 = %d of %d\n",
03312                         cur1, rs1->nvu, cur2, rs2->nvu );
03313 
03314                 if( RT_G_DEBUG || rt_g.NMG_debug )  {
03315                         /* Drop a plot file */
03316                         rt_g.NMG_debug |= DEBUG_VU_SORT|DEBUG_FCUT|DEBUG_PLOTEM;
03317                         nmg_pl_comb_fu( 0, 1, rs1->fu1 );
03318                         nmg_pl_comb_fu( 0, 2, rs1->fu2 );
03319                 }
03320 
03321 #if 0
03322                 bu_log("nmg_face_combine() bad ending state, pushing on\n");
03323 #else
03324                 /* This is the production setting */
03325                 rt_bomb("nmg_face_combine() bad ending state\n");
03326 #endif
03327         }
03328 }
03329 
03330 /**
03331  *                      N M G _ U N L I S T _ V
03332  */
03333 void
03334 nmg_unlist_v(struct bu_ptbl *b, fastf_t *mag, struct vertex *v)
03335 {
03336         register int            i;
03337         struct vertexuse        *vu;
03338 
03339         BU_CK_PTBL(b);
03340         NMG_CK_VERTEX(v);
03341         for( i=0; i<BU_PTBL_END(b); i++ )  {
03342                 vu = (struct vertexuse *)BU_PTBL_GET(b, i);
03343                 if( !vu )  continue;
03344                 if( vu->v_p == v )
03345                 {
03346                         BU_PTBL_GET(b, i) = (long *)0;
03347                         mag[i] = MAX_FASTF;
03348                 }
03349         }
03350 }
03351 
03352 /**
03353  *                      N M G _ O N O N _ F I X
03354  *
03355  *  An attempt to fix the condition:
03356  *      nmg_assess_eu():  ON vertexuse in middle of edge?
03357  *
03358  *  Note that the vertexuse being zapped may have a lower subscript.
03359  *
03360  *  Must be called after vu list has been sorted.
03361  */
03362 int
03363 nmg_onon_fix(struct nmg_ray_state *rs, struct bu_ptbl *b, struct bu_ptbl *ob, fastf_t *mag, fastf_t *omag)
03364 
03365 
03366                                 /* other rs's vu list */
03367                                 /* list of distances from intersect ray start point */
03368                                 /* list of distances from intersect ray start point */
03369 {
03370         int             i;
03371         int             zapped;
03372         struct vertexuse        *vu;
03373         struct vertex           *v;
03374         int             zot;
03375 
03376         NMG_CK_RAYSTATE(rs);
03377         BU_CK_PTBL(b);
03378         BU_CK_PTBL(ob);
03379 
03380         zapped = 0;
03381         for( i=0; i<BU_PTBL_END(b); i++ )  {
03382 again:
03383                 vu = (struct vertexuse *)BU_PTBL_GET(b, i);
03384                 if( !vu )  continue;
03385                 NMG_CK_VERTEXUSE(vu);
03386                 if( *vu->up.magic_p == NMG_LOOPUSE_MAGIC )  continue;
03387                 v = vu->v_p;
03388                 NMG_CK_VERTEX(v);
03389                 if( (zot = nmg_assess_eu( vu->up.eu_p, 0, rs, i )) < 0 )  {
03390                         if(rt_g.NMG_debug&DEBUG_FCUT)  {
03391                                 bu_log("nmg_onon_fix(): vu[%d] zapped (rev)\n", -zot);
03392                         }
03393 doit:
03394                         vu = (struct vertexuse *)BU_PTBL_GET(b, -zot);
03395                         NMG_CK_VERTEXUSE(vu);
03396                         v = vu->v_p;
03397                         /* Need to null out all uses of this vertex from both lists */
03398                         nmg_unlist_v(b, mag, v);
03399                         nmg_unlist_v(ob, omag, v);
03400                         zapped++;
03401                         goto again;
03402                 }
03403 
03404                 if( (zot = nmg_assess_eu( vu->up.eu_p, 1, rs, i )) < 0 )  {
03405                         if(rt_g.NMG_debug&DEBUG_FCUT)  {
03406                                 bu_log("nmg_onon_fix(): vu[%d] zapped (forw)\n", -zot);
03407                         }
03408                         goto doit;
03409                 }
03410         }
03411         if( zapped )  {
03412                 int removed;
03413 
03414                 /* If any vertexuses got zapped, their pointer was set to NULL.
03415                  *  They can all be removed from the list in one easy operation.
03416                  */
03417                 bu_log("nmg_onon_fix(): removing %d dead vertexuses\n", zapped);
03418                 /* remove entries from distance list first */
03419                 removed = 0;
03420                 for( i=BU_PTBL_END( b ) ; i>=0 ; i-- )
03421                 {
03422                         int count=0;
03423                         int j,k;
03424 
03425                         j = i;
03426                         while( j>=0 && !BU_PTBL_GET( b, j ) ) --j;
03427                         count = i-j;
03428                         removed += count;
03429                         for( k=j+1; k<BU_PTBL_END(b)-removed ; k++ )
03430                                 mag[k] = mag[k+count];
03431                 }
03432                 bu_ptbl_rm(b, 0 );
03433                 removed = 0;
03434                 for( i=BU_PTBL_END( ob ) ; i>=0 ; i-- )
03435                 {
03436                         int count=0;
03437                         int j,k;
03438 
03439                         j = i;
03440                         while( j>=0 && !BU_PTBL_GET( ob, j ) ) --j;
03441                         count = i-j;
03442                         removed += count;
03443                         for( k=j+1 ; k<BU_PTBL_END(ob)-removed ; k++ )
03444                                 omag[k] = omag[k+count];
03445                 }
03446                 bu_ptbl_rm(ob, 0 );
03447 #if 0
03448 rt_bomb("nmg_onon_fix(): check the intersector\n");
03449 #endif
03450                 return 1;
03451         }
03452 
03453         return 0;
03454 }
03455 #if 0
03456 void
03457 nmg_sort_coincident_vus( tbl, tol )
03458 struct bu_ptbl *tbl;
03459 const struct bn_tol *tol;
03460 {
03461         int curr_vu=0;
03462         int start1,end1;
03463         int start2,end2;
03464         struct vertexuse *vu1;
03465         struct vertexuse *vu2;
03466         struct loopuse **matching_lus;
03467         int match_count=0;
03468 
03469         BN_CK_TOL( tol );
03470         BU_CK_PTBL( tbl );
03471 
03472         if( BU_PTBL_END( tbl ) < 3 )
03473                 return;
03474 
03475         matching_lus = (struct loopuse **)bu_calloc( BU_PTBL_END( tbl ),
03476                 sizeof( struct loopuse *), "nmg_sort_coincident_vus: matching_lus" );
03477 
03478         /* look for coincident vu's */
03479         while( curr_vu < BU_PTBL_END( tbl )-1 )
03480         {
03481                 struct loopuse *lu1,*lu2;
03482 
03483                 vu1 = (struct vertexuse *)BU_PTBL_GET( tbl, curr_vu );
03484                 start1 = curr_vu;
03485                 end1 = start1;
03486                 vu2 = (struct vertexuse *)BU_PTBL_GET( tbl, start1 + 1 );
03487                 if( vu1->v-p != vu2->v_p )
03488                 {
03489                         /* not coincident */
03490                         curr_vu++;
03491                         continue;
03492                 }
03493                 while( vu2->v_p == vu1->v_p )
03494                 {
03495                         end1++;
03496                         vu2 = (struct vertexuse *)BU_PTBL_GET( tbl, end1 + 1 );
03497                 }
03498 
03499                 /*
03500                  * get next vu after coincident list
03501                  * might be another list of coincident VU's
03502                  */
03503                 start2 = end1 + 1;
03504                 end2 = start2;
03505                 vu1 = (struct vertexuse *)BU_PTBL_GET( tbl, start2 );
03506                 vu2 = (struct vertexuse *)BU_PTBL_GET( tbl, start2+1 );
03507                 while( vu2->v_p == vu1->v_p )
03508                 {
03509                         end2++;
03510                         vu2 = (struct vertexuse *)BU_PTBL_GET( tbl, end2+1 );
03511                 }
03512 
03513                 match_count = 0;
03514                 for( i=start1 ; i<=end1 ; i++ )
03515                 {
03516                         vu1 = (struct vertexuse *)BU_PTBL_GET( tbl, i );
03517                         lu1 = nmg_find_lu_of_vu( vu1 );
03518                         if( !lu1 )
03519                                 continue;
03520 
03521                         /* look for same LU in next list */
03522                         for( j=start1 ; j<= end1 ; j++ )
03523                         {
03524                                 vu2 = (struct vertexuse *)BU_PTBL_GET( tbl, j );
03525                                 lu2 = nmg_find_lu_of_vu( vu2 );
03526                                 if( lu2 == lu1 )
03527                                 {
03528                                         matching_lus[match_count] = lu1;
03529                                         match_count++;
03530                                 }
03531                         }
03532                 }
03533         }
03534 }
03535 
03536 #endif
03537 /**
03538  *                      N M G _ F A C E _ C U T J O I N
03539  *
03540  *  The main face cut handler.
03541  *  Called from nmg_inter.c by nmg_isect_2faces().
03542  *
03543  *  A wrapper for nmg_face_combine, for now.
03544  *
03545  *  The two vertexuse lists may be of different lengths, because
03546  *  one may have multiple uses of a vertex, while the other has only
03547  *  a single use of that same vertex.
03548  */
03549 struct edge_g_lseg *
03550 nmg_face_cutjoin(struct bu_ptbl *b1, struct bu_ptbl *b2, fastf_t *mag1, fastf_t *mag2, struct faceuse *fu1, struct faceuse *fu2, fastf_t *pt, fastf_t *dir, struct edge_g_lseg *eg, const struct bn_tol *tol)
03551                                 /* table of vertexuses in fu1 on intercept line */
03552                                 /* table of vertexuses in fu2 on intercept line */
03553                                 /* table of distances to vertexuses from is->pt */
03554                                 /* table of distances to vertexuses from is->pt */
03555                                 /* face being worked */
03556                                 /* for plane equation */
03557 
03558 
03559                                         /* may be null.  geometry of isect line */
03560 
03561 {
03562         struct vertexuse **vu1, **vu2;
03563         int             i;
03564         struct nmg_ray_state    rs1;
03565         struct nmg_ray_state    rs2;
03566 
03567         if(rt_g.NMG_debug&DEBUG_FCUT)  {
03568                 bu_log("\nnmg_face_cutjoin(fu1=x%x, fu2=x%x) eg=x%x START\n", fu1, fu2, eg);
03569         }
03570 
03571         BN_CK_TOL(tol);
03572         NMG_CK_FACEUSE(fu1);
03573         NMG_CK_FACEUSE(fu2);
03574 
03575         /* Perhaps this should only happen when debugging is on? */
03576         if( rt_g.NMG_debug&DEBUG_FCUT && ( b1->end <= 0 || b2->end <= 0) )  {
03577                 bu_log("nmg_face_cutjoin(fu1=x%x, fu2=x%x): WARNING empty list %d %d\n",
03578                         fu1, fu2, b1->end, b2->end );
03579 #if 0
03580                 return eg;
03581 #endif
03582         }
03583 
03584 top:
03585         /*
03586          *  Sort hit points by increasing distance, vertex ptr, vu ptr,
03587          *  and eliminate any duplicate vu's.
03588          */
03589         ptbl_vsort(b1, fu1, fu2, pt, dir, mag1, tol->dist);
03590         ptbl_vsort(b2, fu2, fu1, pt, dir, mag2, tol->dist);
03591 
03592         vu1 = (struct vertexuse **)b1->buffer;
03593         vu2 = (struct vertexuse **)b2->buffer;
03594 
03595         /* Print list of intersections */
03596         if(rt_g.NMG_debug&DEBUG_FCUT)  {
03597                 bu_log("Ray vu intersection list:\n");
03598                 for( i=0; i < b1->end; i++ )  {
03599                         bu_log(" %d %e ", i, mag1[i] );
03600                         nmg_pr_vu_briefly( vu1[i], (char *)0 );
03601                 }
03602                 for( i=0; i < b2->end; i++ )  {
03603                         bu_log(" %d %e ", i, mag2[i] );
03604                         nmg_pr_vu_briefly( vu2[i], (char *)0 );
03605                 }
03606         }
03607 
03608         /* Check to make sure that intersector didn't miss anything */
03609         if( nmg_ck_vu_ptbl( b1, fu1 ) || nmg_ck_vu_ptbl( b2, fu2 ) )  goto top;
03610 
03611 #if 0
03612         /* Check to see if lists are different */
03613         /* XXX Note that there may be different numbers of multiple uses in different faces.  This won't work. */
03614         {
03615                 i = b1->end-1;
03616                 if( b2->end-1 < i )  i = b2->end-1;
03617                 for( ; i >= 0; i-- )  {
03618                         NMG_CK_VERTEXUSE(vu1[i]);
03619                         NMG_CK_VERTEXUSE(vu2[i]);
03620                         if( vu1[i]->v_p == vu2[i]->v_p ) continue;
03621                         bu_log("Index %d mis-match, x%x != x%x\n",
03622                                 i, vu1[i]->v_p, vu2[i]->v_p );
03623                 }
03624         }
03625 #endif
03626 
03627         /* this block of code checks if the two lists of intersection vertexuses
03628          * contain vertexuses from the appropriate faceuse */
03629         if(rt_g.NMG_debug&DEBUG_FCUT)  {
03630                 int found1=(-1),found2=(-1); /* -1 => not set, 0 => no vertexuses from faceuse found */
03631                 int tmp_found;
03632                 struct faceuse *fu;
03633                 struct vertexuse *vu;
03634 
03635                 /* list b1 should contain vertexuses from faceuse fu1 */
03636                 for( i=0 ; i<BU_PTBL_END( b1 ) ; i++ )
03637                 {
03638                         tmp_found = 0;
03639                         vu = (struct vertexuse *)BU_PTBL_GET( b1 , i );
03640                         fu = nmg_find_fu_of_vu(vu);
03641                         if( fu == fu1 )
03642                                 tmp_found = 1;
03643                         if( found1 == (-1) )
03644                                 found1 = tmp_found;
03645                         else if( tmp_found != found1 ) /* some found, some not found!!!!! */
03646                         {
03647                                 bu_log ("nmg_face_cutjoin: Intersection list is screwy for face 1\n" );
03648                                 break;
03649                         }
03650                 }
03651 
03652                 /* and list b2 should contain vertexuses from faceuse fu2 */
03653                 for( i=0 ; i<BU_PTBL_END( b2 ) ; i++ )
03654                 {
03655                         tmp_found = 0;
03656                         vu = (struct vertexuse *)BU_PTBL_GET( b2 , i );
03657                         fu = nmg_find_fu_of_vu(vu);
03658                         if( fu == fu2 )
03659                                 tmp_found = 1;
03660                         if( found2 == (-1) )
03661                                 found2 = tmp_found;
03662                         else if( tmp_found != found2 ) /* some found, some not found!!!!! */
03663                         {
03664                                 bu_log ("nmg_face_cutjoin: Intersection list is screwy for face 2\n" );
03665                                 break;
03666                         }
03667                 }
03668                 if( !found1 )
03669                         bu_log( "nmg_face_cutjoin: intersection list for face 1 doesn't contain vertexuses from face 1!!!\n" );
03670                 if( !found2 )
03671                         bu_log( "nmg_face_cutjoin: intersection list for face 2 doesn't contain vertexuses from face 2!!!\n" );
03672         }
03673 
03674         nmg_face_rs_init( &rs1, b1, fu1, fu2, pt, dir, eg, tol );
03675         nmg_face_rs_init( &rs2, b2, fu2, fu1, pt, dir, eg, tol );
03676 #if 0
03677         /* Ensure that small angles don't plunk vertexuses down onto the intersection line */
03678         if( nmg_onon_fix( &rs1, b1, b2, mag1, mag2 ) || nmg_onon_fix( &rs2, b2, b1, mag2, mag1 ) )  goto top;
03679 #endif
03680 
03681 #if 0
03682         nmg_face_combineX( &rs1, mag1, &rs2, mag2 );
03683 #else
03684         nmg_face_combine_jra( &rs1, mag1, &rs2, mag2 );
03685 #endif
03686 
03687         /* Can't do simplifications here,
03688          * because the caller's linked lists & pointers might get disrupted.
03689          */
03690 
03691         /* Merging uses of common edges is OK, though, and quite necessary. */
03692         if( (i = nmg_mesh_two_faces( fu1, fu2, tol )) )  {
03693                 if(rt_g.NMG_debug&DEBUG_FCUT)
03694                         bu_log("nmg_face_cutjoin() meshed %d edges\n", i);
03695         }
03696         if(rt_g.NMG_debug&DEBUG_FCUT)  {
03697                 bu_log("nmg_face_cutjoin(fu1=x%x, fu2=x%x) eg=x%x END\n", fu1, fu2, rs1.eg_p);
03698         }
03699         if( eg && !rs1.eg_p )  rt_bomb("nmg_face_cutjoin() lost edge_g_lseg?\n");
03700         if( eg && eg != rs1.eg_p )  bu_log("nmg_face_cutjoin() changed from eg=x%x to rs1.eg_p=x%x\n", eg, rs1.eg_p);
03701         return rs1.eg_p;
03702 }
03703 
03704 void
03705 nmg_fcut_face_2d(struct bu_ptbl *vu_list, fastf_t *mag, struct faceuse *fu1, struct faceuse *fu2, struct bn_tol *tol)
03706 {
03707         struct nmg_ray_state rs;
03708         point_t pt;
03709         vect_t dir;
03710         struct edge_g_lseg *eg;
03711 
03712         NMG_CK_FACEUSE( fu1 );
03713         NMG_CK_FACEUSE( fu2 );
03714         BN_CK_TOL( tol );
03715         BU_CK_PTBL( vu_list );
03716 
03717         VSETALL( pt, 0.0 );
03718         VSET( dir, 1.0, 0.0 ,0.0 );
03719         eg = (struct edge_g_lseg *)NULL;
03720 
03721         nmg_face_rs_init( &rs, vu_list, fu1, fu2, pt,  dir, eg, tol );
03722 
03723         nmg_fcut_face( &rs );
03724 }
03725 
03726 /*
03727  *  State machine transition tables
03728  *  Indexed by MNG_V_ASSESSMENT values.
03729  */
03730 
03731 struct state_transitions {
03732         int     assessment;
03733         int     new_state;
03734         int     action;
03735 };
03736 
03737 static const struct state_transitions nmg_state_is_out[17] = {
03738         { NMG_LEFT_LEFT,        NMG_STATE_OUT,          NMG_ACTION_NONE },
03739         { NMG_LEFT_RIGHT,       NMG_STATE_IN,           NMG_ACTION_VFY_EXT },
03740         { NMG_LEFT_ON_FORW,     NMG_STATE_ON_L,         NMG_ACTION_VFY_EXT },
03741         { NMG_LEFT_ON_REV,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03742         { NMG_RIGHT_LEFT,       NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03743         { NMG_RIGHT_RIGHT,      NMG_STATE_OUT,          NMG_ACTION_NONE },
03744         { NMG_RIGHT_ON_FORW,    NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03745         { NMG_RIGHT_ON_REV,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03746         { NMG_ON_FORW_LEFT,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03747         { NMG_ON_FORW_RIGHT,    NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03748         { NMG_ON_FORW_ON_FORW,  NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03749         { NMG_ON_FORW_ON_REV,   NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03750         { NMG_ON_REV_LEFT,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03751         { NMG_ON_REV_RIGHT,     NMG_STATE_ON_R,         NMG_ACTION_VFY_EXT },
03752         { NMG_ON_REV_ON_FORW,   NMG_STATE_ON_N,         NMG_ACTION_NONE },
03753         { NMG_ON_REV_ON_REV,    NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03754         { NMG_LONE,             NMG_STATE_OUT,          NMG_ACTION_NONE }
03755 };
03756 
03757 static const struct state_transitions nmg_state_is_on_L[17] = {
03758         { NMG_LEFT_LEFT,        NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03759         { NMG_LEFT_RIGHT,       NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03760         { NMG_LEFT_ON_FORW,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03761         { NMG_LEFT_ON_REV,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03762         { NMG_RIGHT_LEFT,       NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03763         { NMG_RIGHT_RIGHT,      NMG_STATE_ON_L,         NMG_ACTION_NONE },
03764         { NMG_RIGHT_ON_FORW,    NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03765         { NMG_RIGHT_ON_REV,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03766         { NMG_ON_FORW_LEFT,     NMG_STATE_OUT,          NMG_ACTION_NONE },
03767         { NMG_ON_FORW_RIGHT,    NMG_STATE_IN,           NMG_ACTION_NONE },
03768         { NMG_ON_FORW_ON_FORW,  NMG_STATE_ON_L,         NMG_ACTION_NONE },
03769         { NMG_ON_FORW_ON_REV,   NMG_STATE_IN,           NMG_ACTION_NONE },
03770         { NMG_ON_REV_LEFT,      NMG_STATE_ON_N,         NMG_ACTION_VFY_MULTI },
03771         { NMG_ON_REV_RIGHT,     NMG_STATE_ON_B,         NMG_ACTION_VFY_EXT },
03772         { NMG_ON_REV_ON_FORW,   NMG_STATE_ON_L,         NMG_ACTION_VFY_MULTI },
03773         { NMG_ON_REV_ON_REV,    NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03774         { NMG_LONE,             NMG_STATE_ON_L,         NMG_ACTION_LONE_V_ESPLIT }
03775 };
03776 
03777 static const struct state_transitions nmg_state_is_on_R[17] = {
03778         { NMG_LEFT_LEFT,        NMG_STATE_ON_R,         NMG_ACTION_NONE },
03779         { NMG_LEFT_RIGHT,       NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03780         { NMG_LEFT_ON_FORW,     NMG_STATE_ON_B,         NMG_ACTION_NONE },
03781         { NMG_LEFT_ON_REV,      NMG_STATE_IN,           NMG_ACTION_NONE },
03782         { NMG_RIGHT_LEFT,       NMG_STATE_ON_N,         NMG_ACTION_VFY_MULTI },
03783         { NMG_RIGHT_RIGHT,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03784         { NMG_RIGHT_ON_FORW,    NMG_STATE_ON_N,         NMG_ACTION_VFY_MULTI },
03785         { NMG_RIGHT_ON_REV,     NMG_STATE_OUT,          NMG_ACTION_NONE },
03786         { NMG_ON_FORW_LEFT,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03787         { NMG_ON_FORW_RIGHT,    NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03788         { NMG_ON_FORW_ON_FORW,  NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03789         { NMG_ON_FORW_ON_REV,   NMG_STATE_IN,           NMG_ACTION_NONE },
03790         { NMG_ON_REV_LEFT,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03791         { NMG_ON_REV_RIGHT,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03792         { NMG_ON_REV_ON_FORW,   NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03793         { NMG_ON_REV_ON_REV,    NMG_STATE_ON_R,         NMG_ACTION_NONE },
03794         { NMG_LONE,             NMG_STATE_ON_R,         NMG_ACTION_LONE_V_ESPLIT }
03795 };
03796 
03797 static const struct state_transitions nmg_state_is_on_B[17] = {
03798         { NMG_LEFT_LEFT,        NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03799         { NMG_LEFT_RIGHT,       NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03800         { NMG_LEFT_ON_FORW,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03801         { NMG_LEFT_ON_REV,      NMG_STATE_IN,           NMG_ACTION_VFY_MULTI },
03802         { NMG_RIGHT_LEFT,       NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03803         { NMG_RIGHT_RIGHT,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03804         { NMG_RIGHT_ON_FORW,    NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03805         { NMG_RIGHT_ON_REV,     NMG_STATE_ON_L,         NMG_ACTION_NONE },
03806         { NMG_ON_FORW_LEFT,     NMG_STATE_ON_R,         NMG_ACTION_NONE },
03807         { NMG_ON_FORW_RIGHT,    NMG_STATE_IN,           NMG_ACTION_VFY_MULTI },
03808         { NMG_ON_FORW_ON_FORW,  NMG_STATE_ON_B,         NMG_ACTION_VFY_MULTI },
03809         { NMG_ON_FORW_ON_REV,   NMG_STATE_IN,           NMG_ACTION_NONE },
03810         { NMG_ON_REV_LEFT,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03811         { NMG_ON_REV_RIGHT,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03812         { NMG_ON_REV_ON_FORW,   NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03813         { NMG_ON_REV_ON_REV,    NMG_STATE_ON_B,         NMG_ACTION_VFY_MULTI },
03814         { NMG_LONE,             NMG_STATE_ON_B,         NMG_ACTION_LONE_V_ESPLIT }
03815 };
03816 
03817 static const struct state_transitions nmg_state_is_on_N[17] = {
03818         { NMG_LEFT_LEFT,        NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03819         { NMG_LEFT_RIGHT,       NMG_STATE_OUT,          NMG_ACTION_VFY_MULTI },
03820         { NMG_LEFT_ON_FORW,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03821         { NMG_LEFT_ON_REV,      NMG_STATE_ON_L,         NMG_ACTION_VFY_MULTI },
03822         { NMG_RIGHT_LEFT,       NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03823         { NMG_RIGHT_RIGHT,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03824         { NMG_RIGHT_ON_FORW,    NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03825         { NMG_RIGHT_ON_REV,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03826         { NMG_ON_FORW_LEFT,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03827         { NMG_ON_FORW_RIGHT,    NMG_STATE_ON_R,         NMG_ACTION_VFY_MULTI },
03828         { NMG_ON_FORW_ON_FORW,  NMG_STATE_ON_N,         NMG_ACTION_VFY_MULTI },
03829         { NMG_ON_FORW_ON_REV,   NMG_STATE_OUT,          NMG_ACTION_NONE },
03830         { NMG_ON_REV_LEFT,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03831         { NMG_ON_REV_RIGHT,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03832         { NMG_ON_REV_ON_FORW,   NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03833         { NMG_ON_REV_ON_REV,    NMG_STATE_ON_N,         NMG_ACTION_VFY_MULTI },
03834         { NMG_LONE,             NMG_STATE_ON_N,         NMG_ACTION_LONE_V_ESPLIT }
03835 };
03836 
03837 static const struct state_transitions nmg_state_is_in[17] = {
03838         { NMG_LEFT_LEFT,        NMG_STATE_IN,           NMG_ACTION_CUTJOIN },
03839         { NMG_LEFT_RIGHT,       NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03840         { NMG_LEFT_ON_FORW,     NMG_STATE_ON_R,         NMG_ACTION_CUTJOIN },
03841         { NMG_LEFT_ON_REV,      NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03842         { NMG_RIGHT_LEFT,       NMG_STATE_OUT,          NMG_ACTION_CUTJOIN },
03843         { NMG_RIGHT_RIGHT,      NMG_STATE_IN,           NMG_ACTION_CUTJOIN },
03844         { NMG_RIGHT_ON_FORW,    NMG_STATE_ON_L,         NMG_ACTION_CUTJOIN },
03845         { NMG_RIGHT_ON_REV,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03846         { NMG_ON_FORW_LEFT,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03847         { NMG_ON_FORW_RIGHT,    NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03848         { NMG_ON_FORW_ON_FORW,  NMG_STATE_IN,           NMG_ACTION_NONE },
03849         { NMG_ON_FORW_ON_REV,   NMG_STATE_OUT,          NMG_ACTION_NONE },
03850         { NMG_ON_REV_LEFT,      NMG_STATE_ON_R,         NMG_ACTION_CUTJOIN },
03851         { NMG_ON_REV_RIGHT,     NMG_STATE_ERROR,        NMG_ACTION_ERROR },
03852         { NMG_ON_REV_ON_FORW,   NMG_STATE_ON_B,         NMG_ACTION_CUTJOIN },
03853         { NMG_ON_REV_ON_REV,    NMG_STATE_IN,           NMG_ACTION_NONE },
03854         { NMG_LONE,             NMG_STATE_IN,           NMG_ACTION_LONE_V_JAUNT }
03855 };
03856 
03857 /**
03858  *                      N M G _ I N S E R T _ V U _ I F _ O N _ E D G E
03859  *
03860  *      This code checks if the vertex from a loop of a single vertex lies on
03861  *      an edge containing vu2. If so, the edge is split, vu1 is inserted,
03862  *      the loop containing vu1 is killed, and the newly created edgeuse is
03863  *      returned in "new_eu".
03864  *
03865  *              returns:
03866  *                      0 - did nothing
03867  *                      1 - inserted vu1 and created a new edge
03868  */
03869 int
03870 nmg_insert_vu_if_on_edge(struct vertexuse *vu1, struct vertexuse *vu2, struct edgeuse *new_eu, struct bn_tol *tol)
03871                         /* vertexuse from a loop of a single vertex */
03872                         /* vertexuse from another loop */
03873                         /* use of new edge that may be created (implicit return ) */
03874                         /* tolerance for collinearity check */
03875 {
03876         struct edgeuse *eu_from;        /* edgeuse that starts at end of vu2's eu */
03877         struct edgeuse *eu_to;          /* edgeuse that terminates at vu2 */
03878         vect_t eu_vect;                 /* edge vector starting or terminating at vu2 */
03879         vect_t vect_to_loop;            /* vector from start of eu_vect to vu1 */
03880         fastf_t eu_len_sq;              /* square of length of edge containing vu2 */
03881         fastf_t dist_to_loop_sq;        /* square of distance between vu1 and vu2 */
03882 
03883         NMG_CK_VERTEXUSE( vu1 );
03884         if( *vu1->up.magic_p != NMG_LOOPUSE_MAGIC )
03885                 rt_bomb( "nmg_insert_vu_if_on_edge: vu1 is not from a loop of a single vertex" );
03886 
03887         NMG_CK_VERTEXUSE( vu2 );
03888         if( *vu2->up.magic_p != NMG_EDGEUSE_MAGIC )
03889                 rt_bomb( "nmg_insert_vu_if_on_edge: vu2 is not from an edgeuse" );
03890 
03891         BN_CK_TOL( tol );
03892 
03893         if(rt_g.NMG_debug&DEBUG_FCUT)
03894                 bu_log( "nmg_insert_vu_if_on_edge: vu1=x%x, vu2=x%x\n" , vu1 , vu2 );
03895 
03896         eu_from = BU_LIST_PNEXT_CIRC( edgeuse , vu2->up.eu_p );
03897         eu_to = BU_LIST_PPREV_CIRC( edgeuse , vu2->up.eu_p );
03898         if( bn_3pts_collinear( vu1->v_p->vg_p->coord , vu2->v_p->vg_p->coord , eu_from->vu_p->v_p->vg_p->coord , tol ))
03899         {
03900                 if(rt_g.NMG_debug&DEBUG_FCUT)
03901                         bu_log( "\t points are collinear with vu2's eu ( %g , %g , %g ) -> ( %g , %g , %g )\n",
03902                                 V3ARGS( vu2->v_p->vg_p->coord ),
03903                                 V3ARGS( eu_from->vu_p->v_p->vg_p->coord ) );
03904                 VSUB2( eu_vect , eu_from->vu_p->v_p->vg_p->coord , vu2->v_p->vg_p->coord );
03905                 VSUB2( vect_to_loop , vu1->v_p->vg_p->coord , vu2->v_p->vg_p->coord );
03906                 if( VDOT( eu_vect , vect_to_loop ) > 0.0 )
03907                 {
03908                         eu_len_sq = MAGSQ( eu_vect );
03909                         dist_to_loop_sq = MAGSQ( vect_to_loop );
03910                         if( dist_to_loop_sq < eu_len_sq )
03911                         {
03912                                 if(rt_g.NMG_debug&DEBUG_FCUT)
03913                                         bu_log( "\tvu1 is on vu2's eu, creating new edge (MAGSQ=%g, tol->dist_sq=%g)\n" , dist_to_loop_sq , tol->dist_sq );
03914                                 (void) nmg_ebreaker( vu1->v_p , vu2->up.eu_p, tol );
03915                                 nmg_klu( vu1->up.lu_p );
03916                                 return( 1 );
03917                         }
03918                 }
03919         }
03920         if( bn_3pts_collinear( vu1->v_p->vg_p->coord , vu2->v_p->vg_p->coord , eu_to->vu_p->v_p->vg_p->coord , tol ))
03921         {
03922                 if(rt_g.NMG_debug&DEBUG_FCUT)
03923                         bu_log( "\t points are collinear with eu that ends at vu2 ( %g , %g , %g ) -> ( %g , %g , %g )\n",
03924                                 V3ARGS( eu_to->vu_p->v_p->vg_p->coord ),
03925                                 V3ARGS( vu2->v_p->vg_p->coord ) );
03926                 VSUB2( eu_vect , vu2->v_p->vg_p->coord , eu_to->vu_p->v_p->vg_p->coord );
03927                 VSUB2( vect_to_loop , vu1->v_p->vg_p->coord , eu_to->vu_p->v_p->vg_p->coord );
03928                 if( VDOT( eu_vect , vect_to_loop ) > 0.0 )
03929                 {
03930                         eu_len_sq = MAGSQ( eu_vect );
03931                         dist_to_loop_sq = MAGSQ( vect_to_loop );
03932                         if( dist_to_loop_sq < eu_len_sq )
03933                         {
03934 
03935                                 if(rt_g.NMG_debug&DEBUG_FCUT)
03936                                         bu_log( "\tvu1 is on eu that ends at vu2, creating new edge (MAGSQ=%g, tol->dist_sq=%g)\n" , dist_to_loop_sq , tol->dist_sq );
03937                                 (void) nmg_ebreaker( vu1->v_p , eu_to, tol );
03938                                 nmg_klu( vu1->up.lu_p );
03939                                 return( 1 );
03940                         }
03941                 }
03942         }
03943         return( 0 );
03944 }
03945 
03946 /**
03947  *                      N M G _ F A C E _ S T A T E _ T R A N S I T I O N
03948  *
03949  *  Given current (old) state, assess the current vertexuse, and
03950  *  pull the appropriate action and new state from the tables.
03951  *  Then perform the indicated action.
03952  *
03953  *  The real work happens in the nmg_assess_vu() and in the tables.
03954  *
03955  *  Explicit Returns -
03956  *      Nothing useful yet.
03957  *
03958  *  Implicit Returns -
03959  *      Modifications to the NMG shell being operated on.
03960  *      Updated state etc. in nmg_ray_state structure.
03961  */
03962 int
03963 nmg_face_state_transition(struct nmg_ray_state *rs, int pos, int multi, int other_rs_state)
03964 {
03965         int                     assessment;
03966         int                     old_state;
03967         int                     new_state;
03968         const struct state_transitions  *stp;
03969         struct vertexuse        *vu;
03970         struct vertexuse        *prev_vu = (struct vertexuse *)NULL;
03971         struct loopuse          *lu;
03972         struct loopuse          *prev_lu;
03973         struct faceuse          *fu;
03974         struct edgeuse          *eu;
03975         struct edgeuse          *first_new_eu;
03976         struct edgeuse          *second_new_eu;
03977         struct edgeuse          *old_eu;
03978         int                     e_assessment;
03979         int                     action;
03980         int                     e_pos;
03981 
03982         NMG_CK_RAYSTATE(rs);
03983         vu = rs->vu[pos];
03984         NMG_CK_VERTEXUSE(vu);
03985         BN_CK_TOL(rs->tol);
03986         if(rs->eg_p) NMG_CK_EDGE_G_LSEG(rs->eg_p);
03987 
03988         if(rt_g.NMG_debug&DEBUG_FCUT)  {
03989                 bu_log("nmg_face_state_transition(vu x%x, pos=%d) START\n",
03990                         vu, pos);
03991                 bu_log("Plotting this loopuse, before action:\n");
03992                 nmg_pr_lu_briefly(nmg_find_lu_of_vu(vu), (char *)0);
03993                 nmg_plot_lu_ray(nmg_find_lu_of_vu(vu),
03994                         rs->vu[0], rs->vu[rs->nvu-1], rs->left );
03995         }
03996 
03997         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
03998                 nmg_vfu( &rs->fu1->s_p->fu_hd, rs->fu1->s_p );
03999                 nmg_vfu( &rs->fu2->s_p->fu_hd, rs->fu2->s_p );
04000                 nmg_fu_touchingloops(rs->fu1);
04001                 nmg_fu_touchingloops(rs->fu2);
04002         }
04003 
04004         assessment = nmg_assess_vu( rs, pos );
04005         old_state = rs->state;
04006         switch( old_state )  {
04007         default:
04008         case NMG_STATE_ERROR:
04009                 rt_bomb("nmg_face_state_transition: was in ERROR state\n");
04010         case NMG_STATE_OUT:
04011                 stp = &nmg_state_is_out[assessment];
04012                 break;
04013         case NMG_STATE_ON_L:
04014                 stp = &nmg_state_is_on_L[assessment];
04015                 break;
04016         case NMG_STATE_ON_R:
04017                 stp = &nmg_state_is_on_R[assessment];
04018                 break;
04019         case NMG_STATE_ON_B:
04020                 stp = &nmg_state_is_on_B[assessment];
04021                 break;
04022         case NMG_STATE_ON_N:
04023                 stp = &nmg_state_is_on_N[assessment];
04024                 break;
04025         case NMG_STATE_IN:
04026                 stp = &nmg_state_is_in[assessment];
04027                 break;
04028         }
04029 
04030         if( assessment != stp->assessment )  {
04031                 bu_log("assessment=%d, stp->assessment=%d, error\n", assessment, stp->assessment);
04032                 rt_bomb("nmg_face_state_transition() bad table\n");
04033         }
04034         action = stp->action;
04035         new_state = stp->new_state;
04036         rs->last_action = action;
04037 
04038         /*
04039          *  Major optimization here.
04040          *  If the state machine for the other face is still in OUT state,
04041          *  then take no actions in this face,
04042          *  because any cutting or joining done here will have no effect
04043          *  on the final result of the boolean, it's just extra work.
04044          *  This can reduce the amount of unnecessary topology by 75% or more.
04045          */
04046         if( other_rs_state == NMG_STATE_OUT && action != NMG_ACTION_ERROR &&
04047             action != NMG_ACTION_NONE )  {
04048                 action = NMG_ACTION_NONE_OPTIM;
04049         }
04050 
04051         if(rt_g.NMG_debug&DEBUG_FCUT)  {
04052                 bu_log("nmg_face_state_transition(vu x%x, pos=%d)\n\told=%s, assessed=%s, new=%s, action=%s\n",
04053                         vu, pos,
04054                         nmg_state_names[old_state], nmg_v_assessment_names[assessment],
04055                         nmg_state_names[new_state], action_names[action] );
04056         }
04057 
04058         /*
04059          *  Force edge geometry that lies on the intersection line
04060          *  to use the edge_g_lseg structure of the intersection line (ray).
04061          */
04062         if( NMG_V_ASSESSMENT_PREV(assessment) == NMG_E_ASSESSMENT_ON_REV )  {
04063                 eu = nmg_find_eu_of_vu(vu);
04064                 eu = BU_LIST_PPREV_CIRC( edgeuse, eu );
04065                 NMG_CK_EDGEUSE(eu);
04066                 if( !rs->eg_p || eu->g.lseg_p != rs->eg_p )  {
04067                         if( rs->eg_p )
04068                                 NMG_CK_EDGE_G_LSEG(rs->eg_p)
04069                         nmg_edge_geom_isect_line( eu, rs, "force ON_REV to line" );
04070                 }
04071         }
04072         if( NMG_V_ASSESSMENT_NEXT(assessment) == NMG_E_ASSESSMENT_ON_FORW )  {
04073                 eu = nmg_find_eu_of_vu(vu);
04074                 NMG_CK_EDGEUSE(eu);
04075                 if( !rs->eg_p || eu->g.lseg_p != rs->eg_p )  {
04076                         if( rs->eg_p )
04077                                 NMG_CK_EDGE_G_LSEG(rs->eg_p)
04078                         nmg_edge_geom_isect_line( eu, rs, "force ON_FORW to line" );
04079                 }
04080         }
04081 
04082         switch( action )  {
04083         default:
04084         case NMG_ACTION_ERROR:
04085         bomb:
04086             {
04087                 struct bu_vls   str;
04088 
04089                 bu_log("nmg_face_state_transition: got action=ERROR\n");
04090                 bu_vls_init(&str);
04091                 bu_vls_printf(&str,"nmg_face_state_transition(vu x%lx, pos=%d)\n\told=%s, assessed=%s, new=%s, action=%s\n",
04092                         (long)vu, pos,
04093                         nmg_state_names[old_state], nmg_v_assessment_names[assessment],
04094                         nmg_state_names[new_state], action_names[action] );
04095              if( RT_G_DEBUG || rt_g.NMG_debug )  {
04096                 /* First, print this faceuse */
04097                 lu = nmg_find_lu_of_vu( vu );
04098                 NMG_CK_LOOPUSE(lu);
04099                 /* Print the faceuse for later analysis */
04100                 bu_log("Loop with the offending vertex\n");
04101                 nmg_pr_lu_briefly(lu, (char *)0);
04102 #if 0
04103                 if(rt_g.NMG_debug&DEBUG_FCUT)  {
04104                         bu_log("The whole face\n");
04105                         nmg_pr_fu(lu->up.fu_p, (char *)0);
04106                 }
04107 #endif
04108 
04109                 /* Drop a plot file */
04110 #if 0
04111                 rt_g.NMG_debug |= DEBUG_FCUT|DEBUG_PLOTEM;
04112                 nmg_pl_comb_fu( 0, 1, lu->up.fu_p );
04113                 nmg_plot_lu_ray(lu, rs->vu[0], rs->vu[rs->nvu-1], rs->left );
04114                 {
04115                         FILE    *fp = fopen("error.pl", "w");
04116                         nmg_pl_m(fp, nmg_find_model((long *)lu));
04117                         fclose(fp);
04118                         bu_log("wrote error.pl\n");
04119                 }
04120                 /* Store this face in a .g file for examination! */
04121                 nmg_stash_model_to_file( "error.g", nmg_find_model((long*)lu), "nmg_fcut.c error dump" );
04122 #endif
04123              }
04124                 /* Explode */
04125                 rt_bomb(bu_vls_addr(&str));
04126             }
04127         case NMG_ACTION_NONE:
04128         case NMG_ACTION_NONE_OPTIM:
04129                 if( *(vu->up.magic_p) != NMG_LOOPUSE_MAGIC )  break;
04130                 lu = vu->up.lu_p;
04131                 if( old_state != NMG_STATE_OUT && lu->orientation == OT_BOOLPLACE )  {
04132                         /* If something connects to the surface of our face,
04133                          * hang on to this vertexuse.
04134                          */
04135                         lu->orientation = lu->lumate_p->orientation = OT_UNSPEC;
04136                 }
04137                 break;
04138         case NMG_ACTION_VFY_EXT:
04139                 /* Verify loop containing this vertex has external orientation */
04140                 lu = nmg_find_lu_of_vu( vu );
04141                 NMG_CK_LOOPUSE(lu);
04142                 switch( lu->orientation )  {
04143                 case OT_SAME:
04144                         break;
04145                 default:
04146                         bu_log("nmg_face_state_transition: VFY_EXT got orientation=%s\n",
04147                                 nmg_orientation(lu->orientation) );
04148                         break;
04149                 }
04150                 break;
04151         case NMG_ACTION_VFY_MULTI:
04152                 /*  Ensure that there are multiple vertexuse's at this
04153                  *  vertex along the ray.
04154                  *  If not, the table entry is illegal.
04155                  */
04156                 if( multi )  break;
04157                 bu_log("nmg_face_state_transition: VFY_MULTI had only 1 vertex\n");
04158                 goto bomb;
04159         case NMG_ACTION_LONE_V_ESPLIT:
04160                 /*
04161                  *  Split edge to include vertex from this lone vert loop.
04162                  *  This only happens in an "ON" state, so split the edge that
04163                  *  starts (or ends) with the previously seen vertex.
04164                  *  Note that the forward going edge may point the wrong way,
04165                  *  i.e., not lie on the ray at all.
04166                  *  Also note that the previous member(s) of vu[] may be
04167                  *  lone vert loops that were not processed due to optimization,
04168                  *  so it may be necessary to look back a ways to find
04169                  *  the vertexuse which started this ON edge.
04170                  */
04171                 lu = nmg_find_lu_of_vu( vu );
04172                 NMG_CK_LOOPUSE(lu);
04173                 for( e_pos = pos-1; e_pos >= 0; e_pos-- )  {
04174                         prev_vu = rs->vu[e_pos];
04175                         NMG_CK_VERTEXUSE(prev_vu);
04176                         prev_lu = nmg_find_lu_of_vu( prev_vu );
04177                         /* lu is lone vert loop; l_p is distinct from prev_lu->l_p */
04178                         if( *prev_vu->up.magic_p == NMG_EDGEUSE_MAGIC )
04179                                 break;
04180                         /* Not an edgeuse, prob. a loopuse, continue backwards */
04181 #if 0
04182                         bu_log("prev_vu->up is %s\n", bu_identify_magic(*prev_vu->up.magic_p) );
04183                         nmg_pr_vu(prev_vu, "prev ");
04184                         nmg_pr_vu(rs->vu[e_pos], "cur  ");
04185 #endif
04186                 }
04187                 if( e_pos < 0 ) rt_bomb("nmg_face_state_transition: LONE_V_ESPLIT can't find start of edge!\n");
04188                 eu = prev_vu->up.eu_p;
04189                 NMG_CK_EDGEUSE(eu);
04190                 e_assessment = nmg_assess_eu( eu, 1, rs, e_pos );       /* forw */
04191                 if( e_assessment == NMG_E_ASSESSMENT_ON_FORW )  {
04192                         /* "eu" (forw) is the right edge to split */
04193                 } else {
04194                         e_assessment = nmg_assess_eu( eu, 0, rs, e_pos ); /*rev*/
04195                         if( e_assessment == NMG_E_ASSESSMENT_ON_REV )  {
04196                                 /* (reverse) "eu" is the right one */
04197                                 eu = BU_LIST_PPREV_CIRC( edgeuse, eu );
04198                         } else {
04199                                 /* What went wrong? */
04200                                 bu_log("LONE_V_ESPLIT:  rev e_assessment = %s\n", nmg_e_assessment_names[e_assessment]);
04201                                 rt_bomb("nmg_face_state_transition: LONE_V_ESPLIT could not find ON edge to split\n");
04202                         }
04203                 }
04204                 /* Break edge, update vu table with new value */
04205                 if( vu->v_p == eu->vu_p->v_p )  {
04206                         /* Edge already starts at same vertex */
04207                         rs->vu[pos] = eu->vu_p;
04208                 } else if( vu->v_p == eu->eumate_p->vu_p->v_p )  {
04209                         /* Edge already ends at same vertex */
04210                         rs->vu[pos] = BU_LIST_PNEXT_CIRC(edgeuse, eu)->vu_p;
04211                 } else {
04212                         /* Break edge, force onto isect line */
04213                         nmg_edge_geom_isect_line( eu, rs, "LONE_V_ESPLIT, before edge split" );
04214                         rs->vu[pos] = nmg_ebreaker( vu->v_p, eu, rs->tol )->vu_p;
04215                 }
04216                 /* Kill lone vertex loop (and vertexuse) */
04217                 nmg_klu(lu);
04218                 if(rt_g.NMG_debug&DEBUG_FCUT)  {
04219                         bu_log("After LONE_V_ESPLIT, the final loop:\n");
04220                         lu = nmg_find_lu_of_vu(rs->vu[pos]);
04221                         NMG_CK_LOOPUSE(lu);
04222                         nmg_pr_lu(lu, "   ");
04223                         nmg_plot_lu_ray(lu, rs->vu[0], rs->vu[rs->nvu-1], rs->left );
04224                 }
04225                 break;
04226         case NMG_ACTION_LONE_V_JAUNT:
04227                 /*
04228                  * Take current loop on a jaunt from current (prev_vu) edge
04229                  * up to the vertex (vu) of this lone vertex loop,
04230                  * and back again.
04231                  * This only happens in "IN" state.
04232                  */
04233                 prev_vu = rs->vu[pos-1];
04234                 NMG_CK_VERTEXUSE(prev_vu);
04235 
04236                 if( *prev_vu->up.magic_p == NMG_LOOPUSE_MAGIC )  {
04237                         /* Both prev and current are lone vertex loops */
04238                         rs->vu[pos] = nmg_join_2singvu_loops( prev_vu, vu );
04239                         /* Set orientation */
04240                         lu = nmg_find_lu_of_vu(rs->vu[pos]);
04241                         NMG_CK_LOOPUSE(lu);
04242                         /* If state is IN, this is a "crack" loop */
04243                         nmg_set_lu_orientation( lu, old_state==NMG_STATE_IN );
04244                 } else {
04245                         rs->vu[pos] = nmg_join_singvu_loop( prev_vu, vu );
04246                 }
04247 
04248                 /*  We know edge geom is null, make it be the isect line */
04249                 first_new_eu = BU_LIST_PPREV_CIRC(edgeuse, rs->vu[pos]->up.eu_p);
04250                 nmg_edge_geom_isect_line( first_new_eu, rs, "LONE_V_JAUNT, new edge" );
04251 
04252                 /* Fusing to this new edge will happen in nmg_face_cutjoin() */
04253 
04254                 /* Recompute loop geometry.  Bounding box may have expanded */
04255                 nmg_loop_g(nmg_find_lu_of_vu(rs->vu[pos])->l_p, rs->tol);
04256 
04257                 if(rt_g.NMG_debug&DEBUG_FCUT)  {
04258                         bu_log("After LONE_V_JAUNT, the final loop:\n");
04259                         nmg_pr_lu_briefly(nmg_find_lu_of_vu(rs->vu[pos]), (char *)0);
04260                         nmg_plot_lu_ray(nmg_find_lu_of_vu(rs->vu[pos]),
04261                                 rs->vu[0], rs->vu[rs->nvu-1], rs->left );
04262                 }
04263                 break;
04264         case NMG_ACTION_CUTJOIN:
04265                 /*
04266                  *  Cut loop into two, or join two into one.
04267                  *  The operation happens between the previous vu
04268                  *  and the current one.
04269                  *  If the two vu's are part of the same loop,
04270                  *  then cut the loop into two, otherwise
04271                  *  join the two loops into one.
04272                  */
04273                 lu = nmg_find_lu_of_vu( vu );
04274                 NMG_CK_LOOPUSE(lu);
04275                 fu = lu->up.fu_p;
04276                 NMG_CK_FACEUSE(fu);
04277                 prev_vu = rs->vu[pos-1];
04278                 NMG_CK_VERTEXUSE(prev_vu);
04279                 prev_lu = nmg_find_lu_of_vu( prev_vu );
04280                 NMG_CK_LOOPUSE(prev_lu);
04281 
04282                 /* See if there is an edge joining the 2 vertices already */
04283                 old_eu = nmg_findeu(prev_vu->v_p, vu->v_p, (struct shell *)NULL,
04284                         (struct edgeuse *)NULL, 0);
04285 
04286                 if( lu->l_p == prev_lu->l_p )  {
04287                         int is_crack;
04288 
04289                         /* Same loop, cut into two */
04290                         is_crack = nmg_loop_is_a_crack(lu);
04291                         if(rt_g.NMG_debug&DEBUG_FCUT)
04292                                 bu_log("Calling nmg_cut_loop(prev_vu=x%x, vu=x%x) is_crack=%d, old_eu=x%x\n", prev_vu, vu, is_crack, old_eu);
04293                         if( prev_vu->v_p == vu->v_p )  {
04294                                 /* The loop touches itself already */
04295                                 lu = nmg_split_lu_at_vu( prev_lu, prev_vu );
04296                         } else {
04297                                 lu = nmg_cut_loop( prev_vu, vu );
04298 
04299                                 /* New edge has been created between 2 verts, fuse */
04300                                 /* first_new_eu starts at vu, ends at prev_vu */
04301                                 /* second_new_eu starts at prev_vu, ends at vu */
04302                                 first_new_eu = BU_LIST_PPREV_CIRC( edgeuse, &prev_vu->up.eu_p->l );
04303                                 second_new_eu = BU_LIST_PPREV_CIRC( edgeuse, &vu->up.eu_p->l );
04304                                 NMG_CK_EDGEUSE(first_new_eu);
04305                                 NMG_CK_EDGEUSE(second_new_eu);
04306                                 if( first_new_eu->vu_p->v_p != vu->v_p || first_new_eu->eumate_p->vu_p->v_p != prev_vu->v_p )  {
04307                                         nmg_pr_vu_briefly(prev_vu, 0);
04308                                         nmg_pr_vu_briefly(vu, 0);
04309                                         nmg_pr_eu_endpoints(first_new_eu, 0);
04310                                         nmg_pr_eu_endpoints(second_new_eu, 0);
04311                                         if(old_eu)      nmg_pr_eu_endpoints(old_eu, 0);
04312                                         rt_bomb("nmg_face_state_transition() cut loop bafflement\n");
04313                                 }
04314                                 /* Fuse new edge to intersect line, old edge */
04315                                 nmg_edge_geom_isect_line( first_new_eu, rs, "CUTJOIN, new edge after loop cut" );
04316                                 if( old_eu )  nmg_radial_join_eu( old_eu, first_new_eu, rs->tol );
04317                         }
04318 
04319                         nmg_loop_g( lu->l_p, rs->tol );
04320                         nmg_loop_g( prev_lu->l_p, rs->tol );
04321 
04322                         nmg_lu_reorient( lu );
04323                         nmg_lu_reorient( prev_lu );
04324 
04325                         if(rt_g.NMG_debug&DEBUG_FCUT)  {
04326                                 bu_log("After CUT, the final loop:\n");
04327                                 nmg_pr_lu_briefly(nmg_find_lu_of_vu(rs->vu[pos]), (char *)0);
04328                                 nmg_plot_lu_ray(nmg_find_lu_of_vu(rs->vu[pos]),
04329                                         rs->vu[0], rs->vu[rs->nvu-1], rs->left );
04330                         }
04331                         break;
04332                 }
04333                 /*
04334                  *  prev_vu and vu are in different loops,
04335                  *  join the two loops into one loop.
04336                  *  No edgeuses are deleted at this stage,
04337                  *  so some "snakes" may appear in the process.
04338                  */
04339                 if(rt_g.NMG_debug&DEBUG_FCUT)  {
04340                         bu_log("nmg_face_state_transition() joining 2 loops, prev_vu=x%x, vu=x%x, old_eu=x%x\n",
04341                                 prev_vu, vu, old_eu);
04342                 }
04343 
04344                 if( *prev_vu->up.magic_p == NMG_LOOPUSE_MAGIC ||
04345                     *vu->up.magic_p == NMG_LOOPUSE_MAGIC )  {
04346                         /* One (or both) is a loop of a single vertex */
04347                         /* This is the special boolean vertex marker */
04348 
04349                         /* See if there is an existing edge between
04350                          * the two vertices.
04351                          */
04352 
04353                         if( *prev_vu->up.magic_p == NMG_LOOPUSE_MAGIC &&
04354                             *vu->up.magic_p != NMG_LOOPUSE_MAGIC )  {
04355                                 if(rt_g.NMG_debug&DEBUG_FCUT)
04356                                         bu_log( "\tprev_vu is a vertex loop\n" );
04357                                 /* if prev_vu is geometrically on an edge that goes through vu,
04358                                  * then split that edge at prev_vu */
04359                                 rs->vu[pos-1] = nmg_join_singvu_loop( vu, prev_vu );
04360                         } else if( *vu->up.magic_p == NMG_LOOPUSE_MAGIC &&
04361                             *prev_vu->up.magic_p != NMG_LOOPUSE_MAGIC )  {
04362                                 if(rt_g.NMG_debug&DEBUG_FCUT)
04363                                         bu_log( "\tvu is a vertex loop\n" );
04364                                 /* if vu is geometrically on an edge that goes through prev_vu,
04365                                  * then split that edge at vu */
04366                                 rs->vu[pos] = nmg_join_singvu_loop( prev_vu, vu );
04367                         } else {
04368                                 /* Both are loops of single vertex */
04369                                 if(rt_g.NMG_debug&DEBUG_FCUT)
04370                                         bu_log( "\tprev_vu and vu are vertex loops\n" );
04371                                 vu = rs->vu[pos] = nmg_join_2singvu_loops( prev_vu, vu );
04372                                 /* Set orientation */
04373                                 lu = nmg_find_lu_of_vu(vu);
04374                                 NMG_CK_LOOPUSE(lu);
04375                                 nmg_set_lu_orientation( lu, old_state==NMG_STATE_IN );
04376                         }
04377                 } else {
04378                         rs->vu[pos] = nmg_join_2loops( prev_vu, vu );
04379                 }
04380 
04381                 /* XXX If an edge has been built between prev_vu and vu,
04382                  * force it's geometry to lie on the ray.
04383                  */
04384                 vu = rs->vu[pos];
04385                 lu = nmg_find_lu_of_vu(vu);
04386                 NMG_CK_LOOPUSE(lu);
04387                 prev_vu = rs->vu[pos-1];
04388                 eu = prev_vu->up.eu_p;
04389                 NMG_CK_EDGEUSE(eu);
04390                 first_new_eu = BU_LIST_PPREV_CIRC(edgeuse, rs->vu[pos]->up.eu_p);
04391                 NMG_CK_EDGEUSE(first_new_eu);
04392                 if( eu == first_new_eu )  {
04393                         nmg_edge_geom_isect_line( first_new_eu, rs, "CUTJOIN new edge" );
04394                         if( old_eu )  nmg_radial_join_eu( old_eu, eu, rs->tol );
04395                 }
04396 
04397                 /* Recompute loop geometry.  Bounding box may have expanded */
04398                 nmg_loop_g(lu->l_p, rs->tol);
04399 
04400                 if(rt_g.NMG_debug&DEBUG_FCUT)  {
04401                         bu_log("After JOIN, the final loop:\n");
04402                         nmg_pr_lu_briefly(lu, (char *)0);
04403                         nmg_plot_lu_ray( lu, rs->vu[0], rs->vu[rs->nvu-1], rs->left );
04404                 }
04405                 break;
04406         }
04407 
04408         rs->state = new_state;
04409 
04410         if( rt_g.NMG_debug & DEBUG_VERIFY )  {
04411                 /* Verify both faces are still OK */
04412                 nmg_vfu( &rs->fu1->s_p->fu_hd, rs->fu1->s_p );
04413                 nmg_vfu( &rs->fu2->s_p->fu_hd, rs->fu2->s_p );
04414 nmg_fu_touchingloops(rs->fu1);
04415 nmg_fu_touchingloops(rs->fu2);
04416         }
04417 
04418         if(rt_g.NMG_debug&DEBUG_FCUT)  {
04419                 bu_log("nmg_face_state_transition(vu x%x, pos=%d) END\n",
04420                         rs->vu[pos], pos);
04421         }
04422         if(rs->eg_p) NMG_CK_EDGE_G_LSEG(rs->eg_p);
04423         return 0;
04424 }
04425 
04426 
04427 /*
04428  * Local Variables:
04429  * mode: C
04430  * tab-width: 8
04431  * c-basic-offset: 4
04432  * indent-tabs-mode: t
04433  * End:
04434  * ex: shiftwidth=4 tabstop=8
04435  */

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