cgma
KdTree.cpp
Go to the documentation of this file.
00001 /*
00002  *
00003  *
00004  * Copyright (C) 2004 Sandia Corporation.  Under the terms of Contract DE-AC04-94AL85000
00005  * with Sandia Corporation, the U.S. Government retains certain rights in this software.
00006  *
00007  * This file is part of facetbool--contact via [email protected]
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  *
00024  *
00025  */
00026 
00027 #include "KdTree.hpp"
00028 #include <stack>
00029 #include <vector>
00030 #include <math.h>
00031 
00032 const int XCUT = 0;
00033 const int YCUT = 1;
00034 const int ZCUT = 2;
00035 
00036 KDTree::KDTree()
00037 {
00038   epsilonkd = 1.e-6;
00039 }
00040 
00041 KDTree::~KDTree()
00042 {
00043 int i;
00044 FSBoundingBox* fsbb;
00045  for ( i = 0; i < 2*numtris-1; i++ ) {
00046     fsbb = treebox[i];
00047     delete fsbb;
00048   }
00049   delete [] treebox;
00050   delete [] nextbranch; 
00051 }
00052 
00053 int KDTree::makeKDTree(int npoly, const FSBOXVECTOR& boxlist)
00054 {
00055 double *xcenterdata, *ycenterdata, *zcenterdata, *whichcut[3], *cutarray; 
00056 int i, cuttingdir, min_tri_sequence_value, max_tri_sequence_value, 
00057     median_value;
00058 double xcen, ycen, zcen;
00059 std::vector<TreeStack* > mytreestack;
00060 int icnt;
00061 TreeStack *thistreestack;
00062 FSBoundingBox *thisbox;
00063 
00064   numtris = npoly;
00065   boxlistptr = boxlist;
00066   isequence = new int[npoly];
00067   xcenterdata = new double[npoly];
00068   ycenterdata = new double[npoly];
00069   zcenterdata = new double[npoly];
00070   nextbranch = new int[2*npoly];
00071   treebox = new FSBoundingBox*[2*npoly];
00072   
00073 //  Get the arrays of bounding box center points for x, y, and z.  We will use 
00074 //  these arrays to find the median values along each direction.
00075   for ( i = 0; i < npoly; i++ ) {
00076     isequence[i] = i;
00077     xcen = 0.5*(boxlist[i]->xmin + boxlist[i]->xmax);
00078     ycen = 0.5*(boxlist[i]->ymin + boxlist[i]->ymax);
00079     zcen = 0.5*(boxlist[i]->zmin + boxlist[i]->zmax);
00080     xcenterdata[i] = xcen;
00081     ycenterdata[i] = ycen;
00082     zcenterdata[i] = zcen;  
00083   }
00084   whichcut[0] = xcenterdata; whichcut[1] = ycenterdata; whichcut[2] = zcenterdata;
00085   
00086   //  Get the bounding box of the root node -- the entire set of bounding boxes.
00087   thisbox = getbox(0,npoly-1);
00088   icnt = 0;
00089   treebox[icnt] = thisbox;
00090   nextbranch[icnt] = icnt;
00091    
00092   max_tri_sequence_value = npoly-1;
00093   min_tri_sequence_value = 0;
00094  
00095   if ( max_tri_sequence_value == 0 ) return 1;  //  Just one triangle in the data set.
00096 
00097   //  Get the cutting direction for the next branch.  
00098   cuttingdir = getcuttingdirection(thisbox); 
00099      
00100   thistreestack = new TreeStack(min_tri_sequence_value,
00101                                        max_tri_sequence_value,
00102                        cuttingdir,icnt);
00103   icnt++;                                         
00104   mytreestack.push_back(thistreestack);
00105     
00106   while ( mytreestack.size() > 0 ) {
00107     TreeStack* thisone = mytreestack[mytreestack.size()-1];
00108     mytreestack.pop_back();
00109     cuttingdir = thisone->cuttingdir;
00110     min_tri_sequence_value = thisone->min;
00111     max_tri_sequence_value = thisone->max;
00112 
00113 
00114     median_value = (min_tri_sequence_value + max_tri_sequence_value)/2;
00115     cutarray = whichcut[cuttingdir];
00116     
00117     find_the_median(median_value-min_tri_sequence_value,0,
00118                     max_tri_sequence_value-min_tri_sequence_value,
00119                     cutarray,&isequence[min_tri_sequence_value]);
00120     if ( min_tri_sequence_value == median_value ) {  //  This is a leaf.
00121 //      FSBoundingBox *thisbox = boxlist[isequence[median_value]];
00122       thisbox = new FSBoundingBox(
00123                              boxlist[isequence[median_value]]->xmin,
00124                  boxlist[isequence[median_value]]->ymin, 
00125                              boxlist[isequence[median_value]]->zmin,
00126                  boxlist[isequence[median_value]]->xmax,
00127                  boxlist[isequence[median_value]]->ymax,
00128                  boxlist[isequence[median_value]]->zmax);
00129 
00130 
00131       treebox[icnt] = thisbox;
00132       nextbranch[icnt] = -isequence[median_value];
00133       nextbranch[thisone->sequence] = icnt;
00134       icnt++;
00135     } else {
00136       thisbox = getbox(min_tri_sequence_value,median_value);
00137         nextbranch[thisone->sequence] = icnt;
00138       treebox[icnt] = thisbox;
00139 //      nextbranch[icnt] = 11111;
00140       cuttingdir = getcuttingdirection(thisbox);
00141 
00142       thistreestack = new TreeStack(min_tri_sequence_value,
00143                                        median_value,cuttingdir,icnt);
00144       icnt++;                                    
00145       mytreestack.push_back(thistreestack);
00146     } 
00147     //  The delete that follows is because we need to delete items that
00148     //  were created and placed on mytreestack.  This one comes from the pop()
00149     
00150     delete thisone;
00151     
00152     if ( median_value+1 == max_tri_sequence_value ) {  //  This is a leaf.
00153 //      FSBoundingBox *thisbox = boxlist[isequence[max_tri_sequence_value]];
00154       thisbox = new FSBoundingBox(
00155                              boxlist[isequence[max_tri_sequence_value]]->xmin,
00156                  boxlist[isequence[max_tri_sequence_value]]->ymin, 
00157                              boxlist[isequence[max_tri_sequence_value]]->zmin,
00158                  boxlist[isequence[max_tri_sequence_value]]->xmax,
00159                  boxlist[isequence[max_tri_sequence_value]]->ymax,
00160                  boxlist[isequence[max_tri_sequence_value]]->zmax);
00161 
00162 
00163       treebox[icnt] = thisbox;
00164       nextbranch[icnt] = -isequence[max_tri_sequence_value];
00165       icnt++;
00166     } else {
00167       thisbox = getbox(median_value+1,max_tri_sequence_value);
00168       treebox[icnt] = thisbox;
00169 //      nextbranch[icnt] = 22222;
00170       cuttingdir = getcuttingdirection(thisbox);
00171       thistreestack = new TreeStack(median_value+1,
00172                                        max_tri_sequence_value,
00173                        cuttingdir,icnt);
00174       icnt++;                                     
00175       mytreestack.push_back(thistreestack);    
00176     }     
00177 
00178   } 
00179  
00180   delete [] isequence;
00181   delete [] xcenterdata;
00182   delete [] ycenterdata;
00183   delete [] zcenterdata;
00184    
00185   return 1;
00186 }
00187 
00188 FSBoundingBox* KDTree::getbox(int min, int max)
00189 {
00190 FSBoundingBox *thisbox;
00191 int i;
00192 //  Makes a bounding box and sets its size to include all of the boxes in the
00193 //  sequence of bounding boxes from min to max of index isequence[].  Returns pointer
00194 //  to this box.
00195 
00196   thisbox = new FSBoundingBox(1.e20,1.e20,1.e20,-1.e20,-1.e20,-1.e20);
00197 double xmin, ymin, zmin, xmax, ymax, zmax;
00198   
00199   for ( i = min; i <= max; i++ ) {
00200     xmin = boxlistptr[isequence[i]]->xmin;
00201     ymin = boxlistptr[isequence[i]]->ymin;
00202     zmin = boxlistptr[isequence[i]]->zmin;
00203     xmax = boxlistptr[isequence[i]]->xmax;
00204     ymax = boxlistptr[isequence[i]]->ymax;
00205     zmax = boxlistptr[isequence[i]]->zmax;
00206 
00207     if ( xmin < thisbox->xmin ) thisbox->xmin = xmin;
00208     if ( ymin < thisbox->ymin ) thisbox->ymin = ymin;
00209     if ( zmin < thisbox->zmin ) thisbox->zmin = zmin;    
00210     if ( xmax > thisbox->xmax ) thisbox->xmax = xmax;
00211     if ( ymax > thisbox->ymax ) thisbox->ymax = ymax;
00212     if ( zmax > thisbox->zmax ) thisbox->zmax = zmax;
00213      
00214   }
00215 
00216   return thisbox;
00217 }
00218 
00219 void KDTree::box_kdtree_intersect(FSBoundingBox& bbox, int *count, int *indexlist) const
00220 {
00221 int index, i, child;
00222 std::stack<int> mystack;
00223 
00224   *count = 0;
00225   if ( (bbox.xmax < (treebox[0]->xmin - epsilonkd) ) ||
00226        (bbox.xmin > (treebox[0]->xmax + epsilonkd) ) ||
00227        (bbox.ymax < (treebox[0]->ymin - epsilonkd) ) ||
00228        (bbox.ymin > (treebox[0]->ymax + epsilonkd) ) ||
00229        (bbox.zmax < (treebox[0]->zmin - epsilonkd) ) ||
00230        (bbox.zmin > (treebox[0]->zmax + epsilonkd) ) )
00231     return;
00232   //  Gotta put something on the stack, so do the root node 
00233   //  evaluation here.
00234   if ( nextbranch[0] <= 0 ) {
00235     indexlist[*count] = -nextbranch[0]; *count += 1;
00236     return;
00237   }
00238   mystack.push(0);
00239 
00240   while ( mystack.size() > 0 ) {
00241     index = mystack.top();
00242     mystack.pop();
00243     child = nextbranch[index];
00244     
00245     for ( i = 0; i < 2; i++ ) {
00246       if ( (bbox.xmax < (treebox[child+i]->xmin - epsilonkd) ) ||
00247            (bbox.xmin > (treebox[child+i]->xmax + epsilonkd) ) ||
00248            (bbox.ymax < (treebox[child+i]->ymin - epsilonkd) ) ||
00249            (bbox.ymin > (treebox[child+i]->ymax + epsilonkd) ) ||
00250            (bbox.zmax < (treebox[child+i]->zmin - epsilonkd) ) ||
00251            (bbox.zmin > (treebox[child+i]->zmax + epsilonkd) ) )
00252       continue;
00253       if ( nextbranch[child+i] <= 0 ) {        
00254         indexlist[*count] = -nextbranch[child+i]; *count += 1;  
00255       } else {            
00256         mystack.push(child+i);   
00257       }  
00258     }
00259   }  
00260   return;
00261 }
00262 
00263 
00264 void KDTree::find_the_median(int k, int l, int r, double *array, int *ia)
00265 {
00266 int i, j;
00267 double t;
00268 
00269   while ( r > l ) {
00270     t = array[ia[k]];
00271     i = l;
00272     j = r;
00273 
00274     SWAP(ia[l],ia[k]);
00275     if ( array[ia[r]] > t ) SWAP(ia[l],ia[r]);
00276     while ( i < j ) {
00277       SWAP(ia[i],ia[j]);
00278       i += 1; j -= 1;
00279       while ( array[ia[i]] < t ) i++;
00280       while ( array[ia[j]] > t ) j--;
00281     }
00282     if ( array[ia[l]] == t ) SWAP(ia[l],ia[j]);
00283     else {
00284       j += 1;
00285       SWAP(ia[r],ia[j]);
00286     }
00287     if ( j <= k ) l = j + 1;
00288     if ( k <= j ) r = j - 1;
00289   }
00290 
00291 }
00292 
00293 int KDTree::getcuttingdirection(FSBoundingBox* box)
00294 {
00295 double xlen, ylen, zlen;
00296 
00297   xlen = box->xmax - box->xmin;
00298   ylen = box->ymax - box->ymin;
00299   zlen = box->zmax - box->zmin;
00300   
00301   if ( (xlen >= ylen) && (xlen >= zlen) ) return XCUT; 
00302   else if ( ylen >= zlen ) return YCUT;
00303   else return ZCUT;
00304 }
00305 
00306 
00307 bool KDTree::rayintersectsbox(FSBoundingBox *box)
00308 {
00309 double pmin, pmax, tmin, tmax;
00310 double dtemp;
00311 
00312 //  Get the parametric distance along each direction from the min point to
00313 //  the min and max box planes.  If the min dist is grater than the max
00314 //  dist, we have to swap them.  Keep a running total of the max min and the
00315 //  min max.  The ray intersects the box iff tmin <= tmax and tmax >= 0.0.
00316 //  Otherwise, the ray misses the box or points away from the box (with the
00317 //  starting point outside).
00318 
00319   tmin = (box->xmin - rayxstart)/dx;
00320   tmax = (box->xmax - rayxstart)/dx;
00321   if ( tmin > tmax ) {
00322   dtemp = tmin; tmin = tmax; tmax = dtemp;
00323   }
00324   pmin = (box->ymin - rayystart)/dy;
00325   pmax = (box->ymax - rayystart)/dy;
00326   if ( pmin > pmax ) {
00327   dtemp = pmin; pmin = pmax; pmax = dtemp;
00328   }
00329   tmin = MAXX(pmin,tmin);
00330   tmax = MINN(pmax,tmax);
00331 
00332   if ( tmin > tmax ) return false;
00333   
00334   pmin = (box->zmin - rayzstart)/dz;
00335   pmax = (box->zmax - rayzstart)/dz;
00336   if ( pmin > pmax ) {
00337   dtemp = pmin; pmin = pmax; pmax = dtemp;
00338   }
00339   tmin = MAXX(pmin,tmin);
00340   tmax = MINN(pmax,tmax);
00341   
00342   if ( (tmax < 0.0) || (tmin > tmax) ) return false;
00343   
00344   return true;
00345 }
00346   
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines