vshoot.c

Go to the documentation of this file.
00001 /*                        V S H O O T . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1985-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 ray */
00023 /*@{*/
00024 
00025 /** @file vshoot.c
00026  *  EXPERIMENTAL vector version of the
00027  * Ray Tracing program shot coordinator.
00028  *
00029  *  Author -
00030  *      Michael John Muuss
00031  *
00032  *  Source -
00033  *      SECAD/VLD Computing Consortium, Bldg 394
00034  *      The U. S. Army Ballistic Research Laboratory
00035  *      Aberdeen Proving Ground, Maryland  21005
00036  *
00037  */
00038 
00039 #ifndef lint
00040 static const char RCSshoot[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/vshoot.c,v 14.13 2006/09/16 02:04:26 lbutler Exp $ (BRL)";
00041 #endif
00042 
00043 #include "common.h"
00044 
00045 #include <stdio.h>
00046 #include <math.h>
00047 #include "machine.h"
00048 #include "vmath.h"
00049 #include "raytrace.h"
00050 #include "./debug.h"
00051 
00052 struct resource rt_uniresource;         /* Resources for uniprocessor */
00053 
00054 /*
00055  *                      R T _ S H O O T R A Y
00056  *
00057  *  Given a ray, shoot it at all the relevant parts of the model,
00058  *  (building the HeadSeg chain), and then call rt_boolregions()
00059  *  to build and evaluate the partition chain.
00060  *  If the ray actually hit anything, call the application's
00061  *  a_hit() routine with a pointer to the partition chain,
00062  *  otherwise, call the application's a_miss() routine.
00063  *
00064  *  It is important to note that rays extend infinitely only in the
00065  *  positive direction.  The ray is composed of all points P, where
00066  *
00067  *      P = r_pt + K * r_dir
00068  *
00069  *  for K ranging from 0 to +infinity.  There is no looking backwards.
00070  *
00071  *  It is also important to note that the direction vector r_dir
00072  *  must have unit length;  this is mandatory, and is not ordinarily checked,
00073  *  in the name of efficiency.
00074  *
00075  *  Input:  Pointer to an application structure, with these mandatory fields:
00076  *      a_ray.r_pt      Starting point of ray to be fired
00077  *      a_ray.r_dir     UNIT VECTOR with direction to fire in (dir cosines)
00078  *      a_hit           Routine to call when something is hit
00079  *      a_miss          Routine to call when ray misses everything
00080  *
00081  *  Calls user's a_miss() or a_hit() routine as appropriate.
00082  *  Passes a_hit() routine list of partitions, with only hit_dist
00083  *  fields valid.  Normal computation deferred to user code,
00084  *  to avoid needless computation here.
00085  *
00086  *  Returns: whatever the application function returns (an int).
00087  *
00088  *  NOTE:  The appliction functions may call rt_shootray() recursively.
00089  *      Thus, none of the local variables may be static.
00090  *
00091  *  An open issue for execution in a PARALLEL environment is locking
00092  *  of the statistics variables.
00093  */
00094 int
00095 rt_shootray( struct application *ap )
00096 {
00097         struct seg              *HeadSeg;
00098         int             ret;
00099         auto vect_t             inv_dir;        /* inverses of ap->a_ray.r_dir */
00100         union bitv_elem *solidbits;     /* bits for all solids shot so far */
00101         bitv_t          *regionbits;    /* bits for all involved regions */
00102         char            *status;
00103         auto struct partition   InitialPart;    /* Head of Initial Partitions */
00104         auto struct partition   FinalPart;      /* Head of Final Partitions */
00105         int                     nrays = 1;      /* for now */
00106         int                     vlen;
00107         int                     id;
00108         int                     i;
00109         struct soltab           **ary_stp;      /* array of pointers */
00110         struct xray             **ary_rp;       /* array of pointers */
00111         struct seg              *ary_seg;       /* array of structures */
00112         struct rt_i             *rtip;
00113 
00114 #define BACKING_DIST    (-2.0)          /* mm to look behind start point */
00115         rtip = ap->a_rt_i;
00116         RT_AP_CHECK(ap);
00117         if( ap->a_resource == RESOURCE_NULL )  {
00118                 ap->a_resource = &rt_uniresource;
00119                 rt_uniresource.re_magic = RESOURCE_MAGIC;
00120         }
00121         RT_CK_RESOURCE(ap->a_resource);
00122 
00123         if(RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION)) {
00124                 rt_g.rtg_logindent += 2;
00125                 bu_log("\n**********mshootray cpu=%d  %d,%d lvl=%d (%s)\n",
00126                         ap->a_resource->re_cpu,
00127                         ap->a_x, ap->a_y,
00128                         ap->a_level,
00129                         ap->a_purpose != (char *)0 ? ap->a_purpose : "?" );
00130                 VPRINT("Pnt", ap->a_ray.r_pt);
00131                 VPRINT("Dir", ap->a_ray.r_dir);
00132         }
00133 
00134         rtip->rti_nrays++;
00135         if( rtip->needprep )
00136                 rt_prep(rtip);
00137 
00138         /* Allocate dynamic memory */
00139         vlen = nrays * rtip->rti_maxsol_by_type;
00140         ary_stp = (struct soltab **)bu_calloc( vlen, sizeof(struct soltab *),
00141                 "*ary_stp[]" );
00142         ary_rp = (struct xray **)bu_calloc( vlen, sizeof(struct xray *),
00143                 "*ary_rp[]" );
00144         ary_seg = (struct seg *)bu_calloc( vlen, sizeof(struct seg),
00145                 "ary_seg[]" );
00146 
00147         /**** for each ray, do this ****/
00148 
00149         InitialPart.pt_forw = InitialPart.pt_back = &InitialPart;
00150         FinalPart.pt_forw = FinalPart.pt_back = &FinalPart;
00151 
00152         HeadSeg = SEG_NULL;
00153 
00154         GET_BITV( rtip, solidbits, ap->a_resource );    /* see rt_get_bitv() for details */
00155         bzero( (char *)solidbits, rtip->rti_bv_bytes );
00156         regionbits = &solidbits->be_v[
00157                 2+RT_BITV_BITS2WORDS(ap->a_rt_i->nsolids)];
00158 
00159         /* Compute the inverse of the direction cosines */
00160         if( !NEAR_ZERO( ap->a_ray.r_dir[X], SQRT_SMALL_FASTF ) )  {
00161                 inv_dir[X]=1.0/ap->a_ray.r_dir[X];
00162         } else {
00163                 inv_dir[X] = INFINITY;
00164                 ap->a_ray.r_dir[X] = 0.0;
00165         }
00166         if( !NEAR_ZERO( ap->a_ray.r_dir[Y], SQRT_SMALL_FASTF ) )  {
00167                 inv_dir[Y]=1.0/ap->a_ray.r_dir[Y];
00168         } else {
00169                 inv_dir[Y] = INFINITY;
00170                 ap->a_ray.r_dir[Y] = 0.0;
00171         }
00172         if( !NEAR_ZERO( ap->a_ray.r_dir[Z], SQRT_SMALL_FASTF ) )  {
00173                 inv_dir[Z]=1.0/ap->a_ray.r_dir[Z];
00174         } else {
00175                 inv_dir[Z] = INFINITY;
00176                 ap->a_ray.r_dir[Z] = 0.0;
00177         }
00178 
00179         /*
00180          *  XXX handle infinite solids here, later.
00181          */
00182 
00183         /*
00184          *  If ray does not enter the model RPP, skip on.
00185          *  If ray ends exactly at the model RPP, trace it.
00186          */
00187         if( !rt_in_rpp( &ap->a_ray, inv_dir, rtip->mdl_min, rtip->mdl_max )  ||
00188             ap->a_ray.r_max < 0.0 )  {
00189                 rtip->nmiss_model++;
00190                 ret = ap->a_miss( ap );
00191                 status = "MISS model";
00192                 goto out;
00193         }
00194 
00195         /* For each type of solid to be shot at, assemble the vectors */
00196         for( id = 1; id <= ID_MAX_SOLID; id++ )  {
00197                 register int    nsol;
00198 
00199                 if( (nsol = rtip->rti_nsol_by_type[id]) <= 0 )  continue;
00200 
00201                 /* For each instance of this solid type */
00202                 for( i = nsol-1; i >= 0; i-- )  {
00203                         ary_stp[i] = rtip->rti_sol_by_type[id][i];
00204                         ary_rp[i] = &(ap->a_ray);       /* XXX, sb [ray] */
00205                         ary_seg[i].seg_stp = SOLTAB_NULL;
00206                         ary_seg[i].seg_next = SEG_NULL;
00207                 }
00208                 /* bounding box check */
00209                 /* bit vector per ray check */
00210                 /* mark elements to be skipped with ary_stp[] = SOLTAB_NULL */
00211                 ap->a_rt_i->nshots += nsol;     /* later: skipped ones */
00212                 rt_functab[id].ft_vshot(
00213                         ary_stp, ary_rp, ary_seg,
00214                         nsol, ap->a_resource );
00215 
00216                 /* set bits for all solids shot at for each ray */
00217 
00218                 /* append resulting seg list to input for boolweave */
00219                 for( i = nsol-1; i >= 0; i-- )  {
00220                         register struct seg     *seg2;
00221 
00222                         if( ary_seg[i].seg_stp == SOLTAB_NULL )  {
00223                                 /* MISS */
00224                                 ap->a_rt_i->nmiss++;
00225                                 continue;
00226                         }
00227                         ap->a_rt_i->nhits++;
00228 
00229                         /* For now, do it the slow way.  sb [ray] */
00230                         /* MUST dup it -- all segs have to live till after a_hit() */
00231                         GET_SEG( seg2, ap->a_resource );
00232                         *seg2 = ary_seg[i];     /* struct copy */
00233                         rt_boolweave( seg2, &InitialPart, ap );
00234 
00235                         /* Add seg chain to list of used segs awaiting reclaim */
00236                         {
00237                                 register struct seg *seg3 = seg2;
00238                                 while( seg3->seg_next != SEG_NULL )
00239                                         seg3 = seg3->seg_next;
00240                                 seg3->seg_next = HeadSeg;
00241                                 HeadSeg = seg2;
00242                         }
00243                 }
00244 
00245                 /* OR in regionbits */
00246                 for( i = nsol-1; i >= 0; i-- )  {
00247                         register int words;
00248                         register bitv_t *in = ary_stp[i]->st_regions;
00249                         register bitv_t *out = regionbits;      /* XXX sb [ray] */
00250 
00251                         words = RT_BITV_BITS2WORDS(ary_stp[i]->st_maxreg);
00252 #                       include "noalias.h"
00253                         for( --words; words >= 0; words-- )
00254                                 regionbits[words] |= in[words];
00255                 }
00256         }
00257 
00258         /*
00259          *  Ray has finally left known space.
00260          */
00261         if( InitialPart.pt_forw == &InitialPart )  {
00262                 ret = ap->a_miss( ap );
00263                 status = "MISSed all primitives";
00264                 goto freeup;
00265         }
00266 
00267         /*
00268          *  All intersections of the ray with the model have
00269          *  been computed.  Evaluate the boolean trees over each partition.
00270          */
00271         rt_boolfinal( &InitialPart, &FinalPart, BACKING_DIST,
00272                 INFINITY,
00273                 regionbits, ap);
00274 
00275         if( FinalPart.pt_forw == &FinalPart )  {
00276                 ret = ap->a_miss( ap );
00277                 status = "MISS bool";
00278                 goto freeup;
00279         }
00280 
00281         /*
00282          *  Ray/model intersections exist.  Pass the list to the
00283          *  user's a_hit() routine.  Note that only the hit_dist
00284          *  elements of pt_inhit and pt_outhit have been computed yet.
00285          *  To compute both hit_point and hit_normal, use the
00286          *
00287          *      RT_HIT_NORM( hitp, stp, rayp )
00288          *
00289          *  macro.  To compute just hit_point, use
00290          *
00291          *  VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
00292          */
00293 hitit:
00294         if(RT_G_DEBUG&DEBUG_SHOOT)  rt_pr_partitions(rtip,&FinalPart,"a_hit()");
00295 
00296         ret = ap->a_hit( ap, &FinalPart );
00297         status = "HIT";
00298 
00299         /*
00300          * Processing of this ray is complete.  Free dynamic resources.
00301          */
00302 freeup:
00303         {
00304                 register struct partition *pp;
00305 
00306                 /* Free up initial partition list */
00307                 for( pp = InitialPart.pt_forw; pp != &InitialPart;  )  {
00308                         register struct partition *newpp;
00309                         newpp = pp;
00310                         pp = pp->pt_forw;
00311                         FREE_PT(newpp, ap->a_resource);
00312                 }
00313                 /* Free up final partition list */
00314                 for( pp = FinalPart.pt_forw; pp != &FinalPart;  )  {
00315                         register struct partition *newpp;
00316                         newpp = pp;
00317                         pp = pp->pt_forw;
00318                         FREE_PT(newpp, ap->a_resource);
00319                 }
00320         }
00321         /* Segs can't be freed until after a_hit() has returned */
00322         {
00323                 register struct seg *segp;
00324 
00325                 while( HeadSeg != SEG_NULL )  {
00326                         segp = HeadSeg->seg_next;
00327                         FREE_SEG( HeadSeg, ap->a_resource );
00328                         HeadSeg = segp;
00329                 }
00330         }
00331 
00332 out:
00333         bu_free( (char *)ary_stp, "*ary_stp[]" );
00334         bu_free( (char *)ary_rp, "*ary_rp[]" );
00335         bu_free( (char *)ary_seg, "ary_seg[]" );
00336 
00337         if( solidbits != BITV_NULL)  {
00338                 FREE_BITV( solidbits, ap->a_resource );
00339         }
00340         if(RT_G_DEBUG&(DEBUG_ALLRAYS|DEBUG_SHOOT|DEBUG_PARTITION))  {
00341                 if( rt_g.rtg_logindent > 0 )
00342                         rt_g.rtg_logindent -= 2;
00343                 else
00344                         rt_g.rtg_logindent = 0;
00345                 bu_log("----------mshootray cpu=%d  %d,%d lvl=%d (%s) %s ret=%d\n",
00346                         ap->a_resource->re_cpu,
00347                         ap->a_x, ap->a_y,
00348                         ap->a_level,
00349                         ap->a_purpose != (char *)0 ? ap->a_purpose : "?",
00350                         status, ret);
00351         }
00352         return( ret );
00353 }
00354 
00355 #define SEG_MISS(SEG)           (SEG).seg_stp=(struct soltab *) 0;
00356 
00357 /* Stub function which will "similate" a call to a vector shot routine */
00358 /*void*/
00359 rt_vstub(struct soltab *stp[],  /* An array of solid pointers */
00360          struct xray *rp[],     /* An array of ray pointers */
00361          struct seg segp[],     /* array of segs (results returned) */
00362          int n,                 /* Number of ray/object pairs */
00363          struct resource *resp)
00364 {
00365         register int    i;
00366         register struct seg *tmp_seg;
00367 
00368         /* go through each ray/solid pair and call a scalar function */
00369         for (i = 0; i < n; i++) {
00370                 if (stp[i] != 0){ /* skip call if solid table pointer is NULL */
00371                         /* do scalar call */
00372                         tmp_seg = rt_functab[stp[i]->st_id].ft_shot(
00373                                 stp[i], rp[i], resp);
00374 
00375                         /* place results in segp array */
00376                         if ( tmp_seg == 0) {
00377                                 SEG_MISS(segp[i]);
00378                         }
00379                         else {
00380                                 segp[i] = *tmp_seg; /* structure copy */
00381                                 FREE_SEG(tmp_seg, resp);
00382                         }
00383                 }
00384         }
00385 }
00386 
00387 /*
00388  *                      R T _ I N _ R P P
00389  *
00390  *  Compute the intersections of a ray with a rectangular parallelpiped (RPP)
00391  *  that has faces parallel to the coordinate planes
00392  *
00393  *  The algorithm here was developed by Gary Kuehl for GIFT.
00394  *  A good description of the approach used can be found in
00395  *  "??" by XYZZY and Barsky,
00396  *  ACM Transactions on Graphics, Vol 3 No 1, January 1984.
00397  *
00398  * Note -
00399  *  The computation of entry and exit distance is mandatory, as the final
00400  *  test catches the majority of misses.
00401  *
00402  *  Returns -
00403  *       0  if ray does not hit RPP,
00404  *      !0  if ray hits RPP.
00405  *
00406  *  invdir is the inverses of rp->r_dir[]
00407  *
00408  *  Implicit return -
00409  *      rp->r_min = dist from start of ray to point at which ray ENTERS solid
00410  *      rp->r_max = dist from start of ray to point at which ray LEAVES solid
00411  */
00412 rt_in_rpp( struct xray *rp, fastf_t *invdir, fastf_t *min, fastf_t *max )
00413 {
00414         register fastf_t *pt = &rp->r_pt[0];
00415         FAST fastf_t sv;
00416 #define st sv                   /* reuse the register */
00417 
00418         /* Start with infinite ray, and trim it down */
00419         rp->r_min = -INFINITY;
00420         rp->r_max = INFINITY;
00421 
00422         /* X axis */
00423         if( rp->r_dir[X] < 0.0 )  {
00424                 /* Heading towards smaller numbers */
00425                 /* if( *min > *pt )  miss */
00426                 if( (sv = (*min - *pt) * *invdir) < 0.0 )
00427                         return(0);      /* MISS */
00428                 if(rp->r_max > sv)
00429                         rp->r_max = sv;
00430                 if( rp->r_min < (st = (*max - *pt) * *invdir) )
00431                         rp->r_min = st;
00432         }  else if( rp->r_dir[X] > 0.0 )  {
00433                 /* Heading towards larger numbers */
00434                 /* if( *max < *pt )  miss */
00435                 if( (st = (*max - *pt) * *invdir) < 0.0 )
00436                         return(0);      /* MISS */
00437                 if(rp->r_max > st)
00438                         rp->r_max = st;
00439                 if( rp->r_min < ((sv = (*min - *pt) * *invdir)) )
00440                         rp->r_min = sv;
00441         }  else  {
00442                 /*
00443                  *  Direction cosines along this axis is NEAR 0,
00444                  *  which implies that the ray is perpendicular to the axis,
00445                  *  so merely check position against the boundaries.
00446                  */
00447                 if( (*min > *pt) || (*max < *pt) )
00448                         return(0);      /* MISS */
00449         }
00450 
00451         /* Y axis */
00452         pt++; invdir++; max++; min++;
00453         if( rp->r_dir[Y] < 0.0 )  {
00454                 if( (sv = (*min - *pt) * *invdir) < 0.0 )
00455                         return(0);      /* MISS */
00456                 if(rp->r_max > sv)
00457                         rp->r_max = sv;
00458                 if( rp->r_min < (st = (*max - *pt) * *invdir) )
00459                         rp->r_min = st;
00460         }  else if( rp->r_dir[Y] > 0.0 )  {
00461                 if( (st = (*max - *pt) * *invdir) < 0.0 )
00462                         return(0);      /* MISS */
00463                 if(rp->r_max > st)
00464                         rp->r_max = st;
00465                 if( rp->r_min < ((sv = (*min - *pt) * *invdir)) )
00466                         rp->r_min = sv;
00467         }  else  {
00468                 if( (*min > *pt) || (*max < *pt) )
00469                         return(0);      /* MISS */
00470         }
00471 
00472         /* Z axis */
00473         pt++; invdir++; max++; min++;
00474         if( rp->r_dir[Z] < 0.0 )  {
00475                 if( (sv = (*min - *pt) * *invdir) < 0.0 )
00476                         return(0);      /* MISS */
00477                 if(rp->r_max > sv)
00478                         rp->r_max = sv;
00479                 if( rp->r_min < (st = (*max - *pt) * *invdir) )
00480                         rp->r_min = st;
00481         }  else if( rp->r_dir[Z] > 0.0 )  {
00482                 if( (st = (*max - *pt) * *invdir) < 0.0 )
00483                         return(0);      /* MISS */
00484                 if(rp->r_max > st)
00485                         rp->r_max = st;
00486                 if( rp->r_min < ((sv = (*min - *pt) * *invdir)) )
00487                         rp->r_min = sv;
00488         }  else  {
00489                 if( (*min > *pt) || (*max < *pt) )
00490                         return(0);      /* MISS */
00491         }
00492 
00493         /* If equal, RPP is actually a plane */
00494         if( rp->r_min > rp->r_max )
00495                 return(0);      /* MISS */
00496         return(1);              /* HIT */
00497 }
00498 
00499 /*
00500  *                      R T _ B I T V _ O R
00501  */
00502 void
00503 rt_bitv_or( bitv_t *out, bitv_t *in, int nbits )
00504 {
00505         register int words;
00506 
00507         words = RT_BITV_BITS2WORDS(nbits);
00508 #ifdef VECTORIZE
00509 #       include "noalias.h"
00510         for( --words; words >= 0; words-- )
00511                 out[words] |= in[words];
00512 #else
00513         while( words-- > 0 )
00514                 *out++ |= *in++;
00515 #endif
00516 }
00517 
00518 /*
00519  *                      R T _ G E T _ B I T V
00520  *
00521  *  This routine is called by the GET_BITV macro when the freelist
00522  *  is exhausted.  Rather than simply getting one additional structure,
00523  *  we get a whole batch, saving overhead.  When this routine is called,
00524  *  the bitv resource must already be locked.
00525  *  malloc() locking is done in bu_malloc.
00526  *
00527  *  Also note that there is a bit of trickery going on here:
00528  *  the *real* size of be_v[] array is determined at runtime, here.
00529  */
00530 void
00531 rt_get_bitv(struct rt_i *rtip, struct resource *res)
00532 {
00533         register char *cp;
00534         register int bytes;
00535         register int size;              /* size of structure to really get */
00536 
00537         size = rtip->rti_bv_bytes;
00538         size = (size+sizeof(long)-1) & ~(sizeof(long)-1);
00539         bytes = bu_malloc_len_roundup(16*size);
00540         if( (cp = bu_malloc(bytes, "rt_get_bitv")) == (char *)0 )  {
00541                 bu_log("rt_get_bitv: malloc failure\n");
00542                 exit(17);
00543         }
00544         while( bytes >= size )  {
00545                 ((union bitv_elem *)cp)->be_next = res->re_bitv;
00546                 res->re_bitv = (union bitv_elem *)cp;
00547                 res->re_bitvlen++;
00548                 cp += size;
00549                 bytes -= size;
00550         }
00551 }
00552 
00553 /*@}*/
00554 /*
00555  * Local Variables:
00556  * mode: C
00557  * tab-width: 8
00558  * c-basic-offset: 4
00559  * indent-tabs-mode: t
00560  * End:
00561  * ex: shiftwidth=4 tabstop=8
00562  */

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