g_tgc.c

Go to the documentation of this file.
00001 /*                         G _ T G C . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1985-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup g_ */
00023 
00024 /*@{*/
00025 /** @file g_tgc.c
00026  *      Intersect a ray with a Truncated General Cone.
00027  *
00028  * Method -
00029  *      TGC:  solve quartic equation of cone and line
00030  *
00031  * Authors -
00032  *      Edwin O. Davisson       (Analysis)
00033  *      Jeff Hanes              (Programming)
00034  *      Gary Moss               (Improvement)
00035  *      Mike Muuss              (Optimization)
00036  *      Peter F. Stiller        (Curvature)
00037  *      Phillip Dykstra         (Curvature)
00038  *      Bill Homer              (Vectorization)
00039  *      Paul Stay               (Convert to tnurbs)
00040  *
00041  *  Source -
00042  *      SECAD/VLD Computing Consortium, Bldg 394
00043  *      The U. S. Army Ballistic Research Laboratory
00044  *      Aberdeen Proving Ground, Maryland  21005
00045  *
00046  */
00047 /*@}*/
00048 
00049 #ifndef lint
00050 static const char RCStgc[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_tgc.c,v 14.17 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00051 #endif
00052 
00053 #include "common.h"
00054 
00055 #include <stddef.h>
00056 #include <stdio.h>
00057 #ifdef HAVE_STRING_H
00058 #  include <string.h>
00059 #else
00060 #  include <strings.h>
00061 #endif
00062 #include <math.h>
00063 
00064 #include "machine.h"
00065 #include "vmath.h"
00066 #include "db.h"
00067 #include "nmg.h"
00068 #include "raytrace.h"
00069 #include "rtgeom.h"
00070 #include "./debug.h"
00071 #include "nurb.h"
00072 
00073 BU_EXTERN(int rt_rec_prep, (struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip));
00074 
00075 struct  tgc_specific {
00076         vect_t  tgc_V;          /*  Vector to center of base of TGC     */
00077         fastf_t tgc_sH;         /*  magnitude of sheared H vector       */
00078         fastf_t tgc_A;          /*  magnitude of A vector               */
00079         fastf_t tgc_B;          /*  magnitude of B vector               */
00080         fastf_t tgc_C;          /*  magnitude of C vector               */
00081         fastf_t tgc_D;          /*  magnitude of D vector               */
00082         fastf_t tgc_CdAm1;      /*  (C/A - 1)                           */
00083         fastf_t tgc_DdBm1;      /*  (D/B - 1)                           */
00084         fastf_t tgc_AAdCC;      /*  (|A|**2)/(|C|**2)                   */
00085         fastf_t tgc_BBdDD;      /*  (|B|**2)/(|D|**2)                   */
00086         vect_t  tgc_N;          /*  normal at 'top' of cone             */
00087         mat_t   tgc_ScShR;      /*  Scale( Shear( Rot( vect )))         */
00088         mat_t   tgc_invRtShSc;  /*  invRot( trnShear( Scale( vect )))   */
00089         char    tgc_AD_CB;      /*  boolean:  A*D == C*B  */
00090 };
00091 
00092 
00093 static void rt_tgc_rotate(fastf_t *A, fastf_t *B, fastf_t *Hv, fastf_t *Rot, fastf_t *Inv, struct tgc_specific *tgc);
00094 static void rt_tgc_shear(const fastf_t *vect, int axis, fastf_t *Shr, fastf_t *Trn, fastf_t *Inv);
00095 static void rt_tgc_scale(fastf_t a, fastf_t b, fastf_t h, fastf_t *Scl, fastf_t *Inv);
00096 static void nmg_tgc_disk(struct faceuse *fu, fastf_t *rmat, fastf_t height, int flip);
00097 static void nmg_tgc_nurb_cyl(struct faceuse *fu, fastf_t *top_mat, fastf_t *bot_mat);
00098 void rt_pt_sort(register fastf_t *t, int npts);
00099 
00100 #define VLARGE          1000000.0
00101 #define ALPHA(x,y,c,d)  ( (x)*(x)*(c) + (y)*(y)*(d) )
00102 
00103 const struct bu_structparse rt_tgc_parse[] = {
00104     { "%f", 3, "V", bu_offsetof(struct rt_tgc_internal, v[X]), BU_STRUCTPARSE_FUNC_NULL },
00105     { "%f", 3, "H", bu_offsetof(struct rt_tgc_internal, h[X]), BU_STRUCTPARSE_FUNC_NULL },
00106     { "%f", 3, "A", bu_offsetof(struct rt_tgc_internal, a[X]), BU_STRUCTPARSE_FUNC_NULL },
00107     { "%f", 3, "B", bu_offsetof(struct rt_tgc_internal, b[X]), BU_STRUCTPARSE_FUNC_NULL },
00108     { "%f", 3, "C", bu_offsetof(struct rt_tgc_internal, c[X]), BU_STRUCTPARSE_FUNC_NULL },
00109     { "%f", 3, "D", bu_offsetof(struct rt_tgc_internal, d[X]), BU_STRUCTPARSE_FUNC_NULL },
00110     { {'\0','\0','\0','\0'}, 0, (char *)NULL, 0, BU_STRUCTPARSE_FUNC_NULL }
00111 };
00112 
00113 
00114 /**
00115  *                      R T _ T G C _ P R E P
00116  *
00117  *  Given the parameters (in vector form) of a truncated general cone,
00118  *  compute the constant terms and a transformation matrix needed for
00119  *  solving the intersection of a ray with the cone.
00120  *
00121  *  Also compute the return transformation for normals in the transformed
00122  *  space to the original space.  This NOT the inverse of the transformation
00123  *  matrix (if you really want to know why, talk to Ed Davisson).
00124  */
00125 int
00126 rt_tgc_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00127 {
00128         struct rt_tgc_internal  *tip;
00129         register struct tgc_specific *tgc;
00130         register fastf_t        f;
00131         LOCAL fastf_t   prod_ab, prod_cd;
00132         LOCAL fastf_t   magsq_a, magsq_b, magsq_c, magsq_d;
00133         LOCAL fastf_t   mag_h, mag_a, mag_b, mag_c, mag_d;
00134         LOCAL mat_t     Rot, Shr, Scl;
00135         LOCAL mat_t     iRot, tShr, iShr, iScl;
00136         LOCAL mat_t     tmp;
00137         LOCAL vect_t    nH;
00138         LOCAL vect_t    work;
00139 
00140         tip = (struct rt_tgc_internal *)ip->idb_ptr;
00141         RT_TGC_CK_MAGIC(tip);
00142 
00143         /*
00144          *  For a fast way out, hand this solid off to the REC routine.
00145          *  If it takes it, then there is nothing to do, otherwise
00146          *  the solid is a TGC.
00147          */
00148         if( rt_rec_prep( stp, ip, rtip ) == 0 )
00149                 return(0);              /* OK */
00150 
00151         /* Validate that |H| > 0, compute |A| |B| |C| |D|               */
00152         mag_h = sqrt( MAGSQ( tip->h ) );
00153         mag_a = sqrt( magsq_a = MAGSQ( tip->a ) );
00154         mag_b = sqrt( magsq_b = MAGSQ( tip->b ) );
00155         mag_c = sqrt( magsq_c = MAGSQ( tip->c ) );
00156         mag_d = sqrt( magsq_d = MAGSQ( tip->d ) );
00157         prod_ab = mag_a * mag_b;
00158         prod_cd = mag_c * mag_d;
00159 
00160         if( NEAR_ZERO( mag_h, RT_LEN_TOL ) ) {
00161                 bu_log("tgc(%s):  zero length H vector\n", stp->st_name );
00162                 return(1);              /* BAD */
00163         }
00164 
00165         /* Validate that figure is not two-dimensional                  */
00166         if( NEAR_ZERO( mag_a, RT_LEN_TOL ) &&
00167             NEAR_ZERO( mag_c, RT_LEN_TOL ) ) {
00168                 bu_log("tgc(%s):  vectors A, C zero length\n", stp->st_name );
00169                 return (1);
00170         }
00171         if( NEAR_ZERO( mag_b, RT_LEN_TOL ) &&
00172             NEAR_ZERO( mag_d, RT_LEN_TOL ) ) {
00173                 bu_log("tgc(%s):  vectors B, D zero length\n", stp->st_name );
00174                 return (1);
00175         }
00176 
00177         /* Validate that both ends are not degenerate */
00178         if( prod_ab <= SMALL )  {
00179                 /* AB end is degenerate */
00180                 if( prod_cd <= SMALL )  {
00181                         bu_log("tgc(%s):  Both ends degenerate\n", stp->st_name);
00182                         return(1);              /* BAD */
00183                 }
00184                 /* Exchange ends, so that in solids with one degenerate end,
00185                  * the CD end always is always the degenerate one
00186                  */
00187                 VADD2( tip->v, tip->v, tip->h );
00188                 VREVERSE( tip->h, tip->h );
00189 #define VEXCHANGE( a, b, tmp )  { VMOVE(tmp,a); VMOVE(a,b); VMOVE(b,tmp); }
00190                 VEXCHANGE( tip->a, tip->c, work );
00191                 VEXCHANGE( tip->b, tip->d, work );
00192                 bu_log("NOTE: tgc(%s): degenerate end exchanged\n", stp->st_name);
00193         }
00194 
00195         /* Ascertain whether H lies in A-B plane                        */
00196         VCROSS( work, tip->a, tip->b );
00197         f = VDOT( tip->h, work ) / ( prod_ab*mag_h );
00198         if ( NEAR_ZERO(f, RT_DOT_TOL) ) {
00199                 bu_log("tgc(%s):  H lies in A-B plane\n",stp->st_name);
00200                 return(1);              /* BAD */
00201         }
00202 
00203         if( prod_ab > SMALL )  {
00204                 /* Validate that A.B == 0 */
00205                 f = VDOT( tip->a, tip->b ) / prod_ab;
00206                 if( ! NEAR_ZERO(f, RT_DOT_TOL) ) {
00207                         bu_log("tgc(%s):  A not perpendicular to B, f=%g\n",
00208                             stp->st_name, f);
00209                         bu_log("tgc: dot=%g / a*b=%g\n",
00210                             VDOT( tip->a, tip->b ),  prod_ab );
00211                         return(1);              /* BAD */
00212                 }
00213         }
00214         if( prod_cd > SMALL )  {
00215                 /* Validate that C.D == 0 */
00216                 f = VDOT( tip->c, tip->d ) / prod_cd;
00217                 if( ! NEAR_ZERO(f, RT_DOT_TOL) ) {
00218                         bu_log("tgc(%s):  C not perpendicular to D, f=%g\n",
00219                             stp->st_name, f);
00220                         bu_log("tgc: dot=%g / c*d=%g\n",
00221                             VDOT( tip->c, tip->d ), prod_cd );
00222                         return(1);              /* BAD */
00223                 }
00224         }
00225 
00226         if( mag_a * mag_c > SMALL )  {
00227                 /* Validate that  A || C */
00228                 f = 1.0 - VDOT( tip->a, tip->c ) / (mag_a * mag_c);
00229                 if( ! NEAR_ZERO(f, RT_DOT_TOL) ) {
00230                         bu_log("tgc(%s):  A not parallel to C, f=%g\n",
00231                             stp->st_name, f);
00232                         return(1);              /* BAD */
00233                 }
00234         }
00235 
00236         if( mag_b * mag_d > SMALL )  {
00237                 /* Validate that  B || D, for parallel planes   */
00238                 f = 1.0 - VDOT( tip->b, tip->d ) / (mag_b * mag_d);
00239                 if( ! NEAR_ZERO(f, RT_DOT_TOL) ) {
00240                         bu_log("tgc(%s):  B not parallel to D, f=%g\n",
00241                             stp->st_name, f);
00242                         return(1);              /* BAD */
00243                 }
00244         }
00245 
00246         /* solid is OK, compute constant terms, etc. */
00247         BU_GETSTRUCT( tgc, tgc_specific );
00248         stp->st_specific = (genptr_t)tgc;
00249 
00250         VMOVE( tgc->tgc_V, tip->v );
00251         tgc->tgc_A = mag_a;
00252         tgc->tgc_B = mag_b;
00253         tgc->tgc_C = mag_c;
00254         tgc->tgc_D = mag_d;
00255 
00256         /* Part of computing ALPHA() */
00257         if( NEAR_ZERO(magsq_c, SMALL) )
00258                 tgc->tgc_AAdCC = VLARGE;
00259         else
00260                 tgc->tgc_AAdCC = magsq_a / magsq_c;
00261         if( NEAR_ZERO(magsq_d, SMALL) )
00262                 tgc->tgc_BBdDD = VLARGE;
00263         else
00264                 tgc->tgc_BBdDD = magsq_b / magsq_d;
00265 
00266         /*  If the eccentricities of the two ellipses are the same,
00267          *  then the cone equation reduces to a much simpler quadratic
00268          *  form.  Otherwise it is a (gah!) quartic equation.
00269          */
00270         f = rt_reldiff( (tgc->tgc_A*tgc->tgc_D), (tgc->tgc_C*tgc->tgc_B) );
00271         tgc->tgc_AD_CB = (f < 0.0001);          /* A*D == C*B */
00272         rt_tgc_rotate( tip->a, tip->b, tip->h, Rot, iRot, tgc );
00273         MAT4X3VEC( nH, Rot, tip->h );
00274         tgc->tgc_sH = nH[Z];
00275 
00276         tgc->tgc_CdAm1 = tgc->tgc_C/tgc->tgc_A - 1.0;
00277         tgc->tgc_DdBm1 = tgc->tgc_D/tgc->tgc_B - 1.0;
00278         if( NEAR_ZERO( tgc->tgc_CdAm1, SMALL ) )
00279                 tgc->tgc_CdAm1 = 0.0;
00280         if( NEAR_ZERO( tgc->tgc_DdBm1, SMALL ) )
00281                 tgc->tgc_DdBm1 = 0.0;
00282 
00283         /*
00284          *      Added iShr parameter to tgc_shear().
00285          *      Changed inverse transformation of normal vectors of std.
00286          *              solid intersection to include shear inverse
00287          *              (tgc_invRtShSc).
00288          *      Fold in scaling transformation into the transformation to std.
00289          *              space from target space (tgc_ScShR).
00290          */
00291         rt_tgc_shear( nH, Z, Shr, tShr, iShr );
00292         rt_tgc_scale( tgc->tgc_A, tgc->tgc_B, tgc->tgc_sH, Scl, iScl );
00293 
00294         bn_mat_mul( tmp, Shr, Rot );
00295         bn_mat_mul( tgc->tgc_ScShR, Scl, tmp );
00296 
00297         bn_mat_mul( tmp, tShr, Scl );
00298         bn_mat_mul( tgc->tgc_invRtShSc, iRot, tmp );
00299 
00300         /* Compute bounding sphere and RPP */
00301         {
00302                 LOCAL fastf_t dx, dy, dz;       /* For bounding sphere */
00303                 LOCAL vect_t temp;
00304 
00305                 /* There are 8 corners to the bounding RPP */
00306                 /* This may not be minimal, but does fully contain the TGC */
00307                 VADD2( temp, tgc->tgc_V, tip->a );
00308                 VADD2( work, temp, tip->b );
00309 #define TGC_MM(v)       VMINMAX( stp->st_min, stp->st_max, v );
00310                 TGC_MM( work ); /* V + A + B */
00311                 VSUB2( work, temp, tip->b );
00312                 TGC_MM( work ); /* V + A - B */
00313 
00314                 VSUB2( temp, tgc->tgc_V, tip->a );
00315                 VADD2( work, temp, tip->b );
00316                 TGC_MM( work ); /* V - A + B */
00317                 VSUB2( work, temp, tip->b );
00318                 TGC_MM( work ); /* V - A - B */
00319 
00320                 VADD3( temp, tgc->tgc_V, tip->h, tip->c );
00321                 VADD2( work, temp, tip->d );
00322                 TGC_MM( work ); /* V + H + C + D */
00323                 VSUB2( work, temp, tip->d );
00324                 TGC_MM( work ); /* V + H + C - D */
00325 
00326                 VADD2( temp, tgc->tgc_V, tip->h );
00327                 VSUB2( temp, temp, tip->c );
00328                 VADD2( work, temp, tip->d );
00329                 TGC_MM( work ); /* V + H - C + D */
00330                 VSUB2( work, temp, tip->d );
00331                 TGC_MM( work ); /* V + H - C - D */
00332 
00333                 VSET( stp->st_center,
00334                     (stp->st_max[X] + stp->st_min[X])/2,
00335                     (stp->st_max[Y] + stp->st_min[Y])/2,
00336                     (stp->st_max[Z] + stp->st_min[Z])/2 );
00337 
00338                 dx = (stp->st_max[X] - stp->st_min[X])/2;
00339                 f = dx;
00340                 dy = (stp->st_max[Y] - stp->st_min[Y])/2;
00341                 if( dy > f )  f = dy;
00342                 dz = (stp->st_max[Z] - stp->st_min[Z])/2;
00343                 if( dz > f )  f = dz;
00344                 stp->st_aradius = f;
00345                 stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz);
00346         }
00347         return (0);
00348 }
00349 
00350 
00351 /**
00352  *                      R T _ T G C _ R O T A T E
00353  *
00354  *  To rotate vectors  A  and  B  ( where  A  is perpendicular to  B )
00355  *  to the X and Y axes respectively, create a rotation matrix
00356  *
00357  *          | A' |
00358  *      R = | B' |
00359  *          | C' |
00360  *
00361  *  where  A',  B'  and  C'  are vectors such that
00362  *
00363  *      A' = A/|A|      B' = B/|B|      C' = C/|C|
00364  *
00365  *  where    C = H - ( H.A' )A' - ( H.B' )B'
00366  *
00367  *  The last operation ( Gram Schmidt method ) finds the component
00368  *  of the vector  H  perpendicular  A  and to  B.  This is, therefore
00369  *  the normal for the planar sections of the truncated cone.
00370  */
00371 static void
00372 rt_tgc_rotate(fastf_t *A, fastf_t *B, fastf_t *Hv, fastf_t *Rot, fastf_t *Inv, struct tgc_specific *tgc)
00373 {
00374         LOCAL vect_t    uA, uB, uC;     /*  unit vectors                */
00375         LOCAL fastf_t   mag_ha,         /*  magnitude of H in the       */
00376         mag_hb;         /*    A and B directions        */
00377 
00378         /* copy A and B, then 'unitize' the results                     */
00379         VMOVE( uA, A );
00380         VUNITIZE( uA );
00381         VMOVE( uB, B );
00382         VUNITIZE( uB );
00383 
00384         /*  Find component of H in the A direction                      */
00385         mag_ha = VDOT( Hv, uA );
00386         /*  Find component of H in the B direction                      */
00387         mag_hb = VDOT( Hv, uB );
00388 
00389         /*  Subtract the A and B components of H to find the component
00390          *  perpendicular to both, then 'unitize' the result.
00391          */
00392         VJOIN2( uC, Hv, -mag_ha, uA, -mag_hb, uB );
00393         VUNITIZE( uC );
00394         VMOVE( tgc->tgc_N, uC );
00395 
00396         MAT_IDN( Rot );
00397         MAT_IDN( Inv );
00398 
00399         Rot[0] = Inv[0] = uA[X];
00400         Rot[1] = Inv[4] = uA[Y];
00401         Rot[2] = Inv[8] = uA[Z];
00402 
00403         Rot[4] = Inv[1] = uB[X];
00404         Rot[5] = Inv[5] = uB[Y];
00405         Rot[6] = Inv[9] = uB[Z];
00406 
00407         Rot[8]  = Inv[2]  = uC[X];
00408         Rot[9]  = Inv[6]  = uC[Y];
00409         Rot[10] = Inv[10] = uC[Z];
00410 }
00411 
00412 /**
00413  *                      R T _ T G C _ S H E A R
00414  *
00415  *  To shear the H vector to the Z axis, every point must be shifted
00416  *  in the X direction by  -(Hx/Hz)*z , and in the Y direction by
00417  *  -(Hy/Hz)*z .  This operation makes the equation for the standard
00418  *  cone much easier to work with.
00419  *
00420  *  NOTE:  This computes the TRANSPOSE of the shear matrix rather than
00421  *  the inverse.
00422  *
00423  * Begin changes GSM, EOD -- Added INVERSE (Inv) calculation.
00424  */
00425 static void
00426 rt_tgc_shear(const fastf_t *vect, int axis, fastf_t *Shr, fastf_t *Trn, fastf_t *Inv)
00427 {
00428         MAT_IDN( Shr );
00429         MAT_IDN( Trn );
00430         MAT_IDN( Inv );
00431 
00432         if( NEAR_ZERO( vect[axis], SMALL_FASTF ) )
00433                 rt_bomb("rt_tgc_shear() divide by zero\n");
00434 
00435         if ( axis == X ){
00436                 Inv[4] = -(Shr[4] = Trn[1] = -vect[Y]/vect[X]);
00437                 Inv[8] = -(Shr[8] = Trn[2] = -vect[Z]/vect[X]);
00438         } else if ( axis == Y ){
00439                 Inv[1] = -(Shr[1] = Trn[4] = -vect[X]/vect[Y]);
00440                 Inv[9] = -(Shr[9] = Trn[6] = -vect[Z]/vect[Y]);
00441         } else if ( axis == Z ){
00442                 Inv[2] = -(Shr[2] = Trn[8] = -vect[X]/vect[Z]);
00443                 Inv[6] = -(Shr[6] = Trn[9] = -vect[Y]/vect[Z]);
00444         }
00445 }
00446 
00447 /**
00448  *                      R T _ T G C _ S C A L E
00449  */
00450 static void
00451 rt_tgc_scale(fastf_t a, fastf_t b, fastf_t h, fastf_t *Scl, fastf_t *Inv)
00452 {
00453         MAT_IDN( Scl );
00454         MAT_IDN( Inv );
00455         Scl[0]  /= a;
00456         Scl[5]  /= b;
00457         Scl[10] /= h;
00458         Inv[0]  = a;
00459         Inv[5]  = b;
00460         Inv[10] = h;
00461         return;
00462 }
00463 
00464 /**
00465  *                      R T _ T G C _ P R I N T
00466  */
00467 void
00468 rt_tgc_print(register const struct soltab *stp)
00469 {
00470         register const struct tgc_specific      *tgc =
00471         (struct tgc_specific *)stp->st_specific;
00472 
00473         VPRINT( "V", tgc->tgc_V );
00474         bu_log( "mag sheared H = %f\n", tgc->tgc_sH );
00475         bu_log( "mag A = %f\n", tgc->tgc_A );
00476         bu_log( "mag B = %f\n", tgc->tgc_B );
00477         bu_log( "mag C = %f\n", tgc->tgc_C );
00478         bu_log( "mag D = %f\n", tgc->tgc_D );
00479         VPRINT( "Top normal", tgc->tgc_N );
00480 
00481         bn_mat_print( "Sc o Sh o R", tgc->tgc_ScShR );
00482         bn_mat_print( "invR o trnSh o Sc", tgc->tgc_invRtShSc );
00483 
00484         if( tgc->tgc_AD_CB )  {
00485                 bu_log( "A*D == C*B.  Equal eccentricities gives quadratic equation.\n");
00486         } else {
00487                 bu_log( "A*D != C*B.  Quartic equation.\n");
00488         }
00489         bu_log( "(C/A - 1) = %f\n", tgc->tgc_CdAm1 );
00490         bu_log( "(D/B - 1) = %f\n", tgc->tgc_DdBm1 );
00491         bu_log( "(|A|**2)/(|C|**2) = %f\n", tgc->tgc_AAdCC );
00492         bu_log( "(|B|**2)/(|D|**2) = %f\n", tgc->tgc_BBdDD );
00493 }
00494 
00495 /* hit_surfno is set to one of these */
00496 #define TGC_NORM_BODY   (1)             /* compute normal */
00497 #define TGC_NORM_TOP    (2)             /* copy tgc_N */
00498 #define TGC_NORM_BOT    (3)             /* copy reverse tgc_N */
00499 
00500 /**
00501  *                      R T _ T G C _ S H O T
00502  *
00503  *  Intersect a ray with a truncated general cone, where all constant
00504  *  terms have been computed by rt_tgc_prep().
00505  *
00506  *  NOTE:  All lines in this function are represented parametrically
00507  *  by a point,  P( Px, Py, Pz ) and a unit direction vector,
00508  *  D = iDx + jDy + kDz.  Any point on a line can be expressed
00509  *  by one variable 't', where
00510  *
00511  *        X = Dx*t + Px,
00512  *        Y = Dy*t + Py,
00513  *        Z = Dz*t + Pz.
00514  *
00515  *  First, convert the line to the coordinate system of a "stan-
00516  *  dard" cone.  This is a cone whose base lies in the X-Y plane,
00517  *  and whose H (now H') vector is lined up with the Z axis.
00518  *
00519  *  Then find the equation of that line and the standard cone
00520  *  as an equation in 't'.  Solve the equation using a general
00521  *  polynomial root finder.  Use those values of 't' to compute
00522  *  the points of intersection in the original coordinate system.
00523  */
00524 int
00525 rt_tgc_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00526 {
00527         register const struct tgc_specific      *tgc =
00528         (struct tgc_specific *)stp->st_specific;
00529         register struct seg     *segp;
00530         LOCAL vect_t            pprime;
00531         LOCAL vect_t            dprime;
00532         LOCAL vect_t            work;
00533         LOCAL fastf_t           k[6];
00534         LOCAL int               hit_type[6];
00535         LOCAL fastf_t           t, b, zval, dir;
00536         LOCAL fastf_t           t_scale;
00537         LOCAL fastf_t           alf1, alf2;
00538         LOCAL int               npts;
00539         LOCAL int               intersect;
00540         LOCAL vect_t            cor_pprime;     /* corrected P prime */
00541         LOCAL fastf_t           cor_proj = 0;   /* corrected projected dist */
00542         LOCAL int               i;
00543         LOCAL bn_poly_t         C;      /*  final equation      */
00544         LOCAL bn_poly_t         Xsqr, Ysqr;
00545         LOCAL bn_poly_t         R, Rsqr;
00546 
00547         /* find rotated point and direction */
00548         MAT4X3VEC( dprime, tgc->tgc_ScShR, rp->r_dir );
00549 
00550         /*
00551          *  A vector of unit length in model space (r_dir) changes length in
00552          *  the special unit-tgc space.  This scale factor will restore
00553          *  proper length after hit points are found.
00554          */
00555         t_scale = MAGNITUDE(dprime);
00556         if( NEAR_ZERO( t_scale, SMALL_FASTF ) )  {
00557                 bu_log("tgc(%s) dprime=(%g,%g,%g), t_scale=%e, miss.\n",
00558                     V3ARGS(dprime), t_scale);
00559                 return 0;
00560         }
00561         t_scale = 1/t_scale;
00562         VSCALE( dprime, dprime, t_scale );      /* VUNITIZE( dprime ); */
00563 
00564         if( NEAR_ZERO( dprime[Z], RT_PCOEF_TOL ) )  {
00565                 dprime[Z] = 0.0;        /* prevent rootfinder heartburn */
00566         }
00567 
00568         VSUB2( work, rp->r_pt, tgc->tgc_V );
00569         MAT4X3VEC( pprime, tgc->tgc_ScShR, work );
00570 
00571         /* Translating ray origin along direction of ray to closest
00572          * pt. to origin of solids coordinate system, new ray origin
00573          * is 'cor_pprime'.
00574          */
00575         cor_proj = -VDOT( pprime, dprime );
00576         VJOIN1( cor_pprime, pprime, cor_proj, dprime );
00577 
00578         /*
00579          * The TGC is defined in "unit" space, so the parametric distance
00580          * from one side of the TGC to the other is on the order of 2.
00581          * Therefore, any vector/point coordinates that are very small
00582          * here may be considered to be zero,
00583          * since double precision only has 18 digits of significance.
00584          * If these tiny values were left in, then as they get
00585          * squared (below) they will cause difficulties.
00586          */
00587         for( i=0; i<3; i++ )  {
00588                 /* Direction cosines */
00589                 if( NEAR_ZERO( dprime[i], 1e-10 ) )  dprime[i] = 0;
00590                 /* Position in -1..+1 coordinates */
00591                 if( NEAR_ZERO( cor_pprime[i], 1e-20 ) )  cor_pprime[i] = 0;
00592         }
00593 
00594         /*
00595          *  Given a line and the parameters for a standard cone, finds
00596          *  the roots of the equation for that cone and line.
00597          *  Returns the number of real roots found.
00598          *
00599          *  Given a line and the cone parameters, finds the equation
00600          *  of the cone in terms of the variable 't'.
00601          *
00602          *  The equation for the cone is:
00603          *
00604          *      X**2 * Q**2  +  Y**2 * R**2  -  R**2 * Q**2 = 0
00605          *
00606          *  where       R = a + ((c - a)/|H'|)*Z
00607          *              Q = b + ((d - b)/|H'|)*Z
00608          *
00609          *  First, find X, Y, and Z in terms of 't' for this line, then
00610          *  substitute them into the equation above.
00611          *
00612          *  Express each variable (X, Y, and Z) as a linear equation
00613          *  in 'k', eg, (dprime[X] * k) + cor_pprime[X], and
00614          *  substitute into the cone equation.
00615          */
00616         Xsqr.dgr = 2;
00617         Xsqr.cf[0] = dprime[X] * dprime[X];
00618         Xsqr.cf[1] = 2.0 * dprime[X] * cor_pprime[X];
00619         Xsqr.cf[2] = cor_pprime[X] * cor_pprime[X];
00620 
00621         Ysqr.dgr = 2;
00622         Ysqr.cf[0] = dprime[Y] * dprime[Y];
00623         Ysqr.cf[1] = 2.0 * dprime[Y] * cor_pprime[Y];
00624         Ysqr.cf[2] = cor_pprime[Y] * cor_pprime[Y];
00625 
00626         R.dgr = 1;
00627         R.cf[0] = dprime[Z] * tgc->tgc_CdAm1;
00628         /* A vector is unitized (tgc->tgc_A == 1.0) */
00629         R.cf[1] = (cor_pprime[Z] * tgc->tgc_CdAm1) + 1.0;
00630 
00631         /* (void) rt_poly_mul( &R, &R, &Rsqr ); */
00632         Rsqr.dgr = 2;
00633         Rsqr.cf[0] = R.cf[0] * R.cf[0];
00634         Rsqr.cf[1] = R.cf[0] * R.cf[1] * 2;
00635         Rsqr.cf[2] = R.cf[1] * R.cf[1];
00636 
00637         /*
00638          *  If the eccentricities of the two ellipses are the same,
00639          *  then the cone equation reduces to a much simpler quadratic
00640          *  form.  Otherwise it is a (gah!) quartic equation.
00641          *
00642          *  this can only be done when C.cf[0] is not too small!!!! (JRA)
00643          */
00644         C.cf[0] = Xsqr.cf[0] + Ysqr.cf[0] - Rsqr.cf[0];
00645         if( tgc->tgc_AD_CB && !NEAR_ZERO( C.cf[0], 1.0e-10 )  ) {
00646                 FAST fastf_t roots;
00647 
00648                 /*
00649                  *  (void) rt_poly_add( &Xsqr, &Ysqr, &sum );
00650                  *  (void) rt_poly_sub( &sum, &Rsqr, &C );
00651                  */
00652                 C.dgr = 2;
00653                 C.cf[1] = Xsqr.cf[1] + Ysqr.cf[1] - Rsqr.cf[1];
00654                 C.cf[2] = Xsqr.cf[2] + Ysqr.cf[2] - Rsqr.cf[2];
00655 
00656                 /* Find the real roots the easy way.  C.dgr==2 */
00657                 if( (roots = C.cf[1]*C.cf[1] - 4 * C.cf[0] * C.cf[2]) < 0 ) {
00658                         npts = 0;       /* no real roots */
00659                 } else {
00660                         register fastf_t        f;
00661                         roots = sqrt(roots);
00662                         k[0] = (roots - C.cf[1]) * (f = 0.5 / C.cf[0]);
00663                         hit_type[0] = TGC_NORM_BODY;
00664                         k[1] = (roots + C.cf[1]) * -f;
00665                         hit_type[1] = TGC_NORM_BODY;
00666                         npts = 2;
00667                 }
00668         } else {
00669                 LOCAL bn_poly_t Q, Qsqr;
00670                 LOCAL bn_complex_t      val[4]; /* roots of final equation */
00671                 register int    l;
00672                 register int nroots;
00673 
00674                 Q.dgr = 1;
00675                 Q.cf[0] = dprime[Z] * tgc->tgc_DdBm1;
00676                 /* B vector is unitized (tgc->tgc_B == 1.0) */
00677                 Q.cf[1] = (cor_pprime[Z] * tgc->tgc_DdBm1) + 1.0;
00678 
00679                 /* (void) rt_poly_mul( &Q, &Q, &Qsqr ); */
00680                 Qsqr.dgr = 2;
00681                 Qsqr.cf[0] = Q.cf[0] * Q.cf[0];
00682                 Qsqr.cf[1] = Q.cf[0] * Q.cf[1] * 2;
00683                 Qsqr.cf[2] = Q.cf[1] * Q.cf[1];
00684 
00685                 /*
00686                  * (void) rt_poly_mul( &Qsqr, &Xsqr, &T1 );
00687                  * (void) rt_poly_mul( &Rsqr, &Ysqr, &T2 );
00688                  * (void) rt_poly_mul( &Rsqr, &Qsqr, &T3 );
00689                  * (void) rt_poly_add( &T1, &T2, &sum );
00690                  * (void) rt_poly_sub( &sum, &T3, &C );
00691                  */
00692                 C.dgr = 4;
00693                 C.cf[0] = Qsqr.cf[0] * Xsqr.cf[0] +
00694                     Rsqr.cf[0] * Ysqr.cf[0] -
00695                     (Rsqr.cf[0] * Qsqr.cf[0]);
00696                 C.cf[1] = Qsqr.cf[0] * Xsqr.cf[1] + Qsqr.cf[1] * Xsqr.cf[0] +
00697                     Rsqr.cf[0] * Ysqr.cf[1] + Rsqr.cf[1] * Ysqr.cf[0] -
00698                     (Rsqr.cf[0] * Qsqr.cf[1] + Rsqr.cf[1] * Qsqr.cf[0]);
00699                 C.cf[2] = Qsqr.cf[0] * Xsqr.cf[2] + Qsqr.cf[1] * Xsqr.cf[1] +
00700                     Qsqr.cf[2] * Xsqr.cf[0] +
00701                     Rsqr.cf[0] * Ysqr.cf[2] + Rsqr.cf[1] * Ysqr.cf[1] +
00702                     Rsqr.cf[2] * Ysqr.cf[0] -
00703                     (Rsqr.cf[0] * Qsqr.cf[2] + Rsqr.cf[1] * Qsqr.cf[1] +
00704                     Rsqr.cf[2] * Qsqr.cf[0]);
00705                 C.cf[3] = Qsqr.cf[1] * Xsqr.cf[2] + Qsqr.cf[2] * Xsqr.cf[1] +
00706                     Rsqr.cf[1] * Ysqr.cf[2] + Rsqr.cf[2] * Ysqr.cf[1] -
00707                     (Rsqr.cf[1] * Qsqr.cf[2] + Rsqr.cf[2] * Qsqr.cf[1]);
00708                 C.cf[4] = Qsqr.cf[2] * Xsqr.cf[2] +
00709                     Rsqr.cf[2] * Ysqr.cf[2] -
00710                     (Rsqr.cf[2] * Qsqr.cf[2]);
00711 
00712                 /*  The equation is 4th order, so we expect 0 to 4 roots */
00713                 nroots = rt_poly_roots( &C , val, stp->st_dp->d_namep );
00714 
00715                 /*  Only real roots indicate an intersection in real space.
00716                  *
00717                  *  Look at each root returned; if the imaginary part is zero
00718                  *  or sufficiently close, then use the real part as one value
00719                  *  of 't' for the intersections
00720                  */
00721                 for ( l=0, npts=0; l < nroots; l++ ){
00722                         if ( NEAR_ZERO( val[l].im, 1e-10 ) ) {
00723                                 hit_type[npts] = TGC_NORM_BODY;
00724                                 k[npts++] = val[l].re;
00725                         }
00726                 }
00727                 /* Here, 'npts' is number of points being returned */
00728                 if ( npts != 0 && npts != 2 && npts != 4 && npts > 0 ){
00729                         bu_log("tgc:  reduced %d to %d roots\n",nroots,npts);
00730                         bn_pr_roots( stp->st_name, val, nroots );
00731                 } else if (nroots < 0) {
00732                     static int reported=0;
00733                     bu_log("The root solver failed to converge on a solution for %s\n", stp->st_dp->d_namep);
00734                     if (!reported) {
00735                         VPRINT("while shooting from:\t", rp->r_pt);
00736                         VPRINT("while shooting at:\t", rp->r_dir);
00737                         bu_log("Additional truncated general cone convergence failure details will be suppressed.\n");
00738                         reported=1;
00739                     }
00740                 }
00741         }
00742 
00743         /*
00744          * Reverse above translation by adding distance to all 'k' values.
00745          */
00746         for( i = 0; i < npts; ++i )  {
00747                 k[i] += cor_proj;
00748         }
00749 
00750         /*
00751          * Eliminate hits beyond the end planes
00752          */
00753         i = 0;
00754         while( i < npts ) {
00755                 zval = k[i]*dprime[Z] + pprime[Z];
00756                 /* Height vector is unitized (tgc->tgc_sH == 1.0) */
00757                 if ( zval >= 1.0 || zval <= 0.0 ){
00758                         int j;
00759                         /* drop this hit */
00760                         npts--;
00761                         for( j=i ; j<npts ; j++ ) {
00762                                 hit_type[j] = hit_type[j+1];
00763                                 k[j] = k[j+1];
00764                         }
00765                 } else {
00766                         i++;
00767                 }
00768         }
00769 
00770         /*
00771          * Consider intersections with the end ellipses
00772          */
00773         dir = VDOT( tgc->tgc_N, rp->r_dir );
00774         if( !NEAR_ZERO( dprime[Z], SMALL_FASTF ) && !NEAR_ZERO( dir, RT_DOT_TOL ) )  {
00775                 b = ( -pprime[Z] )/dprime[Z];
00776                 /*  Height vector is unitized (tgc->tgc_sH == 1.0) */
00777                 t = ( 1.0 - pprime[Z] )/dprime[Z];
00778 
00779                 VJOIN1( work, pprime, b, dprime );
00780                 /* A and B vectors are unitized (tgc->tgc_A == _B == 1.0) */
00781                 /* alf1 = ALPHA(work[X], work[Y], 1.0, 1.0 ) */
00782                 alf1 = work[X]*work[X] + work[Y]*work[Y];
00783 
00784                 VJOIN1( work, pprime, t, dprime );
00785 
00786                 /* Must scale C and D vectors */
00787                 alf2 = ALPHA(work[X], work[Y], tgc->tgc_AAdCC,tgc->tgc_BBdDD);
00788 
00789                 if ( alf1 <= 1.0 ){
00790                         hit_type[npts] = TGC_NORM_BOT;
00791                         k[npts++] = b;
00792                 }
00793                 if ( alf2 <= 1.0 ){
00794                         hit_type[npts] = TGC_NORM_TOP;
00795                         k[npts++] = t;
00796                 }
00797         }
00798 
00799 
00800         /* Sort Most distant to least distant: rt_pt_sort( k, npts ) */
00801         {
00802                 register fastf_t        u;
00803                 register short          lim, n;
00804                 register int            type;
00805 
00806                 for( lim = npts-1; lim > 0; lim-- )  {
00807                         for( n = 0; n < lim; n++ )  {
00808                                 if( (u=k[n]) < k[n+1] )  {
00809                                         /* bubble larger towards [0] */
00810                                         type = hit_type[n];
00811                                         hit_type[n] = hit_type[n+1];
00812                                         hit_type[n+1] = type;
00813                                         k[n] = k[n+1];
00814                                         k[n+1] = u;
00815                                 }
00816                         }
00817                 }
00818         }
00819         /* Now, k[0] > k[npts-1] */
00820 
00821         if( npts%2 ) {
00822                 /* odd number of hits!!!
00823                  * perhaps we got two hits on an edge
00824                  * check for duplicate hit distances
00825                  */
00826 
00827                 for( i=npts-1 ; i>0 ; i-- ) {
00828                         fastf_t diff;
00829 
00830                         diff = k[i-1] - k[i];   /* non-negative due to sorting */
00831                         if( diff < ap->a_rt_i->rti_tol.dist ) {
00832                                 /* remove this duplicate hit */
00833                                 int j;
00834 
00835                                 npts--;
00836                                 for( j=i ; j<npts ; j++ ) {
00837                                         hit_type[j] = hit_type[j+1];
00838                                         k[j] = k[j+1];
00839                                 }
00840 
00841                                 /* now have even number of hits */
00842                                 break;
00843                         }
00844                 }
00845         }
00846 
00847         if ( npts != 0 && npts != 2 && npts != 4 ){
00848                 bu_log("tgc(%s):  %d intersects != {0,2,4}\n",
00849                     stp->st_name, npts );
00850                 bu_log( "\tray: pt = (%g %g %g), dir = (%g %g %g)\n",
00851                         V3ARGS( ap->a_ray.r_pt ),
00852                         V3ARGS( ap->a_ray.r_dir ) );
00853                 for( i=0 ; i<npts ; i++ ) {
00854                         bu_log( "\t%g", k[i]*t_scale );
00855                 }
00856                 bu_log( "\n" );
00857                 return(0);                      /* No hit */
00858         }
00859 
00860         intersect = 0;
00861         for( i=npts-1 ; i>0 ; i -= 2 ) {
00862                 RT_GET_SEG( segp, ap->a_resource );
00863                 segp->seg_stp = stp;
00864 
00865                 segp->seg_in.hit_dist = k[i] * t_scale;
00866                 segp->seg_in.hit_surfno = hit_type[i];
00867                 if( segp->seg_in.hit_surfno == TGC_NORM_BODY ) {
00868                         VJOIN1( segp->seg_in.hit_vpriv, pprime, k[i], dprime );
00869                 } else {
00870                         if( dir > 0.0 ) {
00871                                 segp->seg_in.hit_surfno = TGC_NORM_BOT;
00872                         } else {
00873                                 segp->seg_in.hit_surfno = TGC_NORM_TOP;
00874                         }
00875                 }
00876 
00877                 segp->seg_out.hit_dist = k[i-1] * t_scale;
00878                 segp->seg_out.hit_surfno = hit_type[i-1];
00879                 if( segp->seg_out.hit_surfno == TGC_NORM_BODY ) {
00880                         VJOIN1( segp->seg_out.hit_vpriv, pprime, k[i-1], dprime );
00881                 } else {
00882                         if( dir > 0.0 ) {
00883                                 segp->seg_out.hit_surfno = TGC_NORM_TOP;
00884                         } else {
00885                                 segp->seg_out.hit_surfno = TGC_NORM_BOT;
00886                         }
00887                 }
00888                 intersect++;
00889                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00890         }
00891 
00892         return( intersect );
00893 }
00894 
00895 #define RT_TGC_SEG_MISS(SEG)    (SEG).seg_stp=RT_SOLTAB_NULL
00896 
00897 /**
00898  *                      R T _ T G C _ V S H O T
00899  *
00900  *  The Homer vectorized version.
00901  */
00902 void
00903 rt_tgc_vshot(struct soltab **stp, register struct xray **rp, struct seg *segp, int n, struct application *ap)
00904 
00905 
00906                                /* array of segs (results returned) */
00907                                /* Number of ray/object pairs */
00908 
00909 {
00910         register struct tgc_specific    *tgc;
00911         register int            ix;
00912         LOCAL vect_t            pprime;
00913         LOCAL vect_t            dprime;
00914         LOCAL vect_t            work;
00915         LOCAL fastf_t           k[4], pt[2];
00916         LOCAL fastf_t           t, b, zval, dir;
00917         LOCAL fastf_t           t_scale = 0;
00918         LOCAL fastf_t           alf1, alf2;
00919         LOCAL int               npts;
00920         LOCAL int               intersect;
00921         LOCAL vect_t            cor_pprime;     /* corrected P prime */
00922         LOCAL fastf_t           cor_proj = 0;   /* corrected projected dist */
00923         LOCAL int               i;
00924         LOCAL bn_poly_t         *C;     /*  final equation      */
00925         LOCAL bn_poly_t         Xsqr, Ysqr;
00926         LOCAL bn_poly_t         R, Rsqr;
00927 
00928         /* Allocate space for polys and roots */
00929         C = (bn_poly_t *)bu_malloc(n * sizeof(bn_poly_t), "tor bn_poly_t");
00930 
00931         /* Initialize seg_stp to assume hit (zero will then flag miss) */
00932 #       include "noalias.h"
00933         for(ix = 0; ix < n; ix++) segp[ix].seg_stp = stp[ix];
00934 
00935         /* for each ray/cone pair */
00936 #   include "noalias.h"
00937         for(ix = 0; ix < n; ix++) {
00938 
00939 #if !CRAY       /* XXX currently prevents vectorization on cray */
00940                 if (segp[ix].seg_stp == 0) continue; /* == 0 signals skip ray */
00941 #endif
00942 
00943                 tgc = (struct tgc_specific *)stp[ix]->st_specific;
00944 
00945                 /* find rotated point and direction */
00946                 MAT4X3VEC( dprime, tgc->tgc_ScShR, rp[ix]->r_dir );
00947 
00948                 /*
00949          *  A vector of unit length in model space (r_dir) changes length in
00950          *  the special unit-tgc space.  This scale factor will restore
00951          *  proper length after hit points are found.
00952          */
00953                 t_scale = 1/MAGNITUDE( dprime );
00954                 VSCALE( dprime, dprime, t_scale );      /* VUNITIZE( dprime ); */
00955 
00956                 if( NEAR_ZERO( dprime[Z], RT_PCOEF_TOL ) )
00957                         dprime[Z] = 0.0;        /* prevent rootfinder heartburn */
00958 
00959                 /* Use segp[ix].seg_in.hit_normal as tmp to hold dprime */
00960                 VMOVE( segp[ix].seg_in.hit_normal, dprime );
00961 
00962                 VSUB2( work, rp[ix]->r_pt, tgc->tgc_V );
00963                 MAT4X3VEC( pprime, tgc->tgc_ScShR, work );
00964 
00965                 /* Use segp[ix].seg_out.hit_normal as tmp to hold pprime */
00966                 VMOVE( segp[ix].seg_out.hit_normal, pprime );
00967 
00968                 /* Translating ray origin along direction of ray to closest
00969          * pt. to origin of solids coordinate system, new ray origin
00970          * is 'cor_pprime'.
00971          */
00972                 cor_proj = VDOT( pprime, dprime );
00973                 VSCALE( cor_pprime, dprime, cor_proj );
00974                 VSUB2( cor_pprime, pprime, cor_pprime );
00975 
00976                 /*
00977          *  Given a line and the parameters for a standard cone, finds
00978          *  the roots of the equation for that cone and line.
00979          *  Returns the number of real roots found.
00980          *
00981          *  Given a line and the cone parameters, finds the equation
00982          *  of the cone in terms of the variable 't'.
00983          *
00984          *  The equation for the cone is:
00985          *
00986          *      X**2 * Q**2  +  Y**2 * R**2  -  R**2 * Q**2 = 0
00987          *
00988          *  where       R = a + ((c - a)/|H'|)*Z
00989          *              Q = b + ((d - b)/|H'|)*Z
00990          *
00991          *  First, find X, Y, and Z in terms of 't' for this line, then
00992          *  substitute them into the equation above.
00993          *
00994          *  Express each variable (X, Y, and Z) as a linear equation
00995          *  in 'k', eg, (dprime[X] * k) + cor_pprime[X], and
00996          *  substitute into the cone equation.
00997          */
00998                 Xsqr.dgr = 2;
00999                 Xsqr.cf[0] = dprime[X] * dprime[X];
01000                 Xsqr.cf[1] = 2.0 * dprime[X] * cor_pprime[X];
01001                 Xsqr.cf[2] = cor_pprime[X] * cor_pprime[X];
01002 
01003                 Ysqr.dgr = 2;
01004                 Ysqr.cf[0] = dprime[Y] * dprime[Y];
01005                 Ysqr.cf[1] = 2.0 * dprime[Y] * cor_pprime[Y];
01006                 Ysqr.cf[2] = cor_pprime[Y] * cor_pprime[Y];
01007 
01008                 R.dgr = 1;
01009                 R.cf[0] = dprime[Z] * tgc->tgc_CdAm1;
01010                 /* A vector is unitized (tgc->tgc_A == 1.0) */
01011                 R.cf[1] = (cor_pprime[Z] * tgc->tgc_CdAm1) + 1.0;
01012 
01013                 /* (void) rt_poly_mul( &R, &R, &Rsqr ); inline expands to: */
01014                 Rsqr.dgr = 2;
01015                 Rsqr.cf[0] = R.cf[0] * R.cf[0];
01016                 Rsqr.cf[1] = R.cf[0] * R.cf[1] * 2;
01017                 Rsqr.cf[2] = R.cf[1] * R.cf[1];
01018 
01019                 /*
01020          *  If the eccentricities of the two ellipses are the same,
01021          *  then the cone equation reduces to a much simpler quadratic
01022          *  form.  Otherwise it is a (gah!) quartic equation.
01023          */
01024                 if ( tgc->tgc_AD_CB ){
01025                         /* (void) rt_poly_add( &Xsqr, &Ysqr, &sum ); and */
01026                         /* (void) rt_poly_sub( &sum, &Rsqr, &C ); inline expand to */
01027                         C[ix].dgr = 2;
01028                         C[ix].cf[0] = Xsqr.cf[0] + Ysqr.cf[0] - Rsqr.cf[0];
01029                         C[ix].cf[1] = Xsqr.cf[1] + Ysqr.cf[1] - Rsqr.cf[1];
01030                         C[ix].cf[2] = Xsqr.cf[2] + Ysqr.cf[2] - Rsqr.cf[2];
01031                 } else {
01032                         LOCAL bn_poly_t Q, Qsqr;
01033 
01034                         Q.dgr = 1;
01035                         Q.cf[0] = dprime[Z] * tgc->tgc_DdBm1;
01036                         /* B vector is unitized (tgc->tgc_B == 1.0) */
01037                         Q.cf[1] = (cor_pprime[Z] * tgc->tgc_DdBm1) + 1.0;
01038 
01039                         /* (void) rt_poly_mul( &Q, &Q, &Qsqr ); inline expands to */
01040                         Qsqr.dgr = 2;
01041                         Qsqr.cf[0] = Q.cf[0] * Q.cf[0];
01042                         Qsqr.cf[1] = Q.cf[0] * Q.cf[1] * 2;
01043                         Qsqr.cf[2] = Q.cf[1] * Q.cf[1];
01044 
01045                         /* (void) rt_poly_mul( &Qsqr, &Xsqr, &T1 ); inline expands to */
01046                         C[ix].dgr = 4;
01047                         C[ix].cf[0] = Qsqr.cf[0] * Xsqr.cf[0];
01048                         C[ix].cf[1] = Qsqr.cf[0] * Xsqr.cf[1] +
01049                             Qsqr.cf[1] * Xsqr.cf[0];
01050                         C[ix].cf[2] = Qsqr.cf[0] * Xsqr.cf[2] +
01051                             Qsqr.cf[1] * Xsqr.cf[1] +
01052                             Qsqr.cf[2] * Xsqr.cf[0];
01053                         C[ix].cf[3] = Qsqr.cf[1] * Xsqr.cf[2] +
01054                             Qsqr.cf[2] * Xsqr.cf[1];
01055                         C[ix].cf[4] = Qsqr.cf[2] * Xsqr.cf[2];
01056 
01057                         /* (void) rt_poly_mul( &Rsqr, &Ysqr, &T2 ); and */
01058                         /* (void) rt_poly_add( &T1, &T2, &sum ); inline expand to */
01059                         C[ix].cf[0] += Rsqr.cf[0] * Ysqr.cf[0];
01060                         C[ix].cf[1] += Rsqr.cf[0] * Ysqr.cf[1] +
01061                             Rsqr.cf[1] * Ysqr.cf[0];
01062                         C[ix].cf[2] += Rsqr.cf[0] * Ysqr.cf[2] +
01063                             Rsqr.cf[1] * Ysqr.cf[1] +
01064                             Rsqr.cf[2] * Ysqr.cf[0];
01065                         C[ix].cf[3] += Rsqr.cf[1] * Ysqr.cf[2] +
01066                             Rsqr.cf[2] * Ysqr.cf[1];
01067                         C[ix].cf[4] += Rsqr.cf[2] * Ysqr.cf[2];
01068 
01069                         /* (void) rt_poly_mul( &Rsqr, &Qsqr, &T3 ); and */
01070                         /* (void) rt_poly_sub( &sum, &T3, &C ); inline expand to */
01071                         C[ix].cf[0] -= Rsqr.cf[0] * Qsqr.cf[0];
01072                         C[ix].cf[1] -= Rsqr.cf[0] * Qsqr.cf[1] +
01073                             Rsqr.cf[1] * Qsqr.cf[0];
01074                         C[ix].cf[2] -= Rsqr.cf[0] * Qsqr.cf[2] +
01075                             Rsqr.cf[1] * Qsqr.cf[1] +
01076                             Rsqr.cf[2] * Qsqr.cf[0];
01077                         C[ix].cf[3] -= Rsqr.cf[1] * Qsqr.cf[2] +
01078                             Rsqr.cf[2] * Qsqr.cf[1];
01079                         C[ix].cf[4] -= Rsqr.cf[2] * Qsqr.cf[2];
01080                 }
01081 
01082         }
01083 
01084         /* It seems impractical to try to vectorize finding and sorting roots. */
01085         for(ix = 0; ix < n; ix++){
01086                 if (segp[ix].seg_stp == 0) continue; /* == 0 signals skip ray */
01087 
01088                 /* Again, check for the equal eccentricities case. */
01089                 if ( C[ix].dgr == 2 ){
01090                         FAST fastf_t roots;
01091 
01092                         /* Find the real roots the easy way. */
01093                         if( (roots = C[ix].cf[1]*C[ix].cf[1]-4*C[ix].cf[0]*C[ix].cf[2]
01094                             ) < 0 ) {
01095                                 npts = 0;       /* no real roots */
01096                         } else {
01097                                 roots = sqrt(roots);
01098                                 k[0] = (roots - C[ix].cf[1]) * 0.5 / C[ix].cf[0];
01099                                 k[1] = (roots + C[ix].cf[1]) * (-0.5) / C[ix].cf[0];
01100                                 npts = 2;
01101                         }
01102                 } else {
01103                         LOCAL bn_complex_t      val[4]; /* roots of final equation */
01104                         register int    l;
01105                         register int nroots;
01106 
01107                         /*  The equation is 4th order, so we expect 0 to 4 roots */
01108                         nroots = rt_poly_roots( &C[ix] , val, (*stp)->st_dp->d_namep );
01109 
01110                         /*  Only real roots indicate an intersection in real space.
01111                  *
01112                  *  Look at each root returned; if the imaginary part is zero
01113                  *  or sufficiently close, then use the real part as one value
01114                  *  of 't' for the intersections
01115                  */
01116                         for ( l=0, npts=0; l < nroots; l++ ){
01117                                 if ( NEAR_ZERO( val[l].im, 0.0001 ) )
01118                                         k[npts++] = val[l].re;
01119                         }
01120                         /* Here, 'npts' is number of points being returned */
01121                         if ( npts != 0 && npts != 2 && npts != 4 && npts > 0 ){
01122                                 bu_log("tgc:  reduced %d to %d roots\n",nroots,npts);
01123                                 bn_pr_roots( "tgc", val, nroots );
01124                         } else if (nroots < 0) {
01125                             static int reported=0;
01126                             bu_log("The root solver failed to converge on a solution for %s\n", stp[ix]->st_dp->d_namep);
01127                             if (!reported) {
01128                                 VPRINT("while shooting from:\t", rp[ix]->r_pt);
01129                                 VPRINT("while shooting at:\t", rp[ix]->r_dir);
01130                                 bu_log("Additional truncated general cone convergence failure details will be suppressed.\n");
01131                                 reported=1;
01132                             }
01133                         }
01134                 }
01135 
01136                 /*
01137          * Reverse above translation by adding distance to all 'k' values.
01138          */
01139                 for( i = 0; i < npts; ++i )
01140                         k[i] -= cor_proj;
01141 
01142                 if ( npts != 0 && npts != 2 && npts != 4 ){
01143                         bu_log("tgc(%s):  %d intersects != {0,2,4}\n",
01144                             stp[ix]->st_name, npts );
01145                         RT_TGC_SEG_MISS(segp[ix]);              /* No hit       */
01146                         continue;
01147                 }
01148 
01149                 /* Most distant to least distant        */
01150                 rt_pt_sort( k, npts );
01151 
01152                 /* Now, k[0] > k[npts-1] */
01153 
01154                 /* General Cone may have 4 intersections, but   *
01155          * Truncated Cone may only have 2.              */
01156 
01157 #define OUT             0
01158 #define IN              1
01159 
01160                 /*              Truncation Procedure
01161          *
01162          *  Determine whether any of the intersections found are
01163          *  between the planes truncating the cone.
01164          */
01165                 intersect = 0;
01166                 tgc = (struct tgc_specific *)stp[ix]->st_specific;
01167                 for ( i=0; i < npts; i++ ){
01168                         /* segp[ix].seg_in.hit_normal holds dprime */
01169                         /* segp[ix].seg_out.hit_normal holds pprime */
01170                         zval = k[i]*segp[ix].seg_in.hit_normal[Z] +
01171                             segp[ix].seg_out.hit_normal[Z];
01172                         /* Height vector is unitized (tgc->tgc_sH == 1.0) */
01173                         if ( zval < 1.0 && zval > 0.0 ){
01174                                 if ( ++intersect == 2 )  {
01175                                         pt[IN] = k[i];
01176                                 }  else
01177                                         pt[OUT] = k[i];
01178                         }
01179                 }
01180                 /* Reuse C to hold values of intersect and k. */
01181                 C[ix].dgr = intersect;
01182                 C[ix].cf[OUT] = pt[OUT];
01183                 C[ix].cf[IN]  = pt[IN];
01184         }
01185 
01186         /* for each ray/cone pair */
01187 #   include "noalias.h"
01188         for(ix = 0; ix < n; ix++) {
01189                 if (segp[ix].seg_stp == 0) continue; /* Skip */
01190 
01191                 tgc = (struct tgc_specific *)stp[ix]->st_specific;
01192                 intersect = C[ix].dgr;
01193                 pt[OUT] = C[ix].cf[OUT];
01194                 pt[IN]  = C[ix].cf[IN];
01195                 /* segp[ix].seg_out.hit_normal holds pprime */
01196                 VMOVE( pprime, segp[ix].seg_out.hit_normal );
01197                 /* segp[ix].seg_in.hit_normal holds dprime */
01198                 VMOVE( dprime, segp[ix].seg_in.hit_normal );
01199 
01200                 if ( intersect == 2 ){
01201                         /*  If two between-plane intersections exist, they are
01202                  *  the hit points for the ray.
01203                  */
01204                         segp[ix].seg_in.hit_dist = pt[IN] * t_scale;
01205                         segp[ix].seg_in.hit_surfno = TGC_NORM_BODY;     /* compute N */
01206                         VJOIN1( segp[ix].seg_in.hit_vpriv, pprime, pt[IN], dprime );
01207 
01208                         segp[ix].seg_out.hit_dist = pt[OUT] * t_scale;
01209                         segp[ix].seg_out.hit_surfno = TGC_NORM_BODY;    /* compute N */
01210                         VJOIN1( segp[ix].seg_out.hit_vpriv, pprime, pt[OUT], dprime );
01211                 } else if ( intersect == 1 ) {
01212                         int     nflag;
01213                         /*
01214                  *  If only one between-plane intersection exists (pt[OUT]),
01215                  *  then the other intersection must be on
01216                  *  one of the planar surfaces (pt[IN]).
01217                  *
01218                  *  Find which surface it lies on by calculating the
01219                  *  X and Y values of the line as it intersects each
01220                  *  plane (in the standard coordinate system), and test
01221                  *  whether this lies within the governing ellipse.
01222                  */
01223                         if( dprime[Z] == 0.0 )  {
01224 #if 0
01225                                 bu_log("tgc: dprime[Z] = 0!\n" );
01226 #endif
01227                                 RT_TGC_SEG_MISS(segp[ix]);
01228                                 continue;
01229                         }
01230                         b = ( -pprime[Z] )/dprime[Z];
01231                         /*  Height vector is unitized (tgc->tgc_sH == 1.0) */
01232                         t = ( 1.0 - pprime[Z] )/dprime[Z];
01233 
01234                         VJOIN1( work, pprime, b, dprime );
01235                         /* A and B vectors are unitized (tgc->tgc_A == _B == 1.0) */
01236                         /* alf1 = ALPHA(work[X], work[Y], 1.0, 1.0 ) */
01237                         alf1 = work[X]*work[X] + work[Y]*work[Y];
01238 
01239                         VJOIN1( work, pprime, t, dprime );
01240                         /* Must scale C and D vectors */
01241                         alf2 = ALPHA(work[X], work[Y], tgc->tgc_AAdCC,tgc->tgc_BBdDD);
01242 
01243                         if ( alf1 <= 1.0 ){
01244                                 pt[IN] = b;
01245                                 nflag = TGC_NORM_BOT; /* copy reverse normal */
01246                         } else if ( alf2 <= 1.0 ){
01247                                 pt[IN] = t;
01248                                 nflag = TGC_NORM_TOP;   /* copy normal */
01249                         } else {
01250                                 /* intersection apparently invalid  */
01251 #if 0
01252                                 bu_log("tgc(%s):  only 1 intersect\n", stp[ix]->st_name);
01253 #endif
01254                                 RT_TGC_SEG_MISS(segp[ix]);
01255                                 continue;
01256                         }
01257 
01258                         /* pt[OUT] on skin, pt[IN] on end */
01259                         if ( pt[OUT] >= pt[IN] )  {
01260                                 segp[ix].seg_in.hit_dist = pt[IN] * t_scale;
01261                                 segp[ix].seg_in.hit_surfno = nflag;
01262 
01263                                 segp[ix].seg_out.hit_dist = pt[OUT] * t_scale;
01264                                 segp[ix].seg_out.hit_surfno = TGC_NORM_BODY;    /* compute N */
01265                                 /* transform-space vector needed for normal */
01266                                 VJOIN1( segp[ix].seg_out.hit_vpriv, pprime, pt[OUT], dprime );
01267                         } else {
01268                                 segp[ix].seg_in.hit_dist = pt[OUT] * t_scale;
01269                                 /* transform-space vector needed for normal */
01270                                 segp[ix].seg_in.hit_surfno = TGC_NORM_BODY;     /* compute N */
01271                                 VJOIN1( segp[ix].seg_in.hit_vpriv, pprime, pt[OUT], dprime );
01272 
01273                                 segp[ix].seg_out.hit_dist = pt[IN] * t_scale;
01274                                 segp[ix].seg_out.hit_surfno = nflag;
01275                         }
01276                 } else {
01277 
01278                         /*  If all conic interections lie outside the plane,
01279          *  then check to see whether there are two planar
01280          *  intersections inside the governing ellipses.
01281          *
01282          *  But first, if the direction is parallel (or nearly
01283          *  so) to the planes, it (obviously) won't intersect
01284          *  either of them.
01285          */
01286                         if( dprime[Z] == 0.0 ) {
01287                                 RT_TGC_SEG_MISS(segp[ix]);
01288                                 continue;
01289                         }
01290 
01291                         dir = VDOT( tgc->tgc_N, rp[ix]->r_dir );        /* direc */
01292                         if ( NEAR_ZERO( dir, RT_DOT_TOL ) ) {
01293                                 RT_TGC_SEG_MISS(segp[ix]);
01294                                 continue;
01295                         }
01296 
01297                         b = ( -pprime[Z] )/dprime[Z];
01298                         /* Height vector is unitized (tgc->tgc_sH == 1.0) */
01299                         t = ( 1.0 - pprime[Z] )/dprime[Z];
01300 
01301                         VJOIN1( work, pprime, b, dprime );
01302                         /* A and B vectors are unitized (tgc->tgc_A == _B == 1.0) */
01303                         /* alpf = ALPHA(work[0], work[1], 1.0, 1.0 ) */
01304                         alf1 = work[X]*work[X] + work[Y]*work[Y];
01305 
01306                         VJOIN1( work, pprime, t, dprime );
01307                         /* Must scale C and D vectors. */
01308                         alf2 = ALPHA(work[X], work[Y], tgc->tgc_AAdCC,tgc->tgc_BBdDD);
01309 
01310                         /*  It should not be possible for one planar intersection
01311          *  to be outside its ellipse while the other is inside ...
01312          *  but I wouldn't take any chances.
01313          */
01314                         if ( alf1 > 1.0 || alf2 > 1.0 ) {
01315                                 RT_TGC_SEG_MISS(segp[ix]);
01316                                 continue;
01317                         }
01318 
01319                         /*  Use the dot product (found earlier) of the plane
01320          *  normal with the direction vector to determine the
01321          *  orientation of the intersections.
01322          */
01323                         if ( dir > 0.0 ){
01324                                 segp[ix].seg_in.hit_dist = b * t_scale;
01325                                 segp[ix].seg_in.hit_surfno = TGC_NORM_BOT;      /* reverse normal */
01326 
01327                                 segp[ix].seg_out.hit_dist = t * t_scale;
01328                                 segp[ix].seg_out.hit_surfno = TGC_NORM_TOP;     /* normal */
01329                         } else {
01330                                 segp[ix].seg_in.hit_dist = t * t_scale;
01331                                 segp[ix].seg_in.hit_surfno = TGC_NORM_TOP;      /* normal */
01332 
01333                                 segp[ix].seg_out.hit_dist = b * t_scale;
01334                                 segp[ix].seg_out.hit_surfno = TGC_NORM_BOT;     /* reverse normal */
01335                         }
01336                 }
01337         } /* end for each ray/cone pair */
01338         bu_free( (char *)C, "tor bn_poly_t" );
01339 }
01340 
01341 /**
01342  *                      R T _ P T _ S O R T
01343  *
01344  *  Sorts the values in t[] in descending order.
01345  */
01346 void
01347 rt_pt_sort(register fastf_t t[], int npts)
01348 {
01349         FAST fastf_t    u;
01350         register short  lim, n;
01351 
01352         for( lim = npts-1; lim > 0; lim-- )  {
01353                 for( n = 0; n < lim; n++ )  {
01354                         if( (u=t[n]) < t[n+1] )  {
01355                                 /* bubble larger towards [0] */
01356                                 t[n] = t[n+1];
01357                                 t[n+1] = u;
01358                         }
01359                 }
01360         }
01361 }
01362 
01363 
01364 /**
01365  *                      R T _ T G C _ N O R M
01366  *
01367  *  Compute the normal to the cone, given a point on the STANDARD
01368  *  CONE centered at the origin of the X-Y plane.
01369  *
01370  *  The gradient of the cone at that point is the normal vector in
01371  *  the standard space.  This vector will need to be transformed
01372  *  back to the coordinate system of the original cone in order
01373  *  to be useful.  Then the transformed vector must be 'unitized.'
01374  *
01375  *  NOTE:  The transformation required is NOT the inverse of the of
01376  *         the rotation to the standard cone, due to the shear involved
01377  *         in the mapping.  The inverse maps points back to points,
01378  *         but it is the transpose which maps normals back to normals.
01379  *         If you really want to know why, talk to Ed Davisson or
01380  *         Peter Stiller.
01381  *
01382  *  The equation for the standard cone *without* scaling is:
01383  *  (rotated the sheared)
01384  *
01385  *      f(X,Y,Z) =  X**2 * Q**2  +  Y**2 * R**2  -  R**2 * Q**2 = 0
01386  *
01387  *  where,
01388  *              R = a + ((c - a)/|H'|)*Z
01389  *              Q = b + ((d - b)/|H'|)*Z
01390  *
01391  *  When the equation is scaled so the A, B, and the sheared H are
01392  *  unit length, as is done here, the equation can be coerced back
01393  *  into this same form with R and Q now being:
01394  *
01395  *              R = 1 + (c/a - 1)*Z
01396  *              Q = 1 + (d/b - 1)*Z
01397  *
01398  *  The gradient of f(x,y,z) = 0 is:
01399  *
01400  *      df/dx = 2 * x * Q**2
01401  *      df/dy = 2 * y * R**2
01402  *      df/dz = x**2 * 2 * Q * dQ/dz + y**2 * 2 * R * dR/dz
01403  *            - R**2 * 2 * Q * dQ/dz - Q**2 * 2 * R * dR/dz
01404  *            = 2 [(x**2 - R**2) * Q * dQ/dz + (y**2 - Q**2) * R * dR/dz]
01405  *
01406  *  where,
01407  *              dR/dz = (c/a - 1)
01408  *              dQ/dz = (d/b - 1)
01409  *
01410  *  [in the *unscaled* case these would be (c - a)/|H'| and (d - b)/|H'|]
01411  *  Since the gradient (normal) needs to be rescaled to unit length
01412  *  after mapping back to absolute coordinates, we divide the 2 out of
01413  *  the above expressions.
01414  */
01415 void
01416 rt_tgc_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
01417 {
01418         register struct tgc_specific    *tgc =
01419         (struct tgc_specific *)stp->st_specific;
01420         FAST fastf_t    Q;
01421         FAST fastf_t    R;
01422         LOCAL vect_t    stdnorm;
01423 
01424         /* Hit point */
01425         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
01426 
01427         /* Hits on the end plates are easy */
01428         switch( hitp->hit_surfno )  {
01429         case TGC_NORM_TOP:
01430                 VMOVE( hitp->hit_normal, tgc->tgc_N );
01431                 break;
01432         case TGC_NORM_BOT:
01433                 VREVERSE( hitp->hit_normal, tgc->tgc_N );
01434                 break;
01435         case TGC_NORM_BODY:
01436                 /* Compute normal, given hit point on standard (unit) cone */
01437                 R = 1 + tgc->tgc_CdAm1 * hitp->hit_vpriv[Z];
01438                 Q = 1 + tgc->tgc_DdBm1 * hitp->hit_vpriv[Z];
01439                 stdnorm[X] = hitp->hit_vpriv[X] * Q * Q;
01440                 stdnorm[Y] = hitp->hit_vpriv[Y] * R * R;
01441                 stdnorm[Z] = (hitp->hit_vpriv[X]*hitp->hit_vpriv[X] - R*R)
01442                     * Q * tgc->tgc_DdBm1
01443                     + (hitp->hit_vpriv[Y]*hitp->hit_vpriv[Y] - Q*Q)
01444                     * R * tgc->tgc_CdAm1;
01445                 MAT4X3VEC( hitp->hit_normal, tgc->tgc_invRtShSc, stdnorm );
01446                 /*XXX - save scale */
01447                 VUNITIZE( hitp->hit_normal );
01448                 break;
01449         default:
01450                 bu_log("rt_tgc_norm: bad surfno=%d\n", hitp->hit_surfno);
01451                 break;
01452         }
01453 }
01454 
01455 /**
01456  *                      R T _ T G C _ U V
01457  */
01458 void
01459 rt_tgc_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
01460 {
01461         register struct tgc_specific    *tgc =
01462         (struct tgc_specific *)stp->st_specific;
01463         LOCAL vect_t work;
01464         LOCAL vect_t pprime;
01465         FAST fastf_t len;
01466 
01467         /* hit_point is on surface;  project back to unit cylinder,
01468          * creating a vector from vertex to hit point.
01469          */
01470         VSUB2( work, hitp->hit_point, tgc->tgc_V );
01471         MAT4X3VEC( pprime, tgc->tgc_ScShR, work );
01472 
01473         switch( hitp->hit_surfno )  {
01474         case TGC_NORM_BODY:
01475                 /* scale coords to unit circle (they are already scaled by bottom plate radii) */
01476                 pprime[X] *= tgc->tgc_A / (tgc->tgc_A*( 1.0 - pprime[Z]) + tgc->tgc_C*pprime[Z]);
01477                 pprime[Y] *= tgc->tgc_B / (tgc->tgc_B*( 1.0 - pprime[Z]) + tgc->tgc_D*pprime[Z]);
01478                 uvp->uv_u = atan2( pprime[Y], pprime[X] ) / bn_twopi + 0.5;
01479                 uvp->uv_v = pprime[Z];          /* height */
01480                 break;
01481         case TGC_NORM_TOP:
01482                 /* top plate */
01483                 /* scale coords to unit circle (they are already scaled by bottom plate radii) */
01484                 pprime[X] *= tgc->tgc_A / tgc->tgc_C;
01485                 pprime[Y] *= tgc->tgc_B / tgc->tgc_D;
01486                 uvp->uv_u = atan2( pprime[Y], pprime[X] ) / bn_twopi + 0.5;
01487                 len = sqrt(pprime[X]*pprime[X]+pprime[Y]*pprime[Y]);
01488                 uvp->uv_v = len;                /* rim v = 1 */
01489                 break;
01490         case TGC_NORM_BOT:
01491                 /* bottom plate */
01492                 len = sqrt(pprime[X]*pprime[X]+pprime[Y]*pprime[Y]);
01493                 uvp->uv_u = atan2( pprime[Y], pprime[X] ) / bn_twopi + 0.5;
01494                 uvp->uv_v = 1 - len;    /* rim v = 0 */
01495                 break;
01496         }
01497 
01498         if( uvp->uv_u < 0.0 )
01499                 uvp->uv_u = 0.0;
01500         else if( uvp->uv_u > 1.0 )
01501                 uvp->uv_u = 1.0;
01502         if( uvp->uv_v < 0.0 )
01503                 uvp->uv_v = 0.0;
01504         else if( uvp->uv_v > 1.0 )
01505                 uvp->uv_v = 1.0;
01506 
01507         /* uv_du should be relative to rotation, uv_dv relative to height */
01508         uvp->uv_du = uvp->uv_dv = 0;
01509 }
01510 
01511 
01512 /**
01513  *                      R T _ T G C _ F R E E
01514  */
01515 void
01516 rt_tgc_free(struct soltab *stp)
01517 {
01518         register struct tgc_specific    *tgc =
01519         (struct tgc_specific *)stp->st_specific;
01520 
01521         bu_free( (char *)tgc, "tgc_specific");
01522 }
01523 
01524 int
01525 rt_tgc_class(void)
01526 {
01527         return(0);
01528 }
01529 
01530 
01531 /**
01532  *                      R T _ T G C _ I M P O R T
01533  *
01534  *  Import a TGC from the database format to the internal format.
01535  *  Apply modeling transformations as well.
01536  */
01537 int
01538 rt_tgc_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
01539 {
01540         struct rt_tgc_internal  *tip;
01541         union record            *rp;
01542         LOCAL fastf_t   vec[3*6];
01543 
01544         BU_CK_EXTERNAL( ep );
01545         rp = (union record *)ep->ext_buf;
01546         /* Check record type */
01547         if( rp->u_id != ID_SOLID )  {
01548                 bu_log("rt_tgc_import: defective record\n");
01549                 return(-1);
01550         }
01551 
01552         RT_CK_DB_INTERNAL( ip );
01553         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
01554         ip->idb_type = ID_TGC;
01555         ip->idb_meth = &rt_functab[ID_TGC];
01556         ip->idb_ptr = bu_malloc( sizeof(struct rt_tgc_internal), "rt_tgc_internal");
01557         tip = (struct rt_tgc_internal *)ip->idb_ptr;
01558         tip->magic = RT_TGC_INTERNAL_MAGIC;
01559 
01560         /* Convert from database to internal format */
01561         rt_fastf_float( vec, rp->s.s_values, 6 );
01562 
01563         /* Apply modeling transformations */
01564         MAT4X3PNT( tip->v, mat, &vec[0*3] );
01565         MAT4X3VEC( tip->h, mat, &vec[1*3] );
01566         MAT4X3VEC( tip->a, mat, &vec[2*3] );
01567         MAT4X3VEC( tip->b, mat, &vec[3*3] );
01568         MAT4X3VEC( tip->c, mat, &vec[4*3] );
01569         MAT4X3VEC( tip->d, mat, &vec[5*3] );
01570 
01571         return(0);              /* OK */
01572 }
01573 
01574 /**
01575  *                      R T _ T G C _ E X P O R T
01576  */
01577 int
01578 rt_tgc_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
01579 {
01580         struct rt_tgc_internal  *tip;
01581         union record            *rec;
01582 
01583         RT_CK_DB_INTERNAL(ip);
01584         if( ip->idb_type != ID_TGC && ip->idb_type != ID_REC )  return(-1);
01585         tip = (struct rt_tgc_internal *)ip->idb_ptr;
01586         RT_TGC_CK_MAGIC(tip);
01587 
01588         BU_CK_EXTERNAL(ep);
01589         ep->ext_nbytes = sizeof(union record);
01590         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "tgc external");
01591         rec = (union record *)ep->ext_buf;
01592 
01593         rec->s.s_id = ID_SOLID;
01594         rec->s.s_type = GENTGC;
01595 
01596         /* NOTE: This also converts to dbfloat_t */
01597         VSCALE( &rec->s.s_values[0], tip->v, local2mm );
01598         VSCALE( &rec->s.s_values[3], tip->h, local2mm );
01599         VSCALE( &rec->s.s_values[6], tip->a, local2mm );
01600         VSCALE( &rec->s.s_values[9], tip->b, local2mm );
01601         VSCALE( &rec->s.s_values[12], tip->c, local2mm );
01602         VSCALE( &rec->s.s_values[15], tip->d, local2mm );
01603 
01604         return(0);
01605 }
01606 
01607 /**
01608  *                      R T _ T G C _ I M P O R T 5
01609  *
01610  *  Import a TGC from the database format to the internal format.
01611  *  Apply modeling transformations as well.
01612  */
01613 int
01614 rt_tgc_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
01615 {
01616         struct rt_tgc_internal  *tip;
01617         fastf_t                 vec[3*6];
01618 
01619         BU_CK_EXTERNAL( ep );
01620 
01621         BU_ASSERT_LONG( ep->ext_nbytes, ==, SIZEOF_NETWORK_DOUBLE * 3*6 );
01622 
01623         RT_CK_DB_INTERNAL( ip );
01624         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
01625         ip->idb_type = ID_TGC;
01626         ip->idb_meth = &rt_functab[ID_TGC];
01627         ip->idb_ptr = bu_malloc( sizeof(struct rt_tgc_internal), "rt_tgc_internal");
01628 
01629         tip = (struct rt_tgc_internal *)ip->idb_ptr;
01630         tip->magic = RT_TGC_INTERNAL_MAGIC;
01631 
01632         /* Convert from database (network) to internal (host) format */
01633         ntohd( (unsigned char *)vec, ep->ext_buf, 3*6 );
01634 
01635         /* Apply modeling transformations */
01636         MAT4X3PNT( tip->v, mat, &vec[0*3] );
01637         MAT4X3VEC( tip->h, mat, &vec[1*3] );
01638         MAT4X3VEC( tip->a, mat, &vec[2*3] );
01639         MAT4X3VEC( tip->b, mat, &vec[3*3] );
01640         MAT4X3VEC( tip->c, mat, &vec[4*3] );
01641         MAT4X3VEC( tip->d, mat, &vec[5*3] );
01642 
01643         return(0);              /* OK */
01644 }
01645 
01646 /**
01647  *                      R T _ T G C _ E X P O R T 5
01648  */
01649 int
01650 rt_tgc_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
01651 {
01652         struct rt_tgc_internal  *tip;
01653         fastf_t                 vec[3*6];
01654 
01655         RT_CK_DB_INTERNAL(ip);
01656         if( ip->idb_type != ID_TGC && ip->idb_type != ID_REC )  return(-1);
01657         tip = (struct rt_tgc_internal *)ip->idb_ptr;
01658         RT_TGC_CK_MAGIC(tip);
01659 
01660         BU_CK_EXTERNAL(ep);
01661         ep->ext_nbytes = SIZEOF_NETWORK_DOUBLE * 3*6;
01662         ep->ext_buf = (genptr_t)bu_malloc( ep->ext_nbytes, "tgc external");
01663 
01664         /* scale 'em into local buffer */
01665         VSCALE( &vec[0*3], tip->v, local2mm );
01666         VSCALE( &vec[1*3], tip->h, local2mm );
01667         VSCALE( &vec[2*3], tip->a, local2mm );
01668         VSCALE( &vec[3*3], tip->b, local2mm );
01669         VSCALE( &vec[4*3], tip->c, local2mm );
01670         VSCALE( &vec[5*3], tip->d, local2mm );
01671 
01672         /* Convert from internal (host) to database (network) format */
01673         htond( ep->ext_buf, (unsigned char *)vec, 3*6 );
01674 
01675         return(0);
01676 }
01677 
01678 /**
01679  *                      R T _ T G C _ D E S C R I B E
01680  *
01681  *  Make human-readable formatted presentation of this solid.
01682  *  First line describes type of solid.
01683  *  Additional lines are indented one tab, and give parameter values.
01684  */
01685 int
01686 rt_tgc_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
01687 {
01688         register struct rt_tgc_internal *tip =
01689         (struct rt_tgc_internal *)ip->idb_ptr;
01690         char    buf[256];
01691         double  angles[5];
01692         vect_t  unitv;
01693         fastf_t Hmag;
01694 
01695         RT_TGC_CK_MAGIC(tip);
01696         bu_vls_strcat( str, "truncated general cone (TGC)\n");
01697 
01698         sprintf(buf, "\tV (%g, %g, %g)\n",
01699             INTCLAMP(tip->v[X] * mm2local),
01700             INTCLAMP(tip->v[Y] * mm2local),
01701             INTCLAMP(tip->v[Z] * mm2local) );
01702         bu_vls_strcat( str, buf );
01703 
01704         sprintf(buf, "\tTop (%g, %g, %g)\n",
01705             INTCLAMP((tip->v[X] + tip->h[X]) * mm2local),
01706             INTCLAMP((tip->v[Y] + tip->h[Y]) * mm2local),
01707             INTCLAMP((tip->v[Z] + tip->h[Z]) * mm2local) );
01708         bu_vls_strcat( str, buf );
01709 
01710         Hmag = MAGNITUDE(tip->h);
01711         sprintf(buf, "\tH (%g, %g, %g) mag=%g\n",
01712             INTCLAMP(tip->h[X] * mm2local),
01713             INTCLAMP(tip->h[Y] * mm2local),
01714             INTCLAMP(tip->h[Z] * mm2local),
01715             INTCLAMP(Hmag * mm2local) );
01716         bu_vls_strcat( str, buf );
01717         if( Hmag < VDIVIDE_TOL )  {
01718                 bu_vls_strcat( str, "H vector is zero!\n");
01719         } else {
01720                 register double f = 1/Hmag;
01721                 VSCALE( unitv, tip->h, f );
01722                 rt_find_fallback_angle( angles, unitv );
01723                 rt_pr_fallback_angle( str, "\tH", angles );
01724         }
01725 
01726         sprintf(buf, "\tA (%g, %g, %g) mag=%g\n",
01727             INTCLAMP(tip->a[X] * mm2local),
01728             INTCLAMP(tip->a[Y] * mm2local),
01729             INTCLAMP(tip->a[Z] * mm2local),
01730             INTCLAMP(MAGNITUDE(tip->a) * mm2local) );
01731         bu_vls_strcat( str, buf );
01732 
01733         sprintf(buf, "\tB (%g, %g, %g) mag=%g\n",
01734             INTCLAMP(tip->b[X] * mm2local),
01735             INTCLAMP(tip->b[Y] * mm2local),
01736             INTCLAMP(tip->b[Z] * mm2local),
01737             INTCLAMP(MAGNITUDE(tip->b) * mm2local) );
01738         bu_vls_strcat( str, buf );
01739 
01740         sprintf(buf, "\tC (%g, %g, %g) mag=%g\n",
01741             INTCLAMP(tip->c[X] * mm2local),
01742             INTCLAMP(tip->c[Y] * mm2local),
01743             INTCLAMP(tip->c[Z] * mm2local),
01744             INTCLAMP(MAGNITUDE(tip->c) * mm2local) );
01745         bu_vls_strcat( str, buf );
01746 
01747         sprintf(buf, "\tD (%g, %g, %g) mag=%g\n",
01748             INTCLAMP(tip->d[X] * mm2local),
01749             INTCLAMP(tip->d[Y] * mm2local),
01750             INTCLAMP(tip->d[Z] * mm2local),
01751             INTCLAMP(MAGNITUDE(tip->d) * mm2local) );
01752         bu_vls_strcat( str, buf );
01753 
01754         VCROSS( unitv, tip->c, tip->d );
01755         VUNITIZE( unitv );
01756         rt_find_fallback_angle( angles, unitv );
01757         rt_pr_fallback_angle( str, "\tAxB", angles );
01758 
01759         return(0);
01760 }
01761 
01762 /**
01763  *                      R T _ T G C _ I F R E E
01764  *
01765  *  Free the storage associated with the rt_db_internal version of this solid.
01766  */
01767 void
01768 rt_tgc_ifree(struct rt_db_internal *ip)
01769 {
01770         RT_CK_DB_INTERNAL(ip);
01771         bu_free( ip->idb_ptr, "tgc ifree" );
01772         ip->idb_ptr = GENPTR_NULL;
01773 }
01774 
01775 /**
01776  *                      R T _ T G C _ P L O T
01777  */
01778 int
01779 rt_tgc_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01780 {
01781         LOCAL struct rt_tgc_internal    *tip;
01782         register int            i;
01783         LOCAL fastf_t           top[16*3];
01784         LOCAL fastf_t           bottom[16*3];
01785         LOCAL vect_t            work;           /* Vec addition work area */
01786 
01787         RT_CK_DB_INTERNAL(ip);
01788         tip = (struct rt_tgc_internal *)ip->idb_ptr;
01789         RT_TGC_CK_MAGIC(tip);
01790 
01791         rt_ell_16pts( bottom, tip->v, tip->a, tip->b );
01792         VADD2( work, tip->v, tip->h );
01793         rt_ell_16pts( top, work, tip->c, tip->d );
01794 
01795         /* Draw the top */
01796         RT_ADD_VLIST( vhead, &top[15*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
01797         for( i=0; i<16; i++ )  {
01798                 RT_ADD_VLIST( vhead, &top[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
01799         }
01800 
01801         /* Draw the bottom */
01802         RT_ADD_VLIST( vhead, &bottom[15*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
01803         for( i=0; i<16; i++ )  {
01804                 RT_ADD_VLIST( vhead, &bottom[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
01805         }
01806 
01807         /* Draw connections */
01808         for( i=0; i<16; i += 4 )  {
01809                 RT_ADD_VLIST( vhead, &top[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
01810                 RT_ADD_VLIST( vhead, &bottom[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
01811         }
01812         return(0);
01813 }
01814 
01815 /**
01816  *                      R T _ T G C _ C U R V E
01817  *
01818  *  Return the curvature of the TGC.
01819  */
01820 void
01821 rt_tgc_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
01822 {
01823         register struct tgc_specific *tgc =
01824         (struct tgc_specific *)stp->st_specific;
01825         fastf_t R, Q, R2, Q2;
01826         mat_t   M, dN, mtmp;
01827         vect_t  gradf, tmp, u, v;
01828         fastf_t a, b, c, scale;
01829         vect_t  vec1, vec2;
01830 
01831         if( hitp->hit_surfno != TGC_NORM_BODY ) {
01832                 /* We hit an end plate.  Choose any tangent vector. */
01833                 bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
01834                 cvp->crv_c1 = cvp->crv_c2 = 0;
01835                 return;
01836         }
01837 
01838         R = 1 + tgc->tgc_CdAm1 * hitp->hit_vpriv[Z];
01839         Q = 1 + tgc->tgc_DdBm1 * hitp->hit_vpriv[Z];
01840         R2 = R*R;
01841         Q2 = Q*Q;
01842 
01843         /*
01844          * Compute derivatives of the gradient (normal) field
01845          * in ideal coords.  This is a symmetric matrix with
01846          * the columns (dNx, dNy, dNz).
01847          */
01848         MAT_IDN( dN );
01849         dN[0] = Q2;
01850         dN[2] = dN[8] = 2.0*Q*tgc->tgc_DdBm1 * hitp->hit_vpriv[X];
01851         dN[5] = R2;
01852         dN[6] = dN[9] = 2.0*R*tgc->tgc_CdAm1 * hitp->hit_vpriv[Y];
01853         dN[10] = tgc->tgc_DdBm1*tgc->tgc_DdBm1 * hitp->hit_vpriv[X]*hitp->hit_vpriv[X]
01854             + tgc->tgc_CdAm1*tgc->tgc_CdAm1 * hitp->hit_vpriv[Y]*hitp->hit_vpriv[Y]
01855             - tgc->tgc_DdBm1*tgc->tgc_DdBm1 * R2
01856             - tgc->tgc_CdAm1*tgc->tgc_CdAm1 * Q2
01857             - 4.0*tgc->tgc_CdAm1*tgc->tgc_DdBm1 * R*Q;
01858 
01859         /* M = At * dN * A */
01860         bn_mat_mul( mtmp, dN, tgc->tgc_ScShR );
01861         bn_mat_mul( M, tgc->tgc_invRtShSc, mtmp );
01862 
01863         /* XXX - determine the scaling */
01864         gradf[X] = Q2 * hitp->hit_vpriv[X];
01865         gradf[Y] = R2 * hitp->hit_vpriv[Y];
01866         gradf[Z] = (hitp->hit_vpriv[X]*hitp->hit_vpriv[X] - R2) * Q * tgc->tgc_DdBm1 +
01867             (hitp->hit_vpriv[Y]*hitp->hit_vpriv[Y] - Q2) * R * tgc->tgc_CdAm1;
01868         MAT4X3VEC( tmp, tgc->tgc_invRtShSc, gradf );
01869         scale = -1.0 / MAGNITUDE(tmp);
01870         /* XXX */
01871 
01872         /*
01873          * choose a tangent plane coordinate system
01874          *  (u, v, normal) form a right-handed triple
01875          */
01876         bn_vec_ortho( u, hitp->hit_normal );
01877         VCROSS( v, hitp->hit_normal, u );
01878 
01879         /* find the second fundamental form */
01880         MAT4X3VEC( tmp, M, u );
01881         a = VDOT(u, tmp) * scale;
01882         b = VDOT(v, tmp) * scale;
01883         MAT4X3VEC( tmp, M, v );
01884         c = VDOT(v, tmp) * scale;
01885 
01886         bn_eigen2x2( &cvp->crv_c1, &cvp->crv_c2, vec1, vec2, a, b, c );
01887         VCOMB2( cvp->crv_pdir, vec1[X], u, vec1[Y], v );
01888         VUNITIZE( cvp->crv_pdir );
01889 }
01890 
01891 /**
01892  *                      R T _ T G C _ T E S S
01893  *
01894  *  Tesselation of the TGC.
01895  *
01896  *  Returns -
01897  *      -1      failure
01898  *       0      OK.  *r points to nmgregion that holds this tessellation.
01899  */
01900 
01901 struct tgc_pts
01902 {
01903         point_t         pt;
01904         vect_t          tan_axb;
01905         struct vertex   *v;
01906         char            dont_use;
01907 };
01908 
01909 #define MAX_RATIO       10.0    /* maximum allowed height-to-width ration for triangles */
01910 
01911 /* version using tolerances */
01912 int
01913 rt_tgc_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01914 {
01915         struct shell            *s;             /* shell to hold facetted TGC */
01916         struct faceuse          *fu,*fu_top,*fu_base;
01917         struct rt_tgc_internal  *tip;
01918         fastf_t                 radius;         /* bounding sphere radius */
01919         fastf_t                 max_radius,min_radius; /* max/min of a,b,c,d */
01920         fastf_t                 h,a,b,c,d;      /* lengths of TGC vectors */
01921         fastf_t                 inv_length;     /* 1.0/length of a vector */
01922         vect_t                  unit_a,unit_b,unit_c,unit_d; /* units vectors in a,b,c,d directions */
01923         fastf_t                 rel,abs,norm;   /* interpreted tolerances */
01924         fastf_t                 alpha_tol;      /* final tolerance for ellipse parameter */
01925         fastf_t                 abs_tol;        /* handle invalid ttol->abs */
01926         int                     nells;          /* total number of ellipses */
01927         int                     nsegs;          /* number of vertices/ellipse */
01928         vect_t                  *A;             /* array of A vectors for ellipses */
01929         vect_t                  *B;             /* array of B vectors for ellipses */
01930         fastf_t                 *factors;       /* array of ellipse locations along height vector */
01931         vect_t                  vtmp;
01932         vect_t                  normal;         /* normal vector */
01933         vect_t                  rev_norm;       /* reverse normal */
01934         struct tgc_pts          **pts;          /* array of points (pts[ellipse#][seg#]) */
01935         struct bu_ptbl          verts;          /* table of vertices used for top and bottom faces */
01936         struct bu_ptbl          faces;          /* table of faceuses for nmg_gluefaces */
01937         struct vertex           **v[3];         /* array for making triangular faces */
01938 
01939         int                     i;
01940 
01941         RT_CK_DB_INTERNAL(ip);
01942         tip = (struct rt_tgc_internal *)ip->idb_ptr;
01943         RT_TGC_CK_MAGIC(tip);
01944 
01945         if( ttol->abs > 0.0 && ttol->abs < tol->dist )
01946         {
01947             bu_log( "WARNING: tesselation tolerance is %fmm while calculational tolerance is %fmm\n",
01948                     ttol->abs , tol->dist );
01949             bu_log( "Cannot tesselate a TGC to finer tolerance than the calculational tolerance\n" );
01950             abs_tol = tol->dist;
01951         } else {
01952             abs_tol = ttol->abs;
01953         }
01954 
01955         h = MAGNITUDE( tip->h );
01956         a = MAGNITUDE( tip->a );
01957         if( 2.0*a <= tol->dist )
01958                 a = 0.0;
01959         b = MAGNITUDE( tip->b );
01960         if( 2.0*b <= tol->dist )
01961                 b = 0.0;
01962         c = MAGNITUDE( tip->c );
01963         if( 2.0*c <= tol->dist )
01964                 c = 0.0;
01965         d = MAGNITUDE( tip->d );
01966         if( 2.0*d <= tol->dist )
01967                 d = 0.0;
01968 
01969         if( a == 0.0 && b == 0.0 && (c == 0.0 || d == 0.0) )
01970         {
01971                 bu_log( "Illegal TGC a, b, and c or d less than tolerance\n" );
01972                 return( -1);
01973         }
01974         else if( c == 0.0 && d == 0.0 && (a == 0.0 || b == 0.0 ) )
01975         {
01976                 bu_log( "Illegal TGC c, d, and a or b less than tolerance\n" );
01977                 return( -1 );
01978         }
01979 
01980         if( a > 0.0 )
01981         {
01982                 inv_length = 1.0/a;
01983                 VSCALE( unit_a, tip->a, inv_length );
01984         }
01985         if( b > 0.0 )
01986         {
01987                 inv_length = 1.0/b;
01988                 VSCALE( unit_b, tip->b, inv_length );
01989         }
01990         if( c > 0.0 )
01991         {
01992                 inv_length = 1.0/c;
01993                 VSCALE( unit_c, tip->c, inv_length );
01994         }
01995         if( d > 0.0 )
01996         {
01997                 inv_length = 1.0/d;
01998                 VSCALE( unit_d, tip->d, inv_length );
01999         }
02000 
02001         /* get bounding sphere radius for relative tolerance */
02002         radius = h/2.0;
02003         max_radius = 0.0;
02004         if( a > max_radius )
02005                 max_radius = a;
02006         if( b > max_radius )
02007                 max_radius = b;
02008         if( c > max_radius )
02009                 max_radius = c;
02010         if( d > max_radius )
02011                 max_radius = d;
02012 
02013         if( max_radius > radius )
02014                 radius = max_radius;
02015 
02016         min_radius = MAX_FASTF;
02017         if( a < min_radius && a > 0.0 )
02018                 min_radius = a;
02019         if( b < min_radius && b > 0.0 )
02020                 min_radius = b;
02021         if( c < min_radius && c > 0.0 )
02022                 min_radius = c;
02023         if( d < min_radius && d > 0.0 )
02024                 min_radius = d;
02025 
02026         if( abs_tol <= 0.0 && ttol->rel <= 0.0 && ttol->norm <= 0.0 )
02027         {
02028                 /* no tolerances specified, use 10% relative tolerance */
02029                 if( (radius * 0.2) < max_radius )
02030                         alpha_tol = 2.0 * acos( 1.0 - 2.0 * radius * 0.1 / max_radius );
02031                 else
02032                         alpha_tol = bn_halfpi;
02033         }
02034         else
02035         {
02036                 if( abs_tol > 0.0 )
02037                         abs = 2.0 * acos( 1.0 - abs_tol/max_radius );
02038                 else
02039                         abs = bn_halfpi;
02040 
02041                 if( ttol->rel > 0.0 )
02042                 {
02043                         if( ttol->rel * 2.0 * radius < max_radius )
02044                                 rel = 2.0 * acos( 1.0 - ttol->rel * 2.0 * radius/max_radius );
02045                         else
02046                                 rel = bn_halfpi;
02047                 }
02048                 else
02049                         rel = bn_halfpi;
02050 
02051                 if( ttol->norm > 0.0 )
02052                 {
02053                         fastf_t norm_top,norm_bot;
02054 
02055                         if( a<b )
02056                                 norm_bot = 2.0 * atan( tan( ttol->norm ) * (a/b) );
02057                         else
02058                                 norm_bot = 2.0 * atan( tan( ttol->norm ) * (b/a) );
02059 
02060                         if( c<d )
02061                                 norm_top = 2.0 * atan( tan( ttol->norm ) * (c/d) );
02062                         else
02063                                 norm_top = 2.0 * atan( tan( ttol->norm ) * (d/c) );
02064 
02065                         if( norm_bot < norm_top )
02066                                 norm = norm_bot;
02067                         else
02068                                 norm = norm_top;
02069                 }
02070                 else
02071                         norm = bn_halfpi;
02072 
02073                 if( abs < rel )
02074                         alpha_tol = abs;
02075                 else
02076                         alpha_tol = rel;
02077                 if( norm < alpha_tol )
02078                         alpha_tol = norm;
02079         }
02080 
02081         /* get number of segments per quadrant */
02082         nsegs = (int)(bn_halfpi / alpha_tol + 0.9999);
02083         if( nsegs < 2 )
02084                 nsegs = 2;
02085 
02086         /* and for complete ellipse */
02087         nsegs *= 4;
02088 
02089         /* get nunber and placement of intermediate ellipses */
02090         {
02091                 fastf_t ratios[4],max_ratio;
02092                 fastf_t new_ratio = 0;
02093                 int which_ratio;
02094                 fastf_t len_ha,len_hb;
02095                 vect_t ha,hb;
02096                 fastf_t ang;
02097                 fastf_t sin_ang,cos_ang,cos_m_1_sq, sin_sq;
02098                 fastf_t len_A, len_B, len_C, len_D;
02099                 int bot_ell=0, top_ell=1;
02100                 int reversed=0;
02101 
02102                 nells = 2;
02103 
02104                 max_ratio = MAX_RATIO + 1.0;
02105 
02106                 factors = (fastf_t *)bu_malloc( nells*sizeof( fastf_t ), "factors" );
02107                 A = (vect_t *)bu_malloc( nells*sizeof( vect_t ), "A vectors" );
02108                 B = (vect_t *)bu_malloc( nells*sizeof( vect_t ), "B vectors" );
02109 
02110                 factors[bot_ell] = 0.0;
02111                 factors[top_ell] = 1.0;
02112                 VMOVE( A[bot_ell], tip->a );
02113                 VMOVE( A[top_ell], tip->c );
02114                 VMOVE( B[bot_ell], tip->b );
02115                 VMOVE( B[top_ell], tip->d );
02116 
02117                 /* make sure that AxB points in the general direction of H */
02118                 VCROSS( vtmp , A[0] , B[0] );
02119                 if( VDOT( vtmp , tip->h ) < 0.0 )
02120                 {
02121                         VMOVE( A[bot_ell], tip->b );
02122                         VMOVE( A[top_ell], tip->d );
02123                         VMOVE( B[bot_ell], tip->a );
02124                         VMOVE( B[top_ell], tip->c );
02125                         reversed = 1;
02126                 }
02127                 ang = 2.0*bn_pi/((double)nsegs);
02128                 sin_ang = sin( ang );
02129                 cos_ang = cos( ang );
02130                 cos_m_1_sq = (cos_ang - 1.0)*(cos_ang - 1.0);
02131                 sin_sq = sin_ang*sin_ang;
02132 
02133                 VJOIN2( ha, tip->h, 1.0, tip->c, -1.0, tip->a )
02134                 VJOIN2( hb, tip->h, 1.0, tip->d, -1.0, tip->b )
02135                 len_ha = MAGNITUDE( ha );
02136                 len_hb = MAGNITUDE( hb );
02137 
02138                 while( max_ratio > MAX_RATIO )
02139                 {
02140                         fastf_t tri_width;
02141 
02142                         len_A = MAGNITUDE( A[bot_ell] );
02143                         if( 2.0*len_A <= tol->dist )
02144                                 len_A = 0.0;
02145                         len_B = MAGNITUDE( B[bot_ell] );
02146                         if( 2.0*len_B <= tol->dist )
02147                                 len_B = 0.0;
02148                         len_C = MAGNITUDE( A[top_ell] );
02149                         if( 2.0*len_C <= tol->dist )
02150                                 len_C = 0.0;
02151                         len_D = MAGNITUDE( B[top_ell] );
02152                         if( 2.0*len_D <= tol->dist )
02153                                 len_D = 0.0;
02154 
02155                         if( (len_B > 0.0 && len_D > 0.0) ||
02156                                 (len_B > 0.0 && (len_D == 0.0 && len_C == 0.0 )) )
02157                         {
02158                                 tri_width = sqrt( cos_m_1_sq*len_A*len_A + sin_sq*len_B*len_B );
02159                                 ratios[0] = (factors[top_ell] - factors[bot_ell])*len_ha
02160                                                 /tri_width;
02161                         }
02162                         else
02163                                 ratios[0] = 0.0;
02164 
02165                         if( (len_A > 0.0 && len_C > 0.0) ||
02166                                 ( len_A > 0.0 && (len_C == 0.0 && len_D == 0.0)) )
02167                         {
02168                                 tri_width = sqrt( sin_sq*len_A*len_A + cos_m_1_sq*len_B*len_B );
02169                                 ratios[1] = (factors[top_ell] - factors[bot_ell])*len_hb
02170                                                 /tri_width;
02171                         }
02172                         else
02173                                 ratios[1] = 0.0;
02174 
02175                         if( (len_D > 0.0 && len_B > 0.0) ||
02176                                 (len_D > 0.0 && (len_A == 0.0 && len_B == 0.0)) )
02177                         {
02178                                 tri_width = sqrt( cos_m_1_sq*len_C*len_C + sin_sq*len_D*len_D );
02179                                 ratios[2] = (factors[top_ell] - factors[bot_ell])*len_ha
02180                                                 /tri_width;
02181                         }
02182                         else
02183                                 ratios[2] = 0.0;
02184 
02185                         if( (len_C > 0.0 && len_A > 0.0) ||
02186                                 (len_C > 0.0 && (len_A == 0.0 && len_B == 0.0)) )
02187                         {
02188                                 tri_width = sqrt( sin_sq*len_C*len_C + cos_m_1_sq*len_D*len_D );
02189                                 ratios[3] = (factors[top_ell] - factors[bot_ell])*len_hb
02190                                                 /tri_width;
02191                         }
02192                         else
02193                                 ratios[3] = 0.0;
02194 
02195                         which_ratio = -1;
02196                         max_ratio = 0.0;
02197 
02198                         for( i=0 ; i<4 ; i++ )
02199                         {
02200                                 if( ratios[i] > max_ratio )
02201                                 {
02202                                         max_ratio = ratios[i];
02203                                         which_ratio = i;
02204                                 }
02205                         }
02206 
02207                         if( len_A == 0.0 && len_B == 0.0 && len_C == 0.0 && len_D == 0.0 )
02208                         {
02209                                 if( top_ell == nells - 1 )
02210                                 {
02211                                         VMOVE( A[top_ell-1], A[top_ell] )
02212                                         VMOVE( B[top_ell-1], A[top_ell] )
02213                                         factors[top_ell-1] = factors[top_ell];
02214                                 }
02215                                 else if( bot_ell == 0 )
02216                                 {
02217                                         for( i=0 ; i<nells-1 ; i++ )
02218                                         {
02219                                                 VMOVE( A[i], A[i+1] )
02220                                                 VMOVE( B[i], B[i+1] )
02221                                                 factors[i] = factors[i+1];
02222                                         }
02223                                 }
02224 
02225                                 nells -= 1;
02226                                 break;
02227                         }
02228 
02229                         if( max_ratio <= MAX_RATIO )
02230                                 break;
02231 
02232                         if( which_ratio == 0 || which_ratio == 1 )
02233                         {
02234                                 new_ratio = MAX_RATIO/max_ratio;
02235                                 if( bot_ell == 0 && new_ratio > 0.5 )
02236                                         new_ratio = 0.5;
02237                         }
02238                         else if( which_ratio == 2 || which_ratio == 3 )
02239                         {
02240                                 new_ratio = 1.0 - MAX_RATIO/max_ratio;
02241                                 if( top_ell == nells - 1 && new_ratio < 0.5 )
02242                                         new_ratio = 0.5;
02243                         }
02244                         else    /* no MAX??? */
02245                         {
02246                                 bu_log( "rt_tgc_tess: Should never get here!!\n" );
02247                                 rt_bomb( "rt_tgc_tess: Should never get here!!\n" );
02248                         }
02249 
02250                         nells++;
02251                         factors = (fastf_t *)bu_realloc( factors, nells*sizeof( fastf_t ), "factors" );
02252                         A = (vect_t *)bu_realloc( A, nells*sizeof( vect_t ), "A vectors" );
02253                         B = (vect_t *)bu_realloc( B, nells*sizeof( vect_t ), "B vectors" );
02254 
02255                         for( i=nells-1 ; i>top_ell ; i-- )
02256                         {
02257                                 factors[i] = factors[i-1];
02258                                 VMOVE( A[i], A[i-1] )
02259                                 VMOVE( B[i], B[i-1] )
02260                         }
02261 
02262                         factors[top_ell] = factors[bot_ell] +
02263                                 new_ratio*(factors[top_ell+1] - factors[bot_ell]);
02264 
02265                         if( reversed )
02266                         {
02267                                 VBLEND2( A[top_ell], (1.0-factors[top_ell]), tip->b, factors[top_ell], tip->d )
02268                                 VBLEND2( B[top_ell], (1.0-factors[top_ell]), tip->a, factors[top_ell], tip->c )
02269                         }
02270                         else
02271                         {
02272                                 VBLEND2( A[top_ell], (1.0-factors[top_ell]), tip->a, factors[top_ell], tip->c )
02273                                 VBLEND2( B[top_ell], (1.0-factors[top_ell]), tip->b, factors[top_ell], tip->d )
02274                         }
02275 
02276                         if( which_ratio == 0 || which_ratio == 1 )
02277                         {
02278                                 top_ell++;
02279                                 bot_ell++;
02280                         }
02281 
02282                 }
02283 
02284         }
02285 
02286         /* get memory for points */
02287         pts = (struct tgc_pts **)bu_calloc( nells , sizeof( struct tgc_pts *) , "rt_tgc_tess: pts" );
02288         for( i=0 ; i<nells ; i++ )
02289                 pts[i] = (struct tgc_pts *)bu_calloc( nsegs , sizeof( struct tgc_pts ) , "rt_tgc_tess: pts" );
02290 
02291         /* calculate geometry for points */
02292         for( i=0 ; i<nells ; i++ )
02293         {
02294                 fastf_t h_factor;
02295                 int j;
02296 
02297                 h_factor = factors[i];
02298                 for( j=0 ; j<nsegs ; j++ )
02299                 {
02300                         double alpha;
02301                         double sin_alpha,cos_alpha;
02302 
02303                         alpha = bn_twopi * (double)(2*j+1)/(double)(2*nsegs);
02304                         sin_alpha = sin( alpha );
02305                         cos_alpha = cos( alpha );
02306 
02307                         /* vertex geometry */
02308                         if( i == 0 && a == 0.0 && b == 0.0 )
02309                                 VMOVE( pts[i][j].pt , tip->v )
02310                         else if( i == nells-1 && c == 0.0 && d == 0.0 )
02311                                 VADD2( pts[i][j].pt, tip->v, tip->h )
02312                         else
02313                                 VJOIN3( pts[i][j].pt , tip->v , h_factor , tip->h , cos_alpha , A[i] , sin_alpha , B[i] )
02314 
02315                         /* Storing the tangent here while sines and cosines are available */
02316                         if( i == 0 && a == 0.0 && b == 0.0 )
02317                                 VCOMB2( pts[0][j].tan_axb, -sin_alpha, unit_c, cos_alpha, unit_d )
02318                         else if( i == nells-1 && c == 0.0 && d == 0.0 )
02319                                 VCOMB2( pts[i][j].tan_axb, -sin_alpha, unit_a, cos_alpha, unit_b )
02320                         else
02321                                 VCOMB2( pts[i][j].tan_axb , -sin_alpha , A[i] , cos_alpha , B[i] )
02322                 }
02323         }
02324 
02325         /* make sure no edges will be created with length < tol->dist */
02326         for( i=0 ; i<nells ; i++ )
02327         {
02328                 int j;
02329                 point_t curr_pt;
02330                 vect_t edge_vect;
02331 
02332                 if( i == 0 && (a == 0.0 || b == 0.0) )
02333                         continue;
02334                 else if( i == nells-1 && (c == 0.0 || d == 0.0) )
02335                         continue;
02336 
02337                 VMOVE( curr_pt, pts[i][0].pt )
02338                 for( j=1 ; j<nsegs ; j++ )
02339                 {
02340                         fastf_t edge_len_sq;
02341 
02342                         VSUB2( edge_vect, curr_pt, pts[i][j].pt )
02343                         edge_len_sq = MAGSQ( edge_vect );
02344                         if(edge_len_sq > tol->dist_sq )
02345                                 VMOVE( curr_pt, pts[i][j].pt )
02346                         else
02347                         {
02348                                 /* don't use this point, it will create a too short edge */
02349                                 pts[i][j].dont_use = 'n';
02350                         }
02351                 }
02352         }
02353 
02354         /* make region, shell, vertex */
02355         *r = nmg_mrsv( m );
02356         s = BU_LIST_FIRST(shell, &(*r)->s_hd);
02357 
02358         bu_ptbl_init( &verts , 64, " &verts ");
02359         bu_ptbl_init( &faces , 64, " &faces ");
02360         /* Make bottom face */
02361         if( a > 0.0 && b > 0.0 )
02362         {
02363                 for( i=nsegs-1 ; i>=0 ; i-- ) /* reverse order to get outward normal */
02364                 {
02365                         if( !pts[0][i].dont_use )
02366                                 bu_ptbl_ins( &verts , (long *)&pts[0][i].v );
02367                 }
02368 
02369                 if( BU_PTBL_END( &verts ) > 2 )
02370                 {
02371                         fu_base = nmg_cmface( s , (struct vertex ***)BU_PTBL_BASEADDR( &verts ), BU_PTBL_END( &verts ) );
02372                         bu_ptbl_ins( &faces , (long *)fu_base );
02373                 }
02374                 else
02375                         fu_base = (struct faceuse *)NULL;
02376         }
02377         else
02378                 fu_base = (struct faceuse *)NULL;
02379 
02380 
02381         /* Make top face */
02382         if( c > 0.0 && d > 0.0 )
02383         {
02384                 bu_ptbl_reset( &verts );
02385                 for( i=0 ; i<nsegs ; i++ )
02386                 {
02387                         if( !pts[nells-1][i].dont_use )
02388                                 bu_ptbl_ins( &verts , (long *)&pts[nells-1][i].v );
02389                 }
02390 
02391                 if( BU_PTBL_END( &verts ) > 2 )
02392                 {
02393                         fu_top = nmg_cmface( s , (struct vertex ***)BU_PTBL_BASEADDR( &verts ), BU_PTBL_END( &verts ) );
02394                         bu_ptbl_ins( &faces , (long *)fu_top );
02395                 }
02396                 else
02397                         fu_top = (struct faceuse *)NULL;
02398         }
02399         else
02400                 fu_top = (struct faceuse *)NULL;
02401 
02402         /* Free table of vertices */
02403         bu_ptbl_free( &verts );
02404 
02405         /* Make triangular faces */
02406         for( i=0 ; i<nells-1 ; i++ )
02407         {
02408                 int j;
02409                 struct vertex **curr_top;
02410                 struct vertex **curr_bot;
02411 
02412                 curr_bot = &pts[i][0].v;
02413                 curr_top = &pts[i+1][0].v;
02414                 for( j=0 ; j<nsegs ; j++ )
02415                 {
02416                         int k;
02417 
02418                         k = j+1;
02419                         if( k == nsegs )
02420                                 k = 0;
02421                         if( i != 0 || a > 0.0 || b > 0.0 )
02422                         {
02423                                 if( !pts[i][k].dont_use )
02424                                 {
02425                                         v[0] = curr_bot;
02426                                         v[1] = &pts[i][k].v;
02427                                         if( i+1 == nells-1 && c == 0.0 && d == 0.0 )
02428                                                 v[2] = &pts[i+1][0].v;
02429                                         else
02430                                                 v[2] = curr_top;
02431                                         fu = nmg_cmface( s , v , 3 );
02432                                         bu_ptbl_ins( &faces , (long *)fu );
02433                                         curr_bot = &pts[i][k].v;
02434                                 }
02435                         }
02436 
02437                         if( i != nells-2 || c > 0.0 || d > 0.0 )
02438                         {
02439                                 if( !pts[i+1][k].dont_use )
02440                                 {
02441                                         v[0] = &pts[i+1][k].v;
02442                                         v[1] = curr_top;
02443                                         if( i == 0 && a == 0.0 && b == 0.0 )
02444                                                 v[2] = &pts[i][0].v;
02445                                         else
02446                                                 v[2] = curr_bot;
02447                                         fu = nmg_cmface( s , v , 3 );
02448                                         bu_ptbl_ins( &faces , (long *)fu );
02449                                         curr_top = &pts[i+1][k].v;
02450                                 }
02451                         }
02452                 }
02453         }
02454 
02455         /* Assign geometry */
02456         for( i=0 ; i<nells ; i++ )
02457         {
02458                 int j;
02459 
02460                 for( j=0 ; j<nsegs ; j++ )
02461                 {
02462                         point_t pt_geom;
02463                         double alpha;
02464                         double sin_alpha,cos_alpha;
02465 
02466                         alpha = bn_twopi * (double)(2*j+1)/(double)(2*nsegs);
02467                         sin_alpha = sin( alpha );
02468                         cos_alpha = cos( alpha );
02469 
02470                         /* vertex geometry */
02471                         if( i == 0 && a == 0.0 && b == 0.0 )
02472                         {
02473                                 if( j == 0 )
02474                                         nmg_vertex_gv( pts[0][0].v, tip->v );
02475                         }
02476                         else if( i == nells-1 && c == 0.0 && d == 0.0 )
02477                         {
02478                                 if( j == 0 )
02479                                 {
02480                                         VADD2( pt_geom, tip->v, tip->h );
02481                                         nmg_vertex_gv( pts[i][0].v , pt_geom );
02482                                 }
02483                         }
02484                         else if( pts[i][j].v )
02485                                 nmg_vertex_gv( pts[i][j].v , pts[i][j].pt );
02486 
02487                         /* Storing the tangent here while sines and cosines are available */
02488                         if( i == 0 && a == 0.0 && b == 0.0 )
02489                                 VCOMB2( pts[0][j].tan_axb, -sin_alpha, unit_c, cos_alpha, unit_d )
02490                         else if( i == nells-1 && c == 0.0 && d == 0.0 )
02491                                 VCOMB2( pts[i][j].tan_axb, -sin_alpha, unit_a, cos_alpha, unit_b )
02492                         else
02493                                 VCOMB2( pts[i][j].tan_axb , -sin_alpha , A[i] , cos_alpha , B[i] )
02494                 }
02495         }
02496 
02497         /* Associate face plane equations */
02498         for( i=0 ; i<BU_PTBL_END( &faces ) ; i++ )
02499         {
02500                 fu = (struct faceuse *)BU_PTBL_GET( &faces , i );
02501                 NMG_CK_FACEUSE( fu );
02502 
02503                 if( nmg_calc_face_g( fu ) )
02504                 {
02505                         bu_log( "rt_tess_tgc: failed to calculate plane equation\n" );
02506                         nmg_pr_fu_briefly( fu, "" );
02507                         return( -1 );
02508                 }
02509         }
02510 
02511 
02512         /* Calculate vertexuse normals */
02513         for( i=0 ; i<nells ; i++ )
02514         {
02515                 int j,k;
02516 
02517                 k = i + 1;
02518                 if( k == nells )
02519                         k = i - 1;
02520 
02521                 for( j=0 ; j<nsegs ; j++ )
02522                 {
02523                         vect_t tan_h;           /* vector tangent from one ellipse to next */
02524                         struct vertexuse *vu;
02525 
02526                         /* normal at vertex */
02527                         if( i == nells - 1 )
02528                         {
02529                                 if( c == 0.0 && d == 0.0 )
02530                                         VSUB2( tan_h , pts[i][0].pt , pts[k][j].pt )
02531                                 else if( k == 0 && c == 0.0 && d == 0.0 )
02532                                         VSUB2( tan_h , pts[i][j].pt , pts[k][0].pt )
02533                                 else
02534                                         VSUB2( tan_h , pts[i][j].pt , pts[k][j].pt )
02535                         }
02536                         else if( i == 0 )
02537                         {
02538                                 if( a == 0.0 && b == 0.0 )
02539                                         VSUB2( tan_h , pts[k][j].pt , pts[i][0].pt )
02540                                 else if( k == nells-1 && c == 0.0 && d == 0.0 )
02541                                         VSUB2( tan_h , pts[k][0].pt , pts[i][j].pt )
02542                                 else
02543                                         VSUB2( tan_h , pts[k][j].pt , pts[i][j].pt )
02544                         }
02545                         else if( k == 0 && a == 0.0 && b == 0.0 )
02546                                 VSUB2( tan_h , pts[k][0].pt , pts[i][j].pt )
02547                         else if( k == nells-1 && c == 0.0 && d == 0.0 )
02548                                 VSUB2( tan_h , pts[k][0].pt , pts[i][j].pt )
02549                         else
02550                                 VSUB2( tan_h , pts[k][j].pt , pts[i][j].pt )
02551 
02552                         VCROSS( normal , pts[i][j].tan_axb , tan_h );
02553                         VUNITIZE( normal );
02554                         VREVERSE( rev_norm , normal );
02555 
02556                         if( !(i == 0 && a == 0.0 && b == 0.0) &&
02557                             !(i == nells-1 && c == 0.0 && d == 0.0 ) &&
02558                               pts[i][j].v )
02559                         {
02560                                 for( BU_LIST_FOR( vu , vertexuse , &pts[i][j].v->vu_hd ) )
02561                                 {
02562                                         NMG_CK_VERTEXUSE( vu );
02563 
02564                                         fu = nmg_find_fu_of_vu( vu );
02565                                         NMG_CK_FACEUSE( fu );
02566 
02567                                         /* don't need vertexuse normals for faces that are really flat */
02568                                         if( fu == fu_base || fu->fumate_p == fu_base ||
02569                                             fu == fu_top  || fu->fumate_p == fu_top )
02570                                                 continue;
02571 
02572                                         if( fu->orientation == OT_SAME )
02573                                                 nmg_vertexuse_nv( vu , normal );
02574                                         else if( fu->orientation == OT_OPPOSITE )
02575                                                 nmg_vertexuse_nv( vu , rev_norm );
02576                                 }
02577                         }
02578                 }
02579         }
02580 
02581         /* Finished with storage, so free it */
02582         bu_free( (char *)factors, "rt_tgc_tess: factors" );
02583         bu_free( (char *)A , "rt_tgc_tess: A" );
02584         bu_free( (char *)B , "rt_tgc_tess: B" );
02585         for( i=0 ; i<nells ; i++ )
02586                 bu_free( (char *)pts[i] , "rt_tgc_tess: pts[i]" );
02587         bu_free( (char *)pts , "rt_tgc_tess: pts" );
02588 
02589         /* mark real edges for top and bottom faces */
02590         for( i=0 ; i<2 ; i++ )
02591         {
02592                 struct loopuse *lu;
02593 
02594                 if( i == 0 )
02595                         fu = fu_base;
02596                 else
02597                         fu = fu_top;
02598 
02599                 if( fu == (struct faceuse *)NULL )
02600                         continue;
02601 
02602                 NMG_CK_FACEUSE( fu );
02603 
02604                 for( BU_LIST_FOR( lu , loopuse , &fu->lu_hd ) )
02605                 {
02606                         struct edgeuse *eu;
02607 
02608                         NMG_CK_LOOPUSE( lu );
02609 
02610                         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
02611                                 continue;
02612 
02613                         for( BU_LIST_FOR( eu , edgeuse , &lu->down_hd ) )
02614                         {
02615                                 struct edge *e;
02616 
02617                                 NMG_CK_EDGEUSE( eu );
02618                                 e = eu->e_p;
02619                                 NMG_CK_EDGE( e );
02620                                 e->is_real = 1;
02621                         }
02622                 }
02623         }
02624 
02625         nmg_region_a( *r , tol );
02626 
02627         /* glue faces together */
02628         nmg_gluefaces( (struct faceuse **)BU_PTBL_BASEADDR( &faces) , BU_PTBL_END( &faces ), tol );
02629         bu_ptbl_free( &faces );
02630 
02631         return( 0 );
02632 }
02633 
02634 /**     R T _ T G C _ T N U R B
02635  *
02636  *  "Tessellate an TGC into a trimmed-NURB-NMG data structure.
02637  *  Computing NRUB surfaces and trimming curves to interpolate
02638  *  the parameters of the TGC
02639  *
02640  *  The process is to create the nmg  topology of the TGC fill it
02641  *  in with a unit cylinder geometry (i.e. unitcircle at the top (0,0,1)
02642  *  unit cylinder of radius 1, and unitcirlce at the bottom), and then
02643  *  scale it with a perspective matrix derived from the parameters of the
02644  *  tgc. The result is three trimmed nub surfaces which interpolate the
02645  *  parameters of  the original TGC.
02646  *
02647  *  Returns -
02648  *      -1      failure
02649  *      0       OK. *r points to nmgregion that holds this tesselation
02650  */
02651 
02652 int
02653 rt_tgc_tnurb(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct bn_tol *tol)
02654 {
02655         LOCAL struct rt_tgc_internal    *tip;
02656 
02657         struct shell                    *s;
02658         struct vertex                   *verts[2];
02659         struct vertex                   **vertp[4];
02660         struct faceuse                  * top_fu;
02661         struct faceuse                  * cyl_fu;
02662         struct faceuse                  * bot_fu;
02663         vect_t                          uvw;
02664         struct loopuse                  *lu;
02665         struct edgeuse                  *eu;
02666         struct edgeuse                  *top_eu;
02667         struct edgeuse                  *bot_eu;
02668 
02669         mat_t                           mat;
02670         mat_t                           imat, omat, top_mat, bot_mat;
02671         vect_t                          anorm;
02672         vect_t                          bnorm;
02673         vect_t                          cnorm;
02674 
02675 
02676         /* Get the internal representation of the tgc */
02677 
02678         RT_CK_DB_INTERNAL(ip);
02679         tip = (struct rt_tgc_internal *) ip->idb_ptr;
02680         RT_TGC_CK_MAGIC(tip);
02681 
02682         /* Create the NMG Topology */
02683 
02684         *r = nmg_mrsv( m );     /* Make region, empty shell, vertex */
02685         s = BU_LIST_FIRST( shell, &(*r)->s_hd);
02686 
02687 
02688         /* Create transformation matrix  for the top cap surface*/
02689 
02690         MAT_IDN( omat );
02691         MAT_IDN( mat);
02692 
02693         omat[0] = MAGNITUDE(tip->c);
02694         omat[5] = MAGNITUDE(tip->d);
02695         omat[3] = tip->v[0] + tip->h[0];
02696         omat[7] = tip->v[1] + tip->h[1];
02697         omat[11] = tip->v[2] + tip->h[2];
02698 
02699         bn_mat_mul(imat, mat, omat);
02700 
02701         VMOVE(anorm, tip->c);
02702         VMOVE(bnorm, tip->d);
02703         VCROSS(cnorm, tip->c, tip->d);
02704         VUNITIZE(anorm);
02705         VUNITIZE(bnorm);
02706         VUNITIZE(cnorm);
02707 
02708         MAT_IDN( omat );
02709 
02710         VMOVE( &omat[0], anorm);
02711         VMOVE( &omat[4], bnorm);
02712         VMOVE( &omat[8], cnorm);
02713 
02714 
02715         bn_mat_mul(top_mat, omat, imat);
02716 
02717         /* Create topology for top cap surface */
02718 
02719         verts[0] = verts[1] = NULL;
02720         vertp[0] = &verts[0];
02721         top_fu = nmg_cmface(s, vertp, 1);
02722 
02723         lu = BU_LIST_FIRST( loopuse, &top_fu->lu_hd);
02724         NMG_CK_LOOPUSE(lu);
02725         eu= BU_LIST_FIRST( edgeuse, &lu->down_hd);
02726         NMG_CK_EDGEUSE(eu);
02727         top_eu = eu;
02728 
02729         VSET( uvw, 0,0,0);
02730         nmg_vertexuse_a_cnurb( eu->vu_p, uvw);
02731         VSET( uvw, 1, 0, 0);
02732         nmg_vertexuse_a_cnurb( eu->eumate_p->vu_p, uvw );
02733         eu = BU_LIST_NEXT( edgeuse, &eu->l);
02734 
02735         /* Top cap surface */
02736         nmg_tgc_disk( top_fu, top_mat, 0.0, 0 );
02737 
02738         /* Create transformation matrix  for the bottom cap surface*/
02739 
02740         MAT_IDN( omat );
02741         MAT_IDN( mat);
02742 
02743         omat[0] = MAGNITUDE(tip->a);
02744         omat[5] = MAGNITUDE(tip->b);
02745         omat[3] = tip->v[0];
02746         omat[7] = tip->v[1];
02747         omat[11] = tip->v[2];
02748 
02749         bn_mat_mul(imat, mat, omat);
02750 
02751         VMOVE(anorm, tip->a);
02752         VMOVE(bnorm, tip->b);
02753         VCROSS(cnorm, tip->a, tip->b);
02754         VUNITIZE(anorm);
02755         VUNITIZE(bnorm);
02756         VUNITIZE(cnorm);
02757 
02758         MAT_IDN( omat );
02759 
02760         VMOVE( &omat[0], anorm);
02761         VMOVE( &omat[4], bnorm);
02762         VMOVE( &omat[8], cnorm);
02763 
02764         bn_mat_mul(bot_mat, omat, imat);
02765 
02766         /* Create topology for bottom cap surface */
02767 
02768         vertp[0] = &verts[1];
02769         bot_fu = nmg_cmface(s, vertp, 1);
02770 
02771         lu = BU_LIST_FIRST( loopuse, &bot_fu->lu_hd);
02772         NMG_CK_LOOPUSE(lu);
02773         eu= BU_LIST_FIRST( edgeuse, &lu->down_hd);
02774         NMG_CK_EDGEUSE(eu);
02775         bot_eu = eu;
02776 
02777         VSET( uvw, 0,0,0);
02778         nmg_vertexuse_a_cnurb( eu->vu_p, uvw);
02779         VSET( uvw, 1, 0, 0);
02780         nmg_vertexuse_a_cnurb( eu->eumate_p->vu_p, uvw );
02781 
02782 
02783         nmg_tgc_disk( bot_fu, bot_mat, 0.0, 1 );
02784 
02785         /* Create topology for cylinder surface  */
02786 
02787         vertp[0] = &verts[0];
02788         vertp[1] = &verts[0];
02789         vertp[2] = &verts[1];
02790         vertp[3] = &verts[1];
02791         cyl_fu = nmg_cmface(s, vertp, 4);
02792 
02793         nmg_tgc_nurb_cyl( cyl_fu, top_mat, bot_mat);
02794 
02795         /* fuse top cylinder edge to matching edge on body of cylinder */
02796         lu = BU_LIST_FIRST( loopuse, &cyl_fu->lu_hd);
02797 
02798         eu= BU_LIST_FIRST( edgeuse, &lu->down_hd);
02799 
02800         nmg_je( top_eu, eu );
02801 
02802         eu= BU_LIST_LAST( edgeuse, &lu->down_hd);
02803         eu= BU_LIST_LAST( edgeuse, &eu->l);
02804 
02805         nmg_je( bot_eu, eu );
02806         nmg_region_a( *r,tol);
02807 
02808         return( 0 );
02809 }
02810 
02811 
02812 #define RAT  .707107
02813 
02814 fastf_t nmg_tgc_unitcircle[36] = {
02815         1.0, 0.0, 0.0, 1.0,
02816         RAT, -RAT, 0.0, RAT,
02817         0.0, -1.0, 0.0, 1.0,
02818         -RAT, -RAT, 0.0, RAT,
02819         -1.0, 0.0, 0.0, 1.0,
02820         -RAT, RAT, 0.0, RAT,
02821         0.0, 1.0, 0.0, 1.0,
02822         RAT, RAT, 0.0, RAT,
02823         1.0, 0.0, 0.0, 1.0
02824 };
02825 
02826 fastf_t nmg_uv_unitcircle[27] = {
02827         1.0,   .5,  1.0,
02828         RAT,  RAT,  RAT,
02829         .5,   1.0,  1.0,
02830         0.0,  RAT,  RAT,
02831         0.0,   .5,  1.0,
02832         0.0,  0.0,  RAT,
02833         .5,   0.0,  1.0,
02834         RAT,  0.0,  RAT,
02835         1.0,   .5,  1.0
02836 };
02837 
02838 static void
02839 nmg_tgc_disk(struct faceuse *fu, fastf_t *rmat, fastf_t height, int flip)
02840 {
02841         struct face_g_snurb     * fg;
02842         struct loopuse          * lu;
02843         struct edgeuse          * eu;
02844         struct edge_g_cnurb     * eg;
02845         fastf_t *mptr;
02846         int i;
02847         vect_t  vect;
02848         point_t point;
02849 
02850         nmg_face_g_snurb( fu,
02851                 2, 2,                   /* u,v order */
02852                 4, 4,                   /* number of knots */
02853                 NULL, NULL,             /* initial knot vectors */
02854                 2, 2,                   /* n_rows, n_cols */
02855                 RT_NURB_MAKE_PT_TYPE(3, 2, 0),
02856                 NULL );                 /* Initial mesh */
02857 
02858         fg = fu->f_p->g.snurb_p;
02859 
02860 
02861         fg->u.knots[0] = 0.0;
02862         fg->u.knots[1] = 0.0;
02863         fg->u.knots[2] = 1.0;
02864         fg->u.knots[3] = 1.0;
02865 
02866         fg->v.knots[0] = 0.0;
02867         fg->v.knots[1] = 0.0;
02868         fg->v.knots[2] = 1.0;
02869         fg->v.knots[3] = 1.0;
02870 
02871         if(flip)
02872         {
02873                 fg->ctl_points[0] = 1.;
02874                 fg->ctl_points[1] = -1.;
02875                 fg->ctl_points[2] = height;
02876 
02877                 fg->ctl_points[3] = -1;
02878                 fg->ctl_points[4] = -1.;
02879                 fg->ctl_points[5] = height;
02880 
02881                 fg->ctl_points[6] = 1.;
02882                 fg->ctl_points[7] = 1.;
02883                 fg->ctl_points[8] = height;
02884 
02885                 fg->ctl_points[9] = -1.;
02886                 fg->ctl_points[10] = 1.;
02887                 fg->ctl_points[11] = height;
02888         } else
02889         {
02890 
02891                 fg->ctl_points[0] = -1.;
02892                 fg->ctl_points[1] = -1.;
02893                 fg->ctl_points[2] = height;
02894 
02895                 fg->ctl_points[3] = 1;
02896                 fg->ctl_points[4] = -1.;
02897                 fg->ctl_points[5] = height;
02898 
02899                 fg->ctl_points[6] = -1.;
02900                 fg->ctl_points[7] = 1.;
02901                 fg->ctl_points[8] = height;
02902 
02903                 fg->ctl_points[9] = 1.;
02904                 fg->ctl_points[10] = 1.;
02905                 fg->ctl_points[11] = height;
02906         }
02907 
02908         /* multiple the matrix to get orientation and scaling that we want */
02909         mptr = fg->ctl_points;
02910 
02911         i = fg->s_size[0] * fg->s_size[1];
02912 
02913         for( ; i> 0; i--)
02914         {
02915                 MAT4X3PNT(vect,rmat,mptr);
02916                 mptr[0] = vect[0];
02917                 mptr[1] = vect[1];
02918                 mptr[2] = vect[2];
02919                 mptr += 3;
02920         }
02921 
02922         lu = BU_LIST_FIRST( loopuse, &fu->lu_hd);
02923         NMG_CK_LOOPUSE(lu);
02924         eu= BU_LIST_FIRST( edgeuse, &lu->down_hd);
02925         NMG_CK_EDGEUSE(eu);
02926 
02927 
02928         if(!flip)
02929         {
02930                 rt_nurb_s_eval( fu->f_p->g.snurb_p,
02931                         nmg_uv_unitcircle[0], nmg_uv_unitcircle[1], point );
02932                 nmg_vertex_gv( eu->vu_p->v_p, point );
02933         } else
02934         {
02935                 rt_nurb_s_eval( fu->f_p->g.snurb_p,
02936                         nmg_uv_unitcircle[12], nmg_uv_unitcircle[13], point );
02937                 nmg_vertex_gv( eu->vu_p->v_p, point );
02938         }
02939 
02940         nmg_edge_g_cnurb(eu, 3, 12, NULL, 9, RT_NURB_MAKE_PT_TYPE(3,3,1),
02941                 NULL);
02942 
02943         eg = eu->g.cnurb_p;
02944         eg->order = 3;
02945 
02946         eg->k.knots[0] = 0.0;
02947         eg->k.knots[1] = 0.0;
02948         eg->k.knots[2] = 0.0;
02949         eg->k.knots[3] = .25;
02950         eg->k.knots[4] = .25;
02951         eg->k.knots[5] = .5;
02952         eg->k.knots[6] = .5;
02953         eg->k.knots[7] = .75;
02954         eg->k.knots[8] = .75;
02955         eg->k.knots[9] = 1.0;
02956         eg->k.knots[10] = 1.0;
02957         eg->k.knots[11] = 1.0;
02958 
02959         if( !flip )
02960         {
02961                 for( i = 0; i < 27; i++)
02962                         eg->ctl_points[i] = nmg_uv_unitcircle[i];
02963         }
02964         else
02965         {
02966 
02967                 VSET(&eg->ctl_points[0], 0.0, .5, 1.0);
02968                 VSET(&eg->ctl_points[3], 0.0, 0.0, RAT);
02969                 VSET(&eg->ctl_points[6], 0.5, 0.0, 1.0);
02970                 VSET(&eg->ctl_points[9], RAT, 0.0, RAT);
02971                 VSET(&eg->ctl_points[12], 1.0, .5, 1.0);
02972                 VSET(&eg->ctl_points[15], RAT,RAT, RAT);
02973                 VSET(&eg->ctl_points[18], .5, 1.0, 1.0);
02974                 VSET(&eg->ctl_points[21], 0.0, RAT, RAT);
02975                 VSET(&eg->ctl_points[24], 0.0, .5, 1.0);
02976         }
02977 }
02978 
02979 /* Create a cylinder with a top surface and a bottom surfce
02980  * defined by the ellipsods at the top and bottom of the
02981  * cylinder, the top_mat, and bot_mat are applied to a unit circle
02982  * for the top row of the surface and the bot row of the surface
02983  * respectively.
02984  */
02985 static void
02986 nmg_tgc_nurb_cyl(struct faceuse *fu, fastf_t *top_mat, fastf_t *bot_mat)
02987 {
02988         struct face_g_snurb     * fg;
02989         struct loopuse          * lu;
02990         struct edgeuse          * eu;
02991         fastf_t         * mptr;
02992         int             i;
02993         hvect_t         vect;
02994         point_t         uvw;
02995         point_t         point;
02996         hvect_t         hvect;
02997 
02998         nmg_face_g_snurb( fu,
02999                 3, 2,
03000                 12, 4,
03001                 NULL, NULL,
03002                 2, 9,
03003                 RT_NURB_MAKE_PT_TYPE(4,3,1),
03004                 NULL );
03005 
03006         fg = fu->f_p->g.snurb_p;
03007 
03008         fg->v.knots[0] = 0.0;
03009         fg->v.knots[1] = 0.0;
03010         fg->v.knots[2] = 1.0;
03011         fg->v.knots[3] = 1.0;
03012 
03013         fg->u.knots[0] = 0.0;
03014         fg->u.knots[1] = 0.0;
03015         fg->u.knots[2] = 0.0;
03016         fg->u.knots[3] = .25;
03017         fg->u.knots[4] = .25;
03018         fg->u.knots[5] = .5;
03019         fg->u.knots[6] = .5;
03020         fg->u.knots[7] = .75;
03021         fg->u.knots[8] = .75;
03022         fg->u.knots[9] = 1.0;
03023         fg->u.knots[10] = 1.0;
03024         fg->u.knots[11] = 1.0;
03025 
03026         mptr = fg->ctl_points;
03027 
03028         for(i = 0; i < 9; i++)
03029         {
03030                 MAT4X4PNT(vect, top_mat, &nmg_tgc_unitcircle[i*4]);
03031                 mptr[0] = vect[0];
03032                 mptr[1] = vect[1];
03033                 mptr[2] = vect[2];
03034                 mptr[3] = vect[3];
03035                 mptr += 4;
03036         }
03037 
03038         for(i = 0; i < 9; i++)
03039         {
03040                 MAT4X4PNT(vect, bot_mat, &nmg_tgc_unitcircle[i*4]);
03041                 mptr[0] = vect[0];
03042                 mptr[1] = vect[1];
03043                 mptr[2] = vect[2];
03044                 mptr[3] = vect[3];
03045                 mptr += 4;
03046         }
03047 
03048         /* Assign edgeuse parameters & vertex geometry */
03049 
03050         lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
03051         NMG_CK_LOOPUSE(lu);
03052         eu = BU_LIST_FIRST( edgeuse, &lu->down_hd);
03053         NMG_CK_EDGEUSE(eu);
03054 
03055         /* March around the fu's loop assigning uv parameter values */
03056 
03057         rt_nurb_s_eval( fg, 0.0, 0.0, hvect);
03058         HDIVIDE( point, hvect );
03059         nmg_vertex_gv( eu->vu_p->v_p, point );  /* 0,0 vertex */
03060 
03061         VSET( uvw, 0, 0, 0);
03062         nmg_vertexuse_a_cnurb( eu->vu_p, uvw );
03063         VSET( uvw, 1, 0, 0);
03064         nmg_vertexuse_a_cnurb( eu->eumate_p->vu_p, uvw );
03065         eu = BU_LIST_NEXT( edgeuse, &eu->l);
03066 
03067         VSET( uvw, 1, 0, 0);
03068         nmg_vertexuse_a_cnurb( eu->vu_p, uvw );
03069         VSET( uvw, 1, 1, 0);
03070         nmg_vertexuse_a_cnurb( eu->eumate_p->vu_p, uvw );
03071         eu = BU_LIST_NEXT( edgeuse, &eu->l);
03072 
03073         VSET( uvw, 1, 1, 0);
03074         nmg_vertexuse_a_cnurb( eu->vu_p, uvw );
03075         VSET( uvw, 0, 1, 0);
03076         nmg_vertexuse_a_cnurb( eu->eumate_p->vu_p, uvw );
03077 
03078         rt_nurb_s_eval( fg, 1., 1., hvect);
03079         HDIVIDE( point, hvect);
03080         nmg_vertex_gv( eu->vu_p->v_p, point );          /* 4,1 vertex */
03081 
03082         eu = BU_LIST_NEXT( edgeuse, &eu->l);
03083 
03084         VSET( uvw, 0, 1, 0);
03085         nmg_vertexuse_a_cnurb( eu->vu_p, uvw );
03086         VSET( uvw, 0, 0, 0);
03087         nmg_vertexuse_a_cnurb( eu->eumate_p->vu_p, uvw );
03088         eu = BU_LIST_NEXT( edgeuse, &eu->l);
03089 
03090         /* Create the edge loop geometry */
03091 
03092         lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
03093         NMG_CK_LOOPUSE(lu);
03094         eu = BU_LIST_FIRST( edgeuse, &lu->down_hd);
03095         NMG_CK_EDGEUSE(eu);
03096 
03097         for( i = 0; i < 4; i++)
03098         {
03099                 nmg_edge_g_cnurb_plinear(eu);
03100                 eu = BU_LIST_NEXT(edgeuse, &eu->l);
03101         }
03102 }
03103 
03104 /*
03105  * Local Variables:
03106  * mode: C
03107  * tab-width: 8
03108  * c-basic-offset: 4
03109  * indent-tabs-mode: t
03110  * End:
03111  * ex: shiftwidth=4 tabstop=8
03112  */

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