g_pipe.c

Go to the documentation of this file.
00001 /*                        G _ P I P E . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1990-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup g_  */
00023 
00024 /*@{*/
00025 /** @file g_pipe.c
00026  *      Intersect a ray with a pipe solid.
00027  *
00028  *  Authors -
00029  *
00030  *  Source -
00031  *      SECAD/VLD Computing Consortium, Bldg 394
00032  *      The U. S. Army Ballistic Research Laboratory
00033  *      Aberdeen Proving Ground, Maryland  21005-5066
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    /* for isnan() function */
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;                 /* start point for pipe section */
00083         vect_t  pipe_H;                 /* unit vector in direction of pipe section */
00084         fastf_t pipe_ribase, pipe_ritop;        /* base and top inner radii */
00085         fastf_t pipe_ribase_sq, pipe_ritop_sq;  /* inner radii squared */
00086         fastf_t pipe_ridiff_sq, pipe_ridiff;    /* difference between top and base inner radii */
00087         fastf_t pipe_rodiff_sq, pipe_rodiff;    /* difference between top and base outer radii */
00088         fastf_t pipe_robase, pipe_rotop;        /* base and top outer radii */
00089         fastf_t pipe_robase_sq, pipe_rotop_sq;  /* outer radii squared */
00090         fastf_t pipe_len;                       /* length of pipe segment */
00091         mat_t   pipe_SoR;       /* Scale and rotate */
00092         mat_t   pipe_invRoS;    /* inverse rotation and scale */
00093 };
00094 
00095 struct bend_pipe
00096 {
00097         struct bu_list l;
00098         int     pipe_is_bend;
00099         fastf_t bend_radius;            /* distance from bend_v to center of pipe */
00100         fastf_t bend_or;                /* outer radius */
00101         fastf_t bend_ir;                /* inner radius */
00102         mat_t   bend_invR;              /* inverse rotation matrix */
00103         mat_t   bend_SoR;               /* Scale and rotate */
00104         point_t bend_V;                 /* Center of bend */
00105         point_t bend_start;             /* Start of bend */
00106         point_t bend_end;               /* End of bend */
00107         fastf_t bend_alpha_i;           /* ratio of inner radius to bend radius */
00108         fastf_t bend_alpha_o;           /* ratio of outer radius to bend radius */
00109         fastf_t bend_angle;             /* Angle that bend goes through */
00110         vect_t  bend_ra;                /* unit vector in plane of bend (points toward start from bend_V) */
00111         vect_t  bend_rb;                /* unit vector in plane of bend (normal to bend_ra) */
00112         vect_t  bend_N;                 /* unit vector normal to plane of bend */
00113         fastf_t bend_R_SQ;              /* bounding sphere radius squared */
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      /* number of segments used to plot a circle */
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         /* angle goes from 0.0 at start to some angle less than PI */
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; /* there is nothing to bend, that's OK */
00191         }
00192 
00193 
00194         MAT_COPY( pipe->bend_SoR, R );
00195         pipe->bend_SoR[15] *= pipe->bend_radius;
00196 
00197         /* bounding box for entire torus */
00198         /* X */
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         /* Y */
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         /* Z */
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         /* build R matrix */
00267         MAT_IDN( R );
00268         VMOVE( &R[0], v1 );
00269         VMOVE( &R[4], v2 );
00270         VMOVE( &R[8], seg_ht );
00271 
00272         /* Rinv is transpose */
00273         bn_mat_trn( Rinv, R );
00274 
00275         /* Build Scale matrix */
00276         MAT_IDN( S );
00277         S[10] = 1.0/pipe->pipe_len;
00278 
00279         /* Compute SoR and invRoS */
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  *                      R T _ P I P E _ P R E P
00307  *
00308  *  Given a pointer to a GED database record, and a transformation matrix,
00309  *  determine if this is a valid pipe solid, and if so, precompute various
00310  *  terms of the formula.
00311  *
00312  *  Returns -
00313  *      0       pipe solid is OK
00314  *      !0      Error in description
00315  *
00316  *  Implicit return -
00317  *      A struct bu_list is created, and it's address is stored in
00318  *      stp->st_specific for use by pipe_shot().
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                         /* duplicate point, skip to next point */
00365                         goto next_pt;
00366                 }
00367 
00368                 if( !pp3 )
00369                 {
00370                         /* last segment */
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                         /* points are colinear, treat as a linear segment */
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                 /* linear section */
00396                 rt_linear_pipe_prep( stp, head, curr_pt, curr_id, curr_od,
00397                                 bend_start, pp2->pp_id, pp2->pp_od );
00398 
00399                 /* and bend section */
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  *                      R T _ P I P E _ P R I N T
00437  */
00438 void
00439 rt_pipe_print(register const struct soltab *stp)
00440 {
00441 /*      register struct bu_list *pipe =
00442                 (struct bu_list *)stp->st_specific; */
00443 }
00444 
00445 /**
00446  *                      R T _ P I P E P T _ P R I N T
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  *                      R T _ V L S _ P I P E P T
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;         /* D' */
00509         LOCAL vect_t    pprime;         /* P' */
00510         LOCAL vect_t    work;           /* temporary vector */
00511         LOCAL bn_poly_t C;              /* The final equation */
00512         LOCAL bn_complex_t      val[4]; /* The complex roots */
00513         LOCAL int       j;
00514         LOCAL int       root_count=0;
00515         LOCAL bn_poly_t A, Asqr;
00516         LOCAL bn_poly_t X2_Y2;          /* X**2 + Y**2 */
00517         LOCAL vect_t    cor_pprime;     /* new ray origin */
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;          /* miss */
00524         }
00525 
00526         /* Convert vector into the space of the unit torus */
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         /* normalize distance from torus.  substitute
00534          * corrected pprime which contains a translation along ray
00535          * direction to closest approach to vertex of torus.
00536          * Translating ray origin along direction of ray to closest pt. to
00537          * origin of solid's coordinate system, new ray origin is
00538          * 'cor_pprime'.
00539          */
00540         cor_proj = VDOT( pprime, dprime );
00541         VSCALE( cor_pprime, dprime, cor_proj );
00542         VSUB2( cor_pprime, pprime, cor_pprime );
00543 
00544         /*
00545          *  Given a line and a ratio, alpha, finds the equation of the
00546          *  unit torus in terms of the variable 't'.
00547          *
00548          *  The equation for the torus is:
00549          *
00550          * [ X**2 + Y**2 + Z**2 + (1 - alpha**2) ]**2 - 4*( X**2 + Y**2 ) = 0
00551          *
00552          *  First, find X, Y, and Z in terms of 't' for this line, then
00553          *  substitute them into the equation above.
00554          *
00555          *      Wx = Dx*t + Px
00556          *
00557          *      Wx**2 = Dx**2 * t**2  +  2 * Dx * Px  +  Px**2
00558          *              [0]                [1]           [2]    dgr=2
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         /* A = X2_Y2 + Z2 */
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         /* Inline expansion of (void) rt_poly_mul( &A, &A, &Asqr ) */
00575         /* Both polys have degree two */
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         /* Inline expansion of bn_poly_scale( &X2_Y2, 4.0 ) and
00584          * rt_poly_sub( &Asqr, &X2_Y2, &C ).
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         /*  It is known that the equation is 4th order.  Therefore,
00594          *  if the root finder returns other than 4 roots, error.
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;     /* MISSED */
00611         }
00612 
00613         /*  Only real roots indicate an intersection in real space.
00614          *
00615          *  Look at each root returned; if the imaginary part is zero
00616          *  or sufficiently close, then use the real part as one value
00617          *  of 't' for the intersections
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                         /* check if this hit is within bend angle */
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;         /* no inner torus */
00654 
00655         /* Now do inner torus */
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         /* Inline expansion of (void) rt_poly_mul( &A, &A, &Asqr ) */
00660         /* Both polys have degree two */
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         /* Inline expansion of bn_poly_scale( &X2_Y2, 4.0 ) and
00669          * rt_poly_sub( &Asqr, &X2_Y2, &C ).
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         /*  It is known that the equation is 4th order.  Therefore,
00679          *  if the root finder returns other than 4 roots, error.
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;     /* MISSED */
00696         }
00697 
00698         /*  Only real roots indicate an intersection in real space.
00699          *
00700          *  Look at each root returned; if the imaginary part is zero
00701          *  or sufficiently close, then use the real part as one value
00702          *  of 't' for the intersections
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                         /* check if this hit is within bend angle */
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         /* transform ray start point */
00763         VSUB2( work_pt, rp->r_pt, pipe->pipe_V );
00764         MAT4X3VEC( ray_start, pipe->pipe_SoR, work_pt );
00765 
00766         /* rotate ray direction */
00767         MAT4X3VEC( ray_dir, pipe->pipe_SoR, rp->r_dir );
00768 
00769         /* Intersect with outer sides */
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                 /* Intersect with inner sides */
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                         /* move this hit to the end of the list */
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         /* delete duplicate hits */
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         /* handle cases where this pipe overlaps with itself */
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  *                      R T _ P I P E _ N O R M
01183  *
01184  *  Given ONE ray distance, return the normal and entry/exit point.
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  *                      R T _ P I P E _ S H O T
01268  *
01269  *  Intersect a ray with a pipe.
01270  *  If an intersection occurs, a struct seg will be acquired
01271  *  and filled in.
01272  *
01273  *  Returns -
01274  *      0       MISS
01275  *      >0      HIT
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         /* calculate hit points and normals */
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         /* Build segments */
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                 /* free the list of hits */
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         /* free the list of hits */
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 );            /* HIT */
01384         else
01385                 return(0);              /* MISS */
01386 }
01387 
01388 #define SEG_MISS(SEG)           (SEG).seg_stp=(struct soltab *) 0;
01389 
01390 /**
01391  *                      R T_ P I P E _ V S H O T
01392  *
01393  *  Vectorized version.
01394  */
01395 void
01396 rt_pipe_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
01397                                /* An array of solid pointers */
01398                                /* An array of ray pointers */
01399                                /* array of segs (results returned) */
01400                                /* Number of ray/object pairs */
01401 
01402 {
01403         rt_vstub( stp, rp, segp, n, ap );
01404 }
01405 
01406 /**
01407  *                      R T _ P I P E _ C U R V E
01408  *
01409  *  Return the curvature of the pipe.
01410  */
01411 void
01412 rt_pipe_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
01413 {
01414 /*      register struct bu_list *pipe =
01415                 (struct bu_list *)stp->st_specific; */
01416 
01417         cvp->crv_c1 = cvp->crv_c2 = 0;
01418 
01419         /* any tangent direction */
01420         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
01421 }
01422 
01423 /**
01424  *                      R T _ P I P E _ U V
01425  *
01426  *  For a hit on the surface of an pipe, return the (u,v) coordinates
01427  *  of the hit point, 0 <= u,v <= 1.
01428  *  u = azimuth
01429  *  v = elevation
01430  */
01431 void
01432 rt_pipe_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
01433 {
01434 /*      register struct bu_list *pipe =
01435                 (struct bu_list *)stp->st_specific; */
01436 }
01437 
01438 /**
01439  *              R T _ P I P E _ F R E E
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         /* free linked list */
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         /* free list head */
01458         bu_free( (char *)pipe, "pipe_specific head" );
01459 #endif
01460 }
01461 
01462 /**
01463  *                      R T _ P I P E _ C L A S S
01464  */
01465 int
01466 rt_pipe_class(void)
01467 {
01468         return(0);
01469 }
01470 
01471 /**                     D R A W _ P I P E _ A R C
01472  *
01473  * v1 and v2 must be unit vectors normal to each other in plane of circle
01474  * v1 must be in direction from center to start point (unless a full circle is
01475  * requested). "End" is the endpoint of arc. "Seg_count"
01476  * is how many straight line segements to use to draw the arc. "Full_circle"
01477  * is a flag to indicate that a complete circle is desired.
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  *                      R T _ P I P E _ P L O T
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 );    /* nothing to plot */
01672 
01673         VMOVE( current_point, prevp->pp_coord );
01674 
01675         /* draw end at pipe start */
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                         /* last segment */
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                         /* duplicate point, nothing to plot */
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                         /* points are colinear, draw linear segment */
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                         /* draw linear segment to start of bend */
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                         /* draw bend */
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                 /* create a loop of a single vertex using the first vertex from the inner loop */
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                 /* split edges in loop for each vertex in inner loop */
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                 /* make a loop of a single vertex in this face */
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                                         /* assign vertexuse normals */
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                                 /* assign vertexuse normals */
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                                         /* assign vertexuse normals */
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                                 /* assign vertexuse normals */
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;        /* minimum number of edges along bend */
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         /* Calculate vector b1, unit vector in direction from
02700          * bend center to start point
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         /* bend_norm is normal to plane of bend */
02707         VSUB2( to_end, bend_end, bend_center );
02708         VCROSS( bend_norm, b1, to_end );
02709         VUNITIZE( bend_norm );
02710 
02711         /* b1, b2, and bend_norm form a RH coord, system */
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         /* calculate number of segments to use along bend */
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                 /* make a loop of a single vertex in this face */
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  *                      R T _ P I P E _ T E S S
03171  *
03172  *      XXXX Still needs vertexuse normals!
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;                 /* minimum number of segments for a circle */
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 );    /* nothing to tesselate */
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         /* find max diameter */
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 );    /* nothing to tesselate */
03227 
03228         /* calculate pipe size for relative tolerance */
03229         VSUB2( min_to_max, max_pt, min_pt );
03230         pipe_size = MAGNITUDE( min_to_max );
03231 
03232         /* calculate number of segments for circles */
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                         /* duplicate point, skip to next point */
03290                         goto next_pt;
03291                 }
03292 
03293                 if( !pp3 )
03294                 {
03295                         /* last segment */
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                         /* points are colinear, treat as a linear segment */
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                 /* linear section */
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                 /* and bend section */
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  *                      R T _ P I P E _ I M P O R T
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         /* Check record type */
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          *  Walk the array of segments in reverse order,
03389          *  allocating a linked list of segments in internal format,
03390          *  using exactly the same structures as libwdb.
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                 /* Apply modeling transformations */
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);                      /* OK */
03410 }
03411 
03412 /**
03413  *                      R T _ P I P E _ E X P O R T
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; /* no segments provided, empty pipe is bogus */
03435         }
03436         headp = &pip->pipe_segs_head;
03437 
03438         /* Count number of points */
03439         count = 0;
03440         for( BU_LIST_FOR( ppt, wdb_pipept, headp ) )
03441                 count++;
03442 
03443         if( count < 1 )
03444                 return(-4);                     /* Not enough for 1 pipe! */
03445 
03446         /* Determine how many whole granules will be required */
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 );  /* # EXTRA grans */
03458         (void)bu_plong( rec->pwr.pwr_pt_count, count );
03459 
03460         /* Convert the pipe segments to external form */
03461         epp = &rec->pwr.pwr_data[0];
03462         for( BU_LIST_FOR( ppt, wdb_pipept, headp ), epp++ )  {
03463                 /* Convert from user units to mm */
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  *                      R T _ P I P E _ I M P O R T 5
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         /* Convert from database (network) to internal (host) format */
03512         ntohd((unsigned char *)vec, (unsigned char *)ep->ext_buf + 4, double_count);
03513 
03514         /*
03515          *  Walk the array of segments in reverse order,
03516          *  allocating a linked list of segments in internal format,
03517          *  using exactly the same structures as libwdb.
03518          */
03519         BU_LIST_INIT( &pipe->pipe_segs_head );
03520         for (i = 0; i < double_count; i += 6) {
03521                 /* Apply modeling transformations */
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);                      /* OK */
03533 }
03534 
03535 /**
03536  *                      R T _ P I P E _ E X P O R T 5
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; /* no segments provided, empty pipe is bogus */
03558         }
03559         headp = &pip->pipe_segs_head;
03560 
03561         /* Count number of points */
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);                     /* Not enough for 1 pipe! */
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         /* Convert the pipe segments to external form */
03581         for( BU_LIST_FOR( ppt, wdb_pipept, headp ), i += 6  )  {
03582                 /* Convert from user units to mm */
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         /* Convert from internal (host) to database (network) format */
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  *                      R T _ P I P E _ D E S C R I B E
03598  *
03599  *  Make human-readable formatted presentation of this solid.
03600  *  First line describes type of solid.
03601  *  Additional lines are indented one tab, and give parameter values.
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         /* Too much for the MGED Display!!!! */
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  *                      R T _ P I P E _ I F R E E
03648  *
03649  *  Free the storage associated with the rt_db_internal version of this solid.
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  *                      R T _ P I P E _ C K
03673  *
03674  *  Check pipe solid
03675  *      Bend radius must be at least as large as the outer radius
03676  *      All bends must have constant diameters
03677  *      No consecutive LINEAR sections without BENDS unless the
03678  *              LINEAR sections are collinear.
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  *                      R T _ P I P E _ T C L _ G E T
03774  *
03775  *  Examples -
03776  *      db get name V#                  get coordinates for vertex #
03777  *      db get name I#                  get inner radius for vertex #
03778  *      db get name O#                  get outer radius for vertex #
03779  *      db get name R#                  get bendradius for vertex #
03780  *      db get name P#                  get all data for vertex #
03781  *      db get name N                   get number of vertices
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         /* count segments */
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                 /* find the desired vertex */
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                 /* count vertices */
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;         /* struct copy */
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                 /* get the specified vertex */
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  * Local Variables:
04015  * mode: C
04016  * tab-width: 8
04017  * c-basic-offset: 4
04018  * indent-tabs-mode: t
04019  * End:
04020  * ex: shiftwidth=4 tabstop=8
04021  */

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