g_bot_include.c

Go to the documentation of this file.
00001 /*                 G _ B O T _ I N C L U D E . 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_include.c
00026  *      This file contains all the routines for "g_bot.c" that contain references to
00027  *      "tri_specific" structs. This file is included in "g_bot.c" twice. Each time
00028  *      the macro TRI_TYPE is defined to reflect the desired version of the
00029  *      "tri_specific" structure:
00030  *
00031  *              TRI_TYPE == float   -> use the "tri_float_specific" struct
00032  *              TRI_TYPE == double     -> use the original "tri_specific" struct
00033  *
00034  *  Authors -
00035  *      John R. Anderson
00036  *  Source -
00037  *      The U. S. Army Research Laboratory
00038  *      Aberdeen Proving Ground, Maryland  21005-5066
00039  *
00040  */
00041 
00042 #ifndef lint
00043 static const char XGLUE(RCSbot_inc_,TRI_TYPE)[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_bot_include.c,v 14.14 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00044 #endif
00045 
00046 /**
00047  *                      R T _ B O T F A C E
00048  *
00049  *  This function is called with pointers to 3 points,
00050  *  and is used to prepare BOT faces.
00051  *  ap, bp, cp point to vect_t points.
00052  *
00053  * Return -
00054  *      0       if the 3 points didn't form a plane (eg, colinear, etc).
00055  *      # pts   (3) if a valid plane resulted.
00056  */
00057 int
00058 XGLUE(rt_botface_w_normals_,TRI_TYPE)(struct soltab     *stp,
00059            struct bot_specific  *bot,
00060            fastf_t              *ap,
00061            fastf_t              *bp,
00062            fastf_t              *cp,
00063            fastf_t              *vertex_normals, /* array of nine values (three unit normals vectors) */
00064            int                  face_no,
00065            const struct bn_tol  *tol)
00066 {
00067         register XGLUE(tri_specific_,TRI_TYPE) *trip;
00068         vect_t work;
00069         LOCAL fastf_t m1, m2, m3, m4;
00070         int i;
00071 
00072         BU_GETTYPE( trip, XGLUE(tri_specific_,TRI_TYPE) );
00073         VMOVE( trip->tri_A, ap );
00074         VSUB2( trip->tri_BA, bp, ap );
00075         VSUB2( trip->tri_CA, cp, ap );
00076         VCROSS( trip->tri_wn, trip->tri_BA, trip->tri_CA );
00077         trip->tri_surfno = face_no;
00078 
00079         /* Check to see if this plane is a line or pnt */
00080         m1 = MAGNITUDE( trip->tri_BA );
00081         m2 = MAGNITUDE( trip->tri_CA );
00082         VSUB2( work, bp, cp );
00083         m3 = MAGNITUDE( work );
00084         m4 = MAGNITUDE( trip->tri_wn );
00085         if( m1 < 0.00001 || m2 < 0.00001 ||
00086             m3 < 0.00001 || m4 < 0.00001 )  {
00087                 bu_free( (char *)trip, "getstruct tri_specific");
00088 
00089                 if( RT_G_DEBUG & DEBUG_SHOOT ) {
00090                     bu_log("%s: degenerate facet #%d\n",
00091                            stp->st_name, face_no);
00092                     bu_log( "\t(%g %g %g) (%g %g %g) (%g %g %g)\n",
00093                             V3ARGS( ap ), V3ARGS( bp ), V3ARGS( cp ) );
00094                 }
00095                 return(0);                      /* BAD */
00096         }
00097 
00098         if( (bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) && (bot->bot_flags & RT_BOT_USE_NORMALS) && vertex_normals ) {
00099                 trip->tri_normals = (NORM_TYPE *)bu_malloc( 9 * sizeof( NORM_TYPE ), "trip->tri_normals" );
00100                 for( i=0 ; i<3 ; i++ ) {
00101                         int j;
00102 
00103                         for( j=0 ; j<3 ; j++ ) {
00104                                 trip->tri_normals[i*3+j] = vertex_normals[i*3+j] * NORMAL_SCALE;
00105                         }
00106                 }
00107         } else {
00108                 trip->tri_normals = (NORM_TYPE *)NULL;
00109         }
00110 
00111         /*  wn is a normal of not necessarily unit length.
00112          *  N is an outward pointing unit normal.
00113          *  We depend on the points being given in CCW order here.
00114          */
00115         VMOVE( trip->tri_N, trip->tri_wn );
00116         VUNITIZE( trip->tri_N );
00117         if( bot->bot_mode == RT_BOT_CW )
00118                 VREVERSE( trip->tri_N, trip->tri_N );
00119 
00120         /* Add this face onto the linked list for this solid */
00121         trip->tri_forw = (XGLUE(tri_specific_,TRI_TYPE) *)bot->bot_facelist;
00122         bot->bot_facelist = (genptr_t)trip;
00123         return(3);                              /* OK */
00124 }
00125 
00126 /*
00127  *      Do the prep to support pieces for a BOT/ARS
00128  *
00129  */
00130 void
00131 XGLUE(rt_bot_prep_pieces_,TRI_TYPE)(struct bot_specific *bot,
00132                    struct soltab        *stp,
00133                    int                  ntri,
00134                    const struct bn_tol          *tol)
00135 {
00136     struct bound_rpp    *minmax = (struct bound_rpp *)NULL;
00137     XGLUE(tri_specific_,TRI_TYPE) **fap;
00138     register XGLUE(tri_specific_,TRI_TYPE) *trip;
00139     point_t b,c;
00140     point_t d,e,f;
00141     vect_t offset;
00142     fastf_t los;
00143     int surfno;
00144     long num_rpps;
00145     int tri_per_piece, tpp_m1;
00146 
00147     tri_per_piece = bot->bot_tri_per_piece = rt_bot_tri_per_piece;
00148 
00149     num_rpps = ntri / tri_per_piece;
00150     if (ntri % tri_per_piece) num_rpps++;
00151 
00152     stp->st_npieces = num_rpps;
00153 
00154     fap = (XGLUE(tri_specific_,TRI_TYPE) **)
00155         bu_malloc( sizeof(XGLUE(tri_specific_,TRI_TYPE) *) * ntri,
00156                    "bot_facearray" );
00157     bot->bot_facearray = (genptr_t *)fap;
00158 
00159     stp->st_piece_rpps = (struct bound_rpp *)
00160         bu_malloc( sizeof(struct bound_rpp) * num_rpps,
00161                    "st_piece_rpps" );
00162 
00163 
00164     tpp_m1 = tri_per_piece - 1;
00165     trip = bot->bot_facelist;
00166     minmax = &stp->st_piece_rpps[num_rpps-1];
00167     minmax->min[X] = minmax->max[X] = trip->tri_A[X];
00168     minmax->min[Y] = minmax->max[Y] = trip->tri_A[Y];
00169     minmax->min[Z] = minmax->max[Z] = trip->tri_A[Z];
00170     for (surfno=ntri-1 ; trip; trip = trip->tri_forw, surfno-- )  {
00171 
00172         if ( (surfno % tri_per_piece) == tpp_m1) {
00173             /* top most surfno in a piece group */
00174             /* first surf for this piece */
00175             minmax = &stp->st_piece_rpps[surfno / tri_per_piece];
00176 
00177             minmax->min[X] = minmax->max[X] = trip->tri_A[X];
00178             minmax->min[Y] = minmax->max[Y] = trip->tri_A[Y];
00179             minmax->min[Z] = minmax->max[Z] = trip->tri_A[Z];
00180         } else {
00181             VMINMAX( minmax->min, minmax->max, trip->tri_A);
00182         }
00183 
00184         fap[surfno] = trip;
00185 
00186         if (bot->bot_mode == RT_BOT_PLATE ||
00187            bot->bot_mode == RT_BOT_PLATE_NOCOS )  {
00188             if( BU_BITTEST( bot->bot_facemode, surfno ) )  {
00189                 /* Append full thickness on both sides */
00190                 los = bot->bot_thickness[surfno];
00191             } else {
00192                 /* Center thickness.  Append 1/2 thickness on both sides */
00193                 los = bot->bot_thickness[surfno] * 0.51;
00194             }
00195         } else {
00196                                 /* Prevent the RPP from being 0 thickness */
00197             los = tol->dist;    /* typ 0.005mm */
00198         }
00199 
00200         VADD2( b, trip->tri_BA, trip->tri_A );
00201         VADD2( c, trip->tri_CA, trip->tri_A );
00202         VMINMAX( minmax->min, minmax->max, b );
00203         VMINMAX( minmax->min, minmax->max, c );
00204 
00205         /* Offset face in +los */
00206         VSCALE( offset, trip->tri_N, los );
00207         VADD2( d, trip->tri_A, offset );
00208         VADD2( e, b, offset );
00209         VADD2( f, c, offset );
00210         VMINMAX( minmax->min, minmax->max, d );
00211         VMINMAX( minmax->min, minmax->max, e );
00212         VMINMAX( minmax->min, minmax->max, f );
00213 
00214         /* Offset face in -los */
00215         VSCALE( offset, trip->tri_N, -los );
00216         VADD2( d, trip->tri_A, offset );
00217         VADD2( e, b, offset );
00218         VADD2( f, c, offset );
00219         VMINMAX( minmax->min, minmax->max, d );
00220         VMINMAX( minmax->min, minmax->max, e );
00221         VMINMAX( minmax->min, minmax->max, f );
00222 
00223         VMINMAX( stp->st_min, stp->st_max, minmax->min );
00224         VMINMAX( stp->st_min, stp->st_max, minmax->max );
00225 
00226     }
00227 
00228 }
00229 
00230 /**
00231  *                      R T _ B O T _ P R E P
00232  *
00233  *  Given a pointer to a GED database record, and a transformation matrix,
00234  *  determine if this is a valid BOT, and if so, precompute various
00235  *  terms of the formula.
00236  *
00237  *  Returns -
00238  *      0       BOT is OK
00239  *      !0      Error in description
00240  *
00241  *  Implicit return -
00242  *      A struct bot_specific is created, and it's address is stored in
00243  *      stp->st_specific for use by bot_shot().
00244  */
00245 int
00246 XGLUE(rt_bot_prep_,TRI_TYPE)( stp, bot_ip, rtip )
00247 struct soltab           *stp;
00248 struct rt_bot_internal  *bot_ip;
00249 struct rt_i             *rtip;
00250 {
00251         register struct bot_specific    *bot;
00252         const struct bn_tol             *tol = &rtip->rti_tol;
00253         int                             tri_index, i;
00254         LOCAL fastf_t                   dx, dy, dz;
00255         LOCAL fastf_t                   f;
00256         int                             ntri = 0;
00257 
00258         RT_BOT_CK_MAGIC(bot_ip);
00259 
00260         BU_GETSTRUCT( bot, bot_specific );
00261         stp->st_specific = (genptr_t)bot;
00262         bot->bot_mode = bot_ip->mode;
00263         bot->bot_orientation = bot_ip->orientation;
00264         bot->bot_flags = bot_ip->bot_flags;
00265         if( bot_ip->thickness )
00266         {
00267                 bot->bot_thickness = (fastf_t *)bu_calloc( bot_ip->num_faces, sizeof( fastf_t ), "bot_thickness" );
00268                 for( tri_index=0 ; tri_index <  bot_ip->num_faces ; tri_index++ )
00269                         bot->bot_thickness[tri_index] = bot_ip->thickness[tri_index];
00270         }
00271         if( bot_ip->face_mode )
00272                 bot->bot_facemode = bu_bitv_dup( bot_ip->face_mode );
00273         bot->bot_facelist = (XGLUE(tri_specific_,TRI_TYPE) *)NULL;
00274 
00275         VSETALL( stp->st_min, MAX_FASTF );
00276         VREVERSE( stp->st_max, stp->st_min );
00277         for( tri_index=0 ; tri_index < bot_ip->num_faces ; tri_index++ )
00278         {
00279                 point_t p1, p2, p3;
00280                 int default_normal=-1;
00281 
00282                 VMOVE( p1, &bot_ip->vertices[bot_ip->faces[tri_index*3]*3] );
00283                 VMOVE( p2, &bot_ip->vertices[bot_ip->faces[tri_index*3 + 1]*3] );
00284                 VMOVE( p3, &bot_ip->vertices[bot_ip->faces[tri_index*3 + 2]*3] );
00285 
00286                 if( rt_bot_minpieces <= 0 || bot_ip->num_faces <= rt_bot_minpieces ) {
00287                         VMINMAX( stp->st_min, stp->st_max, p1 );
00288                         VMINMAX( stp->st_min, stp->st_max, p2 );
00289                         VMINMAX( stp->st_min, stp->st_max, p3 );
00290                 }
00291 
00292                 if( (bot_ip->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) && (bot_ip->bot_flags & RT_BOT_USE_NORMALS)
00293                         && (bot_ip->num_normals > 0) && (bot_ip->num_face_normals > tri_index) ) {
00294                         for( i=0 ; i<3 ; i++ ) {
00295                                 int index;
00296 
00297                                 index = bot_ip->face_normals[tri_index*3 + i];
00298                                 if( index >= 0 && index < bot_ip->num_normals ) {
00299                                         default_normal = index;
00300                                 }
00301                         }
00302                         if( default_normal < 0 ) {
00303                                 if( rt_botface( stp, bot, p1, p2, p3, tri_index, tol ) > 0 )
00304                                         ntri++;
00305                         } else {
00306                                 fastf_t normals[9];
00307 
00308                                 for( i=0 ; i<3 ; i++ ) {
00309                                         int index;
00310 
00311                                         index = bot_ip->face_normals[tri_index*3 + i];
00312                                         if( index < 0 || index > bot_ip->num_normals ) {
00313                                                 VMOVE( &normals[i*3], &bot_ip->normals[default_normal*3] );
00314                                         } else {
00315                                                 VMOVE( &normals[i*3], &bot_ip->normals[index*3] );
00316                                         }
00317                                 }
00318                                 if( rt_botface_w_normals( stp, bot, p1, p2, p3, normals, tri_index, tol ) > 0 )
00319                                         ntri++;
00320                         }
00321                 } else {
00322                         if( rt_botface( stp, bot, p1, p2, p3, tri_index, tol ) > 0 )
00323                                 ntri++;
00324                 }
00325         }
00326 
00327         if( bot->bot_facelist == (XGLUE(tri_specific_,TRI_TYPE) *)0 )  {
00328                 bu_log("bot(%s):  no faces\n", stp->st_name);
00329                 return(-1);             /* BAD */
00330         }
00331 
00332         bot->bot_ntri = ntri;
00333 
00334         if( rt_bot_minpieces > 0 && bot_ip->num_faces > rt_bot_minpieces ) {
00335                 rt_bot_prep_pieces( bot, stp, ntri, tol );
00336         }
00337 
00338         /* zero thickness will get missed by the raytracer */
00339         for( i=0 ; i<3 ; i++ )
00340         {
00341                 if( NEAR_ZERO( stp->st_min[i] - stp->st_max[i], 1.0 ) )
00342                 {
00343                         stp->st_min[i] -= 0.000001;
00344                         stp->st_max[i] += 0.000001;
00345                 }
00346         }
00347 
00348         VADD2SCALE( stp->st_center, stp->st_max, stp->st_min, 0.5 );
00349 
00350         dx = (stp->st_max[X] - stp->st_min[X])/2;
00351         f = dx;
00352         dy = (stp->st_max[Y] - stp->st_min[Y])/2;
00353         if( dy > f )  f = dy;
00354         dz = (stp->st_max[Z] - stp->st_min[Z])/2;
00355         if( dz > f )  f = dz;
00356         stp->st_aradius = f;
00357         stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz);
00358 
00359         /*
00360          *  Support for solid 'pieces'
00361          *
00362          *  Each piece can represent a number of triangles.  This is encoded
00363          *  in bot->bot_tri_per_piece.
00364          *
00365          *  These array allocations can't be made until the number of
00366          *  triangles are known.
00367          *
00368          *  If the number of triangles is too small,
00369          *  don't bother making pieces, the overhead isn't worth it.
00370          *
00371          *  To disable BoT pieces, on the RT command line specify:
00372          *      -c "set rt_bot_minpieces=0"
00373          */
00374 
00375         return 0;
00376 }
00377 
00378 static int
00379 XGLUE(rt_bot_plate_segs_,TRI_TYPE)(struct hit           *hits,
00380                   int                   nhits,
00381                   struct soltab         *stp,
00382                   struct xray           *rp,
00383                   struct application    *ap,
00384                   struct seg            *seghead,
00385                   struct bot_specific   *bot)
00386 {
00387     register struct seg *segp;
00388     register int i;
00389     register fastf_t los;
00390     int surfno;
00391 
00392 
00393     for( i=0; i < nhits; i++ ) {
00394         XGLUE(tri_specific_,TRI_TYPE) *trip=(XGLUE(tri_specific_,TRI_TYPE) *)hits[i].hit_private;
00395 
00396         surfno = hits[i].hit_surfno;
00397 
00398         if( bot->bot_mode == RT_BOT_PLATE_NOCOS )
00399             los = bot->bot_thickness[surfno];
00400         else {
00401             los = bot->bot_thickness[surfno] / hits[i].hit_vpriv[X];
00402             if( los < 0.0 )
00403                 los = -los;
00404         }
00405         if( BU_BITTEST( bot->bot_facemode, hits[i].hit_surfno ) ) {
00406 
00407                                 /* append thickness to hit point */
00408             RT_GET_SEG( segp, ap->a_resource);
00409             segp->seg_stp = stp;
00410 
00411                                 /* set in hit */
00412             segp->seg_in = hits[i];
00413             RT_BOT_UNORIENTED_NORM( &segp->seg_in, 1 );
00414 
00415                                 /* set out hit */
00416             segp->seg_out.hit_surfno = surfno;
00417             segp->seg_out.hit_dist = segp->seg_in.hit_dist + los;
00418             VMOVE( segp->seg_out.hit_vpriv, hits[i].hit_vpriv );
00419             RT_BOT_UNORIENTED_NORM( &segp->seg_out, -1 );
00420             segp->seg_out.hit_private = segp->seg_in.hit_private;
00421             segp->seg_out.hit_rayp = &ap->a_ray;
00422 
00423             BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00424         } else {
00425                                 /* center thickness about hit point */
00426             RT_GET_SEG( segp, ap->a_resource);
00427             segp->seg_stp = stp;
00428 
00429                                 /* set in hit */
00430             segp->seg_in.hit_surfno = surfno;
00431             VMOVE( segp->seg_in.hit_vpriv, hits[i].hit_vpriv );
00432             RT_BOT_UNORIENTED_NORM( &segp->seg_in, 1 );
00433             segp->seg_in.hit_private = hits[i].hit_private;
00434             segp->seg_in.hit_dist = hits[i].hit_dist - (los*0.5 );
00435             segp->seg_in.hit_rayp = &ap->a_ray;
00436 
00437                                 /* set out hit */
00438             segp->seg_out.hit_surfno = surfno;
00439             segp->seg_out.hit_dist = segp->seg_in.hit_dist + los;
00440             VMOVE( segp->seg_out.hit_vpriv, hits[i].hit_vpriv );
00441             RT_BOT_UNORIENTED_NORM( &segp->seg_out, -1 );
00442             segp->seg_out.hit_private = hits[i].hit_private;
00443             segp->seg_out.hit_rayp = &ap->a_ray;
00444 
00445             BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00446         }
00447     }
00448     /* Every hit turns into two, and makes a seg.  No leftovers */
00449     return( nhits*2 );
00450 
00451 }
00452 
00453 static int
00454 XGLUE(rt_bot_unoriented_segs_,TRI_TYPE)(struct hit              *hits,
00455                   int                   nhits,
00456                   struct soltab         *stp,
00457                   struct xray           *rp,
00458                   struct application    *ap,
00459                   struct seg            *seghead,
00460                   struct bot_specific   *bot)
00461 {
00462     register struct seg *segp;
00463     register int i, j;
00464 
00465     /*
00466      *  RT_BOT_SOLID, RT_BOT_UNORIENTED.
00467      */
00468     fastf_t rm_dist=0.0;
00469     int removed=0;
00470 
00471     if( nhits == 1 ) {
00472         XGLUE(tri_specific_,TRI_TYPE) *trip=(XGLUE(tri_specific_,TRI_TYPE) *)hits[0].hit_private;
00473 
00474         /* make a zero length partition */
00475         RT_GET_SEG( segp, ap->a_resource );
00476         segp->seg_stp = stp;
00477 
00478         /* set in hit */
00479         segp->seg_in = hits[0];
00480         RT_BOT_UNORIENTED_NORM( &segp->seg_in, 1 );
00481 
00482         /* set out hit */
00483         segp->seg_out = hits[0];
00484         RT_BOT_UNORIENTED_NORM( &segp->seg_out, -1 );
00485 
00486         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00487         return( 1 );
00488     }
00489 
00490     /* Remove duplicate hits */
00491     for( i=0 ; i<nhits-1 ; i++ ) {
00492         fastf_t dist;
00493 
00494         dist = hits[i].hit_dist - hits[i+1].hit_dist;
00495         if( NEAR_ZERO( dist, ap->a_rt_i->rti_tol.dist ) ) {
00496             removed++;
00497             rm_dist = hits[i+1].hit_dist;
00498             for( j=i ; j<nhits-1 ; j++ )
00499                 hits[j] = hits[j+1];
00500             nhits--;
00501             i--;
00502         }
00503     }
00504 
00505 
00506     if( nhits == 1 )
00507         return( 0 );
00508 
00509     if( nhits&1 && removed ) {
00510         /* If we have an odd number of hits and have removed
00511          * a duplicate, then it was likely on an edge, so
00512          * remove the one we left.
00513          */
00514         register int j;
00515 
00516         for( i=0 ; i<nhits ; i++ ) {
00517             if( hits[i].hit_dist == rm_dist ) {
00518                 for( j=i ; j<nhits-1 ; j++ )
00519                     hits[j] = hits[j+1];
00520                 nhits--;
00521                 i--;
00522                 break;
00523             }
00524         }
00525     }
00526 
00527     for( i=0 ; i<(nhits&~1) ; i += 2 ) {
00528         XGLUE(tri_specific_,TRI_TYPE) *trip;
00529 
00530         RT_GET_SEG( segp, ap->a_resource );
00531         segp->seg_stp = stp;
00532 
00533         /* set in hit */
00534         segp->seg_in = hits[i];
00535         trip = (XGLUE(tri_specific_,TRI_TYPE) *)hits[i].hit_private;
00536         RT_BOT_UNORIENTED_NORM( &segp->seg_in, 1 );
00537 
00538         /* set out hit */
00539         segp->seg_out = hits[i+1];
00540         trip = (XGLUE(tri_specific_,TRI_TYPE) *)hits[i+1].hit_private;
00541         RT_BOT_UNORIENTED_NORM( &segp->seg_out, -1 );
00542 
00543         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00544     }
00545     if( nhits&1 ) {
00546         if( RT_G_DEBUG & DEBUG_SHOOT ) {
00547             bu_log( "rt_bot_unoriented_segs(%s): WARNING: odd number of hits (%d), last hit ignored\n",
00548                     stp->st_name, nhits );
00549             bu_log( "\tray = -p %g %g %g -d %g %g %g\n",
00550                     V3ARGS( rp->r_pt ), V3ARGS( rp->r_dir ) );
00551         }
00552         nhits--;
00553     }
00554     return( nhits );
00555 }
00556 
00557 
00558 
00559 /**
00560  *                      R T _ B O T _ M A K E S E G S
00561  *
00562  *  Given an array of hits, make segments out of them.
00563  *  Exactly how this is to be done depends on the mode of the BoT.
00564  */
00565 HIDDEN int
00566 XGLUE(rt_bot_makesegs_,TRI_TYPE)( struct hit *hits, int nhits, struct soltab *stp,
00567                                   struct xray *rp, struct application *ap,
00568                                   struct seg *seghead, struct rt_piecestate *psp )
00569 {
00570     struct bot_specific *bot = (struct bot_specific *)stp->st_specific;
00571     register struct seg *segp;
00572     register int i;
00573 
00574     RT_CK_SOLTAB(stp);
00575 
00576     if( bot->bot_mode == RT_BOT_SURFACE ) {
00577         for( i=0 ; i<nhits ; i++ )
00578             {
00579                 XGLUE(tri_specific_,TRI_TYPE) *trip=(XGLUE(tri_specific_,TRI_TYPE) *)hits[i].hit_private;
00580 
00581                 RT_GET_SEG( segp, ap->a_resource );
00582                 segp->seg_stp = stp;
00583 
00584                 /* set in hit */
00585                 segp->seg_in = hits[i];
00586                 RT_BOT_UNORIENTED_NORM( &segp->seg_in, 1 );
00587 
00588                 /* set out hit */
00589                 segp->seg_out = hits[i];
00590                 RT_BOT_UNORIENTED_NORM( &segp->seg_out, -1 );
00591                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00592             }
00593         /* Every hit turns into two, and makes a seg.  No leftovers */
00594         return( nhits*2 );
00595     }
00596 
00597     BU_ASSERT( bot->bot_mode == RT_BOT_SOLID );
00598 
00599     if( bot->bot_orientation == RT_BOT_UNORIENTED ) {
00600         return rt_bot_unoriented_segs(hits, nhits, stp, rp, ap,
00601                                       seghead, bot);
00602     }
00603 
00604     /*
00605          *  RT_BOT_SOLID, RT_BOT_ORIENTED.
00606          *
00607          *  From this point on, process very similar to a polysolid
00608          */
00609 
00610     /* Remove duplicate hits */
00611     {
00612         register int j,k,l;
00613 
00614         for( i=0 ; i<nhits-1 ; i++ )
00615             {
00616                 FAST fastf_t dist;
00617                 FAST fastf_t dn;
00618 
00619                 dn = hits[i].hit_vpriv[X];
00620 
00621                 k = i + 1;
00622                 dist = hits[i].hit_dist - hits[k].hit_dist;
00623 
00624                 /* count number of hits at this distance */
00625                 while( NEAR_ZERO( dist, ap->a_rt_i->rti_tol.dist ) ) {
00626                         k++;
00627                         if( k > nhits - 1 )
00628                                 break;
00629                         dist = hits[i].hit_dist - hits[k].hit_dist;
00630                 }
00631 
00632                 if( (k - i) == 2 && dn * hits[i+1].hit_vpriv[X] > 0) {
00633                         /* a pair of hits at the same distance and both are exits or entrances,
00634                          * likely an edge hit, remove one */
00635                         for( j=i ; j<nhits-1 ; j++ )
00636                                 hits[j] = hits[j+1];
00637                         if( psp ) {
00638                                 psp->htab.end--;
00639                         }
00640                         nhits--;
00641                         i--;
00642                         continue;
00643                 } else if( (k - i) > 2 ) {
00644                         int keep1=-1, keep2=-1;
00645                         int enters=0, exits=0;
00646                         int reorder=0;
00647                         int reorder_failed=0;
00648 
00649                         /* more than two hits at the same distance, likely a vertex hit
00650                          * try to keep just two, one entrance and one exit.
00651                          * unless they are all entrances or all exits, then just keep one */
00652 
00653                         /* first check if we need to do anything */
00654                         for( j=0 ; j<k ; j++ ) {
00655                                 if( hits[j].hit_vpriv[X] > 0 )
00656                                         exits++;
00657                                 else
00658                                         enters++;
00659                         }
00660 
00661                         if( k%2 ) {
00662                                 if( exits == (enters - 1) ) {
00663                                         reorder = 1;
00664                                 }
00665                         } else {
00666                                 if( exits == enters ) {
00667                                         reorder = 1;
00668                                 }
00669                         }
00670 
00671                         if( reorder ) {
00672                                 struct hit tmp_hit;
00673                                 int changed=0;
00674 
00675                                 for( j=i ; j<k ; j++ ) {
00676                                         int l;
00677 
00678                                         if( j%2 ) {
00679                                                 if( hits[j].hit_vpriv[X] > 0 ) {
00680                                                         continue;
00681                                                 }
00682                                                 /* should be an exit here */
00683                                                 l = j+1;
00684                                                 while( l < k ) {
00685                                                         if( hits[l].hit_vpriv[X] > 0 ) {
00686                                                                 /* swap with this exit */
00687                                                                 tmp_hit = hits[j];
00688                                                                 hits[j] = hits[l];
00689                                                                 hits[l] = tmp_hit;
00690                                                                 changed = 1;
00691                                                                 break;
00692                                                         }
00693                                                         l++;
00694                                                 }
00695                                                 if( hits[j].hit_vpriv[X] < 0 ) {
00696                                                         reorder_failed = 1;
00697                                                         break;
00698                                                 }
00699                                         } else {
00700                                                 if( hits[j].hit_vpriv[X] < 0 ) {
00701                                                         continue;
00702                                                 }
00703                                                 /* should be an entrance here */
00704                                                 l = j+1;
00705                                                 while( l < k ) {
00706                                                         if( hits[l].hit_vpriv[X] < 0 ) {
00707                                                                 /* swap with this entrance */
00708                                                                 tmp_hit = hits[j];
00709                                                                 hits[j] = hits[l];
00710                                                                 hits[l] = tmp_hit;
00711                                                                 changed = 1;
00712                                                                 break;
00713                                                         }
00714                                                         l++;
00715                                                 }
00716                                                 if( hits[j].hit_vpriv[X] > 0 ) {
00717                                                         reorder_failed = 1;
00718                                                         break;
00719                                                 }
00720                                         }
00721                                 }
00722                                 if( changed ) {
00723                                         /* if we have re-ordered these hits, make sure they are really
00724                                          *  at the same distance.
00725                                          */
00726                                         for( j=i+1 ; j<k ; j++ ) {
00727                                                 hits[j].hit_dist = hits[i].hit_dist;
00728                                         }
00729                                 }
00730                         }
00731                         if( !reorder || reorder_failed ) {
00732 
00733                                 exits = 0;
00734                                 enters = 0;
00735                                 if( i == 0 ) {
00736                                         dn = 1.0;
00737                                 } else {
00738                                         dn = hits[i-1].hit_vpriv[X];
00739                                 }
00740                                 for( j=i ; j<k ; j++ ) {
00741                                         if( hits[j].hit_vpriv[X] > 0 )
00742                                                 exits++;
00743                                         else
00744                                                 enters++;
00745                                         if( dn * hits[j].hit_vpriv[X] < 0 ) {
00746                                                 if( keep1 < 0 ) {
00747                                                         keep1 = j;
00748                                                         dn = hits[j].hit_vpriv[X];
00749                                                 } else if( keep2 < 0 ) {
00750                                                         keep2 = j;
00751                                                         dn = hits[j].hit_vpriv[X];
00752                                                         break;
00753                                                 }
00754                                         }
00755                                 }
00756 
00757                                 if( keep2 == -1 ) {
00758                                 /* did not find two keepers, perhaps they were all entrances or all exits */
00759                                         if( exits == k - i || enters == k - i ) {
00760                                                 /* eliminate all but one entrance or exit */
00761                                                 for( j=k-1 ; j>i ; j-- ) {
00762                                                         /* delete this hit */
00763                                                         for( l=j ; l<nhits-1 ; l++ )
00764                                                                 hits[l] = hits[l+1];
00765                                                         if( psp ) {
00766                                                                 psp->htab.end--;
00767                                                         }
00768                                                         nhits--;
00769                                                 }
00770                                                 i--;
00771                                         }
00772                                 } else if( keep2 >= 0 ) {
00773                                 /* found an entrance and an exit to keep */
00774                                         for( j=k-1 ; j>=i ; j-- ) {
00775                                                 if( j != keep1 && j != keep2 ) {
00776                                                         /* delete this hit */
00777                                                         for( l=j ; l<nhits-1 ; l++ )
00778                                                                 hits[l] = hits[l+1];
00779                                                         if( psp ) {
00780                                                                 psp->htab.end--;
00781                                                         }
00782                                                         nhits--;
00783                                                 }
00784                                         }
00785                                         i--;
00786                                 }
00787                         }
00788                 }
00789             }
00790     }
00791 #if 0
00792     bu_log( "nhits = %d\n", nhits );
00793     for( i=0 ; i<nhits ; i++ ) {
00794             rt_bot_norm( &hits[i], stp, rp );
00795             bu_log( "dist=%g, normal = (%g %g %g), %s\n", hits[i].hit_dist, V3ARGS( hits[i].hit_normal), hits[i].hit_vpriv[X] > 0 ? "exit" : "entrance" );
00796     }
00797 #endif
00798 
00799     /* if first hit is an exit, it is likely due to the "piece" for the corresponding entrance
00800      * not being processed (this is OK, but we need to eliminate the stray exit hit)
00801      */
00802     while( nhits > 0 && hits[0].hit_vpriv[X] > 0.0 ) {
00803             int j;
00804 
00805             for( j=1 ; j<nhits ; j++ ) {
00806                     hits[j-1] = hits[j];
00807             }
00808             nhits--;
00809     }
00810 
00811     /* similar for trailing entrance hits */
00812     while( nhits > 0 && hits[nhits-1].hit_vpriv[X] < 0.0 ) {
00813             nhits--;
00814     }
00815 
00816     if( (nhits&1) )  {
00817         register int i;
00818         /*
00819          * If this condition exists, it is almost certainly due to
00820          * the dn==0 check above.  Thus, we will make the last
00821          * surface rather thin.
00822          * This at least makes the
00823          * presence of this solid known.  There may be something
00824          * better we can do.
00825          */
00826 
00827         if( nhits > 2 )
00828             {
00829                 fastf_t dot1,dot2;
00830                 int j;
00831 
00832                 /* likely an extra hit,
00833                  * look for consecutive entrances or exits */
00834 
00835                 dot2 = 1.0;
00836                 i = 0;
00837                 while( i<nhits )
00838                     {
00839                         dot1 = dot2;
00840                         dot2 = hits[i].hit_vpriv[X];
00841                         if( dot1 > 0.0 && dot2 > 0.0 )
00842                             {
00843                                 /* two consectutive exits,
00844                                  * manufacture an entrance at same distance
00845                                  * as second exit.
00846                                  */
00847                                 /* XXX This consumes an extra hit structure in the array */
00848                                 if( psp ) {
00849                                         /* using pieces */
00850                                         (void)rt_htbl_get(&psp->htab);  /* make sure space exists in the hit array */
00851                                         hits = psp->htab.hits;
00852                                 } else if( nhits + 1 >= MAXHITS ) {
00853                                         /* not using pieces */
00854                                         bu_log( "rt_bot_makesegs: too many hits on %s\n", stp->st_dp->d_namep );
00855                                         i++;
00856                                         continue;
00857                                 }
00858                                 for( j=nhits ; j>i ; j-- )
00859                                     hits[j] = hits[j-1];        /* struct copy */
00860 
00861                                 hits[i].hit_vpriv[X] = -hits[i].hit_vpriv[X];
00862                                 dot2 = hits[i].hit_vpriv[X];
00863                                 nhits++;
00864                                 bu_log( "\t\tadding fictitious entry at %f (%s)\n", hits[i].hit_dist, stp->st_name );
00865                                 bu_log( "\t\t\tray = (%g %g %g) -> (%g %g %g)\n", V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ) );
00866                             }
00867                         else if( dot1 < 0.0 && dot2 < 0.0 )
00868                             {
00869                                 /* two consectutive entrances,
00870                                  * manufacture an exit between them.
00871                                  */
00872                                 /* XXX This consumes an extra hit structure in the array */
00873 
00874                                 if( psp ) {
00875                                         /* using pieces */
00876                                         (void)rt_htbl_get(&psp->htab);  /* make sure space exists in the hit array */
00877                                         hits = psp->htab.hits;
00878                                 } else if( nhits + 1 >= MAXHITS ) {
00879                                         /* not using pieces */
00880                                         bu_log( "rt_bot_makesegs: too many hits on %s\n", stp->st_dp->d_namep );
00881                                         i++;
00882                                         continue;
00883                                 }
00884                                 for( j=nhits ; j>i ; j-- )
00885                                     hits[j] = hits[j-1];        /* struct copy */
00886 
00887                                 hits[i] = hits[i-1];    /* struct copy */
00888                                 hits[i].hit_vpriv[X] = -hits[i].hit_vpriv[X];
00889                                 dot2 = hits[i].hit_vpriv[X];
00890                                 nhits++;
00891                                 bu_log( "\t\tadding fictitious exit at %f (%s)\n", hits[i].hit_dist, stp->st_name );
00892                                 bu_log( "\t\t\tray = (%g %g %g) -> (%g %g %g)\n", V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ) );
00893                             }
00894                         i++;
00895                     }
00896             }
00897     }
00898 
00899     if( (nhits&1) )  {
00900 #if 1
00901         /* XXX This consumes an extra hit structure in the array */
00902         if( psp ) {
00903                 (void)rt_htbl_get(&psp->htab);  /* make sure space exists in the hit array */
00904                 hits = psp->htab.hits;
00905         }
00906         if( !psp && (nhits + 1 >= MAXHITS) ) {
00907                 bu_log( "rt_bot_makesegs: too many hits on %s\n", stp->st_dp->d_namep );
00908                 nhits--;
00909         } else {
00910                 hits[nhits] = hits[nhits-1];    /* struct copy */
00911                 hits[nhits].hit_vpriv[X] = -hits[nhits].hit_vpriv[X];
00912                 nhits++;
00913         }
00914 #else
00915         nhits--;
00916 #endif
00917     }
00918 
00919     /* nhits is even, build segments */
00920     for( i=0; i < nhits; i += 2 )  {
00921         XGLUE(tri_specific_,TRI_TYPE) *trip;
00922 
00923         RT_GET_SEG(segp, ap->a_resource);
00924         segp->seg_stp = stp;
00925         segp->seg_in = hits[i]; /* struct copy */
00926         trip = (XGLUE(tri_specific_,TRI_TYPE) *)hits[i].hit_private;
00927         RT_BOT_UNORIENTED_NORM( &segp->seg_in, 1 );
00928         segp->seg_out = hits[i+1];      /* struct copy */
00929         trip = (XGLUE(tri_specific_,TRI_TYPE) *)hits[i+1].hit_private;
00930         RT_BOT_UNORIENTED_NORM( &segp->seg_out, -1 );
00931         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00932     }
00933 
00934     return(nhits);                      /* HIT */
00935 }
00936 
00937 /**
00938  *                      R T _ B O T _ S H O T
00939  *
00940  *  Intersect a ray with a bot.
00941  *  If an intersection occurs, a struct seg will be acquired
00942  *  and filled in.
00943  *
00944  *      Notes for rt_bot_norm():
00945  *              hit_private contains pointer to the tri_specific structure
00946  *              hit_vpriv[X] contains dot product of ray direction and unit normal from tri_specific
00947  *
00948  *  Returns -
00949  *      0       MISS
00950  *      >0      HIT
00951  */
00952 int
00953 XGLUE(rt_bot_shot_,TRI_TYPE)( struct soltab *stp, struct xray *rp, struct application *ap, struct seg *seghead )
00954 {
00955         struct bot_specific *bot = (struct bot_specific *)stp->st_specific;
00956         register XGLUE(tri_specific_,TRI_TYPE) *trip = bot->bot_facelist;
00957         LOCAL struct hit hits[MAXHITS];
00958         register struct hit *hp;
00959         LOCAL int       nhits;
00960         fastf_t         toldist, dn_plus_tol;
00961 
00962         nhits = 0;
00963         hp = &hits[0];
00964         if( bot->bot_orientation != RT_BOT_UNORIENTED && bot->bot_mode == RT_BOT_SOLID ) {
00965                 toldist = stp->st_aradius / 10.0e+6;
00966         } else {
00967                 toldist = 0.0;
00968         }
00969 
00970         /* consider each face */
00971         for( ; trip; trip = trip->tri_forw )  {
00972                 FAST fastf_t    dn;             /* Direction dot Normal */
00973                 LOCAL fastf_t   abs_dn;
00974                 FAST fastf_t    k;
00975                 LOCAL fastf_t   alpha, beta;
00976                 LOCAL vect_t    wxb;            /* vertex - ray_start */
00977                 LOCAL vect_t    xp;             /* wxb cross ray_dir */
00978 
00979                 /*
00980                  *  Ray Direction dot N.  (N is outward-pointing normal)
00981                  *  wn points inwards, and is not unit length.
00982                  */
00983                 dn = VDOT( trip->tri_wn, rp->r_dir );
00984 
00985                 /*
00986                  *  If ray lies directly along the face, (ie, dot product
00987                  *  is zero), drop this face.
00988                  */
00989                 abs_dn = dn >= 0.0 ? dn : (-dn);
00990                 if( abs_dn < BOT_MIN_DN ) {
00991                         continue;
00992                 }
00993                 VSUB2( wxb, trip->tri_A, rp->r_pt );
00994                 VCROSS( xp, wxb, rp->r_dir );
00995 
00996                 dn_plus_tol = toldist + abs_dn;
00997 
00998                 /* Check for exceeding along the one side */
00999                 alpha = VDOT( trip->tri_CA, xp );
01000                 if( dn < 0.0 )  alpha = -alpha;
01001                 if( alpha < -toldist || alpha > dn_plus_tol ) {
01002                         continue;
01003                 }
01004 
01005                 /* Check for exceeding along the other side */
01006                 beta = VDOT( trip->tri_BA, xp );
01007                 if( dn > 0.0 )  beta = -beta;
01008                 if( beta < -toldist || beta > dn_plus_tol ) {
01009                         continue;
01010                 }
01011                 if( alpha+beta > dn_plus_tol ) {
01012                         continue;
01013                 }
01014                 k = VDOT( wxb, trip->tri_wn ) / dn;
01015                 /* HIT is within planar face */
01016                 hp->hit_magic = RT_HIT_MAGIC;
01017                 hp->hit_dist = k;
01018                 hp->hit_private = (genptr_t)trip;
01019                 hp->hit_vpriv[X] = VDOT( trip->tri_N, rp->r_dir );
01020                 hp->hit_vpriv[Y] = alpha / abs_dn;
01021                 hp->hit_vpriv[Z] = beta / abs_dn;
01022                 hp->hit_surfno = trip->tri_surfno;
01023                 hp->hit_rayp = &ap->a_ray;
01024                 if( ++nhits >= MAXHITS )  {
01025                         bu_log("rt_bot_shot(%s): too many hits (%d)\n", stp->st_name, nhits);
01026                         break;
01027                 }
01028                 hp++;
01029         }
01030         if( nhits == 0 )
01031                 return(0);              /* MISS */
01032 
01033         /* Sort hits, Near to Far */
01034         rt_hitsort( hits, nhits );
01035 
01036         /* build segments */
01037         return rt_bot_makesegs( hits, nhits, stp, rp, ap, seghead, NULL );
01038 }
01039 
01040 /**
01041  *                      R T _ B O T _ P I E C E _ S H O T
01042  *
01043  *  Intersect a ray with a list of "pieces" of a BoT.
01044  *
01045  *  This routine may be invoked many times for a single ray,
01046  *  as the ray traverses from one space partitioning cell to the next.
01047  *
01048  *  Plate-mode (2 hit) segments will be returned immediately in seghead.
01049  *
01050  *  Generally the hits are stashed between invocations in psp.
01051  */
01052 int
01053 XGLUE(rt_bot_piece_shot_,TRI_TYPE)( struct rt_piecestate *psp, struct rt_piecelist *plp,
01054                                     double dist_corr, struct xray *rp, struct application *ap, struct seg *seghead )
01055 {
01056         struct resource         *resp;
01057         long            *sol_piece_subscr_p;
01058         struct soltab   *stp;
01059         long            piecenum;
01060         register struct hit *hp;
01061         struct bot_specific *bot;
01062         const int       debug_shoot = RT_G_DEBUG & DEBUG_SHOOT;
01063         int             starting_hits;
01064         fastf_t         toldist, dn_plus_tol;
01065         int             trinum;
01066 
01067         RT_CK_PIECELIST(plp);
01068         stp = plp->stp;
01069 
01070         RT_CK_APPLICATION(ap);
01071         resp = ap->a_resource;
01072         RT_CK_RESOURCE(resp);
01073 
01074         RT_CK_SOLTAB(stp);
01075         bot = (struct bot_specific *)stp->st_specific;
01076 
01077         RT_CK_PIECESTATE(psp);
01078         starting_hits = psp->htab.end;
01079 
01080         if( bot->bot_orientation != RT_BOT_UNORIENTED &&
01081             bot->bot_mode == RT_BOT_SOLID ) {
01082 
01083                 toldist = psp->stp->st_aradius / 10.0e+6;
01084         } else {
01085                 toldist = 0.0;
01086         }
01087 
01088         if( debug_shoot ) {
01089                 bu_log( "In rt_bot_piece_shot(), looking at %d pieces\n", plp->npieces );
01090         }
01091         sol_piece_subscr_p = &(plp->pieces[plp->npieces-1]);
01092         for( ; sol_piece_subscr_p >= plp->pieces; sol_piece_subscr_p-- )  {
01093                 FAST fastf_t    dn;             /* Direction dot Normal */
01094                 LOCAL fastf_t   abs_dn;
01095                 FAST fastf_t    k;
01096                 LOCAL fastf_t   alpha, beta;
01097                 LOCAL vect_t    wxb;            /* vertex - ray_start */
01098                 LOCAL vect_t    xp;             /* wxb cross ray_dir */
01099                 LOCAL int       face_array_index;
01100                 LOCAL int       tris_in_piece;
01101 
01102                 piecenum = *sol_piece_subscr_p;
01103 
01104                 if( BU_BITTEST( psp->shot, piecenum ) )  {
01105                         if(debug_shoot)
01106                             bu_log("%s piece %d already shot\n",
01107                                    stp->st_name, piecenum);
01108 
01109                         resp->re_piece_ndup++;
01110                         continue;       /* this piece already shot */
01111                 }
01112 
01113                 /* Shoot a ray */
01114                 BU_BITSET( psp->shot, piecenum );
01115                 if(debug_shoot)
01116                     bu_log("%s piece %d ...\n", stp->st_name, piecenum);
01117 
01118                 /* Now intersect with each piece, which means
01119                  * intesecting with each triangle that makes up
01120                  * the piece.
01121                  */
01122                 face_array_index = piecenum*bot->bot_tri_per_piece;
01123                 tris_in_piece = bot->bot_ntri - face_array_index;
01124                 if( tris_in_piece > bot->bot_tri_per_piece ) {
01125                         tris_in_piece = bot->bot_tri_per_piece;
01126                 }
01127                 for( trinum=0; trinum<tris_in_piece; trinum++ ) {
01128                     register XGLUE(tri_specific_,TRI_TYPE) *trip = bot->bot_facearray[face_array_index+trinum];
01129                     fastf_t                                 dN, abs_dN;
01130                     /*
01131                      *  Ray Direction dot N.  (N is outward-pointing normal)
01132                      *  wn points inwards, and is not unit length.
01133                      *  Therefore, wn is not a good choice for this test
01134                      */
01135                     dn = VDOT( trip->tri_wn, rp->r_dir );
01136                     dN = VDOT( trip->tri_N, rp->r_dir );
01137 
01138                     /*
01139                      *  If ray lies directly along the face, (ie, dot product
01140                      *  is zero), drop this face.
01141                      */
01142                     abs_dN = dN >= 0.0 ? dN : (-dN);
01143                     abs_dn = dn >= 0.0 ? dn : (-dn);
01144                     if( abs_dN < BOT_MIN_DN ) {
01145                         continue;
01146                     }
01147                     VSUB2( wxb, trip->tri_A, rp->r_pt );
01148                     VCROSS( xp, wxb, rp->r_dir );
01149 
01150                     dn_plus_tol = toldist + abs_dn;
01151 
01152                     /* Check for exceeding along the one side */
01153                     alpha = VDOT( trip->tri_CA, xp );
01154                     if( dn < 0.0 )  alpha = -alpha;
01155                     if( alpha < -toldist || alpha > dn_plus_tol ) {
01156                         continue;
01157                     }
01158 
01159                     /* Check for exceeding along the other side */
01160                     beta = VDOT( trip->tri_BA, xp );
01161                     if( dn > 0.0 )  beta = -beta;
01162                     if( beta < -toldist || beta > dn_plus_tol ) {
01163                         continue;
01164                     }
01165                     if( alpha+beta > dn_plus_tol ) {
01166                         continue;
01167                     }
01168                     k = VDOT( wxb, trip->tri_wn ) / dn;
01169 
01170                     /* HIT is within planar face */
01171                     hp = rt_htbl_get( &psp->htab );
01172                     hp->hit_magic = RT_HIT_MAGIC;
01173                     hp->hit_dist = k + dist_corr;
01174                     hp->hit_private = (genptr_t)trip;
01175                     hp->hit_vpriv[X] = VDOT( trip->tri_N, rp->r_dir );
01176                     hp->hit_vpriv[Y] = alpha / abs_dn;
01177                     hp->hit_vpriv[Z] = beta / abs_dn;
01178                     hp->hit_surfno = trip->tri_surfno;
01179                     hp->hit_rayp = &ap->a_ray;
01180                     if(debug_shoot)
01181                         bu_log("%s piece %d surfno %d ... HIT %g\n",
01182                                stp->st_name, piecenum, trip->tri_surfno, hp->hit_dist);
01183                 } /* for (trinum...) */
01184         } /* for (;sol_piece_subscr_p...) */
01185 
01186         if( psp->htab.end > 0 &&
01187             (bot->bot_mode == RT_BOT_PLATE ||
01188              bot->bot_mode == RT_BOT_PLATE_NOCOS) ) {
01189                 /*
01190                  * Each of these hits is really two, resulting in an instant
01191                  * seg.  Saving an odd number of these will confuse a_onehit
01192                  * processing.
01193                  */
01194                 rt_hitsort( psp->htab.hits, psp->htab.end );
01195                 return rt_bot_makesegs( psp->htab.hits, psp->htab.end,
01196                                         stp, rp, ap, seghead, psp );
01197         }
01198         return psp->htab.end - starting_hits;
01199 }
01200 
01201 /**
01202  *                      R T _ B O T _ N O R M
01203  *
01204  *  Given ONE ray distance, return the normal and entry/exit point.
01205  */
01206 void
01207 XGLUE(rt_bot_norm_,TRI_TYPE)( bot, hitp, stp, rp )
01208 struct bot_specific     *bot;
01209 register struct hit     *hitp;
01210 struct soltab           *stp;
01211 register struct xray    *rp;
01212 {
01213         XGLUE(tri_specific_,TRI_TYPE) *trip=(XGLUE(tri_specific_,TRI_TYPE) *)hitp->hit_private;
01214         vect_t old_norm;
01215 
01216         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
01217         VMOVE( old_norm, hitp->hit_normal );
01218 
01219         if( (bot->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) && (bot->bot_flags & RT_BOT_USE_NORMALS) && trip->tri_normals ) {
01220                 fastf_t old_ray_dot_norm, new_ray_dot_norm;
01221                 fastf_t u, v, w; /*barycentric coords of hit point */
01222                 int i;
01223 
01224                 old_ray_dot_norm = VDOT( hitp->hit_normal, rp->r_dir );
01225 
01226                 v = hitp->hit_vpriv[Y];
01227                 if( v < 0.0 ) v = 0.0;
01228                 if( v > 1.0 ) v = 1.0;
01229 
01230                 w = hitp->hit_vpriv[Z];
01231                 if( w < 0.0 ) w = 0.0;
01232                 if( w > 1.0 ) w =  1.0;
01233 
01234                 u = 1.0 - v - w;
01235                 if( u < 0.0 ) u = 0.0;
01236                 VSETALL( hitp->hit_normal, 0.0 );
01237 
01238                 for( i=X ; i<=Z ; i++ ) {
01239                         hitp->hit_normal[i] = u*trip->tri_normals[i]*ONE_OVER_SCALE + v*trip->tri_normals[i+3]*ONE_OVER_SCALE + w*trip->tri_normals[i+6]*ONE_OVER_SCALE;
01240                 }
01241                 VUNITIZE( hitp->hit_normal );
01242 
01243                 if( bot->bot_mode == RT_BOT_PLATE || bot->bot_mode == RT_BOT_PLATE_NOCOS ) {
01244                         if( VDOT( old_norm, hitp->hit_normal ) < 0.0 ) {
01245                                 VREVERSE( hitp->hit_normal, hitp->hit_normal );
01246                         }
01247                 }
01248 
01249                 new_ray_dot_norm = VDOT( hitp->hit_normal, rp->r_dir );
01250 
01251                 if( (old_ray_dot_norm < 0.0 && new_ray_dot_norm > 0.0) ||
01252                     (old_ray_dot_norm > 0.0 && new_ray_dot_norm < 0.0) ) {
01253                         /* surface normal interpolation has produced an incompatible normal direction
01254                          * clamp the normal to 90 degrees to the ray direction
01255                          */
01256 
01257                         vect_t tmp;
01258 
01259                         VCROSS( tmp, rp->r_dir, hitp->hit_normal );
01260                         VCROSS( hitp->hit_normal, tmp, rp->r_dir );
01261                 }
01262 
01263                 VUNITIZE( hitp->hit_normal );
01264         }
01265 }
01266 
01267 /**
01268  *              R T _ B O T _ F R E E
01269  */
01270 void
01271 XGLUE(rt_bot_free_,TRI_TYPE)( bot )
01272 register struct bot_specific *bot;
01273 {
01274         register XGLUE(tri_specific_,TRI_TYPE) *tri, *ptr;
01275 
01276         if( bot->bot_facearray ) {
01277                 bu_free( (char *)bot->bot_facearray, "bot_facearray" );
01278                 bot->bot_facearray = NULL;
01279         }
01280 
01281         if( bot->bot_thickness ) {
01282                 bu_free( (char *)bot->bot_thickness, "bot_thickness" );
01283                 bot->bot_thickness = NULL;
01284         }
01285         if( bot->bot_facemode ) {
01286                 bu_free( (char *)bot->bot_facemode, "bot_facemode" );
01287                 bot->bot_facemode = NULL;
01288         }
01289         ptr = bot->bot_facelist;
01290         while( ptr )
01291         {
01292                 tri = ptr->tri_forw;
01293                 if( ptr ) {
01294                         if( ptr->tri_normals ) {
01295                                 bu_free( (char *)ptr->tri_normals, "bot tri_specific normals" );
01296                         }
01297                         bu_free( (char *)ptr, "bot tri_specific" );
01298                 }
01299                 ptr = tri;
01300         }
01301         bot->bot_facelist = NULL;
01302         bu_free( (char *)bot, "bot_specific" );
01303 }
01304 
01305 /*@}*/
01306 
01307 /*
01308  * Local Variables:
01309  * mode: C
01310  * tab-width: 8
01311  * c-basic-offset: 4
01312  * indent-tabs-mode: t
01313  * End:
01314  * ex: shiftwidth=4 tabstop=8
01315  */

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