g_cline.c

Go to the documentation of this file.
00001 /*                       G _ C L I N E . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2000-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_cline.c
00026  *      Intersect a ray with a FASTGEN4 CLINE element.
00027  *
00028  *  Authors -
00029  *      John Anderson
00030  *
00031  *  Source -
00032  *      SECAD/VLD Computing Consortium, Bldg 394
00033  *      The U. S. Army Ballistic Research Laboratory
00034  *      Aberdeen Proving Ground, Maryland  21005-5066
00035  *
00036  */
00037 
00038 #ifndef lint
00039 static const char RCScline[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_cline.c,v 14.13 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00040 #endif
00041 
00042 #include "common.h"
00043 
00044 #include <stdlib.h>
00045 #include <stddef.h>
00046 #include <stdio.h>
00047 #include <math.h>
00048 
00049 #include "tcl.h"
00050 #include "machine.h"
00051 #include "vmath.h"
00052 #include "db.h"
00053 #include "nmg.h"
00054 #include "raytrace.h"
00055 #include "rtgeom.h"
00056 #include "./debug.h"
00057 
00058 /* ray tracing form of solid, including precomputed terms */
00059 struct cline_specific {
00060         point_t V;
00061         vect_t height;
00062         fastf_t radius;
00063         fastf_t thickness;
00064         vect_t h;       /* unitized height */
00065 };
00066 
00067 #define RT_CLINE_O(m)   bu_offsetof( struct rt_cline_internal, m )
00068 
00069 const struct bu_structparse rt_cline_parse[] = {
00070         { "%f", 3, "V", RT_CLINE_O( v ),  BU_STRUCTPARSE_FUNC_NULL },
00071         { "%f", 3, "H", RT_CLINE_O( h ),  BU_STRUCTPARSE_FUNC_NULL },
00072         { "%f", 1, "r", RT_CLINE_O( radius ), BU_STRUCTPARSE_FUNC_NULL },
00073         { "%f", 1, "t", RT_CLINE_O( thickness ), BU_STRUCTPARSE_FUNC_NULL },
00074         { {'\0','\0','\0','\0'}, 0, (char *)NULL, 0, BU_STRUCTPARSE_FUNC_NULL }
00075         };
00076 
00077 /* shared with do.c */
00078 fastf_t rt_cline_radius=-1.0;
00079 
00080 /**
00081  *                      R T _ C L I N E _ P R E P
00082  *
00083  *  Given a pointer to a GED database record,
00084  *  determine if this is a valid cline solid, and if so, precompute various
00085  *  terms of the formula.
00086  *
00087  *  Returns -
00088  *      0       cline is OK
00089  *      !0      Error in description
00090  *
00091  *  Implicit return -
00092  *      A struct cline_specific is created, and it's address is stored in
00093  *      stp->st_specific for use by rt_cline_shot().
00094  */
00095 int
00096 rt_cline_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00097 {
00098         struct rt_cline_internal                *cline_ip;
00099         register struct cline_specific          *cline;
00100         vect_t                                  work;
00101         vect_t                                  rad;
00102         point_t                                 top;
00103         fastf_t                                 tmp;
00104         fastf_t                                 max_tr;
00105 
00106         RT_CK_DB_INTERNAL(ip);
00107         cline_ip = (struct rt_cline_internal *)ip->idb_ptr;
00108         RT_CLINE_CK_MAGIC(cline_ip);
00109 
00110         BU_GETSTRUCT( cline, cline_specific );
00111         cline->thickness = cline_ip->thickness;
00112         cline->radius = cline_ip->radius;
00113         VMOVE( cline->V, cline_ip->v );
00114         VMOVE( cline->height, cline_ip->h );
00115         VMOVE( cline->h, cline_ip->h );
00116         VUNITIZE( cline->h );
00117         stp->st_specific = (genptr_t)cline;
00118 
00119         if( rt_cline_radius > 0.0 )
00120                 max_tr = rt_cline_radius;
00121         else
00122                 max_tr = 0.0;
00123         tmp = MAGNITUDE( cline_ip->h ) * 0.5;
00124         stp->st_aradius = sqrt( tmp*tmp + cline_ip->radius*cline_ip->radius );
00125         stp->st_bradius = stp->st_aradius + max_tr;
00126         VSETALL( stp->st_min, MAX_FASTF );
00127         VREVERSE( stp->st_max, stp->st_min );
00128 
00129         VSETALL( rad, cline_ip->radius + max_tr );
00130         VADD2( work, cline_ip->v, rad );
00131         VMINMAX( stp->st_min,stp->st_max, work );
00132         VSUB2( work, cline_ip->v, rad );
00133         VMINMAX( stp->st_min,stp->st_max, work );
00134         VADD2( top, cline_ip->v, cline_ip->h );
00135         VADD2( work, top, rad );
00136         VMINMAX( stp->st_min,stp->st_max, work );
00137         VSUB2( work, top, rad );
00138         VMINMAX( stp->st_min,stp->st_max, work );
00139 
00140         return( 0 );
00141 }
00142 
00143 /**
00144  *                      R T _ C L I N E _ P R I N T
00145  */
00146 void
00147 rt_cline_print(register const struct soltab *stp)
00148 {
00149         register const struct cline_specific *cline =
00150                 (struct cline_specific *)stp->st_specific;
00151 
00152         VPRINT( "V", cline->V );
00153         VPRINT( "Height", cline->height );
00154         VPRINT( "Unit Height", cline->h );
00155         bu_log( "Radius: %g\n", cline->radius );
00156         if( cline->thickness > 0.0 )
00157                 bu_log( "Plate Mode Thickness: %g\n", cline->thickness );
00158         else
00159                 bu_log( "Volume mode\n" );
00160 }
00161 
00162 /**
00163  *                      R T _ C L I N E _ S H O T
00164  *
00165  *  Intersect a ray with a cline mode solid.
00166  *  If an intersection occurs, at least one struct seg will be acquired
00167  *  and filled in.
00168  *
00169  *  Returns -
00170  *      0       MISS
00171  *      >0      HIT
00172  */
00173 int
00174 rt_cline_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00175 {
00176         register struct cline_specific *cline =
00177                 (struct cline_specific *)stp->st_specific;
00178         struct seg              ref_seghead;
00179         register struct seg     *segp;
00180         fastf_t reff;
00181         fastf_t dist[3];
00182         fastf_t cosa, sina;
00183         fastf_t half_los;
00184         point_t pt1, pt2;
00185         vect_t diff;
00186         fastf_t tmp;
00187         fastf_t distmin, distmax;
00188         fastf_t add_radius;
00189 
00190         BU_LIST_INIT( &ref_seghead.l );
00191 
00192         /* This is a CLINE FASTGEN element */
00193         if( rt_cline_radius > 0.0 )
00194         {
00195                 add_radius = rt_cline_radius;
00196                 reff = cline->radius + add_radius;
00197         }
00198         else
00199         {
00200                 add_radius = 0.0;
00201                 reff = cline->radius;
00202         }
00203 
00204         cosa = VDOT( rp->r_dir, cline->h );
00205 
00206         if( cosa > 0.0 )
00207                 tmp = cosa - 1.0;
00208         else
00209                 tmp = cosa + 1.0;
00210 
00211         (void)bn_distsq_line3_line3( dist, cline->V, cline->height,
00212                                      rp->r_pt, rp->r_dir, pt1, pt2 );
00213 
00214         if( NEAR_ZERO( tmp, RT_DOT_TOL ) )
00215         {
00216                 /* ray is parallel to CLINE */
00217 #if 1
00218                 /* FASTGEN developers claim they report hits on volume mode
00219                  * when ray is parallel to CLINE axis, but their code drops
00220                  * this case from consideration before their intersection code
00221                  * is even called (see SUBROUTINE BULK)
00222                  */
00223                 return( 0 );
00224 #else
00225 
00226                 if( cline->thickness > 0.0 )
00227                         return( 0 );    /* No end-on hits for plate mode cline */
00228 
00229                 if( dist[2] > reff*reff )
00230                         return( 0 );    /* missed */
00231 
00232                 VJOIN2( diff, cline->V, 1.0, cline->height, -1.0, rp->r_pt );
00233                 dist[0] = VDOT( diff, rp->r_dir );
00234                 if( dist[1] < dist[0] )
00235                 {
00236                         dist[2] = dist[0];
00237                         dist[0] = dist[1];
00238                         dist[1] = dist[2];
00239                 }
00240 
00241                 /* vloume mode */
00242 
00243                 RT_GET_SEG( segp, ap->a_resource);
00244                 segp->seg_stp = stp;
00245                 segp->seg_in.hit_dist = dist[0];
00246                 segp->seg_in.hit_surfno = 1;
00247                 if( cosa > 0.0 )
00248                         VREVERSE( segp->seg_in.hit_normal, cline->h )
00249                 else
00250                         VMOVE( segp->seg_in.hit_normal, cline->h );
00251 
00252                 segp->seg_out.hit_dist = dist[1];
00253                 segp->seg_out.hit_surfno = -1;
00254                 if( cosa < 0.0 )
00255                         VREVERSE( segp->seg_out.hit_normal, cline->h )
00256                 else
00257                         VMOVE( segp->seg_out.hit_normal, cline->h );
00258                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00259                 return( 1 );
00260 #endif
00261         }
00262 
00263         if( dist[2] > reff*reff )
00264                 return( 0 );    /* missed */
00265 
00266 
00267         /* Exactly ==0 and ==1 are hits, not misses */
00268         if( dist[0] < 0.0 || dist[0] > 1.0 )
00269                 return( 0 );    /* missed */
00270 
00271         sina = sqrt( 1.0 - cosa*cosa);
00272         tmp = sqrt( dist[2] ) - add_radius;
00273         if( dist[2] > add_radius * add_radius )
00274                 half_los = sqrt( cline->radius*cline->radius - tmp*tmp) / sina;
00275         else
00276                 half_los = cline->radius / sina;
00277 
00278         VSUB2( diff, cline->V, rp->r_pt );
00279         distmin = VDOT( rp->r_dir, diff );
00280         VADD2( diff, cline->V, cline->height );
00281         VSUB2( diff, diff, rp->r_pt );
00282         distmax = VDOT( rp->r_dir, diff );
00283 
00284         if( distmin > distmax )
00285         {
00286                 tmp = distmin;
00287                 distmin = distmax;
00288                 distmax = tmp;
00289         }
00290 
00291         distmin -= cline->radius;
00292         distmax += cline->radius;
00293 
00294         if( cline->thickness <= 0.0 )
00295         {
00296                 /* volume mode */
00297 
00298                 RT_GET_SEG( segp, ap->a_resource);
00299                 segp->seg_stp = stp;
00300                 segp->seg_in.hit_surfno = 2;
00301                 segp->seg_in.hit_dist = dist[1] - half_los;
00302                 if( segp->seg_in.hit_dist < distmin )
00303                         segp->seg_in.hit_dist = distmin;
00304                 VMOVE( segp->seg_in.hit_vpriv, cline->h );
00305 
00306                 segp->seg_out.hit_surfno = -2;
00307                 segp->seg_out.hit_dist = dist[1] + half_los;
00308                 if( segp->seg_out.hit_dist > distmax )
00309                         segp->seg_out.hit_dist = distmax;
00310                 VMOVE( segp->seg_out.hit_vpriv, cline->h );
00311                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00312 
00313                 return( 1 );
00314         }
00315         else
00316         {
00317                 /* plate mode */
00318 
00319                 RT_GET_SEG( segp, ap->a_resource);
00320                         segp->seg_stp = stp;
00321                         segp->seg_in.hit_surfno = 2;
00322                 segp->seg_in.hit_dist = dist[1] - half_los;
00323                 if( segp->seg_in.hit_dist < distmin )
00324                         segp->seg_in.hit_dist = distmin;
00325                 VMOVE( segp->seg_in.hit_vpriv, cline->h );
00326 
00327                 segp->seg_out.hit_surfno = -2;
00328                 segp->seg_out.hit_dist = segp->seg_in.hit_dist + cline->thickness;
00329                 VMOVE( segp->seg_out.hit_vpriv, cline->h );
00330                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00331 
00332                 RT_GET_SEG( segp, ap->a_resource);
00333                         segp->seg_stp = stp;
00334                         segp->seg_in.hit_surfno = 2;
00335                 segp->seg_in.hit_dist = dist[1] + half_los;
00336                 if( segp->seg_in.hit_dist > distmax )
00337                         segp->seg_in.hit_dist = distmax;
00338                 segp->seg_in.hit_dist -=  cline->thickness;
00339                 VMOVE( segp->seg_in.hit_vpriv, cline->h );
00340 
00341                 segp->seg_out.hit_surfno = -2;
00342                 segp->seg_out.hit_dist = segp->seg_in.hit_dist + cline->thickness;
00343                 VMOVE( segp->seg_out.hit_vpriv, cline->h );
00344                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00345 
00346                 return( 2 );
00347         }
00348 }
00349 
00350 #define RT_CLINE_SEG_MISS(SEG)  (SEG).seg_stp=RT_SOLTAB_NULL
00351 
00352 /**
00353  *                      R T _ C L I N E _ V S H O T
00354  *
00355  *  Vectorized version.
00356  */
00357 void
00358 rt_cline_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
00359                                /* An array of solid pointers */
00360                                /* An array of ray pointers */
00361                                /* array of segs (results returned) */
00362                                /* Number of ray/object pairs */
00363 
00364 {
00365         rt_vstub( stp, rp, segp, n, ap );
00366 }
00367 
00368 /**
00369  *                      R T _ C L I N E _ N O R M
00370  *
00371  *  Given ONE ray distance, return the normal and entry/exit point.
00372  */
00373 void
00374 rt_cline_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00375 {
00376         vect_t tmp;
00377         fastf_t dot;
00378 
00379         if( hitp->hit_surfno == 1 || hitp->hit_surfno == -1 )
00380                 return;
00381 
00382         /* only need to do some calculations for surfno 2 or -2 */
00383 
00384         /* this is wrong, but agrees with FASTGEN */
00385         VCROSS( tmp, rp->r_dir, hitp->hit_vpriv );
00386         VCROSS( hitp->hit_normal, tmp, hitp->hit_vpriv );
00387         VUNITIZE( hitp->hit_normal );
00388         dot = VDOT( hitp->hit_normal, rp->r_dir );
00389         if( dot < 0.0 && hitp->hit_surfno < 0 )
00390                 VREVERSE( hitp->hit_normal, hitp->hit_normal )
00391         else if( dot >  0.0 && hitp->hit_surfno > 0 )
00392                 VREVERSE( hitp->hit_normal, hitp->hit_normal )
00393 
00394         if( MAGNITUDE( hitp->hit_normal ) < 0.9 ) {
00395                 bu_log( "BAD normal for solid %s for ray -p %g %g %g -d %g %g %g\n",
00396                         stp->st_name, V3ARGS( rp->r_pt ), V3ARGS( rp->r_dir ) );
00397                 bu_bomb( "BAD normal\n" );
00398         }
00399         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
00400 }
00401 
00402 /**
00403  *                      R T _ C L I N E _ C U R V E
00404  *
00405  *  Return the curvature of the cline.
00406  */
00407 void
00408 rt_cline_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00409 {
00410 
00411         /* for now, don't do curvature */
00412         cvp->crv_c1 = cvp->crv_c2 = 0;
00413 
00414         /* any tangent direction */
00415         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00416 }
00417 
00418 /**
00419  *                      R T _ C L I N E_ U V
00420  *
00421  *  For a hit on the surface of an cline, return the (u,v) coordinates
00422  *  of the hit point, 0 <= u,v <= 1.
00423  */
00424 void
00425 rt_cline_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00426 {
00427         uvp->uv_u = 0.0;
00428         uvp->uv_v = 0.0;
00429         uvp->uv_du = 0.0;
00430         uvp->uv_dv = 0.0;
00431 }
00432 
00433 /**
00434  *              R T _ C L I N E _ F R E E
00435  */
00436 void
00437 rt_cline_free(register struct soltab *stp)
00438 {
00439         register struct cline_specific *cline =
00440                 (struct cline_specific *)stp->st_specific;
00441 
00442         bu_free( (char *)cline, "cline_specific" );
00443 }
00444 
00445 /**
00446  *                      R T _ C L I N E _ C L A S S
00447  */
00448 int
00449 rt_cline_class(const struct soltab *stp, const fastf_t *min, const fastf_t *max, const struct bn_tol *tol)
00450 {
00451 
00452         return( 0 );
00453 }
00454 
00455 /**
00456  *                      R T _ C L I N E _ P L O T
00457  */
00458 int
00459 rt_cline_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00460 {
00461         LOCAL struct rt_cline_internal  *cline_ip;
00462         LOCAL fastf_t           top[16*3];
00463         LOCAL fastf_t           bottom[16*3];
00464         point_t top_pt;
00465         vect_t unit_a, unit_b;
00466         vect_t a, b;
00467         fastf_t inner_radius;
00468         int i;
00469 
00470         RT_CK_DB_INTERNAL(ip);
00471         cline_ip = (struct rt_cline_internal *)ip->idb_ptr;
00472         RT_CLINE_CK_MAGIC(cline_ip);
00473 
00474         VADD2( top_pt, cline_ip->v, cline_ip->h );
00475         bn_vec_ortho( unit_a, cline_ip->h );
00476         VCROSS( unit_b, unit_a, cline_ip->h );
00477         VUNITIZE( unit_b );
00478         VSCALE( a, unit_a, cline_ip->radius );
00479         VSCALE( b, unit_b, cline_ip->radius );
00480 
00481         rt_ell_16pts( bottom, cline_ip->v, a, b );
00482         rt_ell_16pts( top, top_pt, a, b );
00483 
00484         /* Draw the top */
00485         RT_ADD_VLIST( vhead, &top[15*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
00486         for( i=0; i<16; i++ )  {
00487                 RT_ADD_VLIST( vhead, &top[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
00488         }
00489 
00490         /* Draw the bottom */
00491         RT_ADD_VLIST( vhead, &bottom[15*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
00492         for( i=0; i<16; i++ )  {
00493                 RT_ADD_VLIST( vhead, &bottom[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
00494         }
00495 
00496         /* Draw connections */
00497         for( i=0; i<16; i += 4 )  {
00498                 RT_ADD_VLIST( vhead, &top[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
00499                 RT_ADD_VLIST( vhead, &bottom[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
00500         }
00501 
00502         if( cline_ip->thickness > 0.0 && cline_ip->thickness < cline_ip->radius )
00503         {
00504                 /* draw inner cylinder */
00505 
00506                 inner_radius = cline_ip->radius - cline_ip->thickness;
00507 
00508                 VSCALE( a, unit_a, inner_radius );
00509                 VSCALE( b, unit_b, inner_radius );
00510 
00511                 rt_ell_16pts( bottom, cline_ip->v, a, b );
00512                 rt_ell_16pts( top, top_pt, a, b );
00513 
00514                 /* Draw the top */
00515                 RT_ADD_VLIST( vhead, &top[15*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
00516                 for( i=0; i<16; i++ )  {
00517                         RT_ADD_VLIST( vhead, &top[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
00518                 }
00519 
00520                 /* Draw the bottom */
00521                 RT_ADD_VLIST( vhead, &bottom[15*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
00522                 for( i=0; i<16; i++ )  {
00523                         RT_ADD_VLIST( vhead, &bottom[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
00524                 }
00525 
00526                 /* Draw connections */
00527                 for( i=0; i<16; i += 4 )  {
00528                         RT_ADD_VLIST( vhead, &top[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
00529                         RT_ADD_VLIST( vhead, &bottom[i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
00530                 }
00531 
00532         }
00533 
00534         return(0);
00535 }
00536 
00537 struct cline_vert {
00538         point_t pt;
00539         struct vertex *v;
00540 };
00541 
00542 /**
00543  *                      R T _ C L I N E _ T E S S
00544  *
00545  *  Returns -
00546  *      -1      failure
00547  *       0      OK.  *r points to nmgregion that holds this tessellation.
00548  */
00549 int
00550 rt_cline_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00551 {
00552         struct shell                    *s;
00553         struct rt_cline_internal        *cline_ip;
00554         fastf_t                         ang_tol, abs_tol, norm_tol, rel_tol;
00555         int                             nsegs, seg_no, i;
00556         struct cline_vert               *base_outer, *base_inner, *top_outer, *top_inner;
00557         struct cline_vert               base_center, top_center;
00558         vect_t                          v1, v2;
00559         point_t                         top;
00560         struct bu_ptbl                  faces;
00561 
00562         RT_CK_DB_INTERNAL(ip);
00563         cline_ip = (struct rt_cline_internal *)ip->idb_ptr;
00564         RT_CLINE_CK_MAGIC(cline_ip);
00565 
00566         *r = nmg_mrsv( m );
00567         s = BU_LIST_FIRST(shell, &(*r)->s_hd);
00568 
00569         ang_tol = bn_halfpi;
00570         abs_tol = bn_halfpi;
00571         rel_tol = bn_halfpi;
00572         norm_tol = bn_halfpi;
00573 
00574         if( ttol->abs <= 0.0 && ttol->rel <= 0.0 && ttol->norm <= 0.0 )
00575         {
00576                 /* no tolerances specified, use 10% relative tolerance */
00577                 ang_tol = 2.0 * acos( 0.9 );
00578         }
00579         else
00580         {
00581                 if( ttol->abs > 0.0 && ttol->abs < cline_ip->radius )
00582                         abs_tol = 2.0 * acos( 1.0 - ttol->abs / cline_ip->radius );
00583                 if( ttol->rel > 0.0 && ttol->rel < 1.0 )
00584                         rel_tol = 2.0 * acos( 1.0 - ttol->rel );
00585                 if( ttol->norm > 0.0 )
00586                         norm_tol = 2.0 * ttol->norm;
00587         }
00588 
00589         if( abs_tol < ang_tol )
00590                 ang_tol = abs_tol;
00591         if( rel_tol < ang_tol )
00592                 ang_tol = rel_tol;
00593         if( norm_tol < ang_tol )
00594                 ang_tol = norm_tol;
00595 
00596         /* get number of segments per quadrant */
00597         nsegs = (int)(bn_halfpi / ang_tol + 0.9999);
00598         if( nsegs < 2 )
00599                 nsegs = 2;
00600 
00601         ang_tol = bn_halfpi / nsegs;
00602 
00603         /* and for complete circle */
00604         nsegs *= 4;
00605 
00606         /* allocate memory for arrays of vertices */
00607         base_outer = (struct cline_vert *)bu_calloc( nsegs, sizeof( struct cline_vert ), "base outer vertices" );
00608         top_outer = (struct cline_vert *)bu_calloc( nsegs, sizeof( struct cline_vert ), "top outer vertices" );
00609 
00610         if( cline_ip->thickness > 0.0 && cline_ip->thickness < cline_ip->radius )
00611         {
00612                 base_inner = (struct cline_vert *)bu_calloc( nsegs, sizeof( struct cline_vert ), "base inner vertices" );
00613                 top_inner = (struct cline_vert *)bu_calloc( nsegs, sizeof( struct cline_vert ), "top inner vertices" );
00614         } else {
00615                 base_inner = NULL;
00616                 top_inner = NULL;
00617         }
00618 
00619         /* calculate geometry for each vertex */
00620         bn_vec_ortho( v1, cline_ip->h );
00621         VCROSS( v2, cline_ip->h, v1 );
00622         VUNITIZE( v2 );
00623         VADD2( top, cline_ip->v, cline_ip->h );
00624         for( seg_no = 0; seg_no < nsegs ; seg_no++ )
00625         {
00626                 fastf_t a, b, c, d, angle;
00627 
00628                 angle = ang_tol * seg_no;
00629 
00630                 a = cos( angle );
00631                 b = sin( angle );
00632 
00633                 if( cline_ip->thickness > 0.0 && cline_ip->thickness < cline_ip->radius )
00634                 {
00635                         c = a * (cline_ip->radius - cline_ip->thickness);
00636                         d = b * (cline_ip->radius - cline_ip->thickness);
00637                 } else {
00638                         c = d = 0;
00639                 }
00640 
00641                 a *= cline_ip->radius;
00642                 b *= cline_ip->radius;
00643 
00644                 VJOIN2( base_outer[seg_no].pt, cline_ip->v, a, v1, b, v2 );
00645                 VADD2( top_outer[seg_no].pt, base_outer[seg_no].pt, cline_ip->h );
00646 
00647                 if( cline_ip->thickness > 0.0 && cline_ip->thickness < cline_ip->radius )
00648                 {
00649                         VJOIN2( base_inner[seg_no].pt, cline_ip->v, c, v1, d, v2 );
00650                         VADD2( top_inner[seg_no].pt, base_inner[seg_no].pt, cline_ip->h );
00651                 }
00652         }
00653 
00654         bu_ptbl_init( &faces , 64, "faces");
00655         /* build outer faces */
00656         for( seg_no=0 ; seg_no<nsegs ; seg_no++ )
00657         {
00658                 int next_seg;
00659                 struct vertex **verts[3];
00660                 struct faceuse *fu;
00661 
00662                 next_seg = seg_no + 1;
00663                 if( next_seg == nsegs )
00664                         next_seg = 0;
00665 
00666                 verts[2] = &top_outer[seg_no].v;
00667                 verts[1] = &top_outer[next_seg].v;
00668                 verts[0] = &base_outer[seg_no].v;
00669 
00670                 fu = nmg_cmface( s, verts, 3 );
00671                 bu_ptbl_ins( &faces , (long *)fu );
00672 
00673                 verts[2] = &base_outer[seg_no].v;
00674                 verts[1] = &top_outer[next_seg].v;
00675                 verts[0] = &base_outer[next_seg].v;
00676 
00677                 fu = nmg_cmface( s, verts, 3 );
00678                 bu_ptbl_ins( &faces , (long *)fu );
00679         }
00680 
00681         /* build inner faces */
00682         if( cline_ip->thickness > 0.0 && cline_ip->thickness < cline_ip->radius )
00683         {
00684                 for( seg_no=0 ; seg_no<nsegs ; seg_no++ )
00685                 {
00686                         int next_seg;
00687                         struct vertex **verts[3];
00688                         struct faceuse *fu;
00689 
00690                         next_seg = seg_no + 1;
00691                         if( next_seg == nsegs )
00692                                 next_seg = 0;
00693 
00694                         verts[0] = &top_inner[seg_no].v;
00695                         verts[1] = &top_inner[next_seg].v;
00696                         verts[2] = &base_inner[seg_no].v;
00697 
00698                         fu = nmg_cmface( s, verts, 3 );
00699                         bu_ptbl_ins( &faces , (long *)fu );
00700 
00701                         verts[0] = &base_inner[seg_no].v;
00702                         verts[1] = &top_inner[next_seg].v;
00703                         verts[2] = &base_inner[next_seg].v;
00704 
00705                         fu = nmg_cmface( s, verts, 3 );
00706                         bu_ptbl_ins( &faces , (long *)fu );
00707                 }
00708         }
00709 
00710         /* build top faces */
00711         top_center.v = (struct vertex *)NULL;
00712         VMOVE( top_center.pt, top );
00713         for( seg_no=0 ; seg_no<nsegs ; seg_no++ )
00714         {
00715                 int next_seg;
00716                 struct vertex **verts[3];
00717                 struct faceuse *fu;
00718 
00719                 next_seg = seg_no + 1;
00720                 if( next_seg == nsegs )
00721                         next_seg = 0;
00722 
00723                 if( cline_ip->thickness > 0.0 && cline_ip->thickness < cline_ip->radius )
00724                 {
00725                         verts[2] = &top_outer[seg_no].v;
00726                         verts[1] = &top_inner[seg_no].v;
00727                         verts[0] = &top_inner[next_seg].v;
00728                         fu = nmg_cmface( s, verts, 3 );
00729                         bu_ptbl_ins( &faces , (long *)fu );
00730 
00731                         verts[2] = &top_inner[next_seg].v;
00732                         verts[1] = &top_outer[next_seg].v;
00733                         verts[0] = &top_outer[seg_no].v;
00734                         fu = nmg_cmface( s, verts, 3 );
00735                         bu_ptbl_ins( &faces , (long *)fu );
00736                 }
00737                 else
00738                 {
00739                         verts[2] = &top_outer[seg_no].v;
00740                         verts[1] = &top_center.v;
00741                         verts[0] = &top_outer[next_seg].v;
00742                         fu = nmg_cmface( s, verts, 3 );
00743                         bu_ptbl_ins( &faces , (long *)fu );
00744                 }
00745         }
00746 
00747         /* build base faces */
00748         base_center.v = (struct vertex *)NULL;
00749         VMOVE( base_center.pt, cline_ip->v );
00750         for( seg_no=0 ; seg_no<nsegs ; seg_no++ )
00751         {
00752                 int next_seg;
00753                 struct vertex **verts[3];
00754                 struct faceuse *fu;
00755 
00756                 next_seg = seg_no + 1;
00757                 if( next_seg == nsegs )
00758                         next_seg = 0;
00759 
00760                 if( cline_ip->thickness > 0.0 && cline_ip->thickness < cline_ip->radius )
00761                 {
00762                         verts[0] = &base_outer[seg_no].v;
00763                         verts[1] = &base_inner[seg_no].v;
00764                         verts[2] = &base_inner[next_seg].v;
00765                         fu = nmg_cmface( s, verts, 3 );
00766                         bu_ptbl_ins( &faces , (long *)fu );
00767 
00768                         verts[0] = &base_inner[next_seg].v;
00769                         verts[1] = &base_outer[next_seg].v;
00770                         verts[2] = &base_outer[seg_no].v;
00771                         fu = nmg_cmface( s, verts, 3 );
00772                         bu_ptbl_ins( &faces , (long *)fu );
00773                 }
00774                 else
00775                 {
00776                         verts[0] = &base_outer[seg_no].v;
00777                         verts[1] = &base_center.v;
00778                         verts[2] = &base_outer[next_seg].v;
00779                         fu = nmg_cmface( s, verts, 3 );
00780                         bu_ptbl_ins( &faces , (long *)fu );
00781                 }
00782         }
00783 
00784         /* assign vertex geometry */
00785         if( top_center.v )
00786                 nmg_vertex_gv( top_center.v, top_center.pt );
00787         if( base_center.v )
00788                 nmg_vertex_gv( base_center.v, base_center.pt );
00789 
00790         for( seg_no=0 ; seg_no<nsegs ; seg_no++ )
00791         {
00792                 nmg_vertex_gv( top_outer[seg_no].v, top_outer[seg_no].pt );
00793                 nmg_vertex_gv( base_outer[seg_no].v, base_outer[seg_no].pt );
00794         }
00795 
00796         if( cline_ip->thickness > 0.0 && cline_ip->thickness < cline_ip->radius )
00797         {
00798                 for( seg_no=0 ; seg_no<nsegs ; seg_no++ )
00799                 {
00800                         nmg_vertex_gv( top_inner[seg_no].v, top_inner[seg_no].pt );
00801                         nmg_vertex_gv( base_inner[seg_no].v, base_inner[seg_no].pt );
00802                 }
00803         }
00804 
00805         bu_free( (char *)base_outer, "base outer vertices" );
00806         bu_free( (char *)top_outer, "top outer vertices" );
00807         if( cline_ip->thickness > 0.0 && cline_ip->thickness < cline_ip->radius )
00808         {
00809                 bu_free( (char *)base_inner, "base inner vertices" );
00810                 bu_free( (char *)top_inner, "top inner vertices" );
00811         }
00812 
00813         /* Associate face plane equations */
00814         for( i=0 ; i<BU_PTBL_END( &faces ) ; i++ )
00815         {
00816                 struct faceuse *fu;
00817 
00818                 fu = (struct faceuse *)BU_PTBL_GET( &faces , i );
00819                 NMG_CK_FACEUSE( fu );
00820 
00821                 if( nmg_calc_face_g( fu ) )
00822                 {
00823                         bu_log( "rt_tess_cline: failed to calculate plane equation\n" );
00824                         nmg_pr_fu_briefly( fu, "" );
00825                         return( -1 );
00826                 }
00827         }
00828 
00829         nmg_region_a( *r , tol );
00830         bu_ptbl_free( &faces );
00831 
00832         return(0);
00833 }
00834 
00835 /**
00836  *                      R T _ C L I N E _ I M P O R T
00837  *
00838  *  Import an cline from the database format to the internal format.
00839  *  Apply modeling transformations as well.
00840  */
00841 int
00842 rt_cline_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
00843 {
00844         LOCAL struct rt_cline_internal  *cline_ip;
00845         union record                    *rp;
00846         point_t                         work;
00847 
00848         BU_CK_EXTERNAL( ep );
00849         rp = (union record *)ep->ext_buf;
00850         /* Check record type */
00851 
00852         if( rp->u_id != DBID_CLINE )  {
00853                 bu_log("rt_cline_import: defective record\n");
00854                 return(-1);
00855         }
00856 
00857         RT_CK_DB_INTERNAL( ip );
00858         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00859         ip->idb_type = ID_CLINE;
00860         ip->idb_meth = &rt_functab[ID_CLINE];
00861         ip->idb_ptr = bu_malloc( sizeof(struct rt_cline_internal), "rt_cline_internal");
00862         cline_ip = (struct rt_cline_internal *)ip->idb_ptr;
00863         cline_ip->magic = RT_CLINE_INTERNAL_MAGIC;
00864         ntohd( (unsigned char *)(&cline_ip->thickness), rp->cli.cli_thick, 1 );
00865         cline_ip->thickness /= mat[15];
00866         ntohd( (unsigned char *)(&cline_ip->radius), rp->cli.cli_radius, 1 );
00867         cline_ip->radius /= mat[15];
00868         ntohd( (unsigned char *)(&work), rp->cli.cli_V, 3 );
00869         MAT4X3PNT( cline_ip->v, mat, work );
00870         ntohd( (unsigned char *)(&work), rp->cli.cli_h, 3 );
00871         MAT4X3VEC( cline_ip->h, mat, work );
00872 
00873         return(0);                      /* OK */
00874 }
00875 
00876 /**
00877  *                      R T _ C L I N E _ E X P O R T
00878  *
00879  *  The name is added by the caller, in the usual place.
00880  */
00881 int
00882 rt_cline_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00883 {
00884         struct rt_cline_internal        *cline_ip;
00885         union record                    *rec;
00886         fastf_t                         tmp;
00887         point_t                         work;
00888 
00889         RT_CK_DB_INTERNAL(ip);
00890         if( ip->idb_type != ID_CLINE )  return(-1);
00891         cline_ip = (struct rt_cline_internal *)ip->idb_ptr;
00892         RT_CLINE_CK_MAGIC(cline_ip);
00893 
00894         BU_CK_EXTERNAL(ep);
00895         ep->ext_nbytes = sizeof(union record);
00896         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "cline external");
00897         rec = (union record *)ep->ext_buf;
00898 
00899         rec->s.s_id = ID_SOLID;
00900         rec->cli.cli_id = DBID_CLINE;   /* GED primitive type from db.h */
00901 
00902         tmp = cline_ip->thickness * local2mm;
00903         htond( rec->cli.cli_thick, (unsigned char *)(&tmp), 1 );
00904         tmp = cline_ip->radius * local2mm;
00905         htond( rec->cli.cli_radius, (unsigned char *)(&tmp), 1 );
00906         VSCALE( work, cline_ip->v, local2mm );
00907         htond( rec->cli.cli_V, (unsigned char *)work, 3 );
00908         VSCALE( work, cline_ip->h, local2mm );
00909         htond( rec->cli.cli_h, (unsigned char *)work, 3 );
00910 
00911         return(0);
00912 }
00913 
00914 /**
00915  *                      R T _ C L I N E _ I M P O R T 5
00916  *
00917  *  Import an cline from the database format to the internal format.
00918  *  Apply modeling transformations as well.
00919  */
00920 int
00921 rt_cline_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
00922 {
00923         struct rt_cline_internal        *cline_ip;
00924         fastf_t                         vec[8];
00925 
00926         BU_CK_EXTERNAL( ep );
00927 
00928         BU_ASSERT_LONG( ep->ext_nbytes, ==, SIZEOF_NETWORK_DOUBLE * 8 );
00929 
00930         RT_CK_DB_INTERNAL( ip );
00931         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00932         ip->idb_type = ID_CLINE;
00933         ip->idb_meth = &rt_functab[ID_CLINE];
00934         ip->idb_ptr = bu_malloc( sizeof(struct rt_cline_internal), "rt_cline_internal");
00935 
00936         cline_ip = (struct rt_cline_internal *)ip->idb_ptr;
00937         cline_ip->magic = RT_CLINE_INTERNAL_MAGIC;
00938 
00939         /* Convert from database (network) to internal (host) format */
00940         ntohd( (unsigned char *)vec, ep->ext_buf, 8 );
00941 
00942         cline_ip->thickness = vec[0] / mat[15];
00943         cline_ip->radius = vec[1] / mat[15];
00944         MAT4X3PNT(cline_ip->v, mat, &vec[2]);
00945         MAT4X3VEC(cline_ip->h, mat, &vec[5]);
00946 
00947         return(0);                      /* OK */
00948 }
00949 
00950 /**
00951  *                      R T _ C L I N E _ E X P O R T 5
00952  *
00953  *  The name is added by the caller, in the usual place.
00954  */
00955 int
00956 rt_cline_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00957 {
00958         struct rt_cline_internal        *cline_ip;
00959         fastf_t                         vec[8];
00960 
00961         RT_CK_DB_INTERNAL(ip);
00962         if (ip->idb_type != ID_CLINE)  return(-1);
00963         cline_ip = (struct rt_cline_internal *)ip->idb_ptr;
00964         RT_CLINE_CK_MAGIC(cline_ip);
00965 
00966         BU_CK_EXTERNAL(ep);
00967         ep->ext_nbytes = SIZEOF_NETWORK_DOUBLE * 8;
00968         ep->ext_buf = (genptr_t)bu_malloc(ep->ext_nbytes, "cline external");
00969 
00970         vec[0] = cline_ip->thickness * local2mm;
00971         vec[1] = cline_ip->radius * local2mm;
00972         VSCALE(&vec[2], cline_ip->v, local2mm);
00973         VSCALE(&vec[5], cline_ip->h, local2mm);
00974 
00975         /* Convert from internal (host) to database (network) format */
00976         htond(ep->ext_buf, (unsigned char *)vec, 8);
00977 
00978         return(0);
00979 }
00980 
00981 /**
00982  *                      R T _ C L I N E _ D E S C R I B E
00983  *
00984  *  Make human-readable formatted presentation of this solid.
00985  *  First line describes type of solid.
00986  *  Additional lines are indented one tab, and give parameter values.
00987  */
00988 int
00989 rt_cline_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
00990 {
00991         register struct rt_cline_internal       *cline_ip =
00992                 (struct rt_cline_internal *)ip->idb_ptr;
00993         char    buf[256];
00994         point_t local_v;
00995         vect_t local_h;
00996 
00997         RT_CLINE_CK_MAGIC(cline_ip);
00998         bu_vls_strcat( str, "cline solid (CLINE)\n");
00999 
01000         VSCALE( local_v, cline_ip->v, mm2local );
01001         VSCALE( local_h, cline_ip->h, mm2local );
01002 
01003         if( cline_ip->thickness > 0.0 )
01004         {
01005                 sprintf( buf, "\tV (%g %g %g)\n\tH (%g %g %g)\n\tradius %g\n\tplate mode thickness %g",
01006                                 V3INTCLAMPARGS( local_v ), V3INTCLAMPARGS( local_h ), INTCLAMP(cline_ip->radius*mm2local), INTCLAMP(cline_ip->thickness*mm2local) );
01007         }
01008         else
01009         {
01010                 sprintf( buf, "\tV (%g %g %g)\n\tH (%g %g %g)\n\tradius %g\n\tVolume mode\n",
01011                                 V3INTCLAMPARGS( local_v ), V3INTCLAMPARGS( local_h ), INTCLAMP(cline_ip->radius*mm2local) );
01012         }
01013         bu_vls_strcat( str, buf );
01014 
01015         return(0);
01016 }
01017 
01018 /**
01019  *                      R T _ C L I N E _ I F R E E
01020  *
01021  *  Free the storage associated with the rt_db_internal version of this solid.
01022  */
01023 void
01024 rt_cline_ifree(struct rt_db_internal *ip)
01025 {
01026         register struct rt_cline_internal       *cline_ip;
01027 
01028         RT_CK_DB_INTERNAL(ip);
01029         cline_ip = (struct rt_cline_internal *)ip->idb_ptr;
01030         RT_CLINE_CK_MAGIC(cline_ip);
01031         cline_ip->magic = 0;                    /* sanity */
01032 
01033         bu_free( (char *)cline_ip, "cline ifree" );
01034         ip->idb_ptr = GENPTR_NULL;      /* sanity */
01035 }
01036 
01037 int
01038 rt_cline_tnurb(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct bn_tol *tol)
01039 {
01040         return( 1 );
01041 }
01042 
01043 int
01044 rt_cline_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr)
01045 {
01046         register struct rt_cline_internal *cli =
01047                 (struct rt_cline_internal *)intern->idb_ptr;
01048         Tcl_DString     ds;
01049         struct bu_vls   vls;
01050         int ret=TCL_OK;
01051 
01052         RT_CLINE_CK_MAGIC( cli );
01053 
01054         Tcl_DStringInit( &ds );
01055         bu_vls_init( &vls );
01056 
01057         if( attr == (char *)NULL )
01058         {
01059                 bu_vls_strcpy( &vls, "cline" );
01060                 bu_vls_printf( &vls, " V {%.25G %.25G %.25G}", V3ARGS( cli->v ) );
01061                 bu_vls_printf( &vls, " H {%.25G %.25G %.25G}", V3ARGS( cli->h ) );
01062                 bu_vls_printf( &vls, " R %.25G T %.25G", cli->radius, cli->thickness );
01063         }
01064         else if( *attr == 'V')
01065                 bu_vls_printf( &vls, "%.25G %.25G %.25G", V3ARGS( cli->v ) );
01066         else if( *attr == 'H' )
01067                 bu_vls_printf( &vls, "%.25G %.25G %.25G", V3ARGS( cli->h ) );
01068         else if( *attr == 'R' )
01069                 bu_vls_printf( &vls, "%.25G", cli->radius );
01070         else if( *attr == 'T' )
01071                 bu_vls_printf( &vls, "%.25G", cli->thickness );
01072         else
01073         {
01074                 bu_vls_strcat( &vls, "ERROR: unrecognized attribute, must be V, H, R, or T!!!" );
01075                 ret = TCL_ERROR;
01076         }
01077 
01078         Tcl_DStringAppend( &ds, bu_vls_addr( &vls ), -1 );
01079         Tcl_DStringResult( interp, &ds );
01080         Tcl_DStringFree( &ds );
01081         bu_vls_free( &vls );
01082         return( ret );
01083 }
01084 
01085 int
01086 rt_cline_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, char **argv)
01087 {
01088         struct rt_cline_internal *cli =
01089                 (struct rt_cline_internal *)intern->idb_ptr;
01090         fastf_t *new;
01091 
01092         RT_CK_DB_INTERNAL( intern );
01093         RT_CLINE_CK_MAGIC( cli );
01094 
01095         while( argc >= 2 )
01096         {
01097                 int array_len=3;
01098 
01099                 if( *argv[0] == 'V' )
01100                 {
01101                         new = cli->v;
01102                         if( tcl_list_to_fastf_array( interp, argv[1], &new, &array_len ) !=
01103                             array_len ) {
01104                                 Tcl_SetResult( interp,
01105                                       "ERROR: Incorrect number of coordinates for vector\n",
01106                                       TCL_STATIC );
01107                                 return( TCL_ERROR );
01108                         }
01109                 }
01110                 else if( *argv[0] == 'H' )
01111                 {
01112                         new = cli->h;
01113                         if( tcl_list_to_fastf_array( interp, argv[1], &new, &array_len ) !=
01114                             array_len ) {
01115                                 Tcl_SetResult( interp,
01116                                       "ERROR: Incorrect number of coordinates for point\n",
01117                                       TCL_STATIC );
01118                                 return( TCL_ERROR );
01119                         }
01120                 }
01121                 else if( *argv[0] == 'R' )
01122                         cli->radius = atof( argv[1] );
01123                 else if( *argv[0] == 'T' )
01124                         cli->thickness = atof( argv[1] );
01125 
01126                 argc -= 2;
01127                 argv += 2;
01128         }
01129 
01130         return( TCL_OK );
01131 }
01132 
01133 int
01134 rt_cline_tclform( const struct rt_functab *ftp, Tcl_Interp *interp )
01135 {
01136         RT_CK_FUNCTAB(ftp);
01137 
01138         Tcl_AppendResult( interp,
01139                           "V {%f %f %f} H {%f %f %f} R %f T %f", (char *)NULL );
01140 
01141         return TCL_OK;
01142 
01143 }
01144 
01145 /*@}*/
01146 /*
01147  * Local Variables:
01148  * mode: C
01149  * tab-width: 8
01150  * c-basic-offset: 4
01151  * indent-tabs-mode: t
01152  * End:
01153  * ex: shiftwidth=4 tabstop=8
01154  */

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