tree.c

Go to the documentation of this file.
00001 /*                          T R E E . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1995-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 librt */
00023 /*@{*/
00024 
00025 /** @file tree.c
00026  * Ray Tracing library database tree walker.
00027  *  Collect and prepare regions and solids for subsequent ray-tracing.
00028  *
00029  *  Author -
00030  *      Michael John Muuss
00031  *
00032  *  Source -
00033  *      The U. S. Army Research Laboratory
00034  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00035  */
00036 /*@}*/
00037 #ifndef lint
00038 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/tree.c,v 14.18 2006/09/16 02:04:26 lbutler Exp $ (ARL)";
00039 #endif
00040 
00041 #include "common.h"
00042 
00043 #include <stddef.h>
00044 #include <stdio.h>
00045 #include <math.h>
00046 #ifdef HAVE_STRING_H
00047 #  include <string.h>
00048 #else
00049 #  include <strings.h>
00050 #endif
00051 
00052 #include "machine.h"
00053 #include "bu.h"
00054 #include "vmath.h"
00055 #include "bn.h"
00056 #include "db.h"
00057 #include "raytrace.h"
00058 
00059 #include "./debug.h"
00060 
00061 BU_EXTERN(void          rt_tree_kill_dead_solid_refs, (union tree *tp));
00062 
00063 HIDDEN struct region *rt_getregion(struct rt_i *rtip, register const char *reg_name);
00064 HIDDEN void     rt_tree_region_assign(register union tree *tp, register const struct region *regionp);
00065 
00066 /*
00067  *  Also used by converters in conv/ directory.
00068  *  Don't forget to initialize ts_dbip before use.
00069  */
00070 const struct db_tree_state      rt_initial_tree_state = {
00071         RT_DBTS_MAGIC,          /* magic */
00072         0,                      /* ts_dbip */
00073         0,                      /* ts_sofar */
00074         0, 0, 0, 0,             /* region, air, gmater, LOS */
00075 #if __STDC__
00076         {
00077 #endif
00078                 /* struct mater_info ts_mater */
00079 #if __STDC__
00080                 {
00081 #endif
00082                     1.0, 1.0, 1.0
00083 #if __STDC__
00084                 }
00085 #endif
00086                 ,       /* color, RGB */
00087                 -1.0,                   /* Temperature */
00088                 0,                      /* ma_color_valid=0 --> use default */
00089                 DB_INH_LOWER,           /* color inherit */
00090                 DB_INH_LOWER,           /* mater inherit */
00091                 NULL                    /* shader */
00092 #if __STDC__
00093         }
00094 #endif
00095         ,
00096 #if __STDC__
00097         {
00098 #endif
00099             1.0, 0.0, 0.0, 0.0,
00100             0.0, 1.0, 0.0, 0.0,
00101             0.0, 0.0, 1.0, 0.0,
00102             0.0, 0.0, 0.0, 1.0
00103 #if __STDC__
00104         }
00105 #endif
00106         ,
00107         REGION_NON_FASTGEN,             /* ts_is_fastgen */
00108 #if __STDC__
00109         {
00110 #endif
00111                 /* attribute value set */
00112                 BU_AVS_MAGIC,
00113                 0,
00114                 0,
00115                 NULL,
00116                 NULL,
00117                 NULL
00118 #if __STDC__
00119         }
00120 #endif
00121         ,
00122         0,                              /* ts_stop_at_regions */
00123         NULL,                           /* ts_region_start_func */
00124         NULL,                           /* ts_region_end_func */
00125         NULL,                           /* ts_leaf_func */
00126         NULL,                           /* ts_ttol */
00127         NULL,                           /* ts_tol */
00128         NULL,                           /* ts_m */
00129         NULL,                           /* ts_rtip */
00130         NULL                            /* ts_resp */
00131 };
00132 
00133 #define ACQUIRE_SEMAPHORE_TREE(_hash)   switch((_hash)&03)  { \
00134         case 0: \
00135                 bu_semaphore_acquire( RT_SEM_TREE0 ); \
00136                 break; \
00137         case 1: \
00138                 bu_semaphore_acquire( RT_SEM_TREE1 ); \
00139                 break; \
00140         case 2: \
00141                 bu_semaphore_acquire( RT_SEM_TREE2 ); \
00142                 break; \
00143         default: \
00144                 bu_semaphore_acquire( RT_SEM_TREE3 ); \
00145                 break; \
00146         }
00147 
00148 #define RELEASE_SEMAPHORE_TREE(_hash)   switch((_hash)&03)  { \
00149         case 0: \
00150                 bu_semaphore_release( RT_SEM_TREE0 ); \
00151                 break; \
00152         case 1: \
00153                 bu_semaphore_release( RT_SEM_TREE1 ); \
00154                 break; \
00155         case 2: \
00156                 bu_semaphore_release( RT_SEM_TREE2 ); \
00157                 break; \
00158         default: \
00159                 bu_semaphore_release( RT_SEM_TREE3 ); \
00160                 break; \
00161         }
00162 
00163 /*
00164  *                      R T _ G E T T R E E _ R E G I O N _ S T A R T
00165  *
00166  *  This routine must be prepared to run in parallel.
00167  */
00168 /* ARGSUSED */
00169 HIDDEN int rt_gettree_region_start(struct db_tree_state *tsp, struct db_full_path *pathp, const struct rt_comb_internal *combp, genptr_t client_data)
00170 /*const*/
00171 /*const*/
00172 
00173 
00174 {
00175         RT_CK_RTI(tsp->ts_rtip);
00176         RT_CK_RESOURCE(tsp->ts_resp);
00177 
00178         /* Ignore "air" regions unless wanted */
00179         if( tsp->ts_rtip->useair == 0 &&  tsp->ts_aircode != 0 )  {
00180                 tsp->ts_rtip->rti_air_discards++;
00181                 return(-1);     /* drop this region */
00182         }
00183         return(0);
00184 }
00185 
00186 /*
00187  *                      R T _ G E T T R E E _ R E G I O N _ E N D
00188  *
00189  *  This routine will be called by db_walk_tree() once all the
00190  *  solids in this region have been visited.
00191  *
00192  *  This routine must be prepared to run in parallel.
00193  *  As a result, note that the details of the solids pointed to
00194  *  by the soltab pointers in the tree may not be filled in
00195  *  when this routine is called (due to the way multiple instances of
00196  *  solids are handled).
00197  *  Therefore, everything which referred to the tree has been moved
00198  *  out into the serial section.  (rt_tree_region_assign, rt_bound_tree)
00199  */
00200 HIDDEN union tree *rt_gettree_region_end(register struct db_tree_state *tsp, struct db_full_path *pathp, union tree *curtree, genptr_t client_data)
00201 {
00202         struct region           *rp;
00203         struct directory        *dp;
00204         int                     shader_len=0;
00205         struct rt_i             *rtip;
00206         int                     i;
00207         Tcl_HashTable           *tbl = (Tcl_HashTable *)client_data;
00208         Tcl_HashEntry           *entry;
00209         matp_t                  inv_mat;
00210 
00211         RT_CK_DBI(tsp->ts_dbip);
00212         RT_CK_FULL_PATH(pathp);
00213         RT_CK_TREE(curtree);
00214         rtip =  tsp->ts_rtip;
00215         RT_CK_RTI(rtip);
00216         RT_CK_RESOURCE(tsp->ts_resp);
00217 
00218         if( curtree->tr_op == OP_NOP )  {
00219                 /* Ignore empty regions */
00220                 return  curtree;
00221         }
00222 
00223         BU_GETSTRUCT( rp, region );
00224         rp->l.magic = RT_REGION_MAGIC;
00225         rp->reg_regionid = tsp->ts_regionid;
00226         rp->reg_is_fastgen = tsp->ts_is_fastgen;
00227         rp->reg_aircode = tsp->ts_aircode;
00228         rp->reg_gmater = tsp->ts_gmater;
00229         rp->reg_los = tsp->ts_los;
00230 
00231         if( tsp->ts_attrs.count && tsp->ts_attrs.avp ) {
00232                 rp->attr_values = (struct bu_mro **)bu_calloc( tsp->ts_attrs.count+1,
00233                                      sizeof( struct bu_mro *), "regp->attr_values" );
00234                 for( i=0 ; i<tsp->ts_attrs.count ; i++ ) {
00235                         rp->attr_values[i] = bu_malloc( sizeof( struct bu_mro ),
00236                                                         "rp->attr_values[i]" );
00237                         bu_mro_init_with_string( rp->attr_values[i], tsp->ts_attrs.avp[i].value );
00238                 }
00239         } else {
00240                 rp->attr_values = (struct bu_mro **)NULL;
00241         }
00242 
00243         rp->reg_mater = tsp->ts_mater;          /* struct copy */
00244         if( tsp->ts_mater.ma_shader )
00245                 shader_len = strlen( tsp->ts_mater.ma_shader );
00246         if( shader_len )
00247         {
00248                 rp->reg_mater.ma_shader = bu_strdup( tsp->ts_mater.ma_shader );
00249         }
00250         else
00251                 rp->reg_mater.ma_shader = (char *)NULL;
00252 
00253         rp->reg_name = db_path_to_string( pathp );
00254 
00255         dp = (struct directory *)DB_FULL_PATH_CUR_DIR(pathp);
00256 
00257         if(RT_G_DEBUG&DEBUG_TREEWALK)  {
00258                 bu_log("rt_gettree_region_end() %s\n", rp->reg_name );
00259                 rt_pr_tree( curtree, 0 );
00260         }
00261 
00262         rp->reg_treetop = curtree;
00263         rp->reg_all_unions = db_is_tree_all_unions( curtree );
00264 
00265         /* Determine material properties */
00266         rp->reg_mfuncs = (char *)0;
00267         rp->reg_udata = (char *)0;
00268         if( rp->reg_mater.ma_color_valid == 0 )
00269                 rt_region_color_map(rp);
00270 
00271         bu_semaphore_acquire( RT_SEM_RESULTS ); /* enter critical section */
00272 
00273         rp->reg_instnum = dp->d_uses++;
00274 
00275         /*
00276          *  Add the region to the linked list of regions.
00277          *  Positions in the region bit vector are established at this time.
00278          */
00279         BU_LIST_INSERT( &(rtip->HeadRegion), &rp->l );
00280 
00281         rp->reg_bit = rtip->nregions++; /* Assign bit vector pos. */
00282         bu_semaphore_release( RT_SEM_RESULTS ); /* leave critical section */
00283 
00284         if( tbl && bu_avs_get( &tsp->ts_attrs, "ORCA_Comp" ) ) {
00285                 int newentry;
00286                 long int reg_bit = rp->reg_bit;
00287 
00288                 inv_mat = (matp_t)bu_calloc( 16, sizeof( fastf_t ), "inv_mat" );
00289                 if( tsp->ts_mat )
00290                         bn_mat_inv( inv_mat, tsp->ts_mat );
00291                 else
00292                         bn_mat_idn( inv_mat );
00293 
00294                 bu_semaphore_acquire( RT_SEM_RESULTS ); /* enter critical section */
00295 
00296                 entry = Tcl_CreateHashEntry(tbl, (char *)reg_bit, &newentry);
00297                 Tcl_SetHashValue( entry, (ClientData)inv_mat );
00298 
00299                 bu_semaphore_release( RT_SEM_RESULTS ); /* leave critical section */
00300         }
00301 
00302         if( RT_G_DEBUG & DEBUG_REGIONS )  {
00303                 bu_log("Add Region %s instnum %d\n",
00304                         rp->reg_name, rp->reg_instnum);
00305         }
00306 
00307         /* Indicate that we have swiped 'curtree' */
00308         return(TREE_NULL);
00309 }
00310 
00311 /*
00312  *                      R T _ F I N D _ I D E N T I C A L _ S O L I D
00313  *
00314  *  See if solid "dp" as transformed by "mat" already exists in the
00315  *  soltab list.  If it does, return the matching stp, otherwise,
00316  *  create a new soltab structure, enrole it in the list, and return
00317  *  a pointer to that.
00318  *
00319  *  "mat" will be a null pointer when an identity matrix is signified.
00320  *  This greatly speeds the comparison process.
00321  *
00322  *  The two cases can be distinguished by the fact that stp->st_id will
00323  *  be 0 for a new soltab structure, and non-zero for an existing one.
00324  *
00325  *  This routine will run in parallel.
00326  *
00327  *  In order to avoid a race between searching the soltab list and
00328  *  adding new solids to it, the new solid to be added *must* be
00329  *  enrolled in the list before exiting the critical section.
00330  *
00331  *  To limit the size of the list to be searched, there are many lists.
00332  *  The selection of which list is determined by the hash value
00333  *  computed from the solid's name.
00334  *  This is the same optimization used in searching the directory lists.
00335  *
00336  *  This subroutine is the critical bottleneck in parallel tree walking.
00337  *
00338  *  It is safe, and much faster, to use several different
00339  *  critical sections when searching different lists.
00340  *
00341  *  There are only 4 dedicated semaphores defined, TREE0 through TREE3.
00342  *  This unfortunately limits the code to having only 4 CPUs doing list
00343  *  searching at any one time.  Hopefully, this is enough parallelism
00344  *  to keep the rest of the CPUs doing I/O and actual solid prepping.
00345  *
00346  *  Since the algorithm has been reduced from an O((nsolid/128)**2)
00347  *  search on the entire rti_solidheads[hash] list to an O(ninstance)
00348  *  search on the dp->d_use_head list for this one solid, the critical
00349  *  section should be relatively short-lived.  Having the 3-way split
00350  *  should provide ample opportunity for parallelism through here,
00351  *  while still ensuring that the necessary variables are protected.
00352  *
00353  *  There are two critical variables which *both* need to be protected:
00354  *  the specific rti_solidhead[hash] list head, and the specific
00355  *  dp->d_use_hd list head.  Fortunately, since the selection of
00356  *  critical section is based upon db_dirhash(dp->d_namep), any other
00357  *  processor that wants to search this same 'dp' will get the same
00358  *  hash as the current thread, and will thus wait for the appropriate
00359  *  semaphore to be released.  Similarly, any other thread that
00360  *  wants to search the same rti_solidhead[hash] list as the current
00361  *  thread will be using the same hash, and will thus wait for the
00362  *  proper semaphore.
00363  */
00364 HIDDEN struct soltab *rt_find_identical_solid(register const matp_t mat, register struct directory *dp, struct rt_i *rtip)
00365 {
00366         register struct soltab  *stp = RT_SOLTAB_NULL;
00367         int                     hash;
00368 
00369         RT_CK_DIR(dp);
00370         RT_CK_RTI(rtip);
00371 
00372         hash = db_dirhash( dp->d_namep );
00373 
00374         /* Enter the appropriate dual critical-section */
00375         ACQUIRE_SEMAPHORE_TREE(hash);
00376 
00377         /*
00378          *  If solid has not been referenced yet, the search can be skipped.
00379          *  If solid is being referenced a _lot_, it certainly isn't
00380          *  all going to be in the same place, so don't bother searching.
00381          *  Consider the case of a million instances of the same tree
00382          *  submodel solid.
00383          */
00384         if( dp->d_uses > 0 && dp->d_uses < 100 &&
00385             rtip->rti_dont_instance == 0
00386         )  {
00387                 struct bu_list  *mid;
00388 
00389                 /* Search dp->d_use_hd list for other instances */
00390                 for( BU_LIST_FOR( mid, bu_list, &dp->d_use_hd ) )  {
00391 
00392                         stp = BU_LIST_MAIN_PTR( soltab, mid, l2 );
00393                         RT_CK_SOLTAB(stp);
00394 
00395                         if( stp->st_matp == (matp_t)0 )  {
00396                                 if( mat == (matp_t)0 )  {
00397                                         /* Both have identity matrix */
00398                                         goto more_checks;
00399                                 }
00400                                 continue;
00401                         }
00402                         if( mat == (matp_t)0 )  continue;       /* doesn't match */
00403 
00404                         if( !bn_mat_is_equal(mat, stp->st_matp, &rtip->rti_tol))
00405                                 continue;
00406 
00407 more_checks:
00408                         /* Don't instance this solid from some other model instance */
00409                         /* As this is nearly always equal, check it last */
00410                         if( stp->st_rtip != rtip )  continue;
00411 
00412                         /*
00413                          *  stp now points to re-referenced solid.
00414                          *  stp->st_id is non-zero, indicating pre-existing solid.
00415                          */
00416                         RT_CK_SOLTAB(stp);              /* sanity */
00417 
00418                         /* Only increment use counter for non-dead solids. */
00419                         if( !(stp->st_aradius <= -1) )
00420                                 stp->st_uses++;
00421                         /* dp->d_uses is NOT incremented, because number of soltab's using it has not gone up. */
00422                         if( RT_G_DEBUG & DEBUG_SOLIDS )  {
00423                                 bu_log( mat ?
00424                                     "rt_find_identical_solid:  %s re-referenced %d\n" :
00425                                     "rt_find_identical_solid:  %s re-referenced %d (identity mat)\n",
00426                                         dp->d_namep, stp->st_uses );
00427                         }
00428 
00429                         /* Leave the appropriate dual critical-section */
00430                         RELEASE_SEMAPHORE_TREE(hash);
00431                         return stp;
00432                 }
00433         }
00434 
00435         /*
00436          *  Create and link a new solid into the list.
00437          *
00438          *  Ensure the search keys "dp", "st_mat" and "st_rtip"
00439          *  are stored now, while still
00440          *  inside the critical section, because they are searched on, above.
00441          */
00442         BU_GETSTRUCT(stp, soltab);
00443         stp->l.magic = RT_SOLTAB_MAGIC;
00444         stp->l2.magic = RT_SOLTAB2_MAGIC;
00445         stp->st_rtip = rtip;
00446         stp->st_dp = dp;
00447         dp->d_uses++;
00448         stp->st_uses = 1;
00449         /* stp->st_id is intentionally left zero here, as a flag */
00450 
00451         if( mat )  {
00452                 stp->st_matp = (matp_t)bu_malloc( sizeof(mat_t), "st_matp" );
00453                 MAT_COPY( stp->st_matp, mat );
00454         } else {
00455                 stp->st_matp = (matp_t)0;
00456         }
00457 
00458         /* Add to the appropriate soltab list head */
00459         /* PARALLEL NOTE:  Uses critical section on rt_solidheads element */
00460         BU_LIST_INSERT( &(rtip->rti_solidheads[hash]), &(stp->l) );
00461 
00462         /* Also add to the directory structure list head */
00463         /* PARALLEL NOTE:  Uses critical section on this 'dp' */
00464         BU_LIST_INSERT( &dp->d_use_hd, &(stp->l2) );
00465 
00466         /*
00467          * Leave the 4-way critical-section protecting dp and [hash]
00468          */
00469         RELEASE_SEMAPHORE_TREE(hash);
00470 
00471         /* Enter an exclusive critical section to protect nsolids */
00472         /* nsolids++ needs to be locked to a SINGLE thread */
00473         bu_semaphore_acquire(RT_SEM_STATS);
00474         stp->st_bit = rtip->nsolids++;
00475         bu_semaphore_release(RT_SEM_STATS);
00476 
00477         /*
00478          *  Fill in the last little bit of the structure in
00479          *  full parallel mode, outside of any critical section.
00480          */
00481 
00482         /* Init tables of regions using this solid.  Usually small. */
00483         bu_ptbl_init( &stp->st_regions, 7, "st_regions ptbl" );
00484 
00485         return stp;
00486 }
00487 
00488 
00489 /*
00490  *                      R T _ G E T T R E E _ L E A F
00491  *
00492  *  This routine must be prepared to run in parallel.
00493  */
00494 HIDDEN union tree *rt_gettree_leaf(struct db_tree_state *tsp, struct db_full_path *pathp, struct rt_db_internal *ip, genptr_t client_data)
00495 /*const*/
00496 
00497 /*const*/
00498 
00499 {
00500         register struct soltab  *stp;
00501         union tree              *curtree;
00502         struct directory        *dp;
00503         register matp_t         mat;
00504         int                     i;
00505         struct rt_i             *rtip;
00506 
00507         RT_CK_DBTS(tsp);
00508         RT_CK_DBI(tsp->ts_dbip);
00509         RT_CK_FULL_PATH(pathp);
00510         RT_CK_DB_INTERNAL(ip);
00511         rtip = tsp->ts_rtip;
00512         RT_CK_RTI(rtip);
00513         RT_CK_RESOURCE(tsp->ts_resp);
00514         dp = DB_FULL_PATH_CUR_DIR(pathp);
00515 
00516         /* Determine if this matrix is an identity matrix */
00517 
00518         if( !bn_mat_is_equal(tsp->ts_mat, bn_mat_identity, &rtip->rti_tol)) {
00519                 /* Not identity matrix */
00520                 mat = (matp_t)tsp->ts_mat;
00521         } else {
00522                 /* Identity matrix */
00523                 mat = (matp_t)0;
00524         }
00525 
00526         /*
00527          *  Check to see if this exact solid has already been processed.
00528          *  Match on leaf name and matrix.
00529          *  Note that there is a race here between having st_id filled
00530          *  in a few lines below (which is necessary for calling ft_prep),
00531          *  and ft_prep filling in st_aradius.  Fortunately, st_aradius
00532          *  starts out as zero, and will never go down to -1 unless this
00533          *  soltab structure has become a dead solid, so by testing against
00534          *  -1 (instead of <= 0, like before, oops), it isn't a problem.
00535          */
00536         stp = rt_find_identical_solid( mat, dp, rtip );
00537         if( stp->st_id != 0 )  {
00538                 /* stp is an instance of a pre-existing solid */
00539                 if( stp->st_aradius <= -1 )  {
00540                         /* It's dead, Jim.  st_uses was not incremented. */
00541                         return( TREE_NULL );    /* BAD: instance of dead solid */
00542                 }
00543                 goto found_it;
00544         }
00545 
00546         if( rtip->rti_add_to_new_solids_list ) {
00547                 bu_ptbl_ins( &rtip->rti_new_solids, (long *)stp );
00548         }
00549 
00550         stp->st_id = ip->idb_type;
00551         stp->st_meth = &rt_functab[ip->idb_type];
00552         if( mat )  {
00553                 mat = stp->st_matp;
00554         } else {
00555                 mat = (matp_t)bn_mat_identity;
00556         }
00557 
00558         RT_CK_DB_INTERNAL( ip );
00559 
00560         /* init solid's maxima and minima */
00561         VSETALL( stp->st_max, -INFINITY );
00562         VSETALL( stp->st_min,  INFINITY );
00563 
00564         /*
00565          *  If the ft_prep routine wants to keep the internal structure,
00566          *  that is OK, as long as idb_ptr is set to null.
00567          *  Note that the prep routine may have changed st_id.
00568          */
00569         if( stp->st_meth->ft_prep( stp, ip, rtip ) )  {
00570                 int     hash;
00571                 /* Error, solid no good */
00572                 bu_log("rt_gettree_leaf(%s):  prep failure\n", dp->d_namep );
00573                 /* Too late to delete soltab entry; mark it as "dead" */
00574                 hash = db_dirhash( dp->d_namep );
00575                 ACQUIRE_SEMAPHORE_TREE(hash);
00576                 stp->st_aradius = -1;
00577                 stp->st_uses--;
00578                 RELEASE_SEMAPHORE_TREE(hash);
00579                 return( TREE_NULL );            /* BAD */
00580         }
00581 
00582         if( rtip->rti_dont_instance )  {
00583                 /*
00584                  *  If instanced solid refs are not being compressed,
00585                  *  then memory isn't an issue, and the application
00586                  *  (such as solids_on_ray) probably cares about the
00587                  *  full path of this solid, from root to leaf.
00588                  *  So make it available here.
00589                  *  (stp->st_dp->d_uses could be the way to discriminate
00590                  *  references uniquely, if the path isn't enough.
00591                  *  To locate given dp and d_uses, search dp->d_use_hd list.
00592                  *  Question is, where to stash current val of d_uses?)
00593                  */
00594                 db_full_path_init( &stp->st_path );
00595                 db_dup_full_path( &stp->st_path, pathp );
00596         } else {
00597                 /*
00598                  *  If there is more than just a direct reference to this leaf
00599                  *  from it's containing region, copy that below-region path
00600                  *  into st_path.  Otherwise, leave st_path's magic number 0.
00601                  * XXX nothing depends on this behavior yet, and this whole
00602                  * XXX 'else' clause might well be deleted. -Mike
00603                  */
00604                 i = pathp->fp_len-1;
00605                 if( i > 0 && !(pathp->fp_names[i-1]->d_flags & DIR_REGION) )  {
00606                         /* Search backwards for region.  If no region, use whole path */
00607                         for( --i; i > 0; i-- )  {
00608                                 if( pathp->fp_names[i-1]->d_flags & DIR_REGION ) break;
00609                         }
00610                         if( i < 0 )  i = 0;
00611                         db_full_path_init( &stp->st_path );
00612                         db_dup_path_tail( &stp->st_path, pathp, i );
00613                 }
00614         }
00615         if(RT_G_DEBUG&DEBUG_TREEWALK && stp->st_path.magic == DB_FULL_PATH_MAGIC)  {
00616                 char    *sofar = db_path_to_string(&stp->st_path);
00617                 bu_log("rt_gettree_leaf() st_path=%s\n", sofar );
00618                 bu_free(sofar, "path string");
00619         }
00620 
00621         if(RT_G_DEBUG&DEBUG_SOLIDS)  {
00622                 struct bu_vls   str;
00623                 bu_log("\n---Primitive %d: %s\n", stp->st_bit, dp->d_namep);
00624                 bu_vls_init( &str );
00625                 /* verbose=1, mm2local=1.0 */
00626                 if( stp->st_meth->ft_describe( &str, ip, 1, 1.0, tsp->ts_resp, tsp->ts_dbip ) < 0 )  {
00627                         bu_log("rt_gettree_leaf(%s):  solid describe failure\n",
00628                                 dp->d_namep );
00629                 }
00630                 bu_log( "%s:  %s", dp->d_namep, bu_vls_addr( &str ) );
00631                 bu_vls_free( &str );
00632         }
00633 
00634 found_it:
00635         RT_GET_TREE( curtree, tsp->ts_resp );
00636         curtree->magic = RT_TREE_MAGIC;
00637         curtree->tr_op = OP_SOLID;
00638         curtree->tr_a.tu_stp = stp;
00639         /* regionp will be filled in later by rt_tree_region_assign() */
00640         curtree->tr_a.tu_regionp = (struct region *)0;
00641 
00642         if(RT_G_DEBUG&DEBUG_TREEWALK)  {
00643                 char    *sofar = db_path_to_string(pathp);
00644                 bu_log("rt_gettree_leaf() %s\n", sofar );
00645                 bu_free(sofar, "path string");
00646         }
00647 
00648         return(curtree);
00649 }
00650 
00651 /*
00652  *                      R T _ F R E E _ S O L T A B
00653  *
00654  *  Decrement use count on soltab structure.  If no longer needed,
00655  *  release associated storage, and free the structure.
00656  *
00657  *  This routine semaphore protects against other copies of itself
00658  *  running in parallel, and against
00659  *  other routines (such as rt_find_identical_solid()) which might
00660  *  also be modifying the linked list heads.
00661  *
00662  *  Called by -
00663  *      db_free_tree()
00664  *      rt_clean()
00665  *      rt_gettrees()
00666  *      rt_kill_deal_solid_refs()
00667  */
00668 void
00669 rt_free_soltab(struct soltab *stp)
00670 {
00671         int     hash;
00672 
00673         RT_CK_SOLTAB(stp);
00674         if( stp->st_id < 0 || stp->st_id >= rt_nfunctab )
00675                 rt_bomb("rt_free_soltab:  bad st_id");
00676         hash = db_dirhash(stp->st_dp->d_namep);
00677 
00678         ACQUIRE_SEMAPHORE_TREE(hash);           /* start critical section */
00679         if( --(stp->st_uses) > 0 )  {
00680                 RELEASE_SEMAPHORE_TREE(hash);
00681                 return;
00682         }
00683         BU_LIST_DEQUEUE( &(stp->l2) );          /* remove from st_dp->d_use_hd list */
00684         BU_LIST_DEQUEUE( &(stp->l) );           /* uses rti_solidheads[] */
00685 
00686         RELEASE_SEMAPHORE_TREE(hash);           /* end critical section */
00687 
00688         if( stp->st_aradius > 0 )  {
00689                 stp->st_meth->ft_free( stp );
00690                 stp->st_aradius = 0;
00691         }
00692         if( stp->st_matp )  bu_free( (char *)stp->st_matp, "st_matp");
00693         stp->st_matp = (matp_t)0;       /* Sanity */
00694 
00695         bu_ptbl_free(&stp->st_regions);
00696 
00697         stp->st_dp = DIR_NULL;          /* Sanity */
00698 
00699         if( stp->st_path.magic )  {
00700                 RT_CK_FULL_PATH( &stp->st_path );
00701                 db_free_full_path( &stp->st_path );
00702         }
00703 
00704         bu_free( (char *)stp, "struct soltab" );
00705 }
00706 
00707 /*                      R T _ G E T T R E E S _ M U V E S
00708  *
00709  *  User-called function to add a set of tree hierarchies to the active set.
00710  *
00711  *  Includes getting the indicated list of attributes and a Tcl_HashTable
00712  *  for use with the ORCA man regions. (stashed in the rt_i structure).
00713  *
00714  *  This function may run in parallel, but is not multiply re-entrant itself,
00715  *  because db_walk_tree() isn't multiply re-entrant.
00716  *
00717  *  Semaphores used for critical sections in parallel mode:
00718  *      RT_SEM_TREE*    protects rti_solidheads[] lists, d_uses(solids)
00719  *      RT_SEM_RESULTS  protects HeadRegion, mdl_min/max, d_uses(reg), nregions
00720  *      RT_SEM_WORKER   (db_walk_dispatcher, from db_walk_tree)
00721  *      RT_SEM_STATS    nsolids
00722  *
00723  *  INPUTS
00724  *      rtip    - RT instance pointer
00725  *      attrs   - array of pointers (NULL terminated) to strings (attribute names). A corresponding
00726  *                array of "bu_mro" objects containing the attribute values will be attached to region
00727  *                structures ("attr_values")
00728  *      argc    - number of trees to get
00729  *      argv    - array of char pointers to the names of the tree tops
00730  *      ncpus   - number of cpus to use
00731  *
00732  *  Returns -
00733  *      0       Ordinarily
00734  *      -1      On major error
00735  */
00736 int
00737 rt_gettrees_muves(struct rt_i *rtip, const char **attrs, int argc, const char **argv, int ncpus)
00738 {
00739         register struct soltab  *stp;
00740         register struct region  *regp;
00741         Tcl_HashTable           *tbl;
00742         int                     prev_sol_count;
00743         int                     i;
00744         int                     num_attrs=0;
00745         point_t                 region_min, region_max;
00746 
00747         RT_CHECK_RTI(rtip);
00748         RT_CK_DBI(rtip->rti_dbip);
00749 
00750         if(!rtip->needprep)  {
00751                 bu_log("ERROR: rt_gettree() called again after rt_prep!\n");
00752                 return(-1);             /* FAIL */
00753         }
00754 
00755         if( argc <= 0 )  return(-1);    /* FAIL */
00756 
00757         tbl = (Tcl_HashTable *)bu_malloc( sizeof( Tcl_HashTable ), "rtip->Orca_hash_tbl" );
00758         Tcl_InitHashTable( tbl, TCL_ONE_WORD_KEYS );
00759         rtip->Orca_hash_tbl = (genptr_t)tbl;
00760 
00761         prev_sol_count = rtip->nsolids;
00762 
00763         {
00764                 struct db_tree_state    tree_state;
00765 
00766                 tree_state = rt_initial_tree_state;     /* struct copy */
00767                 tree_state.ts_dbip = rtip->rti_dbip;
00768                 tree_state.ts_rtip = rtip;
00769                 tree_state.ts_resp = NULL;      /* sanity.  Needs to be updated */
00770 
00771                 if( attrs ) {
00772                        if( rtip->rti_dbip->dbi_version < 5 ) {
00773                                bu_log( "WARNING: requesting attributes from an old database version (ignored)\n" );
00774                                bu_avs_init_empty( &tree_state.ts_attrs );
00775                        } else {
00776                                while( attrs[num_attrs] ) {
00777                                        num_attrs++;
00778                                }
00779                                if( num_attrs ) {
00780                                        bu_avs_init( &tree_state.ts_attrs,
00781                                                     num_attrs,
00782                                                     "avs in tree_state" );
00783                                        num_attrs = 0;
00784                                        while( attrs[num_attrs] ) {
00785                                                bu_avs_add( &tree_state.ts_attrs,
00786                                                            attrs[num_attrs],
00787                                                            NULL );
00788                                                num_attrs++;
00789                                        }
00790                                } else {
00791                                        bu_avs_init_empty( &tree_state.ts_attrs );
00792                                }
00793                        }
00794                 } else {
00795                         bu_avs_init_empty( &tree_state.ts_attrs );
00796                 }
00797 
00798                 /* ifdef this out for now, it is only using memory.
00799                  * perhaps a better way of initiating ORCA stuff
00800                  * can be found.
00801                  */
00802 #if 0
00803                 bu_avs_add( &tree_state.ts_attrs, "ORCA_Comp", (char *)NULL );
00804 #endif
00805                 i = db_walk_tree( rtip->rti_dbip, argc, argv, ncpus,
00806                                   &tree_state,
00807                                   rt_gettree_region_start,
00808                                   rt_gettree_region_end,
00809                                   rt_gettree_leaf, (genptr_t)tbl );
00810                 bu_avs_free( &tree_state.ts_attrs );
00811         }
00812 
00813         /* DEBUG:  Ensure that all region trees are valid */
00814         for( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
00815                 RT_CK_REGION(regp);
00816                 db_ck_tree(regp->reg_treetop);
00817         }
00818 
00819         /*
00820          *  Eliminate any "dead" solids that parallel code couldn't change.
00821          *  First remove any references from the region tree,
00822          *  then remove actual soltab structs from the soltab list.
00823          */
00824         for( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
00825                 RT_CK_REGION(regp);
00826                 rt_tree_kill_dead_solid_refs( regp->reg_treetop );
00827                 (void)rt_tree_elim_nops( regp->reg_treetop, &rt_uniresource );
00828         }
00829 again:
00830         RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
00831                 RT_CK_SOLTAB(stp);
00832                 if( stp->st_aradius <= 0 )  {
00833                         bu_log("rt_gettrees() cleaning up dead solid '%s'\n",
00834                                 stp->st_dp->d_namep );
00835                         rt_free_soltab(stp);
00836                         /* Can't do rtip->nsolids--, that doubles as max bit number! */
00837                         /* The macro makes it hard to regain place, punt */
00838                         goto again;
00839                 }
00840         } RT_VISIT_ALL_SOLTABS_END
00841 
00842         /*
00843          *  Another pass, no restarting.
00844          *  Assign "piecestate" indices for those solids
00845          *  which contain pieces.
00846          */
00847         RT_VISIT_ALL_SOLTABS_START( stp, rtip )  {
00848                 if( stp->st_npieces > 1 )  {
00849                         /* all pieces must be within model bounding box for pieces to work correctly */
00850                         VMINMAX( rtip->mdl_min, rtip->mdl_max, stp->st_min );
00851                         VMINMAX( rtip->mdl_min, rtip->mdl_max, stp->st_max );
00852                         stp->st_piecestate_num = rtip->rti_nsolids_with_pieces++;
00853                 }
00854                 if(RT_G_DEBUG&DEBUG_SOLIDS)
00855                         rt_pr_soltab( stp );
00856         } RT_VISIT_ALL_SOLTABS_END
00857 
00858         /* Handle finishing touches on the trees that needed soltab structs
00859          * that the parallel code couldn't look at yet.
00860          */
00861         for( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
00862                 RT_CK_REGION(regp);
00863 
00864                 /* The region and the entire tree are cross-referenced */
00865                 rt_tree_region_assign( regp->reg_treetop, regp );
00866 
00867                 /*
00868                  *  Find region RPP, and update the model maxima and minima
00869                  *
00870                  *  Don't update min & max for halfspaces;  instead, add them
00871                  *  to the list of infinite solids, for special handling.
00872                  */
00873                 if( rt_bound_tree( regp->reg_treetop, region_min, region_max ) < 0 )  {
00874                         bu_log("rt_gettrees() %s\n", regp->reg_name );
00875                         rt_bomb("rt_gettrees(): rt_bound_tree() fail\n");
00876                 }
00877                 if( region_max[X] < INFINITY )  {
00878                         /* infinite regions are exempted from this */
00879                         VMINMAX( rtip->mdl_min, rtip->mdl_max, region_min );
00880                         VMINMAX( rtip->mdl_min, rtip->mdl_max, region_max );
00881                 }
00882         }
00883 
00884         /* DEBUG:  Ensure that all region trees are valid */
00885         for( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
00886                 RT_CK_REGION(regp);
00887                 db_ck_tree(regp->reg_treetop);
00888         }
00889 
00890         if( i < 0 )  return(i);
00891 
00892         if( rtip->nsolids <= prev_sol_count )
00893                 bu_log("rt_gettrees(%s) warning:  no primitives found\n", argv[0]);
00894         return(0);      /* OK */
00895 }
00896 
00897 /*
00898  *                      R T _ G E T T R E E S _ A N D _ A T T R S
00899  *
00900  *  User-called function to add a set of tree hierarchies to the active set.
00901  *
00902  *  This function may run in parallel, but is not multiply re-entrant itself,
00903  *  because db_walk_tree() isn't multiply re-entrant.
00904  *
00905  *  Semaphores used for critical sections in parallel mode:
00906  *      RT_SEM_TREE*    protects rti_solidheads[] lists, d_uses(solids)
00907  *      RT_SEM_RESULTS  protects HeadRegion, mdl_min/max, d_uses(reg), nregions
00908  *      RT_SEM_WORKER   (db_walk_dispatcher, from db_walk_tree)
00909  *      RT_SEM_STATS    nsolids
00910  *
00911  *  Returns -
00912  *      0       Ordinarily
00913  *      -1      On major error
00914  *      -2      If there were unresolved names
00915  */
00916 int
00917 rt_gettrees_and_attrs(struct rt_i *rtip, const char **attrs, int argc, const char **argv, int ncpus)
00918 {
00919         return( rt_gettrees_muves( rtip, attrs, argc, argv, ncpus ) );
00920 }
00921 
00922 /*
00923  *                      R T _ G E T T R E E
00924  *
00925  *  User-called function to add a tree hierarchy to the displayed set.
00926  *
00927  *  This function is not multiply re-entrant.
00928  *
00929  *  Returns -
00930  *      0       Ordinarily
00931  *      -1      On major error
00932  *
00933  *  Note: -2 returns from rt_gettrees_and_attrs are filtered.
00934  */
00935 int
00936 rt_gettree(struct rt_i *rtip, const char *node)
00937 {
00938   int rv;
00939   const char *argv[2];
00940 
00941   argv[0] = node;
00942   argv[1] = (const char *)NULL;
00943 
00944   rv =  rt_gettrees_and_attrs( rtip, NULL, 1, argv, 1 );
00945 
00946   if (rv == 0 || rv == -2)
00947     {
00948       return 0;
00949     }
00950   else
00951     {
00952       return -1;
00953     }
00954 }
00955 
00956 int
00957 rt_gettrees(struct rt_i *rtip, int argc, const char **argv, int ncpus)
00958 {
00959   int rv;
00960   rv = rt_gettrees_and_attrs( rtip, NULL, argc, argv, ncpus );
00961 
00962   if (rv == 0 || rv == -2)
00963     {
00964       return 0;
00965     }
00966   else
00967     {
00968       return -1;
00969     }
00970 }
00971 
00972 /*
00973  *                      R T _ B O U N D _ T R E E
00974  *
00975  *  Calculate the bounding RPP of the region whose boolean tree is 'tp'.
00976  *  The bounding RPP is returned in tree_min and tree_max, which need
00977  *  not have been initialized first.
00978  *
00979  *  Returns -
00980  *      0       success
00981  *      -1      failure (tree_min and tree_max may have been altered)
00982  */
00983 int
00984 rt_bound_tree(register const union tree *tp, fastf_t *tree_min, fastf_t *tree_max)
00985 {
00986         vect_t  r_min, r_max;           /* rpp for right side of tree */
00987 
00988         RT_CK_TREE(tp);
00989 
00990         switch( tp->tr_op )  {
00991 
00992         case OP_SOLID:
00993                 {
00994                         register const struct soltab    *stp;
00995 
00996                         stp = tp->tr_a.tu_stp;
00997                         RT_CK_SOLTAB(stp);
00998                         if( stp->st_aradius <= 0 )  {
00999                                 bu_log("rt_bound_tree: encountered dead solid '%s'\n",
01000                                         stp->st_dp->d_namep);
01001                                 return -1;      /* ERROR */
01002                         }
01003 
01004                         if( stp->st_aradius >= INFINITY )  {
01005                                 VSETALL( tree_min, -INFINITY );
01006                                 VSETALL( tree_max,  INFINITY );
01007                                 return(0);
01008                         }
01009                         VMOVE( tree_min, stp->st_min );
01010                         VMOVE( tree_max, stp->st_max );
01011                         return(0);
01012                 }
01013 
01014         default:
01015                 bu_log( "rt_bound_tree(x%x): unknown op=x%x\n",
01016                         tp, tp->tr_op );
01017                 return(-1);
01018 
01019         case OP_XOR:
01020         case OP_UNION:
01021                 /* BINARY type -- expand to contain both */
01022                 if( rt_bound_tree( tp->tr_b.tb_left, tree_min, tree_max ) < 0 ||
01023                     rt_bound_tree( tp->tr_b.tb_right, r_min, r_max ) < 0 )
01024                         return(-1);
01025                 VMIN( tree_min, r_min );
01026                 VMAX( tree_max, r_max );
01027                 break;
01028         case OP_INTERSECT:
01029                 /* BINARY type -- find common area only */
01030                 if( rt_bound_tree( tp->tr_b.tb_left, tree_min, tree_max ) < 0 ||
01031                     rt_bound_tree( tp->tr_b.tb_right, r_min, r_max ) < 0 )
01032                         return(-1);
01033                 /* min = largest min, max = smallest max */
01034                 VMAX( tree_min, r_min );
01035                 VMIN( tree_max, r_max );
01036                 break;
01037         case OP_SUBTRACT:
01038                 /* BINARY type -- just use left tree */
01039                 if( rt_bound_tree( tp->tr_b.tb_left, tree_min, tree_max ) < 0 ||
01040                     rt_bound_tree( tp->tr_b.tb_right, r_min, r_max ) < 0 )
01041                         return(-1);
01042                 /* Discard right rpp */
01043                 break;
01044         case OP_NOP:
01045                 /* Implies that this tree has nothing in it */
01046                 break;
01047         }
01048         return(0);
01049 }
01050 
01051 /*
01052  *                      R T _ T R E E _ K I L L _ D E A D _ S O L I D _ R E F S
01053  *
01054  *  Convert any references to "dead" solids into NOP nodes.
01055  */
01056 void
01057 rt_tree_kill_dead_solid_refs(register union tree *tp)
01058 {
01059 
01060         RT_CK_TREE(tp);
01061 
01062         switch( tp->tr_op )  {
01063 
01064         case OP_SOLID:
01065                 {
01066                         register struct soltab  *stp;
01067 
01068                         stp = tp->tr_a.tu_stp;
01069                         RT_CK_SOLTAB(stp);
01070                         if( stp->st_aradius <= 0 )  {
01071                                 if(RT_G_DEBUG&DEBUG_TREEWALK)bu_log("rt_tree_kill_dead_solid_refs: encountered dead solid '%s' stp=x%x, tp=x%x\n",
01072                                         stp->st_dp->d_namep, stp, tp);
01073                                 rt_free_soltab(stp);
01074                                 tp->tr_a.tu_stp = SOLTAB_NULL;
01075                                 tp->tr_op = OP_NOP;     /* Convert to NOP */
01076                         }
01077                         return;
01078                 }
01079 
01080         default:
01081                 bu_log( "rt_tree_kill_dead_solid_refs(x%x): unknown op=x%x\n",
01082                         tp, tp->tr_op );
01083                 return;
01084 
01085         case OP_XOR:
01086         case OP_UNION:
01087         case OP_INTERSECT:
01088         case OP_SUBTRACT:
01089                 /* BINARY */
01090                 rt_tree_kill_dead_solid_refs( tp->tr_b.tb_left );
01091                 rt_tree_kill_dead_solid_refs( tp->tr_b.tb_right );
01092                 break;
01093         case OP_NOT:
01094         case OP_GUARD:
01095         case OP_XNOP:
01096                 /* UNARY tree -- for completeness only, should never be seen */
01097                 rt_tree_kill_dead_solid_refs( tp->tr_b.tb_left );
01098                 break;
01099         case OP_NOP:
01100                 /* This sub-tree has nothing further in it */
01101                 return;
01102         }
01103         return;
01104 }
01105 
01106 /*
01107  *                      R T _ T R E E _ E L I M _ N O P S
01108  *
01109  *  Eliminate any references to NOP nodes from the tree.
01110  *  It is safe to use db_free_tree() here, because there will not
01111  *  be any dead solids.  They will all have been converted to OP_NOP
01112  *  nodes by rt_tree_kill_dead_solid_refs(), previously, so there
01113  *  is no need to worry about multiple db_free_tree()'s repeatedly
01114  *  trying to free one solid that has been instanced multiple times.
01115  *
01116  *  Returns -
01117  *      0       this node is OK.
01118  *      -1      request caller to kill this node
01119  */
01120 int
01121 rt_tree_elim_nops( register union tree *tp, struct resource *resp )
01122 {
01123         union tree      *left, *right;
01124 
01125         RT_CK_RESOURCE(resp);
01126 top:
01127         RT_CK_TREE(tp);
01128 
01129         switch( tp->tr_op )  {
01130 
01131         case OP_SOLID:
01132                 return(0);              /* Retain */
01133 
01134         default:
01135                 bu_log( "rt_tree_elim_nops(x%x): unknown op=x%x\n",
01136                         tp, tp->tr_op );
01137                 return(-1);
01138 
01139         case OP_XOR:
01140         case OP_UNION:
01141                 /* BINARY type -- rewrite tp as surviving side */
01142                 left = tp->tr_b.tb_left;
01143                 right = tp->tr_b.tb_right;
01144                 if( rt_tree_elim_nops( left, resp ) < 0 )  {
01145                         *tp = *right;   /* struct copy */
01146                         RT_FREE_TREE( left, resp );
01147                         RT_FREE_TREE( right, resp );
01148                         goto top;
01149                 }
01150                 if( rt_tree_elim_nops( right, resp ) < 0 )  {
01151                         *tp = *left;    /* struct copy */
01152                         RT_FREE_TREE( left, resp );
01153                         RT_FREE_TREE( right, resp );
01154                         goto top;
01155                 }
01156                 break;
01157         case OP_INTERSECT:
01158                 /* BINARY type -- if either side fails, nuke subtree */
01159                 left = tp->tr_b.tb_left;
01160                 right = tp->tr_b.tb_right;
01161                 if( rt_tree_elim_nops( left, resp ) < 0 ||
01162                     rt_tree_elim_nops( right, resp ) < 0 )  {
01163                         db_free_tree( left, resp );
01164                         db_free_tree( right, resp );
01165                         tp->tr_op = OP_NOP;
01166                         return(-1);     /* eliminate reference to tp */
01167                 }
01168                 break;
01169         case OP_SUBTRACT:
01170                 /* BINARY type -- if right fails, rewrite (X - 0 = X).
01171                  *  If left fails, nuke entire subtree (0 - X = 0).
01172                  */
01173                 left = tp->tr_b.tb_left;
01174                 right = tp->tr_b.tb_right;
01175                 if( rt_tree_elim_nops( left, resp ) < 0 )  {
01176                         db_free_tree( left, resp );
01177                         db_free_tree( right, resp );
01178                         tp->tr_op = OP_NOP;
01179                         return(-1);     /* eliminate reference to tp */
01180                 }
01181                 if( rt_tree_elim_nops( right, resp ) < 0 )  {
01182                         *tp = *left;    /* struct copy */
01183                         RT_FREE_TREE( left, resp );
01184                         RT_FREE_TREE( right, resp );
01185                         goto top;
01186                 }
01187                 break;
01188         case OP_NOT:
01189         case OP_GUARD:
01190         case OP_XNOP:
01191                 /* UNARY tree -- for completeness only, should never be seen */
01192                 left = tp->tr_b.tb_left;
01193                 if( rt_tree_elim_nops( left, resp ) < 0 )  {
01194                         RT_FREE_TREE( left, resp );
01195                         tp->tr_op = OP_NOP;
01196                         return(-1);     /* Kill ref to unary op, too */
01197                 }
01198                 break;
01199         case OP_NOP:
01200                 /* Implies that this tree has nothing in it */
01201                 return(-1);             /* Kill ref to this NOP */
01202         }
01203         return(0);
01204 }
01205 
01206 /*
01207  *                      R T _ B A S E N A M E
01208  *
01209  *  Given a string containing slashes such as a pathname, return a
01210  *  pointer to the first character after the last slash.
01211  */
01212 const char *
01213 rt_basename(register const char *str)
01214 {
01215         register const char     *p = str;
01216         while( *p != '\0' )
01217                 if( *p++ == '/' )
01218                         str = p;
01219         return  str;
01220 }
01221 
01222 /*
01223  *                      R T _ G E T R E G I O N
01224  *
01225  *  Return a pointer to the corresponding region structure of the given
01226  *  region's name (reg_name), or REGION_NULL if it does not exist.
01227  *
01228  *  If the full path of a region is specified, then that one is
01229  *  returned.  However, if only the database node name of the
01230  *  region is specified and that region has been referenced multiple
01231  *  time in the tree, then this routine will simply return the first one.
01232  */
01233 HIDDEN struct region *
01234 rt_getregion(struct rt_i *rtip, register const char *reg_name)
01235 {
01236         register struct region  *regp;
01237         register const char *reg_base = rt_basename(reg_name);
01238 
01239         RT_CK_RTI(rtip);
01240         for( BU_LIST_FOR( regp, region, &(rtip->HeadRegion) ) )  {
01241                 register const char     *cp;
01242                 /* First, check for a match of the full path */
01243                 if( *reg_base == regp->reg_name[0] &&
01244                     strcmp( reg_base, regp->reg_name ) == 0 )
01245                         return(regp);
01246                 /* Second, check for a match of the database node name */
01247                 cp = rt_basename( regp->reg_name );
01248                 if( *cp == *reg_name && strcmp( cp, reg_name ) == 0 )
01249                         return(regp);
01250         }
01251         return(REGION_NULL);
01252 }
01253 
01254 /*
01255  *                      R T _ R P P _ R E G I O N
01256  *
01257  *  Calculate the bounding RPP for a region given the name of
01258  *  the region node in the database.  See remarks in rt_getregion()
01259  *  above for name conventions.
01260  *  Returns 0 for failure (and prints a diagnostic), or 1 for success.
01261  */
01262 int
01263 rt_rpp_region(struct rt_i *rtip, const char *reg_name, fastf_t *min_rpp, fastf_t *max_rpp)
01264 {
01265         register struct region  *regp;
01266 
01267         RT_CHECK_RTI(rtip);
01268 
01269         regp = rt_getregion( rtip, reg_name );
01270         if( regp == REGION_NULL )  return(0);
01271         if( rt_bound_tree( regp->reg_treetop, min_rpp, max_rpp ) < 0)
01272                 return(0);
01273         return(1);
01274 }
01275 
01276 /*
01277  *                      R T _ F A S T F _ F L O A T
01278  *
01279  *  Convert TO fastf_t FROM 3xfloats (for database)
01280  */
01281 void
01282 rt_fastf_float(register fastf_t *ff, register const dbfloat_t *fp, register int n)
01283 {
01284 #       include "noalias.h"
01285         while( n-- )  {
01286                 *ff++ = *fp++;
01287                 *ff++ = *fp++;
01288                 *ff++ = *fp++;
01289                 ff += ELEMENTS_PER_VECT-3;
01290         }
01291 }
01292 
01293 /*
01294  *                      R T _ M A T _ D B M A T
01295  *
01296  *  Convert TO fastf_t matrix FROM dbfloats (for database)
01297  */
01298 void
01299 rt_mat_dbmat(register fastf_t *ff, register const dbfloat_t *dbp)
01300 {
01301 
01302         *ff++ = *dbp++;
01303         *ff++ = *dbp++;
01304         *ff++ = *dbp++;
01305         *ff++ = *dbp++;
01306 
01307         *ff++ = *dbp++;
01308         *ff++ = *dbp++;
01309         *ff++ = *dbp++;
01310         *ff++ = *dbp++;
01311 
01312         *ff++ = *dbp++;
01313         *ff++ = *dbp++;
01314         *ff++ = *dbp++;
01315         *ff++ = *dbp++;
01316 
01317         *ff++ = *dbp++;
01318         *ff++ = *dbp++;
01319         *ff++ = *dbp++;
01320         *ff++ = *dbp++;
01321 }
01322 
01323 /*
01324  *                      R T _ D B M A T _ M A T
01325  *
01326  *  Convert FROM fastf_t matrix TO dbfloats (for updating database)
01327  */
01328 void
01329 rt_dbmat_mat(register dbfloat_t *dbp, register const fastf_t *ff)
01330 {
01331 
01332         *dbp++ = (dbfloat_t) *ff++;
01333         *dbp++ = (dbfloat_t) *ff++;
01334         *dbp++ = (dbfloat_t) *ff++;
01335         *dbp++ = (dbfloat_t) *ff++;
01336 
01337         *dbp++ = (dbfloat_t) *ff++;
01338         *dbp++ = (dbfloat_t) *ff++;
01339         *dbp++ = (dbfloat_t) *ff++;
01340         *dbp++ = (dbfloat_t) *ff++;
01341 
01342         *dbp++ = (dbfloat_t) *ff++;
01343         *dbp++ = (dbfloat_t) *ff++;
01344         *dbp++ = (dbfloat_t) *ff++;
01345         *dbp++ = (dbfloat_t) *ff++;
01346 
01347         *dbp++ = (dbfloat_t) *ff++;
01348         *dbp++ = (dbfloat_t) *ff++;
01349         *dbp++ = (dbfloat_t) *ff++;
01350         *dbp++ = (dbfloat_t) *ff++;
01351 }
01352 
01353 /*
01354  *                      R T _ F I N D _ S O L I D
01355  *
01356  *  Given the (leaf) name of a solid, find the first occurance of it
01357  *  in the solid list.  Used mostly to find the light source.
01358  *  Returns soltab pointer, or RT_SOLTAB_NULL.
01359  */
01360 struct soltab *
01361 rt_find_solid(const struct rt_i *rtip, register const char *name)
01362 {
01363         register struct soltab  *stp;
01364         struct directory        *dp;
01365 
01366         RT_CHECK_RTI(rtip);
01367         if( (dp = db_lookup( (struct db_i *)rtip->rti_dbip, (char *)name,
01368             LOOKUP_QUIET )) == DIR_NULL )
01369                 return(RT_SOLTAB_NULL);
01370 
01371         RT_VISIT_ALL_SOLTABS_START( stp, (struct rt_i *)rtip )  {
01372                 if( stp->st_dp == dp )
01373                         return(stp);
01374         } RT_VISIT_ALL_SOLTABS_END
01375         return(RT_SOLTAB_NULL);
01376 }
01377 
01378 
01379 /*
01380  *                      R T _ O P T I M _ T R E E
01381  */
01382 void
01383 rt_optim_tree(register union tree *tp, struct resource *resp)
01384 {
01385         register union tree     **sp;
01386         register union tree     *low;
01387         register union tree     **stackend;
01388 
01389         RT_CK_TREE(tp);
01390         while( (sp = resp->re_boolstack) == (union tree **)0 )
01391                 rt_grow_boolstack( resp );
01392         stackend = &(resp->re_boolstack[resp->re_boolslen-1]);
01393         *sp++ = TREE_NULL;
01394         *sp++ = tp;
01395         while( (tp = *--sp) != TREE_NULL ) {
01396                 switch( tp->tr_op )  {
01397                 case OP_NOP:
01398                         /* XXX Consider eliminating nodes of form (A op NOP) */
01399                         /* XXX Needs to be detected in previous iteration */
01400                         break;
01401                 case OP_SOLID:
01402                         break;
01403                 case OP_SUBTRACT:
01404                         while( (low=tp->tr_b.tb_left)->tr_op == OP_SUBTRACT )  {
01405                                 /* Rewrite X - A - B as X - ( A union B ) */
01406                                 tp->tr_b.tb_left = low->tr_b.tb_left;
01407                                 low->tr_op = OP_UNION;
01408                                 low->tr_b.tb_left = low->tr_b.tb_right;
01409                                 low->tr_b.tb_right = tp->tr_b.tb_right;
01410                                 tp->tr_b.tb_right = low;
01411                         }
01412                         /* push both nodes - search left first */
01413                         *sp++ = tp->tr_b.tb_right;
01414                         *sp++ = tp->tr_b.tb_left;
01415                         if( sp >= stackend )  {
01416                                 register int off = sp - resp->re_boolstack;
01417                                 rt_grow_boolstack( resp );
01418                                 sp = &(resp->re_boolstack[off]);
01419                                 stackend = &(resp->re_boolstack[resp->re_boolslen-1]);
01420                         }
01421                         break;
01422                 case OP_UNION:
01423                 case OP_INTERSECT:
01424                 case OP_XOR:
01425                         /* Need to look at 3-level optimizations here, both sides */
01426                         /* push both nodes - search left first */
01427                         *sp++ = tp->tr_b.tb_right;
01428                         *sp++ = tp->tr_b.tb_left;
01429                         if( sp >= stackend )  {
01430                                 register int off = sp - resp->re_boolstack;
01431                                 rt_grow_boolstack( resp );
01432                                 sp = &(resp->re_boolstack[off]);
01433                                 stackend = &(resp->re_boolstack[resp->re_boolslen-1]);
01434                         }
01435                         break;
01436                 default:
01437                         bu_log("rt_optim_tree: bad op x%x\n", tp->tr_op);
01438                         break;
01439                 }
01440         }
01441 }
01442 
01443 /*
01444  *                      R T _ T R E E _ R E G I O N _ A S S I G N
01445  */
01446 HIDDEN void
01447 rt_tree_region_assign(register union tree *tp, register const struct region *regionp)
01448 {
01449         RT_CK_TREE(tp);
01450         RT_CK_REGION(regionp);
01451         switch( tp->tr_op )  {
01452         case OP_NOP:
01453                 return;
01454 
01455         case OP_SOLID:
01456                 tp->tr_a.tu_regionp = (struct region *)regionp;
01457                 return;
01458 
01459         case OP_NOT:
01460         case OP_GUARD:
01461         case OP_XNOP:
01462                 tp->tr_b.tb_regionp = (struct region *)regionp;
01463                 rt_tree_region_assign( tp->tr_b.tb_left, regionp );
01464                 return;
01465 
01466         case OP_UNION:
01467         case OP_INTERSECT:
01468         case OP_SUBTRACT:
01469         case OP_XOR:
01470                 tp->tr_b.tb_regionp = (struct region *)regionp;
01471                 rt_tree_region_assign( tp->tr_b.tb_left, regionp );
01472                 rt_tree_region_assign( tp->tr_b.tb_right, regionp );
01473                 return;
01474 
01475         default:
01476                 rt_bomb("rt_tree_region_assign: bad op\n");
01477         }
01478 }
01479 
01480 /*
01481  * Local Variables:
01482  * mode: C
01483  * tab-width: 8
01484  * c-basic-offset: 4
01485  * indent-tabs-mode: t
01486  * End:
01487  * ex: shiftwidth=4 tabstop=8
01488  */

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