nmg_plot.c

Go to the documentation of this file.
00001 /*                      N M G _ P L O T . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1993-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup nmg */
00023 
00024 /*@{*/
00025 /** @file nmg_plot.c
00026  *  This file contains routines that create VLISTs and UNIX-plot files.
00027  *  Some routines are essential to the MGED interface, some are
00028  *  more for diagnostic and visualization purposes.
00029  *
00030  *  There are several distinct families -
00031  *      nmg_ENTITY_to_vlist     Wireframes & polgyons.  For MGED "ev".
00032  *      nmg_pl_ENTITY           Fancy edgeuse drawing, to plot file.
00033  *      nmg_vlblock_ENTITY      Fancy edgeuse drawing, into vlblocks.
00034  *      show_broken_ENTITY      Graphical display of classifier results.
00035  *      ...as well as assorted wrappers for debugging use.
00036  *
00037  *  In the interest of having only a single way of creating the fancy
00038  *  drawings, the code is migrating to creating everything first as
00039  *  VLBLOCKS, and converting that to UNIX-plot files or other formats
00040  *  as appropriate.
00041  *
00042  *  Authors -
00043  *      Lee A. Butler
00044  *      Michael John Muuss
00045  *
00046  *  Source -
00047  *      The U. S. Army Research Laboratory
00048  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00049  */
00050 /*@}*/
00051 
00052 #ifndef lint
00053 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_plot.c,v 14.14 2006/09/16 02:04:25 lbutler Exp $ (ARL)";
00054 #endif
00055 
00056 #include "common.h"
00057 
00058 #include <stdlib.h>
00059 #include <stdio.h>
00060 #include <string.h>
00061 #include <fcntl.h>
00062 #include <signal.h>
00063 
00064 #include "machine.h"
00065 #include "vmath.h"
00066 #include "nmg.h"
00067 #include "raytrace.h"
00068 #include "nurb.h"
00069 #include "plot3.h"
00070 
00071 
00072 #define US_DELAY        10      /* Additional delay between frames */
00073 
00074 void            (*nmg_plot_anim_upcall)();      /* For I/F with MGED */
00075 void            (*nmg_vlblock_anim_upcall)();   /* For I/F with MGED */
00076 void            (*nmg_mged_debug_display_hack)();
00077 double nmg_eue_dist = 0.05;
00078 
00079 /************************************************************************
00080  *                                                                      *
00081  *              NMG to VLIST routines, for MGED "ev" command.           *
00082  * XXX should take a flags array, to ensure each item done only once!   *
00083  *                                                                      *
00084  ************************************************************************/
00085 
00086 /**
00087  *                      N M G _ V U _ T O _ V L I S T
00088  *
00089  *  Plot a single vertexuse
00090  */
00091 void
00092 nmg_vu_to_vlist(struct bu_list *vhead, const struct vertexuse *vu)
00093 {
00094         struct vertex   *v;
00095         register struct vertex_g *vg;
00096 
00097         NMG_CK_VERTEXUSE(vu);
00098         v = vu->v_p;
00099         NMG_CK_VERTEX(v);
00100         vg = v->vg_p;
00101         if( vg )  {
00102                 /* Only thing in this shell is a point */
00103                 NMG_CK_VERTEX_G(vg);
00104                 RT_ADD_VLIST( vhead, vg->coord, BN_VLIST_LINE_MOVE );
00105                 RT_ADD_VLIST( vhead, vg->coord, BN_VLIST_LINE_DRAW );
00106         }
00107 }
00108 
00109 /**
00110  *                      N M G _ E U _ T O _ V L I S T
00111  *
00112  *  Plot a list of edgeuses.  The last edge is joined back to the first.
00113  */
00114 void
00115 nmg_eu_to_vlist(struct bu_list *vhead, const struct bu_list *eu_hd)
00116 {
00117         struct edgeuse          *eu;
00118         struct edgeuse          *eumate;
00119         struct vertexuse        *vu;
00120         struct vertexuse        *vumate;
00121         register struct vertex_g *vg;
00122         register struct vertex_g *vgmate;
00123 
00124         /* Consider all the edges in the wire edge list */
00125         for( BU_LIST_FOR( eu, edgeuse, eu_hd ) )  {
00126                 /* This wire edge runs from vertex to mate's vertex */
00127                 NMG_CK_EDGEUSE(eu);
00128                 vu = eu->vu_p;
00129                 NMG_CK_VERTEXUSE(vu);
00130                 NMG_CK_VERTEX(vu->v_p);
00131                 vg = vu->v_p->vg_p;
00132 
00133                 eumate = eu->eumate_p;
00134                 NMG_CK_EDGEUSE(eumate);
00135                 vumate = eumate->vu_p;
00136                 NMG_CK_VERTEXUSE(vumate);
00137                 NMG_CK_VERTEX(vumate->v_p);
00138                 vgmate = vumate->v_p->vg_p;
00139 
00140                 if( !vg || !vgmate ) {
00141                         bu_log("nmg_eu_to_vlist() no vg or mate?\n");
00142                         continue;
00143                 }
00144                 NMG_CK_VERTEX_G(vg);
00145                 NMG_CK_VERTEX_G(vgmate);
00146 
00147                 RT_ADD_VLIST( vhead, vg->coord, BN_VLIST_LINE_MOVE );
00148                 RT_ADD_VLIST( vhead, vgmate->coord, BN_VLIST_LINE_DRAW );
00149         }
00150 }
00151 
00152 /**
00153  *                      N M G _ L U _ T O _ V L I S T
00154  *
00155  *  Plot a single loopuse into a bn_vlist chain headed by vhead.
00156  *
00157  *  Needs to be able to handle both linear edges and cnurb edges.
00158  */
00159 void
00160 nmg_lu_to_vlist(struct bu_list *vhead, const struct loopuse *lu, int poly_markers, const vectp_t normal)
00161 
00162 
00163                                                 /* bit vector! */
00164 
00165 {
00166         const struct edgeuse            *eu;
00167         const struct vertexuse          *vu;
00168         const struct vertex             *v;
00169         register const struct vertex_g  *vg;
00170         const struct vertex_g           *first_vg;
00171         const struct vertexuse          *first_vu;
00172         int             isfirst;
00173         point_t         centroid;
00174         int             npoints;
00175 
00176         BU_CK_LIST_HEAD(vhead);
00177 
00178         NMG_CK_LOOPUSE(lu);
00179         if( BU_LIST_FIRST_MAGIC(&lu->down_hd)==NMG_VERTEXUSE_MAGIC )  {
00180                 /* Process a loop of a single vertex */
00181                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
00182                 nmg_vu_to_vlist( vhead, vu );
00183                 return;
00184         }
00185 
00186         /* Consider all the edges in the loop */
00187         isfirst = 1;
00188         first_vg = (struct vertex_g *)0;
00189         first_vu = (struct vertexuse *)0;
00190         npoints = 0;
00191         VSETALL( centroid, 0 );
00192         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
00193 
00194                 /* Consider this edge */
00195                 NMG_CK_EDGEUSE(eu);
00196                 vu = eu->vu_p;
00197                 NMG_CK_VERTEXUSE(vu);
00198                 v = vu->v_p;
00199                 NMG_CK_VERTEX(v);
00200                 vg = v->vg_p;
00201                 if( !vg ) {
00202                         continue;
00203                 }
00204                 NMG_CK_VERTEX_G(vg);
00205                 VADD2( centroid, centroid, vg->coord );
00206                 npoints++;
00207                 if (isfirst) {
00208                         if( poly_markers & NMG_VLIST_STYLE_POLYGON ) {
00209                                 /* Insert a "start polygon, normal" marker */
00210                                 RT_ADD_VLIST( vhead, normal, BN_VLIST_POLY_START );
00211                                 if( poly_markers & NMG_VLIST_STYLE_USE_VU_NORMALS
00212                                     && vu->a.magic_p ) {
00213                                         RT_ADD_VLIST( vhead,
00214                                                 vu->a.plane_p->N,
00215                                                 BN_VLIST_POLY_VERTNORM );
00216                                 }
00217                                 RT_ADD_VLIST( vhead, vg->coord, BN_VLIST_POLY_MOVE );
00218                         } else {
00219                                 /* move */
00220                                 RT_ADD_VLIST( vhead, vg->coord, BN_VLIST_LINE_MOVE );
00221                         }
00222                         isfirst = 0;
00223                         first_vg = vg;
00224                         first_vu = vu;
00225                 } else {
00226                         if( poly_markers & NMG_VLIST_STYLE_POLYGON ) {
00227                                 if( poly_markers & NMG_VLIST_STYLE_USE_VU_NORMALS
00228                                     && vu->a.magic_p ) {
00229                                         RT_ADD_VLIST( vhead,
00230                                                 vu->a.plane_p->N,
00231                                                 BN_VLIST_POLY_VERTNORM );
00232                                 }
00233                                 RT_ADD_VLIST( vhead, vg->coord, BN_VLIST_POLY_DRAW );
00234                         } else {
00235                                 /* Draw */
00236                                 RT_ADD_VLIST( vhead, vg->coord, BN_VLIST_LINE_DRAW );
00237                         }
00238                 }
00239 
00240                 if( !eu->g.magic_p )
00241                         continue;
00242 
00243                 /* If cnurb edgeuse, draw points interior to the curve here */
00244                 if( *eu->g.magic_p != NMG_EDGE_G_CNURB_MAGIC )  continue;
00245 
00246                 /* XXX only use poly markers when face is planar, not snurb */
00247                 nmg_cnurb_to_vlist( vhead, eu, 10,
00248                         (poly_markers & NMG_VLIST_STYLE_POLYGON ) ?
00249                                 BN_VLIST_POLY_DRAW : BN_VLIST_LINE_DRAW );
00250         }
00251 
00252         /* Draw back to the first vertex used */
00253         if( !isfirst && first_vg )  {
00254                 if( poly_markers & NMG_VLIST_STYLE_POLYGON  )  {
00255                         /* Draw, end polygon */
00256                         if( poly_markers & NMG_VLIST_STYLE_USE_VU_NORMALS
00257                             && first_vu->a.magic_p ) {
00258                                 RT_ADD_VLIST( vhead,
00259                                         first_vu->a.plane_p->N,
00260                                         BN_VLIST_POLY_VERTNORM );
00261                         }
00262                         RT_ADD_VLIST( vhead, first_vg->coord, BN_VLIST_POLY_END );
00263                 } else {
00264                         /* Draw */
00265                         RT_ADD_VLIST( vhead, first_vg->coord, BN_VLIST_LINE_DRAW );
00266                 }
00267         }
00268         if( (poly_markers  & NMG_VLIST_STYLE_VISUALIZE_NORMALS) && npoints > 2 )  {
00269                 /* Draw surface normal as a little vector */
00270                 double  f;
00271                 vect_t  tocent;
00272                 point_t tip;
00273                 struct faceuse *fu;
00274                 struct face *fp;
00275 
00276                 if( *lu->up.magic_p == NMG_FACEUSE_MAGIC )
00277                 {
00278                         fu = lu->up.fu_p;
00279                         NMG_CK_FACEUSE( fu );
00280 
00281                         fp = fu->f_p;
00282                 }
00283                 else
00284                         fp = (struct face *)NULL;
00285 
00286                 f = 1.0 / npoints;
00287                 VSCALE( centroid, centroid, f );
00288                 VSUB2( tocent, first_vg->coord, centroid );
00289                 f = MAGNITUDE( tocent ) * 0.5;
00290                 if( *fp->g.magic_p != NMG_FACE_G_SNURB_MAGIC )
00291                 {
00292                         /* snurb normals are plotted in nmg_snurb_fu_to_vlist() */
00293                         RT_ADD_VLIST( vhead, centroid, BN_VLIST_LINE_MOVE );
00294                         VJOIN1( tip, centroid, f, normal );
00295                         RT_ADD_VLIST( vhead, tip, BN_VLIST_LINE_DRAW );
00296                 }
00297 
00298                 /* For any vertexuse attributes with normals, draw them too */
00299                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
00300                         struct vertexuse_a_plane        *vua;
00301                         /* Consider this edge */
00302                         vu = eu->vu_p;
00303                         if( !vu->a.magic_p || *vu->a.magic_p != NMG_VERTEXUSE_A_PLANE_MAGIC )  continue;
00304                         vua = vu->a.plane_p;
00305                         v = vu->v_p;
00306                         vg = v->vg_p;
00307                         if( !vg )  continue;
00308                         NMG_CK_VERTEX_G(vg);
00309                         RT_ADD_VLIST( vhead, vg->coord, BN_VLIST_LINE_MOVE );
00310                         VJOIN1( tip, vg->coord, f, vua->N );
00311                         RT_ADD_VLIST( vhead, tip, BN_VLIST_LINE_DRAW );
00312                 }
00313         }
00314 }
00315 
00316 /**
00317  *                      N M G _ S N U R B _ F U _ T O _ V L I S T
00318  */
00319 void
00320 nmg_snurb_fu_to_vlist(struct bu_list *vhead, const struct faceuse *fu, int poly_markers)
00321 {
00322         struct face_g_snurb     *fg;
00323 
00324         BU_CK_LIST_HEAD(vhead);
00325 
00326         NMG_CK_FACEUSE(fu);
00327         NMG_CK_FACE(fu->f_p);
00328         fg = fu->f_p->g.snurb_p;
00329         NMG_CK_FACE_G_SNURB(fg);
00330 
00331         /* XXX For now, draw the whole surface, not just the interior */
00332         nmg_snurb_to_vlist( vhead, fg, 10 );
00333 
00334         if( poly_markers & NMG_VLIST_STYLE_VISUALIZE_NORMALS )
00335         {
00336                 fastf_t f;
00337                 point_t uv_centroid;
00338                 point_t mid_srf;
00339                 point_t corner;
00340                 vect_t fu_norm;
00341                 vect_t tocent;
00342                 point_t tip;
00343 
00344                 uv_centroid[0] = (fg->u.knots[fg->u.k_size-1] + fg->u.knots[0])/2.0;
00345                 uv_centroid[1] = (fg->v.knots[fg->v.k_size-1] + fg->v.knots[0])/2.0;
00346                 uv_centroid[2] = 1.0;
00347 
00348                 nmg_snurb_fu_get_norm( fu, uv_centroid[0], uv_centroid[1], fu_norm );
00349                 nmg_snurb_fu_eval( fu, uv_centroid[0], uv_centroid[1], mid_srf );
00350 
00351                 nmg_snurb_fu_eval( fu, fg->u.knots[0], fg->v.knots[0], corner );
00352                 VSUB2( tocent, corner, mid_srf );
00353                 f = MAGNITUDE( tocent ) * 0.5;
00354 
00355                 RT_ADD_VLIST( vhead, mid_srf, BN_VLIST_LINE_MOVE );
00356                 VJOIN1( tip, mid_srf, f, fu_norm );
00357                 RT_ADD_VLIST( vhead, tip, BN_VLIST_LINE_DRAW );
00358         }
00359 }
00360 
00361 /**
00362  *                      N M G _ S _ T O _ V L I S T
00363  *
00364  *  Plot the entire contents of a shell.
00365  *
00366  *  poly_markers =
00367  *      0 for vectors
00368  *      1 for polygons
00369  *      2 for polygons and surface normals drawn with vectors
00370  */
00371 void
00372 nmg_s_to_vlist(struct bu_list *vhead, const struct shell *s, int poly_markers)
00373 {
00374         struct faceuse  *fu;
00375         struct face_g_plane     *fg;
00376         register struct loopuse *lu;
00377         vect_t          normal;
00378 
00379         NMG_CK_SHELL(s);
00380 
00381         /* faces */
00382         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )  {
00383                 vect_t          n;
00384 
00385                 /* Consider this face */
00386                 NMG_CK_FACEUSE(fu);
00387                 if (fu->orientation != OT_SAME)  continue;
00388                 NMG_CK_FACE(fu->f_p);
00389 
00390                 if( fu->f_p->g.magic_p && *fu->f_p->g.magic_p == NMG_FACE_G_SNURB_MAGIC )  {
00391 
00392                         if( !(poly_markers & NMG_VLIST_STYLE_NO_SURFACES) )
00393                                 nmg_snurb_fu_to_vlist( vhead, fu, poly_markers );
00394 
00395                         VSET( n, 1, 0, 0 );     /* sanity */
00396                         for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
00397                                 nmg_lu_to_vlist( vhead, lu, poly_markers, n );
00398                         }
00399                         continue;
00400                 }
00401 
00402                 /* Handle planar faces directly */
00403                 fg = fu->f_p->g.plane_p;
00404                 NMG_CK_FACE_G_PLANE(fg);
00405                 NMG_GET_FU_NORMAL( n, fu );
00406                 for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
00407                         nmg_lu_to_vlist( vhead, lu, poly_markers, n );
00408                 }
00409         }
00410 
00411         /* wire loops.  poly_markers=0 so wires are always drawn as vectors */
00412         VSETALL(normal, 0);
00413         for( BU_LIST_FOR( lu, loopuse, &s->lu_hd ) )  {
00414                 nmg_lu_to_vlist( vhead, lu, 0, normal );
00415         }
00416 
00417         /* wire edges */
00418         nmg_eu_to_vlist( vhead, &s->eu_hd );
00419 
00420         /* single vertices */
00421         if (s->vu_p)  {
00422                 nmg_vu_to_vlist( vhead, s->vu_p );
00423         }
00424 }
00425 
00426 /**
00427  *                      N M G _ R _ T O _ V L I S T
00428  */
00429 void
00430 nmg_r_to_vlist(struct bu_list *vhead, const struct nmgregion *r, int poly_markers)
00431 {
00432         register struct shell   *s;
00433 
00434         NMG_CK_REGION( r );
00435         for( BU_LIST_FOR( s, shell, &r->s_hd ) )  {
00436                 nmg_s_to_vlist( vhead, s, poly_markers );
00437         }
00438 }
00439 
00440 /**
00441  *                      N M G _ M _ T O _ V L I S T
00442  *
00443  */
00444 void
00445 nmg_m_to_vlist(struct bu_list *vhead, struct model *m, int poly_markers)
00446 {
00447         register struct nmgregion       *r;
00448 
00449         NMG_CK_MODEL( m );
00450         for( BU_LIST_FOR( r, nmgregion, &m->r_hd ) )  {
00451                 NMG_CK_REGION( r );
00452                 nmg_r_to_vlist( vhead, r, poly_markers );
00453         }
00454 }
00455 /************************************************************************
00456  *                                                                      *
00457  *              Routines to lay out the fancy edgeuse drawings          *
00458  *                                                                      *
00459  ************************************************************************/
00460 
00461 #define LEE_DIVIDE_TOL  (1.0e-5)        /* sloppy tolerance */
00462 
00463 
00464 /**
00465  *                      N M G _ O F F S E T _ E U _ V E R T
00466  *
00467  *      Given an edgeuse, find an offset for its vertexuse which will place
00468  *      it "above" and "inside" the area of the face.
00469  *
00470  *  The point will be offset inwards along the edge
00471  *  slightly, to avoid obscuring the vertex, and will be offset off the
00472  *  face (in the direction of the face normal) slightly, to avoid
00473  *  obscuring the edge itself.
00474  *
00475  */
00476 void
00477 nmg_offset_eu_vert(fastf_t *base, const struct edgeuse *eu, const fastf_t *face_normal, int tip)
00478 {
00479         struct edgeuse  *prev_eu;
00480         const struct edgeuse    *this_eu;
00481         vect_t          prev_vec;       /* from cur_pt to prev_pt */
00482         vect_t          eu_vec;         /* from cur_pt to next_pt */
00483         vect_t          prev_left;
00484         vect_t          eu_left;
00485         vect_t          delta_vec;      /* offset vector from vertex */
00486         struct vertex_g *this_vg, *mate_vg, *prev_vg;
00487 
00488         bzero( (char *)delta_vec, sizeof(vect_t)),
00489         prev_eu = BU_LIST_PPREV_CIRC( edgeuse, eu );
00490         this_eu = eu;
00491 
00492         NMG_CK_EDGEUSE(this_eu);
00493         NMG_CK_VERTEXUSE(this_eu->vu_p);
00494         NMG_CK_VERTEX(this_eu->vu_p->v_p);
00495         this_vg = this_eu->vu_p->v_p->vg_p;
00496         NMG_CK_VERTEX_G(this_vg);
00497 
00498         NMG_CK_EDGEUSE(this_eu->eumate_p);
00499         NMG_CK_VERTEXUSE(this_eu->eumate_p->vu_p);
00500         NMG_CK_VERTEX(this_eu->eumate_p->vu_p->v_p);
00501         mate_vg = this_eu->eumate_p->vu_p->v_p->vg_p;
00502         NMG_CK_VERTEX_G(mate_vg);
00503 
00504         NMG_CK_EDGEUSE(prev_eu);
00505         NMG_CK_VERTEXUSE(prev_eu->vu_p);
00506         NMG_CK_VERTEX(prev_eu->vu_p->v_p);
00507         prev_vg = prev_eu->vu_p->v_p->vg_p;
00508         NMG_CK_VERTEX_G(prev_vg);
00509 
00510         /* get "left" vector for edgeuse */
00511         VSUB2(eu_vec, mate_vg->coord, this_vg->coord);
00512         VUNITIZE(eu_vec);
00513         VCROSS(eu_left, face_normal, eu_vec);
00514 
00515 
00516         /* get "left" vector for previous edgeuse */
00517         VSUB2(prev_vec, this_vg->coord, prev_vg->coord);
00518         VUNITIZE(prev_vec);
00519         VCROSS(prev_left, face_normal, prev_vec);
00520 
00521         /* get "delta" vector to apply to vertex */
00522         VADD2(delta_vec, prev_left, eu_left);
00523 
00524         if (MAGSQ(delta_vec) > VDIVIDE_TOL) {
00525                 VUNITIZE(delta_vec);
00526                 VJOIN2(base, this_vg->coord,
00527                         (nmg_eue_dist*1.3),delta_vec,
00528                         (nmg_eue_dist*0.8),face_normal);
00529 
00530         } else if (tip) {
00531                 VJOIN2(base, this_vg->coord,
00532                         (nmg_eue_dist*1.3),prev_left,
00533                         (nmg_eue_dist*0.8),face_normal);
00534         } else {
00535                 VJOIN2(base, this_vg->coord,
00536                         (nmg_eue_dist*1.3),eu_left,
00537                         (nmg_eue_dist*0.8),face_normal);
00538         }
00539 }
00540 
00541 
00542 
00543 /**                     N M G _ E U _ C O O R D S
00544  *
00545  *  Get the two (offset and shrunken) endpoints that represent
00546  *  an edgeuse.
00547  *  Return the base point, and a point 60% along the way towards the
00548  *  other end.
00549  */
00550 static void nmg_eu_coords(const struct edgeuse *eu, fastf_t *base, fastf_t *tip60)
00551 {
00552         point_t tip;
00553 
00554         NMG_CK_EDGEUSE(eu);
00555 
00556         if (*eu->up.magic_p == NMG_SHELL_MAGIC ||
00557             (*eu->up.magic_p == NMG_LOOPUSE_MAGIC &&
00558             *eu->up.lu_p->up.magic_p == NMG_SHELL_MAGIC) ) {
00559                 /* Wire edge, or edge in wire loop */
00560                 VMOVE( base, eu->vu_p->v_p->vg_p->coord );
00561                 NMG_CK_EDGEUSE(eu->eumate_p);
00562                 VMOVE( tip, eu->eumate_p->vu_p->v_p->vg_p->coord );
00563         }
00564         else if (*eu->up.magic_p == NMG_LOOPUSE_MAGIC &&
00565             *eu->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC) {
00566                 /* Loop in face */
00567                 struct faceuse  *fu;
00568                 vect_t          face_normal;
00569 
00570                 fu = eu->up.lu_p->up.fu_p;
00571                 NMG_GET_FU_NORMAL( face_normal, fu );
00572 
00573 
00574                 nmg_offset_eu_vert(base, eu, face_normal, 0);
00575                 nmg_offset_eu_vert(tip, BU_LIST_PNEXT_CIRC(edgeuse, eu),
00576                         face_normal, 1);
00577 
00578         } else
00579                 rt_bomb("nmg_eu_coords: bad edgeuse up. What's going on?\n");
00580 
00581         VBLEND2( tip60, 0.4, base, 0.6, tip );
00582 }
00583 
00584 /**
00585  *                      N M G _ E U _ R A D I A L
00586  *
00587  *  Find location for 80% tip on edgeuse's radial edgeuse.
00588  */
00589 static void nmg_eu_radial(const struct edgeuse *eu, fastf_t *tip)
00590 {
00591         point_t b2, t2;
00592 
00593         NMG_CK_EDGEUSE(eu->radial_p);
00594         NMG_CK_VERTEXUSE(eu->radial_p->vu_p);
00595         NMG_CK_VERTEX(eu->radial_p->vu_p->v_p);
00596         NMG_CK_VERTEX_G(eu->radial_p->vu_p->v_p->vg_p);
00597 
00598         nmg_eu_coords(eu->radial_p, b2, t2);
00599 
00600         /* find point 80% along other eu where radial pointer should touch */
00601         VCOMB2( tip, 0.8, t2, 0.2, b2 );
00602 }
00603 
00604 #if 0
00605 /**
00606  *                      N M G _ E U _ L A S T
00607  *
00608  *  Find the tip of the last (previous) edgeuse from 'eu'.
00609  */
00610 static void nmg_eu_last( eu, tip_out )
00611 const struct edgeuse    *eu;
00612 point_t         tip_out;
00613 {
00614         point_t         radial_base;
00615         point_t         radial_tip;
00616         point_t         last_base;
00617         point_t         last_tip;
00618         point_t         p;
00619         struct edgeuse  *eulast;
00620 
00621         NMG_CK_EDGEUSE(eu);
00622         eulast = BU_LIST_PPREV_CIRC( edgeuse, eu );
00623         NMG_CK_EDGEUSE(eulast);
00624         NMG_CK_VERTEXUSE(eulast->vu_p);
00625         NMG_CK_VERTEX(eulast->vu_p->v_p);
00626         NMG_CK_VERTEX_G(eulast->vu_p->v_p->vg_p);
00627 
00628         nmg_eu_coords(eulast->radial_p, radial_base, radial_tip);
00629 
00630         /* find pt 80% along LAST eu's radial eu where radial ptr touches */
00631         VCOMB2( p, 0.8, radial_tip, 0.2, radial_base );
00632 
00633         /* get coordinates of last edgeuse */
00634         nmg_eu_coords(eulast, last_base, last_tip);
00635 
00636         /* Find pt 80% along other eu where last pointer should touch */
00637         VCOMB2( tip_out, 0.8, last_tip, 0.2, p );
00638 }
00639 #endif
00640 
00641 /**
00642  *                      N M G _ E U _ N E X T
00643  *
00644  *  Return the base of the next edgeuse
00645  */
00646 static void nmg_eu_next_base(const struct edgeuse *eu, fastf_t *next_base)
00647 {
00648         point_t t2;
00649         register struct edgeuse *nexteu;
00650 
00651         NMG_CK_EDGEUSE(eu);
00652         nexteu = BU_LIST_PNEXT_CIRC( edgeuse, eu );
00653         NMG_CK_EDGEUSE(nexteu);
00654         NMG_CK_VERTEXUSE(nexteu->vu_p);
00655         NMG_CK_VERTEX(nexteu->vu_p->v_p);
00656         NMG_CK_VERTEX_G(nexteu->vu_p->v_p->vg_p);
00657 
00658         nmg_eu_coords(nexteu, next_base, t2);
00659 }
00660 
00661 /************************************************************************
00662  *                                                                      *
00663  *              NMG to UNIX-Plot routines, for visualization            *
00664  *  XXX These should get replaced with calls to the vlblock routines    *
00665  *                                                                      *
00666  ************************************************************************/
00667 
00668 /**
00669  *                      N M G _ P L _ V
00670  */
00671 void
00672 nmg_pl_v(FILE *fp, const struct vertex *v, long int *b)
00673 {
00674         pointp_t p;
00675         static char label[128];
00676 
00677         NMG_INDEX_RETURN_IF_SET_ELSE_SET(b, v->index);
00678 
00679         NMG_CK_VERTEX(v);
00680         NMG_CK_VERTEX_G(v->vg_p);
00681         p = v->vg_p->coord;
00682 
00683         pl_color(fp, 255, 255, 255);
00684         if (rt_g.NMG_debug & DEBUG_LABEL_PTS) {
00685                 (void)sprintf(label, "%g %g %g", p[0], p[1], p[2]);
00686                 pdv_3move( fp, p );
00687                 pl_label(fp, label);
00688         }
00689         pdv_3point(fp, p);
00690 }
00691 
00692 /**
00693  *                      N M G _ P L _ E
00694  */
00695 void
00696 nmg_pl_e(FILE *fp, const struct edge *e, long int *b, int red, int green, int blue)
00697 {
00698         pointp_t        p0, p1;
00699         point_t         end0, end1;
00700         vect_t          v;
00701 
00702         NMG_INDEX_RETURN_IF_SET_ELSE_SET(b, e->index);
00703 
00704         NMG_CK_EDGEUSE(e->eu_p);
00705         NMG_CK_VERTEXUSE(e->eu_p->vu_p);
00706         NMG_CK_VERTEX(e->eu_p->vu_p->v_p);
00707         NMG_CK_VERTEX_G(e->eu_p->vu_p->v_p->vg_p);
00708         p0 = e->eu_p->vu_p->v_p->vg_p->coord;
00709 
00710         NMG_CK_VERTEXUSE(e->eu_p->eumate_p->vu_p);
00711         NMG_CK_VERTEX(e->eu_p->eumate_p->vu_p->v_p);
00712         NMG_CK_VERTEX_G(e->eu_p->eumate_p->vu_p->v_p->vg_p);
00713         p1 = e->eu_p->eumate_p->vu_p->v_p->vg_p->coord;
00714 
00715         /* leave a little room between the edge endpoints and the vertex
00716          * compute endpoints by forming a vector between verets, scale vector
00717          * and modify points
00718          */
00719         VSUB2SCALE(v, p1, p0, 0.95);
00720         VADD2(end0, p0, v);
00721         VSUB2(end1, p1, v);
00722 
00723         pl_color(fp, red, green, blue);
00724         pdv_3line( fp, end0, end1 );
00725 
00726         nmg_pl_v(fp, e->eu_p->vu_p->v_p, b);
00727         nmg_pl_v(fp, e->eu_p->eumate_p->vu_p->v_p, b);
00728 }
00729 
00730 /**
00731  *                      M N G _ P L _ E U
00732  */
00733 void
00734 nmg_pl_eu(FILE *fp, const struct edgeuse *eu, long int *b, int red, int green, int blue)
00735 {
00736         point_t base, tip;
00737         point_t radial_tip;
00738         point_t next_base;
00739 
00740         NMG_CK_EDGEUSE(eu);
00741         NMG_CK_EDGE(eu->e_p);
00742         NMG_CK_VERTEXUSE(eu->vu_p);
00743         NMG_CK_VERTEX(eu->vu_p->v_p);
00744         NMG_CK_VERTEX_G(eu->vu_p->v_p->vg_p);
00745 
00746         NMG_CK_VERTEXUSE(eu->eumate_p->vu_p);
00747         NMG_CK_VERTEX(eu->eumate_p->vu_p->v_p);
00748         NMG_CK_VERTEX_G(eu->eumate_p->vu_p->v_p->vg_p);
00749 
00750         NMG_INDEX_RETURN_IF_SET_ELSE_SET(b, eu->index);
00751 
00752         nmg_pl_e(fp, eu->e_p, b, red, green, blue);
00753 
00754         if (*eu->up.magic_p == NMG_LOOPUSE_MAGIC &&
00755             *eu->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC) {
00756 
00757                 nmg_eu_coords(eu, base, tip);
00758                 if (eu->up.lu_p->up.fu_p->orientation == OT_SAME)
00759                         red += 50;
00760                 else if (eu->up.lu_p->up.fu_p->orientation == OT_OPPOSITE)
00761                         red -= 50;
00762                 else
00763                         red = green = blue = 255;
00764 
00765                 pl_color(fp, red, green, blue);
00766                 pdv_3line( fp, base, tip );
00767 
00768                 nmg_eu_radial( eu, radial_tip );
00769                 pl_color(fp, red, green-20, blue);
00770                 pdv_3line( fp, tip, radial_tip );
00771 
00772                 pl_color(fp, 0, 100, 0);
00773                 nmg_eu_next_base( eu, next_base );
00774                 pdv_3line( fp, tip, next_base );
00775 
00776 /*** presently unused ***
00777                 nmg_eu_last( eu, last_tip );
00778                 pl_color(fp, 0, 200, 0);
00779                 pdv_3line( fp, base, last_tip );
00780 ****/
00781             }
00782 }
00783 
00784 /**
00785  *                      N M G _ P L _ L U
00786  */
00787 void
00788 nmg_pl_lu(FILE *fp, const struct loopuse *lu, long int *b, int red, int green, int blue)
00789 {
00790         struct bn_vlblock       *vbp;
00791 
00792         vbp = rt_vlblock_init();
00793         nmg_vlblock_lu(vbp, lu, b, red, green, blue, 0, 0);
00794         rt_plot_vlblock(fp, vbp);
00795         rt_vlblock_free(vbp);
00796 }
00797 
00798 /**
00799  *                      M N G _ P L _ F U
00800  */
00801 void
00802 nmg_pl_fu(FILE *fp, const struct faceuse *fu, long int *b, int red, int green, int blue)
00803 {
00804         struct loopuse          *lu;
00805         struct bn_vlblock       *vbp;
00806         int             loopnum = 0;
00807 
00808         NMG_CK_FACEUSE(fu);
00809         NMG_INDEX_RETURN_IF_SET_ELSE_SET(b, fu->index);
00810 
00811         vbp = rt_vlblock_init();
00812 
00813         for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
00814                 nmg_vlblock_lu(vbp, lu, b, red, green, blue, 1, loopnum++);
00815         }
00816 
00817         rt_plot_vlblock(fp, vbp);
00818         rt_vlblock_free(vbp);
00819 }
00820 
00821 /**
00822  *                      N M G _ P L _ S
00823  *
00824  *  Note that "b" should probably be defined a level higher,
00825  *  to reduce malloc/free calls when plotting multiple shells.
00826  */
00827 void
00828 nmg_pl_s(FILE *fp, const struct shell *s)
00829 {
00830         struct bn_vlblock       *vbp;
00831 
00832         vbp = rt_vlblock_init();
00833         nmg_vlblock_s(vbp, s, 0);
00834         rt_plot_vlblock(fp, vbp);
00835         rt_vlblock_free(vbp);
00836 }
00837 
00838 void
00839 nmg_pl_shell(FILE *fp, const struct shell *s, int fancy)
00840 {
00841         struct bn_vlblock       *vbp;
00842 
00843         vbp = rt_vlblock_init();
00844         nmg_vlblock_s(vbp, s, fancy);
00845         rt_plot_vlblock(fp, vbp);
00846         rt_vlblock_free(vbp);
00847 }
00848 
00849 /**
00850  *                      N M G _ P L _ R
00851  */
00852 void
00853 nmg_pl_r(FILE *fp, const struct nmgregion *r)
00854 {
00855         struct bn_vlblock       *vbp;
00856 
00857         vbp = rt_vlblock_init();
00858         nmg_vlblock_r(vbp, r, 0);
00859         rt_plot_vlblock(fp, vbp);
00860         rt_vlblock_free(vbp);
00861 }
00862 
00863 /**
00864  *                      N M G _ P L _ M
00865  */
00866 void
00867 nmg_pl_m(FILE *fp, const struct model *m)
00868 {
00869         struct bn_vlblock       *vbp;
00870 
00871         vbp = rt_vlblock_init();
00872         nmg_vlblock_m(vbp, m, 0);
00873         rt_plot_vlblock(fp, vbp);
00874         rt_vlblock_free(vbp);
00875 }
00876 
00877 /************************************************************************
00878  *                                                                      *
00879  *              Visualization of fancy edgeuses into VLBLOCKs           *
00880  *                                                                      *
00881  *  This is the preferred method of obtaining fancy NMG displays.       *
00882  *                                                                      *
00883  ************************************************************************/
00884 
00885 /**
00886  *                      N M G _ V L B L O C K _ V
00887  */
00888 void
00889 nmg_vlblock_v(struct bn_vlblock *vbp, const struct vertex *v, long int *tab)
00890 {
00891         pointp_t p;
00892         struct bu_list  *vh;
00893 
00894         BN_CK_VLBLOCK(vbp);
00895         NMG_CK_VERTEX(v);
00896         NMG_INDEX_RETURN_IF_SET_ELSE_SET( tab, v->index );
00897 
00898         NMG_CK_VERTEX_G(v->vg_p);
00899         p = v->vg_p->coord;
00900 
00901         vh = rt_vlblock_find( vbp, 255, 255, 255 );
00902 #if 0
00903         if (rt_g.NMG_debug & DEBUG_LABEL_PTS) {
00904                 static char label[128];
00905                 mat_t   mat;
00906                 MAT_IDN(mat);
00907                 (void)sprintf(label, "%g %g %g", p[0], p[1], p[2]);
00908                 /* XXX What size characters to use? */
00909                 bn_vlist_3string( vh, vbp->free_vlist_hd, label, p, mat, scale );
00910         }
00911 #endif
00912         RT_ADD_VLIST( vh, p, BN_VLIST_LINE_MOVE );
00913         RT_ADD_VLIST( vh, p, BN_VLIST_LINE_DRAW );
00914 }
00915 
00916 /**
00917  *                      N M G _ V L B L O C K _ E
00918  */
00919 void
00920 nmg_vlblock_e(struct bn_vlblock *vbp, const struct edge *e, long int *tab, int red, int green, int blue, int fancy)
00921 {
00922         pointp_t p0, p1;
00923         point_t end0, end1;
00924         vect_t v;
00925         struct bu_list  *vh;
00926 
00927         BN_CK_VLBLOCK(vbp);
00928         NMG_CK_EDGE(e);
00929         NMG_INDEX_RETURN_IF_SET_ELSE_SET( tab, e->index );
00930 
00931         NMG_CK_EDGEUSE(e->eu_p);
00932         NMG_CK_VERTEXUSE(e->eu_p->vu_p);
00933         NMG_CK_VERTEX(e->eu_p->vu_p->v_p);
00934         NMG_CK_VERTEX_G(e->eu_p->vu_p->v_p->vg_p);
00935         p0 = e->eu_p->vu_p->v_p->vg_p->coord;
00936 
00937         NMG_CK_VERTEXUSE(e->eu_p->eumate_p->vu_p);
00938         NMG_CK_VERTEX(e->eu_p->eumate_p->vu_p->v_p);
00939         NMG_CK_VERTEX_G(e->eu_p->eumate_p->vu_p->v_p->vg_p);
00940         p1 = e->eu_p->eumate_p->vu_p->v_p->vg_p->coord;
00941 
00942         /* leave a little room between the edge endpoints and the vertex
00943          * compute endpoints by forming a vector between verets, scale vector
00944          * and modify points
00945          */
00946         VSUB2SCALE(v, p1, p0, 0.90);
00947         VADD2(end0, p0, v);
00948         VSUB2(end1, p1, v);
00949 
00950         vh = rt_vlblock_find( vbp, red, green, blue );
00951         RT_ADD_VLIST( vh, end0, BN_VLIST_LINE_MOVE );
00952         RT_ADD_VLIST( vh, end1, BN_VLIST_LINE_DRAW );
00953 
00954         nmg_vlblock_v(vbp, e->eu_p->vu_p->v_p, tab);
00955         nmg_vlblock_v(vbp, e->eu_p->eumate_p->vu_p->v_p, tab);
00956 }
00957 
00958 /**
00959  *                      M N G _ V L B L O C K _ E U
00960  */
00961 void
00962 nmg_vlblock_eu(struct bn_vlblock *vbp, const struct edgeuse *eu, long int *tab, int red, int green, int blue, int fancy, int loopnum)
00963 {
00964         point_t base, tip;
00965         point_t radial_tip;
00966         point_t next_base;
00967         struct bu_list  *vh;
00968 
00969         BN_CK_VLBLOCK(vbp);
00970         NMG_CK_EDGEUSE(eu);
00971         NMG_INDEX_RETURN_IF_SET_ELSE_SET( tab, eu->index );
00972 
00973         NMG_CK_EDGE(eu->e_p);
00974         NMG_CK_VERTEXUSE(eu->vu_p);
00975         NMG_CK_VERTEX(eu->vu_p->v_p);
00976         NMG_CK_VERTEX_G(eu->vu_p->v_p->vg_p);
00977 
00978         NMG_CK_VERTEXUSE(eu->eumate_p->vu_p);
00979         NMG_CK_VERTEX(eu->eumate_p->vu_p->v_p);
00980         NMG_CK_VERTEX_G(eu->eumate_p->vu_p->v_p->vg_p);
00981 
00982         nmg_vlblock_e(vbp, eu->e_p, tab, red, green, blue, fancy);
00983 
00984         if( !fancy )  return;
00985 
00986         if (*eu->up.magic_p == NMG_LOOPUSE_MAGIC &&
00987             *eu->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC) {
00988 
00989                 /* if "fancy" doesn't specify plotting edgeuses of this
00990                  * particular face orientation, return
00991                  */
00992                 if ( (eu->up.lu_p->up.fu_p->orientation == OT_SAME &&
00993                      (fancy & 1) == 0) ||
00994                      (eu->up.lu_p->up.fu_p->orientation == OT_OPPOSITE &&
00995                      (fancy & 2) == 0) )
00996                         return;
00997 
00998                 nmg_eu_coords(eu, base, tip);
00999                 /* draw edgeuses of an OT_SAME faceuse in bright green,
01000                  * and  edgeuses of an OT_OPPOSITE faceuse in cyan.
01001                  * WIRE/UNSPEC edgeuses are drawn white.
01002                  */
01003                 if (eu->up.lu_p->up.fu_p->orientation == OT_SAME) {
01004                         if (eu->up.lu_p->orientation == OT_SAME) {
01005                                 /* green */
01006                                 red = 75;
01007                                 green = 250;
01008                                 blue = 75;
01009                         } else if (eu->up.lu_p->orientation == OT_OPPOSITE) {
01010                                 /* yellow */
01011                                 red = 250;
01012                                 green = 250;
01013                                 blue = 75;
01014                         } else {
01015                                 red = 250;
01016                                 green = 50;
01017                                 blue = 250;
01018                         }
01019                 } else if (eu->up.lu_p->up.fu_p->orientation == OT_OPPOSITE) {
01020                         if (eu->up.lu_p->orientation == OT_SAME) {
01021                                 /* blue */
01022                                 red = 100;
01023                                 green = 100;
01024                                 blue = 250;
01025                         } else if (eu->up.lu_p->orientation == OT_OPPOSITE) {
01026                                 /* cyan */
01027                                 red = 200;
01028                                 green = 100;
01029                                 blue = 250;
01030                         } else {
01031                                 /* dark magenta */
01032                                 red = 125;
01033                                 green = 0;
01034                                 blue = 125;
01035                         }
01036                 } else
01037                         red = green = blue = 255;
01038 
01039                 /* draw the portion from the vertexuse to just beyond the
01040                  * midway point to represent the edgeuse
01041                  */
01042                 vh = rt_vlblock_find( vbp, red, green, blue );
01043                 RT_ADD_VLIST( vh, base, BN_VLIST_LINE_MOVE );
01044                 RT_ADD_VLIST( vh, tip, BN_VLIST_LINE_DRAW );
01045 
01046                 /* draw a line from the tip of the edgeuse part to a point
01047                  * behind the tip of the radial edgeuse.  This provides 2
01048                  * visual cues.  First it allows us to identify the radial
01049                  * edgeuse, and second, it makes a "half arrowhead" on the
01050                  * edgeuse, making it easier to recognize the direction
01051                  * of the edgeuse
01052                  */
01053                 nmg_eu_radial( eu, radial_tip );
01054                 vh = rt_vlblock_find( vbp, red, green-20, blue );
01055                 RT_ADD_VLIST( vh, tip, BN_VLIST_LINE_MOVE );
01056                 RT_ADD_VLIST( vh, radial_tip, BN_VLIST_LINE_DRAW );
01057 
01058                 /* we draw a line from the tip of the edgeuse line
01059                  * to the vertexuse/start of the next edgeuse in the loop.
01060                  * This helps us to visually trace the loop from edgeuse to
01061                  * edgeuse.  The color of this part encodes the loopuse
01062                  * orientation.
01063                  */
01064                 nmg_eu_next_base( eu, next_base );
01065                 red *= 0.5;
01066                 green *= 0.5;
01067                 blue *= 0.5;
01068                 vh = rt_vlblock_find( vbp, red, green, blue );
01069                 RT_ADD_VLIST( vh, tip, BN_VLIST_LINE_MOVE );
01070                 RT_ADD_VLIST( vh, next_base, BN_VLIST_LINE_DRAW );
01071         }
01072 }
01073 
01074 /**
01075  *                      N M G _ V L B L O C K _ E U L E F T
01076  *
01077  *  Draw the left vector for this edgeuse.
01078  *  At the tip, write the angle around the edgeuse, in degrees.
01079  *
01080  *  Color is determined by caller.
01081  */
01082 void
01083 nmg_vlblock_euleft(struct bu_list *vh, const struct edgeuse *eu, const fastf_t *center, const fastf_t *mat, const fastf_t *xvec, const fastf_t *yvec, double len, const struct bn_tol *tol)
01084 {
01085         vect_t          left;
01086         point_t         tip;
01087         fastf_t         fan_len;
01088         fastf_t         char_scale;
01089         double          ang;
01090         char            str[128];
01091 
01092         NMG_CK_EDGEUSE(eu);
01093         BN_CK_TOL(tol);
01094 
01095         if( nmg_find_eu_leftvec( left, eu ) < 0 )  return;
01096 
01097         /* fan_len is baed on length of eu */
01098         fan_len = len * 0.2;
01099         VJOIN1( tip, center, fan_len, left );
01100 
01101         RT_ADD_VLIST( vh, center, BN_VLIST_LINE_MOVE );
01102         RT_ADD_VLIST( vh, tip, BN_VLIST_LINE_DRAW );
01103 
01104         ang = bn_angle_measure( left, xvec, yvec ) * bn_radtodeg;
01105         sprintf( str, "%g", ang );
01106 
01107         /* char_scale is based on length of eu */
01108         char_scale = len * 0.05;
01109         bn_vlist_3string( vh, &rt_g.rtg_vlfree, str, tip, mat, char_scale );
01110 }
01111 
01112 /**
01113  *                      N M G _ V L B L O C K _ A R O U N D _ E U
01114  *
01115  *  Given an edgeuse, plot all the edgeuses around the common edge.
01116  *  A graphical parallel to nmg_pr_fu_around_eu_vecs().
01117  *
01118  *  If the "fancy" flag is set, draw an angle fan around the edge midpoint,
01119  *  using the same angular reference as nmg_pr_fu_around_eu_vecs(), so
01120  *  that the printed output can be cross-referenced to this display.
01121  */
01122 void
01123 nmg_vlblock_around_eu(struct bn_vlblock *vbp, const struct edgeuse *arg_eu, long int *tab, int fancy, const struct bn_tol *tol)
01124 {
01125         const struct edgeuse            *orig_eu;
01126         register const struct edgeuse   *eu;
01127         vect_t                  xvec, yvec, zvec;
01128         point_t                 center;
01129         mat_t                   mat;
01130         struct bu_list          *vh;
01131         fastf_t                 len;
01132 
01133         BN_CK_VLBLOCK(vbp);
01134         NMG_CK_EDGEUSE(arg_eu);
01135         BN_CK_TOL(tol);
01136 
01137         if( fancy )  {
01138                 VSUB2( xvec, arg_eu->eumate_p->vu_p->v_p->vg_p->coord,
01139                         arg_eu->vu_p->v_p->vg_p->coord );
01140                 len = MAGNITUDE( xvec );
01141 
01142                 /* Erect coordinate system around eu */
01143                 nmg_eu_2vecs_perp( xvec, yvec, zvec, arg_eu, tol );
01144 
01145                 /*  Construct matrix to rotate characters from 2D drawing space
01146                  *  into model coordinates, oriented in plane perpendicular to eu.
01147                  */
01148                 MAT_ZERO( mat );
01149                 mat[0] = xvec[X];
01150                 mat[4] = xvec[Y];
01151                 mat[8] = xvec[Z];
01152 
01153                 mat[1] = yvec[X];
01154                 mat[5] = yvec[Y];
01155                 mat[9] = yvec[Z];
01156 
01157                 mat[2] = zvec[X];
01158                 mat[6] = zvec[Y];
01159                 mat[10] = zvec[Z];
01160                 mat[15] = 1;
01161 
01162                 VADD2SCALE( center, arg_eu->vu_p->v_p->vg_p->coord,
01163                         arg_eu->eumate_p->vu_p->v_p->vg_p->coord, 0.5 );
01164 
01165                 /* Yellow, for now */
01166                 vh = rt_vlblock_find( vbp, 255, 200, 0 );
01167         } else {
01168                 vh = (struct bu_list *)NULL;
01169                 len = 1;
01170         }
01171 
01172         orig_eu = arg_eu->eumate_p;
01173 
01174         eu = orig_eu;
01175         do {
01176                 if(fancy) nmg_vlblock_euleft( vh, eu, center, mat, xvec, yvec, len, tol );
01177 
01178                 nmg_vlblock_eu(vbp, eu, tab, 80, 100, 170, 3, 0);
01179                 eu = eu->eumate_p;
01180 
01181                 nmg_vlblock_eu(vbp, eu, tab, 80, 100, 170, 3, 0);
01182                 eu = eu->radial_p;
01183         } while( eu != orig_eu );
01184 }
01185 
01186 /**
01187  *                      N M G _ V L B L O C K _ L U
01188  */
01189 void
01190 nmg_vlblock_lu(struct bn_vlblock *vbp, const struct loopuse *lu, long int *tab, int red, int green, int blue, int fancy, int loopnum)
01191 {
01192         struct edgeuse  *eu;
01193         long            magic1;
01194         struct vertexuse *vu;
01195 
01196         BN_CK_VLBLOCK(vbp);
01197         NMG_CK_LOOPUSE(lu);
01198         NMG_INDEX_RETURN_IF_SET_ELSE_SET( tab, lu->index );
01199 
01200         magic1 = BU_LIST_FIRST_MAGIC( &lu->down_hd );
01201         if (magic1 == NMG_VERTEXUSE_MAGIC &&
01202             lu->orientation != OT_BOOLPLACE) {
01203                 vu = BU_LIST_PNEXT(vertexuse, &lu->down_hd);
01204                 NMG_CK_VERTEXUSE(vu);
01205                 nmg_vlblock_v(vbp, vu->v_p, tab);
01206         } else if (magic1 == NMG_EDGEUSE_MAGIC) {
01207                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
01208                         nmg_vlblock_eu(vbp, eu, tab, red, green, blue,
01209                                 fancy, loopnum);
01210                 }
01211         }
01212 }
01213 
01214 /**
01215  *                      M N G _ V L B L O C K _ F U
01216  */
01217 void
01218 nmg_vlblock_fu(struct bn_vlblock *vbp, const struct faceuse *fu, long int *tab, int fancy)
01219 {
01220         struct loopuse *lu;
01221         int             loopnum = 0;
01222 
01223         BN_CK_VLBLOCK(vbp);
01224         NMG_CK_FACEUSE(fu);
01225         NMG_INDEX_RETURN_IF_SET_ELSE_SET( tab, fu->index );
01226 
01227         for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
01228                 /* Draw in pale blue / purple */
01229                 if( fancy )  {
01230                         nmg_vlblock_lu(vbp, lu, tab, 80, 100, 170, fancy, loopnum++ );
01231                 } else {
01232                         /* Non-fancy */
01233                         nmg_vlblock_lu(vbp, lu, tab, 80, 100, 170, 0, loopnum++ );
01234                 }
01235         }
01236 }
01237 
01238 /**
01239  *                      N M G _ V L B L O C K _ S
01240  */
01241 void
01242 nmg_vlblock_s(struct bn_vlblock *vbp, const struct shell *s, int fancy)
01243 {
01244         struct faceuse *fu;
01245         struct loopuse *lu;
01246         struct edgeuse *eu;
01247         struct model    *m;
01248         long            *tab;
01249 
01250         BN_CK_VLBLOCK(vbp);
01251         NMG_CK_SHELL(s);
01252         NMG_CK_REGION(s->r_p);
01253         m = s->r_p->m_p;
01254         NMG_CK_MODEL(m);
01255 
01256         /* get space for list of items processed */
01257         tab = (long *)bu_calloc( m->maxindex+1, sizeof(long),
01258                 "nmg_vlblock_s tab[]");
01259 
01260         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )  {
01261                 NMG_CK_FACEUSE(fu);
01262                 nmg_vlblock_fu(vbp, fu, tab, fancy );
01263         }
01264 
01265         for( BU_LIST_FOR( lu, loopuse, &s->lu_hd ) )  {
01266                 NMG_CK_LOOPUSE(lu);
01267                 if( fancy ) {
01268                         nmg_vlblock_lu(vbp, lu, tab, 255, 0, 0, fancy, 0);
01269                 } else {
01270                         /* non-fancy, wire loops in red */
01271                         nmg_vlblock_lu(vbp, lu, tab, 200, 0, 0, 0, 0);
01272                 }
01273         }
01274 
01275         for( BU_LIST_FOR( eu, edgeuse, &s->eu_hd ) )  {
01276                 NMG_CK_EDGEUSE(eu);
01277                 NMG_CK_EDGE(eu->e_p);
01278 
01279                 if( fancy )  {
01280                         nmg_vlblock_eu(vbp, eu, tab, 200, 200, 0, fancy, 0 );
01281                 } else {
01282                         /* non-fancy, wire edges in yellow */
01283                         nmg_vlblock_eu(vbp, eu, tab, 200, 200, 0, 0, 0);
01284                 }
01285         }
01286         if (s->vu_p) {
01287                 nmg_vlblock_v(vbp, s->vu_p->v_p, tab );
01288         }
01289 
01290         bu_free( (char *)tab, "nmg_vlblock_s tab[]" );
01291 }
01292 
01293 /**
01294  *                      N M G _ V L B L O C K _ R
01295  */
01296 void
01297 nmg_vlblock_r(struct bn_vlblock *vbp, const struct nmgregion *r, int fancy)
01298 {
01299         struct shell *s;
01300 
01301         BN_CK_VLBLOCK(vbp);
01302         NMG_CK_REGION(r);
01303 
01304         for( BU_LIST_FOR( s, shell, &r->s_hd ) )  {
01305                 nmg_vlblock_s(vbp, s, fancy);
01306         }
01307 }
01308 
01309 /**
01310  *                      N M G _ V L B L O C K _ M
01311  */
01312 void
01313 nmg_vlblock_m(struct bn_vlblock *vbp, const struct model *m, int fancy)
01314 {
01315         struct nmgregion *r;
01316 
01317         BN_CK_VLBLOCK(vbp);
01318         NMG_CK_MODEL(m);
01319 
01320         for( BU_LIST_FOR( r, nmgregion, &m->r_hd ) )  {
01321                 nmg_vlblock_r(vbp, r, fancy);
01322         }
01323 }
01324 
01325 /************************************************************************
01326  *                                                                      *
01327  *              Visualization helper routines                           *
01328  *                                                                      *
01329  ************************************************************************/
01330 
01331 /*
01332  *  If another use of this edge is in another shell, plot all the
01333  *  uses around this edge.
01334  */
01335 void
01336 nmg_pl_edges_in_2_shells(struct bn_vlblock *vbp, long int *b, const struct edgeuse *eu, int fancy, const struct bn_tol *tol)
01337 {
01338         const struct edgeuse    *eur;
01339         const struct shell      *s;
01340 
01341         BN_CK_TOL(tol);
01342         eur = eu;
01343         NMG_CK_EDGEUSE(eu);
01344         NMG_CK_LOOPUSE(eu->up.lu_p);
01345         NMG_CK_FACEUSE(eu->up.lu_p->up.fu_p);
01346         s = eu->up.lu_p->up.fu_p->s_p;
01347         NMG_CK_SHELL(s);
01348 
01349         do {
01350                 NMG_CK_EDGEUSE(eur);
01351 
01352                 if (*eur->up.magic_p == NMG_LOOPUSE_MAGIC &&
01353                     *eur->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC &&
01354                     eur->up.lu_p->up.fu_p->s_p != s) {
01355                         nmg_vlblock_around_eu(vbp, eu, b, fancy, tol);
01356                         break;
01357                     }
01358 
01359                 eur = eur->radial_p->eumate_p;
01360         } while (eur != eu);
01361 }
01362 
01363 /**
01364  *                      N M G _ P L _ I S E C T
01365  *
01366  *  Called by nmg_bool.c
01367  */
01368 void
01369 nmg_pl_isect(const char *filename, const struct shell *s, const struct bn_tol *tol)
01370 {
01371         struct faceuse          *fu;
01372         struct loopuse          *lu;
01373         struct edgeuse          *eu;
01374         long                    *b;
01375         FILE                    *fp;
01376         long                    magic1;
01377         struct bn_vlblock       *vbp;
01378 
01379         NMG_CK_SHELL(s);
01380         BN_CK_TOL(tol);
01381 
01382         if ((fp=fopen(filename, "w")) == (FILE *)NULL) {
01383                 (void)perror(filename);
01384                 bu_bomb("unable to open file for writing");
01385         }
01386 
01387         b = (long *)bu_calloc( s->r_p->m_p->maxindex+1, sizeof(long),
01388                 "nmg_pl_isect flags[]" );
01389 
01390         vbp = rt_vlblock_init();
01391 
01392         bu_log("overlay %s\n", filename);
01393         if( s->sa_p )  {
01394                 NMG_CK_SHELL_A( s->sa_p );
01395 #if 0
01396                 pdv_3space( fp, s->sa_p->min_pt, s->sa_p->max_pt );
01397 #endif
01398         }
01399 
01400         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )  {
01401                 NMG_CK_FACEUSE(fu);
01402                 for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
01403                         NMG_CK_LOOPUSE(lu);
01404                         magic1 = BU_LIST_FIRST_MAGIC( &lu->down_hd );
01405                         if (magic1 == NMG_EDGEUSE_MAGIC) {
01406                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
01407                                         NMG_CK_EDGEUSE(eu);
01408                                         nmg_pl_edges_in_2_shells(vbp, b, eu, 0, tol);
01409                                 }
01410                         } else if (magic1 == NMG_VERTEXUSE_MAGIC) {
01411                                 ;
01412                         } else {
01413                                 rt_bomb("nmg_pl_isect() bad loopuse down\n");
01414                         }
01415                 }
01416         }
01417 
01418         rt_plot_vlblock(fp, vbp);
01419         rt_vlblock_free(vbp);
01420 
01421         bu_free( (char *)b, "nmg_pl_isect flags[]" );
01422 
01423         (void)fclose(fp);
01424 }
01425 
01426 /**
01427  *                      N M G _ P L _ C O M B _ F U
01428  *
01429  *  Called from nmg_bool.c/nmg_face_combine()
01430  */
01431 void
01432 nmg_pl_comb_fu(int num1, int num2, const struct faceuse *fu1)
01433 {
01434         FILE                    *fp;
01435         char                    name[64];
01436         int                     do_plot = 0;
01437         int                     do_anim = 0;
01438         struct model            *m;
01439         long                    *tab;
01440         struct bn_vlblock       *vbp;
01441 
01442         if(rt_g.NMG_debug & DEBUG_PLOTEM &&
01443            rt_g.NMG_debug & DEBUG_FCUT ) do_plot = 1;
01444         if( rt_g.NMG_debug & DEBUG_PL_ANIM )  do_anim = 1;
01445 
01446         if( !do_plot && !do_anim )  return;
01447 
01448         m = nmg_find_model( &fu1->l.magic );
01449         NMG_CK_MODEL(m);
01450         /* get space for list of items processed */
01451         tab = (long *)bu_calloc( m->maxindex+1, sizeof(long),
01452                 "nmg_pl_comb_fu tab[]");
01453 
01454         vbp = rt_vlblock_init();
01455 
01456         nmg_vlblock_fu(vbp, fu1, tab, 3);
01457 
01458         if( do_plot )  {
01459                 (void)sprintf(name, "comb%d.%d.pl", num1, num2);
01460                 if ((fp=fopen(name, "w")) == (FILE *)NULL) {
01461                         (void)perror(name);
01462                         return;
01463                 }
01464                 bu_log("overlay %s\n", name);
01465 
01466                 rt_plot_vlblock(fp, vbp);
01467 
01468                 (void)fclose(fp);
01469         }
01470 
01471         if( do_anim )  {
01472                 if( nmg_vlblock_anim_upcall )  {
01473                         (*nmg_vlblock_anim_upcall)( vbp,
01474                                 (rt_g.NMG_debug&DEBUG_PL_SLOW) ? US_DELAY : 0,
01475                                 0 );
01476                 } else {
01477                         bu_log("null nmg_vlblock_anim_upcall, no animation\n");
01478                 }
01479         }
01480         rt_vlblock_free(vbp);
01481         bu_free( (char *)tab, "nmg_pl_comb_fu tab[]" );
01482 }
01483 
01484 /**
01485  *                      N M G _ P L _ 2 F U
01486  *
01487  *  Note that 'str' is expected to contain a %d to place the frame number.
01488  *
01489  *  Called from nmg_isect_2faces and other places.
01490  */
01491 void
01492 nmg_pl_2fu(const char *str, int unused, const struct faceuse *fu1, const struct faceuse *fu2, int show_mates)
01493 {
01494         FILE            *fp;
01495         char            name[32];
01496         struct model    *m;
01497         long            *tab;
01498         static int      num = 1;
01499         struct bn_vlblock       *vbp;
01500 
01501         if( (rt_g.NMG_debug & (DEBUG_PLOTEM|DEBUG_PL_ANIM)) == 0 )  return;
01502 
01503         m = nmg_find_model( &fu1->l.magic );
01504         NMG_CK_MODEL(m);
01505         /* get space for list of items processed */
01506         tab = (long *)bu_calloc( m->maxindex+1, sizeof(long),
01507                 "nmg_pl_comb_fu tab[]");
01508 
01509         /* Create the vlblock */
01510         vbp = rt_vlblock_init();
01511 
01512         nmg_vlblock_fu( vbp, fu1, tab, 3);
01513         if( show_mates )
01514                 nmg_vlblock_fu( vbp, fu1->fumate_p, tab, 3);
01515 
01516         nmg_vlblock_fu( vbp, fu2, tab, 3);
01517         if( show_mates )
01518                 nmg_vlblock_fu( vbp, fu2->fumate_p, tab, 3);
01519 
01520         if( rt_g.NMG_debug & DEBUG_PLOTEM )  {
01521                 (void)sprintf(name, str, num++);
01522                 bu_log("overlay %s\n", name);
01523                 if ((fp=fopen(name, "w")) == (FILE *)NULL)  {
01524                         perror(name);
01525                         return;
01526                 }
01527                 rt_plot_vlblock( fp, vbp );
01528                 (void)fclose(fp);
01529         }
01530 
01531         if( rt_g.NMG_debug & DEBUG_PL_ANIM )  {
01532                 /* Cause animation of boolean operation as it proceeds! */
01533                 if( nmg_vlblock_anim_upcall )  {
01534                         (*nmg_vlblock_anim_upcall)( vbp,
01535                                 (rt_g.NMG_debug&DEBUG_PL_SLOW) ? US_DELAY : 0,
01536                                 0 );
01537                 }
01538         }
01539 
01540         rt_vlblock_free(vbp);
01541         bu_free( (char *)tab, "nmg_pl_2fu tab[]" );
01542 }
01543 
01544 /************************************************************************
01545  *                                                                      *
01546  *                      Graphical display of classifier results         *
01547  *                                                                      *
01548  ************************************************************************/
01549 
01550 int             nmg_class_nothing_broken=1;
01551 static long     **global_classlist;
01552 static long     *broken_tab;
01553 static int      broken_tab_len;
01554 static int      broken_color;
01555 static unsigned char broken_colors[][3] = {
01556         { 100, 100, 255 },      /* NMG_CLASS_AinB (bright blue) */
01557         { 255,  50,  50 },      /* NMG_CLASS_AonBshared (red) */
01558         { 255,  50, 255 },      /* NMG_CLASS_AonBanti (magenta) */
01559         {  50, 255,  50 },      /* NMG_CLASS_AoutB (bright green) */
01560         { 255, 255, 255 },      /* UNKNOWN (white) */
01561         { 255, 255, 125 }       /* no classification list (cyan) */
01562 };
01563 #define PICK_BROKEN_COLOR(p) { \
01564         if (global_classlist == (long **)NULL) { \
01565                 broken_color = 5; \
01566         } else if( NMG_INDEX_TEST(global_classlist[NMG_CLASS_AinB], (p)) ) \
01567                 broken_color = NMG_CLASS_AinB; \
01568         else if( NMG_INDEX_TEST(global_classlist[NMG_CLASS_AonBshared], (p)) ) \
01569                 broken_color = NMG_CLASS_AonBshared; \
01570         else if( NMG_INDEX_TEST(global_classlist[NMG_CLASS_AonBanti], (p)) ) \
01571                 broken_color = NMG_CLASS_AonBanti; \
01572         else if ( NMG_INDEX_TEST(global_classlist[NMG_CLASS_AoutB], (p)) ) \
01573                 broken_color = NMG_CLASS_AoutB; \
01574         else \
01575                 broken_color = 4;}
01576 
01577 /**
01578  *                      S H O W _ B R O K E N _ V U
01579  */
01580 static void
01581 show_broken_vu(struct bn_vlblock *vbp, const struct vertexuse *vu, int fancy)
01582 {
01583         pointp_t p;
01584         struct bu_list  *vh;
01585         struct vertex *v;
01586         point_t pt;
01587 
01588         NMG_CK_VERTEXUSE(vu);
01589         v = vu->v_p;
01590         NMG_CK_VERTEX(v);
01591         NMG_CK_VERTEX_G(v->vg_p);
01592 
01593         NMG_INDEX_RETURN_IF_SET_ELSE_SET( broken_tab, v->index );
01594 
01595         NMG_CK_VERTEX_G(v->vg_p);
01596         p = v->vg_p->coord;
01597 
01598         PICK_BROKEN_COLOR(vu->v_p);
01599         if (broken_color == 4) {
01600 /*              fprintf(stderr, "vertex broken_color %d...", broken_color); */
01601                 PICK_BROKEN_COLOR(vu);
01602 /*              fprintf(stderr, "vertexuse broken_color %d\n", broken_color); */
01603         }
01604         vh = rt_vlblock_find( vbp,
01605                 broken_colors[broken_color][0], broken_colors[broken_color][1], broken_colors[broken_color][2]);
01606 
01607         RT_ADD_VLIST( vh, p, BN_VLIST_LINE_MOVE );
01608         RT_ADD_VLIST( vh, p, BN_VLIST_LINE_DRAW );
01609 
01610 
01611         VMOVE(pt, p);
01612         pt[0] += 0.05;
01613         RT_ADD_VLIST( vh, pt, BN_VLIST_LINE_MOVE );
01614         VMOVE(pt, p);
01615         pt[0] -= 0.05;
01616         RT_ADD_VLIST( vh, pt, BN_VLIST_LINE_DRAW );
01617 
01618         VMOVE(pt, p);
01619         pt[1] += 0.05;
01620         RT_ADD_VLIST( vh, pt, BN_VLIST_LINE_MOVE );
01621         VMOVE(pt, p);
01622         pt[1] -= 0.05;
01623         RT_ADD_VLIST( vh, pt, BN_VLIST_LINE_DRAW );
01624 
01625         VMOVE(pt, p);
01626         pt[2] += 0.05;
01627         RT_ADD_VLIST( vh, pt, BN_VLIST_LINE_MOVE );
01628         VMOVE(pt, p);
01629         pt[2] -= 0.05;
01630         RT_ADD_VLIST( vh, pt, BN_VLIST_LINE_DRAW );
01631 
01632         RT_ADD_VLIST( vh, p, BN_VLIST_LINE_MOVE );
01633 }
01634 
01635 static void
01636 show_broken_e(struct bn_vlblock *vbp, const struct edgeuse *eu, int fancy)
01637 {
01638         pointp_t p0, p1;
01639         point_t end0, end1;
01640         vect_t v;
01641         struct bu_list  *vh;
01642 
01643         NMG_CK_VERTEXUSE(eu->vu_p);
01644         NMG_CK_VERTEX(eu->vu_p->v_p);
01645         NMG_CK_VERTEX_G(eu->vu_p->v_p->vg_p);
01646         NMG_CK_VERTEXUSE(eu->eumate_p->vu_p);
01647         NMG_CK_VERTEX(eu->eumate_p->vu_p->v_p);
01648         NMG_CK_VERTEX_G(eu->eumate_p->vu_p->v_p->vg_p);
01649 
01650         NMG_INDEX_RETURN_IF_SET_ELSE_SET( broken_tab, eu->e_p->index );
01651 
01652         p0 = eu->vu_p->v_p->vg_p->coord;
01653         p1 = eu->eumate_p->vu_p->v_p->vg_p->coord;
01654 
01655         /* leave a little room between the edge endpoints and the vertex
01656          * compute endpoints by forming a vector between verts, scale vector,
01657          * and modify points
01658          */
01659         VSUB2SCALE(v, p1, p0, 0.90);
01660         VADD2(end0, p0, v);
01661         VSUB2(end1, p1, v);
01662 
01663 
01664         PICK_BROKEN_COLOR(eu->e_p);
01665         if (broken_color == 4) {
01666 /*              fprintf(stderr, "edge broken_color %d... ", broken_color); */
01667                 PICK_BROKEN_COLOR(eu);
01668 /*              fprintf(stderr, "edgeuse broken_color %d\n", broken_color); */
01669         }
01670 
01671         vh = rt_vlblock_find( vbp,
01672                 broken_colors[broken_color][0], broken_colors[broken_color][1], broken_colors[broken_color][2]);
01673 
01674         RT_ADD_VLIST( vh, end0, BN_VLIST_LINE_MOVE );
01675         RT_ADD_VLIST( vh, end1, BN_VLIST_LINE_DRAW );
01676 
01677         show_broken_vu(vbp, eu->vu_p, fancy);
01678         show_broken_vu(vbp, eu->eumate_p->vu_p, fancy);
01679 
01680 }
01681 
01682 
01683 static void
01684 show_broken_eu(struct bn_vlblock *vbp, const struct edgeuse *eu, int fancy)
01685 {
01686         struct bu_list  *vh;
01687         int red, green, blue;
01688         point_t base, tip;
01689         point_t radial_tip;
01690         point_t next_base;
01691 
01692         NMG_CK_EDGEUSE(eu);
01693         NMG_CK_EDGE(eu->e_p);
01694 
01695         show_broken_e(vbp, eu, fancy);
01696 
01697         if (!fancy) return;
01698 
01699         /* paint the edgeuse lines */
01700         if (*eu->up.magic_p == NMG_LOOPUSE_MAGIC &&
01701             *eu->up.lu_p->up.magic_p == NMG_FACEUSE_MAGIC) {
01702 
01703                 red = broken_colors[broken_color][0];
01704                 green = broken_colors[broken_color][1];
01705                 blue = broken_colors[broken_color][2];
01706 
01707                 nmg_eu_coords(eu, base, tip);
01708                 if (eu->up.lu_p->up.fu_p->orientation == OT_SAME)
01709                         red += 50;
01710                 else if (eu->up.lu_p->up.fu_p->orientation == OT_OPPOSITE)
01711                         red -= 50;
01712                 else
01713                         red = green = blue = 255;
01714 
01715                 vh = rt_vlblock_find( vbp, red, green, blue );
01716                 RT_ADD_VLIST( vh, base, BN_VLIST_LINE_MOVE );
01717                 RT_ADD_VLIST( vh, tip, BN_VLIST_LINE_DRAW );
01718 
01719                 nmg_eu_radial( eu, radial_tip );
01720                 vh = rt_vlblock_find( vbp, red, green-20, blue );
01721                 RT_ADD_VLIST( vh, tip, BN_VLIST_LINE_MOVE );
01722                 RT_ADD_VLIST( vh, radial_tip, BN_VLIST_LINE_DRAW );
01723 
01724                 nmg_eu_next_base( eu, next_base );
01725                 vh = rt_vlblock_find( vbp, 0, 100, 0 );
01726                 RT_ADD_VLIST( vh, tip, BN_VLIST_LINE_MOVE );
01727                 RT_ADD_VLIST( vh, next_base, BN_VLIST_LINE_DRAW );
01728         }
01729 
01730 }
01731 
01732 static void
01733 show_broken_lu(struct bn_vlblock *vbp, const struct loopuse *lu, int fancy)
01734 {
01735         register struct edgeuse *eu;
01736         struct bu_list  *vh;
01737         vect_t          n;
01738 
01739         NMG_CK_LOOPUSE(lu);
01740 
01741         if( BU_LIST_FIRST_MAGIC(&lu->down_hd)==NMG_VERTEXUSE_MAGIC )  {
01742                 register struct vertexuse *vu;
01743                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
01744                 show_broken_vu(vbp, vu, fancy);
01745                 return;
01746         }
01747 
01748         if (rt_g.NMG_debug & DEBUG_GRAPHCL)  {
01749                 for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd))
01750                         show_broken_eu(vbp, eu, fancy);
01751         }
01752 
01753         /* Draw colored polygons for the actual face loops */
01754         /* Faces are not classified, only loops */
01755         /* This can obscure the edge/vertex info */
01756         PICK_BROKEN_COLOR(lu->l_p);
01757         vh = rt_vlblock_find( vbp,
01758                 broken_colors[broken_color][0], broken_colors[broken_color][1], broken_colors[broken_color][2]);
01759 
01760         if( *lu->up.magic_p == NMG_FACEUSE_MAGIC )  {
01761                 NMG_GET_FU_NORMAL( n, lu->up.fu_p );
01762         } else {
01763                 /* For wire loops, use a constant normal */
01764                 VSET( n, 0, 0, 1 );
01765         }
01766 
01767         if ((rt_g.NMG_debug & (DEBUG_GRAPHCL|DEBUG_PL_LOOP)) == (DEBUG_PL_LOOP) ) {
01768                 /* If only DEBUG_PL_LOOP set, just draw lu as wires */
01769                 nmg_lu_to_vlist( vh, lu, 0, n );
01770         } else if ((rt_g.NMG_debug & (DEBUG_GRAPHCL|DEBUG_PL_LOOP)) == (DEBUG_GRAPHCL|DEBUG_PL_LOOP) ) {
01771                 /* Draw as polygons if both set */
01772                 nmg_lu_to_vlist( vh, lu, 1, n );
01773         } else {
01774                 /* If only DEBUG_GRAPHCL set, don't draw lu's at all */
01775         }
01776 }
01777 
01778 
01779 
01780 static void
01781 show_broken_fu(struct bn_vlblock *vbp, const struct faceuse *fu, int fancy)
01782 {
01783         register struct loopuse *lu;
01784 
01785         NMG_CK_FACEUSE(fu);
01786         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
01787                 show_broken_lu(vbp, lu, fancy);
01788         }
01789 }
01790 
01791 static void
01792 show_broken_s(struct bn_vlblock *vbp, const struct shell *s, int fancy)
01793 {
01794         struct faceuse *fu;
01795         struct loopuse *lu;
01796         struct edgeuse *eu;
01797 
01798         NMG_CK_SHELL(s);
01799         for ( BU_LIST_FOR(fu, faceuse, &s->fu_hd ))
01800                 show_broken_fu(vbp, fu, fancy);
01801         for ( BU_LIST_FOR(lu, loopuse, &s->lu_hd ))
01802                 show_broken_lu(vbp, lu, fancy);
01803         for ( BU_LIST_FOR(eu, edgeuse, &s->eu_hd ))
01804                 show_broken_eu(vbp, eu, fancy);
01805         if ( s->vu_p )
01806                 show_broken_vu(vbp, s->vu_p, fancy);
01807 }
01808 static void
01809 show_broken_r(struct bn_vlblock *vbp, const struct nmgregion *r, int fancy)
01810 {
01811         register struct shell *s;
01812 
01813         NMG_CK_REGION(r);
01814         for ( BU_LIST_FOR(s, shell, & r->s_hd))
01815                 show_broken_s(vbp, s, fancy);
01816 }
01817 
01818 static void
01819 show_broken_m(struct bn_vlblock *vbp, const struct model *m, int fancy)
01820 {
01821         register struct nmgregion *r;
01822 
01823         NMG_CK_MODEL(m);
01824         for (BU_LIST_FOR(r, nmgregion, &m->r_hd))
01825                 show_broken_r(vbp, r, fancy);
01826 }
01827 
01828 static struct bn_vlblock *vbp = (struct bn_vlblock *)NULL;
01829 static int stepalong = 0;
01830 
01831 void
01832 nmg_plot_sigstepalong(int i)
01833 {
01834         stepalong=1;
01835 }
01836 
01837 /**
01838  *                      S H O W _ B R O K E N _ S T U F F
01839  *
01840  * XXX Needs new name, with nmg_ prefix, and a stronger indication
01841  * that this is a graphical display of classifier operation.
01842  */
01843 void
01844 nmg_show_broken_classifier_stuff(long int *p, long int **classlist, int all_new, int fancy, const char *a_string)
01845 {
01846         struct model *m;
01847 
01848 /*      printf("showing broken stuff\n"); */
01849 
01850         global_classlist = classlist;
01851 
01852         nmg_class_nothing_broken = 0;
01853 
01854         if (!vbp)
01855                 vbp = rt_vlblock_init();
01856         else if (all_new) {
01857                 rt_vlblock_free(vbp);
01858                 vbp = (struct bn_vlblock *)NULL;
01859                 vbp = rt_vlblock_init();
01860         }
01861 
01862         m = nmg_find_model(p);
01863         /* get space for list of items processed */
01864         if (!broken_tab) {
01865                 broken_tab = (long *)bu_calloc( m->maxindex+1, sizeof(long),
01866                         "nmg_vlblock_s tab[]");
01867                 broken_tab_len = m->maxindex+1;
01868         } else {
01869                 if( broken_tab_len < m->maxindex+1 ) {
01870                         bu_log("nmg_show_broken_classifier_stuff() maxindex increased! was %d, now %d\n",
01871                                 broken_tab_len, m->maxindex+1 );
01872                         broken_tab = (long *)rt_realloc( (char *)broken_tab,
01873                                 (m->maxindex+1) * sizeof(long),
01874                                 "nmg_vlblock_s tab[] enlargement");
01875                         broken_tab_len = m->maxindex+1;
01876                 }
01877                 if (all_new) {
01878                         bzero( (char *)broken_tab,  (m->maxindex+1) * sizeof(long));
01879                 }
01880         }
01881 
01882 
01883         switch (*p) {
01884         case NMG_MODEL_MAGIC:
01885                 show_broken_m( vbp, (struct model *)p, fancy);
01886                 break;
01887         case NMG_REGION_MAGIC:
01888                 show_broken_r( vbp, (struct nmgregion *)p, fancy);
01889                 break;
01890         case NMG_SHELL_MAGIC:
01891                 show_broken_s( vbp, (struct shell *)p, fancy);
01892                 break;
01893         case NMG_FACE_MAGIC:
01894                 show_broken_fu( vbp, ((struct face *)p)->fu_p, fancy);
01895                 break;
01896         case NMG_FACEUSE_MAGIC:
01897                 show_broken_fu( vbp, (struct faceuse *)p, fancy);
01898 #if 0
01899                 {
01900                         struct bn_vlblock *vbp2 = vbp;
01901                         register struct loopuse *lu;
01902                         struct faceuse *fu = (struct faceuse *)p;
01903                         int i;
01904                         void            (*cur_sigint)();
01905 
01906                         cur_sigint = signal(SIGINT, nmg_plot_sigstepalong);
01907                         for (stepalong=0;!stepalong;) {
01908                                 for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
01909                                         nmg_show_broken_classifier_stuff(lu, classlist, 1, fancy);
01910                                         for (i=0 ; ++i ; );
01911                                 }
01912                         }
01913                         signal(SIGINT, cur_sigint);
01914 
01915                         show_broken_fu( vbp, (struct faceuse *)p, fancy);
01916                 }
01917 #endif
01918                 break;
01919         case NMG_LOOPUSE_MAGIC:
01920                 show_broken_lu( vbp, (struct loopuse *)p, fancy);
01921                 break;
01922         case NMG_EDGE_MAGIC:
01923                  show_broken_eu( vbp, ((struct edge *)p)->eu_p, fancy);
01924                  break;
01925         case NMG_EDGEUSE_MAGIC:
01926                 show_broken_eu( vbp, (struct edgeuse *)p, fancy);
01927                 break;
01928         case NMG_VERTEXUSE_MAGIC:
01929                 show_broken_vu( vbp, (struct vertexuse *)p, fancy);
01930                 break;
01931         default: fprintf(stderr, "Unknown magic number %ld %0lx %lu %0lx\n", *p, *p, (unsigned long)p, (unsigned long)p);
01932                                 break;
01933         }
01934 
01935         /* Cause animation of boolean operation as it proceeds! */
01936         /* The "copy" flag on nmg_vlblock_anim_upcall() means that
01937          * the vlist will remain, undisturbed, for further use. */
01938         if( nmg_vlblock_anim_upcall )  {
01939                 void            (*cur_sigint)();
01940 
01941                 if (!a_string) {
01942                         (*nmg_vlblock_anim_upcall)( vbp,
01943                                 (rt_g.NMG_debug&DEBUG_PL_SLOW) ? US_DELAY : 0,
01944                                 1 );
01945                 } else {
01946 
01947                         bu_log("NMG Intermediate display Ctrl-C to continue (%s)\n", a_string);
01948                         cur_sigint = signal(SIGINT, nmg_plot_sigstepalong);
01949                         (*nmg_vlblock_anim_upcall)( vbp,
01950                                 (rt_g.NMG_debug&DEBUG_PL_SLOW) ? US_DELAY : 0,
01951                                 1 );
01952                         for (stepalong = 0; !stepalong ; ) {
01953                                 (*nmg_mged_debug_display_hack)();
01954                         }
01955                         signal(SIGINT, cur_sigint);
01956                         bu_log("Continuing\n");
01957                 }
01958         } else {
01959                 /* Non interactive, drop a plot file */
01960                 char    buf[128];
01961                 static int      num=0;
01962                 FILE            *fp;
01963 
01964                 sprintf( buf, "cbroke%d.pl", num++ );
01965                 if( (fp = fopen(buf, "w")) )  {
01966                         rt_plot_vlblock(fp, vbp);
01967                         fclose(fp);
01968                         bu_log("overlay %s for %s\n", buf, a_string);
01969                 }
01970 
01971                 rt_vlblock_free(vbp);
01972                 vbp = (struct bn_vlblock *)NULL;
01973                 bu_free((char *)broken_tab, "broken_tab");
01974                 broken_tab = (long *)NULL;
01975                 broken_tab_len = 0;
01976         }
01977 }
01978 
01979 /**
01980  *                      N M G _ F A C E _ P L O T
01981  */
01982 void
01983 nmg_face_plot(const struct faceuse *fu)
01984 {
01985         FILE            *fp;
01986         char            name[32];
01987         extern void (*nmg_vlblock_anim_upcall)();
01988         struct model            *m;
01989         struct bn_vlblock       *vbp;
01990         long            *tab;
01991         int             fancy;
01992         static int      num = 1;
01993 
01994         if( (rt_g.NMG_debug & (DEBUG_PLOTEM|DEBUG_PL_ANIM)) == 0 )  return;
01995 
01996         NMG_CK_FACEUSE(fu);
01997 
01998         m = nmg_find_model( (long *)fu );
01999         NMG_CK_MODEL(m);
02000 
02001         /* get space for list of items processed */
02002         tab = (long *)bu_calloc( m->maxindex+1, sizeof(long),
02003                 "nmg_face_plot tab[]");
02004 
02005         vbp = rt_vlblock_init();
02006 
02007         fancy = 3;      /* show both types of edgeuses */
02008         nmg_vlblock_fu(vbp, fu, tab, fancy );
02009 
02010         if( rt_g.NMG_debug & DEBUG_PLOTEM )  {
02011                 (void)sprintf(name, "face%d.pl", num++);
02012                 bu_log("overlay %s\n", name);
02013                 if ((fp=fopen(name, "w")) == (FILE *)NULL)  {
02014                         perror(name);
02015                         return;
02016                 }
02017                 rt_plot_vlblock( fp, vbp );
02018                 (void)fclose(fp);
02019         }
02020 
02021         if( rt_g.NMG_debug & DEBUG_PL_ANIM )  {
02022                 /* Cause animation of boolean operation as it proceeds! */
02023                 if( nmg_vlblock_anim_upcall )  {
02024                         /* if requested, delay 3/4 second */
02025                         (*nmg_vlblock_anim_upcall)( vbp,
02026                                 (rt_g.NMG_debug&DEBUG_PL_SLOW) ? 750000 : 0,
02027                                 0 );
02028                 } else {
02029                         bu_log("null nmg_vlblock_anim_upcall, no animation\n");
02030                 }
02031         }
02032         rt_vlblock_free(vbp);
02033         bu_free( (char *)tab, "nmg_face_plot tab[]" );
02034 
02035 }
02036 
02037 /**
02038  *                      N M G _ 2 F A C E _ P L O T
02039  *
02040  *  Just like nmg_face_plot, except it draws two faces each iteration.
02041  */
02042 void
02043 nmg_2face_plot(const struct faceuse *fu1, const struct faceuse *fu2)
02044 {
02045         extern void (*nmg_vlblock_anim_upcall)();
02046         struct model            *m;
02047         struct bn_vlblock       *vbp;
02048         long            *tab;
02049         int             fancy;
02050 
02051         if( ! (rt_g.NMG_debug & DEBUG_PL_ANIM) )  return;
02052 
02053         NMG_CK_FACEUSE(fu1);
02054         NMG_CK_FACEUSE(fu2);
02055 
02056         m = nmg_find_model( (long *)fu1 );
02057         NMG_CK_MODEL(m);
02058 
02059         /* get space for list of items processed */
02060         tab = (long *)bu_calloc( m->maxindex+1, sizeof(long),
02061                 "nmg_2face_plot tab[]");
02062 
02063         vbp = rt_vlblock_init();
02064 
02065         fancy = 3;      /* show both types of edgeuses */
02066         nmg_vlblock_fu(vbp, fu1, tab, fancy );
02067         nmg_vlblock_fu(vbp, fu2, tab, fancy );
02068 
02069         /* Cause animation of boolean operation as it proceeds! */
02070         if( nmg_vlblock_anim_upcall )  {
02071                 /* if requested, delay 3/4 second */
02072                 (*nmg_vlblock_anim_upcall)( vbp,
02073                         (rt_g.NMG_debug&DEBUG_PL_SLOW) ? 750000 : 0,
02074                         0 );
02075         } else {
02076                 bu_log("null nmg_vlblock_anim_upcall, no animation\n");
02077         }
02078         rt_vlblock_free(vbp);
02079         bu_free( (char *)tab, "nmg_2face_plot tab[]" );
02080 
02081 }
02082 
02083 /**
02084  *                      N M G _ F A C E _ L U _ P L O T
02085  *
02086  *  Plot the loop, and a ray from vu1 to vu2.
02087  */
02088 void
02089 nmg_face_lu_plot(const struct loopuse *lu, const struct vertexuse *vu1, const struct vertexuse *vu2)
02090 {
02091         FILE    *fp;
02092         struct model    *m;
02093         long            *b;
02094         char            buf[128];
02095         static int      num = 0;
02096         vect_t          dir;
02097         point_t         p1, p2;
02098 
02099         if(!(rt_g.NMG_debug&DEBUG_PLOTEM)) return;
02100 
02101         NMG_CK_LOOPUSE(lu);
02102         NMG_CK_VERTEXUSE(vu1);
02103         NMG_CK_VERTEXUSE(vu2);
02104 
02105         m = nmg_find_model((long *)lu);
02106         sprintf(buf, "loop%d.pl", num++ );
02107 
02108         if( (fp = fopen(buf, "w")) == NULL )  {
02109                 perror(buf);
02110                 return;
02111         }
02112         b = (long *)bu_calloc( m->maxindex, sizeof(long), "nmg_face_lu_plot flag[]" );
02113         nmg_pl_lu(fp, lu, b, 255, 0, 0);
02114 
02115         /*
02116          *  Two yellow lines for the ray.
02117          *  Overshoot edge by +/-10%, for visibility.
02118          *  Don't draw over top of the actual edge, it might hide verts.
02119          */
02120         pl_color(fp, 255, 255, 0);
02121         VSUB2( dir, vu2->v_p->vg_p->coord, vu1->v_p->vg_p->coord );
02122         VJOIN1( p1, vu1->v_p->vg_p->coord, -0.1, dir );
02123         pdv_3line(fp, p1, vu1->v_p->vg_p->coord );
02124         VJOIN1( p2, vu1->v_p->vg_p->coord,  1.1, dir );
02125         pdv_3line(fp, vu2->v_p->vg_p->coord, p2 );
02126 
02127         fclose(fp);
02128         bu_log("overlay %s\n", buf);
02129         bu_free( (char *)b, "nmg_face_lu_plot flag[]" );
02130 }
02131 
02132 /**
02133  *                      N M G _ P L O T _ L U _ R A Y
02134  *
02135  *  Plot the loop, a ray from vu1 to vu2, and the left vector.
02136  */
02137 void
02138 nmg_plot_lu_ray(const struct loopuse *lu, const struct vertexuse *vu1, const struct vertexuse *vu2, const fastf_t *left)
02139 {
02140         FILE    *fp;
02141         struct model    *m;
02142         long            *b;
02143         char            buf[128];
02144         static int      num = 0;
02145         vect_t          dir;
02146         point_t         p1, p2;
02147         fastf_t         left_mag;
02148 
02149         if(!(rt_g.NMG_debug&DEBUG_PLOTEM)) return;
02150 
02151         NMG_CK_LOOPUSE(lu);
02152         NMG_CK_VERTEXUSE(vu1);
02153         NMG_CK_VERTEXUSE(vu2);
02154 
02155         m = nmg_find_model((long *)lu);
02156         sprintf(buf, "loop%d.pl", num++ );
02157 
02158         if( (fp = fopen(buf, "w")) == NULL )  {
02159                 perror(buf);
02160                 return;
02161         }
02162         b = (long *)bu_calloc( m->maxindex, sizeof(long), "nmg_plot_lu_ray flag[]" );
02163         nmg_pl_lu(fp, lu, b, 255, 0, 0);
02164 
02165         /*
02166          *  Two yellow lines for the ray, and a third for the left vector.
02167          *  Overshoot edge by +/-10%, for visibility.
02168          *  Don't draw over top of the actual edge, it might hide verts.
02169          */
02170         pl_color(fp, 255, 255, 0);
02171         VSUB2( dir, vu2->v_p->vg_p->coord, vu1->v_p->vg_p->coord );
02172         VJOIN1( p1, vu1->v_p->vg_p->coord, -0.1, dir );
02173         pdv_3line(fp, p1, vu1->v_p->vg_p->coord );
02174         VJOIN1( p2, vu1->v_p->vg_p->coord,  1.1, dir );
02175         pdv_3line(fp, vu2->v_p->vg_p->coord, p2 );
02176 
02177         /* The left vector */
02178         left_mag = 0.1 * MAGNITUDE(dir);
02179         VJOIN1( p2, p1, left_mag, left );
02180         pdv_3line(fp, p1, p2);
02181 
02182         fclose(fp);
02183         bu_log("overlay %s\n", buf);
02184         bu_free( (char *)b, "nmg_plot_lu_ray flag[]" );
02185 }
02186 
02187 /**
02188  *                      N M G _ P L O T _ R A Y _ F A C E
02189  */
02190 void
02191 nmg_plot_ray_face(const char *fname, fastf_t *pt, const fastf_t *dir, const struct faceuse *fu)
02192 {
02193         FILE *fd;
02194         long *b;
02195         point_t pp;
02196         static int i=0;
02197         char name[1024] = {0};
02198 
02199         if ( ! (rt_g.NMG_debug & DEBUG_NMGRT) )
02200                 return;
02201 
02202         sprintf(name, "%s%0d.pl", fname, i++);
02203         if ((fd = fopen(name, "w")) == (FILE *)NULL) {
02204                 perror(name);
02205                 bu_log("plot_ray_face cannot open %s", name);
02206                 rt_bomb("aborting");
02207         }
02208 
02209         b = (long *)bu_calloc( fu->s_p->r_p->m_p->maxindex, sizeof(long), "bit vec");
02210 
02211         nmg_pl_fu(fd, fu, b, 200, 200, 200);
02212 
02213         bu_free((char *)b, "bit vec");
02214 
02215         VSCALE(pp, dir, 1000.0);
02216         VADD2(pp, pt, pp);
02217         pdv_3line( fd, pt, pp );
02218         (void)fclose(fd);
02219         bu_log("overlay %s\n", name);
02220 }
02221 
02222 /**
02223  *                      N M G _ P L O T _ L U _ A R O U N D _ E U
02224  *
02225  *  Draw and label all the loopuses gathered around this edgeuse.
02226  *
02227  *  Called by nmg_radial_join_eu().
02228  */
02229 void
02230 nmg_plot_lu_around_eu(const char *prefix, const struct edgeuse *eu, const struct bn_tol *tol)
02231 {
02232         char                    file[256];
02233         static int              num=0;
02234         struct model            *m;
02235         struct bn_vlblock       *vbp;
02236         long                    *tab;
02237         const struct edgeuse    *eur;
02238         FILE                    *fp;
02239 
02240         NMG_CK_EDGEUSE(eu);
02241         BN_CK_TOL(tol);
02242 
02243         sprintf(file, "%s%0d.pl", prefix, num++);
02244         bu_log("overlay %s\n", file);
02245         if ((fp = fopen(file, "w")) == (FILE *)NULL) {
02246                 bu_log("plot_lu_around_eu() cannot open %s", file);
02247                 return;
02248         }
02249 
02250         m = nmg_find_model( (long *)eu );
02251         NMG_CK_MODEL(m);
02252         tab = (long *)bu_calloc( m->maxindex, sizeof(long), "bit vec");
02253 
02254         vbp = rt_vlblock_init();
02255 
02256         /* Draw all the left vectors, and a fancy edgeuse plot */
02257         nmg_vlblock_around_eu(vbp, eu, tab, 3, tol );
02258 
02259         eur = eu;
02260         do {
02261                 NMG_CK_EDGEUSE(eur);
02262 
02263                 if (*eur->up.magic_p == NMG_LOOPUSE_MAGIC )  {
02264                         /* Draw this loop in non-fancy format, for context */
02265                         nmg_vlblock_lu(vbp, eur->up.lu_p, tab, 80, 100, 170, 0, 0 );
02266                 }
02267                 eur = eur->radial_p->eumate_p;
02268         } while (eur != eu);
02269 
02270         rt_plot_vlblock( fp, vbp );
02271         (void)fclose(fp);
02272         rt_vlblock_free(vbp);
02273         bu_free((char *)tab, "bit vec");
02274 }
02275 
02276 /**
02277  *                      N M G _ S N U R B _ T O _ V L I S T
02278  *
02279  *  A routine to draw the entire surface of a face_g_snurb.
02280  *  No handling of trimming curves is done.
02281  */
02282 int
02283 nmg_snurb_to_vlist(struct bu_list *vhead, const struct face_g_snurb *fg, int n_interior)
02284 
02285 
02286                                                 /* typ. 10 */
02287 {
02288         register int            i;
02289         register int            j;
02290         register fastf_t        * vp;
02291         struct knot_vector      tkv1,
02292                                 tkv2,
02293                                 tau1,
02294                                 tau2;
02295         struct face_g_snurb     *r, *c;
02296         int             coords;
02297 
02298         BU_CK_LIST_HEAD( vhead );
02299         NMG_CK_FACE_G_SNURB(fg);
02300 
02301         rt_nurb_kvgen( &tkv1,
02302                 fg->u.knots[0],
02303                 fg->u.knots[fg->u.k_size-1], n_interior, (struct resource *)NULL);
02304 
02305         rt_nurb_kvgen( &tkv2,
02306                 fg->v.knots[0],
02307                 fg->v.knots[fg->v.k_size-1], n_interior, (struct resource *)NULL);
02308 
02309         rt_nurb_kvmerge(&tau1, &tkv1, &fg->u, (struct resource *)NULL);
02310         rt_nurb_kvmerge(&tau2, &tkv2, &fg->v, (struct resource *)NULL);
02311 
02312 /**     nmg_hack_snurb( &n, fg );       / XXX */
02313 
02314         r = rt_nurb_s_refine( fg, RT_NURB_SPLIT_COL, &tau2, (struct resource *)NULL);
02315         NMG_CK_SNURB(r);
02316         c = rt_nurb_s_refine( r, RT_NURB_SPLIT_ROW, &tau1, (struct resource *)NULL);
02317         NMG_CK_SNURB(c);
02318 
02319         coords = RT_NURB_EXTRACT_COORDS(c->pt_type);
02320 
02321         if( RT_NURB_IS_PT_RATIONAL(c->pt_type))
02322         {
02323                 vp = c->ctl_points;
02324                 for(i= 0;
02325                         i < c->s_size[0] * c->s_size[1];
02326                         i++)
02327                 {
02328                         FAST fastf_t    div;
02329                         vp[0] *= (div = 1/vp[3]);
02330                         vp[1] *= div;
02331                         vp[2] *= div;
02332                         vp[3] *= div;
02333                         vp += coords;
02334                 }
02335         }
02336 
02337         vp = c->ctl_points;
02338         for( i = 0; i < c->s_size[0]; i++)
02339         {
02340                 RT_ADD_VLIST( vhead, vp, BN_VLIST_LINE_MOVE );
02341                 vp += coords;
02342                 for( j = 1; j < c->s_size[1]; j++)
02343                 {
02344                         RT_ADD_VLIST( vhead, vp, BN_VLIST_LINE_DRAW );
02345                         vp += coords;
02346                 }
02347         }
02348 
02349         for( j = 0; j < c->s_size[1]; j++)
02350         {
02351                 int stride;
02352 
02353                 stride = c->s_size[1] * coords;
02354                 vp = &c->ctl_points[j * coords];
02355                 RT_ADD_VLIST( vhead, vp, BN_VLIST_LINE_MOVE );
02356                 vp += stride;
02357                 for( i = 1; i < c->s_size[0]; i++)
02358                 {
02359                         RT_ADD_VLIST( vhead, vp, BN_VLIST_LINE_DRAW );
02360                         vp += stride;
02361                 }
02362         }
02363         rt_nurb_free_snurb(c, (struct resource *)NULL);
02364         rt_nurb_free_snurb(r, (struct resource *)NULL);
02365 
02366         bu_free( (char *) tau1.knots, "rt_nurb_plot:tau1.knots");
02367         bu_free( (char *) tau2.knots, "rt_nurb_plot:tau2.knots");
02368         bu_free( (char *) tkv1.knots, "rt_nurb_plot:tkv1>knots");
02369         bu_free( (char *) tkv2.knots, "rt_nurb_plot:tkv2.knots");
02370 
02371         return(0);
02372 }
02373 
02374 /**
02375  *                      N M G _ C N U R B _ T O _ V L I S T
02376  *
02377  *  Draw interior points on a cnurb curve.
02378  *  The endpoints are not drawn, as those points are (should) match
02379  *  the vertices at the end of the edgeuse, and are handled by the caller.
02380  *
02381  *  Special processing is performed for the order <= 0 (linear) cnurbs.
02382  *
02383  *  If the curve is on a snurb face, it is in parameter space.
02384  *  If the curve is on a planar face, it is in XYZ space.
02385  */
02386 void
02387 nmg_cnurb_to_vlist(struct bu_list *vhead, const struct edgeuse *eu, int n_interior, int cmd)
02388 
02389 
02390                                                 /* typ. 10 */
02391                                                 /* BN_VLIST_LINE_DRAW, etc */
02392 {
02393         const struct edge_g_cnurb       *eg;
02394         const struct faceuse    *fu;
02395         register int            i;
02396         register fastf_t        *vp = (fastf_t  *)NULL;
02397         struct edge_g_cnurb     n;
02398         const struct edge_g_cnurb       *c;
02399         int                     coords;
02400 
02401         BU_CK_LIST_HEAD( vhead );
02402         NMG_CK_EDGEUSE(eu);
02403         eg = eu->g.cnurb_p;
02404         NMG_CK_EDGE_G_CNURB(eg);
02405 
02406         fu = nmg_find_fu_of_eu(eu);     /* may return NULL */
02407         NMG_CK_FACEUSE(fu);
02408         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02409                 bu_log("nmg_cnurb_to_vlist() eu=x%x, n=%d, order=%d\n",
02410                         eu, n_interior, eg->order);
02411         }
02412 
02413         if( eg->order <= 0 )  {
02414                 /* linear cnurb on planar face -- no intermediate points to draw */
02415                 if( *fu->f_p->g.magic_p == NMG_FACE_G_PLANE_MAGIC )
02416                         return;
02417 
02418                 /* linear cnurb on snurb face -- cnurb ctl pts are UV */
02419                 n.order = 2;
02420                 n.l.magic = RT_CNURB_MAGIC;
02421                 rt_nurb_gen_knot_vector( &n.k, n.order, 0.0, 1.0, (struct resource *)NULL );
02422                 n.c_size = 2;
02423                 n.pt_type = RT_NURB_MAKE_PT_TYPE(2, RT_NURB_PT_UV, RT_NURB_PT_NONRAT );
02424                 n.ctl_points = (fastf_t *)bu_malloc(
02425                         sizeof(fastf_t) * RT_NURB_EXTRACT_COORDS(n.pt_type) *
02426                         n.c_size, "nmg_cnurb_to_vlist() order0 ctl_points[]");
02427                 /* Set ctl points to parametric values */
02428                 NMG_CK_VERTEXUSE_A_CNURB(eu->vu_p->a.cnurb_p);
02429                 n.ctl_points[0] = eu->vu_p->a.cnurb_p->param[0];
02430                 n.ctl_points[1] = eu->vu_p->a.cnurb_p->param[1];
02431                 n.ctl_points[2] = eu->eumate_p->vu_p->a.cnurb_p->param[0];
02432                 n.ctl_points[3] = eu->eumate_p->vu_p->a.cnurb_p->param[1];
02433                 c = &n;
02434         } else {
02435                 /* Just use eg */
02436                 c = eg;
02437         }
02438 
02439         NMG_CK_CNURB( c );
02440 
02441         coords = RT_NURB_EXTRACT_COORDS( c->pt_type );
02442 
02443         if( *fu->f_p->g.magic_p == NMG_FACE_G_PLANE_MAGIC )  {
02444                 /* cnurb on planar face -- ctl points are XYZ */
02445 
02446                 vp = c->ctl_points;
02447                 /* Omit first and last points */
02448                 for( i = 1; i < c->c_size-1; i++)  {
02449                         RT_ADD_VLIST( vhead, vp, cmd );
02450                         vp += coords;
02451                 }
02452         } else {
02453                 const struct face_g_snurb       *s;
02454                 fastf_t         final[4];
02455                 fastf_t         inv_homo;
02456                 fastf_t         param_delta;
02457                 fastf_t         crv_param;
02458 
02459                 /* cnurb on spline face -- ctl points are UV or UVW */
02460                 if( coords != 2 && !RT_NURB_IS_PT_RATIONAL(c->pt_type) ) bu_log("nmg_cnurb_to_vlist() coords=%d\n", coords);
02461                 s = fu->f_p->g.snurb_p;
02462 
02463                 /* This section uses rt_nurb_c_eval(), but rt_nurb_c_refine is likely faster.
02464                  * XXXX Need a way to selectively and recursively refine curve to avoid
02465                  * feeding rt_nurb_s_eval() parameters outside domain of surface.
02466                  */
02467                 param_delta = (c->k.knots[c->k.k_size-1] - c->k.knots[0])/(fastf_t)(n_interior+1);
02468                 crv_param = c->k.knots[0];
02469                 for( i = 0; i < n_interior; i++)  {
02470                         point_t uvw;
02471 
02472                         /* evaluate curve at parameter values */
02473                         crv_param += param_delta;
02474 
02475                         VSETALL(uvw,0);
02476 
02477                         rt_nurb_c_eval( c, crv_param, uvw );
02478 
02479                         if( RT_NURB_IS_PT_RATIONAL( c->pt_type ) )
02480                         {
02481                                 uvw[0] = uvw[0]/uvw[2];
02482                                 uvw[1] = uvw[1]/uvw[2];
02483                         }
02484 
02485                         /* convert 'uvw' from UV coord to XYZ coord via surf! */
02486                         rt_nurb_s_eval( s, uvw[0], uvw[1], final );
02487 
02488                         if( RT_NURB_IS_PT_RATIONAL( s->pt_type ) )
02489                         {
02490                                 /* divide out homogeneous coordinate */
02491                                 inv_homo = 1.0/final[3];
02492                                 VSCALE( final, final, inv_homo );
02493                         }
02494 
02495                         RT_ADD_VLIST( vhead, final, cmd );
02496                         vp += coords;
02497                 }
02498         }
02499 
02500         if( eg->order <= 0 )  {
02501                 bu_free( (char *)n.k.knots, "nmg_cnurb_to_vlist() n.knot.knots");
02502                 bu_free( (char *)n.ctl_points, "nmg_cnurb_to_vlist() ctl_points");
02503         }
02504 }
02505 
02506 /*
02507  * Local Variables:
02508  * mode: C
02509  * tab-width: 8
02510  * c-basic-offset: 4
02511  * indent-tabs-mode: t
02512  * End:
02513  * ex: shiftwidth=4 tabstop=8
02514  */

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