g_bot.c

Go to the documentation of this file.
00001 /*                         G _ B O T . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1999-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 g_  */
00023 
00024 /*@{*/
00025 /** @file g_bot.c
00026  *      Intersect a ray with a bag o' triangles.
00027  *
00028  *  Authors -
00029  *      John R. Anderson
00030  *  Source -
00031  *      The U. S. Army Research Laboratory
00032  *      Aberdeen Proving Ground, Maryland  21005-5066
00033  *
00034  */
00035 
00036 #ifndef lint
00037 static const char RCSbot[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_bot.c,v 14.16 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00038 #endif
00039 
00040 #include "common.h"
00041 
00042 #include <stdlib.h>
00043 #include <stdio.h>
00044 #ifdef HAVE_STRING_H
00045 #  include <string.h>
00046 #else
00047 #  include <strings.h>
00048 #endif
00049 #include <math.h>
00050 #include <ctype.h>
00051 
00052 #include "tcl.h"
00053 #include "machine.h"
00054 #include "vmath.h"
00055 #include "db.h"
00056 #include "nmg.h"
00057 #include "rtgeom.h"
00058 #include "raytrace.h"
00059 #include "./debug.h"
00060 #include "./plane.h"
00061 #include "./bot.h"
00062 
00063 #define GLUE(_a, _b)      _a ## _b
00064 #define XGLUE(_a,_b)      GLUE(_a,_b)
00065 
00066 /* Set to 32 to enable pieces by default */
00067 int rt_bot_minpieces = RT_DEFAULT_MINPIECES;
00068 int rt_bot_tri_per_piece = RT_DEFAULT_TRIS_PER_PIECE;
00069 
00070 #define MAXHITS 128
00071 
00072 #define BOT_MIN_DN      1.0e-9
00073 
00074 #define RT_BOT_UNORIENTED_NORM( _hitp, _in_or_out)      { \
00075         if( _in_or_out < 0 ) {  /* this is an exit */ \
00076                 if( (_hitp)->hit_vpriv[X] < 0.0 ) { \
00077                         VREVERSE( (_hitp)->hit_normal, trip->tri_N ); \
00078                 } else { \
00079                         VMOVE( (_hitp)->hit_normal, trip->tri_N ); \
00080                 } \
00081         } else {        /* this is an entrance */ \
00082                 if( (_hitp)->hit_vpriv[X] > 0.0 ) { \
00083                         VREVERSE( (_hitp)->hit_normal, trip->tri_N ); \
00084                 } else { \
00085                         VMOVE( (_hitp)->hit_normal, trip->tri_N ); \
00086                 } \
00087         } \
00088 }
00089 
00090 /* forward declarations needed for the included routines below */
00091 HIDDEN int
00092 rt_bot_makesegs(
00093                 struct hit              *hits,
00094                 int                     nhits,
00095                 struct soltab           *stp,
00096                 struct xray             *rp,
00097                 struct application      *ap,
00098                 struct seg              *seghead,
00099                 struct rt_piecestate    *psp);
00100 
00101 static int
00102 rt_bot_unoriented_segs(struct hit               *hits,
00103                   int                   nhits,
00104                   struct soltab         *stp,
00105                   struct xray           *rp,
00106                   struct application    *ap,
00107                   struct seg            *seghead,
00108                   struct bot_specific   *bot);
00109 
00110 int
00111 rt_botface_w_normals(struct soltab      *stp,
00112                      struct bot_specific        *bot,
00113                      fastf_t            *ap,
00114                      fastf_t            *bp,
00115                      fastf_t            *cp,
00116                      fastf_t            *vertex_normals, /* array of nine values (three unit normals vectors) */
00117                      int                        face_no,
00118                      const struct bn_tol        *tol);
00119 
00120 
00121 #define TRI_TYPE        float
00122 #define NORM_TYPE       signed char
00123 #define NORMAL_SCALE    127.0
00124 #define ONE_OVER_SCALE  (1.0/127.0)
00125 #include "./g_bot_include.c"
00126 #undef TRI_TYPE
00127 #undef NORM_TYPE
00128 #undef NORMAL_SCALE
00129 #undef ONE_OVER_SCALE
00130 #define TRI_TYPE        double
00131 #define NORM_TYPE       fastf_t
00132 #define NORMAL_SCALE    1.0
00133 #define ONE_OVER_SCALE  1.0
00134 #include "./g_bot_include.c"
00135 #undef TRI_TYPE
00136 #undef NORM_TYPE
00137 #undef NORMAL_SCALE
00138 #undef ONE_OVER_SCALE
00139 
00140 
00141 /**
00142  *                      R T _ B O T F A C E
00143  *
00144  *  This function is called with pointers to 3 points,
00145  *  and is used to prepare BOT faces.
00146  *  ap, bp, cp point to vect_t points.
00147  *
00148  * Return -
00149  *      0       if the 3 points didn't form a plane (eg, colinear, etc).
00150  *      # pts   (3) if a valid plane resulted.
00151  */
00152 int
00153 rt_botface_w_normals(struct soltab      *stp,
00154            struct bot_specific  *bot,
00155            fastf_t              *ap,
00156            fastf_t              *bp,
00157            fastf_t              *cp,
00158            fastf_t              *vertex_normals, /* array of nine values (three unit normals vectors) */
00159            int                  face_no,
00160            const struct bn_tol  *tol)
00161 {
00162 
00163         if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
00164                 return rt_botface_w_normals_float( stp, bot, ap, bp, cp,
00165                                                    vertex_normals, face_no, tol );
00166         } else {
00167                 return rt_botface_w_normals_double( stp, bot, ap, bp, cp,
00168                                                    vertex_normals, face_no, tol );
00169         }
00170 }
00171 
00172 int
00173 rt_botface(struct soltab        *stp,
00174            struct bot_specific  *bot,
00175            fastf_t              *ap,
00176            fastf_t              *bp,
00177            fastf_t              *cp,
00178            int                  face_no,
00179            const struct bn_tol  *tol)
00180 {
00181         return( rt_botface_w_normals( stp, bot, ap, bp, cp, NULL, face_no, tol ) );
00182 }
00183 
00184 /*
00185  *      Do the prep to support pieces for a BOT/ARS
00186  *
00187  */
00188 void
00189 rt_bot_prep_pieces(struct bot_specific  *bot,
00190                    struct soltab        *stp,
00191                    int                  ntri,
00192                    const struct bn_tol          *tol)
00193 {
00194         if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
00195                 rt_bot_prep_pieces_float( bot, stp, ntri, tol );
00196         } else {
00197                 rt_bot_prep_pieces_double( bot, stp, ntri, tol );
00198         }
00199 }
00200 
00201 /**
00202  *                      R T _ B O T _ P R E P
00203  *
00204  *  Given a pointer to a GED database record, and a transformation matrix,
00205  *  determine if this is a valid BOT, and if so, precompute various
00206  *  terms of the formula.
00207  *
00208  *  Returns -
00209  *      0       BOT is OK
00210  *      !0      Error in description
00211  *
00212  *  Implicit return -
00213  *      A struct bot_specific is created, and it's address is stored in
00214  *      stp->st_specific for use by bot_shot().
00215  */
00216 int
00217 rt_bot_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00218 {
00219         struct rt_bot_internal          *bot_ip;
00220 
00221 
00222         RT_CK_DB_INTERNAL(ip);
00223         bot_ip = (struct rt_bot_internal *)ip->idb_ptr;
00224         RT_BOT_CK_MAGIC(bot_ip);
00225 
00226         if( bot_ip->bot_flags & RT_BOT_USE_FLOATS ) {
00227                 return (rt_bot_prep_float( stp, bot_ip, rtip ));
00228         } else {
00229                 return( rt_bot_prep_double( stp, bot_ip, rtip ));
00230         }
00231 }
00232 
00233 /**
00234  *                      R T _ B O T _ P R I N T
00235  */
00236 void
00237 rt_bot_print(register const struct soltab *stp)
00238 {
00239 }
00240 
00241 static int
00242 rt_bot_plate_segs(struct hit            *hits,
00243                   int                   nhits,
00244                   struct soltab         *stp,
00245                   struct xray           *rp,
00246                   struct application    *ap,
00247                   struct seg            *seghead,
00248                   struct bot_specific   *bot)
00249 {
00250         if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
00251                 return (rt_bot_plate_segs_float( hits, nhits, stp, rp, ap, seghead, bot ));
00252         } else {
00253                 return (rt_bot_plate_segs_double( hits, nhits, stp, rp, ap, seghead, bot ));
00254         }
00255 }
00256 
00257 static int
00258 rt_bot_unoriented_segs(struct hit               *hits,
00259                   int                   nhits,
00260                   struct soltab         *stp,
00261                   struct xray           *rp,
00262                   struct application    *ap,
00263                   struct seg            *seghead,
00264                   struct bot_specific   *bot)
00265 {
00266         if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
00267                 return (rt_bot_unoriented_segs_float( hits, nhits, stp, rp, ap, seghead, bot ));
00268         } else {
00269                 return (rt_bot_unoriented_segs_double( hits, nhits, stp, rp, ap, seghead, bot ));
00270         }
00271 }
00272 
00273 
00274 
00275 /**
00276  *                      R T _ B O T _ M A K E S E G S
00277  *
00278  *  Given an array of hits, make segments out of them.
00279  *  Exactly how this is to be done depends on the mode of the BoT.
00280  */
00281 HIDDEN int
00282 rt_bot_makesegs(struct hit *hits, int nhits, struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead, struct rt_piecestate *psp)
00283 {
00284     struct bot_specific *bot = (struct bot_specific *)stp->st_specific;
00285 
00286     if(bot->bot_mode == RT_BOT_PLATE ||
00287        bot->bot_mode == RT_BOT_PLATE_NOCOS) {
00288         return rt_bot_plate_segs(hits, nhits, stp, rp, ap, seghead, bot);
00289     }
00290 
00291     if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
00292             return( rt_bot_makesegs_float( hits, nhits, stp, rp, ap, seghead, psp ) );
00293     } else {
00294             return( rt_bot_makesegs_double( hits, nhits, stp, rp, ap, seghead, psp ) );
00295     }
00296 }
00297 
00298 /**
00299  *                      R T _ B O T _ S H O T
00300  *
00301  *  Intersect a ray with a bot.
00302  *  If an intersection occurs, a struct seg will be acquired
00303  *  and filled in.
00304  *
00305  *      Notes for rt_bot_norm():
00306  *              hit_private contains pointer to the tri_specific structure
00307  *              hit_vpriv[X] contains dot product of ray direction and unit normal from tri_specific
00308  *
00309  *  Returns -
00310  *      0       MISS
00311  *      >0      HIT
00312  */
00313 int
00314 rt_bot_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00315 {
00316         struct bot_specific *bot = (struct bot_specific *)stp->st_specific;
00317 
00318         if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
00319                 return( rt_bot_shot_float( stp, rp, ap, seghead ) );
00320         } else {
00321                 return( rt_bot_shot_double( stp, rp, ap, seghead ) );
00322         }
00323 }
00324 
00325 /**
00326  *                      R T _ B O T _ P I E C E _ S H O T
00327  *
00328  *  Intersect a ray with a list of "pieces" of a BoT.
00329  *
00330  *  This routine may be invoked many times for a single ray,
00331  *  as the ray traverses from one space partitioning cell to the next.
00332  *
00333  *  Plate-mode (2 hit) segments will be returned immediately in seghead.
00334  *
00335  *  Generally the hits are stashed between invocations in psp.
00336  */
00337 int
00338 rt_bot_piece_shot(struct rt_piecestate *psp, struct rt_piecelist *plp, double dist_corr, register struct xray *rp, struct application *ap, struct seg *seghead)
00339 {
00340         struct soltab   *stp;
00341         struct bot_specific *bot;
00342 
00343         RT_CK_PIECELIST(plp);
00344         stp = plp->stp;
00345         RT_CK_SOLTAB(stp);
00346         bot = (struct bot_specific *)stp->st_specific;
00347 
00348         if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
00349                 return( rt_bot_piece_shot_float( psp, plp, dist_corr, rp, ap, seghead ) );
00350         } else {
00351                 return( rt_bot_piece_shot_double( psp, plp, dist_corr, rp, ap, seghead ) );
00352         }
00353 }
00354 
00355 /**
00356  *                      R T _ B O T _ P I E C E _ H I T S E G S
00357  */
00358 void
00359 rt_bot_piece_hitsegs(struct rt_piecestate *psp, struct seg *seghead, struct application *ap)
00360 {
00361         RT_CK_PIECESTATE(psp);
00362         RT_CK_AP(ap);
00363         RT_CK_HTBL(&psp->htab);
00364 
00365         /* Sort hits, Near to Far */
00366         rt_hitsort( psp->htab.hits, psp->htab.end );
00367 
00368         /* build segments */
00369         (void)rt_bot_makesegs( psp->htab.hits, psp->htab.end, psp->stp, &ap->a_ray, ap, seghead, psp );
00370 }
00371 
00372 #define RT_BOT_SEG_MISS(SEG)    (SEG).seg_stp=RT_SOLTAB_NULL
00373 
00374 /**
00375  *                      R T _ B O T _ V S H O T
00376  *
00377  *  Vectorized version.
00378  */
00379 void
00380 rt_bot_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
00381                                /* An array of solid pointers */
00382                                /* An array of ray pointers */
00383                                /* array of segs (results returned) */
00384                                /* Number of ray/object pairs */
00385 
00386 {
00387         rt_vstub( stp, rp, segp, n, ap );
00388 }
00389 
00390 /**
00391  *                      R T _ B O T _ N O R M
00392  *
00393  *  Given ONE ray distance, return the normal and entry/exit point.
00394  */
00395 void
00396 rt_bot_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00397 {
00398         struct bot_specific *bot=(struct bot_specific *)stp->st_specific;
00399 
00400         if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
00401                 rt_bot_norm_float( bot, hitp, stp, rp );
00402         } else {
00403                 rt_bot_norm_double( bot, hitp, stp, rp );
00404         }
00405 }
00406 
00407 /**
00408  *                      R T _ B O T _ C U R V E
00409  *
00410  *  Return the curvature of the bot.
00411  */
00412 void
00413 rt_bot_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00414 {
00415         cvp->crv_c1 = cvp->crv_c2 = 0;
00416 
00417         /* any tangent direction */
00418         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00419         cvp->crv_c1 = cvp->crv_c2 = 0;
00420 }
00421 
00422 /**
00423  *                      R T _ B O T _ U V
00424  *
00425  *  For a hit on the surface of an bot, return the (u,v) coordinates
00426  *  of the hit point, 0 <= u,v <= 1.
00427  *  u = azimuth
00428  *  v = elevation
00429  */
00430 void
00431 rt_bot_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00432 {
00433 }
00434 
00435 /**
00436  *              R T _ B O T _ F R E E
00437  */
00438 void
00439 rt_bot_free(register struct soltab *stp)
00440 {
00441         register struct bot_specific *bot =
00442                 (struct bot_specific *)stp->st_specific;
00443 
00444         if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
00445                 rt_bot_free_float( bot );
00446         } else {
00447                 rt_bot_free_double( bot );
00448         }
00449 }
00450 
00451 /**
00452  *                      R T _ B O T _ C L A S S
00453  */
00454 int
00455 rt_bot_class(const struct soltab *stp, const fastf_t *min, const fastf_t *max, const struct bn_tol *tol)
00456 {
00457         return RT_CLASSIFY_UNIMPLEMENTED;
00458 }
00459 
00460 /**
00461  *                      R T _ B O T _ P L O T
00462  */
00463 int
00464 rt_bot_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00465 {
00466         LOCAL struct rt_bot_internal    *bot_ip;
00467         int i;
00468 
00469         RT_CK_DB_INTERNAL(ip);
00470         bot_ip = (struct rt_bot_internal *)ip->idb_ptr;
00471         RT_BOT_CK_MAGIC(bot_ip);
00472 
00473         for( i=0 ; i<bot_ip->num_faces ; i++ )
00474         {
00475                 RT_ADD_VLIST( vhead, &bot_ip->vertices[bot_ip->faces[i*3]*3], BN_VLIST_LINE_MOVE );
00476                 RT_ADD_VLIST( vhead, &bot_ip->vertices[bot_ip->faces[i*3+1]*3], BN_VLIST_LINE_DRAW );
00477                 RT_ADD_VLIST( vhead, &bot_ip->vertices[bot_ip->faces[i*3+2]*3], BN_VLIST_LINE_DRAW );
00478                 RT_ADD_VLIST( vhead, &bot_ip->vertices[bot_ip->faces[i*3]*3], BN_VLIST_LINE_DRAW );
00479         }
00480 
00481         return(0);
00482 }
00483 
00484 /**
00485  *                      R T _ B O T _ P L O T _ P O L Y
00486  */
00487 int
00488 rt_bot_plot_poly(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00489 {
00490         LOCAL struct rt_bot_internal    *bot_ip;
00491         int i;
00492 
00493         RT_CK_DB_INTERNAL(ip);
00494         bot_ip = (struct rt_bot_internal *)ip->idb_ptr;
00495         RT_BOT_CK_MAGIC(bot_ip);
00496 
00497         /* XXX Should consider orientation here, flip if necessary. */
00498         for( i=0 ; i<bot_ip->num_faces ; i++ )
00499         {
00500                 point_t aa, bb, cc;
00501                 vect_t  ab, ac;
00502                 vect_t norm;
00503 
00504                 VMOVE( aa, &bot_ip->vertices[bot_ip->faces[i*3+0]*3] );
00505                 VMOVE( bb, &bot_ip->vertices[bot_ip->faces[i*3+1]*3] );
00506                 VMOVE( cc, &bot_ip->vertices[bot_ip->faces[i*3+2]*3] );
00507 
00508                 VSUB2( ab, aa, bb );
00509                 VSUB2( ac, aa, cc );
00510                 VCROSS( norm, ab, ac );
00511                 VUNITIZE(norm);
00512                 RT_ADD_VLIST(vhead, norm, BN_VLIST_POLY_START);
00513 
00514                 if( (bot_ip->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) &&
00515                     (bot_ip->bot_flags & RT_BOT_USE_NORMALS) ) {
00516                         vect_t na, nb, nc;
00517 
00518                         VMOVE( na, &bot_ip->normals[bot_ip->face_normals[i*3+0]*3] );
00519                         VMOVE( nb, &bot_ip->normals[bot_ip->face_normals[i*3+1]*3] );
00520                         VMOVE( nc, &bot_ip->normals[bot_ip->face_normals[i*3+2]*3] );
00521                         RT_ADD_VLIST( vhead, na, BN_VLIST_POLY_VERTNORM );
00522                         RT_ADD_VLIST( vhead, aa, BN_VLIST_POLY_MOVE );
00523                         RT_ADD_VLIST( vhead, nb, BN_VLIST_POLY_VERTNORM );
00524                         RT_ADD_VLIST( vhead, bb, BN_VLIST_POLY_DRAW );
00525                         RT_ADD_VLIST( vhead, nc, BN_VLIST_POLY_VERTNORM );
00526                         RT_ADD_VLIST( vhead, cc, BN_VLIST_POLY_DRAW );
00527                         RT_ADD_VLIST( vhead, aa, BN_VLIST_POLY_END );
00528                 } else {
00529                         RT_ADD_VLIST( vhead, aa, BN_VLIST_POLY_MOVE );
00530                         RT_ADD_VLIST( vhead, bb, BN_VLIST_POLY_DRAW );
00531                         RT_ADD_VLIST( vhead, cc, BN_VLIST_POLY_DRAW );
00532                         RT_ADD_VLIST( vhead, aa, BN_VLIST_POLY_END );
00533                 }
00534         }
00535 
00536         return(0);
00537 }
00538 
00539 /**
00540  *                      R T _ B O T _ T E S S
00541  *
00542  *  Returns -
00543  *      -1      failure
00544  *       0      OK.  *r points to nmgregion that holds this tessellation.
00545  */
00546 int
00547 rt_bot_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00548 {
00549         LOCAL struct rt_bot_internal    *bot_ip;
00550         struct shell *s;
00551         struct vertex **verts;
00552         point_t pt[3];
00553         int i;
00554 
00555         RT_CK_DB_INTERNAL(ip);
00556         bot_ip = (struct rt_bot_internal *)ip->idb_ptr;
00557         RT_BOT_CK_MAGIC(bot_ip);
00558 #if 0
00559         if( bot_ip->mode == RT_BOT_PLATE || bot_ip->mode == RT_BOT_PLATE_NOCOS )        /* tesselation not supported */
00560                 return( -1 );
00561 #endif
00562         *r = nmg_mrsv( m );     /* Make region, empty shell, vertex */
00563         s = BU_LIST_FIRST(shell, &(*r)->s_hd);
00564 
00565         verts = (struct vertex **)bu_calloc( bot_ip->num_vertices, sizeof( struct vertex *),
00566                 "rt_bot_tess: *verts[]" );
00567 
00568         for( i=0 ; i<bot_ip->num_faces ; i++ )
00569         {
00570                 struct faceuse *fu;
00571                 struct vertex **corners[3];
00572 
00573                 if( bot_ip->orientation == RT_BOT_CW )
00574                 {
00575                         VMOVE( pt[2], &bot_ip->vertices[bot_ip->faces[i*3]*3] );
00576                         VMOVE( pt[1], &bot_ip->vertices[bot_ip->faces[i*3+1]*3] );
00577                         VMOVE( pt[0], &bot_ip->vertices[bot_ip->faces[i*3+2]*3] );
00578                         corners[2] = &verts[bot_ip->faces[i*3]];
00579                         corners[1] = &verts[bot_ip->faces[i*3+1]];
00580                         corners[0] = &verts[bot_ip->faces[i*3+2]];
00581                 }
00582                 else
00583                 {
00584                         VMOVE( pt[0], &bot_ip->vertices[bot_ip->faces[i*3]*3] );
00585                         VMOVE( pt[1], &bot_ip->vertices[bot_ip->faces[i*3+1]*3] );
00586                         VMOVE( pt[2], &bot_ip->vertices[bot_ip->faces[i*3+2]*3] );
00587                         corners[0] = &verts[bot_ip->faces[i*3]];
00588                         corners[1] = &verts[bot_ip->faces[i*3+1]];
00589                         corners[2] = &verts[bot_ip->faces[i*3+2]];
00590                 }
00591 
00592                 if( !bn_3pts_distinct( pt[0], pt[1], pt[2], tol )
00593                            || bn_3pts_collinear( pt[0], pt[1], pt[2], tol ) )
00594                                 continue;
00595 
00596                 if( (fu=nmg_cmface( s, corners, 3 )) == (struct faceuse *)NULL )
00597                 {
00598                         bu_log( "rt_bot_tess() nmg_cmface() failed for face #%d\n", i );
00599                         continue;
00600                 }
00601 
00602                 if( !(*corners[0])->vg_p )
00603                         nmg_vertex_gv( *(corners[0]), pt[0] );
00604                 if( !(*corners[1])->vg_p )
00605                         nmg_vertex_gv( *(corners[1]), pt[1] );
00606                 if( !(*corners[2])->vg_p )
00607                         nmg_vertex_gv( *(corners[2]), pt[2] );
00608 
00609                 if( nmg_calc_face_g( fu ) )
00610                         nmg_kfu( fu );
00611                 else if( bot_ip->mode == RT_BOT_SURFACE )
00612                 {
00613                         struct vertex **tmp;
00614 
00615                         tmp = corners[0];
00616                         corners[0] = corners[2];
00617                         corners[2] = tmp;
00618                         if( (fu=nmg_cmface( s, corners, 3 )) == (struct faceuse *)NULL )
00619                                 bu_log( "rt_bot_tess() nmg_cmface() failed for face #%d\n", i );
00620                         else
00621                                  nmg_calc_face_g( fu );
00622                 }
00623         }
00624 
00625         bu_free( (char *)verts, "rt_bot_tess *verts[]" );
00626 
00627         nmg_mark_edges_real( &s->l.magic );
00628 
00629         nmg_region_a( *r, tol );
00630 
00631         if( bot_ip->mode == RT_BOT_SOLID && bot_ip->orientation == RT_BOT_UNORIENTED )
00632                 nmg_fix_normals( s, tol );
00633 
00634         return( 0 );
00635 }
00636 
00637 /**
00638  *                      R T _ B O T _ I M P O R T
00639  *
00640  *  Import an BOT from the database format to the internal format.
00641  *  Apply modeling transformations as well.
00642  */
00643 int
00644 rt_bot_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
00645 {
00646         LOCAL struct rt_bot_internal    *bot_ip;
00647         union record                    *rp;
00648         int                             i;
00649         int                             chars_used;
00650 
00651         BU_CK_EXTERNAL( ep );
00652         rp = (union record *)ep->ext_buf;
00653         /* Check record type */
00654         if( rp->u_id != DBID_BOT )  {
00655                 bu_log("rt_bot_import: defective record\n");
00656                 return(-1);
00657         }
00658 
00659         RT_CK_DB_INTERNAL( ip );
00660         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00661         ip->idb_type = ID_BOT;
00662         ip->idb_meth = &rt_functab[ID_BOT];
00663         ip->idb_ptr = bu_malloc( sizeof(struct rt_bot_internal), "rt_bot_internal");
00664         bot_ip = (struct rt_bot_internal *)ip->idb_ptr;
00665         bot_ip->magic = RT_BOT_INTERNAL_MAGIC;
00666 
00667         bot_ip->num_vertices = bu_glong( rp->bot.bot_num_verts );
00668         bot_ip->num_faces = bu_glong( rp->bot.bot_num_triangles );
00669         bot_ip->orientation = rp->bot.bot_orientation;
00670         bot_ip->mode = rp->bot.bot_mode;
00671         bot_ip->bot_flags = 0;
00672 
00673         bot_ip->vertices = (fastf_t *)bu_calloc( bot_ip->num_vertices * 3, sizeof( fastf_t ), "Bot vertices" );
00674         bot_ip->faces = (int *)bu_calloc( bot_ip->num_faces * 3, sizeof( int ), "Bot faces" );
00675 
00676         for( i=0 ; i<bot_ip->num_vertices ; i++ )
00677         {
00678                 point_t tmp;
00679 
00680                 ntohd( (unsigned char *)tmp, (const unsigned char *)(&rp->bot.bot_data[i*24]), 3 );
00681                 MAT4X3PNT( &(bot_ip->vertices[i*3]), mat, tmp );
00682         }
00683 
00684         chars_used = bot_ip->num_vertices * 3 * 8;
00685 
00686         for( i=0 ; i<bot_ip->num_faces ; i++ )
00687         {
00688                 int index=chars_used + i * 12;
00689 
00690                 bot_ip->faces[i*3] = bu_glong( (const unsigned char *)&rp->bot.bot_data[index] );
00691                 bot_ip->faces[i*3 + 1] = bu_glong( (const unsigned char *)&rp->bot.bot_data[index + 4] );
00692                 bot_ip->faces[i*3 + 2] = bu_glong( (const unsigned char *)&rp->bot.bot_data[index + 8] );
00693         }
00694 
00695         if( bot_ip->mode == RT_BOT_PLATE || bot_ip->mode == RT_BOT_PLATE_NOCOS )
00696         {
00697                 chars_used = bot_ip->num_vertices * 3 * 8 + bot_ip->num_faces * 12;
00698 
00699                 bot_ip->thickness = (fastf_t *)bu_calloc( bot_ip->num_faces, sizeof( fastf_t ), "BOT thickness" );
00700                 for( i=0 ; i<bot_ip->num_faces ; i++ )
00701                         ntohd( (unsigned char *)&(bot_ip->thickness[i]),
00702                                 (const unsigned char *)(&rp->bot.bot_data[chars_used + i*8]), 1 );
00703                 bot_ip->face_mode = bu_hex_to_bitv( (const char *)(&rp->bot.bot_data[chars_used + bot_ip->num_faces * 8]) );
00704         }
00705         else
00706         {
00707                 bot_ip->thickness = (fastf_t *)NULL;
00708                 bot_ip->face_mode = (struct bu_bitv *)NULL;
00709         }
00710 
00711         return(0);                      /* OK */
00712 }
00713 
00714 /**
00715  *                      R T _ B O T _ E X P O R T
00716  *
00717  *  The name is added by the caller, in the usual place.
00718  */
00719 int
00720 rt_bot_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00721 {
00722         struct rt_bot_internal  *bot_ip;
00723         union record            *rec;
00724         int                     i;
00725         int                     chars_used;
00726         int                     num_recs;
00727         struct bu_vls           face_mode;
00728 
00729 
00730         RT_CK_DB_INTERNAL(ip);
00731         if( ip->idb_type != ID_BOT )  return(-1);
00732         bot_ip = (struct rt_bot_internal *)ip->idb_ptr;
00733         RT_BOT_CK_MAGIC(bot_ip);
00734 
00735         if( bot_ip->num_normals > 0 ) {
00736                 bu_log( "BOT surface normals not supported in older database formats, normals not saved\n" );
00737                 bu_log( "\tPlease update to current database format using \"dbupgrade\"\n" );
00738         }
00739 
00740         BU_CK_EXTERNAL(ep);
00741         ep->ext_nbytes = sizeof( struct bot_rec ) - 1 +
00742                 bot_ip->num_vertices * 3 * 8 + bot_ip->num_faces * 3 * 4;
00743         if( bot_ip->mode == RT_BOT_PLATE || bot_ip->mode == RT_BOT_PLATE_NOCOS )
00744         {
00745           if( !bot_ip->face_mode )
00746             {
00747               bot_ip->face_mode = bu_bitv_new( bot_ip->num_faces );
00748               bu_bitv_clear( bot_ip->face_mode );
00749             }
00750           if( !bot_ip->thickness )
00751               bot_ip->thickness = (fastf_t *)bu_calloc( bot_ip->num_faces, sizeof( fastf_t ), "BOT thickness" );
00752           bu_vls_init( &face_mode );
00753           bu_bitv_to_hex( &face_mode, bot_ip->face_mode );
00754           ep->ext_nbytes += bot_ip->num_faces * 8 + bu_vls_strlen( &face_mode ) + 1;
00755         }
00756 
00757         /* round up to the nearest granule */
00758         if( ep->ext_nbytes % (sizeof( union record ) ) )
00759         {
00760                 ep->ext_nbytes += (sizeof( union record ) )
00761                         - ep->ext_nbytes % (sizeof( union record ) );
00762         }
00763         num_recs = ep->ext_nbytes / sizeof( union record ) - 1;
00764         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "bot external");
00765         rec = (union record *)ep->ext_buf;
00766 
00767         rec->bot.bot_id = DBID_BOT;
00768 
00769         bu_plong( (unsigned char *)rec->bot.bot_nrec, num_recs );
00770         rec->bot.bot_orientation = bot_ip->orientation;
00771         rec->bot.bot_mode = bot_ip->mode;
00772         rec->bot.bot_err_mode = 0;
00773         bu_plong( (unsigned char *)rec->bot.bot_num_verts, bot_ip->num_vertices );
00774         bu_plong( (unsigned char *)rec->bot.bot_num_triangles, bot_ip->num_faces );
00775 
00776         /* Since libwdb users may want to operate in units other
00777          * than mm, we offer the opportunity to scale the solid
00778          * (to get it into mm) on the way out.
00779          */
00780 
00781 
00782         /* convert from local editing units to mm and export
00783          * to database record format
00784          */
00785         for( i=0 ; i<bot_ip->num_vertices ; i++ )
00786         {
00787                 point_t tmp;
00788 
00789                 VSCALE( tmp, &bot_ip->vertices[i*3], local2mm );
00790                 htond( (unsigned char *)&rec->bot.bot_data[i*24], (const unsigned char *)tmp, 3 );
00791         }
00792 
00793         chars_used = bot_ip->num_vertices * 24;
00794 
00795         for( i=0 ; i<bot_ip->num_faces ; i++ )
00796         {
00797                 int index=chars_used + i * 12;
00798 
00799                 bu_plong( (unsigned char *)(&rec->bot.bot_data[index]), bot_ip->faces[i*3] );
00800                 bu_plong( (unsigned char *)(&rec->bot.bot_data[index + 4]), bot_ip->faces[i*3+1] );
00801                 bu_plong( (unsigned char *)(&rec->bot.bot_data[index + 8]), bot_ip->faces[i*3+2] );
00802         }
00803 
00804         chars_used += bot_ip->num_faces * 12;
00805 
00806         if( bot_ip->mode == RT_BOT_PLATE || bot_ip->mode == RT_BOT_PLATE_NOCOS )
00807         {
00808                 for( i=0 ; i<bot_ip->num_faces ; i++ )
00809                 {
00810                         fastf_t tmp;
00811                         tmp = bot_ip->thickness[i] * local2mm;
00812                         htond( (unsigned char *)&rec->bot.bot_data[chars_used], (const unsigned char *)&tmp, 1 );
00813                         chars_used += 8;
00814                 }
00815                 strcpy( (char *)&rec->bot.bot_data[chars_used], bu_vls_addr( &face_mode ) );
00816                 bu_vls_free( &face_mode );
00817         }
00818 
00819         return(0);
00820 }
00821 
00822 /**
00823  *                      R T _ B O T _ I M P O R T 5
00824  */
00825 int
00826 rt_bot_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
00827 {
00828         struct rt_bot_internal          *bip;
00829         register unsigned char          *cp;
00830         int                             i;
00831 
00832         BU_CK_EXTERNAL( ep );
00833 
00834         RT_CK_DB_INTERNAL( ip );
00835         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00836         ip->idb_type = ID_BOT;
00837         ip->idb_meth = &rt_functab[ID_BOT];
00838         ip->idb_ptr = bu_calloc( 1, sizeof(struct rt_bot_internal), "rt_bot_internal");
00839 
00840         bip = (struct rt_bot_internal *)ip->idb_ptr;
00841         bip->magic = RT_BOT_INTERNAL_MAGIC;
00842 
00843         cp = ep->ext_buf;
00844         bip->num_vertices = bu_glong( cp );
00845         cp += SIZEOF_NETWORK_LONG;
00846         bip->num_faces = bu_glong( cp );
00847         cp += SIZEOF_NETWORK_LONG;
00848         bip->orientation = *cp++;
00849         bip->mode = *cp++;
00850         bip->bot_flags = *cp++;
00851 
00852         bip->vertices = (fastf_t *)bu_calloc( bip->num_vertices * 3, sizeof( fastf_t ), "BOT vertices" );
00853         bip->faces = (int *)bu_calloc( bip->num_faces * 3, sizeof( int ), "BOT faces" );
00854 
00855         for( i=0 ; i<bip->num_vertices ; i++ )
00856         {
00857                 point_t tmp;
00858 
00859                 ntohd( (unsigned char *)tmp, (const unsigned char *)cp, 3 );
00860                 cp += SIZEOF_NETWORK_DOUBLE * 3;
00861                 MAT4X3PNT( &(bip->vertices[i*3]), mat, tmp );
00862         }
00863 
00864         for( i=0 ; i<bip->num_faces ; i++ )
00865         {
00866                 bip->faces[i*3] = bu_glong( cp );
00867                 cp += SIZEOF_NETWORK_LONG;
00868                 bip->faces[i*3 + 1] = bu_glong( cp );
00869                 cp += SIZEOF_NETWORK_LONG;
00870                 bip->faces[i*3 + 2] = bu_glong( cp );
00871                 cp += SIZEOF_NETWORK_LONG;
00872         }
00873 
00874         if( bip->mode == RT_BOT_PLATE || bip->mode == RT_BOT_PLATE_NOCOS )
00875         {
00876                 bip->thickness = (fastf_t *)bu_calloc( bip->num_faces, sizeof( fastf_t ), "BOT thickness" );
00877                 for( i=0 ; i<bip->num_faces ; i++ )
00878                 {
00879                         ntohd( (unsigned char *)&(bip->thickness[i]), cp, 1 );
00880                         cp += SIZEOF_NETWORK_DOUBLE;
00881                 }
00882                 bip->face_mode = bu_hex_to_bitv( (const char *)cp );
00883                 while( *(cp++) != '\0' );
00884         }
00885         else
00886         {
00887                 bip->thickness = (fastf_t *)NULL;
00888                 bip->face_mode = (struct bu_bitv *)NULL;
00889         }
00890 
00891         if( bip->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
00892                 vect_t tmp;
00893 
00894                 bip->num_normals = bu_glong( cp );
00895                 cp += SIZEOF_NETWORK_LONG;
00896                 bip->num_face_normals = bu_glong( cp );
00897                 cp += SIZEOF_NETWORK_LONG;
00898 
00899                 if( bip->num_normals <= 0 ) {
00900                         bip->normals = (fastf_t *)NULL;
00901                 }
00902                 if( bip->num_face_normals <= 0 ) {
00903                         bip->face_normals = (int *)NULL;
00904                 }
00905                 if( bip->num_normals > 0 ) {
00906                         bip->normals = (fastf_t *)bu_calloc( bip->num_normals * 3, sizeof( fastf_t ), "BOT normals" );
00907 
00908                         for( i=0 ; i<bip->num_normals ; i++ ) {
00909                                 ntohd( (unsigned char *)tmp, (const unsigned char *)cp, 3 );
00910                                 cp += SIZEOF_NETWORK_DOUBLE * 3;
00911                                 MAT4X3VEC( &(bip->normals[i*3]), mat, tmp );
00912                         }
00913                 }
00914                 if( bip->num_face_normals > 0 ) {
00915                         bip->face_normals = (int *)bu_calloc( bip->num_face_normals * 3, sizeof( int ), "BOT face normals" );
00916 
00917                         for( i=0 ; i<bip->num_face_normals ; i++ ) {
00918                                 bip->face_normals[i*3] = bu_glong( cp );
00919                                 cp += SIZEOF_NETWORK_LONG;
00920                                 bip->face_normals[i*3 + 1] = bu_glong( cp );
00921                                 cp += SIZEOF_NETWORK_LONG;
00922                                 bip->face_normals[i*3 + 2] = bu_glong( cp );
00923                                 cp += SIZEOF_NETWORK_LONG;
00924                         }
00925                 }
00926         } else {
00927                 bip->normals = (fastf_t *)NULL;
00928                 bip->face_normals = (int *)NULL;
00929                 bip->num_normals = 0;
00930         }
00931 
00932         return(0);                      /* OK */
00933 }
00934 
00935 /**
00936  *                      R T _ B O T _ E X P O R T 5
00937  */
00938 int
00939 rt_bot_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00940 {
00941         struct rt_bot_internal          *bip;
00942         struct bu_vls                   vls;
00943         register unsigned char          *cp;
00944         int                             i;
00945 
00946         RT_CK_DB_INTERNAL( ip );
00947 
00948         if( ip->idb_type != ID_BOT ) return -1;
00949         bip = (struct rt_bot_internal *)ip->idb_ptr;
00950         RT_BOT_CK_MAGIC( bip );
00951 
00952         BU_CK_EXTERNAL( ep );
00953 
00954         if( bip->mode == RT_BOT_PLATE || bip->mode == RT_BOT_PLATE_NOCOS )
00955         {
00956                 /* build hex string for face mode */
00957                 bu_vls_init( &vls );
00958                 if( bip->face_mode )
00959                         bu_bitv_to_hex( &vls, bip->face_mode );
00960         }
00961 
00962         ep->ext_nbytes = 3                              /* orientation, mode, bot_flags */
00963                         + SIZEOF_NETWORK_LONG * (bip->num_faces * 3 + 2) /* faces, num_faces, num_vertices */
00964                         + SIZEOF_NETWORK_DOUBLE * bip->num_vertices * 3; /* vertices */
00965 
00966         if( bip->mode == RT_BOT_PLATE || bip->mode == RT_BOT_PLATE_NOCOS ) {
00967                 ep->ext_nbytes += SIZEOF_NETWORK_DOUBLE * bip->num_faces /* face thicknesses */
00968                         + bu_vls_strlen( &vls ) + 1;    /* face modes */
00969         }
00970 
00971         if( bip->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
00972                 ep->ext_nbytes += SIZEOF_NETWORK_DOUBLE * bip->num_normals * 3 /* vertex normals */
00973                         + SIZEOF_NETWORK_LONG * (bip->num_face_normals * 3 + 2); /* indices into normals array, num_normals, num_face_normals */
00974         }
00975 
00976         ep->ext_buf = (genptr_t)bu_malloc( ep->ext_nbytes, "BOT external" );
00977 
00978         cp = ep->ext_buf;
00979 
00980         (void)bu_plong( cp, bip->num_vertices );
00981         cp += SIZEOF_NETWORK_LONG;
00982         (void)bu_plong( cp, bip->num_faces );
00983         cp += SIZEOF_NETWORK_LONG;
00984         *cp++ = bip->orientation;
00985         *cp++ = bip->mode;
00986         *cp++ = bip->bot_flags;
00987 
00988         for( i=0 ; i<bip->num_vertices ; i++ )
00989         {
00990                 point_t tmp;
00991 
00992                 VSCALE( tmp, &bip->vertices[i*3], local2mm );
00993                 htond( cp, (unsigned char *)tmp, 3 );
00994                 cp += SIZEOF_NETWORK_DOUBLE * 3;
00995         }
00996 
00997         for( i=0 ; i<bip->num_faces ; i++ )
00998         {
00999                 (void)bu_plong( cp, bip->faces[i*3] );
01000                 cp += SIZEOF_NETWORK_LONG;
01001                 (void)bu_plong( cp, bip->faces[i*3 + 1] );
01002                 cp += SIZEOF_NETWORK_LONG;
01003                 (void)bu_plong( cp, bip->faces[i*3 + 2] );
01004                 cp += SIZEOF_NETWORK_LONG;
01005         }
01006 
01007         if( bip->mode == RT_BOT_PLATE || bip->mode == RT_BOT_PLATE_NOCOS )
01008         {
01009                 for( i=0 ; i<bip->num_faces ; i++ )
01010                 {
01011                         fastf_t tmp;
01012 
01013                         tmp = bip->thickness[i] * local2mm;
01014                         htond( cp, (const unsigned char *)&tmp, 1 );
01015                         cp += SIZEOF_NETWORK_DOUBLE;
01016                 }
01017                 strcpy( (char *)cp, bu_vls_addr( &vls ) );
01018                 cp += bu_vls_strlen( &vls );
01019                 *cp = '\0';
01020                 cp++;
01021                 bu_vls_free( &vls );
01022         }
01023 
01024         if( bip->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
01025                 (void)bu_plong( cp, bip->num_normals );
01026                 cp += SIZEOF_NETWORK_LONG;
01027                 (void)bu_plong( cp, bip->num_face_normals );
01028                 cp += SIZEOF_NETWORK_LONG;
01029                 if( bip->num_normals > 0 ) {
01030                         htond( cp, (unsigned char*)bip->normals, bip->num_normals*3 );
01031                         cp += SIZEOF_NETWORK_DOUBLE * 3 * bip->num_normals;
01032                 }
01033                 if( bip->num_face_normals > 0 ) {
01034                         for( i=0 ; i<bip->num_face_normals ; i++ ) {
01035                                 (void)bu_plong( cp, bip->face_normals[i*3] );
01036                                 cp += SIZEOF_NETWORK_LONG;
01037                                 (void)bu_plong( cp, bip->face_normals[i*3 + 1] );
01038                                 cp += SIZEOF_NETWORK_LONG;
01039                                 (void)bu_plong( cp, bip->face_normals[i*3 + 2] );
01040                                 cp += SIZEOF_NETWORK_LONG;
01041                         }
01042                 }
01043         }
01044 
01045         return 0;
01046 }
01047 
01048 /**
01049  *                      R T _ B O T _ D E S C R I B E
01050  *
01051  *  Make human-readable formatted presentation of this solid.
01052  *  First line describes type of solid.
01053  *  Additional lines are indented one tab, and give parameter values.
01054  */
01055 static char *unoriented="unoriented";
01056 static char *ccw="counter-clockwise";
01057 static char *cw="clockwise";
01058 static char *unknown_orientation="unknown orientation";
01059 static char *surface="\tThis is a surface with no volume\n";
01060 static char *solid="\tThis is a solid object (not just a surface)\n";
01061 static char *plate="\tThis is a FASTGEN plate mode solid\n";
01062 static char *nocos="\tThis is a plate mode solid with no obliquity angle effect\n";
01063 static char *unknown_mode="\tunknown mode\n";
01064 int
01065 rt_bot_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
01066 {
01067         register struct rt_bot_internal *bot_ip =
01068                 (struct rt_bot_internal *)ip->idb_ptr;
01069         char    buf[256];
01070         char *orientation,*mode;
01071         int i;
01072 
01073         RT_BOT_CK_MAGIC(bot_ip);
01074         bu_vls_strcat( str, "Bag of triangles (BOT)\n");
01075 
01076         switch( bot_ip->orientation )
01077         {
01078                 case RT_BOT_UNORIENTED:
01079                         orientation = unoriented;
01080                         break;
01081                 case RT_BOT_CCW:
01082                         orientation = ccw;
01083                         break;
01084                 case RT_BOT_CW:
01085                         orientation = cw;
01086                         break;
01087                 default:
01088                         orientation = unknown_orientation;
01089                         break;
01090         }
01091         switch( bot_ip->mode )
01092         {
01093                 case RT_BOT_SURFACE:
01094                         mode = surface;
01095                         break;
01096                 case RT_BOT_SOLID:
01097                         mode = solid;
01098                         break;
01099                 case RT_BOT_PLATE:
01100                         mode = plate;
01101                         break;
01102                 case RT_BOT_PLATE_NOCOS:
01103                         mode = nocos;
01104                         break;
01105                 default:
01106                         mode = unknown_mode;
01107                         break;
01108         }
01109         sprintf(buf, "\t%d vertices, %d faces (%s)\n",
01110                 bot_ip->num_vertices,
01111                 bot_ip->num_faces,
01112                 orientation );
01113         bu_vls_strcat( str, buf );
01114         bu_vls_strcat( str, mode );
01115         if( (bot_ip->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) && bot_ip->num_normals > 0 ) {
01116                 bu_vls_strcat( str, "\twith surface normals" );
01117                 if( bot_ip->bot_flags & RT_BOT_USE_NORMALS ) {
01118                         bu_vls_strcat( str, " (they will be used)\n" );
01119                 } else {
01120                         bu_vls_strcat( str, " (they will be ignored)\n" );
01121                 }
01122         }
01123 
01124         if( verbose )
01125         {
01126                 for( i=0 ; i<bot_ip->num_faces ; i++ )
01127                 {
01128                         int j, k;
01129                         point_t pt[3];
01130 
01131                         for( j=0 ; j<3 ; j++ )
01132                                 VSCALE( pt[j], &bot_ip->vertices[bot_ip->faces[i*3+j]*3], mm2local );
01133                         if( (bot_ip->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) && bot_ip->num_normals > 0 ) {
01134                                 sprintf( buf, "\tface %d: (%g %g %g), (%g %g %g), (%g %g %g) normals: ", i,
01135                                          V3INTCLAMPARGS( pt[0] ),
01136                                          V3INTCLAMPARGS( pt[1] ),
01137                                          V3INTCLAMPARGS( pt[2] ) );
01138                                 bu_vls_strcat( str, buf );
01139                                 for( k=0 ; k<3 ; k++ ) {
01140                                         int index;
01141 
01142                                         index = i*3 + k;
01143                                         if( bot_ip->face_normals[index] < 0 ||  bot_ip->face_normals[index] >= bot_ip->num_normals ) {
01144                                                 bu_vls_strcat( str, "none " );
01145                                         } else {
01146                                                 sprintf( buf, "(%g %g %g) ", V3INTCLAMPARGS( &bot_ip->normals[bot_ip->face_normals[index]*3]));
01147                                                 bu_vls_strcat( str, buf );
01148                                         }
01149                                 }
01150                                 bu_vls_strcat( str, "\n" );
01151                         } else {
01152                                 sprintf( buf, "\tface %d: (%g %g %g), (%g %g %g), (%g %g %g)\n", i,
01153                                          V3INTCLAMPARGS( pt[0] ),
01154                                          V3INTCLAMPARGS( pt[1] ),
01155                                          V3INTCLAMPARGS( pt[2] ) );
01156                                 bu_vls_strcat( str, buf );
01157                         }
01158                         if( bot_ip->mode == RT_BOT_PLATE || bot_ip->mode == RT_BOT_PLATE_NOCOS )
01159                         {
01160                                 char *face_mode;
01161 
01162                                 if( BU_BITTEST( bot_ip->face_mode, i ) )
01163                                         face_mode = "appended to hit point";
01164                                 else
01165                                         face_mode = "centered about hit point";
01166                                 sprintf( buf, "\t\tthickness = %g, %s\n", INTCLAMP(mm2local*bot_ip->thickness[i]), face_mode );
01167                                 bu_vls_strcat( str, buf );
01168                         }
01169                 }
01170         }
01171 
01172         return(0);
01173 }
01174 
01175 /**
01176  *                      R T _ B O T _ I F R E E
01177  *
01178  *  Free the storage associated with the rt_db_internal version of this solid.
01179  */
01180 void
01181 rt_bot_ifree(struct rt_db_internal *ip)
01182 {
01183         register struct rt_bot_internal *bot_ip;
01184 
01185         RT_CK_DB_INTERNAL(ip);
01186         bot_ip = (struct rt_bot_internal *)ip->idb_ptr;
01187         RT_BOT_CK_MAGIC(bot_ip);
01188         bot_ip->magic = 0;                      /* sanity */
01189 
01190         bu_free( (char *)bot_ip->vertices, "BOT vertices" );
01191         bu_free( (char *)bot_ip->faces, "BOT faces" );
01192 
01193         if( bot_ip->mode == RT_BOT_PLATE || bot_ip->mode == RT_BOT_PLATE_NOCOS )
01194         {
01195                 bu_free( (char *)bot_ip->thickness, "BOT thickness" );
01196                 bu_free( (char *)bot_ip->face_mode, "BOT face_mode" );
01197         }
01198 
01199         bu_free( (char *)bot_ip, "bot ifree" );
01200         ip->idb_ptr = GENPTR_NULL;      /* sanity */
01201 }
01202 
01203 int
01204 rt_bot_tnurb(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct bn_tol *tol)
01205 {
01206         return( 1 );
01207 }
01208 
01209 int
01210 rt_bot_xform(struct rt_db_internal *op, const fastf_t *mat, struct rt_db_internal *ip, const int free, struct db_i *dbip)
01211 {
01212         struct rt_bot_internal *botip, *botop;
01213         register int            i;
01214         point_t                 pt;
01215 
01216         RT_CK_DB_INTERNAL( ip );
01217         botip = (struct rt_bot_internal *)ip->idb_ptr;
01218         RT_BOT_CK_MAGIC(botip);
01219 
01220         if( op != ip && !free )
01221         {
01222                 RT_INIT_DB_INTERNAL(op);
01223                 BU_GETSTRUCT( botop, rt_bot_internal );
01224                 botop->magic = RT_BOT_INTERNAL_MAGIC;
01225                 botop->mode = botip->mode;
01226                 botop->orientation = botip->orientation;
01227                 botop->bot_flags = botip->bot_flags;
01228                 botop->num_vertices = botip->num_vertices;
01229                 botop->num_faces = botip->num_faces;
01230                 if( botop->num_vertices > 0 ) {
01231                         botop->vertices = (fastf_t *)bu_malloc( botip->num_vertices * 3 *
01232                                                                 sizeof( fastf_t ), "botop->vertices" );
01233                 }
01234                 if( botop->num_faces > 0 ) {
01235                         botop->faces = (int *)bu_malloc( botip->num_faces * 3 *
01236                                                          sizeof( int ), "botop->faces" );
01237                         memcpy( botop->faces, botip->faces, botop->num_faces * 3 * sizeof( int ) );
01238                 }
01239                 if( botip->thickness )
01240                         botop->thickness = (fastf_t *)bu_malloc( botip->num_faces *
01241                                 sizeof( fastf_t ), "botop->thickness" );
01242                 if( botip->face_mode )
01243                         botop->face_mode = bu_bitv_dup( botip->face_mode );
01244                 if( botip->thickness )
01245                 {
01246                         for( i=0 ; i<botip->num_faces ; i++ )
01247                                 botop->thickness[i] = botip->thickness[i];
01248                 }
01249 
01250                 if( botop->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
01251                         botop->num_normals = botip->num_normals;
01252                         botop->normals = (fastf_t *)bu_calloc( botop->num_normals * 3, sizeof( fastf_t ), "BOT normals" );
01253                         botop->face_normals = (int *)bu_calloc( botop->num_faces * 3, sizeof( int ), "BOT face normals" );
01254                         memcpy( botop->face_normals, botip->face_normals, botop->num_faces * 3 * sizeof( int ) );
01255                 }
01256                 op->idb_ptr = (genptr_t)botop;
01257                 op->idb_major_type = DB5_MAJORTYPE_BRLCAD;
01258                 op->idb_type = ID_BOT;
01259                 op->idb_meth = &rt_functab[ID_BOT];
01260         }
01261         else
01262                 botop = botip;
01263 
01264         if( ip != op ) {
01265                 if( ip->idb_avs.magic == BU_AVS_MAGIC ) {
01266                         bu_avs_init( &op->idb_avs, ip->idb_avs.count, "avs" );
01267                         bu_avs_merge( &op->idb_avs, &ip->idb_avs );
01268                 }
01269         }
01270 
01271         for( i=0 ; i<botip->num_vertices ; i++ )
01272         {
01273                 MAT4X3PNT( pt, mat, &botip->vertices[i*3] );
01274                 VMOVE( &botop->vertices[i*3], pt );
01275         }
01276 
01277         for( i=0 ; i<botip->num_normals ; i++ ) {
01278                 MAT4X3VEC( pt, mat, &botip->normals[i*3] );
01279                 VMOVE( &botop->normals[i*3], pt );
01280         }
01281 
01282         if( free && op != ip ) {
01283                 rt_bot_ifree( ip );
01284         }
01285 
01286         return( 0 );
01287 }
01288 
01289 int
01290 rt_bot_find_v_nearest_pt2(
01291         const struct rt_bot_internal *bot,
01292         const point_t   pt2,
01293         const mat_t     mat)
01294 {
01295         point_t v;
01296         int index;
01297         fastf_t dist=MAX_FASTF;
01298         int closest=-1;
01299 
01300         RT_BOT_CK_MAGIC( bot );
01301 
01302         for( index=0 ; index < bot->num_vertices ; index++ )
01303         {
01304                 fastf_t tmp_dist;
01305                 fastf_t tmpx, tmpy;
01306 
01307                 MAT4X3PNT( v, mat, &bot->vertices[index*3] )
01308                 tmpx = v[X] - pt2[X];
01309                 tmpy = v[Y] - pt2[Y];
01310                 tmp_dist = tmpx * tmpx + tmpy * tmpy;
01311                 if( tmp_dist < dist )
01312                 {
01313                         dist = tmp_dist;
01314                         closest = index;
01315                 }
01316         }
01317 
01318         return( closest );
01319 }
01320 
01321 int
01322 rt_bot_edge_in_list( const int v1, const int v2, const int edge_list[], const int edge_count )
01323 {
01324         int i, ev1, ev2;
01325 
01326         for( i=0 ; i<edge_count ; i++ )
01327         {
01328                 ev1 = edge_list[i*2];
01329                 ev2 = edge_list[i*2 + 1];
01330 
01331                 if( ev1 == v1 && ev2 == v2 )
01332                         return( 1 );
01333 
01334                 if( ev1 == v2 && ev2 == v1 )
01335                         return( 1 );
01336         }
01337 
01338         return( 0 );
01339 }
01340 
01341 /** This routine finds the edge closest to the 2D point "pt2", and
01342  * returns the edge as two
01343  * vertex indices (vert1 and vert2). These vertices are ordered (closest to pt2 is first)
01344  */
01345 int
01346 rt_bot_find_e_nearest_pt2(
01347         int *vert1,
01348         int *vert2,
01349         const struct rt_bot_internal *bot,
01350         const point_t   pt2,
01351         const mat_t     mat)
01352 {
01353         int i;
01354         int v1, v2, v3;
01355         fastf_t dist=MAX_FASTF, tmp_dist;
01356         int *edge_list;
01357         int edge_count=0;
01358         struct bn_tol tol;
01359 
01360         RT_BOT_CK_MAGIC( bot );
01361 
01362         if( bot->num_faces < 1 )
01363                 return( -1 );
01364 
01365         /* first build a list of edges */
01366         edge_list = (int *)bu_calloc( bot->num_faces * 3 * 2, sizeof( int ), "bot edge list" );
01367 
01368         for( i=0 ; i<bot->num_faces ; i++ )
01369         {
01370                 v1 = bot->faces[i*3];
01371                 v2 = bot->faces[i*3 + 1];
01372                 v3 = bot->faces[i*3 + 2];
01373 
01374                 if( !rt_bot_edge_in_list( v1, v2, edge_list, edge_count ) )
01375                 {
01376                         edge_list[edge_count*2] = v1;
01377                         edge_list[edge_count*2 + 1] = v2;
01378                         edge_count++;
01379                 }
01380                 if( !rt_bot_edge_in_list( v3, v2, edge_list, edge_count ) )
01381                 {
01382                         edge_list[edge_count*2] = v3;
01383                         edge_list[edge_count*2 + 1] = v2;
01384                         edge_count++;
01385                 }
01386                 if( !rt_bot_edge_in_list( v1, v3, edge_list, edge_count ) )
01387                 {
01388                         edge_list[edge_count*2] = v1;
01389                         edge_list[edge_count*2 + 1] = v3;
01390                         edge_count++;
01391                 }
01392         }
01393 
01394         /* build a tyolerance structure for the bn_dist routine */
01395         tol.magic = BN_TOL_MAGIC;
01396         tol.dist = 0.0;
01397         tol.dist_sq = 0.0;
01398         tol.perp = 0.0;
01399         tol.para =  1.0;
01400 
01401         /* now look for the closest edge */
01402         for( i=0 ; i<edge_count ; i++ )
01403         {
01404                 point_t p1, p2, pca;
01405                 vect_t p1_to_pca, p1_to_p2;
01406                 int ret;
01407 
01408                 MAT4X3PNT( p1, mat, &bot->vertices[ edge_list[i*2]*3] )
01409                 MAT4X3PNT( p2, mat, &bot->vertices[ edge_list[i*2+1]*3] )
01410 
01411                 ret = bn_dist_pt2_lseg2( &tmp_dist, pca, p1, p2, pt2, &tol );
01412 
01413                 if( ret < 3 || tmp_dist < dist )
01414                 {
01415                         switch( ret )
01416                         {
01417                                 case 0:
01418                                         dist = 0.0;
01419                                         if( tmp_dist < 0.5 )
01420                                         {
01421                                                 *vert1 = edge_list[i*2];
01422                                                 *vert2 = edge_list[i*2+1];
01423                                         }
01424                                         else
01425                                         {
01426                                                 *vert1 = edge_list[i*2+1];
01427                                                 *vert2 = edge_list[i*2];
01428                                         }
01429                                         break;
01430                                 case 1:
01431                                         dist = 0.0;
01432                                         *vert1 = edge_list[i*2];
01433                                         *vert2 = edge_list[i*2+1];
01434                                         break;
01435                                 case 2:
01436                                         dist = 0.0;
01437                                         *vert1 = edge_list[i*2+1];
01438                                         *vert2 = edge_list[i*2];
01439                                         break;
01440                                 case 3:
01441                                         dist = tmp_dist;
01442                                         *vert1 = edge_list[i*2];
01443                                         *vert2 = edge_list[i*2+1];
01444                                         break;
01445                                 case 4:
01446                                         dist = tmp_dist;
01447                                         *vert1 = edge_list[i*2+1];
01448                                         *vert2 = edge_list[i*2];
01449                                 case 5:
01450                                         dist = tmp_dist;
01451                                         V2SUB2( p1_to_pca, pca, p1 );
01452                                         V2SUB2( p1_to_p2, p2, p1 );
01453                                         if( MAG2SQ( p1_to_pca ) / MAG2SQ( p1_to_p2 ) < 0.25 )
01454                                         {
01455                                                 *vert1 = edge_list[i*2];
01456                                                 *vert2 = edge_list[i*2+1];
01457                                         }
01458                                         else
01459                                         {
01460                                                 *vert1 = edge_list[i*2+1];
01461                                                 *vert2 = edge_list[i*2];
01462                                         }
01463                                         break;
01464                         }
01465                 }
01466         }
01467 
01468         bu_free( (char *)edge_list, "bot edge list" );
01469 
01470         return( 0 );
01471 }
01472 
01473 static char *modes[]={
01474         "ERROR: Unrecognized mode",
01475         "surf",
01476         "volume",
01477         "plate",
01478         "plate_nocos"
01479 };
01480 
01481 static char *orientation[]={
01482         "ERROR: Unrecognized orientation",
01483         "no",
01484         "rh",
01485         "lh"
01486 };
01487 
01488 static char *los[]={
01489         "center",
01490         "append"
01491 };
01492 
01493 /**
01494  *                      R T _ B O T _ T C L G E T
01495  *
01496  *  Examples -
01497  *      db get name fm          get los facemode bit vector
01498  *      db get name fm#         get los face mode of face # (center, append)
01499  *      db get name V           get coords for all vertices
01500  *      db get name V#          get coords for vertex #
01501  *      db get name F           get vertex indices for all faces
01502  *      db get name F#          get vertex indices for face #
01503  *      db get name f           get list of coords for all faces
01504  *      db get name f#          get list of 3 3tuple coords for face #
01505  *      db get name T           get thickness for all faces
01506  *      db get name T#          get thickness for face #
01507  *      db get name N           get list of normals
01508  *      db get name N#          get coords for normal #
01509  *      db get name fn          get list indices into normal vectors for all faces
01510  *      db get name fn#         get list indices into normal vectors for face #
01511  *      db get name nv          get num_vertices
01512  *      db get name nt          get num_faces
01513  *      db get name nn          get num_normals
01514  *      db get name nfn         get num_face_normals
01515  *      db get name mode        get mode (surf, volume, plate, plane_nocos)
01516  *      db get name orient      get orientation (no, rh, lh)
01517  *      db get name flags       get BOT flags
01518  */
01519 int
01520 rt_bot_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr)
01521 {
01522         register struct rt_bot_internal *bot=(struct rt_bot_internal *)intern->idb_ptr;
01523         Tcl_DString     ds;
01524         struct bu_vls   vls;
01525         int             status;
01526         int             i;
01527 
01528         RT_BOT_CK_MAGIC( bot );
01529 
01530         Tcl_DStringInit( &ds );
01531         bu_vls_init( &vls );
01532 
01533         if( attr == (char *)NULL )
01534         {
01535                 bu_vls_strcpy( &vls, "bot" );
01536                 bu_vls_printf( &vls, " mode %s orient %s",
01537                                 modes[bot->mode], orientation[bot->orientation] );
01538                 bu_vls_printf( &vls, " flags {" );
01539                 if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
01540                         bu_vls_printf( &vls, " has_normals" );
01541                 }
01542                 if( bot->bot_flags & RT_BOT_USE_NORMALS ) {
01543                         bu_vls_printf( &vls, " use_normals" );
01544                 }
01545                 if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
01546                         bu_vls_printf( &vls, " use_floats" );
01547                 }
01548                 bu_vls_printf( &vls, "} V {" );
01549                 for( i=0 ; i<bot->num_vertices ; i++ )
01550                         bu_vls_printf( &vls, " { %.25G %.25G %.25G }",
01551                                 V3ARGS( &bot->vertices[i*3] ) );
01552                 bu_vls_strcat( &vls, "} F {" );
01553                 for( i=0 ; i<bot->num_faces ; i++ )
01554                         bu_vls_printf( &vls, " { %d %d %d }",
01555                                 V3ARGS( &bot->faces[i*3] ) );
01556                 bu_vls_strcat( &vls, "}" );
01557                 if( bot->mode == RT_BOT_PLATE || bot->mode == RT_BOT_PLATE_NOCOS )
01558                 {
01559                         bu_vls_strcat( &vls, " T {" );
01560                         for( i=0 ; i<bot->num_faces ; i++ )
01561                                 bu_vls_printf( &vls, " %.25G", bot->thickness[i] );
01562                         bu_vls_strcat( &vls, "} fm " );
01563                         bu_bitv_to_hex( &vls, bot->face_mode );
01564                 }
01565                 if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
01566                         bu_vls_printf( &vls, " N {" );
01567                         for( i=0 ; i<bot->num_normals ; i++ ) {
01568                                 bu_vls_printf( &vls, " { %.25G %.25G %.25G }", V3ARGS( &bot->normals[i*3] ) );
01569                         }
01570                         bu_vls_printf( &vls, "} fn {" );
01571                         for( i=0 ; i<bot->num_faces ; i++ ) {
01572                                 bu_vls_printf( &vls, " { %d %d %d }", V3ARGS( &bot->face_normals[i*3] ) );
01573                         }
01574                         bu_vls_printf( &vls, "}" );
01575                 }
01576                 status = TCL_OK;
01577         }
01578         else
01579         {
01580                 if( attr[0] == 'N' )
01581                 {
01582                         if( attr[1] == '\0' ) {
01583                                 if( !(bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) || bot->num_normals < 1 ) {
01584                                         bu_vls_strcat( &vls, "{}" );
01585                                 } else {
01586                                         for( i=0 ; i<bot->num_normals ; i++ ) {
01587                                                 bu_vls_printf( &vls, " { %.25G %.25G %.25G }", V3ARGS( &bot->normals[i*3] ) );
01588                                         }
01589                                 }
01590                                 status = TCL_OK;
01591                         } else {
01592                                 i = atoi( &attr[1] );
01593                                 if( i < 0 || i >= bot->num_normals ) {
01594                                         bu_vls_strcat( &vls, "Specified normal index is out of range" );
01595                                         status = TCL_ERROR;
01596                                 } else {
01597                                         bu_vls_printf( &vls, "%.25G %.25G %.25G", V3ARGS( &bot->normals[i*3] ) );
01598                                         status = TCL_OK;
01599                                 }
01600                         }
01601                 }
01602                 else if( !strncmp( attr, "fn", 2 ) )
01603                 {
01604                         if( attr[2] == '\0' ) {
01605                                 for( i=0 ; i<bot->num_faces ; i++ ) {
01606                                         bu_vls_printf( &vls, " { %d %d %d }", V3ARGS( &bot->face_normals[i*3] ) );
01607                                 }
01608                                 status = TCL_OK;
01609                         } else {
01610                                 i = atoi( &attr[2] );
01611                                 if( i < 0 || i >= bot->num_faces ) {
01612                                         bu_vls_strcat( &vls, "Specified face index is out of range" );
01613                                         status = TCL_ERROR;
01614                                 } else {
01615                                         bu_vls_printf( &vls, "%d %d %d", V3ARGS( &bot->face_normals[i*3] ) );
01616                                         status = TCL_OK;
01617                                 }
01618                         }
01619                 }
01620                 else if( !strcmp( attr, "nn" ) )
01621                 {
01622                         if( !(bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) || bot->num_normals < 1 ) {
01623                                 bu_vls_strcat( &vls, "0" );
01624                         } else {
01625                                 bu_vls_printf( &vls, "%d", bot->num_normals );
01626                         }
01627                         status = TCL_OK;
01628                 }
01629                 else if( !strcmp( attr, "nfn" ) )
01630                 {
01631                         if( !(bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) || bot->num_face_normals < 1 ) {
01632                                 bu_vls_strcat( &vls, "0" );
01633                         } else {
01634                                 bu_vls_printf( &vls, "%d", bot->num_face_normals );
01635                         }
01636                         status = TCL_OK;
01637                 }
01638                 else if( !strncmp( attr, "fm", 2 ) )
01639                 {
01640                         if( bot->mode != RT_BOT_PLATE && bot->mode != RT_BOT_PLATE_NOCOS )
01641                         {
01642                                 bu_vls_strcat( &vls, "Only plate mode BOTs have face_modes" );
01643                                 status = TCL_ERROR;
01644                         }
01645                         else
01646                         {
01647                                 if( attr[2] == '\0' )
01648                                 {
01649                                         bu_bitv_to_hex( &vls, bot->face_mode );
01650                                         status = TCL_OK;
01651                                 }
01652                                 else
01653                                 {
01654                                         i = atoi( &attr[2] );
01655                                         if( i < 0 || i >=bot->num_faces )
01656                                         {
01657                                                 bu_vls_printf( &vls, "face number %d out of range (0..%d)", i, bot->num_faces-1 );
01658                                                 status = TCL_ERROR;
01659                                         }
01660                                         else
01661                                         {
01662                                                 bu_vls_printf( &vls, "%s",
01663                                                         los[BU_BITTEST( bot->face_mode, i )?1:0] );
01664                                                 status = TCL_OK;
01665                                         }
01666                                 }
01667                         }
01668                 }
01669                 else if( attr[0] == 'V' )
01670                 {
01671                         if( attr[1] != '\0' )
01672                         {
01673                                 i = atoi( &attr[1] );
01674                                 if( i < 0 || i >=bot->num_vertices )
01675                                 {
01676                                         bu_vls_printf( &vls, "vertex number %d out of range (0..%d)", i, bot->num_vertices-1 );
01677                                         status = TCL_ERROR;
01678                                 }
01679                                 else
01680                                 {
01681                                         bu_vls_printf( &vls, "%.25G %.25G %.25G",
01682                                                 V3ARGS( &bot->vertices[i*3] ) );
01683                                         status = TCL_OK;
01684                                 }
01685                         }
01686                         else
01687                         {
01688                                 for( i=0 ; i<bot->num_vertices ; i++ )
01689                                         bu_vls_printf( &vls, " { %.25G %.25G %.25G }",
01690                                                 V3ARGS( &bot->vertices[i*3] ) );
01691                                 status = TCL_OK;
01692                         }
01693                 }
01694                 else if( attr[0] == 'F' )
01695                 {
01696                         /* Retrieve one face, as vertex indices */
01697                         if( attr[1] == '\0' )
01698                         {
01699                                 for( i=0 ; i<bot->num_faces ; i++ )
01700                                         bu_vls_printf( &vls, " { %d %d %d }",
01701                                                 V3ARGS( &bot->faces[i*3] ) );
01702                                 status = TCL_OK;
01703                         }
01704                         else
01705                         {
01706                                 i = atoi( &attr[1] );
01707                                 if( i < 0 || i >=bot->num_faces )
01708                                 {
01709                                         bu_vls_printf( &vls, "face number %d out of range (0..%d)", i, bot->num_faces-1 );
01710                                         status = TCL_ERROR;
01711                                 }
01712                                 else
01713                                 {
01714                                         bu_vls_printf( &vls, "%d %d %d",
01715                                                 V3ARGS( &bot->faces[i*3] ) );
01716                                         status = TCL_OK;
01717                                 }
01718                         }
01719                 }
01720                 else if( !strcmp( attr, "flags" ) )
01721                 {
01722                         bu_vls_printf( &vls, "{" );
01723                         if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
01724                                 bu_vls_printf( &vls, " has_normals" );
01725                         }
01726                         if( bot->bot_flags & RT_BOT_USE_NORMALS ) {
01727                                 bu_vls_printf( &vls, " use_normals" );
01728                         }
01729                         if( bot->bot_flags & RT_BOT_USE_FLOATS ) {
01730                                 bu_vls_printf( &vls, " use_floats" );
01731                         }
01732                         bu_vls_printf( &vls, "}" );
01733                         status = TCL_OK;
01734                 }
01735                 else if( attr[0] == 'f' )
01736                 {
01737                         int indx;
01738                         /* Retrieve one face, as list of 3 3tuple coordinates */
01739                         if( attr[1] == '\0' )
01740                         {
01741                                 for( i=0 ; i<bot->num_faces ; i++ )  {
01742                                         indx = bot->faces[i*3];
01743                                         bu_vls_printf( &vls, " { %.25G %.25G %.25G }",
01744                                                 bot->vertices[indx*3],
01745                                                 bot->vertices[indx*3+1],
01746                                                 bot->vertices[indx*3+2] );
01747                                         indx = bot->faces[i*3+1];
01748                                         bu_vls_printf( &vls, " { %.25G %.25G %.25G }",
01749                                                 bot->vertices[indx*3],
01750                                                 bot->vertices[indx*3+1],
01751                                                 bot->vertices[indx*3+2] );
01752                                         indx = bot->faces[i*3+2];
01753                                         bu_vls_printf( &vls, " { %.25G %.25G %.25G }",
01754                                                 bot->vertices[indx*3],
01755                                                 bot->vertices[indx*3+1],
01756                                                 bot->vertices[indx*3+2] );
01757                                 }
01758                                 status = TCL_OK;
01759                         }
01760                         else
01761                         {
01762                                 i = atoi( &attr[1] );
01763                                 if( i < 0 || i >=bot->num_faces )
01764                                 {
01765                                         bu_vls_printf( &vls, "face number %d out of range (0..%d)", i, bot->num_faces-1 );
01766                                         status = TCL_ERROR;
01767                                 }
01768                                 else
01769                                 {
01770                                         indx = bot->faces[i*3];
01771                                         bu_vls_printf( &vls, " { %.25G %.25G %.25G }",
01772                                                 bot->vertices[indx*3],
01773                                                 bot->vertices[indx*3+1],
01774                                                 bot->vertices[indx*3+2] );
01775                                         indx = bot->faces[i*3+1];
01776                                         bu_vls_printf( &vls, " { %.25G %.25G %.25G }",
01777                                                 bot->vertices[indx*3],
01778                                                 bot->vertices[indx*3+1],
01779                                                 bot->vertices[indx*3+2] );
01780                                         indx = bot->faces[i*3+2];
01781                                         bu_vls_printf( &vls, " { %.25G %.25G %.25G }",
01782                                                 bot->vertices[indx*3],
01783                                                 bot->vertices[indx*3+1],
01784                                                 bot->vertices[indx*3+2] );
01785                                         status = TCL_OK;
01786                                 }
01787                         }
01788                 }
01789                 else if( attr[0] == 'T' )
01790                 {
01791                         if( bot->mode != RT_BOT_PLATE && bot->mode != RT_BOT_PLATE_NOCOS )
01792                         {
01793                                 bu_vls_strcat( &vls, "Only plate mode BOTs have thicknesses" );
01794                                 status = TCL_ERROR;
01795                         }
01796                         else
01797                         {
01798                                 if( attr[1] == '\0' )
01799                                 {
01800                                         for( i=0 ; i<bot->num_faces ; i++ )
01801                                                 bu_vls_printf( &vls, " %.25G", bot->thickness[i] );
01802                                         status = TCL_OK;
01803                                 }
01804                                 else
01805                                 {
01806                                         i = atoi( &attr[1] );
01807                                         if( i < 0 || i >=bot->num_faces )
01808                                         {
01809                                                 bu_vls_printf( &vls, "face number %d out of range (0..%d)", i, bot->num_faces-1 );
01810                                                 status = TCL_ERROR;
01811                                         }
01812                                         else
01813                                         {
01814                                                 bu_vls_printf( &vls, " %.25G", bot->thickness[i] );
01815                                                 status = TCL_OK;
01816                                         }
01817                                 }
01818                         }
01819                 }
01820                 else if( !strcmp( attr, "nv" ) )
01821                 {
01822                         bu_vls_printf( &vls, "%d", bot->num_vertices );
01823                         status = TCL_OK;
01824                 }
01825                 else if( !strcmp( attr, "nt" ) )
01826                 {
01827                         bu_vls_printf( &vls, "%d", bot->num_faces );
01828                         status = TCL_OK;
01829                 }
01830                 else if( !strcmp( attr, "mode" ) )
01831                 {
01832                         bu_vls_printf( &vls, "%s", modes[bot->mode] );
01833                         status = TCL_OK;
01834                 }
01835                 else if( !strcmp( attr, "orient" ) )
01836                 {
01837                         bu_vls_printf( &vls, "%s", orientation[bot->orientation] );
01838                         status = TCL_OK;
01839                 }
01840                 else
01841                 {
01842                         bu_vls_printf( &vls, "BoT has no attribute '%s'", attr );
01843                         status = TCL_ERROR;
01844                 }
01845         }
01846 
01847         Tcl_DStringAppend( &ds, bu_vls_addr( &vls ), -1 );
01848         Tcl_DStringResult( interp, &ds );
01849         Tcl_DStringFree( &ds );
01850         bu_vls_free( &vls );
01851 
01852         return( status );
01853 }
01854 
01855 /**
01856  *                      R T _ B O T _ T C L A D J U S T
01857  *
01858  * Examples -
01859  *      db adjust name fm               set los facemode bit vector
01860  *      db adjust name fm#              set los face mode of face # (center, append)
01861  *      db adjust name V                set coords for all vertices
01862  *      db adjust name V#               set coords for vertex #
01863  *      db adjust name F                set vertex indices for all faces
01864  *      db adjust name F#               set vertex indices for face #
01865  *      db adjust name T                set thickness for all faces
01866  *      db adjust name T#               set thickness for face #
01867  *      db adjust name N                set list of normals
01868  *      db adjust name N#               set coords for normal #
01869  *      db adjust name fn               set list indices into normal vectors for all faces
01870  *      db adjust name fn#              set list indices into normal vectors for face #
01871  *      db adjust name nn               set num_normals
01872  *      db adjust name mode             set mode (surf, volume, plate, plane_nocos)
01873  *      db adjust name orient           set orientation (no, rh, lh)
01874  *      db adjust name flags            set flags
01875  */
01876 int
01877 rt_bot_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, char **argv)
01878 {
01879         struct rt_bot_internal *bot;
01880         Tcl_Obj *obj, *list, **obj_array;
01881         int len;
01882         int i;
01883 
01884         RT_CK_DB_INTERNAL( intern );
01885         bot = (struct rt_bot_internal *)intern->idb_ptr;
01886         RT_BOT_CK_MAGIC( bot );
01887 
01888         while( argc >= 2 )
01889         {
01890                 obj = Tcl_NewStringObj( argv[1], -1 );
01891                 list = Tcl_NewListObj( 0, NULL );
01892                 Tcl_ListObjAppendList( interp, list, obj );
01893 
01894                 if( !strncmp( argv[0], "fm", 2 ) )
01895                 {
01896                         if( argv[0][2] == '\0' )
01897                         {
01898                                 if( bot->face_mode )
01899                                         bu_free( (char *)bot->face_mode, "bot->face_mode" );
01900                                 bot->face_mode = bu_hex_to_bitv( argv[1] );
01901                         }
01902                         else
01903                         {
01904                                 i = atoi( &(argv[0][2]) );
01905                                 if( i < 0 || i >= bot->num_faces )
01906                                 {
01907                                         Tcl_SetResult( interp, "Face number out of range", TCL_STATIC );
01908                                         Tcl_DecrRefCount( list );
01909                                         return( TCL_ERROR );
01910                                 }
01911 
01912                                 if( isdigit( *argv[1] ) )
01913                                   {
01914                                     if( atoi( argv[1] ) == 0 )
01915                                         BU_BITCLR( bot->face_mode, i );
01916                                     else
01917                                         BU_BITSET( bot->face_mode, i );
01918                                   }
01919                                 else if( !strcmp( argv[1], "append" ) )
01920                                         BU_BITSET( bot->face_mode, i );
01921                                 else
01922                                         BU_BITCLR( bot->face_mode, i );
01923                         }
01924                 }
01925                 else if( !strcmp( argv[0], "nn" ) )
01926                 {
01927                         int new_num=0;
01928                         int old_num = bot->num_normals;
01929 
01930                         new_num = atoi( Tcl_GetStringFromObj( obj, NULL ) );
01931                         if( new_num < 0 ) {
01932                                 Tcl_SetResult( interp, "Number of normals may not be less than 0", TCL_STATIC );
01933                                 Tcl_DecrRefCount( list );
01934                                 return( TCL_ERROR );
01935                         }
01936 
01937                         if( new_num == 0 ) {
01938                                 bot->num_normals = 0;
01939                                 if( bot->normals ) {
01940                                         bu_free( (char *)bot->normals, "BOT normals" );
01941                                 }
01942                                 bot->normals = (fastf_t *)NULL;
01943                         } else {
01944                                 if( new_num != old_num ) {
01945                                         bot->num_normals = new_num;
01946                                         if( bot->normals ) {
01947                                                 bot->normals = (fastf_t *)bu_realloc( (char *)bot->normals,
01948                                                                      bot->num_normals * 3 * sizeof( fastf_t ), "BOT normals" );
01949                                         } else {
01950                                                 bot->normals = (fastf_t *)bu_calloc( bot->num_normals * 3, sizeof( fastf_t ),
01951                                                                                      "BOT normals" );
01952                                         }
01953 
01954                                         if( new_num > old_num ) {
01955                                                 for( i = old_num ; i<new_num ; i++ ) {
01956                                                         VSET( &bot->normals[i*3], 0, 0, 0 );
01957                                                 }
01958                                         }
01959                                 }
01960 
01961                         }
01962 
01963                 }
01964                 else if( !strncmp( argv[0], "fn", 2 ) )
01965                 {
01966                     char *f_str;
01967 
01968                     if( argv[0][2] == '\0' )
01969                       {
01970                         (void)Tcl_ListObjGetElements( interp, list, &len, &obj_array );
01971                         if( len != bot->num_faces || len <= 0 ) {
01972                             Tcl_SetResult( interp, "Must provide normals for all faces!!!", TCL_STATIC );
01973                             Tcl_DecrRefCount( list );
01974                             return( TCL_ERROR );
01975                         }
01976                         if( bot->face_normals )
01977                                 bu_free( (char *)bot->face_normals, "BOT face_normals" );
01978                         bot->face_normals = (int *)bu_calloc( len*3, sizeof( int ), "BOT face_normals" );
01979                         bot->num_face_normals = len;
01980                         for( i=0 ; i<len ; i++ ) {
01981                                 f_str = Tcl_GetStringFromObj( obj_array[i], NULL );
01982                                 while( isspace( *f_str ) ) f_str++;
01983 
01984                                 if( *f_str == '\0' ) {
01985                                         Tcl_SetResult( interp, "incomplete list of face_normals", TCL_STATIC );
01986                                         Tcl_DecrRefCount( list );
01987                                         return( TCL_ERROR );
01988                                 }
01989                                 bot->face_normals[i*3] = atoi( f_str );
01990                                 f_str = bu_next_token( f_str );
01991                                 if( *f_str == '\0' ) {
01992                                         Tcl_SetResult( interp, "incomplete list of face_normals", TCL_STATIC );
01993                                         Tcl_DecrRefCount( list );
01994                                         return( TCL_ERROR );
01995                                 }
01996                                 bot->face_normals[i*3+1] = atoi( f_str );
01997                                 f_str = bu_next_token( f_str );
01998                                 if( *f_str == '\0' ) {
01999                                         Tcl_SetResult( interp, "incomplete list of face_normals", TCL_STATIC );
02000                                         Tcl_DecrRefCount( list );
02001                                         return( TCL_ERROR );
02002                                 }
02003                                 bot->face_normals[i*3+2] = atoi( f_str );
02004                         }
02005                         bot->bot_flags |= RT_BOT_HAS_SURFACE_NORMALS;
02006                       }
02007                     else
02008                       {
02009                         i = atoi( &argv[0][2] );
02010                         if( i < 0 || i >= bot->num_faces )
02011                           {
02012                             Tcl_SetResult( interp, "face_normal number out of range!!!", TCL_STATIC );
02013                             Tcl_DecrRefCount( list );
02014                             return( TCL_ERROR );
02015                           }
02016                         f_str = Tcl_GetStringFromObj( list, NULL );
02017                         while( isspace( *f_str ) ) f_str++;
02018                         bot->face_normals[i*3] = atoi( f_str );
02019                         f_str = bu_next_token( f_str );
02020                         if( *f_str == '\0' )
02021                           {
02022                             Tcl_SetResult( interp, "incomplete vertex", TCL_STATIC );
02023                             Tcl_DecrRefCount( list );
02024                             return( TCL_ERROR );
02025                           }
02026                         bot->face_normals[i*3+1] = atoi( f_str );
02027                         f_str = bu_next_token( f_str );
02028                         if( *f_str == '\0' )
02029                           {
02030                             Tcl_SetResult( interp, "incomplete vertex", TCL_STATIC );
02031                             Tcl_DecrRefCount( list );
02032                             return( TCL_ERROR );
02033                           }
02034                         bot->face_normals[i*3+2] = atoi( f_str );
02035                       }
02036                 }
02037                 else if( argv[0][0] == 'N' )
02038                 {
02039                   char *v_str;
02040 
02041                   if( argv[0][1] == '\0' )
02042                     {
02043                       (void)Tcl_ListObjGetElements( interp, list, &len, &obj_array );
02044                       if( len <= 0 )
02045                         {
02046                           Tcl_SetResult( interp, "Must provide at least one normal!!!", TCL_STATIC );
02047                           Tcl_DecrRefCount( list );
02048                           return( TCL_ERROR );
02049                         }
02050                       bot->num_normals = len;
02051                       if( bot->normals )
02052                               bu_free( (char *)bot->normals, "BOT normals" );
02053                       bot->normals = (fastf_t *)bu_calloc( len*3, sizeof( fastf_t ), "BOT normals" );
02054                       for( i=0 ; i<len ; i++ )
02055                         {
02056                           v_str = Tcl_GetStringFromObj( obj_array[i], NULL );
02057                           while( isspace( *v_str ) ) v_str++;
02058                           if( *v_str == '\0' )
02059                             {
02060                               Tcl_SetResult( interp, "incomplete list of normals", TCL_STATIC );
02061                               Tcl_DecrRefCount( list );
02062                               return( TCL_ERROR );
02063                             }
02064                           bot->normals[i*3] = atof( v_str );
02065                           v_str = bu_next_token( v_str );
02066                           if( *v_str == '\0' )
02067                             {
02068                               Tcl_SetResult( interp, "incomplete list of normals", TCL_STATIC );
02069                               Tcl_DecrRefCount( list );
02070                               return( TCL_ERROR );
02071                             }
02072                           bot->normals[i*3+1] = atof( v_str );
02073                           v_str = bu_next_token( v_str );
02074                           if( *v_str == '\0' )
02075                             {
02076                               Tcl_SetResult( interp, "incomplete list of normals", TCL_STATIC );
02077                               Tcl_DecrRefCount( list );
02078                               return( TCL_ERROR );
02079                             }
02080                           bot->normals[i*3+2] = atof( v_str );
02081                           Tcl_DecrRefCount( obj_array[i] );
02082                         }
02083                       bot->bot_flags |= RT_BOT_HAS_SURFACE_NORMALS;
02084                     } else {
02085                       i = atoi( &argv[0][1] );
02086                       if( i < 0 || i >= bot->num_normals )
02087                         {
02088                           Tcl_SetResult( interp, "normal number out of range!!!", TCL_STATIC );
02089                           Tcl_DecrRefCount( list );
02090                           return( TCL_ERROR );
02091                         }
02092                       v_str = Tcl_GetStringFromObj( list, NULL );
02093                       while( isspace( *v_str ) ) v_str++;
02094 
02095                       bot->normals[i*3] = atof( v_str );
02096                       v_str = bu_next_token( v_str );
02097                       if( *v_str == '\0' )
02098                         {
02099                           Tcl_SetResult( interp, "incomplete normal", TCL_STATIC );
02100                           Tcl_DecrRefCount( list );
02101                           return( TCL_ERROR );
02102                         }
02103                       bot->normals[i*3+1] = atof( v_str );
02104                       v_str = bu_next_token( v_str );
02105                       if( *v_str == '\0' )
02106                         {
02107                           Tcl_SetResult( interp, "incomplete normal", TCL_STATIC );
02108                           Tcl_DecrRefCount( list );
02109                           return( TCL_ERROR );
02110                         }
02111                       bot->normals[i*3+2] = atof( v_str );
02112                     }
02113                 }
02114                 else if( argv[0][0] == 'V' )
02115                 {
02116                   char *v_str;
02117 
02118                   if( argv[0][1] == '\0' )
02119                     {
02120                       (void)Tcl_ListObjGetElements( interp, list, &len, &obj_array );
02121                       if( len <= 0 )
02122                         {
02123                           Tcl_SetResult( interp, "Must provide at least one vertex!!!", TCL_STATIC );
02124                           Tcl_DecrRefCount( list );
02125                           return( TCL_ERROR );
02126                         }
02127                       bot->num_vertices = len;
02128                       if( bot->vertices )
02129                               bu_free( (char *)bot->vertices, "BOT vertices" );
02130                       bot->vertices = (fastf_t *)bu_calloc( len*3, sizeof( fastf_t ), "BOT vertices" );
02131                       for( i=0 ; i<len ; i++ )
02132                         {
02133                           v_str = Tcl_GetStringFromObj( obj_array[i], NULL );
02134                           while( isspace( *v_str ) ) v_str++;
02135                           if( *v_str == '\0' )
02136                             {
02137                               Tcl_SetResult( interp, "incomplete list of vertices", TCL_STATIC );
02138                               Tcl_DecrRefCount( list );
02139                               return( TCL_ERROR );
02140                             }
02141                           bot->vertices[i*3] = atof( v_str );
02142                           v_str = bu_next_token( v_str );
02143                           if( *v_str == '\0' )
02144                             {
02145                               Tcl_SetResult( interp, "incomplete list of vertices", TCL_STATIC );
02146                               Tcl_DecrRefCount( list );
02147                               return( TCL_ERROR );
02148                             }
02149                           bot->vertices[i*3+1] = atof( v_str );
02150                           v_str = bu_next_token( v_str );
02151                           if( *v_str == '\0' )
02152                             {
02153                               Tcl_SetResult( interp, "incomplete list of vertices", TCL_STATIC );
02154                               Tcl_DecrRefCount( list );
02155                               return( TCL_ERROR );
02156                             }
02157                           bot->vertices[i*3+2] = atof( v_str );
02158                           Tcl_DecrRefCount( obj_array[i] );
02159                         }
02160                     }
02161                   else
02162                     {
02163                       i = atoi( &argv[0][1] );
02164                       if( i < 0 || i >= bot->num_vertices )
02165                         {
02166                           Tcl_SetResult( interp, "vertex number out of range!!!", TCL_STATIC );
02167                           Tcl_DecrRefCount( list );
02168                           return( TCL_ERROR );
02169                         }
02170                       v_str = Tcl_GetStringFromObj( list, NULL );
02171                       while( isspace( *v_str ) ) v_str++;
02172 
02173                       bot->vertices[i*3] = atof( v_str );
02174                       v_str = bu_next_token( v_str );
02175                       if( *v_str == '\0' )
02176                         {
02177                           Tcl_SetResult( interp, "incomplete vertex", TCL_STATIC );
02178                           Tcl_DecrRefCount( list );
02179                           return( TCL_ERROR );
02180                         }
02181                       bot->vertices[i*3+1] = atof( v_str );
02182                       v_str = bu_next_token( v_str );
02183                       if( *v_str == '\0' )
02184                         {
02185                           Tcl_SetResult( interp, "incomplete vertex", TCL_STATIC );
02186                           Tcl_DecrRefCount( list );
02187                           return( TCL_ERROR );
02188                         }
02189                       bot->vertices[i*3+2] = atof( v_str );
02190                     }
02191                 }
02192                 else if( argv[0][0] == 'F' )
02193                   {
02194                     char *f_str;
02195 
02196                     if( argv[0][1] == '\0' )
02197                       {
02198                         (void)Tcl_ListObjGetElements( interp, list, &len, &obj_array );
02199                         if( len <= 0 )
02200                           {
02201                             Tcl_SetResult( interp, "Must provide at least one face!!!", TCL_STATIC );
02202                             Tcl_DecrRefCount( list );
02203                             return( TCL_ERROR );
02204                           }
02205                         bot->num_faces = len;
02206                         if( bot->faces )
02207                                 bu_free( (char *)bot->faces, "BOT faces" );
02208                         bot->faces = (int *)bu_calloc( len*3, sizeof( int ), "BOT faces" );
02209                         if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
02210                                 if( !bot->face_normals ) {
02211                                         bot->face_normals = (int *)bu_malloc( bot->num_faces * 3 * sizeof( int ),
02212                                                                               "bot->face_normals" );
02213                                         bot->num_face_normals = bot->num_faces;
02214                                         for( i=0 ; i<bot->num_face_normals ; i++ ) {
02215                                                 VSETALL( &bot->face_normals[i*3], -1 );
02216                                         }
02217                                 } else if( bot->num_face_normals < bot->num_faces ) {
02218                                         bot->face_normals = (int *)bu_realloc( bot->face_normals,
02219                                                              bot->num_faces * 3 * sizeof( int ), "bot->face_normals" );
02220                                         for( i=bot->num_face_normals ; i<bot->num_faces ; i++ ) {
02221                                                 VSETALL( &bot->face_normals[i*3], -1 );
02222                                         }
02223                                         bot->num_face_normals = bot->num_faces;
02224                                 }
02225                         }
02226                         for( i=0 ; i<len ; i++ )
02227                           {
02228                             f_str = Tcl_GetStringFromObj( obj_array[i], NULL );
02229                             while( isspace( *f_str ) ) f_str++;
02230 
02231                             if( *f_str == '\0' )
02232                               {
02233                                 Tcl_SetResult( interp, "incomplete list of faces", TCL_STATIC );
02234                                 Tcl_DecrRefCount( list );
02235                                 return( TCL_ERROR );
02236                               }
02237                             bot->faces[i*3] = atoi( f_str );
02238                             f_str = bu_next_token( f_str );
02239                             if( *f_str == '\0' )
02240                               {
02241                                 Tcl_SetResult( interp, "incomplete list of faces", TCL_STATIC );
02242                                 Tcl_DecrRefCount( list );
02243                                 return( TCL_ERROR );
02244                               }
02245                             bot->faces[i*3+1] = atoi( f_str );
02246                             f_str = bu_next_token( f_str );
02247                             if( *f_str == '\0' )
02248                               {
02249                                 Tcl_SetResult( interp, "incomplete list of faces", TCL_STATIC );
02250                                 Tcl_DecrRefCount( list );
02251                                 return( TCL_ERROR );
02252                               }
02253                             bot->faces[i*3+2] = atoi( f_str );
02254                           }
02255                       }
02256                     else
02257                       {
02258                         i = atoi( &argv[0][1] );
02259                         if( i < 0 || i >= bot->num_faces )
02260                           {
02261                             Tcl_SetResult( interp, "face number out of range!!!", TCL_STATIC );
02262                             Tcl_DecrRefCount( list );
02263                             return( TCL_ERROR );
02264                           }
02265                         f_str = Tcl_GetStringFromObj( list, NULL );
02266                         while( isspace( *f_str ) ) f_str++;
02267                         bot->faces[i*3] = atoi( f_str );
02268                         f_str = bu_next_token( f_str );
02269                         if( *f_str == '\0' )
02270                           {
02271                             Tcl_SetResult( interp, "incomplete vertex", TCL_STATIC );
02272                             Tcl_DecrRefCount( list );
02273                             return( TCL_ERROR );
02274                           }
02275                         bot->faces[i*3+1] = atoi( f_str );
02276                         f_str = bu_next_token( f_str );
02277                         if( *f_str == '\0' )
02278                           {
02279                             Tcl_SetResult( interp, "incomplete vertex", TCL_STATIC );
02280                             Tcl_DecrRefCount( list );
02281                             return( TCL_ERROR );
02282                           }
02283                         bot->faces[i*3+2] = atoi( f_str );
02284                       }
02285                   }
02286                 else if( argv[0][0] ==  'T' )
02287                   {
02288                     char *t_str;
02289 
02290                     if( argv[0][1] == '\0' )
02291                       {
02292                         (void)Tcl_ListObjGetElements( interp, list, &len, &obj_array );
02293                         if( len <= 0 )
02294                           {
02295                             Tcl_SetResult( interp, "Must provide at least one thickness!!!", TCL_STATIC );
02296                             Tcl_DecrRefCount( list );
02297                             return( TCL_ERROR );
02298                           }
02299                         if( len > bot->num_faces )
02300                           {
02301                             Tcl_SetResult( interp, "Too many thicknesses (there are not that many faces)!!!", TCL_STATIC );
02302                             Tcl_DecrRefCount( list );
02303                             return( TCL_ERROR );
02304                           }
02305                         if( !bot->thickness ) {
02306                                 bot->thickness = (fastf_t *)bu_calloc( bot->num_faces, sizeof( fastf_t ),
02307                                                                        "bot->thickness" );
02308                         }
02309                         for( i=0 ; i<len ; i++ )
02310                           {
02311                             bot->thickness[i] = atof( Tcl_GetStringFromObj( obj_array[i], NULL ) );
02312                             Tcl_DecrRefCount( obj_array[i] );
02313                           }
02314                       }
02315                     else
02316                       {
02317                         i = atoi( &argv[0][1] );
02318                         if( i < 0 || i >= bot->num_faces )
02319                           {
02320                             Tcl_SetResult( interp, "face number out of range!!!", TCL_STATIC );
02321                             Tcl_DecrRefCount( list );
02322                             return( TCL_ERROR );
02323                           }
02324                         if( !bot->thickness ) {
02325                                 bot->thickness = (fastf_t *)bu_calloc( bot->num_faces, sizeof( fastf_t ),
02326                                                                        "bot->thickness" );
02327                         }
02328                         t_str = Tcl_GetStringFromObj( list, NULL );
02329                         bot->thickness[i] = atof( t_str );
02330                       }
02331                   }
02332                 else if( !strcmp( argv[0], "mode" ) )
02333                   {
02334                     char *m_str;
02335 
02336                     m_str = Tcl_GetStringFromObj( list, NULL );
02337                     if( isdigit( *m_str ) )
02338                       {
02339                         int mode;
02340 
02341                         mode = atoi( m_str );
02342                         if( mode < RT_BOT_SURFACE || mode > RT_BOT_PLATE_NOCOS )
02343                           {
02344                             Tcl_SetResult( interp, "unrecognized mode!!!", TCL_STATIC );
02345                             Tcl_DecrRefCount( list );
02346                             return( TCL_ERROR );
02347                           }
02348                         bot->mode = mode;
02349                       }
02350                     else
02351                       {
02352                         if( !strncmp( m_str, modes[RT_BOT_SURFACE], 4 ) )
02353                           bot->mode = RT_BOT_SURFACE;
02354                         else if( !strcmp( m_str, modes[RT_BOT_SOLID] ) )
02355                           bot->mode = RT_BOT_SOLID;
02356                         else if( !strcmp( m_str, modes[RT_BOT_PLATE] ) )
02357                           bot->mode = RT_BOT_PLATE;
02358                         else if( !strcmp( m_str, modes[RT_BOT_PLATE_NOCOS] ) )
02359                           bot->mode = RT_BOT_PLATE_NOCOS;
02360                         else
02361                           {
02362                             Tcl_SetResult( interp, "unrecognized mode!!!", TCL_STATIC );
02363                             Tcl_DecrRefCount( list );
02364                             return( TCL_ERROR );
02365                           }
02366                       }
02367                   }
02368                 else if( !strncmp( argv[0], "orient", 6 ) )
02369                   {
02370                     char *o_str;
02371 
02372                     o_str = Tcl_GetStringFromObj( list, NULL );
02373                     if( isdigit( *o_str ) )
02374                       {
02375                         int orientation;
02376 
02377                         orientation = atoi( o_str );
02378                         if( orientation < RT_BOT_UNORIENTED || orientation > RT_BOT_CW )
02379                           {
02380                             Tcl_SetResult( interp, "unrecognized orientation!!!", TCL_STATIC );
02381                             Tcl_DecrRefCount( list );
02382                             return( TCL_ERROR );
02383                           }
02384                         bot->orientation = orientation;
02385                       }
02386                     else
02387                       {
02388                         if( !strcmp( o_str, orientation[RT_BOT_UNORIENTED] ) )
02389                           bot->orientation = RT_BOT_UNORIENTED;
02390                         else if( !strcmp( o_str, orientation[RT_BOT_CCW] ) )
02391                           bot->orientation = RT_BOT_CCW;
02392                         else if( !strcmp( o_str, orientation[RT_BOT_CW] ) )
02393                           bot->orientation = RT_BOT_CW;
02394                         else
02395                           {
02396                             Tcl_SetResult( interp, "unrecognized orientation!!!", TCL_STATIC );
02397                             Tcl_DecrRefCount( list );
02398                             return( TCL_ERROR );
02399                           }
02400                       }
02401                   }
02402                 else if( !strcmp( argv[0], "flags" ) )
02403                   {
02404                           (void)Tcl_ListObjGetElements( interp, list, &len, &obj_array );
02405                           bot->bot_flags = 0;
02406                           for( i=0 ; i<len ; i++ ) {
02407                                   char *str;
02408 
02409                                   str = Tcl_GetStringFromObj( obj_array[i], NULL );
02410                                   if( !strcmp( str, "has_normals" ) ) {
02411                                           bot->bot_flags |= RT_BOT_HAS_SURFACE_NORMALS;
02412                                   } else if( !strcmp( str, "use_normals" ) ) {
02413                                           bot->bot_flags |= RT_BOT_USE_NORMALS;
02414                                   } else if( !strcmp( str, "use_floats" ) ) {
02415                                           bot->bot_flags |= RT_BOT_USE_FLOATS;
02416                                   } else {
02417                                           Tcl_SetResult( interp, "unrecognized flag (must be \"has_normals\", \"use_normals\", or \"use_floats\"!!!", TCL_STATIC );
02418                                           Tcl_DecrRefCount( list );
02419                                           return( TCL_ERROR );
02420                                   }
02421                           }
02422                   }
02423 
02424                 Tcl_DecrRefCount( list );
02425 
02426                 argc -= 2;
02427                 argv += 2;
02428         }
02429 
02430         if( bot->mode == RT_BOT_PLATE || bot->mode == RT_BOT_PLATE_NOCOS )
02431           {
02432             if( !bot->thickness )
02433               bot->thickness = (fastf_t *)bu_calloc( bot->num_faces, sizeof( fastf_t ), "BOT thickness" );
02434             if( !bot->face_mode )
02435               {
02436                 bot->face_mode = bu_bitv_new( bot->num_faces );
02437                 bu_bitv_clear( bot->face_mode );
02438               }
02439           }
02440         else
02441           {
02442             if( bot->thickness )
02443               {
02444                 bu_free( (char *)bot->thickness, "BOT thickness" );
02445                 bot->thickness = (fastf_t *)NULL;
02446               }
02447             if( bot->face_mode )
02448               {
02449                 bu_free( (char *)bot->face_mode, "BOT facemode" );
02450                 bot->face_mode = (bitv_t)NULL;
02451               }
02452           }
02453 
02454         return( TCL_OK );
02455 }
02456 
02457 int
02458 rt_bot_tclform( const struct rt_functab *ftp, Tcl_Interp *interp)
02459 {
02460         RT_CK_FUNCTAB(ftp);
02461 
02462         Tcl_AppendResult( interp,
02463                           "mode {%s} orient {%s} V { {%f %f %f} {%f %f %f} ...} F { {%d %d %d} {%d %d %d} ...} T { %f %f %f ... } fm %s", (char *)NULL );
02464 
02465         return TCL_OK;
02466 }
02467 
02468 /*************************************************************************
02469  *
02470  *  BoT support routines used by MGED, converters, etc.
02471  *
02472  *************************************************************************/
02473 
02474 /**     This routine adjusts the vertex pointers in each face so that
02475  *      pointers to duplicate vertices end up pointing to the same vertex.
02476  *      The unused vertices are removed.
02477  *      Returns the number of vertices fused.
02478  */
02479 int
02480 rt_bot_vertex_fuse( struct rt_bot_internal *bot )
02481 {
02482         int i,j,k;
02483         int count=0;
02484 
02485         RT_BOT_CK_MAGIC( bot );
02486 
02487         for( i=0 ; i<bot->num_vertices ; i++ )
02488         {
02489                 j = i + 1;
02490                 while( j < bot->num_vertices ) {
02491                         /* specifically not using tolerances here */
02492                         if( VEQUAL( &bot->vertices[i*3], &bot->vertices[j*3] ) )
02493                         {
02494                                 count++;
02495                                 bot->num_vertices--;
02496                                 for( k=j ; k<bot->num_vertices ; k++ )
02497                                         VMOVE( &bot->vertices[k*3] , &bot->vertices[(k+1)*3] );
02498                                 for( k=0 ; k<bot->num_faces*3 ; k++ )
02499                                 {
02500                                         if( bot->faces[k] == j )
02501                                         {
02502                                                 bot->faces[k] = i;
02503                                         }
02504                                         else if ( bot->faces[k] > j )
02505                                                 bot->faces[k]--;
02506                                 }
02507                         } else {
02508                                 j++;
02509                         }
02510                 }
02511         }
02512 
02513         return( count );
02514 }
02515 
02516 int
02517 rt_bot_same_orientation( const int *a, const int *b )
02518 {
02519         int i;
02520 
02521         for( i=0 ; i<3 ; i++ )
02522         {
02523                 if( a[0] == b[i] )
02524                 {
02525                         i++;
02526                         if( i == 3 )
02527                                 i = 0;
02528                         if( a[1] == b[i] )
02529                                 return( 1 );
02530                         else
02531                                 return( 0 );
02532                 }
02533         }
02534 
02535         return( 0 );
02536 }
02537 
02538 int
02539 rt_bot_face_fuse( struct rt_bot_internal *bot )
02540 {
02541         int num_faces;
02542         int i,j,k,l;
02543         int count=0;
02544 
02545         RT_BOT_CK_MAGIC( bot );
02546 
02547         num_faces = bot->num_faces;
02548         for( i=0 ; i<num_faces ; i++ )
02549         {
02550                 j = i+1;
02551                 while( j<num_faces )
02552                 {
02553                         /* each pass through this loop either increments j or decrements num_faces */
02554                         int match=0;
02555                         int elim;
02556 
02557                         for( k=i*3 ; k<(i+1)*3 ; k++ )
02558                         {
02559                                 for( l=j*3 ; l<(j+1)*3 ; l++ )
02560                                 {
02561                                         if( bot->faces[k] == bot->faces[l] )
02562                                         {
02563                                                 match++;
02564                                                 break;
02565                                         }
02566                                 }
02567                         }
02568 
02569                         if( match != 3 )
02570                         {
02571                                 j++;
02572                                 continue;
02573                         }
02574 
02575                         /* these two faces have the same vertices */
02576                         elim = -1;
02577                         switch( bot->mode )
02578                         {
02579                                 case RT_BOT_PLATE:
02580                                 case RT_BOT_PLATE_NOCOS:
02581                                         /* check the face thickness and face mode */
02582                                         if( bot->thickness[i] != bot->thickness[j] ||
02583                                             (BU_BITTEST( bot->face_mode, i )?1:0) != (BU_BITTEST( bot->face_mode, j )?1:0) )
02584                                                         break;
02585                                 case RT_BOT_SOLID:
02586                                 case RT_BOT_SURFACE:
02587                                         if( bot->orientation == RT_BOT_UNORIENTED )
02588                                         {
02589                                                 /* faces are identical, so eliminate one */
02590                                                 elim = j;
02591                                         }
02592                                         else
02593                                         {
02594                                                 /* need to check orientation */
02595                                                 if( rt_bot_same_orientation( &bot->faces[i*3], &bot->faces[j*3] ) )
02596                                                         elim = j;
02597                                         }
02598                                         break;
02599                                 default:
02600                                         bu_bomb( "bot_face_condense: Unrecognized BOT mode!!!\n" );
02601                                         break;
02602                         }
02603 
02604                         if( elim < 0 )
02605                         {
02606                                 j++;
02607                                 continue;
02608                         }
02609 
02610                         /* we are eliminating face number "elim" */
02611                         for( l=elim ; l< num_faces-1 ; l++ )
02612                                 VMOVE( &bot->faces[l*3], &bot->faces[(l+1)*3] )
02613                         if( bot->mode == RT_BOT_PLATE || bot->mode == RT_BOT_PLATE_NOCOS )
02614                         {
02615                                 for( l=elim ; l<num_faces-1 ; l++ )
02616                                 {
02617                                         bot->thickness[l] = bot->thickness[l+1];
02618                                         if( BU_BITTEST( bot->face_mode, l+1 ) )
02619                                                 BU_BITSET( bot->face_mode, l );
02620                                         else
02621                                                 BU_BITCLR( bot->face_mode, l );
02622                                 }
02623                         }
02624                         num_faces--;
02625                 }
02626         }
02627 
02628         count = bot->num_faces - num_faces;
02629 
02630         if( count )
02631         {
02632                 bot->num_faces = num_faces;
02633                 bot->faces = (int *)bu_realloc( bot->faces, num_faces*3*sizeof( int ), "BOT faces realloc" );
02634                 if( bot->mode == RT_BOT_PLATE || bot->mode == RT_BOT_PLATE_NOCOS )
02635                 {
02636                         struct bu_bitv *new_mode;
02637 
02638                         bot->thickness = bu_realloc( bot->thickness, num_faces*sizeof( fastf_t ), "BOT thickness realloc" );
02639                         new_mode = bu_bitv_new( num_faces );
02640                         bu_bitv_clear( new_mode );
02641                         for( l=0 ; l<num_faces ; l++ )
02642                         {
02643                                 if( BU_BITTEST( bot->face_mode, l ) )
02644                                         BU_BITSET( new_mode, l );
02645                         }
02646                         bu_free( (char *)bot->face_mode, "BOT face_mode" );
02647                         bot->face_mode = new_mode;
02648                 }
02649         }
02650 
02651         return( count );
02652 }
02653 
02654 /**
02655  *
02656  *
02657  *  Get rid of unused verticies
02658  */
02659 int
02660 rt_bot_condense( struct rt_bot_internal *bot )
02661 {
02662         int i,j,k;
02663         int num_verts;
02664         int dead_verts=0;
02665         int *verts;
02666 
02667         RT_BOT_CK_MAGIC( bot );
02668 
02669         num_verts = bot->num_vertices;
02670         verts = (int *)bu_calloc( num_verts, sizeof( int ), "VERTEX LIST" );
02671 
02672         /* walk the list of verticies, and mark each one if it is used */
02673 
02674         for( i=0 ; i<bot->num_faces*3 ; i++ )
02675         {
02676                 j = bot->faces[i];
02677                 if( j >= num_verts || j < 0 )
02678                 {
02679                         bu_log( "Illegal vertex number %d, should be 0 through %d\n", j, num_verts-1 );
02680                         bu_bomb( "Illegal vertex number\n" );
02681                 }
02682                 verts[j] = 1;
02683         }
02684 
02685         /* Walk the list of verticies, eliminate each unused vertex by
02686          * copying the rest of the array downwards
02687          */
02688         i = 0;
02689         while( i < num_verts-dead_verts )
02690         {
02691                 while( !verts[i] && i < num_verts-dead_verts )
02692                 {
02693                         dead_verts++;
02694                         for( j=i ; j<num_verts-dead_verts ; j++ )
02695                         {
02696                                 k = j+1;
02697                                 VMOVE( &bot->vertices[j*3], &bot->vertices[k*3] );
02698                                 verts[j] = verts[k];
02699                         }
02700                         for( j=0 ; j<bot->num_faces*3 ; j++ )
02701                         {
02702                                 if( bot->faces[j] >= i )
02703                                         bot->faces[j]--;
02704                         }
02705                 }
02706                 i++;
02707         }
02708 
02709         if( !dead_verts )
02710                 return( 0 );
02711 
02712         /* Reallocate the vertex array (which should free the space
02713          * we are no longer using)
02714          */
02715         bot->num_vertices -= dead_verts;
02716         bot->vertices = (fastf_t *)bu_realloc( bot->vertices, bot->num_vertices*3*sizeof( fastf_t ), "bot verts realloc" );
02717 
02718         return( dead_verts );
02719 }
02720 
02721 int
02722 find_closest_face( fastf_t **centers, int *piece, int *old_faces, int num_faces, fastf_t *vertices )
02723 {
02724         pointp_t v0, v1, v2;
02725         point_t center;
02726         int i;
02727         fastf_t one_third = 1.0/3.0;
02728         fastf_t min_dist;
02729         int min_face=-1;
02730 
02731         if( (*centers) == NULL ) {
02732                 int count_centers=0;
02733 
02734                 /* need to build the centers array */
02735                 (*centers) = (fastf_t *)bu_malloc( num_faces * 3 * sizeof( fastf_t ), "center" );
02736                 for( i=0 ; i<num_faces ; i++ ) {
02737                         if( old_faces[i*3] < 0 ) {
02738                                 continue;
02739                         }
02740                         count_centers++;
02741                         v0 = &vertices[old_faces[i*3]*3];
02742                         v1 = &vertices[old_faces[i*3+1]*3];
02743                         v2 = &vertices[old_faces[i*3+2]*3];
02744                         VADD3( center, v0 , v1, v2 );
02745                         VSCALE( &(*centers)[i*3], center, one_third );
02746                 }
02747         }
02748 
02749         v0 = &vertices[piece[0]*3];
02750         v1 = &vertices[piece[1]*3];
02751         v2 = &vertices[piece[2]*3];
02752 
02753         VADD3( center, v0, v1, v2 );
02754         VSCALE( center, center, one_third );
02755 
02756         min_dist = MAX_FASTF;
02757 
02758         for( i=0 ; i<num_faces ; i++ ) {
02759                 vect_t diff;
02760                 fastf_t dist;
02761 
02762                 if( old_faces[i*3] < 0 ) {
02763                         continue;
02764                 }
02765 
02766                 VSUB2( diff, center, &(*centers)[i*3] );
02767                 dist = MAGSQ( diff );
02768                 if( dist < min_dist ) {
02769                         min_dist = dist;
02770                         min_face = i;
02771                 }
02772         }
02773 
02774         return( min_face );
02775 }
02776 
02777 void
02778 Add_unique_verts( int *piece_verts, int *v )
02779 {
02780         int i, j;
02781         int *ptr=v;
02782 
02783         for( j=0 ; j<3 ; j++ ) {
02784                 i = -1;
02785                 while( piece_verts[++i] > -1 ) {
02786                         if( piece_verts[i] == (*ptr) ) {
02787                                 break;
02788                         }
02789                 }
02790                 if( piece_verts[i] == -1 ) {
02791                         piece_verts[i] = (*ptr);
02792                 }
02793                 ptr++;
02794         }
02795 }
02796 
02797 
02798 /**     This routine sorts the faces of the BOT such that when they are taken
02799 in groups of "tris_per_piece",
02800  *      each group (piece) will consist of adjacent faces
02801  */
02802 int
02803 rt_bot_sort_faces( struct rt_bot_internal *bot, int tris_per_piece )
02804 {
02805         int *new_faces;         /* the sorted list of faces to be attached to the BOT at the end of this routine */
02806         int new_face_count=0;   /* the current number of faces in the "new_faces" list */
02807         int *new_norms = (int*)NULL;            /* the sorted list of vertex normals corrsponding to the "new_faces" list */
02808         int *old_faces;         /* a copy of the original face list from the BOT */
02809         int *piece;             /* a small face list, for just the faces in the current piece */
02810         int *piece_norms = (int*)NULL;  /* vertex normals for faces in the current piece */
02811         int *piece_verts;       /* a list of vertices in the current piece (each vertex appears only once) */
02812         unsigned char *vert_count;      /* an array used to hold the number of piece vertices that appear in each BOT face */
02813         int faces_left;         /* the number of faces in the "old_faces" array that have not yet been used */
02814         int piece_len;          /* the current number of faces in the piece */
02815         int max_verts;          /* the maximum number of piece_verts found in a single unused face */
02816         fastf_t *centers;       /* triangle centers, used when all else fails */
02817         int i, j;
02818 
02819         RT_BOT_CK_MAGIC( bot );
02820 
02821         /* allocate memory for all the data */
02822         new_faces = (int *)bu_calloc( bot->num_faces * 3, sizeof( int ), "new_faces" );
02823         old_faces = (int *)bu_calloc( bot->num_faces * 3, sizeof( int ), "old_faces" );
02824         piece = (int *)bu_calloc( tris_per_piece * 3, sizeof( int ), "piece" );
02825         vert_count = (unsigned char *)bu_malloc( bot->num_faces * sizeof( unsigned char ), "vert_count" );
02826         piece_verts = (int *)bu_malloc( (tris_per_piece * 3 + 1) * sizeof( int ), "piece_verts" );
02827         centers = (fastf_t *)NULL;
02828 
02829         if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
02830                 new_norms = (int *)bu_calloc( bot->num_faces * 3, sizeof( int ), "new_norms" );
02831                 piece_norms = (int *)bu_calloc( tris_per_piece * 3, sizeof( int ), "piece_norms" );
02832         }
02833 
02834         /* make a copy of the faces list, this list will be modified during the process */
02835         for( i=0 ; i<bot->num_faces*3 ; i++) {
02836                 old_faces[i] = bot->faces[i];
02837         }
02838 
02839         /* process until we have sorted all the faces */
02840         faces_left = bot->num_faces;
02841         while( faces_left ) {
02842                 int cur_face;
02843                 int done_with_piece;
02844 
02845                 /* initialize piece_verts */
02846                 for( i=0 ; i<tris_per_piece*3+1 ; i++ ) {
02847                         piece_verts[i] = -1;
02848                 }
02849 
02850                 /* choose first unused face on the list */
02851                 cur_face = 0;
02852                 while( cur_face < bot->num_faces && old_faces[cur_face*3] < 0 ) {
02853                         cur_face++;
02854                 }
02855 
02856                 if( cur_face >= bot->num_faces ) {
02857                         /* all faces used, we must be done */
02858                         break;
02859                 }
02860 
02861                 /* copy that face to start the piece */
02862                 VMOVE( piece, &old_faces[cur_face*3] );
02863                 if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
02864                         VMOVE( piece_norms, &bot->face_normals[cur_face*3] );
02865                 }
02866 
02867                 /* also copy it to the piece vertex list */
02868                 VMOVE( piece_verts, piece );
02869 
02870                 /* mark this face as used */
02871                 VSETALL( &old_faces[cur_face*3], -1 );
02872 
02873                 /* update counts */
02874                 piece_len = 1;
02875                 faces_left--;
02876 
02877                 if( faces_left == 0 ) {
02878                         /* handle the case where the first face in a piece is the only face left */
02879                         for( j=0 ; j<piece_len ; j++ ) {
02880                                 VMOVE( &new_faces[new_face_count*3], &piece[j*3] );
02881                                 if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
02882                                         VMOVE( &new_norms[new_face_count*3], &piece_norms[j*3] );
02883                                 }
02884                                 new_face_count++;
02885                         }
02886                         piece_len = 0;
02887                         max_verts = 0;
02888 
02889                         /* set flag to skip the loop below */
02890                         done_with_piece = 1;
02891                 } else {
02892                         done_with_piece = 0;
02893                 }
02894 
02895                 while( !done_with_piece ) {
02896                         int max_verts_min;
02897 
02898                         /* count the number of times vertices from the current piece appear in the remaining faces */
02899                         (void)memset( vert_count, '\0', bot->num_faces );
02900                         max_verts = 0;
02901                         for( i=0 ; i<bot->num_faces ; i++) {
02902                                 int vert_num;
02903                                 int v0, v1, v2;
02904 
02905                                 vert_num = i*3;
02906                                 if( old_faces[vert_num] < 0 ) {
02907                                         continue;
02908                                 }
02909                                 v0 = old_faces[vert_num];
02910                                 v1 = old_faces[vert_num+1];
02911                                 v2 = old_faces[vert_num+2];
02912 
02913                                 j = -1;
02914                                 while( piece_verts[ ++j ] > -1 ) {
02915                                         if( v0 == piece_verts[j] ||
02916                                             v1 == piece_verts[j] ||
02917                                             v2 == piece_verts[j] ) {
02918                                                 vert_count[i]++;
02919                                         }
02920                                 }
02921 
02922                                 if( vert_count[i] > 1 ) {
02923                                         /* add this face to the piece */
02924                                         VMOVE( &piece[piece_len*3], &old_faces[i*3] );
02925                                         if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
02926                                                 VMOVE( &piece_norms[piece_len*3], &bot->face_normals[i*3] );
02927                                         }
02928 
02929                                         /* Add its vertices to the list of piece vertices */
02930                                         Add_unique_verts( piece_verts, &old_faces[i*3] );
02931 
02932                                         /* mark this face as used */
02933                                         VSETALL( &old_faces[i*3], -1 );
02934 
02935                                         /* update counts */
02936                                         piece_len++;
02937                                         faces_left--;
02938                                         vert_count[i] = 0;
02939 
02940                                         /* check if this piece is done */
02941                                         if( piece_len == tris_per_piece || faces_left == 0 ) {
02942                                                 /* copy this piece to the "new_faces" list */
02943                                                 for( j=0 ; j<piece_len ; j++ ) {
02944                                                         VMOVE( &new_faces[new_face_count*3], &piece[j*3] );
02945                                                         if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
02946                                                                 VMOVE( &new_norms[new_face_count*3], &piece_norms[j*3] );
02947                                                         }
02948                                                         new_face_count++;
02949                                                 }
02950                                                 piece_len = 0;
02951                                                 max_verts = 0;
02952                                                 done_with_piece = 1;
02953                                                 break;
02954                                         }
02955                                 }
02956                                 if( vert_count[i] > max_verts ) {
02957                                         max_verts = vert_count[i];
02958                                 }
02959                         }
02960 
02961                         /* set this variable to 2, means look for faces with at least common edges */
02962                         max_verts_min = 2;
02963 
02964                         if( max_verts == 0 && !done_with_piece ) {
02965                                 /* none of the remaining faces has any vertices in common with the current piece */
02966                                 int face_to_add;
02967 
02968                                 /* resort to using triangle centers
02969                                  * find the closest face to the first face in the piece
02970                                  */
02971                                 face_to_add = find_closest_face( &centers, piece, old_faces, bot->num_faces, bot->vertices );
02972 
02973                                 /* Add this face to the current piece */
02974                                 VMOVE( &piece[piece_len*3], &old_faces[face_to_add*3] );
02975                                 if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
02976                                         VMOVE( &piece_norms[piece_len*3], &bot->face_normals[face_to_add*3] );
02977                                 }
02978 
02979                                 /* Add its vertices to the list of piece vertices */
02980                                 Add_unique_verts( piece_verts, &old_faces[face_to_add*3] );
02981 
02982                                 /* mark this face as used */
02983                                 VSETALL( &old_faces[face_to_add*3], -1 );
02984 
02985                                 /* update counts */
02986                                 piece_len++;
02987                                 faces_left--;
02988 
02989                                 /* check if this piece is done */
02990                                 if( piece_len == tris_per_piece || faces_left == 0 ) {
02991                                         /* copy this piece to the "new_faces" list */
02992                                         for( j=0 ; j<piece_len ; j++ ) {
02993                                                 VMOVE( &new_faces[new_face_count*3], &piece[j*3] );
02994                                                 if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
02995                                                         VMOVE( &new_norms[new_face_count*3], &piece_norms[j*3] );
02996                                                 }
02997                                                 new_face_count++;
02998                                         }
02999                                         piece_len = 0;
03000                                         max_verts = 0;
03001                                         done_with_piece = 1;
03002                                 }
03003                         } else if( max_verts == 1 && !done_with_piece ) {
03004                                 /* the best we can find is common vertices */
03005                                 max_verts_min = 1;
03006                         } else if( !done_with_piece ) {
03007                                 /* there are some common edges, so ignore simple shared vertices */
03008                                 max_verts_min = 2;
03009                         }
03010 
03011                         /* now add the faces with the highest counts to the current piece
03012                          * do this in a loop that starts by only accepting the faces with the
03013                          * most vertices in common with the current piece
03014                          */
03015                         while( max_verts >= max_verts_min && !done_with_piece ) {
03016                                 /* check every face */
03017                                 for( i=0 ; i<bot->num_faces ; i++ ) {
03018                                         /* if this face has enough vertices in common with the piece,
03019                                          * add it to the piece
03020                                          */
03021                                         if( vert_count[i] == max_verts ) {
03022                                                 VMOVE( &piece[piece_len*3], &old_faces[i*3] );
03023                                                 if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
03024                                                         VMOVE( &piece_norms[piece_len*3], &bot->face_normals[i*3] );
03025                                                 }
03026                                                 Add_unique_verts( piece_verts, &old_faces[i*3] );
03027                                                 VSETALL( &old_faces[i*3], -1 );
03028 
03029                                                 piece_len++;
03030                                                 faces_left--;
03031 
03032                                                 /* Check if we are done */
03033                                                 if( piece_len == tris_per_piece || faces_left == 0 ) {
03034                                                         /* copy this piece to the "new_faces" list */
03035                                                         for( j=0 ; j<piece_len ; j++ ) {
03036                                                                 VMOVE( &new_faces[new_face_count*3], &piece[j*3] );
03037                                                                 if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
03038                                                                         VMOVE( &new_norms[new_face_count*3], &piece_norms[j*3] );
03039                                                                 }
03040                                                                 new_face_count++;
03041                                                         }
03042                                                         piece_len = 0;
03043                                                         max_verts = 0;
03044                                                         done_with_piece = 1;
03045                                                         break;
03046                                                 }
03047                                         }
03048                                 }
03049                                 max_verts--;
03050                         }
03051                 }
03052         }
03053 
03054         bu_free( (char *)old_faces, "old_faces" );
03055         bu_free( (char *)piece, "piece" );
03056         bu_free( (char *)vert_count, "vert_count" );
03057         bu_free( (char *)piece_verts, "piece_verts" );
03058         if( centers ) {
03059                 bu_free( (char *)centers, "centers" );
03060         }
03061 
03062         /* do some checking on the "new_faces" */
03063         if( new_face_count != bot->num_faces ) {
03064                 bu_log( "new_face_count = %d, should be %d\n", new_face_count, bot->num_faces );
03065                 bu_free( (char *)new_faces, "new_faces" );
03066                 return( 1 );
03067         }
03068 
03069         bu_free( (char *)bot->faces, "bot->faces" );
03070 
03071         bot->faces = new_faces;
03072 
03073         if( bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS ) {
03074                 bu_free( (char *)piece_norms, "piece_norms" );
03075                 bu_free( (char *)bot->face_normals, "bot->face_normals" );
03076                 bot->face_normals = new_norms;
03077         }
03078 
03079         return( 0 );
03080 }
03081 
03082 struct bot_edge {
03083   int v;
03084   int use_count;
03085   struct bot_edge *next;
03086 };
03087 
03088 static void
03089 delete_edge( int v1, int v2, struct bot_edge **edges )
03090 {
03091         struct bot_edge *edg, *prev=NULL;
03092 
03093         if( v1 < v2 ) {
03094                 edg = edges[v1];
03095                 while( edg ) {
03096                         if( edg->v == v2 ) {
03097                                 edg->use_count--;
03098                                 if( edg->use_count < 1 ) {
03099                                         if( prev ) {
03100                                                 prev->next = edg->next;
03101                                         } else {
03102                                                 edges[v1] = edg->next;
03103                                         }
03104                                         edg->v = -1;
03105                                         edg->next = NULL;
03106                                         bu_free( (char *)edg, "bot_edge" );
03107                                         return;
03108                                 }
03109                         }
03110                         prev = edg;
03111                         edg = edg->next;
03112                 }
03113         } else {
03114                 edg = edges[v2];
03115                 while( edg ) {
03116                         if( edg->v == v1 ) {
03117                                 edg->use_count--;
03118                                 if( edg->use_count < 1 ) {
03119                                         if( prev ) {
03120                                                 prev->next = edg->next;
03121                                         } else {
03122                                                 edges[v2] = edg->next;
03123                                         }
03124                                         edg->v = -1;
03125                                         edg->next = NULL;
03126                                         bu_free( (char *)edg, "bot_edge" );
03127                                         return;
03128                                 }
03129                         }
03130                         prev = edg;
03131                         edg = edg->next;
03132                 }
03133         }
03134 }
03135 
03136 /**
03137  *                      D E C I M A T E _ E D G E
03138  *
03139  *      Routine to perform the actual edge decimation step
03140  *      The edge from v1 to v2 is eliminated by moving v1 to v2.
03141  *      Faces that used this edge are eliminated.
03142  *      Faces that used v1 will have that reference changed to v2.
03143  */
03144 
03145 static int
03146 decimate_edge( int v1, int v2, struct bot_edge **edges, int num_edges, int *faces, int num_faces, int face_del1, int face_del2 )
03147 {
03148         int i;
03149         struct bot_edge *edg;
03150 
03151         /* first eliminate all the edges of the two deleted faces from the edge list */
03152         delete_edge( faces[face_del1*3 + 0], faces[face_del1*3 + 1], edges );
03153         delete_edge( faces[face_del1*3 + 1], faces[face_del1*3 + 2], edges );
03154         delete_edge( faces[face_del1*3 + 2], faces[face_del1*3 + 0], edges );
03155         delete_edge( faces[face_del2*3 + 0], faces[face_del2*3 + 1], edges );
03156         delete_edge( faces[face_del2*3 + 1], faces[face_del2*3 + 2], edges );
03157         delete_edge( faces[face_del2*3 + 2], faces[face_del2*3 + 0], edges );
03158 
03159         /* do the decimation */
03160         for( i=0 ; i<3 ; i++ ) {
03161                 faces[face_del1*3 + i] = -1;
03162                 faces[face_del2*3 + i] = -1;
03163         }
03164         for( i=0 ; i<num_faces*3 ; i++ ) {
03165                 if( faces[i] == v1 ) {
03166                         faces[i] = v2;
03167                 }
03168         }
03169 
03170         /* update the edge list */
03171         /* now move all the remaining edges at edges[v1] to somewhere else */
03172         edg = edges[v1];
03173         while( edg ) {
03174                 struct bot_edge *ptr;
03175                 struct bot_edge *next;
03176 
03177                 next = edg->next;
03178 
03179                 if( edg->v < v2 ) {
03180                         ptr = edges[edg->v];
03181                         while( ptr ) {
03182                                 if( ptr->v == v2 ) {
03183                                         ptr->use_count++;
03184                                         edg->v = -1;
03185                                         edg->next = NULL;
03186                                         bu_free( (char *)edg, "bot edge" );
03187                                         break;
03188                                 }
03189                                 ptr = ptr->next;
03190                         }
03191                         if( !ptr ) {
03192                                 edg->next = edges[edg->v];
03193                                 edges[edg->v] = edg;
03194                                 edg->v = v2;
03195                         }
03196                 } else {
03197                         ptr = edges[v2];
03198                         while( ptr ) {
03199                                 if( ptr->v == edg->v ) {
03200                                         ptr->use_count++;
03201                                         edg->v = -1;
03202                                         edg->next = NULL;
03203                                         bu_free( (char *)edg, "bot edge" );
03204                                         break;
03205                                 }
03206                                 ptr = ptr->next;
03207                         }
03208                         if( !ptr ) {
03209                                 edg->next = edges[v2];
03210                                 edges[v2] = edg;
03211                         }
03212                 }
03213 
03214                 edg = next;
03215         }
03216         edges[v1] = NULL;
03217 
03218         /* now change all remaining v1 references to v2 */
03219         for( i=0 ; i<num_edges ; i++ ) {
03220                 struct bot_edge *next, *prev, *ptr;
03221 
03222                 prev = NULL;
03223                 edg = edges[i];
03224                 /* look at edges starting from vertex #i */
03225                 while( edg ) {
03226                         next = edg->next;
03227 
03228                         if( edg->v == v1 ) {
03229                                 /* this one is affected */
03230                                 edg->v = v2;    /* change v1 to v2 */
03231                                 if( v2 < i ) {
03232                                         /* disconnect this edge from list #i */
03233                                         if( prev ) {
03234                                                 prev->next = next;
03235                                         } else {
03236                                                 edges[i] = next;
03237                                         }
03238 
03239                                         /* this edge must move to the "v2" list */
03240                                         ptr = edges[v2];
03241                                         while( ptr ) {
03242                                                 if( ptr->v == i ) {
03243                                                         /* found another occurence of this edge
03244                                                          * increment use count
03245                                                          */
03246                                                         ptr->use_count++;
03247 
03248                                                         /* delete the original */
03249                                                         edg->v = -1;
03250                                                         edg->next = NULL;
03251                                                         bu_free( (char *)edg, "bot edge" );
03252                                                         break;
03253                                                 }
03254                                                 ptr = ptr->next;
03255                                         }
03256                                         if( !ptr ) {
03257                                                 /* did not find another occurence, add to list */
03258                                                 edg->next = edges[v2];
03259                                                 edges[v2] = edg;
03260                                         }
03261                                         edg = next;
03262                                 } else {
03263                                         /* look for other occurences of this edge in this list
03264                                          * if found, just increment use count
03265                                          */
03266                                         ptr = edges[i];
03267                                         while( ptr ) {
03268                                                 if( ptr->v == v2 && ptr != edg ) {
03269                                                         /* found another occurence */
03270                                                         /* increment use count */
03271                                                         ptr->use_count++;
03272 
03273                                                         /* disconnect original from list */
03274                                                         if( prev ) {
03275                                                                 prev->next = next;
03276                                                         } else {
03277                                                                 edges[i] = next;
03278                                                         }
03279 
03280                                                         /* free it */
03281                                                         edg->v = -1;
03282                                                         edg->next = NULL;
03283                                                         bu_free( (char *)edg, "bot edge" );
03284 
03285                                                         break;
03286                                                 }
03287                                                 ptr = ptr->next;
03288                                         }
03289                                         if( !ptr ) {
03290                                                 prev = edg;
03291                                         }
03292                                         edg = next;
03293                                 }
03294                         } else {
03295                                 /* unaffected edge, just continue */
03296                                 edg = next;
03297                         }
03298                 }
03299         }
03300 
03301         return 2;
03302 }
03303 
03304 /**
03305  *                              E D G E _ C A N _ B E _ D E C I M A T E D
03306  *
03307  *      Routine to determine if the specified edge can be eliminated within the given constraints
03308  *              "faces" is the current working version of the BOT face list.
03309  *              "v1" and "v2" are the indices into the BOT vertex list, they define the edge.
03310  *              "max_chord_error" is the maximum distance allowed between the old surface and new.
03311  *              "max_normal_error" is actually the minimum dot product allowed between old and new
03312  *                      surface normals (cosine).
03313  *              "min_edge_length_sq" is the square of the minimum allowed edge length.
03314  *              any constraint value of -1 means ignore this constraint
03315  *      returns 1 if edge can be eliminated without breaking conatraints, 0 otherwise
03316  */
03317 
03318 /* for simplicity, only consider vertices that are shared with less than MAX_AFFECTED_FACES */
03319 #define MAX_AFFECTED_FACES      128
03320 
03321 static int
03322 edge_can_be_decimated( struct rt_bot_internal *bot,
03323                        int *faces,
03324                        struct bot_edge **edges,
03325                        int v1,
03326                        int v2,
03327                        int *face_del1,
03328                        int *face_del2,
03329                        fastf_t max_chord_error,
03330                        fastf_t max_normal_error,
03331                        fastf_t min_edge_length_sq )
03332 {
03333         int i, j, k;
03334         int num_faces=bot->num_faces;
03335         int num_edges=bot->num_vertices;
03336         int count, v1_count;
03337         int affected_count=0;
03338         vect_t v01, v02, v12;
03339         fastf_t *vertices=bot->vertices;
03340         int faces_affected[MAX_AFFECTED_FACES];
03341 
03342         if( v1 < 0 || v2 < 0 ) {
03343                 return 0;
03344         }
03345 
03346         /* find faces to be deleted or affected */
03347         *face_del1 = -1;
03348         *face_del2 = -1;
03349         for( i=0 ; i<num_faces*3 ; i += 3 ) {
03350                 count = 0;
03351                 v1_count = 0;
03352                 for( j=0 ; j<3 ; j++ ) {
03353                         k = i + j;
03354                         if( faces[k] == v1 ) {
03355                                 /* found a reference to v1, count it */
03356                                 count++;
03357                                 v1_count++;
03358                         } else if( faces[k] == v2 ) {
03359                                 /* found a reference to v2, count it */
03360                                 count++;
03361                         }
03362                 }
03363                 if( count > 1 ) {
03364                         /* this face will get deleted */
03365                         if( *face_del1 > -1 ) {
03366                                 *face_del2 = i/3;
03367                         } else {
03368                                 *face_del1 = i/3;
03369                         }
03370                 } else if( v1_count ) {
03371                         /* this face will be affected */
03372                         faces_affected[affected_count] = i;
03373                         affected_count++;
03374                         if( affected_count >= MAX_AFFECTED_FACES ) {
03375                                 return 0;
03376                         }
03377                 }
03378         }
03379 
03380         /* if only one face will be deleted, do not decimate
03381          * this may be a free edge
03382          */
03383         if( *face_del2 < 0 ) {
03384           return 0;
03385         }
03386 
03387         /* another  easy test to avoid moving free edges */
03388         if( affected_count < 1 ) {
03389                 return 0;
03390         }
03391 
03392         /* for BOTs that are expected to have free edges, do a rigorous check for free edges */
03393         if( bot->mode == RT_BOT_PLATE || bot->mode == RT_BOT_SURFACE ) {
03394                 struct bot_edge *edg;
03395 
03396                 /* check if vertex v1 is on a free edge */
03397                 for( i=0 ; i<num_edges ; i++ ) {
03398                         edg = edges[i];
03399                         while( edg ) {
03400                                 if( (i == v1 || edg->v == v1) && edg->use_count < 2 ) {
03401                                         return 0;
03402                                 }
03403                                 edg = edg->next;
03404                         }
03405                 }
03406         }
03407 
03408         /* calculate edge vector */
03409         VSUB2( v12, &vertices[v1*3], &vertices[v2*3] );
03410 
03411         if( min_edge_length_sq > SMALL_FASTF ) {
03412                 if( MAGSQ( v12 ) > min_edge_length_sq ) {
03413                         return 0;
03414                 }
03415         }
03416 
03417         if( max_chord_error > -1.0 || max_normal_error > -1.0 ) {
03418                 /* check if surface is within max_chord_error of vertex to be eliminated */
03419                 /* loop through all affected faces */
03420                 for( i=0 ; i<affected_count ; i++ ) {
03421                         fastf_t dist;
03422                         fastf_t dot;
03423                         plane_t pla, plb;
03424                         int va, vb, vc;
03425 
03426                         /* calculate plane of this face before and after adjustment
03427                          *  if the normal changes too much, do not decimate
03428                          */
03429 
03430                         /* first calculate original face normal (use original BOT face list) */
03431                         va = bot->faces[faces_affected[i]];
03432                         vb = bot->faces[faces_affected[i]+1];
03433                         vc = bot->faces[faces_affected[i]+2];
03434                         VSUB2( v01, &vertices[vb*3], &vertices[va*3] );
03435                         VSUB2( v02, &vertices[vc*3], &vertices[va*3] );
03436                         VCROSS( plb, v01, v02 );
03437                         VUNITIZE( plb );
03438                         plb[3] = VDOT( &vertices[va*3], plb );
03439 
03440                         /* do the same using the working face list */
03441                         va = faces[faces_affected[i]];
03442                         vb = faces[faces_affected[i]+1];
03443                         vc = faces[faces_affected[i]+2];
03444                         /* make the proposed decimation changes */
03445                         if( va == v1 ) {
03446                                 va = v2;
03447                         } else if( vb == v1 ) {
03448                                 vb = v2;
03449                         } else if( vc == v1 ) {
03450                                 vc = v2;
03451                         }
03452                         VSUB2( v01, &vertices[vb*3], &vertices[va*3] );
03453                         VSUB2( v02, &vertices[vc*3], &vertices[va*3] );
03454                         VCROSS( pla, v01, v02 );
03455                         VUNITIZE( pla );
03456                         pla[3] = VDOT( &vertices[va*3], pla );
03457 
03458                         /* max_normal_error is actually a minimum dot product */
03459                         dot = VDOT( pla, plb );
03460                         if( max_normal_error > -1.0 && dot < max_normal_error ) {
03461                                 return 0;
03462                         }
03463 
03464                         /* check the distance between this new plane and vertex v1 */
03465                         dist = fabs( DIST_PT_PLANE( &vertices[v1*3], pla ) );
03466                         if( max_chord_error > -1.0 && dist > max_chord_error ) {
03467                                 return 0;
03468                         }
03469                 }
03470         }
03471 
03472         return 1;
03473 }
03474 
03475 
03476 /**
03477  *                              R T _ B O T _ D E C I M A T E
03478  *
03479  *      routine to reduce the number of triangles in a BOT by edges decimation
03480  *              max_chord_error is the maximum error distance allowed
03481  *              max_normal_error is the maximum change in surface normal allowed
03482  *
03483  *      This and associated routines maintain a list of edges and their "use counts"
03484  *      A "free edge" is one with a use count of 1, most edges have a use count of 2
03485  *      When a use count reaches zero, the edge is removed from the list.
03486  *      The list is used to direct the edge decimation process and to avoid deforming the shape
03487  *      of a non-volume enclosing BOT by keeping track of use counts (and thereby free edges)
03488  *      If a free edge would be moved, that deciamtion is not performed.
03489  */
03490 int
03491 rt_bot_decimate( struct rt_bot_internal *bot,   /* BOT to be decimated */
03492                  fastf_t max_chord_error,       /* maximum allowable chord error (mm) */
03493                  fastf_t max_normal_error,      /* maximum allowable normal error (degrees) */
03494                  fastf_t min_edge_length )      /* minimum allowed edge length */
03495 {
03496         int *faces;
03497         struct bot_edge **edges;
03498         fastf_t min_edge_length_sq;
03499         int edges_deleted=0;
03500         int edge_count=0;
03501         int face_count;
03502         int actual_count;
03503         int deleted;
03504         int v1, v2;
03505         int i, j;
03506         int done;
03507 
03508         RT_BOT_CK_MAGIC( bot );
03509 
03510 #if 0
03511         if( max_chord_error <= SMALL_FASTF &&
03512             max_normal_error <= SMALL_FASTF &&
03513             min_edge_length <= SMALL_FASTF )
03514                 return 0;
03515 #endif
03516         /* convert normal error to something useful (a minimum dot product) */
03517         if( max_normal_error > -1.0 ) {
03518                 max_normal_error = cos( max_normal_error * M_PI / 180.0 );
03519         }
03520 
03521         if( min_edge_length > SMALL_FASTF ) {
03522                 min_edge_length_sq = min_edge_length * min_edge_length;
03523         } else {
03524                 min_edge_length_sq = min_edge_length;
03525         }
03526 
03527         /* make a working copy of the face list */
03528         faces = (int *)bu_malloc( sizeof( int ) * bot->num_faces * 3, "faces" );
03529         for( i=0 ; i<bot->num_faces*3 ; i++ ) {
03530                 faces[i] = bot->faces[i];
03531         }
03532         face_count = bot->num_faces;
03533 
03534         /* make a list of edges in the BOT
03535          * each edge will be in the list for its lower numbered vertex index
03536          */
03537         edges = (struct bot_edge **)bu_calloc( bot->num_vertices,
03538                                      sizeof( struct bot_edge *), "edges" );
03539 
03540         /* loop through all the faces building the edge lists */
03541         for( i=0 ; i<bot->num_faces*3 ; i += 3 ) {
03542           for( j=0 ; j<3 ; j++ ) {
03543             struct bot_edge *ptr;
03544             int k;
03545 
03546             k = j + 1;
03547             if( k > 2 ) {
03548               k = 0;
03549             }
03550             /* v1 is starting vertex index for this edge
03551              * v2 is the ending vertex index
03552              */
03553             v1 = faces[i+j];
03554             v2 = faces[i+k];
03555 
03556             /* make sure the lower index is v1 */
03557             if( v2 < v1 ) {
03558               int tmp;
03559 
03560               tmp = v1;
03561               v1 = v2;
03562               v2 = tmp;
03563             }
03564 
03565             /* store this edge in the appropiate list */
03566             ptr = edges[v1];
03567             if( !ptr ) {
03568               ptr = bu_calloc( 1, sizeof( struct bot_edge ), "edges[v1]" );
03569               edges[v1] = ptr;
03570             } else {
03571               while( ptr->next && ptr->v != v2 ) ptr = ptr->next;
03572               if( ptr->v == v2 ) {
03573                 ptr->use_count++;
03574                 continue;
03575               }
03576               ptr->next = bu_calloc( 1, sizeof( struct bot_edge ), "ptr->next" );
03577               ptr = ptr->next;
03578             }
03579             edge_count++;
03580             ptr->v = v2;
03581             ptr->use_count++;
03582             ptr->next = NULL;
03583           }
03584         }
03585 
03586         /* the decimation loop */
03587         done = 0;
03588         while( !done ) {
03589                 done = 1;
03590 
03591                 /* visit each edge */
03592                 for( i=0 ; i<bot->num_vertices ; i++ ) {
03593                         struct bot_edge *ptr;
03594                         int face_del1, face_del2;
03595 
03596                         ptr = edges[i];
03597                         while( ptr ) {
03598 
03599                                 /* try to avoid making 2D objects */
03600                                 if( face_count < 5 )
03601                                         break;
03602 
03603                                 /* check if this edge can be eliminated (try both directions) */
03604                                 if( edge_can_be_decimated( bot, faces, edges, i, ptr->v,
03605                                                            &face_del1, &face_del2,
03606                                                            max_chord_error,
03607                                                            max_normal_error,
03608                                                            min_edge_length_sq )) {
03609                                         face_count -= decimate_edge( i, ptr->v, edges, bot->num_vertices,
03610                                                                      faces, bot->num_faces,
03611                                                                      face_del1, face_del2 );
03612                                         edges_deleted++;
03613                                         done = 0;
03614                                         break;
03615                                 } else if( edge_can_be_decimated( bot, faces, edges, ptr->v, i,
03616                                                                   &face_del1, &face_del2,
03617                                                                   max_chord_error,
03618                                                                   max_normal_error,
03619                                                                   min_edge_length_sq )) {
03620                                         face_count -= decimate_edge( ptr->v, i, edges, bot->num_vertices,
03621                                                                      faces, bot->num_faces,
03622                                                                      face_del1, face_del2 );
03623                                         edges_deleted++;
03624                                         done = 0;
03625                                         break;
03626                                 } else {
03627                                         ptr = ptr->next;
03628                                 }
03629                         }
03630                 }
03631         }
03632 
03633         /* free some memory */
03634         for( i=0 ; i<bot->num_vertices ; i++ ) {
03635           struct bot_edge *ptr, *ptr2;
03636 
03637           ptr = edges[i];
03638           while( ptr ) {
03639             ptr2 = ptr;
03640             ptr = ptr->next;
03641             bu_free( (char *)ptr2, "ptr->edges" );
03642           }
03643         }
03644         bu_free( (char *)edges, "edges" );
03645 
03646         /* condense the face list */
03647         actual_count = 0;
03648         deleted = 0;
03649         for( i=0 ; i<bot->num_faces*3 ; i++ ) {
03650                 if( faces[i] < 0 ) {
03651                         deleted++;
03652                         continue;
03653                 }
03654                 if( deleted ) {
03655                         faces[i-deleted] = faces[i];
03656                 }
03657                 actual_count++;
03658         }
03659 
03660         if( actual_count % 3 ) {
03661                 bu_log( "rt_bot_decimate: face vertices count is not a multilple of 3!!\n" );
03662                 bu_free( ( char *)faces, "faces" );
03663                 return -1;
03664         }
03665 
03666         bu_log( "original face count = %d, edge count = %d\n",
03667                 bot->num_faces, edge_count );
03668         bu_log( "\tedges deleted = %d\n", edges_deleted );
03669         bu_log( "\tnew face_count = %d\n", face_count );
03670 
03671         actual_count /= 3;
03672 
03673         if( face_count != actual_count ) {
03674                 bu_log( "rt_bot_decimate: Face count is confused!!\n" );
03675                 bu_free( ( char *)faces, "faces" );
03676                 return -2;
03677         }
03678 
03679         bu_free( (char *)bot->faces, "bot->faces" );
03680         bot->faces = (int *)bu_realloc( faces, sizeof( int ) * face_count * 3, "bot->faces" );
03681         bot->num_faces = face_count;
03682 
03683         /* removed unused vertices */
03684         (void)rt_bot_condense( bot );
03685 
03686         return edges_deleted;
03687 }
03688 
03689 static int
03690 smooth_bot_miss( struct application *ap )
03691 {
03692         return 0;
03693 }
03694 
03695 static int
03696 smooth_bot_hit( struct application *ap, struct partition *PartHeadp, struct seg *seg )
03697 {
03698         struct partition *pp;
03699         struct soltab *stp;
03700         vect_t inormal, onormal;
03701         vect_t *normals=(vect_t *)ap->a_uptr;
03702 
03703         for( pp=PartHeadp->pt_forw ; pp != PartHeadp; pp = pp->pt_forw )  {
03704                 stp = pp->pt_inseg->seg_stp;
03705                 RT_HIT_NORMAL( inormal, pp->pt_inhit, stp, &(ap->a_ray), pp->pt_inflip );
03706 
03707                 stp = pp->pt_outseg->seg_stp;
03708                 RT_HIT_NORMAL( onormal, pp->pt_outhit, stp, &(ap->a_ray), pp->pt_outflip );
03709                 if( pp->pt_inhit->hit_surfno == ap->a_user ) {
03710                         VMOVE( normals[pp->pt_inhit->hit_surfno], inormal );
03711                         break;
03712                 }
03713                 if( pp->pt_outhit->hit_surfno == ap->a_user ) {
03714                         VMOVE( normals[pp->pt_outhit->hit_surfno], onormal );
03715                         break;
03716                 }
03717         }
03718 
03719         return 1;
03720 }
03721 
03722 int
03723 rt_smooth_bot( struct rt_bot_internal *bot, char *bot_name, struct db_i *dbip, fastf_t norm_tol_angle )
03724 {
03725         int vert_no;
03726         int i,j,k;
03727         struct rt_i *rtip;
03728         struct application ap;
03729         fastf_t normal_dot_tol=0.0;
03730         vect_t *normals;
03731 
03732         RT_BOT_CK_MAGIC( bot );
03733 
03734         if( norm_tol_angle < 0.0 || norm_tol_angle > M_PI ) {
03735                 bu_log( "normal tolerance angle must be from 0 to Pi\n" );
03736                 return( -2 );
03737         }
03738 
03739         if( (bot->orientation == RT_BOT_UNORIENTED) && (bot->mode != RT_BOT_SOLID) ) {
03740                 bu_log( "Cannot smooth unoriented BOT primitives unless they are solid objects\n" );
03741                 return( -3 );
03742         }
03743 
03744         normal_dot_tol = cos( norm_tol_angle );
03745 
03746         if( bot->normals ) {
03747                 bu_free( (char *)bot->normals, "bot->normals" );
03748                 bot->normals = NULL;
03749         }
03750 
03751         if( bot->face_normals ) {
03752                 bu_free( (char *)bot->face_normals, "bot->face_normals" );
03753                 bot->face_normals = NULL;
03754         }
03755 
03756         bot->bot_flags &= !(RT_BOT_HAS_SURFACE_NORMALS | RT_BOT_USE_NORMALS);
03757         bot->num_normals = 0;
03758         bot->num_face_normals = 0;
03759 
03760         /* build an array of surface normals */
03761         normals = (vect_t *)bu_calloc( bot->num_faces , sizeof( vect_t ), "normals" );
03762 
03763         if( bot->orientation == RT_BOT_UNORIENTED ) {
03764                 /* need to do raytracing, do prepping */
03765                 rtip = rt_new_rti( dbip );
03766 
03767                 RT_APPLICATION_INIT(&ap);
03768                 ap.a_rt_i = rtip;
03769                 ap.a_hit = smooth_bot_hit;
03770                 ap.a_miss = smooth_bot_miss;
03771                 ap.a_uptr = (genptr_t)normals;
03772                 if( rt_gettree( rtip, bot_name ) ) {
03773                         bu_log( "rt_gettree failed for %s\n", bot_name );
03774                         return( -1 );
03775                 }
03776                 rt_prep( rtip );
03777 
03778                 /* find the surface normal for each face */
03779                 for( i=0 ; i<bot->num_faces ; i++ ) {
03780                         vect_t a, b;
03781                         vect_t inv_dir;
03782 
03783                         VSUB2( a, &bot->vertices[bot->faces[i*3+1]*3], &bot->vertices[bot->faces[i*3]*3] );
03784                         VSUB2( b, &bot->vertices[bot->faces[i*3+2]*3], &bot->vertices[bot->faces[i*3]*3] );
03785                         VCROSS( ap.a_ray.r_dir, a, b );
03786                         VUNITIZE( ap.a_ray.r_dir );
03787 
03788                         /* calculate ray start point */
03789                         VADD3( ap.a_ray.r_pt, &bot->vertices[bot->faces[i*3]*3],
03790                                &bot->vertices[bot->faces[i*3+1]*3],
03791                                &bot->vertices[bot->faces[i*3+2]*3] );
03792                         VSCALE( ap.a_ray.r_pt, ap.a_ray.r_pt, 0.333333333333 );
03793 
03794                         /* back out to bounding box limits */
03795 
03796                         /* Compute the inverse of the direction cosines */
03797                         if( ap.a_ray.r_dir[X] < -SQRT_SMALL_FASTF )  {
03798                                 inv_dir[X]=1.0/ap.a_ray.r_dir[X];
03799                         } else if( ap.a_ray.r_dir[X] > SQRT_SMALL_FASTF )  {
03800                                 inv_dir[X]=1.0/ap.a_ray.r_dir[X];
03801                         } else {
03802                                 ap.a_ray.r_dir[X] = 0.0;
03803                                 inv_dir[X] = INFINITY;
03804                         }
03805                         if( ap.a_ray.r_dir[Y] < -SQRT_SMALL_FASTF )  {
03806                                 inv_dir[Y]=1.0/ap.a_ray.r_dir[Y];
03807                         } else if( ap.a_ray.r_dir[Y] > SQRT_SMALL_FASTF )  {
03808                                 inv_dir[Y]=1.0/ap.a_ray.r_dir[Y];
03809                         } else {
03810                                 ap.a_ray.r_dir[Y] = 0.0;
03811                                 inv_dir[Y] = INFINITY;
03812                         }
03813                         if( ap.a_ray.r_dir[Z] < -SQRT_SMALL_FASTF )  {
03814                                 inv_dir[Z]=1.0/ap.a_ray.r_dir[Z];
03815                         } else if( ap.a_ray.r_dir[Z] > SQRT_SMALL_FASTF )  {
03816                                 inv_dir[Z]=1.0/ap.a_ray.r_dir[Z];
03817                         } else {
03818                                 ap.a_ray.r_dir[Z] = 0.0;
03819                                 inv_dir[Z] = INFINITY;
03820                         }
03821 
03822                         if( !rt_in_rpp( &ap.a_ray, inv_dir, rtip->mdl_min, rtip->mdl_max ) ) {
03823                                 /* ray missed!!! */
03824                                 bu_log( "ERROR: Ray missed target!!!!\n" );
03825                         }
03826                         VJOIN1( ap.a_ray.r_pt, ap.a_ray.r_pt, ap.a_ray.r_min, ap.a_ray.r_dir );
03827                         ap.a_user = i;
03828                         (void) rt_shootray( &ap );
03829                 }
03830                 rt_free_rti( rtip );
03831         } else {
03832                 /* calculate normals */
03833                 for( i=0 ; i<bot->num_faces ; i++ ) {
03834                         vect_t a, b;
03835 
03836                         VSUB2( a, &bot->vertices[bot->faces[i*3+1]*3], &bot->vertices[bot->faces[i*3]*3] );
03837                         VSUB2( b, &bot->vertices[bot->faces[i*3+2]*3], &bot->vertices[bot->faces[i*3]*3] );
03838                         VCROSS( normals[i], a, b );
03839                         VUNITIZE( normals[i] );
03840                         if( bot->orientation == RT_BOT_CW ) {
03841                                 VREVERSE( normals[i], normals[i] );
03842                         }
03843                 }
03844         }
03845 
03846         bot->num_normals = bot->num_faces * 3;
03847         bot->num_face_normals = bot->num_faces;
03848 
03849         bot->normals = (fastf_t *)bu_calloc( bot->num_normals * 3, sizeof( fastf_t ), "bot->normals" );
03850         bot->face_normals = (int *)bu_calloc( bot->num_face_normals * 3, sizeof( int ), "bot->face_normals" );
03851 
03852         /* process each face */
03853         for( i=0 ; i<bot->num_faces ; i++ ) {
03854                 vect_t def_norm; /* default normal for this face */
03855 
03856                 VMOVE( def_norm, normals[i] );
03857 
03858                 /* process each vertex in his face */
03859                 for( k=0 ; k<3 ; k++ ) {
03860                         vect_t ave_norm;
03861 
03862                         /* the actual vertex index */
03863                         vert_no = bot->faces[i*3+k];
03864                         VSETALL( ave_norm, 0.0 );
03865 
03866                         /* find all the faces that use this vertex */
03867                            for( j=0 ; j<bot->num_faces*3 ; j++ ) {
03868                                    if( bot->faces[j] == vert_no ) {
03869                                            int the_face;
03870 
03871                                            the_face = j / 3;
03872 
03873                                            /* add all the normals that are within tolerance
03874                                             * this also gets def_norm
03875                                             */
03876                                            if( VDOT( normals[the_face], def_norm ) >= normal_dot_tol ) {
03877                                                    VADD2( ave_norm, ave_norm, normals[the_face] );
03878                                            }
03879                                    }
03880                            }
03881                            VUNITIZE( ave_norm );
03882                            VMOVE( &bot->normals[(i*3+k)*3], ave_norm );
03883                            bot->face_normals[i*3+k] = i*3+k;
03884                 }
03885         }
03886 
03887         bu_free( (char *)normals, "normals" );
03888 
03889         bot->bot_flags |= RT_BOT_HAS_SURFACE_NORMALS;
03890         bot->bot_flags |= RT_BOT_USE_NORMALS;
03891 
03892         return( 0 );
03893 }
03894 
03895 /*@}*/
03896 /*
03897  * Local Variables:
03898  * mode: C
03899  * tab-width: 8
03900  * c-basic-offset: 4
03901  * indent-tabs-mode: t
03902  * End:
03903  * ex: shiftwidth=4 tabstop=8
03904  */

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