g_ehy.c

Go to the documentation of this file.
00001 /*                         G _ E H Y . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1990-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_ehy.c
00025  *      Intersect a ray with a Right Hyperbolic Cylinder.
00026  *
00027  *  Algorithm -
00028  *
00029  *  Given V, H, R, and B, there is a set of points on this ehy
00030  *
00031  *  { (x,y,z) | (x,y,z) is on ehy }
00032  *
00033  *  Through a series of Affine Transformations, this set of points will be
00034  *  transformed into a set of points on an ehy located at the origin
00035  *  with a semi-major axis R1 along the +Y axis, a semi-minor axis R2
00036  *  along the -X axis, a height H along the -Z axis, a vertex V at
00037  *  the origin, and a distance c between the tip of the hyperboloid and
00038  *  vertex of the asymptotic cone.
00039  *
00040  *
00041  *  { (x',y',z') | (x',y',z') is on ehy at origin }
00042  *
00043  *  The transformation from X to X' is accomplished by:
00044  *
00045  *  X' = S(R( X - V ))
00046  *
00047  *  where R(X) =  ( R2/(-|R2|) )
00048  *               (  R1/( |R1|)  ) . X
00049  *                ( H /(-|H |) )
00050  *
00051  *  and S(X) =   (  1/|R2|   0     0   )
00052  *              (    0    1/|R1|   0    ) . X
00053  *               (   0      0   1/|H | )
00054  *
00055  *  To find the intersection of a line with the surface of the ehy,
00056  *  consider the parametric line L:
00057  *
00058  *      L : { P(n) | P + t(n) . D }
00059  *
00060  *  Call W the actual point of intersection between L and the ehy.
00061  *  Let W' be the point of intersection between L' and the unit ehy.
00062  *
00063  *      L' : { P'(n) | P' + t(n) . D' }
00064  *
00065  *  W = invR( invS( W' ) ) + V
00066  *
00067  *  Where W' = k D' + P'.
00068  *
00069  *  If Dy' and Dz' are both 0, then there is no hit on the ehy;
00070  *  but the end plates need checking.  If there is now only 1 hit
00071  *  point, the top plate needs to be checked as well.
00072  *
00073  *  Line L' hits the infinitely long canonical ehy at W' when
00074  *
00075  *      A * k**2 + B * k + C = 0
00076  *
00077  *  where
00078  *
00079  *  A = Dz'**2 - (2*c' + 1)*(Dx'**2 + Dy'**2)
00080  *  B = 2*( (Pz' + c' + 1)*Dz' - (2*c' + 1)*(Dx'*Px' + Dy'Py') )
00081  *  C = Pz'**2 - (2*c' + 1)*(Px'**2 + Py'**2 - 1) + 2*(c' + 1)*Pz'
00082  *  b = |Breadth| = 1.0
00083  *  h = |Height| = 1.0
00084  *  r = 1.0
00085  *  c' = c / |Breadth|
00086  *
00087  *  The quadratic formula yields k (which is constant):
00088  *
00089  *  k = [ -B +/- sqrt( B**2 - 4 * A * C )] / (2.0 * A)
00090  *
00091  *  Now, D' = S( R( D ) )
00092  *  and  P' = S( R( P - V ) )
00093  *
00094  *  Substituting,
00095  *
00096  *  W = V + invR( invS[ k *( S( R( D ) ) ) + S( R( P - V ) ) ] )
00097  *    = V + invR( ( k * R( D ) ) + R( P - V ) )
00098  *    = V + k * D + P - V
00099  *    = k * D + P
00100  *
00101  *  Note that ``k'' is constant, and is the same in the formulations
00102  *  for both W and W'.
00103  *
00104  *  The hit at ``k'' is a hit on the canonical ehy IFF
00105  *  -1 <= Wz' <= 0.
00106  *
00107  *  NORMALS.  Given the point W on the surface of the ehy,
00108  *  what is the vector normal to the tangent plane at that point?
00109  *
00110  *  Map W onto the unit ehy, ie:  W' = S( R( W - V ) ).
00111  *
00112  *  Plane on unit ehy at W' has a normal vector N' where
00113  *
00114  *  N' = <Wx', Wy', -(z + c + 1) / (2*c + 1)>
00115  *
00116  *  The plane transforms back to the tangent plane at W, and this
00117  *  new plane (on the original ehy) has a normal vector of N, viz:
00118  *
00119  *  N = inverse[ transpose( inverse[ S o R ] ) ] ( N' )
00120  *
00121  *  because if H is perpendicular to plane Q, and matrix M maps from
00122  *  Q to Q', then inverse[ transpose(M) ] (H) is perpendicular to Q'.
00123  *  Here, H and Q are in "prime space" with the unit sphere.
00124  *  [Somehow, the notation here is backwards].
00125  *  So, the mapping matrix M = inverse( S o R ), because
00126  *  S o R maps from normal space to the unit sphere.
00127  *
00128  *  N = inverse[ transpose( inverse[ S o R ] ) ] ( N' )
00129  *    = inverse[ transpose(invR o invS) ] ( N' )
00130  *    = inverse[ transpose(invS) o transpose(invR) ] ( N' )
00131  *    = inverse[ inverse(S) o R ] ( N' )
00132  *    = invR o S ( N' )
00133  *
00134  *  because inverse(R) = transpose(R), so R = transpose( invR ),
00135  *  and S = transpose( S ).
00136  *
00137  *  Note that the normal vector produced above will not have unit length.
00138  *
00139  *  THE TOP PLATE.
00140  *
00141  *  If Dz' == 0, line L' is parallel to the top plate, so there is no
00142  *  hit on the top plate.  Otherwise, rays intersect the top plate
00143  *  with k = (0 - Pz')/Dz'.  The solution is within the top plate
00144  *  IFF Wx'**2 + Wy'**2 <= 1.
00145  *
00146  *  The normal for a hit on the top plate is -Hunit.
00147  *
00148  *  Authors -
00149  *      Michael J. Markowski
00150  *
00151  *  Source -
00152  *      SECAD/VLD Computing Consortium, Bldg 394
00153  *      The U. S. Army Ballistic Research Laboratory
00154  *      Aberdeen Proving Ground, Maryland  21005-5066
00155  *
00156  */
00157 
00158 #ifndef lint
00159 static const char RCSehy[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_ehy.c,v 14.12 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00160 #endif
00161 
00162 #include "common.h"
00163 
00164 #include <stddef.h>
00165 #include <stdio.h>
00166 #ifdef HAVE_STRING_H
00167 #  include <string.h>
00168 #else
00169 #  include <strings.h>
00170 #endif
00171 #include <math.h>
00172 
00173 #include "machine.h"
00174 #include "vmath.h"
00175 #include "db.h"
00176 #include "nmg.h"
00177 #include "raytrace.h"
00178 #include "rtgeom.h"
00179 #include "./debug.h"
00180 
00181 struct ehy_specific {
00182         point_t ehy_V;          /* vector to ehy origin */
00183         vect_t  ehy_Hunit;      /* unit H vector */
00184         vect_t  ehy_Aunit;      /* unit vector along semi-major axis */
00185         vect_t  ehy_Bunit;      /* unit vector, A x H, semi-minor axis */
00186         mat_t   ehy_SoR;        /* Scale(Rot(vect)) */
00187         mat_t   ehy_invRoS;     /* invRot(Scale(vect)) */
00188         fastf_t ehy_cprime;     /* c / |H| */
00189 };
00190 
00191 const struct bu_structparse rt_ehy_parse[] = {
00192     { "%f", 3, "V",   bu_offsetof(struct rt_ehy_internal, ehy_V[X]),  BU_STRUCTPARSE_FUNC_NULL },
00193     { "%f", 3, "H",   bu_offsetof(struct rt_ehy_internal, ehy_H[X]),  BU_STRUCTPARSE_FUNC_NULL },
00194     { "%f", 3, "A",   bu_offsetof(struct rt_ehy_internal, ehy_Au[X]), BU_STRUCTPARSE_FUNC_NULL },
00195     { "%f", 1, "r_1", bu_offsetof(struct rt_ehy_internal, ehy_r1),    BU_STRUCTPARSE_FUNC_NULL },
00196     { "%f", 1, "r_2", bu_offsetof(struct rt_ehy_internal, ehy_r2),    BU_STRUCTPARSE_FUNC_NULL },
00197     { "%f", 1, "c",   bu_offsetof(struct rt_ehy_internal, ehy_c),     BU_STRUCTPARSE_FUNC_NULL },
00198     { {'\0','\0','\0','\0'}, 0, (char *)NULL, 0, BU_STRUCTPARSE_FUNC_NULL }
00199  };
00200 
00201 /**
00202  *                      R T _ E H Y _ P R E P
00203  *
00204  *  Given a pointer to a GED database record, and a transformation matrix,
00205  *  determine if this is a valid EHY, and if so, precompute various
00206  *  terms of the formula.
00207  *
00208  *  Returns -
00209  *      0       EHY is OK
00210  *      !0      Error in description
00211  *
00212  *  Implicit return -
00213  *      A struct ehy_specific is created, and it's address is stored in
00214  *      stp->st_specific for use by ehy_shot().
00215  */
00216 int
00217 rt_ehy_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00218 {
00219         struct rt_ehy_internal          *xip;
00220         register struct ehy_specific    *ehy;
00221 #ifndef NO_MAGIC_CHECKING
00222         const struct bn_tol             *tol = &rtip->rti_tol;
00223 #endif
00224         LOCAL fastf_t   magsq_h;
00225         LOCAL fastf_t   mag_a, mag_h;
00226         LOCAL fastf_t   c, f, r1, r2;
00227         LOCAL mat_t     R;
00228         LOCAL mat_t     Rinv;
00229         LOCAL mat_t     S;
00230 
00231 #ifndef NO_MAGIC_CHECKING
00232         RT_CK_DB_INTERNAL(ip);
00233         BN_CK_TOL(tol);
00234 #endif
00235         xip = (struct rt_ehy_internal *)ip->idb_ptr;
00236         RT_EHY_CK_MAGIC(xip);
00237 
00238         /* compute |A| |H| */
00239         mag_a = sqrt( MAGSQ( xip->ehy_Au ) );
00240         mag_h = sqrt( magsq_h = MAGSQ( xip->ehy_H ) );
00241         r1 = xip->ehy_r1;
00242         r2 = xip->ehy_r2;
00243         c = xip->ehy_c;
00244         /* Check for |H| > 0, |A| == 1, r1 > 0, r2 > 0, c > 0 */
00245         if( NEAR_ZERO(mag_h, RT_LEN_TOL)
00246                 || !NEAR_ZERO(mag_a - 1.0, RT_LEN_TOL)
00247                 || r1 < 0.0 || r2 < 0.0 || c < 0.0 )  {
00248                 return(-2);             /* BAD, too small */
00249         }
00250 
00251         /* Check for A.H == 0 */
00252         f = VDOT( xip->ehy_Au, xip->ehy_H ) / mag_h;
00253         if( !NEAR_ZERO(f, RT_DOT_TOL) )  {
00254                 return(-2);             /* BAD */
00255         }
00256 
00257         /*
00258          *  EHY is ok
00259          */
00260         stp->st_id = ID_EHY;            /* set soltab ID */
00261         stp->st_meth = &rt_functab[ID_EHY];
00262 
00263         BU_GETSTRUCT( ehy, ehy_specific );
00264         stp->st_specific = (genptr_t)ehy;
00265 
00266         /* make unit vectors in A, H, and BxH directions */
00267         VMOVE(    ehy->ehy_Hunit, xip->ehy_H );
00268         VUNITIZE( ehy->ehy_Hunit );
00269         VMOVE(    ehy->ehy_Aunit, xip->ehy_Au );
00270         VCROSS(   ehy->ehy_Bunit, ehy->ehy_Aunit, ehy->ehy_Hunit );
00271 
00272         VMOVE( ehy->ehy_V, xip->ehy_V );
00273         ehy->ehy_cprime = c / mag_h;
00274 
00275         /* Compute R and Rinv matrices */
00276         MAT_IDN( R );
00277         VREVERSE( &R[0], ehy->ehy_Bunit );
00278         VMOVE(    &R[4], ehy->ehy_Aunit );
00279         VREVERSE( &R[8], ehy->ehy_Hunit );
00280         bn_mat_trn( Rinv, R );                  /* inv of rot mat is trn */
00281 
00282         /* Compute S */
00283         MAT_IDN( S );
00284         S[ 0] = 1.0/r2;
00285         S[ 5] = 1.0/r1;
00286         S[10] = 1.0/mag_h;
00287 
00288         /* Compute SoR and invRoS */
00289         bn_mat_mul( ehy->ehy_SoR, S, R );
00290         bn_mat_mul( ehy->ehy_invRoS, Rinv, S );
00291 
00292         /* Compute bounding sphere and RPP */
00293         /* bounding sphere center */
00294         VJOIN1( stp->st_center, ehy->ehy_V, mag_h / 2.0, ehy->ehy_Hunit );
00295         /* bounding radius */
00296         stp->st_bradius = sqrt(0.25*magsq_h + r2*r2 + r1*r1);
00297         /* approximate bounding radius */
00298         stp->st_aradius = stp->st_bradius;
00299 
00300         /* cheat, make bounding RPP by enclosing bounding sphere */
00301         stp->st_min[X] = stp->st_center[X] - stp->st_bradius;
00302         stp->st_max[X] = stp->st_center[X] + stp->st_bradius;
00303         stp->st_min[Y] = stp->st_center[Y] - stp->st_bradius;
00304         stp->st_max[Y] = stp->st_center[Y] + stp->st_bradius;
00305         stp->st_min[Z] = stp->st_center[Z] - stp->st_bradius;
00306         stp->st_max[Z] = stp->st_center[Z] + stp->st_bradius;
00307 
00308         return(0);                      /* OK */
00309 }
00310 
00311 /**
00312  *                      R T _ E H Y _ P R I N T
00313  */
00314 void
00315 rt_ehy_print(register const struct soltab *stp)
00316 {
00317         register const struct ehy_specific *ehy =
00318                 (struct ehy_specific *)stp->st_specific;
00319 
00320         VPRINT("V", ehy->ehy_V);
00321         VPRINT("Hunit", ehy->ehy_Hunit);
00322         VPRINT("Aunit", ehy->ehy_Aunit);
00323         VPRINT("Bunit", ehy->ehy_Bunit);
00324         fprintf(stderr, "c = %g\n", ehy->ehy_cprime);
00325         bn_mat_print("S o R", ehy->ehy_SoR );
00326         bn_mat_print("invR o S", ehy->ehy_invRoS );
00327 }
00328 
00329 /* hit_surfno is set to one of these */
00330 #define EHY_NORM_BODY   (1)             /* compute normal */
00331 #define EHY_NORM_TOP    (2)             /* copy ehy_N */
00332 
00333 /**
00334  *                      R T _ E H Y _ S H O T
00335  *
00336  *  Intersect a ray with a ehy.
00337  *  If an intersection occurs, a struct seg will be acquired
00338  *  and filled in.
00339  *
00340  *  Returns -
00341  *      0       MISS
00342  *      >0      HIT
00343  */
00344 int
00345 rt_ehy_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00346 {
00347         register struct ehy_specific *ehy =
00348                 (struct ehy_specific *)stp->st_specific;
00349         LOCAL vect_t    dp;             /* D' */
00350         LOCAL vect_t    pp;             /* P' */
00351         LOCAL fastf_t   k1, k2;         /* distance constants of solution */
00352         LOCAL fastf_t   cp;             /* c' */
00353         LOCAL vect_t    xlated;         /* translated vector */
00354         LOCAL struct hit hits[3];       /* 2 potential hit points */
00355         register struct hit *hitp;      /* pointer to hit point */
00356 
00357         hitp = &hits[0];
00358 
00359         /* out, Mat, vect */
00360         MAT4X3VEC( dp, ehy->ehy_SoR, rp->r_dir );
00361         VSUB2( xlated, rp->r_pt, ehy->ehy_V );
00362         MAT4X3VEC( pp, ehy->ehy_SoR, xlated );
00363 
00364         cp = ehy->ehy_cprime;
00365         /* Find roots of the equation, using formula for quadratic */
00366         {
00367                 FAST fastf_t    a, b, c;        /* coeffs of polynomial */
00368                 FAST fastf_t    disc;           /* discriminant */
00369 
00370                 a = dp[Z] * dp[Z]
00371                         - (2 * cp + 1) * (dp[X] * dp[X] + dp[Y] * dp[Y]);
00372                 b = 2.0 * (dp[Z] * (pp[Z] + cp + 1)
00373                         - (2 * cp + 1) * (dp[X] * pp[X] + dp[Y] * pp[Y]));
00374                 c = pp[Z] * pp[Z]
00375                         - (2 * cp + 1) * (pp[X] * pp[X] + pp[Y] * pp[Y] - 1.0)
00376                         + 2 * (cp + 1) * pp[Z];
00377                 if ( !NEAR_ZERO(a, RT_PCOEF_TOL) ) {
00378                         disc = b*b - 4 * a * c;
00379                         if (disc <= 0)
00380                                 goto check_plates;
00381                         disc = sqrt(disc);
00382 
00383                         k1 = (-b + disc) / (2.0 * a);
00384                         k2 = (-b - disc) / (2.0 * a);
00385 
00386                         /*
00387                          *  k1 and k2 are potential solutions to intersection
00388                          *  with side.  See if they fall in range.
00389                          */
00390                         VJOIN1( hitp->hit_vpriv, pp, k1, dp );  /* hit' */
00391                         if( hitp->hit_vpriv[Z] >= -1.0
00392                                 && hitp->hit_vpriv[Z] <= 0.0 ) {
00393                                 hitp->hit_magic = RT_HIT_MAGIC;
00394                                 hitp->hit_dist = k1;
00395                                 hitp->hit_surfno = EHY_NORM_BODY;       /* compute N */
00396                                 hitp++;
00397                         }
00398 
00399                         VJOIN1( hitp->hit_vpriv, pp, k2, dp );  /* hit' */
00400                         if( hitp->hit_vpriv[Z] >= -1.0
00401                                 && hitp->hit_vpriv[Z] <= 0.0 ) {
00402                                 hitp->hit_magic = RT_HIT_MAGIC;
00403                                 hitp->hit_dist = k2;
00404                                 hitp->hit_surfno = EHY_NORM_BODY;       /* compute N */
00405                                 hitp++;
00406                         }
00407                 } else if ( !NEAR_ZERO(b, RT_PCOEF_TOL) ) {
00408                         k1 = -c/b;
00409                         VJOIN1( hitp->hit_vpriv, pp, k1, dp );  /* hit' */
00410                         if( hitp->hit_vpriv[Z] >= -1.0
00411                                 && hitp->hit_vpriv[Z] <= 0.0 ) {
00412                                 hitp->hit_magic = RT_HIT_MAGIC;
00413                                 hitp->hit_dist = k1;
00414                                 hitp->hit_surfno = EHY_NORM_BODY;       /* compute N */
00415                                 hitp++;
00416                         }
00417                 }
00418         }
00419 
00420 
00421         /*
00422          * Check for hitting the top plate.
00423          */
00424 check_plates:
00425         /* check top plate */
00426         if( hitp == &hits[1]  &&  !NEAR_ZERO(dp[Z], SMALL) )  {
00427                 /* 1 hit so far, this is worthwhile */
00428                 k1 = -pp[Z] / dp[Z];            /* top plate */
00429 
00430                 VJOIN1( hitp->hit_vpriv, pp, k1, dp );  /* hit' */
00431                 if( hitp->hit_vpriv[X] * hitp->hit_vpriv[X] +
00432                         hitp->hit_vpriv[Y] * hitp->hit_vpriv[Y] <= 1.0 ) {
00433                         hitp->hit_magic = RT_HIT_MAGIC;
00434                         hitp->hit_dist = k1;
00435                         hitp->hit_surfno = EHY_NORM_TOP;        /* -H */
00436                         hitp++;
00437                 }
00438         }
00439 
00440         if( hitp != &hits[2] )
00441                 return(0);      /* MISS */
00442 
00443         if( hits[0].hit_dist < hits[1].hit_dist )  {
00444                 /* entry is [0], exit is [1] */
00445                 register struct seg *segp;
00446 
00447                 RT_GET_SEG(segp, ap->a_resource);
00448                 segp->seg_stp = stp;
00449                 segp->seg_in = hits[0];         /* struct copy */
00450                 segp->seg_out = hits[1];        /* struct copy */
00451                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00452         } else {
00453                 /* entry is [1], exit is [0] */
00454                 register struct seg *segp;
00455 
00456                 RT_GET_SEG(segp, ap->a_resource);
00457                 segp->seg_stp = stp;
00458                 segp->seg_in = hits[1];         /* struct copy */
00459                 segp->seg_out = hits[0];        /* struct copy */
00460                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00461         }
00462         return(2);                      /* HIT */
00463 }
00464 
00465 #define RT_EHY_SEG_MISS(SEG)    (SEG).seg_stp=RT_SOLTAB_NULL
00466 
00467 /**
00468  *                      R T _ E H Y _ V S H O T
00469  *
00470  *  Vectorized version.
00471  */
00472 void
00473 rt_ehy_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
00474                                /* An array of solid pointers */
00475                                /* An array of ray pointers */
00476                                /* array of segs (results returned) */
00477                                /* Number of ray/object pairs */
00478 
00479 {
00480         rt_vstub( stp, rp, segp, n, ap );
00481 }
00482 
00483 /**
00484  *                      R T _ E H Y _ N O R M
00485  *
00486  *  Given ONE ray distance, return the normal and entry/exit point.
00487  */
00488 void
00489 rt_ehy_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00490 {
00491         vect_t  can_normal;     /* normal to canonical ehy */
00492         fastf_t cp, scale;
00493         register struct ehy_specific *ehy =
00494                 (struct ehy_specific *)stp->st_specific;
00495 
00496         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
00497         switch( hitp->hit_surfno )  {
00498         case EHY_NORM_BODY:
00499                 cp = ehy->ehy_cprime;
00500                 VSET( can_normal,
00501                         hitp->hit_vpriv[X] * (2 * cp + 1),
00502                         hitp->hit_vpriv[Y] * (2 * cp + 1),
00503                         -(hitp->hit_vpriv[Z] + cp + 1) );
00504                 MAT4X3VEC( hitp->hit_normal, ehy->ehy_invRoS, can_normal );
00505                 scale = 1.0 / MAGNITUDE( hitp->hit_normal );
00506                 VSCALE( hitp->hit_normal, hitp->hit_normal, scale );
00507 
00508                 /* tuck away this scale for the curvature routine */
00509                 hitp->hit_vpriv[X] = scale;
00510                 break;
00511         case EHY_NORM_TOP:
00512                 VREVERSE( hitp->hit_normal, ehy->ehy_Hunit );
00513                 break;
00514         default:
00515                 bu_log("rt_ehy_norm: surfno=%d bad\n", hitp->hit_surfno);
00516                 break;
00517         }
00518 }
00519 
00520 /**
00521  *                      R T _ E H Y _ C U R V E
00522  *
00523  *  Return the curvature of the ehy.
00524  */
00525 void
00526 rt_ehy_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00527 {
00528         fastf_t a, b, c, scale;
00529         mat_t   M1, M2;
00530         register struct ehy_specific *ehy =
00531                 (struct ehy_specific *)stp->st_specific;
00532         vect_t  u, v;                   /* basis vectors (with normal) */
00533         vect_t  vec1, vec2;             /* eigen vectors */
00534         vect_t  tmp;
00535 
00536         switch( hitp->hit_surfno )  {
00537         case EHY_NORM_BODY:
00538                 /*
00539                  * choose a tangent plane coordinate system
00540                  *  (u, v, normal) form a right-handed triple
00541                  */
00542                 bn_vec_ortho( u, hitp->hit_normal );
00543                 VCROSS( v, hitp->hit_normal, u );
00544 
00545                 /* get the saved away scale factor */
00546                 scale = - hitp->hit_vpriv[X];
00547 
00548                 MAT_IDN( M1 );
00549                 M1[0] = M1[5] = (4 * ehy->ehy_cprime + 2)
00550                         / (ehy->ehy_cprime * ehy->ehy_cprime);
00551                 M1[10] = -1.;
00552                 /* M1 = invR * S * M1 * S * R */
00553                 bn_mat_mul( M2, ehy->ehy_invRoS, M1);
00554                 bn_mat_mul( M1, M2, ehy->ehy_SoR );
00555 
00556                 /* find the second fundamental form */
00557                 MAT4X3VEC( tmp, ehy->ehy_invRoS, u );
00558                 a = VDOT(u, tmp) * scale;
00559                 b = VDOT(v, tmp) * scale;
00560                 MAT4X3VEC( tmp, ehy->ehy_invRoS, v );
00561                 c = VDOT(v, tmp) * scale;
00562 
00563                 eigen2x2( &cvp->crv_c1, &cvp->crv_c2, vec1, vec2, a, b, c );
00564                 VCOMB2( cvp->crv_pdir, vec1[X], u, vec1[Y], v );
00565                 VUNITIZE( cvp->crv_pdir );
00566                 break;
00567         case EHY_NORM_TOP:
00568                 cvp->crv_c1 = cvp->crv_c2 = 0;
00569                 /* any tangent direction */
00570                 bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00571                 break;
00572         }
00573 
00574         cvp->crv_c1 = cvp->crv_c2 = 0;
00575 
00576         /* any tangent direction */
00577         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00578 }
00579 
00580 /**
00581  *                      R T _ E H Y _ U V
00582  *
00583  *  For a hit on the surface of an ehy, return the (u,v) coordinates
00584  *  of the hit point, 0 <= u,v <= 1.
00585  *  u = azimuth
00586  *  v = elevation
00587  */
00588 void
00589 rt_ehy_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00590 {
00591         register struct ehy_specific *ehy =
00592                 (struct ehy_specific *)stp->st_specific;
00593         LOCAL vect_t work;
00594         LOCAL vect_t pprime;
00595         FAST fastf_t len;
00596 
00597         /*
00598          * hit_point is on surface;  project back to unit ehy,
00599          * creating a vector from vertex to hit point.
00600          */
00601         VSUB2( work, hitp->hit_point, ehy->ehy_V );
00602         MAT4X3VEC( pprime, ehy->ehy_SoR, work );
00603 
00604         switch( hitp->hit_surfno )  {
00605         case EHY_NORM_BODY:
00606                 /* top plate, polar coords */
00607                 if (pprime[Z] == -1.0) {        /* bottom pt of body */
00608                         uvp->uv_u = 0;
00609                 } else {
00610                         len = sqrt(pprime[X]*pprime[X] + pprime[Y]*pprime[Y]);
00611                         uvp->uv_u = acos(pprime[X]/len) * bn_inv2pi;
00612                 }
00613                 uvp->uv_v = -pprime[Z];
00614                 break;
00615         case EHY_NORM_TOP:
00616                 /* top plate, polar coords */
00617                 len = sqrt(pprime[X]*pprime[X] + pprime[Y]*pprime[Y]);
00618                 uvp->uv_u = acos(pprime[X]/len) * bn_inv2pi;
00619                 uvp->uv_v = 1.0 - len;
00620                 break;
00621         }
00622         /* Handle other half of acos() domain */
00623         if( pprime[Y] < 0 )
00624                 uvp->uv_u = 1.0 - uvp->uv_u;
00625 
00626         /* uv_du should be relative to rotation, uv_dv relative to height */
00627         uvp->uv_du = uvp->uv_dv = 0;
00628 }
00629 
00630 /**
00631  *              R T _ E H Y _ F R E E
00632  */
00633 void
00634 rt_ehy_free(register struct soltab *stp)
00635 {
00636         register struct ehy_specific *ehy =
00637                 (struct ehy_specific *)stp->st_specific;
00638 
00639 
00640         bu_free( (char *)ehy, "ehy_specific" );
00641 }
00642 
00643 /**
00644  *                      R T _ E H Y _ C L A S S
00645  */
00646 int
00647 rt_ehy_class(void)
00648 {
00649         return(0);
00650 }
00651 
00652 /**
00653  *                      R T _ E H Y _ P L O T
00654  */
00655 int
00656 rt_ehy_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00657 {
00658         fastf_t         c, dtol, f, mag_a, mag_h, ntol, r1, r2;
00659         fastf_t         **ellipses, theta_prev, theta_new, rt_ell_ang(fastf_t *p1, fastf_t a, fastf_t b, fastf_t dtol, fastf_t ntol);
00660         int             *pts_dbl, i, j, nseg;
00661         int             jj, na, nb, nell, recalc_b;
00662         LOCAL mat_t     R;
00663         LOCAL mat_t     invR;
00664         point_t         p1;
00665         struct rt_pt_node       *pos_a, *pos_b, *pts_a, *pts_b, *rt_ptalloc(void);
00666         LOCAL struct rt_ehy_internal    *xip;
00667         vect_t          A, Au, B, Bu, Hu, V, Work;
00668 
00669         RT_CK_DB_INTERNAL(ip);
00670         xip = (struct rt_ehy_internal *)ip->idb_ptr;
00671         RT_EHY_CK_MAGIC(xip);
00672 
00673         /*
00674          *      make sure ehy description is valid
00675          */
00676 
00677         /* compute |A| |H| */
00678         mag_a = MAGSQ( xip->ehy_Au );   /* should already be unit vector */
00679         mag_h = MAGNITUDE( xip->ehy_H );
00680         c = xip->ehy_c;
00681         r1 = xip->ehy_r1;
00682         r2 = xip->ehy_r2;
00683         /* Check for |H| > 0, |A| == 1, r1 > 0, r2 > 0, c > 0 */
00684         if( NEAR_ZERO(mag_h, RT_LEN_TOL)
00685                 || !NEAR_ZERO(mag_a - 1.0, RT_LEN_TOL)
00686                 || r1 <= 0.0 || r2 <= 0.0 || c <= 0. )  {
00687                 return(-2);             /* BAD */
00688         }
00689 
00690         /* Check for A.H == 0 */
00691         f = VDOT( xip->ehy_Au, xip->ehy_H ) / mag_h;
00692         if( ! NEAR_ZERO(f, RT_DOT_TOL) )  {
00693                 return(-2);             /* BAD */
00694         }
00695 
00696         /* make unit vectors in A, H, and BxH directions */
00697         VMOVE(    Hu, xip->ehy_H );
00698         VUNITIZE( Hu );
00699         VMOVE(    Au, xip->ehy_Au );
00700         VCROSS(   Bu, Au, Hu );
00701 
00702         /* Compute R and Rinv matrices */
00703         MAT_IDN( R );
00704         VREVERSE( &R[0], Bu );
00705         VMOVE(    &R[4], Au );
00706         VREVERSE( &R[8], Hu );
00707         bn_mat_trn( invR, R );                  /* inv of rot mat is trn */
00708 
00709         /*
00710          *  Establish tolerances
00711          */
00712         if( ttol->rel <= 0.0 || ttol->rel >= 1.0 )
00713                 dtol = 0.0;             /* none */
00714         else
00715                 /* Convert rel to absolute by scaling by smallest side */
00716                 dtol = ttol->rel * 2 * r2;
00717         if( ttol->abs <= 0.0 )  {
00718                 if( dtol <= 0.0 )
00719                         /* No tolerance given, use a default */
00720                         dtol = 2 * 0.10 * r2;   /* 10% */
00721                 else
00722                         /* Use absolute-ized relative tolerance */
00723                         ;
00724         } else {
00725                 /* Absolute tolerance was given, pick smaller */
00726                 if( ttol->rel <= 0.0 || dtol > ttol->abs )
00727                         dtol = ttol->abs;
00728         }
00729 
00730         /* To ensure normal tolerance, remain below this angle */
00731         if( ttol->norm > 0.0 )
00732                 ntol = ttol->norm;
00733         else
00734                 /* tolerate everything */
00735                 ntol = bn_pi;
00736 
00737         /*
00738          *      build ehy from 2 hyperbolas
00739          */
00740 
00741         /* approximate positive half of hyperbola along semi-minor axis */
00742         pts_b = rt_ptalloc();
00743         pts_b->next = rt_ptalloc();
00744         pts_b->next->next = NULL;
00745         VSET( pts_b->p,       0, 0, -mag_h);
00746         VSET( pts_b->next->p, 0, r2, 0);
00747         /* 2 endpoints in 1st approximation */
00748         nb = 2;
00749         /* recursively break segment 'til within error tolerances */
00750         nb += rt_mk_hyperbola( pts_b, r2, mag_h, c, dtol, ntol );
00751         nell = nb - 1;  /* # of ellipses needed */
00752 
00753         /* construct positive half of hyperbola along semi-major axis
00754          * of ehy using same z coords as hyperbola along semi-minor axis
00755          */
00756         pts_a = rt_ptalloc();
00757         VMOVE(pts_a->p, pts_b->p);      /* 1st pt is the apex */
00758         pts_a->next = NULL;
00759         pos_b = pts_b->next;
00760         pos_a = pts_a;
00761         while (pos_b) {
00762                 /* copy node from b_hyperbola to a_hyperbola */
00763                 pos_a->next = rt_ptalloc();
00764                 pos_a = pos_a->next;
00765                 pos_a->p[Z] = pos_b->p[Z];
00766                 /* at given z, find y on hyperbola */
00767                 pos_a->p[Y] = r1
00768                         * sqrt(
00769                                 (   (pos_b->p[Z] + mag_h + c)
00770                                   * (pos_b->p[Z] + mag_h + c) - c*c )
00771                                 / ( mag_h*(mag_h + 2*c) )
00772                               );
00773                 pos_a->p[X] = 0;
00774                 pos_b = pos_b->next;
00775         }
00776         pos_a->next = NULL;
00777 
00778         /* see if any segments need further breaking up */
00779         recalc_b = 0;
00780         pos_a = pts_a;
00781         while (pos_a->next) {
00782                 na = rt_mk_hyperbola( pos_a, r1, mag_h, c, dtol, ntol );
00783                 if (na != 0) {
00784                         recalc_b = 1;
00785                         nell += na;
00786                 }
00787                 pos_a = pos_a->next;
00788         }
00789         /* if any were broken, recalculate hyperbola 'a' */
00790         if ( recalc_b ) {
00791                 /* free mem for old approximation of hyperbola */
00792                 pos_b = pts_b;
00793                 while ( pos_b ) {
00794                         struct rt_pt_node *next;
00795 
00796                         /* get next node before freeing */
00797                         next = pos_b->next;
00798                         bu_free( (char *)pos_b, "rt_pt_node" );
00799                         pos_b = next;
00800                 }
00801                 /* construct hyperbola along semi-major axis of ehy
00802                  * using same z coords as parab along semi-minor axis
00803                  */
00804                 pts_b = rt_ptalloc();
00805                 pts_b->p[Z] = pts_a->p[Z];
00806                 pts_b->next = NULL;
00807                 pos_a = pts_a->next;
00808                 pos_b = pts_b;
00809                 while (pos_a) {
00810                         /* copy node from a_hyperbola to b_hyperbola */
00811                         pos_b->next = rt_ptalloc();
00812                         pos_b = pos_b->next;
00813                         pos_b->p[Z] = pos_a->p[Z];
00814                         /* at given z, find y on hyperbola */
00815                         pos_b->p[Y] = r2
00816                                 * sqrt(
00817                                         (   (pos_a->p[Z] + mag_h + c)
00818                                           * (pos_a->p[Z] + mag_h + c) - c*c )
00819                                         / ( mag_h*(mag_h + 2*c) )
00820                                       );
00821                         pos_b->p[X] = 0;
00822                         pos_a = pos_a->next;
00823                 }
00824                 pos_b->next = NULL;
00825         }
00826 
00827         /* make array of ptrs to ehy ellipses */
00828         ellipses = (fastf_t **)bu_malloc( nell * sizeof(fastf_t *), "fastf_t ell[]");
00829         /* keep track of whether pts in each ellipse are doubled or not */
00830         pts_dbl = (int *)bu_malloc( nell * sizeof(int), "dbl ints" );
00831 
00832         /* make ellipses at each z level */
00833         i = 0;
00834         nseg = 0;
00835         theta_prev = bn_twopi;
00836         pos_a = pts_a->next;    /* skip over apex of ehy */
00837         pos_b = pts_b->next;
00838         while (pos_a) {
00839                 VSCALE( A, Au, pos_a->p[Y] );   /* semimajor axis */
00840                 VSCALE( B, Bu, pos_b->p[Y] );   /* semiminor axis */
00841                 VJOIN1( V, xip->ehy_V, -pos_a->p[Z], Hu );
00842 
00843                 VSET( p1, 0., pos_b->p[Y], 0. );
00844                 theta_new = rt_ell_ang(p1, pos_a->p[Y], pos_b->p[Y], dtol, ntol);
00845                 if (nseg == 0) {
00846                         nseg = (int)(bn_twopi / theta_new) + 1;
00847                         pts_dbl[i] = 0;
00848                 } else if (theta_new < theta_prev) {
00849                         nseg *= 2;
00850                         pts_dbl[i] = 1;
00851                 } else
00852                         pts_dbl[i] = 0;
00853                 theta_prev = theta_new;
00854 
00855                 ellipses[i] = (fastf_t *)bu_malloc(3*(nseg+1)*sizeof(fastf_t),
00856                         "pts ell");
00857                 rt_ell( ellipses[i], V, A, B, nseg );
00858 
00859                 i++;
00860                 pos_a = pos_a->next;
00861                 pos_b = pos_b->next;
00862         }
00863 
00864         /* Draw the top ellipse */
00865         RT_ADD_VLIST( vhead,
00866                 &ellipses[nell-1][(nseg-1)*ELEMENTS_PER_VECT],
00867                 BN_VLIST_LINE_MOVE );
00868         for( i = 0; i < nseg; i++ )  {
00869                 RT_ADD_VLIST( vhead,
00870                         &ellipses[nell-1][i*ELEMENTS_PER_VECT],
00871                         BN_VLIST_LINE_DRAW );
00872         }
00873 
00874         /* connect ellipses */
00875         for (i = nell-2; i >= 0; i--) { /* skip top ellipse */
00876                 int bottom, top;
00877 
00878                 top = i + 1;
00879                 bottom = i;
00880                 if (pts_dbl[top])
00881                         nseg /= 2;      /* # segs in 'bottom' ellipse */
00882 
00883                 /* Draw the current ellipse */
00884                 RT_ADD_VLIST( vhead,
00885                         &ellipses[bottom][(nseg-1)*ELEMENTS_PER_VECT],
00886                         BN_VLIST_LINE_MOVE );
00887                 for( j = 0; j < nseg; j++ )  {
00888                         RT_ADD_VLIST( vhead,
00889                                 &ellipses[bottom][j*ELEMENTS_PER_VECT],
00890                                 BN_VLIST_LINE_DRAW );
00891                 }
00892 
00893                 /* make connections between ellipses */
00894                 for (j = 0; j < nseg; j++) {
00895                         if (pts_dbl[top])
00896                                 jj = j + j;     /* top ellipse index */
00897                         else
00898                                 jj = j;
00899                         RT_ADD_VLIST( vhead,
00900                                 &ellipses[bottom][j*ELEMENTS_PER_VECT],
00901                                 BN_VLIST_LINE_MOVE );
00902                         RT_ADD_VLIST( vhead,
00903                                 &ellipses[top][jj*ELEMENTS_PER_VECT],
00904                                 BN_VLIST_LINE_DRAW );
00905                 }
00906         }
00907 
00908         VADD2( Work, xip->ehy_V, xip->ehy_H );
00909         for (i = 0; i < nseg; i++) {
00910                 /* Draw connector */
00911                 RT_ADD_VLIST( vhead, Work, BN_VLIST_LINE_MOVE );
00912                 RT_ADD_VLIST( vhead,
00913                         &ellipses[0][i*ELEMENTS_PER_VECT],
00914                         BN_VLIST_LINE_DRAW );
00915         }
00916 
00917         /* free mem */
00918         for (i = 0; i < nell; i++) {
00919                 bu_free( (char *)ellipses[i], "pts ell");
00920         }
00921         bu_free( (char *)ellipses, "fastf_t ell[]");
00922         bu_free( (char *)pts_dbl, "dbl ints" );
00923 
00924         return(0);
00925 }
00926 
00927 /**
00928  *                      R T _ E H Y _ T E S S
00929  *
00930  *  Returns -
00931  *      -1      failure
00932  *       0      OK.  *r points to nmgregion that holds this tessellation.
00933  */
00934 int
00935 rt_ehy_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00936 {
00937         fastf_t         c, dtol, f, mag_a, mag_h, ntol, r1, r2, cprime;
00938         fastf_t         **ellipses, theta_prev, theta_new, rt_ell_ang(fastf_t *p1, fastf_t a, fastf_t b, fastf_t dtol, fastf_t ntol);
00939         int             *pts_dbl, face, i, j, nseg;
00940         int             jj, na, nb, nell, recalc_b;
00941         LOCAL mat_t     R;
00942         LOCAL mat_t     invR;
00943         LOCAL mat_t     invRoS;
00944         LOCAL mat_t     S;
00945         LOCAL mat_t     SoR;
00946         LOCAL struct rt_ehy_internal    *xip;
00947         point_t         p1;
00948         struct rt_pt_node       *pos_a, *pos_b, *pts_a, *pts_b, *rt_ptalloc(void);
00949         struct shell    *s;
00950         struct faceuse  **outfaceuses = NULL;
00951         struct faceuse  *fu_top;
00952         struct loopuse  *lu;
00953         struct edgeuse  *eu;
00954         struct vertex   *vertp[3];
00955         struct vertex   ***vells = (struct vertex ***)NULL;
00956         vect_t          A, Au, B, Bu, Hu, V;
00957         struct bu_ptbl  vert_tab;
00958 
00959         RT_CK_DB_INTERNAL(ip);
00960         xip = (struct rt_ehy_internal *)ip->idb_ptr;
00961         RT_EHY_CK_MAGIC(xip);
00962 
00963         /*
00964          *      make sure ehy description is valid
00965          */
00966 
00967         /* compute |A| |H| */
00968         mag_a = MAGSQ( xip->ehy_Au );   /* should already be unit vector */
00969         mag_h = MAGNITUDE( xip->ehy_H );
00970         c = xip->ehy_c;
00971         cprime = c / mag_h;
00972         r1 = xip->ehy_r1;
00973         r2 = xip->ehy_r2;
00974         /* Check for |H| > 0, |A| == 1, r1 > 0, r2 > 0, c > 0 */
00975         if( NEAR_ZERO(mag_h, RT_LEN_TOL)
00976                 || !NEAR_ZERO(mag_a - 1.0, RT_LEN_TOL)
00977                 || r1 <= 0.0 || r2 <= 0.0 || c <= 0. )  {
00978                 return(1);              /* BAD */
00979         }
00980 
00981         /* Check for A.H == 0 */
00982         f = VDOT( xip->ehy_Au, xip->ehy_H ) / mag_h;
00983         if( ! NEAR_ZERO(f, RT_DOT_TOL) )  {
00984                 return(1);              /* BAD */
00985         }
00986 
00987         /* make unit vectors in A, H, and BxH directions */
00988         VMOVE(    Hu, xip->ehy_H );
00989         VUNITIZE( Hu );
00990         VMOVE(    Au, xip->ehy_Au );
00991         VCROSS(   Bu, Au, Hu );
00992 
00993         /* Compute R and Rinv matrices */
00994         MAT_IDN( R );
00995         VREVERSE( &R[0], Bu );
00996         VMOVE(    &R[4], Au );
00997         VREVERSE( &R[8], Hu );
00998         bn_mat_trn( invR, R );                  /* inv of rot mat is trn */
00999 
01000         /* Compute S */
01001         MAT_IDN( S );
01002         S[ 0] = 1.0/r2;
01003         S[ 5] = 1.0/r1;
01004         S[10] = 1.0/mag_h;
01005 
01006         /* Compute SoR and invRoS */
01007         bn_mat_mul( SoR, S, R );
01008         bn_mat_mul( invRoS, invR, S );
01009 
01010         /*
01011          *  Establish tolerances
01012          */
01013         if( ttol->rel <= 0.0 || ttol->rel >= 1.0 )
01014                 dtol = 0.0;             /* none */
01015         else
01016                 /* Convert rel to absolute by scaling by smallest side */
01017                 dtol = ttol->rel * 2 * r2;
01018         if( ttol->abs <= 0.0 )  {
01019                 if( dtol <= 0.0 )
01020                         /* No tolerance given, use a default */
01021                         dtol = 2 * 0.10 * r2;   /* 10% */
01022                 else
01023                         /* Use absolute-ized relative tolerance */
01024                         ;
01025         } else {
01026                 /* Absolute tolerance was given, pick smaller */
01027                 if( ttol->rel <= 0.0 || dtol > ttol->abs )
01028                         dtol = ttol->abs;
01029         }
01030 
01031         /* To ensure normal tolerance, remain below this angle */
01032         if( ttol->norm > 0.0 )
01033                 ntol = ttol->norm;
01034         else
01035                 /* tolerate everything */
01036                 ntol = bn_pi;
01037 
01038         /*
01039          *      build ehy from 2 hyperbolas
01040          */
01041 
01042         /* approximate positive half of hyperbola along semi-minor axis */
01043         pts_b = rt_ptalloc();
01044         pts_b->next = rt_ptalloc();
01045         pts_b->next->next = NULL;
01046         VSET( pts_b->p,       0, 0, -mag_h);
01047         VSET( pts_b->next->p, 0, r2, 0);
01048         /* 2 endpoints in 1st approximation */
01049         nb = 2;
01050         /* recursively break segment 'til within error tolerances */
01051         nb += rt_mk_hyperbola( pts_b, r2, mag_h, c, dtol, ntol );
01052         nell = nb - 1;  /* # of ellipses needed */
01053 
01054         /* construct positive half of hyperbola along semi-major axis
01055          * of ehy using same z coords as parab along semi-minor axis
01056          */
01057         pts_a = rt_ptalloc();
01058         VMOVE(pts_a->p, pts_b->p);      /* 1st pt is the apex */
01059         pts_a->next = NULL;
01060         pos_b = pts_b->next;
01061         pos_a = pts_a;
01062         while (pos_b) {
01063                 /* copy node from b_hyperbola to a_hyperbola */
01064                 pos_a->next = rt_ptalloc();
01065                 pos_a = pos_a->next;
01066                 pos_a->p[Z] = pos_b->p[Z];
01067                 /* at given z, find y on hyperbola */
01068                 pos_a->p[Y] = r1
01069                         * sqrt(
01070                                 (   (pos_b->p[Z] + mag_h + c)
01071                                   * (pos_b->p[Z] + mag_h + c) - c*c )
01072                                 / ( mag_h*(mag_h + 2*c) )
01073                               );
01074                 pos_a->p[X] = 0;
01075                 pos_b = pos_b->next;
01076         }
01077         pos_a->next = NULL;
01078 
01079         /* see if any segments need further breaking up */
01080         recalc_b = 0;
01081         pos_a = pts_a;
01082         while (pos_a->next) {
01083                 na = rt_mk_hyperbola( pos_a, r1, mag_h, c, dtol, ntol );
01084                 if (na != 0) {
01085                         recalc_b = 1;
01086                         nell += na;
01087                 }
01088                 pos_a = pos_a->next;
01089         }
01090         /* if any were broken, recalculate hyperbola 'a' */
01091         if ( recalc_b ) {
01092                 /* free mem for old approximation of hyperbola */
01093                 pos_b = pts_b;
01094                 while ( pos_b ) {
01095                         struct rt_pt_node *tmp;
01096 
01097                         tmp = pos_b->next;
01098                         bu_free( (char *)pos_b, "rt_pt_node" );
01099                         pos_b = tmp;
01100                 }
01101                 /* construct hyperbola along semi-major axis of ehy
01102                  * using same z coords as parab along semi-minor axis
01103                  */
01104                 pts_b = rt_ptalloc();
01105                 pts_b->p[Z] = pts_a->p[Z];
01106                 pts_b->next = NULL;
01107                 pos_a = pts_a->next;
01108                 pos_b = pts_b;
01109                 while (pos_a) {
01110                         /* copy node from a_hyperbola to b_hyperbola */
01111                         pos_b->next = rt_ptalloc();
01112                         pos_b = pos_b->next;
01113                         pos_b->p[Z] = pos_a->p[Z];
01114                         /* at given z, find y on hyperbola */
01115                         pos_b->p[Y] = r2
01116                                 * sqrt(
01117                                         (   (pos_a->p[Z] + mag_h + c)
01118                                           * (pos_a->p[Z] + mag_h + c) - c*c )
01119                                         / ( mag_h*(mag_h + 2*c) )
01120                                       );
01121                         pos_b->p[X] = 0;
01122                         pos_a = pos_a->next;
01123                 }
01124                 pos_b->next = NULL;
01125         }
01126 
01127         /* make array of ptrs to ehy ellipses */
01128         ellipses = (fastf_t **)bu_malloc( nell * sizeof(fastf_t *), "fastf_t ell[]");
01129 
01130         /* keep track of whether pts in each ellipse are doubled or not */
01131         pts_dbl = (int *)bu_malloc( nell * sizeof(int), "dbl ints" );
01132 
01133         /* make ellipses at each z level */
01134         i = 0;
01135         nseg = 0;
01136         theta_prev = bn_twopi;
01137         pos_a = pts_a->next;    /* skip over apex of ehy */
01138         pos_b = pts_b->next;
01139         while (pos_a) {
01140                 VSCALE( A, Au, pos_a->p[Y] );   /* semimajor axis */
01141                 VSCALE( B, Bu, pos_b->p[Y] );   /* semiminor axis */
01142                 VJOIN1( V, xip->ehy_V, -pos_a->p[Z], Hu );
01143 
01144                 VSET( p1, 0., pos_b->p[Y], 0. );
01145                 theta_new = rt_ell_ang(p1, pos_a->p[Y], pos_b->p[Y], dtol, ntol);
01146                 if (nseg == 0) {
01147                         nseg = (int)(bn_twopi / theta_new) + 1;
01148                         pts_dbl[i] = 0;
01149                         /* maximum number of faces needed for ehy */
01150                         face = nseg*(1 + 3*((1 << (nell-1)) - 1));
01151                         /* array for each triangular face */
01152                         outfaceuses = (struct faceuse **)
01153                                 bu_malloc( (face+1) * sizeof(struct faceuse *), "ehy: *outfaceuses[]" );
01154                 } else if (theta_new < theta_prev) {
01155                         nseg *= 2;
01156                         pts_dbl[i] = 1;
01157                 } else {
01158                         pts_dbl[i] = 0;
01159                 }
01160                 theta_prev = theta_new;
01161 
01162                 ellipses[i] = (fastf_t *)bu_malloc(3*(nseg+1)*sizeof(fastf_t),
01163                         "pts ell");
01164                 rt_ell( ellipses[i], V, A, B, nseg );
01165 
01166                 i++;
01167                 pos_a = pos_a->next;
01168                 pos_b = pos_b->next;
01169         }
01170 
01171         /*
01172          *      put ehy geometry into nmg data structures
01173          */
01174 
01175         *r = nmg_mrsv( m );     /* Make region, empty shell, vertex */
01176         s = BU_LIST_FIRST(shell, &(*r)->s_hd);
01177 
01178         /* vertices of ellipses of ehy */
01179         vells = (struct vertex ***)
01180                 bu_malloc(nell*sizeof(struct vertex **), "vertex [][]");
01181         j = nseg;
01182         for (i = nell-1; i >= 0; i--) {
01183                 vells[i] = (struct vertex **)
01184                         bu_malloc(j*sizeof(struct vertex *), "vertex []");
01185                 if (i && pts_dbl[i])
01186                         j /= 2;
01187         }
01188 
01189         /* top face of ehy */
01190         for (i = 0; i < nseg; i++)
01191                 vells[nell-1][i] = (struct vertex *)NULL;
01192         face = 0;
01193         BU_ASSERT_PTR( outfaceuses, !=, NULL );
01194         if ( (outfaceuses[face++] = nmg_cface(s, vells[nell-1], nseg)) == 0) {
01195                 bu_log("rt_ehy_tess() failure, top face\n");
01196                 goto fail;
01197         }
01198         fu_top = outfaceuses[0];
01199 
01200         /* Mark edges of this face as real, this is the only real edge */
01201         for( BU_LIST_FOR( lu , loopuse , &outfaceuses[0]->lu_hd ) )
01202         {
01203                 NMG_CK_LOOPUSE( lu );
01204 
01205                 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
01206                         continue;
01207                 for( BU_LIST_FOR( eu , edgeuse , &lu->down_hd ) )
01208                 {
01209                         struct edge *e;
01210 
01211                         NMG_CK_EDGEUSE( eu );
01212                         e = eu->e_p;
01213                         NMG_CK_EDGE( e );
01214                         e->is_real = 1;
01215                 }
01216         }
01217 
01218         for (i = 0; i < nseg; i++) {
01219                 NMG_CK_VERTEX( vells[nell-1][i] );
01220                 nmg_vertex_gv( vells[nell-1][i], &ellipses[nell-1][3*i] );
01221         }
01222 
01223         /* connect ellipses with triangles */
01224         for (i = nell-2; i >= 0; i--) { /* skip top ellipse */
01225                 int bottom, top;
01226 
01227                 top = i + 1;
01228                 bottom = i;
01229                 if (pts_dbl[top])
01230                         nseg /= 2;      /* # segs in 'bottom' ellipse */
01231                 vertp[0] = (struct vertex *)0;
01232 
01233                 /* make triangular faces */
01234                 for (j = 0; j < nseg; j++) {
01235                         jj = j + j;     /* top ellipse index */
01236 
01237                         if (pts_dbl[top]) {
01238                                 /* first triangle */
01239                                 vertp[1] = vells[top][jj+1];
01240                                 vertp[2] = vells[top][jj];
01241                                 if ( (outfaceuses[face++] = nmg_cface(s, vertp, 3)) == 0) {
01242                                         bu_log("rt_ehy_tess() failure\n");
01243                                         goto fail;
01244                                 }
01245                                 if (j == 0)
01246                                         vells[bottom][j] = vertp[0];
01247 
01248                                 /* second triangle */
01249                                 vertp[2] = vertp[1];
01250                                 if (j == nseg-1)
01251                                         vertp[1] = vells[bottom][0];
01252                                 else
01253                                         vertp[1] = (struct vertex *)0;
01254                                 if ( (outfaceuses[face++] = nmg_cface(s, vertp, 3)) == 0) {
01255                                         bu_log("rt_ehy_tess() failure\n");
01256                                         goto fail;
01257                                 }
01258                                 if (j != nseg-1)
01259                                         vells[bottom][j+1] = vertp[1];
01260 
01261                                 /* third triangle */
01262                                 vertp[0] = vertp[1];
01263                                 if (j == nseg-1)
01264                                         vertp[1] = vells[top][0];
01265                                 else
01266                                         vertp[1] = vells[top][jj+2];
01267                                 if ( (outfaceuses[face++] = nmg_cface(s, vertp, 3)) == 0) {
01268                                         bu_log("rt_ehy_tess() failure\n");
01269                                         goto fail;
01270                                 }
01271                         } else {
01272                                 /* first triangle */
01273                                 if (j == nseg-1)
01274                                         vertp[1] = vells[top][0];
01275                                 else
01276                                         vertp[1] = vells[top][j+1];
01277                                 vertp[2] = vells[top][j];
01278                                 if ( (outfaceuses[face++] = nmg_cface(s, vertp, 3)) == 0) {
01279                                         bu_log("rt_ehy_tess() failure\n");
01280                                         goto fail;
01281                                 }
01282                                 if (j == 0)
01283                                         vells[bottom][j] = vertp[0];
01284 
01285                                 /* second triangle */
01286                                 vertp[2] = vertp[0];
01287                                 if (j == nseg-1)
01288                                         vertp[0] = vells[bottom][0];
01289                                 else
01290                                         vertp[0] = (struct vertex *)0;
01291                                 if ( (outfaceuses[face++] = nmg_cface(s, vertp, 3)) == 0) {
01292                                         bu_log("rt_ehy_tess() failure\n");
01293                                         goto fail;
01294                                 }
01295                                 if (j != nseg-1)
01296                                         vells[bottom][j+1] = vertp[0];
01297                         }
01298                 }
01299 
01300                 /* associate geometry with each vertex */
01301                 for (j = 0; j < nseg; j++)
01302                 {
01303                         NMG_CK_VERTEX( vells[bottom][j] );
01304                         nmg_vertex_gv( vells[bottom][j],
01305                                 &ellipses[bottom][3*j] );
01306                 }
01307         }
01308 
01309         /* connect bottom of ellipse to apex of ehy */
01310         VADD2(V, xip->ehy_V, xip->ehy_H);
01311         vertp[0] = (struct vertex *)0;
01312         vertp[1] = vells[0][1];
01313         vertp[2] = vells[0][0];
01314         if ( (outfaceuses[face++] = nmg_cface(s, vertp, 3)) == 0) {
01315                 bu_log("rt_ehy_tess() failure\n");
01316                 goto fail;
01317         }
01318         /* associate geometry with topology */
01319         NMG_CK_VERTEX(vertp[0]);
01320         nmg_vertex_gv( vertp[0], (fastf_t *)V );
01321         /* create rest of faces around apex */
01322         for (i = 1; i < nseg; i++) {
01323                 vertp[2] = vertp[1];
01324                 if (i == nseg-1)
01325                         vertp[1] = vells[0][0];
01326                 else
01327                         vertp[1] = vells[0][i+1];
01328                 if ( (outfaceuses[face++] = nmg_cface(s, vertp, 3)) == 0) {
01329                         bu_log("rt_ehy_tess() failure\n");
01330                         goto fail;
01331                 }
01332         }
01333 
01334         /* Associate the face geometry */
01335         for (i=0 ; i < face ; i++) {
01336                 if( nmg_fu_planeeqn( outfaceuses[i], tol ) < 0 )
01337                         goto fail;
01338         }
01339 
01340         /* Glue the edges of different outward pointing face uses together */
01341         nmg_gluefaces( outfaceuses, face, tol );
01342 
01343         /* Compute "geometry" for region and shell */
01344         nmg_region_a( *r, tol );
01345 
01346         /* XXX just for testing, to make up for loads of triangles ... */
01347         nmg_shell_coplanar_face_merge( s, tol, 1 );
01348 
01349         /* free mem */
01350         bu_free( (char *)outfaceuses, "faceuse []");
01351         for (i = 0; i < nell; i++) {
01352                 bu_free( (char *)ellipses[i], "pts ell");
01353                 bu_free( (char *)vells[i], "vertex []");
01354         }
01355         bu_free( (char *)ellipses, "fastf_t ell[]");
01356         bu_free( (char *)vells, "vertex [][]");
01357 
01358         /* Assign vertexuse normals */
01359         nmg_vertex_tabulate( &vert_tab , &s->l.magic );
01360         for( i=0 ; i<BU_PTBL_END( &vert_tab ) ; i++ )
01361         {
01362                 point_t pt_prime,tmp_pt;
01363                 vect_t norm,rev_norm,tmp_vect;
01364                 struct vertex_g *vg;
01365                 struct vertex *v;
01366                 struct vertexuse *vu;
01367 
01368                 v = (struct vertex *)BU_PTBL_GET( &vert_tab , i );
01369                 NMG_CK_VERTEX( v );
01370                 vg = v->vg_p;
01371                 NMG_CK_VERTEX_G( vg );
01372 
01373                 VSUB2( tmp_pt , vg->coord , xip->ehy_V );
01374                 MAT4X3VEC( pt_prime , SoR , tmp_pt );
01375                 VSET( tmp_vect , pt_prime[X]*(2*cprime+1), pt_prime[Y]*(2*cprime+1), -(pt_prime[Z]+cprime+1) );
01376                 MAT4X3VEC( norm , invRoS , tmp_vect );
01377                 VUNITIZE( norm );
01378                 VREVERSE( rev_norm , norm );
01379 
01380                 for( BU_LIST_FOR( vu , vertexuse , &v->vu_hd ) )
01381                 {
01382                         struct faceuse *fu;
01383 
01384                         NMG_CK_VERTEXUSE( vu );
01385                         fu = nmg_find_fu_of_vu( vu );
01386 
01387                         /* don't assign vertexuse normals to top face (flat) */
01388                         if( fu == fu_top || fu->fumate_p == fu_top )
01389                                 continue;
01390 
01391                         NMG_CK_FACEUSE( fu );
01392                         if( fu->orientation == OT_SAME )
01393                                 nmg_vertexuse_nv( vu , norm );
01394                         else if( fu->orientation == OT_OPPOSITE )
01395                                 nmg_vertexuse_nv( vu , rev_norm );
01396                 }
01397         }
01398 
01399         bu_ptbl_free( &vert_tab );
01400         return(0);
01401 
01402 fail:
01403         /* free mem */
01404         bu_free( (char *)outfaceuses, "faceuse []");
01405         for (i = 0; i < nell; i++) {
01406                 bu_free( (char *)ellipses[i], "pts ell");
01407                 bu_free( (char *)vells[i], "vertex []");
01408         }
01409         bu_free( (char *)ellipses, "fastf_t ell[]");
01410         bu_free( (char *)vells, "vertex [][]");
01411 
01412         return(-1);
01413 }
01414 
01415 /**
01416  *                      R T _ E H Y _ I M P O R T
01417  *
01418  *  Import an EHY from the database format to the internal format.
01419  *  Apply modeling transformations as well.
01420  */
01421 int
01422 rt_ehy_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
01423 {
01424         LOCAL struct rt_ehy_internal    *xip;
01425         union record                    *rp;
01426 
01427         BU_CK_EXTERNAL( ep );
01428         rp = (union record *)ep->ext_buf;
01429         /* Check record type */
01430         if( rp->u_id != ID_SOLID )  {
01431                 bu_log("rt_ehy_import: defective record\n");
01432                 return(-1);
01433         }
01434 
01435         RT_CK_DB_INTERNAL( ip );
01436         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
01437         ip->idb_type = ID_EHY;
01438         ip->idb_meth = &rt_functab[ID_EHY];
01439         ip->idb_ptr = bu_malloc( sizeof(struct rt_ehy_internal), "rt_ehy_internal");
01440         xip = (struct rt_ehy_internal *)ip->idb_ptr;
01441         xip->ehy_magic = RT_EHY_INTERNAL_MAGIC;
01442 
01443         /* Warning:  type conversion */
01444         MAT4X3PNT( xip->ehy_V, mat, &rp->s.s_values[0*3] );
01445         MAT4X3VEC( xip->ehy_H, mat, &rp->s.s_values[1*3] );
01446         MAT4X3VEC( xip->ehy_Au, mat, &rp->s.s_values[2*3] );
01447         VUNITIZE( xip->ehy_Au );
01448         xip->ehy_r1 = rp->s.s_values[3*3] / mat[15];
01449         xip->ehy_r2 = rp->s.s_values[3*3+1] / mat[15];
01450         xip->ehy_c  = rp->s.s_values[3*3+2] / mat[15];
01451 
01452         if( xip->ehy_r1 < SMALL_FASTF || xip->ehy_r2 < SMALL_FASTF || xip->ehy_c < SMALL_FASTF )
01453         {
01454                 bu_log( "rt_ehy_import: r1, r2, or c are zero\n" );
01455                 bu_free( (char *)ip->idb_ptr , "rt_ehy_import: ip->idb_ptr" );
01456                 return( -1 );
01457         }
01458 
01459         return(0);                      /* OK */
01460 }
01461 
01462 /**
01463  *                      R T _ E H Y _ E X P O R T
01464  *
01465  *  The name is added by the caller, in the usual place.
01466  */
01467 int
01468 rt_ehy_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
01469 {
01470         struct rt_ehy_internal  *xip;
01471         union record            *ehy;
01472 
01473         RT_CK_DB_INTERNAL(ip);
01474         if( ip->idb_type != ID_EHY )  return(-1);
01475         xip = (struct rt_ehy_internal *)ip->idb_ptr;
01476         RT_EHY_CK_MAGIC(xip);
01477 
01478         BU_CK_EXTERNAL(ep);
01479         ep->ext_nbytes = sizeof(union record);
01480         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "ehy external");
01481         ehy = (union record *)ep->ext_buf;
01482 
01483         ehy->s.s_id = ID_SOLID;
01484         ehy->s.s_type = EHY;
01485 
01486         if (!NEAR_ZERO( MAGNITUDE(xip->ehy_Au) - 1., RT_LEN_TOL)) {
01487                 bu_log("rt_ehy_export: Au not a unit vector!\n");
01488                 return(-1);
01489         }
01490 
01491         if (MAGNITUDE(xip->ehy_H) < RT_LEN_TOL
01492                 || xip->ehy_c < RT_LEN_TOL
01493                 || xip->ehy_r1 < RT_LEN_TOL
01494                 || xip->ehy_r2 < RT_LEN_TOL) {
01495                 bu_log("rt_ehy_export: not all dimensions positive!\n");
01496                 return(-1);
01497         }
01498 
01499         if ( !NEAR_ZERO( VDOT(xip->ehy_Au, xip->ehy_H), RT_DOT_TOL) ) {
01500                 bu_log("rt_ehy_export: Au and H are not perpendicular!\n");
01501                 return(-1);
01502         }
01503 
01504         if (xip->ehy_r2 > xip->ehy_r1) {
01505                 bu_log("rt_ehy_export: semi-minor axis cannot be longer than semi-major axis!\n");
01506                 return(-1);
01507         }
01508 
01509         /* Warning:  type conversion */
01510         VSCALE( &ehy->s.s_values[0*3], xip->ehy_V, local2mm );
01511         VSCALE( &ehy->s.s_values[1*3], xip->ehy_H, local2mm );
01512         /* don't scale ehy_Au (unit vector!!) */
01513         VMOVE( &ehy->s.s_values[2*3], xip->ehy_Au );
01514         ehy->s.s_values[3*3] = xip->ehy_r1 * local2mm;
01515         ehy->s.s_values[3*3+1] = xip->ehy_r2 * local2mm;
01516         ehy->s.s_values[3*3+2] = xip->ehy_c * local2mm;
01517 
01518         return(0);
01519 }
01520 
01521 /**
01522  *                      R T _ E H Y _ I M P O R T 5
01523  *
01524  *  Import an EHY from the database format to the internal format.
01525  *  Apply modeling transformations as well.
01526  */
01527 int
01528 rt_ehy_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
01529 {
01530         LOCAL struct rt_ehy_internal    *xip;
01531         fastf_t                         vec[3*4];
01532 
01533         BU_CK_EXTERNAL( ep );
01534 
01535         BU_ASSERT_LONG( ep->ext_nbytes, ==, SIZEOF_NETWORK_DOUBLE * 3*4 );
01536 
01537         RT_CK_DB_INTERNAL( ip );
01538         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
01539         ip->idb_type = ID_EHY;
01540         ip->idb_meth = &rt_functab[ID_EHY];
01541         ip->idb_ptr = bu_malloc( sizeof(struct rt_ehy_internal), "rt_ehy_internal");
01542 
01543         xip = (struct rt_ehy_internal *)ip->idb_ptr;
01544         xip->ehy_magic = RT_EHY_INTERNAL_MAGIC;
01545 
01546         /* Convert from database (network) to internal (host) format */
01547         ntohd( (unsigned char *)vec, ep->ext_buf, 3*4 );
01548 
01549         /* Apply modeling transformations */
01550         MAT4X3PNT( xip->ehy_V, mat, &vec[0*3] );
01551         MAT4X3VEC( xip->ehy_H, mat, &vec[1*3] );
01552         MAT4X3VEC( xip->ehy_Au, mat, &vec[2*3] );
01553         VUNITIZE( xip->ehy_Au );
01554         xip->ehy_r1 = vec[3*3] / mat[15];
01555         xip->ehy_r2 = vec[3*3+1] / mat[15];
01556         xip->ehy_c  = vec[3*3+2] / mat[15];
01557 
01558         if( xip->ehy_r1 < SMALL_FASTF || xip->ehy_r2 < SMALL_FASTF || xip->ehy_c < SMALL_FASTF )
01559         {
01560                 bu_log( "rt_ehy_import: r1, r2, or c are zero\n" );
01561                 bu_free( (char *)ip->idb_ptr , "rt_ehy_import: ip->idb_ptr" );
01562                 return( -1 );
01563         }
01564 
01565         return(0);                      /* OK */
01566 }
01567 
01568 /**
01569  *                      R T _ E H Y _ E X P O R T 5
01570  *
01571  *  The name is added by the caller, in the usual place.
01572  */
01573 int
01574 rt_ehy_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
01575 {
01576         struct rt_ehy_internal  *xip;
01577         fastf_t                 vec[3*4];
01578 
01579         RT_CK_DB_INTERNAL(ip);
01580         if( ip->idb_type != ID_EHY )  return(-1);
01581         xip = (struct rt_ehy_internal *)ip->idb_ptr;
01582         RT_EHY_CK_MAGIC(xip);
01583 
01584         BU_CK_EXTERNAL(ep);
01585         ep->ext_nbytes = SIZEOF_NETWORK_DOUBLE * 3*4;
01586         ep->ext_buf = (genptr_t)bu_malloc( ep->ext_nbytes, "ehy external");
01587 
01588         if (!NEAR_ZERO( MAGNITUDE(xip->ehy_Au) - 1., RT_LEN_TOL)) {
01589                 bu_log("rt_ehy_export: Au not a unit vector!\n");
01590                 return(-1);
01591         }
01592 
01593         if (MAGNITUDE(xip->ehy_H) < RT_LEN_TOL
01594                 || xip->ehy_c < RT_LEN_TOL
01595                 || xip->ehy_r1 < RT_LEN_TOL
01596                 || xip->ehy_r2 < RT_LEN_TOL) {
01597                 bu_log("rt_ehy_export: not all dimensions positive!\n");
01598                 return(-1);
01599         }
01600 
01601         if ( !NEAR_ZERO( VDOT(xip->ehy_Au, xip->ehy_H), RT_DOT_TOL) ) {
01602                 bu_log("rt_ehy_export: Au and H are not perpendicular!\n");
01603                 return(-1);
01604         }
01605 
01606         if (xip->ehy_r2 > xip->ehy_r1) {
01607                 bu_log("rt_ehy_export: semi-minor axis cannot be longer than semi-major axis!\n");
01608                 return(-1);
01609         }
01610 
01611         /* Warning:  type conversion */
01612         VSCALE( &vec[0*3], xip->ehy_V, local2mm );
01613         VSCALE( &vec[1*3], xip->ehy_H, local2mm );
01614         /* don't scale ehy_Au (unit vector!!) */
01615         VMOVE( &vec[2*3], xip->ehy_Au );
01616         vec[3*3] = xip->ehy_r1 * local2mm;
01617         vec[3*3+1] = xip->ehy_r2 * local2mm;
01618         vec[3*3+2] = xip->ehy_c * local2mm;
01619 
01620         /* Convert from internal (host) to database (network) format */
01621         htond( ep->ext_buf, (unsigned char *)vec, 3*4 );
01622 
01623         return(0);
01624 }
01625 
01626 /**
01627  *                      R T _ E H Y _ D E S C R I B E
01628  *
01629  *  Make human-readable formatted presentation of this solid.
01630  *  First line describes type of solid.
01631  *  Additional lines are indented one tab, and give parameter values.
01632  */
01633 int
01634 rt_ehy_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
01635 {
01636         register struct rt_ehy_internal *xip =
01637                 (struct rt_ehy_internal *)ip->idb_ptr;
01638         char    buf[256];
01639 
01640         RT_EHY_CK_MAGIC(xip);
01641         bu_vls_strcat( str, "Elliptical Hyperboloid (EHY)\n");
01642 
01643         sprintf(buf, "\tV (%g, %g, %g)\n",
01644                 INTCLAMP(xip->ehy_V[X] * mm2local),
01645                 INTCLAMP(xip->ehy_V[Y] * mm2local),
01646                 INTCLAMP(xip->ehy_V[Z] * mm2local) );
01647         bu_vls_strcat( str, buf );
01648 
01649         sprintf(buf, "\tH (%g, %g, %g) mag=%g\n",
01650                 INTCLAMP(xip->ehy_H[X] * mm2local),
01651                 INTCLAMP(xip->ehy_H[Y] * mm2local),
01652                 INTCLAMP(xip->ehy_H[Z] * mm2local),
01653                 INTCLAMP(MAGNITUDE(xip->ehy_H) * mm2local) );
01654         bu_vls_strcat( str, buf );
01655 
01656         sprintf(buf, "\tA=%g\n", INTCLAMP(xip->ehy_r1 * mm2local));
01657         bu_vls_strcat( str, buf );
01658 
01659         sprintf(buf, "\tB=%g\n", INTCLAMP(xip->ehy_r2 * mm2local));
01660         bu_vls_strcat( str, buf );
01661 
01662         sprintf(buf, "\tc=%g\n", INTCLAMP(xip->ehy_c * mm2local));
01663         bu_vls_strcat( str, buf );
01664 
01665         return(0);
01666 }
01667 
01668 /**
01669  *                      R T _ E H Y _ I F R E E
01670  *
01671  *  Free the storage associated with the rt_db_internal version of this solid.
01672  */
01673 void
01674 rt_ehy_ifree(struct rt_db_internal *ip)
01675 {
01676         register struct rt_ehy_internal *xip;
01677 
01678         RT_CK_DB_INTERNAL(ip);
01679         xip = (struct rt_ehy_internal *)ip->idb_ptr;
01680         RT_EHY_CK_MAGIC(xip);
01681         xip->ehy_magic = 0;             /* sanity */
01682 
01683         bu_free( (char *)xip, "ehy ifree" );
01684         ip->idb_ptr = GENPTR_NULL;      /* sanity */
01685 }
01686 
01687 /*@}*/
01688 /*
01689  * Local Variables:
01690  * mode: C
01691  * tab-width: 8
01692  * c-basic-offset: 4
01693  * indent-tabs-mode: t
01694  * End:
01695  * ex: shiftwidth=4 tabstop=8
01696  */

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