g_rec.c

Go to the documentation of this file.
00001 /*                         G _ R E C . 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 g_  */
00023 /*@{*/
00024 /** @file g_rec.c
00025  *      Intersect a ray with a Right Eliptical Cylinder.
00026  *      This is a special (but common) case of the TGC,
00027  *      which is handled separately.
00028  *
00029  *  Algorithm -
00030  *
00031  *  Given V, H, A, and B, there is a set of points on this cylinder
00032  *
00033  *  { (x,y,z) | (x,y,z) is on cylinder }
00034  *
00035  *  Through a series of Affine Transformations, this set of points will be
00036  *  transformed into a set of points on a unit cylinder located at the origin
00037  *  with a radius of 1, and a height of +1 along the +Z axis.
00038  *
00039  *  { (x',y',z') | (x',y',z') is on cylinder at origin }
00040  *
00041  *  The transformation from X to X' is accomplished by:
00042  *
00043  *  X' = S(R( X - V ))
00044  *
00045  *  where R(X) =  ( A/(|A|) )
00046  *               (  B/(|B|)  ) . X
00047  *                ( H/(|H|) )
00048  *
00049  *  and S(X) =   (  1/|A|   0     0   )
00050  *              (    0    1/|B|   0    ) . X
00051  *               (   0      0   1/|H| )
00052  *
00053  *  To find the intersection of a line with the surface of the cylinder,
00054  *  consider the parametric line L:
00055  *
00056  *      L : { P(n) | P + t(n) . D }
00057  *
00058  *  Call W the actual point of intersection between L and the cylinder.
00059  *  Let W' be the point of intersection between L' and the unit cylinder.
00060  *
00061  *      L' : { P'(n) | P' + t(n) . D' }
00062  *
00063  *  W = invR( invS( W' ) ) + V
00064  *
00065  *  Where W' = k D' + P'.
00066  *
00067  *  If Dx' and Dy' are both 0, then there is no hit on the cylinder;
00068  *  but the end plates need checking.
00069  *
00070  *  Line L' hits the infinitely tall unit cylinder at W' when
00071  *
00072  *      k**2 + b * k + c = 0
00073  *
00074  *  where
00075  *
00076  *  b = 2 * ( Dx' * Px' + Dy' * Py' ) / ( Dx'**2 + Dy'**2 )
00077  *  c = ( ( Px'**2 + Py'**2 ) - r**2 ) / ( Dx'**2 + Dy'**2 )
00078  *  r = 1.0
00079  *
00080  *  The qudratic formula yields k (which is constant):
00081  *
00082  *  k = [ -b +/- sqrt( b**2 - 4 * c ] / 2.0
00083  *
00084  *  Now, D' = S( R( D ) )
00085  *  and  P' = S( R( P - V ) )
00086  *
00087  *  Substituting,
00088  *
00089  *  W = V + invR( invS[ k *( S( R( D ) ) ) + S( R( P - V ) ) ] )
00090  *    = V + invR( ( k * R( D ) ) + R( P - V ) )
00091  *    = V + k * D + P - V
00092  *    = k * D + P
00093  *
00094  *  Note that ``k'' is constant, and is the same in the formulations
00095  *  for both W and W'.
00096  *
00097  *  The hit at ``k'' is a hit on the height=1 unit cylinder IFF
00098  *  0 <= Wz' <= 1.
00099  *
00100  *  NORMALS.  Given the point W on the surface of the cylinder,
00101  *  what is the vector normal to the tangent plane at that point?
00102  *
00103  *  Map W onto the unit cylinder, ie:  W' = S( R( W - V ) ).
00104  *
00105  *  Plane on unit cylinder at W' has a normal vector N' of the same value
00106  *  as W' in x and y, with z set to zero, ie, (Wx', Wy', 0)
00107  *
00108  *  The plane transforms back to the tangent plane at W, and this
00109  *  new plane (on the original cylinder) has a normal vector of N, viz:
00110  *
00111  *  N = inverse[ transpose(invR o invS) ] ( N' )
00112  *    = inverse[ transpose(invS) o transpose(invR) ] ( N' )
00113  *    = inverse[ inverse(S) o R ] ( N' )
00114  *    = invR o S ( N' )
00115  *
00116  *  Note that the normal vector produced above will not have unit length.
00117  *
00118  *  THE END PLATES.
00119  *
00120  *  If Dz' == 0, line L' is parallel to the end plates, so there is no hit.
00121  *
00122  *  Otherwise, the line L' hits the bottom plate with k = (0 - Pz') / Dz',
00123  *  and hits the top plate with k = (1 - Pz') / Dz'.
00124  *
00125  *  The solution W' is within the end plate IFF
00126  *
00127  *      Wx'**2 + Wy'**2 <= 1.0
00128  *
00129  *  The normal for a hit on the bottom plate is -Hunit, and
00130  *  the normal for a hit on the top plate is +Hunit.
00131  *
00132  *  Authors -
00133  *      Edwin O. Davisson       (Analysis)
00134  *      Michael John Muuss      (Programming)
00135  *
00136  *  Source -
00137  *      SECAD/VLD Computing Consortium, Bldg 394
00138  *      The U. S. Army Ballistic Research Laboratory
00139  *      Aberdeen Proving Ground, Maryland  21005
00140  *
00141  */
00142 
00143 #ifndef lint
00144 static const char RCSrec[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_rec.c,v 14.11 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00145 #endif
00146 
00147 #include "common.h"
00148 
00149 
00150 
00151 #include <stdio.h>
00152 #ifdef HAVE_STRING_H
00153 #include <string.h>
00154 #endif
00155 #include <math.h>
00156 #include "machine.h"
00157 #include "vmath.h"
00158 #include "raytrace.h"
00159 #include "rtgeom.h"
00160 #include "./debug.h"
00161 
00162 struct rec_specific {
00163         vect_t  rec_V;          /* Vector to center of base of cylinder  */
00164         vect_t  rec_Hunit;      /* Unit H vector */
00165         mat_t   rec_SoR;        /* Scale(Rot(vect)) */
00166         mat_t   rec_invRoS;     /* invRot(Scale(vect)) */
00167         vect_t  rec_A;          /* One axis of ellipse */
00168         vect_t  rec_B;          /* Other axis of ellipse */
00169         fastf_t rec_iAsq;       /* 1/MAGSQ(A) */
00170         fastf_t rec_iBsq;       /* 1/MAGSQ(B) */
00171 };
00172 
00173 /**
00174  *                      R E C _ P R E P
00175  *
00176  *  Given a pointer to a GED database record, and a transformation matrix,
00177  *  determine if this is a valid REC,
00178  *  and if so, precompute various terms of the formulas.
00179  *
00180  *  Returns -
00181  *      0       REC is OK
00182  *      !0      Error in description
00183  *
00184  *  Implicit return -
00185  *      A struct rec_specific is created,
00186  *      and it's address is stored in
00187  *      stp->st_specific for use by rt_rec_shot().
00188  *      If the TGC is really an REC, stp->st_id is modified to ID_REC.
00189  */
00190 int
00191 rt_rec_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00192 {
00193         struct rt_tgc_internal  *tip;
00194         register struct rec_specific *rec;
00195         LOCAL double    magsq_h, magsq_a, magsq_b, magsq_c, magsq_d;
00196         LOCAL double    mag_h, mag_a, mag_b;
00197         LOCAL mat_t     R;
00198         LOCAL mat_t     Rinv;
00199         LOCAL mat_t     S;
00200         LOCAL vect_t    invsq;  /* [ 1/(|A|**2), 1/(|B|**2), 1/(|Hv|**2) ] */
00201         LOCAL vect_t    work;
00202         LOCAL fastf_t   f;
00203 
00204         tip = (struct rt_tgc_internal *)ip->idb_ptr;
00205         RT_TGC_CK_MAGIC(tip);
00206 
00207         /* Validate that |H| > 0, compute |A| |B| |C| |D| */
00208         mag_h = sqrt( magsq_h = MAGSQ( tip->h ) );
00209         mag_a = sqrt( magsq_a = MAGSQ( tip->a ) );
00210         mag_b = sqrt( magsq_b = MAGSQ( tip->b ) );
00211         magsq_c = MAGSQ( tip->c );
00212         magsq_d = MAGSQ( tip->d );
00213 
00214         /* Check for |H| > 0, |A| > 0, |B| > 0 */
00215         if( NEAR_ZERO(mag_h, RT_LEN_TOL) || NEAR_ZERO(mag_a, RT_LEN_TOL)
00216          || NEAR_ZERO(mag_b, RT_LEN_TOL) )  {
00217                 return(1);              /* BAD, too small */
00218         }
00219 
00220         /* Make sure that A == C, B == D */
00221         VSUB2( work, tip->a, tip->c );
00222         f = MAGSQ( work );
00223         if( ! NEAR_ZERO(f, 0.0001) )  {
00224                 return(1);              /* BAD, !cylinder */
00225         }
00226         VSUB2( work, tip->b, tip->d );
00227         f = MAGSQ( work );
00228         if( ! NEAR_ZERO(f, 0.0001) )  {
00229                 return(1);              /* BAD, !cylinder */
00230         }
00231 
00232         /* Check for A.B == 0, H.A == 0 and H.B == 0 */
00233         f = VDOT( tip->a, tip->b ) / (mag_a * mag_b);
00234         if( ! NEAR_ZERO(f, RT_DOT_TOL) )  {
00235                 return(1);              /* BAD */
00236         }
00237         f = VDOT( tip->h, tip->a ) / (mag_h * mag_a);
00238         if( ! NEAR_ZERO(f, RT_DOT_TOL) )  {
00239                 return(1);              /* BAD */
00240         }
00241         f = VDOT( tip->h, tip->b ) / (mag_h * mag_b);
00242         if( ! NEAR_ZERO(f, RT_DOT_TOL) )  {
00243                 return(1);              /* BAD */
00244         }
00245 
00246         /*
00247          *  This TGC is really an REC
00248          */
00249         stp->st_id = ID_REC;            /* "fix" soltab ID */
00250         stp->st_meth = &rt_functab[ID_REC];
00251 
00252         BU_GETSTRUCT( rec, rec_specific );
00253         stp->st_specific = (genptr_t)rec;
00254 
00255         VMOVE( rec->rec_Hunit, tip->h );
00256         VUNITIZE( rec->rec_Hunit );
00257 
00258         VMOVE( rec->rec_V, tip->v );
00259         VMOVE( rec->rec_A, tip->a );
00260         VMOVE( rec->rec_B, tip->b );
00261         rec->rec_iAsq = 1.0/magsq_a;
00262         rec->rec_iBsq = 1.0/magsq_b;
00263 
00264         VSET( invsq, 1.0/magsq_a, 1.0/magsq_b, 1.0/magsq_h );
00265 
00266         /* Compute R and Rinv matrices */
00267         MAT_IDN( R );
00268         f = 1.0/mag_a;
00269         VSCALE( &R[0], tip->a, f );
00270         f = 1.0/mag_b;
00271         VSCALE( &R[4], tip->b, f );
00272         f = 1.0/mag_h;
00273         VSCALE( &R[8], tip->h, f );
00274         bn_mat_trn( Rinv, R );                  /* inv of rot mat is trn */
00275 
00276         /* Compute S */
00277         MAT_IDN( S );
00278         S[ 0] = sqrt( invsq[0] );
00279         S[ 5] = sqrt( invsq[1] );
00280         S[10] = sqrt( invsq[2] );
00281 
00282         /* Compute SoR and invRoS */
00283         bn_mat_mul( rec->rec_SoR, S, R );
00284         bn_mat_mul( rec->rec_invRoS, Rinv, S );
00285 
00286         /* Compute bounding sphere and RPP */
00287         {
00288                 LOCAL fastf_t   dx, dy, dz;     /* For bounding sphere */
00289                 LOCAL vect_t    P, w1;
00290                 LOCAL fastf_t   f, tmp, z;
00291 
00292                 /* X */
00293                 VSET( P, 1.0, 0, 0 );           /* bounding plane normal */
00294                 MAT3X3VEC( w1, R, P );          /* map plane into local coord syst */
00295                 /* 1st end ellipse (no Z part) */
00296                 tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y];
00297                 if( tmp > SMALL )
00298                         f = sqrt(tmp);          /* XY part */
00299                 else
00300                         f = 0;
00301                 stp->st_min[X] = rec->rec_V[X] - f;     /* V.P +/- f */
00302                 stp->st_max[X] = rec->rec_V[X] + f;
00303                 /* 2nd end ellipse */
00304                 z = w1[Z] * mag_h;              /* Z part */
00305                 tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y];
00306                 if( tmp > SMALL )
00307                         f = sqrt(tmp);          /* XY part */
00308                 else
00309                         f = 0;
00310                 if( rec->rec_V[X] - f + z < stp->st_min[X] )
00311                         stp->st_min[X] = rec->rec_V[X] - f + z;
00312                 if( rec->rec_V[X] + f + z > stp->st_max[X] )
00313                         stp->st_max[X] = rec->rec_V[X] + f + z;
00314 
00315                 /* Y */
00316                 VSET( P, 0, 1.0, 0 );           /* bounding plane normal */
00317                 MAT3X3VEC( w1, R, P );          /* map plane into local coord syst */
00318                 /* 1st end ellipse (no Z part) */
00319                 tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y];
00320                 if( tmp > SMALL )
00321                         f = sqrt(tmp);          /* XY part */
00322                 else
00323                         f = 0;
00324                 stp->st_min[Y] = rec->rec_V[Y] - f;     /* V.P +/- f */
00325                 stp->st_max[Y] = rec->rec_V[Y] + f;
00326                 /* 2nd end ellipse */
00327                 z = w1[Z] * mag_h;              /* Z part */
00328                 tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y];
00329                 if( tmp > SMALL )
00330                         f = sqrt(tmp);          /* XY part */
00331                 else
00332                         f = 0;
00333                 if( rec->rec_V[Y] - f + z < stp->st_min[Y] )
00334                         stp->st_min[Y] = rec->rec_V[Y] - f + z;
00335                 if( rec->rec_V[Y] + f + z > stp->st_max[Y] )
00336                         stp->st_max[Y] = rec->rec_V[Y] + f + z;
00337 
00338                 /* Z */
00339                 VSET( P, 0, 0, 1.0 );           /* bounding plane normal */
00340                 MAT3X3VEC( w1, R, P );          /* map plane into local coord syst */
00341                 /* 1st end ellipse (no Z part) */
00342                 tmp = magsq_a * w1[X] * w1[X] + magsq_b * w1[Y] * w1[Y];
00343                 if( tmp > SMALL )
00344                         f = sqrt(tmp);          /* XY part */
00345                 else
00346                         f = 0;
00347                 stp->st_min[Z] = rec->rec_V[Z] - f;     /* V.P +/- f */
00348                 stp->st_max[Z] = rec->rec_V[Z] + f;
00349                 /* 2nd end ellipse */
00350                 z = w1[Z] * mag_h;              /* Z part */
00351                 tmp = magsq_c * w1[X] * w1[X] + magsq_d * w1[Y] * w1[Y];
00352                 if( tmp > SMALL )
00353                         f = sqrt(tmp);          /* XY part */
00354                 else
00355                         f = 0;
00356                 if( rec->rec_V[Z] - f + z < stp->st_min[Z] )
00357                         stp->st_min[Z] = rec->rec_V[Z] - f + z;
00358                 if( rec->rec_V[Z] + f + z > stp->st_max[Z] )
00359                         stp->st_max[Z] = rec->rec_V[Z] + f + z;
00360 
00361                 VSET( stp->st_center,
00362                         (stp->st_max[X] + stp->st_min[X])/2,
00363                         (stp->st_max[Y] + stp->st_min[Y])/2,
00364                         (stp->st_max[Z] + stp->st_min[Z])/2 );
00365 
00366                 dx = (stp->st_max[X] - stp->st_min[X])/2;
00367                 f = dx;
00368                 dy = (stp->st_max[Y] - stp->st_min[Y])/2;
00369                 if( dy > f )  f = dy;
00370                 dz = (stp->st_max[Z] - stp->st_min[Z])/2;
00371                 if( dz > f )  f = dz;
00372                 stp->st_aradius = f;
00373                 stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz);
00374         }
00375         return(0);                      /* OK */
00376 }
00377 
00378 /**
00379  *                      R E C _ P R I N T
00380  */
00381 void
00382 rt_rec_print(register const struct soltab *stp)
00383 {
00384         register const struct rec_specific *rec =
00385                 (struct rec_specific *)stp->st_specific;
00386 
00387         VPRINT("V", rec->rec_V);
00388         VPRINT("Hunit", rec->rec_Hunit);
00389         bn_mat_print("S o R", rec->rec_SoR );
00390         bn_mat_print("invR o S", rec->rec_invRoS );
00391 }
00392 
00393 /* hit_surfno is set to one of these */
00394 #define REC_NORM_BODY   (1)             /* compute normal */
00395 #define REC_NORM_TOP    (2)             /* copy tgc_N */
00396 #define REC_NORM_BOT    (3)             /* copy reverse tgc_N */
00397 
00398 /**
00399  *                      R E C _ S H O T
00400  *
00401  *  Intersect a ray with a right elliptical cylinder,
00402  *  where all constant terms have
00403  *  been precomputed by rt_rec_prep().  If an intersection occurs,
00404  *  a struct seg will be acquired and filled in.
00405  *
00406  *  Returns -
00407  *      0       MISS
00408  *      >0      HIT
00409  */
00410 int
00411 rt_rec_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00412 {
00413         register struct rec_specific *rec =
00414                 (struct rec_specific *)stp->st_specific;
00415         LOCAL vect_t    dprime;         /* D' */
00416         LOCAL vect_t    pprime;         /* P' */
00417         LOCAL fastf_t   k1, k2;         /* distance constants of solution */
00418         LOCAL vect_t    xlated;         /* translated vector */
00419         LOCAL struct hit hits[4];       /* 4 potential hit points */
00420         register struct hit *hitp;      /* pointer to hit point */
00421         int             nhits = 0;      /* Number of hit points */
00422 
00423         hitp = &hits[0];
00424 
00425         /* out, Mat, vect */
00426         MAT4X3VEC( dprime, rec->rec_SoR, rp->r_dir );
00427         VSUB2( xlated, rp->r_pt, rec->rec_V );
00428         MAT4X3VEC( pprime, rec->rec_SoR, xlated );
00429 
00430         if( NEAR_ZERO(dprime[X], SMALL) && NEAR_ZERO(dprime[Y], SMALL) )
00431                 goto check_plates;
00432 
00433         /* Find roots of the equation, using forumla for quadratic w/ a=1 */
00434         {
00435                 FAST fastf_t    b;              /* coeff of polynomial */
00436                 FAST fastf_t    root;           /* root of radical */
00437                 FAST fastf_t    dx2dy2;
00438 
00439                 b = 2 * ( dprime[X]*pprime[X] + dprime[Y]*pprime[Y] ) *
00440                    (dx2dy2 = 1 / (dprime[X]*dprime[X] + dprime[Y]*dprime[Y]));
00441                 if( (root = b*b - 4 * dx2dy2 *
00442                     (pprime[X]*pprime[X] + pprime[Y]*pprime[Y] - 1)) <= 0 )
00443                         goto check_plates;
00444                 root = sqrt(root);
00445 
00446                 k1 = (root-b) * 0.5;
00447                 k2 = (root+b) * (-0.5);
00448         }
00449 
00450         /*
00451          *  k1 and k2 are potential solutions to intersection with side.
00452          *  See if they fall in range.
00453          */
00454         VJOIN1( hitp->hit_vpriv, pprime, k1, dprime );          /* hit' */
00455         if( hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0 ) {
00456                 hitp->hit_magic = RT_HIT_MAGIC;
00457                 hitp->hit_dist = k1;
00458                 hitp->hit_surfno = REC_NORM_BODY;       /* compute N */
00459                 hitp++; nhits++;
00460         }
00461 
00462         VJOIN1( hitp->hit_vpriv, pprime, k2, dprime );          /* hit' */
00463         if( hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0 )  {
00464                 hitp->hit_magic = RT_HIT_MAGIC;
00465                 hitp->hit_dist = k2;
00466                 hitp->hit_surfno = REC_NORM_BODY;       /* compute N */
00467                 hitp++; nhits++;
00468         }
00469 
00470         /*
00471          * Check for hitting the end plates.
00472          */
00473 check_plates:
00474         if( nhits < 2  &&  !NEAR_ZERO(dprime[Z], SMALL) )  {
00475                 /* 0 or 1 hits so far, this is worthwhile */
00476                 k1 = -pprime[Z] / dprime[Z];            /* bottom plate */
00477                 k2 = (1.0 - pprime[Z]) / dprime[Z];     /* top plate */
00478 
00479                 VJOIN1( hitp->hit_vpriv, pprime, k1, dprime );  /* hit' */
00480                 if( hitp->hit_vpriv[X] * hitp->hit_vpriv[X] +
00481                     hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0 )  {
00482                         hitp->hit_magic = RT_HIT_MAGIC;
00483                         hitp->hit_dist = k1;
00484                         hitp->hit_surfno = REC_NORM_BOT;        /* -H */
00485                         hitp++; nhits++;
00486                 }
00487 
00488                 VJOIN1( hitp->hit_vpriv, pprime, k2, dprime );  /* hit' */
00489                 if( hitp->hit_vpriv[X] * hitp->hit_vpriv[X] +
00490                     hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0 )  {
00491                         hitp->hit_magic = RT_HIT_MAGIC;
00492                         hitp->hit_dist = k2;
00493                         hitp->hit_surfno = REC_NORM_TOP;        /* +H */
00494                         hitp++; nhits++;
00495                 }
00496         }
00497         if( nhits == 0 )  return 0;     /* MISS */
00498         if( nhits == 2 )  {
00499 hit:
00500                 if( hits[0].hit_dist < hits[1].hit_dist )  {
00501                         /* entry is [0], exit is [1] */
00502                         register struct seg *segp;
00503 
00504                         RT_GET_SEG(segp, ap->a_resource);
00505                         segp->seg_stp = stp;
00506                         segp->seg_in = hits[0];         /* struct copy */
00507                         segp->seg_out = hits[1];        /* struct copy */
00508                         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00509                 } else {
00510                         /* entry is [1], exit is [0] */
00511                         register struct seg *segp;
00512 
00513                         RT_GET_SEG(segp, ap->a_resource);
00514                         segp->seg_stp = stp;
00515                         segp->seg_in = hits[1];         /* struct copy */
00516                         segp->seg_out = hits[0];        /* struct copy */
00517                         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00518                 }
00519                 return 2;                       /* HIT */
00520         }
00521         if( nhits == 1 )  {
00522                 if( hits[0].hit_surfno != REC_NORM_BODY )
00523                         bu_log("rt_rec_shot(%s): 1 intersection with end plate?\n", stp->st_name );
00524                 /*
00525                  *  Ray is tangent to body of cylinder,
00526                  *  or a single hit on on an end plate (??)
00527                  *  This could be considered a MISS,
00528                  *  but to signal the condition, return 0-thickness hit.
00529                  */
00530                 hits[1] = hits[0];      /* struct copy */
00531                 nhits++;
00532                 goto hit;
00533         }
00534         if( nhits == 3 )  {
00535                 fastf_t tol_dist = ap->a_rt_i->rti_tol.dist;
00536                 /*
00537                  *  Check for case where two of the three hits
00538                  *  have the same distance, e.g. hitting at the rim.
00539                  */
00540                 k1 = hits[0].hit_dist - hits[1].hit_dist;
00541                 if( NEAR_ZERO( k1, tol_dist ) )  {
00542                         if(RT_G_DEBUG&DEBUG_ARB8)bu_log("rt_rec_shot(%s): 3 hits, collapsing 0&1\n", stp->st_name);
00543                         hits[1] = hits[2];      /* struct copy */
00544                         nhits--;
00545                         goto hit;
00546                 }
00547                 k1 = hits[1].hit_dist - hits[2].hit_dist;
00548                 if( NEAR_ZERO( k1, tol_dist ) )  {
00549                         if(RT_G_DEBUG&DEBUG_ARB8)bu_log("rt_rec_shot(%s): 3 hits, collapsing 1&2\n", stp->st_name);
00550                         nhits--;
00551                         goto hit;
00552                 }
00553                 k1 = hits[0].hit_dist - hits[2].hit_dist;
00554                 if( NEAR_ZERO( k1, tol_dist ) )  {
00555                         if(RT_G_DEBUG&DEBUG_ARB8)bu_log("rt_rec_shot(%s): 3 hits, collapsing 1&2\n", stp->st_name);
00556                         nhits--;
00557                         goto hit;
00558                 }
00559         }
00560         /*  nhits >= 3 */
00561         bu_log("rt_rec_shot(%s): %d unique hits?!?  %g, %g, %g, %g\n",
00562                 stp->st_name, nhits,
00563                 hits[0].hit_dist,
00564                 hits[1].hit_dist,
00565                 hits[2].hit_dist,
00566                 hits[3].hit_dist);
00567 
00568         /* count just the first two, to have something */
00569         goto hit;
00570 }
00571 
00572 #define SEG_MISS(SEG)           (SEG).seg_stp=(struct soltab *) 0;
00573 /**
00574  *                      R E C _ V S H O T
00575  *
00576  *  This is the Becker vector version
00577  */
00578 void
00579 rt_rec_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
00580                                /* An array of solid pointers */
00581                                /* An array of ray pointers */
00582                                /* array of segs (results returned) */
00583                                /* Number of ray/object pairs */
00584 
00585 {
00586         register int    i;
00587         register struct rec_specific *rec;
00588         LOCAL vect_t    dprime;         /* D' */
00589         LOCAL vect_t    pprime;         /* P' */
00590         LOCAL fastf_t   k1, k2;         /* distance constants of solution */
00591         LOCAL vect_t    xlated;         /* translated vector */
00592         LOCAL struct hit hits[3];       /* 4 potential hit points */
00593         register struct hit *hitp;      /* pointer to hit point */
00594         FAST fastf_t    b;              /* coeff of polynomial */
00595         FAST fastf_t    root;           /* root of radical */
00596         FAST fastf_t    dx2dy2;
00597 
00598         /* for each ray/right_eliptical_cylinder pair */
00599 #       include "noalias.h"
00600         for(i = 0; i < n; i++){
00601 #if !CRAY /* XXX currently prevents vectorization on cray */
00602                 if (stp[i] == 0) continue; /* stp[i] == 0 signals skip ray */
00603 #endif
00604 
00605                 rec = (struct rec_specific *)stp[i]->st_specific;
00606                 hitp = &hits[0];
00607 
00608                 /* out, Mat, vect */
00609                 MAT4X3VEC( dprime, rec->rec_SoR, rp[i]->r_dir );
00610                 VSUB2( xlated, rp[i]->r_pt, rec->rec_V );
00611                 MAT4X3VEC( pprime, rec->rec_SoR, xlated );
00612 
00613                 if( NEAR_ZERO(dprime[X], SMALL) && NEAR_ZERO(dprime[Y], SMALL) )
00614                         goto check_plates;
00615 
00616                 /* Find roots of eqn, using forumla for quadratic w/ a=1 */
00617                 b = 2 * ( dprime[X]*pprime[X] + dprime[Y]*pprime[Y] ) *
00618                    (dx2dy2 = 1 / (dprime[X]*dprime[X] + dprime[Y]*dprime[Y]));
00619                 if( (root = b*b - 4 * dx2dy2 *
00620                     (pprime[X]*pprime[X] + pprime[Y]*pprime[Y] - 1)) <= 0 )
00621                         goto check_plates;
00622 
00623                 root = sqrt(root);
00624                 k1 = (root-b) * 0.5;
00625                 k2 = (root+b) * (-0.5);
00626 
00627                 /*
00628                  *  k1 and k2 are potential solutions to intersection with side.
00629                  *  See if they fall in range.
00630                  */
00631                 VJOIN1( hitp->hit_vpriv, pprime, k1, dprime );  /* hit' */
00632                 if( hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0 ) {
00633                         hitp->hit_dist = k1;
00634                         hitp->hit_surfno = REC_NORM_BODY;       /* compute N */
00635                         hitp++;
00636                 }
00637 
00638                 VJOIN1( hitp->hit_vpriv, pprime, k2, dprime );          /* hit' */
00639                 if( hitp->hit_vpriv[Z] >= 0.0 && hitp->hit_vpriv[Z] <= 1.0 )  {
00640                         hitp->hit_dist = k2;
00641                         hitp->hit_surfno = REC_NORM_BODY;       /* compute N */
00642                         hitp++;
00643                 }
00644 
00645                 /*
00646                  * Check for hitting the end plates.
00647                  */
00648 check_plates:
00649                 if( hitp < &hits[2]  &&  !NEAR_ZERO(dprime[Z], SMALL) )  {
00650                         /* 0 or 1 hits so far, this is worthwhile */
00651                         k1 = -pprime[Z] / dprime[Z];    /* bottom plate */
00652                         k2 = (1.0 - pprime[Z]) / dprime[Z];     /* top plate */
00653 
00654                         VJOIN1( hitp->hit_vpriv, pprime, k1, dprime );/* hit' */
00655                         if( hitp->hit_vpriv[X] * hitp->hit_vpriv[X] +
00656                             hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0 )  {
00657                                 hitp->hit_dist = k1;
00658                                 hitp->hit_surfno = REC_NORM_BOT;        /* -H */
00659                                 hitp++;
00660                         }
00661 
00662                         VJOIN1( hitp->hit_vpriv, pprime, k2, dprime );/* hit' */
00663                         if( hitp->hit_vpriv[X] * hitp->hit_vpriv[X] +
00664                             hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0 )  {
00665                                 hitp->hit_dist = k2;
00666                                 hitp->hit_surfno = REC_NORM_TOP;        /* +H */
00667                                 hitp++;
00668                         }
00669                 }
00670 
00671                 if( hitp != &hits[2] ) {
00672                         SEG_MISS(segp[i]);              /* MISS */
00673                 } else {
00674                         segp[i].seg_stp = stp[i];
00675 
00676                         if( hits[0].hit_dist < hits[1].hit_dist )  {
00677                                 /* entry is [0], exit is [1] */
00678                                 VMOVE(segp[i].seg_in.hit_vpriv, hits[0].hit_vpriv);
00679                                 segp[i].seg_in.hit_dist = hits[0].hit_dist;
00680                                 segp[i].seg_in.hit_surfno = hits[0].hit_surfno;
00681                                 VMOVE(segp[i].seg_out.hit_vpriv, hits[1].hit_vpriv);
00682                                 segp[i].seg_out.hit_dist = hits[1].hit_dist;
00683                                 segp[i].seg_out.hit_surfno = hits[1].hit_surfno;
00684                         } else {
00685                                 /* entry is [1], exit is [0] */
00686                                 VMOVE(segp[i].seg_in.hit_vpriv, hits[1].hit_vpriv);
00687                                 segp[i].seg_in.hit_dist = hits[1].hit_dist;
00688                                 segp[i].seg_in.hit_surfno = hits[1].hit_surfno;
00689                                 VMOVE(segp[i].seg_out.hit_vpriv, hits[0].hit_vpriv);
00690                                 segp[i].seg_out.hit_dist = hits[0].hit_dist;
00691                                 segp[i].seg_out.hit_surfno = hits[0].hit_surfno;
00692                         }
00693                 }
00694         }
00695 }
00696 
00697 /**
00698  *                      R E C _ N O R M
00699  *
00700  *  Given ONE ray distance, return the normal and entry/exit point.
00701  *  hit_surfno is a flag indicating if normal needs to be computed or not.
00702  */
00703 void
00704 rt_rec_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00705 {
00706         register struct rec_specific *rec =
00707                 (struct rec_specific *)stp->st_specific;
00708 
00709         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
00710         switch( hitp->hit_surfno )  {
00711         case REC_NORM_BODY:
00712                 /* compute it */
00713                 hitp->hit_vpriv[Z] = 0.0;
00714                 MAT4X3VEC( hitp->hit_normal, rec->rec_invRoS,
00715                         hitp->hit_vpriv );
00716                 VUNITIZE( hitp->hit_normal );
00717                 break;
00718         case REC_NORM_TOP:
00719                 VMOVE( hitp->hit_normal, rec->rec_Hunit );
00720                 break;
00721         case REC_NORM_BOT:
00722                 VREVERSE( hitp->hit_normal, rec->rec_Hunit );
00723                 break;
00724         default:
00725                 bu_log("rt_rec_norm: surfno=%d bad\n", hitp->hit_surfno);
00726                 break;
00727         }
00728 }
00729 
00730 /**
00731  *                      R E C _ C U R V E
00732  *
00733  *  Return the "curvature" of the cylinder.  If an endplate,
00734  *  pick a principle direction orthogonal to the normal, and
00735  *  indicate no curvature.  Otherwise, compute curvature.
00736  *  Normal must have been computed before calling this routine.
00737  */
00738 void
00739 rt_rec_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00740 {
00741         register struct rec_specific *rec =
00742                 (struct rec_specific *)stp->st_specific;
00743         vect_t  uu;
00744         fastf_t ax, bx, q;
00745 
00746         switch( hitp->hit_surfno )  {
00747         case REC_NORM_BODY:
00748                 /* This could almost certainly be simpler if we used
00749                  * inverse A rather than inverse A squared, right Ed?
00750                  */
00751                 VMOVE( cvp->crv_pdir, rec->rec_Hunit );
00752                 VSUB2( uu, hitp->hit_point, rec->rec_V );
00753                 cvp->crv_c1 = 0;
00754                 ax = VDOT( uu, rec->rec_A ) * rec->rec_iAsq;
00755                 bx = VDOT( uu, rec->rec_B ) * rec->rec_iBsq;
00756                 q = sqrt( ax * ax * rec->rec_iAsq + bx * bx * rec->rec_iBsq );
00757                 cvp->crv_c2 = - rec->rec_iAsq * rec->rec_iBsq / (q*q*q);
00758                 break;
00759         case REC_NORM_TOP:
00760         case REC_NORM_BOT:
00761                 bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00762                 cvp->crv_c1 = cvp->crv_c2 = 0;
00763                 break;
00764         default:
00765                 bu_log("rt_rec_curve: bad surfno %d\n", hitp->hit_surfno);
00766                 break;
00767         }
00768 }
00769 
00770 /**
00771  *                      R E C _ U V
00772  *
00773  *  For a hit on the surface of an REC, return the (u,v) coordinates
00774  *  of the hit point, 0 <= u,v <= 1.
00775  *
00776  *  u is the rotation around the cylinder, and
00777  *  v is the displacement along H.
00778  */
00779 void
00780 rt_rec_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00781 {
00782         register struct rec_specific *rec =
00783                 (struct rec_specific *)stp->st_specific;
00784         LOCAL vect_t work;
00785         LOCAL vect_t pprime;
00786         FAST fastf_t len;
00787         FAST fastf_t ratio;
00788 
00789         /* hit_point is on surface;  project back to unit cylinder,
00790          * creating a vector from vertex to hit point.
00791          */
00792         VSUB2( work, hitp->hit_point, rec->rec_V );
00793         MAT4X3VEC( pprime, rec->rec_SoR, work );
00794 
00795         switch( hitp->hit_surfno )  {
00796         case REC_NORM_BODY:
00797                 /* Skin.  x,y coordinates define rotation.  radius = 1 */
00798                 ratio = pprime[Y];
00799                 if( ratio > 1.0 )
00800                         ratio = 1.0;
00801                 if( ratio < -1.0 )
00802                         ratio = -1.0;
00803                 uvp->uv_u = acos(ratio) * bn_inv2pi;
00804                 uvp->uv_v = pprime[Z];          /* height */
00805                 break;
00806         case REC_NORM_TOP:
00807                 /* top plate */
00808                 len = sqrt(pprime[X]*pprime[X]+pprime[Y]*pprime[Y]);
00809                 ratio = pprime[Y]/len;
00810                 if( ratio > 1.0 )
00811                         ratio = 1.0;
00812                 if( ratio < -1.0 )
00813                         ratio = -1.0;
00814                 uvp->uv_u = acos(ratio) * bn_inv2pi;
00815                 uvp->uv_v = len;                /* rim v = 1 */
00816                 break;
00817         case REC_NORM_BOT:
00818                 /* bottom plate */
00819                 len = sqrt(pprime[X]*pprime[X]+pprime[Y]*pprime[Y]);
00820                 ratio = pprime[Y]/len;
00821                 if( ratio > 1.0 )
00822                         ratio = 1.0;
00823                 if( ratio < -1.0 )
00824                         ratio = -1.0;
00825                 uvp->uv_u = acos(ratio) * bn_inv2pi;
00826                 uvp->uv_v = 1 - len;    /* rim v = 0 */
00827                 break;
00828         }
00829         /* Handle other half of acos() domain */
00830         if( pprime[X] < 0 )
00831                 uvp->uv_u = 1.0 - uvp->uv_u;
00832 
00833         if( uvp->uv_u < 0 )  uvp->uv_u = 0;
00834         else if( uvp->uv_u > 1 )  uvp->uv_u = 1;
00835         if( uvp->uv_v < 0 )  uvp->uv_v = 0;
00836         else if( uvp->uv_v > 1 )  uvp->uv_v = 1;
00837 
00838         /* XXX uv_du should be relative to rotation, uv_dv relative to height */
00839         uvp->uv_du = uvp->uv_dv = 0;
00840 }
00841 
00842 /**
00843  *                      R E C _ F R E E
00844  */
00845 void
00846 rt_rec_free(struct soltab *stp)
00847 {
00848         register struct rec_specific *rec =
00849                 (struct rec_specific *)stp->st_specific;
00850 
00851         bu_free( (char *)rec, "rec_specific");
00852 }
00853 
00854 int
00855 rt_rec_class(void)
00856 {
00857         return(0);
00858 }
00859 
00860 /* plot and tess are handled by g_tgc.c */
00861 /* import, export, ifree, and describe are also handled by g_tgc.c */
00862 
00863 /*@}*/
00864 /*
00865  * Local Variables:
00866  * mode: C
00867  * tab-width: 8
00868  * c-basic-offset: 4
00869  * indent-tabs-mode: t
00870  * End:
00871  * ex: shiftwidth=4 tabstop=8
00872  */

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