g_ars.c

Go to the documentation of this file.
00001 /*                         G _ A R S . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1985-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup g_  */
00023 
00024 /*@{*/
00025 /** @file g_ars.c
00026  *      Intersect a ray with an ARS (Arbitrary faceted solid).
00027  *
00028  *  Author -
00029  *      Michael John Muuss
00030  *
00031  *  Source -
00032  *      SECAD/VLD Computing Consortium, Bldg 394
00033  *      The U. S. Army Ballistic Research Laboratory
00034  *      Aberdeen Proving Ground, Maryland  21005
00035  *
00036  */
00037 
00038 #ifndef lint
00039 static const char RCSars[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_ars.c,v 14.12 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00040 #endif
00041 
00042 #include "common.h"
00043 
00044 #include <stdlib.h>
00045 #include <stdio.h>
00046 #ifdef HAVE_STRING_H
00047 #  include <string.h>
00048 #endif
00049 #include <math.h>
00050 #include <ctype.h>
00051 
00052 #include "machine.h"
00053 #include "tcl.h"
00054 #include "vmath.h"
00055 #include "db.h"
00056 #include "nmg.h"
00057 #include "raytrace.h"
00058 #include "rtgeom.h"
00059 #include "./debug.h"
00060 #include "./plane.h"
00061 #include "./bot.h"
00062 
00063 
00064 #define TRI_NULL        ((struct tri_specific *)0)
00065 
00066 /* Describe algorithm here */
00067 
00068 extern int rt_bot_minpieces;
00069 
00070 /* from g_bot.c */
00071 extern int rt_bot_prep( struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip );
00072 extern void rt_bot_ifree( struct rt_db_internal *ip );
00073 
00074 int rt_ars_tess( struct nmgregion **r, struct model *m, struct rt_db_internal *ip,
00075                  const struct rt_tess_tol *ttol, const struct bn_tol *tol );
00076 
00077 void
00078 rt_ars_free( register struct soltab *stp )
00079 {
00080     bu_bomb("rt_ars_free s/b rt_bot_free\n");
00081 }
00082 int
00083 rt_ars_class(const struct soltab        *stp,
00084              const vect_t               min,
00085              const vect_t               max,
00086              const struct bn_tol        *tol)
00087 {
00088     bu_bomb("rt_ars_class s/b rt_bot_class\n");
00089     return 0; /* not reached */
00090 }
00091 
00092 
00093 /**
00094  *                      R T _ A R S _ R D _ C U R V E
00095  *
00096  *  rt_ars_rd_curve() reads a set of ARS B records and returns a pointer
00097  *  to a malloc()'ed memory area of fastf_t's to hold the curve.
00098  */
00099 fastf_t *
00100 rt_ars_rd_curve(union record *rp, int npts)
00101 {
00102         LOCAL int lim;
00103         LOCAL fastf_t *base;
00104         register fastf_t *fp;           /* pointer to temp vector */
00105         register int i;
00106         LOCAL union record *rr;
00107         int     rec;
00108 
00109         /* Leave room for first point to be repeated */
00110         base = fp = (fastf_t *)bu_malloc(
00111             (npts+1) * sizeof(fastf_t) * ELEMENTS_PER_VECT,
00112             "ars curve" );
00113 
00114         rec = 0;
00115         for( ; npts > 0; npts -= 8 )  {
00116                 rr = &rp[rec++];
00117                 if( rr->b.b_id != ID_ARS_B )  {
00118                         bu_log("rt_ars_rd_curve():  non-ARS_B record!\n");
00119                         break;
00120                 }
00121                 lim = (npts>8) ? 8 : npts;
00122                 for( i=0; i<lim; i++ )  {
00123                         /* cvt from dbfloat_t */
00124                         VMOVE( fp, (&(rr->b.b_values[i*3])) );
00125                         fp += ELEMENTS_PER_VECT;
00126                 }
00127         }
00128         return( base );
00129 }
00130 
00131 
00132 
00133 
00134 /**
00135  *                      R T _ A R S _ I M P O R T
00136  *
00137  *  Read all the curves in as a two dimensional array.
00138  *  The caller is responsible for freeing the dynamic memory.
00139  *
00140  *  Note that in each curve array, the first point is replicated
00141  *  as the last point, to make processing the data easier.
00142  */
00143 int
00144 rt_ars_import(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
00145 {
00146         struct rt_ars_internal *ari;
00147         union record    *rp;
00148         register int    i, j;
00149         LOCAL vect_t    base_vect;
00150         int             currec;
00151 
00152         BU_CK_EXTERNAL( ep );
00153         rp = (union record *)ep->ext_buf;
00154         if( rp->u_id != ID_ARS_A )  {
00155                 bu_log("rt_ars_import: defective record\n");
00156                 return(-1);
00157         }
00158 
00159         RT_CK_DB_INTERNAL( ip );
00160         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00161         ip->idb_type = ID_ARS;
00162         ip->idb_meth = &rt_functab[ID_ARS];
00163         ip->idb_ptr = bu_malloc(sizeof(struct rt_ars_internal), "rt_ars_internal");
00164         ari = (struct rt_ars_internal *)ip->idb_ptr;
00165         ari->magic = RT_ARS_INTERNAL_MAGIC;
00166         ari->ncurves = rp[0].a.a_m;
00167         ari->pts_per_curve = rp[0].a.a_n;
00168 
00169         /*
00170          * Read all the curves into internal form.
00171          */
00172         ari->curves = (fastf_t **)bu_malloc(
00173                 (ari->ncurves+1) * sizeof(fastf_t **), "ars curve ptrs" );
00174         currec = 1;
00175         for( i=0; i < ari->ncurves; i++ )  {
00176                 ari->curves[i] =
00177                         rt_ars_rd_curve( &rp[currec], ari->pts_per_curve );
00178                 currec += (ari->pts_per_curve+7)/8;
00179         }
00180 
00181         /*
00182          * Convert from vector to point notation IN PLACE
00183          * by rotating vectors and adding base vector.
00184          * Observe special treatment for base vector.
00185          */
00186         for( i = 0; i < ari->ncurves; i++ )  {
00187                 register fastf_t *v;
00188 
00189                 v = ari->curves[i];
00190                 for( j = 0; j < ari->pts_per_curve; j++ )  {
00191                         LOCAL vect_t    homog;
00192 
00193                         if( i==0 && j == 0 )  {
00194                                 /* base vector */
00195                                 VMOVE( homog, v );
00196                                 MAT4X3PNT( base_vect, mat, homog );
00197                                 VMOVE( v, base_vect );
00198                         }  else  {
00199                                 MAT4X3VEC( homog, mat, v );
00200                                 VADD2( v, base_vect, homog );
00201                         }
00202                         v += ELEMENTS_PER_VECT;
00203                 }
00204                 VMOVE( v, ari->curves[i] );             /* replicate first point */
00205         }
00206         return( 0 );
00207 }
00208 
00209 /**
00210  *                      R T _ A R S _ E X P O R T
00211  *
00212  *  The name will be added by the caller.
00213  *  Generally, only libwdb will set conv2mm != 1.0
00214  */
00215 int
00216 rt_ars_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00217 {
00218         struct rt_ars_internal  *arip;
00219         union record            *rec;
00220         point_t         base_pt;
00221         int             per_curve_grans;
00222         int             cur;            /* current curve number */
00223         int             gno;            /* current granule number */
00224 
00225         RT_CK_DB_INTERNAL(ip);
00226         if( ip->idb_type != ID_ARS )  return(-1);
00227         arip = (struct rt_ars_internal *)ip->idb_ptr;
00228         RT_ARS_CK_MAGIC(arip);
00229 
00230         per_curve_grans = (arip->pts_per_curve+7)/8;
00231 
00232         BU_CK_EXTERNAL(ep);
00233         ep->ext_nbytes = (1 + per_curve_grans * arip->ncurves) *
00234                 sizeof(union record);
00235         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "ars external");
00236         rec = (union record *)ep->ext_buf;
00237 
00238         rec[0].a.a_id = ID_ARS_A;
00239         rec[0].a.a_type = ARS;                  /* obsolete? */
00240         rec[0].a.a_m = arip->ncurves;
00241         rec[0].a.a_n = arip->pts_per_curve;
00242         rec[0].a.a_curlen = per_curve_grans;
00243         rec[0].a.a_totlen = per_curve_grans * arip->ncurves;
00244 
00245         VMOVE( base_pt, &arip->curves[0][0] );
00246         gno = 1;
00247         for( cur=0; cur<arip->ncurves; cur++ )  {
00248                 register fastf_t        *fp;
00249                 int                     npts;
00250                 int                     left;
00251 
00252                 fp = arip->curves[cur];
00253                 left = arip->pts_per_curve;
00254                 for( npts=0; npts < arip->pts_per_curve; npts+=8, left -= 8 )  {
00255                         register int    el;
00256                         register int    lim;
00257                         register struct ars_ext *bp = &rec[gno].b;
00258 
00259                         bp->b_id = ID_ARS_B;
00260                         bp->b_type = ARSCONT;   /* obsolete? */
00261                         bp->b_n = cur+1;                /* obsolete? */
00262                         bp->b_ngranule = (npts/8)+1; /* obsolete? */
00263 
00264                         lim = (left > 8 ) ? 8 : left;
00265                         for( el=0; el < lim; el++ )  {
00266                                 vect_t  diff;
00267                                 if( cur==0 && npts==0 && el==0 )
00268                                         VSCALE( diff , fp , local2mm )
00269                                 else
00270                                         VSUB2SCALE( diff, fp, base_pt, local2mm )
00271                                 /* NOTE: also type converts to dbfloat_t */
00272                                 VMOVE( &(bp->b_values[el*3]), diff );
00273                                 fp += ELEMENTS_PER_VECT;
00274                         }
00275                         gno++;
00276                 }
00277         }
00278         return(0);
00279 }
00280 
00281 
00282 /**
00283  *                      R T _ A R S _ I M P O R T 5
00284  *
00285  *  Read all the curves in as a two dimensional array.
00286  *  The caller is responsible for freeing the dynamic memory.
00287  *
00288  *  Note that in each curve array, the first point is replicated
00289  *  as the last point, to make processing the data easier.
00290  */
00291 int
00292 rt_ars_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
00293 {
00294         struct rt_ars_internal *ari;
00295         register int            i, j;
00296         register unsigned char  *cp;
00297         vect_t                  tmp_vec;
00298         register fastf_t        *fp;
00299 
00300         BU_CK_EXTERNAL( ep );
00301         RT_CK_DB_INTERNAL( ip );
00302 
00303         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00304         ip->idb_type = ID_ARS;
00305         ip->idb_meth = &rt_functab[ID_ARS];
00306         ip->idb_ptr = bu_malloc(sizeof(struct rt_ars_internal), "rt_ars_internal");
00307 
00308         ari = (struct rt_ars_internal *)ip->idb_ptr;
00309         ari->magic = RT_ARS_INTERNAL_MAGIC;
00310 
00311         cp = (unsigned char *)ep->ext_buf;
00312         ari->ncurves = bu_glong( cp );
00313         cp += SIZEOF_NETWORK_LONG;
00314         ari->pts_per_curve = bu_glong( cp );
00315         cp += SIZEOF_NETWORK_LONG;
00316 
00317         /*
00318          * Read all the curves into internal form.
00319          */
00320         ari->curves = (fastf_t **)bu_calloc(
00321                 (ari->ncurves+1), sizeof(fastf_t *), "ars curve ptrs" );
00322         for( i=0; i < ari->ncurves; i++ )  {
00323                 ari->curves[i] = (fastf_t *)bu_calloc( (ari->pts_per_curve + 1) * 3,
00324                         sizeof( fastf_t ), "ARS points" );
00325                 fp = ari->curves[i];
00326                 for( j=0 ; j<ari->pts_per_curve ; j++ ) {
00327                         ntohd( (unsigned char *)tmp_vec, cp, 3 );
00328                         MAT4X3PNT( fp, mat, tmp_vec );
00329                         cp += 3 * SIZEOF_NETWORK_DOUBLE;
00330                         fp += ELEMENTS_PER_VECT;
00331                 }
00332                 VMOVE( fp, ari->curves[i] );    /* duplicate first point */
00333         }
00334         return( 0 );
00335 }
00336 
00337 /**
00338  *                      R T _ A R S _ E X P O R T 5
00339  *
00340  *  The name will be added by the caller.
00341  *  Generally, only libwdb will set conv2mm != 1.0
00342  */
00343 int
00344 rt_ars_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00345 {
00346         struct rt_ars_internal  *arip;
00347         unsigned char   *cp;
00348         vect_t          tmp_vec;
00349         int             cur;            /* current curve number */
00350 
00351         RT_CK_DB_INTERNAL(ip);
00352         if( ip->idb_type != ID_ARS )  return(-1);
00353         arip = (struct rt_ars_internal *)ip->idb_ptr;
00354         RT_ARS_CK_MAGIC(arip);
00355 
00356         BU_CK_EXTERNAL(ep);
00357         ep->ext_nbytes = 2 * SIZEOF_NETWORK_LONG +
00358                 3 * arip->ncurves * arip->pts_per_curve * SIZEOF_NETWORK_DOUBLE;
00359         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "ars external");
00360         cp = (unsigned char *)ep->ext_buf;
00361 
00362         (void)bu_plong( cp, arip->ncurves );
00363         cp += SIZEOF_NETWORK_LONG;
00364         (void)bu_plong( cp, arip->pts_per_curve );
00365         cp += SIZEOF_NETWORK_LONG;
00366 
00367         for( cur=0; cur<arip->ncurves; cur++ )  {
00368                 register fastf_t        *fp;
00369                 int                     npts;
00370 
00371                 fp = arip->curves[cur];
00372                 for( npts=0; npts < arip->pts_per_curve; npts++ )  {
00373                         VSCALE( tmp_vec, fp, local2mm );
00374                         ntohd( cp, (unsigned char *)tmp_vec, 3 );
00375                         cp += 3 * SIZEOF_NETWORK_DOUBLE;
00376                         fp += ELEMENTS_PER_VECT;
00377                 }
00378         }
00379         return(0);
00380 }
00381 
00382 /**
00383  *                      R T _ A R S _ D E S C R I B E
00384  *
00385  *  Make human-readable formatted presentation of this solid.
00386  *  First line describes type of solid.
00387  *  Additional lines are indented one tab, and give parameter values.
00388  */
00389 int
00390 rt_ars_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
00391 {
00392         register int                    j;
00393         register struct rt_ars_internal *arip =
00394                 (struct rt_ars_internal *)ip->idb_ptr;
00395         char                            buf[256];
00396         int                             i;
00397 
00398         RT_ARS_CK_MAGIC(arip);
00399         bu_vls_strcat( str, "arbitrary rectangular solid (ARS)\n");
00400 
00401         sprintf(buf, "\t%d curves, %d points per curve\n",
00402                 arip->ncurves, arip->pts_per_curve );
00403         bu_vls_strcat( str, buf );
00404 
00405         if( arip->ncurves > 0 ) {
00406                 sprintf(buf, "\tV (%g, %g, %g)\n",
00407                         INTCLAMP(arip->curves[0][X] * mm2local),
00408                         INTCLAMP(arip->curves[0][Y] * mm2local),
00409                         INTCLAMP(arip->curves[0][Z] * mm2local) );
00410                 bu_vls_strcat( str, buf );
00411         }
00412 
00413         if( !verbose )  return(0);
00414 
00415         /* Print out all the points */
00416         for( i=0; i < arip->ncurves; i++ )  {
00417                 register fastf_t *v = arip->curves[i];
00418 
00419                 sprintf( buf, "\tCurve %d:\n", i );
00420                 bu_vls_strcat( str, buf );
00421                 for( j=0; j < arip->pts_per_curve; j++ )  {
00422                         sprintf(buf, "\t\t(%g, %g, %g)\n",
00423                                 INTCLAMP(v[X] * mm2local),
00424                                 INTCLAMP(v[Y] * mm2local),
00425                                 INTCLAMP(v[Z] * mm2local) );
00426                         bu_vls_strcat( str, buf );
00427                         v += ELEMENTS_PER_VECT;
00428                 }
00429         }
00430 
00431         return(0);
00432 }
00433 
00434 /**
00435  *                      R T _ A R S _ I F R E E
00436  *
00437  *  Free the storage associated with the rt_db_internal version of this solid.
00438  */
00439 void
00440 rt_ars_ifree(struct rt_db_internal *ip)
00441 {
00442         register struct rt_ars_internal *arip;
00443         register int                    i;
00444 
00445         RT_CK_DB_INTERNAL(ip);
00446         arip = (struct rt_ars_internal *)ip->idb_ptr;
00447         RT_ARS_CK_MAGIC(arip);
00448 
00449         /*
00450          *  Free storage for faces
00451          */
00452         for( i = 0; i < arip->ncurves; i++ )  {
00453                 bu_free( (char *)arip->curves[i], "ars curve" );
00454         }
00455         bu_free( (char *)arip->curves, "ars curve ptrs" );
00456         arip->magic = 0;                /* sanity */
00457         arip->ncurves = 0;
00458         bu_free( (char *)arip, "ars ifree" );
00459         ip->idb_ptr = GENPTR_NULL;      /* sanity */
00460 }
00461 
00462 /**
00463  *                      R T _ A R S _ P R E P
00464  *
00465  *  This routine is used to prepare a list of planar faces for
00466  *  being shot at by the ars routines.
00467  *
00468  * Process an ARS, which is represented as a vector
00469  * from the origin to the first point, and many vectors
00470  * from the first point to the remaining points.
00471  *
00472  *  This routine is unusual in that it has to read additional
00473  *  database records to obtain all the necessary information.
00474  */
00475 int
00476 rt_ars_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00477 {
00478 #if 1
00479     struct rt_db_internal intern;
00480     struct rt_bot_internal *bot;
00481     struct model *m;
00482     struct nmgregion *r;
00483     struct shell *s;
00484     int ret;
00485 
00486     m = nmg_mm();
00487     r = BU_LIST_FIRST( nmgregion, &m->r_hd );
00488 
00489     if( rt_ars_tess( &r, m, ip, &rtip->rti_ttol, &rtip->rti_tol) ) {
00490             bu_log( "Failed to tessellate ARS (%s)\n", stp->st_dp->d_namep );
00491             nmg_km( m );
00492             return( -1 );
00493     }
00494     rt_ars_ifree( ip );
00495 
00496     s = BU_LIST_FIRST( shell, &r->s_hd );
00497     bot = nmg_bot( s, &rtip->rti_tol );
00498 
00499     if( !bot ) {
00500             bu_log( "Failed to convert ARS to BOT (%s)\n", stp->st_dp->d_namep );
00501             nmg_km( m );
00502             return( -1 );
00503     }
00504 
00505     nmg_km( m );
00506 
00507     intern.idb_magic = RT_DB_INTERNAL_MAGIC;
00508     intern.idb_major_type = DB5_MAJORTYPE_BRLCAD;
00509     intern.idb_minor_type = ID_BOT;
00510     intern.idb_meth = &rt_functab[ID_BOT];
00511     intern.idb_ptr = (genptr_t)bot;
00512     bu_avs_init( &intern.idb_avs, 0, "ARS to a BOT for prep" );
00513 
00514     ret = rt_bot_prep( stp, &intern, rtip );
00515 
00516     rt_bot_ifree( &intern );
00517 
00518     return( ret );
00519 #else
00520     LOCAL fastf_t       dx, dy, dz;     /* For finding the bounding spheres */
00521     int i, j, ntri;
00522     LOCAL fastf_t       f;
00523     struct rt_ars_internal      *arip;
00524     struct bot_specific *bot;
00525     const struct bn_tol         *tol = &rtip->rti_tol;
00526     int ncv;
00527 
00528     arip = (struct rt_ars_internal *)ip->idb_ptr;
00529     RT_ARS_CK_MAGIC(arip);
00530 
00531     /* initialize the Bag-'o-triangles structure we need */
00532     BU_GETSTRUCT( bot, bot_specific );
00533     stp->st_specific = (genptr_t)bot;
00534     bot->bot_mode = RT_BOT_SOLID;
00535     bot->bot_orientation = RT_BOT_UNORIENTED;
00536     bot->bot_errmode = (unsigned char)NULL;
00537     bot->bot_thickness = (fastf_t *)NULL;
00538     bot->bot_facemode = (struct bu_bitv *)NULL;
00539     bot->bot_facelist = (struct tri_specific *)NULL;
00540 
00541     /*
00542      * Compute bounding sphere.
00543      * Find min and max of the point co-ordinates.
00544      */
00545     VSETALL( stp->st_max, -INFINITY );
00546     VSETALL( stp->st_min,  INFINITY );
00547 
00548     for( i = 0; i < arip->ncurves; i++ )  {
00549         register fastf_t *v;
00550 
00551         v = arip->curves[i];
00552         for( j = 0; j < arip->pts_per_curve; j++ )  {
00553             VMINMAX( stp->st_min, stp->st_max, v );
00554             v += ELEMENTS_PER_VECT;
00555         }
00556     }
00557     VSET( stp->st_center,
00558           (stp->st_max[X] + stp->st_min[X])/2,
00559           (stp->st_max[Y] + stp->st_min[Y])/2,
00560           (stp->st_max[Z] + stp->st_min[Z])/2 );
00561 
00562     dx = (stp->st_max[X] - stp->st_min[X])/2;
00563     f = dx;
00564     dy = (stp->st_max[Y] - stp->st_min[Y])/2;
00565     if( dy > f )  f = dy;
00566     dz = (stp->st_max[Z] - stp->st_min[Z])/2;
00567     if( dz > f )  f = dz;
00568     stp->st_aradius = f;
00569     stp->st_bradius = sqrt(dx*dx + dy*dy + dz*dz);
00570 
00571 
00572     /*
00573      *  Compute planar faces
00574      *  Will examine curves[i][pts_per_curve], provided by rt_ars_rd_curve.
00575      */
00576     ncv = arip->ncurves-2;
00577     ntri = 0;
00578     for(i=0; i <= ncv; i++ )  {
00579         register fastf_t *v1, *v2;
00580 
00581         v1 = arip->curves[i];
00582         v2 = arip->curves[i+1];
00583         for( j = 0; j < arip->pts_per_curve;
00584              j++, v1 += ELEMENTS_PER_VECT, v2 += ELEMENTS_PER_VECT )  {
00585 
00586             /* XXX make sure the faces are actual triangles */
00587 
00588 
00589             /* carefully make faces, w/inward pointing normals */
00590             /* [0][0] [1][1], [0][1] */
00591             if (i != 0 &&
00592                 rt_botface(stp, bot, &v1[0], &v2[ELEMENTS_PER_VECT],
00593                            &v1[ELEMENTS_PER_VECT], ntri, tol) > 0)   ntri++;
00594 
00595             /* [1][0] [1][1] [0][0] */
00596             if (i < ncv &&
00597                 rt_botface(stp, bot, &v2[0], &v2[ELEMENTS_PER_VECT],
00598                            &v1[0], ntri, tol) > 0)   ntri++;
00599         }
00600     }
00601 
00602 
00603     if( bot->bot_facelist == (struct tri_specific *)0 )  {
00604         bu_log("ars(%s):  no faces\n", stp->st_name);
00605         return(-1);             /* BAD */
00606     }
00607 
00608     bot->bot_ntri = ntri;
00609 
00610 
00611     /*
00612      *  Support for solid 'pieces'
00613      *  For now, each triangle is considered a separate piece.
00614      *  These array allocations can't be made until the number of
00615      *  triangles are known.
00616      *
00617      *  If the number of triangles is too small,
00618      *  don't bother making pieces, the overhead isn't worth it.
00619      *
00620      *  To disable BoT pieces, on the RT command line specify:
00621      *  -c "set rt_bot_minpieces=0"
00622      */
00623     if( rt_bot_minpieces <= 0 )  return 0;
00624     if( ntri < rt_bot_minpieces )  return 0;
00625 
00626 
00627     rt_bot_prep_pieces(bot, stp, ntri, tol);
00628 
00629     rt_ars_ifree( ip );
00630 
00631 
00632     return(0);          /* OK */
00633 #endif
00634 }
00635 
00636 
00637 /**
00638  *                      R T _ A R S _ P R I N T
00639  */
00640 void
00641 rt_ars_print(register const struct soltab *stp)
00642 {
00643         register struct tri_specific *trip =
00644                 (struct tri_specific *)stp->st_specific;
00645 
00646         if( trip == TRI_NULL )  {
00647                 bu_log("ars(%s):  no faces\n", stp->st_name);
00648                 return;
00649         }
00650         do {
00651                 VPRINT( "A", trip->tri_A );
00652                 VPRINT( "B-A", trip->tri_BA );
00653                 VPRINT( "C-A", trip->tri_CA );
00654                 VPRINT( "BA x CA", trip->tri_wn );
00655                 VPRINT( "Normal", trip->tri_N );
00656                 bu_log("\n");
00657         } while( (trip = trip->tri_forw) );
00658 }
00659 
00660 /**
00661  *                      R T _ A R S _ S H O T
00662  *
00663  * Function -
00664  *      Shoot a ray at an ARS.
00665  *
00666  * Returns -
00667  *      0       MISS
00668  *      !0      HIT
00669  */
00670 int
00671 rt_ars_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00672 {
00673         register struct tri_specific *trip =
00674                 (struct tri_specific *)stp->st_specific;
00675 #define RT_ARS_MAXHITS 128              /* # surfaces hit, must be even */
00676         LOCAL struct hit hits[RT_ARS_MAXHITS];
00677         register struct hit *hp;
00678         LOCAL int       nhits;
00679 
00680         nhits = 0;
00681         hp = &hits[0];
00682 
00683         /* consider each face */
00684         for( ; trip; trip = trip->tri_forw )  {
00685                 FAST fastf_t    dn;             /* Direction dot Normal */
00686                 LOCAL fastf_t   abs_dn;
00687                 FAST fastf_t    k;
00688                 LOCAL fastf_t   alpha, beta;
00689                 LOCAL fastf_t   ds;
00690                 LOCAL vect_t    wxb;            /* vertex - ray_start */
00691                 LOCAL vect_t    xp;             /* wxb cross ray_dir */
00692 
00693                 /*
00694                  *  Ray Direction dot N.  (wn is inward pointing normal)
00695                  */
00696                 dn = VDOT( trip->tri_wn, rp->r_dir );
00697                 if( RT_G_DEBUG & DEBUG_ARB8 )
00698                         bu_log("N.Dir=%g ", dn );
00699 
00700                 /*
00701                  *  If ray lies directly along the face, drop this face.
00702                  */
00703                 abs_dn = dn >= 0.0 ? dn : (-dn);
00704                 if( abs_dn < 1.0e-10 )
00705                         continue;
00706                 VSUB2( wxb, trip->tri_A, rp->r_pt );
00707                 VCROSS( xp, wxb, rp->r_dir );
00708 
00709                 /* Check for exceeding along the one side */
00710                 alpha = VDOT( trip->tri_CA, xp );
00711                 if( dn < 0.0 )  alpha = -alpha;
00712                 if( alpha < 0.0 || alpha > abs_dn )
00713                         continue;
00714 
00715                 /* Check for exceeding along the other side */
00716                 beta = VDOT( trip->tri_BA, xp );
00717                 if( dn > 0.0 )  beta = -beta;
00718                 if( beta < 0.0 || beta > abs_dn )
00719                         continue;
00720                 if( alpha+beta > abs_dn )
00721                         continue;
00722                 ds = VDOT( wxb, trip->tri_wn );
00723                 k = ds / dn;            /* shot distance */
00724 
00725                 /* For hits other than the first one, might check
00726                  *  to see it this is approx. equal to previous one */
00727 
00728                 /*  If dn < 0, we should be entering the solid.
00729                  *  However, we just assume in/out sorting later will work.
00730                  */
00731                 hp->hit_magic = RT_HIT_MAGIC;
00732                 hp->hit_dist = k;
00733                 hp->hit_private = (char *)trip;
00734                 hp->hit_vpriv[X] = dn;
00735                 hp->hit_rayp = rp;
00736 
00737                 if(RT_G_DEBUG&DEBUG_ARB8) bu_log("ars: dist k=%g, ds=%g, dn=%g\n", k, ds, dn );
00738 
00739                 /* Bug fix: next line was "nhits++".  This caused rt_hitsort
00740                         to exceed bounds of "hits" array by one member and
00741                         clobber some stack variables i.e. "stp" -- GSM */
00742                 if( ++nhits >= RT_ARS_MAXHITS )  {
00743                         bu_log("ars(%s): too many hits\n", stp->st_name);
00744                         break;
00745                 }
00746                 hp++;
00747         }
00748         if( nhits == 0 )
00749                 return(0);              /* MISS */
00750 
00751         /* Sort hits, Near to Far */
00752         rt_hitsort( hits, nhits );
00753 
00754         /* Remove duplicate hits.
00755            We remove one of a pair of hits when they are
00756                 1) close together, and
00757                 2) both "entry" or both "exit" occurrences.
00758            Two immediate "entry" or two immediate "exit" hits suggest
00759            that we hit both of two joined faces, while we want to hit only
00760            one.  An "entry" followed by an "exit" (or vice versa) suggests
00761            that we grazed an edge, and thus we should leave both
00762            in the hit list. */
00763 
00764         {
00765                 register int i, j;
00766 
00767                 if( nhits )
00768                         RT_HIT_NORM( &hits[0], stp, 0 )
00769 
00770                 for( i=0 ; i<nhits-1 ; i++ )
00771                 {
00772                         fastf_t dist;
00773 
00774                         RT_HIT_NORM( &hits[i+1], stp, 0 )
00775                         dist = hits[i].hit_dist - hits[i+1].hit_dist;
00776                         if( NEAR_ZERO( dist, ap->a_rt_i->rti_tol.dist ) &&
00777                                 VDOT( hits[i].hit_normal, rp->r_dir ) *
00778                                 VDOT( hits[i+1].hit_normal, rp->r_dir) > 0)
00779                         {
00780                                 for( j=i ; j<nhits-1 ; j++ )
00781                                         hits[j] = hits[j+1];
00782                                 nhits--;
00783                                 i--;
00784                         }
00785                 }
00786         }
00787 
00788         if( nhits&1 )  {
00789                 register int i;
00790                 /*
00791                  * If this condition exists, it is almost certainly due to
00792                  * the dn==0 check above.  Just log error.
00793                  */
00794                 bu_log("ERROR: ars(%s): %d hits odd, skipping solid\n",
00795                         stp->st_name, nhits);
00796                 for(i=0; i < nhits; i++ )
00797                         bu_log("k=%g dn=%g\n",
00798                                 hits[i].hit_dist, hp->hit_vpriv[X]);
00799                 return(0);              /* MISS */
00800         }
00801 
00802         /* nhits is even, build segments */
00803         {
00804                 register struct seg *segp;
00805                 register int    i,j;
00806 
00807                 /* Check in/out properties */
00808                 for( i=nhits; i > 0; i -= 2 )  {
00809                         if( hits[i-2].hit_vpriv[X] >= 0 )
00810                                 continue;               /* seg_in */
00811                         if( hits[i-1].hit_vpriv[X] <= 0 )
00812                                 continue;               /* seg_out */
00813 
00814 #ifndef CONSERVATIVE
00815                         /* if this segment is small enough, just swap the in/out hits */
00816                         if( (hits[i-1].hit_dist - hits[i-2].hit_dist) < 200.0*RT_LEN_TOL )
00817                         {
00818                                 struct hit temp;
00819                                 fastf_t temp_dist;
00820 
00821                                 temp_dist = hits[i-1].hit_dist;
00822                                 hits[i-1].hit_dist = hits[i-2].hit_dist;
00823                                 hits[i-2].hit_dist = temp_dist;
00824 
00825                                 temp = hits[i-1];       /* struct copy */
00826                                 hits[i-1] = hits[i-2];  /* struct copy */
00827                                 hits[i-2] = temp;       /* struct copy */
00828                                 continue;
00829                         }
00830 #endif
00831                         bu_log("ars(%s): in/out error\n", stp->st_name );
00832                         for( j=nhits-1; j >= 0; j-- )  {
00833                                 bu_log("%d %s dist=%g dn=%g\n",
00834                                         j,
00835                                         ((hits[j].hit_vpriv[X] > 0) ?
00836                                                 " In" : "Out" ),
00837                                         hits[j].hit_dist,
00838                                         hits[j].hit_vpriv[X] );
00839                                 if( j>0 )
00840                                         bu_log( "\tseg length = %g\n", hits[j].hit_dist - hits[j-1].hit_dist );
00841                         }
00842 #ifdef CONSERVATIVE
00843                         return(0);
00844 #else
00845                         /* For now, just chatter, and return *something* */
00846                         break;
00847 #endif
00848                 }
00849 
00850                 for( i=nhits; i > 0; i -= 2 )  {
00851                         RT_GET_SEG(segp, ap->a_resource);
00852                         segp->seg_stp = stp;
00853                         segp->seg_in = hits[i-2];       /* struct copy */
00854                         segp->seg_out = hits[i-1];      /* struct copy */
00855                         BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00856                 }
00857         }
00858         return(nhits);                  /* HIT */
00859 }
00860 
00861 /**
00862  *                      R T _ H I T S O R T
00863  *
00864  *  Sort an array of hits into ascending order.
00865  */
00866 void
00867 rt_hitsort(register struct hit *h, register int nh)
00868 {
00869         register int i, j;
00870         LOCAL struct hit temp;
00871 
00872         for( i=0; i < nh-1; i++ )  {
00873                 for( j=i+1; j < nh; j++ )  {
00874                         if( h[i].hit_dist <= h[j].hit_dist )
00875                                 continue;
00876                         temp = h[j];            /* struct copy */
00877                         h[j] = h[i];            /* struct copy */
00878                         h[i] = temp;            /* struct copy */
00879                 }
00880         }
00881 }
00882 
00883 /**
00884  *                      R T _ A R S _ N O R M
00885  *
00886  *  Given ONE ray distance, return the normal and entry/exit point.
00887  */
00888 void
00889 rt_ars_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00890 {
00891         register struct tri_specific *trip =
00892                 (struct tri_specific *)hitp->hit_private;
00893 
00894         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
00895         VMOVE( hitp->hit_normal, trip->tri_N );
00896 }
00897 
00898 /**
00899  *                      R T _ A R S _ C U R V E
00900  *
00901  *  Return the "curvature" of the ARB face.
00902  *  Pick a principle direction orthogonal to normal, and
00903  *  indicate no curvature.
00904  */
00905 void
00906 rt_ars_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00907 {
00908 /*      register struct tri_specific *trip =
00909  *              (struct tri_specific *)hitp->hit_private;
00910  */
00911         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00912         cvp->crv_c1 = cvp->crv_c2 = 0;
00913 }
00914 
00915 /**
00916  *                      R T _ A R S _ U V
00917  *
00918  *  For a hit on a face of an ARB, return the (u,v) coordinates
00919  *  of the hit point.  0 <= u,v <= 1.
00920  *  u extends along the Xbasis direction defined by B-A,
00921  *  v extends along the "Ybasis" direction defined by (B-A)xN.
00922  */
00923 void
00924 rt_ars_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00925 {
00926         register struct tri_specific *trip =
00927                 (struct tri_specific *)hitp->hit_private;
00928         LOCAL vect_t P_A;
00929         LOCAL fastf_t r;
00930         LOCAL fastf_t xxlen, yylen;
00931 
00932         xxlen = MAGNITUDE(trip->tri_BA);
00933         yylen = MAGNITUDE(trip->tri_CA);
00934 
00935         VSUB2( P_A, hitp->hit_point, trip->tri_A );
00936         /* Flipping v is an artifact of how the faces are built */
00937         uvp->uv_u = VDOT( P_A, trip->tri_BA ) * xxlen;
00938         uvp->uv_v = 1.0 - ( VDOT( P_A, trip->tri_CA ) * yylen );
00939         if( uvp->uv_u < 0 || uvp->uv_v < 0 )  {
00940                 if( RT_G_DEBUG )
00941                         bu_log("rt_ars_uv: bad uv=%g,%g\n", uvp->uv_u, uvp->uv_v);
00942                 /* Fix it up */
00943                 if( uvp->uv_u < 0 )  uvp->uv_u = (-uvp->uv_u);
00944                 if( uvp->uv_v < 0 )  uvp->uv_v = (-uvp->uv_v);
00945         }
00946         r = ap->a_rbeam + ap->a_diverge * hitp->hit_dist;
00947         uvp->uv_du = r * xxlen;
00948         uvp->uv_dv = r * yylen;
00949 }
00950 
00951 
00952 /**
00953  *                      R T _ A R S _ P L O T
00954  */
00955 int
00956 rt_ars_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00957 {
00958         register int    i;
00959         register int    j;
00960         struct rt_ars_internal  *arip;
00961 
00962         RT_CK_DB_INTERNAL(ip);
00963         arip = (struct rt_ars_internal *)ip->idb_ptr;
00964         RT_ARS_CK_MAGIC(arip);
00965 
00966         /*
00967          *  Draw the "waterlines", by tracing each curve.
00968          *  n+1th point is first point replicated by code above.
00969          */
00970         for( i = 0; i < arip->ncurves; i++ )  {
00971                 register fastf_t *v1;
00972 
00973                 v1 = arip->curves[i];
00974                 RT_ADD_VLIST( vhead, v1, BN_VLIST_LINE_MOVE );
00975                 v1 += ELEMENTS_PER_VECT;
00976                 for( j = 1; j <= arip->pts_per_curve; j++, v1 += ELEMENTS_PER_VECT )
00977                         RT_ADD_VLIST( vhead, v1, BN_VLIST_LINE_DRAW );
00978         }
00979 
00980         /*
00981          *  Connect the Ith points on each curve, to make a mesh.
00982          */
00983         for( i = 0; i < arip->pts_per_curve; i++ )  {
00984                 RT_ADD_VLIST( vhead, &arip->curves[0][i*ELEMENTS_PER_VECT], BN_VLIST_LINE_MOVE );
00985                 for( j = 1; j < arip->ncurves; j++ )
00986                         RT_ADD_VLIST( vhead, &arip->curves[j][i*ELEMENTS_PER_VECT], BN_VLIST_LINE_DRAW );
00987         }
00988 
00989         return(0);
00990 }
00991 
00992 #define IJ(ii,jj)       (((i+(ii))*(arip->pts_per_curve+1))+(j+(jj)))
00993 #define ARS_PT(ii,jj)   (&arip->curves[i+(ii)][(j+(jj))*ELEMENTS_PER_VECT])
00994 #define FIND_IJ(a,b)    \
00995         if( !(verts[IJ(a,b)]) )  { \
00996                 verts[IJ(a,b)] = \
00997                 nmg_find_pt_in_shell( s, ARS_PT(a,b), tol ); \
00998         }
00999 #define ASSOC_GEOM(corn, a,b)   \
01000         if( !((*corners[corn])->vg_p) )  { \
01001                 nmg_vertex_gv( *(corners[corn]), ARS_PT(a,b) ); \
01002         }
01003 /**
01004  *                      R T _ A R S _ T E S S
01005  */
01006 int
01007 rt_ars_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01008 {
01009         register int    i;
01010         register int    j;
01011         register int    k;
01012         struct rt_ars_internal  *arip;
01013         struct shell    *s;
01014         struct vertex   **verts;
01015         struct faceuse  *fu;
01016         struct bu_ptbl  kill_fus;
01017         int             bad_ars=0;
01018 
01019         RT_CK_DB_INTERNAL(ip);
01020         arip = (struct rt_ars_internal *)ip->idb_ptr;
01021         RT_ARS_CK_MAGIC(arip);
01022 
01023         /* Check for a legal ARS */
01024         for( i = 0; i < arip->ncurves-1; i++ )
01025         {
01026                 for( j = 2; j < arip->pts_per_curve; j++ )
01027                 {
01028                         fastf_t dist;
01029                         vect_t pca;
01030                         int code;
01031 
01032                         if( VAPPROXEQUAL( ARS_PT(0,-2), ARS_PT(0,-1), tol->dist ) )
01033                                 continue;
01034 
01035                         code = bn_dist_pt3_lseg3( &dist, pca, ARS_PT(0,-2), ARS_PT(0,-1), ARS_PT(0,0), tol );
01036 
01037                         if( code < 2 )
01038                         {
01039                                 bu_log( "ARS curve backtracks on itself!!!\n" );
01040                                 bu_log( "\tCurve #%d, points #%d through %d are:\n", i, j-2, j );
01041                                 bu_log( "\t\t%d (%f %f %f)\n", j-2, V3ARGS( ARS_PT(0,-2) ) );
01042                                 bu_log( "\t\t%d (%f %f %f)\n", j-1, V3ARGS( ARS_PT(0,-1) ) );
01043                                 bu_log( "\t\t%d (%f %f %f)\n", j, V3ARGS( ARS_PT(0,0) ) );
01044                                 bad_ars = 1;
01045                                 j++;
01046                         }
01047                 }
01048         }
01049 
01050         if( bad_ars )
01051         {
01052                 bu_log( "TESSELATION FAILURE: This ARS solid has not been tesselated.\n\tAny result you may obtain is incorrect.\n" );
01053                 return( -1 );
01054         }
01055 
01056         bu_ptbl_init( &kill_fus, 64, " &kill_fus");
01057 
01058         /* Build the topology of the ARS.  Start by allocating storage */
01059 
01060         *r = nmg_mrsv( m );     /* Make region, empty shell, vertex */
01061         s = BU_LIST_FIRST(shell, &(*r)->s_hd);
01062 
01063         verts = (struct vertex **)bu_calloc( arip->ncurves * (arip->pts_per_curve+1),
01064                 sizeof(struct vertex *),
01065                 "rt_tor_tess *verts[]" );
01066 
01067         /*
01068          *  Draw the "waterlines", by tracing each curve.
01069          *  n+1th point is first point replicated by import code.
01070          */
01071         k = arip->pts_per_curve-2;      /* next to last point on curve */
01072         for( i = 0; i < arip->ncurves-1; i++ )  {
01073                 int double_ended;
01074 
01075                 if( k != 1 && VAPPROXEQUAL( &arip->curves[i][1*ELEMENTS_PER_VECT], &arip->curves[i][k*ELEMENTS_PER_VECT], tol->dist ) )
01076                         double_ended = 1;
01077                 else
01078                         double_ended = 0;
01079 
01080                 for( j = 0; j < arip->pts_per_curve; j++ )  {
01081                         struct vertex **corners[3];
01082 
01083 
01084                         if( double_ended &&
01085                              i != 0 &&
01086                              ( j == 0 || j == k || j == arip->pts_per_curve-1 ) )
01087                                         continue;
01088 
01089                         /*
01090                          *  First triangular face
01091                          */
01092                         if( bn_3pts_distinct( ARS_PT(0,0), ARS_PT(1,1),
01093                                 ARS_PT(0,1), tol )
01094                            && !bn_3pts_collinear( ARS_PT(0,0), ARS_PT(1,1),
01095                                 ARS_PT(0,1), tol )
01096                         )  {
01097                                 /* Locate these points, if previously mentioned */
01098                                 FIND_IJ(0, 0);
01099                                 FIND_IJ(1, 1);
01100                                 FIND_IJ(0, 1);
01101 
01102                                 /* Construct first face topology, CCW order */
01103                                 corners[0] = &verts[IJ(0,0)];
01104                                 corners[1] = &verts[IJ(0,1)];
01105                                 corners[2] = &verts[IJ(1,1)];
01106 
01107                                 if( (fu = nmg_cmface( s, corners, 3 )) == (struct faceuse *)0 )  {
01108                                         bu_log("rt_ars_tess() nmg_cmface failed, skipping face a[%d][%d]\n",
01109                                                 i,j);
01110                                 }
01111 
01112                                 /* Associate vertex geometry, if new */
01113                                 ASSOC_GEOM( 0, 0, 0 );
01114                                 ASSOC_GEOM( 1, 0, 1 );
01115                                 ASSOC_GEOM( 2, 1, 1 );
01116                                 if( nmg_calc_face_g( fu ) )
01117                                 {
01118                                         bu_log( "Degenerate face created, will kill it later\n" );
01119                                         bu_ptbl_ins( &kill_fus, (long *)fu );
01120                                 }
01121                         }
01122 
01123                         /*
01124                          *  Second triangular face
01125                          */
01126                         if( bn_3pts_distinct( ARS_PT(1,0), ARS_PT(1,1),
01127                                 ARS_PT(0,0), tol )
01128                            && !bn_3pts_collinear( ARS_PT(1,0), ARS_PT(1,1),
01129                                 ARS_PT(0,0), tol )
01130                         )  {
01131                                 /* Locate these points, if previously mentioned */
01132                                 FIND_IJ(1, 0);
01133                                 FIND_IJ(1, 1);
01134                                 FIND_IJ(0, 0);
01135 
01136                                 /* Construct second face topology, CCW */
01137                                 corners[0] = &verts[IJ(1,0)];
01138                                 corners[1] = &verts[IJ(0,0)];
01139                                 corners[2] = &verts[IJ(1,1)];
01140 
01141                                 if( (fu = nmg_cmface( s, corners, 3 )) == (struct faceuse *)0 )  {
01142                                         bu_log("rt_ars_tess() nmg_cmface failed, skipping face b[%d][%d]\n",
01143                                                 i,j);
01144                                 }
01145 
01146                                 /* Associate vertex geometry, if new */
01147                                 ASSOC_GEOM( 0, 1, 0 );
01148                                 ASSOC_GEOM( 1, 0, 0 );
01149                                 ASSOC_GEOM( 2, 1, 1 );
01150                                 if( nmg_calc_face_g( fu ) )
01151                                 {
01152                                         bu_log( "Degenerate face created, will kill it later\n" );
01153                                         bu_ptbl_ins( &kill_fus, (long *)fu );
01154                                 }
01155                         }
01156                 }
01157         }
01158 
01159         bu_free( (char *)verts, "rt_ars_tess *verts[]" );
01160 
01161         /* kill any degenerate faces that may have been created */
01162         for( i=0 ; i<BU_PTBL_END( &kill_fus ) ; i++ )
01163         {
01164                 fu = (struct faceuse *)BU_PTBL_GET( &kill_fus, i );
01165                 NMG_CK_FACEUSE( fu );
01166                 (void)nmg_kfu( fu );
01167         }
01168 
01169         /* ARS solids are often built with incorrect face normals.
01170          * Don't depend on them to be correct.
01171          */
01172         nmg_fix_normals( s , tol );
01173 
01174         /* set edge's is_real flag */
01175         nmg_mark_edges_real( &s->l.magic );
01176 
01177         /* Compute "geometry" for region and shell */
01178         nmg_region_a( *r, tol );
01179 
01180         return(0);
01181 }
01182 
01183 int
01184 rt_ars_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr)
01185 {
01186         register struct rt_ars_internal *ars=(struct rt_ars_internal *)intern->idb_ptr;
01187         Tcl_DString     ds;
01188         struct bu_vls   vls;
01189         int             i,j;
01190 
01191         RT_ARS_CK_MAGIC( ars );
01192 
01193         Tcl_DStringInit( &ds );
01194         bu_vls_init( &vls );
01195 
01196         if( attr == (char *)NULL ) {
01197                 bu_vls_strcpy( &vls, "ars" );
01198                 bu_vls_printf( &vls, " NC %d PPC %d", ars->ncurves, ars->pts_per_curve );
01199                 for( i=0 ; i<ars->ncurves ; i++ ) {
01200                         bu_vls_printf( &vls, " C%d {", i );
01201                         for( j=0 ; j<ars->pts_per_curve ; j++ ) {
01202                                 bu_vls_printf( &vls, " { %.25g %.25g %.25g }",
01203                                                V3ARGS( &ars->curves[i][j*3] ) );
01204                         }
01205                         bu_vls_printf( &vls, " }" );
01206                 }
01207         }
01208         else if( !strcmp( attr, "NC" ) ) {
01209                 bu_vls_printf( &vls, "%d", ars->ncurves );
01210         }
01211         else if( !strcmp( attr, "PPC" ) ) {
01212                 bu_vls_printf( &vls, "%d", ars->pts_per_curve );
01213         }
01214         else if( attr[0] == 'C' ) {
01215                 char *ptr;
01216 
01217                 if( attr[1] == '\0' ) {
01218                         /* all the curves */
01219                         for( i=0 ; i<ars->ncurves ; i++ ) {
01220                                 bu_vls_printf( &vls, " C%d {", i );
01221                                 for( j=0 ; j<ars->pts_per_curve ; j++ ) {
01222                                         bu_vls_printf( &vls, " { %.25g %.25g %.25g }",
01223                                                        V3ARGS( &ars->curves[i][j*3] ) );
01224                                 }
01225                                 bu_vls_printf( &vls, " }" );
01226                         }
01227                 }
01228                 else if( !isdigit( attr[1] ) ) {
01229                         Tcl_SetResult( interp,
01230                               "ERROR: illegal argument, must be NC, PPC, C, C#, or C#P#\n",
01231                               TCL_STATIC );
01232                         return( TCL_ERROR );
01233                 }
01234 
01235                 if( (ptr=strchr( attr, 'P' )) ) {
01236                         /* a specific point on a specific curve */
01237                         if( !isdigit( *(ptr+1) ) ) {
01238                            Tcl_SetResult( interp,
01239                                "ERROR: illegal argument, must be NC, PPC, C, C#, or C#P#\n",
01240                                 TCL_STATIC );
01241                            return( TCL_ERROR );
01242                         }
01243                         j = atoi( (ptr+1) );
01244                         *ptr = '\0';
01245                         i = atoi( &attr[1] );
01246                         bu_vls_printf( &vls, "%.25g %.25g %.25g",
01247                                  V3ARGS( &ars->curves[i][j*3] ) );
01248                 }
01249                 else {
01250                         /* the entire curve */
01251                         i = atoi( &attr[1] );
01252                         for( j=0 ; j<ars->pts_per_curve ; j++ ) {
01253                                 bu_vls_printf( &vls, " { %.25g %.25g %.25g }",
01254                                                V3ARGS( &ars->curves[i][j*3] ) );
01255                         }
01256                 }
01257         }
01258         Tcl_DStringAppend( &ds, bu_vls_addr( &vls ), -1 );
01259         Tcl_DStringResult( interp, &ds );
01260         Tcl_DStringFree( &ds );
01261         bu_vls_free( &vls );
01262         return( TCL_OK );
01263 }
01264 
01265 int
01266 rt_ars_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, char **argv)
01267 {
01268         struct rt_ars_internal          *ars;
01269         int                             i,j,k;
01270         int                             len;
01271         fastf_t                         *array;
01272 
01273         RT_CK_DB_INTERNAL( intern );
01274 
01275         ars = (struct rt_ars_internal *)intern->idb_ptr;
01276         RT_ARS_CK_MAGIC( ars );
01277 
01278         while( argc >= 2 ) {
01279                 if( !strcmp( argv[0], "NC" ) ) {
01280                         /* change number of curves */
01281                         i = atoi( argv[1] );
01282                         if( i < ars->ncurves ) {
01283                                 for( j=i ; j<ars->ncurves ; j++ )
01284                                         bu_free( (char *)ars->curves[j], "ars->curves[j]" );
01285                                 ars->curves = (fastf_t **)bu_realloc( ars->curves,
01286                                                     i*sizeof( fastf_t *), "ars->curves" );
01287                                 ars->ncurves = i;
01288                         }
01289                         else if( i > ars->ncurves ) {
01290                                 ars->curves = (fastf_t **)bu_realloc( ars->curves,
01291                                                     i*sizeof( fastf_t *), "ars->curves" );
01292                                 if( ars->pts_per_curve ) {
01293                                         /* new curves are duplicates of the last */
01294                                         for( j=ars->ncurves ; j<i ; j++ ) {
01295                                             ars->curves[j] = (fastf_t *)bu_malloc(
01296                                                  ars->pts_per_curve * 3 * sizeof( fastf_t ),
01297                                                                     "ars->curves[j]" );
01298                                             for( k=0 ; k<ars->pts_per_curve ; k++ ) {
01299                                                  if ( j ) {
01300                                                          VMOVE( &ars->curves[j][k*3],
01301                                                                 &ars->curves[j-1][k*3] );
01302                                                  }
01303                                                  else {
01304                                                          VSETALL(&ars->curves[j][k*3], 0.0);
01305                                                  }
01306                                             }
01307                                         }
01308                                 }
01309                                 else {
01310                                         for( j=ars->ncurves ; j<i ; j++ ) {
01311                                                 ars->curves[j] = NULL;
01312                                         }
01313                                 }
01314                                 ars->ncurves = i;
01315                         }
01316                 }
01317                 else if( !strcmp( argv[0], "PPC" ) ) {
01318                         /* change the number of points per curve */
01319                         i = atoi( argv[1] );
01320                         if( i < 3 ) {
01321                                 Tcl_SetResult( interp,
01322                                       "ERROR: must have at least 3 points per curve\n",
01323                                       TCL_STATIC );
01324                                 return( TCL_ERROR );
01325                         }
01326                         if( i < ars->pts_per_curve ) {
01327                                 for( j=0 ; j<ars->ncurves ; j++ ) {
01328                                         ars->curves[j] = bu_realloc( ars->curves[j],
01329                                                     i * 3 * sizeof( fastf_t ),
01330                                                     "ars->curves[j]" );
01331                                 }
01332                                 ars->pts_per_curve = i;
01333                         }
01334                         else if( i > ars->pts_per_curve ) {
01335                                 for( j=0 ; j<ars->ncurves ; j++ ) {
01336                                         ars->curves[j] = bu_realloc( ars->curves[j],
01337                                                     i * 3 * sizeof( fastf_t ),
01338                                                     "ars->curves[j]" );
01339                                         /* new points are duplicates of last */
01340                                         for( k=ars->pts_per_curve ; k<i ; k++ ) {
01341                                                 if( k ) {
01342                                                         VMOVE( &ars->curves[j][k*3],
01343                                                                &ars->curves[j][(k-1)*3] );
01344                                                 }
01345                                                 else {
01346                                                         VSETALL( &ars->curves[j][k*3], 0 );
01347                                                 }
01348                                         }
01349                                 }
01350                                 ars->pts_per_curve = i;
01351                         }
01352                 }
01353                 else if( argv[0][0] == 'C' ) {
01354                         if( isdigit( argv[0][1] ) ) {
01355                                 char *ptr;
01356 
01357                                 /* a specific curve */
01358                                 if( (ptr=strchr( argv[0], 'P' )) ) {
01359                                         /* a specific point on this curve */
01360                                         i = atoi( &argv[0][1] );
01361                                         j = atoi( ptr+1 );
01362                                         len = 3;
01363                                         array = &ars->curves[i][j*3];
01364                                         if( tcl_list_to_fastf_array( interp, argv[1],
01365                                                    &array,
01366                                                    &len )!= len ) {
01367                                                 Tcl_SetResult( interp,
01368                                                     "WARNING: incorrect number of parameters provided for a point\n",
01369                                                        TCL_STATIC );
01370                                         }
01371                                 }
01372                                 else {
01373                                         /* one complete curve */
01374                                         i = atoi( &argv[0][1] );
01375                                         len = ars->pts_per_curve * 3;
01376                                         ptr = argv[1];
01377                                         while( *ptr ) {
01378                                                 if( *ptr == '{' || *ptr == '}' )
01379                                                         *ptr = ' ';
01380                                                 ptr++;
01381                                         }
01382                                         if( !ars->curves[i] ) {
01383                                                 ars->curves[i] = (fastf_t *)bu_calloc(
01384                                                                   ars->pts_per_curve * 3,
01385                                                                   sizeof( fastf_t ),
01386                                                                   "ars->curves[i]" );
01387                                         }
01388                                         if( tcl_list_to_fastf_array( interp, argv[1],
01389                                                    &ars->curves[i],
01390                                                    &len ) != len ) {
01391                                                 Tcl_SetResult( interp,
01392                                                     "WARNING: incorrect number of parameters provided for a curve\n",
01393                                                        TCL_STATIC );
01394                                         }
01395                                 }
01396                         }
01397                         else {
01398                                 Tcl_SetResult( interp,
01399                                   "ERROR: Illegal argument, must be NC, PPC, C#, or C#P#\n",
01400                                   TCL_STATIC );
01401                                 return( TCL_ERROR );
01402                         }
01403                 }
01404                 else {
01405                         Tcl_SetResult( interp,
01406                                  "ERROR: Illegal argument, must be NC, PPC, C#, or C#P#\n",
01407                                  TCL_STATIC );
01408                         return( TCL_ERROR );
01409                 }
01410                 argc -= 2;
01411                 argv += 2;
01412         }
01413 
01414         return( TCL_OK );
01415 }
01416 
01417 /*@}*/
01418 /*
01419  * Local Variables:
01420  * mode: C
01421  * tab-width: 8
01422  * c-basic-offset: 4
01423  * indent-tabs-mode: t
01424  * End:
01425  * ex: shiftwidth=4 tabstop=8
01426  */

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