g_arbn.c

Go to the documentation of this file.
00001 /*                        G _ A R B N . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1989-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_arbn.c
00026  *  Intersect a ray with an Arbitrary Regular Polyhedron with
00027  *      an arbitrary number of faces.
00028  *
00029  *  Author -
00030  *      Michael John Muuss
00031  *
00032  *  Source -
00033  *      SECAD/VLD Computing Consortium, Bldg 394
00034  *      The U. S. Army Ballistic Research Laboratory
00035  *      Aberdeen Proving Ground, Maryland  21005-5066
00036  *
00037  */
00038 
00039 #ifndef lint
00040 static const char RCSarbn[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_arbn.c,v 14.13 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00041 #endif
00042 
00043 #include "common.h"
00044 
00045 #include <stdlib.h>
00046 #include <stdio.h>
00047 #ifdef HAVE_STRING_H
00048 #  include <string.h>
00049 #endif
00050 #include <math.h>
00051 #include <ctype.h>
00052 
00053 #include "machine.h"
00054 #include "tcl.h"
00055 #include "vmath.h"
00056 #include "nmg.h"
00057 #include "db.h"
00058 #include "raytrace.h"
00059 #include "rtgeom.h"
00060 #include "./debug.h"
00061 
00062 
00063 BU_EXTERN(void rt_arbn_print, (const struct soltab *stp) );
00064 BU_EXTERN(void rt_arbn_ifree, (struct rt_db_internal *ip) );
00065 
00066 /**
00067  *                      R T _ A R B N _ P R E P
00068  *
00069  *  Returns -
00070  *       0      OK
00071  *      !0      failure
00072  */
00073 int
00074 rt_arbn_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00075 {
00076         struct rt_arbn_internal *aip;
00077         vect_t          work;
00078         fastf_t         f;
00079         register int    i;
00080         int             j;
00081         int             k;
00082         int             *used = (int *)0;       /* plane eqn use count */
00083         const struct bn_tol     *tol = &rtip->rti_tol;
00084 
00085         RT_CK_DB_INTERNAL( ip );
00086         aip = (struct rt_arbn_internal *)ip->idb_ptr;
00087         RT_ARBN_CK_MAGIC(aip);
00088 
00089         used = (int *)bu_malloc(aip->neqn*sizeof(int), "arbn used[]");
00090 
00091         /*
00092          *  ARBN must be convex.  Test for concavity.
00093          *  Byproduct is an enumeration of all the verticies,
00094          *  which are used to make the bounding RPP.
00095          */
00096 
00097         /* Zero face use counts */
00098         for( i=0; i<aip->neqn; i++ )  {
00099                 used[i] = 0;
00100         }
00101         for( i=0; i<aip->neqn-2; i++ )  {
00102                 for( j=i+1; j<aip->neqn-1; j++ )  {
00103                         double  dot;
00104 
00105                         /* If normals are parallel, no intersection */
00106                         dot = VDOT( aip->eqn[i], aip->eqn[j] );
00107                         if( BN_VECT_ARE_PARALLEL(dot, tol) )  continue;
00108 
00109                         /* Have an edge line, isect with higher numbered planes */
00110                         for( k=j+1; k<aip->neqn; k++ )  {
00111                                 register int    m;
00112                                 point_t         pt;
00113                                 int             next_k;
00114 
00115                                 next_k = 0;
00116 
00117                                 if( bn_mkpoint_3planes( pt, aip->eqn[i], aip->eqn[j], aip->eqn[k] ) < 0 )  continue;
00118 
00119                                 /* See if point is outside arb */
00120                                 for( m=0; m<aip->neqn; m++ )  {
00121                                         if( i==m || j==m || k==m )  continue;
00122                                         if( VDOT(pt, aip->eqn[m])-aip->eqn[m][3] > tol->dist )
00123                                         {
00124                                                 next_k = 1;
00125                                                 break;
00126                                         }
00127                                 }
00128                                 if( next_k != 0)  continue;
00129 
00130                                 VMINMAX( stp->st_min, stp->st_max, pt );
00131 
00132                                 /* Increment "face used" counts */
00133                                 used[i]++;
00134                                 used[j]++;
00135                                 used[k]++;
00136                         }
00137                 }
00138         }
00139 
00140         /* If any planes were not used, then arbn is not convex */
00141         for( i=0; i<aip->neqn; i++ )  {
00142                 if( used[i] != 0 )  continue;   /* face was used */
00143                 bu_log("arbn(%s) face %d unused, solid is not convex\n",
00144                         stp->st_name, i);
00145                 bu_free( (char *)used, "arbn used[]");
00146                 return(-1);             /* BAD */
00147         }
00148         bu_free( (char *)used, "arbn used[]");
00149 
00150         stp->st_specific = (genptr_t)aip;
00151         ip->idb_ptr = GENPTR_NULL;      /* indicate we stole it */
00152 
00153         VADD2SCALE( stp->st_center, stp->st_min, stp->st_max, 0.5 );
00154         VSUB2SCALE( work, stp->st_max, stp->st_min, 0.5 );
00155 
00156         f = work[X];
00157         if( work[Y] > f )  f = work[Y];
00158         if( work[Z] > f )  f = work[Z];
00159         stp->st_aradius = f;
00160         stp->st_bradius = MAGNITUDE(work);
00161         return(0);                      /* OK */
00162 }
00163 
00164 /**
00165  *                      R T _ A R B N _ P R I N T
00166  */
00167 void
00168 rt_arbn_print(register const struct soltab *stp)
00169 {
00170 }
00171 
00172 /**
00173  *                      R T _ A R B N _ S H O T
00174  *
00175  *  Intersect a ray with an ARBN.
00176  *  Find the largest "in" distance and the smallest "out" distance.
00177  *  Cyrus & Beck algorithm for convex polyhedra.
00178  *
00179  *  Returns -
00180  *      0       MISS
00181  *      >0      HIT
00182  */
00183 int
00184 rt_arbn_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00185 {
00186         register struct rt_arbn_internal        *aip =
00187                 (struct rt_arbn_internal *)stp->st_specific;
00188         register int    i;
00189         LOCAL int       iplane, oplane;
00190         LOCAL fastf_t   in, out;        /* ray in/out distances */
00191 
00192         in = -INFINITY;
00193         out = INFINITY;
00194         iplane = oplane = -1;
00195 
00196         for( i = aip->neqn-1; i >= 0; i-- )  {
00197                 FAST fastf_t    slant_factor;   /* Direction dot Normal */
00198                 FAST fastf_t    norm_dist;
00199                 FAST fastf_t    s;
00200 
00201                 norm_dist = VDOT( aip->eqn[i], rp->r_pt ) - aip->eqn[i][3];
00202                 if( (slant_factor = -VDOT( aip->eqn[i], rp->r_dir )) < -1.0e-10 )  {
00203                         /* exit point, when dir.N < 0.  out = min(out,s) */
00204                         if( out > (s = norm_dist/slant_factor) )  {
00205                                 out = s;
00206                                 oplane = i;
00207                         }
00208                 } else if ( slant_factor > 1.0e-10 )  {
00209                         /* entry point, when dir.N > 0.  in = max(in,s) */
00210                         if( in < (s = norm_dist/slant_factor) )  {
00211                                 in = s;
00212                                 iplane = i;
00213                         }
00214                 }  else  {
00215                         /* ray is parallel to plane when dir.N == 0.
00216                          * If it is outside the solid, stop now
00217                          * Allow very small amount of slop, to catch
00218                          * rays that lie very nearly in the plane of a face.
00219                          */
00220                         if( norm_dist > SQRT_SMALL_FASTF )
00221                                 return( 0 );    /* MISS */
00222                 }
00223                 if( in > out )
00224                         return( 0 );    /* MISS */
00225         }
00226 
00227         /* Validate */
00228         if( iplane == -1 || oplane == -1 )  {
00229                 bu_log("rt_arbn_shoot(%s): 1 hit => MISS\n",
00230                         stp->st_name);
00231                 return( 0 );    /* MISS */
00232         }
00233         if( in >= out || out >= INFINITY )
00234                 return( 0 );    /* MISS */
00235 
00236         {
00237                 register struct seg *segp;
00238 
00239                 RT_GET_SEG( segp, ap->a_resource );
00240                 segp->seg_stp = stp;
00241                 segp->seg_in.hit_dist = in;
00242                 segp->seg_in.hit_surfno = iplane;
00243 
00244                 segp->seg_out.hit_dist = out;
00245                 segp->seg_out.hit_surfno = oplane;
00246                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00247         }
00248         return(2);                      /* HIT */
00249 }
00250 
00251 /**
00252  *                      R T _ A R B N _ V S H O T
00253  */
00254 void
00255 rt_arbn_vshot(struct soltab **stp, struct xray **rp, struct seg *segp, int n, struct application *ap)
00256                                /* An array of solid pointers */
00257                                /* An array of ray pointers */
00258                                /* array of segs (results returned) */
00259                                /* Number of ray/object pairs */
00260 
00261 {
00262         rt_vstub( stp, rp, segp, n, ap );
00263 }
00264 
00265 /**
00266  *                      R T _ A R B N _ N O R M
00267  *
00268  *  Given ONE ray distance, return the normal and entry/exit point.
00269  */
00270 void
00271 rt_arbn_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00272 {
00273         register struct rt_arbn_internal *aip =
00274                 (struct rt_arbn_internal *)stp->st_specific;
00275         int     h;
00276 
00277         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
00278         h = hitp->hit_surfno;
00279         if( h < 0 || h > aip->neqn )  {
00280                 bu_log("rt_arbn_norm(%s): hit_surfno=%d?\n", h );
00281                 VSETALL( hitp->hit_normal, 0 );
00282                 return;
00283         }
00284         VMOVE( hitp->hit_normal, aip->eqn[h] );
00285 }
00286 
00287 /**
00288  *                      R T _ A R B N _ C U R V E
00289  *
00290  *  Return the "curvature" of the ARB face.
00291  *  Pick a principle direction orthogonal to normal, and
00292  *  indicate no curvature.
00293  */
00294 void
00295 rt_arbn_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00296 {
00297 
00298         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00299         cvp->crv_c1 = cvp->crv_c2 = 0;
00300 }
00301 
00302 /**
00303  *                      R T _ A R B N _ U V
00304  *
00305  *  For a hit on a face of an ARB, return the (u,v) coordinates
00306  *  of the hit point.  0 <= u,v <= 1.
00307  *  u extends along the arb_U direction defined by B-A,
00308  *  v extends along the arb_V direction defined by Nx(B-A).
00309  */
00310 void
00311 rt_arbn_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00312 {
00313         uvp->uv_u = uvp->uv_v = 0;
00314         uvp->uv_du = uvp->uv_dv = 0;
00315 }
00316 
00317 /**
00318  *                      R T _ A R B N _ F R E E
00319  */
00320 void
00321 rt_arbn_free(register struct soltab *stp)
00322 {
00323         register struct rt_arbn_internal *aip =
00324                 (struct rt_arbn_internal *)stp->st_specific;
00325 
00326         bu_free( (char *)aip->eqn, "rt_arbn_internal eqn[]");
00327         bu_free( (char *)aip, "rt_arbn_internal" );
00328 }
00329 
00330 /**
00331  *                      R T _ A R B N _ P L O T
00332  *
00333  *  Brute force through all possible plane intersections.
00334  *  Generate all edge lines, then intersect the line with all
00335  *  the other faces to find the vertices on that line.
00336  *  If the geometry is correct, there will be no more than two.
00337  *  While not the fastest strategy, this will produce an accurate
00338  *  plot without requiring extra bookkeeping.
00339  *  Note that the vectors will be drawn in no special order.
00340  */
00341 int
00342 rt_arbn_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00343 {
00344         register struct rt_arbn_internal        *aip;
00345         register int    i;
00346         register int    j;
00347         register int    k;
00348 
00349         RT_CK_DB_INTERNAL(ip);
00350         aip = (struct rt_arbn_internal *)ip->idb_ptr;
00351         RT_ARBN_CK_MAGIC(aip);
00352 
00353         for( i=0; i<aip->neqn-1; i++ )  {
00354                 for( j=i+1; j<aip->neqn; j++ )  {
00355                         double  dot;
00356                         int     point_count;    /* # points on this line */
00357                         point_t a,b;            /* start and end points */
00358                         vect_t  dist;
00359 
00360                         /* If normals are parallel, no intersection */
00361                         dot = VDOT( aip->eqn[i], aip->eqn[j] );
00362                         if( BN_VECT_ARE_PARALLEL(dot, tol) )  continue;
00363 
00364                         /* Have an edge line, isect with all other planes */
00365                         point_count = 0;
00366                         for( k=0; k<aip->neqn; k++ )  {
00367                                 register int    m;
00368                                 point_t         pt;
00369                                 int             next_k;
00370 
00371                                 next_k = 0;
00372 
00373                                 if( k==i || k==j )  continue;
00374                                 if( bn_mkpoint_3planes( pt, aip->eqn[i], aip->eqn[j], aip->eqn[k] ) < 0 )  continue;
00375 
00376                                 /* See if point is outside arb */
00377                                 for( m=0; m<aip->neqn; m++ )  {
00378                                         if( i==m || j==m || k==m )  continue;
00379                                         if( VDOT(pt, aip->eqn[m])-aip->eqn[m][3] > tol->dist )
00380                                         {
00381                                                 next_k = 1;
00382                                                 break;
00383                                         }
00384                                 }
00385 
00386                                 if( next_k != 0)  continue;
00387 
00388                                 if( point_count <= 0 )  {
00389                                         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_MOVE );
00390                                         VMOVE( a, pt );
00391                                 } else if( point_count == 1 )  {
00392                                         VSUB2( dist, pt, a );
00393                                         if( MAGSQ(dist) < tol->dist_sq )  continue;
00394                                         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );
00395                                         VMOVE( b, pt );
00396                                 } else {
00397                                         VSUB2( dist, pt, a );
00398                                         if( MAGSQ(dist) < tol->dist_sq )  continue;
00399                                         VSUB2( dist, pt, b );
00400                                         if( MAGSQ(dist) < tol->dist_sq )  continue;
00401                                         bu_log("rt_arbn_plot() error, point_count=%d (>2) on edge %d/%d, non-convex\n",
00402                                                 point_count+1,
00403                                                 i, j );
00404                                         VPRINT(" a", a);
00405                                         VPRINT(" b", b);
00406                                         VPRINT("pt", pt);
00407                                         RT_ADD_VLIST( vhead, pt, BN_VLIST_LINE_DRAW );  /* draw it */
00408                                 }
00409                                 point_count++;
00410                         }
00411                         /* Point counts of 1 are (generally) not harmful,
00412                          * occuring on pyramid peaks and the like.
00413                          */
00414                 }
00415         }
00416         return(0);
00417 }
00418 
00419 /**
00420  *                      R T _ A R B N _ C L A S S
00421  */
00422 int
00423 rt_arbn_class(void)
00424 {
00425         return(0);
00426 }
00427 
00428 
00429 /* structures used by arbn tessellator */
00430 struct arbn_pts
00431 {
00432         point_t         pt;             /* coordinates for vertex */
00433         int             plane_no[3];    /* which planes intersect here */
00434         struct vertex   **vp;           /* pointer to vertex struct pointer for NMG's */
00435 };
00436 struct arbn_edges
00437 {
00438         int             v1_no,v2_no;    /* index into arbn_pts for endpoints of edge */
00439 };
00440 
00441 #define         LOC(i,j)        i*(aip->neqn)+j
00442 
00443 static void
00444 Sort_edges(struct arbn_edges *edges, int *edge_count, const struct rt_arbn_internal *aip)
00445 {
00446         int face;
00447 
00448         for( face=0 ; face<aip->neqn ; face++ )
00449         {
00450                 int done=0;
00451                 int edge1,edge2;
00452 
00453                 if( edge_count[face] < 3 )
00454                         continue;       /* nothing to sort */
00455 
00456                 edge1 = 0;
00457                 edge2 = 0;
00458                 while( !done )
00459                 {
00460                         int edge3;
00461                         int tmp_v1,tmp_v2;
00462 
00463                         /* Look for out of order edge (edge2) */
00464                         while( ++edge2 < edge_count[face] &&
00465                                 edges[LOC(face,edge1)].v2_no == edges[LOC(face,edge2)].v1_no )
00466                                         edge1++;
00467                         if( edge2 == edge_count[face] )
00468                         {
00469                                 /* all edges are in order */
00470                                 done = 1;
00471                                 continue;
00472                         }
00473 
00474                         /* look for edge (edge3) that belongs where edge2 is */
00475                         edge3 = edge2 - 1;
00476                         while( ++edge3 < edge_count[face] &&
00477                                 edges[LOC(face,edge1)].v2_no != edges[LOC(face,edge3)].v1_no &&
00478                                 edges[LOC(face,edge1)].v2_no != edges[LOC(face,edge3)].v2_no );
00479 
00480                         if( edge3 == edge_count[face] )
00481                                 rt_bomb( "rt_arbn_tess: Sort_edges: Cannot find next edge in loop\n" );
00482 
00483                         if( edge2 != edge3 )
00484                         {
00485                                 /* swap edge2 and edge3 */
00486                                 tmp_v1 = edges[LOC(face,edge2)].v1_no;
00487                                 tmp_v2 = edges[LOC(face,edge2)].v2_no;
00488                                 edges[LOC(face,edge2)].v1_no = edges[LOC(face,edge3)].v1_no;
00489                                 edges[LOC(face,edge2)].v2_no = edges[LOC(face,edge3)].v2_no;
00490                                 edges[LOC(face,edge3)].v1_no = tmp_v1;
00491                                 edges[LOC(face,edge3)].v2_no = tmp_v2;
00492                         }
00493                         if( edges[LOC(face,edge1)].v2_no == edges[LOC(face,edge2)].v2_no )
00494                         {
00495                                 /* reverse order of edge */
00496                                 tmp_v1 = edges[LOC(face,edge2)].v1_no;
00497                                 edges[LOC(face,edge2)].v1_no = edges[LOC(face,edge2)].v2_no;
00498                                 edges[LOC(face,edge2)].v2_no = tmp_v1;
00499                         }
00500 
00501                         edge1 = edge2;
00502                 }
00503         }
00504 }
00505 
00506 /**
00507  *                      R T _ A R B N _ T E S S
00508  *
00509  *  "Tessellate" an ARB into an NMG data structure.
00510  *  Purely a mechanical transformation of one faceted object
00511  *  into another.
00512  *
00513  *  Returns -
00514  *      -1      failure
00515  *       0      OK.  *r points to nmgregion that holds this tessellation.
00516  */
00517 int
00518 rt_arbn_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00519 {
00520         LOCAL struct rt_arbn_internal   *aip;
00521         struct shell            *s;
00522         struct faceuse          **fu;           /* array of faceuses */
00523         int                     nverts;         /* maximum possible number of vertices = neqn!/(3!(neqn-3)! */
00524         int                     point_count=0;  /* actual number of vertices */
00525         int                     face_count=0;   /* actual number of faces built */
00526         int                     i,j,k,l,n;
00527         struct arbn_pts         *pts;
00528         struct arbn_edges       *edges;         /* A list of edges for each plane eqn (each face) */
00529         int                     *edge_count;    /* number of edges for each face */
00530         int                     max_edge_count; /* maximium number of edges for any face */
00531         struct vertex           **verts;        /* Array of pointers to vertex structs */
00532         struct vertex           ***loop_verts;  /* Array of pointers to vertex structs to pass to nmg_cmface */
00533 
00534         RT_CK_DB_INTERNAL(ip);
00535         aip = (struct rt_arbn_internal *)ip->idb_ptr;
00536         RT_ARBN_CK_MAGIC(aip);
00537 
00538         /* Allocate memory for the vertices */
00539         nverts = aip->neqn * (aip->neqn-1) * (aip->neqn-2) / 6;
00540         pts = (struct arbn_pts *)bu_calloc( nverts , sizeof( struct arbn_pts ) , "rt_arbn_tess: pts" );
00541 
00542         /* Allocate memory for arbn_edges */
00543         edges = (struct arbn_edges *)bu_calloc( aip->neqn*aip->neqn , sizeof( struct arbn_edges ) ,
00544                         "rt_arbn_tess: edges" );
00545         edge_count = (int *)bu_calloc( aip->neqn , sizeof( int ) , "rt_arbn_tess: edge_count" );
00546 
00547         /* Allocate memory for faceuses */
00548         fu = (struct faceuse **)bu_calloc( aip->neqn , sizeof( struct faceuse *) , "rt_arbn_tess: fu" );
00549 
00550         /* Calculate all vertices */
00551         for( i=0 ; i<aip->neqn ; i++ )
00552         {
00553                 for( j=i+1 ; j<aip->neqn ; j++ )
00554                 {
00555                         for( k=j+1 ; k<aip->neqn ; k++ )
00556                         {
00557                                 int keep_point=1;
00558 
00559                                 if( bn_mkpoint_3planes( pts[point_count].pt, aip->eqn[i], aip->eqn[j], aip->eqn[k]))
00560                                         continue;
00561 
00562                                 for( l=0 ; l<aip->neqn ; l++ )
00563                                 {
00564                                         if( l == i || l == j || l == k )
00565                                                 continue;
00566                                         if( DIST_PT_PLANE( pts[point_count].pt , aip->eqn[l] ) > tol->dist )
00567                                         {
00568                                                 keep_point = 0;
00569                                                 break;
00570                                         }
00571                                 }
00572                                 if( keep_point )
00573                                 {
00574                                         pts[point_count].plane_no[0] = i;
00575                                         pts[point_count].plane_no[1] = j;
00576                                         pts[point_count].plane_no[2] = k;
00577                                         point_count++;
00578                                 }
00579                         }
00580                 }
00581         }
00582 
00583         /* Allocate memory for the NMG vertex pointers */
00584         verts = (struct vertex **)bu_calloc( point_count , sizeof( struct vertex *) ,
00585                         "rt_arbn_tess: verts" );
00586 
00587         /* Associate points with vertices */
00588         for( i=0 ; i<point_count ; i++ )
00589                 pts[i].vp = &verts[i];
00590 
00591         /* Check for duplicate points */
00592         for( i=0 ; i<point_count ; i++ )
00593         {
00594                 for( j=i+1 ; j<point_count ; j++ )
00595                 {
00596                         vect_t dist;
00597 
00598                         VSUB2( dist , pts[i].pt , pts[j].pt )
00599                         if( MAGSQ( dist ) < tol->dist_sq )
00600                         {
00601                                 /* These two points should point to the same vertex */
00602                                 pts[j].vp = pts[i].vp;
00603                         }
00604                 }
00605         }
00606 
00607         /* Make list of edges for each face */
00608         for( i=0 ; i<aip->neqn ; i++ )
00609         {
00610                 /* look for a point that lies in this face */
00611                 for( j=0 ; j<point_count ; j++ )
00612                 {
00613                         if( pts[j].plane_no[0] != i && pts[j].plane_no[1] != i && pts[j].plane_no[2] != i )
00614                                 continue;
00615 
00616                         /* look for another point that shares plane "i" and another with this one */
00617                         for( k=j+1 ; k<point_count ; k++ )
00618                         {
00619                                 int match=(-1);
00620                                 int pt1,pt2;
00621                                 int duplicate=0;
00622 
00623                                 /* skip points not on plane "i" */
00624                                 if( pts[k].plane_no[0] != i && pts[k].plane_no[1] != i && pts[k].plane_no[2] != i )
00625                                         continue;
00626 
00627                                 for( l=0 ; l<3 ; l++ )
00628                                 {
00629                                         for( n=0 ; n<3 ; n++ )
00630                                         {
00631                                                 if( pts[j].plane_no[l] == pts[k].plane_no[n] &&
00632                                                     pts[j].plane_no[l] != i )
00633                                                 {
00634                                                         match = pts[j].plane_no[l];
00635                                                         break;
00636                                                 }
00637                                         }
00638                                         if( match != (-1) )
00639                                                 break;
00640                                 }
00641 
00642                                 if( match == (-1) )
00643                                         continue;
00644 
00645                                 /* convert equivalent points to lowest point number */
00646                                 pt1 = j;
00647                                 pt2 = k;
00648                                 for( l=0 ; l<pt1 ; l++ )
00649                                 {
00650                                         if( pts[pt1].vp == pts[l].vp )
00651                                         {
00652                                                 pt1 = l;
00653                                                 break;
00654                                         }
00655                                 }
00656                                 for( l=0 ; l<pt2 ; l++ )
00657                                 {
00658                                         if( pts[pt2].vp == pts[l].vp )
00659                                         {
00660                                                 pt2 = l;
00661                                                 break;
00662                                         }
00663                                 }
00664 
00665                                 /* skip null edges */
00666                                 if( pt1 == pt2 )
00667                                         continue;
00668 
00669                                 /* check for duplicate edge */
00670                                 for( l=0 ; l<edge_count[i] ; l++ )
00671                                 {
00672                                         if( (edges[LOC(i,l)].v1_no == pt1 &&
00673                                             edges[LOC(i,l)].v2_no == pt2) ||
00674                                             (edges[LOC(i,l)].v2_no == pt1 &&
00675                                             edges[LOC(i,l)].v1_no == pt2) )
00676                                         {
00677                                                 duplicate = 1;
00678                                                 break;
00679                                         }
00680                                 }
00681                                 if( duplicate )
00682                                         continue;
00683 
00684                                 /* found an edge belonging to faces "i" and "match" */
00685                                 if( edge_count[i] == aip->neqn )
00686                                 {
00687                                         bu_log( "Too many edges found for one face\n" );
00688                                         goto fail;
00689                                 }
00690                                 edges[LOC( i , edge_count[i] )].v1_no = pt1;
00691                                 edges[LOC( i , edge_count[i] )].v2_no = pt2;
00692                                 edge_count[i]++;
00693                         }
00694                 }
00695         }
00696 
00697         /* for each face, sort the list of edges into a loop */
00698         Sort_edges( edges , edge_count , aip );
00699 
00700         /* Get max number of edges for any face */
00701         max_edge_count = 0;
00702         for( i=0 ; i<aip->neqn ; i++ )
00703                 if( edge_count[i] > max_edge_count )
00704                         max_edge_count = edge_count[i];
00705 
00706         /* Allocate memory for array to pass to nmg_cmface */
00707         loop_verts = (struct vertex ***) bu_calloc( max_edge_count , sizeof( struct vertex **) ,
00708                                 "rt_arbn_tess: loop_verts" );
00709 
00710         *r = nmg_mrsv( m );     /* Make region, empty shell, vertex */
00711         s = BU_LIST_FIRST(shell, &(*r)->s_hd);
00712 
00713         /* Make the faces */
00714         for( i=0 ; i<aip->neqn ; i++ )
00715         {
00716                 int loop_length=0;
00717 
00718                 for( j=0 ; j<edge_count[i] ; j++ )
00719                 {
00720                         /* skip zero length edges */
00721                         if( pts[edges[LOC(i,j)].v1_no].vp == pts[edges[LOC(i,j)].v2_no].vp )
00722                                 continue;
00723 
00724                         /* put vertex pointers into loop_verts array */
00725                         loop_verts[loop_length] = pts[edges[LOC(i,j)].v2_no].vp;
00726                         loop_length++;
00727                 }
00728 
00729                 /* Make the face if there is are least 3 vertices */
00730                 if( loop_length > 2 )
00731                         fu[face_count++] = nmg_cmface( s , loop_verts , loop_length );
00732         }
00733 
00734         /* Associate vertex geometry */
00735         for( i=0 ; i<point_count ; i++ )
00736         {
00737                 if( !(*pts[i].vp) )
00738                         continue;
00739 
00740                 if( (*pts[i].vp)->vg_p )
00741                         continue;
00742 
00743                 nmg_vertex_gv( *pts[i].vp , pts[i].pt );
00744         }
00745 
00746         bu_free( (char *)pts , "rt_arbn_tess: pts" );
00747         bu_free( (char *)edges , "rt_arbn_tess: edges" );
00748         bu_free( (char *)edge_count , "rt_arbn_tess: edge_count" );
00749         bu_free( (char *)verts , "rt_arbn_tess: verts" );
00750         bu_free( (char *)loop_verts , "rt_arbn_tess: loop_verts" );
00751 
00752         /* Associate face geometry */
00753         for( i=0 ; i<face_count ; i++ )
00754         {
00755                 if( nmg_fu_planeeqn( fu[i] , tol ) )
00756                 {
00757                         bu_log( "Failed to calculate face plane equation\n" );
00758                         bu_free( (char *)fu , "rt_arbn_tess: fu" );
00759                         nmg_kr( *r );
00760                         *r = (struct nmgregion *)NULL;
00761                         return( -1 );
00762                 }
00763         }
00764 
00765         bu_free( (char *)fu , "rt_arbn_tess: fu" );
00766 
00767         nmg_fix_normals( s , tol );
00768 
00769         (void)nmg_mark_edges_real( &s->l.magic );
00770 
00771         /* Compute "geometry" for region and shell */
00772         nmg_region_a( *r, tol );
00773 
00774         return( 0 );
00775 
00776 fail:
00777         bu_free( (char *)pts , "rt_arbn_tess: pts" );
00778         bu_free( (char *)edges , "rt_arbn_tess: edges" );
00779         bu_free( (char *)edge_count , "rt_arbn_tess: edge_count" );
00780         bu_free( (char *)verts , "rt_arbn_tess: verts" );
00781         return( -1 );
00782 }
00783 
00784 /**
00785  *                      R T _ A R B N _ I M P O R T
00786  *
00787  *  Convert from "network" doubles to machine specific.
00788  *  Transform
00789  */
00790 int
00791 rt_arbn_import(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
00792 {
00793         union record            *rp;
00794         struct rt_arbn_internal *aip;
00795         register int    i;
00796 
00797         BU_CK_EXTERNAL( ep );
00798         rp = (union record *)ep->ext_buf;
00799         if( rp->u_id != DBID_ARBN )  {
00800                 bu_log("rt_arbn_import: defective record, id=x%x\n", rp->u_id );
00801                 return(-1);
00802         }
00803 
00804         RT_CK_DB_INTERNAL( ip );
00805         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00806         ip->idb_type = ID_ARBN;
00807         ip->idb_meth = &rt_functab[ID_ARBN];
00808         ip->idb_ptr = bu_malloc( sizeof(struct rt_arbn_internal), "rt_arbn_internal");
00809         aip = (struct rt_arbn_internal *)ip->idb_ptr;
00810         aip->magic = RT_ARBN_INTERNAL_MAGIC;
00811         aip->neqn = bu_glong( rp->n.n_neqn );
00812         if( aip->neqn <= 0 )  return(-1);
00813         aip->eqn = (plane_t *)bu_malloc( aip->neqn*sizeof(plane_t), "arbn plane eqn[]");
00814 
00815         ntohd( (unsigned char *)aip->eqn, (unsigned char *)(&rp[1]), aip->neqn*4 );
00816 
00817         /* Transform by the matrix */
00818 #       include "noalias.h"
00819         for( i=0; i < aip->neqn; i++ )  {
00820                 point_t orig_pt;
00821                 point_t pt;
00822                 vect_t  norm;
00823 
00824                 /* Pick a point on the original halfspace */
00825                 VSCALE( orig_pt, aip->eqn[i], aip->eqn[i][3] );
00826 
00827                 /* Transform the point, and the normal */
00828                 MAT4X3VEC( norm, mat, aip->eqn[i] );
00829                 MAT4X3PNT( pt, mat, orig_pt );
00830 
00831                 /* Measure new distance from origin to new point */
00832                 VUNITIZE( norm );
00833                 VMOVE( aip->eqn[i], norm );
00834                 aip->eqn[i][3] = VDOT( pt, norm );
00835         }
00836 
00837         return(0);
00838 }
00839 
00840 /**
00841  *                      R T _ A R B N _ E X P O R T
00842  */
00843 int
00844 rt_arbn_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00845 {
00846         struct rt_arbn_internal *aip;
00847         union record            *rec;
00848         int                     ngrans;
00849         double                  *sbuf;          /* scalling buffer */
00850         register double         *sp;
00851         register int            i;
00852 
00853         RT_CK_DB_INTERNAL(ip);
00854         if( ip->idb_type != ID_ARBN )  return(-1);
00855         aip = (struct rt_arbn_internal *)ip->idb_ptr;
00856         RT_ARBN_CK_MAGIC(aip);
00857 
00858         if( aip->neqn <= 0 )  return(-1);
00859 
00860         /*
00861          * The network format for a double is 8 bytes and there are 4
00862          * doubles per plane equation.
00863          */
00864         ngrans = (aip->neqn * 8 * 4 + sizeof(union record)-1 ) /
00865                 sizeof(union record);
00866 
00867         BU_CK_EXTERNAL(ep);
00868         ep->ext_nbytes = (ngrans + 1) * sizeof(union record);
00869         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "arbn external");
00870         rec = (union record *)ep->ext_buf;
00871 
00872         rec[0].n.n_id = DBID_ARBN;
00873         (void)bu_plong( rec[0].n.n_neqn, aip->neqn );
00874         (void)bu_plong( rec[0].n.n_grans, ngrans );
00875 
00876         /* Take the data from the caller, and scale it, into sbuf */
00877         sp = sbuf = (double *)bu_malloc(
00878                 aip->neqn * sizeof(double) * 4, "arbn temp");
00879         for( i=0; i<aip->neqn; i++ )  {
00880                 /* Normal is unscaled, should have unit length; d is scaled */
00881                 *sp++ = aip->eqn[i][X];
00882                 *sp++ = aip->eqn[i][Y];
00883                 *sp++ = aip->eqn[i][Z];
00884                 *sp++ = aip->eqn[i][3] * local2mm;
00885         }
00886 
00887         htond( (unsigned char *)&rec[1], (unsigned char *)sbuf, aip->neqn * 4 );
00888 
00889         bu_free( (char *)sbuf, "arbn temp" );
00890         return(0);                      /* OK */
00891 }
00892 
00893 
00894 /**
00895  *                      R T _ A R B N _ I M P O R T 5
00896  *
00897  *  Convert from "network" doubles to machine specific.
00898  *  Transform
00899  */
00900 int
00901 rt_arbn_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
00902 {
00903         struct rt_arbn_internal *aip;
00904         register int            i;
00905         unsigned long           neqn;
00906         int                     double_count;
00907         int                     byte_count;
00908 
00909         BU_CK_EXTERNAL( ep );
00910 
00911         neqn = bu_glong((unsigned char *)ep->ext_buf);
00912         double_count = neqn * ELEMENTS_PER_PLANE;
00913         byte_count = double_count * SIZEOF_NETWORK_DOUBLE;
00914 
00915         BU_ASSERT_LONG(ep->ext_nbytes, ==, 4+ byte_count);
00916 
00917         RT_CK_DB_INTERNAL( ip );
00918         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00919         ip->idb_type = ID_ARBN;
00920         ip->idb_meth = &rt_functab[ID_ARBN];
00921         ip->idb_ptr = bu_malloc( sizeof(struct rt_arbn_internal), "rt_arbn_internal");
00922 
00923         aip = (struct rt_arbn_internal *)ip->idb_ptr;
00924         aip->magic = RT_ARBN_INTERNAL_MAGIC;
00925         aip->neqn = neqn;
00926         if (aip->neqn <= 0)  return(-1);
00927         aip->eqn = (plane_t *)bu_malloc(byte_count, "arbn plane eqn[]");
00928 
00929         ntohd((unsigned char *)aip->eqn, (unsigned char *)ep->ext_buf + 4, double_count);
00930 
00931         /* Transform by the matrix, if we have one that is not the identity */
00932 #       include "noalias.h"
00933         if( mat && !bn_mat_is_identity( mat ) ) {
00934                 for (i=0; i < aip->neqn; i++) {
00935                         point_t orig_pt;
00936                         point_t pt;
00937                         vect_t  norm;
00938 
00939                         /* Pick a point on the original halfspace */
00940                         VSCALE( orig_pt, aip->eqn[i], aip->eqn[i][3] );
00941 
00942                         /* Transform the point, and the normal */
00943                         MAT4X3VEC( norm, mat, aip->eqn[i] );
00944                         MAT4X3PNT( pt, mat, orig_pt );
00945 
00946                         /* Measure new distance from origin to new point */
00947                         VUNITIZE( norm );
00948                         VMOVE( aip->eqn[i], norm );
00949                         aip->eqn[i][3] = VDOT( pt, norm );
00950                 }
00951         }
00952 
00953         return(0);
00954 }
00955 
00956 /**
00957  *                      R T _ A R B N _ E X P O R T 5
00958  */
00959 int
00960 rt_arbn_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00961 {
00962         struct rt_arbn_internal *aip;
00963         register int            i;
00964         fastf_t                 *vec;
00965         register fastf_t        *sp;
00966         int                     double_count;
00967         int                     byte_count;
00968 
00969         RT_CK_DB_INTERNAL(ip);
00970         if( ip->idb_type != ID_ARBN )  return(-1);
00971         aip = (struct rt_arbn_internal *)ip->idb_ptr;
00972         RT_ARBN_CK_MAGIC(aip);
00973 
00974         if( aip->neqn <= 0 )  return(-1);
00975 
00976         double_count = aip->neqn * ELEMENTS_PER_PLANE;
00977         byte_count = double_count * SIZEOF_NETWORK_DOUBLE;
00978 
00979         BU_CK_EXTERNAL(ep);
00980         ep->ext_nbytes = 4 + byte_count;
00981         ep->ext_buf = (genptr_t)bu_malloc(ep->ext_nbytes, "arbn external");
00982 
00983         (void)bu_plong((unsigned char *)ep->ext_buf, aip->neqn);
00984 
00985         /* Take the data from the caller, and scale it, into vec */
00986         sp = vec = (double *)bu_malloc(byte_count, "arbn temp");
00987         for (i=0; i<aip->neqn; i++) {
00988                 /* Normal is unscaled, should have unit length; d is scaled */
00989                 *sp++ = aip->eqn[i][X];
00990                 *sp++ = aip->eqn[i][Y];
00991                 *sp++ = aip->eqn[i][Z];
00992                 *sp++ = aip->eqn[i][3] * local2mm;
00993         }
00994 
00995         /* Convert from internal (host) to database (network) format */
00996         htond((unsigned char *)ep->ext_buf + 4, (unsigned char *)vec, double_count);
00997 
00998         bu_free((char *)vec, "arbn temp");
00999         return(0);                      /* OK */
01000 }
01001 
01002 
01003 /**
01004  *                      R T _ A R B N _ D E S C R I B E
01005  *
01006  *  Make human-readable formatted presentation of this solid.
01007  *  First line describes type of solid.
01008  *  Additional lines are indented one tab, and give parameter values.
01009  */
01010 int
01011 rt_arbn_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
01012 {
01013         register struct rt_arbn_internal        *aip =
01014                 (struct rt_arbn_internal *)ip->idb_ptr;
01015         char    buf[256];
01016         int     i;
01017 
01018         RT_ARBN_CK_MAGIC(aip);
01019         sprintf(buf, "arbn bounded by %d planes\n", aip->neqn);
01020         bu_vls_strcat( str, buf );
01021 
01022         if( !verbose )  return(0);
01023 
01024         for( i=0; i < aip->neqn; i++ )  {
01025                 sprintf(buf, "\t%d: (%g, %g, %g) %g\n",
01026                         i,
01027                         INTCLAMP(aip->eqn[i][X]),               /* should have unit length */
01028                         INTCLAMP(aip->eqn[i][Y]),
01029                         INTCLAMP(aip->eqn[i][Z]),
01030                         INTCLAMP(aip->eqn[i][3] * mm2local) );
01031                 bu_vls_strcat( str, buf );
01032         }
01033         return(0);
01034 }
01035 
01036 
01037 /**
01038  *                      R T _ A R B N _ I F R E E
01039  *
01040  *  Free the storage associated with the rt_db_internal version of this solid.
01041  */
01042 void
01043 rt_arbn_ifree(struct rt_db_internal *ip)
01044 {
01045         struct rt_arbn_internal *aip;
01046 
01047         RT_CK_DB_INTERNAL(ip);
01048         aip = (struct rt_arbn_internal *)ip->idb_ptr;
01049         RT_ARBN_CK_MAGIC(aip);
01050 
01051         if( aip->neqn > 0 )
01052                 bu_free( (char *)aip->eqn, "rt_arbn_internal eqn[]");
01053         bu_free( (char *)aip, "rt_arbn_internal" );
01054 
01055         ip->idb_ptr = (genptr_t)0;      /* sanity */
01056 }
01057 
01058 /**
01059  *              R T _ A R B N _ T C L G E T
01060  *
01061  *      Routine to format the parameters of an ARBN primitive for "db get"
01062  *
01063  *      Legal requested parameters include:
01064  *              "N" - number of equations
01065  *              "P" - list of all the planes
01066  *              "P#" - the specified plane number (0 based)
01067  *              no arguments returns everything
01068  */
01069 
01070 int
01071 rt_arbn_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr)
01072 {
01073         register struct rt_arbn_internal *arbn=(struct rt_arbn_internal *)intern->idb_ptr;
01074         Tcl_DString     ds;
01075         struct bu_vls   vls;
01076         int             i;
01077 
01078         RT_ARBN_CK_MAGIC( arbn );
01079 
01080         Tcl_DStringInit( &ds );
01081         bu_vls_init( &vls );
01082 
01083         if( attr == (char *)NULL ) {
01084                 bu_vls_strcpy( &vls, "arbn" );
01085                 bu_vls_printf( &vls, " N %d", arbn->neqn );
01086                 for( i=0 ; i<arbn->neqn ; i++ ) {
01087                         bu_vls_printf( &vls, " P%d {%.25g %.25g %.25g %.25g}", i,
01088                                        V4ARGS( arbn->eqn[i] ) );
01089                 }
01090         }
01091         else if( !strcmp( attr, "N" ) )
01092                 bu_vls_printf( &vls, "%d", arbn->neqn );
01093         else if( !strcmp( attr, "P" ) ) {
01094                 for( i=0 ; i<arbn->neqn ; i++ ) {
01095                         bu_vls_printf( &vls, " P%d {%.25g %.25g %.25g %.25g}", i,
01096                                        V4ARGS( arbn->eqn[i] ) );
01097                 }
01098         }
01099         else if( attr[0] == 'P' ) {
01100                 if( isdigit( attr[1] ) == 0 ) {
01101                         Tcl_SetResult( interp, "ERROR: Illegal plane number\n",
01102                                        TCL_STATIC );
01103                         bu_vls_free( &vls );
01104                         return( TCL_ERROR );
01105                 }
01106 
01107                 i = atoi( &attr[1] );
01108                 if( i >= arbn->neqn || i < 0 ) {
01109                         Tcl_SetResult( interp, "ERROR: Illegal plane number\n",
01110                                        TCL_STATIC );
01111                         bu_vls_free( &vls );
01112                         return( TCL_ERROR );
01113                 }
01114 
01115                 bu_vls_printf( &vls, "%.25g %.25g %.25g %.25g", V4ARGS( arbn->eqn[i] ) );
01116         }
01117         else {
01118                 Tcl_SetResult( interp,"ERROR: Unknown attribute, choices are N, P, or P#\n",
01119                 TCL_STATIC );
01120                 bu_vls_free( &vls );
01121                 return( TCL_ERROR );
01122         }
01123 
01124         Tcl_DStringAppend( &ds, bu_vls_addr( &vls ), -1 );
01125         Tcl_DStringResult( interp, &ds );
01126         Tcl_DStringFree( &ds );
01127         bu_vls_free( &vls );
01128         return( TCL_OK );
01129 }
01130 
01131 /**
01132  *              R T _ A R B N _ T C L A D J U S T
01133  *
01134  *      Routine to modify an arbn via the "db adjust" command
01135  *
01136  *      Legal parameters are:
01137  *              "N" - adjust the number of planes (new ones will be zeroed)
01138  *              "P" - adjust the entire list of planes
01139  *              "P#" - adjust a specific plane (0 based)
01140  *              "P+" - add a new plane to the list of planes
01141  */
01142 
01143 int
01144 rt_arbn_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, char **argv)
01145 {
01146         struct rt_arbn_internal *arbn;
01147         unsigned char           *c;
01148         int                     len;
01149         int                     i, j;
01150         fastf_t                 *new_planes;
01151         fastf_t                 *array;
01152 
01153         RT_CK_DB_INTERNAL( intern );
01154 
01155         arbn = (struct rt_arbn_internal *)intern->idb_ptr;
01156         RT_ARBN_CK_MAGIC( arbn );
01157 
01158         while( argc >= 2 ) {
01159                 if( !strcmp( argv[0], "N" ) ) {
01160                         i = atoi( argv[1] );
01161                         if( i == arbn->neqn )
01162                                 goto cont;
01163                         if( i > 0 ) {
01164                                 arbn->eqn = (plane_t *)bu_realloc( arbn->eqn,
01165                                                    i * sizeof( plane_t ),
01166                                                                    "arbn->eqn");
01167                                 for( j=arbn->neqn ; j<i ; j++ ) {
01168                                         VSETALLN( arbn->eqn[j], 0.0, 4 );
01169                                 }
01170                                 arbn->neqn = i;
01171                         } else {
01172                                 Tcl_SetResult( interp,
01173                                        "ERROR: number of planes must be greater than 0\n",
01174                                         TCL_STATIC );
01175                         }
01176                 }
01177                 else if( !strcmp( argv[0], "P" ) ) {
01178                         /* eliminate all the '{' and '}' chars */
01179                         c = (unsigned char *)argv[1];
01180                         while( *c != '\0' ) {
01181                                 if( *c == '{' || *c == '}' )
01182                                         *c = ' ';
01183                                 c++;
01184                         }
01185                         len = 0;
01186                         (void)tcl_list_to_fastf_array( interp, argv[1], &new_planes, &len );
01187 
01188                         if( len%4 ) {
01189                                 Tcl_SetResult( interp,
01190                                        "ERROR: Incorrect number of plane coefficients\n",
01191                                         TCL_STATIC );
01192                                 if( len )
01193                                         bu_free( (char *)new_planes, "new_planes" );
01194                                 return( TCL_ERROR );
01195                         }
01196                         if( arbn->eqn )
01197                                 bu_free( (char *)arbn->eqn, "arbn->eqn" );
01198                         arbn->eqn = (plane_t *)new_planes;
01199                         arbn->neqn = len / 4;
01200                         for( i=0 ; i<arbn->neqn ; i++ )
01201                                 VUNITIZE( arbn->eqn[i] );
01202                 }
01203                 else if( argv[0][0] == 'P' ) {
01204                         if( argv[0][1] == '+' ) {
01205                                 i = arbn->neqn;
01206                                 arbn->neqn++;
01207                                 arbn->eqn = (plane_t *)bu_realloc( arbn->eqn,
01208                                                          (arbn->neqn) * sizeof( plane_t ),
01209                                                          "arbn->eqn" );
01210                         }
01211                         else if( isdigit( argv[0][1] ) ) {
01212                                 i = atoi( &argv[0][1] );
01213                         } else {
01214                                 Tcl_SetResult( interp,
01215                                    "ERROR: illegal argument, choices are P, P#, P+, or N\n",
01216                                    TCL_STATIC );
01217                                 return( TCL_ERROR );
01218                         }
01219                         if( i < 0 || i >= arbn->neqn ) {
01220                                 Tcl_SetResult( interp,
01221                                                "ERROR: plane number out of range\n",
01222                                                TCL_STATIC );
01223                                 return( TCL_ERROR );
01224                         }
01225                         len = 4;
01226                         array = (fastf_t *)&arbn->eqn[i];
01227                         if( tcl_list_to_fastf_array( interp, argv[1],
01228                                                           &array, &len ) != 4 ) {
01229                                 Tcl_SetResult( interp,
01230                                     "ERROR: incorrect number of coefficients for a plane\n",
01231                                     TCL_STATIC );
01232                                 return( TCL_ERROR );
01233                         }
01234                         VUNITIZE( arbn->eqn[i] );
01235                 }
01236                 else {
01237                         Tcl_SetResult( interp,
01238                               "ERROR: illegal argument, choices are P, P#, P+, or N\n",
01239                               TCL_STATIC );
01240                         return( TCL_ERROR );
01241                 }
01242         cont:
01243                 argc -= 2;
01244                 argv += 2;
01245         }
01246         return( TCL_OK );
01247 }
01248 
01249 /*@}*/
01250 /*
01251  * Local Variables:
01252  * mode: C
01253  * tab-width: 8
01254  * c-basic-offset: 4
01255  * indent-tabs-mode: t
01256  * End:
01257  * ex: shiftwidth=4 tabstop=8
01258  */

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