g_extrude.c

Go to the documentation of this file.
00001 /*                     G _ E X T R U D 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_extrude.c
00026  *      Provide support for solids of extrusion.
00027  *
00028  *  Authors -
00029  *      John R. Anderson
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 #ifndef lint
00038 static const char RCSextrude[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_extrude.c,v 14.17 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00039 #endif
00040 
00041 #include "common.h"
00042 
00043 #include <stdlib.h>
00044 #include <stdio.h>
00045 #include <math.h>
00046 #ifdef HAVE_STRING_H
00047 #  include <string.h>
00048 #else
00049 #  include <strings.h>
00050 #endif
00051 
00052 #include "machine.h"
00053 #include "tcl.h"
00054 #include "vmath.h"
00055 #include "db.h"
00056 #include "nmg.h"
00057 #include "rtgeom.h"
00058 #include "raytrace.h"
00059 #include "nurb.h"
00060 #include "./debug.h"
00061 
00062 extern int seg_to_vlist( struct bu_list *vhead, const struct rt_tess_tol *ttol, point_t V,
00063                          vect_t u_vec, vect_t v_vec, struct rt_sketch_internal *sketch_ip, genptr_t seg);
00064 
00065 struct extrude_specific {
00066         mat_t rot, irot;        /* rotation and translation to get extrsuion vector in +z direction with V at origin */
00067         vect_t unit_h;          /* unit vector in direction of extrusion vector */
00068         vect_t u_vec;           /* u vector rotated and projected */
00069         vect_t v_vec;           /* v vector rotated and projected */
00070         fastf_t uv_scale;       /* length of original, untransformed u_vec */
00071         vect_t rot_axis;        /* axis of rotation for rotation matrix */
00072         vect_t perp;            /* vector in pl1_rot plane and normal to rot_axis */
00073         plane_t pl1, pl2;       /* plane equations of the top and bottom planes (not rotated) */
00074         plane_t pl1_rot;        /* pl1 rotated by rot */
00075         point_t *verts;         /* sketch vertices projected onto a plane normal to extrusion vector */
00076         struct curve crv;       /* copy of the referenced curve */
00077 };
00078 
00079 static struct bn_tol extr_tol={                 /* a fake tolerance structure for the intersection routines */
00080         BN_TOL_MAGIC,
00081         RT_LEN_TOL,
00082         RT_LEN_TOL*RT_LEN_TOL,
00083         0.0,
00084         1.0};
00085 
00086 #define MAX_HITS 64
00087 
00088 /* defines for surf_no in the hit struct (a negative surf_no indicates an exit point) */
00089 #define TOP_FACE        1       /* extruded face */
00090 #define BOTTOM_FACE     2       /* face in uv-plane */
00091 #define LINE_SEG        3
00092 #define CARC_SEG        4
00093 #define NURB_SEG        5
00094 #define BEZIER_SEG      6
00095 
00096 /* defines for loop classification */
00097 #define UNKNOWN         0
00098 #define A_IN_B          1
00099 #define B_IN_A          2
00100 #define DISJOINT        3
00101 
00102 #define LOOPA           1
00103 #define LOOPB           2
00104 
00105 /**
00106  *                      R T _ E X T R U D E _ P R E P
00107  *
00108  *  Given a pointer to a GED database record, and a transformation matrix,
00109  *  determine if this is a valid EXTRUDE, and if so, precompute various
00110  *  terms of the formula.
00111  *
00112  *  Returns -
00113  *      0       EXTRUDE is OK
00114  *      !0      Error in description
00115  *
00116  *  Implicit return -
00117  *      A struct extrude_specific is created, and it's address is stored in
00118  *      stp->st_specific for use by extrude_shot().
00119  */
00120 int
00121 rt_extrude_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00122 {
00123         struct rt_extrude_internal *eip;
00124         register struct extrude_specific *extr;
00125         struct rt_sketch_internal *skt;
00126         LOCAL vect_t tmp, xyz[3];
00127         fastf_t tmp_f, ldir[3];
00128         int i, j;
00129         int vert_count;
00130         int curr_vert;
00131 
00132         eip = (struct rt_extrude_internal *)ip->idb_ptr;
00133         RT_EXTRUDE_CK_MAGIC( eip );
00134         skt = eip->skt;
00135         RT_SKETCH_CK_MAGIC( skt );
00136 
00137         /* make sure the curve is valid */
00138         if( rt_check_curve( &skt->skt_curve, skt, 1 ) )
00139         {
00140                 bu_log( "ERROR: referenced sketch (%s) is bad!!!\n",
00141                         eip->sketch_name );
00142                 return( -1 );
00143         }
00144 
00145         BU_GETSTRUCT( extr, extrude_specific );
00146         stp->st_specific = (genptr_t)extr;
00147 
00148         VMOVE( extr->unit_h, eip->h );
00149         VUNITIZE(extr->unit_h );
00150 
00151         /* the length of the u_vec is used for scaling radii of circular arcs
00152          * the u_vec and the v_vec must have the same length
00153          */
00154         extr->uv_scale = MAGNITUDE( eip->u_vec );
00155 
00156         /* build a transformation matrix to rotate extrusion vector to z-axis */
00157         VSET( tmp, 0, 0, 1 )
00158         bn_mat_fromto( extr->rot, eip->h, tmp );
00159 
00160         /* and translate to origin */
00161         extr->rot[MDX] = -VDOT( eip->V, &extr->rot[0] );
00162         extr->rot[MDY] = -VDOT( eip->V, &extr->rot[4] );
00163         extr->rot[MDZ] = -VDOT( eip->V, &extr->rot[8] );
00164 
00165         /* and save the inverse */
00166         bn_mat_inv( extr->irot, extr->rot );
00167 
00168         /* calculate plane equations of top and bottom planes */
00169         VCROSS( extr->pl1, eip->u_vec, eip->v_vec );
00170         VUNITIZE( extr->pl1 )
00171         extr->pl1[3] = VDOT( extr->pl1, eip->V );
00172         VMOVE( extr->pl2, extr->pl1 );
00173         VADD2( tmp, eip->V, eip->h );
00174         extr->pl2[3] = VDOT( extr->pl2, tmp );
00175 
00176         vert_count = skt->vert_count;
00177         /* count how many additional vertices we will need for arc centers */
00178         for( i=0 ; i<skt->skt_curve.seg_count ; i++ )
00179         {
00180                 struct carc_seg *csg=(struct carc_seg *)skt->skt_curve.segments[i];
00181 
00182                 if( csg->magic != CURVE_CARC_MAGIC )
00183                         continue;
00184 
00185                 if( csg->radius <= 0.0 )
00186                         continue;
00187 
00188                 vert_count++;
00189         }
00190 
00191         /* apply the rotation matrix to all the vertices, and start bounding box calculation */
00192         if( vert_count )
00193                 extr->verts = (point_t *)bu_calloc( vert_count, sizeof( point_t ), "extr->verts" );
00194         VSETALL( stp->st_min, MAX_FASTF );
00195         VSETALL( stp->st_max, -MAX_FASTF );
00196         for( i=0 ; i<skt->vert_count ; i++ )
00197         {
00198                 VJOIN2( tmp, eip->V, skt->verts[i][0], eip->u_vec, skt->verts[i][1], eip->v_vec );
00199                 VMINMAX( stp->st_min, stp->st_max, tmp );
00200                 MAT4X3PNT( extr->verts[i], extr->rot, tmp );
00201                 VADD2( tmp, tmp, eip->h );
00202                 VMINMAX( stp->st_min, stp->st_max, tmp );
00203         }
00204         curr_vert = skt->vert_count;
00205 
00206         /* and the u,v vectors */
00207         MAT4X3VEC( extr->u_vec, extr->rot, eip->u_vec );
00208         MAT4X3VEC( extr->v_vec, extr->rot, eip->v_vec );
00209 
00210         /* calculate the rotated pl1 */
00211         VCROSS( extr->pl1_rot, extr->u_vec, extr->v_vec );
00212         VUNITIZE( extr->pl1_rot );
00213         extr->pl1_rot[3] = VDOT( extr->pl1_rot, extr->verts[0] );
00214 
00215         VSET( tmp, 0, 0, 1 )
00216         tmp_f = VDOT( tmp, extr->unit_h );
00217         if( tmp_f < 0.0 )
00218                 tmp_f = -tmp_f;
00219         tmp_f -= 1.0;
00220         if( NEAR_ZERO( tmp_f, SQRT_SMALL_FASTF ) )
00221         {
00222                 VSET( extr->rot_axis, 1.0, 0.0, 0.0 );
00223                 VSET( extr->perp, 0.0, 1.0, 0.0 );
00224         }
00225         else
00226         {
00227                 VCROSS( extr->rot_axis, tmp, extr->unit_h );
00228                 VUNITIZE( extr->rot_axis );
00229                 if( MAGNITUDE( extr->rot_axis ) < SQRT_SMALL_FASTF )
00230                 {
00231                         VSET( extr->rot_axis, 1.0, 0.0, 0.0 );
00232                         VSET( extr->perp, 0.0, 1.0, 0.0 );
00233                 }
00234                 else
00235                 {
00236                         VCROSS( extr->perp, extr->rot_axis, extr->pl1_rot );
00237                         VUNITIZE( extr->perp );
00238                 }
00239         }
00240 
00241         /* copy the curve */
00242         rt_copy_curve( &extr->crv, &skt->skt_curve );
00243 
00244         VSET( xyz[X], 1, 0, 0 );
00245         VSET( xyz[Y], 0, 1, 0 );
00246         VSET( xyz[Z], 0, 0, 1 );
00247 
00248         for( i=X ; i<=Z ; i++ ) {
00249                 VCROSS( tmp, extr->unit_h, xyz[i] );
00250                 ldir[i] = MAGNITUDE( tmp );
00251         }
00252 
00253         /* if any part of the curve is a circular arc, the arc may extend beyond the listed vertices */
00254         for( i=0 ; i<skt->skt_curve.seg_count ; i++ )
00255         {
00256                 struct carc_seg *csg=(struct carc_seg *)skt->skt_curve.segments[i];
00257                 struct carc_seg *csg_extr=(struct carc_seg *)extr->crv.segments[i];
00258                 point_t center;
00259 
00260                 if( csg->magic != CURVE_CARC_MAGIC )
00261                         continue;
00262 
00263                 if( csg->radius <= 0.0 )        /* full circle */
00264                 {
00265                         point_t start;
00266                         fastf_t radius;
00267 
00268                         csg_extr->center = csg->end;
00269                         VJOIN2( start, eip->V, skt->verts[csg->start][0], eip->u_vec, skt->verts[csg->start][1], eip->v_vec );
00270                         VJOIN2( center, eip->V, skt->verts[csg->end][0], eip->u_vec, skt->verts[csg->end][1], eip->v_vec );
00271                         VSUB2( tmp, start, center );
00272                         radius = MAGNITUDE( tmp );
00273                         csg_extr->radius = -radius;     /* need the correct magnitude for normal calculation */
00274 
00275                         for( j=X ; j<=Z ; j++ ) {
00276                                 tmp_f = radius * ldir[j];
00277                                 VJOIN1( tmp, center, tmp_f, xyz[j] );
00278                                 VMINMAX( stp->st_min, stp->st_max, tmp );
00279                                 VADD2( tmp, tmp, eip->h );
00280                                 VMINMAX( stp->st_min, stp->st_max, tmp );
00281 
00282                                 VJOIN1( tmp, center, -tmp_f, xyz[j] );
00283                                 VMINMAX( stp->st_min, stp->st_max, tmp );
00284                                 VADD2( tmp, tmp, eip->h );
00285                                 VMINMAX( stp->st_min, stp->st_max, tmp );
00286                         }
00287                 }
00288                 else    /* circular arc */
00289                 {
00290                         point_t start, end, mid;
00291                         vect_t s_to_m;
00292                         vect_t bisector;
00293                         fastf_t dist;
00294                         fastf_t magsq_s2m;
00295 
00296                         VJOIN2( start, eip->V, skt->verts[csg->start][0], eip->u_vec, skt->verts[csg->start][1], eip->v_vec );
00297                         VJOIN2( end, eip->V, skt->verts[csg->end][0], eip->u_vec, skt->verts[csg->end][1], eip->v_vec );
00298                         VBLEND2( mid, 0.5, start, 0.5, end );
00299                         VSUB2( s_to_m, mid, start );
00300                         VCROSS( bisector, extr->pl1, s_to_m );
00301                         VUNITIZE( bisector );
00302                         magsq_s2m = MAGSQ( s_to_m );
00303                         csg_extr->radius = csg->radius * extr->uv_scale;
00304                         if( magsq_s2m > csg_extr->radius*csg_extr->radius )
00305                         {
00306                                 fastf_t max_radius;
00307 
00308                                 max_radius = sqrt( magsq_s2m );
00309                                 if( NEAR_ZERO( max_radius - csg_extr->radius, RT_LEN_TOL ) )
00310                                         csg_extr->radius = max_radius;
00311                                 else
00312                                 {
00313                                         bu_log( "Impossible radius for circular arc in extrusion (%s), is %g, cannot be more than %g!!!\n",
00314                                                         stp->st_dp->d_namep, csg_extr->radius, sqrt(magsq_s2m)  );
00315                                         bu_log( "Difference is %g\n", max_radius - csg->radius );
00316                                         return( -1 );
00317                                 }
00318                         }
00319                         dist = sqrt( csg_extr->radius*csg_extr->radius - magsq_s2m );
00320 
00321                         /* save arc center */
00322                         if( csg->center_is_left )
00323                                 VJOIN1( center, mid, dist, bisector )
00324                         else
00325                                 VJOIN1( center, mid, -dist, bisector )
00326                         MAT4X3PNT( extr->verts[curr_vert], extr->rot, center );
00327                         csg_extr->center = curr_vert;
00328                         curr_vert++;
00329 
00330                         for( j=X ; j<=Z ; j++ ) {
00331                                 tmp_f = csg_extr->radius * ldir[j];
00332                                 VJOIN1( tmp, center, tmp_f, xyz[j] );
00333                                 VMINMAX( stp->st_min, stp->st_max, tmp );
00334                                 VADD2( tmp, tmp, eip->h );
00335                                 VMINMAX( stp->st_min, stp->st_max, tmp );
00336 
00337                                 VJOIN1( tmp, center, -tmp_f, xyz[j] );
00338                                 VMINMAX( stp->st_min, stp->st_max, tmp );
00339                                 VADD2( tmp, tmp, eip->h );
00340                                 VMINMAX( stp->st_min, stp->st_max, tmp );
00341                         }
00342                 }
00343         }
00344 
00345         VBLEND2( stp->st_center, 0.5, stp->st_min, 0.5, stp->st_max );
00346         VSUB2( tmp, stp->st_max, stp->st_min );
00347         stp->st_aradius = 0.5 * MAGNITUDE( tmp );
00348         stp->st_bradius = stp->st_aradius;
00349 
00350         return(0);              /* OK */
00351 }
00352 
00353 /**
00354  *                      R T _ E X T R U D E _ P R I N T
00355  */
00356 void
00357 rt_extrude_print(register const struct soltab *stp)
00358 {
00359 }
00360 
00361 int
00362 get_quadrant(fastf_t *v, fastf_t *local_x, fastf_t *local_y, fastf_t *vx, fastf_t *vy)
00363 {
00364 
00365         *vx = V2DOT( v, local_x );
00366         *vy = V2DOT( v, local_y );
00367 
00368         if( *vy >= 0.0 )
00369         {
00370                 if( *vx >= 0.0 )
00371                         return( 1 );
00372                 else
00373                         return( 2 );
00374         }
00375         else
00376         {
00377                 if( *vx >= 0.0 )
00378                         return( 4 );
00379                 else
00380                         return( 3 );
00381         }
00382 }
00383 
00384 int
00385 isect_line2_ellipse(fastf_t *dist, fastf_t *ray_start, fastf_t *ray_dir, fastf_t *center, fastf_t *ra, fastf_t *rb)
00386 {
00387         fastf_t a, b, c;
00388         point2d_t pmc;
00389         fastf_t pmcda, pmcdb;
00390         fastf_t ra_sq, rb_sq;
00391         fastf_t ra_4, rb_4;
00392         fastf_t dda, ddb;
00393         fastf_t disc;
00394 
00395         V2SUB2( pmc, ray_start, center );
00396         pmcda = V2DOT( pmc, ra );
00397         pmcdb = V2DOT( pmc, rb );
00398         ra_sq = V2DOT( ra, ra );
00399         ra_4 = ra_sq * ra_sq;
00400         rb_sq = V2DOT( rb, rb );
00401         rb_4 = rb_sq * rb_sq;
00402         if( ra_4 < SMALL_FASTF || rb_4 < SMALL_FASTF )
00403         {
00404                 bu_log( "ray (%g %g %g) -> (%g %g %g), semi-axes  = (%g %g %g) and (%g %g %g), center = (%g %g %g)\n",
00405                         V3ARGS( ray_start ), V3ARGS( ray_dir ), V3ARGS( ra ), V3ARGS( rb ), V3ARGS( center ) );
00406                 bu_bomb( "ERROR: isect_line2_ellipse: semi-axis length is too small!!!\n" );
00407         }
00408 
00409         dda = V2DOT( ray_dir, ra );
00410         ddb = V2DOT( ray_dir, rb );
00411 
00412         a = dda*dda/ra_4 + ddb*ddb/rb_4;
00413         b = 2.0 * (pmcda*dda/ra_4 + pmcdb*ddb/rb_4);
00414         c = pmcda*pmcda/ra_4 + pmcdb*pmcdb/rb_4 - 1.0;
00415 
00416         disc = b*b - 4.0*a*c;
00417         if( disc < 0.0 )
00418                 return( 0 );
00419 
00420         if( disc <= SMALL_FASTF )
00421         {
00422                 dist[0] = -b/(2.0*a);
00423                 return( 1 );
00424         }
00425 
00426         dist[0] = (-b - sqrt( disc )) / (2.0*a);
00427         dist[1] = (-b + sqrt( disc )) / (2.0*a);
00428         return( 2 );
00429 }
00430 
00431 
00432 int
00433 isect_line_earc(fastf_t *dist, fastf_t *ray_start, fastf_t *ray_dir, fastf_t *center, fastf_t *ra, fastf_t *rb, fastf_t *norm, fastf_t *start, fastf_t *end, int orientation)
00434 
00435 
00436 
00437 
00438 
00439                         /* 0 -> ccw, !0 -> cw */
00440 {
00441         int dist_count;
00442         vect_t local_x, local_y, local_z;
00443         fastf_t vx, vy;
00444         fastf_t ex, ey;
00445         fastf_t sx, sy;
00446         int quad_start, quad_end, quad_pt;
00447         point2d_t to_pt, pt;
00448         int i;
00449 
00450         dist_count = isect_line2_ellipse( dist, ray_start, ray_dir, center, ra, rb);
00451 
00452         if( dist_count == 0 )
00453                 return( 0 );
00454 
00455         if( orientation )
00456                 VREVERSE( local_z, norm )
00457         else
00458                 VMOVE( local_z, norm )
00459 
00460         VMOVE( local_x, ra );
00461 
00462         VCROSS( local_y, local_z, local_x );
00463 
00464         V2SUB2( to_pt, end, center );
00465         quad_end = get_quadrant( to_pt, local_x, local_y, &ex, &ey );
00466         V2SUB2( to_pt, start, center );
00467         quad_start = get_quadrant( to_pt, local_x, local_y, &sx, &sy );
00468 
00469         i = 0;
00470         while( i < dist_count )
00471         {
00472                 int omit;
00473 
00474                 omit = 0;
00475                 V2JOIN1( pt, ray_start, dist[i], ray_dir );
00476                 V2SUB2( to_pt, pt, center );
00477                 quad_pt = get_quadrant( to_pt, local_x, local_y, &vx, &vy );
00478 
00479                 if( quad_start < quad_end )
00480                 {
00481                         if( quad_pt > quad_end )
00482                                 omit = 1;
00483                         else if( quad_pt < quad_start )
00484                                 omit = 1;
00485                         else if( quad_pt == quad_end )
00486                         {
00487                                 switch( quad_pt )
00488                                 {
00489                                         case 1:
00490                                         case 2:
00491                                                 if( vx < ex )
00492                                                         omit = 1;
00493                                                 break;
00494                                         case 3:
00495                                         case 4:
00496                                                 if( vx > ex )
00497                                                         omit = 1;
00498                                                 break;
00499                                 }
00500                         }
00501                         else if( quad_pt == quad_start )
00502                         {
00503                                 switch( quad_pt )
00504                                 {
00505                                         case 1:
00506                                         case 2:
00507                                                 if( vx > sx )
00508                                                         omit = 1;
00509                                                 break;
00510                                         case 3:
00511                                         case 4:
00512                                                 if( vx < sx )
00513                                                         omit = 1;
00514                                                 break;
00515                                 }
00516                         }
00517                 }
00518                 else if( quad_start > quad_end )
00519                 {
00520                         if( quad_pt > quad_end && quad_pt < quad_start )
00521                                 omit = 1;
00522                         else if( quad_pt == quad_end )
00523                         {
00524                                 switch( quad_pt )
00525                                 {
00526                                         case 1:
00527                                         case 2:
00528                                                 if( vx < ex )
00529                                                         omit = 1;
00530                                                 break;
00531                                         case 3:
00532                                         case 4:
00533                                                 if( vx > ex )
00534                                                         omit = 1;
00535                                                 break;
00536                                 }
00537                         }
00538                         else if( quad_pt == quad_start )
00539                         {
00540                                 switch( quad_pt )
00541                                 {
00542                                         case 1:
00543                                         case 2:
00544                                                 if( vx > sx )
00545                                                         omit = 1;
00546                                                 break;
00547                                         case 3:
00548                                         case 4:
00549                                                 if( vx < sx )
00550                                                         omit = 1;
00551                                                 break;
00552                                 }
00553                         }
00554                 }
00555                 else            /* quad_start == quad_end */
00556                 {
00557                         if( quad_pt != quad_start )
00558                                 omit = 1;
00559                         else
00560                         {
00561                                 switch( quad_pt )
00562                                 {
00563                                         case 1:
00564                                         case 2:
00565                                                 if( vx < ex || vx > sx )
00566                                                         omit = 1;
00567                                                 break;
00568                                         case 3:
00569                                         case 4:
00570                                                 if( vx > ex || vx < sx )
00571                                                         omit = 1;
00572                                                 break;
00573                                 }
00574                         }
00575                 }
00576                 if( omit )
00577                 {
00578                         if( i == 0 )
00579                                 dist[0] = dist[1];
00580                         dist_count--;
00581                 }
00582                 else
00583                         i++;
00584         }
00585 
00586         return( dist_count );
00587 }
00588 
00589 
00590 
00591 /**
00592  *                      R T _ E X T R U D E _ S H O T
00593  *
00594  *  Intersect a ray with a extrude.
00595  *  If an intersection occurs, a struct seg will be acquired
00596  *  and filled in.
00597  *
00598  *  Returns -
00599  *      0       MISS
00600  *      >0      HIT
00601  */
00602 int
00603 rt_extrude_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00604 {
00605         struct extrude_specific *extr=(struct extrude_specific *)stp->st_specific;
00606         register int i, j, k;
00607         fastf_t dist_top, dist_bottom, to_bottom=0;
00608         fastf_t dist[2];
00609         fastf_t dot_pl1, dir_dot_z;
00610         point_t tmp, tmp2;
00611         point_t ray_start, ray_dir, ray_dir_unit;       /* 2D */
00612         struct curve *crv;
00613         struct hit hits[MAX_HITS];
00614         fastf_t dists_before[MAX_HITS];
00615         fastf_t dists_after[MAX_HITS];
00616         fastf_t *dists=NULL;
00617         int dist_count=0;
00618         int hit_count=0;
00619         int hits_before_bottom=0, hits_after_top=0;
00620         int code;
00621         int check_inout=0;
00622         int top_face=TOP_FACE, bot_face=BOTTOM_FACE;
00623         int surfno= -42;
00624         int free_dists=0;
00625         point2d_t *verts;
00626         point2d_t *intercept;
00627         point2d_t *normal;
00628         point2d_t ray_perp;
00629 
00630         crv = &extr->crv;
00631 
00632         /* intersect with top and bottom planes */
00633         dot_pl1 = VDOT( rp->r_dir, extr->pl1 );
00634         if( NEAR_ZERO( dot_pl1, SMALL_FASTF ) )
00635         {
00636                 /* ray is parallel to top and bottom faces */
00637                 dist_bottom = DIST_PT_PLANE( rp->r_pt, extr->pl1 );
00638                 dist_top = DIST_PT_PLANE( rp->r_pt, extr->pl2 );
00639                 if( dist_bottom < 0.0 && dist_top < 0.0 )
00640                         return( 0 );
00641                 if( dist_bottom > 0.0 && dist_top > 0.0 )
00642                         return( 0 );
00643                 dist_bottom = -MAX_FASTF;
00644                 dist_top = MAX_FASTF;
00645         }
00646         else
00647         {
00648                 dist_bottom = -DIST_PT_PLANE( rp->r_pt, extr->pl1 )/dot_pl1;
00649                 to_bottom = dist_bottom;                                        /* need to remember this */
00650                 dist_top = -DIST_PT_PLANE( rp->r_pt, extr->pl2 )/dot_pl1;       /* pl1 and pl2 are parallel */
00651                 if( dist_bottom > dist_top )
00652                 {
00653                         fastf_t tmp1;
00654 
00655                         tmp1 = dist_bottom;
00656                         dist_bottom = dist_top;
00657                         dist_top = tmp1;
00658                         top_face = BOTTOM_FACE;
00659                         bot_face = TOP_FACE;
00660                 }
00661         }
00662 
00663         /* rotate ray */
00664         MAT4X3PNT( ray_start, extr->rot, rp->r_pt );
00665         MAT4X3VEC( ray_dir, extr->rot, rp->r_dir );
00666 
00667         dir_dot_z = ray_dir[Z];
00668         if( dir_dot_z < 0.0 )
00669                 dir_dot_z = -dir_dot_z;
00670 
00671         if( NEAR_ZERO( dir_dot_z - 1.0, SMALL_FASTF ) )
00672         {
00673                 /* ray is parallel to extrusion vector
00674                  * set mode to just count intersections for Jordan Theorem
00675                  */
00676                 check_inout = 1;
00677 
00678                 /* set the ray start to the intersection of the original ray and the base plane */
00679                 VJOIN1( tmp, rp->r_pt, to_bottom, rp->r_dir );
00680                 MAT4X3PNT( ray_start, extr->rot, tmp );
00681 
00682                 /* use the u vector as the ray direction */
00683                 VMOVE( ray_dir, extr->u_vec );
00684         }
00685 
00686         /* intersect with projected curve */
00687         for( i=0 ; i<crv->seg_count ; i++ )
00688         {
00689                 long *lng=(long *)crv->segments[i];
00690                 struct line_seg *lsg;
00691                 struct carc_seg *csg=NULL;
00692                 struct bezier_seg *bsg=NULL;
00693                 fastf_t diff;
00694 
00695                 free_dists = 0;
00696                 switch( *lng )
00697                 {
00698                         case CURVE_LSEG_MAGIC:
00699                                 lsg = (struct line_seg *)lng;
00700                                 VSUB2( tmp, extr->verts[lsg->end], extr->verts[lsg->start] );
00701                                 VMOVE( tmp2, extr->verts[lsg->start] );
00702                                 code = bn_isect_line2_line2( dist, ray_start, ray_dir, tmp2, tmp, &extr_tol );
00703                                 if( code < 1 )
00704                                         continue;
00705 
00706                                 if( dist[1] > 1.0 || dist[1] < 0.0 )
00707                                         continue;
00708 
00709                                 dists = dist;
00710                                 dist_count = 1;
00711                                 surfno = LINE_SEG;
00712                                 break;
00713                         case CURVE_CARC_MAGIC:
00714                                 /* circular arcs become elliptical arcs when projected in the XY-plane */
00715                                 csg = (struct carc_seg *)lng;
00716                                 {
00717                                         vect_t ra, rb;
00718                                         fastf_t radius;
00719 
00720                                         if( csg->radius <= 0.0 )
00721                                         {
00722                                                 /* full circle */
00723                                                 radius = -csg->radius;
00724 
00725                                                 /* build the ellipse, this actually builds a circle in 3D,
00726                                                  * but the intersection routine only uses the X and Y components
00727                                                  */
00728                                                 VSCALE( ra, extr->rot_axis, radius );
00729                                                 VSCALE( rb, extr->perp, radius );
00730 
00731                                                 dist_count = isect_line2_ellipse( dist, ray_start, ray_dir, extr->verts[csg->end], ra, rb );
00732                                                 MAT4X3PNT( tmp, extr->irot, extr->verts[csg->end] ); /* used later in hit->vpriv */
00733                                         }
00734                                         else
00735                                         {
00736                                                 VSCALE( ra, extr->rot_axis, csg->radius );
00737                                                 VSCALE( rb, extr->perp, csg->radius );
00738                                                 dist_count = isect_line_earc( dist, ray_start, ray_dir, extr->verts[csg->center], ra, rb, extr->pl1_rot, extr->verts[csg->start], extr->verts[csg->end], csg->orientation );
00739                                                 MAT4X3PNT( tmp, extr->irot, extr->verts[csg->center] ); /* used later in hit->vpriv */
00740                                         }
00741                                 }
00742                                 if( dist_count < 1 )
00743                                         continue;
00744 
00745                                 dists = dist;
00746                                 surfno = CARC_SEG;
00747                                 break;
00748                         case CURVE_BEZIER_MAGIC:
00749                                 bsg = (struct bezier_seg *)lng;
00750                                 verts = (point2d_t *)bu_calloc( bsg->degree + 1, sizeof( point2d_t ), "Bezier verts" );
00751                                 for( j=0 ; j<=bsg->degree ; j++ ) {
00752                                         V2MOVE( verts[j], extr->verts[bsg->ctl_points[j]] );
00753                                 }
00754                                 V2MOVE( ray_dir_unit, ray_dir );
00755                                 diff = sqrt( MAG2SQ( ray_dir ) );
00756                                 ray_dir_unit[X] /= diff;
00757                                 ray_dir_unit[Y] /= diff;
00758                                 ray_dir_unit[Z] = 0.0;
00759                                 ray_perp[X] = ray_dir[Y];
00760                                 ray_perp[Y] = -ray_dir[X];
00761                                 dist_count = FindRoots( verts, bsg->degree, &intercept, &normal, ray_start, ray_dir_unit, ray_perp,
00762                                                         0, extr_tol.dist );
00763                                 if( dist_count ) {
00764                                         free_dists = 1;
00765                                         dists = (fastf_t *)bu_calloc( dist_count, sizeof( fastf_t ), "dists (Bezier)" );
00766                                         for( j=0 ; j<dist_count ; j++ ) {
00767                                                 point2d_t to_pt;
00768                                                 V2SUB2( to_pt, intercept[j], ray_start );
00769                                                 dists[j] = V2DOT( to_pt, ray_dir_unit) / diff;
00770                                         }
00771                                         bu_free( (char *)intercept, "Bezier intercept" );
00772                                         surfno = BEZIER_SEG;
00773                                 }
00774                                 bu_free( (char *)verts, "Bezier verts" );
00775                                 break;
00776                         case CURVE_NURB_MAGIC:
00777                                 break;
00778                         default:
00779                                 bu_log( "Unrecognized segment type in sketch (%s) referenced by extrusion (%s)\n",
00780                                         stp->st_dp->d_namep );
00781                                 bu_bomb( "Unrecognized segment type in sketch\n" );
00782                                 break;
00783                 }
00784 
00785                 /* eliminate duplicate hit distances */
00786                 for( j=0 ; j<hit_count ; j++ )
00787                 {
00788                         k = 0;
00789                         while( k < dist_count )
00790                         {
00791                                 diff = dists[k] - hits[j].hit_dist;
00792                                 if( NEAR_ZERO( diff, extr_tol.dist ) )
00793                                 {
00794                                         int n;
00795                                         for( n=k ; n<dist_count-1 ; n++ ) {
00796                                                 dists[n] = dists[n+1];
00797                                                 if( *lng == CURVE_BEZIER_MAGIC ) {
00798                                                         V2MOVE( normal[n], normal[n+1] );
00799                                                 }
00800                                         }
00801                                         dist_count--;
00802                                 }
00803                                 else
00804                                         k++;
00805                         }
00806                 }
00807 
00808                 /* eliminate duplicate hits below the bottom plane of the extrusion */
00809                 for( j=0 ; j<hits_before_bottom ; j++ )
00810                 {
00811                         k = 0;
00812                         while( k < dist_count )
00813                         {
00814                                 diff = dists[k] - dists_before[j];
00815                                 if( NEAR_ZERO( diff, extr_tol.dist ) )
00816                                 {
00817                                         int n;
00818 
00819                                         for( n=k ; n<dist_count-1 ; n++ ) {
00820                                                 dists[n] = dists[n+1];
00821                                                 if( *lng == CURVE_BEZIER_MAGIC ) {
00822                                                         V2MOVE( normal[n], normal[n+1] );
00823                                                 }
00824                                         }
00825                                         dist_count--;
00826                                 }
00827                                 else
00828                                         k++;
00829                         }
00830                 }
00831 
00832                 /* eliminate duplicate hits above the top plane of the extrusion */
00833                 for( j=0 ; j<hits_after_top ; j++ )
00834                 {
00835                         k = 0;
00836                         while( k < dist_count )
00837                         {
00838                                 diff = dists[k] - dists_after[j];
00839                                 if( NEAR_ZERO( diff, extr_tol.dist ) )
00840                                 {
00841                                         int n;
00842 
00843                                         for( n=k ; n<dist_count-1 ; n++ )
00844                                                 dists[n] = dists[n+1];
00845                                         dist_count--;
00846                                 }
00847                                 else
00848                                         k++;
00849                         }
00850                 }
00851 
00852                 /* if we are just doing the Jordan curve thereom */
00853                 if( check_inout )
00854                 {
00855                         for( j=0 ; j<dist_count ; j++ )
00856                         {
00857                                 if( dists[j] < 0.0 )
00858                                         hit_count++;
00859                         }
00860                         continue;
00861                 }
00862 
00863                 /* process remaining distances into hits */
00864                 for( j=0 ; j<dist_count ; j++ )
00865                 {
00866                         if( dists[j] < dist_bottom )
00867                         {
00868                                 if( hits_before_bottom >= MAX_HITS )
00869                                 {
00870                                         bu_log( "ERROR: rt_extrude_shot: too many hits before bottom on extrusion (%s), limit is %d\n",
00871                                         stp->st_dp->d_namep, MAX_HITS );
00872                                         bu_bomb( "ERROR: rt_extrude_shot: too many hits before bottom on extrusion\n" );
00873                                 }
00874                                 dists_before[hits_before_bottom] = dists[j];
00875                                 hits_before_bottom++;
00876                                 continue;
00877                         }
00878                         if( dists[j] > dist_top )
00879                         {
00880                                 if( hits_after_top >= MAX_HITS )
00881                                 {
00882                                         bu_log( "ERROR: rt_extrude_shot: too many hits after top on extrusion (%s), limit is %d\n",
00883                                         stp->st_dp->d_namep, MAX_HITS );
00884                                         bu_bomb( "ERROR: rt_extrude_shot: too many hits after top on extrusion\n" );
00885                                 }
00886                                 dists_after[hits_after_top] = dists[j];
00887                                 hits_after_top++;
00888 
00889                                 continue;
00890                         }
00891 
00892                         /* got a hit at distance dists[j] */
00893                         if( hit_count >= MAX_HITS )
00894                         {
00895                                 bu_log( "Too many hits on extrusion (%s), limit is %d\n",
00896                                         stp->st_dp->d_namep, MAX_HITS );
00897                                 bu_bomb( "Too many hits on extrusion\n" );
00898                         }
00899                         hits[hit_count].hit_magic = RT_HIT_MAGIC;
00900                         hits[hit_count].hit_dist = dists[j];
00901                         hits[hit_count].hit_surfno = surfno;
00902                         switch( *lng )
00903                         {
00904                                 case CURVE_CARC_MAGIC:
00905                                         hits[hit_count].hit_private = (genptr_t)csg;
00906                                         VMOVE( hits[hit_count].hit_vpriv, tmp );
00907                                         break;
00908                                 case CURVE_LSEG_MAGIC:
00909                                         VMOVE( hits[hit_count].hit_vpriv, tmp );
00910                                         break;
00911                                 case CURVE_BEZIER_MAGIC:
00912                                         V2MOVE( hits[hit_count].hit_vpriv, normal[j] );
00913                                         hits[hit_count].hit_vpriv[Z] = 0.0;
00914                                         break;
00915                                 default:
00916                                         bu_log( "ERROR: rt_extrude_shot: unrecognized segment type in solid %s\n",
00917                                                 stp->st_dp->d_namep );
00918                                         bu_bomb( "ERROR: rt_extrude_shot: unrecognized segment type in solid\n" );
00919                                         break;
00920                         }
00921                         hit_count++;
00922                 }
00923                 if( free_dists )
00924                         bu_free( (char *)dists, "dists" );
00925         }
00926 
00927         if( check_inout )
00928         {
00929                 if( hit_count&1 )
00930                 {
00931                         register struct seg *segp;
00932 
00933                         hit_count = 2;
00934                         hits[0].hit_magic = RT_HIT_MAGIC;
00935                         hits[0].hit_dist = dist_bottom;
00936                         hits[0].hit_surfno = bot_face;
00937                         VMOVE( hits[0].hit_normal, extr->pl1 );
00938 
00939                         hits[1].hit_magic = RT_HIT_MAGIC;
00940                         hits[1].hit_dist = dist_top;
00941                         hits[1].hit_surfno = -top_face;
00942                         VMOVE( hits[1].hit_normal, extr->pl1 );
00943 
00944                         RT_GET_SEG(segp, ap->a_resource);
00945                         segp->seg_stp = stp;
00946                         segp->seg_in = hits[0];         /* struct copy */
00947                         segp->seg_out = hits[1];        /* struct copy */
00948                         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00949                         return( 2 );
00950                 }
00951                 else
00952                 {
00953                         return( 0 );
00954                 }
00955         }
00956 
00957         if( hit_count )
00958         {
00959                 /* Sort hits, Near to Far */
00960                 rt_hitsort( hits, hit_count );
00961         }
00962 
00963         if( hits_before_bottom & 1 )
00964         {
00965                 if( hit_count >= MAX_HITS )
00966                 {
00967                         bu_log( "Too many hits on extrusion (%s), limit is %d\n",
00968                                 stp->st_dp->d_namep, MAX_HITS );
00969                         bu_bomb( "Too many hits on extrusion\n" );
00970                 }
00971                 for( i=hit_count-1 ; i>=0 ; i-- )
00972                         hits[i+1] = hits[i];
00973                 hits[0].hit_magic = RT_HIT_MAGIC;
00974                 hits[0].hit_dist = dist_bottom;
00975                 hits[0].hit_surfno = bot_face;
00976                 VMOVE( hits[0].hit_normal, extr->pl1 );
00977                 hit_count++;
00978         }
00979 
00980         if( hits_after_top & 1 )
00981         {
00982                 if( hit_count >= MAX_HITS )
00983                 {
00984                         bu_log( "Too many hits on extrusion (%s), limit is %d\n",
00985                                 stp->st_dp->d_namep, MAX_HITS );
00986                         bu_bomb( "Too many hits on extrusion\n" );
00987                 }
00988                 hits[hit_count].hit_magic = RT_HIT_MAGIC;
00989                 hits[hit_count].hit_dist = dist_top;
00990                 hits[hit_count].hit_surfno = top_face;
00991                 VMOVE( hits[hit_count].hit_normal, extr->pl1 );
00992                 hit_count++;
00993         }
00994 
00995         if( hit_count%2 )
00996         {
00997                 point_t pt;
00998 
00999                 if( hit_count != 1 ) {
01000                         bu_log( "ERROR: rt_extrude_shot(): odd number of hits (%d) (ignoring last hit)\n", hit_count );
01001                         bu_log( "ray start = (%20.10f %20.10f %20.10f)\n", V3ARGS( rp->r_pt ) );
01002                         bu_log( "\tray dir = (%20.10f %20.10f %20.10f)", V3ARGS( rp->r_dir ) );
01003                         VJOIN1( pt, rp->r_pt, hits[hit_count-1].hit_dist, rp->r_dir );
01004                         bu_log( "\tignored hit at (%g %g %g)\n", V3ARGS( pt ) );
01005                 }
01006                 hit_count--;
01007         }
01008 
01009         /* build segments */
01010         {
01011                 register struct seg *segp;
01012 
01013                 for( i=0; i < hit_count; i += 2 )  {
01014                         RT_GET_SEG(segp, ap->a_resource);
01015                         segp->seg_stp = stp;
01016                         segp->seg_in = hits[i];         /* struct copy */
01017                         segp->seg_out = hits[i+1];      /* struct copy */
01018                         segp->seg_out.hit_surfno = -segp->seg_out.hit_surfno;   /* for exit hits */
01019                         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
01020                 }
01021         }
01022 
01023         return( hit_count );
01024 }
01025 
01026 #define RT_EXTRUDE_SEG_MISS(SEG)        (SEG).seg_stp=RT_SOLTAB_NULL
01027 
01028 /**
01029  *                      R T _ E X T R U D E _ V S H O T
01030  *
01031  *  Vectorized version.
01032  */
01033 void
01034 rt_extrude_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
01035                                /* An array of solid pointers */
01036                                /* An array of ray pointers */
01037                                /* array of segs (results returned) */
01038                                /* Number of ray/object pairs */
01039 
01040 {
01041         rt_vstub( stp, rp, segp, n, ap );
01042 }
01043 
01044 /**
01045  *                      R T _ E X T R U D E _ N O R M
01046  *
01047  *  Given ONE ray distance, return the normal and entry/exit point.
01048  */
01049 void
01050 rt_extrude_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
01051 {
01052         struct extrude_specific *extr=(struct extrude_specific *)stp->st_specific;
01053         fastf_t alpha;
01054         point_t hit_in_plane;
01055         vect_t tmp, tmp2;
01056 
01057         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
01058 
01059         switch( hitp->hit_surfno )
01060         {
01061                 case LINE_SEG:
01062                         MAT4X3VEC( tmp, extr->irot, hitp->hit_vpriv );
01063                         VCROSS( hitp->hit_normal, extr->unit_h, tmp );
01064                         VUNITIZE( hitp->hit_normal );
01065                         break;
01066                 case -LINE_SEG:
01067                         MAT4X3VEC( tmp, extr->irot, hitp->hit_vpriv );
01068                         VCROSS( hitp->hit_normal, extr->unit_h, tmp );
01069                         VUNITIZE( hitp->hit_normal );
01070                         break;
01071                 case TOP_FACE:
01072                 case BOTTOM_FACE:
01073                 case -TOP_FACE:
01074                 case -BOTTOM_FACE:
01075                         break;
01076                 case CARC_SEG:
01077                 case -CARC_SEG:
01078                         alpha = DIST_PT_PLANE( hitp->hit_point, extr->pl1 ) / VDOT( extr->unit_h, extr->pl1 );
01079                         VJOIN1( hit_in_plane, hitp->hit_point, -alpha, extr->unit_h );
01080                         VSUB2( tmp, hit_in_plane, hitp->hit_vpriv );
01081                         VCROSS( tmp2, extr->pl1, tmp );
01082                         VCROSS( hitp->hit_normal, tmp2, extr->unit_h );
01083                         VUNITIZE( hitp->hit_normal );
01084                         break;
01085                 case BEZIER_SEG:
01086                 case -BEZIER_SEG:
01087                         MAT4X3VEC( hitp->hit_normal, extr->irot, hitp->hit_vpriv );
01088                         VUNITIZE( hitp->hit_normal );
01089                         break;
01090                 default:
01091                         bu_bomb( "ERROR: rt_extrude_norm(): unrecognized surf_no in hit structure!!!\n" );
01092                         break;
01093         }
01094         if( hitp->hit_surfno < 0 )
01095         {
01096                 if( VDOT( hitp->hit_normal, rp->r_dir ) < 0.0 )
01097                         VREVERSE( hitp->hit_normal, hitp->hit_normal );
01098         }
01099         else
01100         {
01101                 if( VDOT( hitp->hit_normal, rp->r_dir ) > 0.0 )
01102                         VREVERSE( hitp->hit_normal, hitp->hit_normal );
01103         }
01104 
01105 }
01106 
01107 /**
01108  *                      R T _ E X T R U D E _ C U R V E
01109  *
01110  *  Return the curvature of the extrude.
01111  */
01112 void
01113 rt_extrude_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
01114 {
01115         struct extrude_specific *extr=(struct extrude_specific *)stp->st_specific;
01116         struct carc_seg *csg;
01117         fastf_t radius, a, b, a_sq, b_sq;
01118         fastf_t curvature, tmp, dota, dotb;
01119         fastf_t der;
01120         vect_t diff;
01121         vect_t ra, rb;
01122 
01123         switch( hitp->hit_surfno )
01124         {
01125                 case LINE_SEG:
01126                 case -LINE_SEG:
01127                         VMOVE( cvp->crv_pdir, hitp->hit_vpriv );
01128                         VUNITIZE( cvp->crv_pdir );
01129                         cvp->crv_c1 = cvp->crv_c2 = 0;
01130                         break;
01131                 case CARC_SEG:
01132                 case -CARC_SEG:
01133                         /* curvature for an ellipse (the rotated and projected circular arc) in XY-plane
01134                          * based on curvature for ellipse = |ra||rb|/(|derivative|**3)
01135                          */
01136                         csg = (struct carc_seg *)hitp->hit_private;
01137                         VCROSS( cvp->crv_pdir, extr->unit_h, hitp->hit_normal );
01138                         VSUB2( diff, hitp->hit_point, hitp->hit_vpriv );
01139                         if( csg->radius < 0.0 )
01140                                 radius = -csg->radius;
01141                         else
01142                                 radius = csg->radius;
01143                         VSCALE( ra, extr->rot_axis, radius );
01144                         VSCALE( rb, extr->perp, radius );
01145 
01146                         a_sq = MAG2SQ( ra );
01147                         b_sq = MAG2SQ( rb );
01148                         a = sqrt( a_sq );
01149                         b = sqrt( b_sq );
01150                         dota = VDOT( diff, ra );
01151                         dotb = VDOT( diff, rb );
01152                         tmp = (a_sq/(b_sq*b_sq))*dotb*dotb + (b_sq/(a_sq*a_sq))*dota*dota;
01153                         der = sqrt( tmp );
01154                         curvature = a*b/(der*der*der);
01155                         if( VDOT( hitp->hit_normal, diff ) > 0.0 )
01156                                 cvp->crv_c1 = curvature;
01157                         else
01158                                 cvp->crv_c1 = -curvature;
01159                         cvp->crv_c2 = 0;
01160                         break;
01161         }
01162 }
01163 
01164 /**
01165  *                      R T _ E X T R U D E _ U V
01166  *
01167  *  For a hit on the surface of an extrude, return the (u,v) coordinates
01168  *  of the hit point, 0 <= u,v <= 1.
01169  *  u = azimuth
01170  *  v = elevation
01171  */
01172 void
01173 rt_extrude_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
01174 {
01175 }
01176 
01177 /**
01178  *              R T _ E X T R U D E _ F R E E
01179  */
01180 void
01181 rt_extrude_free(register struct soltab *stp)
01182 {
01183         register struct extrude_specific *extrude =
01184                 (struct extrude_specific *)stp->st_specific;
01185 
01186         if( extrude->verts )
01187                 bu_free( (char *)extrude->verts, "extrude->verts" );
01188         rt_curve_free( &(extrude->crv) );
01189         bu_free( (char *)extrude, "extrude_specific" );
01190 }
01191 
01192 /**
01193  *                      R T _ E X T R U D E _ C L A S S
01194  */
01195 int
01196 rt_extrude_class(void)
01197 {
01198         return(0);
01199 }
01200 
01201 /**
01202  *                      R T _ E X T R U D E _ P L O T
01203  */
01204 int
01205 rt_extrude_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01206 {
01207         LOCAL struct rt_extrude_internal        *extrude_ip;
01208         struct curve                    *crv=(struct curve *)NULL;
01209         struct rt_sketch_internal       *sketch_ip;
01210         point_t                         end_of_h;
01211         int                             i1, i2, nused1, nused2;
01212         struct bn_vlist                 *vp1, *vp2, *vp2_start;
01213 
01214         RT_CK_DB_INTERNAL(ip);
01215         extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
01216         RT_EXTRUDE_CK_MAGIC(extrude_ip);
01217 
01218         if( !extrude_ip->skt )
01219         {
01220                 bu_log( "ERROR: no sketch to extrude!\n" );
01221                 RT_ADD_VLIST( vhead, extrude_ip->V, BN_VLIST_LINE_MOVE );
01222                 RT_ADD_VLIST( vhead, extrude_ip->V, BN_VLIST_LINE_DRAW );
01223                 return( 0 );
01224         }
01225 
01226         sketch_ip = extrude_ip->skt;
01227         RT_SKETCH_CK_MAGIC( sketch_ip );
01228 
01229         crv = &sketch_ip->skt_curve;
01230 
01231         /* empty sketch, nothing to do */
01232         if (crv->seg_count == 0)
01233         {
01234             if (extrude_ip->sketch_name) {
01235                 bu_log("Sketch [%s] is empty, nothing to draw\n", extrude_ip->sketch_name);
01236             } else {
01237                 bu_log("Unnamed sketch is empty, nothing to draw\n");
01238             }
01239             RT_ADD_VLIST( vhead, extrude_ip->V, BN_VLIST_LINE_MOVE );
01240             RT_ADD_VLIST( vhead, extrude_ip->V, BN_VLIST_LINE_DRAW );
01241             return( 0 );
01242         }
01243 
01244         /* plot bottom curve */
01245         vp1 = BU_LIST_LAST( bn_vlist, vhead );
01246         nused1 = vp1->nused;
01247         if( curve_to_vlist( vhead, ttol, extrude_ip->V, extrude_ip->u_vec, extrude_ip->v_vec, sketch_ip, crv ) )
01248         {
01249                 bu_log( "ERROR: sketch (%s) references non-existent vertices!\n",
01250                         extrude_ip->sketch_name );
01251                 return( -1 );
01252         }
01253 
01254         /* plot top curve */
01255         VADD2( end_of_h, extrude_ip->V, extrude_ip->h );
01256         vp2 = BU_LIST_LAST( bn_vlist, vhead );
01257         nused2 = vp2->nused;
01258         curve_to_vlist( vhead, ttol, end_of_h, extrude_ip->u_vec, extrude_ip->v_vec, sketch_ip, crv );
01259 
01260         /* plot connecting lines */
01261         vp2_start = vp2;
01262         i1 = nused1;
01263         if (i1 >= vp1->nused) {
01264             i1 = 0;
01265             vp1 = BU_LIST_NEXT( bn_vlist, &vp1->l );
01266         }
01267         i2 = nused2;
01268         if (i2 >= vp2->nused) {
01269             i2 = 0;
01270             vp2 = BU_LIST_NEXT( bn_vlist, &vp2->l );
01271             nused2--;
01272         }
01273 
01274         while( vp1 != vp2_start || (i1 < BN_VLIST_CHUNK && i2 < BN_VLIST_CHUNK && i1 != nused2) )
01275         {
01276                 RT_ADD_VLIST( vhead, vp1->pt[i1], BN_VLIST_LINE_MOVE );
01277                 RT_ADD_VLIST( vhead, vp2->pt[i2], BN_VLIST_LINE_DRAW );
01278                 i1++;
01279                 if( i1 >= vp1->nused )
01280                 {
01281                         i1 = 0;
01282                         vp1 = BU_LIST_NEXT( bn_vlist, &vp1->l );
01283                 }
01284                 i2++;
01285                 if( i2 >= vp2->nused )
01286                 {
01287                         i2 = 0;
01288                         vp2 = BU_LIST_NEXT( bn_vlist, &vp2->l );
01289                 }
01290         }
01291 
01292         return(0);
01293 }
01294 
01295 void
01296 get_indices( genptr_t seg, int *start, int *end )
01297 {
01298         struct carc_seg *csg;
01299         struct nurb_seg *nsg;
01300         struct bezier_seg *bsg;
01301         struct line_seg *lsg=(struct line_seg *)seg;
01302 
01303         switch (lsg->magic) {
01304                 case CURVE_LSEG_MAGIC:
01305                         *start = lsg->start;
01306                         *end = lsg->end;
01307                         break;
01308                 case CURVE_CARC_MAGIC:
01309                         csg = (struct carc_seg *)seg;
01310                         if( csg->radius < 0.0 ) {
01311                                 *start = csg->start;
01312                                 *end = *start;
01313                                 break;
01314                         }
01315                         *start = csg->start;
01316                         *end = csg->end;
01317                         break;
01318                 case CURVE_NURB_MAGIC:
01319                         nsg = (struct nurb_seg *)seg;
01320                         *start = nsg->ctl_points[0];
01321                         *end = nsg->ctl_points[nsg->c_size-1];
01322                         break;
01323                 case CURVE_BEZIER_MAGIC:
01324                         bsg = (struct bezier_seg *)seg;
01325                         *start = bsg->ctl_points[0];
01326                         *end = bsg->ctl_points[bsg->degree];
01327                         break;
01328         }
01329 }
01330 
01331 void
01332 get_seg_midpoint( genptr_t seg, struct rt_sketch_internal *skt, point2d_t pt )
01333 {
01334         struct edge_g_cnurb eg;
01335         point_t tmp_pt;
01336         struct line_seg *lsg;
01337         struct carc_seg *csg;
01338         struct nurb_seg *nsg;
01339         struct bezier_seg *bsg;
01340         long *lng;
01341         point2d_t *V;
01342         point2d_t pta;
01343         int i;
01344         int coords;
01345 
01346         lng = (long *)seg;
01347 
01348         switch( *lng )
01349                 {
01350                 case CURVE_LSEG_MAGIC:
01351                         lsg = (struct line_seg *)lng;
01352                         VADD2_2D( pta, skt->verts[lsg->start], skt->verts[lsg->end] );
01353                         VSCALE_2D( pt, pta, 0.5 );
01354                         break;
01355                 case CURVE_CARC_MAGIC:
01356                         csg = (struct carc_seg *)lng;
01357                         if( csg->radius < 0.0 ) {
01358                                 VMOVE_2D( pt, skt->verts[csg->start] );
01359                         } else {
01360                                 point2d_t start2d, end2d, mid_pt, s2m, dir, center2d;
01361                                 fastf_t tmp_len, len_sq, mid_ang, s2m_len_sq, cross_z;
01362                                 fastf_t start_ang, end_ang;
01363 
01364                                 /* this is an arc (not a full circle) */
01365                                 V2MOVE( start2d, skt->verts[csg->start] );
01366                                 V2MOVE( end2d, skt->verts[csg->end] );
01367                                 mid_pt[0] = (start2d[0] + end2d[0]) * 0.5;
01368                                 mid_pt[1] = (start2d[1] + end2d[1]) * 0.5;
01369                                 V2SUB2( s2m, mid_pt, start2d );
01370                                 dir[0] = -s2m[1];
01371                                 dir[1] = s2m[0];
01372                                 s2m_len_sq =  s2m[0]*s2m[0] + s2m[1]*s2m[1];
01373                                 if( s2m_len_sq < SMALL_FASTF ) {
01374                                         bu_log( "start and end points are too close together in circular arc of sketch\n" );
01375                                         break;
01376                                 }
01377                                 len_sq = csg->radius*csg->radius - s2m_len_sq;
01378                                 if( len_sq < 0.0 ) {
01379                                         bu_log( "Impossible radius for specified start and end points in circular arc\n");
01380                                         break;
01381                                 }
01382                                 tmp_len = sqrt( dir[0]*dir[0] + dir[1]*dir[1] );
01383                                 dir[0] = dir[0] / tmp_len;
01384                                 dir[1] = dir[1] / tmp_len;
01385                                 tmp_len = sqrt( len_sq );
01386                                 V2JOIN1( center2d, mid_pt, tmp_len, dir );
01387 
01388                                 /* check center location */
01389                                 cross_z = ( end2d[X] - start2d[X] )*( center2d[Y] - start2d[Y] ) -
01390                                         ( end2d[Y] - start2d[Y] )*( center2d[X] - start2d[X] );
01391                                 if( !(cross_z > 0.0 && csg->center_is_left) ) {
01392                                         V2JOIN1( center2d, mid_pt, -tmp_len, dir );
01393                                 }
01394                                 start_ang = atan2( start2d[Y]-center2d[Y], start2d[X]-center2d[X] );
01395                                 end_ang = atan2( end2d[Y]-center2d[Y], end2d[X]-center2d[X] );
01396                                 if( csg->orientation ) { /* clock-wise */
01397                                         while( end_ang > start_ang )
01398                                                 end_ang -= 2.0 * M_PI;
01399                                 }
01400                                 else { /* counter-clock-wise */
01401                                         while( end_ang < start_ang )
01402                                                 end_ang += 2.0 * M_PI;
01403                                 }
01404 
01405                                 /* get mid angle */
01406                                 mid_ang = (start_ang + end_ang ) * 0.5;
01407 
01408                                 /* calculate mid point */
01409                                 pt[X] = center2d[X] + csg->radius * cos( mid_ang );
01410                                 pt[Y] = center2d[Y] + csg->radius * sin( mid_ang );
01411                                         break;
01412                                 }
01413                         break;
01414                 case CURVE_NURB_MAGIC:
01415                         nsg = (struct nurb_seg *)lng;
01416 
01417                         eg.l.magic = NMG_EDGE_G_CNURB_MAGIC;
01418                         eg.order = nsg->order;
01419                         eg.k.k_size = nsg->k.k_size;
01420                         eg.k.knots = nsg->k.knots;
01421                         eg.c_size = nsg->c_size;
01422                         coords = 2 + RT_NURB_IS_PT_RATIONAL( nsg->pt_type );
01423                         eg.pt_type = RT_NURB_MAKE_PT_TYPE( coords, 2, RT_NURB_IS_PT_RATIONAL( nsg->pt_type ) );
01424                         eg.ctl_points = (fastf_t *)bu_malloc( nsg->c_size * coords * sizeof( fastf_t ), "eg.ctl_points" );
01425                         if( RT_NURB_IS_PT_RATIONAL( nsg->pt_type ) ) {
01426                                 for( i=0 ; i<nsg->c_size ; i++ ) {
01427                                         VMOVE_2D( &eg.ctl_points[i*coords], skt->verts[nsg->ctl_points[i]] );
01428                                         eg.ctl_points[(i+1)*coords - 1] = nsg->weights[i];
01429                                 }
01430                         }
01431                         else {
01432                                 for( i=0 ; i<nsg->c_size ; i++ ) {
01433                                         VMOVE_2D( &eg.ctl_points[i*coords], skt->verts[nsg->ctl_points[i]] );
01434                                 }
01435                         }
01436                         rt_nurb_c_eval( &eg, (nsg->k.knots[nsg->k.k_size-1] - nsg->k.knots[0]) * 0.5, tmp_pt );
01437                         if( RT_NURB_IS_PT_RATIONAL( nsg->pt_type ) ) {
01438                                 int j;
01439 
01440                                 for( j=0 ; j<coords-1 ; j++ )
01441                                         pt[j] = tmp_pt[j] / tmp_pt[coords-1];
01442                         } else {
01443                                 V2MOVE( pt, tmp_pt );
01444                         }
01445                         bu_free( (char *)eg.ctl_points, "eg.ctl_points" );
01446                         break;
01447                 case CURVE_BEZIER_MAGIC:
01448                         bsg = (struct bezier_seg *)lng;
01449                         V = (point2d_t *)bu_calloc( bsg->degree+1, sizeof( point2d_t ), "Bezier control points" );
01450                         for( i=0 ; i<= bsg->degree ; i++ ) {
01451                                 VMOVE_2D( V[i], skt->verts[bsg->ctl_points[i]] );
01452                         }
01453                         Bezier( V, bsg->degree, 0.51, NULL, NULL, pt, NULL );
01454                         bu_free( (char *)V, "Bezier control points" );
01455                         break;
01456                 default:
01457                         bu_bomb( "Unrecognized segment type in sketch\n");
01458                         break;
01459                 }
01460 }
01461 
01462 struct loop_inter {
01463         int                     which_loop;
01464         int                     vert_index;     /* index of vertex intersected, or -1 if no hit on a vertex */
01465         fastf_t                 dist;           /* hit distance */
01466         struct loop_inter       *next;
01467 };
01468 
01469 void
01470 isect_2D_loop_ray( point2d_t pta, point2d_t dir, struct bu_ptbl *loop, struct loop_inter **root,
01471                    int which_loop, struct rt_sketch_internal *ip, struct bn_tol *tol )
01472 {
01473         int i, j;
01474         int code;
01475         point2d_t norm;
01476         fastf_t dist[2];
01477 
01478         norm[0] = -dir[1];
01479         norm[1] = dir[0];
01480 
01481         for( i=0 ; i<BU_PTBL_END( loop ) ; i++ ) {
01482                 long *lng;
01483                 struct loop_inter *inter;
01484                 struct line_seg *lsg=NULL;
01485                 struct carc_seg *csg=NULL;
01486                 struct bezier_seg *bsg=NULL;
01487                 point2d_t d1;
01488                 point2d_t diff;
01489                 fastf_t radius;
01490                 point2d_t *verts;
01491                 point2d_t *intercept;
01492                 point2d_t *normal;
01493 
01494                 lng = BU_PTBL_GET( loop, i );
01495                 switch( *lng ) {
01496                         case CURVE_LSEG_MAGIC:
01497                                 lsg = (struct line_seg *)lng;
01498                                 V2SUB2( d1, ip->verts[lsg->end], ip->verts[lsg->start] );
01499                                 code = bn_isect_line2_lseg2( dist, pta, dir, ip->verts[lsg->start], d1, tol );
01500                                 if( code < 0 )
01501                                         break;
01502                                 if( code == 0 ) {
01503                                         /* edge is collinear with ray */
01504                                         /* add two intersections, one at each end vertex */
01505                                         inter = (struct loop_inter *)bu_calloc( sizeof( struct loop_inter ), 1,
01506                                                                                 "loop intersection" );
01507                                         inter->which_loop = which_loop;
01508                                         inter->vert_index = lsg->start;
01509                                         inter->dist = dist[0];
01510                                         inter->next = NULL;
01511                                         if( !(*root) ) {
01512                                                 (*root) = inter;
01513                                         } else {
01514                                                 inter->next = (*root);
01515                                                 (*root) = inter;
01516                                         }
01517                                         inter = (struct loop_inter *)bu_calloc( sizeof( struct loop_inter ), 1,
01518                                                                                 "loop intersection" );
01519                                         inter->which_loop = which_loop;
01520                                         inter->vert_index = lsg->end;
01521                                         inter->dist = dist[1];
01522                                         inter->next = NULL;
01523                                         inter->next = (*root);
01524                                         (*root) = inter;
01525                                 } else if( code == 1 ) {
01526                                         /* hit at start vertex */
01527                                         inter = (struct loop_inter *)bu_calloc( sizeof( struct loop_inter ), 1,
01528                                                                                 "loop intersection" );
01529                                         inter->which_loop = which_loop;
01530                                         inter->vert_index = lsg->start;
01531                                         inter->dist = dist[0];
01532                                         inter->next = NULL;
01533                                         if( !(*root) ) {
01534                                                 (*root) = inter;
01535                                         } else {
01536                                                 inter->next = (*root);
01537                                                 (*root) = inter;
01538                                         }
01539                                 } else if( code == 2 ) {
01540                                         /* hit at end vertex */
01541                                         inter = (struct loop_inter *)bu_calloc( sizeof( struct loop_inter ), 1,
01542                                                                                 "loop intersection" );
01543                                         inter->which_loop = which_loop;
01544                                         inter->vert_index = lsg->end;
01545                                         inter->dist = dist[0];
01546                                         inter->next = NULL;
01547                                         if( !(*root) ) {
01548                                                 (*root) = inter;
01549                                         } else {
01550                                                 inter->next = (*root);
01551                                                 (*root) = inter;
01552                                         }
01553                                 } else {
01554                                         /* hit on edge, not at a vertex */
01555                                         inter = (struct loop_inter *)bu_calloc( sizeof( struct loop_inter ), 1,
01556                                                                                 "loop intersection" );
01557                                         inter->which_loop = which_loop;
01558                                         inter->vert_index = -1;
01559                                         inter->dist = dist[0];
01560                                         inter->next = NULL;
01561                                         if( !(*root) ) {
01562                                                 (*root) = inter;
01563                                         } else {
01564                                                 inter->next = (*root);
01565                                                 (*root) = inter;
01566                                         }
01567                                 }
01568                                 break;
01569                         case CURVE_CARC_MAGIC:
01570                                 csg = (struct carc_seg *)lng;
01571                                 radius = csg->radius;
01572                                 if( csg->radius <= 0.0 ) {
01573                                         point2d_t ra, rb;
01574 
01575                                         V2SUB2( diff, ip->verts[csg->start], ip->verts[csg->end] );
01576                                         radius = sqrt( MAG2SQ( diff ) );
01577                                         ra[X] = radius;
01578                                         ra[Y] = 0.0;
01579                                         rb[X] = 0.0;
01580                                         rb[Y] = radius;
01581                                         code = isect_line2_ellipse( dist, pta, dir, ip->verts[csg->end],
01582                                                                     ra, rb );
01583 
01584                                         if( code <= 0 )
01585                                                 break;
01586                                         for( j=0 ; j<code ; j++ ) {
01587                                                 inter = (struct loop_inter *)bu_calloc( sizeof( struct loop_inter ), 1,
01588                                                                                 "loop intersection" );
01589                                                 inter->which_loop = which_loop;
01590                                                 inter->vert_index = -1;
01591                                                 inter->dist = dist[j];
01592                                                 inter->next = NULL;
01593                                                 if( !(*root) ) {
01594                                                         (*root) = inter;
01595                                                 } else {
01596                                                         inter->next = (*root);
01597                                                         (*root) = inter;
01598                                                 }
01599                                         }
01600 
01601                                 } else {
01602                                         point2d_t ra, rb;
01603                                         vect_t s2m, tmp_dir;
01604                                         point2d_t start2d, end2d, mid_pt, center2d;
01605                                         fastf_t s2m_len_sq, len_sq, tmp_len, cross_z;
01606 
01607                                         V2MOVE( start2d, ip->verts[csg->start] );
01608                                         V2MOVE( end2d, ip->verts[csg->end] );
01609                                         mid_pt[0] = (start2d[0] + end2d[0]) * 0.5;
01610                                         mid_pt[1] = (start2d[1] + end2d[1]) * 0.5;
01611                                         V2SUB2( s2m, mid_pt, start2d )
01612                                                 tmp_dir[0] = -s2m[1];
01613                                         tmp_dir[1] = s2m[0];
01614                                         s2m_len_sq =  s2m[0]*s2m[0] + s2m[1]*s2m[1];
01615                                         if( s2m_len_sq < SMALL_FASTF )
01616                                                 {
01617                                                         bu_log( "start and end points are too close together in circular arc of sketch\n" );
01618                                                         break;
01619                                                 }
01620                                         len_sq = radius*radius - s2m_len_sq;
01621                                         if( len_sq < 0.0 )
01622                                                 {
01623                                                         bu_log( "Impossible radius for specified start and end points in circular arc\n");
01624                                                         break;
01625                                                 }
01626                                         tmp_len = sqrt( tmp_dir[0]*tmp_dir[0] + tmp_dir[1]*tmp_dir[1] );
01627                                         tmp_dir[0] = tmp_dir[0] / tmp_len;
01628                                         tmp_dir[1] = tmp_dir[1] / tmp_len;
01629                                         tmp_len = sqrt( len_sq );
01630                                         V2JOIN1( center2d, mid_pt, tmp_len, tmp_dir )
01631 
01632                                                 /* check center location */
01633                                                 cross_z = ( end2d[X] - start2d[X] )*( center2d[Y] - start2d[Y] ) -
01634                                                 ( end2d[Y] - start2d[Y] )*( center2d[X] - start2d[X] );
01635                                         if( !(cross_z > 0.0 && csg->center_is_left) )
01636                                                 V2JOIN1( center2d, mid_pt, -tmp_len, tmp_dir );
01637 
01638                                         ra[X] = radius;
01639                                         ra[Y] = 0.0;
01640                                         rb[X] = 0.0;
01641                                         rb[Y] = radius;
01642                                         code = isect_line_earc( dist, pta, dir, center2d, ra, rb,
01643                                                                 norm, ip->verts[csg->start], ip->verts[csg->end],
01644                                                                 csg->orientation );
01645                                         if( code <= 0 )
01646                                                 break;
01647                                         for( j=0 ; j<code ; j++ ) {
01648                                                 inter = (struct loop_inter *)bu_calloc( sizeof( struct loop_inter ), 1,
01649                                                                                 "loop intersection" );
01650                                                 inter->which_loop = which_loop;
01651                                                 inter->vert_index = -1;
01652                                                 inter->dist = dist[j];
01653                                                 inter->next = NULL;
01654                                                 if( !(*root) ) {
01655                                                         (*root) = inter;
01656                                                 } else {
01657                                                         inter->next = (*root);
01658                                                         (*root) = inter;
01659                                                 }
01660                                         }
01661                                 }
01662                                 break;
01663                         case CURVE_BEZIER_MAGIC:
01664                                 bsg = (struct bezier_seg *)lng;
01665                                 intercept = NULL;
01666                                 normal = NULL;
01667                                 verts = (point2d_t *)bu_calloc( bsg->degree + 1, sizeof( point2d_t ), "Bezier verts" );
01668                                 for( j=0 ; j<=bsg->degree ; j++ ) {
01669                                         V2MOVE( verts[j], ip->verts[bsg->ctl_points[j]] );
01670                                 }
01671                                 code = FindRoots( verts, bsg->degree, &intercept, &normal, pta, dir, norm, 0, tol->dist );
01672                                 for( j=0 ; j<code ; j++ ) {
01673                                         V2SUB2( diff, intercept[j], pta );
01674                                         dist[0] = sqrt( MAG2SQ( diff ) );
01675                                         inter = (struct loop_inter *)bu_calloc( sizeof( struct loop_inter ), 1,
01676                                                                                 "loop intersection" );
01677                                         inter->which_loop = which_loop;
01678                                         inter->vert_index = -1;
01679                                         inter->dist = dist[0];
01680                                         inter->next = NULL;
01681                                         if( !(*root) ) {
01682                                                 (*root) = inter;
01683                                         } else {
01684                                                 inter->next = (*root);
01685                                                 (*root) = inter;
01686                                         }
01687                                 }
01688                                 if( (*intercept) )
01689                                         bu_free( (char *)intercept, "Bezier Intercepts" );
01690                                 if( (*normal) )
01691                                         bu_free( (char *)normal, "Bezier normals" );
01692                                 bu_free( ( char *)verts, "Bezier Ctl points" );
01693                                 break;
01694                         default:
01695                                 bu_log( "isect_2D_loop_ray: Unrecognized curve segment type x%x\n", *lng );
01696                                 bu_bomb( "isect_2D_loop_ray: Unrecognized curve segment type\n" );
01697                                 break;
01698                 }
01699         }
01700 }
01701 
01702 static void
01703 sort_intersections( struct loop_inter **root, struct bn_tol *tol )
01704 {
01705         struct loop_inter *ptr, *prev, *pprev;
01706         int done=0;
01707         fastf_t diff;
01708 
01709         /* eliminate any duplicates */
01710         ptr = (*root);
01711         while( ptr->next ) {
01712                 prev = ptr;
01713                 ptr = ptr->next;
01714                 if( ptr->vert_index > -1 && ptr->vert_index == prev->vert_index ) {
01715                         prev->next = ptr->next;
01716                         bu_free( (char *)ptr, "struct loop_inter" );
01717                         ptr = prev;
01718                 }
01719         }
01720 
01721         ptr = (*root);
01722         while( ptr->next ) {
01723                 prev = ptr;
01724                 ptr = ptr->next;
01725                 diff = fabs( ptr->dist - prev->dist );
01726                 if( diff < tol->dist ) {
01727                         prev->next = ptr->next;
01728                         bu_free( (char *)ptr, "struct loop_inter" );
01729                         ptr = prev;
01730                 }
01731         }
01732 
01733         while( !done ) {
01734                 done = 1;
01735                 ptr = (*root);
01736                 prev = NULL;
01737                 pprev = NULL;
01738                 while( ptr->next ) {
01739                         pprev = prev;
01740                         prev = ptr;
01741                         ptr = ptr->next;
01742                         if( ptr->dist < prev->dist ) {
01743                                 done = 0;
01744                                 if( pprev ) {
01745                                         prev->next = ptr->next;
01746                                         pprev->next = ptr;
01747                                         ptr->next = prev;
01748                                 } else {
01749                                         prev->next = ptr->next;
01750                                         ptr->next = prev;
01751                                         (*root) = ptr;
01752                                 }
01753                         }
01754                 }
01755         }
01756 }
01757 
01758 int
01759 classify_sketch_loops( struct bu_ptbl *loopa, struct bu_ptbl *loopb, struct rt_sketch_internal *ip )
01760 {
01761         struct loop_inter *inter_root=NULL, *ptr, *tmp;
01762         struct bn_tol tol;
01763         point2d_t pta, ptb;
01764         point2d_t dir;
01765         genptr_t seg;
01766         fastf_t inv_len;
01767         int loopa_count=0, loopb_count=0;
01768         int ret=UNKNOWN;
01769 
01770         BU_CK_PTBL( loopa );
01771         BU_CK_PTBL( loopb );
01772         RT_SKETCH_CK_MAGIC( ip );
01773 
01774         tol.magic = BN_TOL_MAGIC;
01775         tol.dist = 0.005;
01776         tol.dist_sq = tol.dist * tol.dist;
01777         tol.perp = 1.0e-5;;
01778         tol.para = 1.0 - tol.perp;
01779 
01780         /* find points on a midpoint of a segment for each loop */
01781         seg = (genptr_t)BU_PTBL_GET( loopa, 0 );
01782         get_seg_midpoint( seg, ip, pta );
01783         seg = (genptr_t)BU_PTBL_GET( loopb, 0 );
01784         get_seg_midpoint( seg, ip, ptb );
01785 
01786         V2SUB2( dir, ptb, pta );
01787         inv_len = 1.0 / sqrt( MAGSQ_2D( dir ) );
01788         V2SCALE( dir, dir, inv_len );
01789 
01790         /* intersect pta<->ptb line with both loops */
01791         isect_2D_loop_ray( pta, dir, loopa, &inter_root, LOOPA, ip, &tol );
01792         isect_2D_loop_ray( pta, dir, loopb, &inter_root, LOOPB, ip, &tol );
01793 
01794         sort_intersections( &inter_root, &tol );
01795 
01796         /* examine intercepts to determine loop relationship */
01797         ptr = inter_root;
01798         while( ptr ) {
01799                 tmp = ptr;
01800                 if( ret == UNKNOWN ) {
01801                         if( ptr->which_loop == LOOPA ) {
01802                                 loopa_count++;
01803                                 if( loopa_count && loopb_count ) {
01804                                         if( loopb_count % 2 ) {
01805                                                 ret = A_IN_B;
01806                                         } else {
01807                                                 ret = DISJOINT;
01808                                         }
01809                                 }
01810                         } else {
01811                                 loopb_count++;
01812                                 if( loopa_count && loopb_count ) {
01813                                         if( loopa_count % 2 ) {
01814                                                 ret = B_IN_A;
01815                                         } else {
01816                                                 ret = DISJOINT;
01817                                         }
01818                                 }
01819                         }
01820                 }
01821                 ptr = ptr->next;
01822                 bu_free( (char *)tmp, "loop intercept" );
01823         }
01824 
01825         return( ret );
01826 }
01827 
01828 /*
01829  *                      R T _ E X T R U D E _ T E S S
01830  *
01831  *  Returns -
01832  *      -1      failure
01833  *       0      OK.  *r points to nmgregion that holds this tessellation.
01834  */
01835 int
01836 rt_extrude_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01837 {
01838 #if 0
01839         return( -1 );
01840 #else
01841         struct bu_list                  vhead;
01842         struct shell                    *s;
01843         struct faceuse                  *fu;
01844         struct vertex                   ***verts;
01845         struct vertex                   **vertsa;
01846         int                             vert_count=0;
01847         struct rt_extrude_internal      *extrude_ip;
01848         struct rt_sketch_internal       *sketch_ip;
01849         struct curve                    *crv=(struct curve *)NULL;
01850         struct bu_ptbl                  *aloop=NULL, loops, **containing_loops, *outer_loop;
01851         int                             i, j, k;
01852         int                             *used_seg;
01853         struct bn_vlist                 *vlp;
01854         plane_t                         pl;
01855 
01856         RT_CK_DB_INTERNAL(ip);
01857         extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
01858         RT_EXTRUDE_CK_MAGIC(extrude_ip);
01859 
01860         if( !extrude_ip->skt )
01861         {
01862                 bu_log( "rt_extrude_tess: ERROR: no sketch for extrusion!!!!\n" );
01863                 return( -1 );
01864         }
01865 
01866         sketch_ip = extrude_ip->skt;
01867         RT_SKETCH_CK_MAGIC( sketch_ip );
01868 
01869         crv = &sketch_ip->skt_curve;
01870 
01871         if( crv->seg_count < 1 )
01872                 return( 0 );
01873 
01874         /* find all the loops */
01875         used_seg = (int *)bu_calloc( crv->seg_count, sizeof( int ), "used_seg" );
01876         bu_ptbl_init( &loops, 5, "loops" );
01877         for( i=0 ; i<crv->seg_count ; i++ ) {
01878                 genptr_t cur_seg;
01879                 int loop_start, loop_end;
01880                 int seg_start, seg_end;
01881 
01882                 if( used_seg[i] )
01883                         continue;
01884 
01885                 aloop = (struct bu_ptbl *)bu_calloc( 1, sizeof( struct bu_ptbl ), "aloop" );
01886                 bu_ptbl_init( aloop, 5, "aloop" );
01887 
01888                 bu_ptbl_ins( aloop, (long *)crv->segments[i] );
01889                 used_seg[i] = 1;
01890                 cur_seg = crv->segments[i];
01891                 get_indices( cur_seg, &loop_start, &loop_end );
01892 
01893                 while( loop_end != loop_start ) {
01894                         int j;
01895                         int added_seg;
01896 
01897                         added_seg = 0;
01898                         for( j=0 ; j<crv->seg_count ; j++ ) {
01899                                 if( used_seg[j] )
01900                                         continue;
01901 
01902                                 get_indices( crv->segments[j], &seg_start, &seg_end );
01903                                 if( seg_start != seg_end && seg_start == loop_end ) {
01904                                         added_seg++;
01905                                         bu_ptbl_ins( aloop, (long *)crv->segments[j] );
01906                                         used_seg[j] = 1;
01907                                         loop_end = seg_end;
01908                                         if( loop_start == loop_end )
01909                                                 break;
01910                                 }
01911                         }
01912                         if( !added_seg ) {
01913                                 bu_log( "rt_extrude_tess: A loop is not closed in sketch %s\n",
01914                                         extrude_ip->sketch_name );
01915                                 bu_log( "\ttessellation failed!!\n" );
01916                                 for( j=0 ; j<BU_PTBL_END( &loops ) ; j++ ) {
01917                                         aloop = (struct bu_ptbl *)BU_PTBL_GET( &loops, j );
01918                                         bu_ptbl_free( aloop );
01919                                         bu_free( (char *)aloop, "aloop" );
01920                                 }
01921                                 bu_ptbl_free( &loops );
01922                                 bu_free( ( char *)used_seg, "used_seg" );
01923                                 return( -2 );
01924                         }
01925                 }
01926                 bu_ptbl_ins( &loops, (long *)aloop );
01927         }
01928         bu_free( ( char *)used_seg, "used_seg" );
01929 
01930         /* sort the loops to find inside/outside relationships */
01931         containing_loops = (struct bu_ptbl **)bu_calloc( BU_PTBL_END( &loops ),
01932                                                          sizeof( struct bu_ptbl *), "containing_loops" );
01933         for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ ) {
01934                 containing_loops[i] = (struct bu_ptbl *)bu_calloc( 1, sizeof( struct bu_ptbl ), "containing_loops[i]" );
01935                 bu_ptbl_init( containing_loops[i], BU_PTBL_END( &loops ), "containing_loops[i]" );
01936         }
01937 
01938         for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ ) {
01939                 struct bu_ptbl *loopa;
01940                 int j;
01941 
01942                 loopa = (struct bu_ptbl *)BU_PTBL_GET( &loops, i );
01943                 for( j=i+1 ; j<BU_PTBL_END( &loops ) ; j++ ) {
01944                         struct bu_ptbl *loopb;
01945 
01946                         loopb = (struct bu_ptbl *)BU_PTBL_GET( &loops, j );
01947                         switch( classify_sketch_loops( loopa, loopb, sketch_ip ) ) {
01948                                 case A_IN_B:
01949                                         bu_ptbl_ins( containing_loops[i], (long *)loopb );
01950                                         break;
01951                                 case B_IN_A:
01952                                         bu_ptbl_ins( containing_loops[j], (long *)loopa );
01953                                         break;
01954                                 case DISJOINT:
01955                                         break;
01956                                 default:
01957                                         bu_log( "rt_extrude_tess: Failed to classify loops!!\n" );
01958                                         goto failed;
01959                         }
01960                 }
01961         }
01962 
01963         /* make loops */
01964 
01965         /* find an outermost loop */
01966         outer_loop = (struct bu_ptbl *)NULL;
01967         for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ ) {
01968                 if( BU_PTBL_END( containing_loops[i] ) == 0 ) {
01969                         outer_loop = (struct bu_ptbl *)BU_PTBL_GET( &loops, i );
01970                         break;
01971                 }
01972         }
01973 
01974         if( !outer_loop ) {
01975                 bu_log( "No outer loop in sketch %s\n", extrude_ip->sketch_name );
01976                 bu_log( "\ttessellation failed\n" );
01977                 for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ ) {
01978                 }
01979                 for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ ) {
01980                         aloop = (struct bu_ptbl *)BU_PTBL_GET( &loops, i );
01981                         bu_ptbl_free( aloop );
01982                         bu_free( (char *)aloop, "aloop" );
01983                         bu_ptbl_free( containing_loops[i] );
01984                         bu_free( (char *)containing_loops[i], "aloop" );
01985                 }
01986                 bu_ptbl_free( &loops );
01987                 bu_free( (char *)containing_loops, "containing_loops" );
01988         }
01989 
01990         BU_LIST_INIT( &vhead );
01991         if( BU_LIST_UNINITIALIZED( &rt_g.rtg_vlfree ) ) {
01992                 BU_LIST_INIT( &rt_g.rtg_vlfree );
01993         }
01994         for( i=0 ; i<BU_PTBL_END( outer_loop ) ; i++ ) {
01995                 genptr_t seg;
01996 
01997                 seg = (genptr_t)BU_PTBL_GET( outer_loop, i );
01998                 if( seg_to_vlist( &vhead, ttol, extrude_ip->V, extrude_ip->u_vec, extrude_ip->v_vec, sketch_ip, seg ) )
01999                         goto failed;
02000         }
02001 
02002         /* count vertices */
02003         vert_count = 0;
02004         for( BU_LIST_FOR( vlp, bn_vlist, &vhead ) ) {
02005                 for( i=0 ; i<vlp->nused ; i++ ) {
02006                         if( vlp->cmd[i] == BN_VLIST_LINE_DRAW )
02007                                 vert_count++;
02008                 }
02009         }
02010 
02011         *r = nmg_mrsv( m );
02012         s = BU_LIST_FIRST( shell, &((*r)->s_hd) );
02013 
02014         /* make initial face from outer_loop */
02015         verts = (struct vertex ***)bu_calloc( vert_count, sizeof( struct vertex **), "verts" );
02016         for( i=0 ; i<vert_count ; i++ ) {
02017                 verts[i] = (struct vertex **)bu_calloc( 1, sizeof( struct vertex *), "verts[i]" );
02018         }
02019 
02020         fu = nmg_cmface( s, verts, vert_count );
02021         j = 0;
02022         for( BU_LIST_FOR( vlp, bn_vlist, &vhead ) ) {
02023                 for( i=0 ; i<vlp->nused ; i++ ) {
02024                         if( vlp->cmd[i] == BN_VLIST_LINE_DRAW ) {
02025                                 nmg_vertex_gv( *verts[j], vlp->pt[i] );
02026                                 j++;
02027                         }
02028                 }
02029         }
02030         BN_FREE_VLIST( &rt_g.rtg_vlfree, &vhead );
02031 
02032         /* make sure face normal is in correct direction */
02033         bu_free( (char *)verts, "verts" );
02034         if( nmg_calc_face_plane( fu, pl ) ) {
02035                 bu_log( "Failed to calculate face plane for extrusion\n" );
02036                 return( -1 );
02037         }
02038         nmg_face_g( fu, pl );
02039         if( VDOT( pl, extrude_ip->h ) > 0.0 ) {
02040                 nmg_reverse_face( fu );
02041                 fu = fu->fumate_p;
02042         }
02043 
02044         /* add the rest of the loops */
02045         for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ ) {
02046                 int fdir;
02047                 vect_t cross;
02048                 fastf_t pt_count=0.0;
02049                 fastf_t dot;
02050                 int rev=0;
02051 
02052                 aloop = (struct bu_ptbl *)BU_PTBL_GET( &loops, i );
02053                 if( aloop == outer_loop )
02054                         continue;
02055 
02056                 if( BU_PTBL_END( containing_loops[i] ) % 2 ) {
02057                         fdir = OT_OPPOSITE;
02058                 } else {
02059                         fdir = OT_SAME;
02060                 }
02061 
02062                 for( j=0 ; j<BU_PTBL_END( aloop ) ; j++ ) {
02063                         genptr_t seg;
02064 
02065                         seg = (genptr_t)BU_PTBL_GET( aloop, j );
02066                         if( seg_to_vlist( &vhead, ttol, extrude_ip->V,
02067                                           extrude_ip->u_vec, extrude_ip->v_vec, sketch_ip, seg ) )
02068                                 goto failed;
02069                 }
02070 
02071                 /* calculate plane of this loop */
02072                 VSETALLN( pl, 0.0, 4 );
02073                 for( BU_LIST_FOR( vlp, bn_vlist, &vhead ) ) {
02074                         for( j=1 ; j<vlp->nused ; j++ ) {
02075                                 if( vlp->cmd[j] == BN_VLIST_LINE_DRAW ) {
02076                                         VCROSS( cross, vlp->pt[j-1], vlp->pt[j] );
02077                                         VADD2( pl, pl, cross );
02078                                 }
02079                         }
02080                 }
02081 
02082                 VUNITIZE( pl );
02083 
02084                 for( BU_LIST_FOR( vlp, bn_vlist, &vhead ) ) {
02085                         for( j=1 ; j<vlp->nused ; j++ ) {
02086                                 if( vlp->cmd[j] == BN_VLIST_LINE_DRAW ) {
02087                                         pl[3] += VDOT( pl, vlp->pt[j] );
02088                                         pt_count++;
02089                                 }
02090                         }
02091                 }
02092                 pl[3] /= pt_count;
02093 
02094                 dot = -VDOT( pl, extrude_ip->h );
02095                 rev = 0;
02096                 if( fdir == OT_SAME && dot < 0.0 )
02097                         rev = 1;
02098                 else if( fdir == OT_OPPOSITE && dot > 0.0 )
02099                         rev = 1;
02100 
02101                 vertsa = (struct vertex **)bu_calloc((int)pt_count, sizeof( struct vertex *), "verts" );
02102 
02103                 fu = nmg_add_loop_to_face( s, fu, vertsa, (int)pt_count, fdir );
02104 
02105                 k = 0;
02106                 for( BU_LIST_FOR( vlp, bn_vlist, &vhead ) ) {
02107                         for( j=1 ; j<vlp->nused ; j++ ) {
02108                                 if( vlp->cmd[j] == BN_VLIST_LINE_DRAW ) {
02109                                         if( rev ) {
02110                                                 nmg_vertex_gv( vertsa[(int)(pt_count) - k - 1], vlp->pt[j] );
02111                                         } else {
02112                                                 nmg_vertex_gv( vertsa[k], vlp->pt[j] );
02113                                         }
02114                                         k++;
02115                                 }
02116                         }
02117                 }
02118                 RT_FREE_VLIST( &vhead );
02119         }
02120 
02121         /* extrude this face */
02122         if( nmg_extrude_face( fu, extrude_ip->h, tol ) ) {
02123                 bu_log( "Failed to extrude face sketch\n" );
02124                 return( -1 );
02125         }
02126 
02127         nmg_region_a( *r, tol );
02128 
02129         return( 0 );
02130 
02131  failed:
02132         for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ ) {
02133                 bu_ptbl_free( containing_loops[i] );
02134                 bu_free( (char *)containing_loops[i], "containing_loops[i]" );
02135         }
02136         bu_free( (char *)containing_loops, "containing_loops" );
02137         bu_ptbl_free( aloop );
02138         bu_free( (char *)aloop, "aloop" );
02139         return( -1 );
02140 #endif
02141 }
02142 
02143 /**
02144  *                      R T _ E X T R U D E _ I M P O R T
02145  *
02146  *  Import an EXTRUDE from the database format to the internal format.
02147  *  Apply modeling transformations as well.
02148  */
02149 int
02150 rt_extrude_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip, struct resource *resp)
02151 {
02152         LOCAL struct rt_extrude_internal        *extrude_ip;
02153         struct rt_db_internal                   tmp_ip;
02154         struct directory                        *dp;
02155         char                                    *sketch_name;
02156         union record                            *rp;
02157         char                                    *ptr;
02158         point_t                                 tmp_vec;
02159 
02160         BU_CK_EXTERNAL( ep );
02161         rp = (union record *)ep->ext_buf;
02162         /* Check record type */
02163         if( rp->u_id != DBID_EXTR )  {
02164                 bu_log("rt_extrude_import: defective record\n");
02165                 return(-1);
02166         }
02167 
02168         RT_CK_DB_INTERNAL( ip );
02169         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
02170         ip->idb_type = ID_EXTRUDE;
02171         ip->idb_meth = &rt_functab[ID_EXTRUDE];
02172         ip->idb_ptr = bu_malloc( sizeof(struct rt_extrude_internal), "rt_extrude_internal");
02173         extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
02174         extrude_ip->magic = RT_EXTRUDE_INTERNAL_MAGIC;
02175 
02176         sketch_name = (char *)rp + sizeof( struct extr_rec );
02177         if( !dbip )
02178                 extrude_ip->skt = (struct rt_sketch_internal *)NULL;
02179         else if( (dp=db_lookup( dbip, sketch_name, LOOKUP_NOISY)) == DIR_NULL )
02180         {
02181                 bu_log( "rt_extrude_import: ERROR: Cannot find sketch (%.16s) for extrusion (%.16s)\n",
02182                         sketch_name, rp->extr.ex_name );
02183                 extrude_ip->skt = (struct rt_sketch_internal *)NULL;
02184         }
02185         else
02186         {
02187                 if( rt_db_get_internal( &tmp_ip, dp, dbip, bn_mat_identity, resp ) != ID_SKETCH )
02188                 {
02189                         bu_log( "rt_extrude_import: ERROR: Cannot import sketch (%.16s) for extrusion (%.16s)\n",
02190                                 sketch_name, rp->extr.ex_name );
02191                         bu_free( ip->idb_ptr, "extrusion" );
02192                         return( -1 );
02193                 }
02194                 else
02195                         extrude_ip->skt = (struct rt_sketch_internal *)tmp_ip.idb_ptr;
02196         }
02197 
02198         ntohd( (unsigned char *)tmp_vec, rp->extr.ex_V, ELEMENTS_PER_VECT );
02199         MAT4X3PNT( extrude_ip->V, mat, tmp_vec );
02200         ntohd( (unsigned char *)tmp_vec, rp->extr.ex_h, ELEMENTS_PER_VECT );
02201         MAT4X3VEC( extrude_ip->h, mat, tmp_vec );
02202         ntohd( (unsigned char *)tmp_vec, rp->extr.ex_uvec, ELEMENTS_PER_VECT );
02203         MAT4X3VEC( extrude_ip->u_vec, mat, tmp_vec );
02204         ntohd( (unsigned char *)tmp_vec, rp->extr.ex_vvec, ELEMENTS_PER_VECT );
02205         MAT4X3VEC( extrude_ip->v_vec, mat, tmp_vec );
02206         extrude_ip->keypoint = bu_glong( rp->extr.ex_key );
02207 
02208         ptr = (char *)rp;
02209         ptr += sizeof( struct extr_rec );
02210         extrude_ip->sketch_name = (char *)bu_calloc( 17, sizeof( char ), "Extrude sketch name" );
02211         strncpy( extrude_ip->sketch_name, ptr, 16 );
02212 
02213         return(0);                      /* OK */
02214 }
02215 
02216 /**
02217  *                      R T _ E X T R U D E _ E X P O R T
02218  *
02219  *  The name is added by the caller, in the usual place.
02220  */
02221 int
02222 rt_extrude_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
02223 {
02224         struct rt_extrude_internal      *extrude_ip;
02225         vect_t                          tmp_vec;
02226         union record                    *rec;
02227         unsigned char                   *ptr;
02228 
02229         RT_CK_DB_INTERNAL(ip);
02230         if( ip->idb_type != ID_EXTRUDE )  return(-1);
02231         extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
02232         RT_EXTRUDE_CK_MAGIC(extrude_ip);
02233 
02234         BU_CK_EXTERNAL(ep);
02235         ep->ext_nbytes = 2*sizeof( union record );
02236         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "extrusion external");
02237         rec = (union record *)ep->ext_buf;
02238 
02239         rec->extr.ex_id = DBID_EXTR;
02240 
02241         VSCALE( tmp_vec, extrude_ip->V, local2mm );
02242         htond( rec->extr.ex_V, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT );
02243         VSCALE( tmp_vec, extrude_ip->h, local2mm );
02244         htond( rec->extr.ex_h, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT );
02245         VSCALE( tmp_vec, extrude_ip->u_vec, local2mm );
02246         htond( rec->extr.ex_uvec, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT );
02247         VSCALE( tmp_vec, extrude_ip->v_vec, local2mm );
02248         htond( rec->extr.ex_vvec, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT );
02249         bu_plong( rec->extr.ex_key, extrude_ip->keypoint );
02250         bu_plong( rec->extr.ex_count, 1 );
02251 
02252         ptr = (unsigned char *)rec;
02253         ptr += sizeof( struct extr_rec );
02254 
02255         strcpy( (char *)ptr, extrude_ip->sketch_name );
02256 
02257         return(0);
02258 }
02259 
02260 
02261 /**
02262  *                      R T _ E X T R U D E _ E X P O R T 5
02263  *
02264  *  The name is added by the caller, in the usual place.
02265  */
02266 int
02267 rt_extrude_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
02268 {
02269         struct rt_extrude_internal      *extrude_ip;
02270         vect_t                          tmp_vec[4];
02271         unsigned char                   *ptr;
02272 
02273         RT_CK_DB_INTERNAL(ip);
02274         if( ip->idb_type != ID_EXTRUDE )  return(-1);
02275 
02276         extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
02277         RT_EXTRUDE_CK_MAGIC(extrude_ip);
02278 
02279         BU_CK_EXTERNAL(ep);
02280         ep->ext_nbytes = 4 * ELEMENTS_PER_VECT * SIZEOF_NETWORK_DOUBLE + SIZEOF_NETWORK_LONG + strlen( extrude_ip->sketch_name ) + 1;
02281         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "extrusion external");
02282         ptr = (unsigned char *)ep->ext_buf;
02283 
02284         VSCALE( tmp_vec[0], extrude_ip->V, local2mm );
02285         VSCALE( tmp_vec[1], extrude_ip->h, local2mm );
02286         VSCALE( tmp_vec[2], extrude_ip->u_vec, local2mm );
02287         VSCALE( tmp_vec[3], extrude_ip->v_vec, local2mm );
02288         htond( ptr, (unsigned char *)tmp_vec, ELEMENTS_PER_VECT*4 );
02289         ptr += ELEMENTS_PER_VECT * 4 * SIZEOF_NETWORK_DOUBLE;
02290         bu_plong( ptr, extrude_ip->keypoint );
02291         ptr += SIZEOF_NETWORK_LONG;
02292         strcpy( (char *)ptr, extrude_ip->sketch_name );
02293 
02294         return(0);
02295 }
02296 
02297 
02298 /**
02299  *                      R T _ E X T R U D E _ I M P O R T 5
02300  *
02301  *  Import an EXTRUDE from the database format to the internal format.
02302  *  Apply modeling transformations as well.
02303  */
02304 int
02305 rt_extrude_import5(
02306         struct rt_db_internal           *ip,
02307         const struct bu_external        *ep,
02308         register const mat_t            mat,
02309         const struct db_i               *dbip,
02310         struct resource                 *resp,
02311         const int                       minor_type )
02312 {
02313         LOCAL struct rt_extrude_internal        *extrude_ip;
02314         struct rt_db_internal                   tmp_ip;
02315         struct directory                        *dp;
02316         char                                    *sketch_name;
02317         unsigned char                           *ptr;
02318         point_t                                 tmp_vec[4];
02319 
02320         BU_CK_EXTERNAL( ep );
02321 
02322         RT_CK_DB_INTERNAL( ip );
02323         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
02324         ip->idb_type = ID_EXTRUDE;
02325         ip->idb_meth = &rt_functab[ID_EXTRUDE];
02326         ip->idb_ptr = bu_malloc( sizeof(struct rt_extrude_internal), "rt_extrude_internal");
02327         extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
02328         extrude_ip->magic = RT_EXTRUDE_INTERNAL_MAGIC;
02329 
02330         ptr = (unsigned char *)ep->ext_buf;
02331         sketch_name = (char *)ptr + ELEMENTS_PER_VECT*4*SIZEOF_NETWORK_DOUBLE + SIZEOF_NETWORK_LONG;
02332         if( !dbip )
02333                 extrude_ip->skt = (struct rt_sketch_internal *)NULL;
02334         else if( (dp=db_lookup( dbip, sketch_name, LOOKUP_NOISY)) == DIR_NULL )
02335         {
02336                 bu_log( "rt_extrude_import: ERROR: Cannot find sketch (%s) for extrusion\n",
02337                         sketch_name );
02338                 extrude_ip->skt = (struct rt_sketch_internal *)NULL;
02339         }
02340         else
02341         {
02342                 if( rt_db_get_internal( &tmp_ip, dp, dbip, bn_mat_identity, resp ) != ID_SKETCH )
02343                 {
02344                         bu_log( "rt_extrude_import: ERROR: Cannot import sketch (%s) for extrusion\n",
02345                                 sketch_name );
02346                         bu_free( ip->idb_ptr, "extrusion" );
02347                         return( -1 );
02348                 }
02349                 else
02350                         extrude_ip->skt = (struct rt_sketch_internal *)tmp_ip.idb_ptr;
02351         }
02352 
02353         ntohd( (unsigned char *)tmp_vec, ptr, ELEMENTS_PER_VECT*4 );
02354         MAT4X3PNT( extrude_ip->V, mat, tmp_vec[0] );
02355         MAT4X3VEC( extrude_ip->h, mat, tmp_vec[1] );
02356         MAT4X3VEC( extrude_ip->u_vec, mat, tmp_vec[2] );
02357         MAT4X3VEC( extrude_ip->v_vec, mat, tmp_vec[3] );
02358         ptr += ELEMENTS_PER_VECT * 4 * SIZEOF_NETWORK_DOUBLE;
02359         extrude_ip->keypoint = bu_glong( ptr );
02360         ptr += SIZEOF_NETWORK_LONG;
02361         extrude_ip->sketch_name = bu_strdup( (const char *)ptr );
02362 
02363         return(0);                      /* OK */
02364 }
02365 
02366 /*8
02367  *                      R T _ E X T R U D E _ D E S C R I B E
02368  *
02369  *  Make human-readable formatted presentation of this solid.
02370  *  First line describes type of solid.
02371  *  Additional lines are indented one tab, and give parameter values.
02372  */
02373 int
02374 rt_extrude_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
02375 {
02376         register struct rt_extrude_internal     *extrude_ip =
02377                 (struct rt_extrude_internal *)ip->idb_ptr;
02378         char    buf[256];
02379         point_t V;
02380         vect_t h, u, v;
02381 
02382         RT_EXTRUDE_CK_MAGIC(extrude_ip);
02383         bu_vls_strcat( str, "2D extrude (EXTRUDE)\n");
02384         VSCALE( V, extrude_ip->V, mm2local );
02385         VSCALE( h, extrude_ip->h, mm2local );
02386         VSCALE( u, extrude_ip->u_vec, mm2local );
02387         VSCALE( v, extrude_ip->v_vec, mm2local );
02388         sprintf( buf, "\tV = (%g %g %g)\n\tH = (%g %g %g)\n\tu_dir = (%g %g %g)\n\tv_dir = (%g %g %g)\n",
02389                 V3INTCLAMPARGS( V ),
02390                 V3INTCLAMPARGS( h ),
02391                 V3INTCLAMPARGS( u ),
02392                 V3INTCLAMPARGS( v ) );
02393         bu_vls_strcat( str, buf );
02394         sprintf( buf, "\tsketch name: %s\n",
02395                 extrude_ip->sketch_name );
02396         bu_vls_strcat( str, buf );
02397 
02398 
02399         return(0);
02400 }
02401 
02402 /**
02403  *                      R T _ E X T R U D E _ I F R E E
02404  *
02405  *  Free the storage associated with the rt_db_internal version of this solid.
02406  */
02407 void
02408 rt_extrude_ifree(struct rt_db_internal *ip)
02409 {
02410         register struct rt_extrude_internal     *extrude_ip;
02411         struct rt_db_internal                   tmp_ip;
02412 
02413         RT_CK_DB_INTERNAL(ip);
02414         extrude_ip = (struct rt_extrude_internal *)ip->idb_ptr;
02415         RT_EXTRUDE_CK_MAGIC(extrude_ip);
02416         if( extrude_ip->skt )
02417         {
02418                 RT_INIT_DB_INTERNAL( &tmp_ip );
02419                 tmp_ip.idb_major_type = DB5_MAJORTYPE_BRLCAD;
02420                 tmp_ip.idb_type = ID_SKETCH;
02421                 tmp_ip.idb_ptr = (genptr_t)extrude_ip->skt;
02422                 tmp_ip.idb_meth = &rt_functab[ID_SKETCH];
02423                 rt_sketch_ifree( &tmp_ip );
02424         }
02425         extrude_ip->magic = 0;                  /* sanity */
02426 
02427         bu_free( extrude_ip->sketch_name, "Extrude sketch_name" );
02428         bu_free( (char *)extrude_ip, "extrude ifree" );
02429         ip->idb_ptr = GENPTR_NULL;      /* sanity */
02430 }
02431 
02432 int
02433 rt_extrude_xform(
02434         struct rt_db_internal *op,
02435         const mat_t mat,
02436         struct rt_db_internal *ip,
02437         int free,
02438         struct db_i *dbip,
02439         struct resource *resp)
02440 {
02441         struct rt_extrude_internal      *eip, *eop;
02442         point_t tmp_vec;
02443 
02444         RT_CK_DB_INTERNAL( ip );
02445         RT_CK_RESOURCE(resp)
02446         eip = (struct rt_extrude_internal *)ip->idb_ptr;
02447         RT_EXTRUDE_CK_MAGIC( eip );
02448 
02449         if( bu_debug&BU_DEBUG_MEM_CHECK )
02450         {
02451                 bu_log( "Barrier check at start of extrude_xform():\n" );
02452                 bu_mem_barriercheck();
02453         }
02454 
02455         if( op != ip )
02456         {
02457                 RT_INIT_DB_INTERNAL( op );
02458                 eop = (struct rt_extrude_internal *)bu_malloc( sizeof( struct rt_extrude_internal ), "eop" );
02459                 eop->magic = RT_EXTRUDE_INTERNAL_MAGIC;
02460                 eop->sketch_name = bu_strdup( eip->sketch_name );
02461                 op->idb_ptr = (genptr_t)eop;
02462                 op->idb_meth = &rt_functab[ID_EXTRUDE];
02463                 op->idb_major_type = DB5_MAJORTYPE_BRLCAD;
02464                 op->idb_type = ID_EXTRUDE;
02465                 if( ip->idb_avs.magic == BU_AVS_MAGIC ) {
02466                         bu_avs_init( &op->idb_avs, ip->idb_avs.count, "avs" );
02467                         bu_avs_merge( &op->idb_avs, &ip->idb_avs );
02468                 }
02469         }
02470         else
02471                 eop = (struct rt_extrude_internal *)ip->idb_ptr;
02472 
02473         MAT4X3PNT( tmp_vec, mat, eip->V );
02474         VMOVE( eop->V, tmp_vec );
02475         MAT4X3VEC( tmp_vec, mat, eip->h );
02476         VMOVE( eop->h, tmp_vec );
02477         MAT4X3VEC( tmp_vec, mat, eip->u_vec );
02478         VMOVE( eop->u_vec, tmp_vec );
02479         MAT4X3VEC( tmp_vec, mat, eip->v_vec );
02480         VMOVE( eop->v_vec, tmp_vec );
02481         eop->keypoint = eip->keypoint;
02482 
02483         if( free && ip != op )
02484         {
02485                 eop->skt = eip->skt;
02486                 eip->skt = (struct rt_sketch_internal *)NULL;
02487                 rt_db_free_internal( ip, resp );
02488         }
02489         else if( eip->skt )
02490                 eop->skt = rt_copy_sketch( eip->skt );
02491         else
02492                 eop->skt = (struct rt_sketch_internal *)NULL;
02493 
02494         if( bu_debug&BU_DEBUG_MEM_CHECK )
02495         {
02496                 bu_log( "Barrier check at end of extrude_xform():\n" );
02497                 bu_mem_barriercheck();
02498         }
02499 
02500         return( 0 );
02501 }
02502 
02503 int
02504 rt_extrude_tclform( const struct rt_functab *ftp, Tcl_Interp *interp )
02505 {
02506         RT_CK_FUNCTAB(ftp);
02507 
02508         Tcl_AppendResult( interp,
02509                           "V {%f %f %f} H {%f %f %f} A {%f %f %f} B {%f %f %f} S %s K %d", (char *)NULL );
02510 
02511         return TCL_OK;
02512 
02513 }
02514 
02515 int
02516 rt_extrude_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr)
02517 {
02518         register struct rt_extrude_internal *extr=(struct rt_extrude_internal *) intern->idb_ptr;
02519         Tcl_DString     ds;
02520         struct bu_vls   vls;
02521         int ret=TCL_OK;
02522 
02523         RT_EXTRUDE_CK_MAGIC( extr );
02524 
02525         Tcl_DStringInit( &ds );
02526         bu_vls_init( &vls );
02527 
02528 
02529         if( attr == (char *)NULL )
02530         {
02531                 bu_vls_strcpy( &vls, "extrude" );
02532                 bu_vls_printf( &vls, " V {%.25g %.25g %.25g}", V3ARGS( extr->V ) );
02533                 bu_vls_printf( &vls, " H {%.25g %.25g %.25g}", V3ARGS( extr->h ) );
02534                 bu_vls_printf( &vls, " A {%.25g %.25g %.25g}", V3ARGS( extr->u_vec ) );
02535                 bu_vls_printf( &vls, " B {%.25g %.25g %.25g}", V3ARGS( extr->v_vec ) );
02536                 bu_vls_printf( &vls, " S %s", extr->sketch_name );
02537                 bu_vls_printf( &vls, " K %d", extr->keypoint );
02538         }
02539         else if( *attr == 'V' )
02540                 bu_vls_printf( &vls, "%.25g %.25g %.25g", V3ARGS( extr->V ) );
02541         else if( *attr == 'H' )
02542                 bu_vls_printf( &vls, "%.25g %.25g %.25g", V3ARGS( extr->h ) );
02543         else if( *attr == 'A' )
02544                 bu_vls_printf( &vls, "%.25g %.25g %.25g", V3ARGS( extr->u_vec ) );
02545         else if( *attr == 'B' )
02546                 bu_vls_printf( &vls, "%.25g %.25g %.25g", V3ARGS( extr->v_vec ) );
02547         else if( *attr == 'S' )
02548                 bu_vls_printf( &vls, "%s", extr->sketch_name );
02549         else if( *attr == 'K' )
02550                 bu_vls_printf( &vls, "%d", extr->keypoint );
02551         else
02552         {
02553                 bu_vls_strcat( &vls, "ERROR: unrecognized attribute, must be V, H, A, B, S, or K!!!" );
02554                 ret = TCL_ERROR;
02555         }
02556 
02557         Tcl_DStringAppend( &ds, bu_vls_addr( &vls ), -1 );
02558         Tcl_DStringResult( interp, &ds );
02559         Tcl_DStringFree( &ds );
02560         bu_vls_free( &vls );
02561         return( ret );
02562 }
02563 
02564 int
02565 rt_extrude_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, char **argv)
02566 {
02567         struct rt_extrude_internal *extr;
02568         fastf_t *new;
02569         fastf_t len;
02570 
02571         RT_CK_DB_INTERNAL( intern );
02572         extr = (struct rt_extrude_internal *)intern->idb_ptr;
02573         RT_EXTRUDE_CK_MAGIC( extr );
02574 
02575         while( argc >= 2 )
02576         {
02577                 int array_len=3;
02578 
02579                 if( *argv[0] == 'V' )
02580                 {
02581                         new = extr->V;
02582                         if( tcl_list_to_fastf_array( interp, argv[1], &new, &array_len ) !=
02583                             array_len ) {
02584                                 Tcl_SetResult( interp,
02585                                       "ERROR: incorrect number of coordinates for vertex\n",
02586                                       TCL_STATIC );
02587                                 return( TCL_ERROR );
02588                         }
02589                 }
02590                 else if( *argv[0] == 'H' )
02591                 {
02592                         new = extr->h;
02593                         if( tcl_list_to_fastf_array( interp, argv[1], &new, &array_len ) !=
02594                             array_len ) {
02595                                 Tcl_SetResult( interp,
02596                                       "ERROR: incorrect number of coordinates for vector\n",
02597                                       TCL_STATIC );
02598                                 return( TCL_ERROR );
02599                         }
02600                 }
02601                 else if( *argv[0] == 'A' )
02602                 {
02603                         new = extr->u_vec;
02604                         if( tcl_list_to_fastf_array( interp, argv[1], &new, &array_len ) !=
02605                             array_len ) {
02606                                 Tcl_SetResult( interp,
02607                                       "ERROR: incorrect number of coordinates for vector\n",
02608                                       TCL_STATIC );
02609                                 return( TCL_ERROR );
02610                         }
02611 
02612                         /* insure that u_vec and v_vec are the same length */
02613                         len = MAGNITUDE( extr->u_vec );
02614                         VUNITIZE( extr->v_vec );
02615                         VSCALE( extr->v_vec, extr->v_vec, len );
02616                 }
02617                 else if( *argv[0] == 'B' )
02618                 {
02619                         new = extr->v_vec;
02620                         if( tcl_list_to_fastf_array( interp, argv[1], &new, &array_len ) !=
02621                             array_len ) {
02622                                 Tcl_SetResult( interp,
02623                                       "ERROR: incorrect number of coordinates for vector\n",
02624                                       TCL_STATIC );
02625                                 return( TCL_ERROR );
02626                         }
02627                         /* insure that u_vec and v_vec are the same length */
02628                         len = MAGNITUDE( extr->v_vec );
02629                         VUNITIZE( extr->u_vec );
02630                         VSCALE( extr->u_vec, extr->u_vec, len );
02631                 }
02632                 else if( *argv[0] =='K' )
02633                         extr->keypoint = atoi( argv[1] );
02634                 else if( *argv[0] == 'S' ) {
02635                         if( extr->sketch_name )
02636                                 bu_free( (char *)extr->sketch_name, "rt_extrude_tcladjust: sketch_name" );
02637                         extr->sketch_name = bu_strdup( argv[1] );
02638                 }
02639 
02640                 argc -= 2;
02641                 argv += 2;
02642         }
02643 
02644         return( TCL_OK );
02645 }
02646 
02647 
02648 
02649 
02650 
02651 /*@}*/
02652 
02653 /*
02654  * Local Variables:
02655  * mode: C
02656  * tab-width: 8
02657  * c-basic-offset: 4
02658  * indent-tabs-mode: t
02659  * End:
02660  * ex: shiftwidth=4 tabstop=8
02661  */

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