g_vol.c

Go to the documentation of this file.
00001 /*                         G _ V O L . 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_vol.c
00026  *      Intersect a ray with a 3-D volume.
00027  *      The volume is described as a concatenation of
00028  *      bw(5) files.
00029  *
00030  *  Authors -
00031  *      Michael John Muuss
00032  *      Phil Dykstra
00033  *
00034  *  Source -
00035  *      SECAD/VLD Computing Consortium, Bldg 394
00036  *      The U. S. Army Ballistic Research Laboratory
00037  *      Aberdeen Proving Ground, Maryland  21005
00038  *
00039  */
00040 /*@}*/
00041 
00042 #ifndef lint
00043 static const char RCSvol[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_vol.c,v 14.13 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00044 #endif
00045 
00046 #include "common.h"
00047 
00048 #include <stddef.h>
00049 #include <stdio.h>
00050 #include <ctype.h>
00051 #include <math.h>
00052 #include <string.h>
00053 
00054 #include "machine.h"
00055 #include "vmath.h"
00056 #include "db.h"
00057 #include "nmg.h"
00058 #include "rtgeom.h"
00059 #include "raytrace.h"
00060 #include "./debug.h"
00061 #include "./fixpt.h"
00062 
00063 /*
00064 NOTES:
00065         Changed small to small1 for win32 compatibility
00066 */
00067 
00068 
00069 struct rt_vol_specific {
00070         struct rt_vol_internal vol_i;
00071         vect_t          vol_xnorm;      /* local +X norm in model coords */
00072         vect_t          vol_ynorm;
00073         vect_t          vol_znorm;
00074         mat_t           vol_mat;        /* model to ideal space */
00075         vect_t          vol_origin;     /* local coords of grid origin (0,0,0) for now */
00076         vect_t          vol_large;      /* local coords of XYZ max */
00077 };
00078 #define VOL_NULL        ((struct rt_vol_specific *)0)
00079 
00080 #define VOL_O(m)        bu_offsetof(struct rt_vol_internal, m)
00081 
00082 const struct bu_structparse rt_vol_parse[] = {
00083 #if CRAY && !__STDC__
00084         {"%s",  RT_VOL_NAME_LEN, "file",        1,              BU_STRUCTPARSE_FUNC_NULL },
00085 #else
00086         {"%s",  RT_VOL_NAME_LEN, "file",        bu_offsetofarray(struct rt_vol_internal, file), BU_STRUCTPARSE_FUNC_NULL },
00087 #endif
00088         {"%d",  1, "w",         VOL_O(xdim),    BU_STRUCTPARSE_FUNC_NULL },
00089         {"%d",  1, "n",         VOL_O(ydim),    BU_STRUCTPARSE_FUNC_NULL },
00090         {"%d",  1, "d",         VOL_O(zdim),    BU_STRUCTPARSE_FUNC_NULL },
00091         {"%d",  1, "lo",        VOL_O(lo),              BU_STRUCTPARSE_FUNC_NULL },
00092         {"%d",  1, "hi",        VOL_O(hi),              BU_STRUCTPARSE_FUNC_NULL },
00093         {"%f",  ELEMENTS_PER_VECT, "size",bu_offsetofarray(struct rt_vol_internal, cellsize), BU_STRUCTPARSE_FUNC_NULL },
00094         {"%f",  16, "mat", bu_offsetofarray(struct rt_vol_internal,mat), BU_STRUCTPARSE_FUNC_NULL },
00095         {"",    0, (char *)0,   0,                      BU_STRUCTPARSE_FUNC_NULL }
00096 };
00097 
00098 BU_EXTERN(void rt_vol_plate,(point_t a, point_t b, point_t c, point_t d,
00099         mat_t mat, struct bu_list *vhead, struct rt_vol_internal *vip));
00100 
00101 /*
00102  *  Codes to represent surface normals.
00103  *  In a bitmap, there are only 4 possible normals.
00104  *  With this code, reverse the sign to reverse the direction.
00105  *  As always, the normal is expected to point outwards.
00106  */
00107 #define NORM_ZPOS       3
00108 #define NORM_YPOS       2
00109 #define NORM_XPOS       1
00110 #define NORM_XNEG       (-1)
00111 #define NORM_YNEG       (-2)
00112 #define NORM_ZNEG       (-3)
00113 
00114 /*
00115  *  Regular bit addressing is used:  (0..W-1, 0..N-1),
00116  *  but the bitmap is stored with two cells of zeros all around,
00117  *  so permissible subscripts run (-2..W+1, -2..N+1).
00118  *  This eliminates special-case code for the boundary conditions.
00119  */
00120 #define VOL_XWIDEN      2
00121 #define VOL_YWIDEN      2
00122 #define VOL_ZWIDEN      2
00123 #define VOL(_vip,_xx,_yy,_zz)   (_vip)->map[ \
00124         (((_zz)+VOL_ZWIDEN) * ((_vip)->ydim + VOL_YWIDEN*2)+ \
00125          ((_yy)+VOL_YWIDEN))* ((_vip)->xdim + VOL_XWIDEN*2)+ \
00126           (_xx)+VOL_XWIDEN ]
00127 
00128 #define OK(_vip,_v)     ( (int)(_v) >= (_vip)->lo && (int)(_v) <= (_vip)->hi )
00129 
00130 static int rt_vol_normtab[3] = { NORM_XPOS, NORM_YPOS, NORM_ZPOS };
00131 
00132 
00133 /**
00134  *                      R T _ V O L _ S H O T
00135  *
00136  *  Transform the ray into local coordinates of the volume ("ideal space").
00137  *  Step through the 3-D array, in local coordinates.
00138  *  Return intersection segments.
00139  *
00140  */
00141 int
00142 rt_vol_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00143 {
00144         register struct rt_vol_specific *volp =
00145                 (struct rt_vol_specific *)stp->st_specific;
00146         vect_t  invdir;
00147         double  t0;     /* in point of cell */
00148         double  t1;     /* out point of cell */
00149         double  tmax;   /* out point of entire grid */
00150         vect_t  t;      /* next t value for XYZ cell plane intersect */
00151         vect_t  delta;  /* spacing of XYZ cell planes along ray */
00152         int     igrid[3];/* Grid cell coordinates of cell (integerized) */
00153         vect_t  P;      /* hit point */
00154         int     inside; /* inside/outside a solid flag */
00155         int     in_axis;
00156         int     out_axis;
00157         int     j;
00158         struct xray     ideal_ray;
00159 
00160         /* Transform actual ray into ideal space at origin in X-Y plane */
00161         MAT4X3PNT( ideal_ray.r_pt, volp->vol_mat, rp->r_pt );
00162         MAT4X3VEC( ideal_ray.r_dir, volp->vol_mat, rp->r_dir );
00163         rp = &ideal_ray;        /* XXX */
00164 
00165         /* Compute the inverse of the direction cosines */
00166         if( !NEAR_ZERO( rp->r_dir[X], SQRT_SMALL_FASTF ) )  {
00167                 invdir[X]=1.0/rp->r_dir[X];
00168         } else {
00169                 invdir[X] = INFINITY;
00170                 rp->r_dir[X] = 0.0;
00171         }
00172         if( !NEAR_ZERO( rp->r_dir[Y], SQRT_SMALL_FASTF ) )  {
00173                 invdir[Y]=1.0/rp->r_dir[Y];
00174         } else {
00175                 invdir[Y] = INFINITY;
00176                 rp->r_dir[Y] = 0.0;
00177         }
00178         if( !NEAR_ZERO( rp->r_dir[Z], SQRT_SMALL_FASTF ) )  {
00179                 invdir[Z]=1.0/rp->r_dir[Z];
00180         } else {
00181                 invdir[Z] = INFINITY;
00182                 rp->r_dir[Z] = 0.0;
00183         }
00184 
00185         /* intersect ray with ideal grid rpp */
00186         VSETALL( P, 0 );
00187         if( ! rt_in_rpp(rp, invdir, P, volp->vol_large ) )
00188                 return  0;      /* MISS */
00189         VJOIN1( P, rp->r_pt, rp->r_min, rp->r_dir );    /* P is hit point */
00190 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("vol_large", volp->vol_large);
00191 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("vol_origin", volp->vol_origin);
00192 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("r_pt", rp->r_pt);
00193 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("P", P);
00194 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("cellsize", volp->vol_i.cellsize);
00195         t0 = rp->r_min;
00196         tmax = rp->r_max;
00197 if(RT_G_DEBUG&DEBUG_VOL)bu_log("[shoot: r_min=%g, r_max=%g]\n", rp->r_min, rp->r_max);
00198 
00199         /* find grid cell where ray first hits ideal space bounding RPP */
00200         igrid[X] = (P[X] - volp->vol_origin[X]) / volp->vol_i.cellsize[X];
00201         igrid[Y] = (P[Y] - volp->vol_origin[Y]) / volp->vol_i.cellsize[Y];
00202         igrid[Z] = (P[Z] - volp->vol_origin[Z]) / volp->vol_i.cellsize[Z];
00203         if( igrid[X] < 0 )  {
00204                 igrid[X] = 0;
00205         } else if( igrid[X] >= volp->vol_i.xdim ) {
00206                 igrid[X] = volp->vol_i.xdim-1;
00207         }
00208         if( igrid[Y] < 0 )  {
00209                 igrid[Y] = 0;
00210         } else if( igrid[Y] >= volp->vol_i.ydim ) {
00211                 igrid[Y] = volp->vol_i.ydim-1;
00212         }
00213         if( igrid[Z] < 0 )  {
00214                 igrid[Z] = 0;
00215         } else if( igrid[Z] >= volp->vol_i.zdim ) {
00216                 igrid[Z] = volp->vol_i.zdim-1;
00217         }
00218 if(RT_G_DEBUG&DEBUG_VOL)bu_log("igrid=(%d, %d, %d)\n", igrid[X], igrid[Y], igrid[Z]);
00219 
00220         /* X setup */
00221         if( rp->r_dir[X] == 0.0 )  {
00222                 t[X] = INFINITY;
00223                 delta[X] = 0;
00224         } else {
00225                 j = igrid[X];
00226                 if( rp->r_dir[X] < 0 ) j++;
00227                 t[X] = (volp->vol_origin[X] + j*volp->vol_i.cellsize[X] -
00228                         rp->r_pt[X]) * invdir[X];
00229                 delta[X] = volp->vol_i.cellsize[X] * fabs(invdir[X]);
00230         }
00231         /* Y setup */
00232         if( rp->r_dir[Y] == 0.0 )  {
00233                 t[Y] = INFINITY;
00234                 delta[Y] = 0;
00235         } else {
00236                 j = igrid[Y];
00237                 if( rp->r_dir[Y] < 0 ) j++;
00238                 t[Y] = (volp->vol_origin[Y] + j*volp->vol_i.cellsize[Y] -
00239                         rp->r_pt[Y]) * invdir[Y];
00240                 delta[Y] = volp->vol_i.cellsize[Y] * fabs(invdir[Y]);
00241         }
00242         /* Z setup */
00243         if( rp->r_dir[Z] == 0.0 )  {
00244                 t[Z] = INFINITY;
00245                 delta[Z] = 0;
00246         } else {
00247                 j = igrid[Z];
00248                 if( rp->r_dir[Z] < 0 ) j++;
00249                 t[Z] = (volp->vol_origin[Z] + j*volp->vol_i.cellsize[Z] -
00250                         rp->r_pt[Z]) * invdir[Z];
00251                 delta[Z] = volp->vol_i.cellsize[Z] * fabs(invdir[Z]);
00252         }
00253 
00254         /* The delta[] elements *must* be positive, as t must increase */
00255 if(RT_G_DEBUG&DEBUG_VOL)bu_log("t[X] = %g, delta[X] = %g\n", t[X], delta[X] );
00256 if(RT_G_DEBUG&DEBUG_VOL)bu_log("t[Y] = %g, delta[Y] = %g\n", t[Y], delta[Y] );
00257 if(RT_G_DEBUG&DEBUG_VOL)bu_log("t[Z] = %g, delta[Z] = %g\n", t[Z], delta[Z] );
00258 
00259         /* Find face of entry into first cell -- max initial t value */
00260         if( t[X] >= t[Y] )  {
00261                 in_axis = X;
00262                 t0 = t[X];
00263         } else {
00264                 in_axis = Y;
00265                 t0 = t[Y];
00266         }
00267         if( t[Z] > t0 )  {
00268                 in_axis = Z;
00269                 t0 = t[Z];
00270         }
00271 if(RT_G_DEBUG&DEBUG_VOL)bu_log("Entry axis is %s, t0=%g\n", in_axis==X ? "X" : (in_axis==Y?"Y":"Z"), t0);
00272 
00273         /* Advance to next exits */
00274         t[X] += delta[X];
00275         t[Y] += delta[Y];
00276         t[Z] += delta[Z];
00277 
00278         /* Ensure that next exit is after first entrance */
00279         if( t[X] < t0 )  {
00280                 bu_log("*** advancing t[X]\n");
00281                 t[X] += delta[X];
00282         }
00283         if( t[Y] < t0 )  {
00284                 bu_log("*** advancing t[Y]\n");
00285                 t[Y] += delta[Y];
00286         }
00287         if( t[Z] < t0 )  {
00288                 bu_log("*** advancing t[Z]\n");
00289                 t[Z] += delta[Z];
00290         }
00291 if(RT_G_DEBUG&DEBUG_VOL) VPRINT("Exit t[]", t);
00292 
00293         inside = 0;
00294 
00295         while( t0 < tmax ) {
00296                 int     val;
00297                 struct seg      *segp;
00298 
00299                 /* find minimum exit t value */
00300                 if( t[X] < t[Y] )  {
00301                         if( t[Z] < t[X] )  {
00302                                 out_axis = Z;
00303                                 t1 = t[Z];
00304                         } else {
00305                                 out_axis = X;
00306                                 t1 = t[X];
00307                         }
00308                 } else {
00309                         if( t[Z] < t[Y] )  {
00310                                 out_axis = Z;
00311                                 t1 = t[Z];
00312                         } else {
00313                                 out_axis = Y;
00314                                 t1 = t[Y];
00315                         }
00316                 }
00317 
00318                 /* Ray passes through cell igrid[XY] from t0 to t1 */
00319                 val = VOL( &volp->vol_i, igrid[X], igrid[Y], igrid[Z] );
00320 if(RT_G_DEBUG&DEBUG_VOL)bu_log("igrid [%d %d %d] from %g to %g, val=%d\n",
00321                         igrid[X], igrid[Y], igrid[Z],
00322                         t0, t1, val );
00323 if(RT_G_DEBUG&DEBUG_VOL)bu_log("Exit axis is %s, t[]=(%g, %g, %g)\n",
00324                         out_axis==X ? "X" : (out_axis==Y?"Y":"Z"),
00325                         t[X], t[Y], t[Z] );
00326 
00327                 if( t1 <= t0 )  bu_log("ERROR vol t1=%g < t0=%g\n", t1, t0 );
00328                 if( !inside )  {
00329                         if( OK( &volp->vol_i, val ) )  {
00330                                 /* Handle the transition from vacuum to solid */
00331                                 /* Start of segment (entering a full voxel) */
00332                                 inside = 1;
00333 
00334                                 RT_GET_SEG(segp, ap->a_resource);
00335                                 segp->seg_stp = stp;
00336                                 segp->seg_in.hit_dist = t0;
00337 
00338                                 /* Compute entry normal */
00339                                 if( rp->r_dir[in_axis] < 0 )  {
00340                                         /* Go left, entry norm goes right */
00341                                         segp->seg_in.hit_surfno =
00342                                                 rt_vol_normtab[in_axis];
00343                                 }  else  {
00344                                         /* go right, entry norm goes left */
00345                                         segp->seg_in.hit_surfno =
00346                                                 (-rt_vol_normtab[in_axis]);
00347                                 }
00348                                 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00349                                 if(RT_G_DEBUG&DEBUG_VOL) bu_log("START t=%g, surfno=%d\n",
00350                                         t0, segp->seg_in.hit_surfno);
00351                         } else {
00352                                 /* Do nothing, marching through void */
00353                         }
00354                 } else {
00355                         if( OK( &volp->vol_i, val ) )  {
00356                                 /* Do nothing, marching through solid */
00357                         } else {
00358                                 register struct seg     *tail;
00359                                 /* End of segment (now in an empty voxel) */
00360                                 /* Handle transition from solid to vacuum */
00361                                 inside = 0;
00362 
00363                                 tail = BU_LIST_LAST( seg, &(seghead->l) );
00364                                 tail->seg_out.hit_dist = t0;
00365 
00366                                 /* Compute exit normal */
00367                                 if( rp->r_dir[in_axis] < 0 )  {
00368                                         /* Go left, exit normal goes left */
00369                                         tail->seg_out.hit_surfno =
00370                                                 (-rt_vol_normtab[in_axis]);
00371                                 }  else  {
00372                                         /* go right, exit norm goes right */
00373                                         tail->seg_out.hit_surfno =
00374                                                 rt_vol_normtab[in_axis];
00375                                 }
00376                                 if(RT_G_DEBUG&DEBUG_VOL) bu_log("END t=%g, surfno=%d\n",
00377                                         t0, tail->seg_out.hit_surfno );
00378                         }
00379                 }
00380 
00381                 /* Take next step */
00382                 t0 = t1;
00383                 in_axis = out_axis;
00384                 t[out_axis] += delta[out_axis];
00385                 if( rp->r_dir[out_axis] > 0 ) {
00386                         igrid[out_axis]++;
00387                 } else {
00388                         igrid[out_axis]--;
00389                 }
00390         }
00391 
00392         if( inside )  {
00393                 register struct seg     *tail;
00394 
00395                 /* Close off the final segment */
00396                 tail = BU_LIST_LAST( seg, &(seghead->l) );
00397                 tail->seg_out.hit_dist = tmax;
00398 
00399                 /* Compute exit normal.  Previous out_axis is now in_axis */
00400                 if( rp->r_dir[in_axis] < 0 )  {
00401                         /* Go left, exit normal goes left */
00402                         tail->seg_out.hit_surfno = (-rt_vol_normtab[in_axis]);
00403                 }  else  {
00404                         /* go right, exit norm goes right */
00405                         tail->seg_out.hit_surfno = rt_vol_normtab[in_axis];
00406                 }
00407                 if(RT_G_DEBUG&DEBUG_VOL) bu_log("closed END t=%g, surfno=%d\n",
00408                         tmax, tail->seg_out.hit_surfno );
00409         }
00410 
00411         if( BU_LIST_IS_EMPTY( &(seghead->l) ) )
00412                 return(0);
00413         return(2);
00414 }
00415 
00416 /**
00417  *                      R T _ V O L _ I M P O R T
00418  *
00419  *  Read in the information from the string solid record.
00420  *  Then, as a service to the application, read in the bitmap
00421  *  and set up some of the associated internal variables.
00422  */
00423 int
00424 rt_vol_import(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
00425 {
00426         union record    *rp;
00427         register struct rt_vol_internal *vip;
00428         struct bu_vls   str;
00429         FILE            *fp;
00430         int             nbytes;
00431         register int    y;
00432         register int    z;
00433         mat_t           tmat;
00434         int             ret;
00435 
00436         BU_CK_EXTERNAL( ep );
00437         rp = (union record *)ep->ext_buf;
00438         if( rp->u_id != DBID_STRSOL )  {
00439                 bu_log("rt_ebm_import: defective strsol record\n");
00440                 return(-1);
00441         }
00442 
00443         RT_CK_DB_INTERNAL( ip );
00444         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00445         ip->idb_type = ID_VOL;
00446         ip->idb_meth = &rt_functab[ID_VOL];
00447         ip->idb_ptr = bu_calloc(1, sizeof(struct rt_vol_internal), "rt_vol_internal");
00448         vip = (struct rt_vol_internal *)ip->idb_ptr;
00449         vip->magic = RT_VOL_INTERNAL_MAGIC;
00450 
00451         /* Establish defaults */
00452         MAT_IDN( vip->mat );
00453         vip->lo = 0;
00454         vip->hi = 255;
00455 
00456         /* Default VOL cell size in ideal coordinates is one unit/cell */
00457         VSETALL( vip->cellsize, 1 );
00458 
00459         bu_vls_init( &str );
00460         bu_vls_strcpy( &str, rp->ss.ss_args );
00461         if( bu_struct_parse( &str, rt_vol_parse, (char *)vip ) < 0 )  {
00462                 bu_vls_free( &str );
00463                 return -2;
00464         }
00465         bu_vls_free( &str );
00466 
00467         /* Check for reasonable values */
00468         if( vip->file[0] == '\0' || vip->xdim < 1 ||
00469             vip->ydim < 1 || vip->zdim < 1 || vip->mat[15] <= 0.0 ||
00470             vip->lo < 0 || vip->hi > 255 )  {
00471                 bu_struct_print("Unreasonable VOL parameters", rt_vol_parse,
00472                         (char *)vip );
00473                 return(-1);
00474         }
00475 
00476         /* Apply any modeling transforms to get final matrix */
00477         bn_mat_mul( tmat, mat, vip->mat );
00478         MAT_COPY( vip->mat, tmat );
00479 
00480         /* Get bit map from .bw(5) file */
00481         nbytes = (vip->xdim+VOL_XWIDEN*2)*
00482                 (vip->ydim+VOL_YWIDEN*2)*
00483                 (vip->zdim+VOL_ZWIDEN*2);
00484         vip->map = (unsigned char *)bu_calloc( 1, nbytes, "vol_import bitmap" );
00485 
00486         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00487         if( (fp = fopen(vip->file, "r")) == NULL )  {
00488                 perror(vip->file);
00489                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00490                 return(-1);
00491         }
00492         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00493 
00494         /* Because of in-memory padding, read each scanline separately */
00495         for( z=0; z < vip->zdim; z++ )  {
00496                 for( y=0; y < vip->ydim; y++ )  {
00497                         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00498                         ret = fread( &VOL(vip, 0, y, z), vip->xdim, 1, fp ); /* res_syscall */
00499                         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00500                         if( ret < 1 )  {
00501                                 bu_log("rt_vol_import(%s): Unable to read whole VOL, y=%d, z=%d\n",
00502                                         vip->file, y, z);
00503                                 bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00504                                 fclose(fp);
00505                                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00506                                 return -1;
00507                         }
00508                 }
00509         }
00510         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00511         fclose(fp);
00512         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00513         return( 0 );
00514 }
00515 
00516 /**
00517  *                      R T _ V O L _ E X P O R T
00518  *
00519  *  The name will be added by the caller.
00520  */
00521 int
00522 rt_vol_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00523 {
00524         struct rt_vol_internal  *vip;
00525         struct rt_vol_internal  vol;    /* scaled version */
00526         union record            *rec;
00527         struct bu_vls           str;
00528 
00529         RT_CK_DB_INTERNAL(ip);
00530         if( ip->idb_type != ID_VOL )  return(-1);
00531         vip = (struct rt_vol_internal *)ip->idb_ptr;
00532         RT_VOL_CK_MAGIC(vip);
00533         vol = *vip;                     /* struct copy */
00534 
00535         /* Apply scale factor */
00536         vol.mat[15] /= local2mm;
00537 
00538         BU_CK_EXTERNAL(ep);
00539         ep->ext_nbytes = sizeof(union record)*DB_SS_NGRAN;
00540         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "vol external");
00541         rec = (union record *)ep->ext_buf;
00542 
00543         bu_vls_init( &str );
00544         bu_vls_struct_print( &str, rt_vol_parse, (char *)&vol );
00545 
00546         rec->ss.ss_id = DBID_STRSOL;
00547         strncpy( rec->ss.ss_keyword, "vol", NAMESIZE-1 );
00548         strncpy( rec->ss.ss_args, bu_vls_addr(&str), DB_SS_LEN-1 );
00549         bu_vls_free( &str );
00550 
00551         return(0);
00552 }
00553 
00554 /**
00555  *                      R T _ V O L _ I M P O R T 5
00556  *
00557  *  Read in the information from the string solid record.
00558  *  Then, as a service to the application, read in the bitmap
00559  *  and set up some of the associated internal variables.
00560  */
00561 int
00562 rt_vol_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
00563 {
00564         register struct rt_vol_internal *vip;
00565         struct bu_vls   str;
00566         FILE            *fp;
00567         int             nbytes;
00568         register int    y;
00569         register int    z;
00570         mat_t           tmat;
00571         int             ret;
00572 
00573         BU_CK_EXTERNAL( ep );
00574 
00575         RT_CK_DB_INTERNAL( ip );
00576         ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00577         ip->idb_type = ID_VOL;
00578         ip->idb_meth = &rt_functab[ID_VOL];
00579         ip->idb_ptr = bu_calloc(1, sizeof(struct rt_vol_internal), "rt_vol_internal");
00580         vip = (struct rt_vol_internal *)ip->idb_ptr;
00581         vip->magic = RT_VOL_INTERNAL_MAGIC;
00582 
00583         /* Establish defaults */
00584         MAT_IDN( vip->mat );
00585         vip->lo = 0;
00586         vip->hi = 255;
00587 
00588         /* Default VOL cell size in ideal coordinates is one unit/cell */
00589         VSETALL( vip->cellsize, 1 );
00590 
00591         bu_vls_init( &str );
00592         bu_vls_strncpy( &str, ep->ext_buf, ep->ext_nbytes );
00593         if( bu_struct_parse( &str, rt_vol_parse, (char *)vip ) < 0 )  {
00594                 bu_vls_free( &str );
00595                 return -2;
00596         }
00597         bu_vls_free( &str );
00598 
00599         /* Check for reasonable values */
00600         if( vip->file[0] == '\0' || vip->xdim < 1 ||
00601             vip->ydim < 1 || vip->zdim < 1 || vip->mat[15] <= 0.0 ||
00602             vip->lo < 0 || vip->hi > 255 )  {
00603                 bu_struct_print("Unreasonable VOL parameters", rt_vol_parse,
00604                         (char *)vip );
00605                 return(-1);
00606         }
00607 
00608         /* Apply any modeling transforms to get final matrix */
00609         bn_mat_mul( tmat, mat, vip->mat );
00610         MAT_COPY( vip->mat, tmat );
00611 
00612         /* Get bit map from .bw(5) file */
00613         nbytes = (vip->xdim+VOL_XWIDEN*2)*
00614                 (vip->ydim+VOL_YWIDEN*2)*
00615                 (vip->zdim+VOL_ZWIDEN*2);
00616         vip->map = (unsigned char *)bu_calloc( 1, nbytes, "vol_import bitmap" );
00617 
00618         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00619         if( (fp = fopen(vip->file, "r")) == NULL )  {
00620                 perror(vip->file);
00621                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00622                 return(-1);
00623         }
00624         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00625 
00626         /* Because of in-memory padding, read each scanline separately */
00627         for( z=0; z < vip->zdim; z++ )  {
00628                 for( y=0; y < vip->ydim; y++ )  {
00629                         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00630                         ret = fread( &VOL(vip, 0, y, z), vip->xdim, 1, fp ); /* res_syscall */
00631                         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00632                         if( ret < 1 )  {
00633                                 bu_log("rt_vol_import(%s): Unable to read whole VOL, y=%d, z=%d\n",
00634                                         vip->file, y, z);
00635                                 bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00636                                 fclose(fp);
00637                                 bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00638                                 return -1;
00639                         }
00640                 }
00641         }
00642         bu_semaphore_acquire( BU_SEM_SYSCALL );         /* lock */
00643         fclose(fp);
00644         bu_semaphore_release( BU_SEM_SYSCALL );         /* unlock */
00645         return( 0 );
00646 }
00647 
00648 /**
00649  *                      R T _ V O L _ E X P O R T 5
00650  *
00651  *  The name will be added by the caller.
00652  */
00653 int
00654 rt_vol_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00655 {
00656         struct rt_vol_internal  *vip;
00657         struct rt_vol_internal  vol;    /* scaled version */
00658         struct bu_vls           str;
00659 
00660         RT_CK_DB_INTERNAL(ip);
00661         if( ip->idb_type != ID_VOL )  return(-1);
00662         vip = (struct rt_vol_internal *)ip->idb_ptr;
00663         RT_VOL_CK_MAGIC(vip);
00664         vol = *vip;                     /* struct copy */
00665 
00666         /* Apply scale factor */
00667         vol.mat[15] /= local2mm;
00668 
00669         BU_CK_EXTERNAL(ep);
00670 
00671         bu_vls_init( &str );
00672         bu_vls_struct_print( &str, rt_vol_parse, (char *)&vol );
00673         ep->ext_nbytes = bu_vls_strlen( &str );
00674         ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "vol external");
00675 
00676         strcpy( ep->ext_buf, bu_vls_addr(&str) );
00677         bu_vls_free( &str );
00678 
00679         return(0);
00680 }
00681 
00682 /**
00683  *                      R T _ V O L _ D E S C R I B E
00684  *
00685  *  Make human-readable formatted presentation of this solid.
00686  *  First line describes type of solid.
00687  *  Additional lines are indented one tab, and give parameter values.
00688  */
00689 int
00690 rt_vol_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
00691 {
00692         register struct rt_vol_internal *vip =
00693                 (struct rt_vol_internal *)ip->idb_ptr;
00694         register int i;
00695         struct bu_vls substr;
00696         vect_t local;
00697 
00698         RT_VOL_CK_MAGIC(vip);
00699 
00700         VSCALE( local, vip->cellsize, mm2local )
00701         bu_vls_strcat( str, "thresholded volumetric solid (VOL)\n\t");
00702 
00703 /*      bu_vls_struct_print( str, rt_vol_parse, (char *)vip );
00704         bu_vls_strcat( str, "\n" ); */
00705 
00706         bu_vls_init( &substr );
00707         bu_vls_printf( &substr, "  file=\"%s\" w=%d n=%d d=%d lo=%d hi=%d size=%g %g %g\n   mat=",
00708                 vip->file, vip->xdim, vip->ydim, vip->zdim, vip->lo, vip->hi,
00709                 V3INTCLAMPARGS( local ) );
00710         bu_vls_vlscat( str, &substr );
00711         for( i=0 ; i<15 ; i++ )
00712         {
00713                 bu_vls_trunc2( &substr, 0 );
00714                 bu_vls_printf( &substr, "%g,", INTCLAMP(vip->mat[i]) );
00715                 bu_vls_vlscat( str, &substr );
00716         }
00717         bu_vls_trunc2( &substr, 0 );
00718         bu_vls_printf( &substr, "%g\n", INTCLAMP(vip->mat[i]) );
00719         bu_vls_vlscat( str, &substr );
00720 
00721         bu_vls_free( &substr );
00722 
00723         return(0);
00724 }
00725 
00726 /**
00727  *                      R T _ V O L _ I F R E E
00728  *
00729  *  Free the storage associated with the rt_db_internal version of this solid.
00730  */
00731 void
00732 rt_vol_ifree(struct rt_db_internal *ip)
00733 {
00734         register struct rt_vol_internal *vip;
00735 
00736         RT_CK_DB_INTERNAL(ip);
00737         vip = (struct rt_vol_internal *)ip->idb_ptr;
00738         RT_VOL_CK_MAGIC(vip);
00739 
00740         if( vip->map) bu_free( (char *)vip->map, "vol bitmap" );
00741 
00742         vip->magic = 0;                 /* sanity */
00743         vip->map = (unsigned char *)0;
00744         bu_free( (char *)vip, "vol ifree" );
00745         ip->idb_ptr = GENPTR_NULL;      /* sanity */
00746 }
00747 
00748 /**
00749  *                      R T _ V O L _ P R E P
00750  *
00751  *  Returns -
00752  *      0       OK
00753  *      !0      Failure
00754  *
00755  *  Implicit return -
00756  *      A struct rt_vol_specific is created, and it's address is stored
00757  *      in stp->st_specific for use by rt_vol_shot().
00758  */
00759 int
00760 rt_vol_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00761 {
00762         struct rt_vol_internal  *vip;
00763         register struct rt_vol_specific *volp;
00764         vect_t  norm;
00765         vect_t  radvec;
00766         vect_t  diam;
00767         vect_t  small1;
00768 
00769 
00770         vip = (struct rt_vol_internal *)ip->idb_ptr;
00771         RT_VOL_CK_MAGIC(vip);
00772 
00773         BU_GETSTRUCT( volp, rt_vol_specific );
00774         volp->vol_i = *vip;             /* struct copy */
00775         vip->map = (unsigned char *)0;  /* "steal" the bitmap storage */
00776 
00777         /* build Xform matrix from model(world) to ideal(local) space */
00778         bn_mat_inv( volp->vol_mat, vip->mat );
00779 
00780         /* Pre-compute the necessary normals.  Rotate only. */
00781         VSET( norm, 1, 0 , 0 );
00782         MAT3X3VEC( volp->vol_xnorm, vip->mat, norm );
00783         VSET( norm, 0, 1, 0 );
00784         MAT3X3VEC( volp->vol_ynorm, vip->mat, norm );
00785         VSET( norm, 0, 0, 1 );
00786         MAT3X3VEC( volp->vol_znorm, vip->mat, norm );
00787 
00788         stp->st_specific = (genptr_t)volp;
00789 
00790         /* Find bounding RPP of rotated local RPP */
00791         VSETALL( small1, 0 );
00792         VSET( volp->vol_large,
00793                 volp->vol_i.xdim*vip->cellsize[0], volp->vol_i.ydim*vip->cellsize[1], volp->vol_i.zdim*vip->cellsize[2] );/* type conversion */
00794         bn_rotate_bbox( stp->st_min, stp->st_max, vip->mat,
00795                 small1, volp->vol_large );
00796 
00797         /* for now, VOL origin in ideal coordinates is at origin */
00798         VSETALL( volp->vol_origin, 0 );
00799         VADD2( volp->vol_large, volp->vol_large, volp->vol_origin );
00800 
00801         VSUB2( diam, stp->st_max, stp->st_min );
00802         VADD2SCALE( stp->st_center, stp->st_min, stp->st_max, 0.5 );
00803         VSCALE( radvec, diam, 0.5 );
00804         stp->st_aradius = stp->st_bradius = MAGNITUDE( radvec );
00805 
00806         return(0);              /* OK */
00807 }
00808 
00809 /**
00810  *                      R T _ V O L _ P R I N T
00811  */
00812 void
00813 rt_vol_print(register const struct soltab *stp)
00814 {
00815         register const struct rt_vol_specific *volp =
00816                 (struct rt_vol_specific *)stp->st_specific;
00817 
00818         bu_log("vol file = %s\n", volp->vol_i.file );
00819         bu_log("dimensions = (%d, %d, %d)\n",
00820                 volp->vol_i.xdim, volp->vol_i.ydim,
00821                 volp->vol_i.zdim );
00822         VPRINT("model cellsize", volp->vol_i.cellsize);
00823         VPRINT("model grid origin", volp->vol_origin);
00824 }
00825 
00826 /**
00827  *                      R T _ V O L _ N O R M
00828  *
00829  *  Given one ray distance, return the normal and
00830  *  entry/exit point.
00831  *  This is mostly a matter of translating the stored
00832  *  code into the proper normal.
00833  */
00834 void
00835 rt_vol_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00836 {
00837         register struct rt_vol_specific *volp =
00838                 (struct rt_vol_specific *)stp->st_specific;
00839 
00840         VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
00841 
00842         switch( hitp->hit_surfno )  {
00843         case NORM_XPOS:
00844                 VMOVE( hitp->hit_normal, volp->vol_xnorm );
00845                 break;
00846         case NORM_XNEG:
00847                 VREVERSE( hitp->hit_normal, volp->vol_xnorm );
00848                 break;
00849 
00850         case NORM_YPOS:
00851                 VMOVE( hitp->hit_normal, volp->vol_ynorm );
00852                 break;
00853         case NORM_YNEG:
00854                 VREVERSE( hitp->hit_normal, volp->vol_ynorm );
00855                 break;
00856 
00857         case NORM_ZPOS:
00858                 VMOVE( hitp->hit_normal, volp->vol_znorm );
00859                 break;
00860         case NORM_ZNEG:
00861                 VREVERSE( hitp->hit_normal, volp->vol_znorm );
00862                 break;
00863 
00864         default:
00865                 bu_log("rt_vol_norm(%s): surfno=%d bad\n",
00866                         stp->st_name, hitp->hit_surfno );
00867                 VSETALL( hitp->hit_normal, 0 );
00868                 break;
00869         }
00870 }
00871 
00872 /**
00873  *                      R T _ V O L _ C U R V E
00874  *
00875  *  Everything has sharp edges.  This makes things easy.
00876  */
00877 void
00878 rt_vol_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00879 {
00880 /*      register struct rt_vol_specific *volp =
00881                 (struct rt_vol_specific *)stp->st_specific; */
00882 
00883         bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00884         cvp->crv_c1 = cvp->crv_c2 = 0;
00885 }
00886 
00887 /**
00888  *                      R T _ V O L _ U V
00889  *
00890  *  Map the hit point in 2-D into the range 0..1
00891  *  untransformed X becomes U, and Y becomes V.
00892  */
00893 void
00894 rt_vol_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00895 {
00896 /*      register struct rt_vol_specific *volp =
00897                 (struct rt_vol_specific *)stp->st_specific;*/
00898 
00899         /* XXX uv should be xy in ideal space */
00900 }
00901 
00902 /**
00903  *                      R T _ V O L _ F R E E
00904  */
00905 void
00906 rt_vol_free(struct soltab *stp)
00907 {
00908         register struct rt_vol_specific *volp =
00909                 (struct rt_vol_specific *)stp->st_specific;
00910 
00911         bu_free( (char *)volp->vol_i.map, "vol_map" );
00912         bu_free( (char *)volp, "rt_vol_specific" );
00913 }
00914 
00915 int
00916 rt_vol_class(void)
00917 {
00918         return(0);
00919 }
00920 
00921 /**
00922  *                      R T _ V O L _ P L O T
00923  */
00924 int
00925 rt_vol_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00926 {
00927         register struct rt_vol_internal *vip;
00928         register short  x,y,z;
00929         register short  v1,v2;
00930         point_t         a,b,c,d;
00931 
00932         RT_CK_DB_INTERNAL(ip);
00933         vip = (struct rt_vol_internal *)ip->idb_ptr;
00934         RT_VOL_CK_MAGIC(vip);
00935 
00936         /*
00937          *  Scan across in Z & X.  For each X position, scan down Y,
00938          *  looking for the longest run of edge.
00939          */
00940         for( z=-1; z<=vip->zdim; z++ )  {
00941                 for( x=-1; x<=vip->xdim; x++ )  {
00942                         for( y=-1; y<=vip->ydim; y++ )  {
00943                                 v1 = VOL(vip, x,y,z);
00944                                 v2 = VOL(vip, x+1,y,z);
00945                                 if( OK(vip, v1) == OK(vip, v2) )  continue;
00946                                 /* Note start point, continue scan */
00947                                 VSET( a, x+0.5, y-0.5, z-0.5 );
00948                                 VSET( b, x+0.5, y-0.5, z+0.5 );
00949                                 for( ++y; y<=vip->ydim; y++ )  {
00950                                         v1 = VOL(vip, x,y,z);
00951                                         v2 = VOL(vip, x+1,y,z);
00952                                         if( OK(vip, v1) == OK(vip, v2) )
00953                                                 break;
00954                                 }
00955                                 /* End of run of edge.  One cell beyond. */
00956                                 VSET( c, x+0.5, y-0.5, z+0.5 );
00957                                 VSET( d, x+0.5, y-0.5, z-0.5 );
00958                                 rt_vol_plate( a,b,c,d, vip->mat, vhead, vip );
00959                         }
00960                 }
00961         }
00962 
00963         /*
00964          *  Scan up in Z & Y.  For each Y position, scan across X
00965          */
00966         for( z=-1; z<=vip->zdim; z++ )  {
00967                 for( y=-1; y<=vip->ydim; y++ )  {
00968                         for( x=-1; x<=vip->xdim; x++ )  {
00969                                 v1 = VOL(vip, x,y,z);
00970                                 v2 = VOL(vip, x,y+1,z);
00971                                 if( OK(vip, v1) == OK(vip, v2) )  continue;
00972                                 /* Note start point, continue scan */
00973                                 VSET( a, x-0.5, y+0.5, z-0.5 );
00974                                 VSET( b, x-0.5, y+0.5, z+0.5 );
00975                                 for( ++x; x<=vip->xdim; x++ )  {
00976                                         v1 = VOL(vip, x,y,z);
00977                                         v2 = VOL(vip, x,y+1,z);
00978                                         if( OK(vip, v1) == OK(vip, v2) )
00979                                                 break;
00980                                 }
00981                                 /* End of run of edge.  One cell beyond */
00982                                 VSET( c, (x-0.5), (y+0.5), (z+0.5) );
00983                                 VSET( d, (x-0.5), (y+0.5), (z-0.5) );
00984                                 rt_vol_plate( a,b,c,d, vip->mat, vhead, vip );
00985                         }
00986                 }
00987         }
00988 
00989         /*
00990          * Scan across in Y & X.  For each X position pair edge, scan up Z.
00991          */
00992         for( x=-1; x<=vip->xdim; x++ )  {
00993                 for( z=-1; z<=vip->zdim; z++ )  {
00994                         for( y=-1; y<=vip->ydim; y++ )  {
00995                                 v1 = VOL(vip, x,y,z);
00996                                 v2 = VOL(vip, x,y,z+1);
00997                                 if( OK(vip, v1) == OK(vip, v2) )  continue;
00998                                 /* Note start point, continue scan */
00999                                 VSET( a, (x-0.5), (y-0.5), (z+0.5) );
01000                                 VSET( b, (x+0.5), (y-0.5), (z+0.5) );
01001                                 for( ++y; y<=vip->ydim; y++ )  {
01002                                         v1 = VOL(vip, x,y,z);
01003                                         v2 = VOL(vip, x,y,z+1);
01004                                         if( OK(vip, v1) == OK(vip, v2) )
01005                                                 break;
01006                                 }
01007                                 /* End of run of edge.  One cell beyond */
01008                                 VSET( c, (x+0.5), (y-0.5), (z+0.5) );
01009                                 VSET( d, (x-0.5), (y-0.5), (z+0.5) );
01010                                 rt_vol_plate( a,b,c,d, vip->mat, vhead, vip );
01011                         }
01012                 }
01013         }
01014         return(0);
01015 }
01016 
01017 /**
01018  *                      R T _ V O L _ P L A T E
01019  */
01020 void
01021 rt_vol_plate(fastf_t *a, fastf_t *b, fastf_t *c, fastf_t *d, register fastf_t *mat, register struct bu_list *vhead, register struct rt_vol_internal *vip)
01022 {
01023         LOCAL point_t   s;              /* scaled original point */
01024         LOCAL point_t   arot, prot;
01025 
01026         VELMUL( s, vip->cellsize, a );
01027         MAT4X3PNT( arot, mat, s );
01028         RT_ADD_VLIST( vhead, arot, BN_VLIST_LINE_MOVE );
01029 
01030         VELMUL( s, vip->cellsize, b );
01031         MAT4X3PNT( prot, mat, s );
01032         RT_ADD_VLIST( vhead, prot, BN_VLIST_LINE_DRAW );
01033 
01034         VELMUL( s, vip->cellsize, c );
01035         MAT4X3PNT( prot, mat, s );
01036         RT_ADD_VLIST( vhead, prot, BN_VLIST_LINE_DRAW );
01037 
01038         VELMUL( s, vip->cellsize, d );
01039         MAT4X3PNT( prot, mat, s );
01040         RT_ADD_VLIST( vhead, prot, BN_VLIST_LINE_DRAW );
01041 
01042         RT_ADD_VLIST( vhead, arot, BN_VLIST_LINE_DRAW );
01043 }
01044 
01045 /**
01046  *                      R T _ V O L _ T E S S
01047  */
01048 int
01049 rt_vol_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01050 {
01051         struct rt_vol_internal  *vip;
01052         register int    x,y,z;
01053         int             i;
01054         struct shell    *s;
01055         struct vertex   *verts[4];
01056         struct faceuse  *fu;
01057         struct model    *m_tmp;
01058         struct nmgregion *r_tmp;
01059 
01060         NMG_CK_MODEL( m );
01061         BN_CK_TOL( tol );
01062         RT_CK_TESS_TOL( ttol );
01063 
01064         RT_CK_DB_INTERNAL(ip);
01065         vip = (struct rt_vol_internal *)ip->idb_ptr;
01066         RT_VOL_CK_MAGIC(vip);
01067 
01068         /* make region, shell, vertex */
01069         m_tmp = nmg_mm();
01070         r_tmp = nmg_mrsv( m_tmp );
01071         s = BU_LIST_FIRST(shell, &r_tmp->s_hd);
01072 
01073         for( x=0 ; x<vip->xdim ; x++ )
01074         {
01075                 for( y=0 ; y<vip->ydim ; y++ )
01076                 {
01077                         for( z=0 ; z<vip->zdim ; z++ )
01078                         {
01079                                 point_t pt,pt1;
01080 
01081                                 /* skip empty cells */
01082                                 if( !OK( vip , VOL( vip , x , y , z ) ) )
01083                                         continue;
01084 
01085                                 /* check neighboring cells, make a face where needed */
01086 
01087                                 /* check z+1 */
01088                                 if( !OK( vip , VOL( vip , x , y , z+1 ) ) )
01089                                 {
01090                                         for( i=0 ; i<4 ; i++ )
01091                                                 verts[i] = (struct vertex *)NULL;
01092 
01093                                         fu = nmg_cface( s , verts , 4 );
01094 
01095                                         VSET( pt , x+.5 , y-.5 , z+.5 );
01096                                         VELMUL( pt1 , vip->cellsize , pt );
01097                                         MAT4X3PNT( pt , vip->mat , pt1 );
01098                                         nmg_vertex_gv( verts[0] , pt );
01099                                         VSET( pt , x+.5 , y+.5 , z+.5 );
01100                                         VELMUL( pt1 , vip->cellsize , pt );
01101                                         MAT4X3PNT( pt , vip->mat , pt1 );
01102                                         nmg_vertex_gv( verts[1] , pt );
01103                                         VSET( pt , x-.5 , y+.5 , z+.5 );
01104                                         VELMUL( pt1 , vip->cellsize , pt );
01105                                         MAT4X3PNT( pt , vip->mat , pt1 );
01106                                         nmg_vertex_gv( verts[2] , pt );
01107                                         VSET( pt , x-.5 , y-.5 , z+.5 );
01108                                         VELMUL( pt1 , vip->cellsize , pt );
01109                                         MAT4X3PNT( pt , vip->mat , pt1 );
01110                                         nmg_vertex_gv( verts[3] , pt );
01111 
01112                                         if( nmg_fu_planeeqn( fu , tol ) )
01113                                                 goto fail;
01114                                 }
01115 
01116                                 /* check z-1 */
01117                                 if( !OK( vip , VOL( vip , x , y , z-1 ) ) )
01118                                 {
01119                                         for( i=0 ; i<4 ; i++ )
01120                                                 verts[i] = (struct vertex *)NULL;
01121 
01122                                         fu = nmg_cface( s , verts , 4 );
01123 
01124                                         VSET( pt , x+.5 , y-.5 , z-.5 );
01125                                         VELMUL( pt1 , vip->cellsize , pt );
01126                                         MAT4X3PNT( pt , vip->mat , pt1 );
01127                                         nmg_vertex_gv( verts[3] , pt );
01128                                         VSET( pt , x+.5 , y+.5 , z-.5 );
01129                                         VELMUL( pt1 , vip->cellsize , pt );
01130                                         MAT4X3PNT( pt , vip->mat , pt1 );
01131                                         nmg_vertex_gv( verts[2] , pt );
01132                                         VSET( pt , x-.5 , y+.5 , z-.5 );
01133                                         VELMUL( pt1 , vip->cellsize , pt );
01134                                         MAT4X3PNT( pt , vip->mat , pt1 );
01135                                         nmg_vertex_gv( verts[1] , pt );
01136                                         VSET( pt , x-.5 , y-.5 , z-.5 );
01137                                         VELMUL( pt1 , vip->cellsize , pt );
01138                                         MAT4X3PNT( pt , vip->mat , pt1 );
01139                                         nmg_vertex_gv( verts[0] , pt );
01140 
01141                                         if( nmg_fu_planeeqn( fu , tol ) )
01142                                                 goto fail;
01143                                 }
01144 
01145                                 /* check y+1 */
01146                                 if( !OK( vip , VOL( vip , x , y+1 , z ) ) )
01147                                 {
01148                                         for( i=0 ; i<4 ; i++ )
01149                                                 verts[i] = (struct vertex *)NULL;
01150 
01151                                         fu = nmg_cface( s , verts , 4 );
01152 
01153                                         VSET( pt , x+.5 , y+.5 , z+.5 );
01154                                         VELMUL( pt1 , vip->cellsize , pt );
01155                                         MAT4X3PNT( pt , vip->mat , pt1 );
01156                                         nmg_vertex_gv( verts[0] , pt );
01157                                         VSET( pt , x+.5 , y+.5 , z-.5 );
01158                                         VELMUL( pt1 , vip->cellsize , pt );
01159                                         MAT4X3PNT( pt , vip->mat , pt1 );
01160                                         nmg_vertex_gv( verts[1] , pt );
01161                                         VSET( pt , x-.5 , y+.5 , z-.5 );
01162                                         VELMUL( pt1 , vip->cellsize , pt );
01163                                         MAT4X3PNT( pt , vip->mat , pt1 );
01164                                         nmg_vertex_gv( verts[2] , pt );
01165                                         VSET( pt , x-.5 , y+.5 , z+.5 );
01166                                         VELMUL( pt1 , vip->cellsize , pt );
01167                                         MAT4X3PNT( pt , vip->mat , pt1 );
01168                                         nmg_vertex_gv( verts[3] , pt );
01169 
01170                                         if( nmg_fu_planeeqn( fu , tol ) )
01171                                                 goto fail;
01172                                 }
01173 
01174                                 /* check y-1 */
01175                                 if( !OK( vip , VOL( vip , x , y-1 , z ) ) )
01176                                 {
01177                                         for( i=0 ; i<4 ; i++ )
01178                                                 verts[i] = (struct vertex *)NULL;
01179 
01180                                         fu = nmg_cface( s , verts , 4 );
01181 
01182                                         VSET( pt , x+.5 , y-.5 , z+.5 );
01183                                         VELMUL( pt1 , vip->cellsize , pt );
01184                                         MAT4X3PNT( pt , vip->mat , pt1 );
01185                                         nmg_vertex_gv( verts[3] , pt );
01186                                         VSET( pt , x+.5 , y-.5 , z-.5 );
01187                                         VELMUL( pt1 , vip->cellsize , pt );
01188                                         MAT4X3PNT( pt , vip->mat , pt1 );
01189                                         nmg_vertex_gv( verts[2] , pt );
01190                                         VSET( pt , x-.5 , y-.5 , z-.5 );
01191                                         VELMUL( pt1 , vip->cellsize , pt );
01192                                         MAT4X3PNT( pt , vip->mat , pt1 );
01193                                         nmg_vertex_gv( verts[1] , pt );
01194                                         VSET( pt , x-.5 , y-.5 , z+.5 );
01195                                         VELMUL( pt1 , vip->cellsize , pt );
01196                                         MAT4X3PNT( pt , vip->mat , pt1 );
01197                                         nmg_vertex_gv( verts[0] , pt );
01198 
01199                                         if( nmg_fu_planeeqn( fu , tol ) )
01200                                                 goto fail;
01201                                 }
01202 
01203                                 /* check x+1 */
01204                                 if( !OK( vip , VOL( vip , x+1 , y , z ) ) )
01205                                 {
01206                                         for( i=0 ; i<4 ; i++ )
01207                                                 verts[i] = (struct vertex *)NULL;
01208 
01209                                         fu = nmg_cface( s , verts , 4 );
01210 
01211                                         VSET( pt , x+.5 , y-.5 , z-.5 );
01212                                         VELMUL( pt1 , vip->cellsize , pt );
01213                                         MAT4X3PNT( pt , vip->mat , pt1 );
01214                                         nmg_vertex_gv( verts[0] , pt );
01215                                         VSET( pt , x+.5 , y+.5 , z-.5 );
01216                                         VELMUL( pt1 , vip->cellsize , pt );
01217                                         MAT4X3PNT( pt , vip->mat , pt1 );
01218                                         nmg_vertex_gv( verts[1] , pt );
01219                                         VSET( pt , x+.5 , y+.5 , z+.5 );
01220                                         VELMUL( pt1 , vip->cellsize , pt );
01221                                         MAT4X3PNT( pt , vip->mat , pt1 );
01222                                         nmg_vertex_gv( verts[2] , pt );
01223                                         VSET( pt , x+.5 , y-.5 , z+.5 );
01224                                         VELMUL( pt1 , vip->cellsize , pt );
01225                                         MAT4X3PNT( pt , vip->mat , pt1 );
01226                                         nmg_vertex_gv( verts[3] , pt );
01227 
01228                                         if( nmg_fu_planeeqn( fu , tol ) )
01229                                                 goto fail;
01230                                 }
01231 
01232                                 /* check x-1 */
01233                                 if( !OK( vip , VOL( vip , x-1 , y , z ) ) )
01234                                 {
01235                                         for( i=0 ; i<4 ; i++ )
01236                                                 verts[i] = (struct vertex *)NULL;
01237 
01238                                         fu = nmg_cface( s , verts , 4 );
01239 
01240                                         VSET( pt , x-.5 , y-.5 , z-.5 );
01241                                         VELMUL( pt1 , vip->cellsize , pt );
01242                                         MAT4X3PNT( pt , vip->mat , pt1 );
01243                                         nmg_vertex_gv( verts[3] , pt );
01244                                         VSET( pt , x-.5 , y+.5 , z-.5 );
01245                                         VELMUL( pt1 , vip->cellsize , pt );
01246                                         MAT4X3PNT( pt , vip->mat , pt1 );
01247                                         nmg_vertex_gv( verts[2] , pt );
01248                                         VSET( pt , x-.5 , y+.5 , z+.5 );
01249                                         VELMUL( pt1 , vip->cellsize , pt );
01250                                         MAT4X3PNT( pt , vip->mat , pt1 );
01251                                         nmg_vertex_gv( verts[1] , pt );
01252                                         VSET( pt , x-.5 , y-.5 , z+.5 );
01253                                         VELMUL( pt1 , vip->cellsize , pt );
01254                                         MAT4X3PNT( pt , vip->mat , pt1 );
01255                                         nmg_vertex_gv( verts[0] , pt );
01256 
01257                                         if( nmg_fu_planeeqn( fu , tol ) )
01258                                                 goto fail;
01259                                 }
01260                         }
01261                 }
01262         }
01263 
01264         nmg_region_a( r_tmp , tol );
01265 
01266         /* fuse model */
01267         nmg_model_fuse( m_tmp , tol );
01268 
01269         /* simplify shell */
01270         nmg_shell_coplanar_face_merge( s, tol, 1 );
01271 
01272         /* kill snakes */
01273         for( BU_LIST_FOR( fu , faceuse , &s->fu_hd ) )
01274         {
01275                 struct loopuse *lu;
01276 
01277                 NMG_CK_FACEUSE( fu );
01278 
01279                 if( fu->orientation != OT_SAME )
01280                         continue;
01281 
01282                 for( BU_LIST_FOR( lu , loopuse , &fu->lu_hd ) )
01283                         (void)nmg_kill_snakes( lu );
01284         }
01285 
01286         (void)nmg_unbreak_region_edges( (long *)(&s->l) );
01287 
01288         (void)nmg_mark_edges_real( (long *)&s->l );
01289 
01290         nmg_merge_models( m , m_tmp );
01291         *r = r_tmp;
01292 
01293         return( 0 );
01294 
01295 fail:
01296         nmg_km( m_tmp );
01297         *r = (struct nmgregion *)NULL;
01298 
01299         return( -1 );
01300 }
01301 
01302 /*
01303  * Local Variables:
01304  * mode: C
01305  * tab-width: 8
01306  * c-basic-offset: 4
01307  * indent-tabs-mode: t
01308  * End:
01309  * ex: shiftwidth=4 tabstop=8
01310  */

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