nmg_tri.c

Go to the documentation of this file.
00001 /*                       N M G _ T R I . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1994-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 /** @addtogroup nmg */
00022 /*@{*/
00023 /** @file nmg_tri.c
00024  *  Triangulate the faces of a polygonal NMG.
00025  *
00026  *  Author -
00027  *      Lee A. Butler
00028  *
00029  *  Source -
00030  *      The U. S. Army Research Laboratory
00031  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00032  */
00033 /*@}*/
00034 
00035 #ifndef lint
00036 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_tri.c,v 14.14 2006/09/16 02:04:25 lbutler Exp $ (ARL)";
00037 #endif
00038 
00039 #include "common.h"
00040 
00041 #include <stdlib.h>
00042 #include <stdio.h>
00043 #include <math.h>
00044 
00045 #include "machine.h"
00046 #include "vmath.h"
00047 #include "nmg.h"
00048 #include "raytrace.h"
00049 #include "plot3.h"
00050 
00051 
00052 /* macros for comparing 2D points in scanline order */
00053 /* XXX maybe should use near zero tolerance instead */
00054 #define TOL_2D  1.0e-10
00055 #define P_GT_V(_p, _v) \
00056         (((_p)->coord[Y] - (_v)->coord[Y]) > TOL_2D || (NEAR_ZERO((_p)->coord[Y] - (_v)->coord[Y], TOL_2D) && (_p)->coord[X] < (_v)->coord[X]))
00057 #define P_LT_V(_p, _v) \
00058         (((_p)->coord[Y] - (_v)->coord[Y]) < (-TOL_2D) || (NEAR_ZERO((_p)->coord[Y] - (_v)->coord[Y], TOL_2D) && (_p)->coord[X] > (_v)->coord[X]))
00059 #define P_GE_V(_p, _v) \
00060         (((_p)->coord[Y] - (_v)->coord[Y]) > TOL_2D || (NEAR_ZERO((_p)->coord[Y] - (_v)->coord[Y], TOL_2D) && (_p)->coord[X] <= (_v)->coord[X]))
00061 #define P_LE_V(_p, _v) \
00062         (((_p)->coord[Y] - (_v)->coord[Y]) < (-TOL_2D) || (NEAR_ZERO((_p)->coord[Y] - (_v)->coord[Y], TOL_2D) && (_p)->coord[X] >= (_v)->coord[X]))
00063 
00064 #define NMG_PT2D_MAGIC  0x2d2d2d2d
00065 #define NMG_TRAP_MAGIC  0x1ab1ab
00066 #define NMG_CK_PT2D(_p) NMG_CKMAG(_p, NMG_PT2D_MAGIC, "pt2d")
00067 #define NMG_CK_TRAP(_p) {NMG_CKMAG(_p, NMG_TRAP_MAGIC, "trap");\
00068         if ( ! BU_LIST_PREV(bu_list, &(_p)->l) ) {\
00069                 bu_log("%s %d bad prev pointer of trapezoid 0x%08x\n",\
00070                         __FILE__, __LINE__, &(_p)->l);\
00071                 rt_bomb("NMG_CK_TRAP: aborting");\
00072         } else if (! BU_LIST_NEXT(bu_list, &(_p)->l) ) {\
00073                 bu_log("%s %d bad next pointer of trapezoid 0x%08x\n",\
00074                         __FILE__, __LINE__, &(_p)->l);\
00075                 rt_bomb("NMG_CL_TRAP: aborting");\
00076         }}
00077 
00078 #define NMG_TBL2D_MAGIC 0x3e3e3e3e
00079 #define NMG_CK_TBL2D(_p) NMG_CKMAG(_p, NMG_TBL2D_MAGIC, "tbl2d")
00080 
00081 /* macros to retrieve the next/previous 2D point about loop */
00082 #define PT2D_NEXT(tbl, pt) pt2d_pn(tbl, pt, 1)
00083 #define PT2D_PREV(tbl, pt) pt2d_pn(tbl, pt, -1)
00084 
00085 struct pt2d {
00086         struct bu_list  l;              /* scanline ordered list of points */
00087         fastf_t coord[3];               /* point coordinates in 2-D space */
00088         struct vertexuse *vu_p;         /* associated vertexuse */
00089 };
00090 
00091 
00092 struct trap {
00093         struct bu_list  l;
00094         struct pt2d     *top;      /* point at top of trapezoid */
00095         struct pt2d     *bot;      /* point at bottom of trapezoid */
00096         struct edgeuse  *e_left;
00097         struct edgeuse  *e_right;
00098 };
00099 
00100 /* if there is an edge in this face which connects the points
00101  *      return 1
00102  * else
00103  *      return 0
00104  */
00105 
00106 
00107 /* subroutine version to pass to the rt_tree functions */
00108 int PvsV(struct trap *p, struct trap *v)
00109 {
00110         NMG_CK_TRAP(p);
00111         NMG_CK_TRAP(v);
00112 
00113         if (p->top->coord[Y] > v->top->coord[Y]) return(1);
00114         else if (p->top->coord[Y] < v->top->coord[Y]) return(-1);
00115         else if (p->top->coord[X] < v->top->coord[X]) return(1);
00116         else if (p->top->coord[X] > v->top->coord[X]) return(-1);
00117         else    return(0);
00118 }
00119 
00120 
00121 static struct pt2d *find_pt2d(struct bu_list *tbl2d, struct vertexuse *vu);
00122 static FILE *plot_fd;
00123 
00124 static void
00125 print_2d_eu(char *s, struct edgeuse *eu, struct bu_list *tbl2d)
00126 {
00127         struct pt2d *pt, *pt_next;
00128         NMG_CK_TBL2D(tbl2d);
00129         NMG_CK_EDGEUSE(eu);
00130 
00131         pt = find_pt2d(tbl2d, eu->vu_p);
00132         pt_next = find_pt2d(tbl2d, (BU_LIST_PNEXT_CIRC(edgeuse, eu))->vu_p);
00133         bu_log("%s: 0x%08x %g %g -> %g %g\n", s, eu,
00134                 pt->coord[X], pt->coord[Y],
00135                 pt_next->coord[X], pt_next->coord[Y]);
00136 }
00137 
00138 
00139 static void
00140 print_trap(struct trap *tp, struct bu_list *tbl2d)
00141 {
00142         NMG_CK_TBL2D(tbl2d);
00143         NMG_CK_TRAP(tp);
00144 
00145         bu_log("trap 0x%08x top pt2d: 0x%08x %g %g vu:0x%08x\n",
00146                         tp,
00147                         &tp->top, tp->top->coord[X], tp->top->coord[Y],
00148                         tp->top->vu_p);
00149 
00150         if (tp->bot)
00151                 bu_log("\t\tbot pt2d: 0x%08x %g %g vu:0x%08x\n",
00152                         &tp->bot, tp->bot->coord[X], tp->bot->coord[Y],
00153                         tp->bot->vu_p);
00154         else {
00155                 bu_log("\tbot (nil)\n");
00156         }
00157 
00158         if (tp->e_left)
00159                 print_2d_eu("\t\t  e_left", tp->e_left, tbl2d);
00160 
00161         if (tp->e_right)
00162                 print_2d_eu("\t\t e_right", tp->e_right, tbl2d);
00163 }
00164 static void
00165 print_tlist(struct bu_list *tbl2d, struct bu_list *tlist)
00166 {
00167         struct trap *tp;
00168         NMG_CK_TBL2D(tbl2d);
00169 
00170         bu_log("Trapezoid list start ----------\n");
00171         for (BU_LIST_FOR(tp, trap, tlist)) {
00172                 NMG_CK_TRAP(tp);
00173                 print_trap(tp, tbl2d);
00174         }
00175         bu_log("Trapezoid list end ----------\n");
00176 }
00177 
00178 static int flatten_debug=1;
00179 
00180 static struct pt2d *
00181 find_pt2d(struct bu_list *tbl2d, struct vertexuse *vu)
00182 {
00183         struct pt2d *p;
00184         NMG_CK_TBL2D(tbl2d);
00185         NMG_CK_VERTEXUSE(vu);
00186 
00187         for (BU_LIST_FOR(p, pt2d, tbl2d)) {
00188                 if (p->vu_p == vu) {
00189                         return p;
00190                 }
00191         }
00192         return (struct pt2d *)NULL;
00193 }
00194 
00195 static void
00196 nmg_tri_plfu(struct faceuse *fu, struct bu_list *tbl2d)
00197 {
00198         static int file_number=0;
00199         FILE *fd;
00200         char name[25];
00201         char buf[80];
00202         long *b;
00203         struct loopuse *lu;
00204         struct edgeuse *eu;
00205         struct vertexuse *vu;
00206         struct pt2d *p;
00207 
00208         NMG_CK_TBL2D(tbl2d);
00209         NMG_CK_FACEUSE(fu);
00210 
00211         sprintf(name, "tri%02d.pl", file_number++);
00212         if ((fd=fopen(name, "w")) == (FILE *)NULL) {
00213                 perror(name);
00214                 abort();
00215         }
00216 
00217         bu_log("\tplotting %s\n", name);
00218         b = (long *)bu_calloc( fu->s_p->r_p->m_p->maxindex,
00219                 sizeof(long), "bit vec"),
00220 
00221         pl_erase(fd);
00222         pd_3space(fd,
00223                 fu->f_p->min_pt[0]-1.0,
00224                 fu->f_p->min_pt[1]-1.0,
00225                 fu->f_p->min_pt[2]-1.0,
00226                 fu->f_p->max_pt[0]+1.0,
00227                 fu->f_p->max_pt[1]+1.0,
00228                 fu->f_p->max_pt[2]+1.0);
00229 
00230         nmg_pl_fu(fd, fu, b, 255, 255, 255);
00231 
00232         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
00233                 NMG_CK_LOOPUSE(lu);
00234                 if ( BU_LIST_IS_EMPTY(&lu->down_hd) ) {
00235                         bu_log("Empty child list for loopuse %s %d\n", __FILE__, __LINE__);
00236                 } else if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC){
00237                         vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
00238                         pdv_3move(fd, vu->v_p->vg_p->coord);
00239                         if ( (p=find_pt2d(tbl2d, vu)) ) {
00240                                 sprintf(buf, "%g, %g",
00241                                         p->coord[0], p->coord[1]);
00242                                 pl_label(fd, buf);
00243                         } else
00244                                 pl_label(fd, "X, Y (no 2D coords)");
00245 
00246                 } else {
00247                         eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
00248                         NMG_CK_EDGEUSE( eu );
00249 
00250                         for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
00251                                 if ( (p=find_pt2d(tbl2d,eu->vu_p)) ) {
00252                                         pdv_3move(fd, eu->vu_p->v_p->vg_p->coord);
00253 
00254                                         sprintf(buf, "%g, %g",
00255                                                 p->coord[0], p->coord[1]);
00256                                         pl_label(fd, buf);
00257                                 } else
00258                                         pl_label(fd, "X, Y (no 2D coords)");
00259                         }
00260                 }
00261         }
00262 
00263 
00264         bu_free((char *)b, "plot table");
00265         fclose(fd);
00266 }
00267 
00268 
00269 
00270 /**     P T 2 D _ P N
00271  *
00272  *      Return Prev/Next 2D pt about loop from given 2D pt.
00273  *      if vertex is child of loopuse, return parameter 2D pt.
00274  */
00275 static struct pt2d *
00276 pt2d_pn(struct bu_list *tbl, struct pt2d *pt, int dir)
00277 {
00278         struct edgeuse *eu, *eu_other;
00279         struct pt2d *new_pt;
00280 
00281         NMG_CK_TBL2D(tbl);
00282         NMG_CK_PT2D( pt );
00283         NMG_CK_VERTEXUSE( (pt)->vu_p );
00284 
00285         if ( *(pt)->vu_p->up.magic_p == NMG_EDGEUSE_MAGIC) {
00286                 eu = (pt)->vu_p->up.eu_p;
00287                 NMG_CK_EDGEUSE( eu );
00288                 if (dir < 0)
00289                         eu_other = BU_LIST_PPREV_CIRC(edgeuse, eu);
00290                 else
00291                         eu_other = BU_LIST_PNEXT_CIRC(edgeuse, eu);
00292 
00293                 new_pt = find_pt2d(tbl, eu_other->vu_p);
00294                 if (new_pt == (struct pt2d *)NULL) {
00295                         if (dir < 0)
00296                                 bu_log("can't find prev of %g %g\n",
00297                                         pt->coord[X],
00298                                         pt->coord[Y]);
00299                         else
00300                                 bu_log("can't find next of %g %g\n",
00301                                         pt->coord[X],
00302                                         pt->coord[Y]);
00303                         rt_bomb("goodbye\n");
00304                 }
00305                 NMG_CK_PT2D( new_pt );
00306                 return new_pt;
00307         }
00308 
00309         if ( *(pt)->vu_p->up.magic_p != NMG_LOOPUSE_MAGIC) {
00310                 bu_log("%s %d Bad vertexuse parent (%g %g %g)\n",
00311                         __FILE__, __LINE__,
00312                         V3ARGS( (pt)->vu_p->v_p->vg_p->coord ) );
00313                 rt_bomb("goodbye\n");
00314         }
00315 
00316         return pt;
00317 }
00318 
00319 
00320 
00321 /**     M A P _ V U _ T O _ 2 D
00322  *
00323  *      Add a vertex to the 2D table if it isn't already there.
00324  */
00325 static void
00326 map_vu_to_2d(struct vertexuse *vu, struct bu_list *tbl2d, fastf_t *mat, struct faceuse *fu)
00327 {
00328         struct vertex_g *vg;
00329         struct vertexuse *vu_p;
00330         struct vertex *vp;
00331         struct pt2d *p, *np;
00332 
00333         NMG_CK_TBL2D(tbl2d);
00334         NMG_CK_VERTEXUSE(vu);
00335         NMG_CK_FACEUSE(fu);
00336 
00337         /* if this vertexuse has already been transformed, we're done */
00338         if (find_pt2d(tbl2d, vu)) return;
00339 
00340 
00341         np = (struct pt2d *)bu_calloc(1, sizeof(struct pt2d), "pt2d struct");
00342         np->coord[2] = 0.0;
00343         np->vu_p = vu;
00344         BU_LIST_MAGIC_SET(&np->l, NMG_PT2D_MAGIC);
00345 
00346         /* if one of the other vertexuses has been mapped, use that data */
00347         for (BU_LIST_FOR(vu_p, vertexuse, &vu->v_p->vu_hd)) {
00348                 if ( (p = find_pt2d(tbl2d, vu_p)) ) {
00349                         VMOVE(np->coord, p->coord);
00350                         return;
00351                 }
00352         }
00353 
00354         /* transform the 3-D vertex into a 2-D vertex */
00355         vg = vu->v_p->vg_p;
00356         MAT4X3PNT(np->coord, mat, vg->coord);
00357 
00358 
00359         if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug) bu_log(
00360                 "Transforming 0x%x 3D(%g, %g, %g) to 2D(%g, %g, %g)\n",
00361                 vu, V3ARGS(vg->coord), V3ARGS(np->coord) );
00362 
00363         /* find location in scanline ordered list for vertex */
00364         for ( BU_LIST_FOR(p, pt2d, tbl2d) ) {
00365                 if (P_GT_V(p, np)) continue;
00366                 break;
00367         }
00368         BU_LIST_INSERT(&p->l, &np->l);
00369 
00370         if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug)
00371                 bu_log("transforming other vertexuses...\n");
00372 
00373         /* for all other uses of this vertex in this face, store the
00374          * transformed 2D vertex
00375          */
00376         vp = vu->v_p;
00377 
00378         for (BU_LIST_FOR(vu_p, vertexuse, &vp->vu_hd)) {
00379                 register struct faceuse *fu_of_vu;
00380                 NMG_CK_VERTEXUSE(vu_p);
00381 
00382                 if (vu_p == vu) continue;
00383 
00384                 fu_of_vu = nmg_find_fu_of_vu(vu_p);
00385                 if( !fu_of_vu )  continue;      /* skip vu's of wire edges */
00386                 NMG_CK_FACEUSE(fu_of_vu);
00387                 if (fu_of_vu != fu) continue;
00388 
00389                 if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug)
00390                         bu_log("transform 0x%x... ", vu_p);
00391 
00392                 /* if vertexuse already transformed, skip it */
00393                 if (find_pt2d(tbl2d, vu_p)) {
00394                         if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug) {
00395                                 bu_log("vertexuse already transformed\n", vu);
00396                                 nmg_pr_vu(vu, NULL);
00397                         }
00398                         continue;
00399                 }
00400 
00401                 /* add vertexuse to list */
00402                 p = (struct pt2d *)bu_calloc(1, sizeof(struct pt2d), "pt2d");
00403                 p->vu_p = vu_p;
00404                 VMOVE(p->coord, np->coord);
00405                 BU_LIST_MAGIC_SET(&p->l, NMG_PT2D_MAGIC);
00406 
00407                 BU_LIST_APPEND(&np->l, &p->l);
00408 
00409                 if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug)
00410                         (void)bu_log( "vertexuse transformed\n");
00411         }
00412         if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug)
00413                 (void)bu_log( "Done.\n");
00414 }
00415 
00416 /**     N M G _ F L A T T E N _ F A C E
00417  *
00418  *      Create the 2D coordinate table for the vertexuses of a face.
00419  *
00420  *      ---------       -----------------------------------
00421  *      |pt2d --+-----> |     struct pt2d.{magic,coord[3]} |
00422  *      ---------       -----------------------------------
00423  *                      |     struct pt2d.{magic,coord[3]} |
00424  *                      -----------------------------------
00425  *                      |     struct pt2d.{magic,coord[3]} |
00426  *                      -----------------------------------
00427  *
00428  *      When the caller is done, nmg_free_2d_map() should be called to dispose
00429  *      of the map
00430  */
00431 struct bu_list *
00432 nmg_flatten_face(struct faceuse *fu, fastf_t *TformMat)
00433 {
00434         static const vect_t twoDspace = { 0.0, 0.0, 1.0 };
00435         struct bu_list *tbl2d;
00436         struct vertexuse *vu;
00437         struct loopuse *lu;
00438         struct edgeuse *eu;
00439         vect_t Normal;
00440 
00441         NMG_CK_FACEUSE(fu);
00442 
00443         tbl2d = (struct bu_list *)bu_calloc(1, sizeof(struct bu_list),
00444                 "2D coordinate list");
00445 
00446         /* we use the 0 index entry in the table as the head of the sorted
00447          * list of verticies.  This is safe since the 0 index is always for
00448          * the model structure
00449          */
00450 
00451         BU_LIST_INIT( tbl2d );
00452         BU_LIST_MAGIC_SET(tbl2d, NMG_TBL2D_MAGIC);
00453 
00454         /* construct the matrix that maps the 3D coordinates into 2D space */
00455         NMG_GET_FU_NORMAL(Normal, fu);
00456         bn_mat_fromto( TformMat, Normal, twoDspace );
00457 
00458         if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug)
00459                 bn_mat_print( "TformMat", TformMat );
00460 
00461 
00462         /* convert each vertex in the face to its 2-D equivalent */
00463         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
00464                 if (rt_g.NMG_debug & DEBUG_TRI) {
00465                         switch (lu->orientation) {
00466                         case OT_NONE:   bu_log("flattening OT_NONE loop\n"); break;
00467                         case OT_SAME:   bu_log("flattening OT_SAME loop\n"); break;
00468                         case OT_OPPOSITE:bu_log("flattening OT_OPPOSITE loop\n"); break;
00469                         case OT_UNSPEC: bu_log("flattening OT_UNSPEC loop\n"); break;
00470                         case OT_BOOLPLACE:bu_log("flattening OT_BOOLPLACE loop\n"); break;
00471                         default: bu_log("flattening bad orientation loop\n"); break;
00472                         }
00473                 }
00474                 if (BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC) {
00475                         vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
00476                         if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug)
00477                                 bu_log("vertex loop\n");
00478                         map_vu_to_2d(vu, tbl2d, TformMat, fu);
00479 
00480                 } else if (BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_EDGEUSE_MAGIC) {
00481                         if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug)
00482                                 bu_log("edge loop\n");
00483                         for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
00484                                 vu = eu->vu_p;
00485                                 if (rt_g.NMG_debug & DEBUG_TRI && flatten_debug)
00486                                         bu_log("(%g %g %g) -> (%g %g %g)\n",
00487                                                 V3ARGS(vu->v_p->vg_p->coord),
00488                                                 V3ARGS(eu->eumate_p->vu_p->v_p->vg_p->coord));
00489                                 map_vu_to_2d(vu, tbl2d, TformMat, fu);
00490                         }
00491                 } else rt_bomb("bad magic of loopuse child\n");
00492         }
00493 
00494         return(tbl2d);
00495 }
00496 
00497 
00498 
00499 static int
00500 is_convex(struct pt2d *a, struct pt2d *b, struct pt2d *c, const struct bn_tol *tol)
00501 {
00502         vect_t ab, bc, pv, N;
00503         double angle;
00504 
00505         NMG_CK_PT2D(a);
00506         NMG_CK_PT2D(b);
00507         NMG_CK_PT2D(c);
00508 
00509         /* invent surface normal */
00510         VSET(N, 0.0, 0.0, 1.0);
00511 
00512         /* form vector from a->b */
00513         VSUB2(ab, b->coord, a->coord);
00514 
00515         /* Form "left" vector */
00516         VCROSS(pv, N, ab);
00517 
00518         /* form vector from b->c */
00519         VSUB2(bc, c->coord, b->coord);
00520 
00521         /* find angle about normal in "pv" direction from a->b to b->c */
00522         angle = bn_angle_measure( bc, ab, pv );
00523 
00524         if (rt_g.NMG_debug & DEBUG_TRI)
00525                 bu_log("\tangle == %g tol angle: %g\n", angle, tol->perp);
00526 
00527         return (angle > tol->perp && angle <= M_PI-tol->perp);
00528 }
00529 
00530 #define POLY_SIDE 1
00531 #define HOLE_START 2
00532 #define POLY_START 3
00533 #define HOLE_END 4
00534 #define POLY_END 5
00535 #define HOLE_POINT 6
00536 #define POLY_POINT 7
00537 
00538 
00539 
00540 /**
00541  *
00542  *      characterize the edges which meet at this vertex.
00543  *
00544  *        1          2         3           4        5         6         7
00545  *
00546  *      /- -\     -------               -\   /-     \---/  -------
00547  *     /-- --\    ---O---       O       --\ /--      \-/   ---O---      O
00548  *    O--- ---O   --/ \--      /-\      ---O---       O    -------
00549  *     \-- --/    -/   \-     /---\     -------
00550  *      \- -/
00551  *
00552  *    Poly Side             Poly Start             Poly End
00553  *               Hole Start             Hole end
00554  */
00555 static int
00556 vtype2d(struct pt2d *v, struct bu_list *tbl2d, const struct bn_tol *tol)
00557 {
00558         struct pt2d *p, *n;     /* previous/this edge endpoints */
00559         struct loopuse *lu;
00560 
00561         NMG_CK_TBL2D(tbl2d);
00562         NMG_CK_PT2D(v);
00563 
00564         /* get the next/previous points relative to v */
00565         p = PT2D_PREV(tbl2d, v);
00566         n = PT2D_NEXT(tbl2d, v);
00567 
00568 
00569         lu = nmg_find_lu_of_vu( v->vu_p );
00570 
00571         if (p == n && n == v) {
00572                 /* loopuse of vertexuse or loopuse of 1 edgeuse */
00573                 if (lu->orientation == OT_SAME)
00574                         return(POLY_POINT);
00575                 else if (lu->orientation == OT_OPPOSITE)
00576                         return(HOLE_POINT);
00577         }
00578 
00579         if (P_GT_V(n, v) && P_GT_V(p, v)) {
00580                 /*
00581                  *   \   /
00582                  *    \ /
00583                  *     .
00584                  *
00585                  * if this is a convex point, this is a polygon end
00586                  * if it is a concave point, this is a hole end
00587                  */
00588 
00589                 if (p == n) {
00590                         if (lu->orientation == OT_OPPOSITE)
00591                                 return(HOLE_END);
00592                         else if (lu->orientation == OT_SAME)
00593                                 return(POLY_END);
00594                         else {
00595                                 bu_log("%s: %d loopuse is not OT_SAME or OT_OPPOSITE\n",
00596                                         __FILE__, __LINE__);
00597                                 rt_bomb("bombing\n");
00598                         }
00599                 }
00600 
00601                 if (is_convex(p, v, n, tol)) return(POLY_END);
00602                 else return(HOLE_END);
00603 
00604         }
00605 
00606         if (P_LT_V(n, v) && P_LT_V(p, v)) {
00607                 /*      .
00608                  *     / \
00609                  *    /   \
00610                  *
00611                  * if this is a convex point, this is a polygon start
00612                  * if this is a concave point, this is a hole start
00613                  */
00614 
00615                 if (p == n) {
00616                         if (lu->orientation == OT_OPPOSITE)
00617                                 return(HOLE_START);
00618                         else if (lu->orientation == OT_SAME)
00619                                 return(POLY_START);
00620                         else {
00621                                 bu_log("%s: %d loopuse is not OT_SAME or OT_OPPOSITE\n",
00622                                         __FILE__, __LINE__);
00623                                 rt_bomb("bombing\n");
00624                         }
00625                 }
00626 
00627                 if (is_convex(p, v, n, tol))
00628                         return(POLY_START);
00629                 else
00630                         return(HOLE_START);
00631         }
00632         if ( (P_GT_V(n, v) && P_LT_V(p, v)) ||
00633             (P_LT_V(n, v) && P_GT_V(p, v)) ) {
00634                 /*
00635                  *  |
00636                  *  |
00637                  *  .
00638                  *   \
00639                  *    \
00640                  *
00641                  * This is the "side" of a polygon.
00642                  */
00643                 return(POLY_SIDE);
00644         }
00645         bu_log(
00646                 "%s %d HELP! special case:\n(%g %g)->(%g %g)\n(%g %g)->(%g %g)\n",
00647                 __FILE__, __LINE__,
00648                 p->coord[X], p->coord[Y],
00649                 v->coord[X], v->coord[Y],
00650                 n->coord[X], n->coord[Y]);
00651 
00652         return(0);
00653 }
00654 
00655 /**     Polygon point start.
00656  *
00657  *        O
00658  *       /-\
00659  *      /---\
00660  *      v
00661  *
00662  *      start new trapezoid
00663  */
00664 static void
00665 poly_start_vertex(struct pt2d *pt, struct bu_list *tbl2d, struct bu_list *tlist)
00666 {
00667         struct trap *new_trap;
00668 
00669         NMG_CK_TBL2D(tbl2d);
00670         NMG_CK_PT2D(pt);
00671         if (rt_g.NMG_debug & DEBUG_TRI)
00672                 bu_log( "%g %g is polygon start vertex\n",
00673                                 pt->coord[X], pt->coord[Y]);
00674 
00675         new_trap = (struct trap *)bu_calloc(sizeof(struct trap), 1, "new poly_start trap");
00676         new_trap->top = pt;
00677         new_trap->bot = (struct pt2d *)NULL;
00678         new_trap->e_left = pt->vu_p->up.eu_p;
00679         new_trap->e_right = BU_LIST_PPREV_CIRC(edgeuse, pt->vu_p->up.eu_p);
00680         BU_LIST_MAGIC_SET(&new_trap->l, NMG_TRAP_MAGIC);
00681 
00682         /* add new trapezoid */
00683         BU_LIST_APPEND(tlist, &new_trap->l);
00684         NMG_CK_TRAP(new_trap);
00685 }
00686 
00687 /**
00688  *              ^
00689  *        /-    -\
00690  *       /--    --\
00691  *      O---    ---O
00692  *       \--    --/
00693  *        \-    -/
00694  *         v
00695  *
00696  *      finish trapezoid from vertex, start new trapezoid from vertex
00697  */
00698 static void
00699 poly_side_vertex(struct pt2d *pt, struct pt2d *tbl2d, struct bu_list *tlist)
00700 {
00701         struct trap *new_trap, *tp;
00702         struct edgeuse *upper_edge=NULL, *lower_edge=NULL;
00703         struct pt2d *pnext, *plast;
00704 
00705         NMG_CK_TBL2D(tbl2d);
00706         NMG_CK_PT2D(pt);
00707         pnext = PT2D_NEXT(&tbl2d->l, pt);
00708         plast = PT2D_PREV(&tbl2d->l, pt);
00709         if (rt_g.NMG_debug & DEBUG_TRI) {
00710                 bu_log( "%g %g is polygon side vertex\n",
00711                         pt->coord[X], pt->coord[Y]);
00712                 bu_log( "%g %g -> %g %g -> %g %g\n",
00713                         plast->coord[X],
00714                         plast->coord[Y],
00715                         pt->coord[X], pt->coord[Y],
00716                         pnext->coord[X],
00717                         pnext->coord[Y]);
00718         }
00719 
00720         /* find upper edge */
00721         if (P_LT_V(plast, pt) && P_GT_V(pnext, pt)) {
00722                 /* ascending edge */
00723                 upper_edge = pt->vu_p->up.eu_p;
00724                 lower_edge = plast->vu_p->up.eu_p;
00725         } else if (P_LT_V(pnext, pt) && P_GT_V(plast, pt)) {
00726                 /* descending edge */
00727                 upper_edge = plast->vu_p->up.eu_p;
00728                 lower_edge = pt->vu_p->up.eu_p;
00729         }
00730 
00731         NMG_CK_EDGEUSE(upper_edge);
00732         NMG_CK_EDGEUSE(lower_edge);
00733 
00734         /* find the uncompleted trapezoid in the tree
00735          * which contains the upper edge.  This is the trapezoid we will
00736          * complete, and where we will add a new trapezoid
00737          */
00738         for (BU_LIST_FOR(tp, trap, tlist)) {
00739                 NMG_CK_TRAP(tp);
00740                 NMG_CK_EDGEUSE(tp->e_left);
00741                 NMG_CK_EDGEUSE(tp->e_right);
00742                 if ((tp->e_left == upper_edge || tp->e_right == upper_edge) &&
00743                     tp->bot == (struct pt2d *)NULL) {
00744                         break;
00745                     }
00746         }
00747 
00748         if (BU_LIST_MAGIC_WRONG(&tp->l, NMG_TRAP_MAGIC))
00749                 rt_bomb ("didn't find trapezoid parent\n");
00750 
00751         /* complete trapezoid */
00752         tp->bot = pt;
00753 
00754         /* create new trapezoid with other (not upper) edge */
00755         new_trap = (struct trap *)bu_calloc(sizeof(struct trap), 1, "new side trap");
00756         BU_LIST_MAGIC_SET(&new_trap->l, NMG_TRAP_MAGIC);
00757         new_trap->top = pt;
00758         new_trap->bot = (struct pt2d *)NULL;
00759         if (tp->e_left == upper_edge) {
00760                 new_trap->e_left = lower_edge;
00761                 new_trap->e_right = tp->e_right;
00762         } else if (tp->e_right == upper_edge) {
00763                 new_trap->e_right = lower_edge;
00764                 new_trap->e_left = tp->e_left;
00765         } else  /* how did I get here? */
00766                 rt_bomb("Why me?  Always me!\n");
00767 
00768         BU_LIST_INSERT(tlist, &new_trap->l);
00769         NMG_CK_TRAP(new_trap);
00770 }
00771 
00772 
00773 /**     Polygon point end.
00774  *
00775  *           ^
00776  *      \---/
00777  *       \-/
00778  *        O
00779  *
00780  *      complete trapezoid
00781  */
00782 static void
00783 poly_end_vertex(struct pt2d *pt, struct bu_list *tbl2d, struct bu_list *tlist)
00784 {
00785         struct trap *tp;
00786         struct edgeuse *e_left, *e_right;
00787         struct pt2d *pprev;
00788 
00789         NMG_CK_TBL2D(tbl2d);
00790         NMG_CK_PT2D(pt);
00791         if (rt_g.NMG_debug & DEBUG_TRI)
00792                 bu_log( "%g %g is polygon end vertex\n",
00793                         pt->coord[X], pt->coord[Y]);
00794 
00795         /* get the two edges which end at this point */
00796         pprev = PT2D_PREV(tbl2d, pt);
00797         if (pprev == pt)
00798                 rt_bomb("pprev == pt!\n");
00799 
00800         e_left = pprev->vu_p->up.eu_p;
00801         e_right = pt->vu_p->up.eu_p;
00802 
00803         /* find the trapezoid in tree which has
00804          * both edges ending at this point.
00805          */
00806         for (BU_LIST_FOR(tp, trap, tlist)) {
00807                 NMG_CK_TRAP(tp);
00808                 if (tp->e_left == e_left && tp->e_right == e_right && !tp->bot) {
00809                         goto trap_found;
00810                 } else if (tp->e_right == e_left && tp->e_left == e_right &&
00811                     !tp->bot) {
00812                         /* straighten things out for notational convenience*/
00813                         e_right = tp->e_right;
00814                         e_left = tp->e_left;
00815                         goto trap_found;
00816                 }
00817         }
00818 
00819         rt_bomb("Didn't find trapezoid to close!\n");
00820 
00821         /* Complete the trapezoid. */
00822 trap_found:
00823         tp->bot = pt;
00824 }
00825 
00826 
00827 
00828 
00829 
00830 
00831 
00832 
00833 /**     Hole Start in polygon
00834  *
00835  *      -------
00836  *      ---O---
00837  *      --/ \--
00838  *      -/   \-
00839  *            v
00840  *
00841  *      Finish existing trapezoid, start 2 new ones
00842  */
00843 static void
00844 hole_start_vertex(struct pt2d *pt, struct bu_list *tbl2d, struct bu_list *tlist)
00845 {
00846         struct trap *tp, *new_trap;
00847         vect_t pv, ev, n;
00848         struct pt2d *e_pt, *next_pt;
00849 
00850         NMG_CK_TBL2D(tbl2d);
00851         NMG_CK_PT2D(pt);
00852         if (rt_g.NMG_debug & DEBUG_TRI)
00853                 bu_log( "%g %g is hole start vertex\n",
00854                         pt->coord[X], pt->coord[Y]);
00855 
00856         /* we need to find the un-completed trapezoid which encloses this
00857          * point.
00858          */
00859         for (BU_LIST_FOR(tp, trap, tlist)) {
00860                 NMG_CK_TRAP(tp);
00861                 /* obviously, if the trapezoid has been completed, it's not
00862                  * the one we want.
00863                  */
00864                 if (tp->bot) {
00865                         if (rt_g.NMG_debug & DEBUG_TRI)
00866                                 bu_log("Trapezoid %g %g / %g %g completed... Skipping\n",
00867                                         tp->top->coord[X],
00868                                         tp->top->coord[Y],
00869                                         tp->bot->coord[X],
00870                                         tp->bot->coord[Y]);
00871                         continue;
00872                 }
00873 
00874                 /* if point is at the other end of either the left edge
00875                  * or the right edge, we've found the trapezoid to complete.
00876                  *
00877                  * First, we check the left edge
00878                  */
00879                 e_pt = find_pt2d(tbl2d, tp->e_left->vu_p);
00880                 next_pt = find_pt2d(tbl2d,
00881                         (BU_LIST_PNEXT_CIRC(edgeuse, tp->e_left))->vu_p);
00882 
00883                 if (e_pt->vu_p->v_p == pt->vu_p->v_p ||
00884                     next_pt->vu_p->v_p == pt->vu_p->v_p)
00885                         goto gotit;
00886 
00887 
00888                 /* check to see if the point is at the end of the right edge
00889                  * of the trapezoid
00890                  */
00891                 e_pt = find_pt2d(tbl2d, tp->e_right->vu_p);
00892                 next_pt = find_pt2d(tbl2d,
00893                         (BU_LIST_PNEXT_CIRC(edgeuse, tp->e_right))->vu_p);
00894 
00895                 if (e_pt->vu_p->v_p == pt->vu_p->v_p ||
00896                     next_pt->vu_p->v_p == pt->vu_p->v_p)
00897                         goto gotit;
00898 
00899 
00900                 /* if point is right of left edge and left of right edge
00901                  * we've found the trapezoid we need to work with.
00902                  */
00903 
00904                 /* form a vector from the start point of each edge to pt.
00905                  * if crossing this vector with the vector of the edge
00906                  * produces a vector with a positive Z component then the pt
00907                  * is "inside" the trapezoid as far as this edge is concerned
00908                  */
00909                 e_pt = find_pt2d(tbl2d, tp->e_left->vu_p);
00910                 next_pt = find_pt2d(tbl2d,
00911                         (BU_LIST_PNEXT_CIRC(edgeuse, tp->e_left))->vu_p);
00912                 VSUB2(pv, pt->coord, e_pt->coord);
00913                 VSUB2(ev, next_pt->coord, e_pt->coord);
00914                 VCROSS(n, ev, pv);
00915                 if (n[2] <= 0.0) {
00916                         if (rt_g.NMG_debug & DEBUG_TRI)
00917                                 bu_log("Continue #1\n");
00918                         continue;
00919                 }
00920 
00921                 e_pt = find_pt2d(tbl2d, tp->e_right->vu_p);
00922                 next_pt = find_pt2d(tbl2d,
00923                         (BU_LIST_PNEXT_CIRC(edgeuse, tp->e_right))->vu_p);
00924                 VSUB2(pv, pt->coord, e_pt->coord);
00925                 VSUB2(ev, next_pt->coord, e_pt->coord);
00926                 VCROSS(n, ev, pv);
00927                 if (n[2] <= 0.0) {
00928                         if (rt_g.NMG_debug & DEBUG_TRI)
00929                                 bu_log("Continue #2\n");
00930                         continue;
00931                 }
00932 
00933                 goto gotit;
00934 
00935         }
00936 
00937         bu_log("didn't find trapezoid for hole-start point at:\n\t%g %g %g\n",
00938                 V3ARGS(pt->vu_p->v_p->vg_p->coord) );
00939 
00940         nmg_stash_model_to_file("tri_lone_hole.g",
00941                 nmg_find_model(&pt->vu_p->l.magic),
00942                 "lone hole start");
00943 
00944         rt_bomb("bombing\n");
00945 gotit:
00946         /* complete existing trapezoid */
00947         tp->bot = pt;
00948         /* create new left and right trapezoids */
00949 
00950         new_trap = (struct trap *)bu_calloc(sizeof(struct trap), 1, "New hole start trapezoids");
00951         new_trap->top = pt;
00952         new_trap->bot = (struct pt2d *)NULL;
00953         new_trap->e_left = tp->e_left;
00954         new_trap->e_right = BU_LIST_PPREV_CIRC(edgeuse, pt->vu_p->up.eu_p);
00955         BU_LIST_MAGIC_SET(&new_trap->l, NMG_TRAP_MAGIC);
00956         BU_LIST_APPEND(&tp->l, &new_trap->l);
00957 
00958         new_trap = (struct trap *)bu_calloc(sizeof(struct trap), 1, "New hole start trapezoids");
00959         new_trap->top = pt;
00960         new_trap->bot = (struct pt2d *)NULL;
00961         new_trap->e_left = pt->vu_p->up.eu_p;
00962         new_trap->e_right = tp->e_right;
00963         BU_LIST_MAGIC_SET(&new_trap->l, NMG_TRAP_MAGIC);
00964         BU_LIST_APPEND(&tp->l, &new_trap->l);
00965 }
00966 
00967 
00968 /**     Close hole
00969  *
00970  *      ^
00971  *      -\   /-
00972  *      --\ /--
00973  *      ---O---
00974  *      -------
00975  *
00976  *      complete right and left trapezoids
00977  *      start new trapezoid
00978  *
00979  */
00980 static void
00981 hole_end_vertex(struct pt2d *pt, struct bu_list *tbl2d, struct bu_list *tlist)
00982 {
00983         struct edgeuse *eunext, *euprev;
00984         struct trap *tp, *tpnext, *tpprev;
00985 
00986         NMG_CK_TBL2D(tbl2d);
00987         NMG_CK_PT2D(pt);
00988         if (rt_g.NMG_debug & DEBUG_TRI)
00989                 bu_log( "%g %g is hole end vertex\n",
00990                         pt->coord[X], pt->coord[Y]);
00991 
00992         /* find the trapezoids that will end at this vertex */
00993         eunext = pt->vu_p->up.eu_p;
00994         euprev = BU_LIST_PPREV_CIRC(edgeuse, eunext);
00995         tpnext = tpprev = (struct trap *)NULL;
00996 
00997         if (rt_g.NMG_debug & DEBUG_TRI) {
00998                 print_2d_eu("eunext", eunext, tbl2d);
00999                 print_2d_eu("euprev", euprev, tbl2d);
01000         }
01001 
01002         for (BU_LIST_FOR(tp, trap, tlist)) {
01003                 NMG_CK_TRAP(tp);
01004                 /* obviously, if the trapezoid has been completed, it's not
01005                  * the one we want.
01006                  */
01007                 NMG_CK_TRAP(tp);
01008 
01009                 if (tp->bot) {
01010 #if 0
01011                         if (rt_g.NMG_debug & DEBUG_TRI) {
01012                                 print_trap(tp, tbl2d);
01013                                 bu_log("Completed... Skipping\n");
01014                         }
01015 #endif
01016                         continue;
01017                 } else {
01018                         if (rt_g.NMG_debug & DEBUG_TRI)
01019                                 print_trap(tp, tbl2d);
01020                 }
01021 
01022                 if (tp->e_left == eunext || tp->e_right == eunext) {
01023                         if (rt_g.NMG_debug & DEBUG_TRI)
01024                                 bu_log("Found tpnext\n");
01025                         tpnext = tp;
01026                 }
01027 
01028                 if (tp->e_right == euprev || tp->e_left == euprev) {
01029                         if (rt_g.NMG_debug & DEBUG_TRI)
01030                                 bu_log("Found tpprev\n");
01031                         tpprev = tp;
01032                 }
01033                 if (tpnext && tpprev)
01034                         goto gotem;
01035         }
01036 
01037         rt_bomb("couldn't find both trapezoids of hole closing vertex\n");
01038 gotem:
01039         NMG_CK_TRAP(tpnext);
01040         NMG_CK_TRAP(tpprev);
01041 
01042         /* finish off the two trapezoids */
01043         tpnext->bot = pt;
01044         tpprev->bot = pt;
01045 
01046         /* start one new trapezoid */
01047 
01048         tp = (struct trap *)bu_calloc(1, sizeof(struct pt2d), "pt2d struct");
01049         tp->top = pt;
01050         tp->bot = (struct pt2d *)NULL;
01051         if (tpnext->e_left == eunext) {
01052                 tp->e_right = tpnext->e_right;
01053                 tp->e_left = tpprev->e_left;
01054         } else if (tpnext->e_right == eunext) {
01055                 tp->e_left = tpnext->e_left;
01056                 tp->e_right = tpprev->e_right;
01057         } else
01058                 rt_bomb("Which is my left and which is my right?\n");
01059 
01060         BU_LIST_MAGIC_SET(&tp->l, NMG_TRAP_MAGIC);
01061         BU_LIST_APPEND(&tpprev->l, &tp->l);
01062 }
01063 
01064 
01065 /**
01066  *      N M G _ T R A P _ F A C E
01067  *
01068  *      Produce the trapezoidal decomposition of a face from the set of
01069  *      2D points.
01070  */
01071 static void
01072 nmg_trap_face(struct bu_list *tbl2d, struct bu_list *tlist, const struct bn_tol *tol)
01073 {
01074         struct pt2d *pt;
01075 
01076         NMG_CK_TBL2D(tbl2d);
01077 
01078         for (BU_LIST_FOR(pt, pt2d, tbl2d)) {
01079                 NMG_CK_PT2D(pt);
01080                 switch(vtype2d(pt, tbl2d, tol)) {
01081                 case POLY_SIDE:
01082                         poly_side_vertex(pt, (struct pt2d *)tbl2d, tlist);
01083                         break;
01084                 case HOLE_START:
01085                         hole_start_vertex(pt, tbl2d, tlist);
01086                         break;
01087                 case POLY_START:
01088                         poly_start_vertex(pt, tbl2d, tlist);
01089                         break;
01090                 case HOLE_END:
01091                         hole_end_vertex(pt, tbl2d, tlist);
01092                         break;
01093                 case POLY_END:
01094                         poly_end_vertex(pt, tbl2d, tlist);
01095                         break;
01096                 default:
01097                         bu_log( "%g %g is UNKNOWN type vertex %s %d\n",
01098                                 pt->coord[X], pt->coord[Y],
01099                                 __FILE__, __LINE__);
01100                         break;
01101                 }
01102         }
01103 
01104 }
01105 
01106 
01107 static void
01108 map_new_vertexuse(struct bu_list *tbl2d, struct vertexuse *vu_p)
01109 {
01110         struct vertexuse *vu;
01111         struct pt2d *p, *new_pt2d;
01112 
01113         NMG_CK_TBL2D(tbl2d);
01114         NMG_CK_VERTEXUSE(vu_p);
01115 
01116         /* if it's already mapped we're outta here! */
01117         if ( (p = find_pt2d(tbl2d, vu_p)) ) {
01118                 if (rt_g.NMG_debug & DEBUG_TRI)
01119                     bu_log("%s %d map_new_vertexuse() vertexuse already mapped!\n",
01120                         __FILE__, __LINE__);
01121                 return;
01122         }
01123         /* allocate memory for new 2D point */
01124         new_pt2d = (struct pt2d *)
01125                 bu_calloc(1, sizeof(struct pt2d), "pt2d struct");
01126 
01127         /* find another use of the same vertex that is already mapped */
01128         for ( BU_LIST_FOR(vu, vertexuse, &vu_p->v_p->vu_hd) ) {
01129                 NMG_CK_VERTEXUSE(vu);
01130                 if (! (p=find_pt2d(tbl2d, vu)) )
01131                         continue;
01132 
01133                 /* map parameter vertexuse */
01134                 new_pt2d->vu_p = vu_p;
01135                 VMOVE(new_pt2d->coord, p->coord);
01136                 BU_LIST_MAGIC_SET(&new_pt2d->l, NMG_PT2D_MAGIC);
01137                 BU_LIST_APPEND(&p->l, &new_pt2d->l);
01138                 return;
01139         }
01140 
01141         rt_bomb("Couldn't find mapped vertexuse of vertex!\n");
01142 }
01143 
01144 /** Support routine for
01145  * nmg_find_first_last_use_of_v_in_fu
01146  *
01147  * The object of the game here is to find uses of the given vertex whose
01148  * departing edges have the min/max dot product with the direction vector.
01149  *
01150  */
01151 static void
01152 pick_edges(struct vertex *v, struct vertexuse **vu_first, int *min_dir, struct vertexuse **vu_last, int *max_dir, struct faceuse *fu, const struct bn_tol *tol, fastf_t *dir)
01153 
01154 
01155 
01156                         /* 1: forward -1 reverse */
01157 
01158 
01159 {
01160         struct vertexuse *vu;
01161         struct edgeuse *eu_next, *eu_last;
01162         struct vertexuse *vu_next, *vu_prev;
01163         double dot_max = -2.0;
01164         double dot_min = 2.0;
01165         double vu_dot;
01166         double eu_length_sq;
01167         vect_t eu_dir;
01168         if (rt_g.NMG_debug & DEBUG_TRI)
01169                 bu_log("\t    pick_edges(v:(%g %g %g) dir:(%g %g %g))\n",
01170                         V3ARGS(v->vg_p->coord), V3ARGS(dir));
01171 
01172         /* Look at all the uses of this vertex, and find the uses
01173          * associated with an edgeuse in this faceuse.
01174          *
01175          * Compute the dot product of the direction vector with the vector
01176          * of the edgeuse, and the PRIOR edgeuse in the loopuse.
01177          *
01178          * We're looking for the vertexuses with the min/max edgeuse
01179          * vector dot product.
01180          */
01181         *vu_last = *vu_first = (struct vertexuse *)NULL;
01182         for (BU_LIST_FOR(vu, vertexuse, &v->vu_hd)) {
01183                 NMG_CK_VERTEXUSE(vu);
01184                 NMG_CK_VERTEX(vu->v_p);
01185                 NMG_CK_VERTEX_G(vu->v_p->vg_p);
01186 
01187                 if (vu->v_p != v)
01188                         rt_bomb("vertexuse does not acknoledge parents\n");
01189 
01190                 if (nmg_find_fu_of_vu(vu) != fu ||
01191                     *vu->up.magic_p == NMG_LOOPUSE_MAGIC) {
01192                         if (rt_g.NMG_debug & DEBUG_TRI)
01193                                 bu_log("\t\tskipping irrelevant vertexuse\n");
01194                         continue;
01195                 }
01196 
01197                 NMG_CK_EDGEUSE(vu->up.eu_p);
01198 
01199                 /* compute/compare vu/eu vector w/ ray vector */
01200                 eu_next = BU_LIST_PNEXT_CIRC(edgeuse, vu->up.eu_p);
01201                 NMG_CK_EDGEUSE(eu_next);
01202                 vu_next = eu_next->vu_p;
01203                 NMG_CK_VERTEXUSE(vu_next);
01204                 NMG_CK_VERTEX(vu_next->v_p);
01205                 NMG_CK_VERTEX_G(vu_next->v_p->vg_p);
01206                 VSUB2(eu_dir, vu_next->v_p->vg_p->coord, vu->v_p->vg_p->coord);
01207                 eu_length_sq = MAGSQ(eu_dir);
01208                 VUNITIZE(eu_dir);
01209 
01210                 if (rt_g.NMG_debug & DEBUG_TRI)
01211                         bu_log("\t\tchecking forward edgeuse to %g %g %g\n",
01212                                 V3ARGS(vu_next->v_p->vg_p->coord) );
01213 
01214                 if (eu_length_sq >= SMALL_FASTF) {
01215                         if ((vu_dot = VDOT(eu_dir, dir)) > dot_max) {
01216                                 if (rt_g.NMG_debug & DEBUG_TRI) {
01217                                         bu_log("\t\t\teu_dir %g %g %g\n",
01218                                                 V3ARGS(eu_dir));
01219 
01220                                         bu_log("\t\t\tnew_last/max 0x%08x %g %g %g -> %g %g %g vdot %g\n",
01221                                                 vu,
01222                                                 V3ARGS(vu->v_p->vg_p->coord),
01223                                                 V3ARGS(vu_next->v_p->vg_p->coord),
01224                                                 vu_dot);
01225                                 }
01226                                 dot_max = vu_dot;
01227                                 *vu_last = vu;
01228                                 *max_dir = 1;
01229                         }
01230                         if (vu_dot < dot_min) {
01231                                 if (rt_g.NMG_debug & DEBUG_TRI) {
01232                                         bu_log("\t\t\teu_dir %g %g %g\n", V3ARGS(eu_dir));
01233                                         bu_log("\t\t\tnew_first/min 0x%08x %g %g %g -> %g %g %g vdot %g\n",
01234                                                 vu,
01235                                                 V3ARGS(vu->v_p->vg_p->coord),
01236                                                 V3ARGS(vu_next->v_p->vg_p->coord),
01237                                                 vu_dot);
01238                                 }
01239 
01240                                 dot_min = vu_dot;
01241                                 *vu_first = vu;
01242                                 *min_dir = 1;
01243                         }
01244                 }
01245 
01246 
01247 
01248 
01249 
01250                 /* compute/compare vu/prev_eu vector w/ ray vector */
01251                 eu_last = BU_LIST_PPREV_CIRC(edgeuse, vu->up.eu_p);
01252                 NMG_CK_EDGEUSE(eu_last);
01253                 vu_prev = eu_last->vu_p;
01254                 NMG_CK_VERTEXUSE(vu_prev);
01255                 NMG_CK_VERTEX(vu_prev->v_p);
01256                 NMG_CK_VERTEX_G(vu_prev->v_p->vg_p);
01257                 /* form vector in reverse direction so that all vectors
01258                  * "point out" from the vertex in question.
01259                  */
01260                 VSUB2(eu_dir, vu_prev->v_p->vg_p->coord, vu->v_p->vg_p->coord);
01261                 eu_length_sq = MAGSQ(eu_dir);
01262                 VUNITIZE(eu_dir);
01263 
01264                 if (rt_g.NMG_debug & DEBUG_TRI)
01265                         bu_log("\t\tchecking reverse edgeuse to %g %g %g\n",
01266                                 V3ARGS(vu_prev->v_p->vg_p->coord) );
01267 
01268                 if (eu_length_sq >= SMALL_FASTF) {
01269                         if ((vu_dot = VDOT(eu_dir, dir)) > dot_max) {
01270                                 if (rt_g.NMG_debug & DEBUG_TRI) {
01271                                         bu_log("\t\t\t-eu_dir %g %g %g\n",
01272                                                 V3ARGS(eu_dir));
01273                                         bu_log("\t\t\tnew_last/max 0x%08x %g %g %g <- %g %g %g vdot %g\n",
01274                                                 vu,
01275                                                 V3ARGS(vu->v_p->vg_p->coord),
01276                                                 V3ARGS(vu_prev->v_p->vg_p->coord),
01277                                                 vu_dot);
01278                                 }
01279                                 dot_max = vu_dot;
01280                                 *vu_last = vu;
01281                                 *max_dir = -1;
01282                         }
01283                         if (vu_dot < dot_min) {
01284                                 if (rt_g.NMG_debug & DEBUG_TRI) {
01285                                         bu_log("\t\t\teu_dir %g %g %g\n", V3ARGS(eu_dir));
01286                                         bu_log("\t\t\tnew_first/min 0x%08x %g %g %g <- %g %g %g vdot %g\n",
01287                                                 vu,
01288                                                 V3ARGS(vu->v_p->vg_p->coord),
01289                                                 V3ARGS(vu_prev->v_p->vg_p->coord),
01290                                                 vu_dot);
01291                                 }
01292                                 dot_min = vu_dot;
01293                                 *vu_first = vu;
01294                                 *min_dir = -1;
01295                         }
01296                 }
01297         }
01298 
01299 }
01300 
01301 /** Support routine for
01302  * nmg_find_first_last_use_of_v_in_fu
01303  *
01304  * Given and edgeuse and a faceuse, pick the use of the edge in the faceuse
01305  *      whose left vector has the largest/smallest dot product with the given
01306  *      direction vector.  The parameter "find_max" determines whether we
01307  *      return the edgeuse with the largest (find_max != 0) or the smallest
01308  *      (find_max == 0) left-dot-product.
01309  */
01310 struct edgeuse *
01311 pick_eu(struct edgeuse *eu_p, struct faceuse *fu, fastf_t *dir, int find_max)
01312 {
01313         struct edgeuse *eu, *keep_eu=NULL, *eu_next;
01314         int go_radial_not_mate = 0;
01315         double dot_limit;
01316         double euleft_dot;
01317         vect_t left, eu_vect;
01318 
01319         if (rt_g.NMG_debug & DEBUG_TRI)
01320                 bu_log("\t    pick_eu(%g %g %g  <-> %g %g %g, dir:%g %g %g,  %s)\n",
01321                         V3ARGS(eu_p->vu_p->v_p->vg_p->coord ),
01322                         V3ARGS(eu_p->eumate_p->vu_p->v_p->vg_p->coord ),
01323                         V3ARGS(dir), (find_max==0?"find min":"find max") );
01324 
01325         if (find_max) dot_limit = -2.0;
01326         else dot_limit = 2.0;
01327 
01328         /* walk around the edge looking for uses in this face */
01329         eu = eu_p;
01330         do {
01331                 if (nmg_find_fu_of_eu(eu) == fu) {
01332                         /* compute the vector for this edgeuse */
01333                         eu_next = BU_LIST_PNEXT_CIRC(edgeuse, eu);
01334                         VSUB2(eu_vect, eu_next->vu_p->v_p->vg_p->coord,
01335                                 eu->vu_p->v_p->vg_p->coord);
01336                         VUNITIZE(eu_vect);
01337 
01338                         /* compute the "left" vector for this edgeuse */
01339                         if (nmg_find_eu_leftvec(left, eu)) {
01340                                 bu_log("%s %d: edgeuse no longer in faceuse?\n", __FILE__, __LINE__);
01341                                 rt_bomb("bombing");
01342                         }
01343 
01344                         euleft_dot = VDOT(left, dir);
01345 
01346                         if (rt_g.NMG_debug & DEBUG_TRI)
01347                                 bu_log("\t\tchecking: %g %g %g -> %g %g %g left vdot:%g\n",
01348                                         V3ARGS(eu->vu_p->v_p->vg_p->coord),
01349                                         V3ARGS(eu_next->vu_p->v_p->vg_p->coord),
01350                                         euleft_dot);
01351 
01352 
01353                         /* if this is and edgeuse we need to remember, keep
01354                          * track of it while we go onward
01355                          */
01356                         if (find_max) {
01357                                 if (euleft_dot > dot_limit) {
01358                                         dot_limit = euleft_dot;
01359                                         keep_eu = eu;
01360                                         if (rt_g.NMG_debug & DEBUG_TRI)
01361                                                 bu_log("\t\tnew max\n");
01362                                 }
01363                         } else {
01364                                 if (euleft_dot < dot_limit) {
01365                                         dot_limit = euleft_dot;
01366                                         keep_eu = eu;
01367                                         if (rt_g.NMG_debug & DEBUG_TRI)
01368                                                 bu_log("\t\tnew min\n");
01369                                 }
01370                         }
01371                 }
01372 
01373                 if (go_radial_not_mate) eu = eu->eumate_p;
01374                 else eu = eu->radial_p;
01375                 go_radial_not_mate = ! go_radial_not_mate;
01376 
01377         } while ( eu != eu_p );
01378 
01379         if (rt_g.NMG_debug & DEBUG_TRI)
01380                 bu_log("\t\tpick_eu() returns %g %g %g -> %g %g %g\n\t\t\tbecause vdot(left) = %g\n",
01381                         V3ARGS(keep_eu->vu_p->v_p->vg_p->coord),
01382                         V3ARGS(keep_eu->eumate_p->vu_p->v_p->vg_p->coord),
01383                         dot_limit);
01384 
01385         return keep_eu;
01386 }
01387 
01388 
01389 
01390 
01391 /**
01392  *      Given a pointer to a vertexuse in a face and a ray, find the
01393  *      "first" and "last" uses of the vertex along the ray in the face.
01394  *      Consider the diagram below where 4 OT_SAME loopuses meet at a single
01395  *      vertex.  The ray enters from the upper left and proceeds to the lower
01396  *      right.  The ray encounters vertexuse (represented by "o" below)
01397  *      number 1 first and vertexuse 3 last.
01398  *
01399  *
01400  *                       edge A
01401  *                       |
01402  *                   \  ^||
01403  *                    \ |||
01404  *                     1||V2
01405  *              ------->o|o------->
01406  *  edge D --------------.-------------edge B
01407  *              <-------o|o<------
01408  *                     4^||3
01409  *                      ||| \
01410  *                      |||  \
01411  *                      ||V   \|
01412  *                       |    -
01413  *                  edge C
01414  *
01415  *      The primary purpose of this routine is to find the vertexuses
01416  *      that should be the parameters to nmg_cut_loop() and nmg_join_loop().
01417  */
01418 void
01419 nmg_find_first_last_use_of_v_in_fu(struct vertex *v, struct vertexuse **first_vu, struct vertexuse **last_vu, fastf_t *dir, struct faceuse *fu, const struct bn_tol *tol)
01420 {
01421         struct vertexuse *vu_first, *vu_last;
01422         int max_dir, min_dir;   /* 1: forward -1 reverse */
01423         struct edgeuse *eu_first, *eu_last, *eu_p=NULL;
01424 
01425         NMG_CK_VERTEX(v);
01426         NMG_CK_FACEUSE(fu);
01427         if (first_vu == (struct vertexuse **)(NULL)) {
01428                 bu_log("%s: %d first_vu is null ptr\n", __FILE__, __LINE__);
01429                 rt_bomb("terminating\n");
01430         }
01431         if (last_vu == (struct vertexuse **)(NULL)) {
01432                 bu_log("%s: %d last_vu is null ptr\n", __FILE__, __LINE__);
01433                 rt_bomb("terminating\n");
01434         }
01435 
01436         VUNITIZE(dir);
01437 
01438         if (rt_g.NMG_debug & DEBUG_TRI)
01439                 bu_log("\t  nmg_find_first(v:(%g %g %g) dir:(%g %g %g))\n",
01440                         V3ARGS(v->vg_p->coord), V3ARGS(dir));
01441 
01442         /* go find the edges which are "closest" to the direction vector */
01443         pick_edges(v, &vu_first, &min_dir, &vu_last, &max_dir, fu, tol, dir);
01444 
01445 
01446         /* Now we know which 2 edges are most important to look at.
01447          * The question now is which vertexuse on this edge to pick.
01448          * For example, in the diagram above we will choose a use of edge C
01449          * for our "max".  Either vu3 OR vu4 could be chosen.
01450          *
01451          * For our max/last point, we choose the use for which:
01452          *              vdot(ray, eu_left_vector)
01453          * is largest.
01454          *
01455          * For our min/first point, we choose the use for which:
01456          *              vdot(ray, eu_left_vector)
01457          * is smallest.
01458          */
01459 
01460         /* get an edgeuse of the proper edge */
01461         NMG_CK_VERTEXUSE(vu_first);
01462         switch (min_dir) {
01463         case -1:
01464                 eu_p = BU_LIST_PPREV_CIRC(edgeuse, vu_first->up.eu_p);
01465                 break;
01466         case 1:
01467                 eu_p = vu_first->up.eu_p;
01468                 break;
01469         default:
01470                 rt_bomb("bad max_dir\n");
01471                 break;
01472         }
01473 
01474         NMG_CK_EDGEUSE(eu_p);
01475         NMG_CK_VERTEXUSE(eu_p->vu_p);
01476 
01477         eu_first = pick_eu(eu_p, fu, dir, 0);
01478         NMG_CK_EDGEUSE(eu_first);
01479         NMG_CK_VERTEXUSE(eu_first->vu_p);
01480         NMG_CK_VERTEX(eu_first->vu_p->v_p);
01481         NMG_CK_VERTEX_G(eu_first->vu_p->v_p->vg_p);
01482 
01483         if (rt_g.NMG_debug & DEBUG_TRI)
01484                 bu_log("\t   first_eu: %g %g %g -> %g %g %g\n",
01485                         V3ARGS(eu_first->vu_p->v_p->vg_p->coord),
01486                         V3ARGS(eu_first->eumate_p->vu_p->v_p->vg_p->coord));
01487 
01488 
01489         if (eu_first->vu_p->v_p == v)
01490                 /* if we wound up with and edgeuse whose vertexuse is
01491                  * actually on the vertex "v" we're in business, we
01492                  * simply record the vertexuse with this edgeuse.
01493                  */
01494                 *first_vu = eu_first->vu_p;
01495         else {
01496                 /* It looks like we wound up choosing an edgeuse which is
01497                  * "before" the vertex "v" (an edgeuse that points at "v")
01498                  * so we need to pick the vertexuse of the NEXT edgeuse
01499                  */
01500                 NMG_CK_EDGEUSE(eu_first->eumate_p);
01501                 NMG_CK_VERTEXUSE(eu_first->eumate_p->vu_p);
01502                 NMG_CK_VERTEX(eu_first->eumate_p->vu_p->v_p);
01503 
01504                 if (eu_first->eumate_p->vu_p->v_p == v) {
01505                         eu_p = BU_LIST_PNEXT_CIRC(edgeuse, eu_first);
01506                         NMG_CK_EDGEUSE(eu_p);
01507                         NMG_CK_VERTEXUSE(eu_p->vu_p);
01508                         *first_vu = eu_p->vu_p;
01509                 } else {
01510                         bu_log("I got eu_first: %g %g %g -> %g %g %g but...\n",
01511                                 V3ARGS(eu_first->vu_p->v_p->vg_p->coord),
01512                                 V3ARGS(eu_first->eumate_p->vu_p->v_p->vg_p->coord));
01513                         rt_bomb("I can't find the right vertex\n");
01514                 }
01515         }
01516 
01517 
01518         NMG_CK_VERTEXUSE(vu_last);
01519         switch (max_dir) {
01520         case -1:
01521                 eu_p = BU_LIST_PPREV_CIRC(edgeuse, vu_last->up.eu_p);
01522                 break;
01523         case 1:
01524                 eu_p = vu_last->up.eu_p;
01525                 break;
01526         default:
01527                 rt_bomb("bad min_dir\n");
01528                 break;
01529         }
01530 
01531         NMG_CK_EDGEUSE(eu_p);
01532         NMG_CK_VERTEXUSE(eu_p->vu_p);
01533 
01534         eu_last = pick_eu(eu_p, fu, dir, 1);
01535 
01536         NMG_CK_EDGEUSE(eu_last);
01537         NMG_CK_VERTEXUSE(eu_last->vu_p);
01538         NMG_CK_VERTEX(eu_last->vu_p->v_p);
01539         if (rt_g.NMG_debug & DEBUG_TRI)
01540                 bu_log("\t   last_eu: %g %g %g -> %g %g %g\n",
01541                         V3ARGS(eu_last->vu_p->v_p->vg_p->coord),
01542                         V3ARGS(eu_last->eumate_p->vu_p->v_p->vg_p->coord));
01543 
01544 
01545 
01546         if (eu_last->vu_p->v_p == v)
01547                 /* if we wound up with and edgeuse whose vertexuse is
01548                  * actually on the vertex "v" we're in business, we
01549                  * simply record the vertexuse with this edgeuse.
01550                  */
01551                 *last_vu = eu_last->vu_p;
01552         else {
01553                 /* It looks like we wound up choosing an edgeuse which is
01554                  * "before" the vertex "v" (an edgeuse that points at "v")
01555                  * so we need to pick the vertexuse of the NEXT edgeuse
01556                  */
01557                 NMG_CK_EDGEUSE(eu_last->eumate_p);
01558                 NMG_CK_VERTEXUSE(eu_last->eumate_p->vu_p);
01559                 NMG_CK_VERTEX(eu_last->eumate_p->vu_p->v_p);
01560 
01561                 if (eu_last->eumate_p->vu_p->v_p == v) {
01562                         eu_p = BU_LIST_PNEXT_CIRC(edgeuse, eu_last);
01563                         NMG_CK_EDGEUSE(eu_p);
01564                         NMG_CK_VERTEXUSE(eu_p->vu_p);
01565                         *last_vu = eu_p->vu_p;
01566                 } else {
01567                         bu_log("I got eu_last: %g %g %g -> %g %g %g but...\n",
01568                                 V3ARGS(eu_last->vu_p->v_p->vg_p->coord),
01569                                 V3ARGS(eu_last->eumate_p->vu_p->v_p->vg_p->coord));
01570                         rt_bomb("I can't find the right vertex\n");
01571                 }
01572         }
01573 
01574 
01575         NMG_CK_VERTEXUSE(*first_vu);
01576         NMG_CK_VERTEXUSE(*last_vu);
01577 }
01578 
01579 static void
01580 pick_pt2d_for_cutjoin(struct bu_list *tbl2d, struct pt2d **p1, struct pt2d **p2, const struct bn_tol *tol)
01581 {
01582         struct vertexuse *cut_vu1, *cut_vu2, *junk_vu;
01583         struct faceuse *fu;
01584         vect_t dir;
01585 
01586         NMG_CK_TBL2D(tbl2d);
01587 
01588         if (rt_g.NMG_debug & DEBUG_TRI)
01589                 bu_log("\tpick_pt2d_for_cutjoin()\n");
01590 
01591         BN_CK_TOL(tol);
01592         NMG_CK_PT2D(*p1);
01593         NMG_CK_PT2D(*p2);
01594         NMG_CK_VERTEXUSE((*p1)->vu_p);
01595         NMG_CK_VERTEXUSE((*p2)->vu_p);
01596 
01597         cut_vu1 = (*p1)->vu_p;
01598         cut_vu2 = (*p2)->vu_p;
01599 
01600         NMG_CK_VERTEX(cut_vu1->v_p);
01601         NMG_CK_VERTEX_G(cut_vu1->v_p->vg_p);
01602         NMG_CK_VERTEX(cut_vu2->v_p);
01603         NMG_CK_VERTEX_G(cut_vu2->v_p->vg_p);
01604 
01605         /* form direction vector for the cut we want to make */
01606         VSUB2(dir, cut_vu2->v_p->vg_p->coord,
01607                    cut_vu1->v_p->vg_p->coord);
01608 
01609         if (rt_g.NMG_debug & DEBUG_TRI)
01610                 VPRINT("\t\tdir", dir);
01611 
01612         if ( ! (fu = nmg_find_fu_of_vu(cut_vu1)) ) {
01613                 bu_log("%s: %d no faceuse parent of vu\n", __FILE__, __LINE__);
01614                 rt_bomb("Bye now\n");
01615         }
01616 
01617         nmg_find_first_last_use_of_v_in_fu((*p1)->vu_p->v_p,
01618                 &junk_vu, &cut_vu1, dir, fu, tol);
01619 
01620         NMG_CK_VERTEXUSE(junk_vu);
01621         NMG_CK_VERTEXUSE(cut_vu1);
01622         *p1 = find_pt2d(tbl2d, cut_vu1);
01623 
01624         if (rt_g.NMG_debug & DEBUG_TRI) {
01625                 struct pt2d *pj, *pj_n, *p1_n;
01626 
01627                 pj = find_pt2d(tbl2d, junk_vu);
01628                 pj_n = PT2D_NEXT(tbl2d, pj);
01629 
01630                 p1_n = PT2D_NEXT(tbl2d, (*p1));
01631 
01632                 bu_log("\tp1 pick %g %g -> %g %g (first)\n\t\t%g %g -> %g %g (last)\n",
01633                         pj->coord[0], pj->coord[1],
01634                         pj_n->coord[0], pj_n->coord[1],
01635                         (*p1)->coord[0], (*p1)->coord[1],
01636                         p1_n->coord[0], p1_n->coord[1]);
01637         }
01638 
01639 
01640         nmg_find_first_last_use_of_v_in_fu((*p2)->vu_p->v_p,
01641                 &cut_vu2, &junk_vu, dir, fu, tol);
01642 
01643 
01644         *p2 = find_pt2d(tbl2d, cut_vu2);
01645         if (rt_g.NMG_debug & DEBUG_TRI) {
01646                 struct pt2d *pj, *pj_n, *p2_n;
01647 
01648                 pj = find_pt2d(tbl2d, junk_vu);
01649                 pj_n = PT2D_NEXT(tbl2d, pj);
01650 
01651                 p2_n = PT2D_NEXT(tbl2d, (*p2));
01652                 bu_log("\tp2 pick %g %g -> %g %g (first)\n\t\t%g %g -> %g %g (last)\n",
01653                         (*p2)->coord[0], (*p2)->coord[1],
01654                         p2_n->coord[0], p2_n->coord[1],
01655                         pj->coord[0], pj->coord[1],
01656                         pj_n->coord[0], pj_n->coord[1]);
01657         }
01658 
01659 }
01660 
01661 static void join_mapped_loops(struct bu_list *tbl2d, struct pt2d *p1, struct pt2d *p2, const int *color, const struct bn_tol *tol);
01662 
01663 /**
01664  *
01665  *  Cut a loop which has a 2D mapping.  Since this entails the creation
01666  *  of new vertexuses, it is necessary to add a 2D mapping for the new
01667  *  vertexuses.
01668  *
01669  */
01670 static struct pt2d *
01671 cut_mapped_loop(struct bu_list *tbl2d, struct pt2d *p1, struct pt2d *p2, const int *color, const struct bn_tol *tol, int void_ok)
01672 {
01673         struct loopuse *new_lu;
01674         struct loopuse *old_lu;
01675         struct edgeuse *eu;
01676 
01677         NMG_CK_TBL2D(tbl2d);
01678         BN_CK_TOL(tol);
01679         NMG_CK_PT2D(p1);
01680         NMG_CK_PT2D(p2);
01681         NMG_CK_VERTEXUSE(p1->vu_p);
01682         NMG_CK_VERTEXUSE(p2->vu_p);
01683 
01684         if (rt_g.NMG_debug & DEBUG_TRI)
01685                 bu_log("\tcutting loop @ %g %g -> %g %g\n",
01686                         p1->coord[X], p1->coord[Y],
01687                         p2->coord[X], p2->coord[Y]);
01688 
01689         if (p1->vu_p->up.eu_p->up.lu_p != p2->vu_p->up.eu_p->up.lu_p) {
01690                 bu_log("parent loops are not the same %s %d\n", __FILE__, __LINE__);
01691                 rt_bomb("cut_mapped_loop() goodnight 1\n");
01692         }
01693 
01694         pick_pt2d_for_cutjoin(tbl2d, &p1, &p2, tol);
01695 
01696         if (p1->vu_p->up.eu_p->up.lu_p != p2->vu_p->up.eu_p->up.lu_p) {
01697                 if (void_ok) {
01698                         if(rt_g.NMG_debug)
01699                                 bu_log("cut_mapped_loop() parent loops are not the same %s %d, trying join\n", __FILE__, __LINE__);
01700                         join_mapped_loops(tbl2d, p1, p2, color, tol);
01701                         return (struct pt2d *)NULL;
01702                 } else {
01703                         char buf[80];
01704                         char name[32];
01705                         static int iter=0;
01706                         vect_t cut_vect, cut_start, cut_end;
01707                         FILE *fd;
01708 
01709                         bu_log("parent loops are not the same %s %d\n",
01710                                 __FILE__, __LINE__);
01711 
01712 
01713                         sprintf(buf, "cut %g %g %g -> %g %g %g\n",
01714                                 V3ARGS(p1->vu_p->v_p->vg_p->coord),
01715                                 V3ARGS(p2->vu_p->v_p->vg_p->coord) );
01716 
01717                         sprintf(name, "bad_tri_cut%d.g", iter++);
01718                         if ((fd=fopen("bad_tri_cut.pl", "w")) == (FILE *)NULL)
01719                                 rt_bomb("cut_mapped_loop() goodnight 2\n");
01720 
01721                         VSUB2(cut_vect, p2->vu_p->v_p->vg_p->coord, p1->vu_p->v_p->vg_p->coord);
01722                         /* vector goes past end point by 50% */
01723                         VJOIN1(cut_end, p2->vu_p->v_p->vg_p->coord, 0.5, cut_vect);
01724                         /* vector starts before start point by 25% */
01725                         VJOIN1(cut_start, p1->vu_p->v_p->vg_p->coord, -0.25, cut_vect);
01726 
01727                         pl_color(fd, 100, 100, 100);
01728                         pdv_3line(fd, cut_start, p1->vu_p->v_p->vg_p->coord);
01729                         pl_color(fd, 255, 255, 255);
01730                         pdv_3line(fd, p1->vu_p->v_p->vg_p->coord, p2->vu_p->v_p->vg_p->coord);
01731                         pl_color(fd, 100, 100, 100);
01732                         pdv_3line(fd, p2->vu_p->v_p->vg_p->coord, cut_end);
01733 
01734                         (void)fclose(fd);
01735                         nmg_stash_model_to_file( "bad_tri_cut.g",
01736                                                  nmg_find_model(&p1->vu_p->l.magic), buf );
01737 
01738                         rt_bomb("cut_mapped_loop() goodnight 2\n");
01739                 }
01740         }
01741 
01742         if (plot_fd) {
01743                 pl_color(plot_fd, V3ARGS(color) );
01744                 pdv_3line(plot_fd, p1->coord, p2->coord);
01745         }
01746 
01747         old_lu = p1->vu_p->up.eu_p->up.lu_p;
01748         NMG_CK_LOOPUSE(old_lu);
01749         new_lu = nmg_cut_loop(p1->vu_p, p2->vu_p);
01750         NMG_CK_LOOPUSE(new_lu);
01751         NMG_CK_LOOP(new_lu->l_p);
01752         nmg_loop_g(new_lu->l_p, tol);
01753 
01754         /* XXX Does anyone care about loopuse orientations at this stage?
01755         nmg_lu_reorient( old_lu );
01756         nmg_lu_reorient( new_lu );
01757          */
01758 
01759         /* get the edgeuse of the new vertexuse we just created */
01760         eu = BU_LIST_PPREV_CIRC(edgeuse, &new_lu->down_hd);
01761         NMG_CK_EDGEUSE(eu);
01762 
01763         /* if the original vertexuses had normals,
01764          * copy them to the new vertexuses.
01765          */
01766         if( p1->vu_p->a.magic_p && *p1->vu_p->a.magic_p == NMG_VERTEXUSE_A_PLANE_MAGIC )
01767         {
01768                 struct vertexuse *vu;
01769                 struct faceuse *fu;
01770                 struct loopuse *lu;
01771                 vect_t ot_same_normal;
01772                 vect_t ot_opposite_normal;
01773 
01774                 /* get vertexuse normal */
01775                 VMOVE( ot_same_normal , p1->vu_p->a.plane_p->N );
01776                 fu = nmg_find_fu_of_vu( p1->vu_p );
01777                 NMG_CK_FACEUSE( fu );
01778                 if( fu->orientation == OT_OPPOSITE )
01779                         VREVERSE( ot_same_normal , ot_same_normal )
01780 
01781                 VREVERSE( ot_opposite_normal , ot_same_normal );
01782 
01783                 /* look for new vertexuses in new_lu and old_lu */
01784                 for( BU_LIST_FOR( vu , vertexuse , &p1->vu_p->v_p->vu_hd ) )
01785                 {
01786                         if( vu->a.magic_p )
01787                                 continue;
01788 
01789                         lu = nmg_find_lu_of_vu( vu );
01790                         if( lu != old_lu && lu != old_lu->lumate_p &&
01791                             lu != new_lu && lu != new_lu->lumate_p )
01792                                 continue;
01793 
01794                         /* assign appropriate normal */
01795                         fu = nmg_find_fu_of_vu( vu );
01796                         if( fu->orientation == OT_SAME )
01797                                 nmg_vertexuse_nv( vu , ot_same_normal );
01798                         else if( fu->orientation == OT_OPPOSITE )
01799                                 nmg_vertexuse_nv( vu , ot_opposite_normal );
01800                 }
01801         }
01802         if( p2->vu_p->a.magic_p && *p2->vu_p->a.magic_p == NMG_VERTEXUSE_A_PLANE_MAGIC )
01803         {
01804                 struct vertexuse *vu;
01805                 struct faceuse *fu;
01806                 struct loopuse *lu;
01807                 vect_t ot_same_normal;
01808                 vect_t ot_opposite_normal;
01809 
01810                 /* get vertexuse normal */
01811                 VMOVE( ot_same_normal , p2->vu_p->a.plane_p->N );
01812                 fu = nmg_find_fu_of_vu( p2->vu_p );
01813                 NMG_CK_FACEUSE( fu );
01814                 if( fu->orientation == OT_OPPOSITE )
01815                         VREVERSE( ot_same_normal , ot_same_normal )
01816 
01817                 VREVERSE( ot_opposite_normal , ot_same_normal );
01818 
01819                 /* look for new vertexuses in new_lu and old_lu */
01820                 for( BU_LIST_FOR( vu , vertexuse , &p2->vu_p->v_p->vu_hd ) )
01821                 {
01822                         if( vu->a.magic_p )
01823                                 continue;
01824 
01825                         lu = nmg_find_lu_of_vu( vu );
01826                         if( lu != old_lu && lu != old_lu->lumate_p &&
01827                             lu != new_lu && lu != new_lu->lumate_p )
01828                                 continue;
01829 
01830                         /* assign appropriate normal */
01831                         fu = nmg_find_fu_of_vu( vu );
01832                         if( fu->orientation == OT_SAME )
01833                                 nmg_vertexuse_nv( vu , ot_same_normal );
01834                         else if( fu->orientation == OT_OPPOSITE )
01835                                 nmg_vertexuse_nv( vu , ot_opposite_normal );
01836                 }
01837         }
01838 
01839         /* map it to the 2D plane */
01840         map_new_vertexuse(tbl2d, eu->vu_p);
01841 
01842         /* now map the vertexuse on the radially-adjacent edgeuse */
01843         NMG_CK_EDGEUSE(eu->radial_p);
01844         map_new_vertexuse(tbl2d, eu->radial_p->vu_p);
01845 
01846         eu = BU_LIST_PPREV_CIRC( edgeuse, &(p1->vu_p->up.eu_p->l));
01847         return find_pt2d(tbl2d, eu->vu_p);
01848 }
01849 
01850 /**
01851  *
01852  *      Join 2 loops (one forms a hole in the other usually )
01853  *
01854  */
01855 static void
01856 join_mapped_loops(struct bu_list *tbl2d, struct pt2d *p1, struct pt2d *p2, const int *color, const struct bn_tol *tol)
01857 {
01858         struct vertexuse *vu1, *vu2;
01859         struct vertexuse *vu;
01860         struct edgeuse *eu;
01861         struct loopuse *lu;
01862 
01863         NMG_CK_TBL2D(tbl2d);
01864         NMG_CK_PT2D(p1);
01865         NMG_CK_PT2D(p2);
01866         BN_CK_TOL(tol);
01867 
01868         vu1 = p1->vu_p;
01869         vu2 = p2->vu_p;
01870 
01871         NMG_CK_VERTEXUSE(vu1);
01872         NMG_CK_VERTEXUSE(vu2);
01873 
01874         if (rt_g.NMG_debug & DEBUG_TRI)
01875                 bu_log("join_mapped_loops()\n");
01876 
01877 
01878         if (p1 == p2) {
01879                 bu_log("%s %d: Attempting to join loop to itself at (%g %g %g)?\n",
01880                         __FILE__, __LINE__,
01881                         V3ARGS(p1->vu_p->v_p->vg_p->coord) );
01882                 rt_bomb("bombing\n");
01883         } else if (p1->vu_p->up.eu_p->up.lu_p == p2->vu_p->up.eu_p->up.lu_p) {
01884                 bu_log("parent loops are the same %s %d\n", __FILE__, __LINE__);
01885                 rt_bomb("goodnight\n");
01886         }
01887         /* check to see if we're joining two loops that share a vertex */
01888         if (p1->vu_p->v_p == p2->vu_p->v_p) {
01889 #if 1
01890                 if (rt_g.NMG_debug & DEBUG_TRI)
01891                         bu_log("Joining two loops that share a vertex at (%g %g %g)\n",
01892                                 V3ARGS(p1->vu_p->v_p->vg_p->coord) );
01893                 (void)nmg_join_2loops(p1->vu_p,  p2->vu_p);
01894 #else
01895                 if (rt_g.NMG_debug & DEBUG_TRI)
01896                         bu_log("NOT Joining two loops that share a vertex at (%g %g %g)\n",
01897                                 V3ARGS(p1->vu_p->v_p->vg_p->coord) );
01898 #endif
01899                 return;
01900         }
01901 
01902         pick_pt2d_for_cutjoin(tbl2d, &p1, &p2, tol);
01903 
01904         vu1 = p1->vu_p;
01905         vu2 = p2->vu_p;
01906         NMG_CK_VERTEXUSE(vu1);
01907         NMG_CK_VERTEXUSE(vu2);
01908 
01909         if (p1 == p2) {
01910                 bu_log("%s: %d I'm a fool...\n\ttrying to join a vertexuse (%g %g %g) to itself\n",
01911                         __FILE__, __LINE__,
01912                         V3ARGS(p1->vu_p->v_p->vg_p->coord) );
01913         } else if (p1->vu_p->up.eu_p->up.lu_p == p2->vu_p->up.eu_p->up.lu_p) {
01914                 if (rt_g.NMG_debug & DEBUG_TRI) {
01915                         bu_log("parent loops are the same %s %d\n",
01916                                 __FILE__, __LINE__);
01917                 }
01918                 (void)cut_mapped_loop(tbl2d, p1, p2, color, tol, 1);
01919                 return;
01920         }
01921 
01922 
01923         /* XXX nmg_join_2loops() requires that the two loops not be BOTH
01924          *      OT_OPPOSITE.  We should check for this here.
01925          *
01926          * XXX what if vu2 is a vertex loop?
01927          */
01928 
01929         NMG_CK_EDGEUSE(vu2->up.eu_p);
01930 
01931         /* need to save this so we can use it later to get
01932          * the new "next" edge/vertexuse
01933          */
01934         eu = BU_LIST_PPREV_CIRC(edgeuse, vu2->up.eu_p);
01935 
01936 
01937         if (rt_g.NMG_debug & DEBUG_TRI) {
01938                 struct edgeuse *pr1_eu;
01939                 struct edgeuse *pr2_eu;
01940 
01941                 pr1_eu = BU_LIST_PNEXT_CIRC(edgeuse, vu1->up.eu_p);
01942                 pr2_eu = BU_LIST_PNEXT_CIRC(edgeuse, vu2->up.eu_p);
01943 
01944                 bu_log("joining loops between:\n\t%g %g %g -> (%g %g %g)\n\tand%g %g %g -> (%g %g %g)\n",
01945                         V3ARGS(vu1->v_p->vg_p->coord),
01946                         V3ARGS(pr1_eu->vu_p->v_p->vg_p->coord),
01947                         V3ARGS(vu2->v_p->vg_p->coord),
01948                         V3ARGS(pr2_eu->vu_p->v_p->vg_p->coord) );
01949         }
01950 
01951         vu = nmg_join_2loops(vu1, vu2);
01952         if (plot_fd) {
01953                 pl_color(plot_fd, V3ARGS(color) );
01954                 pdv_3line(plot_fd, p1->coord,  p2->coord);
01955         }
01956 
01957 
01958         NMG_CK_VERTEXUSE(vu);
01959 
01960         if (vu == vu2)
01961                 return;
01962 
01963         /* since we've just made some new vertexuses
01964          * we need to map them to the 2D plane.
01965          *
01966          * XXX This should be made more direct and efficient.  For now we
01967          * just go looking for vertexuses without a mapping.
01968          */
01969         NMG_CK_EDGEUSE(vu->up.eu_p);
01970         NMG_CK_LOOPUSE(vu->up.eu_p->up.lu_p);
01971         lu = vu->up.eu_p->up.lu_p;
01972         for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
01973                 if (! find_pt2d(tbl2d, eu->vu_p))
01974                         map_new_vertexuse(tbl2d, eu->vu_p);
01975         }
01976 }
01977 /**
01978  *  Check to see if the edge between the top/bottom of the trapezoid
01979  * already exists.
01980  */
01981 static int
01982 skip_cut(struct bu_list *tbl2d, struct pt2d *top, struct pt2d *bot)
01983 {
01984         struct vertexuse *vu_top;
01985         struct vertexuse *vu_bot;
01986         struct vertexuse *vu;
01987         struct vertex *v;
01988         struct faceuse *fu;
01989         struct edgeuse *eu;
01990         struct edgeuse *eu_next;
01991         struct pt2d *top_next, *bot_next;
01992 
01993         NMG_CK_TBL2D(tbl2d);
01994         NMG_CK_PT2D(top);
01995         NMG_CK_PT2D(bot);
01996 
01997 
01998         top_next = PT2D_NEXT(tbl2d, top);
01999         bot_next = PT2D_NEXT(tbl2d, bot);
02000 
02001         if (top_next == bot || bot_next == top) {
02002                 return 1;
02003         }
02004 
02005         vu_top = top->vu_p;
02006         vu_bot = bot->vu_p;
02007         NMG_CK_VERTEXUSE(vu_top);
02008         NMG_CK_VERTEXUSE(vu_bot);
02009 
02010         v = vu_top->v_p;
02011         NMG_CK_VERTEX(v);
02012         NMG_CK_VERTEX(vu_bot->v_p);
02013 
02014         fu = nmg_find_fu_of_vu(vu_top);
02015 
02016         for (BU_LIST_FOR(vu, vertexuse, &v->vu_hd)) {
02017                 /* if parent is edge of this loop/face, and next
02018                  * vertex around loop is the one for vu_bot, don't
02019                  * make the cut.
02020                  */
02021                 if (nmg_find_fu_of_vu(vu) != fu) continue;
02022                 if (!vu->up.magic_p) {
02023                         bu_log("NULL vertexuse up %s %d\n",
02024                                 __FILE__, __LINE__);
02025                         rt_bomb("");
02026                 }
02027                 if (*vu->up.magic_p != NMG_EDGEUSE_MAGIC) continue;
02028                 eu = vu->up.eu_p;
02029                 eu_next = BU_LIST_PNEXT_CIRC(edgeuse, eu);
02030 
02031                 /* if the edge exists, don't try to re-cut it */
02032                 if (eu_next->vu_p->v_p == vu_bot->v_p)
02033                         return 1;
02034         }
02035 
02036         fu = nmg_find_fu_of_vu(vu_bot);
02037         v = vu_bot->v_p;
02038         for (BU_LIST_FOR(vu, vertexuse, &v->vu_hd)) {
02039                 /* if parent is edge of this loop/face, and next
02040                  * vertex around loop is the one for vu_bot, don't
02041                  * make the cut.
02042                  */
02043                 if (nmg_find_fu_of_vu(vu) != fu) continue;
02044                 if (!vu->up.magic_p) {
02045                         bu_log("NULL vertexuse up %s %d\n",
02046                                 __FILE__, __LINE__);
02047                         rt_bomb("");
02048                 }
02049                 if (*vu->up.magic_p != NMG_EDGEUSE_MAGIC) continue;
02050                 eu = vu->up.eu_p;
02051                 eu_next = BU_LIST_PNEXT_CIRC(edgeuse, eu);
02052 
02053                 /* if the edge exists, don't try to re-cut it */
02054                 if (eu_next->vu_p->v_p == vu_top->v_p)
02055                         return 1;
02056         }
02057         return 0;
02058 }
02059 
02060 static void
02061 cut_diagonals(struct bu_list *tbl2d, struct bu_list *tlist, const struct faceuse *fu, const struct bn_tol *tol)
02062 {
02063         struct trap *tp;
02064         int cut_count=0;
02065 
02066         static const int cut_color[3] = {255, 80, 80};
02067         static const int join_color[3] = {80, 80, 255};
02068 
02069         extern struct loopuse *nmg_find_lu_of_vu(const struct vertexuse *vu);
02070         struct loopuse *toplu, *botlu;
02071         struct loopuse *lu;
02072 
02073         NMG_CK_TBL2D(tbl2d);
02074         BN_CK_TOL(tol);
02075 
02076         /* Convert trap list to unimonotone polygons */
02077         for (BU_LIST_FOR(tp, trap, tlist)) {
02078                 /* if top and bottom points are not on same edge of
02079                  * trapezoid, we cut across the trapezoid with a new edge.
02080                  */
02081 
02082                 /* If the edge already exists in the face, don't bother
02083                  * to add it.
02084                  */
02085                 if( !tp->top || !tp->bot )
02086                 {
02087                         bu_log( "tp->top and/or tp->bot is/are NULL!!!!!!!\n" );
02088                         if (rt_g.NMG_debug & DEBUG_TRI)
02089                         {
02090                                 nmg_pr_fu_briefly( fu, "" );
02091                                 if( tp->top )
02092                                         bu_log( "tp->top is (%g %g %g)\n", V3ARGS( tp->top->vu_p->v_p->vg_p->coord ) );
02093                                 if( tp->bot )
02094                                         bu_log( "tp->bot is (%g %g %g)\n", V3ARGS( tp->bot->vu_p->v_p->vg_p->coord ) );
02095                         }
02096                         rt_bomb( "tp->top and/or tp->bot is/are NULL" );
02097                 }
02098                 if (nmg_find_eu_in_face(tp->top->vu_p->v_p, tp->bot->vu_p->v_p, fu,
02099                     (struct edgeuse *)NULL, 0) != (struct edgeuse *)NULL) {
02100                         if (rt_g.NMG_debug & DEBUG_TRI)
02101                                 bu_log("skipping %g %g/%g %g ... edge exists\n",
02102                                         tp->top->coord[X],
02103                                         tp->top->coord[Y],
02104                                         tp->bot->coord[X],
02105                                         tp->bot->coord[Y]);
02106                         continue;
02107                 }
02108 
02109 
02110                 if (skip_cut(tbl2d, tp->top, tp->bot)) {
02111                         if (rt_g.NMG_debug & DEBUG_TRI)
02112                                 bu_log("skipping %g %g/%g %g ... pts on same edge\n",
02113                                         tp->top->coord[X],
02114                                         tp->top->coord[Y],
02115                                         tp->bot->coord[X],
02116                                         tp->bot->coord[Y]);
02117                         continue;
02118                 }
02119 
02120                 if (rt_g.NMG_debug & DEBUG_TRI) {
02121                         bu_log("trying to cut ...\n");
02122                         print_trap(tp, tbl2d);
02123                 }
02124 
02125                 /* top/bottom points are not on same side of trapezoid. */
02126 
02127                 toplu = nmg_find_lu_of_vu(tp->top->vu_p);
02128                 botlu = nmg_find_lu_of_vu(tp->bot->vu_p);
02129                 NMG_CK_VERTEXUSE(tp->top->vu_p);
02130                 NMG_CK_VERTEXUSE(tp->bot->vu_p);
02131                 NMG_CK_LOOPUSE(toplu);
02132                 NMG_CK_LOOPUSE(botlu);
02133 
02134                 if (toplu == botlu){
02135 
02136                         /* if points are the same, this is a split-loop op */
02137                         if (tp->top->vu_p->v_p == tp->bot->vu_p->v_p) {
02138 
02139                                 int touching_jaunt=0;
02140                                 struct edgeuse *eu1, *eu2, *eu1_prev, *eu2_prev;
02141 
02142                                 eu1 = tp->top->vu_p->up.eu_p;
02143                                 eu2 = tp->bot->vu_p->up.eu_p;
02144 
02145                                 eu1_prev = BU_LIST_PPREV_CIRC( edgeuse, &eu1->l );
02146                                 eu2_prev = BU_LIST_PPREV_CIRC( edgeuse, &eu2->l );
02147                                 if( NMG_ARE_EUS_ADJACENT( eu1, eu1_prev ) )
02148                                         touching_jaunt = 1;
02149                                 else if( NMG_ARE_EUS_ADJACENT( eu2, eu2_prev ) )
02150                                         touching_jaunt = 1;
02151 
02152                                 if( touching_jaunt )
02153                                 {
02154                                         if (rt_g.NMG_debug & DEBUG_TRI)
02155                                                 bu_log("splitting self-touching jaunt loop at (%g %g %g)\n",
02156                                                 V3ARGS(tp->bot->vu_p->v_p->vg_p->coord) );
02157 
02158                                         nmg_loop_split_at_touching_jaunt(toplu, tol);
02159                                 }
02160                                 else
02161                                 {
02162                                         if (rt_g.NMG_debug & DEBUG_TRI)
02163                                                 bu_log("splitting self-touching loop at (%g %g %g)\n",
02164                                                 V3ARGS(tp->bot->vu_p->v_p->vg_p->coord) );
02165 
02166                                         nmg_split_touchingloops(toplu, tol);
02167                                 }
02168                                 for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd))
02169                                         nmg_lu_reorient(lu);
02170 
02171                                 if (rt_g.NMG_debug & DEBUG_TRI)
02172                                 {
02173                                         char fname[32];
02174 
02175                                         sprintf( fname, "split%d.g", cut_count );
02176                                         nmg_stash_model_to_file( fname,
02177                                                 nmg_find_model( &toplu->l.magic ),
02178                                                 "after split_touching_loop()" );
02179                                         cut_count++;
02180                                 }
02181 
02182                         } else {
02183 
02184                                 /* points are in same loop.  Cut the loop */
02185 
02186                                 (void)cut_mapped_loop(tbl2d, tp->top,
02187                                         tp->bot, cut_color, tol, 1);
02188 
02189                                 if (rt_g.NMG_debug & DEBUG_TRI)
02190                                 {
02191                                         char fname[32];
02192 
02193                                         sprintf( fname, "cut%d.g", cut_count );
02194                                         nmg_stash_model_to_file( fname,
02195                                                 nmg_find_model( &toplu->l.magic ),
02196                                                 "after cut_mapped_loop()" );
02197                                         cut_count++;
02198                                 }
02199 
02200                         }
02201 
02202 #if 0
02203                         /* if the bottom vertexuse is on a rising edge and
02204                          * is a top vertex of another trapezoid then
02205                          *      replace the occurrance of the old bottom
02206                          *      vertexuse with the new one in trapezoid "top"
02207                          *      locations.
02208                          */
02209                         bot_next = PT2D_NEXT(tbl2d, tp->bot );
02210 
02211                         if ( P_LT_V( tp->bot, bot_next ) ) {
02212                                 register struct pt2d *new_pt;
02213                                 struct trap *trp;
02214 
02215                                 /* find the new vertexuse of this vertex */
02216                                 new_pt = PT2D_PREV(tbl2d, tp->top);
02217 
02218                                 /* replace all "top" uses of tp->bot with
02219                                  * new_pt
02220                                  */
02221                                 for (BU_LIST_FOR(trp, trap, tlist)) {
02222                                         if (trp->top == tp->bot) {
02223                                                 trp->top = new_pt;
02224                                         }
02225                                 }
02226 
02227                                 /* clean up old trapezoid so that top/bot
02228                                  * are in same loop
02229                                  */
02230                                 tp->top = PT2D_PREV( tbl2d, tp->bot );
02231                         }
02232 #endif
02233                 } else {
02234 
02235                         /* points are in different loops, join the
02236                          * loops together.
02237                          */
02238 
02239                         if (toplu->orientation == OT_OPPOSITE &&
02240                                 botlu->orientation == OT_OPPOSITE)
02241                                         rt_bomb("trying to join 2 interior loops in triangulator?\n");
02242 
02243                         if (rt_g.NMG_debug & DEBUG_TRI)
02244                                 bu_log("joining 2 loops @ %g %g -> %g %g\n",
02245                                         tp->top->coord[X],
02246                                         tp->top->coord[Y],
02247                                         tp->bot->coord[X],
02248                                         tp->bot->coord[Y]);
02249 
02250                         join_mapped_loops(tbl2d, tp->top, tp->bot, join_color, tol);
02251                         NMG_CK_LOOPUSE(toplu);
02252 
02253                         if (rt_g.NMG_debug & DEBUG_TRI)
02254                         {
02255                                 char fname[32];
02256 
02257                                 sprintf( fname, "join%d.g", cut_count );
02258                                 nmg_stash_model_to_file( fname,
02259                                         nmg_find_model( &toplu->l.magic ),
02260                                         "after join_mapped_loop()" );
02261                                 cut_count++;
02262                         }
02263 
02264                 }
02265 
02266                 if (rt_g.NMG_debug & DEBUG_TRI) {
02267                         nmg_tri_plfu( nmg_find_fu_of_vu(tp->top->vu_p),  tbl2d );
02268                         print_tlist(tbl2d, tlist);
02269                 }
02270         }
02271 
02272 }
02273 
02274 
02275 /**     C U T _ U N I M O N O T O N E
02276  *
02277  *      Given a unimonotone loopuse, triangulate it into multiple loopuses
02278  */
02279 static void
02280 cut_unimonotone(struct bu_list *tbl2d, struct bu_list *tlist, struct loopuse *lu, const struct bn_tol *tol)
02281 {
02282         struct pt2d *min, *max, *new, *first=NULL, *prev, *next, *current;
02283         struct edgeuse *eu;
02284         int verts=0;
02285         int vert_count_sq;      /* XXXXX Hack for catching infinite loop */
02286         int loop_count=0;       /* See above */
02287         static const int cut_color[3] = { 90, 255, 90};
02288 
02289         NMG_CK_TBL2D(tbl2d);
02290         BN_CK_TOL(tol);
02291         NMG_CK_LOOPUSE(lu);
02292 
02293         if (rt_g.NMG_debug & DEBUG_TRI)
02294                 bu_log("cutting unimonotone:\n");
02295 
02296         min = max = (struct pt2d *)NULL;
02297 
02298         /* find min/max points & count vertex points */
02299         for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
02300                 new = find_pt2d(tbl2d, eu->vu_p);
02301                 if (!new) {
02302                         bu_log("why can't I find a 2D point for %g %g %g?\n",
02303                         V3ARGS(eu->vu_p->v_p->vg_p->coord));
02304                         rt_bomb("bombing\n");
02305                 }
02306 
02307                 if (rt_g.NMG_debug & DEBUG_TRI)
02308                         bu_log("%g %g\n", new->coord[X], new->coord[Y]);
02309 
02310                 verts++;
02311 
02312                 if (!min || P_LT_V(new, min))
02313                         min = new;
02314                 if (!max || P_GT_V(new, max))
02315                         max = new;
02316         }
02317         vert_count_sq = verts * verts;
02318 
02319         /* pick the pt which does NOT have the other as a "next" pt in loop
02320          * as the place from which we start marching around the uni-monotone
02321          */
02322         if (PT2D_NEXT(tbl2d, max) == min)
02323                 first = min;
02324         else if (PT2D_NEXT(tbl2d, min) == max)
02325                 first = max;
02326         else {
02327                 bu_log("is this a unimonotone loop of just 2 points?:\t%g %g %g and %g %g %g?\n",
02328                         V3ARGS(min->vu_p->v_p->vg_p->coord),
02329                         V3ARGS(max->vu_p->v_p->vg_p->coord) );
02330 
02331                 rt_bomb("aborting\n");
02332         }
02333 
02334         /* */
02335         if (rt_g.NMG_debug & DEBUG_TRI)
02336                 bu_log("%d verts in unimonotone, Min: %g %g  Max: %g %g first:%g %g 0x%08x\n", verts,
02337                         min->coord[X], min->coord[Y],
02338                         max->coord[X], max->coord[Y],
02339                         first->coord[X], first->coord[Y], first);
02340 
02341         current = PT2D_NEXT(tbl2d, first);
02342 
02343         while (verts > 3) {
02344 
02345                 loop_count++;
02346                 if( loop_count > vert_count_sq )
02347                 {
02348                         bu_log( "Cut_unimontone is in an infinite loop!!!\n" );
02349                         rt_bomb( "Cut_unimontone is in an infinite loop" );
02350                 }
02351 
02352                 prev = PT2D_PREV(tbl2d, current);
02353                 next = PT2D_NEXT(tbl2d, current);
02354 
02355                 if (rt_g.NMG_debug & DEBUG_TRI)
02356                         bu_log("%g %g -> %g %g -> %g %g ...\n",
02357                                 prev->coord[X],
02358                                 prev->coord[Y],
02359                                 current->coord[X],
02360                                 current->coord[Y],
02361                                 next->coord[X],
02362                                 next->coord[Y]);
02363 
02364                 if (is_convex(prev, current, next, tol)) {
02365                         struct pt2d *t;
02366                         /* cut a triangular piece off of the loop to
02367                          * create a new loop.
02368                          */
02369                         NMG_CK_LOOPUSE(lu);
02370                         if (rt_g.NMG_debug & DEBUG_TRI)
02371                         {
02372                                 bu_log( "Before cut loop:\n" );
02373                                 nmg_pr_fu_briefly( lu->up.fu_p, "" );
02374                         }
02375                         current = cut_mapped_loop(tbl2d, next, prev, cut_color, tol, 0);
02376                         if (rt_g.NMG_debug & DEBUG_TRI)
02377                         {
02378                                 bu_log( "After cut loop:\n" );
02379                                 nmg_pr_fu_briefly( lu->up.fu_p, "" );
02380                         }
02381                         verts--;
02382                         NMG_CK_LOOPUSE(lu);
02383 
02384                         if (rt_g.NMG_debug & DEBUG_TRI)
02385                                 nmg_tri_plfu( lu->up.fu_p, tbl2d );
02386 
02387                         if (current->vu_p->v_p == first->vu_p->v_p) {
02388                                 t = PT2D_NEXT(tbl2d, first);
02389                                 if (rt_g.NMG_debug & DEBUG_TRI)
02390                                         bu_log("\tfirst(0x%08x -> %g %g\n", first, t->coord[X], t->coord[Y]);
02391                                 t = PT2D_NEXT(tbl2d, current);
02392 
02393                                 if (rt_g.NMG_debug & DEBUG_TRI)
02394                                         bu_log("\tcurrent(0x%08x) -> %g %g\n", current, t->coord[X], t->coord[Y]);
02395 
02396                                 current = PT2D_NEXT(tbl2d, current);
02397                                 if (rt_g.NMG_debug & DEBUG_TRI)
02398                                         bu_log("\tcurrent(0x%08x) -> %g %g\n", current, t->coord[X], t->coord[Y]);
02399                         }
02400                 } else {
02401                         if (rt_g.NMG_debug & DEBUG_TRI)
02402                                 bu_log("\tConcave, moving ahead\n");
02403                         current = next;
02404                 }
02405         }
02406 }
02407 
02408 
02409 
02410 static void
02411 nmg_plot_flat_face(struct faceuse *fu, struct bu_list *tbl2d)
02412 {
02413         struct loopuse *lu;
02414         struct edgeuse *eu;
02415         char buf[80];
02416         vect_t pt;
02417         struct pt2d *p, *pn;
02418 
02419         NMG_CK_TBL2D(tbl2d);
02420         NMG_CK_FACEUSE(fu);
02421 
02422         if (!plot_fd && (plot_fd = fopen("triplot.pl", "w")) == (FILE *)NULL) {
02423                 bu_log( "cannot open triplot.pl\n");
02424         }
02425 
02426         pl_erase(plot_fd);
02427         pd_3space(plot_fd,
02428                 fu->f_p->min_pt[0]-1.0,
02429                 fu->f_p->min_pt[1]-1.0,
02430                 fu->f_p->min_pt[2]-1.0,
02431                 fu->f_p->max_pt[0]+1.0,
02432                 fu->f_p->max_pt[1]+1.0,
02433                 fu->f_p->max_pt[2]+1.0);
02434 
02435         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
02436                 if (BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC) {
02437                         register struct vertexuse *vu;
02438 
02439                         vu = BU_LIST_FIRST( vertexuse, &lu->down_hd );
02440                         if (rt_g.NMG_debug & DEBUG_TRI)
02441                                 bu_log( "lone vert @ %g %g %g\n",
02442                                         V3ARGS(vu->v_p->vg_p->coord) );
02443 
02444                         pl_color(plot_fd, 200, 200, 100);
02445 
02446                         if (! (p=find_pt2d(tbl2d, vu)) )
02447                                 rt_bomb("didn't find vertexuse in list!\n");
02448 
02449                         pdv_3point(plot_fd, p->coord);
02450                         sprintf(buf, "%g, %g", p->coord[0], p->coord[1]);
02451                         pl_label(plot_fd, buf);
02452 
02453                         continue;
02454                 }
02455 
02456                 for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd ) ) {
02457                         register struct edgeuse *eu_pnext;
02458 
02459                         eu_pnext = BU_LIST_PNEXT_CIRC(edgeuse, &eu->l);
02460 
02461 #if 0
02462                         if (rt_g.NMG_debug & DEBUG_TRI)
02463                                 bu_log( "eu vert @ %g %g %g\n",
02464                                         V3ARGS(eu->vu_p->v_p->vg_p->coord) );
02465 
02466 #endif
02467                         if (! (p=find_pt2d(tbl2d, eu->vu_p)) )
02468                                 rt_bomb("didn't find vertexuse in list!\n");
02469 
02470                         if (! (pn=find_pt2d(tbl2d, eu_pnext->vu_p)) )
02471                                 rt_bomb("didn't find vertexuse in list!\n");
02472 
02473 
02474                         VSUB2(pt, pn->coord, p->coord);
02475 
02476                         VSCALE(pt, pt, 0.80);
02477                         VADD2(pt, p->coord, pt);
02478 
02479                         pl_color(plot_fd, 200, 200, 200);
02480                         pdv_3line(plot_fd, p->coord, pt);
02481                         pd_3move(plot_fd, V3ARGS(p->coord));
02482 
02483                         sprintf(buf, "%g, %g", p->coord[0], p->coord[1]);
02484                         pl_label(plot_fd, buf);
02485                 }
02486         }
02487 }
02488 
02489 
02490 void
02491 nmg_triangulate_fu(struct faceuse *fu, const struct bn_tol *tol)
02492 {
02493         mat_t TformMat;
02494         struct bu_list *tbl2d;
02495         struct loopuse *lu;
02496         struct edgeuse *eu;
02497         struct vertexuse *vu;
02498         struct bu_list tlist;
02499         struct trap *tp;
02500         struct pt2d *pt;
02501         int vert_count;
02502         static int iter=0;
02503         static int monotone=0;
02504         vect_t N;
02505 
02506         char db_name[32];
02507 
02508         BN_CK_TOL(tol);
02509         NMG_CK_FACEUSE(fu);
02510 
02511         if (rt_g.NMG_debug & DEBUG_TRI) {
02512                 NMG_GET_FU_NORMAL(N, fu);
02513                 bu_log("---------------- Triangulate face %g %g %g\n",
02514                         V3ARGS(N));
02515         }
02516 
02517 
02518         /* make a quick check to see if we need to bother or not */
02519         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
02520                 if (lu->orientation != OT_SAME) {
02521                         if (rt_g.NMG_debug & DEBUG_TRI)
02522                                 bu_log("faceuse has non-OT_SAME orientation loop\n");
02523                         goto triangulate;
02524                 }
02525                 vert_count = 0;
02526                 for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd ))
02527                         if (++vert_count > 3) {
02528                                 if (rt_g.NMG_debug & DEBUG_TRI)
02529                                         bu_log("loop has more than 3 verticies\n");
02530                                 goto triangulate;
02531                         }
02532         }
02533 
02534         if (rt_g.NMG_debug & DEBUG_TRI) {
02535                 bu_log("---------------- face %g %g %g already triangular\n",
02536                         V3ARGS(N));
02537 
02538                 for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd))
02539                         for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd ))
02540                                 VPRINT("pt", eu->vu_p->v_p->vg_p->coord );
02541 
02542         }
02543         return;
02544 
02545 triangulate:
02546         if (rt_g.NMG_debug & DEBUG_TRI) {
02547                 vect_t N;
02548                 NMG_GET_FU_NORMAL(N, fu);
02549                 bu_log("---------------- proceeding to triangulate face %g %g %g\n", V3ARGS(N));
02550         }
02551 
02552 
02553         /* convert 3D face to face in the X-Y plane */
02554         tbl2d = nmg_flatten_face(fu, TformMat);
02555 
02556         /* avoid having a hole start as the first point */
02557         {
02558                 struct pt2d *pt1, *pt2;
02559 
02560                 pt1 = BU_LIST_FIRST( pt2d, tbl2d );
02561                 pt2 = BU_LIST_PNEXT( pt2d, &pt1->l );
02562 
02563                 if( vtype2d( pt1, tbl2d, tol ) == HOLE_START &&
02564                     pt1->vu_p->v_p == pt2->vu_p->v_p )
02565                 {
02566                         /* swap first and second points */
02567                         if (rt_g.NMG_debug & DEBUG_TRI)
02568                                 bu_log( "Swapping first two points on vertex list (first one was a HOLE_START)\n" );
02569 
02570                         BU_LIST_DEQUEUE( &pt1->l );
02571                         BU_LIST_APPEND( &pt2->l, &pt1->l );
02572                 }
02573         }
02574 
02575         if (rt_g.NMG_debug & DEBUG_TRI) {
02576                 struct pt2d *pt;
02577                 bu_log( "Face Flattened\n");
02578                 bu_log( "Vertex list:\n");
02579                 for (BU_LIST_FOR(pt, pt2d, tbl2d)) {
02580                         bu_log("\tpt2d %26.20e %26.20e\n", pt->coord[0], pt->coord[1]);
02581                 }
02582 
02583                 nmg_tri_plfu( fu, tbl2d );
02584                 nmg_plot_flat_face(fu, tbl2d);
02585                 bu_log( "Face plotted\n\tmaking trapezoids...\n");
02586         }
02587 
02588 
02589         BU_LIST_INIT(&tlist);
02590         nmg_trap_face(tbl2d, &tlist, tol);
02591 
02592         if (rt_g.NMG_debug & DEBUG_TRI){
02593                 print_tlist(tbl2d, &tlist);
02594 
02595                 bu_log("Cutting diagonals ----------\n");
02596         }
02597         cut_diagonals(tbl2d, &tlist, fu, tol);
02598         if (rt_g.NMG_debug & DEBUG_TRI)
02599                 bu_log("Diagonals are cut ----------\n");
02600 
02601         if (rt_g.NMG_debug & DEBUG_TRI) {
02602                 sprintf(db_name, "uni%d.g", iter);
02603                 nmg_stash_model_to_file(db_name,
02604                         nmg_find_model(&fu->s_p->l.magic),
02605                         "trangles and unimonotones");
02606         }
02607 
02608         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd))
02609                 (void)nmg_loop_split_at_touching_jaunt(lu, tol);
02610 
02611         if (rt_g.NMG_debug & DEBUG_TRI) {
02612                 sprintf(db_name, "uni_sj%d.g", iter);
02613                 nmg_stash_model_to_file(db_name,
02614                         nmg_find_model(&fu->s_p->l.magic),
02615                         "after split_at_touching_jaunt");
02616         }
02617 
02618         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd))
02619                 nmg_split_touchingloops( lu, tol );
02620 
02621         if (rt_g.NMG_debug & DEBUG_TRI) {
02622                 sprintf(db_name, "uni_split%d.g", iter++);
02623                 nmg_stash_model_to_file(db_name,
02624                         nmg_find_model(&fu->s_p->l.magic),
02625                         "split trangles and unimonotones");
02626         }
02627 
02628         /* now we're left with a face that has some triangle loops and some
02629          * uni-monotone loops.  Find the uni-monotone loops and triangulate.
02630          */
02631         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
02632 
02633                 if (BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC) {
02634                         vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
02635 
02636                         bu_log("How did I miss this vertex loop %g %g %g?\n%s\n",
02637                                 V3ARGS(vu->v_p->vg_p->coord),
02638                                 "I'm supposed to be dealing with unimonotone loops now");
02639                         rt_bomb("aborting\n");
02640 
02641                 } else if (BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_EDGEUSE_MAGIC) {
02642                         vert_count = 0;
02643                         for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd )) {
02644                                 if (++vert_count > 3) {
02645                                         cut_unimonotone(tbl2d, &tlist, lu, tol);
02646 
02647                                         if (rt_g.NMG_debug & DEBUG_TRI) {
02648                                                 sprintf(db_name, "uni_mono%d.g", monotone++);
02649                                                 nmg_stash_model_to_file(db_name,
02650                                                         nmg_find_model(&fu->s_p->l.magic),
02651                                                         "newly cut unimonotone");
02652                                         }
02653 
02654                                         break;
02655                                 }
02656                         }
02657                 }
02658         }
02659 
02660 
02661         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd))
02662                 nmg_lu_reorient(lu);
02663 
02664         if (rt_g.NMG_debug & DEBUG_TRI)
02665                 nmg_tri_plfu( fu, tbl2d );
02666 
02667         while (BU_LIST_WHILE(tp, trap, &tlist)) {
02668                 BU_LIST_DEQUEUE(&tp->l);
02669                 bu_free((char *)tp, "trapezoid free");
02670         }
02671 
02672         while (BU_LIST_WHILE(pt, pt2d, tbl2d)) {
02673                 BU_LIST_DEQUEUE(&pt->l);
02674                 bu_free((char *)pt, "pt2d free");
02675         }
02676         bu_free((char *)tbl2d, "discard tbl2d");
02677 
02678         return;
02679 }
02680 
02681 void
02682 nmg_triangulate_shell(struct shell *s, const struct bn_tol *tol)
02683 {
02684         struct faceuse *fu;
02685 
02686         BN_CK_TOL(tol);
02687         NMG_CK_SHELL( s );
02688 
02689         for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) {
02690                 NMG_CK_FACEUSE(fu);
02691                 if (fu->orientation == OT_SAME)
02692                         nmg_triangulate_fu(fu, tol);
02693         }
02694 }
02695 
02696 void
02697 nmg_triangulate_model(struct model *m, const struct bn_tol *tol)
02698 {
02699         struct nmgregion *r;
02700         struct shell *s;
02701         struct faceuse *fu;
02702 
02703         BN_CK_TOL(tol);
02704         NMG_CK_MODEL(m);
02705         nmg_vmodel(m);
02706 
02707         if (rt_g.NMG_debug & DEBUG_TRI)
02708                 bu_log("Triangulating NMG\n");
02709 
02710         (void)nmg_model_edge_g_fuse( m, tol );
02711 
02712         (void)nmg_unbreak_region_edges( &m->magic );
02713 
02714         for (BU_LIST_FOR(r, nmgregion, &m->r_hd)) {
02715                 NMG_CK_REGION(r);
02716                 for (BU_LIST_FOR(s, shell, &r->s_hd)) {
02717                         NMG_CK_SHELL(s);
02718                         nmg_s_split_touchingloops(s, tol);
02719 
02720                         for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) {
02721                                 NMG_CK_FACEUSE(fu);
02722                                 if (fu->orientation == OT_SAME)
02723                                         nmg_triangulate_fu(fu, tol);
02724                         }
02725                 }
02726         }
02727         nmg_vmodel(m);
02728 
02729         if (rt_g.NMG_debug & DEBUG_TRI)
02730                 bu_log("Triangulation completed\n");
02731 }
02732 
02733 /*
02734  * Local Variables:
02735  * mode: C
02736  * tab-width: 8
02737  * c-basic-offset: 4
02738  * indent-tabs-mode: t
02739  * End:
02740  * ex: shiftwidth=4 tabstop=8
02741  */

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