kdtree.h
Go to the documentation of this file.
1 /*
2 This file is part of the Ristra portage project.
3 Please see the license file at the root of this repository, or at:
4  https://github.com/laristra/portage/blob/master/LICENSE
5 */
6 
7 /* -----------------------------------------------------------------------------
8 ** INCLUDES/KDTREE.H
9  **
10  ** Contains data structures and prototypes for manipulating polygon data.
11  ** ----------------------------------------------------------------------------
12  */
13 #ifndef PORTAGE_SEARCH_KDTREE_H_
14 #define PORTAGE_SEARCH_KDTREE_H_
15 
16 #include <vector>
17 #include <set>
18 #include <cstdlib>
19 
22 #include "wonton/support/Point.h"
23 
24 namespace Portage {
25 
26 using Wonton::Point;
27 using Wonton::Vector;
28 
29 #define SWAP(a, b, type) { \
30  type c_ = b; \
31  b = a; \
32  a = c_; \
33 }
34 
40 template<int D> struct KDTree {
41 
43  KDTree() {
44  num_entities = 0;
45  linkp = NULL;
46  sbox = NULL;
47  }
49  ~KDTree() {
50  if(linkp) {
51  delete [] linkp;
52  }
53  if(sbox) {
54  delete [] sbox;
55  }
56  }
57  size_t num_entities;
58  int *linkp;
60 };
61 
62 
64 /* The create function for the KD-Tree */
66 template<int D>
68 
70 /* The median function for the KD-Tree */
72 template<int D>
73 void MedianSelect(int , int , double *, int *, int);
74 
75 template<int D>
76 void LocatePoint(const Point<D>& qp,
77  const KDTree<D>* kdtree,
78  std::vector<int>& pfound);
79 
80 template<int D>
81 void Intersect(const IsotheticBBox<D>& box,
82  const KDTree<D>* kdtree,
83  std::vector<int>& pfound);
84 
85 
86 /****************************************************************************/
87 /* File :MedianSelect.c */
88 /* */
89 /* Creation Date :April 20, 1996 */
90 /* */
91 /* Purpose :MedianSelect takes an int `k', a double array 'arr', */
92 /* and an int array `prm' of length `n' */
93 /* and reorders `prm' so that `arr[prm[k]]' is the k'th */
94 /* largest element in the set `{arr[prm[i]], i=1,..,n}', */
95 /* and we have in addition the partitioning properties: */
96 /* i<k ==> arr[prm[i]] <= arr[prm[k]] and */
97 /* i>k ==> arr[prm[i]] >= arr[prm[k]]. */
98 /* */
99 /* Note that setting `k=(1+n)/2', this subroutine */
100 /* computes the MEDIAN VALUE of `n' values in `arr', */
101 /* and it does this in Order(N) time. This is thus a more */
102 /* efficient way of computing the median than a heap sort */
103 /* which is Order(NlogN). */
104 /* */
105 /****************************************************************************/
106 
107 template<int D> void MedianSelect (int k,
108  int n,
109  std::vector<Point<D> >& arr,
110  int *prm,
111  int icut)
112 {
113  int i, j, r, l, mid, ia;
114 
115  l = 0;
116  r = n-1;
117 
118  while ( r-l > 1 ) {
119 
120  mid = (l+r)/2;
121  SWAP(prm[mid], prm[l+1], int);
122 
123  if (arr[prm[l+1]][icut] > arr[prm[r]][icut]) {
124  SWAP(prm[l+1], prm[r], int);
125  }
126 
127  if (arr[prm[l]][icut] > arr[prm[r]][icut]) {
128  SWAP(prm[l], prm[r], int);
129  }
130 
131  if (arr[prm[l+1]][icut] > arr[prm[l]][icut]) {
132  SWAP(prm[l+1], prm[l], int);
133  }
134 
135  i = l + 1;
136  j = r;
137  ia = prm[l];
138 
139  i++;
140  while ( arr[prm[i]][icut] < arr[ia][icut] ) i++;
141 
142  j--;
143  while ( arr[prm[j]][icut] > arr[ia][icut] ) j--;
144 
145  while ( j >= i ) {
146  SWAP(prm[i], prm[j], int);
147 
148  i++;
149  while ( arr[prm[i]][icut] < arr[ia][icut] ) i++;
150 
151  j--;
152  while ( arr[prm[j]][icut] > arr[ia][icut] ) j--;
153  }
154 
155  prm[l] = prm[j];
156  prm[j] = ia;
157 
158  if (j >= k) r = j - 1;
159  if (j <= k) l = i;
160  }
161 
162  if ( (r-l == 1) && (arr[prm[r]][icut] < arr[prm[l]][icut]) ) {
163  SWAP(prm[l], prm[r], int);
164  }
165 
166 }
167 
168 
169 
170 
171 /****************************************************************************/
172 /* File :kdtree.c */
173 /* */
174 /* Creation Date :April 20, 1996 */
175 /* */
176 /* MODIFIED: 15 March, 2001 */
177 /* */
178 /* Purpose :KDTREE takes the set of Safety Boxes and */
179 /* produces a k-D tree that is stored in the array LINKP. */
180 /* Leaf nodes in LINKP each coincide with exactly one */
181 /* Safety Box. For each node in the k-D tree, */
182 /* there is a corresponding Safety Box which is just */
183 /* big enough to contain all the Safety Boxes ``under'' */
184 /* the node. */
185 /* */
186 /****************************************************************************/
187 
188 template <int D>
190 {
191  KDTree<D> *kdtree;
192  std::vector<Point<D> > bbc;
193  int *ipoly = NULL;
194  int i;
195  int node, nextp, itop;
196  int imn, imx, icut, imd;
197  int icrstack[100], imin[100], imax[100];
198  int ict[100];
199  Vector<D> dim;
200 
201 
202  if( sboxp.empty()) std::abort();
203  else {
204 
205  kdtree = new KDTree<D>;
206 
207  /* Obtain allocations for arrays */
208  int const sboxp_size = sboxp.size();
209  kdtree->num_entities = sboxp_size;
210  ipoly = new int[sboxp_size];
211  kdtree->sbox = new IsotheticBBox<D>[2*sboxp_size];
212  kdtree->linkp = new int[2*sboxp_size];
213  bbc.resize(sboxp_size);
214 
215  for (i = 0; i < sboxp_size; i++) {
216 
217  /* Compute the centers of the bounding boxes */
218  bbc[i] = sboxp[i].center();
219 
220  /* Compute the root node of the k-D tree */
221  kdtree->sbox[0].add(sboxp[i]);
222  }
223 
224  /* If there is only one safety box, the root node is a leaf.
225  (Our convention is to set the link corresponding to a leaf
226  equal to the negative of the unique item contained in
227  that leaf.) If the root is a leaf, our work is done. */
228 
229  if (sboxp_size == 1 ) kdtree->linkp[0] = 0;
230  else
231  {
232  /* dimx, dimy, dimz are equal to the x, y, and z dimensions
233  of the bounding box corresponding to the current node
234  under consideration. */
235 
236  dim = kdtree->sbox[0].getMax() - kdtree->sbox[0].getMin();
237 
238 
239  /* ipoly will contain a permutation of the integers
240  {0,...,sboxp.size()-1}. This permutation will be altered as we
241  create our balanced binary tree. nextp contains the
242  address of the next available node to be filled. */
243 
244  nextp = 1;
245  for (i = 0; i < sboxp_size; i++) ipoly[i] = i;
246 
247  /* Use a stack to create the tree. Put the root node
248  ``0'' on the top of the stack (icrstack). The array
249  subset of ipoly (i.e., subset of boxes associated
250  with this node) is recorded using the arrays
251  imin and imax. */
252 
253  itop = 0;
254  icrstack[itop] = 0;
255  imin[itop] = 0;
256  imax[itop] = sboxp.size()-1;
257 
258  /* Finally, we record in ict the appropriate ``cutting
259  direction'' for bisecting the set of safety boxes
260  corresponding to this node. This direction is either
261  the x, y, or z directions, depending on which dimension
262  of the bounding box is largest. */
263 
264  MaxComponent(dim,ict[itop]);
265 
266  /* Pop nodes off stack, create children nodes and put them
267  on stack. Continue until k-D tree has been created. */
268 
269  while ( itop >= 0) {
270 
271  /* Pop top node off stack. */
272 
273  node = icrstack[itop];
274 
275  /* Make this node point to next available node location (nextp).
276  This link represents the location of the FIRST CHILD
277  of the node. The adjacent location (nextp+1)
278  is implicitly taken to be the location of the SECOND
279  child of the node. */
280 
281  kdtree->linkp[node] = nextp;
282  imn = imin[itop];
283  imx = imax[itop];
284  icut = ict[itop];
285  itop--;
286 
287  /* Partition safety box subset associated with this node.
288  Using the appropriate cutting direction, use SELECT to
289  reorder (ipoly) so that the safety box with median bounding
290  box center coordinate is ipoly(imd), while the
291  boxes {ipoly[i], i<imd} have SMALLER (or equal)
292  bounding box coordinates, and the boxes with
293  {ipoly[i], i>imd} have GREATER (or equal) bounding box
294  coordinates. */
295 
296  imd = (imn+imx)/2;
297 
298  MedianSelect(imd-imn+1,imx-imn+1,bbc,&(ipoly[imn]),icut);
299 
300  /* If the first child's subset of safety boxes is a singleton,
301  the child is a leaf. Set the child's link to point to the
302  negative of the box number. Set the child's bounding
303  box to be equal to the safety box box. */
304 
305  if (imn == imd) {
306  kdtree->linkp[nextp]= -ipoly[imn];
307  kdtree->sbox[nextp] = sboxp[ipoly[imn]];
308  nextp = nextp+1;
309  }
310  else {
311 
312  /* In this case, the subset of safety boxes corres to the
313  first child is more than one, and the child is
314  not a leaf. Compute the bounding box of this child to
315  be the smallest box containing all the associated safety'
316  boxes. */
317 
318  kdtree->sbox[nextp] = sboxp[ipoly[imn]];
319 
320  for (i=imn+1; i<=imd; i++)
321  kdtree->sbox[nextp].add(sboxp[ipoly[i]]);
322 
323  /* Put the first child onto the stack, noting the
324  associated triangle subset in imin and imax, and
325  putting the appropriate cutting direction in ict. */
326 
327  dim = kdtree->sbox[nextp].getMax()
328  - kdtree->sbox[nextp].getMin();
329 
330  itop++;
331  icrstack[itop] = nextp;
332  imin[itop] = imn;
333  imax[itop] = imd;
334 
335  MaxComponent(dim,ict[itop]);
336  nextp++;
337  }
338 
339  /* If the second child's subset of safety boxes is a singleton,
340  the child is a leaf. Set the child's link to point to the
341  negative of the sbox number. Set the child's bounding
342  box to be equal to that of the safety box. */
343 
344  if ((imd+1) == imx) {
345  kdtree->linkp[nextp] = -ipoly[imx];
346  kdtree->sbox[nextp] = sboxp[ipoly[imx]];
347  nextp = nextp+1;
348  }
349  else {
350 
351  /* In this case, the subset of boxes corresponding to the
352  second child is more than one safety box, and the child is
353  not a leaf. Compute the bounding box of this child to
354  be the smallest box containing all the associated safety
355  boxes. */
356 
357  kdtree->sbox[nextp] = sboxp[ipoly[imd+1]];
358 
359  for (i=imd+2; i<=imx; i++)
360  kdtree->sbox[nextp].add(sboxp[ipoly[i]]);
361 
362  /* Put the second child onto the stack, noting the
363  associated triangle subset in imin and imax, and
364  putting the appropriate cutting direction in ict. */
365 
366  dim = kdtree->sbox[nextp].getMax()
367  - kdtree->sbox[nextp].getMin();
368 
369  itop++;
370  icrstack[itop] = nextp;
371  imin[itop] = imd+1;
372  imax[itop] = imx;
373 
374  MaxComponent(dim,ict[itop]);
375  nextp++;
376  }
377 
378  } /* End of the while loop */
379 
380  delete [] ipoly;
381  }
382  }
383 
384  return kdtree;
385 }
386 
387 
388 
389 // Return a list of BBox id's containing the query point
390 template<int D>
391 void LocatePoint(const Point<D>& qp,
392  const KDTree<D>* kdtree,
393  std::vector<int>& pfound)
394 {
395  pfound.clear();
396  int itop, node, ind, j;
397  int istack[100];
398 
399  /* If root node is a leaf, return leaf. */
400 
401  if (kdtree->linkp[0] <= 0) {
402  if (kdtree->sbox[0].intersect(qp))
403  pfound.push_back(-kdtree->linkp[0]);
404  }
405  else {
406  itop = 0;
407  istack[itop] = 0;
408 
409  /* Traverse (relevant part of) k-D tree using stack. */
410 
411  while (itop >= 0) {
412 
413  /* pop node off of stack. */
414  node = istack[itop]; itop--;
415 
416  ind = kdtree->linkp[node];
417 
418  /* check if either child of NODE is a leaf or should be
419  put on stack. */
420  for (j=0; j<=1; j++) {
421  if (kdtree->sbox[ind+j].intersect(qp)) {
422  /* If child is a leaf, add to the list. */
423  if (kdtree->linkp[ind+j] <= 0) {
424  pfound.push_back(-kdtree->linkp[ind+j]);
425  }
426  else {
427  itop++;
428  istack[itop] = ind+j;
429  }
430  }
431  }
432  }
433  }
434 }
435 
436 // Return a list (pfound) of BBox ids in the tree (kdtree) that overlap the
437 // given BBox (box)
438 template<int D>
439 void Intersect(const IsotheticBBox<D>& box,
440  const KDTree<D>* kdtree,
441  std::vector<int>& pfound)
442 {
443  pfound.clear();
444  int itop, node, ind, j;
445  int istack[100];
446 
447  /* If root node is a leaf, return leaf. */
448  if (kdtree->linkp[0] <= 0) {
449  if (kdtree->sbox[0].intersect(box))
450  pfound.push_back(-kdtree->linkp[0]);
451  }
452  else {
453  itop = 0;
454  istack[itop] = 0;
455 
456  /* Traverse (relevant part of) k-D tree using stack. */
457  while (itop >= 0) {
458 
459  /* pop node off of stack. */
460  node = istack[itop]; itop--;
461 
462  ind = kdtree->linkp[node];
463 
464  /* check if either child of NODE is a leaf or should be
465  put on stack. */
466  for (j=0; j<=1; j++) {
467  if (kdtree->sbox[ind+j].intersect(box)) {
468 
469  /* If child is a leaf, add to the list. */
470  if (kdtree->linkp[ind+j] <= 0) {
471  pfound.push_back(-kdtree->linkp[ind+j]);
472  }
473  else {
474  itop++;
475  istack[itop] = ind+j;
476  }
477  }
478  }
479  }
480  }
481 }
482 
483 #undef SWAP
484 } // namespace Portage
485 
486 #endif // PORTAGE_SEARCH_KDTREE_H_
487 
~KDTree()
Default destructor.
Definition: kdtree.h:49
IsotheticBBox< D > * sbox
Definition: kdtree.h:59
std::vector< T > vector
Definition: portage.h:238
void LocatePoint(const Point< D > &qp, const KDTree< D > *kdtree, std::vector< int > &pfound)
Definition: kdtree.h:391
Definition: coredriver.h:42
size_t num_entities
Definition: kdtree.h:57
KDTree()
Default constructor.
Definition: kdtree.h:43
An N-dimensional k-d tree for manipulating polygon data.
Definition: kdtree.h:40
An isothetic (axis-aligned) N-dimensional bounding box.
Definition: BoundBox.h:46
void MedianSelect(int, int, double *, int *, int)
KDTree< D > * KDTreeCreate(const std::vector< IsotheticBBox< D > > &bbox)
Definition: kdtree.h:189
void Intersect(const IsotheticBBox< D > &box, const KDTree< D > *kdtree, std::vector< int > &pfound)
Definition: kdtree.h:439
#define SWAP(a, b, type)
Definition: kdtree.h:29
int * linkp
Definition: kdtree.h:58