00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 #ifndef lint
00039 static const char RCSpipe[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_pipe.c,v 14.20 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00040 #endif
00041 
00042 #include "common.h"
00043 
00044 #include <stdlib.h>
00045 #include <stdio.h>
00046 #include <ctype.h>
00047 #ifdef HAVE_UNISTD_H
00048 #  include <unistd.h>
00049 #endif
00050 #ifdef HAVE_STRING_H
00051 #  include <string.h>
00052 #endif
00053 #include <math.h>
00054 
00055 #ifdef HAVE_FLOAT_H
00056    
00057 #  include <float.h>
00058 #endif
00059 
00060 #include "tcl.h"
00061 #include "machine.h"
00062 #include "vmath.h"
00063 #include "bu.h"
00064 #include "bn.h"
00065 #include "db.h"
00066 #include "nmg.h"
00067 #include "raytrace.h"
00068 #include "wdb.h"
00069 #include "rtgeom.h"
00070 #include "./debug.h"
00071 
00072 struct id_pipe
00073 {
00074         struct bu_list l;
00075         int     pipe_is_bend;
00076 };
00077 
00078 struct lin_pipe
00079 {
00080         struct bu_list l;
00081         int     pipe_is_bend;
00082         vect_t  pipe_V;                 
00083         vect_t  pipe_H;                 
00084         fastf_t pipe_ribase, pipe_ritop;        
00085         fastf_t pipe_ribase_sq, pipe_ritop_sq;  
00086         fastf_t pipe_ridiff_sq, pipe_ridiff;    
00087         fastf_t pipe_rodiff_sq, pipe_rodiff;    
00088         fastf_t pipe_robase, pipe_rotop;        
00089         fastf_t pipe_robase_sq, pipe_rotop_sq;  
00090         fastf_t pipe_len;                       
00091         mat_t   pipe_SoR;       
00092         mat_t   pipe_invRoS;    
00093 };
00094 
00095 struct bend_pipe
00096 {
00097         struct bu_list l;
00098         int     pipe_is_bend;
00099         fastf_t bend_radius;            
00100         fastf_t bend_or;                
00101         fastf_t bend_ir;                
00102         mat_t   bend_invR;              
00103         mat_t   bend_SoR;               
00104         point_t bend_V;                 
00105         point_t bend_start;             
00106         point_t bend_end;               
00107         fastf_t bend_alpha_i;           
00108         fastf_t bend_alpha_o;           
00109         fastf_t bend_angle;             
00110         vect_t  bend_ra;                
00111         vect_t  bend_rb;                
00112         vect_t  bend_N;                 
00113         fastf_t bend_R_SQ;              
00114         point_t bend_min;
00115         point_t bend_max;
00116 };
00117 
00118 
00119 struct hit_list
00120 {
00121         struct bu_list  l;
00122         struct hit      *hitp;
00123 };
00124 
00125 #define PIPE_MM(_v)       VMINMAX( stp->st_min, stp->st_max, _v );
00126 
00127 #define ARC_SEGS        16      
00128 
00129 #define PIPE_LINEAR_OUTER_BODY  1
00130 #define PIPE_LINEAR_INNER_BODY  2
00131 #define PIPE_LINEAR_TOP         3
00132 #define PIPE_LINEAR_BASE        4
00133 #define PIPE_BEND_OUTER_BODY    5
00134 #define PIPE_BEND_INNER_BODY    6
00135 #define PIPE_BEND_BASE          7
00136 #define PIPE_BEND_TOP           8
00137 
00138 BU_EXTERN( void rt_pipe_ifree, (struct rt_db_internal *ip) );
00139 
00140 
00141 HIDDEN int
00142 rt_bend_pipe_prep(struct soltab *stp, struct bu_list *head, fastf_t *bend_center, fastf_t *bend_start, fastf_t *bend_end, fastf_t bend_radius, fastf_t bend_angle, fastf_t *v1, fastf_t *v2, fastf_t od, fastf_t id)
00143 {
00144         register struct bend_pipe *pipe;
00145         LOCAL vect_t    to_start,to_end;
00146         LOCAL mat_t     R;
00147         LOCAL point_t   work;
00148         LOCAL vect_t    tmp_vec;
00149         LOCAL fastf_t   f;
00150 
00151         pipe = (struct bend_pipe *)bu_malloc( sizeof( struct bend_pipe ), "rt_bend_pipe_prep:pipe" )     ;
00152 
00153         pipe->pipe_is_bend = 1;
00154         pipe->bend_or = od * 0.5;
00155         pipe->bend_ir = id * 0.5;
00156 
00157         VMOVE( pipe->bend_start, bend_start );
00158         VMOVE( pipe->bend_end, bend_end );
00159         VMOVE( pipe->bend_V, bend_center );
00160         VSUB2( to_start, bend_start, bend_center );
00161         pipe->bend_radius = bend_radius;
00162         VSUB2( to_end, bend_end, bend_center );
00163         VSCALE( pipe->bend_ra, to_start, 1.0/pipe->bend_radius );
00164         VCROSS( pipe->bend_N, to_start, to_end );
00165         VUNITIZE( pipe->bend_N );
00166         VCROSS( pipe->bend_rb, pipe->bend_N, pipe->bend_ra );
00167 
00168         pipe->bend_angle = bend_angle;
00169 
00170         
00171         if( pipe->bend_angle >= bn_pi )
00172         {
00173                 bu_log( "Error: rt_pipe_prep: Bend section bends through more than 180 degrees\n" );
00174                 return( 1 );
00175         }
00176 
00177         pipe->bend_alpha_i = pipe->bend_ir/pipe->bend_radius;
00178         pipe->bend_alpha_o = pipe->bend_or/pipe->bend_radius;
00179 
00180         pipe->bend_R_SQ = (pipe->bend_radius + pipe->bend_or) *
00181                                 (pipe->bend_radius + pipe->bend_or);
00182 
00183         MAT_IDN( R );
00184         VMOVE( &R[0], pipe->bend_ra );
00185         VMOVE( &R[4], pipe->bend_rb );
00186         VMOVE( &R[8], pipe->bend_N );
00187 
00188         if (bn_mat_inverse( pipe->bend_invR, R ) == 0) {
00189                 bu_free(pipe, "rt_bend_pipe_prep:pipe");
00190                 return 0; 
00191         }
00192 
00193 
00194         MAT_COPY( pipe->bend_SoR, R );
00195         pipe->bend_SoR[15] *= pipe->bend_radius;
00196 
00197         
00198         
00199         VSET( tmp_vec, 1.0, 0.0, 0.0 );
00200         VCROSS( work, pipe->bend_N, tmp_vec );
00201         f = pipe->bend_or + pipe->bend_radius * MAGNITUDE(work);
00202         pipe->bend_min[X] = pipe->bend_V[X] - f;
00203         pipe->bend_max[X] = pipe->bend_V[X] + f;
00204 
00205         
00206         VSET( tmp_vec, 0.0, 1.0, 0.0 );
00207         VCROSS( work, pipe->bend_N, tmp_vec );
00208         f = pipe->bend_or + pipe->bend_radius * MAGNITUDE(work);
00209         pipe->bend_min[Y] = pipe->bend_V[Y] - f;
00210         pipe->bend_max[Y] = pipe->bend_V[Y] + f;
00211 
00212         
00213         VSET( tmp_vec, 0.0, 0.0, 1.0 );
00214         VCROSS( work, pipe->bend_N, tmp_vec );
00215         f = pipe->bend_or + pipe->bend_radius * MAGNITUDE(work);
00216         pipe->bend_min[Z] = pipe->bend_V[Z] - f;
00217         pipe->bend_max[Z] = pipe->bend_V[Z] + f;
00218 
00219         PIPE_MM( pipe->bend_min );
00220         PIPE_MM( pipe->bend_max );
00221 
00222         BU_LIST_INSERT( head, &pipe->l );
00223 
00224         return( 0 );
00225 
00226 }
00227 
00228 HIDDEN void
00229 rt_linear_pipe_prep(struct soltab *stp, struct bu_list *head, fastf_t *pt1, fastf_t id1, fastf_t od1, fastf_t *pt2, fastf_t id2, fastf_t od2)
00230 {
00231         register struct lin_pipe *pipe;
00232         LOCAL mat_t     R;
00233         LOCAL mat_t     Rinv;
00234         LOCAL mat_t     S;
00235         LOCAL point_t work;
00236         LOCAL vect_t seg_ht;
00237         LOCAL vect_t v1,v2;
00238 
00239         pipe = (struct lin_pipe *)bu_malloc( sizeof( struct lin_pipe ), "rt_bend_pipe_prep:pipe" );
00240         BU_LIST_INSERT( head, &pipe->l );
00241 
00242 
00243         VMOVE( pipe->pipe_V, pt1 );
00244 
00245         VSUB2( seg_ht, pt2, pt1 );
00246         pipe->pipe_ribase = id1/2.0;
00247         pipe->pipe_ribase_sq = pipe->pipe_ribase * pipe->pipe_ribase;
00248         pipe->pipe_ritop = id2/2.0;
00249         pipe->pipe_ritop_sq = pipe->pipe_ritop * pipe->pipe_ritop;
00250         pipe->pipe_robase = od1/2.0;
00251         pipe->pipe_robase_sq = pipe->pipe_robase * pipe->pipe_robase;
00252         pipe->pipe_rotop = od2/2.0;
00253         pipe->pipe_rotop_sq = pipe->pipe_rotop * pipe->pipe_rotop;
00254         pipe->pipe_ridiff = pipe->pipe_ritop - pipe->pipe_ribase;
00255         pipe->pipe_ridiff_sq = pipe->pipe_ridiff * pipe->pipe_ridiff;
00256         pipe->pipe_rodiff = pipe->pipe_rotop - pipe->pipe_robase;
00257         pipe->pipe_rodiff_sq = pipe->pipe_rodiff * pipe->pipe_rodiff;
00258         pipe->pipe_is_bend = 0;
00259 
00260         pipe->pipe_len = MAGNITUDE( seg_ht );
00261         VSCALE( seg_ht, seg_ht, 1.0/pipe->pipe_len );
00262         VMOVE( pipe->pipe_H, seg_ht );
00263         bn_vec_ortho( v1, seg_ht );
00264         VCROSS( v2, seg_ht, v1 );
00265 
00266         
00267         MAT_IDN( R );
00268         VMOVE( &R[0], v1 );
00269         VMOVE( &R[4], v2 );
00270         VMOVE( &R[8], seg_ht );
00271 
00272         
00273         bn_mat_trn( Rinv, R );
00274 
00275         
00276         MAT_IDN( S );
00277         S[10] = 1.0/pipe->pipe_len;
00278 
00279         
00280         bn_mat_mul( pipe->pipe_SoR, S, R );
00281         bn_mat_mul( pipe->pipe_invRoS, Rinv, S );
00282 
00283 
00284 
00285         VJOIN2( work, pt1, od1, v1, od1, v2 );
00286         PIPE_MM( work )
00287         VJOIN2( work, pt1, -od1, v1, od1, v2 );
00288         PIPE_MM( work )
00289         VJOIN2( work, pt1, od1, v1, -od1, v2 );
00290         PIPE_MM( work )
00291         VJOIN2( work, pt1, -od1, v1, -od1, v2 );
00292         PIPE_MM( work )
00293 
00294         VJOIN2( work, pt2, od2, v1, od2, v2 );
00295         PIPE_MM( work )
00296         VJOIN2( work, pt2, -od2, v1, od2, v2 );
00297         PIPE_MM( work )
00298         VJOIN2( work, pt2, od2, v1, -od2, v2 );
00299         PIPE_MM( work )
00300         VJOIN2( work, pt2, -od2, v1, -od2, v2 );
00301         PIPE_MM( work )
00302 
00303 }
00304 
00305 
00306 
00307 
00308 
00309 
00310 
00311 
00312 
00313 
00314 
00315 
00316 
00317 
00318 
00319 
00320 int
00321 rt_pipe_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00322 {
00323         register struct bu_list *head;
00324         struct rt_pipe_internal *pip;
00325         struct wdb_pipept *pp1,*pp2,*pp3;
00326         point_t curr_pt;
00327         fastf_t curr_id, curr_od;
00328         fastf_t dx,dy,dz,f;
00329 
00330         RT_CK_DB_INTERNAL( ip );
00331         pip = (struct rt_pipe_internal *)ip->idb_ptr;
00332         RT_PIPE_CK_MAGIC(pip);
00333 
00334         head = (struct bu_list *)bu_malloc( sizeof( struct bu_list ), "rt_pipe_prep:head" );
00335         stp->st_specific = (genptr_t)head;
00336         BU_LIST_INIT( head );
00337 
00338         if( BU_LIST_IS_EMPTY( &(pip->pipe_segs_head) ) )
00339                 return( 0 );
00340 
00341         pp1 = BU_LIST_FIRST( wdb_pipept, &(pip->pipe_segs_head) );
00342         pp2 = BU_LIST_NEXT( wdb_pipept, &pp1->l );
00343         if( BU_LIST_IS_HEAD( &pp2->l, &(pip->pipe_segs_head) ) )
00344                 return( 0 );
00345         pp3 = BU_LIST_NEXT( wdb_pipept, &pp2->l );
00346         if( BU_LIST_IS_HEAD( &pp3->l ,  &(pip->pipe_segs_head) ) )
00347                 pp3 = (struct wdb_pipept *)NULL;
00348 
00349         VMOVE( curr_pt, pp1->pp_coord );
00350         curr_od = pp1->pp_od;
00351         curr_id = pp1->pp_id;
00352         while( 1 )
00353         {
00354                 vect_t n1,n2;
00355                 vect_t norm;
00356                 vect_t v1,v2;
00357                 fastf_t angle;
00358                 fastf_t dist_to_bend;
00359                 point_t bend_start, bend_end, bend_center;
00360 
00361                 VSUB2( n1, curr_pt, pp2->pp_coord );
00362                 if( VNEAR_ZERO( n1, SQRT_SMALL_FASTF ) )
00363                 {
00364                         
00365                         goto next_pt;
00366                 }
00367 
00368                 if( !pp3 )
00369                 {
00370                         
00371                         rt_linear_pipe_prep( stp, head, curr_pt, curr_id, curr_od, pp2->pp_coord, pp2->pp_id, pp2->pp_od );
00372                         break;
00373                 }
00374 
00375                 VSUB2( n2, pp3->pp_coord, pp2->pp_coord );
00376                 VCROSS( norm, n1, n2 );
00377                 VUNITIZE( n1 );
00378                 VUNITIZE( n2 );
00379                 angle = bn_pi - acos( VDOT( n1, n2 ) );
00380                 dist_to_bend = pp2->pp_bendradius * tan( angle/2.0 );
00381                 if( isnan( dist_to_bend ) || VNEAR_ZERO( norm, SQRT_SMALL_FASTF) || NEAR_ZERO( dist_to_bend, SQRT_SMALL_FASTF) )
00382                 {
00383                         
00384                         rt_linear_pipe_prep( stp, head, curr_pt, curr_id, curr_od,
00385                                 pp2->pp_coord, pp2->pp_id, pp2->pp_od );
00386                         VMOVE( curr_pt, pp2->pp_coord );
00387                         goto next_pt;
00388                 }
00389 
00390                 VJOIN1( bend_start, pp2->pp_coord, dist_to_bend, n1 );
00391                 VJOIN1( bend_end, pp2->pp_coord, dist_to_bend, n2 );
00392 
00393                 VUNITIZE( norm );
00394 
00395                 
00396                 rt_linear_pipe_prep( stp, head, curr_pt, curr_id, curr_od,
00397                                 bend_start, pp2->pp_id, pp2->pp_od );
00398 
00399                 
00400                 VCROSS( v1, n1, norm );
00401                 VCROSS( v2, v1, norm );
00402                 VJOIN1( bend_center, bend_start, -pp2->pp_bendradius, v1 );
00403                 rt_bend_pipe_prep( stp, head, bend_center, bend_start, bend_end, pp2->pp_bendradius, angle,
00404                         v1, v2, pp2->pp_od, pp2->pp_id );
00405 
00406                 VMOVE( curr_pt, bend_end );
00407 next_pt:
00408                 if (!pp3) break;
00409                 curr_id = pp2->pp_id;
00410                 curr_od = pp2->pp_od;
00411                 pp1 = pp2;
00412                 pp2 = pp3;
00413                 pp3 = BU_LIST_NEXT( wdb_pipept, &pp3->l );
00414                 if( BU_LIST_IS_HEAD( &pp3->l ,  &(pip->pipe_segs_head) ) )
00415                         pp3 = (struct wdb_pipept *)NULL;
00416         }
00417 
00418         VSET( stp->st_center,
00419                 (stp->st_max[X] + stp->st_min[X])/2,
00420                 (stp->st_max[Y] + stp->st_min[Y])/2,
00421                 (stp->st_max[Z] + stp->st_min[Z])/2 );
00422 
00423         dx = (stp->st_max[X] - stp->st_min[X])/2;
00424         f = dx;
00425         dy = (stp->st_max[Y] - stp->st_min[Y])/2;
00426         if( dy > f )  f = dy;
00427         dz = (stp->st_max[Z] - stp->st_min[Z])/2;
00428         if( dz > f )  f = dz;
00429         stp->st_aradius = f;
00430         stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz);
00431 
00432         return( 0 );
00433 }
00434 
00435 
00436 
00437 
00438 void
00439 rt_pipe_print(register const struct soltab *stp)
00440 {
00441 
00442 
00443 }
00444 
00445 
00446 
00447 
00448 void
00449 rt_pipept_print( const struct wdb_pipept *pipe, double mm2local )
00450 {
00451         point_t p1;
00452 
00453         bu_log( "Pipe Vertex:\n" );
00454         VSCALE( p1, pipe->pp_coord, mm2local );
00455         bu_log( "\tat (%g %g %g)\n", V3ARGS( p1 ) );
00456         bu_log( "\tbend radius = %g\n", pipe->pp_bendradius*mm2local );
00457         if( pipe->pp_id > 0.0 )
00458                 bu_log( "\tod=%g, id=%g\n",
00459                         pipe->pp_od*mm2local,
00460                         pipe->pp_id*mm2local );
00461         else
00462                 bu_log( "\tod=%g\n", pipe->pp_od*mm2local );
00463 }
00464 
00465 
00466 
00467 
00468 void
00469 rt_vls_pipept(
00470         struct bu_vls *vp,
00471         int seg_no,
00472         const struct rt_db_internal *ip,
00473         double mm2local)
00474 {
00475         struct rt_pipe_internal *pint;
00476         struct wdb_pipept *pipe;
00477         int seg_count=0;
00478         char buf[256];
00479         point_t p1;
00480 
00481         pint = (struct rt_pipe_internal *)ip->idb_ptr;
00482         RT_PIPE_CK_MAGIC( pint );
00483 
00484         pipe = BU_LIST_FIRST( wdb_pipept, &pint->pipe_segs_head );
00485         while( ++seg_count != seg_no && BU_LIST_NOT_HEAD( &pipe->l, &pint->pipe_segs_head ) )
00486                 pipe = BU_LIST_NEXT( wdb_pipept, &pipe->l );
00487 
00488 
00489         sprintf( buf, "Pipe Vertex:\n" );
00490         bu_vls_strcat( vp, buf );
00491         VSCALE( p1, pipe->pp_coord, mm2local );
00492         sprintf( buf, "\tat (%g %g %g)\n", V3ARGS( p1 ) );
00493         bu_vls_strcat( vp, buf );
00494         sprintf( buf, "\tbend radius = %g\n", pipe->pp_bendradius*mm2local );
00495         bu_vls_strcat( vp, buf );
00496         if( pipe->pp_id > 0.0 )
00497                 sprintf( buf, "\tod=%g, id=%g\n",
00498                         pipe->pp_od*mm2local,
00499                         pipe->pp_id*mm2local );
00500         else
00501                 sprintf( buf, "\tod=%g\n", pipe->pp_od*mm2local );
00502         bu_vls_strcat( vp, buf );
00503 }
00504 
00505 HIDDEN void
00506 bend_pipe_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead, struct bend_pipe *pipe, struct hit_list *hit_headp, int *hit_count, int seg_no)
00507 {
00508         LOCAL vect_t    dprime;         
00509         LOCAL vect_t    pprime;         
00510         LOCAL vect_t    work;           
00511         LOCAL bn_poly_t C;              
00512         LOCAL bn_complex_t      val[4]; 
00513         LOCAL int       j;
00514         LOCAL int       root_count=0;
00515         LOCAL bn_poly_t A, Asqr;
00516         LOCAL bn_poly_t X2_Y2;          
00517         LOCAL vect_t    cor_pprime;     
00518         LOCAL fastf_t   cor_proj;
00519 
00520         *hit_count = 0;
00521 
00522         if( !rt_in_rpp( rp, ap->a_inv_dir, pipe->bend_min, pipe->bend_max ) ) {
00523                 return;          
00524         }
00525 
00526         
00527         MAT4X3VEC( dprime, pipe->bend_SoR, rp->r_dir );
00528         VUNITIZE( dprime );
00529 
00530         VSUB2( work, rp->r_pt, pipe->bend_V );
00531         MAT4X3VEC( pprime, pipe->bend_SoR, work );
00532 
00533         
00534 
00535 
00536 
00537 
00538 
00539 
00540         cor_proj = VDOT( pprime, dprime );
00541         VSCALE( cor_pprime, dprime, cor_proj );
00542         VSUB2( cor_pprime, pprime, cor_pprime );
00543 
00544         
00545 
00546 
00547 
00548 
00549 
00550 
00551 
00552 
00553 
00554 
00555 
00556 
00557 
00558 
00559 
00560         X2_Y2.dgr = 2;
00561         X2_Y2.cf[0] = dprime[X] * dprime[X] + dprime[Y] * dprime[Y];
00562         X2_Y2.cf[1] = 2.0 * (dprime[X] * cor_pprime[X] +
00563                              dprime[Y] * cor_pprime[Y]);
00564         X2_Y2.cf[2] = cor_pprime[X] * cor_pprime[X] +
00565                       cor_pprime[Y] * cor_pprime[Y];
00566 
00567         
00568         A.dgr = 2;
00569         A.cf[0] = X2_Y2.cf[0] + dprime[Z] * dprime[Z];
00570         A.cf[1] = X2_Y2.cf[1] + 2.0 * dprime[Z] * cor_pprime[Z];
00571         A.cf[2] = X2_Y2.cf[2] + cor_pprime[Z] * cor_pprime[Z] +
00572                   1.0 - pipe->bend_alpha_o * pipe->bend_alpha_o;
00573 
00574         
00575         
00576         Asqr.dgr = 4;
00577         Asqr.cf[0] = A.cf[0] * A.cf[0];
00578         Asqr.cf[1] = A.cf[0] * A.cf[1] + A.cf[1] * A.cf[0];
00579         Asqr.cf[2] = A.cf[0] * A.cf[2] + A.cf[1] * A.cf[1] + A.cf[2] * A.cf[0];
00580         Asqr.cf[3] = A.cf[1] * A.cf[2] + A.cf[2] * A.cf[1];
00581         Asqr.cf[4] = A.cf[2] * A.cf[2];
00582 
00583         
00584 
00585 
00586         C.dgr   = 4;
00587         C.cf[0] = Asqr.cf[0];
00588         C.cf[1] = Asqr.cf[1];
00589         C.cf[2] = Asqr.cf[2] - X2_Y2.cf[0] * 4.0;
00590         C.cf[3] = Asqr.cf[3] - X2_Y2.cf[1] * 4.0;
00591         C.cf[4] = Asqr.cf[4] - X2_Y2.cf[2] * 4.0;
00592 
00593         
00594 
00595 
00596         if ( (root_count = rt_poly_roots( &C, val, stp->st_dp->d_namep )) != 4 ){
00597             if( root_count > 0 )  {
00598                 bu_log("tor:  rt_poly_roots() 4!=%d\n", root_count);
00599                 bn_pr_roots( stp->st_name, val, root_count );
00600             } else if (root_count < 0) {
00601                 static int reported=0;
00602                 bu_log("The root solver failed to converge on a solution for %s\n", stp->st_dp->d_namep);
00603                 if (!reported) {
00604                     VPRINT("while shooting from:\t", rp->r_pt);
00605                     VPRINT("while shooting at:\t", rp->r_dir);
00606                     bu_log("Additional pipe convergence failure details will be suppressed.\n");
00607                     reported=1;
00608                 }
00609             }
00610             return;     
00611         }
00612 
00613         
00614 
00615 
00616 
00617 
00618 
00619         for ( j=0, (*hit_count)=0; j < 4; j++ ){
00620                 if( NEAR_ZERO( val[j].im, 0.0001 ) )
00621                 {
00622                         struct hit_list *hitp;
00623                         fastf_t normalized_dist;
00624                         fastf_t dist;
00625                         point_t hit_pt;
00626                         vect_t  to_hit;
00627                         fastf_t angle;
00628 
00629                         normalized_dist = val[j].re - cor_proj;
00630                         dist = normalized_dist * pipe->bend_radius;
00631 
00632                         
00633                         VJOIN1( hit_pt, rp->r_pt, dist, rp->r_dir );
00634                         VSUB2( to_hit, hit_pt, pipe->bend_V );
00635                         angle = atan2( VDOT( to_hit, pipe->bend_rb ), VDOT( to_hit, pipe->bend_ra ) );
00636                         if( angle < 0.0 )
00637                                 angle += 2.0 * bn_pi;
00638                         if( angle <= pipe->bend_angle )
00639                         {
00640                                 BU_GETSTRUCT( hitp, hit_list );
00641                                 BU_GETSTRUCT( hitp->hitp, hit );
00642                                 hitp->hitp->hit_magic = RT_HIT_MAGIC;
00643                                 hitp->hitp->hit_dist = dist;
00644                                 VJOIN1( hitp->hitp->hit_vpriv, pprime, normalized_dist, dprime );
00645                                 hitp->hitp->hit_surfno = seg_no*10 + PIPE_BEND_OUTER_BODY;
00646                                 BU_LIST_INSERT( &hit_headp->l, &hitp->l );
00647                                 (*hit_count)++;
00648                         }
00649                 }
00650         }
00651 
00652         if( pipe->bend_alpha_i <= 0.0 )
00653                 return;         
00654 
00655         
00656         A.cf[2] = X2_Y2.cf[2] + cor_pprime[Z] * cor_pprime[Z] +
00657                   1.0 - pipe->bend_alpha_i * pipe->bend_alpha_i;
00658 
00659         
00660         
00661         Asqr.dgr = 4;
00662         Asqr.cf[0] = A.cf[0] * A.cf[0];
00663         Asqr.cf[1] = A.cf[0] * A.cf[1] + A.cf[1] * A.cf[0];
00664         Asqr.cf[2] = A.cf[0] * A.cf[2] + A.cf[1] * A.cf[1] + A.cf[2] * A.cf[0];
00665         Asqr.cf[3] = A.cf[1] * A.cf[2] + A.cf[2] * A.cf[1];
00666         Asqr.cf[4] = A.cf[2] * A.cf[2];
00667 
00668         
00669 
00670 
00671         C.dgr   = 4;
00672         C.cf[0] = Asqr.cf[0];
00673         C.cf[1] = Asqr.cf[1];
00674         C.cf[2] = Asqr.cf[2] - X2_Y2.cf[0] * 4.0;
00675         C.cf[3] = Asqr.cf[3] - X2_Y2.cf[1] * 4.0;
00676         C.cf[4] = Asqr.cf[4] - X2_Y2.cf[2] * 4.0;
00677 
00678         
00679 
00680 
00681         if ( (root_count = rt_poly_roots( &C, val, stp->st_dp->d_namep)) != 4 ){
00682             if( root_count > 0 )  {
00683                 bu_log("tor:  rt_poly_roots() 4!=%d\n", root_count);
00684                 bn_pr_roots( stp->st_name, val, root_count );
00685             } else if (root_count < 0) {
00686                 static int reported=0;
00687                 bu_log("The root solver failed to converge on a solution for %s\n", stp->st_dp->d_namep);
00688                 if (!reported) {
00689                     VPRINT("while shooting from:\t", rp->r_pt);
00690                     VPRINT("while shooting at:\t", rp->r_dir);
00691                     bu_log("Additional pipe convergence failure details will be suppressed.\n");
00692                     reported=1;
00693                 }
00694             }
00695             return;     
00696         }
00697 
00698         
00699 
00700 
00701 
00702 
00703 
00704         for ( j=0, root_count=0; j < 4; j++ ){
00705                 if( NEAR_ZERO( val[j].im, 0.0001 ) )
00706                 {
00707                         struct hit_list *hitp;
00708                         fastf_t normalized_dist;
00709                         fastf_t dist;
00710                         point_t hit_pt;
00711                         vect_t  to_hit;
00712                         fastf_t angle;
00713 
00714                         normalized_dist = val[j].re - cor_proj;
00715                         dist = normalized_dist * pipe->bend_radius;
00716 
00717                         
00718                         VJOIN1( hit_pt, rp->r_pt, dist, rp->r_dir );
00719                         VSUB2( to_hit, hit_pt, pipe->bend_V );
00720                         angle = atan2( VDOT( to_hit, pipe->bend_rb ), VDOT( to_hit, pipe->bend_ra ) );
00721                         if( angle < 0.0 )
00722                                 angle += 2.0 * bn_pi;
00723                         if( angle <= pipe->bend_angle )
00724                         {
00725                                 BU_GETSTRUCT( hitp, hit_list );
00726                                 BU_GETSTRUCT( hitp->hitp, hit );
00727                                 hitp->hitp->hit_magic = RT_HIT_MAGIC;
00728                                 hitp->hitp->hit_dist = dist;
00729                                 VJOIN1( hitp->hitp->hit_vpriv, pprime, normalized_dist, dprime );
00730                                 hitp->hitp->hit_surfno = seg_no*10 + PIPE_BEND_INNER_BODY;
00731                                 BU_LIST_INSERT( &hit_headp->l, &hitp->l );
00732                                 root_count++;
00733                         }
00734                 }
00735         }
00736 
00737         *hit_count += root_count;
00738 
00739         return;
00740 
00741 }
00742 
00743 HIDDEN void
00744 linear_pipe_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead, struct lin_pipe *pipe, struct hit_list *hit_headp, int *hit_count, int seg_no)
00745 {
00746         LOCAL struct hit_list   *hitp;
00747         LOCAL point_t   work_pt;
00748         LOCAL point_t   ray_start;
00749         LOCAL vect_t    ray_dir;
00750         LOCAL double    t_tmp;
00751         LOCAL double    a,b,c;
00752         LOCAL double    descrim;
00753 
00754         if( pipe->pipe_is_bend )
00755         {
00756                 bu_log( "linear_pipe_shot called for pipe bend\n" );
00757                 rt_bomb( "linear_pipe_shot\n" );
00758         }
00759 
00760         *hit_count = 0;
00761 
00762         
00763         VSUB2( work_pt, rp->r_pt, pipe->pipe_V );
00764         MAT4X3VEC( ray_start, pipe->pipe_SoR, work_pt );
00765 
00766         
00767         MAT4X3VEC( ray_dir, pipe->pipe_SoR, rp->r_dir );
00768 
00769         
00770         a = ray_dir[X]*ray_dir[X]
00771                 + ray_dir[Y]*ray_dir[Y]
00772                 - ray_dir[Z]*ray_dir[Z]*pipe->pipe_rodiff_sq;
00773         b = 2.0*(ray_start[X]*ray_dir[X]
00774                 + ray_start[Y]*ray_dir[Y]
00775                 - ray_start[Z]*ray_dir[Z]*pipe->pipe_rodiff_sq
00776                 - ray_dir[Z]*pipe->pipe_robase*pipe->pipe_rodiff);
00777         c = ray_start[X]*ray_start[X]
00778                 + ray_start[Y]*ray_start[Y]
00779                 - pipe->pipe_robase*pipe->pipe_robase
00780                 - ray_start[Z]*ray_start[Z]*pipe->pipe_rodiff_sq
00781                 - 2.0*ray_start[Z]*pipe->pipe_robase*pipe->pipe_rodiff;
00782 
00783         descrim = b*b - 4.0*a*c;
00784 
00785         if( descrim > 0.0 )
00786         {
00787                 LOCAL fastf_t   sqrt_descrim;
00788                 LOCAL point_t   hit_pt;
00789 
00790                 sqrt_descrim = sqrt( descrim );
00791 
00792                 t_tmp = (-b - sqrt_descrim)/(2.0*a);
00793                 VJOIN1( hit_pt, ray_start, t_tmp, ray_dir );
00794                 if( hit_pt[Z] >= 0.0 && hit_pt[Z] <= 1.0 )
00795                 {
00796                         BU_GETSTRUCT( hitp, hit_list );
00797                         BU_GETSTRUCT( hitp->hitp, hit );
00798                         hitp->hitp->hit_magic = RT_HIT_MAGIC;
00799                         hitp->hitp->hit_dist = t_tmp;
00800                         hitp->hitp->hit_surfno = seg_no*10 + PIPE_LINEAR_OUTER_BODY;
00801                         VMOVE( hitp->hitp->hit_vpriv, hit_pt );
00802                         hitp->hitp->hit_vpriv[Z] = (-pipe->pipe_robase - hit_pt[Z] * pipe->pipe_rodiff) *
00803                                         pipe->pipe_rodiff;
00804                         (*hit_count)++;
00805                         BU_LIST_INSERT( &hit_headp->l, &hitp->l );
00806                 }
00807 
00808                 t_tmp = (-b + sqrt_descrim)/(2.0*a);
00809                 VJOIN1( hit_pt, ray_start, t_tmp, ray_dir );
00810                 if( hit_pt[Z] >= 0.0 && hit_pt[Z] <= 1.0 )
00811                 {
00812                         BU_GETSTRUCT( hitp, hit_list );
00813                         BU_GETSTRUCT( hitp->hitp, hit );
00814                         hitp->hitp->hit_magic = RT_HIT_MAGIC;
00815                         hitp->hitp->hit_dist = t_tmp;
00816                         hitp->hitp->hit_surfno = seg_no*10 + PIPE_LINEAR_OUTER_BODY;
00817                         VMOVE( hitp->hitp->hit_vpriv, hit_pt );
00818                         hitp->hitp->hit_vpriv[Z] = (-pipe->pipe_robase - hit_pt[Z] * pipe->pipe_rodiff) *
00819                                         pipe->pipe_rodiff;
00820                         (*hit_count)++;
00821                         BU_LIST_INSERT( &hit_headp->l, &hitp->l );
00822                 }
00823         }
00824 
00825         if( pipe->pipe_ribase > 0.0 || pipe->pipe_ritop > 0.0 )
00826         {
00827                 
00828 
00829                 a = ray_dir[X]*ray_dir[X]
00830                         + ray_dir[Y]*ray_dir[Y]
00831                         - ray_dir[Z]*ray_dir[Z]*pipe->pipe_ridiff_sq;
00832                 b = 2.0*(ray_start[X]*ray_dir[X]
00833                         + ray_start[Y]*ray_dir[Y]
00834                         - ray_start[Z]*ray_dir[Z]*pipe->pipe_ridiff_sq
00835                         - ray_dir[Z]*pipe->pipe_ribase*pipe->pipe_ridiff);
00836                 c = ray_start[X]*ray_start[X]
00837                         + ray_start[Y]*ray_start[Y]
00838                         - pipe->pipe_ribase*pipe->pipe_ribase
00839                         - ray_start[Z]*ray_start[Z]*pipe->pipe_ridiff_sq
00840                         - 2.0*ray_start[Z]*pipe->pipe_ribase*pipe->pipe_ridiff;
00841 
00842                 descrim = b*b - 4.0*a*c;
00843 
00844                 if( descrim > 0.0 )
00845                 {
00846                         LOCAL fastf_t   sqrt_descrim;
00847                         LOCAL point_t   hit_pt;
00848 
00849                         sqrt_descrim = sqrt( descrim );
00850 
00851                         t_tmp = (-b - sqrt_descrim)/(2.0*a);
00852                         VJOIN1( hit_pt, ray_start, t_tmp, ray_dir );
00853                         if( hit_pt[Z] >= 0.0 && hit_pt[Z] <= 1.0 )
00854                         {
00855                                 BU_GETSTRUCT( hitp, hit_list );
00856                                 BU_GETSTRUCT( hitp->hitp, hit );
00857                                 hitp->hitp->hit_magic = RT_HIT_MAGIC;
00858                                 hitp->hitp->hit_dist = t_tmp;
00859                                 hitp->hitp->hit_surfno = seg_no*10 + PIPE_LINEAR_INNER_BODY;
00860                                 VMOVE( hitp->hitp->hit_vpriv, hit_pt );
00861                                 hitp->hitp->hit_vpriv[Z] = (-pipe->pipe_ribase - hit_pt[Z] * pipe->pipe_ridiff) *
00862                                         pipe->pipe_ridiff;
00863                                 (*hit_count)++;
00864                                 BU_LIST_INSERT( &hit_headp->l, &hitp->l );
00865                         }
00866 
00867                         t_tmp = (-b + sqrt_descrim)/(2.0*a);
00868                         VJOIN1( hit_pt, ray_start, t_tmp, ray_dir );
00869                         if( hit_pt[Z] >= 0.0 && hit_pt[Z] <= 1.0 )
00870                         {
00871                                 BU_GETSTRUCT( hitp, hit_list );
00872                                 BU_GETSTRUCT( hitp->hitp, hit );
00873                                 hitp->hitp->hit_magic = RT_HIT_MAGIC;
00874                                 hitp->hitp->hit_dist = t_tmp;
00875                                 hitp->hitp->hit_surfno = seg_no*10 + PIPE_LINEAR_INNER_BODY;
00876                                 VMOVE( hitp->hitp->hit_vpriv, hit_pt );
00877                                 hitp->hitp->hit_vpriv[Z] = (-pipe->pipe_ribase - hit_pt[Z] * pipe->pipe_ridiff) *
00878                                         pipe->pipe_ridiff;
00879                                 (*hit_count)++;
00880                                 BU_LIST_INSERT( &hit_headp->l, &hitp->l );
00881                         }
00882                 }
00883         }
00884 
00885 }
00886 
00887 HIDDEN void
00888 pipe_start_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead, struct id_pipe *pipe, struct hit_list *hit_headp, int *hit_count, int seg_no)
00889 {
00890         point_t hit_pt;
00891         fastf_t t_tmp;
00892         fastf_t radius_sq;
00893         struct hit_list *hitp;
00894 
00895         *hit_count = 0;
00896 
00897         if( !pipe->pipe_is_bend )
00898         {
00899                 struct lin_pipe *lin=(struct lin_pipe *)(&pipe->l);
00900                 fastf_t dist_to_plane;
00901                 fastf_t norm_dist;
00902                 fastf_t slant_factor;
00903 
00904                 dist_to_plane = VDOT( lin->pipe_H, lin->pipe_V );
00905                 norm_dist = dist_to_plane - VDOT( lin->pipe_H, rp->r_pt );
00906                 slant_factor = VDOT( lin->pipe_H, rp->r_dir );
00907                 if( !NEAR_ZERO( slant_factor, SMALL_FASTF ) )
00908                 {
00909                         vect_t to_center;
00910 
00911                         t_tmp = norm_dist/slant_factor;
00912                         VJOIN1( hit_pt, rp->r_pt, t_tmp, rp->r_dir );
00913                         VSUB2( to_center, lin->pipe_V, hit_pt );
00914                         radius_sq = MAGSQ( to_center );
00915                         if( radius_sq <= lin->pipe_robase_sq && radius_sq >= lin->pipe_ribase_sq )
00916                         {
00917                                 BU_GETSTRUCT( hitp, hit_list );
00918                                 BU_GETSTRUCT( hitp->hitp, hit );
00919                                 hitp->hitp->hit_magic = RT_HIT_MAGIC;
00920                                 hitp->hitp->hit_dist = t_tmp;
00921                                 hitp->hitp->hit_surfno = seg_no*10 + PIPE_LINEAR_BASE;
00922                                 (*hit_count)++;
00923                                 BU_LIST_INSERT( &hit_headp->l, &hitp->l );
00924                         }
00925                 }
00926         }
00927         else if( pipe->pipe_is_bend )
00928         {
00929                 struct bend_pipe *bend=(struct bend_pipe *)(&pipe->l);
00930                 fastf_t dist_to_plane;
00931                 fastf_t norm_dist;
00932                 fastf_t slant_factor;
00933 
00934                 dist_to_plane = VDOT( bend->bend_rb, bend->bend_start );
00935                 norm_dist = dist_to_plane - VDOT( bend->bend_rb, rp->r_pt );
00936                 slant_factor = VDOT( bend->bend_rb, rp->r_dir );
00937 
00938                 if( !NEAR_ZERO( slant_factor, SMALL_FASTF ) )
00939                 {
00940                         vect_t to_center;
00941 
00942                         t_tmp = norm_dist/slant_factor;
00943                         VJOIN1( hit_pt, rp->r_pt, t_tmp, rp->r_dir );
00944                         VSUB2( to_center, bend->bend_start, hit_pt );
00945                         radius_sq = MAGSQ( to_center );
00946                         if( radius_sq <= bend->bend_or*bend->bend_or && radius_sq >= bend->bend_ir*bend->bend_ir )
00947                         {
00948                                 BU_GETSTRUCT( hitp, hit_list );
00949                                 BU_GETSTRUCT( hitp->hitp, hit );
00950                                 hitp->hitp->hit_magic = RT_HIT_MAGIC;
00951                                 hitp->hitp->hit_dist = t_tmp;
00952                                 hitp->hitp->hit_surfno = seg_no*10 + PIPE_BEND_BASE;
00953                                 (*hit_count)++;
00954                                 BU_LIST_INSERT( &hit_headp->l, &hitp->l );
00955                         }
00956                 }
00957         }
00958 }
00959 
00960 HIDDEN void
00961 pipe_end_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead, struct id_pipe *pipe, struct hit_list *hit_headp, int *hit_count, int seg_no)
00962 {
00963         point_t hit_pt;
00964         fastf_t t_tmp;
00965         fastf_t radius_sq;
00966         struct hit_list *hitp;
00967 
00968         *hit_count = 0;
00969 
00970         if( !pipe->pipe_is_bend )
00971         {
00972                 struct lin_pipe *lin=(struct lin_pipe *)(&pipe->l);
00973                 point_t top;
00974                 fastf_t dist_to_plane;
00975                 fastf_t norm_dist;
00976                 fastf_t slant_factor;
00977 
00978                 VJOIN1( top, lin->pipe_V, lin->pipe_len, lin->pipe_H );
00979                 dist_to_plane = VDOT( lin->pipe_H, top );
00980                 norm_dist = dist_to_plane - VDOT( lin->pipe_H, rp->r_pt );
00981                 slant_factor = VDOT( lin->pipe_H, rp->r_dir );
00982                 if( !NEAR_ZERO( slant_factor, SMALL_FASTF ) )
00983                 {
00984                         vect_t to_center;
00985 
00986                         t_tmp = norm_dist/slant_factor;
00987                         VJOIN1( hit_pt, rp->r_pt, t_tmp, rp->r_dir );
00988                         VSUB2( to_center, top, hit_pt );
00989                         radius_sq = MAGSQ( to_center );
00990                         if( radius_sq <= lin->pipe_rotop_sq && radius_sq >= lin->pipe_ritop_sq )
00991                         {
00992                                 BU_GETSTRUCT( hitp, hit_list );
00993                                 BU_GETSTRUCT( hitp->hitp, hit );
00994                                 hitp->hitp->hit_magic = RT_HIT_MAGIC;
00995                                 hitp->hitp->hit_dist = t_tmp;
00996                                 hitp->hitp->hit_surfno = seg_no*10 + PIPE_LINEAR_TOP;
00997                                 (*hit_count)++;
00998                                 BU_LIST_INSERT( &hit_headp->l, &hitp->l );
00999                         }
01000                 }
01001         }
01002         else if( pipe->pipe_is_bend )
01003         {
01004                 struct bend_pipe *bend=(struct bend_pipe *)(&pipe->l);
01005                 vect_t to_end;
01006                 vect_t plane_norm;
01007                 fastf_t dist_to_plane;
01008                 fastf_t norm_dist;
01009                 fastf_t slant_factor;
01010 
01011                 VSUB2( to_end, bend->bend_end, bend->bend_V );
01012                 VCROSS( plane_norm, to_end, bend->bend_N );
01013                 VUNITIZE( plane_norm );
01014 
01015                 dist_to_plane = VDOT( plane_norm, bend->bend_end );
01016                 norm_dist = dist_to_plane - VDOT( plane_norm, rp->r_pt );
01017                 slant_factor = VDOT( plane_norm, rp->r_dir );
01018 
01019                 if( !NEAR_ZERO( slant_factor, SMALL_FASTF ) )
01020                 {
01021                         vect_t to_center;
01022 
01023                         t_tmp = norm_dist/slant_factor;
01024                         VJOIN1( hit_pt, rp->r_pt, t_tmp, rp->r_dir );
01025                         VSUB2( to_center, bend->bend_end, hit_pt );
01026                         radius_sq = MAGSQ( to_center );
01027                         if( radius_sq <= bend->bend_or*bend->bend_or && radius_sq >= bend->bend_ir*bend->bend_ir )
01028                         {
01029                                 BU_GETSTRUCT( hitp, hit_list );
01030                                 BU_GETSTRUCT( hitp->hitp, hit );
01031                                 hitp->hitp->hit_magic = RT_HIT_MAGIC;
01032                                 hitp->hitp->hit_dist = t_tmp;
01033                                 hitp->hitp->hit_surfno = seg_no*10 + PIPE_BEND_TOP;
01034                                 (*hit_count)++;
01035                                 BU_LIST_INSERT( &hit_headp->l, &hitp->l );
01036                         }
01037                 }
01038         }
01039 }
01040 
01041 HIDDEN void
01042 rt_pipe_hitsort(struct hit_list *h, int *nh, register struct xray *rp, struct soltab *stp)
01043 {
01044         struct hit_list *hitp;
01045         struct hit_list *first;
01046         struct hit_list *second;
01047         struct hit_list *prev;
01048         struct hit_list *next_hit;
01049 
01050         hitp = BU_LIST_FIRST( hit_list, &h->l );
01051         while( BU_LIST_NEXT_NOT_HEAD( &hitp->l, &h->l ) )
01052         {
01053                 struct hit_list *next_hit;
01054                 struct hit_list *prev_hit;
01055 
01056                 next_hit = BU_LIST_NEXT( hit_list, &hitp->l );
01057                 if( hitp->hitp->hit_dist > next_hit->hitp->hit_dist )
01058                 {
01059                         struct hit_list *tmp;
01060 
01061                         if( hitp == BU_LIST_FIRST( hit_list, &h->l ) )
01062                                 prev_hit = (struct hit_list *)NULL;
01063                         else
01064                                 prev_hit = BU_LIST_PREV( hit_list, &hitp->l );
01065 
01066                         
01067                         tmp = hitp;
01068                         BU_LIST_DEQUEUE( &tmp->l );
01069                         BU_LIST_INSERT( &h->l, &tmp->l );
01070 
01071                         if( prev_hit )
01072                                 hitp = prev_hit;
01073                         else
01074                                 hitp = BU_LIST_FIRST( hit_list, &h->l );
01075                 }
01076                 else
01077                         hitp = next_hit;
01078         }
01079 
01080         
01081         hitp = BU_LIST_FIRST( hit_list, &h->l );
01082         while( BU_LIST_NEXT_NOT_HEAD( &hitp->l, &h->l ) )
01083         {
01084                 next_hit = BU_LIST_NEXT( hit_list, &hitp->l );
01085 
01086                 if( NEAR_ZERO( hitp->hitp->hit_dist - next_hit->hitp->hit_dist, 0.00001) &&
01087                                hitp->hitp->hit_surfno == next_hit->hitp->hit_surfno )
01088                 {
01089                         struct hit_list *tmp;
01090 
01091                         tmp = hitp;
01092                         hitp = next_hit;
01093                         BU_LIST_DEQUEUE( &tmp->l );
01094                         bu_free( (char *)tmp->hitp, "rt_pipe_hitsort: tmp->hitp" );
01095                         bu_free( (char *)tmp, "rt_pipe_hitsort: tmp" );
01096                         (*nh)--;
01097                         tmp = hitp;
01098                         next_hit = BU_LIST_NEXT( hit_list, &hitp->l );
01099                         hitp = next_hit;
01100                         BU_LIST_DEQUEUE( &tmp->l );
01101                         bu_free( (char *)tmp->hitp, "rt_pipe_hitsort: tmp->hitp" );
01102                         bu_free( (char *)tmp, "rt_pipe_hitsort: tmp" );
01103                         (*nh)--;
01104                         if( BU_LIST_IS_HEAD( &hitp->l, &h->l ) )
01105                                 break;
01106                 }
01107                 else
01108                         hitp = next_hit;
01109         }
01110 
01111         if( *nh == 1 )
01112         {
01113                 while( BU_LIST_WHILE( hitp, hit_list, &h->l ) )
01114                 {
01115                         BU_LIST_DEQUEUE( &hitp->l );
01116                         bu_free( (char *)hitp->hitp, "pipe_hitsort: hitp->hitp" );
01117                         bu_free( (char *)hitp, "pipe_hitsort: hitp" );
01118                 }
01119                 (*nh) = 0;
01120                 return;
01121         }
01122 
01123         if( *nh == 0 || *nh == 2 )
01124                 return;
01125 
01126         
01127         first = BU_LIST_FIRST( hit_list, &h->l );
01128         if( VDOT( first->hitp->hit_normal, rp->r_dir ) > 0.0 )
01129         {
01130 
01131                 bu_log( "ERROR: first hit on %s (surfno = %d) is an exit at (%g %g %g)\n",
01132                         stp->st_dp->d_namep, first->hitp->hit_surfno, V3ARGS( first->hitp->hit_point ) );
01133                 bu_log( "\tray start = (%.12e %.12e %.12e), ray dir = (%.12e %.12e %.12e)\n",
01134                         V3ARGS( rp->r_pt ), V3ARGS( rp->r_dir ) );
01135 
01136                 while( BU_LIST_WHILE( hitp, hit_list, &h->l ) )
01137                 {
01138                         BU_LIST_DEQUEUE( &hitp->l );
01139                         bu_free( (char *)hitp->hitp, "pipe_hitsort: hitp->hitp" );
01140                         bu_free( (char *)hitp, "pipe_hitsort: hitp" );
01141                 }
01142                 (*nh) = 0;
01143                 return;
01144         }
01145 
01146         while( BU_LIST_NOT_HEAD( &first->l, &h->l ) )
01147         {
01148                 second = BU_LIST_NEXT( hit_list, &first->l );
01149                 if( BU_LIST_IS_HEAD( &second->l, &h->l ) )
01150                         break;
01151 
01152                 while( BU_LIST_NOT_HEAD( &second->l, &h->l ) && VDOT( second->hitp->hit_normal, rp->r_dir ) < 0.0 )
01153                 {
01154                         prev = second;
01155                         second = BU_LIST_NEXT( hit_list, &second->l );
01156                         if( BU_LIST_NOT_HEAD( &second->l, &h->l ) )
01157                         {
01158                                 BU_LIST_DEQUEUE( &prev->l );
01159                                 bu_free( (char *)prev->hitp, "pipe_hitsort: prev->hitp" );
01160                                 bu_free( (char *)prev, "pipe_hitsort: prev" );
01161                                 (*nh)--;
01162                         }
01163                 }
01164                 prev = NULL;
01165                 while( BU_LIST_NOT_HEAD( &second->l, &h->l ) && VDOT( second->hitp->hit_normal, rp->r_dir ) > 0.0 )
01166                 {
01167                         if( prev )
01168                         {
01169                                 BU_LIST_DEQUEUE( &prev->l );
01170                                 bu_free( (char *)prev->hitp, "pipe_hitsort: prev->hitp" );
01171                                 bu_free( (char *)prev, "pipe_hitsort: prev" );
01172                                 (*nh)--;
01173                         }
01174                         prev = second;
01175                         second = BU_LIST_NEXT( hit_list, &second->l );
01176                 }
01177                 first = second;
01178         }
01179 }
01180 
01181 
01182 
01183 
01184 
01185 
01186 void
01187 rt_pipe_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
01188 {
01189         register struct bu_list         *pipe =
01190                 (struct bu_list *)stp->st_specific;
01191         register struct id_pipe         *pipe_id;
01192         register struct lin_pipe        *pipe_lin;
01193         register struct bend_pipe       *pipe_bend;
01194         LOCAL fastf_t   w;
01195         LOCAL vect_t    work;
01196         LOCAL vect_t    work1;
01197         LOCAL int       segno;
01198         LOCAL int       i;
01199 
01200         segno = hitp->hit_surfno/10;
01201 
01202         pipe_id = BU_LIST_FIRST( id_pipe, pipe );
01203         for( i=1 ; i<segno ; i++ )
01204                 pipe_id = BU_LIST_NEXT( id_pipe, &pipe_id->l );
01205 
01206         pipe_lin = (struct lin_pipe *)pipe_id;
01207         pipe_bend = (struct bend_pipe *)pipe_id;
01208 
01209         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
01210         switch( hitp->hit_surfno%10 )
01211         {
01212                 case PIPE_LINEAR_TOP:
01213                         VMOVE( hitp->hit_normal, pipe_lin->pipe_H );
01214                         break;
01215                 case PIPE_LINEAR_BASE:
01216                         VREVERSE( hitp->hit_normal, pipe_lin->pipe_H );
01217                         break;
01218                 case PIPE_LINEAR_OUTER_BODY:
01219                         MAT4X3VEC( hitp->hit_normal, pipe_lin->pipe_invRoS, hitp->hit_vpriv );
01220                         VUNITIZE( hitp->hit_normal );
01221                         break;
01222                 case PIPE_LINEAR_INNER_BODY:
01223                         MAT4X3VEC( hitp->hit_normal, pipe_lin->pipe_invRoS, hitp->hit_vpriv );
01224                         VUNITIZE( hitp->hit_normal );
01225                         VREVERSE( hitp->hit_normal, hitp->hit_normal );
01226                         break;
01227                 case PIPE_BEND_OUTER_BODY:
01228                         w = hitp->hit_vpriv[X]*hitp->hit_vpriv[X] +
01229                             hitp->hit_vpriv[Y]*hitp->hit_vpriv[Y] +
01230                             hitp->hit_vpriv[Z]*hitp->hit_vpriv[Z] +
01231                             1.0 - pipe_bend->bend_alpha_o*pipe_bend->bend_alpha_o;
01232                         VSET( work,
01233                                 ( w - 2.0 ) * hitp->hit_vpriv[X],
01234                                 ( w - 2.0 ) * hitp->hit_vpriv[Y],
01235                                   w * hitp->hit_vpriv[Z] );
01236                         VUNITIZE( work );
01237                         MAT3X3VEC( hitp->hit_normal, pipe_bend->bend_invR, work );
01238                         break;
01239                 case PIPE_BEND_INNER_BODY:
01240                         w = hitp->hit_vpriv[X]*hitp->hit_vpriv[X] +
01241                             hitp->hit_vpriv[Y]*hitp->hit_vpriv[Y] +
01242                             hitp->hit_vpriv[Z]*hitp->hit_vpriv[Z] +
01243                             1.0 - pipe_bend->bend_alpha_o*pipe_bend->bend_alpha_o;
01244                         VSET( work,
01245                                 ( w - 2.0 ) * hitp->hit_vpriv[X],
01246                                 ( w - 2.0 ) * hitp->hit_vpriv[Y],
01247                                   w * hitp->hit_vpriv[Z] );
01248                         VUNITIZE( work );
01249                         MAT3X3VEC( work1, pipe_bend->bend_invR, work );
01250                         VREVERSE( hitp->hit_normal, work1 );
01251                         break;
01252                 case PIPE_BEND_BASE:
01253                         VREVERSE( hitp->hit_normal, pipe_bend->bend_rb );
01254                         break;
01255                 case PIPE_BEND_TOP:
01256                         VSUB2( work, pipe_bend->bend_end, pipe_bend->bend_V );
01257                         VCROSS( hitp->hit_normal, pipe_bend->bend_N, work );
01258                         VUNITIZE( hitp->hit_normal );
01259                         break;
01260                 default:
01261                         bu_log( "rt_pipe_norm: Unrecognized surfno (%d)\n", hitp->hit_surfno );
01262                         break;
01263         }
01264 }
01265 
01266 
01267 
01268 
01269 
01270 
01271 
01272 
01273 
01274 
01275 
01276 
01277 int
01278 rt_pipe_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
01279 {
01280         register struct bu_list         *head =
01281                 (struct bu_list *)stp->st_specific;
01282         register struct id_pipe         *pipe_id;
01283         register struct seg             *segp;
01284         LOCAL struct hit_list           hit_head;
01285         LOCAL struct hit_list           *hitp;
01286         LOCAL int                       hit_count;
01287         LOCAL int                       total_hits;
01288         LOCAL int                       seg_no;
01289         LOCAL int                       i;
01290 
01291         BU_LIST_INIT( &hit_head.l );
01292 
01293         pipe_start_shot( stp, rp, ap, seghead, BU_LIST_FIRST( id_pipe, head ),
01294                 &hit_head, &total_hits, 1 );
01295         seg_no = 0;
01296         for( BU_LIST_FOR( pipe_id, id_pipe, head ) )
01297                 seg_no++;
01298         pipe_end_shot( stp, rp, ap, seghead, BU_LIST_LAST( id_pipe, head ),
01299                 &hit_head, &hit_count, seg_no );
01300         total_hits += hit_count;
01301 
01302         seg_no = 0;
01303         for( BU_LIST_FOR( pipe_id, id_pipe, head ) )
01304         {
01305                 seg_no++;
01306 
01307                 if( !pipe_id->pipe_is_bend )
01308                 {
01309                         linear_pipe_shot( stp, rp, ap, seghead, (struct lin_pipe *)pipe_id,
01310                                 &hit_head, &hit_count, seg_no );
01311                         total_hits += hit_count;
01312                 }
01313                 else
01314                 {
01315                         bend_pipe_shot( stp, rp, ap, seghead, (struct bend_pipe *)pipe_id,
01316                                 &hit_head, &hit_count, seg_no );
01317                         total_hits += hit_count;
01318                 }
01319         }
01320         if( !total_hits )
01321                 return( 0 );
01322 
01323         
01324         for( BU_LIST_FOR( hitp, hit_list, &hit_head.l ) )
01325                 rt_pipe_norm( hitp->hitp, stp , rp );
01326 
01327         rt_pipe_hitsort( &hit_head, &total_hits, rp, stp );
01328 
01329         
01330         if( total_hits%2 )
01331         {
01332                 i = 0;
01333                 bu_log( "rt_pipe_shot: bad number of hits on solid %s (%d)\n", stp->st_dp->d_namep, total_hits );
01334                 bu_log( "Ignoring this solid for this ray\n" );
01335                 bu_log( "\tray start = (%e %e %e), ray dir = (%e %e %e)\n", V3ARGS( rp->r_pt ), V3ARGS( rp->r_dir ) );
01336                 for( BU_LIST_FOR( hitp, hit_list, &hit_head.l ) )
01337                 {
01338                         point_t hit_pt;
01339 
01340                         bu_log( "#%d, dist = %g, surfno=%d\n" , ++i, hitp->hitp->hit_dist, hitp->hitp->hit_surfno );
01341                         VJOIN1( hit_pt, rp->r_pt, hitp->hitp->hit_dist,  rp->r_dir );
01342                         bu_log( "\t( %g %g %g )\n" , V3ARGS( hit_pt ) );
01343                 }
01344 
01345                 
01346                 while( BU_LIST_WHILE( hitp, hit_list, &hit_head.l ) )
01347                 {
01348                         BU_LIST_DEQUEUE( &hitp->l );
01349                         bu_free( (char *)hitp->hitp, "rt_pipe_shot: hitp->hitp" );
01350                         bu_free( (char *)hitp, "rt_pipe_shot: hitp" );
01351                 }
01352 
01353                 return( 0 );
01354         }
01355 
01356         hitp = BU_LIST_FIRST( hit_list, &hit_head.l );
01357         while( BU_LIST_NOT_HEAD( &hitp->l, &hit_head.l ) )
01358         {
01359                 struct hit_list *next;
01360 
01361                 next = BU_LIST_NEXT( hit_list, &hitp->l );
01362 
01363                 RT_GET_SEG(segp, ap->a_resource);
01364 
01365                 segp->seg_stp = stp;
01366                 segp->seg_in = (*hitp->hitp);
01367                 segp->seg_out = (*next->hitp);
01368 
01369                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
01370 
01371                 hitp = BU_LIST_NEXT( hit_list, &next->l );
01372         }
01373 
01374         
01375         while( BU_LIST_WHILE( hitp, hit_list, &hit_head.l ) )
01376         {
01377                 BU_LIST_DEQUEUE( &hitp->l );
01378                 bu_free( (char *)hitp->hitp, "rt_pipe_shot: hitp->hitp" );
01379                 bu_free( (char *)hitp, "rt_pipe_shot: hitp" );
01380         }
01381 
01382         if( total_hits )
01383                 return( 1 );            
01384         else
01385                 return(0);              
01386 }
01387 
01388 #define SEG_MISS(SEG)           (SEG).seg_stp=(struct soltab *) 0;
01389 
01390 
01391 
01392 
01393 
01394 
01395 void
01396 rt_pipe_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
01397                                
01398                                
01399                                
01400                                
01401 
01402 {
01403         rt_vstub( stp, rp, segp, n, ap );
01404 }
01405 
01406 
01407 
01408 
01409 
01410 
01411 void
01412 rt_pipe_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
01413 {
01414 
01415 
01416 
01417         cvp->crv_c1 = cvp->crv_c2 = 0;
01418 
01419         
01420         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
01421 }
01422 
01423 
01424 
01425 
01426 
01427 
01428 
01429 
01430 
01431 void
01432 rt_pipe_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
01433 {
01434 
01435 
01436 }
01437 
01438 
01439 
01440 
01441 void
01442 rt_pipe_free(register struct soltab *stp)
01443 {
01444 #if 0
01445         register struct bu_list *pipe =
01446                 (struct bu_list *)stp->st_specific;
01447 
01448         
01449         while( BU_LIST_NON_EMPTY( &pipe->id.l ) )
01450         {
01451                 register struct bu_list *pipe_ptr;
01452 
01453                 pipe_ptr = (struct bu_list *)(&pipe->id.l)->forw;
01454                 bu_free( (char *)pipe_ptr, "pipe_specific" );
01455         }
01456 
01457         
01458         bu_free( (char *)pipe, "pipe_specific head" );
01459 #endif
01460 }
01461 
01462 
01463 
01464 
01465 int
01466 rt_pipe_class(void)
01467 {
01468         return(0);
01469 }
01470 
01471 
01472 
01473 
01474 
01475 
01476 
01477 
01478 
01479 
01480 HIDDEN void
01481 draw_pipe_arc(struct bu_list *vhead, fastf_t radius, fastf_t *center, const fastf_t *v1, const fastf_t *v2, fastf_t *end, int seg_count, int full_circle)
01482 {
01483         fastf_t         arc_angle;
01484         fastf_t         delta_ang;
01485         fastf_t         cos_del, sin_del;
01486         fastf_t         x, y, xnew, ynew;
01487         vect_t          to_end;
01488         point_t         pt;
01489         int             i;
01490 
01491         if( !full_circle )
01492         {
01493                 VSUB2( to_end, end, center );
01494                 arc_angle = atan2( VDOT( to_end, v2 ), VDOT( to_end, v1 ) );
01495                 delta_ang = arc_angle/seg_count;
01496         }
01497         else
01498                 delta_ang = 2.0*bn_pi/seg_count;
01499 
01500         cos_del = cos( delta_ang );
01501         sin_del = sin( delta_ang );
01502 
01503         x = radius;
01504         y = 0.0;
01505         VJOIN2( pt, center, x, v1, y, v2 );
01506         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
01507         for( i=0 ; i<seg_count ; i++ )
01508         {
01509                 xnew = x*cos_del - y*sin_del;
01510                 ynew = x*sin_del + y*cos_del;
01511                 VJOIN2( pt, center, xnew, v1, ynew, v2 );
01512                 RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
01513                 x = xnew;
01514                 y = ynew;
01515         }
01516 }
01517 
01518 HIDDEN void
01519 draw_linear_seg(struct bu_list *vhead, const fastf_t *p1, const fastf_t or1, const fastf_t ir1, const fastf_t *p2, const fastf_t or2, const fastf_t ir2, const fastf_t *v1, const fastf_t *v2)
01520 {
01521         point_t pt;
01522 
01523         VJOIN1( pt, p1, or1, v1 );
01524         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
01525         VJOIN1( pt, p2, or2, v1 );
01526         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
01527         VJOIN1( pt, p1, or1, v2 );
01528         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
01529         VJOIN1( pt, p2, or2, v2 );
01530         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
01531         VJOIN1( pt, p1, -or1, v1 );
01532         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
01533         VJOIN1( pt, p2, -or2, v1 );
01534         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
01535         VJOIN1( pt, p1, -or1, v2 );
01536         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
01537         VJOIN1( pt, p2, -or2, v2 );
01538         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
01539 
01540         if( ir1 <= 0.0 && ir2 <= 0.0 )
01541                 return;
01542 
01543         VJOIN1( pt, p1, ir1, v1 );
01544         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
01545         VJOIN1( pt, p2, ir2, v1 );
01546         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
01547         VJOIN1( pt, p1, ir1, v2 );
01548         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
01549         VJOIN1( pt, p2, ir2, v2 );
01550         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
01551         VJOIN1( pt, p1, -ir1, v1 );
01552         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
01553         VJOIN1( pt, p2, -ir2, v1 );
01554         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
01555         VJOIN1( pt, p1, -ir1, v2 );
01556         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
01557         VJOIN1( pt, p2, -ir2, v2 );
01558         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
01559 }
01560 
01561 HIDDEN void
01562 draw_pipe_bend(struct bu_list *vhead, const fastf_t *center, const fastf_t *end, const fastf_t radius, const fastf_t angle, const fastf_t *v1, const fastf_t *v2, const fastf_t *norm, const fastf_t or, const fastf_t ir, fastf_t *f1, fastf_t *f2, const int
01563 seg_count)
01564 {
01565 
01566         point_t tmp_center, tmp_start, tmp_end;
01567         vect_t tmp_vec;
01568         fastf_t tmp_radius;
01569         fastf_t move_dist;
01570         vect_t end_f1,end_f2;
01571         mat_t mat;
01572         vect_t tmp_norm;
01573 
01574         VREVERSE( tmp_norm, norm );
01575         bn_mat_arb_rot( mat, center, tmp_norm, angle );
01576         MAT4X3VEC( tmp_vec, mat, f1 );
01577         VMOVE( end_f1, tmp_vec );
01578         MAT4X3VEC( tmp_vec, mat, f2 );
01579         VMOVE( end_f2, tmp_vec );
01580 
01581         move_dist = or * VDOT( f1, norm );
01582         VJOIN2( tmp_start, center, radius, v1, or, f1 );
01583         VJOIN1( tmp_center, center, move_dist, norm );
01584         VJOIN1( tmp_end, end, or, end_f1 );
01585         VSUB2( tmp_vec, tmp_start, tmp_center );
01586         tmp_radius = MAGNITUDE( tmp_vec );
01587         draw_pipe_arc( vhead, tmp_radius, tmp_center, v1, v2, tmp_end, seg_count, 0 );
01588         VJOIN2( tmp_start, center, radius, v1, -or, f1 );
01589         VJOIN1( tmp_center, center, -move_dist, norm );
01590         VJOIN1( tmp_end, end, -or, end_f1 );
01591         VSUB2( tmp_vec, tmp_start, tmp_center );
01592         tmp_radius = MAGNITUDE( tmp_vec );
01593         draw_pipe_arc( vhead, tmp_radius, tmp_center, v1, v2, tmp_end, seg_count, 0 );
01594         move_dist = or * VDOT( f2, norm );
01595         VJOIN2( tmp_start, center, radius, v1, or, f2 );
01596         VJOIN1( tmp_center, center, move_dist, norm );
01597         VJOIN1( tmp_end, end, or, end_f2 );
01598         VSUB2( tmp_vec, tmp_start, tmp_center );
01599         tmp_radius = MAGNITUDE( tmp_vec );
01600         draw_pipe_arc( vhead, tmp_radius, tmp_center, v1, v2, tmp_end, seg_count, 0 );
01601         VJOIN2( tmp_start, center, radius, v1, -or, f2 );
01602         VJOIN1( tmp_center, center, -move_dist, norm );
01603         VJOIN1( tmp_end, end, -or, end_f2 );
01604         VSUB2( tmp_vec, tmp_start, tmp_center );
01605         tmp_radius = MAGNITUDE( tmp_vec );
01606         draw_pipe_arc( vhead, tmp_radius, tmp_center, v1, v2, tmp_end, seg_count, 0 );
01607 
01608         if( ir <= 0.0 )
01609         {
01610                 VMOVE( f1, end_f1 );
01611                 VMOVE( f2, end_f2 );
01612                 return;
01613         }
01614 
01615         move_dist = ir * VDOT( f1, norm );
01616         VJOIN2( tmp_start, center, radius, v1, ir, f1 );
01617         VJOIN1( tmp_center, center, move_dist, norm );
01618         VJOIN1( tmp_end, end, ir, end_f1 );
01619         VSUB2( tmp_vec, tmp_start, tmp_center );
01620         tmp_radius = MAGNITUDE( tmp_vec );
01621         draw_pipe_arc( vhead, tmp_radius, tmp_center, v1, v2, tmp_end, seg_count, 0 );
01622         VJOIN2( tmp_start, center, radius, v1, -ir, f1 );
01623         VJOIN1( tmp_center, center, -move_dist, norm );
01624         VJOIN1( tmp_end, end, -ir, end_f1 );
01625         VSUB2( tmp_vec, tmp_start, tmp_center );
01626         tmp_radius = MAGNITUDE( tmp_vec );
01627         draw_pipe_arc( vhead, tmp_radius, tmp_center, v1, v2, tmp_end, seg_count, 0 );
01628         move_dist = ir * VDOT( f2, norm );
01629         VJOIN2( tmp_start, center, radius, v1, ir, f2 );
01630         VJOIN1( tmp_center, center, move_dist, norm );
01631         VJOIN1( tmp_end, end, ir, end_f2 );
01632         VSUB2( tmp_vec, tmp_start, tmp_center );
01633         tmp_radius = MAGNITUDE( tmp_vec );
01634         draw_pipe_arc( vhead, tmp_radius, tmp_center, v1, v2, tmp_end, seg_count, 0 );
01635         VJOIN2( tmp_start, center, radius, v1, -ir, f2 );
01636         VJOIN1( tmp_center, center, -move_dist, norm );
01637         VJOIN1( tmp_end, end, -ir, end_f2 );
01638         VSUB2( tmp_vec, tmp_start, tmp_center );
01639         tmp_radius = MAGNITUDE( tmp_vec );
01640         draw_pipe_arc( vhead, tmp_radius, tmp_center, v1, v2, tmp_end, seg_count, 0 );
01641 
01642         VMOVE( f1, end_f1 );
01643         VMOVE( f2, end_f2 );
01644 }
01645 
01646 
01647 
01648 
01649 int
01650 rt_pipe_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01651 {
01652         register struct wdb_pipept              *prevp;
01653         register struct wdb_pipept              *curp;
01654         register struct wdb_pipept              *nextp;
01655         LOCAL struct rt_pipe_internal           *pip;
01656         LOCAL point_t                           current_point;
01657         LOCAL vect_t                            f1,f2,f3;
01658 
01659         RT_CK_DB_INTERNAL(ip);
01660         pip = (struct rt_pipe_internal *)ip->idb_ptr;
01661         RT_PIPE_CK_MAGIC(pip);
01662 
01663         if( BU_LIST_IS_EMPTY( &pip->pipe_segs_head ) )
01664                 return( 0 );
01665 
01666         prevp = BU_LIST_FIRST( wdb_pipept, &pip->pipe_segs_head );
01667         curp = BU_LIST_NEXT( wdb_pipept, &prevp->l );
01668         nextp = BU_LIST_NEXT( wdb_pipept, &curp->l );
01669 
01670         if( BU_LIST_IS_HEAD( &curp->l , &pip->pipe_segs_head ) )
01671                 return( 0 );    
01672 
01673         VMOVE( current_point, prevp->pp_coord );
01674 
01675         
01676         VSUB2( f3, prevp->pp_coord, curp->pp_coord );
01677         bn_vec_ortho( f1, f3 );
01678         VCROSS( f2, f3, f1 );
01679         VUNITIZE( f2 );
01680 
01681         draw_pipe_arc( vhead, prevp->pp_od/2.0, prevp->pp_coord, f1, f2, f2, ARC_SEGS, 1 );
01682         if( prevp->pp_id > 0.0 )
01683                 draw_pipe_arc( vhead, prevp->pp_id/2.0, prevp->pp_coord, f1, f2, f2, ARC_SEGS, 1 );
01684 
01685         while( 1 )
01686         {
01687                 LOCAL vect_t n1,n2;
01688                 LOCAL vect_t norm;
01689                 LOCAL fastf_t angle;
01690                 LOCAL fastf_t dist_to_bend;
01691 
01692                 if( BU_LIST_IS_HEAD( &nextp->l, &pip->pipe_segs_head ) )
01693                 {
01694                         
01695                         draw_linear_seg( vhead, current_point, prevp->pp_od/2.0, prevp->pp_id/2.0,
01696                                 curp->pp_coord, curp->pp_od/2.0, curp->pp_id/2.0, f1, f2 );
01697                         break;
01698                 }
01699 
01700                 VSUB2( n1, prevp->pp_coord, curp->pp_coord );
01701                 if( VNEAR_ZERO( n1, SQRT_SMALL_FASTF ) )
01702                 {
01703                         
01704                         goto next_pt;
01705                 }
01706                 VSUB2( n2, nextp->pp_coord, curp->pp_coord );
01707                 VCROSS( norm, n1, n2 );
01708                 VUNITIZE( n1 );
01709                 VUNITIZE( n2 );
01710                 angle = bn_pi - acos( VDOT( n1, n2 ) );
01711                 dist_to_bend = curp->pp_bendradius * tan( angle/2.0 );
01712                 if( isnan( dist_to_bend ) || VNEAR_ZERO( norm, SQRT_SMALL_FASTF) || NEAR_ZERO( dist_to_bend, SQRT_SMALL_FASTF) )
01713                 {
01714                         
01715                         draw_linear_seg( vhead, current_point, prevp->pp_od/2.0, prevp->pp_id/2.0,
01716                                 curp->pp_coord, curp->pp_od/2.0, curp->pp_id/2.0, f1, f2 );
01717                         VMOVE( current_point, curp->pp_coord );
01718                 }
01719                 else
01720                 {
01721                         LOCAL point_t bend_center;
01722                         LOCAL point_t bend_start;
01723                         LOCAL point_t bend_end;
01724                         LOCAL vect_t v1,v2;
01725 
01726                         VUNITIZE( norm );
01727 
01728                         
01729                         VJOIN1( bend_start, curp->pp_coord, dist_to_bend, n1 );
01730                         draw_linear_seg( vhead, current_point, prevp->pp_od/2.0, prevp->pp_id/2.0,
01731                                 bend_start, curp->pp_od/2.0, curp->pp_id/2.0, f1, f2 );
01732 
01733                         
01734                         VJOIN1( bend_end, curp->pp_coord, dist_to_bend, n2 );
01735                         VCROSS( v1, n1, norm );
01736                         VCROSS( v2, v1, norm );
01737                         VJOIN1( bend_center, bend_start, -curp->pp_bendradius, v1 );
01738                         draw_pipe_bend( vhead, bend_center, bend_end, curp->pp_bendradius, angle, v1, v2, norm,
01739                                 curp->pp_od/2.0, curp->pp_id/2.0, f1, f2, ARC_SEGS );
01740 
01741                         VMOVE( current_point, bend_end );
01742                 }
01743 next_pt:
01744                 prevp = curp;
01745                 curp = nextp;
01746                 nextp = BU_LIST_NEXT( wdb_pipept, &curp->l );
01747         }
01748 
01749         draw_pipe_arc( vhead, curp->pp_od/2.0, curp->pp_coord, f1, f2, f2, ARC_SEGS, 1 );
01750         if( curp->pp_id > 0.0 )
01751                 draw_pipe_arc( vhead, curp->pp_id/2.0, curp->pp_coord, f1, f2, f2, ARC_SEGS, 1 );
01752 
01753         return(0);
01754 }
01755 
01756 HIDDEN void
01757 tesselate_pipe_start(struct wdb_pipept *pipe, int arc_segs, double sin_del, double cos_del, struct vertex ***outer_loop, struct vertex ***inner_loop, fastf_t *r1, fastf_t *r2, struct shell *s, const struct bn_tol *tol)
01758 {
01759         struct faceuse *fu;
01760         struct loopuse *lu;
01761         struct edgeuse *eu;
01762         struct wdb_pipept *next;
01763         point_t pt;
01764         fastf_t or;
01765         fastf_t ir;
01766         fastf_t x,y,xnew,ynew;
01767         vect_t n;
01768         int i;
01769 
01770         NMG_CK_SHELL( s );
01771         BN_CK_TOL( tol );
01772 
01773         next = BU_LIST_NEXT( wdb_pipept, &pipe->l );
01774 
01775         VSUB2( n, pipe->pp_coord, next->pp_coord );
01776         VUNITIZE( n );
01777         bn_vec_ortho( r1, n );
01778         VCROSS( r2, n, r1 );
01779 
01780         or = pipe->pp_od/2.0;
01781         ir = pipe->pp_id/2.0;
01782 
01783         if( or <= tol->dist )
01784                 return;
01785 
01786         if( ir > or )
01787         {
01788                 bu_log( "Inner radius larger than outer radius at start of pipe solid\n" );
01789                 return;
01790         }
01791 
01792         if( NEAR_ZERO( ir - or, tol->dist) )
01793                 return;
01794 
01795 
01796         fu = nmg_cface( s, *outer_loop, arc_segs );
01797 
01798         x = or;
01799         y = 0.0;
01800         i = (-1);
01801         lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
01802         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
01803         {
01804                 VJOIN2( pt, pipe->pp_coord, x, r1, y, r2 );
01805                 (*outer_loop)[++i] = eu->vu_p->v_p;
01806                 nmg_vertex_gv( eu->vu_p->v_p, pt );
01807                 xnew = x*cos_del - y*sin_del;
01808                 ynew = x*sin_del + y*cos_del;
01809                 x = xnew;
01810                 y = ynew;
01811         }
01812 
01813         if( ir > tol->dist )
01814         {
01815                 struct edgeuse *new_eu;
01816                 struct vertexuse *vu;
01817 
01818                 
01819                 lu = nmg_mlv( &fu->l.magic, (struct vertex *)NULL, OT_OPPOSITE );
01820 
01821                 vu = BU_LIST_FIRST( vertexuse, &lu->down_hd );
01822                 eu = nmg_meonvu( vu );
01823                 (*inner_loop)[0] = eu->vu_p->v_p;
01824 
01825                 x = ir;
01826                 y = 0.0;
01827                 VJOIN2( pt, pipe->pp_coord, x, r1, y, r2 );
01828                 nmg_vertex_gv( (*inner_loop)[0], pt );
01829                 
01830                 for( i=1 ; i<arc_segs ; i++ )
01831                 {
01832                         new_eu = nmg_eusplit( (struct vertex *)NULL, eu, 0 );
01833                         (*inner_loop)[i] = new_eu->vu_p->v_p;
01834                         xnew = x*cos_del - y*sin_del;
01835                         ynew = x*sin_del + y*cos_del;
01836                         x = xnew;
01837                         y = ynew;
01838                         VJOIN2( pt, pipe->pp_coord, x, r1, y, r2 );
01839                         nmg_vertex_gv( (*inner_loop)[i], pt );
01840                 }
01841         }
01842 
01843         else if( next->pp_id > tol->dist )
01844         {
01845                 struct vertexuse *vu;
01846 
01847                 
01848                 lu = nmg_mlv( &fu->l.magic, (struct vertex *)NULL, OT_OPPOSITE );
01849                 vu = BU_LIST_FIRST( vertexuse, &lu->down_hd );
01850 
01851                 nmg_vertex_gv( vu->v_p, pipe->pp_coord );
01852         }
01853 
01854         if( nmg_calc_face_g( fu ) )
01855                 rt_bomb( "tesselate_pipe_start: nmg_calc_face_g failed\n" );
01856 
01857         for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )
01858         {
01859                 NMG_CK_LOOPUSE( lu );
01860 
01861                 if( BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC )
01862                         continue;
01863 
01864                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
01865                 {
01866                         NMG_CK_EDGEUSE( eu );
01867                         eu->e_p->is_real = 1;
01868                 }
01869         }
01870 }
01871 
01872 HIDDEN void
01873 tesselate_pipe_linear(fastf_t *start_pt,
01874                       fastf_t or,
01875                       fastf_t ir,
01876                       fastf_t *end_pt,
01877                       fastf_t end_or,
01878                       fastf_t end_ir,
01879                       int arc_segs,
01880                       double sin_del,
01881                       double cos_del,
01882                       struct vertex ***outer_loop,
01883                       struct vertex ***inner_loop,
01884                       fastf_t *r1,
01885                       fastf_t *r2,
01886                       struct shell *s,
01887                       const struct bn_tol *tol)
01888 {
01889         struct vertex **new_outer_loop;
01890         struct vertex **new_inner_loop;
01891         struct vertex **verts[3];
01892         struct faceuse *fu;
01893         vect_t *norms;
01894         vect_t n;
01895         fastf_t slope;
01896         fastf_t seg_len;
01897         int i,j;
01898 
01899         NMG_CK_SHELL( s );
01900         BN_CK_TOL( tol );
01901 
01902         norms = (vect_t *)bu_calloc( arc_segs, sizeof( vect_t ), "tesselate_pipe_linear: new normals" );
01903 
01904         if( end_or > tol->dist )
01905                 new_outer_loop = (struct vertex **)bu_calloc( arc_segs, sizeof( struct vertex *),
01906                                 "tesselate_pipe_linear: new_outer_loop" );
01907         else
01908                 new_outer_loop = (struct vertex **)NULL;
01909 
01910         if( end_ir > tol->dist )
01911                 new_inner_loop = (struct vertex **)bu_calloc( arc_segs, sizeof( struct vertex *),
01912                                 "tesselate_pipe_linear: new_inner_loop" );
01913         else
01914                 new_inner_loop = (struct vertex **)NULL;
01915 
01916         VSUB2( n, end_pt, start_pt );
01917         seg_len = MAGNITUDE( n );
01918         VSCALE( n, n, 1.0/seg_len );
01919         slope = (or - end_or)/seg_len;
01920 
01921         if( or > tol->dist && end_or > tol->dist )
01922         {
01923                 point_t pt;
01924                 fastf_t x,y,xnew,ynew;
01925                 struct faceuse *fu_prev=(struct faceuse *)NULL;
01926                 struct vertex **verts[3];
01927 
01928                 x = 1.0;
01929                 y = 0.0;
01930                 VCOMB2( norms[0], x, r1, y, r2 );
01931                 VJOIN1( norms[0], norms[0], slope, n );
01932                 VUNITIZE( norms[0] );
01933                 for( i=0 ; i<arc_segs ; i++ )
01934                 {
01935                         j = i+1;
01936                         if( j == arc_segs )
01937                                 j = 0;
01938 
01939                         VJOIN2( pt, end_pt, x*end_or, r1, y*end_or, r2 );
01940                         xnew = x*cos_del - y*sin_del;
01941                         ynew = x*sin_del + y*cos_del;
01942                         x = xnew;
01943                         y = ynew;
01944                         if( i < arc_segs-1 )
01945                         {
01946                                 VCOMB2( norms[j], x, r1, y, r2 );
01947                                 VJOIN1( norms[j], norms[j], slope, n );
01948                                 VUNITIZE( norms[j] );
01949                         }
01950 
01951                         if( fu_prev )
01952                         {
01953                                 nmg_vertex_gv( new_outer_loop[i], pt );
01954                                 if( nmg_calc_face_g( fu_prev ) )
01955                                 {
01956                                         bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
01957                                         nmg_kfu( fu_prev );
01958                                 }
01959                                 else
01960                                 {
01961                                         
01962                                         struct loopuse *lu;
01963                                         struct edgeuse *eu;
01964 
01965                                         NMG_CK_FACEUSE( fu_prev );
01966 
01967                                         if( fu_prev->orientation != OT_SAME )
01968                                                 fu_prev = fu_prev->fumate_p;
01969 
01970                                         lu = BU_LIST_FIRST( loopuse, &fu_prev->lu_hd );
01971 
01972                                         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
01973                                         {
01974                                                 vect_t reverse_norm;
01975                                                 struct edgeuse *eu_opp_use;
01976 
01977                                                 eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
01978                                                 if( eu->vu_p->v_p == new_outer_loop[i-1] )
01979                                                 {
01980                                                         nmg_vertexuse_nv( eu->vu_p, norms[i-1] );
01981                                                         VREVERSE( reverse_norm, norms[i-1] );
01982                                                         nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
01983                                                 }
01984                                                 else if(  eu->vu_p->v_p == (*outer_loop)[i-1] )
01985                                                 {
01986                                                         nmg_vertexuse_nv( eu->vu_p, norms[i-1] );
01987                                                         VREVERSE( reverse_norm, norms[i-1] );
01988                                                         nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
01989                                                 }
01990                                                 else if(  eu->vu_p->v_p == new_outer_loop[i] )
01991                                                 {
01992                                                         nmg_vertexuse_nv( eu->vu_p, norms[i] );
01993                                                         VREVERSE( reverse_norm, norms[i] );
01994                                                         nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
01995                                                 }
01996                                                 else if(  eu->vu_p->v_p == (*outer_loop)[i] )
01997                                                 {
01998                                                         nmg_vertexuse_nv( eu->vu_p, norms[i] );
01999                                                         VREVERSE( reverse_norm, norms[i] );
02000                                                         nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02001                                                 }
02002                                                 else
02003                                                 {
02004                                                         bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02005                                                         bu_log( "\ti=%d, arc_segs=%d, fu_prev = x%x\n" , i, arc_segs, fu_prev );
02006                                                 }
02007                                         }
02008                                 }
02009                         }
02010 
02011                         verts[0] = &(*outer_loop)[j];
02012                         verts[1] = &(*outer_loop)[i];
02013                         verts[2] = &new_outer_loop[i];
02014 
02015                         if( (fu = nmg_cmface( s, verts, 3 ) ) == NULL )
02016                         {
02017                                 bu_log( "tesselate_pipe_linear: failed to make outer face #%d or=%g, end_or=%g\n",
02018                                                 i, or, end_or );
02019                                 continue;
02020                         }
02021                         if( !new_outer_loop[i]->vg_p )
02022                                 nmg_vertex_gv( new_outer_loop[i], pt );
02023 
02024                         if( nmg_calc_face_g( fu ) )
02025                         {
02026                                 bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
02027                                 nmg_kfu( fu );
02028                         }
02029                         else
02030                         {
02031                                 
02032                                 struct loopuse *lu;
02033                                 struct edgeuse *eu;
02034 
02035                                 NMG_CK_FACEUSE( fu );
02036 
02037                                 if( fu->orientation != OT_SAME )
02038                                         fu = fu->fumate_p;
02039 
02040                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
02041 
02042                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02043                                 {
02044                                         vect_t reverse_norm;
02045                                         struct edgeuse *eu_opp_use;
02046 
02047                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02048                                         if( eu->vu_p->v_p == (*outer_loop)[0] )
02049                                         {
02050                                                 nmg_vertexuse_nv( eu->vu_p, norms[0] );
02051                                                 VREVERSE( reverse_norm, norms[0] );
02052                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02053                                         }
02054                                         else if(  eu->vu_p->v_p == new_outer_loop[i] )
02055                                         {
02056                                                 nmg_vertexuse_nv( eu->vu_p, norms[i] );
02057                                                 VREVERSE( reverse_norm, norms[i] );
02058                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02059                                         }
02060                                         else if(  eu->vu_p->v_p == (*outer_loop)[i] )
02061                                         {
02062                                                 nmg_vertexuse_nv( eu->vu_p, norms[i] );
02063                                                 VREVERSE( reverse_norm, norms[i] );
02064                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02065                                         }
02066                                         else if(  eu->vu_p->v_p == (*outer_loop)[j] )
02067                                         {
02068                                                 nmg_vertexuse_nv( eu->vu_p, norms[j] );
02069                                                 VREVERSE( reverse_norm, norms[j] );
02070                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02071                                         }
02072                                         else
02073                                         {
02074                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02075                                                 bu_log( "\ti=%d, arc_segs=%d, fu = x%x\n" , i, arc_segs, fu );
02076                                         }
02077                                 }
02078                         }
02079 
02080                         verts[1] = verts[2];
02081                         verts[2] = &new_outer_loop[j];
02082 
02083                         if( (fu_prev = nmg_cmface( s, verts, 3 ) ) == NULL )
02084                         {
02085                                 bu_log( "tesselate_pipe_linear: failed to make outer face #%d or=%g, end_or=%g\n",
02086                                                 i, or, end_or );
02087                                 continue;
02088                         }
02089                         if( i == arc_segs-1 )
02090                         {
02091                                 if( nmg_calc_face_g( fu_prev ) )
02092                                 {
02093                                         bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
02094                                         nmg_kfu( fu_prev );
02095                                 }
02096                         }
02097                 }
02098                 bu_free( (char *)(*outer_loop), "tesselate_pipe_bend: outer_loop" );
02099                 *outer_loop = new_outer_loop;
02100         }
02101         else if( or > tol->dist && end_or <= tol->dist )
02102         {
02103                 struct vertex *v=(struct vertex *)NULL;
02104 
02105                 VSUB2( norms[0], (*outer_loop)[0]->vg_p->coord, start_pt );
02106                 VJOIN1( norms[0], norms[0], slope*or, n );
02107                 VUNITIZE( norms[0] );
02108                 for( i=0 ; i<arc_segs; i++ )
02109                 {
02110                         j = i+1;
02111                         if( j == arc_segs )
02112                                 j = 0;
02113 
02114                         verts[0] = &(*outer_loop)[j];
02115                         verts[1] = &(*outer_loop)[i];
02116                         verts[2] = &v;
02117 
02118                         if( (fu = nmg_cmface( s, verts, 3 ) ) == NULL )
02119                         {
02120                                 bu_log( "tesselate_pipe_linear: failed to make outer face #%d or=%g, end_or=%g\n",
02121                                                 i, or, end_or );
02122                                 continue;
02123                         }
02124                         if( i == 0 )
02125                                 nmg_vertex_gv( v, end_pt );
02126 
02127                         if( i < arc_segs-1 )
02128                         {
02129                                 VSUB2( norms[j], (*outer_loop)[j]->vg_p->coord, start_pt );
02130                                 VJOIN1( norms[j], norms[j], slope*or, n );
02131                                 VUNITIZE( norms[j] );
02132                         }
02133 
02134                         if( nmg_calc_face_g( fu ) )
02135                         {
02136                                 bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
02137                                 nmg_kfu( fu );
02138                         }
02139                         else
02140                         {
02141                                 struct loopuse *lu;
02142                                 struct edgeuse *eu;
02143                                 struct edgeuse *eu_opp_use;
02144                                 vect_t reverse_norm;
02145 
02146                                 NMG_CK_FACEUSE( fu );
02147                                 if( fu->orientation != OT_SAME )
02148                                         fu = fu->fumate_p;
02149 
02150                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
02151                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02152                                 {
02153                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02154                                         if( eu->vu_p->v_p == (*outer_loop)[i] )
02155                                         {
02156                                                 nmg_vertexuse_nv( eu->vu_p, norms[i] );
02157                                                 VREVERSE( reverse_norm, norms[i] );
02158                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02159                                         }
02160                                         else if( eu->vu_p->v_p == (*outer_loop)[j] )
02161                                         {
02162                                                 nmg_vertexuse_nv( eu->vu_p, norms[j] );
02163                                                 VREVERSE( reverse_norm, norms[j] );
02164                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02165                                         }
02166                                         else if( eu->vu_p->v_p == v )
02167                                         {
02168                                                 vect_t tmp_norm;
02169                                                 VBLEND2( tmp_norm, 0.5, norms[i], 0.5, norms[j] );
02170                                                 VUNITIZE( tmp_norm );
02171                                                 nmg_vertexuse_nv( eu->vu_p, tmp_norm );
02172                                                 VREVERSE( reverse_norm, tmp_norm );
02173                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02174                                         }
02175                                         else
02176                                         {
02177                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02178                                                 bu_log( "\ti=%d, j=%d, arc_segs=%d, fu = x%x\n" , i,j, arc_segs, fu );
02179                                         }
02180                                 }
02181                         }
02182                 }
02183 
02184                 bu_free( (char *)(*outer_loop), "tesselate_pipe_linear: outer_loop" );
02185                 outer_loop[0] = &v;
02186         }
02187         else if( or <= tol->dist && end_or > tol->dist )
02188         {
02189                 point_t pt,pt_next;
02190                 fastf_t x,y,xnew,ynew;
02191                 struct vertex **verts[3];
02192 
02193 
02194                 x = 1.0;
02195                 y = 0.0;
02196                 VCOMB2( norms[0], x, r1, y, r2 );
02197                 VJOIN1( pt_next, end_pt, end_or, norms[0] );
02198                 VJOIN1( norms[0], norms[0], slope, n );
02199                 VUNITIZE( norms[0] );
02200                 for( i=0 ; i<arc_segs; i++ )
02201                 {
02202                         j = i + 1;
02203                         if( j == arc_segs )
02204                                 j = 0;
02205 
02206                         VMOVE( pt, pt_next )
02207                         xnew = x*cos_del - y*sin_del;
02208                         ynew = x*sin_del + y*cos_del;
02209                         x = xnew;
02210                         y = ynew;
02211                         if( i < j )
02212                         {
02213                                 VCOMB2( norms[j], x, r1, y, r2 );
02214                                 VJOIN1( pt_next, end_pt, end_or, norms[j] );
02215                                 VJOIN1( norms[j], norms[j], slope, n );
02216                                 VUNITIZE( norms[j] );
02217                         }
02218 
02219                         verts[0] = &(*outer_loop)[0];
02220                         verts[1] = &new_outer_loop[i];
02221                         verts[2] = &new_outer_loop[j];
02222 
02223                         if( (fu = nmg_cmface( s, verts, 3 ) ) == NULL )
02224                         {
02225                                 bu_log( "tesselate_pipe_linear: failed to make outer face #%d or=%g, end_or=%g\n",
02226                                                 i, or, end_or );
02227                                 continue;
02228                         }
02229                         if( !(*outer_loop)[0]->vg_p )
02230                                 nmg_vertex_gv( (*outer_loop)[0], start_pt );
02231                         if( !new_outer_loop[i]->vg_p )
02232                                 nmg_vertex_gv( new_outer_loop[i], pt );
02233                         if( !new_outer_loop[j]->vg_p )
02234                                 nmg_vertex_gv( new_outer_loop[j], pt_next );
02235                         if( nmg_calc_face_g( fu ) )
02236                         {
02237                                 bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
02238                                 nmg_kfu( fu );
02239                         }
02240                         else
02241                         {
02242                                 struct loopuse *lu;
02243                                 struct edgeuse *eu;
02244                                 struct edgeuse *eu_opp_use;
02245                                 vect_t reverse_norm;
02246 
02247                                 NMG_CK_FACEUSE( fu );
02248                                 if( fu->orientation != OT_SAME )
02249                                         fu = fu->fumate_p;
02250 
02251                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
02252                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02253                                 {
02254                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02255                                         if( eu->vu_p->v_p == new_outer_loop[i] )
02256                                         {
02257                                                 nmg_vertexuse_nv( eu->vu_p, norms[i] );
02258                                                 VREVERSE( reverse_norm, norms[i] );
02259                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02260                                         }
02261                                         else if( eu->vu_p->v_p == new_outer_loop[j] )
02262                                         {
02263                                                 nmg_vertexuse_nv( eu->vu_p, norms[j] );
02264                                                 VREVERSE( reverse_norm, norms[j] );
02265                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02266                                         }
02267                                         else if( eu->vu_p->v_p == (*outer_loop)[0] )
02268                                         {
02269                                                 vect_t tmp_norm;
02270                                                 VBLEND2( tmp_norm, 0.5, norms[i], 0.5, norms[j] );
02271                                                 VUNITIZE( tmp_norm );
02272                                                 nmg_vertexuse_nv( eu->vu_p, tmp_norm );
02273                                                 VREVERSE( reverse_norm, tmp_norm );
02274                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02275                                         }
02276                                         else
02277                                         {
02278                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02279                                                 bu_log( "\ti=%d, j=%d, arc_segs=%d, fu = x%x\n" , i,j, arc_segs, fu );
02280                                         }
02281                                 }
02282                         }
02283                 }
02284                 bu_free( (char *)(*outer_loop), "tesselate_pipe_linear: outer_loop" );
02285                 *outer_loop = new_outer_loop;
02286         }
02287 
02288         slope = (ir - end_ir)/seg_len;
02289 
02290         if( ir > tol->dist && end_ir > tol->dist )
02291         {
02292                 point_t pt;
02293                 fastf_t x,y,xnew,ynew;
02294                 struct faceuse *fu_prev=(struct faceuse *)NULL;
02295                 struct vertex **verts[3];
02296 
02297                 x = 1.0;
02298                 y = 0.0;
02299                 VCOMB2( norms[0], -x, r1, -y, r2 );
02300                 VJOIN1( norms[0], norms[0], -slope, n );
02301                 VUNITIZE( norms[0] );
02302                 for( i=0 ; i<arc_segs ; i++ )
02303                 {
02304                         j = i+1;
02305                         if( j == arc_segs )
02306                                 j = 0;
02307 
02308                         VJOIN2( pt, end_pt, x*end_ir, r1, y*end_ir, r2 );
02309                         xnew = x*cos_del - y*sin_del;
02310                         ynew = x*sin_del + y*cos_del;
02311                         x = xnew;
02312                         y = ynew;
02313                         if( i < arc_segs-1 )
02314                         {
02315                                 VCOMB2( norms[j], -x, r1, -y, r2 );
02316                                 VJOIN1( norms[j], norms[j], -slope, n );
02317                                 VUNITIZE( norms[j] );
02318                         }
02319 
02320                         if( fu_prev )
02321                         {
02322                                 nmg_vertex_gv( new_inner_loop[i], pt );
02323                                 if( nmg_calc_face_g( fu_prev ) )
02324                                 {
02325                                         bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
02326                                         nmg_kfu( fu_prev );
02327                                 }
02328                                 else
02329                                 {
02330                                         
02331                                         struct loopuse *lu;
02332                                         struct edgeuse *eu;
02333 
02334                                         NMG_CK_FACEUSE( fu_prev );
02335 
02336                                         if( fu_prev->orientation != OT_SAME )
02337                                                 fu_prev = fu_prev->fumate_p;
02338 
02339                                         lu = BU_LIST_FIRST( loopuse, &fu_prev->lu_hd );
02340 
02341                                         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02342                                         {
02343                                                 vect_t reverse_norm;
02344                                                 struct edgeuse *eu_opp_use;
02345 
02346                                                 eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02347                                                 if( eu->vu_p->v_p == new_inner_loop[i-1] )
02348                                                 {
02349                                                         nmg_vertexuse_nv( eu->vu_p, norms[i-1] );
02350                                                         VREVERSE( reverse_norm, norms[i-1] );
02351                                                         nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02352                                                 }
02353                                                 else if(  eu->vu_p->v_p == (*inner_loop)[i-1] )
02354                                                 {
02355                                                         nmg_vertexuse_nv( eu->vu_p, norms[i-1] );
02356                                                         VREVERSE( reverse_norm, norms[i-1] );
02357                                                         nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02358                                                 }
02359                                                 else if(  eu->vu_p->v_p == new_inner_loop[i] )
02360                                                 {
02361                                                         nmg_vertexuse_nv( eu->vu_p, norms[i] );
02362                                                         VREVERSE( reverse_norm, norms[i] );
02363                                                         nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02364                                                 }
02365                                                 else if(  eu->vu_p->v_p == (*inner_loop)[i] )
02366                                                 {
02367                                                         nmg_vertexuse_nv( eu->vu_p, norms[i] );
02368                                                         VREVERSE( reverse_norm, norms[i] );
02369                                                         nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02370                                                 }
02371                                                 else
02372                                                 {
02373                                                         bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02374                                                         bu_log( "\ti=%d, arc_segs=%d, fu_prev = x%x\n" , i, arc_segs, fu_prev );
02375                                                 }
02376                                         }
02377                                 }
02378                         }
02379 
02380                         verts[0] = &(*inner_loop)[j];
02381                         verts[1] = &new_inner_loop[i];
02382                         verts[2] = &(*inner_loop)[i];
02383 
02384                         if( (fu = nmg_cmface( s, verts, 3 ) ) == NULL )
02385                         {
02386                                 bu_log( "tesselate_pipe_linear: failed to make inner face #%d ir=%g, end_ir=%g\n",
02387                                                 i, ir, end_ir );
02388                                 continue;
02389                         }
02390                         if( !new_inner_loop[i]->vg_p )
02391                                 nmg_vertex_gv( new_inner_loop[i], pt );
02392 
02393                         if( nmg_calc_face_g( fu ) )
02394                         {
02395                                 bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
02396                                 nmg_kfu( fu );
02397                         }
02398                         else
02399                         {
02400                                 
02401                                 struct loopuse *lu;
02402                                 struct edgeuse *eu;
02403 
02404                                 NMG_CK_FACEUSE( fu );
02405 
02406                                 if( fu->orientation != OT_SAME )
02407                                         fu = fu->fumate_p;
02408 
02409                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
02410 
02411                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02412                                 {
02413                                         vect_t reverse_norm;
02414                                         struct edgeuse *eu_opp_use;
02415 
02416                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02417                                         if( eu->vu_p->v_p == (*inner_loop)[0] )
02418                                         {
02419                                                 nmg_vertexuse_nv( eu->vu_p, norms[0] );
02420                                                 VREVERSE( reverse_norm, norms[0] );
02421                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02422                                         }
02423                                         else if(  eu->vu_p->v_p == new_inner_loop[i] )
02424                                         {
02425                                                 nmg_vertexuse_nv( eu->vu_p, norms[i] );
02426                                                 VREVERSE( reverse_norm, norms[i] );
02427                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02428                                         }
02429                                         else if(  eu->vu_p->v_p == (*inner_loop)[i] )
02430                                         {
02431                                                 nmg_vertexuse_nv( eu->vu_p, norms[i] );
02432                                                 VREVERSE( reverse_norm, norms[i] );
02433                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02434                                         }
02435                                         else if(  eu->vu_p->v_p == (*inner_loop)[j] )
02436                                         {
02437                                                 nmg_vertexuse_nv( eu->vu_p, norms[j] );
02438                                                 VREVERSE( reverse_norm, norms[j] );
02439                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02440                                         }
02441                                         else
02442                                         {
02443                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02444                                                 bu_log( "\ti=%d, arc_segs=%d, fu = x%x\n" , i, arc_segs, fu );
02445                                         }
02446                                 }
02447                         }
02448 
02449                         verts[2] = verts[0];
02450                         verts[0] = verts[1];
02451                         verts[1] = verts[2];
02452                         if( i == arc_segs-1 )
02453                                 verts[2] = &new_inner_loop[0];
02454                         else
02455                                 verts[2] = &new_inner_loop[j];
02456                         if( (fu_prev = nmg_cmface( s, verts, 3 ) ) == NULL )
02457                         {
02458                                 bu_log( "tesselate_pipe_linear: failed to make inner face #%d ir=%g, end_ir=%g\n",
02459                                                 i, ir, end_ir );
02460                                 continue;
02461                         }
02462                         if( i == arc_segs-1 )
02463                         {
02464                                 if( nmg_calc_face_g( fu_prev ) )
02465                                 {
02466                                         bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
02467                                         nmg_kfu( fu_prev );
02468                                 }
02469                         }
02470 
02471                 }
02472                 bu_free( (char *)(*inner_loop), "tesselate_pipe_bend: inner_loop" );
02473                 *inner_loop = new_inner_loop;
02474         }
02475         else if( ir > tol->dist && end_ir <= tol->dist )
02476         {
02477                 struct vertex *v=(struct vertex *)NULL;
02478 
02479                 VSUB2( norms[0], (*inner_loop)[0]->vg_p->coord, start_pt );
02480                 VJOIN1( norms[0], norms[0], -slope*ir, n );
02481                 VUNITIZE( norms[0] );
02482                 VREVERSE( norms[0], norms[0] );
02483                 for( i=0 ; i<arc_segs; i++ )
02484                 {
02485                         j = i+1;
02486                         if( j == arc_segs )
02487                                 j = 0;
02488 
02489                         verts[0] = &(*inner_loop)[i];
02490                         verts[1] = &(*inner_loop)[j];
02491                         verts[2] = &v;
02492 
02493                         if( (fu = nmg_cmface( s, verts, 3 ) ) == NULL )
02494                         {
02495                                 bu_log( "tesselate_pipe_linear: failed to make inner face #%d ir=%g, end_ir=%g\n",
02496                                                 i, ir, end_ir );
02497                                 continue;
02498                         }
02499                         if( i == 0 )
02500                                 nmg_vertex_gv( v, end_pt );
02501 
02502                         if( i < arc_segs-1 )
02503                         {
02504                                 VSUB2( norms[j], (*inner_loop)[j]->vg_p->coord, start_pt );
02505                                 VJOIN1( norms[j], norms[j], -slope*ir, n );
02506                                 VUNITIZE( norms[j] );
02507                                 VREVERSE( norms[j], norms[j] );
02508                         }
02509 
02510                         if( nmg_calc_face_g( fu ) )
02511                         {
02512                                 bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
02513                                 nmg_kfu( fu );
02514                         }
02515                         else
02516                         {
02517                                 struct loopuse *lu;
02518                                 struct edgeuse *eu;
02519                                 struct edgeuse *eu_opp_use;
02520                                 vect_t reverse_norm;
02521 
02522                                 NMG_CK_FACEUSE( fu );
02523                                 if( fu->orientation != OT_SAME )
02524                                         fu = fu->fumate_p;
02525 
02526                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
02527                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02528                                 {
02529                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02530                                         if( eu->vu_p->v_p == (*inner_loop)[i] )
02531                                         {
02532                                                 nmg_vertexuse_nv( eu->vu_p, norms[i] );
02533                                                 VREVERSE( reverse_norm, norms[i] );
02534                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02535                                         }
02536                                         else if( eu->vu_p->v_p == (*inner_loop)[j] )
02537                                         {
02538                                                 nmg_vertexuse_nv( eu->vu_p, norms[j] );
02539                                                 VREVERSE( reverse_norm, norms[j] );
02540                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02541                                         }
02542                                         else if( eu->vu_p->v_p == v )
02543                                         {
02544                                                 vect_t tmp_norm;
02545                                                 VBLEND2( tmp_norm, 0.5, norms[i], 0.5, norms[j] );
02546                                                 VUNITIZE( tmp_norm );
02547                                                 nmg_vertexuse_nv( eu->vu_p, tmp_norm );
02548                                                 VREVERSE( reverse_norm, tmp_norm );
02549                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02550                                         }
02551                                         else
02552                                         {
02553                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02554                                                 bu_log( "\ti=%d, j=%d, arc_segs=%d, fu = x%x\n" , i,j, arc_segs, fu );
02555                                         }
02556                                 }
02557                         }
02558                 }
02559 
02560                 bu_free( (char *)(*inner_loop), "tesselate_pipe_linear: inner_loop" );
02561                 inner_loop[0] = &v;
02562         }
02563         else if( ir <= tol->dist && end_ir > tol->dist )
02564         {
02565                 point_t pt,pt_next;
02566                 fastf_t x,y,xnew,ynew;
02567                 struct vertex **verts[3];
02568 
02569                 x = 1.0;
02570                 y = 0.0;
02571                 VCOMB2( norms[0], -x, r1, -y, r2 );
02572                 VJOIN1( pt_next, end_pt, -end_ir, norms[0] );
02573                 VJOIN1( norms[0], norms[0], -slope, n );
02574                 VUNITIZE( norms[0] );
02575                 for( i=0 ; i<arc_segs; i++ )
02576                 {
02577                         j = i + 1;
02578                         if( j == arc_segs )
02579                                 j = 0;
02580 
02581                         VMOVE( pt, pt_next )
02582                         xnew = x*cos_del - y*sin_del;
02583                         ynew = x*sin_del + y*cos_del;
02584                         x = xnew;
02585                         y = ynew;
02586                         if( i < j )
02587                         {
02588                                 VCOMB2( norms[j], -x, r1, -y, r2 );
02589                                 VJOIN1( pt_next, end_pt, -end_ir, norms[j] );
02590                                 VJOIN1( norms[j], norms[j], -slope, n );
02591                                 VUNITIZE( norms[j] );
02592                         }
02593 
02594                         verts[0] = &new_inner_loop[j];
02595                         verts[1] = &new_inner_loop[i];
02596                         verts[2] = &(*inner_loop)[0];
02597 
02598                         if( (fu = nmg_cmface( s, verts, 3 ) ) == NULL )
02599                         {
02600                                 bu_log( "tesselate_pipe_linear: failed to make inner face #%d ir=%g, end_ir=%g\n",
02601                                                 i, ir, end_ir );
02602                                 continue;
02603                         }
02604                         if( !(*inner_loop)[0]->vg_p )
02605                                 nmg_vertex_gv( (*inner_loop)[0], start_pt );
02606                         if( !new_inner_loop[i]->vg_p )
02607                                 nmg_vertex_gv( new_inner_loop[i], pt );
02608                         if( !new_inner_loop[j]->vg_p )
02609                                 nmg_vertex_gv( new_inner_loop[j], pt_next );
02610                         if( nmg_calc_face_g( fu ) )
02611                         {
02612                                 bu_log( "tesselate_pipe_linear: nmg_calc_face_g failed\n" );
02613                                 nmg_kfu( fu );
02614                         }
02615                         else
02616                         {
02617                                 struct loopuse *lu;
02618                                 struct edgeuse *eu;
02619                                 struct edgeuse *eu_opp_use;
02620                                 vect_t reverse_norm;
02621 
02622                                 NMG_CK_FACEUSE( fu );
02623                                 if( fu->orientation != OT_SAME )
02624                                         fu = fu->fumate_p;
02625 
02626                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
02627                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02628                                 {
02629                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02630                                         if( eu->vu_p->v_p == new_inner_loop[i] )
02631                                         {
02632                                                 nmg_vertexuse_nv( eu->vu_p, norms[i] );
02633                                                 VREVERSE( reverse_norm, norms[i] );
02634                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02635                                         }
02636                                         else if( eu->vu_p->v_p == new_inner_loop[j] )
02637                                         {
02638                                                 nmg_vertexuse_nv( eu->vu_p, norms[j] );
02639                                                 VREVERSE( reverse_norm, norms[j] );
02640                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02641                                         }
02642                                         else if( eu->vu_p->v_p == (*inner_loop)[0] )
02643                                         {
02644                                                 vect_t tmp_norm;
02645                                                 VBLEND2( tmp_norm, 0.5, norms[i], 0.5, norms[j] );
02646                                                 VUNITIZE( tmp_norm );
02647                                                 nmg_vertexuse_nv( eu->vu_p, tmp_norm );
02648                                                 VREVERSE( reverse_norm, tmp_norm );
02649                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, reverse_norm );
02650                                         }
02651                                         else
02652                                         {
02653                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02654                                                 bu_log( "\ti=%d, j=%d, arc_segs=%d, fu = x%x\n" , i,j, arc_segs, fu );
02655                                         }
02656                                 }
02657                         }
02658                 }
02659                 bu_free( (char *)(*inner_loop), "tesselate_pipe_linear: inner_loop" );
02660                 *inner_loop = new_inner_loop;
02661         }
02662         bu_free( (char *)norms, "tesselate_linear_pipe: norms" );
02663 }
02664 
02665 HIDDEN void
02666 tesselate_pipe_bend(fastf_t *bend_start, fastf_t *bend_end, fastf_t *bend_center, fastf_t or, fastf_t ir, int arc_segs, double sin_del, double cos_del, struct vertex ***outer_loop, struct vertex ***inner_loop, fastf_t *start_r1, fastf_t *start_r2, struct
02667 shell *s, const struct bn_tol *tol, const struct rt_tess_tol *ttol)
02668 {
02669         struct vertex **new_outer_loop;
02670         struct vertex **new_inner_loop;
02671         fastf_t bend_radius;
02672         fastf_t bend_angle;
02673         fastf_t x,y,xnew,ynew;
02674         fastf_t delta_angle;
02675         mat_t rot;
02676         vect_t b1;
02677         vect_t b2;
02678         vect_t r1, r2;
02679         vect_t r1_tmp,r2_tmp;
02680         vect_t bend_norm;
02681         vect_t to_start;
02682         vect_t to_end;
02683         vect_t norm;
02684         point_t origin;
02685         point_t center;
02686         point_t old_center;
02687         int bend_segs=1;        
02688         int bend_seg;
02689         int tol_segs;
02690         int i,j;
02691 
02692         NMG_CK_SHELL( s );
02693         BN_CK_TOL( tol );
02694         RT_CK_TESS_TOL( ttol );
02695 
02696         VMOVE( r1, start_r1 );
02697         VMOVE( r2, start_r2 );
02698 
02699         
02700 
02701 
02702         VSUB2( to_start, bend_start, bend_center );
02703         bend_radius = MAGNITUDE( to_start );
02704         VSCALE( b1, to_start, 1.0/bend_radius );
02705 
02706         
02707         VSUB2( to_end, bend_end, bend_center );
02708         VCROSS( bend_norm, b1, to_end );
02709         VUNITIZE( bend_norm );
02710 
02711         
02712         VCROSS( b2, bend_norm, b1 );
02713 
02714         bend_angle = atan2( VDOT( to_end, b2 ), VDOT( to_end, b1 ) );
02715         if( bend_angle < 0.0 )
02716                 bend_angle += 2.0*bn_pi;
02717 
02718         
02719         if( ttol->abs > 0.0 && ttol->abs < bend_radius+or )
02720         {
02721                 tol_segs = ceil( bend_angle/(2.0*acos( 1.0 - ttol->abs/(bend_radius+or) ) ) );
02722                 if( tol_segs > bend_segs )
02723                         bend_segs = tol_segs;
02724         }
02725         if( ttol->rel > 0.0 )
02726         {
02727                 tol_segs = ceil(bend_angle/(2.0*acos( 1.0 - ttol->rel ) ) );
02728                 if( tol_segs > bend_segs )
02729                         bend_segs = tol_segs;
02730         }
02731         if( ttol->norm > 0.0 )
02732         {
02733                 tol_segs = ceil( bend_angle/(2.0*ttol->norm ) );
02734                 if( tol_segs > bend_segs )
02735                         bend_segs = tol_segs;
02736         }
02737 
02738         delta_angle = bend_angle/(fastf_t)(bend_segs);
02739 
02740         VSETALL( origin, 0.0 );
02741         bn_mat_arb_rot( rot, origin, bend_norm, delta_angle);
02742 
02743         VMOVE( old_center, bend_start )
02744         for( bend_seg=0; bend_seg<bend_segs ; bend_seg++ )
02745         {
02746 
02747                 new_outer_loop = (struct vertex **)bu_calloc( arc_segs, sizeof( struct vertex *),
02748                                 "tesselate_pipe_bend(): new_outer_loop" );
02749 
02750                 MAT4X3VEC( r1_tmp, rot, r1 )
02751                 MAT4X3VEC( r2_tmp, rot, r2 )
02752                 VMOVE( r1, r1_tmp )
02753                 VMOVE( r2, r2_tmp )
02754 
02755                 VSUB2( r1_tmp, old_center, bend_center )
02756                 MAT4X3PNT( r2_tmp, rot, r1_tmp )
02757                 VADD2( center, r2_tmp, bend_center )
02758 
02759                 x = or;
02760                 y = 0.0;
02761                 for( i=0; i<arc_segs; i++ )
02762                 {
02763                         struct faceuse *fu;
02764                         struct vertex **verts[3];
02765                         point_t pt;
02766 
02767                         j = i+1;
02768                         if( j == arc_segs )
02769                                 j = 0;
02770 
02771                         verts[0] = &(*outer_loop)[j];
02772                         verts[1] = &(*outer_loop)[i];
02773                         verts[2] = &new_outer_loop[i];
02774 
02775                         if( (fu=nmg_cmface( s, verts, 3 )) == NULL )
02776                         {
02777                                 bu_log( "tesselate_pipe_bend(): nmg_cmface failed\n" );
02778                                 rt_bomb( "tesselate_pipe_bend\n" );
02779                         }
02780                         VJOIN2( pt, center, x, r1, y, r2 );
02781                         if( !new_outer_loop[i]->vg_p )
02782                                 nmg_vertex_gv( new_outer_loop[i], pt );
02783                         if( nmg_calc_face_g( fu ) )
02784                         {
02785                                 bu_log( "tesselate_pipe_bend: nmg_calc_face_g failed\n" );
02786                                 nmg_kfu( fu );
02787                         }
02788                         else
02789                         {
02790                                 struct loopuse *lu;
02791                                 struct edgeuse *eu;
02792 
02793                                 NMG_CK_FACEUSE( fu );
02794                                 if( fu->orientation != OT_SAME )
02795                                         fu = fu->fumate_p;
02796 
02797                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
02798                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02799                                 {
02800                                         struct edgeuse *eu_opp_use;
02801 
02802                                         NMG_CK_EDGEUSE( eu );
02803                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02804 
02805                                         if( eu->vu_p->v_p == (*outer_loop)[j] )
02806                                         {
02807                                                 VSUB2( norm, (*outer_loop)[j]->vg_p->coord, old_center );
02808                                                 VUNITIZE( norm );
02809                                                 nmg_vertexuse_nv( eu->vu_p, norm );
02810                                                 VREVERSE( norm, norm );
02811                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
02812                                         }
02813                                         else if( eu->vu_p->v_p == (*outer_loop)[i] )
02814                                         {
02815                                                 VSUB2( norm, (*outer_loop)[i]->vg_p->coord, old_center );
02816                                                 VUNITIZE( norm );
02817                                                 nmg_vertexuse_nv( eu->vu_p, norm );
02818                                                 VREVERSE( norm, norm );
02819                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
02820                                         }
02821                                         else if( eu->vu_p->v_p == new_outer_loop[i] )
02822                                         {
02823                                                 VSUB2( norm, new_outer_loop[i]->vg_p->coord, center );
02824                                                 VUNITIZE( norm );
02825                                                 nmg_vertexuse_nv( eu->vu_p, norm );
02826                                                 VREVERSE( norm, norm );
02827                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
02828                                         }
02829                                         else
02830                                         {
02831                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02832                                                 bu_log( "\ti=%d, j=%d, arc_segs=%d, fu = x%x\n" , i,j, arc_segs, fu );
02833                                         }
02834                                 }
02835                         }
02836 
02837                         xnew = x*cos_del - y*sin_del;
02838                         ynew = x*sin_del + y*cos_del;
02839                         x = xnew;
02840                         y = ynew;
02841 
02842                         verts[1] = verts[2];
02843                         verts[2] = &new_outer_loop[j];
02844 
02845                         if( (fu=nmg_cmface( s, verts, 3 )) == NULL )
02846                         {
02847                                 bu_log( "tesselate_pipe_bend(): nmg_cmface failed\n" );
02848                                 rt_bomb( "tesselate_pipe_bend\n" );
02849                         }
02850                         VJOIN2( pt, center, x, r1, y, r2 );
02851                         if( !(*verts[2])->vg_p )
02852                                 nmg_vertex_gv( *verts[2], pt );
02853                         if( nmg_calc_face_g( fu ) )
02854                         {
02855                                 bu_log( "tesselate_pipe_bend: nmg_calc_face_g failed\n" );
02856                                 nmg_kfu( fu );
02857                         }
02858                         else
02859                         {
02860                                 struct loopuse *lu;
02861                                 struct edgeuse *eu;
02862 
02863                                 NMG_CK_FACEUSE( fu );
02864                                 if( fu->orientation != OT_SAME )
02865                                         fu = fu->fumate_p;
02866 
02867                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
02868                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02869                                 {
02870                                         struct edgeuse *eu_opp_use;
02871 
02872                                         NMG_CK_EDGEUSE( eu );
02873                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02874 
02875                                         if( eu->vu_p->v_p == (*outer_loop)[j] )
02876                                         {
02877                                                 VSUB2( norm, (*outer_loop)[j]->vg_p->coord, old_center );
02878                                                 VUNITIZE( norm );
02879                                                 nmg_vertexuse_nv( eu->vu_p, norm );
02880                                                 VREVERSE( norm, norm );
02881                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
02882                                         }
02883                                         else if( eu->vu_p->v_p == new_outer_loop[i] )
02884                                         {
02885                                                 VSUB2( norm, new_outer_loop[i]->vg_p->coord, center );
02886                                                 VUNITIZE( norm );
02887                                                 nmg_vertexuse_nv( eu->vu_p, norm );
02888                                                 VREVERSE( norm, norm );
02889                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
02890                                         }
02891                                         else if( eu->vu_p->v_p == new_outer_loop[j] )
02892                                         {
02893                                                 VSUB2( norm, new_outer_loop[j]->vg_p->coord, center );
02894                                                 VUNITIZE( norm );
02895                                                 nmg_vertexuse_nv( eu->vu_p, norm );
02896                                                 VREVERSE( norm, norm );
02897                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
02898                                         }
02899                                         else
02900                                         {
02901                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
02902                                                 bu_log( "\ti=%d, j=%d, arc_segs=%d, fu = x%x\n" , i,j, arc_segs, fu );
02903                                         }
02904                                 }
02905                         }
02906                 }
02907 
02908                 bu_free( (char *)(*outer_loop), "tesselate_pipe_bend: outer_loop" );
02909                 *outer_loop = new_outer_loop;
02910                 VMOVE( old_center, center );
02911         }
02912 
02913         if( ir <= tol->dist )
02914         {
02915                 VMOVE( start_r1, r1 )
02916                 VMOVE( start_r2, r2 )
02917                 return;
02918         }
02919 
02920         VMOVE( r1, start_r1 )
02921         VMOVE( r2, start_r2 )
02922 
02923         VMOVE( old_center, bend_start )
02924         for( bend_seg=0; bend_seg<bend_segs ; bend_seg++ )
02925         {
02926 
02927                 new_inner_loop = (struct vertex **)bu_calloc( arc_segs, sizeof( struct vertex *),
02928                                 "tesselate_pipe_bend(): new_inner_loop" );
02929 
02930                 MAT4X3VEC( r1_tmp, rot, r1 )
02931                 MAT4X3VEC( r2_tmp, rot, r2 )
02932                 VMOVE( r1, r1_tmp )
02933                 VMOVE( r2, r2_tmp )
02934 
02935                 VSUB2( r1_tmp, old_center, bend_center )
02936                 MAT4X3PNT( r2_tmp, rot, r1_tmp )
02937                 VADD2( center, r2_tmp, bend_center )
02938 
02939                 x = ir;
02940                 y = 0.0;
02941                 for( i=0; i<arc_segs; i++ )
02942                 {
02943                         struct faceuse *fu;
02944                         struct vertex **verts[3];
02945                         point_t pt;
02946 
02947                         j = i + 1;
02948                         if( j == arc_segs )
02949                                 j = 0;
02950 
02951                         verts[0] = &(*inner_loop)[i];
02952                         verts[1] = &(*inner_loop)[j];
02953                         verts[2] = &new_inner_loop[i];
02954 
02955                         if( (fu=nmg_cmface( s, verts, 3 )) == NULL )
02956                         {
02957                                 bu_log( "tesselate_pipe_bend(): nmg_cmface failed\n" );
02958                                 rt_bomb( "tesselate_pipe_bend\n" );
02959                         }
02960                         VJOIN2( pt, center, x, r1, y, r2 );
02961                         if( !new_inner_loop[i]->vg_p )
02962                                 nmg_vertex_gv( new_inner_loop[i], pt );
02963                         if( nmg_calc_face_g( fu ) )
02964                         {
02965                                 bu_log( "tesselate_pipe_bend: nmg_calc_face_g failed\n" );
02966                                 nmg_kfu( fu );
02967                         }
02968                         else
02969                         {
02970                                 struct loopuse *lu;
02971                                 struct edgeuse *eu;
02972 
02973                                 NMG_CK_FACEUSE( fu );
02974                                 if( fu->orientation != OT_SAME )
02975                                         fu = fu->fumate_p;
02976 
02977                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
02978                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
02979                                 {
02980                                         struct edgeuse *eu_opp_use;
02981 
02982                                         NMG_CK_EDGEUSE( eu );
02983                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
02984 
02985                                         if( eu->vu_p->v_p == (*inner_loop)[j] )
02986                                         {
02987                                                 VSUB2( norm, old_center, (*inner_loop)[j]->vg_p->coord );
02988                                                 VUNITIZE( norm );
02989                                                 nmg_vertexuse_nv( eu->vu_p, norm );
02990                                                 VREVERSE( norm, norm );
02991                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
02992                                         }
02993                                         else if( eu->vu_p->v_p == (*inner_loop)[i] )
02994                                         {
02995                                                 VSUB2( norm, old_center, (*inner_loop)[i]->vg_p->coord );
02996                                                 VUNITIZE( norm );
02997                                                 nmg_vertexuse_nv( eu->vu_p, norm );
02998                                                 VREVERSE( norm, norm );
02999                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
03000                                         }
03001                                         else if( eu->vu_p->v_p == new_inner_loop[i] )
03002                                         {
03003                                                 VSUB2( norm, center, new_inner_loop[i]->vg_p->coord );
03004                                                 VUNITIZE( norm );
03005                                                 nmg_vertexuse_nv( eu->vu_p, norm );
03006                                                 VREVERSE( norm, norm );
03007                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
03008                                         }
03009                                         else
03010                                         {
03011                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
03012                                                 bu_log( "\ti=%d, j=%d, arc_segs=%d, fu = x%x\n" , i,j, arc_segs, fu );
03013                                         }
03014                                 }
03015                         }
03016 
03017                         xnew = x*cos_del - y*sin_del;
03018                         ynew = x*sin_del + y*cos_del;
03019                         x = xnew;
03020                         y = ynew;
03021 
03022                         verts[0] = verts[2];
03023                         verts[2] = &new_inner_loop[j];
03024 
03025                         if( (fu=nmg_cmface( s, verts, 3 )) == NULL )
03026                         {
03027                                 bu_log( "tesselate_pipe_bend(): nmg_cmface failed\n" );
03028                                 rt_bomb( "tesselate_pipe_bend\n" );
03029                         }
03030                         VJOIN2( pt, center, x, r1, y, r2 );
03031                         if( !(*verts[2])->vg_p )
03032                                 nmg_vertex_gv( *verts[2], pt );
03033                         if( nmg_calc_face_g( fu ) )
03034                         {
03035                                 bu_log( "tesselate_pipe_bend: nmg_calc_face_g failed\n" );
03036                                 nmg_kfu( fu );
03037                         }
03038                         else
03039                         {
03040                                 struct loopuse *lu;
03041                                 struct edgeuse *eu;
03042 
03043                                 NMG_CK_FACEUSE( fu );
03044                                 if( fu->orientation != OT_SAME )
03045                                         fu = fu->fumate_p;
03046 
03047                                 lu = BU_LIST_FIRST( loopuse, &fu->lu_hd );
03048                                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
03049                                 {
03050                                         struct edgeuse *eu_opp_use;
03051 
03052                                         NMG_CK_EDGEUSE( eu );
03053                                         eu_opp_use = BU_LIST_PNEXT_CIRC( edgeuse, &eu->eumate_p->l );
03054 
03055                                         if( eu->vu_p->v_p == (*inner_loop)[j] )
03056                                         {
03057                                                 VSUB2( norm, old_center, (*inner_loop)[j]->vg_p->coord );
03058                                                 VUNITIZE( norm );
03059                                                 nmg_vertexuse_nv( eu->vu_p, norm );
03060                                                 VREVERSE( norm, norm );
03061                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
03062                                         }
03063                                         else if( eu->vu_p->v_p == new_inner_loop[i] )
03064                                         {
03065                                                 VSUB2( norm, center, new_inner_loop[i]->vg_p->coord );
03066                                                 VUNITIZE( norm );
03067                                                 nmg_vertexuse_nv( eu->vu_p, norm );
03068                                                 VREVERSE( norm, norm );
03069                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
03070                                         }
03071                                         else if( eu->vu_p->v_p == new_inner_loop[j] )
03072                                         {
03073                                                 VSUB2( norm, center, new_inner_loop[j]->vg_p->coord );
03074                                                 VUNITIZE( norm );
03075                                                 nmg_vertexuse_nv( eu->vu_p, norm );
03076                                                 VREVERSE( norm, norm );
03077                                                 nmg_vertexuse_nv( eu_opp_use->vu_p, norm );
03078                                         }
03079                                         else
03080                                         {
03081                                                 bu_log( "No vu_normal assigned at (%g %g %g)\n", V3ARGS( eu->vu_p->v_p->vg_p->coord ) );
03082                                                 bu_log( "\ti=%d, j=%d, arc_segs=%d, fu = x%x\n" , i,j, arc_segs, fu );
03083                                         }
03084                                 }
03085                         }
03086                 }
03087                 bu_free( (char *)(*inner_loop), "tesselate_pipe_bend: inner_loop" );
03088                 *inner_loop = new_inner_loop;
03089                 VMOVE( old_center, center );
03090         }
03091         VMOVE( start_r1, r1 )
03092         VMOVE( start_r2, r2 )
03093 }
03094 
03095 HIDDEN void
03096 tesselate_pipe_end(struct wdb_pipept *pipe, int arc_segs, double sin_del, double cos_del, struct vertex ***outer_loop, struct vertex ***inner_loop, struct shell *s, const struct bn_tol *tol)
03097 {
03098         struct wdb_pipept *prev;
03099         struct faceuse *fu;
03100         struct loopuse *lu;
03101 
03102         NMG_CK_SHELL( s );
03103         BN_CK_TOL( tol );
03104 
03105         if( pipe->pp_od <= tol->dist )
03106                 return;
03107 
03108         if( NEAR_ZERO( pipe->pp_od - pipe->pp_id, tol->dist) )
03109                 return;
03110 
03111         if( (fu = nmg_cface( s, *outer_loop, arc_segs )) == NULL )
03112         {
03113                 bu_log( "tesselate_pipe_end(): nmg_cface failed\n" );
03114                 return;
03115         }
03116         fu = fu->fumate_p;
03117         if( nmg_calc_face_g( fu ) )
03118         {
03119                 bu_log( "tesselate_pipe_end: nmg_calc_face_g failed\n" );
03120                 nmg_kfu( fu );
03121                 return;
03122         }
03123 
03124         prev = BU_LIST_PREV( wdb_pipept, &pipe->l );
03125 
03126         if( pipe->pp_id > tol->dist )
03127         {
03128                 struct vertex **verts;
03129                 int i;
03130 
03131                 verts = (struct vertex **)bu_calloc( arc_segs, sizeof( struct vertex *),
03132                         "tesselate_pipe_end: verts" );
03133                 for( i=0 ; i<arc_segs; i++ )
03134                         verts[i] = (*inner_loop)[i];
03135 
03136                 fu = nmg_add_loop_to_face( s, fu, verts, arc_segs, OT_OPPOSITE );
03137 
03138                 bu_free( (char *)verts, "tesselate_pipe_end: verts" );
03139         }
03140 
03141         else if( prev->pp_id > tol->dist )
03142         {
03143                 struct vertexuse *vu;
03144 
03145                 
03146                 lu = nmg_mlv( &fu->l.magic, (struct vertex *)NULL, OT_OPPOSITE );
03147                 vu = BU_LIST_FIRST( vertexuse, &lu->down_hd );
03148 
03149                 nmg_vertex_gv( vu->v_p, pipe->pp_coord );
03150         }
03151 
03152         for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )
03153         {
03154                 struct edgeuse *eu;
03155 
03156                 NMG_CK_LOOPUSE( lu );
03157 
03158                 if( BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC )
03159                         continue;
03160 
03161                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
03162                 {
03163                         NMG_CK_EDGEUSE( eu );
03164                         eu->e_p->is_real = 1;
03165                 }
03166         }
03167 }
03168 
03169 
03170 
03171 
03172 
03173 
03174 int
03175 rt_pipe_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
03176 {
03177         struct wdb_pipept       *pp1;
03178         struct wdb_pipept       *pp2;
03179         struct wdb_pipept       *pp3;
03180         point_t                 curr_pt;
03181         struct shell *s;
03182         struct rt_pipe_internal *pip;
03183         int arc_segs=6;                 
03184         int tol_segs;
03185         fastf_t max_diam=0.0;
03186         fastf_t pipe_size;
03187         fastf_t curr_od,curr_id;
03188         double delta_angle;
03189         double sin_del;
03190         double cos_del;
03191         point_t min_pt;
03192         point_t max_pt;
03193         vect_t min_to_max;
03194         vect_t r1, r2;
03195         struct vertex **outer_loop;
03196         struct vertex **inner_loop;
03197 
03198         RT_CK_DB_INTERNAL(ip);
03199         pip = (struct rt_pipe_internal *)ip->idb_ptr;
03200         RT_PIPE_CK_MAGIC( pip );
03201 
03202         BN_CK_TOL( tol );
03203         RT_CK_TESS_TOL( ttol );
03204         NMG_CK_MODEL( m );
03205 
03206         *r = (struct nmgregion *)NULL;
03207 
03208         if( BU_LIST_IS_EMPTY( &pip->pipe_segs_head ) )
03209                 return( 0 );    
03210 
03211         pp1 = BU_LIST_FIRST( wdb_pipept, &pip->pipe_segs_head );
03212 
03213         VMOVE( min_pt, pp1->pp_coord );
03214         VMOVE( max_pt, pp1->pp_coord );
03215 
03216         
03217         for( BU_LIST_FOR( pp1, wdb_pipept, &pip->pipe_segs_head ) )
03218         {
03219                 if( pp1->pp_od > 0.0 && pp1->pp_od > max_diam )
03220                         max_diam = pp1->pp_od;
03221 
03222                 VMINMAX( min_pt, max_pt, pp1->pp_coord );
03223         }
03224 
03225         if( max_diam <= tol->dist )
03226                 return( 0 );    
03227 
03228         
03229         VSUB2( min_to_max, max_pt, min_pt );
03230         pipe_size = MAGNITUDE( min_to_max );
03231 
03232         
03233         if( ttol->abs > 0.0 && ttol->abs * 2.0 < max_diam )
03234         {
03235                 tol_segs = ceil( bn_pi/acos( 1.0 - 2.0 * ttol->abs/max_diam) );
03236                 if( tol_segs > arc_segs )
03237                         arc_segs = tol_segs;
03238         }
03239         if( ttol->rel > 0.0 && 2.0 * ttol->rel * pipe_size < max_diam )
03240         {
03241                 tol_segs = ceil( bn_pi/acos( 1.0 - 2.0 * ttol->rel*pipe_size/max_diam) );
03242                 if( tol_segs > arc_segs )
03243                         arc_segs = tol_segs;
03244         }
03245         if( ttol->norm > 0.0 )
03246         {
03247                 tol_segs = ceil( bn_pi/ttol->norm );
03248                 if( tol_segs > arc_segs )
03249                         arc_segs = tol_segs;
03250         }
03251 
03252         *r = nmg_mrsv( m );
03253         s = BU_LIST_FIRST(shell, &(*r)->s_hd);
03254 
03255         outer_loop = (struct vertex **)bu_calloc( arc_segs, sizeof( struct vertex *),
03256                         "rt_pipe_tess: outer_loop" );
03257         inner_loop = (struct vertex **)bu_calloc( arc_segs, sizeof( struct vertex *),
03258                         "rt_pipe_tess: inner_loop" );
03259         delta_angle = 2.0 * bn_pi / (double)arc_segs;
03260         sin_del = sin( delta_angle );
03261         cos_del = cos( delta_angle );
03262 
03263         pp1 = BU_LIST_FIRST( wdb_pipept, &(pip->pipe_segs_head) );
03264         tesselate_pipe_start( pp1, arc_segs, sin_del, cos_del,
03265                 &outer_loop, &inner_loop, r1, r2, s, tol );
03266 
03267         pp2 = BU_LIST_NEXT( wdb_pipept, &pp1->l );
03268         if( BU_LIST_IS_HEAD( &pp2->l, &(pip->pipe_segs_head) ) )
03269                 return( 0 );
03270         pp3 = BU_LIST_NEXT( wdb_pipept, &pp2->l );
03271         if( BU_LIST_IS_HEAD( &pp3->l ,  &(pip->pipe_segs_head) ) )
03272                 pp3 = (struct wdb_pipept *)NULL;
03273 
03274         VMOVE( curr_pt, pp1->pp_coord );
03275         curr_od = pp1->pp_od;
03276         curr_id = pp1->pp_id;
03277         while( 1 )
03278         {
03279                 vect_t n1,n2;
03280                 vect_t norm;
03281                 vect_t v1;
03282                 fastf_t angle;
03283                 fastf_t dist_to_bend;
03284                 point_t bend_start, bend_end, bend_center;
03285 
03286                 VSUB2( n1, curr_pt, pp2->pp_coord );
03287                 if( VNEAR_ZERO( n1, SQRT_SMALL_FASTF ) )
03288                 {
03289                         
03290                         goto next_pt;
03291                 }
03292 
03293                 if( !pp3 )
03294                 {
03295                         
03296                         tesselate_pipe_linear(curr_pt, curr_od/2.0, curr_id/2.0,
03297                                 pp2->pp_coord, pp2->pp_od/2.0, pp2->pp_id/2.0,
03298                                 arc_segs, sin_del, cos_del, &outer_loop, &inner_loop, r1, r2, s, tol );
03299                         break;
03300                 }
03301 
03302                 VSUB2( n2, pp3->pp_coord, pp2->pp_coord );
03303                 VCROSS( norm, n1, n2 );
03304                 if( VNEAR_ZERO( norm, SQRT_SMALL_FASTF ) )
03305                 {
03306                         
03307                         tesselate_pipe_linear(curr_pt, curr_od/2.0, curr_id/2.0,
03308                                 pp2->pp_coord, pp2->pp_od/2.0, pp2->pp_id/2.0,
03309                                 arc_segs, sin_del, cos_del, &outer_loop, &inner_loop, r1, r2, s, tol );
03310 
03311                         VMOVE( curr_pt, pp2->pp_coord );
03312                         curr_id = pp2->pp_id;
03313                         curr_od = pp2->pp_od;
03314                         goto next_pt;
03315                 }
03316 
03317                 VUNITIZE( n1 );
03318                 VUNITIZE( n2 );
03319                 VUNITIZE( norm );
03320 
03321                 
03322                 angle = bn_pi - acos( VDOT( n1, n2 ) );
03323                 dist_to_bend = pp2->pp_bendradius * tan( angle/2.0 );
03324                 VJOIN1( bend_start, pp2->pp_coord, dist_to_bend, n1 );
03325                 tesselate_pipe_linear( curr_pt, curr_od/2.0, curr_id/2.0,
03326                                 bend_start, pp2->pp_od/2.0, pp2->pp_id/2.0,
03327                                 arc_segs, sin_del, cos_del, &outer_loop, &inner_loop, r1, r2, s, tol );
03328 
03329                 
03330                 VJOIN1( bend_end, pp2->pp_coord, dist_to_bend, n2 );
03331                 VCROSS( v1, n1, norm );
03332                 VJOIN1( bend_center, bend_start, -pp2->pp_bendradius, v1 );
03333                 tesselate_pipe_bend( bend_start, bend_end, bend_center, curr_od/2.0, curr_id/2.0,
03334                         arc_segs, sin_del, cos_del, &outer_loop, &inner_loop,
03335                         r1, r2, s, tol, ttol );
03336 
03337                 VMOVE( curr_pt, bend_end );
03338                 curr_id = pp2->pp_id;
03339                 curr_od = pp2->pp_od;
03340 next_pt:
03341                 pp1 = pp2;
03342                 pp2 = pp3;
03343                 pp3 = BU_LIST_NEXT( wdb_pipept, &pp3->l );
03344                 if( BU_LIST_IS_HEAD( &pp3->l ,  &(pip->pipe_segs_head) ) )
03345                         pp3 = (struct wdb_pipept *)NULL;
03346         }
03347 
03348         tesselate_pipe_end( pp2, arc_segs, sin_del, cos_del, &outer_loop, &inner_loop, s, tol );
03349 
03350         bu_free( (char *)outer_loop, "rt_pipe_tess: outer_loop" );
03351         bu_free( (char *)inner_loop, "rt_pipe_tess: inner_loop" );
03352 
03353         nmg_rebound( m, tol );
03354 
03355         return( 0 );
03356 }
03357 
03358 
03359 
03360 
03361 int
03362 rt_pipe_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
03363 {
03364         register struct exported_pipept *exp;
03365         register struct wdb_pipept      *ptp;
03366         struct wdb_pipept               tmp;
03367         struct rt_pipe_internal         *pipe;
03368         union record                    *rp;
03369 
03370         BU_CK_EXTERNAL( ep );
03371         rp = (union record *)ep->ext_buf;
03372         
03373         if( rp->u_id != DBID_PIPE )  {
03374                 bu_log("rt_pipe_import: defective record\n");
03375                 return(-1);
03376         }
03377 
03378         RT_CK_DB_INTERNAL( ip );
03379         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
03380         ip->idb_type = ID_PIPE;
03381         ip->idb_meth = &rt_functab[ID_PIPE];
03382         ip->idb_ptr = bu_malloc( sizeof(struct rt_pipe_internal), "rt_pipe_internal");
03383         pipe = (struct rt_pipe_internal *)ip->idb_ptr;
03384         pipe->pipe_magic = RT_PIPE_INTERNAL_MAGIC;
03385         pipe->pipe_count = bu_glong( rp->pwr.pwr_pt_count);
03386 
03387         
03388 
03389 
03390 
03391 
03392         BU_LIST_INIT( &pipe->pipe_segs_head );
03393         for( exp = &rp->pwr.pwr_data[pipe->pipe_count-1]; exp >= &rp->pwr.pwr_data[0]; exp-- )  {
03394                 ntohd( (unsigned char *)&tmp.pp_id, exp->epp_id, 1 );
03395                 ntohd( (unsigned char *)&tmp.pp_od, exp->epp_od, 1 );
03396                 ntohd( (unsigned char *)&tmp.pp_bendradius, exp->epp_bendradius, 1 );
03397                 ntohd( (unsigned char *)tmp.pp_coord, exp->epp_coord, 3 );
03398 
03399                 
03400                 BU_GETSTRUCT( ptp, wdb_pipept );
03401                 ptp->l.magic = WDB_PIPESEG_MAGIC;
03402                 MAT4X3PNT( ptp->pp_coord, mat, tmp.pp_coord );
03403                 ptp->pp_id = tmp.pp_id / mat[15];
03404                 ptp->pp_od = tmp.pp_od / mat[15];
03405                 ptp->pp_bendradius = tmp.pp_bendradius / mat[15];
03406                 BU_LIST_APPEND( &pipe->pipe_segs_head, &ptp->l );
03407         }
03408 
03409         return(0);                      
03410 }
03411 
03412 
03413 
03414 
03415 int
03416 rt_pipe_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
03417 {
03418         struct rt_pipe_internal *pip;
03419         struct bu_list          *headp;
03420         register struct exported_pipept *epp;
03421         register struct wdb_pipept      *ppt;
03422         struct wdb_pipept               tmp;
03423         int             count;
03424         int             ngran;
03425         int             nbytes;
03426         union record    *rec;
03427 
03428         RT_CK_DB_INTERNAL(ip);
03429         if( ip->idb_type != ID_PIPE )  return(-1);
03430         pip = (struct rt_pipe_internal *)ip->idb_ptr;
03431         RT_PIPE_CK_MAGIC(pip);
03432 
03433         if (pip->pipe_segs_head.magic == 0) {
03434             return -1; 
03435         }
03436         headp = &pip->pipe_segs_head;
03437 
03438         
03439         count = 0;
03440         for( BU_LIST_FOR( ppt, wdb_pipept, headp ) )
03441                 count++;
03442 
03443         if( count < 1 )
03444                 return(-4);                     
03445 
03446         
03447         nbytes = sizeof(struct pipewire_rec) +
03448                 (count-1) * sizeof(struct exported_pipept);
03449         ngran = (nbytes + sizeof(union record) - 1) / sizeof(union record);
03450 
03451         BU_CK_EXTERNAL(ep);
03452         ep->ext_nbytes = ngran * sizeof(union record);
03453         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "pipe external");
03454         rec = (union record *)ep->ext_buf;
03455 
03456         rec->pwr.pwr_id = DBID_PIPE;
03457         (void)bu_plong( rec->pwr.pwr_count, ngran-1 );  
03458         (void)bu_plong( rec->pwr.pwr_pt_count, count );
03459 
03460         
03461         epp = &rec->pwr.pwr_data[0];
03462         for( BU_LIST_FOR( ppt, wdb_pipept, headp ), epp++ )  {
03463                 
03464                 VSCALE( tmp.pp_coord, ppt->pp_coord, local2mm );
03465                 tmp.pp_id = ppt->pp_id * local2mm;
03466                 tmp.pp_od = ppt->pp_od * local2mm;
03467                 tmp.pp_bendradius = ppt->pp_bendradius * local2mm;
03468                 htond( epp->epp_coord, (unsigned char *)tmp.pp_coord, 3 );
03469                 htond( epp->epp_id, (unsigned char *)&tmp.pp_id, 1 );
03470                 htond( epp->epp_od, (unsigned char *)&tmp.pp_od, 1 );
03471                 htond( epp->epp_bendradius, (unsigned char *)&tmp.pp_bendradius, 1 );
03472         }
03473 
03474         return(0);
03475 }
03476 
03477 
03478 
03479 
03480 int
03481 rt_pipe_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
03482 {
03483         register struct wdb_pipept      *ptp;
03484         struct rt_pipe_internal         *pipe;
03485         fastf_t                         *vec;
03486         int                             total_count;
03487         int                             double_count;
03488         int                             byte_count;
03489         unsigned long                   pipe_count;
03490         int                             i;
03491 
03492         BU_CK_EXTERNAL( ep );
03493 
03494         pipe_count = bu_glong((unsigned char *)ep->ext_buf);
03495         double_count = pipe_count * 6;
03496         byte_count = double_count * SIZEOF_NETWORK_DOUBLE;
03497         total_count = 4 + byte_count;
03498         BU_ASSERT_LONG( ep->ext_nbytes, ==, total_count);
03499 
03500         RT_CK_DB_INTERNAL( ip );
03501         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
03502         ip->idb_type = ID_PIPE;
03503         ip->idb_meth = &rt_functab[ID_PIPE];
03504         ip->idb_ptr = bu_malloc( sizeof(struct rt_pipe_internal), "rt_pipe_internal");
03505 
03506         pipe = (struct rt_pipe_internal *)ip->idb_ptr;
03507         pipe->pipe_magic = RT_PIPE_INTERNAL_MAGIC;
03508         pipe->pipe_count = pipe_count;
03509 
03510         vec = (fastf_t *)bu_malloc(byte_count, "rt_pipe_import5: vec");
03511         
03512         ntohd((unsigned char *)vec, (unsigned char *)ep->ext_buf + 4, double_count);
03513 
03514         
03515 
03516 
03517 
03518 
03519         BU_LIST_INIT( &pipe->pipe_segs_head );
03520         for (i = 0; i < double_count; i += 6) {
03521                 
03522                 BU_GETSTRUCT( ptp, wdb_pipept );
03523                 ptp->l.magic = WDB_PIPESEG_MAGIC;
03524                 MAT4X3PNT( ptp->pp_coord, mat, &vec[i] );
03525                 ptp->pp_id =            vec[i+3] / mat[15];
03526                 ptp->pp_od =            vec[i+4] / mat[15];
03527                 ptp->pp_bendradius =    vec[i+5] / mat[15];
03528                 BU_LIST_INSERT( &pipe->pipe_segs_head, &ptp->l );
03529         }
03530 
03531         bu_free((genptr_t)vec, "rt_pipe_import5: vec");
03532         return(0);                      
03533 }
03534 
03535 
03536 
03537 
03538 int
03539 rt_pipe_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
03540 {
03541         struct rt_pipe_internal *pip;
03542         struct bu_list          *headp;
03543         register struct wdb_pipept      *ppt;
03544         fastf_t                         *vec;
03545         int                             total_count;
03546         int                             double_count;
03547         int                             byte_count;
03548         unsigned long                   pipe_count;
03549         int                             i = 0;
03550 
03551         RT_CK_DB_INTERNAL(ip);
03552         if( ip->idb_type != ID_PIPE )  return(-1);
03553         pip = (struct rt_pipe_internal *)ip->idb_ptr;
03554         RT_PIPE_CK_MAGIC(pip);
03555 
03556         if (pip->pipe_segs_head.magic == 0) {
03557             return -1; 
03558         }
03559         headp = &pip->pipe_segs_head;
03560 
03561         
03562         pipe_count = 0;
03563         for( BU_LIST_FOR( ppt, wdb_pipept, headp ) )
03564                 pipe_count++;
03565 
03566         if( pipe_count <= 1 )
03567                 return(-4);                     
03568 
03569         double_count = pipe_count * 6;
03570         byte_count = double_count * SIZEOF_NETWORK_DOUBLE;
03571         total_count = 4 + byte_count;
03572         vec = (fastf_t *)bu_malloc(byte_count, "rt_pipe_export5: vec");
03573 
03574         BU_CK_EXTERNAL(ep);
03575         ep->ext_nbytes = total_count;
03576         ep->ext_buf = (genptr_t)bu_malloc(ep->ext_nbytes, "pipe external");
03577 
03578         (void)bu_plong((unsigned char *)ep->ext_buf, pipe_count);
03579 
03580         
03581         for( BU_LIST_FOR( ppt, wdb_pipept, headp ), i += 6  )  {
03582                 
03583                 VSCALE( &vec[i], ppt->pp_coord, local2mm );
03584                 vec[i+3] = ppt->pp_id * local2mm;
03585                 vec[i+4] = ppt->pp_od * local2mm;
03586                 vec[i+5] = ppt->pp_bendradius * local2mm;
03587         }
03588 
03589         
03590         htond((unsigned char *)ep->ext_buf + 4, (unsigned char *)vec, double_count);
03591 
03592         bu_free((genptr_t)vec, "rt_pipe_export5: vec");
03593         return(0);
03594 }
03595 
03596 
03597 
03598 
03599 
03600 
03601 
03602 
03603 int
03604 rt_pipe_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
03605 {
03606         register struct rt_pipe_internal        *pip;
03607         register struct wdb_pipept      *ptp;
03608         char    buf[256];
03609         int     segno = 0;
03610 
03611         RT_CK_DB_INTERNAL(ip);
03612         pip = (struct rt_pipe_internal *)ip->idb_ptr;
03613         RT_PIPE_CK_MAGIC(pip);
03614 
03615         sprintf(buf, "pipe with %d points\n", pip->pipe_count );
03616         bu_vls_strcat( str, buf );
03617 
03618         if( !verbose )  return(0);
03619 
03620 #if 1
03621         
03622         for( BU_LIST_FOR( ptp, wdb_pipept, &pip->pipe_segs_head ) )  {
03623                 sprintf(buf, "\t%d ", segno++ );
03624                 bu_vls_strcat( str, buf );
03625                 sprintf( buf, "\tbend radius = %g", INTCLAMP(ptp->pp_bendradius * mm2local) );
03626                 bu_vls_strcat( str, buf );
03627                 sprintf(buf, "  od=%g", INTCLAMP(ptp->pp_od * mm2local) );
03628                 bu_vls_strcat( str, buf );
03629                 if( ptp->pp_id > 0 )  {
03630                         sprintf(buf, ", id  = %g", INTCLAMP(ptp->pp_id * mm2local) );
03631                         bu_vls_strcat( str, buf );
03632                 }
03633                 bu_vls_strcat( str, "\n" );
03634 
03635                 sprintf(buf, "\t  at=(%g, %g, %g)\n",
03636                         INTCLAMP(ptp->pp_coord[X] * mm2local),
03637                         INTCLAMP(ptp->pp_coord[Y] * mm2local),
03638                         INTCLAMP(ptp->pp_coord[Z] * mm2local) );
03639                 bu_vls_strcat( str, buf );
03640 
03641         }
03642 #endif
03643         return(0);
03644 }
03645 
03646 
03647 
03648 
03649 
03650 
03651 void
03652 rt_pipe_ifree(struct rt_db_internal *ip)
03653 {
03654         register struct rt_pipe_internal        *pipe;
03655         register struct wdb_pipept      *ptp;
03656 
03657         RT_CK_DB_INTERNAL(ip);
03658         pipe = (struct rt_pipe_internal*)ip->idb_ptr;
03659         RT_PIPE_CK_MAGIC(pipe);
03660 
03661         if (pipe->pipe_segs_head.magic != 0) {
03662             while( BU_LIST_WHILE( ptp, wdb_pipept, &pipe->pipe_segs_head ) )  {
03663                 BU_LIST_DEQUEUE( &(ptp->l) );
03664                 bu_free( (char *)ptp, "wdb_pipept" );
03665             }
03666         }
03667         bu_free( ip->idb_ptr, "pipe ifree" );
03668         ip->idb_ptr = GENPTR_NULL;
03669 }
03670 
03671 
03672 
03673 
03674 
03675 
03676 
03677 
03678 
03679 
03680 int
03681 rt_pipe_ck( const struct bu_list *headp )
03682 {
03683         int error_count=0;
03684         struct wdb_pipept *cur,*prev,*next;
03685         fastf_t old_bend_dist=0.0;
03686         fastf_t new_bend_dist;
03687         fastf_t v2_len=0.0;
03688 
03689         prev = BU_LIST_FIRST( wdb_pipept, headp );
03690         if( prev->pp_bendradius < prev->pp_od * 0.5 )
03691         {
03692                 bu_log( "Bend radius (%gmm) is less than outer radius at ( %g %g %g )\n",
03693                         prev->pp_bendradius, V3ARGS( prev->pp_coord ) );
03694                 error_count++;
03695         }
03696         cur = BU_LIST_NEXT( wdb_pipept, &prev->l );
03697         next = BU_LIST_NEXT( wdb_pipept, &cur->l );
03698         while( BU_LIST_NOT_HEAD( &next->l, headp ) )
03699         {
03700                 vect_t v1, v2, norm;
03701                 fastf_t v1_len;
03702                 fastf_t angle;
03703 
03704                 if( cur->pp_bendradius < cur->pp_od * 0.5 )
03705                 {
03706                         bu_log( "Bend radius (%gmm) is less than outer radius at ( %g %g %g )\n",
03707                                 cur->pp_bendradius, V3ARGS( cur->pp_coord ) );
03708                         error_count++;
03709                 }
03710 
03711                 VSUB2( v1, prev->pp_coord, cur->pp_coord );
03712                 v1_len = MAGNITUDE( v1 );
03713                 if( v1_len > VDIVIDE_TOL )
03714                 {
03715                         fastf_t inv_len;
03716 
03717                         inv_len = 1.0/v1_len;
03718                         VSCALE( v1, v1, inv_len );
03719                 }
03720                 else
03721                         VSETALL( v1, 0.0 )
03722 
03723                 VSUB2( v2, next->pp_coord, cur->pp_coord );
03724                 v2_len = MAGNITUDE( v2 );
03725                 if( v2_len > VDIVIDE_TOL )
03726                 {
03727                         fastf_t inv_len;
03728 
03729                         inv_len = 1.0/v2_len;
03730                         VSCALE( v2, v2, inv_len );
03731                 }
03732                 else
03733                         VSETALL( v2, 0.0 )
03734 
03735                 VCROSS( norm, v1, v2 );
03736                 if( VNEAR_ZERO( norm, SQRT_SMALL_FASTF) )
03737                 {
03738                         new_bend_dist = 0.0;
03739                         goto next_pt;
03740                 }
03741 
03742                 angle = bn_pi - acos( VDOT( v1, v2 ) );
03743                 new_bend_dist = cur->pp_bendradius * tan( angle/2.0 );
03744 
03745                 if( new_bend_dist + old_bend_dist > v1_len )
03746                 {
03747                         error_count++;
03748                         bu_log( "Bend radii (%gmm) at ( %g %g %g ) and (%gmm) at ( %g %g %g ) are too large\n",
03749                                 prev->pp_bendradius, V3ARGS( prev->pp_coord),
03750                                 cur->pp_bendradius,V3ARGS( cur->pp_coord ) );
03751                         bu_log( "for pipe segment between ( %g %g %g ) and ( %g %g %g )\n",
03752                                 V3ARGS( prev->pp_coord ), V3ARGS( cur->pp_coord ) );
03753                 }
03754 next_pt:
03755                 old_bend_dist = new_bend_dist;
03756                 prev = cur;
03757                 cur = next;
03758                 next = BU_LIST_NEXT( wdb_pipept, &cur->l );
03759         }
03760 
03761         if( old_bend_dist > v2_len )
03762         {
03763                 error_count++;
03764                 bu_log( "last segment ( %g %g %g ) to ( %g %g %g ) is too short to allow\n",
03765                         V3ARGS( prev->pp_coord ), V3ARGS( cur->pp_coord ) );
03766                 bu_log( "bend radius of %gmm\n", prev->pp_bendradius );
03767         }
03768         return( error_count );
03769 }
03770 
03771 
03772 
03773 
03774 
03775 
03776 
03777 
03778 
03779 
03780 
03781 
03782 
03783 
03784 int
03785 rt_pipe_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr)
03786 {
03787         register struct rt_pipe_internal *pipe=(struct rt_pipe_internal *)intern->idb_ptr;
03788         struct wdb_pipept *ptp;
03789         Tcl_DString     ds;
03790         struct bu_vls   vls;
03791         int             status=TCL_OK;
03792         int             seg_no;
03793         int             num_segs=0;
03794 
03795         RT_PIPE_CK_MAGIC( pipe );
03796 
03797         Tcl_DStringInit( &ds );
03798         bu_vls_init( &vls );
03799 
03800         
03801         for( BU_LIST_FOR( ptp, wdb_pipept, &pipe->pipe_segs_head ) )
03802                 num_segs++;
03803 
03804         if( attr == (char *)NULL )
03805         {
03806                 bu_vls_strcat( &vls, "pipe");
03807 
03808                 seg_no = 0;
03809                 for( BU_LIST_FOR( ptp, wdb_pipept, &pipe->pipe_segs_head ) ) {
03810                         bu_vls_printf( &vls, " V%d { %.25G %.25G %.25G } O%d %.25G I%d %.25G R%d %.25G",
03811                                       seg_no, V3ARGS( ptp->pp_coord ),
03812                                       seg_no, ptp->pp_od,
03813                                       seg_no, ptp->pp_id,
03814                                       seg_no, ptp->pp_bendradius );
03815                         seg_no++;
03816                 }
03817         }
03818         else if( attr[0] == 'N' )
03819         {
03820                 bu_vls_printf( &vls, "%d", num_segs );
03821                 goto out;
03822         }
03823         else
03824         {
03825                 int curr_seg=0;
03826 
03827                 seg_no = atoi( &attr[1] );
03828                 if( seg_no < 0 || seg_no >= num_segs ) {
03829                         bu_vls_printf( &vls, "segment number out of range (0 - %d)", num_segs-1 );
03830                         status = TCL_ERROR;
03831                         goto out;
03832                 }
03833 
03834                 
03835                 for( BU_LIST_FOR( ptp, wdb_pipept, &pipe->pipe_segs_head ) ) {
03836                         if( curr_seg == seg_no )
03837                                 break;
03838                         curr_seg++;
03839                 }
03840 
03841                 switch( attr[0] ) {
03842                         case 'V':
03843                                 bu_vls_printf( &vls, "%.25G %.25G %.25G", V3ARGS( ptp->pp_coord ) );
03844                                 break;
03845                         case 'I':
03846                                 bu_vls_printf( &vls, "%.25G", ptp->pp_id );
03847                                 break;
03848                         case 'O':
03849                                 bu_vls_printf( &vls, "%.25G", ptp->pp_od );
03850                                 break;
03851                         case 'R':
03852                                 bu_vls_printf( &vls, "%.25G", ptp->pp_bendradius );
03853                                 break;
03854                         case 'P':
03855                                 bu_vls_printf( &vls, " V%d { %.25G %.25G %.25G } I%d %.25G O%d %.25G R%d %.25G",
03856                                               seg_no, V3ARGS( ptp->pp_coord ),
03857                                               seg_no, ptp->pp_id,
03858                                               seg_no, ptp->pp_od,
03859                                               seg_no, ptp->pp_bendradius );
03860                                 break;
03861                         default:
03862                                 bu_vls_printf( &vls, "unrecognized attribute (%c), choices are V, I, O, R, or P", attr[0] );
03863                                 status = TCL_ERROR;
03864                                 break;
03865                 }
03866         }
03867 out:
03868         Tcl_DStringAppend( &ds, bu_vls_addr( &vls ), -1 );
03869         Tcl_DStringResult( interp, &ds );
03870         Tcl_DStringFree( &ds );
03871         bu_vls_free( &vls );
03872 
03873         return( status );
03874 
03875 }
03876 
03877 int
03878 rt_pipe_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, char **argv, struct resource *resp)
03879 {
03880         struct rt_pipe_internal         *pipe;
03881         struct wdb_pipept               *ptp;
03882         Tcl_Obj                         *obj, *list;
03883         int                             seg_no;
03884         int                             num_segs;
03885         int                             curr_seg;
03886         fastf_t                         tmp;
03887         char                            *v_str;
03888 
03889 
03890         RT_CK_DB_INTERNAL( intern );
03891         pipe = (struct rt_pipe_internal *)intern->idb_ptr;
03892         RT_PIPE_CK_MAGIC( pipe );
03893 
03894         while( argc >= 2 ) {
03895 
03896                 
03897                 num_segs = 0;
03898                 if( pipe->pipe_segs_head.forw ) {
03899                         for( BU_LIST_FOR( ptp, wdb_pipept, &pipe->pipe_segs_head ) )
03900                                 num_segs++;
03901                 } else {
03902                         BU_LIST_INIT( &pipe->pipe_segs_head );
03903                 }
03904 
03905                 if( !isdigit( argv[0][1] ) ) {
03906                         Tcl_SetResult( interp, "no vertex number specified", TCL_STATIC );
03907                         return( TCL_ERROR );
03908                 }
03909 
03910                 seg_no = atoi( &argv[0][1] );
03911                 if( seg_no == num_segs ) {
03912                         struct wdb_pipept *new_pt;
03913 
03914                         new_pt = (struct wdb_pipept *)bu_calloc( 1, sizeof( struct wdb_pipept ), "New pipe segment" );
03915                         if( num_segs > 0 ) {
03916                                 ptp = BU_LIST_LAST( wdb_pipept, &pipe->pipe_segs_head );
03917                                 *new_pt = *ptp;         
03918                                 BU_LIST_INSERT( &pipe->pipe_segs_head, &new_pt->l );
03919                                 ptp = new_pt;
03920                         } else {
03921                                 VSETALL( new_pt->pp_coord, 0.0 );
03922                                 new_pt->pp_id = 0.0;
03923                                 new_pt->pp_od = 10.0;
03924                                 new_pt->pp_bendradius = 20.0;
03925                                 BU_LIST_INSERT( &pipe->pipe_segs_head, &new_pt->l );
03926                                 ptp = new_pt;
03927                         }
03928                         num_segs++;
03929                 }
03930                 if( seg_no < 0 || seg_no >= num_segs ) {
03931                         Tcl_SetResult( interp, "vertex number out of range", TCL_STATIC );
03932                         return( TCL_ERROR );
03933                 }
03934 
03935                 
03936                 curr_seg = 0;
03937                 for( BU_LIST_FOR( ptp, wdb_pipept, &pipe->pipe_segs_head ) ) {
03938                         if( curr_seg == seg_no )
03939                                 break;
03940                         curr_seg++;
03941                 }
03942 
03943 
03944                 switch( argv[0][0] ) {
03945                         case 'V':
03946                                 obj = Tcl_NewStringObj( argv[1], -1 );
03947                                 list = Tcl_NewListObj( 0, NULL );
03948                                 Tcl_ListObjAppendList( interp, list, obj );
03949                                 v_str = Tcl_GetStringFromObj( list, NULL );
03950                                 while( isspace( *v_str ) ) v_str++;
03951                                 if( *v_str == '\0' ) {
03952                                         Tcl_SetResult( interp, "incomplete vertex specification", TCL_STATIC );
03953                                         Tcl_DecrRefCount( list );
03954                                         return( TCL_ERROR );
03955                                 }
03956                                 ptp->pp_coord[0] = atof( v_str );
03957                                 v_str = bu_next_token( v_str );
03958                                 if( *v_str == '\0' ) {
03959                                         Tcl_SetResult( interp, "incomplete vertex specification", TCL_STATIC );
03960                                         Tcl_DecrRefCount( list );
03961                                         return( TCL_ERROR );
03962                                 }
03963                                 ptp->pp_coord[1] = atof( v_str );
03964                                 v_str = bu_next_token( v_str );
03965                                 if( *v_str == '\0' ) {
03966                                         Tcl_SetResult( interp, "incomplete vertex specification", TCL_STATIC );
03967                                         Tcl_DecrRefCount( list );
03968                                         return( TCL_ERROR );
03969                                 }
03970                                 ptp->pp_coord[2] = atof( v_str );
03971                                 Tcl_DecrRefCount( list );
03972                                 break;
03973                         case 'I':
03974                                 tmp = atof( argv[1] );
03975                                 if( tmp >= ptp->pp_od ) {
03976                                         Tcl_SetResult( interp, "inner diameter must be less than outer diameter", TCL_STATIC );
03977                                         return( TCL_ERROR );
03978                                 }
03979                                 ptp->pp_id = tmp;
03980                                 break;
03981                         case 'O':
03982                                 tmp = atof( argv[1] );
03983                                 if( tmp <= 0.0 ) {
03984                                         Tcl_SetResult( interp, "outer diameter cannot be 0.0 or less", TCL_STATIC );
03985                                         return( TCL_ERROR );
03986                                 }
03987                                 if( tmp <= ptp->pp_id ) {
03988                                         Tcl_SetResult( interp, "outer diameter must be greater than inner diameter", TCL_STATIC );
03989                                         return( TCL_ERROR );
03990                                 }
03991                                 ptp->pp_od = tmp;
03992                                 break;
03993                         case 'R':
03994                                 tmp = atof( argv[1] );
03995                                 if( tmp < ptp->pp_od * 0.5 ) {
03996                                         Tcl_SetResult( interp, "cannot set bend radius to less than outer radius", TCL_STATIC );
03997                                         return( TCL_ERROR );
03998                                 }
03999                                 ptp->pp_bendradius = tmp;
04000                                 break;
04001                         default:
04002                                 Tcl_SetResult( interp, "unrecognized attribute, choices are V, I, O, or R", TCL_STATIC );
04003                                 return( TCL_ERROR );
04004                 }
04005 
04006                 argc -= 2;
04007                 argv += 2;
04008         }
04009 
04010         return( TCL_OK );
04011 }
04012 
04013 
04014 
04015 
04016 
04017 
04018 
04019 
04020 
04021