g_torus.c

Go to the documentation of this file.
00001 /*                       G _ T O R U S . 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 /*@{*/
00025 /** @file g_torus.c
00026  *      Intersect a ray with a Torus
00027  *
00028  * Authors -
00029  *      Edwin O. Davisson       (Analysis)
00030  *      Jeff Hanes              (Programming)
00031  *      Michael John Muuss      (RT adaptation)
00032  *      Gary S. Moss            (Improvement)
00033  *
00034  *  Source -
00035  *      SECAD/VLD Computing Consortium, Bldg 394
00036  *      The U. S. Army Ballistic Research Laboratory
00037  *      Aberdeen Proving Ground, Maryland  21005
00038  *
00039  */
00040 /*@}*/
00041 
00042 #ifndef lint
00043 static const char RCStorus[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_torus.c,v 14.14 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00044 #endif
00045 
00046 #include "common.h"
00047 
00048 #include <stddef.h>
00049 #include <stdio.h>
00050 #ifdef HAVE_STRING_H
00051 #  include <string.h>
00052 #else
00053 #  include <strings.h>
00054 #endif
00055 #include <math.h>
00056 
00057 #include "machine.h"
00058 #include "vmath.h"
00059 #include "db.h"
00060 #include "nmg.h"
00061 #include "raytrace.h"
00062 #include "rtgeom.h"
00063 #include "./debug.h"
00064 
00065 /*
00066  * The TORUS has the following input fields:
00067  *      V       V from origin to center
00068  *      H       Radius Vector, Normal to plane of torus.  |H| = R2
00069  *      A,B     perpindicular, to CENTER of torus.  |A|==|B|==R1
00070  *      F5,F6   perpindicular, for inner edge (unused)
00071  *      F7,F8   perpindicular, for outer edge (unused)
00072  *
00073  */
00074 
00075 const struct bu_structparse rt_tor_parse[] = {
00076     { "%f", 3, "V",   bu_offsetof(struct rt_tor_internal, v[X]), BU_STRUCTPARSE_FUNC_NULL },
00077     { "%f", 3, "H",   bu_offsetof(struct rt_tor_internal, h[X]), BU_STRUCTPARSE_FUNC_NULL },
00078     { "%f", 1, "r_a", bu_offsetof(struct rt_tor_internal, r_a),  BU_STRUCTPARSE_FUNC_NULL },
00079     { "%f", 1, "r_h", bu_offsetof(struct rt_tor_internal, r_h),  BU_STRUCTPARSE_FUNC_NULL },
00080     { {'\0','\0','\0','\0'}, 0, (char *)NULL, 0, BU_STRUCTPARSE_FUNC_NULL }
00081     };
00082 
00083 /*
00084  *  Algorithm:
00085  *
00086  *  Given V, H, A, and B, there is a set of points on this torus
00087  *
00088  *  { (x,y,z) | (x,y,z) is on torus defined by V, H, A, B }
00089  *
00090  *  Through a series of  Transformations, this set will be
00091  *  transformed into a set of points on a unit torus (R1==1)
00092  *  centered at the origin
00093  *  which lies on the X-Y plane (ie, H is on the Z axis).
00094  *
00095  *  { (x',y',z') | (x',y',z') is on unit torus at origin }
00096  *
00097  *  The transformation from X to X' is accomplished by:
00098  *
00099  *  X' = S(R( X - V ))
00100  *
00101  *  where R(X) =  ( A/(|A|) )
00102  *               (  B/(|B|)  ) . X
00103  *                ( H/(|H|) )
00104  *
00105  *  and S(X) =   (  1/|A|   0     0   )
00106  *              (    0    1/|A|   0    ) . X
00107  *               (   0      0   1/|A| )
00108  *  where |A| = R1
00109  *
00110  *  To find the intersection of a line with the torus, consider
00111  *  the parametric line L:
00112  *
00113  *      L : { P(n) | P + t(n) . D }
00114  *
00115  *  Call W the actual point of intersection between L and the torus.
00116  *  Let W' be the point of intersection between L' and the unit torus.
00117  *
00118  *      L' : { P'(n) | P' + t(n) . D' }
00119  *
00120  *  W = invR( invS( W' ) ) + V
00121  *
00122  *  Where W' = k D' + P'.
00123  *
00124  *
00125  *  Given a line and a ratio, alpha, finds the equation of the
00126  *  unit torus in terms of the variable 't'.
00127  *
00128  *  The equation for the torus is:
00129  *
00130  *      [ X**2 + Y**2 + Z**2 + (1 - alpha**2) ]**2 - 4*( X**2 + Y**2 )  =  0
00131  *
00132  *  First, find X, Y, and Z in terms of 't' for this line, then
00133  *  substitute them into the equation above.
00134  *
00135  *      Wx = Dx*t + Px
00136  *
00137  *      Wx**2 = Dx**2 * t**2  +  2 * Dx * Px  +  Px**2
00138  *
00139  *  The real roots of the equation in 't' are the intersect points
00140  *  along the parameteric line.
00141  *
00142  *  NORMALS.  Given the point W on the torus, what is the vector
00143  *  normal to the tangent plane at that point?
00144  *
00145  *  Map W onto the unit torus, ie:  W' = S( R( W - V ) ).
00146  *  In this case, we find W' by solving the parameteric line given k.
00147  *
00148  *  The gradient of the torus at W' is in fact the
00149  *  normal vector.
00150  *
00151  *  Given that the equation for the unit torus is:
00152  *
00153  *      [ X**2 + Y**2 + Z**2 + (1 - alpha**2) ]**2 - 4*( X**2 + Y**2 )  =  0
00154  *
00155  *  let w = X**2 + Y**2 + Z**2 + (1 - alpha**2), then the equation becomes:
00156  *
00157  *      w**2 - 4*( X**2 + Y**2 )  =  0
00158  *
00159  *  For f(x,y,z) = 0, the gradient of f() is ( df/dx, df/dy, df/dz ).
00160  *
00161  *      df/dx = 2 * w * 2 * x - 8 * x   = (4 * w - 8) * x
00162  *      df/dy = 2 * w * 2 * y - 8 * y   = (4 * w - 8) * y
00163  *      df/dz = 2 * w * 2 * z           = 4 * w * z
00164  *
00165  *  Note that the normal vector produced above will not have unit length.
00166  *  Also, to make this useful for the original torus, it will have
00167  *  to be rotated back to the orientation of the original torus.
00168  */
00169 
00170 struct tor_specific {
00171         fastf_t tor_alpha;      /* 0 < (R2/R1) <= 1 */
00172         fastf_t tor_r1;         /* for inverse scaling of k values. */
00173         fastf_t tor_r2;         /* for curvature */
00174         vect_t  tor_V;          /* Vector to center of torus */
00175         vect_t  tor_N;          /* unit normal to plane of torus */
00176         mat_t   tor_SoR;        /* Scale(Rot(vect)) */
00177         mat_t   tor_invR;       /* invRot(vect') */
00178 };
00179 
00180 /**
00181  *                      R T _ T O R _ P R E P
00182  *
00183  *  Given a pointer to a GED database record, and a transformation matrix,
00184  *  determine if this is a valid torus, and if so, precompute various
00185  *  terms of the formula.
00186  *
00187  *  Returns -
00188  *      0       TOR is OK
00189  *      !0      Error in description
00190  *
00191  *  Implicit return -
00192  *      A struct tor_specific is created, and it's address is stored in
00193  *      stp->st_specific for use by rt_tor_shot().
00194  */
00195 int
00196 rt_tor_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00197 {
00198         register struct tor_specific *tor;
00199         LOCAL mat_t     R;
00200         LOCAL vect_t    P, w1;  /* for RPP calculation */
00201         FAST fastf_t    f;
00202         struct rt_tor_internal  *tip;
00203 
00204         tip = (struct rt_tor_internal *)ip->idb_ptr;
00205         RT_TOR_CK_MAGIC(tip);
00206 
00207         /* Validate that |A| == |B| (for now) */
00208         if( rt_fdiff( tip->r_a, tip->r_b ) != 0 ) {
00209                 bu_log("tor(%s):  (|A|=%f) != (|B|=%f) \n",
00210                         stp->st_name, tip->r_a, tip->r_b );
00211                 return(1);              /* BAD */
00212         }
00213 
00214         /* Validate that A.B == 0, B.H == 0, A.H == 0 */
00215         f = VDOT( tip->a, tip->b )/(tip->r_a*tip->r_b);
00216 
00217         if( ! NEAR_ZERO(f, rtip->rti_tol.dist) )  {
00218                 bu_log("tor(%s):  A not perpendicular to B, f=%f\n",
00219                         stp->st_name, f);
00220                 return(1);              /* BAD */
00221         }
00222         f = VDOT( tip->b, tip->h )/(tip->r_b);
00223         if( ! NEAR_ZERO(f, rtip->rti_tol.dist) )  {
00224                 bu_log("tor(%s):  B not perpendicular to H, f=%f\n",
00225                         stp->st_name, f);
00226                 return(1);              /* BAD */
00227         }
00228         f = VDOT( tip->a, tip->h )/(tip->r_a);
00229         if( ! NEAR_ZERO(f, rtip->rti_tol.dist) )  {
00230                 bu_log("tor(%s):  A not perpendicular to H, f=%f\n",
00231                         stp->st_name, f);
00232                 return(1);              /* BAD */
00233         }
00234 
00235         /* Validate that 0 < r2 <= r1 for alpha computation */
00236         if( 0.0 >= tip->r_h  || tip->r_h > tip->r_a )  {
00237                 bu_log("r1 = %f, r2 = %f\n", tip->r_a, tip->r_h );
00238                 bu_log("tor(%s):  0 < r2 <= r1 is not true\n", stp->st_name);
00239                 return(1);              /* BAD */
00240         }
00241 
00242         /* Solid is OK, compute constant terms now */
00243         BU_GETSTRUCT( tor, tor_specific );
00244         stp->st_specific = (genptr_t)tor;
00245 
00246         tor->tor_r1 = tip->r_a;
00247         tor->tor_r2 = tip->r_h;
00248 
00249         VMOVE( tor->tor_V, tip->v );
00250         tor->tor_alpha = tip->r_h/tor->tor_r1;
00251 
00252         /* Compute R and invR matrices */
00253         VMOVE( tor->tor_N, tip->h );
00254 
00255         MAT_IDN( R );
00256         VSCALE( &R[0], tip->a, 1.0/tip->r_a );
00257         VSCALE( &R[4], tip->b, 1.0/tip->r_b );
00258         VMOVE( &R[8], tor->tor_N );
00259         bn_mat_inv( tor->tor_invR, R );
00260 
00261         /* Compute SoR.  Here, S = I / r1 */
00262         MAT_COPY( tor->tor_SoR, R );
00263         tor->tor_SoR[15] *= tor->tor_r1;
00264 
00265         VMOVE( stp->st_center, tor->tor_V );
00266         stp->st_aradius = stp->st_bradius = tor->tor_r1 + tip->r_h;
00267 
00268         /*
00269          *  Compute the bounding RPP planes for a circular torus.
00270          *
00271          *  Given a circular torus with vertex V, vector N, and
00272          *  radii r1 and r2.  A bounding plane with direction
00273          *  vector P will touch the surface of the torus at the
00274          *  points:  V +/- [r2 + r1 * |N x P|] P
00275          */
00276         /* X */
00277         VSET( P, 1.0, 0, 0 );           /* bounding plane normal */
00278         VCROSS( w1, tor->tor_N, P );    /* for sin(angle N P) */
00279         f = tor->tor_r2 + tor->tor_r1 * MAGNITUDE(w1);
00280         VSCALE( w1, P, f );
00281         f = fabs( w1[X] );
00282         stp->st_min[X] = tor->tor_V[X] - f;
00283         stp->st_max[X] = tor->tor_V[X] + f;
00284 
00285         /* Y */
00286         VSET( P, 0, 1.0, 0 );           /* bounding plane normal */
00287         VCROSS( w1, tor->tor_N, P );    /* for sin(angle N P) */
00288         f = tor->tor_r2 + tor->tor_r1 * MAGNITUDE(w1);
00289         VSCALE( w1, P, f );
00290         f = fabs( w1[Y] );
00291         stp->st_min[Y] = tor->tor_V[Y] - f;
00292         stp->st_max[Y] = tor->tor_V[Y] + f;
00293 
00294         /* Z */
00295         VSET( P, 0, 0, 1.0 );           /* bounding plane normal */
00296         VCROSS( w1, tor->tor_N, P );    /* for sin(angle N P) */
00297         f = tor->tor_r2 + tor->tor_r1 * MAGNITUDE(w1);
00298         VSCALE( w1, P, f );
00299         f = fabs( w1[Z] );
00300         stp->st_min[Z] = tor->tor_V[Z] - f;
00301         stp->st_max[Z] = tor->tor_V[Z] + f;
00302 
00303         return(0);                      /* OK */
00304 }
00305 
00306 /**
00307  *                      R T _ T O R _ P R I N T
00308  */
00309 void
00310 rt_tor_print(register const struct soltab *stp)
00311 {
00312         register const struct tor_specific *tor =
00313                 (struct tor_specific *)stp->st_specific;
00314 
00315         bu_log("r2/r1 (alpha) = %f\n", tor->tor_alpha);
00316         bu_log("r1 = %f\n", tor->tor_r1);
00317         bu_log("r2 = %f\n", tor->tor_r2);
00318         VPRINT("V", tor->tor_V);
00319         VPRINT("N", tor->tor_N);
00320         bn_mat_print("S o R", tor->tor_SoR );
00321         bn_mat_print("invR", tor->tor_invR );
00322 }
00323 
00324 /**
00325  *                      R T _ T O R _ S H O T
00326  *
00327  *  Intersect a ray with an torus, where all constant terms have
00328  *  been precomputed by rt_tor_prep().  If an intersection occurs,
00329  *  one or two struct seg(s) will be acquired and filled in.
00330  *
00331  *  NOTE:  All lines in this function are represented parametrically
00332  *  by a point,  P( x0, y0, z0 ) and a direction normal,
00333  *  D = ax + by + cz.  Any point on a line can be expressed
00334  *  by one variable 't', where
00335  *
00336  *      X = a*t + x0,   eg,  X = Dx*t + Px
00337  *      Y = b*t + y0,
00338  *      Z = c*t + z0.
00339  *
00340  *  First, convert the line to the coordinate system of a "stan-
00341  *  dard" torus.  This is a torus which lies in the X-Y plane,
00342  *  circles the origin, and whose primary radius is one.  The
00343  *  secondary radius is  alpha = ( R2/R1 )  of the original torus
00344  *  where  ( 0 < alpha <= 1 ).
00345  *
00346  *  Then find the equation of that line and the standard torus,
00347  *  which turns out to be a quartic equation in 't'.  Solve the
00348  *  equation using a general polynomial root finder.  Use those
00349  *  values of 't' to compute the points of intersection in the
00350  *  original coordinate system.
00351  *
00352  *  Returns -
00353  *      0       MISS
00354  *      >0      HIT
00355  */
00356 int
00357 rt_tor_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00358 {
00359         register struct tor_specific *tor =
00360                 (struct tor_specific *)stp->st_specific;
00361         register struct seg *segp;
00362         LOCAL vect_t    dprime;         /* D' */
00363         LOCAL vect_t    pprime;         /* P' */
00364         LOCAL vect_t    work;           /* temporary vector */
00365         LOCAL bn_poly_t C;              /* The final equation */
00366         LOCAL bn_complex_t val[4];              /* The complex roots */
00367         LOCAL double    k[4];           /* The real roots */
00368         register int    i;
00369         LOCAL int       j;
00370         LOCAL bn_poly_t A, Asqr;
00371         LOCAL bn_poly_t X2_Y2;          /* X**2 + Y**2 */
00372         LOCAL vect_t    cor_pprime;     /* new ray origin */
00373         LOCAL fastf_t   cor_proj;
00374 
00375         /* Convert vector into the space of the unit torus */
00376         MAT4X3VEC( dprime, tor->tor_SoR, rp->r_dir );
00377         VUNITIZE( dprime );
00378 
00379         VSUB2( work, rp->r_pt, tor->tor_V );
00380         MAT4X3VEC( pprime, tor->tor_SoR, work );
00381 
00382         /* normalize distance from torus.  substitute
00383          * corrected pprime which contains a translation along ray
00384          * direction to closest approach to vertex of torus.
00385          * Translating ray origin along direction of ray to closest pt. to
00386          * origin of solid's coordinate system, new ray origin is
00387          * 'cor_pprime'.
00388          */
00389         cor_proj = VDOT( pprime, dprime );
00390         VSCALE( cor_pprime, dprime, cor_proj );
00391         VSUB2( cor_pprime, pprime, cor_pprime );
00392 
00393         /*
00394          *  Given a line and a ratio, alpha, finds the equation of the
00395          *  unit torus in terms of the variable 't'.
00396          *
00397          *  The equation for the torus is:
00398          *
00399          * [ X**2 + Y**2 + Z**2 + (1 - alpha**2) ]**2 - 4*( X**2 + Y**2 ) = 0
00400          *
00401          *  First, find X, Y, and Z in terms of 't' for this line, then
00402          *  substitute them into the equation above.
00403          *
00404          *      Wx = Dx*t + Px
00405          *
00406          *      Wx**2 = Dx**2 * t**2  +  2 * Dx * Px  +  Px**2
00407          *              [0]                [1]           [2]    dgr=2
00408          */
00409         X2_Y2.dgr = 2;
00410         X2_Y2.cf[0] = dprime[X] * dprime[X] + dprime[Y] * dprime[Y];
00411         X2_Y2.cf[1] = 2.0 * (dprime[X] * cor_pprime[X] +
00412                              dprime[Y] * cor_pprime[Y]);
00413         X2_Y2.cf[2] = cor_pprime[X] * cor_pprime[X] +
00414                       cor_pprime[Y] * cor_pprime[Y];
00415 
00416         /* A = X2_Y2 + Z2 */
00417         A.dgr = 2;
00418         A.cf[0] = X2_Y2.cf[0] + dprime[Z] * dprime[Z];
00419         A.cf[1] = X2_Y2.cf[1] + 2.0 * dprime[Z] * cor_pprime[Z];
00420         A.cf[2] = X2_Y2.cf[2] + cor_pprime[Z] * cor_pprime[Z] +
00421                   1.0 - tor->tor_alpha * tor->tor_alpha;
00422 
00423         /* Inline expansion of (void) rt_poly_mul( &A, &A, &Asqr ) */
00424         /* Both polys have degree two */
00425         Asqr.dgr = 4;
00426         Asqr.cf[0] = A.cf[0] * A.cf[0];
00427         Asqr.cf[1] = A.cf[0] * A.cf[1] + A.cf[1] * A.cf[0];
00428         Asqr.cf[2] = A.cf[0] * A.cf[2] + A.cf[1] * A.cf[1] + A.cf[2] * A.cf[0];
00429         Asqr.cf[3] = A.cf[1] * A.cf[2] + A.cf[2] * A.cf[1];
00430         Asqr.cf[4] = A.cf[2] * A.cf[2];
00431 
00432         /* Inline expansion of bn_poly_scale( &X2_Y2, 4.0 ) and
00433          * rt_poly_sub( &Asqr, &X2_Y2, &C ).
00434          */
00435         C.dgr   = 4;
00436         C.cf[0] = Asqr.cf[0];
00437         C.cf[1] = Asqr.cf[1];
00438         C.cf[2] = Asqr.cf[2] - X2_Y2.cf[0] * 4.0;
00439         C.cf[3] = Asqr.cf[3] - X2_Y2.cf[1] * 4.0;
00440         C.cf[4] = Asqr.cf[4] - X2_Y2.cf[2] * 4.0;
00441 
00442         /*  It is known that the equation is 4th order.  Therefore,
00443          *  if the root finder returns other than 4 roots, error.
00444          */
00445         if ( (i = rt_poly_roots( &C, val, stp->st_dp->d_namep )) != 4 ){
00446             if( i > 0 )  {
00447                 bu_log("tor:  rt_poly_roots() 4!=%d\n", i);
00448                 bn_pr_roots( stp->st_name, val, i );
00449             } else if (i < 0) {
00450                 static int reported=0;
00451                 bu_log("The root solver failed to converge on a solution for %s\n", stp->st_dp->d_namep);
00452                 if (!reported) {
00453                     VPRINT("while shooting from:\t", rp->r_pt);
00454                     VPRINT("while shooting at:\t", rp->r_dir);
00455                     bu_log("Additional torus convergence failure details will be suppressed.\n");
00456                     reported=1;
00457                 }
00458             }
00459             return(0);          /* MISS */
00460         }
00461 
00462         /*  Only real roots indicate an intersection in real space.
00463          *
00464          *  Look at each root returned; if the imaginary part is zero
00465          *  or sufficiently close, then use the real part as one value
00466          *  of 't' for the intersections
00467          */
00468         for ( j=0, i=0; j < 4; j++ ){
00469                 if( NEAR_ZERO( val[j].im, ap->a_rt_i->rti_tol.dist ) )
00470                         k[i++] = val[j].re;
00471         }
00472 
00473         /* reverse above translation by adding distance to all 'k' values. */
00474         for( j = 0; j < i; ++j )
00475                 k[j] -= cor_proj;
00476 
00477         /* Here, 'i' is number of points found */
00478         switch( i )  {
00479         case 0:
00480                 return(0);              /* No hit */
00481 
00482         default:
00483                 bu_log("rt_tor_shot: reduced 4 to %d roots\n",i);
00484                 bn_pr_roots( stp->st_name, val, 4 );
00485                 return(0);              /* No hit */
00486 
00487         case 2:
00488                 {
00489                         /* Sort most distant to least distant. */
00490                         FAST fastf_t    u;
00491                         if( (u=k[0]) < k[1] )  {
00492                                 /* bubble larger towards [0] */
00493                                 k[0] = k[1];
00494                                 k[1] = u;
00495                         }
00496                 }
00497                 break;
00498         case 4:
00499                 {
00500                         register short  n;
00501                         register short  lim;
00502 
00503                         /*  Inline rt_pt_sort().  Sorts k[] into descending order. */
00504                         for( lim = i-1; lim > 0; lim-- )  {
00505                                 for( n = 0; n < lim; n++ )  {
00506                                         FAST fastf_t    u;
00507                                         if( (u=k[n]) < k[n+1] )  {
00508                                                 /* bubble larger towards [0] */
00509                                                 k[n] = k[n+1];
00510                                                 k[n+1] = u;
00511                                         }
00512                                 }
00513                         }
00514                 }
00515                 break;
00516         }
00517 
00518         /* Now, t[0] > t[npts-1] */
00519         /* k[1] is entry point, and k[0] is farthest exit point */
00520         RT_GET_SEG(segp, ap->a_resource);
00521         segp->seg_stp = stp;
00522         segp->seg_in.hit_dist = k[1]*tor->tor_r1;
00523         segp->seg_out.hit_dist = k[0]*tor->tor_r1;
00524         segp->seg_in.hit_surfno = segp->seg_out.hit_surfno = 0;
00525         /* Set aside vector for rt_tor_norm() later */
00526         VJOIN1( segp->seg_in.hit_vpriv, pprime, k[1], dprime );
00527         VJOIN1( segp->seg_out.hit_vpriv, pprime, k[0], dprime );
00528         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00529 
00530         if( i == 2 )
00531                 return(2);                      /* HIT */
00532 
00533         /* 4 points */
00534         /* k[3] is entry point, and k[2] is exit point */
00535         RT_GET_SEG(segp, ap->a_resource);
00536         segp->seg_stp = stp;
00537         segp->seg_in.hit_dist = k[3]*tor->tor_r1;
00538         segp->seg_out.hit_dist = k[2]*tor->tor_r1;
00539         segp->seg_in.hit_surfno = segp->seg_out.hit_surfno = 1;
00540         VJOIN1( segp->seg_in.hit_vpriv, pprime, k[3], dprime );
00541         VJOIN1( segp->seg_out.hit_vpriv, pprime, k[2], dprime );
00542         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00543         return(4);                      /* HIT */
00544 }
00545 
00546 #define SEG_MISS(SEG)           (SEG).seg_stp=(struct soltab *) 0;
00547 /***
00548  *                      R T _ T O R _ V S H O T
00549  *
00550  *  This is the Becker vector version
00551  */
00552 void
00553 rt_tor_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
00554                                /* An array of solid pointers */
00555                                /* An array of ray pointers */
00556                                /* array of segs (results returned) */
00557                                /* Number of ray/object pairs */
00558 
00559 {
00560         register int    i;
00561         register struct tor_specific *tor;
00562         LOCAL vect_t    dprime;         /* D' */
00563         LOCAL vect_t    pprime;         /* P' */
00564         LOCAL vect_t    work;           /* temporary vector */
00565         LOCAL bn_poly_t *C;             /* The final equation */
00566         LOCAL bn_complex_t (*val)[4];   /* The complex roots */
00567         LOCAL int       num_roots;
00568         LOCAL int       num_zero;
00569         LOCAL bn_poly_t A, Asqr;
00570         LOCAL bn_poly_t X2_Y2;          /* X**2 + Y**2 */
00571         LOCAL vect_t    cor_pprime;     /* new ray origin */
00572         LOCAL fastf_t   *cor_proj;
00573 
00574         /* Allocate space for polys and roots */
00575         C = (bn_poly_t *)bu_malloc(n * sizeof(bn_poly_t), "tor bn_poly_t");
00576         val = (bn_complex_t (*)[4])bu_malloc(n * sizeof(bn_complex_t) * 4,
00577                 "tor bn_complex_t");
00578         cor_proj = (fastf_t *)bu_malloc(n * sizeof(fastf_t), "tor proj");
00579 
00580         /* Initialize seg_stp to assume hit (zero will then flag miss) */
00581 #       include "noalias.h"
00582         for(i = 0; i < n; i++) segp[i].seg_stp = stp[i];
00583 
00584         /* for each ray/torus pair */
00585 #       include "noalias.h"
00586         for(i = 0; i < n; i++){
00587                 if( segp[i].seg_stp == 0) continue;     /* Skip */
00588                 tor = (struct tor_specific *)stp[i]->st_specific;
00589 
00590                 /* Convert vector into the space of the unit torus */
00591                 MAT4X3VEC( dprime, tor->tor_SoR, rp[i]->r_dir );
00592                 VUNITIZE( dprime );
00593 
00594                 /* Use segp[i].seg_in.hit_normal as tmp to hold dprime */
00595                 VMOVE( segp[i].seg_in.hit_normal, dprime );
00596 
00597                 VSUB2( work, rp[i]->r_pt, tor->tor_V );
00598                 MAT4X3VEC( pprime, tor->tor_SoR, work );
00599 
00600                 /* Use segp[i].seg_out.hit_normal as tmp to hold pprime */
00601                 VMOVE( segp[i].seg_out.hit_normal, pprime );
00602 
00603                 /* normalize distance from torus.  substitute
00604                  * corrected pprime which contains a translation along ray
00605                  * direction to closest approach to vertex of torus.
00606                  * Translating ray origin along direction of ray to closest
00607                  * pt. to origin of solid's coordinate system, new ray origin is
00608                  * 'cor_pprime'.
00609                  */
00610                 cor_proj[i] = VDOT( pprime, dprime );
00611                 VSCALE( cor_pprime, dprime, cor_proj[i] );
00612                 VSUB2( cor_pprime, pprime, cor_pprime );
00613 
00614                 /*
00615                  *  Given a line and a ratio, alpha, finds the equation of the
00616                  *  unit torus in terms of the variable 't'.
00617                  *
00618                  *  The equation for the torus is:
00619                  *
00620                  * [X**2 + Y**2 + Z**2 + (1 - alpha**2)]**2 - 4*(X**2 + Y**2) =0
00621                  *
00622                  *  First, find X, Y, and Z in terms of 't' for this line, then
00623                  *  substitute them into the equation above.
00624                  *
00625                  *      Wx = Dx*t + Px
00626                  *
00627                  *      Wx**2 = Dx**2 * t**2  +  2 * Dx * Px  +  Px**2
00628                  *              [0]                [1]           [2]    dgr=2
00629                  */
00630                 X2_Y2.dgr = 2;
00631                 X2_Y2.cf[0] = dprime[X] * dprime[X] + dprime[Y] * dprime[Y];
00632                 X2_Y2.cf[1] = 2.0 * (dprime[X] * cor_pprime[X] +
00633                                      dprime[Y] * cor_pprime[Y]);
00634                 X2_Y2.cf[2] = cor_pprime[X] * cor_pprime[X] +
00635                               cor_pprime[Y] * cor_pprime[Y];
00636 
00637                 /* A = X2_Y2 + Z2 */
00638                 A.dgr = 2;
00639                 A.cf[0] = X2_Y2.cf[0] + dprime[Z] * dprime[Z];
00640                 A.cf[1] = X2_Y2.cf[1] + 2.0 * dprime[Z] * cor_pprime[Z];
00641                 A.cf[2] = X2_Y2.cf[2] + cor_pprime[Z] * cor_pprime[Z] +
00642                           1.0 - tor->tor_alpha * tor->tor_alpha;
00643 
00644                 /* Inline expansion of (void) rt_poly_mul( &A, &A, &Asqr ) */
00645                 /* Both polys have degree two */
00646                 Asqr.dgr = 4;
00647                 Asqr.cf[0] = A.cf[0] * A.cf[0];
00648                 Asqr.cf[1] = A.cf[0] * A.cf[1] +
00649                                  A.cf[1] * A.cf[0];
00650                 Asqr.cf[2] = A.cf[0] * A.cf[2] +
00651                                  A.cf[1] * A.cf[1] +
00652                                  A.cf[2] * A.cf[0];
00653                 Asqr.cf[3] = A.cf[1] * A.cf[2] +
00654                                  A.cf[2] * A.cf[1];
00655                 Asqr.cf[4] = A.cf[2] * A.cf[2];
00656 
00657                 /* Inline expansion of (void) bn_poly_scale( &X2_Y2, 4.0 ) */
00658                 X2_Y2.cf[0] *= 4.0;
00659                 X2_Y2.cf[1] *= 4.0;
00660                 X2_Y2.cf[2] *= 4.0;
00661 
00662                 /* Inline expansion of (void) rt_poly_sub( &Asqr, &X2_Y2, &C ) */
00663                 /* offset is know to be 2 */
00664                 C[i].dgr        = 4;
00665                 C[i].cf[0] = Asqr.cf[0];
00666                 C[i].cf[1] = Asqr.cf[1];
00667                 C[i].cf[2] = Asqr.cf[2] - X2_Y2.cf[0];
00668                 C[i].cf[3] = Asqr.cf[3] - X2_Y2.cf[1];
00669                 C[i].cf[4] = Asqr.cf[4] - X2_Y2.cf[2];
00670         }
00671 
00672         /* Unfortunately finding the 4th order roots are too ugly to inline */
00673         for(i = 0; i < n; i++){
00674             if( segp[i].seg_stp == 0) continue; /* Skip */
00675 
00676             /*  It is known that the equation is 4th order.  Therefore,
00677              *  if the root finder returns other than 4 roots, error.
00678              */
00679             if ( (num_roots = rt_poly_roots( &(C[i]), &(val[i][0]), (*stp)->st_dp->d_namep )) != 4 ){
00680                 if( num_roots > 0 )  {
00681                     bu_log("tor:  rt_poly_roots() 4!=%d\n", num_roots);
00682                     bn_pr_roots( "tor", val[i], num_roots );
00683                 } else if (num_roots < 0) {
00684                     static int reported=0;
00685                     bu_log("The root solver failed to converge on a solution for %s\n", stp[i]->st_dp->d_namep);
00686                     if (!reported) {
00687                         VPRINT("while shooting from:\t", rp[i]->r_pt);
00688                         VPRINT("while shooting at:\t", rp[i]->r_dir);
00689                         bu_log("Additional torus convergence failure details will be suppressed.\n");
00690                         reported=1;
00691                     }
00692                 }
00693                 SEG_MISS(segp[i]);              /* MISS */
00694             }
00695         }
00696 
00697         /* for each ray/torus pair */
00698 #       include "noalias.h"
00699         for(i = 0; i < n; i++){
00700                 if( segp[i].seg_stp == 0) continue; /* Skip */
00701 
00702                 /*  Only real roots indicate an intersection in real space.
00703                  *
00704                  *  Look at each root returned; if the imaginary part is zero
00705                  *  or sufficiently close, then use the real part as one value
00706                  *  of 't' for the intersections
00707                  */
00708                 /* Also reverse translation by adding distance to all 'k' values. */
00709                 /* Reuse C to hold k values */
00710                 num_zero = 0;
00711                 if( NEAR_ZERO( val[i][0].im, ap->a_rt_i->rti_tol.dist ) )
00712                         C[i].cf[num_zero++] = val[i][0].re - cor_proj[i];
00713                 if( NEAR_ZERO( val[i][1].im, ap->a_rt_i->rti_tol.dist ) ) {
00714                         C[i].cf[num_zero++] = val[i][1].re - cor_proj[i];
00715                 }
00716                 if( NEAR_ZERO( val[i][2].im, ap->a_rt_i->rti_tol.dist ) ) {
00717                         C[i].cf[num_zero++] = val[i][2].re - cor_proj[i];
00718                 }
00719                 if( NEAR_ZERO( val[i][3].im, ap->a_rt_i->rti_tol.dist ) ) {
00720                         C[i].cf[num_zero++] = val[i][3].re - cor_proj[i];
00721                 }
00722                 C[i].dgr   = num_zero;
00723 
00724                 /* Here, 'i' is number of points found */
00725                 if( num_zero == 0 ) {
00726                         SEG_MISS(segp[i]);              /* MISS */
00727                 }
00728                 else if( num_zero != 2 && num_zero != 4 ) {
00729 #if 0
00730                         bu_log("rt_tor_shot: reduced 4 to %d roots\n",i);
00731                         bn_pr_roots( stp->st_name, val, 4 );
00732 #endif
00733                         SEG_MISS(segp[i]);              /* MISS */
00734                 }
00735         }
00736 
00737         /* Process each one segment hit */
00738 #       include "noalias.h"
00739         for(i = 0; i < n; i++){
00740                 if( segp[i].seg_stp == 0) continue; /* Skip */
00741                 if( C[i].dgr != 2 )  continue;  /* Not one segment */
00742 
00743                 tor = (struct tor_specific *)stp[i]->st_specific;
00744 
00745                 /* segp[i].seg_in.hit_normal holds dprime */
00746                 /* segp[i].seg_out.hit_normal holds pprime */
00747                 if (C[i].cf[1] < C[i].cf[0]) {
00748                         /* C[i].cf[1] is entry point */
00749                         segp[i].seg_in.hit_dist = C[i].cf[1]*tor->tor_r1;
00750                         segp[i].seg_out.hit_dist = C[i].cf[0]*tor->tor_r1;
00751                         /* Set aside vector for rt_tor_norm() later */
00752                         VJOIN1( segp[i].seg_in.hit_vpriv,
00753                                 segp[i].seg_out.hit_normal,
00754                                 C[i].cf[1], segp[i].seg_in.hit_normal );
00755                         VJOIN1( segp[i].seg_out.hit_vpriv,
00756                                 segp[i].seg_out.hit_normal,
00757                                 C[i].cf[0], segp[i].seg_in.hit_normal );
00758                 } else {
00759                         /* C[i].cf[0] is entry point */
00760                         segp[i].seg_in.hit_dist = C[i].cf[0]*tor->tor_r1;
00761                         segp[i].seg_out.hit_dist = C[i].cf[1]*tor->tor_r1;
00762                         /* Set aside vector for rt_tor_norm() later */
00763                         VJOIN1( segp[i].seg_in.hit_vpriv,
00764                                 segp[i].seg_out.hit_normal,
00765                                 C[i].cf[0], segp[i].seg_in.hit_normal );
00766                         VJOIN1( segp[i].seg_out.hit_vpriv,
00767                                 segp[i].seg_out.hit_normal,
00768                                 C[i].cf[1], segp[i].seg_in.hit_normal );
00769                 }
00770         }
00771 
00772         /* Process each two segment hit */
00773         for(i = 0; i < n; i++){
00774 
00775                 if( segp[i].seg_stp == 0) continue;     /* Skip */
00776                 if( C[i].dgr != 4 )  continue;  /* Not two segment */
00777 
00778                 tor = (struct tor_specific *)stp[i]->st_specific;
00779 
00780                 /* Sort most distant to least distant. */
00781                 rt_pt_sort( C[i].cf, 4 );
00782                 /* Now, t[0] > t[npts-1] */
00783 
00784                 /* segp[i].seg_in.hit_normal holds dprime */
00785                 VMOVE( dprime, segp[i].seg_in.hit_normal );
00786                 /* segp[i].seg_out.hit_normal holds pprime */
00787                 VMOVE( pprime, segp[i].seg_out.hit_normal );
00788 
00789                 /* C[i].cf[1] is entry point */
00790                 segp[i].seg_in.hit_dist =  C[i].cf[1]*tor->tor_r1;
00791                 segp[i].seg_out.hit_dist = C[i].cf[0]*tor->tor_r1;
00792                 /* Set aside vector for rt_tor_norm() later */
00793                 VJOIN1(segp[i].seg_in.hit_vpriv, pprime, C[i].cf[1], dprime );
00794                 VJOIN1(segp[i].seg_out.hit_vpriv, pprime, C[i].cf[0], dprime);
00795 
00796 #if 0
00797                 /* C[i].cf[3] is entry point */
00798                 /* Attach second hit to segment chain */
00799                 /* XXXX need convention for vectorizing doubly linked list! */
00800                 GET_SEG(seg2p, resp);
00801                 segp[i].seg_next = seg2p;
00802                 seg2p->seg_stp = stp[i];
00803                 seg2p->seg_in.hit_dist =  C[i].cf[3]*tor->tor_r1;
00804                 seg2p->seg_out.hit_dist = C[i].cf[2]*tor->tor_r1;
00805                 VJOIN1( seg2p->seg_in.hit_vpriv, pprime, C[i].cf[3], dprime );
00806                 VJOIN1(seg2p->seg_out.hit_vpriv, pprime, C[i].cf[2], dprime );
00807 #endif
00808         }
00809 
00810         /* Free tmp space used */
00811         bu_free( (char *)C, "tor C");
00812         bu_free( (char *)val, "tor val");
00813         bu_free( (char *)cor_proj, "tor cor_proj");
00814 }
00815 
00816 /**
00817  *                      R T _ T O R _ N O R M
00818  *
00819  *  Compute the normal to the torus,
00820  *  given a point on the UNIT TORUS centered at the origin on the X-Y plane.
00821  *  The gradient of the torus at that point is in fact the
00822  *  normal vector, which will have to be given unit length.
00823  *  To make this useful for the original torus, it will have
00824  *  to be rotated back to the orientation of the original torus.
00825  *
00826  *  Given that the equation for the unit torus is:
00827  *
00828  *      [ X**2 + Y**2 + Z**2 + (1 - alpha**2) ]**2 - 4*( X**2 + Y**2 )  =  0
00829  *
00830  *  let w = X**2 + Y**2 + Z**2 + (1 - alpha**2), then the equation becomes:
00831  *
00832  *      w**2 - 4*( X**2 + Y**2 )  =  0
00833  *
00834  *  For f(x,y,z) = 0, the gradient of f() is ( df/dx, df/dy, df/dz ).
00835  *
00836  *      df/dx = 2 * w * 2 * x - 8 * x   = (4 * w - 8) * x
00837  *      df/dy = 2 * w * 2 * y - 8 * y   = (4 * w - 8) * y
00838  *      df/dz = 2 * w * 2 * z           = 4 * w * z
00839  *
00840  *  Since we rescale the gradient (normal) to unity, we divide the
00841  *  above equations by four here.
00842  */
00843 void
00844 rt_tor_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00845 {
00846         register struct tor_specific *tor =
00847                 (struct tor_specific *)stp->st_specific;
00848         FAST fastf_t w;
00849         LOCAL vect_t work;
00850 
00851         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
00852         w = hitp->hit_vpriv[X]*hitp->hit_vpriv[X] +
00853             hitp->hit_vpriv[Y]*hitp->hit_vpriv[Y] +
00854             hitp->hit_vpriv[Z]*hitp->hit_vpriv[Z] +
00855             1.0 - tor->tor_alpha*tor->tor_alpha;
00856         VSET( work,
00857                 ( w - 2.0 ) * hitp->hit_vpriv[X],
00858                 ( w - 2.0 ) * hitp->hit_vpriv[Y],
00859                   w * hitp->hit_vpriv[Z] );
00860         VUNITIZE( work );
00861 
00862         MAT3X3VEC( hitp->hit_normal, tor->tor_invR, work );
00863 }
00864 
00865 /**
00866  *                      R T _ T O R _ C U R V E
00867  *
00868  *  Return the curvature of the torus.
00869  */
00870 void
00871 rt_tor_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00872 {
00873         register struct tor_specific *tor =
00874                 (struct tor_specific *)stp->st_specific;
00875         vect_t  w4, w5;
00876         fastf_t nx, ny, nz, x1, y1, z1;
00877         fastf_t d;
00878 
00879         nx = tor->tor_N[X];
00880         ny = tor->tor_N[Y];
00881         nz = tor->tor_N[Z];
00882 
00883         /* vector from V to hit point */
00884         VSUB2( w4, hitp->hit_point, tor->tor_V );
00885 
00886         if( !NEAR_ZERO(nz, 0.00001) ) {
00887                 z1 = w4[Z]*nx*nx + w4[Z]*ny*ny - w4[X]*nx*nz - w4[Y]*ny*nz;
00888                 x1 = (nx*(z1-w4[Z])/nz) + w4[X];
00889                 y1 = (ny*(z1-w4[Z])/nz) + w4[Y];
00890         } else if( !NEAR_ZERO(ny, 0.00001) ) {
00891                 y1 = w4[Y]*nx*nx + w4[Y]*nz*nz - w4[X]*nx*ny - w4[Z]*ny*nz;
00892                 x1 = (nx*(y1-w4[Y])/ny) + w4[X];
00893                 z1 = (nz*(y1-w4[Y])/ny) + w4[Z];
00894         } else {
00895                 x1 = w4[X]*ny*ny + w4[X]*nz*nz - w4[Y]*nx*ny - w4[Z]*nz*nx;
00896                 y1 = (ny*(x1-w4[X])/nx) + w4[Y];
00897                 z1 = (nz*(x1-w4[X])/nx) + w4[Z];
00898         }
00899         d = sqrt(x1*x1 + y1*y1 + z1*z1);
00900 
00901         cvp->crv_c1 = (tor->tor_r1 - d) / (d * tor->tor_r2);
00902         cvp->crv_c2 = -1.0 / tor->tor_r2;
00903 
00904         w4[X] = x1 / d;
00905         w4[Y] = y1 / d;
00906         w4[Z] = z1 / d;
00907         VCROSS( w5, tor->tor_N, w4 );
00908         VCROSS( cvp->crv_pdir, w5, hitp->hit_normal );
00909         VUNITIZE( cvp->crv_pdir );
00910 }
00911 
00912 /**
00913  *                      R T _ T O R _ U V
00914  */
00915 void
00916 rt_tor_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00917 {
00918         register struct tor_specific    *tor =
00919                         (struct tor_specific *) stp -> st_specific;
00920         LOCAL vect_t                    work;
00921         LOCAL vect_t                    pprime;
00922         LOCAL vect_t                    pprime2;
00923         LOCAL fastf_t                   costheta;
00924 
00925         VSUB2(work, hitp -> hit_point, tor -> tor_V);
00926         MAT4X3VEC(pprime, tor -> tor_SoR, work);
00927         /*
00928          * -pi/2 <= atan2(x,y) <= pi/2
00929          */
00930         uvp -> uv_u = atan2(pprime[Y], pprime[X]) * bn_inv2pi + 0.5;
00931 
00932         VSET(work, pprime[X], pprime[Y], 0.0);
00933         VUNITIZE(work);
00934         VSUB2(pprime2, pprime, work);
00935         VUNITIZE(pprime2);
00936         costheta = VDOT(pprime2, work);
00937         uvp -> uv_v = atan2(pprime2[Z], costheta) * bn_inv2pi + 0.5;
00938 }
00939 
00940 /**
00941  *                      R T _ T O R _ F R E E
00942  */
00943 void
00944 rt_tor_free(struct soltab *stp)
00945 {
00946         register struct tor_specific *tor =
00947                 (struct tor_specific *)stp->st_specific;
00948 
00949         bu_free( (char *)tor, "tor_specific");
00950 }
00951 
00952 int
00953 rt_tor_class(void)
00954 {
00955         return(0);
00956 }
00957 
00958 /**
00959  *                      R T _ N U M _ C I R C U L A R _ S E G M E N T S
00960  *
00961  *  Given a circle with a specified radius, determine the minimum number
00962  *  of straight line segments that the circle can be approximated with,
00963  *  while still meeting the given maximum permissible error distance.
00964  *  Form a chord (straight line) by
00965  *  connecting the start and end points found when
00966  *  sweeping a 'radius' arc through angle 'theta'.
00967  *
00968  *  The error distance is the distance between where a radius line
00969  *  at angle theta/2 hits the chord, and where it hits the circle
00970  *  (at 'radius' distance).
00971  *
00972  *      error_distance = radius * ( 1 - cos( theta/2 ) )
00973  *
00974  *  or
00975  *
00976  *      theta = 2 * acos( 1 - error_distance / radius )
00977  *
00978  *  Returns -
00979  *      number of segments.  Always at least 6.
00980  */
00981 int
00982 rt_num_circular_segments(double maxerr, double  radius)
00983 {
00984         register fastf_t        cos_half_theta;
00985         register fastf_t        half_theta;
00986         int                     n;
00987 
00988         if( radius <= 0.0 || maxerr <= 0.0 || maxerr >= radius )  {
00989                 /* Return a default number of segments */
00990                 return(6);
00991         }
00992         cos_half_theta = 1.0 - maxerr / radius;
00993         /* There does not seem to be any reasonable way to express the
00994          * acos in terms of an atan2(), so extra checking is done.
00995          */
00996         if( cos_half_theta <= 0.0 || cos_half_theta >= 1.0 )  {
00997                 /* Return a default number of segments */
00998                 return(6);
00999         }
01000         half_theta = acos( cos_half_theta );
01001         if( half_theta < SMALL )  {
01002                 /* A very large number of segments will be needed.
01003                  * Impose an upper bound here
01004                  */
01005                 return( 360*10 );
01006         }
01007         n = bn_pi / half_theta + 0.99;
01008 
01009         /* Impose the limits again */
01010         if( n <= 6 )  return(6);
01011         if( n >= 360*10 )  return( 360*10 );
01012         return(n);
01013 }
01014 /**
01015  *                      R T _ T O R _ P L O T
01016  *
01017  * The TORUS has the following input fields:
01018  *      ti.v    V from origin to center
01019  *      ti.h    Radius Vector, Normal to plane of torus
01020  *      ti.a,ti.b       perpindicular, to CENTER of torus (for top, bottom)
01021  *
01022  */
01023 int
01024 rt_tor_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01025 {
01026         fastf_t         alpha;
01027         fastf_t         beta;
01028         fastf_t         cos_alpha, sin_alpha;
01029         fastf_t         cos_beta, sin_beta;
01030         fastf_t         dist_to_rim;
01031         struct rt_tor_internal  *tip;
01032         int             w;
01033         int             nw = 8;
01034         int             len;
01035         int             nlen = 16;
01036         fastf_t         *pts;
01037         vect_t          G;
01038         vect_t          radius;
01039         vect_t          edge;
01040         fastf_t         rel;
01041 
01042         RT_CK_DB_INTERNAL(ip);
01043         tip = (struct rt_tor_internal *)ip->idb_ptr;
01044         RT_TOR_CK_MAGIC(tip);
01045 
01046         if( ttol->rel <= 0.0 || ttol->rel >= 1.0 )  {
01047                 rel = 0.0;              /* none */
01048         } else {
01049                 /* Convert relative tolerance to absolute tolerance
01050                  * by scaling w.r.t. the torus diameter.
01051                  */
01052                 rel = ttol->rel * 2 * (tip->r_a+tip->r_h);
01053         }
01054         /* Take tighter of two (absolute) tolerances */
01055         if( ttol->abs <= 0.0 )  {
01056                 /* No absolute tolerance given */
01057                 if( rel <= 0.0 )  {
01058                         /* User has no tolerance for this kind of drink! */
01059                         nw = 8;
01060                         nlen = 16;
01061                 } else {
01062                         /* Use the absolute-ized relative tolerance */
01063                         nlen = rt_num_circular_segments( rel, tip->r_a );
01064                         nw = rt_num_circular_segments( rel, tip->r_h );
01065                 }
01066         } else {
01067                 /* Absolute tolerance was given */
01068                 if( rel <= 0.0 || rel > ttol->abs)
01069                         rel = ttol->abs;
01070                 nlen = rt_num_circular_segments( rel, tip->r_a );
01071                 nw = rt_num_circular_segments( rel, tip->r_h );
01072         }
01073 
01074         /*
01075          *  Implement surface-normal tolerance, if given
01076          *      nseg = (2 * pi) / (2 * tol)
01077          *  For a facet which subtends angle theta, surface normal
01078          *  is exact in the center, and off by theta/2 at the edges.
01079          *  Note:  1 degree tolerance requires 180*180 tessellation!
01080          */
01081         if( ttol->norm > 0.0 )  {
01082                 register int    nseg;
01083                 nseg = (bn_pi / ttol->norm) + 0.99;
01084                 if( nseg > nlen ) nlen = nseg;
01085                 if( nseg > nw ) nw = nseg;
01086         }
01087 
01088         /* Compute the points on the surface of the torus */
01089         dist_to_rim = tip->r_h/tip->r_a;
01090         pts = (fastf_t *)bu_malloc( nw * nlen * sizeof(point_t),
01091                 "rt_tor_plot pts[]" );
01092 
01093 #define TOR_PT(www,lll) ((((www)%nw)*nlen)+((lll)%nlen))
01094 #define TOR_PTA(ww,ll)  (&pts[TOR_PT(ww,ll)*3])
01095 #define TOR_NORM_A(ww,ll)       (&norms[TOR_PT(ww,ll)*3])
01096 
01097         for( len = 0; len < nlen; len++ )  {
01098                 beta = bn_twopi * len / nlen;
01099                 cos_beta = cos(beta);
01100                 sin_beta = sin(beta);
01101                 /* G always points out to rim, along radius vector */
01102                 VCOMB2( radius, cos_beta, tip->a, sin_beta, tip->b );
01103                 /* We assume that |radius| = |A|.  Circular */
01104                 VSCALE( G, radius, dist_to_rim );
01105                 for( w = 0; w < nw; w++ )  {
01106                         alpha = bn_twopi * w / nw;
01107                         cos_alpha = cos(alpha);
01108                         sin_alpha = sin(alpha);
01109                         VCOMB2( edge, cos_alpha, G, sin_alpha*tip->r_h, tip->h );
01110                         VADD3( TOR_PTA(w,len), tip->v, edge, radius );
01111                 }
01112         }
01113 
01114         /* Draw lengthwise (around outside rim) */
01115         for( w = 0; w < nw; w++ )  {
01116                 len = nlen-1;
01117                 RT_ADD_VLIST( vhead, TOR_PTA(w,len), BN_VLIST_LINE_MOVE );
01118                 for( len = 0; len < nlen; len++ )  {
01119                         RT_ADD_VLIST( vhead, TOR_PTA(w,len), BN_VLIST_LINE_DRAW );
01120                 }
01121         }
01122         /* Draw around the "width" (1 cross section) */
01123         for( len = 0; len < nlen; len++ )  {
01124                 w = nw-1;
01125                 RT_ADD_VLIST( vhead, TOR_PTA(w,len), BN_VLIST_LINE_MOVE );
01126                 for( w = 0; w < nw; w++ )  {
01127                         RT_ADD_VLIST( vhead, TOR_PTA(w,len), BN_VLIST_LINE_DRAW );
01128                 }
01129         }
01130 
01131         bu_free( (char *)pts, "rt_tor_plot pts[]" );
01132         return(0);
01133 }
01134 
01135 /**
01136  *                      R T _ T O R _ T E S S
01137  */
01138 int
01139 rt_tor_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01140 {
01141         fastf_t         alpha;
01142         fastf_t         beta;
01143         fastf_t         cos_alpha, sin_alpha;
01144         fastf_t         cos_beta, sin_beta;
01145         fastf_t         dist_to_rim;
01146         struct rt_tor_internal  *tip;
01147         int             w;
01148         int             nw = 6;
01149         int             len;
01150         int             nlen = 6;
01151         fastf_t         *pts;
01152         vect_t          G;
01153         vect_t          radius;
01154         vect_t          edge;
01155         struct shell    *s;
01156         struct vertex   **verts;
01157         struct faceuse  **faces;
01158         fastf_t         *norms;
01159         struct vertex   **vertp[4];
01160         int             nfaces;
01161         int             i;
01162         fastf_t         rel;
01163 
01164         RT_CK_DB_INTERNAL(ip);
01165         tip = (struct rt_tor_internal *)ip->idb_ptr;
01166         RT_TOR_CK_MAGIC(tip);
01167 
01168         if( ttol->rel <= 0.0 || ttol->rel >= 1.0 )  {
01169                 rel = 0.0;              /* none */
01170         } else {
01171                 /* Convert relative tolerance to absolute tolerance
01172                  * by scaling w.r.t. the torus diameter.
01173                  */
01174                 rel = ttol->rel * 2 * (tip->r_a+tip->r_h);
01175         }
01176         /* Take tighter of two (absolute) tolerances */
01177         if( ttol->abs <= 0.0 )  {
01178                 /* No absolute tolerance given */
01179                 if( rel <= 0.0 )  {
01180                         /* User has no tolerance for this kind of drink! */
01181                         nw = 8;
01182                         nlen = 16;
01183                 } else {
01184                         /* Use the absolute-ized relative tolerance */
01185                         nlen = rt_num_circular_segments( rel, tip->r_a );
01186                         nw = rt_num_circular_segments( rel, tip->r_h );
01187                 }
01188         } else {
01189                 /* Absolute tolerance was given */
01190                 if( rel <= 0.0 || rel > ttol->abs)
01191                         rel = ttol->abs;
01192                 nlen = rt_num_circular_segments( rel, tip->r_a );
01193                 nw = rt_num_circular_segments( rel, tip->r_h );
01194         }
01195 
01196         /*
01197          *  Implement surface-normal tolerance, if given
01198          *      nseg = (2 * pi) / (2 * tol)
01199          *  For a facet which subtends angle theta, surface normal
01200          *  is exact in the center, and off by theta/2 at the edges.
01201          *  Note:  1 degree tolerance requires 180*180 tessellation!
01202          */
01203         if( ttol->norm > 0.0 )  {
01204                 register int    nseg;
01205                 nseg = (bn_pi / ttol->norm) + 0.99;
01206                 if( nseg > nlen ) nlen = nseg;
01207                 if( nseg > nw ) nw = nseg;
01208         }
01209 
01210         /* Compute the points on the surface of the torus */
01211         dist_to_rim = tip->r_h/tip->r_a;
01212         pts = (fastf_t *)bu_malloc( nw * nlen * sizeof(point_t),
01213                 "rt_tor_tess pts[]" );
01214         norms = (fastf_t *)bu_malloc( nw * nlen * sizeof( vect_t ) , "rt_tor_tess: norms[]" );
01215 
01216         for( len = 0; len < nlen; len++ )  {
01217                 beta = bn_twopi * len / nlen;
01218                 cos_beta = cos(beta);
01219                 sin_beta = sin(beta);
01220                 /* G always points out to rim, along radius vector */
01221                 VCOMB2( radius, cos_beta, tip->a, sin_beta, tip->b );
01222                 /* We assume that |radius| = |A|.  Circular */
01223                 VSCALE( G, radius, dist_to_rim );
01224                 for( w = 0; w < nw; w++ )  {
01225                         alpha = bn_twopi * w / nw;
01226                         cos_alpha = cos(alpha);
01227                         sin_alpha = sin(alpha);
01228                         VCOMB2( edge, cos_alpha, G, sin_alpha*tip->r_h, tip->h );
01229                         VADD3( TOR_PTA(w,len), tip->v, edge, radius );
01230 
01231                         VMOVE( TOR_NORM_A(w,len) , edge );
01232                         VUNITIZE( TOR_NORM_A(w,len) );
01233                 }
01234         }
01235 
01236         *r = nmg_mrsv( m );     /* Make region, empty shell, vertex */
01237         s = BU_LIST_FIRST(shell, &(*r)->s_hd);
01238 
01239         verts = (struct vertex **)bu_calloc( nw*nlen, sizeof(struct vertex *),
01240                 "rt_tor_tess *verts[]" );
01241         faces = (struct faceuse **)bu_calloc( nw*nlen, sizeof(struct faceuse *),
01242                 "rt_tor_tess *faces[]" );
01243 
01244         /* Build the topology of the torus */
01245         /* Note that increasing 'w' goes to the left (alpha goes ccw) */
01246         nfaces = 0;
01247         for( w = 0; w < nw; w++ )  {
01248                 for( len = 0; len < nlen; len++ )  {
01249                         vertp[0] = &verts[ TOR_PT(w+0,len+0) ];
01250                         vertp[1] = &verts[ TOR_PT(w+0,len+1) ];
01251                         vertp[2] = &verts[ TOR_PT(w+1,len+1) ];
01252                         vertp[3] = &verts[ TOR_PT(w+1,len+0) ];
01253                         if( (faces[nfaces++] = nmg_cmface( s, vertp, 4 )) == (struct faceuse *)0 )  {
01254                                 bu_log("rt_tor_tess() nmg_cmface failed, w=%d/%d, len=%d/%d\n",
01255                                         w, nw, len, nlen );
01256                                 nfaces--;
01257                         }
01258                 }
01259         }
01260 
01261         /* Associate vertex geometry */
01262         for( w = 0; w < nw; w++ )  {
01263                 for( len = 0; len < nlen; len++ )  {
01264                         nmg_vertex_gv( verts[TOR_PT(w,len)], TOR_PTA(w,len) );
01265                 }
01266         }
01267 
01268         /* Associate face geometry */
01269         for( i=0; i < nfaces; i++ )  {
01270                 if( nmg_fu_planeeqn( faces[i], tol ) < 0 )
01271                         return -1;              /* FAIL */
01272         }
01273 
01274         /* Associate vertexuse normals */
01275         for( w=0 ; w<nw ; w++ )
01276         {
01277                 for( len=0 ; len<nlen ; len++ )
01278                 {
01279                         struct vertexuse *vu;
01280                         vect_t rev_norm;
01281 
01282                         VREVERSE( rev_norm , TOR_NORM_A(w,len) );
01283 
01284                         for( BU_LIST_FOR( vu , vertexuse , &verts[TOR_PT(w,len)]->vu_hd ) )
01285                         {
01286                                 struct faceuse *fu;
01287 
01288                                 NMG_CK_VERTEXUSE( vu );
01289 
01290                                 fu = nmg_find_fu_of_vu( vu );
01291                                 NMG_CK_FACEUSE( fu );
01292 
01293                                 if( fu->orientation == OT_SAME )
01294                                         nmg_vertexuse_nv( vu , TOR_NORM_A(w,len) );
01295                                 else if( fu->orientation == OT_OPPOSITE )
01296                                         nmg_vertexuse_nv( vu , rev_norm );
01297                         }
01298                 }
01299         }
01300 
01301         /* Compute "geometry" for region and shell */
01302         nmg_region_a( *r, tol );
01303 
01304         bu_free( (char *)pts, "rt_tor_tess pts[]" );
01305         bu_free( (char *)verts, "rt_tor_tess *verts[]" );
01306         bu_free( (char *)faces, "rt_tor_tess *faces[]" );
01307         bu_free( (char *)norms , "rt_tor_tess norms[]" );
01308         return(0);
01309 }
01310 
01311 
01312 /**
01313  *                      R T _ T O R _ I M P O R T
01314  *
01315  *  Import a torus from the database format to the internal format.
01316  *  Apply modeling transformations at the same time.
01317  */
01318 int
01319 rt_tor_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
01320 {
01321         struct rt_tor_internal  *tip;
01322         union record            *rp;
01323         LOCAL fastf_t           vec[3*4];
01324         vect_t                  axb;
01325         register fastf_t        f;
01326 
01327         BU_CK_EXTERNAL( ep );
01328         rp = (union record *)ep->ext_buf;
01329         /* Check record type */
01330         if( rp->u_id != ID_SOLID )  {
01331                 bu_log("rt_tor_import: defective record\n");
01332                 return(-1);
01333         }
01334 
01335         RT_CK_DB_INTERNAL( ip );
01336         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
01337         ip->idb_type = ID_TOR;
01338         ip->idb_meth = &rt_functab[ID_TOR];
01339         ip->idb_ptr = bu_malloc(sizeof(struct rt_tor_internal), "rt_tor_internal");
01340         tip = (struct rt_tor_internal *)ip->idb_ptr;
01341         tip->magic = RT_TOR_INTERNAL_MAGIC;
01342 
01343         /* Convert from database to internal format */
01344         rt_fastf_float( vec, rp->s.s_values, 4 );
01345 
01346         /* Apply modeling transformations */
01347         MAT4X3PNT( tip->v, mat, &vec[0*3] );
01348         MAT4X3VEC( tip->h, mat, &vec[1*3] );
01349         MAT4X3VEC( tip->a, mat, &vec[2*3] );
01350         MAT4X3VEC( tip->b, mat, &vec[3*3] );
01351 
01352         /* Make the vectors unit length */
01353         tip->r_a = MAGNITUDE(tip->a);
01354         tip->r_b = MAGNITUDE(tip->b);
01355         tip->r_h = MAGNITUDE(tip->h);
01356         if( tip->r_a < SMALL || tip->r_b < SMALL || tip->r_h < SMALL )  {
01357                 bu_log("rt_tor_import:  zero length A, B, or H vector\n");
01358                 return(-1);
01359         }
01360         /* In memory, the H vector is unit length */
01361         f = 1.0/tip->r_h;
01362         VSCALE( tip->h, tip->h, f );
01363 
01364         /* If H does not point in the direction of A cross B, reverse H. */
01365         /* Somehow, database records have been written with this problem. */
01366         VCROSS( axb, tip->a, tip->b );
01367         if( VDOT( axb, tip->h ) < 0 )  {
01368                 VREVERSE( tip->h, tip->h );
01369         }
01370 
01371         return(0);              /* OK */
01372 }
01373 
01374 /**
01375  *                      R T _ T O R _ E X P O R T 5
01376  */
01377 int
01378 rt_tor_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
01379 {
01380         double                  vec[2*3+2];
01381         struct rt_tor_internal  *tip;
01382 
01383         RT_CK_DB_INTERNAL( ip );
01384         if (ip->idb_type != ID_TOR) return -1;
01385         tip = (struct rt_tor_internal *)ip->idb_ptr;
01386         RT_TOR_CK_MAGIC(tip);
01387 
01388         BU_CK_EXTERNAL(ep);
01389         ep->ext_nbytes = SIZEOF_NETWORK_DOUBLE * (2*3+2);
01390         ep->ext_buf = (genptr_t)bu_malloc( ep->ext_nbytes, "tor external");
01391 
01392         /* scale values into local buffer */
01393         VSCALE( &vec[0*3], tip->v, local2mm );
01394         VMOVE(  &vec[1*3], tip->h);             /* UNIT vector, not scaled */
01395         vec[2*3+0] = tip->r_a*local2mm;         /* r1 */
01396         vec[2*3+1] = tip->r_h*local2mm;         /* r2 */
01397 
01398         /* convert from internal (host) to database (network) format */
01399         htond( ep->ext_buf, (unsigned char *)vec, 2*3+2);
01400 
01401         return 0;
01402 }
01403 /**
01404  *                      R T _ T O R _ E X P O R T
01405  *
01406  *  The name will be added by the caller.
01407  */
01408 int
01409 rt_tor_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
01410 {
01411         struct rt_tor_internal  *tip;
01412         union record            *rec;
01413         vect_t                  norm;
01414         vect_t                  cross1, cross2;
01415         fastf_t                 r1, r2;
01416         fastf_t                 r3, r4;
01417         double                  m2;
01418 
01419         RT_CK_DB_INTERNAL(ip);
01420         if( ip->idb_type != ID_TOR )  return(-1);
01421         tip = (struct rt_tor_internal *)ip->idb_ptr;
01422         RT_TOR_CK_MAGIC(tip);
01423 
01424         BU_CK_EXTERNAL(ep);
01425         ep->ext_nbytes = sizeof(union record);
01426         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "tor external");
01427         rec = (union record *)ep->ext_buf;
01428 
01429         rec->s.s_id = ID_SOLID;
01430         rec->s.s_type = TOR;
01431 
01432         r1 = tip->r_a;
01433         r2 = tip->r_h;
01434 
01435         /* Validate that 0 < r2 <= r1 */
01436         if( r2 <= 0.0 )  {
01437                 bu_log("rt_tor_export:  illegal r2=%.12e <= 0\n", r2);
01438                 return(-1);
01439         }
01440         if( r2 > r1 )  {
01441                 bu_log("rt_tor_export:  illegal r2=%.12e > r1=%.12e\n",
01442                         r2, r1);
01443                 return(-1);
01444         }
01445 
01446         r1 *= local2mm;
01447         r2 *= local2mm;
01448         VSCALE( &rec->s.s_values[0*3], tip->v, local2mm );
01449 
01450         VMOVE( norm, tip->h );
01451         m2 = MAGNITUDE( norm );         /* F2 is NORMAL to torus */
01452         if( m2 <= SQRT_SMALL_FASTF )  {
01453                 bu_log("rt_tor_export: normal magnitude is zero!\n");
01454                 return(-1);             /* failure */
01455         }
01456         m2 = 1.0/m2;
01457         VSCALE( norm, norm, m2 );       /* Give normal unit length */
01458         VSCALE( &rec->s.s_values[1*3], norm, r2 ); /* F2: normal radius len */
01459 
01460         /* Create two mutually perpendicular vectors, perpendicular to Norm */
01461         /* Ensure that AxB points in direction of N */
01462         bn_vec_ortho( cross1, norm );
01463         VCROSS( cross2, norm, cross1 );
01464         VUNITIZE( cross2 );
01465 
01466         /* F3, F4 are perpendicular, goto center of solid part */
01467         VSCALE( &rec->s.s_values[2*3], cross1, r1 );
01468         VSCALE( &rec->s.s_values[3*3], cross2, r1 );
01469 
01470         /*
01471          * The rest of these provide no real extra information,
01472          * and exist for compatability with old versions of MGED.
01473          */
01474         r3=r1-r2;       /* Radius to inner circular edge */
01475         r4=r1+r2;       /* Radius to outer circular edge */
01476 
01477         /* F5, F6 are perpendicular, goto inner edge of ellipse */
01478         VSCALE( &rec->s.s_values[4*3], cross1, r3 );
01479         VSCALE( &rec->s.s_values[5*3], cross2, r3 );
01480 
01481         /* F7, F8 are perpendicular, goto outer edge of ellipse */
01482         VSCALE( &rec->s.s_values[6*3], cross1, r4 );
01483         VSCALE( &rec->s.s_values[7*3], cross2, r4 );
01484 
01485         return(0);
01486 }
01487 
01488 /**
01489  *                      R T _ T O R _ I M P O R T 5
01490  *
01491  *      Taken from the database record:
01492  *              v       vertex (point) of center of torus.
01493  *              h       unit vector in the normal direction of the torus
01494  *              major   radius of ring from 'v' to center of ring
01495  *              minor   radius of the ring
01496  *
01497  *      Calculate:
01498  *              2nd radius of ring (==1st radius)
01499  *              ring unit vector 1
01500  *              ring unit vector 2
01501  */
01502 int
01503 rt_tor_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
01504 {
01505         struct rt_tor_internal  *tip;
01506         LOCAL struct rec {
01507                 double  v[3];
01508                 double  h[3];
01509                 double  ra;     /* r1 */
01510                 double  rh;     /* r2 */
01511         } rec;
01512 
01513 
01514         BU_CK_EXTERNAL( ep );
01515         BU_ASSERT_LONG( ep->ext_nbytes, ==, SIZEOF_NETWORK_DOUBLE * (2*3+2) );
01516 
01517         RT_CK_DB_INTERNAL( ip );
01518 
01519         if (bn_mat_is_non_unif(mat)) {
01520                 bu_log("------------------ WARNING ----------------\nNon-uniform matrix transform on torus.  Ignored\n");
01521         }
01522 
01523 
01524         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
01525         ip->idb_type = ID_TOR;
01526         ip->idb_meth = &rt_functab[ID_TOR];
01527         ip->idb_ptr = bu_malloc( sizeof(struct rt_tor_internal), "rt_tor_internal");
01528         tip = (struct rt_tor_internal *)ip->idb_ptr;
01529 
01530         tip->magic = RT_TOR_INTERNAL_MAGIC;
01531 
01532         ntohd( (unsigned char *)&rec, ep->ext_buf, 2*3+2);
01533 
01534         /* Apply modeling transformations */
01535         MAT4X3PNT( tip->v, mat, rec.v );
01536         MAT4X3VEC( tip->h, mat, rec.h );
01537         VUNITIZE( tip->h );                     /* just to be sure */
01538 
01539         tip->r_a = rec.ra / mat[15];
01540         tip->r_h = rec.rh / mat[15];
01541 
01542         /* Prepare the extra information */
01543         tip->r_b = tip->r_a;
01544 
01545         /* Calculate two mutually perpendicular vectors, perpendicular to N */
01546         bn_vec_ortho( tip->a, tip->h );         /* a has unit length */
01547         VCROSS( tip->b, tip->h, tip->a);        /* |A| = |H| = 1, so |B|=1 */
01548 
01549         VSCALE(tip->a, tip->a, tip->r_a);
01550         VSCALE(tip->b, tip->b, tip->r_b);
01551         return 0;
01552 }
01553 /**
01554  *                      R T _ T O R _ D E S C R I B E
01555  *
01556  *  Make human-readable formatted presentation of this solid.
01557  *  First line describes type of solid.
01558  *  Additional lines are indented one tab, and give parameter values.
01559  */
01560 int
01561 rt_tor_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
01562 {
01563         register struct rt_tor_internal *tip =
01564                 (struct rt_tor_internal *)ip->idb_ptr;
01565         double                          r3, r4;
01566 
01567         RT_TOR_CK_MAGIC(tip);
01568         bu_vls_strcat( str, "torus (TOR)\n");
01569 
01570         bu_vls_printf( str, "\tV (%g, %g, %g), r1=%g (A), r2=%g (H)\n",
01571                        INTCLAMP(tip->v[X] * mm2local),
01572                        INTCLAMP(tip->v[Y] * mm2local),
01573                        INTCLAMP(tip->v[Z] * mm2local),
01574                        INTCLAMP(tip->r_a * mm2local),
01575                        INTCLAMP(tip->r_h * mm2local) );
01576 
01577         bu_vls_printf( str, "\tN=(%g, %g, %g)\n",
01578                 INTCLAMP(tip->h[X] * mm2local),
01579                 INTCLAMP(tip->h[Y] * mm2local),
01580                 INTCLAMP(tip->h[Z] * mm2local) );
01581 
01582         if( !verbose )  return(0);
01583 
01584         bu_vls_printf( str, "\tA=(%g, %g, %g)\n",
01585                 INTCLAMP(tip->a[X] * mm2local / tip->r_a),
01586                 INTCLAMP(tip->a[Y] * mm2local / tip->r_a),
01587                 INTCLAMP(tip->a[Z] * mm2local / tip->r_a) );
01588 
01589         bu_vls_printf( str, "\tB=(%g, %g, %g)\n",
01590                 INTCLAMP(tip->b[X] * mm2local / tip->r_b),
01591                 INTCLAMP(tip->b[Y] * mm2local / tip->r_b),
01592                 INTCLAMP(tip->b[Z] * mm2local / tip->r_b) );
01593 
01594         r3 = tip->r_a - tip->r_h;
01595         bu_vls_printf( str, "\tvector to inner edge = (%g, %g, %g)\n",
01596                 INTCLAMP(tip->a[X] * mm2local / tip->r_a * r3),
01597                 INTCLAMP(tip->a[Y] * mm2local / tip->r_a * r3),
01598                 INTCLAMP(tip->a[Z] * mm2local / tip->r_a * r3) );
01599 
01600         r4 = tip->r_a + tip->r_h;
01601         bu_vls_printf( str, "\tvector to outer edge = (%g, %g, %g)\n",
01602                 INTCLAMP(tip->a[X] * mm2local / tip->r_a * r4),
01603                 INTCLAMP(tip->a[Y] * mm2local / tip->r_a * r4),
01604                 INTCLAMP(tip->a[Z] * mm2local / tip->r_a * r4) );
01605 
01606         return(0);
01607 }
01608 
01609 /**
01610  *                      R T _ T O R _ I F R E E
01611  *
01612  *  Free the storage associated with the rt_db_internal version of this solid.
01613  */
01614 void
01615 rt_tor_ifree(struct rt_db_internal *ip)
01616 {
01617         register struct rt_tor_internal *tip;
01618 
01619         RT_CK_DB_INTERNAL(ip);
01620         tip = (struct rt_tor_internal *)ip->idb_ptr;
01621         RT_TOR_CK_MAGIC(tip);
01622 
01623         bu_free( (char *)tip, "rt_tor_internal" );
01624         ip->idb_ptr = GENPTR_NULL;      /* sanity */
01625 }
01626 
01627 /*
01628  * Local Variables:
01629  * mode: C
01630  * tab-width: 8
01631  * c-basic-offset: 4
01632  * indent-tabs-mode: t
01633  * End:
01634  * ex: shiftwidth=4 tabstop=8
01635  */

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