bool.c

Go to the documentation of this file.
00001 /*                          B O O L . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1985-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup ray */
00023 /*@{*/
00024 /** @file bool.c
00025  * Ray Tracing program, Boolean region evaluator.
00026  *
00027  *  Note to developers -
00028  *      Do not use the hit_point field in these routines, as
00029  *      for some solid types it has been filled in by the g_xxx_shot()
00030  *      routine, and for other solid types it may not have been.
00031  *      In particular, copying a garbage hit_point from a structure which
00032  *      has not yet been filled in, into a structure which won't be
00033  *      filled in again, gives wrong results.
00034  *      Thanks to Keith Bowman for finding this obscure bug.
00035  *
00036  *  Author -
00037  *      Michael John Muuss
00038  *
00039  *  Source -
00040  *      The U. S. Army Research Laboratory
00041  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00042  */
00043 /*@}*/
00044 
00045 #ifndef lint
00046 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/bool.c,v 14.14 2006/09/16 02:04:24 lbutler Exp $ (ARL)";
00047 #endif
00048 
00049 #include "common.h"
00050 
00051 #include <stdio.h>
00052 #ifdef HAVE_STRING_H
00053 #  include <string.h>
00054 #else
00055 #  include <strings.h>
00056 #endif
00057 #include "machine.h"
00058 #include "vmath.h"
00059 #include "raytrace.h"
00060 #include "bu.h"
00061 #include "./debug.h"
00062 
00063 /* Boolean values.  Not easy to change, but defined symbolicly */
00064 #define FALSE   0
00065 #define TRUE    1
00066 
00067 
00068 BU_EXTERN(void rt_grow_boolstack, (struct resource *resp) );
00069 int rt_tree_max_raynum(register const union tree *,
00070                        register const struct partition *);
00071 int rt_bool_partition_eligible(register const struct bu_ptbl *,
00072                                register const struct bu_bitv *,
00073                                register const struct partition *);
00074 int rt_booleval(register union tree*,
00075                 struct partition *,
00076                 struct region **,
00077                 struct resource *);
00078 /*
00079  *                      R T _ W E A V E 0 S E G
00080  *
00081  *  If a zero thickness segment abutts another partition,
00082  *  it will be fused in, later.
00083  *
00084  *  If it is free standing, then it will remain as a
00085  *  zero thickness partition, which probably signals
00086  *  going through some solid an odd number of times,
00087  *  or hitting an NMG wire edge or NMG lone vertex.
00088  */
00089 void
00090 rt_weave0seg(struct seg *segp, struct partition *PartHdp, struct application *ap)
00091 {
00092         register struct partition *pp;
00093         struct resource         *res = ap->a_resource;
00094         struct rt_i             *rtip = ap->a_rt_i;
00095         FAST fastf_t            tol_dist;
00096 
00097         tol_dist = rtip->rti_tol.dist;
00098 
00099         RT_CK_PT_HD(PartHdp);
00100         RT_CK_RTI(ap->a_rt_i);
00101         RT_CK_RESOURCE(res);
00102         RT_CK_RTI(rtip);
00103 
00104         if(RT_G_DEBUG&DEBUG_PARTITION)  {
00105                 bu_log(
00106                 "rt_boolweave:  Zero thickness seg: %s (%.18e,%.18e) %d,%d\n",
00107                 segp->seg_stp->st_name,
00108                 segp->seg_in.hit_dist,
00109                 segp->seg_out.hit_dist,
00110                 segp->seg_in.hit_surfno,
00111                 segp->seg_out.hit_surfno );
00112         }
00113 
00114         if( PartHdp->pt_forw == PartHdp )  rt_bomb("rt_weave0seg() with empty partition list\n");
00115 
00116         /* See if this segment ends before start of first partition */
00117         if( segp->seg_out.hit_dist < PartHdp->pt_forw->pt_inhit->hit_dist )  {
00118                 GET_PT_INIT( rtip, pp, res );
00119                 bu_ptbl_ins_unique( &pp->pt_seglist, (long *)segp );
00120                 pp->pt_inseg = segp;
00121                 pp->pt_inhit = &segp->seg_in;
00122                 pp->pt_outseg = segp;
00123                 pp->pt_outhit = &segp->seg_out;
00124                 APPEND_PT( pp, PartHdp );
00125                 if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("0-len segment ends before start of first partition.\n");
00126                 return;
00127         }
00128 
00129         /*
00130          *  Cases:  seg at start of pt, in middle of pt, at end of pt,
00131          *  or past end of pt but before start of next pt.
00132          *  XXX For the first 3 cases, we might want to make a new 0-len pt,
00133          *  XXX especially as the NMG ray-tracer starts reporting wire hits.
00134          */
00135         for( pp=PartHdp->pt_forw; pp != PartHdp; pp=pp->pt_forw ) {
00136                 if( NEAR_ZERO( segp->seg_in.hit_dist  - pp->pt_inhit->hit_dist, tol_dist ) ||
00137                     NEAR_ZERO( segp->seg_out.hit_dist - pp->pt_inhit->hit_dist, tol_dist )
00138                 )  {
00139                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("0-len segment ends right at start of existing partition.\n");
00140                         return;
00141                 }
00142                 if( NEAR_ZERO( segp->seg_in.hit_dist  - pp->pt_outhit->hit_dist, tol_dist ) ||
00143                     NEAR_ZERO( segp->seg_out.hit_dist - pp->pt_outhit->hit_dist, tol_dist )
00144                 )  {
00145                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("0-len segment ends right at end of existing partition.\n");
00146                         return;
00147                 }
00148                 if( segp->seg_out.hit_dist <= pp->pt_outhit->hit_dist &&
00149                     segp->seg_in.hit_dist >= pp->pt_inhit->hit_dist )  {
00150                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("0-len segment in the middle of existing partition.\n");
00151                         return;
00152                 }
00153                 if( pp->pt_forw == PartHdp ||
00154                     segp->seg_out.hit_dist < pp->pt_forw->pt_inhit->hit_dist )  {
00155                         struct partition        *npp;
00156                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("0-len segment after existing partition, but before next partition.\n");
00157                         GET_PT_INIT( rtip, npp, res );
00158                         bu_ptbl_ins_unique( &npp->pt_seglist, (long *)segp );
00159                         npp->pt_inseg = segp;
00160                         npp->pt_inhit = &segp->seg_in;
00161                         npp->pt_outseg = segp;
00162                         npp->pt_outhit = &segp->seg_out;
00163                         APPEND_PT( npp, pp );
00164                         return;
00165                 }
00166         }
00167         rt_bomb("rt_weave0seg() fell out of partition loop?\n");
00168 }
00169 
00170 /*
00171  *                      R T _ B O O L W E A V E
00172  *
00173  *  Weave a chain of segments into an existing set of partitions.
00174  *  The edge of each partition is an inhit or outhit of some solid (seg).
00175  *
00176  *  NOTE:  When the final partitions are completed, it is the users
00177  *  responsibility to honor the inflip and outflip flags.  They can
00178  *  not be flipped here because an outflip=1 edge and an inflip=0 edge
00179  *  following it may in fact be the same edge.  This could be dealt with
00180  *  by giving the partition struct a COPY of the inhit and outhit rather
00181  *  than a pointer, but that's more cycles than the neatness is worth.
00182  *
00183  * Inputs -
00184  *      Pointer to first segment in seg chain.
00185  *      Pointer to head of circular doubly-linked list of
00186  *      partitions of the original ray.
00187  *
00188  * Outputs -
00189  *      Partitions, queued on doubly-linked list specified.
00190  *
00191  * Notes -
00192  *      It is the responsibility of the CALLER to free the seg chain,
00193  *      as well as the partition list that we return.
00194  */
00195 void
00196 rt_boolweave(struct seg *out_hd, struct seg *in_hd, struct partition *PartHdp, struct application *ap)
00197 {
00198         register struct seg *segp;
00199         register struct partition *pp;
00200         struct resource         *res = ap->a_resource;
00201         struct rt_i             *rtip = ap->a_rt_i;
00202 
00203         FAST fastf_t            diff, diff_se;
00204         FAST fastf_t            tol_dist;
00205 
00206         RT_CK_PT_HD(PartHdp);
00207 
00208         tol_dist = rtip->rti_tol.dist;
00209 
00210         RT_CK_RTI(ap->a_rt_i);
00211         RT_CK_RESOURCE(res);
00212         RT_CK_RTI(rtip);
00213 
00214         if(RT_G_DEBUG&DEBUG_PARTITION)  {
00215                 bu_log( "In rt_boolweave, tol_dist = %g\n", tol_dist );
00216                 rt_pr_partitions( rtip, PartHdp, "-----------------BOOL_WEAVE" );
00217         }
00218 
00219         while( BU_LIST_NON_EMPTY( &(in_hd->l) ) ) {
00220                 register struct partition       *newpp = PT_NULL;
00221                 register struct seg             *lastseg = RT_SEG_NULL;
00222                 register struct hit             *lasthit = HIT_NULL;
00223                 LOCAL int                       lastflip = 0;
00224 
00225                 segp = BU_LIST_FIRST( seg, &(in_hd->l) );
00226                 RT_CHECK_SEG(segp);
00227                 RT_CK_HIT(&(segp->seg_in));
00228                 RT_CK_RAY(segp->seg_in.hit_rayp);
00229                 RT_CK_HIT(&(segp->seg_out));
00230                 RT_CK_RAY(segp->seg_out.hit_rayp);
00231                 if(RT_G_DEBUG&DEBUG_PARTITION)  {
00232                         point_t         pt;
00233 
00234                         bu_log( "************ Input segment:\n" );
00235                         rt_pr_seg(segp);
00236                         rt_pr_hit(" In", &segp->seg_in );
00237                         VJOIN1( pt, ap->a_ray.r_pt, segp->seg_in.hit_dist, ap->a_ray.r_dir );
00238                         /* XXX needs indentation added here */
00239                         VPRINT(" IPoint", pt );
00240 
00241                         rt_pr_hit("Out", &segp->seg_out );
00242                         VJOIN1( pt, ap->a_ray.r_pt, segp->seg_out.hit_dist, ap->a_ray.r_dir );
00243                         /* XXX needs indentation added here */
00244                         VPRINT(" OPoint", pt );
00245                         bu_log( "***********\n" );
00246                 }
00247                 if( segp->seg_stp->st_bit >= rtip->nsolids) rt_bomb("rt_boolweave: st_bit");
00248 
00249                 BU_LIST_DEQUEUE( &(segp->l) );
00250                 BU_LIST_INSERT( &(out_hd->l), &(segp->l) );
00251 
00252                 /* Make nearly zero be exactly zero */
00253                 if( NEAR_ZERO( segp->seg_in.hit_dist, tol_dist ) )
00254                         segp->seg_in.hit_dist = 0;
00255                 if( NEAR_ZERO( segp->seg_out.hit_dist, tol_dist ) )
00256                         segp->seg_out.hit_dist = 0;
00257 
00258                 /* Totally ignore things behind the start position */
00259                 if( segp->seg_out.hit_dist < -10.0 )
00260                         continue;
00261 
00262                 if( segp->seg_stp->st_aradius < INFINITY &&
00263                     !(segp->seg_in.hit_dist >= -INFINITY &&
00264                     segp->seg_out.hit_dist <= INFINITY) )  {
00265                         bu_log("rt_boolweave:  Defective %s segment %s (%.18e,%.18e) %d,%d\n",
00266                                 rt_functab[segp->seg_stp->st_id].ft_name,
00267                                 segp->seg_stp->st_name,
00268                                 segp->seg_in.hit_dist,
00269                                 segp->seg_out.hit_dist,
00270                                 segp->seg_in.hit_surfno,
00271                                 segp->seg_out.hit_surfno );
00272                         continue;
00273                 }
00274                 if( segp->seg_in.hit_dist > segp->seg_out.hit_dist )  {
00275                         bu_log("rt_boolweave:  Inside-out %s segment %s (%.18e,%.18e) %d,%d\n",
00276                                 rt_functab[segp->seg_stp->st_id].ft_name,
00277                                 segp->seg_stp->st_name,
00278                                 segp->seg_in.hit_dist,
00279                                 segp->seg_out.hit_dist,
00280                                 segp->seg_in.hit_surfno,
00281                                 segp->seg_out.hit_surfno );
00282                         continue;
00283                 }
00284 
00285                 /*
00286                  * Weave this segment into the existing partitions,
00287                  * creating new partitions as necessary.
00288                  */
00289                 if( PartHdp->pt_forw == PartHdp )  {
00290                         /* No partitions yet, simple! */
00291                         GET_PT_INIT( rtip, pp, res );
00292                         bu_ptbl_ins_unique( &pp->pt_seglist, (long *)segp );
00293                         pp->pt_inseg = segp;
00294                         pp->pt_inhit = &segp->seg_in;
00295                         pp->pt_outseg = segp;
00296                         pp->pt_outhit = &segp->seg_out;
00297                         APPEND_PT( pp, PartHdp );
00298                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("No partitions yet, segment forms first partition\n");
00299                         goto done_weave;
00300                 }
00301 
00302                 if( ap->a_no_booleans )  {
00303                         lastseg = segp;
00304                         lasthit = &segp->seg_in;
00305                         lastflip = 0;
00306                         /* Just sort in ascending in-dist order */
00307                         for( pp=PartHdp->pt_forw; pp != PartHdp; pp=pp->pt_forw ) {
00308                                 if( lasthit->hit_dist < pp->pt_inhit->hit_dist )  {
00309                                         if(RT_G_DEBUG&DEBUG_PARTITION)  {
00310                                                 bu_log("Insert nobool seg before next pt\n");
00311                                         }
00312                                         GET_PT_INIT( rtip, newpp, res );
00313                                         bu_ptbl_ins_unique( &newpp->pt_seglist, (long *)segp );
00314                                         newpp->pt_inseg = segp;
00315                                         newpp->pt_inhit = &segp->seg_in;
00316                                         newpp->pt_outseg = segp;
00317                                         newpp->pt_outhit = &segp->seg_out;
00318                                         INSERT_PT( newpp, pp );
00319                                         goto done_weave;
00320                                 }
00321                         }
00322                         if(RT_G_DEBUG&DEBUG_PARTITION)  {
00323                                 bu_log("Append nobool seg at end of list\n");
00324                         }
00325                         GET_PT_INIT( rtip, newpp, res );
00326                         bu_ptbl_ins_unique( &newpp->pt_seglist, (long *)segp );
00327                         newpp->pt_inseg = segp;
00328                         newpp->pt_inhit = &segp->seg_in;
00329                         newpp->pt_outseg = segp;
00330                         newpp->pt_outhit = &segp->seg_out;
00331                         INSERT_PT( newpp, PartHdp );
00332                         goto done_weave;
00333                 }
00334 
00335                 /* Check for zero-thickness segment, within tol */
00336                 diff = segp->seg_in.hit_dist - segp->seg_out.hit_dist;
00337                 if( NEAR_ZERO( diff, tol_dist ) )  {
00338                         rt_weave0seg( segp, PartHdp, ap );
00339                         goto done_weave;
00340                 }
00341 
00342                 if( segp->seg_in.hit_dist >= PartHdp->pt_back->pt_outhit->hit_dist )  {
00343                         /*
00344                          * Segment starts exactly at last partition's end,
00345                          * or beyond last partitions end.  Make new partition.
00346                          */
00347                         if(RT_G_DEBUG&DEBUG_PARTITION)  {
00348                                 bu_log("seg starts beyond last partition end. (%g,%g) Appending new partition\n",
00349                                         PartHdp->pt_back->pt_inhit->hit_dist,
00350                                         PartHdp->pt_back->pt_outhit->hit_dist);
00351                         }
00352                         GET_PT_INIT( rtip, pp, res );
00353                         bu_ptbl_ins_unique( &pp->pt_seglist, (long *)segp );
00354                         pp->pt_inseg = segp;
00355                         pp->pt_inhit = &segp->seg_in;
00356                         pp->pt_outseg = segp;
00357                         pp->pt_outhit = &segp->seg_out;
00358                         APPEND_PT( pp, PartHdp->pt_back );
00359                         goto done_weave;
00360                 }
00361 
00362                 /* Loop through current partition list weaving the current input segment
00363                  * into the list. The following three variables keep track of the current
00364                  * starting point of the input segment. The starting point of the segment
00365                  * moves to higher hit_dist values (as it is woven in) until it is entirely consumed.
00366                  */
00367                 lastseg = segp;
00368                 lasthit = &segp->seg_in;
00369                 lastflip = 0;
00370                 for( pp=PartHdp->pt_forw; pp != PartHdp; pp=pp->pt_forw ) {
00371 
00372                         if(RT_G_DEBUG&DEBUG_PARTITION) {
00373                                 bu_log( "At start of loop:\n" );
00374                                 bu_log( "       remaining input segment: (%.12e - %.12e)\n",
00375                                         lasthit->hit_dist, segp->seg_out.hit_dist );
00376                                 bu_log( "       current partition: (%.12e - %.12e)\n",
00377                                         pp->pt_inhit->hit_dist, pp->pt_outhit->hit_dist );
00378                                 rt_pr_partitions( rtip, PartHdp, "At start of loop" );
00379                         }
00380 
00381                         diff_se = lasthit->hit_dist - pp->pt_outhit->hit_dist;
00382                         if( diff_se > tol_dist )  {
00383                                 /* Seg starts beyond the END of the
00384                                  * current partition.
00385                                  *      PPPP
00386                                  *              SSSS
00387                                  * Advance to next partition.
00388                                  */
00389                                 if(RT_G_DEBUG&DEBUG_PARTITION)  {
00390                                         bu_log("seg start beyond partition end, skipping.  (%g,%g)\n",
00391                                                 pp->pt_inhit->hit_dist,
00392                                                 pp->pt_outhit->hit_dist);
00393                                 }
00394                                 continue;
00395                         }
00396                         if(RT_G_DEBUG&DEBUG_PARTITION)  rt_pr_pt(rtip, pp);
00397                         diff = lasthit->hit_dist - pp->pt_inhit->hit_dist;
00398                         if( diff_se > -(tol_dist) && diff > tol_dist )  {
00399                                 /*
00400                                  * Seg starts almost "precisely" at the
00401                                  * end of the current partition.
00402                                  *      PPPP
00403                                  *          SSSS
00404                                  * FUSE an exact match of the endpoints,
00405                                  * advance to next partition.
00406                                  */
00407                                 lasthit->hit_dist = pp->pt_outhit->hit_dist;
00408                                 if(RT_G_DEBUG&DEBUG_PARTITION)  {
00409                                         bu_log("seg start fused to partition end, diff=%g\n", diff);
00410                                 }
00411                                 continue;
00412                         }
00413 
00414                         /*
00415                          *  diff < ~~0
00416                          *  Seg starts before current partition ends
00417                          *      PPPPPPPPPPP
00418                          *        SSSS...
00419                          */
00420                         if( diff > tol_dist )  {
00421                                 /*
00422                                  * lasthit->hit_dist > pp->pt_inhit->hit_dist
00423                                  * pp->pt_inhit->hit_dist < lasthit->hit_dist
00424                                  *
00425                                  *  Segment starts after partition starts,
00426                                  *  but before the end of the partition.
00427                                  *  Note:  pt_seglist will be updated in equal_start.
00428                                  *      PPPPPPPPPPPP
00429                                  *           SSSS...
00430                                  *      newpp|pp
00431                                  */
00432                                 RT_DUP_PT( rtip, newpp, pp, res );
00433                                 /* new partition is the span before seg joins partition */
00434                                 pp->pt_inseg = segp;
00435                                 pp->pt_inhit = &segp->seg_in;
00436                                 pp->pt_inflip = 0;
00437                                 newpp->pt_outseg = segp;
00438                                 newpp->pt_outhit = &segp->seg_in;
00439                                 newpp->pt_outflip = 1;
00440                                 INSERT_PT( newpp, pp );
00441                                 if(RT_G_DEBUG&DEBUG_PARTITION) {
00442                                         bu_log("seg starts within p. Split p at seg start, advance. (diff = %g)\n", diff);
00443                                         bu_log( "newpp starts at %.12e, pp starts at %.12e\n",
00444                                                 newpp->pt_inhit->hit_dist,
00445                                                 pp->pt_inhit->hit_dist );
00446                                         bu_log( "newpp = x%x, pp = x%x\n", newpp, pp );
00447                                 }
00448                                 goto equal_start;
00449                         }
00450                         if( diff > -(tol_dist) )  {
00451                                 /*
00452                                  * Make a subtle but important distinction here.
00453                                  * Even though the two distances are "equal"
00454                                  * within tolerance, they are not exactly
00455                                  * the same.  If the new segment is slightly
00456                                  * closer to the ray origin, then use it's
00457                                  * IN point.
00458                                  * This is an attempt to reduce the deflected
00459                                  * normals sometimes seen along the edges of
00460                                  * e.g. a cylinder unioned with an ARB8,
00461                                  * where the ray hits the top of the cylinder
00462                                  * and the *side* face of the ARB8 rather
00463                                  * than the top face of the ARB8.
00464                                  */
00465                                 diff = segp->seg_in.hit_dist - pp->pt_inhit->hit_dist;
00466                                 if( !pp->pt_back ||
00467                                     pp->pt_back == PartHdp ||
00468                                     pp->pt_back->pt_outhit->hit_dist <=
00469                                     segp->seg_in.hit_dist ) {
00470                                         if( NEAR_ZERO(diff, tol_dist) &&
00471                                             diff < 0 )  {
00472                                                 if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("changing partition start point to segment start point\n");
00473                                                 pp->pt_inseg = segp;
00474                                                 pp->pt_inhit = &segp->seg_in;
00475                                                 pp->pt_inflip = 0;
00476                                         }
00477                                 }
00478 equal_start:
00479                                 if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("equal_start\n");
00480                                 /*
00481                                  * Segment and partition start at
00482                                  * (roughly) the same point.
00483                                  * When fuseing 2 points together
00484                                  * i.e., when NEAR_ZERO(diff,tol) is true,
00485                                  * the two points MUST be forced to become
00486                                  * exactly equal!
00487                                  */
00488                                 diff = segp->seg_out.hit_dist - pp->pt_outhit->hit_dist;
00489                                 if( diff > tol_dist )  {
00490                                         /*
00491                                          * Seg & partition start at roughly
00492                                          * the same spot,
00493                                          * seg extends beyond partition end.
00494                                          *      PPPP
00495                                          *      SSSSSSSS
00496                                          *      pp  |  newpp
00497                                          */
00498                                         bu_ptbl_ins_unique( &pp->pt_seglist, (long *)segp );
00499                                         lasthit = pp->pt_outhit;
00500                                         lastseg = pp->pt_outseg;
00501                                         lastflip = 1;
00502                                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("seg spans partition and extends beyond it\n");
00503                                         continue;
00504                                 }
00505                                 if( diff > -(tol_dist) )  {
00506                                         /*
00507                                          *  diff ~= 0
00508                                          * Segment and partition start & end
00509                                          * (nearly) together.
00510                                          *      PPPP
00511                                          *      SSSS
00512                                          */
00513                                         bu_ptbl_ins_unique( &pp->pt_seglist, (long *)segp );
00514                                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("same start&end\n");
00515                                         goto done_weave;
00516                                 } else {
00517                                         /*
00518                                          *  diff < ~0
00519                                          *
00520                                          *  Segment + Partition start together,
00521                                          *  segment ends before partition ends.
00522                                          *      PPPPPPPPPP
00523                                          *      SSSSSS
00524                                          *      newpp| pp
00525                                          */
00526                                         RT_DUP_PT( rtip, newpp, pp, res );
00527                                         /* new partition contains segment */
00528                                         bu_ptbl_ins_unique( &newpp->pt_seglist, (long *)segp );
00529                                         newpp->pt_outseg = segp;
00530                                         newpp->pt_outhit = &segp->seg_out;
00531                                         newpp->pt_outflip = 0;
00532                                         pp->pt_inseg = segp;
00533                                         pp->pt_inhit = &segp->seg_out;
00534                                         pp->pt_inflip = 1;
00535                                         INSERT_PT( newpp, pp );
00536                                         if(RT_G_DEBUG&DEBUG_PARTITION) {
00537                                                 bu_log("start together, seg shorter than partition\n");
00538                                                 bu_log( "newpp starts at %.12e, pp starts at %.12e\n",
00539                                                         newpp->pt_inhit->hit_dist,
00540                                                         pp->pt_inhit->hit_dist );
00541                                                 bu_log( "newpp = x%x, pp = x%x\n", newpp, pp );
00542                                         }
00543                                         goto done_weave;
00544                                 }
00545                                 /* NOTREACHED */
00546                         } else {
00547                                 /*
00548                                  *  diff < ~~0
00549                                  *
00550                                  * Seg starts before current partition starts,
00551                                  * but after the previous partition ends.
00552                                  *      SSSSSSSS...
00553                                  *           PPPPP...
00554                                  *      newpp|pp
00555                                  */
00556                                 GET_PT_INIT( rtip, newpp, res );
00557                                 bu_ptbl_ins_unique( &newpp->pt_seglist, (long *)segp );
00558                                 newpp->pt_inseg = lastseg;
00559                                 newpp->pt_inhit = lasthit;
00560                                 newpp->pt_inflip = lastflip;
00561                                 diff = segp->seg_out.hit_dist - pp->pt_inhit->hit_dist;
00562                                 if( diff < -(tol_dist) )  {
00563                                         /*
00564                                          *  diff < ~0
00565                                          * Seg starts and ends before current
00566                                          * partition, but after previous
00567                                          * partition ends (diff < 0).
00568                                          *              SSSS
00569                                          *      pppp            PPPPP...
00570                                          *              newpp   pp
00571                                          */
00572                                         newpp->pt_outseg = segp;
00573                                         newpp->pt_outhit = &segp->seg_out;
00574                                         newpp->pt_outflip = 0;
00575                                         INSERT_PT( newpp, pp );
00576                                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("seg between 2 partitions\n");
00577                                         goto done_weave;
00578                                 }
00579                                 if( diff < tol_dist )  {
00580                                         /*
00581                                          *  diff ~= 0
00582                                          *
00583                                          * Seg starts before current
00584                                          * partition starts, and ends at or
00585                                          * near the start of the partition.
00586                                          * (diff == 0).  FUSE the points.
00587                                          *      SSSSSS
00588                                          *           PPPPP
00589                                          *      newpp|pp
00590                                          * NOTE: only copy hit point, not
00591                                          * normals or norm private stuff.
00592                                          */
00593                                         newpp->pt_outseg = segp;
00594                                         newpp->pt_outhit = &segp->seg_out;
00595                                         newpp->pt_outhit->hit_dist = pp->pt_inhit->hit_dist;
00596                                         newpp->pt_outflip = 0;
00597                                         INSERT_PT( newpp, pp );
00598                                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("seg ends at partition start, fuse\n");
00599                                         goto done_weave;
00600                                 }
00601                                 /*
00602                                  *  Seg starts before current partition
00603                                  *  starts, and ends after the start of the
00604                                  *  partition.  (diff > 0).
00605                                  *      SSSSSSSSSS
00606                                  *            PPPPPPP
00607                                  *      newpp| pp | ...
00608                                  */
00609                                 newpp->pt_outseg = pp->pt_inseg;
00610                                 newpp->pt_outhit = pp->pt_inhit;
00611                                 newpp->pt_outflip = 1;
00612                                 lastseg = pp->pt_inseg;
00613                                 lasthit = pp->pt_inhit;
00614                                 lastflip = newpp->pt_outflip;
00615                                 INSERT_PT( newpp, pp );
00616                                 if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("insert seg before p start, ends after p ends.  Making new partition for initial portion.\n");
00617                                 goto equal_start;
00618                         }
00619                         /* NOTREACHED */
00620                 }
00621 
00622                 /*
00623                  *  Segment has portion which extends beyond the end
00624                  *  of the last partition.  Tack on the remainder.
00625                  *      PPPPP
00626                  *           SSSSS
00627                  */
00628                 if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("seg extends beyond partition end\n");
00629                 GET_PT_INIT( rtip, newpp, res );
00630                 bu_ptbl_ins_unique( &newpp->pt_seglist, (long *)segp );
00631                 newpp->pt_inseg = lastseg;
00632                 newpp->pt_inhit = lasthit;
00633                 newpp->pt_inflip = lastflip;
00634                 newpp->pt_outseg = segp;
00635                 newpp->pt_outhit = &segp->seg_out;
00636                 APPEND_PT( newpp, PartHdp->pt_back );
00637 
00638 done_weave:     ; /* Sorry about the goto's, but they give clarity */
00639                 if(RT_G_DEBUG&DEBUG_PARTITION)
00640                         rt_pr_partitions( rtip, PartHdp, "After weave" );
00641         }
00642         if(RT_G_DEBUG&DEBUG_PARTITION)
00643                 bu_log( "--------------------Leaving Booleweave\n" );
00644 }
00645 
00646 
00647 /*
00648  *                      _ R T _ D E F O V E R L A P
00649  *
00650  *  The guts of the default overlap callback.
00651  *  Returns -
00652  *       0      to eliminate partition with overlap entirely
00653  *       1      to retain partition in output list, claimed by reg1
00654  *       2      to retain partition in output list, claimed by reg2
00655  */
00656 HIDDEN int
00657 _rt_defoverlap(register struct application *ap, register struct partition *pp, struct region *reg1, struct region *reg2, struct partition *pheadp, register int verbose)
00658 {
00659         RT_CK_AP(ap);
00660         RT_CK_PT(pp);
00661         RT_CK_REGION(reg1);
00662         RT_CK_REGION(reg2);
00663 
00664         /*
00665          *  Apply heuristics as to which region should claim partition.
00666          */
00667         if( reg1->reg_aircode != 0 )  {
00668                 /* reg1 was air, replace with reg2 */
00669                 return 2;
00670         }
00671         if( pp->pt_back != pheadp ) {
00672                 /* Repeat a prev region, if that is a choice */
00673                 if( pp->pt_back->pt_regionp == reg1 )
00674                         return 1;
00675                 if( pp->pt_back->pt_regionp == reg2 )
00676                         return 2;
00677         }
00678 
00679         /* To provide some consistency from ray to ray, use lowest bit # */
00680         if( reg1->reg_bit < reg2->reg_bit )
00681                 return 1;
00682         return 2;
00683 }
00684 /*
00685  *                      R T _ D E F O V E R L A P
00686  *
00687  *  Default handler for overlaps in rt_boolfinal().
00688  *  Returns -
00689  *       0      to eliminate partition with overlap entirely
00690  *       1      to retain partition in output list, claimed by reg1
00691  *       2      to retain partition in output list, claimed by reg2
00692  *
00693  *  This is now simply a one-line wrapper that calls _rt_defoverlap(),
00694  *  requesting verbosity.
00695  */
00696 int
00697 rt_defoverlap (register struct application *ap, register struct partition *pp, struct region *reg1, struct region *reg2, struct partition *pheadp)
00698 {
00699     return (_rt_defoverlap(ap, pp, reg1, reg2, pheadp, 1));
00700 }
00701 
00702 /*
00703  *                      R T _ O V E R L A P _ Q U I E T L Y
00704  *
00705  *  Silent version of rt_defoverlap().
00706  *  Returns -
00707  *       0      to eliminate partition with overlap entirely
00708  *       1      to retain partition in output list, claimed by reg1
00709  *       2      to retain partition in output list, claimed by reg2
00710  *
00711  */
00712 int
00713 rt_overlap_quietly (register struct application *ap, register struct partition *pp, struct region *reg1, struct region *reg2, struct partition *pheadp)
00714 {
00715     return (_rt_defoverlap(ap, pp, reg1, reg2, pheadp, 0));
00716 }
00717 
00718 /*
00719  *      R T _ G E T _ R E G I O N _ S E G L I S T _ F O R _ P A R T I T I O N
00720  *
00721  *  Given one of the regions that is involved in a given partition
00722  *  (whether the boolean formula for this region is TRUE in this part or not),
00723  *  return a bu_ptbl list containing all the segments in this partition
00724  *  which came from solids that appear as terms in the boolean formula
00725  *  for the given region.
00726  *
00727  *  The bu_ptbl is initialized here, and must be freed by the caller.
00728  *  It will contain a pointer to at least one segment.
00729  */
00730 void
00731 rt_get_region_seglist_for_partition(struct bu_ptbl *sl, const struct partition *pp, const struct region *regp)
00732 {
00733         const struct seg **segpp;
00734 
00735         bu_ptbl_init( sl, 8, "region seglist for partition" );
00736 
00737         /* Walk the partitions segment list */
00738         for( BU_PTBL_FOR( segpp, (const struct seg **), &pp->pt_seglist ) )  {
00739                 const struct region **srpp;
00740 
00741                 RT_CK_SEG(*segpp);
00742                 /* For every segment in part, walk the solid's region list */
00743                 for( BU_PTBL_FOR( srpp, (const struct region **), &(*segpp)->seg_stp->st_regions ) )  {
00744                         RT_CK_REGION(*srpp);
00745 
00746                         if( *srpp != regp )  continue;
00747                         /* This segment is part of a solid in this region */
00748                         bu_ptbl_ins_unique( sl, (long *)(*segpp) );
00749                 }
00750         }
00751 
00752         if( BU_PTBL_LEN(sl) <= 0 )  bu_bomb("rt_get_region_seglist_for_partition() didn't find any segments\n");
00753 }
00754 
00755 /*
00756  *                      R T _ F A S T G E N _ V O L _ V O L _ O V E R L A P
00757  *
00758  *  Handle FASTGEN volume/volume overlap.
00759  *  Look at underlying segs.
00760  *  If one is less than 1/4", take the longer.
00761  *  Otherwise take the shorter.
00762  *
00763  *  Required to null out one of the two regions.
00764  */
00765 void
00766 rt_fastgen_vol_vol_overlap(struct region **fr1, struct region **fr2, const struct partition *pp)
00767 {
00768         struct bu_ptbl  sl1, sl2;
00769         const struct seg *s1 = (const struct seg *)NULL;
00770         const struct seg *s2 = (const struct seg *)NULL;
00771         fastf_t s1_in_dist;
00772         fastf_t s2_in_dist;
00773         fastf_t depth;
00774         struct seg **segpp;
00775 
00776         RT_CK_REGION(*fr1);
00777         RT_CK_REGION(*fr2);
00778 
00779         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("Resolving FASTGEN volume/volume overlap: %s %s\n", (*fr1)->reg_name, (*fr2)->reg_name);
00780 
00781         rt_get_region_seglist_for_partition( &sl1, pp, *fr1 );
00782         rt_get_region_seglist_for_partition( &sl2, pp, *fr2 );
00783 
00784         s1_in_dist = MAX_FASTF;
00785         s2_in_dist = MAX_FASTF;
00786         for( BU_PTBL_FOR( segpp, (struct seg **), &sl1 ) )
00787         {
00788                 if( (*segpp)->seg_in.hit_dist < s1_in_dist )
00789                 {
00790                         s1 = (*segpp);
00791                         s1_in_dist = s1->seg_in.hit_dist;
00792                 }
00793         }
00794         for( BU_PTBL_FOR( segpp, (struct seg **), &sl2 ) )
00795         {
00796                 if( (*segpp)->seg_in.hit_dist < s2_in_dist )
00797                 {
00798                         s2 = (*segpp);
00799                         s2_in_dist = s2->seg_in.hit_dist;
00800                 }
00801         }
00802         RT_CK_SEG(s1);
00803         RT_CK_SEG(s2);
00804 
00805         depth = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist;
00806 
00807         /* 6.35mm = 1/4 inch */
00808         if( depth < 6.35 )  {
00809                 /* take region with lowest inhit */
00810                 if( s1->seg_in.hit_dist < s2->seg_in.hit_dist )  {
00811                         /* keep fr1, delete fr2 */
00812                         *fr2 = REGION_NULL;
00813                 } else {
00814                         /* keep fr2, depete fr1 */
00815                         *fr1 = REGION_NULL;
00816                 }
00817         } else {
00818                 /*
00819                  * take the region with largest inhit
00820                  */
00821                 if( s1->seg_in.hit_dist >= s2->seg_in.hit_dist )  {
00822                         /* keep fr1, delete fr2 */
00823                         *fr2 = REGION_NULL;
00824                 } else {
00825                         *fr1 = REGION_NULL;
00826                 }
00827         }
00828 
00829         bu_ptbl_free( &sl1 );
00830         bu_ptbl_free( &sl2 );
00831 }
00832 
00833 /*
00834  *                      R T _ F A S T G E N _ P L A T E _ V O L _ O V E R L A P
00835  *
00836  *  Handle FASTGEN plate/volume overlap.
00837  *
00838  *  Measure width of _preceeding_ partition,
00839  *  which must have been claimed by the volume mode region fr2.
00840  *  If less than 1/4", delete preceeding partition, and plate wins this part.
00841  *  If less than 1/4", plate wins this part, previous partition untouched.
00842  *  If previous partition is claimed by plate mode region fr1,
00843  *  then overlap is left in output???
00844  *
00845  *  Required to null out one of the two regions.
00846  */
00847 void
00848 rt_fastgen_plate_vol_overlap(struct region **fr1, struct region **fr2, struct partition *pp, struct application *ap)
00849 {
00850         struct partition *prev;
00851         fastf_t depth;
00852 
00853         RT_CK_REGION(*fr1);
00854         RT_CK_REGION(*fr2);
00855         RT_CK_PT(pp);
00856         RT_CK_AP(ap);
00857 
00858         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("Resolving FASTGEN plate/volume overlap: %s %s\n", (*fr1)->reg_name, (*fr2)->reg_name);
00859 
00860         prev = pp->pt_back;
00861         if( prev->pt_magic == PT_HD_MAGIC )  {
00862                 /* No prev partition, this is the first.  d=0, plate wins */
00863                 *fr2 = REGION_NULL;
00864                 return;
00865         }
00866 
00867         if( rt_fdiff(prev->pt_outhit->hit_dist, pp->pt_inhit->hit_dist) != 0 )  {
00868                 /* There is a gap between previous partition and this one */
00869                 /* So both plate and vol start at same place, d=0, plate wins */
00870                 *fr2 = REGION_NULL;
00871                 return;
00872         }
00873 
00874         if( prev->pt_regionp == *fr2 )  {
00875                 /* previous part is volume mode, ends at start of pp */
00876                 depth = prev->pt_outhit->hit_dist - prev->pt_inhit->hit_dist;
00877                 /* 6.35mm = 1/4 inch */
00878                 if( depth < 6.35 )  {
00879                         /* Delete previous partition from list */
00880                         DEQUEUE_PT(prev);
00881                         FREE_PT(prev, ap->a_resource);
00882 
00883                         /* plate mode fr1 wins this partition */
00884                         *fr2 = REGION_NULL;
00885                 } else {
00886                         /* Leave previous partition alone */
00887                         /* plate mode fr1 wins this partition */
00888                         *fr2 = REGION_NULL;
00889                 }
00890         } else if( prev->pt_regionp == *fr1 )  {
00891                 /* previous part is plate mode, ends at start of pp */
00892                 /* d < 0, leave overlap in output??? */
00893                 /* For now, volume mode region just loses. */
00894                 *fr2 = REGION_NULL;
00895         } else {
00896                 /* Some other region preceeds this partition */
00897                 /* So both plate and vol start at same place, d=0, plate wins */
00898                 *fr2 = REGION_NULL;
00899         }
00900 }
00901 
00902 /*
00903  *                      R T _ D E F A U L T _ M U L T I O V E R L A P
00904  *
00905  *  Default version of a_multioverlap().
00906  *
00907  *  Resolve the overlap of multiple regions withing a single partition.
00908  *  There are no null pointers in the table (they have been compressed
00909  *  out by our caller).  Consider BU_PTBL_LEN(regiontable) overlapping
00910  *  regions, and reduce to zero or one "claiming" regions, by
00911  *  setting pointers in the bu_ptbl of non-claiming regions to NULL.
00912  *
00913  *  This default routine reproduces the behavior of BRL-CAD Release 5.0
00914  *  by considerign the regions pairwise and calling the old a_overlap().
00915  *
00916  *  An application which knew how to handle multiple overlapping air
00917  *  regions would provide its own very different version of this routine
00918  *  as the a_multioverlap() handler.
00919  *
00920  *  This routine is for resolving overlaps only, and should not print
00921  *  any messages in normal operation; a_logoverlap() is for logging.
00922  *
00923  *  InputHdp is the list of partitions up to this point.  It allows us
00924  *  to look at the regions that have come before in deciding what to do
00925  *
00926  */
00927 void
00928 rt_default_multioverlap(struct application *ap, struct partition *pp, struct bu_ptbl *regiontable, struct partition *InputHdp)
00929 {
00930         LOCAL struct region *lastregion = (struct region *)NULL;
00931         int     n_regions;
00932         int     n_fastgen = 0;
00933         int     code;
00934         int     i;
00935 
00936         RT_CK_AP(ap);
00937         RT_CK_PARTITION(pp);
00938         BU_CK_PTBL(regiontable);
00939         RT_CK_PT_HD(InputHdp);
00940 
00941         if( ap->a_overlap == RT_AFN_NULL )
00942                 ap->a_overlap = rt_defoverlap;
00943 
00944         /* Count number of FASTGEN regions */
00945         n_regions = BU_PTBL_LEN(regiontable);
00946         for( i = n_regions-1; i >= 0; i-- )  {
00947                 struct region *regp = (struct region *)BU_PTBL_GET(regiontable, i);
00948                 RT_CK_REGION(regp);
00949                 if( regp->reg_is_fastgen != REGION_NON_FASTGEN )  n_fastgen++;
00950         }
00951 
00952         /*
00953          *  Resolve all FASTGEN overlaps before considering BRL-CAD
00954          *  overlaps, because FASTGEN overlaps have strict rules.
00955          */
00956         if( n_fastgen >= 2 )  {
00957                 struct region **fr1;
00958                 struct region **fr2;
00959 
00960                 if(RT_G_DEBUG&DEBUG_PARTITION)  {
00961                         bu_log("I see %d FASTGEN overlaps in this partition\n", n_fastgen);
00962                         for( BU_PTBL_FOR( fr1, (struct region **), regiontable ) )  {
00963                                 if( *fr1 == REGION_NULL )  continue;
00964                                 rt_pr_region(*fr1);
00965                         }
00966                 }
00967 
00968                 /*
00969                  *  First, resolve volume_mode/volume_mode overlaps
00970                  *  because they are a simple choice.
00971                  *  N.B. The searches run from high to low in the ptbl array.
00972                  */
00973                 for( BU_PTBL_FOR( fr1, (struct region **), regiontable ) )  {
00974                         if( *fr1 == REGION_NULL )  continue;
00975                         RT_CK_REGION(*fr1);
00976                         if( (*fr1)->reg_is_fastgen != REGION_FASTGEN_VOLUME )
00977                                 continue;
00978                         for( fr2 = fr1-1; fr2 >= (struct region **)BU_PTBL_BASEADDR(regiontable); fr2-- )  {
00979                                 if( *fr2 == REGION_NULL )  continue;
00980                                 RT_CK_REGION(*fr2);
00981                                 if( (*fr2)->reg_is_fastgen != REGION_FASTGEN_VOLUME )
00982                                         continue;
00983                                 rt_fastgen_vol_vol_overlap( fr1, fr2, pp );
00984                                 if( *fr1 == REGION_NULL )  break;
00985                         }
00986                 }
00987 
00988                 /* Second, resolve plate_mode/volume_mode overlaps */
00989                 for( BU_PTBL_FOR( fr1, (struct region **), regiontable ) )  {
00990                         if( *fr1 == REGION_NULL )  continue;
00991                         RT_CK_REGION(*fr1);
00992                         if( (*fr1)->reg_is_fastgen != REGION_FASTGEN_PLATE )
00993                                 continue;
00994                         for( BU_PTBL_FOR( fr2, (struct region **), regiontable ) )  {
00995                                 if( *fr2 == REGION_NULL )  continue;
00996                                 RT_CK_REGION(*fr2);
00997                                 if( (*fr2)->reg_is_fastgen != REGION_FASTGEN_VOLUME )
00998                                         continue;
00999                                 rt_fastgen_plate_vol_overlap( fr1, fr2, pp, ap );
01000                                 if( *fr1 == REGION_NULL )  break;
01001                         }
01002                 }
01003 
01004 
01005                 /* Finally, think up a way to pass plate/plate overlaps on */
01006                 n_fastgen = 0;
01007                 for( i = n_regions-1; i >= 0; i-- )  {
01008                         struct region *regp = (struct region *)BU_PTBL_GET(regiontable, i);
01009                         if( regp == REGION_NULL ) continue;     /* empty slot in table */
01010                         RT_CK_REGION(regp);
01011                         if( regp->reg_is_fastgen != REGION_NON_FASTGEN )  n_fastgen++;
01012                 }
01013 
01014                 /* Compress out any null pointers in the table */
01015                 bu_ptbl_rm( regiontable, (long *)NULL );
01016         }
01017 
01018         lastregion = (struct region *)BU_PTBL_GET(regiontable, 0);
01019         RT_CK_REGION(lastregion);
01020 
01021         if( BU_PTBL_LEN(regiontable) > 1 && ap->a_rt_i->rti_save_overlaps != 0 )  {
01022                 /*
01023                  *  Snapshot current state of overlap list,
01024                  *  so that downstream application code can resolve any
01025                  *  FASTGEN plate/plate overlaps.
01026                  *  The snapshot is not taken at the top of the routine
01027                  *  because nobody is interested in FASTGEN vol/plate
01028                  *  or vol/vol overlaps.
01029                  *  The list is terminated with a NULL pointer,
01030                  *  placed courtesy of bu_calloc().
01031                  */
01032                 pp->pt_overlap_reg = (struct region **)bu_calloc(
01033                         BU_PTBL_LEN(regiontable)+1, sizeof(struct region *),
01034                         "pt_overlap_reg" );
01035                 bcopy( (char *)BU_PTBL_BASEADDR(regiontable),
01036                         (char *)pp->pt_overlap_reg,
01037                         BU_PTBL_LEN(regiontable) * sizeof(struct region *) );
01038         }
01039 
01040         /* Examine the overlapping regions, pairwise */
01041         for( i=1; i < BU_PTBL_LEN(regiontable); i++ )  {
01042                 struct region *regp = (struct region *)BU_PTBL_GET(regiontable, i);
01043                 if( regp == REGION_NULL ) continue;     /* empty slot in table */
01044                 RT_CK_REGION(regp);
01045 
01046                 code = -1;                              /* For debug out in policy */
01047 
01048                 /*
01049                  * Two or more regions claim this partition
01050                  */
01051                 if( lastregion->reg_aircode != 0 && regp->reg_aircode == 0 )  {
01052                         /* last region is air, replace with solid regp */
01053                         goto code2;
01054                 } else if( lastregion->reg_aircode == 0 && regp->reg_aircode != 0 )  {
01055                         /* last region solid, regp is air, keep last */
01056                         goto code1;
01057                 } else if( lastregion->reg_aircode != 0 &&
01058                     regp->reg_aircode != 0 &&
01059                     regp->reg_aircode == lastregion->reg_aircode )  {
01060                         /* both are same air, keep last */
01061                         goto code1;
01062                 }
01063 
01064                 /*
01065                  *  If a FASTGEN region overlaps a non-FASTGEN region,
01066                  *  the non-FASTGEN ("traditional BRL-CAD") region wins.
01067                  *  No mixed-mode geometry like this will be built by the
01068                  *  fastgen-to-BRL-CAD converters, only by human editors.
01069                  */
01070                 if( lastregion->reg_is_fastgen != regp->reg_is_fastgen )  {
01071                         if( lastregion->reg_is_fastgen )
01072                                 goto code2;             /* keep regp */
01073                         if( regp->reg_is_fastgen )
01074                                 goto code1;             /* keep lastregion */
01075                 }
01076 
01077                 /*
01078                  *  To support ray bundles, find partition with the lower
01079                  *  contributing ray number (closer to center of bundle),
01080                  *  and retain that one.
01081                  */
01082                 {
01083                         int     r1 = rt_tree_max_raynum( lastregion->reg_treetop, pp );
01084                         int     r2 = rt_tree_max_raynum( regp->reg_treetop, pp );
01085                         /* Only use this algorithm if one is not the main ray */
01086                         if( r1 > 0 || r2 > 0 )  {
01087 /* if(RT_G_DEBUG&DEBUG_PARTITION) */
01088 bu_log("Potential overlay along ray bundle: r1=%d, r2=%d, resolved to %s\n", r1, r2,
01089 (r1<r2)?lastregion->reg_name:regp->reg_name);
01090                                 if( r1 < r2 )
01091                                         goto code1;     /* keep lastregion */
01092                                 goto code2;             /* keep regp */
01093                         }
01094                 }
01095 
01096                 /*
01097                  *  Hand overlap to old-style application-specific
01098                  *  overlap handler, or default.
01099                  *      0 = destroy partition,
01100                  *      1 = keep part, claiming region=lastregion
01101                  *      2 = keep part, claiming region=regp
01102                  */
01103                 code = ap->a_overlap(ap, pp, lastregion, regp, InputHdp);
01104 
01105                 /* Implement the policy in "code" */
01106                 if( code == 0 )  {
01107                         /*
01108                          *  Destroy the whole partition.
01109                          */
01110                         if(RT_G_DEBUG&DEBUG_PARTITION)  bu_log("rt_default_multioverlap:  overlap code=0, partition=x%x deleted\n", pp);
01111                         bu_ptbl_reset(regiontable);
01112                         return;
01113                 } else if( code == 1 ) {
01114 code1:
01115                         /* Keep partition, claiming region = lastregion */
01116                         if(RT_G_DEBUG&DEBUG_PARTITION)  bu_log("rt_default_multioverlap:  overlap policy=1, code=%d, p retained in region=%s\n",
01117                                 code, lastregion->reg_name );
01118                         BU_PTBL_CLEAR_I(regiontable, i);
01119                 } else {
01120 code2:
01121                         /* Keep partition, claiming region = regp */
01122                         bu_ptbl_zero(regiontable, (long *)lastregion);
01123                         lastregion = regp;
01124                         if(RT_G_DEBUG&DEBUG_PARTITION)  bu_log("rt_default_multioverlap:  overlap policy!=(0,1) code=%d, p retained in region=%s\n",
01125                                 code, lastregion->reg_name );
01126                 }
01127         }
01128 }
01129 
01130 /*
01131  *                      R T _ S I L E N T _ L O G O V E R L A P
01132  *
01133  *  If an application doesn't want any logging from LIBRT, it should
01134  *  just set ap->a_logoverlap = rt_silent_logoverlap.
01135  */
01136 void
01137 rt_silent_logoverlap(struct application *ap, const struct partition *pp, const struct bu_ptbl *regiontable, const struct partition *InputHdp)
01138 {
01139         RT_CK_AP(ap);
01140         RT_CK_PT(pp);
01141         BU_CK_PTBL(regiontable);
01142         return;
01143 }
01144 
01145 
01146 /*
01147  *                      R T _ D E F A U L T _ L O G O V E R L A P
01148  *
01149  *  Log a multiplicity of overlaps within a single partition.
01150  *  This function is intended for logging only, and a_multioverlap()
01151  *  is intended for resolving the overlap, only.
01152  *  This function can be replaced by an application setting a_logoverlap().
01153  */
01154 void
01155 rt_default_logoverlap(struct application *ap, const struct partition *pp, const struct bu_ptbl *regiontable, const struct partition *InputHdp)
01156 {
01157         point_t pt;
01158         static long count = 0;          /* Not PARALLEL, shouldn't hurt */
01159         register fastf_t depth;
01160         int             i;
01161         struct bu_vls   str;
01162 
01163         RT_CK_AP(ap);
01164         RT_CK_PT(pp);
01165         BU_CK_PTBL(regiontable);
01166 
01167         /* Attempt to control tremendous error outputs */
01168         if( ++count > 100 )  {
01169                 if( (count%100) != 3 )  return;
01170                 bu_log("(overlaps omitted)\n");
01171         }
01172 
01173         /*
01174          * Print all verbiage in one call to bu_log(),
01175          * so that messages will be grouped together in parallel runs.
01176          */
01177         bu_vls_init(&str);
01178         bu_vls_extend(&str, 80*8 );
01179         bu_vls_putc(&str, '\n' );
01180 
01181         /* List all the regions which evaluated to TRUE in this partition */
01182         for( i=0; i < BU_PTBL_LEN(regiontable); i++ )  {
01183                 struct region *regp = (struct region *)BU_PTBL_GET(regiontable, i);
01184 
01185                 if( regp == REGION_NULL )  continue;
01186                 RT_CK_REGION(regp);
01187 
01188                 bu_vls_printf(&str, "OVERLAP%d: %s\n", i+1, regp->reg_name);
01189         }
01190 
01191         /* List all the information common to this whole partition */
01192         bu_vls_printf(&str, "OVERLAPa: dist=(%g,%g) isol=%s osol=%s\n",
01193                 pp->pt_inhit->hit_dist, pp->pt_outhit->hit_dist,
01194                 pp->pt_inseg->seg_stp->st_name,
01195                 pp->pt_outseg->seg_stp->st_name);
01196 
01197         depth = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist;
01198         VJOIN1( pt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist,
01199                 ap->a_ray.r_dir );
01200 
01201         bu_vls_printf(&str, "OVERLAPb: depth %.5fmm at (%g, %g, %g) x%d y%d lvl%d\n",
01202                 depth, pt[X], pt[Y], pt[Z],
01203                 ap->a_x, ap->a_y, ap->a_level );
01204 
01205         bu_log("%s", bu_vls_addr(&str));
01206         bu_vls_free(&str);
01207 
01208 #if 0
01209         rt_pr_partitions( ap->a_rt_i, pheadp, "Entire ray containing overlap");
01210 #endif
01211 
01212 }
01213 
01214 /*
01215  *                      R T _ O V E R L A P _ T A B L E S _ E Q U A L
01216  *
01217  *  Overlap tables are NULL terminated arrays of region pointers.
01218  *  The order of entries may be different between the two.
01219  *
01220  *  Returns -
01221  *      1       The tables match
01222  *      0       The tables do not match
01223  */
01224 int
01225 rt_overlap_tables_equal( struct region *const*a, struct region *const*b )
01226 {
01227         int alen=0, blen=0;
01228         register struct region *const*app;
01229         register struct region *const*bpp;
01230 
01231         if( a == NULL && b == NULL )
01232                 return 1;
01233 
01234         if( a == NULL || b == NULL )
01235                 return 0;
01236 
01237         /* First step, compare lengths */
01238         for( app = a; *app != NULL; app++ )  alen++;
01239         for( bpp = b; *bpp != NULL; bpp++ )  blen++;
01240         if( alen != blen )  return 0;
01241 
01242         /* Second step, compare contents */
01243         for( app = a; *app != NULL; app++ )  {
01244                 register const struct region *t = *app;
01245                 for( bpp = b; *bpp != NULL; bpp++ )  {
01246                         if( *bpp == t )  goto b_ok;
01247                 }
01248                 /* 't' not found in b table, no match */
01249                 return 0;
01250 b_ok:           ;
01251         }
01252         /* Everything matches */
01253         return 1;
01254 }
01255 
01256 /*
01257  *                      R T _ B O O L F I N A L
01258  *
01259  *
01260  *  Consider each partition on the sorted & woven input partition list.
01261  *  If the partition ends before this box's start, discard it immediately.
01262  *  If the partition begins beyond this box's end, return.
01263  *
01264  *  Next, evaluate the boolean expression tree for all regions that have
01265  *  some presence in the partition.
01266  *
01267  * If 0 regions result, continue with next partition.
01268  * If 1 region results, a valid hit has occured, so transfer
01269  * the partition from the Input list to the Final list.
01270  * If 2 or more regions claim the partition, then an overlap exists.
01271  * If the overlap handler gives a non-zero return, then the overlapping
01272  * partition is kept, with the region ID being the first one encountered.
01273  * Otherwise, the partition is eliminated from further consideration.
01274  *
01275  *  All partitions in the indicated range of the ray are evaluated.
01276  *  All partitions which really exist (booleval is true) are appended
01277  *  to the Final partition list.
01278  *  All partitions on the Final partition list have completely valid
01279  *  entry and exit information, except for the last partition's exit
01280  *  information when a_onehit!=0 and a_onehit is odd.
01281  *
01282  *  The flag a_onehit is interpreted as follows:
01283  *
01284  *  If a_onehit = 0, then the ray is traced to +infinity, and all
01285  *  hit points in the final partition list are valid.
01286  *
01287  *  If a_onehit != 0, the ray is traced through a_onehit hit points.
01288  *  (Recall that each partition has 2 hit points, entry and exit).
01289  *  Thus, if a_onehit is odd, the value of pt_outhit.hit_dist in
01290  *  the last partition may be incorrect;  this should not mater because
01291  *  the application specifically said it only wanted pt_inhit there.
01292  *  This is most commonly seen when a_onehit = 1, which is useful for
01293  *  lighting models.  Not having to correctly determine the exit point
01294  *  can result in a significant savings of computer time.
01295  *  If a_onehit is negative, it indicates the number of non-air hits needed.
01296  *
01297  *  Returns -
01298  *      0       If more partitions need to be done
01299  *      1       Requested number of hits are available in FinalHdp
01300  *
01301  *  The caller must free whatever is in both partition chains.
01302  *
01303  *
01304  *  NOTES for code improvements -
01305  *
01306  *  With a_onehit != 0, it is difficult to stop at the 'enddist' value
01307  *  (or the a_ray_length value), and always get correct results.
01308  *  Need to take into account some additional factors:
01309  *
01310  *  1)  A region shouldn't be evaluated until all it's solids have been
01311  *      intersected, to prevent the "CERN" problem of out points being
01312  *      wrong because subtracted solids aren't intersected yet.
01313  *
01314  *      Maybe "all" solids don't have to be intersected, but some strong
01315  *      statements are needed along these lines.
01316  *
01317  *      A region is definitely ready to be evaluated
01318  *      IF all it's solids have been intersected.
01319  *
01320  *  2)  A partition shouldn't be evaluated until all the regions within it
01321  *      are ready to be evaluated.
01322  */
01323 int
01324 rt_boolfinal(struct partition *InputHdp, struct partition *FinalHdp, fastf_t startdist, fastf_t enddist, struct bu_ptbl *regiontable, struct application *ap, const struct bu_bitv *solidbits)
01325 {
01326         LOCAL struct region *lastregion = (struct region *)NULL;
01327         LOCAL struct region *TrueRg[2];
01328         register struct partition *pp;
01329         register int    claiming_regions;
01330         int             hits_avail = 0;
01331         int             hits_needed;
01332         int             ret = 0;
01333         int             indefinite_outpt = 0;
01334         char            *reason = (char *)NULL;
01335         fastf_t         diff;
01336 
01337 #define HITS_TODO       (hits_needed - hits_avail)
01338 
01339         RT_CK_PT_HD(InputHdp);
01340         RT_CK_PT_HD(FinalHdp);
01341         BU_CK_PTBL(regiontable);
01342         RT_CK_RTI(ap->a_rt_i);
01343         BU_CK_BITV(solidbits);
01344 
01345         if(RT_G_DEBUG&DEBUG_PARTITION)  {
01346                 bu_log("\nrt_boolfinal(%g,%g) x%d y%d lvl%d START\n",
01347                         startdist, enddist,
01348                         ap->a_x, ap->a_y, ap->a_level );
01349         }
01350 
01351         if( !ap->a_multioverlap )
01352                 ap->a_multioverlap = rt_default_multioverlap;
01353 
01354         if( !ap->a_logoverlap )
01355                 ap->a_logoverlap = rt_default_logoverlap;
01356 
01357         if( enddist <= 0 )  {
01358                 reason = "not done, behind start point";
01359                 ret = 0;
01360                 goto out;
01361         }
01362 
01363         if( ap->a_onehit < 0 )
01364                 hits_needed = -ap->a_onehit;
01365         else
01366                 hits_needed = ap->a_onehit;
01367 
01368         if( ap->a_onehit != 0 )  {
01369                 register struct partition *npp = FinalHdp->pt_forw;
01370 
01371                 for(; npp != FinalHdp; npp = npp->pt_forw )  {
01372                         if( npp->pt_inhit->hit_dist < 0.0 )
01373                                 continue;
01374                         if( ap->a_onehit < 0 && npp->pt_regionp->reg_aircode != 0 )
01375                                 continue;       /* skip air hits */
01376                         hits_avail += 2;        /* both in and out listed */
01377                 }
01378                 if( hits_avail >= hits_needed )  {
01379                         reason = "a_onehit request satisfied at outset";
01380                         ret = 1;
01381                         goto out;
01382                 }
01383         }
01384 
01385         if( ap->a_no_booleans )  {
01386                 while( (pp = InputHdp->pt_forw) != InputHdp )  {
01387                         RT_CK_PT(pp);
01388                         DEQUEUE_PT(pp);
01389                         pp->pt_regionp = (struct region *)
01390                                 BU_PTBL_GET(&pp->pt_inseg->seg_stp->st_regions, 0);
01391                         RT_CK_REGION(pp->pt_regionp);
01392                         if(RT_G_DEBUG&DEBUG_PARTITION)  {
01393                                 rt_pr_pt( ap->a_rt_i, pp );
01394                         }
01395                         INSERT_PT( pp, FinalHdp );
01396                 }
01397                 ret = 0;
01398                 reason = "No a_onehit processing in a_no_booleans mode";
01399                 goto out;
01400         }
01401 
01402         pp = InputHdp->pt_forw;
01403         while( pp != InputHdp )  {
01404                 RT_CK_PT(pp);
01405                 claiming_regions = 0;
01406                 if(RT_G_DEBUG&DEBUG_PARTITION)  {
01407                         bu_log("\nrt_boolfinal(%g,%g) x%d y%d lvl%d, next input pp\n",
01408                                 startdist, enddist,
01409                                 ap->a_x, ap->a_y, ap->a_level );
01410                         rt_pr_pt( ap->a_rt_i, pp );
01411                 }
01412                 RT_CHECK_SEG(pp->pt_inseg);
01413                 RT_CHECK_SEG(pp->pt_outseg);
01414 
01415                 /* Force "very thin" partitions to have exactly zero thickness. */
01416                 diff = pp->pt_inhit->hit_dist - pp->pt_outhit->hit_dist;
01417                 if( NEAR_ZERO( diff, ap->a_rt_i->rti_tol.dist ) )  {
01418                         if(RT_G_DEBUG&DEBUG_PARTITION)  bu_log(
01419                                 "rt_boolfinal:  Zero thickness partition, prims %s %s (%.18e,%.18e) x%d y%d lvl%d\n",
01420                                 pp->pt_inseg->seg_stp->st_name,
01421                                 pp->pt_outseg->seg_stp->st_name,
01422                                 pp->pt_inhit->hit_dist,
01423                                 pp->pt_outhit->hit_dist,
01424                                 ap->a_x, ap->a_y, ap->a_level );
01425                         pp->pt_outhit->hit_dist = pp->pt_inhit->hit_dist;
01426                 }
01427 
01428 
01429                 /* Sanity checks on sorting. */
01430                 if( pp->pt_inhit->hit_dist > pp->pt_outhit->hit_dist )  {
01431                         bu_log("rt_boolfinal: inverted partition %.8x x%d y%d lvl%d\n",
01432                                 pp,
01433                                 ap->a_x, ap->a_y, ap->a_level );
01434                         rt_pr_partitions( ap->a_rt_i, InputHdp, "With problem" );
01435                 }
01436                 if( pp->pt_forw != InputHdp &&
01437                     pp->pt_outhit->hit_dist != pp->pt_forw->pt_inhit->hit_dist )  {
01438                         diff = pp->pt_outhit->hit_dist - pp->pt_forw->pt_inhit->hit_dist;
01439                         if( NEAR_ZERO( diff, ap->a_rt_i->rti_tol.dist ) )  {
01440                                 if(RT_G_DEBUG&DEBUG_PARTITION)  bu_log("rt_boolfinal:  fusing 2 partitions x%x x%x\n",
01441                                         pp, pp->pt_forw );
01442                                 pp->pt_forw->pt_inhit->hit_dist = pp->pt_outhit->hit_dist;
01443                         } else if( diff > 0 )  {
01444                                 bu_log("rt_boolfinal:  sorting defect %e > %e! x%d y%d lvl%d, diff = %g\n",
01445                                         pp->pt_outhit->hit_dist,
01446                                         pp->pt_forw->pt_inhit->hit_dist,
01447                                         ap->a_x, ap->a_y, ap->a_level, diff );
01448                                 bu_log( "sort defect is between parts x%x and x%x\n",
01449                                         pp, pp->pt_forw );
01450                                 if( !(RT_G_DEBUG & DEBUG_PARTITION) )
01451                                         rt_pr_partitions( ap->a_rt_i, InputHdp, "With DEFECT" );
01452                                 ret = 0;
01453                                 reason = "ERROR, sorting defect, give up";
01454                                 goto out;
01455                         }
01456                 }
01457 
01458                 /*
01459                  *  If partition is behind ray start point, discard it.
01460                  *
01461                  *  Partition may start before current box starts, because
01462                  *  it's still waiting for all it's solids to be shot.
01463                  */
01464                 if( pp->pt_outhit->hit_dist <= 0.001 /* milimeters */ )  {
01465                         register struct partition *zap_pp;
01466                         if(RT_G_DEBUG&DEBUG_PARTITION)bu_log(
01467                                 "discarding partition x%x behind ray start, out dist=%g\n",
01468                                 pp, pp->pt_outhit->hit_dist);
01469                         zap_pp = pp;
01470                         pp = pp->pt_forw;
01471                         DEQUEUE_PT(zap_pp);
01472                         FREE_PT(zap_pp, ap->a_resource);
01473                         continue;
01474                 }
01475 
01476                 /*
01477                  *  If partition begins beyond current box end,
01478                  *  the state of the partition is not fully known yet,
01479                  *  and new partitions might be added in front of this one,
01480                  *  so stop now.
01481                  */
01482                 diff = pp->pt_inhit->hit_dist - enddist;
01483                 if( diff > ap->a_rt_i->rti_tol.dist )  {
01484                         if(RT_G_DEBUG&DEBUG_PARTITION)bu_log(
01485                                 "partition begins %g beyond current box end, returning\n", diff);
01486                         reason = "partition begins beyond current box end";
01487                         ret = 0;
01488                         goto out;
01489                 }
01490 
01491                 /*
01492                  *  If partition ends somewhere beyond the end of the current
01493                  *  box, the condition of the outhit information is not fully
01494                  *  known yet.
01495                  *  The partition might be broken or shortened by subsequent
01496                  *  segments, not discovered until entering future boxes.
01497                  */
01498                 diff = pp->pt_outhit->hit_dist - enddist;
01499                 if( diff > ap->a_rt_i->rti_tol.dist )  {
01500                         if(RT_G_DEBUG&DEBUG_PARTITION)bu_log(
01501                                 "partition ends beyond current box end\n");
01502                         if( ap->a_onehit != 1 )  {
01503                                 ret = 0;
01504                                 reason = "a_onehit != 1, trace remaining boxes";
01505                                 goto out;
01506                         }
01507                         /* pt_outhit may not be correct */
01508                         indefinite_outpt = 1;
01509                 } else {
01510                         indefinite_outpt = 0;
01511                 }
01512 
01513                 /* XXX a_ray_length checking should be done here, not in rt_shootray() */
01514 
01515                 /* Start with a clean slate when evaluating this partition */
01516                 bu_ptbl_reset(regiontable);
01517 
01518                 /*
01519                  *  For each segment's solid that lies in this partition,
01520                  *  add the list of regions that refer to that solid
01521                  *  into the "regiontable" array.
01522                  */
01523                 {
01524                         struct seg **segpp;
01525 
01526                         if(RT_G_DEBUG&DEBUG_PARTITION)
01527                                 bu_log( "Building region table:\n" );
01528                         for( BU_PTBL_FOR(segpp, (struct seg **), &pp->pt_seglist) )  {
01529                                 struct soltab   *stp = (*segpp)->seg_stp;
01530                                 RT_CK_SOLTAB(stp);
01531                                 bu_ptbl_cat_uniq( regiontable, &stp->st_regions );
01532                         }
01533                 }
01534 
01535                 if(RT_G_DEBUG&DEBUG_PARTITION)  {
01536                         struct region **regpp;
01537                         bu_log("Region table for this partition:\n");
01538                         for( BU_PTBL_FOR( regpp, (struct region **), regiontable ) )  {
01539                                 register struct region *regp;
01540 
01541                                 regp = *regpp;
01542                                 RT_CK_REGION(regp);
01543                                 bu_log("%9lx %s\n", (long)regp, regp->reg_name);
01544                         }
01545                 }
01546 
01547                 if( indefinite_outpt )  {
01548                         if(RT_G_DEBUG&DEBUG_PARTITION)bu_log(
01549                                 "indefinite out point, checking partition eligibility for early evaluation.\n");
01550                         /*
01551                          *  More hits still needed.  HITS_TODO > 0.
01552                          *  If every solid in every region participating
01553                          *  in this partition has been intersected,
01554                          *  then it is OK to evaluate it now.
01555                          */
01556                         if( !rt_bool_partition_eligible(regiontable, solidbits, pp) )  {
01557                                 ret = 0;
01558                                 reason = "Partition not yet eligible for evaluation";
01559                                 goto out;
01560                         }
01561                         if(RT_G_DEBUG&DEBUG_PARTITION)bu_log(
01562                                 "Partition is eligibile for evaluation.\n");
01563                 }
01564 
01565                 /* Evaluate the boolean trees of any regions involved */
01566                 {
01567                         struct region **regpp;
01568                         for( BU_PTBL_FOR( regpp, (struct region **), regiontable ) )  {
01569                                 register struct region *regp;
01570 
01571                                 regp = *regpp;
01572                                 RT_CK_REGION(regp);
01573                                 if(RT_G_DEBUG&DEBUG_PARTITION)  {
01574                                         rt_pr_tree_val( regp->reg_treetop, pp, 2, 0 );
01575                                         rt_pr_tree_val( regp->reg_treetop, pp, 1, 0 );
01576                                         rt_pr_tree_val( regp->reg_treetop, pp, 0, 0 );
01577                                         bu_log("%.8x=bit%d, %s: ",
01578                                                 regp, regp->reg_bit,
01579                                                 regp->reg_name );
01580                                 }
01581                                 if( regp->reg_all_unions )  {
01582                                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("TRUE (all union)\n");
01583                                         claiming_regions++;
01584                                         lastregion = regp;
01585                                         continue;
01586                                 }
01587                                 if( rt_booleval( regp->reg_treetop, pp, TrueRg,
01588                                     ap->a_resource ) == FALSE )  {
01589                                         if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("FALSE\n");
01590                                         /* Null out non-claiming region's pointer */
01591                                         *regpp = REGION_NULL;
01592                                         continue;
01593                                 }
01594                                 /* This region claims partition */
01595                                 if(RT_G_DEBUG&DEBUG_PARTITION) bu_log("TRUE (eval)\n");
01596                                 claiming_regions++;
01597                                 lastregion = regp;
01598                         }
01599                 }
01600                 if(RT_G_DEBUG&DEBUG_PARTITION)  bu_log("rt_boolfinal:  claiming_regions=%d (%g <-> %g)\n",
01601                         claiming_regions, pp->pt_inhit->hit_dist, pp->pt_outhit->hit_dist);
01602                 if( claiming_regions == 0 )  {
01603                         if(RT_G_DEBUG&DEBUG_PARTITION)bu_log("rt_boolfinal moving past partition x%x\n", pp);
01604                         pp = pp->pt_forw;               /* onwards! */
01605                         continue;
01606                 }
01607 
01608                 if( claiming_regions > 1 )  {
01609                         /*
01610                          *  There is an overlap between two or more regions,
01611                          *  invoke multi-overlap handler.
01612                          */
01613                         if(RT_G_DEBUG&DEBUG_PARTITION)
01614 bu_log("rt_boolfinal:  invoking a_multioverlap() pp=x%x\n", pp);
01615                         bu_ptbl_rm( regiontable, (long *)NULL );
01616                         ap->a_logoverlap( ap, pp, regiontable, InputHdp );
01617                         ap->a_multioverlap( ap, pp, regiontable, InputHdp );
01618 
01619                         /* Count number of remaining regions, s/b 0 or 1 */
01620                         claiming_regions = 0;
01621                         {
01622                                 register struct region **regpp;
01623                                 for( BU_PTBL_FOR( regpp, (struct region **), regiontable ) )  {
01624                                         if( *regpp != REGION_NULL )  {
01625                                                 claiming_regions++;
01626                                                 lastregion = *regpp;
01627                                         }
01628                                 }
01629                         }
01630 
01631                         /*
01632                          *  If claiming_regions == 0, discard partition.
01633                          *  If claiming_regions > 1, signal error and discard.
01634                          *  There is nothing further we can do to fix it.
01635                          */
01636                         if( claiming_regions > 1)  {
01637                                 bu_log("rt_boolfinal() a_multioverlap() failed to resolve overlap, discarding bad partition:\n");
01638                                 rt_pr_pt( ap->a_rt_i, pp );
01639                         }
01640 
01641                         if( claiming_regions != 1 )  {
01642                                 register struct partition       *zap_pp;
01643 
01644                                 if(RT_G_DEBUG&DEBUG_PARTITION)bu_log("rt_boolfinal discarding overlap partition x%x\n", pp);
01645                                 zap_pp = pp;
01646                                 pp = pp->pt_forw;               /* onwards! */
01647                                 DEQUEUE_PT( zap_pp );
01648                                 FREE_PT( zap_pp, ap->a_resource );
01649                                 continue;
01650                         }
01651                 }
01652 
01653                 /*
01654                  *  claiming_regions == 1
01655                  *
01656                  *  Remove this partition from the input queue, and
01657                  *  append it to the result queue.
01658                  */
01659                 {
01660                         register struct partition       *newpp;
01661                         register struct partition       *lastpp;
01662                         if(RT_G_DEBUG&DEBUG_PARTITION )
01663                                 bu_log( "Appending partition to result queue: %g, %g\n",
01664                                         pp->pt_inhit->hit_dist, pp->pt_outhit->hit_dist );
01665                         newpp = pp;
01666                         pp=pp->pt_forw;                         /* onwards! */
01667                         DEQUEUE_PT( newpp );
01668                         RT_CHECK_SEG(newpp->pt_inseg);          /* sanity */
01669                         RT_CHECK_SEG(newpp->pt_outseg);         /* sanity */
01670                         /* Record the "owning" region.  pt_regionp = NULL before here. */
01671                         newpp->pt_regionp = lastregion;
01672 
01673                         /*  See if this new partition extends the previous
01674                          *  last partition, "exactly" matching.
01675                          */
01676                         lastpp = FinalHdp->pt_back;
01677                         if( lastpp != FinalHdp &&
01678                             lastregion == lastpp->pt_regionp &&
01679                             NEAR_ZERO( newpp->pt_inhit->hit_dist -
01680                                 lastpp->pt_outhit->hit_dist,
01681                                 ap->a_rt_i->rti_tol.dist ) &&
01682                             ( ap->a_rt_i->rti_save_overlaps == 0 ||
01683                                 rt_overlap_tables_equal(
01684                                         lastpp->pt_overlap_reg,
01685                                         newpp->pt_overlap_reg ) )
01686                         )  {
01687                                 /* same region, merge by extending last final partition */
01688                                 if(RT_G_DEBUG&DEBUG_PARTITION)bu_log("rt_boolfinal 'exact match', extending last partition, discarding x%x\n", newpp);
01689                                 RT_CK_PT(lastpp);
01690                                 RT_CHECK_SEG(lastpp->pt_inseg); /* sanity */
01691                                 RT_CHECK_SEG(lastpp->pt_outseg);/* sanity */
01692                                 if(RT_G_DEBUG&DEBUG_PARTITION)bu_log("rt_boolfinal collapsing %x %x\n", lastpp, newpp);
01693                                 lastpp->pt_outhit = newpp->pt_outhit;
01694                                 lastpp->pt_outflip = newpp->pt_outflip;
01695                                 lastpp->pt_outseg = newpp->pt_outseg;
01696 
01697                                 /* Don't lose the fact that the two solids
01698                                  * of this partition contributed.
01699                                  */
01700                                 bu_ptbl_ins_unique( &lastpp->pt_seglist, (long *)newpp->pt_inseg );
01701                                 bu_ptbl_ins_unique( &lastpp->pt_seglist, (long *)newpp->pt_outseg );
01702 
01703                                 FREE_PT( newpp, ap->a_resource );
01704                                 newpp = lastpp;
01705                         }  else  {
01706                                 APPEND_PT( newpp, lastpp );
01707                                 if( !(ap->a_onehit < 0 && newpp->pt_regionp->reg_aircode != 0) )
01708                                         hits_avail += 2;
01709                         }
01710 
01711                         RT_CHECK_SEG(newpp->pt_inseg);          /* sanity */
01712                         RT_CHECK_SEG(newpp->pt_outseg);         /* sanity */
01713                 }
01714 
01715                 /* See if it's worthwhile breaking out of partition loop early */
01716                 if( ap->a_onehit != 0 && HITS_TODO <= 0 )  {
01717                         ret = 1;
01718                         if( pp == InputHdp )
01719                                 reason = "a_onehit satisfied at bottom";
01720                         else
01721                                 reason = "a_onehit satisfied early";
01722                         goto out;
01723                 }
01724         }
01725         if( ap->a_onehit != 0 && HITS_TODO <= 0 )  {
01726                 ret = 1;
01727                 reason = "a_onehit satisfied at end";
01728         } else {
01729                 ret = 0;
01730                 reason = "more partitions needed";
01731         }
01732 out:
01733         if( RT_G_DEBUG&DEBUG_PARTITION )  {
01734                 bu_log("rt_boolfinal() ret=%d, %s\n", ret, reason);
01735                 rt_pr_partitions( ap->a_rt_i, FinalHdp, "rt_boolfinal: Final partition list at return:" );
01736                 rt_pr_partitions( ap->a_rt_i, InputHdp, "rt_boolfinal: Input/pending partition list at return:" );
01737                 bu_log("rt_boolfinal() ret=%d, %s\n", ret, reason);
01738         }
01739 #if 0
01740         /* This is no longer a valid check!!! */
01741         /* Sanity check */
01742         if( RT_G_DEBUG && ap->a_onehit == 0 &&
01743             InputHdp->pt_forw != InputHdp && enddist >= INFINITY )  {
01744                 bu_log("rt_boolfinal() ret=%d, %s\n", ret, reason);
01745                 rt_pr_partitions( ap->a_rt_i, FinalHdp, "rt_boolfinal: Final partition list at return:" );
01746                 rt_pr_partitions( ap->a_rt_i, InputHdp, "rt_boolfinal: Input/pending partition list at return:" );
01747                 rt_bomb("rt_boolfinal() failed to process InputHdp list\n");
01748         }
01749 #endif
01750         return ret;
01751 }
01752 
01753 /*
01754  *                      R T _ B O O L E V A L
01755  *
01756  *  Using a stack to recall state, evaluate a boolean expression
01757  *  without recursion.
01758  *
01759  *  For use with XOR, a pointer to the "first valid subtree" would
01760  *  be a useful addition, for rt_boolregions().
01761  *
01762  *  Returns -
01763  *      !0      tree is TRUE
01764  *       0      tree is FALSE
01765  *      -1      tree is in error (GUARD)
01766  */
01767 int
01768 rt_booleval(register union tree *treep, struct partition *partp, struct region **trueregp, struct resource *resp)
01769                                 /* Tree to evaluate */
01770                                 /* Partition to evaluate */
01771                                 /* XOR true (and overlap) return */
01772                                 /* resource pointer for this CPU */
01773 {
01774         static union tree tree_not[MAX_PSW];    /* for OP_NOT nodes */
01775         static union tree tree_guard[MAX_PSW];  /* for OP_GUARD nodes */
01776         static union tree tree_xnop[MAX_PSW];   /* for OP_XNOP nodes */
01777         register union tree **sp;
01778         register int ret;
01779         register union tree **stackend;
01780 
01781         RT_CK_TREE(treep);
01782         RT_CK_PT(partp);
01783         RT_CK_RESOURCE(resp);
01784         if( treep->tr_op != OP_XOR )
01785                 trueregp[0] = treep->tr_regionp;
01786         else
01787                 trueregp[0] = trueregp[1] = REGION_NULL;
01788         while( (sp = resp->re_boolstack) == (union tree **)0 )
01789                 rt_grow_boolstack( resp );
01790         stackend = &(resp->re_boolstack[resp->re_boolslen]);
01791         *sp++ = TREE_NULL;
01792 stack:
01793         switch( treep->tr_op )  {
01794         case OP_NOP:
01795                 ret = 0;
01796                 goto pop;
01797         case OP_SOLID:
01798                 {
01799                         register struct soltab *seek_stp = treep->tr_a.tu_stp;
01800                         register struct seg **segpp;
01801                         for( BU_PTBL_FOR( segpp, (struct seg **), &partp->pt_seglist ) )  {
01802                                 if( (*segpp)->seg_stp == seek_stp )  {
01803                                         ret = 1;
01804                                         goto pop;
01805                                 }
01806                         }
01807                         ret = 0;
01808                 }
01809                 goto pop;
01810         case OP_UNION:
01811         case OP_INTERSECT:
01812         case OP_SUBTRACT:
01813         case OP_XOR:
01814                 *sp++ = treep;
01815                 if( sp >= stackend )  {
01816                         register int off = sp - resp->re_boolstack;
01817                         rt_grow_boolstack( resp );
01818                         sp = &(resp->re_boolstack[off]);
01819                         stackend = &(resp->re_boolstack[resp->re_boolslen]);
01820                 }
01821                 treep = treep->tr_b.tb_left;
01822                 goto stack;
01823         default:
01824                 bu_log("rt_booleval:  bad stack op x%x\n",treep->tr_op);
01825                 return(TRUE);   /* screw up output */
01826         }
01827 pop:
01828         if( (treep = *--sp) == TREE_NULL )
01829                 return(ret);            /* top of tree again */
01830         /*
01831          *  Here, each operation will look at the operation just
01832          *  completed (the left branch of the tree generally),
01833          *  and rewrite the top of the stack and/or branch
01834          *  accordingly.
01835          */
01836         switch( treep->tr_op )  {
01837         case OP_SOLID:
01838                 bu_log("rt_booleval:  pop SOLID?\n");
01839                 return(TRUE);   /* screw up output */
01840         case OP_UNION:
01841                 if( ret )  goto pop;    /* TRUE, we are done */
01842                 /* lhs was false, rewrite as rhs tree */
01843                 treep = treep->tr_b.tb_right;
01844                 goto stack;
01845         case OP_INTERSECT:
01846                 if( !ret )  {
01847                         ret = FALSE;
01848                         goto pop;
01849                 }
01850                 /* lhs was true, rewrite as rhs tree */
01851                 treep = treep->tr_b.tb_right;
01852                 goto stack;
01853         case OP_SUBTRACT:
01854                 if( !ret )  goto pop;   /* FALSE, we are done */
01855                 /* lhs was true, rewrite as NOT of rhs tree */
01856                 /* We introduce the special NOT operator here */
01857                 tree_not[resp->re_cpu].tr_op = OP_NOT;
01858                 *sp++ = &tree_not[resp->re_cpu];
01859                 treep = treep->tr_b.tb_right;
01860                 goto stack;
01861         case OP_NOT:
01862                 /* Special operation for subtraction */
01863                 ret = !ret;
01864                 goto pop;
01865         case OP_XOR:
01866                 if( ret )  {
01867                         /* lhs was true, rhs better not be, or we have
01868                          * an overlap condition.  Rewrite as guard node
01869                          * followed by rhs.
01870                          */
01871                         if( treep->tr_b.tb_left->tr_regionp )
01872                                 trueregp[0] = treep->tr_b.tb_left->tr_regionp;
01873                         tree_guard[resp->re_cpu].tr_op = OP_GUARD;
01874                         treep = treep->tr_b.tb_right;
01875                         *sp++ = treep;          /* temp val for guard node */
01876                         *sp++ = &tree_guard[resp->re_cpu];
01877                 } else {
01878                         /* lhs was false, rewrite as xnop node and
01879                          * result of rhs.
01880                          */
01881                         tree_xnop[resp->re_cpu].tr_op = OP_XNOP;
01882                         treep = treep->tr_b.tb_right;
01883                         *sp++ = treep;          /* temp val for xnop */
01884                         *sp++ = &tree_xnop[resp->re_cpu];
01885                 }
01886                 goto stack;
01887         case OP_GUARD:
01888                 /*
01889                  *  Special operation for XOR.  lhs was true.
01890                  *  If rhs subtree was true, an
01891                  *  overlap condition exists (both sides of the XOR are
01892                  *  TRUE).  Return error condition.
01893                  *  If subtree is false, then return TRUE (from lhs).
01894                  */
01895                 if( ret )  {
01896                         /* stacked temp val: rhs */
01897                         if( sp[-1]->tr_regionp )
01898                                 trueregp[1] = sp[-1]->tr_regionp;
01899                         return(-1);     /* GUARD error */
01900                 }
01901                 ret = TRUE;
01902                 sp--;                   /* pop temp val */
01903                 goto pop;
01904         case OP_XNOP:
01905                 /*
01906                  *  Special NOP for XOR.  lhs was false.
01907                  *  If rhs is true, take note of it's regionp.
01908                  */
01909                 sp--;                   /* pop temp val */
01910                 if( ret )  {
01911                         if( (*sp)->tr_regionp )
01912                                 trueregp[0] = (*sp)->tr_regionp;
01913                 }
01914                 goto pop;
01915         default:
01916                 bu_log("rt_booleval:  bad pop op x%x\n",treep->tr_op);
01917                 return(TRUE);   /* screw up output */
01918         }
01919         /* NOTREACHED */
01920 }
01921 
01922 /*
01923  *                      R T _ F D I F F
01924  *
01925  *  Compares two floating point numbers.  If they are within "epsilon"
01926  *  of each other, they are considered the same.
01927  *  NOTE:  This is a "fuzzy" difference.  It is important NOT to
01928  *  use the results of this function in compound comparisons,
01929  *  because a return of 0 makes no statement about the PRECISE
01930  *  relationships between the two numbers.  Eg,
01931  *      if( rt_fdiff( a, b ) <= 0 )
01932  *  is poison!
01933  *
01934  *  Returns -
01935  *      -1      if a < b
01936  *       0      if a ~= b
01937  *      +1      if a > b
01938  */
01939 int
01940 rt_fdiff(double a, double b)
01941 {
01942         FAST double diff;
01943         FAST double d;
01944         register int ret;
01945 
01946         /* d = Max(Abs(a),Abs(b)) */
01947         d = (a >= 0.0) ? a : -a;
01948         if( b >= 0.0 )  {
01949                 if( b > d )  d = b;
01950         } else {
01951                 if( (-b) > d )  d = (-b);
01952         }
01953         if( d <= 1.0e-6 )  {
01954                 ret = 0;        /* both nearly zero */
01955                 goto out;
01956         }
01957         if( d >= INFINITY )  {
01958                 if( a == b )  {
01959                         ret = 0;
01960                         goto out;
01961                 }
01962                 if( a < b )  {
01963                         ret = -1;
01964                         goto out;
01965                 }
01966                 ret = 1;
01967                 goto out;
01968         }
01969         if( (diff = a - b) < 0.0 )  diff = -diff;
01970         if( diff < 0.001 )  {
01971                 ret = 0;        /* absolute difference is small, < 1/1000mm */
01972                 goto out;
01973         }
01974         if( diff < 0.000001 * d )  {
01975                 ret = 0;        /* relative difference is small, < 1ppm */
01976                 goto out;
01977         }
01978         if( a < b )  {
01979                 ret = -1;
01980                 goto out;
01981         }
01982         ret = 1;
01983 out:
01984         if(RT_G_DEBUG&DEBUG_FDIFF) bu_log("rt_fdiff(%.18e,%.18e)=%d\n", a, b, ret);
01985         return(ret);
01986 }
01987 
01988 /*
01989  *                      R T _ R E L D I F F
01990  *
01991  * Compute the relative difference of two floating point numbers.
01992  *
01993  * Returns -
01994  *      0.0 if exactly the same, otherwise
01995  *      ratio of difference, relative to the larger of the two (range 0.0-1.0)
01996  */
01997 double
01998 rt_reldiff(double a, double b)
01999 {
02000         FAST fastf_t    d;
02001         FAST fastf_t    diff;
02002 
02003         /* d = Max(Abs(a),Abs(b)) */
02004         d = (a >= 0.0) ? a : -a;
02005         if( b >= 0.0 )  {
02006                 if( b > d )  d = b;
02007         } else {
02008                 if( (-b) > d )  d = (-b);
02009         }
02010         if( d==0.0 )
02011                 return( 0.0 );
02012         if( (diff = a - b) < 0.0 )  diff = -diff;
02013         return( diff / d );
02014 }
02015 
02016 /*
02017  *                      R T _ G R O W _ B O O L S T A C K
02018  *
02019  *  Increase the size of re_boolstack to double the previous size.
02020  *  Depend on rt_realloc() to copy the previous data to the new area
02021  *  when the size is increased.
02022  *  Return the new pointer for what was previously the last element.
02023  */
02024 void
02025 rt_grow_boolstack(register struct resource *resp)
02026 {
02027         if( resp->re_boolstack == (union tree **)0 || resp->re_boolslen <= 0 )  {
02028                 resp->re_boolslen = 128;        /* default len */
02029                 resp->re_boolstack = (union tree **)bu_malloc(
02030                         sizeof(union tree *) * resp->re_boolslen,
02031                         "initial boolstack");
02032         } else {
02033                 resp->re_boolslen <<= 1;
02034                 resp->re_boolstack = (union tree **)rt_realloc(
02035                         (char *)resp->re_boolstack,
02036                         sizeof(union tree *) * resp->re_boolslen,
02037                         "extend boolstack" );
02038         }
02039 }
02040 
02041 /*
02042  *                      R T _ P A R T I T I O N _ L E N
02043  *
02044  *  Return the length of a partition linked list.
02045  */
02046 int
02047 rt_partition_len( const struct partition *partheadp )
02048 {
02049         register struct partition       *pp;
02050         register long   count = 0;
02051 
02052         pp = partheadp->pt_forw;
02053         if( pp == PT_NULL )
02054                 return(0);              /* Header not initialized yet */
02055         for( ; pp != partheadp; pp = pp->pt_forw )  {
02056                 if( pp->pt_magic != 0 )  {
02057                         /* Partitions on the free queue have pt_magic = 0 */
02058                         RT_CK_PT(pp);
02059                 }
02060                 if( ++count > 1000000 )  rt_bomb("partition length > 10000000 elements\n");
02061         }
02062         return( (int)count );
02063 }
02064 
02065 
02066 /*
02067  *                      R T _ T R E E _ T E S T _ R E A D Y
02068  *
02069  *  Test to see if a region is ready to be evaluated over a given
02070  *  partition, i.e. if all the prerequisites have been satisfied.
02071  *
02072  *  Returns -
02073  *      !0      Region is ready for (correct) evaluation.
02074  *      0       Region is not ready
02075  */
02076 int
02077 rt_tree_test_ready(register const union tree *tp, register const struct bu_bitv *solidbits, register const struct region *regionp, register const struct partition *pp)
02078 {
02079         RT_CK_TREE(tp);
02080         BU_CK_BITV(solidbits);
02081         RT_CK_REGION(regionp);
02082         RT_CK_PT(pp);
02083 
02084         switch( tp->tr_op )  {
02085         case OP_NOP:
02086                 return 1;
02087 
02088         case OP_SOLID:
02089                 if( BU_BITTEST( solidbits, tp->tr_a.tu_stp->st_bit ) )
02090                         return 1;       /* This solid's been shot, segs are valid. */
02091                 /*
02092                  *  This solid has not been shot yet.
02093                  */
02094                 return 0;
02095 
02096         case OP_NOT:
02097                 return !rt_tree_test_ready( tp->tr_b.tb_left, solidbits, regionp, pp );
02098 
02099         case OP_UNION:
02100         case OP_INTERSECT:
02101         case OP_SUBTRACT:
02102         case OP_XOR:
02103                 if( !rt_tree_test_ready( tp->tr_b.tb_left, solidbits, regionp, pp ) )
02104                         return 0;
02105                 return rt_tree_test_ready( tp->tr_b.tb_right, solidbits, regionp, pp );
02106 
02107         default:
02108                 rt_bomb("rt_tree_test_ready: bad op\n");
02109         }
02110         return 0;
02111 }
02112 
02113 /*
02114  *                      R T _ B O O L _ P A R T I T I O N _ E L I G I B L E
02115  *
02116  *  If every solid in every region participating in this
02117  *  ray-partition has already been intersected with the ray,
02118  *  then this partition can be safely evaluated.
02119  *
02120  *  Returns -
02121  *      !0      Partition is ready for (correct) evaluation.
02122  *      0       Partition is not ready
02123  */
02124 int
02125 rt_bool_partition_eligible(register const struct bu_ptbl *regiontable, register const struct bu_bitv *solidbits, register const struct partition *pp)
02126 {
02127         struct region **regpp;
02128 
02129         BU_CK_PTBL(regiontable);
02130         BU_CK_BITV(solidbits);
02131         RT_CK_PT(pp);
02132 
02133         for( BU_PTBL_FOR( regpp, (struct region **), regiontable ) )  {
02134                 register struct region *regp;
02135 
02136                 regp = *regpp;
02137                 RT_CK_REGION(regp);
02138 
02139                 /* Check region prerequisites */
02140                 if( !rt_tree_test_ready( regp->reg_treetop, solidbits, regp, pp) )  {
02141                         return 0;
02142                 }
02143         }
02144         return 1;
02145 }
02146 
02147 
02148 /*
02149  *                      R T _ T R E E _ M A X _ R A Y N U M
02150  *
02151  *  Find the maximum value of the raynum (seg_rayp->index)
02152  *  encountered in the segments contributing to this region.
02153  *
02154  *  Returns -
02155  *      #       Maximum ray index
02156  *      -1      If no rays are contributing segs for this region.
02157  */
02158 int
02159 rt_tree_max_raynum(register const union tree *tp, register const struct partition *pp)
02160 {
02161         RT_CK_TREE(tp);
02162         RT_CK_PARTITION(pp);
02163 
02164         switch( tp->tr_op )  {
02165         case OP_NOP:
02166                 return -1;
02167 
02168         case OP_SOLID:
02169                 {
02170                         register struct soltab *seek_stp = tp->tr_a.tu_stp;
02171                         register struct seg **segpp;
02172                         for( BU_PTBL_FOR( segpp, (struct seg **), &pp->pt_seglist ) )  {
02173                                 if( (*segpp)->seg_stp != seek_stp )  continue;
02174                                 return (*segpp)->seg_in.hit_rayp->index;
02175                         }
02176                 }
02177                 /* Maybe it hasn't been shot yet, or ray missed */
02178                 return -1;
02179 
02180         case OP_NOT:
02181                 return rt_tree_max_raynum( tp->tr_b.tb_left, pp );
02182 
02183         case OP_UNION:
02184         case OP_INTERSECT:
02185         case OP_SUBTRACT:
02186         case OP_XOR:
02187                 {
02188                         int a = rt_tree_max_raynum( tp->tr_b.tb_left, pp );
02189                         int b = rt_tree_max_raynum( tp->tr_b.tb_right, pp );
02190                         if( a > b )  return a;
02191                         return b;
02192                 }
02193         default:
02194                 bu_bomb("rt_tree_max_raynum: bad op\n");
02195         }
02196         return 0;
02197 }
02198 
02199 /*
02200  * XXX This routine seems to free things more than once.
02201  * For a temporary measure, don't free things.
02202  */
02203 void
02204 rt_rebuild_overlaps(struct partition *PartHdp, struct application *ap, int rebuild_fastgen_plates_only)
02205 {
02206         struct partition        *pp, *next, *curr;
02207         struct region           *pp_reg;
02208         struct partition        *pp_open;
02209         struct bu_ptbl          open_parts;
02210         int                     i, j;
02211 
02212 /* rt_pr_partitions( ap->a_rt_i, PartHdp, "In rt_rebuild_overlaps:" ); */
02213 
02214         RT_CK_PT_HD(PartHdp);
02215         RT_CK_AP(ap);
02216 
02217         bu_ptbl_init( &open_parts, 0, "Open partitions" );
02218 
02219         pp = PartHdp->pt_forw;
02220         while( pp != PartHdp )
02221         {
02222                 RT_CK_PARTITION(pp);
02223                 next = pp->pt_forw;
02224 
02225                 if( rebuild_fastgen_plates_only && pp->pt_regionp->reg_is_fastgen != REGION_FASTGEN_PLATE )
02226                 {
02227                         bu_ptbl_trunc( &open_parts, 0 );
02228                         pp = next;
02229                         continue;
02230                 }
02231 
02232                 for( i=0 ; i<BU_PTBL_END( &open_parts ) ; i++ )
02233                 {
02234                         int keep_open=0;
02235 
02236                         if( !pp )
02237                                 break;
02238 
02239                         pp_open = (struct partition *)BU_PTBL_GET( &open_parts, i );
02240                         if( !pp_open )
02241                                 continue;
02242                         RT_CK_PARTITION(pp_open);
02243 
02244                         if( pp->pt_overlap_reg )
02245                         {
02246                                 j = -1;
02247                                 while( (pp_reg = pp->pt_overlap_reg[++j]) )
02248                                 {
02249                                         if( pp_reg == (struct region *)(-1) )
02250                                                 continue;
02251                                         RT_CK_REGION(pp_reg);
02252 
02253                                         if( pp_reg == pp_open->pt_regionp )
02254                                         {
02255                                                 /* add this partition to pp_open */
02256                                                 pp_open->pt_outseg = pp->pt_outseg;
02257                                                 pp_open->pt_outhit = pp->pt_outhit;
02258                                                 pp_open->pt_outflip = pp->pt_outflip;
02259                                                 bu_ptbl_cat_uniq( &pp_open->pt_seglist, &pp->pt_seglist );
02260 
02261                                                 /* mark it as used */
02262                                                 pp->pt_overlap_reg[j] = (struct region *)(-1);
02263                                                 if( pp_reg == pp->pt_regionp )
02264                                                         pp->pt_regionp = (struct region *)NULL;
02265 
02266                                                 /* keep pp_open open */
02267                                                 keep_open = 1;
02268                                         }
02269                                 }
02270                         }
02271                         else
02272                         {
02273                                 if( pp->pt_regionp == pp_open->pt_regionp && pp->pt_inhit->hit_dist <= pp_open->pt_outhit->hit_dist )
02274                                 {
02275                                         /* add this partition to pp_open */
02276                                         pp_open->pt_outseg = pp->pt_outseg;
02277                                         pp_open->pt_outhit = pp->pt_outhit;
02278                                         pp_open->pt_outflip = pp->pt_outflip;
02279                                         bu_ptbl_cat_uniq( &pp_open->pt_seglist, &pp->pt_seglist );
02280 
02281                                         /* eliminate this partition */
02282                                         BU_LIST_DEQUEUE( (struct bu_list *)pp )
02283                                         pp->pt_overlap_reg = NULL;      /* sanity */
02284 #if 0
02285                                         FREE_PT( pp, ap->a_resource )
02286 #endif
02287                                         pp = (struct partition *)NULL;
02288 
02289                                         /* keep pp_open open */
02290                                         keep_open = 1;
02291                                 }
02292                         }
02293 
02294                         if( !keep_open )
02295                         {
02296                                 BU_PTBL_CLEAR_I( &open_parts, i );
02297                         }
02298                 }
02299 
02300                 /* if all region claims have been removed, eliminate the partition */
02301                 if( pp && pp->pt_overlap_reg )
02302                 {
02303                         int reg_count=0;
02304 
02305                         /* count remaining region claims */
02306                         j = -1;
02307                         while( (pp_reg = pp->pt_overlap_reg[++j]) )
02308                                 if( pp_reg != (struct region *)(-1) )  {
02309                                         RT_CK_REGION(pp_reg);
02310                                         reg_count++;
02311                                 }
02312 
02313                         if( !reg_count )
02314                         {
02315                                 BU_LIST_DEQUEUE( (struct bu_list *)pp )
02316                                 bu_free( (char *)pp->pt_overlap_reg, "overlap list" );
02317                                 pp->pt_overlap_reg = NULL;      /* sanity */
02318 #if 0
02319                                 FREE_PT( pp, ap->a_resource )
02320 #endif
02321                                 pp = (struct partition *)NULL;
02322                         }
02323                 }
02324 
02325                 /* any remaining region claims must produce new partitions */
02326                 if( pp )
02327                 {
02328                         if( pp->pt_overlap_reg )
02329                         {
02330                                 j = -1;
02331                                 curr = pp;
02332                                 while( (pp_reg = pp->pt_overlap_reg[++j]) )
02333                                 {
02334                                         struct partition *new_pp;
02335 
02336                                         if( pp_reg == (struct region *)(-1) )
02337                                                 continue;
02338                                         RT_CK_REGION(pp_reg);
02339 
02340                                         if( rebuild_fastgen_plates_only &&
02341                                                 pp_reg->reg_is_fastgen != REGION_FASTGEN_PLATE )
02342                                                         continue;
02343 
02344                                         /* if the original partition is available, just use it */
02345                                         if( !pp->pt_regionp || pp->pt_regionp == pp_reg )
02346                                         {
02347                                                 pp->pt_regionp = pp_reg;
02348                                                 bu_ptbl_ins( &open_parts, (long *)pp );
02349                                         }
02350                                         else
02351                                         {
02352                                                 /* create a new partition, link it to the end of the current pp,
02353                                                  * and add it to the open list */
02354                                                 RT_DUP_PT( ap->a_rt_i, new_pp, pp, ap->a_resource )
02355                                                 new_pp->pt_regionp = pp_reg;
02356                                                 new_pp->pt_overlap_reg = (struct region **)NULL;
02357                                                 BU_LIST_APPEND( (struct bu_list *)curr, (struct bu_list *)new_pp )
02358                                                 bu_ptbl_ins( &open_parts, (long *)new_pp );
02359                                                 curr = new_pp;
02360                                         }
02361                                 }
02362                         }
02363                         else
02364                         {
02365                                 if( rebuild_fastgen_plates_only )
02366                                 {
02367                                         if( pp->pt_regionp->reg_is_fastgen == REGION_FASTGEN_PLATE )
02368                                         {
02369                                                 bu_ptbl_ins( &open_parts, (long *)pp );
02370                                         }
02371                                 }
02372                                 else
02373                                 {
02374                                         bu_ptbl_ins( &open_parts, (long *)pp );
02375                                 }
02376                         }
02377                         if( pp->pt_overlap_reg )
02378                         {
02379                                 bu_free( (char *)pp->pt_overlap_reg, "overlap list" );
02380                                 pp->pt_overlap_reg = (struct region **)NULL;
02381                         }
02382                 }
02383                 pp = next;
02384         }
02385 
02386         bu_ptbl_free( &open_parts );
02387 
02388 /* rt_pr_partitions( ap->a_rt_i, PartHdp, "partitions at end of rt_rebuild_overlaps:" ); */
02389 
02390 }
02391 
02392 /*
02393  * Local Variables:
02394  * mode: C
02395  * tab-width: 8
02396  * c-basic-offset: 4
02397  * indent-tabs-mode: t
02398  * End:
02399  * ex: shiftwidth=4 tabstop=8
02400  */

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