prep.c

Go to the documentation of this file.
00001 /*                          P R E P . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1990-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup ray */
00023 /*@{*/
00024 /** @file prep.c
00025  *  Manage one-time preparations to be done before actual
00026  *  ray-tracing can commence.
00027  *
00028  *  Author -
00029  *      Michael John Muuss
00030  *
00031  *  Source -
00032  *      SECAD/VLD Computing Consortium, Bldg 394
00033  *      The U. S. Army Ballistic Research Laboratory
00034  *      Aberdeen Proving Ground, Maryland  21005
00035  *
00036  */
00037 /*@}*/
00038 
00039 #ifndef lint
00040 static const char RCSprep[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/prep.c,v 14.16 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00041 #endif
00042 
00043 #include "common.h"
00044 
00045 #include <stddef.h>
00046 #include <stdio.h>
00047 #include <math.h>
00048 #ifdef HAVE_STRING_H
00049 #  include <string.h>
00050 #else
00051 #  include <strings.h>
00052 #endif
00053 #ifdef HAVE_UNISTD_H
00054 #  include <unistd.h>
00055 #endif
00056 
00057 #include "machine.h"
00058 #include "bu.h"
00059 #include "vmath.h"
00060 #include "bn.h"
00061 #include "raytrace.h"
00062 #include "plot3.h"
00063 
00064 #include "./debug.h"
00065 
00066 
00067 BU_EXTERN(void          rt_ck, (struct rt_i     *rtip));
00068 
00069 HIDDEN void     rt_solid_bitfinder(register union tree *treep, struct region *regp, struct resource *resp);
00070 
00071 extern struct resource  rt_uniresource;         /* from shoot.c */
00072 
00073 /* XXX Need rt_init_rtg(), rt_clean_rtg() */
00074 
00075 /*
00076  *                      R T _ N E W _ R T I
00077  *
00078  *  Given a db_i database instance, create an rt_i instance.
00079  *  If caller just called db_open, they need to do a db_close(),
00080  *  because we have cloned our own instance of the db_i.
00081  */
00082 struct rt_i *
00083 rt_new_rti(struct db_i *dbip)
00084 {
00085         register struct rt_i    *rtip;
00086         register int            i;
00087 
00088         RT_CK_DBI( dbip );
00089 
00090         /* XXX Move to rt_global_init() ? */
00091         if( BU_LIST_FIRST( bu_list, &rt_g.rtg_vlfree ) == 0 )  {
00092                 BU_LIST_INIT( &rt_g.rtg_vlfree );
00093         }
00094 
00095         BU_GETSTRUCT( rtip, rt_i );
00096         rtip->rti_magic = RTI_MAGIC;
00097         for( i=0; i < RT_DBNHASH; i++ )  {
00098                 BU_LIST_INIT( &(rtip->rti_solidheads[i]) );
00099         }
00100         rtip->rti_dbip = db_clone_dbi( dbip, (long *)rtip );
00101         rtip->needprep = 1;
00102 
00103         BU_LIST_INIT( &rtip->HeadRegion );
00104 
00105         /* This table is used for discovering the per-cpu resource structures */
00106         bu_ptbl_init( &rtip->rti_resources, MAX_PSW+1, "rti_resources ptbl" );
00107         BU_PTBL_END(&rtip->rti_resources) = MAX_PSW+1;  /* Make 'em all available */
00108 
00109         rt_uniresource.re_magic = RESOURCE_MAGIC;
00110 
00111         /* list of invisible light regions to be deleted after light_init() */
00112         bu_ptbl_init( &rtip->delete_regs, 8, "rt_i delete regions list" );
00113 
00114         VSETALL( rtip->mdl_min,  INFINITY );
00115         VSETALL( rtip->mdl_max, -INFINITY );
00116         VSETALL( rtip->rti_inf_box.bn.bn_min, -0.1 );
00117         VSETALL( rtip->rti_inf_box.bn.bn_max,  0.1 );
00118         rtip->rti_inf_box.bn.bn_type = CUT_BOXNODE;
00119 
00120         /* XXX These defaults need to be improved */
00121         rtip->rti_tol.magic = BN_TOL_MAGIC;
00122         rtip->rti_tol.dist = 0.0005;
00123         rtip->rti_tol.dist_sq = rtip->rti_tol.dist * rtip->rti_tol.dist;
00124         rtip->rti_tol.perp = 1e-6;
00125         rtip->rti_tol.para = 1 - rtip->rti_tol.perp;
00126 
00127         rtip->rti_ttol.magic = RT_TESS_TOL_MAGIC;
00128         rtip->rti_ttol.abs = 0.0;
00129         rtip->rti_ttol.rel = 0.01;
00130         rtip->rti_ttol.norm = 0;
00131 
00132         rtip->rti_max_beam_radius = 175.0/2;    /* Largest Army bullet */
00133 
00134         /* This sets the space partitioning algorithm to Mike's original
00135          * non-uniform binary space paritioning tree.
00136          * If you change this to anything else, you must also modify
00137          * "rt_find_backing_dist()" (in shoot.c), to handle the different
00138          * alogorithm            -JRA
00139          */
00140         rtip->rti_space_partition = RT_PART_NUBSPT;
00141 
00142         rtip->rti_nugrid_dimlimit = 0;
00143         rtip->rti_nu_gfactor = RT_NU_GFACTOR_DEFAULT;
00144 
00145         /*
00146          *  Zero the solid instancing counters in dbip database instance.
00147          *  Done here because the same dbip could be used by multiple
00148          *  rti's, and rt_gettrees() can be called multiple times on
00149          *  this one rtip.
00150          *  There is a race (collision!) here on d_uses if rt_gettrees()
00151          *  is called on another rtip of the same dbip
00152          *  before this rtip is done
00153          *  with all it's treewalking.
00154          */
00155         for( i=0; i < RT_DBNHASH; i++ )  {
00156                 register struct directory       *dp;
00157 
00158                 dp = rtip->rti_dbip->dbi_Head[i];
00159                 for( ; dp != DIR_NULL; dp = dp->d_forw )
00160                         dp->d_uses = 0;
00161         }
00162 
00163         return rtip;
00164 }
00165 
00166 /*
00167  *                      R T _ F R E E _ R T I
00168  *
00169  *  Release all the dynamic storage acquired by rt_dirbuild() and
00170  *  any subsequent ray-tracing operations.
00171  *
00172  *  Any PARALLEL resource structures are freed by rt_clean().
00173  *  Note that the rt_g structure needs to be cleaned separately.
00174  */
00175 void
00176 rt_free_rti(struct rt_i *rtip)
00177 {
00178         RT_CK_RTI(rtip);
00179 
00180         rt_clean( rtip );
00181 
00182 #if 0
00183         /* XXX These can't be freed here either, because we allocated
00184          * them all on rt_uniresource, which doesn't discriminate
00185          * on which db_i they go with.
00186          */
00187 
00188         /* The 'struct directory' guys are malloc()ed in big blocks */
00189         resp->re_directory_hd = NULL;   /* abandon list */
00190         if( BU_LIST_IS_INITIALIZED( &resp->re_directory_blocks.l ) )  {
00191                 struct directory **dpp;
00192                 BU_CK_PTBL( &resp->re_directory_blocks );
00193                 for( BU_PTBL_FOR( dpp, (struct directory **), &resp->re_directory_blocks ) )  {
00194                         RT_CK_DIR(*dpp);        /* Head of block will be a valid seg */
00195                         bu_free( (genptr_t)(*dpp), "struct directory block" );
00196                 }
00197                 bu_ptbl_free( &resp->re_directory_blocks );
00198         }
00199 #endif
00200 
00201         db_close_client( rtip->rti_dbip, (long *)rtip );
00202         rtip->rti_dbip = (struct db_i *)NULL;
00203 
00204         /* Freeing the actual resource structures's memory is the app's job */
00205         bu_ptbl_free( &rtip->rti_resources );
00206 
00207         bu_free( (char *)rtip, "struct rt_i" );
00208 }
00209 
00210 /*
00211  *                      R T _ P R E P _ P A R A L L E L
00212  *
00213  *  This routine should be called just before the first call to rt_shootray().
00214  *  It should only be called ONCE per execution, unless rt_clean() is
00215  *  called inbetween.
00216  *
00217  *  Because this can be called from rt_shootray(), it may potentially be
00218  *  called ncpu times, hence the critical section.
00219  */
00220 void
00221 rt_prep_parallel(register struct rt_i *rtip, int ncpu)
00222 {
00223         register struct region *regp;
00224         register struct soltab *stp;
00225         register int            i;
00226         struct resource         *resp;
00227         vect_t                  diag;
00228 
00229         RT_CK_RTI(rtip);
00230 
00231         if(RT_G_DEBUG&DEBUG_REGIONS)  bu_log("rt_prep_parallel(%s,%d,ncpu=%d) START\n",
00232                         rtip->rti_dbip->dbi_filename,
00233                         rtip->rti_dbip->dbi_uses, ncpu);
00234 
00235         bu_semaphore_acquire(RT_SEM_RESULTS);   /* start critical section */
00236         if(!rtip->needprep)  {
00237                 bu_log("WARNING: rt_prep_parallel(%s,%d) invoked a second time, ignored",
00238                         rtip->rti_dbip->dbi_filename,
00239                         rtip->rti_dbip->dbi_uses);
00240                 bu_semaphore_release(RT_SEM_RESULTS);
00241                 return;
00242         }
00243 
00244         if( rtip->nsolids <= 0 ) {
00245             if( rtip->rti_air_discards > 0 )
00246                 bu_log("rt_prep_parallel(%s,%d): %d primitives discarded due to air regions\n",
00247                        rtip->rti_dbip->dbi_filename,
00248                        rtip->rti_dbip->dbi_uses,
00249                        rtip->rti_air_discards );
00250             rt_bomb("rt_prep_parallel:  no primitives left to prep\n");
00251         }
00252 
00253         if ( rtip->nregions <= 0 )  {
00254             rt_bomb("rt_prep_parallel:  no regions left to prep\n");
00255         }
00256 
00257         /* In case everything is a halfspace, set a minimum space */
00258         if( rtip->mdl_min[X] >= INFINITY )  {
00259                 bu_log("All primitives are halfspaces, setting minimum\n");
00260                 VSETALL( rtip->mdl_min, -1 );
00261         }
00262         if( rtip->mdl_max[X] <= -INFINITY )  {
00263                 bu_log("All primitives are halfspaces, setting maximum\n");
00264                 VSETALL( rtip->mdl_max, 1 );
00265         }
00266 
00267         /*
00268          *  Enlarge the model RPP just slightly, to avoid nasty
00269          *  effects with a solid's face being exactly on the edge
00270          */
00271         rtip->mdl_min[X] = floor( rtip->mdl_min[X] );
00272         rtip->mdl_min[Y] = floor( rtip->mdl_min[Y] );
00273         rtip->mdl_min[Z] = floor( rtip->mdl_min[Z] );
00274         rtip->mdl_max[X] = ceil( rtip->mdl_max[X] );
00275         rtip->mdl_max[Y] = ceil( rtip->mdl_max[Y] );
00276         rtip->mdl_max[Z] = ceil( rtip->mdl_max[Z] );
00277 
00278         /* Compute radius of a model bounding sphere */
00279         VSUB2( diag, rtip->mdl_max, rtip->mdl_min );
00280         rtip->rti_radius = 0.5 * MAGNITUDE(diag);
00281 
00282         /*  If a resource structure has been provided for us, use it. */
00283         resp = (struct resource *)BU_PTBL_GET(&rtip->rti_resources, 0);
00284         if( !resp )  resp = &rt_uniresource;
00285         RT_CK_RESOURCE(resp);
00286 
00287         /*  Build array of region pointers indexed by reg_bit.
00288          *  Optimize each region's expression tree.
00289          *  Set this region's bit in the bit vector of every solid
00290          *  contained in the subtree.
00291          */
00292         rtip->Regions = (struct region **)bu_calloc(rtip->nregions, sizeof(struct region *), "rtip->Regions[]" );
00293         if(RT_G_DEBUG&DEBUG_REGIONS)  bu_log("rt_prep_parallel(%s,%d) about to optimize regions\n",
00294                         rtip->rti_dbip->dbi_filename,
00295                         rtip->rti_dbip->dbi_uses);
00296         for( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
00297                 /* Ensure bit numbers are unique */
00298                 BU_ASSERT_PTR(rtip->Regions[regp->reg_bit], ==, REGION_NULL);
00299                 rtip->Regions[regp->reg_bit] = regp;
00300                 rt_optim_tree( regp->reg_treetop, resp );
00301                 rt_solid_bitfinder( regp->reg_treetop, regp, resp );
00302                 if(RT_G_DEBUG&DEBUG_REGIONS)  {
00303                         db_ck_tree( regp->reg_treetop);
00304                         rt_pr_region( regp );
00305                 }
00306         }
00307         if(RT_G_DEBUG&DEBUG_REGIONS)  {
00308                 bu_log("rt_prep_parallel() printing primitives' region pointers\n");
00309                 RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
00310                         bu_log("solid %s ", stp->st_name);
00311                         bu_pr_ptbl( "st_regions", &stp->st_regions, 1 );
00312                 } RT_VISIT_ALL_SOLTABS_END
00313         }
00314 
00315         /*  Space for array of soltab pointers indexed by solid bit number.
00316          *  Include enough extra space for an extra bitv_t's worth of bits,
00317          *  to handle round-up.
00318          */
00319         rtip->rti_Solids = (struct soltab **)bu_calloc(
00320                 rtip->nsolids + (1<<BITV_SHIFT), sizeof(struct soltab *),
00321                 "rtip->rti_Solids[]" );
00322         /*
00323          *  Build array of solid table pointers indexed by solid ID.
00324          *  Last element for each kind will be found in
00325          *      rti_sol_by_type[id][rti_nsol_by_type[id]-1]
00326          */
00327         RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
00328                 /* Ensure bit numbers are unique */
00329                 register struct soltab **ssp = &rtip->rti_Solids[stp->st_bit];
00330                 if( *ssp != SOLTAB_NULL )  {
00331                         bu_log("rti_Solids[%d] is non-empty! rtip=x%x\n", stp->st_bit, rtip);
00332                         bu_log("Existing entry is (st_rtip=x%x):\n", (*ssp)->st_rtip);
00333                         rt_pr_soltab(*ssp);
00334                         bu_log("2nd soltab also claiming that bit is (st_rtip=x%x):\n", stp->st_rtip);
00335                         rt_pr_soltab(stp);
00336                 }
00337                 BU_ASSERT_PTR(*ssp, ==, SOLTAB_NULL);
00338                 *ssp = stp;
00339                 rtip->rti_nsol_by_type[stp->st_id]++;
00340         } RT_VISIT_ALL_SOLTABS_END
00341 
00342         /* Find solid type with maximum length (for rt_shootray) */
00343         rtip->rti_maxsol_by_type = 0;
00344         for( i=0; i <= ID_MAX_SOLID; i++ )  {
00345                 if( rtip->rti_nsol_by_type[i] > rtip->rti_maxsol_by_type )
00346                         rtip->rti_maxsol_by_type = rtip->rti_nsol_by_type[i];
00347         }
00348         /* Malloc the storage and zero the counts */
00349         for( i=0; i <= ID_MAX_SOLID; i++ )  {
00350                 if( rtip->rti_nsol_by_type[i] <= 0 )  continue;
00351                 rtip->rti_sol_by_type[i] = (struct soltab **)bu_calloc(
00352                         rtip->rti_nsol_by_type[i],
00353                         sizeof(struct soltab *),
00354                         "rti_sol_by_type[]" );
00355                 rtip->rti_nsol_by_type[i] = 0;
00356         }
00357         /* Fill in the array and rebuild the count (aka index) */
00358         RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
00359                 register int    id;
00360                 id = stp->st_id;
00361                 rtip->rti_sol_by_type[id][rtip->rti_nsol_by_type[id]++] = stp;
00362         } RT_VISIT_ALL_SOLTABS_END
00363         if( RT_G_DEBUG & (DEBUG_DB|DEBUG_SOLIDS) )  {
00364                 bu_log("rt_prep_parallel(%s,%d) printing number of prims by type\n",
00365                         rtip->rti_dbip->dbi_filename,
00366                         rtip->rti_dbip->dbi_uses);
00367                 for( i=1; i <= ID_MAX_SOLID; i++ )  {
00368                         bu_log("%5d %s (%d)\n",
00369                                 rtip->rti_nsol_by_type[i],
00370                                 rt_functab[i].ft_name,
00371                                 i );
00372                 }
00373         }
00374 
00375         /* If region-id expression file exists, process it */
00376         rt_regionfix(rtip);
00377 
00378         /* For plotting, compute a slight enlargement of the model RPP,
00379          * to allow room for rays clipped to the model RPP to be depicted.
00380          * Always do this, because application debugging may use it too.
00381          */
00382         {
00383                 register fastf_t f, diff;
00384 
00385                 diff = (rtip->mdl_max[X] - rtip->mdl_min[X]);
00386                 f = (rtip->mdl_max[Y] - rtip->mdl_min[Y]);
00387                 if( f > diff )  diff = f;
00388                 f = (rtip->mdl_max[Z] - rtip->mdl_min[Z]);
00389                 if( f > diff )  diff = f;
00390                 diff *= 0.1;    /* 10% expansion of box */
00391                 rtip->rti_pmin[0] = rtip->mdl_min[0] - diff;
00392                 rtip->rti_pmin[1] = rtip->mdl_min[1] - diff;
00393                 rtip->rti_pmin[2] = rtip->mdl_min[2] - diff;
00394                 rtip->rti_pmax[0] = rtip->mdl_max[0] + diff;
00395                 rtip->rti_pmax[1] = rtip->mdl_max[1] + diff;
00396                 rtip->rti_pmax[2] = rtip->mdl_max[2] + diff;
00397         }
00398 
00399         /*
00400          *      Partition space
00401          *
00402          *  Multiple CPUs can be used here.
00403          */
00404         for( i=1; i<=CUT_MAXIMUM; i++ ) rtip->rti_ncut_by_type[i] = 0;
00405         rt_cut_it(rtip, ncpu);
00406 
00407         /* Release storage used for bounding RPPs of solid "pieces" */
00408         RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
00409                 if( stp->st_piece_rpps )  {
00410                         bu_free( (char *)stp->st_piece_rpps, "st_piece_rpps[]" );
00411                         stp->st_piece_rpps = NULL;
00412                 }
00413         } RT_VISIT_ALL_SOLTABS_END
00414 
00415         /* Plot bounding RPPs */
00416         if( (RT_G_DEBUG&DEBUG_PLOTBOX) )  {
00417                 FILE    *plotfp;
00418 
00419                 if( (plotfp=fopen("rtrpp.plot", "w"))!=NULL) {
00420                         /* Plot solid bounding boxes, in white */
00421                         pl_color( plotfp, 255, 255, 255 );
00422                         rt_plot_all_bboxes( plotfp, rtip );
00423                         (void)fclose(plotfp);
00424                 }
00425         }
00426 
00427         /* Plot solid outlines */
00428         if( (RT_G_DEBUG&DEBUG_PLOTSOLIDS) )  {
00429                 FILE            *plotfp;
00430 
00431                 if( (plotfp=fopen("rtsolids.pl", "w")) != NULL)  {
00432                         rt_plot_all_solids( plotfp, rtip, resp );
00433                         (void)fclose(plotfp);
00434                 }
00435         }
00436         rtip->needprep = 0;             /* prep is done */
00437         bu_semaphore_release(RT_SEM_RESULTS);   /* end critical section */
00438 
00439         if(RT_G_DEBUG&DEBUG_REGIONS)  bu_log("rt_prep_parallel(%s,%d,ncpu=%d) FINISH\n",
00440                         rtip->rti_dbip->dbi_filename,
00441                         rtip->rti_dbip->dbi_uses, ncpu);
00442 }
00443 
00444 /*
00445  *                      R T _ P R E P
00446  *
00447  *  Compatability stub.  Only uses 1 CPU.
00448  */
00449 void
00450 rt_prep(register struct rt_i *rtip)
00451 {
00452         RT_CK_RTI(rtip);
00453         rt_prep_parallel(rtip, 1);
00454 }
00455 
00456 /*
00457  *                      R T _ P L O T _ A L L _ B B O X E S
00458  *
00459  *  Plot the bounding boxes of all the active solids.
00460  *  Color may be set in advance by the caller.
00461  */
00462 void
00463 rt_plot_all_bboxes(FILE *fp, struct rt_i *rtip)
00464 {
00465         register struct soltab  *stp;
00466 
00467         RT_CK_RTI(rtip);
00468         pdv_3space( fp, rtip->rti_pmin, rtip->rti_pmax );
00469         RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
00470                 /* Ignore "dead" solids in the list.  (They failed prep) */
00471                 if( stp->st_aradius <= 0 )  continue;
00472                 /* Don't draw infinite solids */
00473                 if( stp->st_aradius >= INFINITY )
00474                         continue;
00475                 pdv_3box( fp, stp->st_min, stp->st_max );
00476         } RT_VISIT_ALL_SOLTABS_END
00477 }
00478 
00479 /*
00480  *                      R T _ P L O T _ A L L _ S O L I D S
00481  */
00482 void
00483 rt_plot_all_solids(
00484         FILE            *fp,
00485         struct rt_i     *rtip,
00486         struct resource *resp)
00487 {
00488         register struct soltab  *stp;
00489 
00490         RT_CK_RTI(rtip);
00491 
00492         pdv_3space( fp, rtip->rti_pmin, rtip->rti_pmax );
00493 
00494         RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
00495                 /* Ignore "dead" solids in the list.  (They failed prep) */
00496                 if( stp->st_aradius <= 0 )  continue;
00497 
00498                 /* Don't draw infinite solids */
00499                 if( stp->st_aradius >= INFINITY )
00500                         continue;
00501 
00502                 (void)rt_plot_solid( fp, rtip, stp, resp );
00503         } RT_VISIT_ALL_SOLTABS_END
00504 }
00505 
00506 /*
00507  *                      R T _ V L I S T _ S O L I D
00508  *
00509  *  "Draw" a solid with the same kind of wireframes that MGED would display,
00510  *  appending vectors to an already initialized vlist head.
00511  *
00512  *  Returns -
00513  *      <0      failure
00514  *       0      OK
00515  */
00516 int
00517 rt_vlist_solid(
00518         struct bu_list          *vhead,
00519         struct rt_i             *rtip,
00520         const struct soltab     *stp,
00521         struct resource         *resp)
00522 {
00523         struct rt_db_internal           intern;
00524 
00525         if( rt_db_get_internal( &intern, stp->st_dp, rtip->rti_dbip, stp->st_matp, resp ) < 0 )  {
00526                 bu_log("rt_vlist_solid(%s): rt_db_get_internal() failed\n",
00527                         stp->st_name);
00528                 return(-1);                     /* FAIL */
00529         }
00530         RT_CK_DB_INTERNAL( &intern );
00531 
00532         if( rt_functab[intern.idb_type].ft_plot(
00533                 vhead,
00534                 &intern,
00535                 &rtip->rti_ttol,
00536                 &rtip->rti_tol
00537             ) < 0 )  {
00538                 bu_log("rt_vlist_solid(%s): ft_plot() failure\n",
00539                         stp->st_name);
00540                 rt_db_free_internal( &intern, resp );
00541                 return(-2);
00542         }
00543         rt_db_free_internal( &intern, resp );
00544         return 0;
00545 }
00546 
00547 /*
00548  *                      R T _ P L O T _ S O L I D
00549  *
00550  *  Plot a solid with the same kind of wireframes that MGED would display,
00551  *  in UNIX-plot form, on the indicated file descriptor.
00552  *  The caller is responsible for calling pdv_3space().
00553  *
00554  *  Returns -
00555  *      <0      failure
00556  *       0      OK
00557  */
00558 int
00559 rt_plot_solid(
00560         register FILE           *fp,
00561         struct rt_i             *rtip,
00562         const struct soltab     *stp,
00563         struct resource         *resp)
00564 {
00565         struct bu_list                  vhead;
00566         struct region                   *regp;
00567 
00568         RT_CK_RTI(rtip);
00569         RT_CK_SOLTAB(stp);
00570 
00571         BU_LIST_INIT( &vhead );
00572 
00573         if( rt_vlist_solid( &vhead, rtip, stp, resp ) < 0 )  {
00574                 bu_log("rt_plot_solid(%s): rt_vlist_solid() failed\n",
00575                         stp->st_name);
00576                 return(-1);                     /* FAIL */
00577         }
00578 
00579         if( BU_LIST_IS_EMPTY( &vhead ) )  {
00580                 bu_log("rt_plot_solid(%s): no vectors to plot?\n",
00581                         stp->st_name);
00582                 return(-3);             /* FAIL */
00583         }
00584 
00585         /* Take color from one region */
00586         if( (regp = (struct region *)BU_PTBL_GET(&stp->st_regions,0)) != REGION_NULL )  {
00587                 pl_color( fp,
00588                         (int)(255*regp->reg_mater.ma_color[0]),
00589                         (int)(255*regp->reg_mater.ma_color[1]),
00590                         (int)(255*regp->reg_mater.ma_color[2]) );
00591         }
00592 
00593         rt_vlist_to_uplot( fp, &vhead );
00594 
00595         RT_FREE_VLIST( &vhead );
00596         return(0);                      /* OK */
00597 }
00598 
00599 /*                      R T _ I N I T _ R E S O U R C E
00600  *
00601  *  initialize memory resources.
00602  *      This routine should initialize all the same resources
00603  *      that rt_clean_resource() releases.
00604  *      It shouldn't allocate any dynamic memory, just init pointers & lists.
00605  *
00606  *  if( BU_LIST_UNINITIALIZED( &resp->re_parthead ) )
00607  *  indicates that this initialization is needed.
00608  *
00609  *  Note that this routine is also called as part of rt_clean_resource().
00610  *
00611  *  Special case, resp == rt_uniresource, rtip may be NULL (but give it if you have it).
00612  */
00613 void
00614 rt_init_resource(struct resource *resp,
00615                  int            cpu_num,
00616                  struct rt_i    *rtip)
00617 {
00618 
00619         if( resp == &rt_uniresource )  {
00620                 cpu_num = MAX_PSW;              /* array is [MAX_PSW+1] just for this */
00621                 if(rtip)  RT_CK_RTI(rtip);      /* check it if provided */
00622         } else {
00623                 BU_ASSERT_PTR( resp, !=, NULL );
00624                 BU_ASSERT_LONG( cpu_num, >=, 0 );
00625                 if( rtip->rti_treetop ) {
00626                         /* this is a submodel */
00627                         BU_ASSERT_LONG( cpu_num, <, rtip->rti_resources.blen );
00628                 } else {
00629                         BU_ASSERT_LONG( cpu_num, <, MAX_PSW );
00630                 }
00631                 RT_CK_RTI(rtip);                /* mandatory */
00632         }
00633 
00634         resp->re_magic = RESOURCE_MAGIC;
00635         resp->re_cpu = cpu_num;
00636 
00637         /* XXX resp->re_randptr is an "application" (rt) level field. For now. */
00638 
00639         if( BU_LIST_UNINITIALIZED( &resp->re_seg ) )
00640                 BU_LIST_INIT( &resp->re_seg )
00641 
00642         if( BU_LIST_UNINITIALIZED( &resp->re_seg_blocks.l ) )
00643                 bu_ptbl_init( &resp->re_seg_blocks, 64, "re_seg_blocks ptbl" );
00644 
00645         if( BU_LIST_UNINITIALIZED( &resp->re_directory_blocks.l ) )
00646                 bu_ptbl_init( &resp->re_directory_blocks, 64, "re_directory_blocks ptbl" );
00647 
00648         if( BU_LIST_UNINITIALIZED( &resp->re_parthead ) )
00649                 BU_LIST_INIT( &resp->re_parthead )
00650 
00651         if( BU_LIST_UNINITIALIZED( &resp->re_solid_bitv ) )
00652                 BU_LIST_INIT( &resp->re_solid_bitv )
00653 
00654         if( BU_LIST_UNINITIALIZED( &resp->re_region_ptbl ) )
00655                 BU_LIST_INIT( &resp->re_region_ptbl )
00656 
00657         if( BU_LIST_UNINITIALIZED( &resp->re_nmgfree ) )
00658                 BU_LIST_INIT( &resp->re_nmgfree )
00659 
00660         resp->re_boolstack = NULL;
00661         resp->re_boolslen = 0;
00662 
00663         if( rtip == NULL )  return;     /* only in rt_uniresource case */
00664 
00665         /* Ensure that this CPU's resource structure is registered in rt_i */
00666         /* It may already be there when we're called from rt_clean_resource */
00667         {
00668                 struct resource *ores = (struct resource *)
00669                         BU_PTBL_GET(&rtip->rti_resources, cpu_num);
00670                 if( ores != NULL && ores != resp )  {
00671                         bu_log("rt_init_resource(cpu=%d) re-registering resource, had x%x, new=x%x\n",
00672                                 cpu_num,
00673                                 ores,
00674                                 resp );
00675                         bu_bomb("rt_init_resource() re-registration\n");
00676                 }
00677                 BU_PTBL_SET(&rtip->rti_resources, cpu_num, resp);
00678         }
00679 }
00680 
00681 /*
00682  *                      R T _ C L E A N _ R E S O U R C E
00683  *
00684  *  Deallocate the per-cpu "private" memory resources.
00685  *      segment freelist
00686  *      hitmiss freelist for NMG raytracer
00687  *      partition freelist
00688  *      solid_bitv freelist
00689  *      region_ptbl freelist
00690  *      re_boolstack
00691  *
00692  *  Some care is required, as rt_uniresource may not be fully initialized
00693  *  before it gets freed.
00694  *
00695  *  Note that the resource struct's storage is not freed (it may be static
00696  *  or otherwise allocated by a LIBRT application) but any dynamic
00697  *  memory pointed to by it is freed.
00698  *
00699  *  One exception to this is that the re_directory_hd and re_directory_blocks
00700  *  are not touched, because the "directory" structures (which are really
00701  *  part of the db_i) continue to be in use.
00702  */
00703 void
00704 rt_clean_resource(struct rt_i *rtip, struct resource *resp)
00705 {
00706         RT_CK_RTI(rtip);
00707         RT_CK_RESOURCE(resp);
00708 
00709         /*  The 'struct seg' guys are malloc()ed in blocks, not individually,
00710          *  so they're kept track of two different ways.
00711          */
00712         BU_LIST_INIT( &resp->re_seg );  /* abandon the list of individuals */
00713         if( BU_LIST_IS_INITIALIZED( &resp->re_seg_blocks.l ) )  {
00714                 struct seg **spp;
00715                 BU_CK_PTBL( &resp->re_seg_blocks );
00716                 for( BU_PTBL_FOR( spp, (struct seg **), &resp->re_seg_blocks ) )  {
00717                         RT_CK_SEG(*spp);        /* Head of block will be a valid seg */
00718                         bu_free( (genptr_t)(*spp), "struct seg block" );
00719                 }
00720                 bu_ptbl_free( &resp->re_seg_blocks );
00721         }
00722 
00723         /*
00724          *  The 'struct directory' guys are malloc()ed in big blocks,
00725          *  but CAN'T BE FREED HERE!  We are not done with the db_i yet.
00726          */
00727 
00728         /* The "struct hitmiss' guys are individually malloc()ed */
00729         if( BU_LIST_IS_INITIALIZED( &resp->re_nmgfree ) )  {
00730                 struct hitmiss *hitp;
00731                 while( BU_LIST_WHILE( hitp, hitmiss, &resp->re_nmgfree ) )  {
00732                         NMG_CK_HITMISS(hitp);
00733                         BU_LIST_DEQUEUE( (struct bu_list *)hitp );
00734                         bu_free( (genptr_t)hitp, "struct hitmiss" );
00735                 }
00736         }
00737 
00738         /* The 'struct partition' guys are individually malloc()ed */
00739         if( BU_LIST_IS_INITIALIZED( &resp->re_parthead ) )  {
00740                 struct partition *pp;
00741                 while( BU_LIST_WHILE( pp, partition, &resp->re_parthead ) )  {
00742                         RT_CK_PT(pp);
00743                         BU_LIST_DEQUEUE( (struct bu_list *)pp );
00744                         bu_ptbl_free( &pp->pt_seglist );
00745                         bu_free( (genptr_t)pp, "struct partition" );
00746                 }
00747         }
00748 
00749         /* The 'struct bu_bitv' guys on re_solid_bitv are individually malloc()ed */
00750         if( BU_LIST_IS_INITIALIZED( &resp->re_solid_bitv ) )  {
00751                 struct bu_bitv  *bvp;
00752                 while( BU_LIST_WHILE( bvp, bu_bitv, &resp->re_solid_bitv ) )  {
00753                         BU_CK_BITV( bvp );
00754                         BU_LIST_DEQUEUE( &bvp->l );
00755                         bvp->nbits = 0;         /* sanity */
00756                         bu_free( (genptr_t)bvp, "struct bu_bitv" );
00757                 }
00758         }
00759 
00760         /* The 'struct bu_ptbl' guys on re_region_ptbl are individually malloc()ed */
00761         if( BU_LIST_IS_INITIALIZED( &resp->re_region_ptbl ) )  {
00762                 struct bu_ptbl  *tabp;
00763                 while( BU_LIST_WHILE( tabp, bu_ptbl, &resp->re_region_ptbl ) )  {
00764                         BU_CK_PTBL(tabp);
00765                         BU_LIST_DEQUEUE( &tabp->l );
00766                         bu_ptbl_free( tabp );
00767                         bu_free( (genptr_t)tabp, "struct bu_ptbl" );
00768                 }
00769         }
00770 
00771         /* The 're_tree' guys are individually malloc()ed and linked using the 'tb_left' field */
00772         if( resp->re_tree_hd != TREE_NULL ) {
00773                 union tree *tp;
00774 
00775                 tp = resp->re_tree_hd;
00776                 while( tp != TREE_NULL ) {
00777                         resp->re_tree_hd = tp->tr_b.tb_left;
00778                         bu_free( (char *)tp, "union tree in resource struct" );
00779                         tp = resp->re_tree_hd;
00780                 }
00781         }
00782 
00783         /* 're_boolstack' is a simple pointer */
00784         if( resp->re_boolstack )  {
00785                 bu_free( (genptr_t)resp->re_boolstack, "boolstack" );
00786                 resp->re_boolstack = NULL;
00787                 resp->re_boolslen = 0;
00788         }
00789 
00790 /* Release the state variables for 'solid pieces' */
00791         rt_res_pieces_clean( resp, rtip );
00792 
00793         /* Reinitialize pointers, to be tidy.  No storage is allocated. */
00794         rt_init_resource( resp, resp->re_cpu, rtip );
00795 }
00796 
00797 struct bu_bitv *
00798 get_solidbitv( long nbits, struct resource *resp )
00799 {
00800         struct bu_bitv *solidbits;
00801         int counter=0;
00802 
00803         if( resp->re_solid_bitv.magic != BU_LIST_HEAD_MAGIC ) {
00804                 bu_bomb( "Bad magic number in re_solid_btiv list\n" );
00805         }
00806 
00807         if( BU_LIST_IS_EMPTY( &resp->re_solid_bitv ) )  {
00808                 solidbits = bu_bitv_new( nbits );
00809         } else {
00810                 for( BU_LIST_FOR( solidbits, bu_bitv, &resp->re_solid_bitv ) ) {
00811                         if( solidbits->nbits >= nbits ) {
00812                                 BU_LIST_DEQUEUE( &solidbits->l );
00813                                 BU_CK_BITV(solidbits);
00814                                 break;
00815                         }
00816                         counter++;
00817                 }
00818                 if( solidbits == (struct bu_bitv *)&resp->re_solid_bitv ) {
00819                         solidbits = bu_bitv_new( nbits );
00820                 }
00821         }
00822 
00823         return( solidbits );
00824 }
00825 
00826 /*
00827  *                      R T _ C L E A N
00828  *
00829  *  Release all the dynamic storage associated with a particular rt_i
00830  *  structure, except for the database instance information (dir, etc)
00831  *  and the rti_resources ptbl.
00832  *
00833  *  Note that an animation script can invoke a "clean" operation before
00834  *  anything has been prepped.
00835  */
00836 void
00837 rt_clean(register struct rt_i *rtip)
00838 {
00839         register struct region *regp;
00840         register struct bu_list *head;
00841         register struct soltab *stp;
00842         int     i;
00843 
00844         RT_CK_RTI(rtip);
00845 
00846         /* DEBUG: Ensure that all region trees are valid */
00847         for( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
00848                 RT_CK_REGION(regp);
00849                 db_ck_tree( regp->reg_treetop );
00850         }
00851         /*
00852          *  Clear out the region table
00853          *  db_free_tree() will delete most soltab structures.
00854          */
00855         while( BU_LIST_WHILE( regp, region, &rtip->HeadRegion ) )  {
00856                 RT_CK_REGION(regp);
00857                 BU_LIST_DEQUEUE(&(regp->l));
00858                 db_free_tree( regp->reg_treetop, &rt_uniresource );
00859                 bu_free( (genptr_t)regp->reg_name, "region name str");
00860                 regp->reg_name = (char *)0;
00861                 if( regp->reg_mater.ma_shader )
00862                 {
00863                         bu_free( (genptr_t)regp->reg_mater.ma_shader, "ma_shader" );
00864                         regp->reg_mater.ma_shader = (char *)NULL;
00865                 }
00866                 if( regp->attr_values ) {
00867                         i = 0;
00868                         while( regp->attr_values[i] ) {
00869                                 bu_mro_free( regp->attr_values[i] );
00870                                 i++;
00871                         }
00872                         bu_free( (char *)regp->attr_values, "regp->attr_values" );
00873                 }
00874                 bu_free( (genptr_t)regp, "struct region");
00875         }
00876         rtip->nregions = 0;
00877 
00878         /*
00879          *  Clear out the solid table, AFTER doing the region table.
00880          *  Can't use RT_VISIT_ALL_SOLTABS_START here
00881          */
00882         head = &(rtip->rti_solidheads[0]);
00883         for( ; head < &(rtip->rti_solidheads[RT_DBNHASH]); head++ )  {
00884                 while( BU_LIST_WHILE( stp, soltab, head ) )  {
00885                         RT_CHECK_SOLTAB(stp);
00886                         rt_free_soltab(stp);
00887                 }
00888         }
00889         rtip->nsolids = 0;
00890 
00891         /* Clean out the array of pointers to regions, if any */
00892         if( rtip->Regions )  {
00893                 bu_free( (char *)rtip->Regions, "rtip->Regions[]" );
00894                 rtip->Regions = (struct region **)0;
00895 
00896                 /* Free space partitions */
00897                 rt_fr_cut( rtip, &(rtip->rti_CutHead) );
00898                 bzero( (char *)&(rtip->rti_CutHead), sizeof(union cutter) );
00899                 rt_fr_cut( rtip, &(rtip->rti_inf_box) );
00900                 bzero( (char *)&(rtip->rti_inf_box), sizeof(union cutter) );
00901         }
00902         rt_cut_clean(rtip);
00903 
00904         /* Free animation structures */
00905 /* XXX modify to only free those from this rtip */
00906         db_free_anim(rtip->rti_dbip);
00907 
00908         /* Free array of solid table pointers indexed by solid ID */
00909         for( i=0; i <= ID_MAX_SOLID; i++ )  {
00910                 if( rtip->rti_nsol_by_type[i] <= 0 )  continue;
00911                 if (rtip->rti_sol_by_type[i]) {
00912                     bu_free( (char *)rtip->rti_sol_by_type[i], "sol_by_type" );
00913                 }
00914                 rtip->rti_sol_by_type[i] = (struct soltab **)0;
00915                 rtip->rti_nsol_by_type[i] = 0;
00916         }
00917         if( rtip->rti_Solids )  {
00918                 bu_free( (char *)rtip->rti_Solids, "rtip->rti_Solids[]" );
00919                 rtip->rti_Solids = (struct soltab **)0;
00920         }
00921 
00922         /*
00923          *  Clean out every cpu's "struct resource".
00924          *  These are provided by the caller's application (or are
00925          *  defaulted to rt_uniresource) and can't themselves be freed.
00926          *  rt_shootray() saved a table of them for us to use here.
00927          *  rt_uniresource may or may not be in this table.
00928          */
00929         if( BU_LIST_MAGIC_OK(&rtip->rti_resources.l, BU_PTBL_MAGIC ) )  {
00930                 struct resource **rpp;
00931                 BU_CK_PTBL( &rtip->rti_resources );
00932                 for( BU_PTBL_FOR( rpp, (struct resource **), &rtip->rti_resources ) )  {
00933                         /* After using a submodel, some entries may be NULL
00934                          * while others are not NULL
00935                          */
00936                         if( *rpp == NULL )  continue;
00937                         RT_CK_RESOURCE(*rpp);
00938                         /* Clean but do not free the resource struct */
00939                         rt_clean_resource(rtip, *rpp);
00940 #if 0
00941 /* XXX Can't do this, or 'clean' command in RT animation script will dump core. */
00942 /* rt expects them to stay inited and remembered, forever. */
00943 /* Submodels will clean up after themselves */
00944                         /* Forget remembered ptr, but keep ptbl allocated */
00945                         *rpp = NULL;
00946 #endif
00947                 }
00948         }
00949 
00950         if( rtip->Orca_hash_tbl ) {
00951                 bu_free( (char *)rtip->Orca_hash_tbl, "rtip->Orca_hash_tbl" );
00952                 rtip->Orca_hash_tbl = NULL;
00953         }
00954         if( rt_uniresource.re_magic )  {
00955                 rt_clean_resource(rtip, &rt_uniresource );/* Used for rt_optim_tree() */
00956         }
00957 
00958         /*
00959          *  Re-initialize everything important.
00960          *  This duplicates the code in rt_new_rti().
00961          */
00962 
00963         rtip->rti_inf_box.bn.bn_type = CUT_BOXNODE;
00964         VMOVE( rtip->rti_inf_box.bn.bn_min, rtip->mdl_min );
00965         VMOVE( rtip->rti_inf_box.bn.bn_max, rtip->mdl_max );
00966         VSETALL( rtip->mdl_min,  INFINITY );
00967         VSETALL( rtip->mdl_max, -INFINITY );
00968 
00969         bu_hist_free( &rtip->rti_hist_cellsize );
00970         bu_hist_free( &rtip->rti_hist_cutdepth );
00971 
00972         /*
00973          *  Zero the solid instancing counters in dbip database instance.
00974          *  Done here because the same dbip could be used by multiple
00975          *  rti's, and rt_gettrees() can be called multiple times on
00976          *  this one rtip.
00977          *  There is a race (collision!) here on d_uses if rt_gettrees()
00978          *  is called on another rtip of the same dbip
00979          *  before this rtip is done
00980          *  with all it's treewalking.
00981          *
00982          *  This must be done for each 'clean' to keep
00983          *  rt_find_identical_solid() working properly as d_uses goes up.
00984          */
00985         for( i=0; i < RT_DBNHASH; i++ )  {
00986                 register struct directory       *dp;
00987 
00988                 dp = rtip->rti_dbip->dbi_Head[i];
00989                 for( ; dp != DIR_NULL; dp = dp->d_forw )
00990                         dp->d_uses = 0;
00991         }
00992 
00993         bu_ptbl_reset( &rtip->delete_regs );
00994 
00995         rtip->rti_magic = RTI_MAGIC;
00996         rtip->needprep = 1;
00997 }
00998 
00999 /*
01000  *                      R T _ D E L _ R E G T R E E
01001  *
01002  *  Remove a region from the linked list.  Used to remove a particular
01003  *  region from the active database, presumably after some useful
01004  *  information has been extracted (eg, a light being converted to
01005  *  implicit type), or for special effects.
01006  *
01007  *  Returns -
01008  *       0      success
01009  */
01010 int
01011 rt_del_regtree( struct rt_i *rtip, register struct region *delregp, struct resource *resp )
01012 {
01013         RT_CK_RESOURCE(resp);
01014 
01015         if( RT_G_DEBUG & DEBUG_REGIONS )
01016                 bu_log("rt_del_regtree(%s): region deleted\n", delregp->reg_name);
01017 
01018         BU_LIST_DEQUEUE(&(delregp->l));
01019 
01020         db_free_tree( delregp->reg_treetop, resp );
01021         delregp->reg_treetop = TREE_NULL;
01022         bu_free( (char *)delregp->reg_name, "region name str");
01023         delregp->reg_name = (char *)0;
01024         if( delregp->attr_values ) {
01025                 int i=0;
01026                 while( delregp->attr_values[i] ) {
01027                         bu_mro_free( delregp->attr_values[i] );
01028                         i++;
01029                 }
01030                 bu_free( (char *)delregp->attr_values, "delregp->attr_values" );
01031         }
01032         bu_free( (char *)delregp, "struct region");
01033         return(0);
01034 }
01035 
01036 /*
01037  *                      S O L I D _ B I T F I N D E R
01038  *
01039  *  Used to walk the boolean tree, setting bits for all the solids in the tree
01040  *  to the provided bit vector.  Should be called AFTER the region bits
01041  *  have been assigned.
01042  */
01043 HIDDEN void
01044 rt_solid_bitfinder(register union tree *treep, struct region *regp, struct resource *resp)
01045 {
01046         register union tree     **sp;
01047         register struct soltab  *stp;
01048         register union tree     **stackend;
01049 
01050         RT_CK_REGION(regp);
01051         RT_CK_RESOURCE(resp);
01052 
01053         while( (sp = resp->re_boolstack) == (union tree **)0 )
01054                 rt_grow_boolstack( resp );
01055         stackend = &(resp->re_boolstack[resp->re_boolslen-1]);
01056 
01057         *sp++ = TREE_NULL;
01058         *sp++ = treep;
01059         while( (treep = *--sp) != TREE_NULL ) {
01060                 RT_CK_TREE(treep);
01061                 switch( treep->tr_op )  {
01062                 case OP_NOP:
01063                         break;
01064                 case OP_SOLID:
01065                         stp = treep->tr_a.tu_stp;
01066                         RT_CK_SOLTAB(stp);
01067                         bu_ptbl_ins( &stp->st_regions, (long *)regp );
01068                         break;
01069                 case OP_UNION:
01070                 case OP_INTERSECT:
01071                 case OP_SUBTRACT:
01072                         /* BINARY type */
01073                         /* push both nodes - search left first */
01074                         *sp++ = treep->tr_b.tb_right;
01075                         *sp++ = treep->tr_b.tb_left;
01076                         if( sp >= stackend )  {
01077                                 register int off = sp - resp->re_boolstack;
01078                                 rt_grow_boolstack( resp );
01079                                 sp = &(resp->re_boolstack[off]);
01080                                 stackend = &(resp->re_boolstack[resp->re_boolslen-1]);
01081                         }
01082                         break;
01083                 default:
01084                         bu_log("rt_solid_bitfinder:  op=x%x\n", treep->tr_op);
01085                         break;
01086                 }
01087         }
01088 }
01089 
01090 /*
01091  *                      R T _ C K
01092  *
01093  *  Check as many of the in-memory data structures as is practical.
01094  *  Useful for detecting memory corruption, and inappropriate sharing
01095  *  between different LIBRT instances.
01096  */
01097 void
01098 rt_ck(register struct rt_i *rtip)
01099 {
01100         struct region           *regp;
01101         struct soltab           *stp;
01102 
01103         RT_CK_RTI(rtip);
01104         RT_CK_DBI(rtip->rti_dbip);
01105 
01106         db_ck_directory(rtip->rti_dbip);
01107 
01108         RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
01109                 RT_CK_SOLTAB(stp);
01110         } RT_VISIT_ALL_SOLTABS_END
01111 
01112         for( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
01113                 RT_CK_REGION(regp);
01114                 db_ck_tree(regp->reg_treetop);
01115         }
01116         /* rti_CutHead */
01117 
01118 }
01119 
01120 /*
01121  *              R T _ L O A D _ A T T R S
01122  *
01123  *      Loads a new set of attribute values (corresponding to the provided list of attribute
01124  *      names) for each region structure in the provided rtip.
01125  *
01126  *      RETURNS
01127  *              The number of region structures affected
01128  */
01129 
01130 int rt_load_attrs( struct rt_i *rtip, char **attrs )
01131 {
01132         struct region *regp;
01133         struct bu_attribute_value_set avs;
01134         struct directory *dp;
01135         const char *reg_name;
01136         const char *attr;
01137         int attr_count=0;
01138         int mro_count;
01139         int did_set;
01140         int region_count=0;
01141         int i;
01142 
01143         RT_CHECK_RTI(rtip);
01144         RT_CK_DBI(rtip->rti_dbip);
01145 
01146         if( rtip->rti_dbip->dbi_version < 5 )
01147                 return 0;
01148 
01149         while( attrs[attr_count] )
01150                 attr_count++;
01151 
01152         for( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
01153                 RT_CK_REGION(regp);
01154 
01155                 did_set = 0;
01156                 mro_count = 0;
01157                 while( regp->attr_values[mro_count] )
01158                         mro_count++;
01159 
01160                 if( mro_count < attr_count ) {
01161                         /* don't have enough to store all the values */
01162                         for( i=0 ; i<mro_count ; i++ ) {
01163                                 bu_mro_free( regp->attr_values[i] );
01164                                 bu_free( (char *)regp->attr_values[i], "regp->attr_values[i]" );
01165                         }
01166                         if( mro_count )
01167                                 bu_free( (char *)regp->attr_values, "regp->attr_values" );
01168                         regp->attr_values = (struct bu_mro **)bu_calloc( attr_count + 1,
01169                                                  sizeof( struct bu_mro *), "regp->attr_values" );
01170                         for( i=0 ; i<attr_count ; i++ ) {
01171                                 regp->attr_values[i] = bu_malloc( sizeof( struct bu_mro ),
01172                                                         "regpp->attr_values[i]" );
01173                                 bu_mro_init( regp->attr_values[i] );
01174                         }
01175                 } else if ( mro_count > attr_count ) {
01176                         /* just reuse what we have */
01177                         for( i=attr_count ; i<mro_count ; i++ ) {
01178                                 bu_mro_free( regp->attr_values[i] );
01179                                 bu_free( (char *)regp->attr_values[i], "regp->attr_values[i]" );
01180                         }
01181                         regp->attr_values[attr_count] = (struct bu_mro *)NULL;
01182                 }
01183 
01184                 if( (reg_name=strrchr( regp->reg_name, '/' ) ) == NULL )
01185                         reg_name = regp->reg_name;
01186                 else
01187                         reg_name++;
01188 
01189                 if( (dp=db_lookup( rtip->rti_dbip, reg_name, LOOKUP_NOISY ) ) == DIR_NULL )
01190                         continue;
01191 
01192                 bu_avs_init_empty(&avs);
01193                 if( db5_get_attributes( rtip->rti_dbip, &avs, dp ) ) {
01194                         bu_log( "rt_load_attrs: Failed to get attributes for region %s\n", reg_name );
01195                         continue;
01196                 }
01197 
01198                 for( i=0 ; i<attr_count ; i++ ) {
01199                         if( (attr = bu_avs_get( &avs, attrs[i] ) ) == NULL )
01200                                 continue;
01201 
01202                         bu_mro_set( regp->attr_values[i], attr );
01203                         did_set = 1;
01204                 }
01205 
01206                 if( did_set )
01207                         region_count++;
01208 
01209                 bu_avs_free( &avs );
01210         }
01211 
01212         return( region_count );
01213 }
01214 
01215 /*                      R T _ F I N D _ P A T H
01216  *
01217  *      Routine called by "rt_find_paths". Used for recursing through a tree to find a path
01218  *      to the specified "end". The resulting path is returned in "curr_path".
01219  */
01220 static void
01221 rt_find_path( struct db_i *dbip,
01222               union tree *tp,
01223               struct directory *end,
01224               struct bu_ptbl *paths,
01225               struct db_full_path **curr_path,
01226               struct resource *resp )
01227 {
01228         int curr_path_index=(*curr_path)->fp_len;
01229         struct db_full_path *newpath;
01230         struct directory *dp;
01231         struct rt_db_internal intern;
01232         struct rt_comb_internal *comb;
01233 
01234         switch( tp->tr_op ) {
01235         case OP_DB_LEAF:
01236                 dp = db_lookup( dbip, tp->tr_l.tl_name, 1 );
01237                 if( dp == DIR_NULL ) {
01238                         bu_bomb( "rt_find_path() failed!!\n" );
01239                 }
01240                 db_add_node_to_full_path( *curr_path, dp );
01241                 if( dp == end ) {
01242                         bu_ptbl_ins( paths, (long *)(*curr_path) );
01243                         newpath = (struct db_full_path *)bu_malloc( sizeof( struct db_full_path ),
01244                                                                     "newpath" );
01245                         db_full_path_init( newpath );
01246                         db_dup_full_path( newpath, (*curr_path) );
01247                         (*curr_path) = newpath;
01248                 } else if( (dp->d_flags & DIR_COMB) && !(dp->d_flags & DIR_REGION ) ) {
01249                         if( rt_db_get_internal( &intern, dp, dbip, NULL, resp ) < 0 ) {
01250                                 bu_bomb( "db_get_internal() failed!!\n" );
01251                         }
01252                         comb = (struct rt_comb_internal *)intern.idb_ptr;
01253                         rt_find_path( dbip, comb->tree, end, paths, curr_path, resp );
01254                         rt_db_free_internal( &intern, resp );
01255                 }
01256                 break;
01257         case OP_UNION:
01258         case OP_SUBTRACT:
01259         case OP_INTERSECT:
01260         case OP_XOR:
01261                 /* binary, process both subtrees */
01262                 rt_find_path( dbip, tp->tr_b.tb_left, end, paths, curr_path, resp );
01263                 (*curr_path)->fp_len = curr_path_index;
01264                 rt_find_path( dbip, tp->tr_b.tb_right, end, paths, curr_path, resp );
01265                 break;
01266         case OP_NOT:
01267         case OP_GUARD:
01268                 rt_find_path( dbip, tp->tr_b.tb_left, end, paths, curr_path, resp );
01269                 break;
01270         default:
01271                 bu_log( "rt_find_path(): Unrecognized OP (%d)\n", tp->tr_op );
01272                 bu_bomb( "rt_find_path(): Unrecognized OP\n" );
01273                 break;
01274         }
01275 }
01276 
01277 /*                      R T _ F I N D _ P A T H S
01278  *
01279  *      Routine to find all the paths from the "start" to the "end".
01280  *      The resulting paths are returned in "paths"
01281  */
01282 int
01283 rt_find_paths( struct db_i *dbip,
01284                struct directory *start,
01285                struct directory *end,
01286                struct bu_ptbl *paths,
01287                struct resource *resp )
01288 {
01289         struct rt_db_internal intern;
01290         struct db_full_path *path;
01291         struct rt_comb_internal *comb;
01292 
01293         path = (struct db_full_path *)bu_malloc( sizeof( struct db_full_path ), "path" );
01294         db_full_path_init( path );
01295         db_add_node_to_full_path( path, start );
01296 
01297         if( start == end ) {
01298                 bu_ptbl_ins( paths, (long *)path );
01299                 return( 0 );
01300         }
01301 
01302         if( !(start->d_flags & DIR_COMB) || (start->d_flags & DIR_REGION) ) {
01303                 bu_log( "Cannot find path from %s to %s\n",
01304                         start->d_namep, end->d_namep );
01305                 db_free_full_path( path );
01306                 bu_free( (char *)path, "path" );
01307                 return( 1 );
01308         }
01309 
01310         if( rt_db_get_internal( &intern, start, dbip, NULL, resp ) < 0 ) {
01311                 db_free_full_path( path );
01312                 bu_free( (char *)path, "path" );
01313                 return( 1 );
01314         }
01315 
01316         comb = (struct rt_comb_internal *)intern.idb_ptr;
01317         rt_find_path( dbip, comb->tree, end, paths, &path, resp );
01318         rt_db_free_internal( &intern, resp );
01319 
01320         return( 0 );
01321 }
01322 
01323 /*                      O B J _ I N _ P A T H
01324  *
01325  *      This routine searches the provided path (in the form of a string) for the specified object name.
01326  *      returns:
01327  *              1 - the specified object name is somewhere along the path
01328  *              0 - the specified object name does not appear in this path
01329  */
01330 int
01331 obj_in_path( const char *path, const char *obj )
01332 {
01333         int obj_len=strlen( obj );
01334         char *ptr;
01335 
01336         ptr = strstr( path, obj );
01337 
01338         while( ptr ) {
01339                 if( ptr == path ) {
01340                         /* obj may be first element in path */
01341                         ptr += obj_len;
01342                         if( *ptr == '\0' || *ptr == '/' ) {
01343                                 /* found object in path */
01344                                 return( 1 );
01345                         }
01346                 } else if( *(ptr-1) == '/' ) {
01347                         ptr += obj_len;
01348                         if( *ptr == '\0' || *ptr == '/' ) {
01349                                 /* found object in path */
01350                                 return( 1 );
01351                         }
01352                 } else {
01353                         ptr++;
01354                 }
01355 
01356                 ptr = strstr( ptr, obj );
01357         }
01358 
01359         return( 0 );
01360 }
01361 
01362 static int
01363 unprep_reg_start( struct db_tree_state *tsp,
01364                   struct db_full_path *pathp,
01365                   const struct rt_comb_internal *comb,
01366                   genptr_t client_data )
01367 {
01368         RT_CK_RTI(tsp->ts_rtip);
01369         RT_CK_RESOURCE(tsp->ts_resp);
01370 
01371         /* Ignore "air" regions unless wanted */
01372         if( tsp->ts_rtip->useair == 0 &&  tsp->ts_aircode != 0 )  {
01373                 tsp->ts_rtip->rti_air_discards++;
01374                 return(-1);     /* drop this region */
01375         }
01376         return(0);
01377 }
01378 
01379 static union tree *
01380 unprep_reg_end( struct db_tree_state *tsp,
01381                   struct db_full_path *pathp,
01382                   union tree *tree,
01383                   genptr_t client_data )
01384 {
01385         return( (union tree *)NULL );
01386 }
01387 
01388 static union tree *
01389 unprep_leaf( struct db_tree_state *tsp,
01390              struct db_full_path *pathp,
01391              struct rt_db_internal *ip,
01392              genptr_t client_data )
01393 {
01394         register struct soltab  *stp;
01395         struct directory        *dp;
01396         register matp_t         mat;
01397         struct rt_i             *rtip;
01398         struct bu_list          *mid;
01399         struct rt_reprep_obj_list *objs=(struct rt_reprep_obj_list *)client_data;
01400 
01401         RT_CK_DBTS(tsp);
01402         RT_CK_DBI(tsp->ts_dbip);
01403         RT_CK_FULL_PATH(pathp);
01404         RT_CK_DB_INTERNAL(ip);
01405         rtip = tsp->ts_rtip;
01406         RT_CK_RTI(rtip);
01407         RT_CK_RESOURCE(tsp->ts_resp);
01408         dp = DB_FULL_PATH_CUR_DIR(pathp);
01409 
01410         /* Determine if this matrix is an identity matrix */
01411 
01412         if( !bn_mat_is_equal(tsp->ts_mat, bn_mat_identity, &rtip->rti_tol)) {
01413                 /* Not identity matrix */
01414                 mat = (matp_t)tsp->ts_mat;
01415         } else {
01416                 /* Identity matrix */
01417                 mat = (matp_t)0;
01418         }
01419 
01420         /* find corresponding soltab structure */
01421         mid = BU_LIST_FIRST( bu_list, &dp->d_use_hd );
01422         while( mid != &dp->d_use_hd ) {
01423                 stp = BU_LIST_MAIN_PTR( soltab, mid, l2 );
01424                 RT_CK_SOLTAB(stp);
01425 
01426                 mid = BU_LIST_PNEXT( bu_list, mid );
01427 
01428                 if( ((mat == (matp_t)0) && (stp->st_matp == (matp_t)0) ) ||
01429                     bn_mat_is_equal( mat, stp->st_matp, &rtip->rti_tol ) ) {
01430                         if( stp->st_rtip == rtip ) {
01431                                 long bit=stp->st_bit;
01432                                 struct region *rp;
01433                                 int i,j;
01434 
01435                                 /* found soltab for this instance */
01436 
01437                                 /* check all regions using this soltab
01438                                  * add any that are below an object to be unprepped
01439                                  * to the "unprep_regions" list
01440                                  */
01441                                 for( i=0 ; i<BU_PTBL_LEN( &stp->st_regions ) ; i++ ) {
01442                                         rp = (struct region *)BU_PTBL_GET( &stp->st_regions, i );
01443                                         for( j=0 ; j<objs->nunprepped ; j++ ) {
01444                                                 if( obj_in_path( rp->reg_name, objs->unprepped[j] ) ) {
01445                                                         /* this region has an unprep object
01446                                                          * in its path */
01447                                                         bu_ptbl_ins_unique( &objs->unprep_regions, (long *)rp );
01448                                                         bu_ptbl_rm( &stp->st_regions, (long *)rp );
01449                                                         break;
01450                                                 }
01451                                         }
01452                                 }
01453                                 if( stp->st_uses <= 1 ) {
01454                                         /* soltab structure will actually be freed */
01455                                         remove_from_bsp( stp, &rtip->rti_inf_box, &rtip->rti_tol );
01456                                         remove_from_bsp( stp, &rtip->rti_CutHead, &rtip->rti_tol );
01457                                         rtip->rti_Solids[bit] = (struct soltab *)NULL;
01458                                 }
01459                                 rt_free_soltab( stp );
01460                                 return( (union tree *)NULL );
01461                         }
01462                 }
01463         }
01464 
01465         bu_log( "rt_unprep(): Failed to find soltab structure for an instance of %s\n", dp->d_namep );
01466         bu_bomb( "rt_unprep(): Failed to find soltab structure for a solid instance\n");
01467 
01468         return( (union tree *)NULL );
01469 }
01470 
01471 
01472 /*                      R T _ U N P R E P
01473  *
01474  *      This routine "unpreps" the list of object names that appears in the "unprepped" list
01475  *      of the "objs" structure.
01476  */
01477 int
01478 rt_unprep( struct rt_i *rtip, struct rt_reprep_obj_list *objs, struct resource *resp )
01479 {
01480         struct bu_ptbl paths;
01481         struct bu_ptbl unprep_regions;
01482         struct db_full_path *path;
01483         int i,j,k;
01484 
01485         rt_res_pieces_clean( resp, rtip );
01486 
01487         /* find all paths from top objects to objects being unprepped */
01488         bu_ptbl_init( &objs->paths, 5, "paths" );
01489         for( i=0 ; i<objs->ntopobjs ; i++ ) {
01490                 struct directory *start, *end;
01491 
01492                 start = db_lookup( rtip->rti_dbip, objs->topobjs[i], 1 );
01493                 if( start == DIR_NULL ) {
01494                         for( k=0 ; k<BU_PTBL_END(&objs->paths) ; k++ ) {
01495                                 path = (struct db_full_path *)BU_PTBL_GET( &objs->paths, k );
01496                                 db_free_full_path( path );
01497                         }
01498                         bu_ptbl_free( &objs->paths );
01499                         return( 1 );
01500                 }
01501                 for( j=0 ; j<objs->nunprepped ; j++ ) {
01502                         end = db_lookup( rtip->rti_dbip, objs->unprepped[j], 1 );
01503                         if( end == DIR_NULL ) {
01504                                 for( k=0 ; k<BU_PTBL_END(&objs->paths) ; k++ ) {
01505                                         path = (struct db_full_path *)BU_PTBL_GET( &objs->paths, k );
01506                                         db_free_full_path( path );
01507                                 }
01508                                 bu_ptbl_free( &objs->paths );
01509                                 return( 1 );
01510                         }
01511                         rt_find_paths( rtip->rti_dbip, start, end, &objs->paths, resp );
01512                 }
01513         }
01514 
01515         if( BU_PTBL_LEN( &objs->paths ) < 1 ) {
01516                 bu_log( "rt_unprep(): Failed to find any paths to objects to reprep!!\n" );
01517                 bu_ptbl_free( &objs->paths );
01518         }
01519 
01520         /* accumulate state along each path */
01521         objs->tsp = (struct db_tree_state **)bu_calloc(
01522                                   BU_PTBL_LEN( &objs->paths ),
01523                                   sizeof( struct db_tree_state *),
01524                                   "objs->tsp" );
01525 
01526         bu_ptbl_init( &objs->unprep_regions, 5, "unprep_regions" );
01527 
01528         for( i=0 ; i<BU_PTBL_LEN( &objs->paths ) ; i++ ) {
01529                 struct db_full_path another_path;
01530                 struct db_tree_state    *tree_state;
01531                 char                    *obj_name;
01532 
01533                 tree_state = (struct db_tree_state *)bu_malloc( sizeof( struct db_tree_state ),
01534                                                                 "tree_state" );
01535                 *tree_state = rt_initial_tree_state;    /* struct copy */
01536                 tree_state->ts_dbip = rtip->rti_dbip;
01537                 tree_state->ts_resp = resp;
01538                 tree_state->ts_rtip = rtip;
01539                 tree_state->ts_tol = &rtip->rti_tol;
01540                 objs->tsp[i] = tree_state;
01541 
01542                 db_full_path_init( &another_path );
01543                 path = (struct db_full_path *)BU_PTBL_GET( &objs->paths, i );
01544                 if( db_follow_path( tree_state, &another_path, path, 1, 0 ) ) {
01545                         bu_log( "rt_unprep(): db_follow_path failed!!\n" );
01546                         for( k=0 ; k<BU_PTBL_END(&paths) ; k++ ) {
01547                                 if( objs->tsp[k] ) {
01548                                         db_free_db_tree_state( objs->tsp[k] );
01549                                         bu_free( (char *)objs->tsp[k], "tree_state" );
01550                                 }
01551                                 path = (struct db_full_path *)BU_PTBL_GET( &objs->paths, k );
01552                                 db_free_full_path( path );
01553                         }
01554                         bu_ptbl_free( &paths );
01555                         bu_ptbl_free( &unprep_regions );
01556                         return( 1 );
01557                 }
01558                 db_free_full_path( &another_path );
01559 
01560                 /* walk tree starting from "unprepped" object,
01561                  * using the appropriate tree_state.
01562                  * unprep solids and regions along the way
01563                  */
01564                 obj_name = DB_FULL_PATH_CUR_DIR(path)->d_namep;
01565                 if( db_walk_tree( rtip->rti_dbip, 1, (const char **)&obj_name, 1, tree_state,
01566                                   unprep_reg_start, unprep_reg_end, unprep_leaf,
01567                                   (genptr_t)objs ) ) {
01568                         bu_log( "rt_unprep(): db_walk_tree failed!!!\n" );
01569                         for( k=0 ; k<BU_PTBL_END(&paths) ; k++ ) {
01570                                 if( objs->tsp[k] ) {
01571                                         db_free_db_tree_state( objs->tsp[k] );
01572                                         bu_free( (char *)objs->tsp[k], "tree_state" );
01573                                 }
01574                                 path = (struct db_full_path *)BU_PTBL_GET( &objs->paths, k );
01575                                 db_free_full_path( path );
01576                         }
01577                         bu_ptbl_free( &paths );
01578                         bu_ptbl_free( &unprep_regions );
01579                         return( 1 );
01580                 }
01581 
01582                 db_free_db_tree_state( tree_state );
01583                 bu_free( (char *)tree_state, "tree_state" );
01584         }
01585 
01586         /* eliminate regions to be unprepped */
01587         objs->nregions_unprepped = BU_PTBL_LEN( &objs->unprep_regions );
01588         for( i=0 ; i<BU_PTBL_LEN( &objs->unprep_regions ) ; i++ ) {
01589                 struct region *rp;
01590 
01591                 rp = (struct region *)BU_PTBL_GET( &objs->unprep_regions, i );
01592                 BU_LIST_DEQUEUE( &rp->l );
01593                 rtip->Regions[rp->reg_bit] = (struct region *)NULL;
01594 
01595                 /* XXX
01596                    db_free_tree( rp->reg_treetop, resp ); */
01597                 bu_free( (genptr_t)rp->reg_name, "region name str");
01598                 rp->reg_name = (char *)0;
01599                 if( rp->reg_mater.ma_shader )
01600                 {
01601                         bu_free( (genptr_t)rp->reg_mater.ma_shader, "ma_shader" );
01602                         rp->reg_mater.ma_shader = (char *)NULL;
01603                 }
01604                 if( rp->attr_values ) {
01605                         i = 0;
01606                         while( rp->attr_values[i] ) {
01607                                 bu_mro_free( rp->attr_values[i] );
01608                                 i++;
01609                         }
01610                         bu_free( (char *)rp->attr_values, "rp->attr_values" );
01611                 }
01612                 bu_free( (genptr_t)rp, "struct region");
01613         }
01614 
01615         /* eliminate NULL region structures */
01616         objs->old_nregions = rtip->nregions;
01617         i = 0;
01618         while( i < rtip->nregions ) {
01619                 int nulls=0;
01620 
01621                 while( i < rtip->nregions && !rtip->Regions[i] ) {
01622                         i++;
01623                         nulls++;
01624                 }
01625 
01626                 if( nulls ) {
01627                         rtip->nregions -= nulls;
01628                         for( j=i-nulls ; j<rtip->nregions ; j++ ) {
01629                                 rtip->Regions[j] = rtip->Regions[j+nulls];
01630                                 if( rtip->Regions[j] ) {
01631                                         rtip->Regions[j]->reg_bit = j;
01632                                 }
01633                         }
01634                         nulls = 0;
01635                 } else {
01636                         i++;
01637                 }
01638         }
01639 
01640         /* eliminate NULL soltabs */
01641         objs->old_nsolids = rtip->nsolids;
01642         objs->nsolids_unprepped = 0;
01643         i = 0;
01644         while( i < rtip->nsolids) {
01645                 int nulls=0;
01646 
01647                 while( i < rtip->nsolids && !rtip->rti_Solids[i] ) {
01648                         objs->nsolids_unprepped++;
01649                         i++;
01650                         nulls++;
01651                 }
01652                 if( nulls ) {
01653                         for( j=i-nulls ; j+nulls<rtip->nsolids ; j++ ) {
01654                                 rtip->rti_Solids[j] = rtip->rti_Solids[j+nulls];
01655                                 if( rtip->rti_Solids[j] ) {
01656                                         rtip->rti_Solids[j]->st_bit = j;
01657                                 }
01658                         }
01659                         rtip->nsolids -= nulls;
01660                         i -= nulls;
01661                 } else {
01662                         i++;
01663                 }
01664         }
01665 
01666         return( 0 );
01667 }
01668 
01669 /*                      R T _ R E P R E P
01670  *      This routine "re-preps" the list of objects specified in the "unprepped" list of the
01671  *      "objs" structure. This structure must previously have been passed to "rt_unprep"
01672  */
01673 int
01674 rt_reprep( struct rt_i *rtip, struct rt_reprep_obj_list *objs, struct resource *resp )
01675 {
01676         int i;
01677         char **argv;
01678         struct region *rp;
01679         struct soltab *stp;
01680         fastf_t old_min[3], old_max[3];
01681         int model_extremes_have_changed=0;
01682         long bitno;
01683 
01684         VMOVE( old_min, rtip->mdl_min );
01685         VMOVE( old_max, rtip->mdl_max );
01686 
01687         rtip->needprep = 1;
01688 
01689         argv = (char **)bu_calloc( BU_PTBL_LEN( &(objs->paths) ), sizeof( char *), "argv" );
01690         for( i=0 ; i<BU_PTBL_LEN( &(objs->paths) ) ; i++ ) {
01691                 argv[i] = db_path_to_string( (const struct db_full_path *)BU_PTBL_GET( &(objs->paths), i ));
01692         }
01693 
01694         rtip->rti_add_to_new_solids_list = 1;
01695         bu_ptbl_init( &rtip->rti_new_solids, 128, "rti_new_solids" );
01696         if( rt_gettrees( rtip, BU_PTBL_LEN( &(objs->paths) ), (const char **)argv, 1 ) ) {
01697                 return( 1 );
01698         }
01699         rtip->rti_add_to_new_solids_list = 0;
01700 
01701         for( i=0 ; i<BU_PTBL_LEN( &(objs->paths) ) ; i++ ) {
01702                 bu_free( argv[i], "argv[i]" );
01703         }
01704         bu_free( (char *)argv, "argv" );
01705 
01706         rtip->needprep = 0;
01707 
01708         if( rtip->nregions > objs->old_nregions ) {
01709                 rtip->Regions = (struct region **)bu_realloc( rtip->Regions,
01710                                      rtip->nregions * sizeof( struct region *), "rtip->Regions" );
01711                 memset( rtip->Regions, 0, rtip->nregions );
01712         }
01713 
01714 
01715         bitno = 0;
01716         for( BU_LIST_FOR( rp, region, &(rtip->HeadRegion) ) ) {
01717                 rp->reg_bit = bitno;
01718                 rtip->Regions[bitno] = rp;
01719                 if( bitno >= objs->old_nregions - objs->nregions_unprepped ) {
01720                         point_t region_min, region_max;
01721 
01722                         if( rt_bound_tree( rp->reg_treetop, region_min, region_max ) ) {
01723                                 bu_log( "rt_reprep(): rt_bound_tree() FAILED for %s\n",
01724                                         rp->reg_name );
01725                                 bu_bomb( "rt_reprep(): rt_bound_tree() FAILED\n" );
01726                         }
01727                         if( region_max[X] < INFINITY )  {
01728                                 /* infinite regions are exempted from this */
01729                                 VMINMAX( rtip->mdl_min, rtip->mdl_max, region_min );
01730                                 VMINMAX( rtip->mdl_min, rtip->mdl_max, region_max );
01731                         }
01732                         rt_solid_bitfinder( rp->reg_treetop, rp, resp );
01733                 }
01734                 bitno++;
01735         }
01736 
01737         if( rtip->nsolids > objs->old_nsolids ) {
01738                 rtip->rti_Solids = (struct soltab **)bu_realloc( rtip->rti_Solids,
01739                                                                  rtip->nsolids * sizeof( struct soltab *),
01740                                                                  "rtip->rti_Solids" );
01741                 memset( rtip->rti_Solids, 0, rtip->nsolids * sizeof(struct soltab *));
01742         }
01743 
01744         bitno = 0;
01745         RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
01746                 stp->st_bit = bitno;
01747                 rtip->rti_Solids[bitno] = stp;
01748                 bitno++;
01749 
01750         } RT_VISIT_ALL_SOLTABS_END
01751 
01752         for( i=0 ; i<BU_PTBL_LEN( &rtip->rti_new_solids ) ; i++ ) {
01753                 stp = (struct soltab * )BU_PTBL_GET( &rtip->rti_new_solids, i );
01754                 if( stp->st_aradius >= INFINITY ) {
01755                         insert_in_bsp( stp, &rtip->rti_inf_box );
01756                 } else {
01757                         insert_in_bsp( stp, &rtip->rti_CutHead );
01758                 }
01759         }
01760 
01761         bu_ptbl_free( &rtip->rti_new_solids );
01762 
01763         for( i=0 ; i<3 ; i++ ) {
01764                 if( rtip->mdl_min[i] != old_min[i] ) {
01765                         model_extremes_have_changed = 1;
01766                         break;
01767                 }
01768                 if( rtip->mdl_max[i] != old_max[i] ) {
01769                         model_extremes_have_changed = 1;
01770                         break;
01771                 }
01772         }
01773 
01774         if( model_extremes_have_changed ) {
01775                 /* fill out BSP, it must completely fill the model BB */
01776                 fastf_t bb[6];
01777 
01778                 VSETALL( bb, INFINITY );
01779                 VSETALL( &bb[3], -INFINITY );
01780                 fill_out_bsp( rtip, &rtip->rti_CutHead, resp, bb );
01781         }
01782 
01783         if( BU_PTBL_LEN( &rtip->rti_resources ) ) {
01784                 for( i=0 ; i<BU_PTBL_LEN( &rtip->rti_resources ) ; i++ ) {
01785                         struct resource *re;
01786 
01787                         re = (struct resource *)BU_PTBL_GET( &rtip->rti_resources, i );
01788                         if( re && rtip->rti_nsolids_with_pieces )
01789                                 rt_res_pieces_init( re, rtip );
01790                 }
01791         } else if( rtip->rti_nsolids_with_pieces ) {
01792                 rt_res_pieces_init( &rt_uniresource, rtip );
01793         }
01794 
01795         return( 0 );
01796 }
01797 
01798 /*
01799  * Local Variables:
01800  * mode: C
01801  * tab-width: 8
01802  * c-basic-offset: 4
01803  * indent-tabs-mode: t
01804  * End:
01805  * ex: shiftwidth=4 tabstop=8
01806  */

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