Mitsuba Renderer  0.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
kdtree.h
Go to the documentation of this file.
1 /*
2  This file is part of Mitsuba, a physically based rendering system.
3 
4  Copyright (c) 2007-2014 by Wenzel Jakob and others.
5 
6  Mitsuba is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Mitsuba is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #if !defined(__MITSUBA_CORE_KDTREE_H_)
21 #define __MITSUBA_CORE_KDTREE_H_
22 
23 #include <mitsuba/core/aabb.h>
24 #include <mitsuba/core/timer.h>
25 
27 
28 /**
29  * \brief Simple kd-tree node for use with \ref PointKDTree.
30  *
31  * This class is an example of how one might write a space-efficient kd-tree
32  * node that is compatible with the \ref PointKDTree class. The implementation
33  * supports associating a custom data record with each node and works up to
34  * 16 dimensions.
35  *
36  * \tparam _PointType Underlying point data type (e.g. \ref TPoint3<float>)
37  * \tparam _DataRecord Custom storage that should be associated with each
38  * tree node
39  *
40  * \ingroup libcore
41  * \sa PointKDTree
42  * \sa LeftBalancedKDNode
43  */
44 template <typename _PointType, typename _DataRecord> struct SimpleKDNode {
45  typedef _PointType PointType;
46  typedef _DataRecord DataRecord;
48  typedef typename PointType::Scalar Scalar;
49 
50  enum {
51  ELeafFlag = 0x10,
52  EAxisMask = 0x0F
53  };
54 
55  static const bool leftBalancedLayout = false;
56 
61 
62  /// Initialize a KD-tree node
63  inline SimpleKDNode() : position((Scalar) 0),
64  right(0), data(), flags(0) { }
65  /// Initialize a KD-tree node with the given data record
66  inline SimpleKDNode(const DataRecord &data) : position((Scalar) 0),
67  right(0), data(data), flags(0) { }
68 
69  /// Given the current node's index, return the index of the right child
70  inline IndexType getRightIndex(IndexType self) const { return right; }
71  /// Given the current node's index, set the right child index
72  inline void setRightIndex(IndexType self, IndexType value) { right = value; }
73 
74  /// Given the current node's index, return the index of the left child
75  inline IndexType getLeftIndex(IndexType self) const { return self + 1; }
76  /// Given the current node's index, set the left child index
77  inline void setLeftIndex(IndexType self, IndexType value) {
78  #if defined(MTS_DEBUG)
79  if (value != self+1)
80  SLog(EError, "SimpleKDNode::setLeftIndex(): Internal error!");
81  #endif
82  }
83 
84  /// Check whether this is a leaf node
85  inline bool isLeaf() const { return flags & (uint8_t) ELeafFlag; }
86  /// Specify whether this is a leaf node
87  inline void setLeaf(bool value) {
88  if (value)
89  flags |= (uint8_t) ELeafFlag;
90  else
91  flags &= (uint8_t) ~ELeafFlag;
92  }
93 
94  /// Return the split axis associated with this node
95  inline uint16_t getAxis() const { return flags & (uint8_t) EAxisMask; }
96  /// Set the split flags associated with this node
97  inline void setAxis(uint8_t axis) { flags = (flags & (uint8_t) ~EAxisMask) | axis; }
98 
99  /// Return the position associated with this node
100  inline const PointType &getPosition() const { return position; }
101  /// Set the position associated with this node
102  inline void setPosition(const PointType &value) { position = value; }
103 
104  /// Return the data record associated with this node
105  inline DataRecord &getData() { return data; }
106  /// Return the data record associated with this node (const version)
107  inline const DataRecord &getData() const { return data; }
108  /// Set the data record associated with this node
109  inline void setData(const DataRecord &val) { data = val; }
110 };
111 
112 /**
113  * \brief Left-balanced kd-tree node for use with \ref PointKDTree.
114  *
115  * This class provides a basic kd-tree node layout that can be used with
116  * the \ref PointKDTree class and the \ref PointKDTree::ELeftBalanced
117  * tree construction heuristic. The advantage of a left-balanced tree is
118  * that there is no need to store node pointers within nodes.
119  *
120  * \tparam _PointType Underlying point data type (e.g. \ref TPoint3<float>)
121  * \tparam _DataRecord Custom storage that should be associated with each
122  * tree node
123  *
124  * \ingroup libcore
125  * \sa PointKDTree
126  * \sa SimpleKDNode
127  */
128 template <typename _PointType, typename _DataRecord> struct LeftBalancedKDNode {
129  typedef _PointType PointType;
130  typedef _DataRecord DataRecord;
132  typedef typename PointType::Scalar Scalar;
133 
134  enum {
135  ELeafFlag = 0x10,
136  EAxisMask = 0x0F
137  };
138 
139  static const bool leftBalancedLayout = true;
140 
144 
145  /// Initialize a KD-tree node
146  inline LeftBalancedKDNode() : position((Scalar) 0), data(), flags(0) { }
147  /// Initialize a KD-tree node with the given data record
148  inline LeftBalancedKDNode(const DataRecord &data) : position((Scalar) 0),
149  data(data), flags(0) { }
150 
151  /// Given the current node's index, return the index of the left child
152  inline IndexType getLeftIndex(IndexType self) const { return 2 * self + 1; }
153  /// Given the current node's index, set the left child index
154  inline void setLeftIndex(IndexType self, IndexType value) {
155  #if defined(MTS_DEBUG)
156  if (value != 2*self + 1)
157  SLog(EError, "LeftBalancedKDNode::setLeftIndex(): Internal error!");
158  #endif
159  }
160 
161  /// Given the current node's index, return the index of the right child
162  inline IndexType getRightIndex(IndexType self) const { return 2 * self + 2; }
163  /// Given the current node's index, set the right child index
164  inline void setRightIndex(IndexType self, IndexType value) {
165  #if defined(MTS_DEBUG)
166  if (value != 0 && value != 2*self + 2)
167  SLog(EError, "LeftBalancedKDNode::setRightIndex(): Internal error!");
168  #endif
169  }
170 
171  /// Check whether this is a leaf node
172  inline bool isLeaf() const { return flags & (uint8_t) ELeafFlag; }
173  /// Specify whether this is a leaf node
174  inline void setLeaf(bool value) {
175  if (value)
176  flags |= (uint8_t) ELeafFlag;
177  else
178  flags &= (uint8_t) ~ELeafFlag;
179  }
180 
181  /// Return the split axis associated with this node
182  inline uint16_t getAxis() const { return flags & (uint8_t) EAxisMask; }
183  /// Set the split flags associated with this node
184  inline void setAxis(uint8_t axis) { flags = (flags & (uint8_t) ~EAxisMask) | axis; }
185 
186  /// Return the position associated with this node
187  inline const PointType &getPosition() const { return position; }
188  /// Set the position associated with this node
189  inline void setPosition(const PointType &value) { position = value; }
190 
191  /// Return the data record associated with this node
192  inline DataRecord &getData() { return data; }
193  /// Return the data record associated with this node (const version)
194  inline const DataRecord &getData() const { return data; }
195  /// Set the data record associated with this node
196  inline void setData(const DataRecord &val) { data = val; }
197 };
198 
199 /**
200  * \brief Generic multi-dimensional kd-tree data structure for point data
201  *
202  * This class organizes point data in a hierarchical manner so various
203  * types of queries can be performed efficiently. It supports several
204  * heuristics for building ``good'' trees, and it is oblivious to the
205  * data layout of the nodes themselves.
206  *
207  * Note that this class is meant for point data only --- for things that
208  * have some kind of spatial extent, the classes \ref GenericKDTree and
209  * \ref ShapeKDTree will be more appropriate.
210  *
211  * \tparam _NodeType Underlying node data structure. See \ref SimpleKDNode as
212  * an example for the required public interface
213  *
214  * \ingroup libcore
215  * \see SimpleKDNode
216  */
217 template <typename _NodeType> class PointKDTree {
218 public:
219  typedef _NodeType NodeType;
220  typedef typename NodeType::PointType PointType;
221  typedef typename NodeType::IndexType IndexType;
222  typedef typename PointType::Scalar Scalar;
223  typedef typename PointType::VectorType VectorType;
225 
226  /// Supported tree construction heuristics
227  enum EHeuristic {
228  /// Create a balanced tree by splitting along the median
229  EBalanced = 0,
230 
231  /// Create a left-balanced tree
233 
234  /**
235  * \brief Use the sliding midpoint tree construction rule. This
236  * ensures that cells do not become overly elongated.
237  */
239 
240  /**
241  * \brief Choose the split plane by optimizing a cost heuristic
242  * based on the ratio of voxel volumes.
243  *
244  * Note that Mitsuba's implementation of this heuristic is not
245  * particularly optimized --- the tree construction construction
246  * runs time O(n (log n)^2) instead of O(n log n).
247  */
248  EVoxelVolume
249  };
250 
251  /// Result data type for k-nn queries
252  struct SearchResult {
255 
256  inline SearchResult() {}
257 
258  inline SearchResult(Float distSquared, IndexType index)
259  : distSquared(distSquared), index(index) { }
260 
261  std::string toString() const {
262  std::ostringstream oss;
263  oss << "SearchResult[distance=" << std::sqrt(distSquared)
264  << ", index=" << index << "]";
265  return oss.str();
266  }
267 
268  inline bool operator==(const SearchResult &r) const {
269  return distSquared == r.distSquared &&
270  index == r.index;
271  }
272  };
273 
274  /// Comparison functor for nearest-neighbor search queries
275  struct SearchResultComparator : public
276  std::binary_function<SearchResult, SearchResult, bool> {
277  public:
278  inline bool operator()(const SearchResult &a, const SearchResult &b) const {
279  return a.distSquared < b.distSquared;
280  }
281  };
282 
283 public:
284  /**
285  * \brief Create an empty KD-tree that can hold the specified
286  * number of points
287  */
288  inline PointKDTree(size_t nodes = 0, EHeuristic heuristic = ESlidingMidpoint)
289  : m_nodes(nodes), m_heuristic(heuristic), m_depth(0) { }
290 
291  // =============================================================
292  //! @{ \name \c stl::vector-like interface
293  // =============================================================
294  /// Clear the kd-tree array
295  inline void clear() { m_nodes.clear(); m_aabb.reset(); }
296  /// Resize the kd-tree array
297  inline void resize(size_t size) { m_nodes.resize(size); }
298  /// Reserve a certain amount of memory for the kd-tree array
299  inline void reserve(size_t size) { m_nodes.reserve(size); }
300  /// Return the size of the kd-tree
301  inline size_t size() const { return m_nodes.size(); }
302  /// Return the capacity of the kd-tree
303  inline size_t capacity() const { return m_nodes.capacity(); }
304  /// Append a kd-tree node to the node array
305  inline void push_back(const NodeType &node) {
306  m_nodes.push_back(node);
307  m_aabb.expandBy(node.getPosition());
308  }
309  /// Return one of the KD-tree nodes by index
310  inline NodeType &operator[](size_t idx) { return m_nodes[idx]; }
311  /// Return one of the KD-tree nodes by index (const version)
312  inline const NodeType &operator[](size_t idx) const { return m_nodes[idx]; }
313  //! @}
314  // =============================================================
315 
316  /// Set the AABB of the underlying point data
317  inline void setAABB(const AABBType &aabb) { m_aabb = aabb; }
318  /// Return the AABB of the underlying point data
319  inline const AABBType &getAABB() const { return m_aabb; }
320  /// Return the depth of the constructed KD-tree
321  inline size_t getDepth() const { return m_depth; }
322  /// Set the depth of the constructed KD-tree (be careful with this)
323  inline void setDepth(size_t depth) { m_depth = depth; }
324 
325  /// Construct the KD-tree hierarchy
326  void build(bool recomputeAABB = false) {
327  ref<Timer> timer = new Timer();
328 
329  if (m_nodes.size() == 0) {
330  SLog(EWarn, "build(): kd-tree is empty!");
331  return;
332  }
333 
334  SLog(EDebug, "Building a %i-dimensional kd-tree over " SIZE_T_FMT " data points (%s)",
335  PointType::dim, m_nodes.size(), memString(m_nodes.size() * sizeof(NodeType)).c_str());
336 
337  if (recomputeAABB) {
338  m_aabb.reset();
339  for (size_t i=0; i<m_nodes.size(); ++i)
340  m_aabb.expandBy(m_nodes[i].getPosition());
341 
342  }
343  int aabbTime = timer->getMilliseconds();
344  timer->reset();
345 
346  /* Instead of shuffling around the node data itself, only modify
347  an indirection table initially. Once the tree construction
348  is done, this table will contain a indirection that can then
349  be applied to the data in one pass */
350  std::vector<IndexType> indirection(m_nodes.size());
351  for (size_t i=0; i<m_nodes.size(); ++i)
352  indirection[i] = (IndexType) i;
353 
354  m_depth = 0;
355  int constructionTime;
356  if (NodeType::leftBalancedLayout) {
357  std::vector<IndexType> permutation(m_nodes.size());
358  buildLB(0, 1, indirection.begin(), indirection.begin(),
359  indirection.end(), permutation);
360  constructionTime = timer->getMilliseconds();
361  timer->reset();
362  permute_inplace(&m_nodes[0], permutation);
363  } else {
364  build(1, indirection.begin(), indirection.begin(), indirection.end());
365  constructionTime = timer->getMilliseconds();
366  timer->reset();
367  permute_inplace(&m_nodes[0], indirection);
368  }
369 
370  int permutationTime = timer->getMilliseconds();
371 
372  if (recomputeAABB)
373  SLog(EDebug, "Done after %i ms (breakdown: aabb: %i ms, build: %i ms, permute: %i ms). ",
374  aabbTime + constructionTime + permutationTime, aabbTime, constructionTime, permutationTime);
375  else
376  SLog(EDebug, "Done after %i ms (breakdown: build: %i ms, permute: %i ms). ",
377  constructionTime + permutationTime, constructionTime, permutationTime);
378  }
379 
380  /**
381  * \brief Run a k-nearest-neighbor search query
382  *
383  * \param p Search position
384  * \param sqrSearchRadius
385  * Specifies the squared maximum search radius. This parameter can be used
386  * to restrict the k-nn query to a subset of the data -- it that is not
387  * desired, simply set it to positive infinity. After the query
388  * finishes, the parameter value will correspond to the (potentially lower)
389  * maximum query radius that was necessary to ensure that the number of
390  * results did not exceed \c k.
391  * \param k Maximum number of search results
392  * \param results Target array for search results. Must
393  * contain storage for at least \c k+1 entries!
394  * (one extra entry is needed for shuffling data around)
395  * \return The number of search results (equal to \c k or less)
396  */
397  size_t nnSearch(const PointType &p, Float &_sqrSearchRadius,
398  size_t k, SearchResult *results) const {
399  if (m_nodes.size() == 0)
400  return 0;
401 
402  IndexType *stack = (IndexType *) alloca((m_depth+1) * sizeof(IndexType));
403  IndexType index = 0, stackPos = 1;
404  Float sqrSearchRadius = _sqrSearchRadius;
405  size_t resultCount = 0;
406  bool isHeap = false;
407  stack[0] = 0;
408 
409  while (stackPos > 0) {
410  const NodeType &node = m_nodes[index];
411  IndexType nextIndex;
412 
413  /* Recurse on inner nodes */
414  if (!node.isLeaf()) {
415  Float distToPlane = p[node.getAxis()] - node.getPosition()[node.getAxis()];
416 
417  bool searchBoth = distToPlane*distToPlane <= sqrSearchRadius;
418 
419  if (distToPlane > 0) {
420  /* The search query is located on the right side of the split.
421  Search this side first. */
422  if (hasRightChild(index)) {
423  if (searchBoth)
424  stack[stackPos++] = node.getLeftIndex(index);
425  nextIndex = node.getRightIndex(index);
426  } else if (searchBoth) {
427  nextIndex = node.getLeftIndex(index);
428  } else {
429  nextIndex = stack[--stackPos];
430  }
431  } else {
432  /* The search query is located on the left side of the split.
433  Search this side first. */
434  if (searchBoth && hasRightChild(index))
435  stack[stackPos++] = node.getRightIndex(index);
436 
437  nextIndex = node.getLeftIndex(index);
438  }
439  } else {
440  nextIndex = stack[--stackPos];
441  }
442 
443  /* Check if the current point is within the query's search radius */
444  const Float pointDistSquared = (node.getPosition() - p).lengthSquared();
445 
446  if (pointDistSquared < sqrSearchRadius) {
447  /* Switch to a max-heap when the available search
448  result space is exhausted */
449  if (resultCount < k) {
450  /* There is still room, just add the point to
451  the search result list */
452  results[resultCount++] = SearchResult(pointDistSquared, index);
453  } else {
454  if (!isHeap) {
455  /* Establish the max-heap property */
456  std::make_heap(results, results + resultCount,
457  SearchResultComparator());
458  isHeap = true;
459  }
460  SearchResult *end = results + resultCount + 1;
461 
462  /* Add the new point, remove the one that is farthest away */
463  results[resultCount] = SearchResult(pointDistSquared, index);
464  std::push_heap(results, end, SearchResultComparator());
465  std::pop_heap(results, end, SearchResultComparator());
466 
467  /* Reduce the search radius accordingly */
468  sqrSearchRadius = results[0].distSquared;
469  }
470  }
471  index = nextIndex;
472  }
473  _sqrSearchRadius = sqrSearchRadius;
474  return resultCount;
475  }
476 
477  /**
478  * \brief Run a k-nearest-neighbor search query and record statistics
479  *
480  * \param p Search position
481  * \param sqrSearchRadius
482  * Specifies the squared maximum search radius. This parameter can be used
483  * to restrict the k-nn query to a subset of the data -- it that is not
484  * desired, simply set it to positive infinity. After the query
485  * finishes, the parameter value will correspond to the (potentially lower)
486  * maximum query radius that was necessary to ensure that the number of
487  * results did not exceed \c k.
488  * \param k Maximum number of search results
489  * \param results
490  * Target array for search results. Must contain
491  * storage for at least \c k+1 entries! (one
492  * extra entry is needed for shuffling data around)
493  * \return The number of used traversal steps
494  */
495  size_t nnSearchCollectStatistics(const PointType &p, Float &sqrSearchRadius,
496  size_t k, SearchResult *results, size_t &traversalSteps) const {
497  traversalSteps = 0;
498 
499  if (m_nodes.size() == 0)
500  return 0;
501 
502  IndexType *stack = (IndexType *) alloca((m_depth+1) * sizeof(IndexType));
503  IndexType index = 0, stackPos = 1;
504  size_t resultCount = 0;
505  bool isHeap = false;
506  stack[0] = 0;
507 
508  while (stackPos > 0) {
509  const NodeType &node = m_nodes[index];
510  ++traversalSteps;
511  IndexType nextIndex;
512 
513  /* Recurse on inner nodes */
514  if (!node.isLeaf()) {
515  Float distToPlane = p[node.getAxis()] - node.getPosition()[node.getAxis()];
516 
517  bool searchBoth = distToPlane*distToPlane <= sqrSearchRadius;
518 
519  if (distToPlane > 0) {
520  /* The search query is located on the right side of the split.
521  Search this side first. */
522  if (hasRightChild(index)) {
523  if (searchBoth)
524  stack[stackPos++] = node.getLeftIndex(index);
525  nextIndex = node.getRightIndex(index);
526  } else if (searchBoth) {
527  nextIndex = node.getLeftIndex(index);
528  } else {
529  nextIndex = stack[--stackPos];
530  }
531  } else {
532  /* The search query is located on the left side of the split.
533  Search this side first. */
534  if (searchBoth && hasRightChild(index))
535  stack[stackPos++] = node.getRightIndex(index);
536 
537  nextIndex = node.getLeftIndex(index);
538  }
539  } else {
540  nextIndex = stack[--stackPos];
541  }
542 
543  /* Check if the current point is within the query's search radius */
544  const Float pointDistSquared = (node.getPosition() - p).lengthSquared();
545 
546  if (pointDistSquared < sqrSearchRadius) {
547  /* Switch to a max-heap when the available search
548  result space is exhausted */
549  if (resultCount < k) {
550  /* There is still room, just add the point to
551  the search result list */
552  results[resultCount++] = SearchResult(pointDistSquared, index);
553  } else {
554  if (!isHeap) {
555  /* Establish the max-heap property */
556  std::make_heap(results, results + resultCount,
557  SearchResultComparator());
558  isHeap = true;
559  }
560 
561  /* Add the new point, remove the one that is farthest away */
562  results[resultCount] = SearchResult(pointDistSquared, index);
563  std::push_heap(results, results + resultCount + 1, SearchResultComparator());
564  std::pop_heap(results, results + resultCount + 1, SearchResultComparator());
565 
566  /* Reduce the search radius accordingly */
567  sqrSearchRadius = results[0].distSquared;
568  }
569  }
570  index = nextIndex;
571  }
572  return resultCount;
573  }
574 
575  /**
576  * \brief Run a k-nearest-neighbor search query without any
577  * search radius threshold
578  *
579  * \param p Search position
580  * \param k Maximum number of search results
581  * \param results
582  * Target array for search results. Must contain
583  * storage for at least \c k+1 entries! (one
584  * extra entry is needed for shuffling data around)
585  * \return The number of used traversal steps
586  */
587 
588  inline size_t nnSearch(const PointType &p, size_t k,
589  SearchResult *results) const {
590  Float searchRadiusSqr = std::numeric_limits<Float>::infinity();
591  return nnSearch(p, searchRadiusSqr, k, results);
592  }
593 
594  /**
595  * \brief Execute a search query and run the specified functor on them,
596  * which potentially modifies the nodes themselves
597  *
598  * The functor must have an operator() implementation, which accepts
599  * a \a NodeType as its argument.
600  *
601  * \param p Search position
602  * \param functor Functor to be called on each search result
603  * \param searchRadius Search radius
604  * \return The number of functor invocations
605  */
606  template <typename Functor> size_t executeModifier(const PointType &p,
607  Float searchRadius, Functor &functor) {
608  if (m_nodes.size() == 0)
609  return 0;
610 
611  IndexType *stack = (IndexType *) alloca((m_depth+1) * sizeof(IndexType));
612  size_t index = 0, stackPos = 1, found = 0;
613  Float distSquared = searchRadius*searchRadius;
614  stack[0] = 0;
615 
616  while (stackPos > 0) {
617  NodeType &node = m_nodes[index];
618  IndexType nextIndex;
619 
620  /* Recurse on inner nodes */
621  if (!node.isLeaf()) {
622  Float distToPlane = p[node.getAxis()]
623  - node.getPosition()[node.getAxis()];
624 
625  bool searchBoth = distToPlane*distToPlane <= distSquared;
626 
627  if (distToPlane > 0) {
628  /* The search query is located on the right side of the split.
629  Search this side first. */
630  if (hasRightChild(index)) {
631  if (searchBoth)
632  stack[stackPos++] = node.getLeftIndex(index);
633  nextIndex = node.getRightIndex(index);
634  } else if (searchBoth) {
635  nextIndex = node.getLeftIndex(index);
636  } else {
637  nextIndex = stack[--stackPos];
638  }
639  } else {
640  /* The search query is located on the left side of the split.
641  Search this side first. */
642  if (searchBoth && hasRightChild(index))
643  stack[stackPos++] = node.getRightIndex(index);
644 
645  nextIndex = node.getLeftIndex(index);
646  }
647  } else {
648  nextIndex = stack[--stackPos];
649  }
650 
651  /* Check if the current point is within the query's search radius */
652  const Float pointDistSquared = (node.getPosition() - p).lengthSquared();
653 
654  if (pointDistSquared < distSquared) {
655  functor(node);
656  ++found;
657  }
658 
659  index = nextIndex;
660  }
661  return found;
662  }
663 
664  /**
665  * \brief Execute a search query and run the specified functor on them
666  *
667  * The functor must have an operator() implementation, which accepts
668  * a constant reference to a \a NodeType as its argument.
669  *
670  * \param p Search position
671  * \param functor Functor to be called on each search result
672  * \param searchRadius Search radius
673  * \return The number of functor invocations
674  */
675  template <typename Functor> size_t executeQuery(const PointType &p,
676  Float searchRadius, Functor &functor) const {
677  if (m_nodes.size() == 0)
678  return 0;
679 
680  IndexType *stack = (IndexType *) alloca((m_depth+1) * sizeof(IndexType));
681  IndexType index = 0, stackPos = 1, found = 0;
682  Float distSquared = searchRadius*searchRadius;
683  stack[0] = 0;
684 
685  while (stackPos > 0) {
686  const NodeType &node = m_nodes[index];
687  IndexType nextIndex;
688 
689  /* Recurse on inner nodes */
690  if (!node.isLeaf()) {
691  Float distToPlane = p[node.getAxis()]
692  - node.getPosition()[node.getAxis()];
693 
694  bool searchBoth = distToPlane*distToPlane <= distSquared;
695 
696  if (distToPlane > 0) {
697  /* The search query is located on the right side of the split.
698  Search this side first. */
699  if (hasRightChild(index)) {
700  if (searchBoth)
701  stack[stackPos++] = node.getLeftIndex(index);
702  nextIndex = node.getRightIndex(index);
703  } else if (searchBoth) {
704  nextIndex = node.getLeftIndex(index);
705  } else {
706  nextIndex = stack[--stackPos];
707  }
708  } else {
709  /* The search query is located on the left side of the split.
710  Search this side first. */
711  if (searchBoth && hasRightChild(index))
712  stack[stackPos++] = node.getRightIndex(index);
713 
714  nextIndex = node.getLeftIndex(index);
715  }
716  } else {
717  nextIndex = stack[--stackPos];
718  }
719 
720  /* Check if the current point is within the query's search radius */
721  const Float pointDistSquared = (node.getPosition() - p).lengthSquared();
722 
723  if (pointDistSquared < distSquared) {
724  ++found;
725  functor(node);
726  }
727 
728  index = nextIndex;
729  }
730  return (size_t) found;
731  }
732 
733 
734  /**
735  * \brief Run a search query
736  *
737  * \param p Search position
738  * \param results Index list of search results
739  * \param searchRadius Search radius
740  * \return The number of functor invocations
741  */
742  size_t search(const PointType &p, Float searchRadius, std::vector<IndexType> &results) const {
743  if (m_nodes.size() == 0)
744  return 0;
745 
746  IndexType *stack = (IndexType *) alloca((m_depth+1) * sizeof(IndexType));
747  IndexType index = 0, stackPos = 1, found = 0;
748  Float distSquared = searchRadius*searchRadius;
749  stack[0] = 0;
750 
751  while (stackPos > 0) {
752  const NodeType &node = m_nodes[index];
753  IndexType nextIndex;
754 
755  /* Recurse on inner nodes */
756  if (!node.isLeaf()) {
757  Float distToPlane = p[node.getAxis()]
758  - node.getPosition()[node.getAxis()];
759 
760  bool searchBoth = distToPlane*distToPlane <= distSquared;
761 
762  if (distToPlane > 0) {
763  /* The search query is located on the right side of the split.
764  Search this side first. */
765  if (hasRightChild(index)) {
766  if (searchBoth)
767  stack[stackPos++] = node.getLeftIndex(index);
768  nextIndex = node.getRightIndex(index);
769  } else if (searchBoth) {
770  nextIndex = node.getLeftIndex(index);
771  } else {
772  nextIndex = stack[--stackPos];
773  }
774  } else {
775  /* The search query is located on the left side of the split.
776  Search this side first. */
777  if (searchBoth && hasRightChild(index))
778  stack[stackPos++] = node.getRightIndex(index);
779 
780  nextIndex = node.getLeftIndex(index);
781  }
782  } else {
783  nextIndex = stack[--stackPos];
784  }
785 
786  /* Check if the current point is within the query's search radius */
787  const Float pointDistSquared = (node.getPosition() - p).lengthSquared();
788 
789  if (pointDistSquared < distSquared) {
790  ++found;
791  results.push_back(index);
792  }
793 
794  index = nextIndex;
795  }
796  return (size_t) found;
797  }
798 
799  /**
800  * \brief Return whether or not the inner node of the
801  * specified index has a right child node.
802  *
803  * This function is available for convenience and abstracts away some
804  * details about the underlying node representation.
805  */
806  inline bool hasRightChild(IndexType index) const {
807  if (NodeType::leftBalancedLayout) {
808  return 2*index+2 < m_nodes.size();
809  } else {
810  return m_nodes[index].getRightIndex(index) != 0;
811  }
812  }
813 protected:
814  struct CoordinateOrdering : public std::binary_function<IndexType, IndexType, bool> {
815  public:
816  inline CoordinateOrdering(const std::vector<NodeType> &nodes, int axis)
817  : m_nodes(nodes), m_axis(axis) { }
818  inline bool operator()(const IndexType &i1, const IndexType &i2) const {
819  return m_nodes[i1].getPosition()[m_axis] < m_nodes[i2].getPosition()[m_axis];
820  }
821  private:
822  const std::vector<NodeType> &m_nodes;
823  int m_axis;
824  };
825 
826  struct LessThanOrEqual : public std::unary_function<IndexType, bool> {
827  public:
828  inline LessThanOrEqual(const std::vector<NodeType> &nodes, int axis, Scalar value)
829  : m_nodes(nodes), m_axis(axis), m_value(value) { }
830  inline bool operator()(const IndexType &i) const {
831  return m_nodes[i].getPosition()[m_axis] <= m_value;
832  }
833  private:
834  const std::vector<NodeType> &m_nodes;
835  int m_axis;
836  Scalar m_value;
837  };
838 
839  /**
840  * Given a number of entries, this method calculates the number of nodes
841  * nodes on the left subtree of a left-balanced tree. There are two main
842  * cases here:
843  *
844  * 1) It is possible to completely fill the left subtree
845  * 2) It doesn't work - the last level contains too few nodes, e.g :
846  * O
847  * / \
848  * O O
849  * /
850  * O
851  *
852  * The function assumes that "count" > 1.
853  */
854  inline IndexType leftSubtreeSize(IndexType count) const {
855  /* Layer 0 contains one node */
856  IndexType p = 1;
857 
858  /* Traverse downwards until the first incompletely
859  filled tree level is encountered */
860  while (2*p <= count)
861  p *= 2;
862 
863  /* Calculate the number of filled slots in the last level */
864  IndexType remaining = count - p + 1;
865 
866  if (2*remaining < p) {
867  /* Case 2: The last level contains too few nodes. Remove
868  overestimate from the left subtree node count and add
869  the remaining nodes */
870  p = (p >> 1) + remaining;
871  }
872 
873  return p - 1;
874  }
875 
876  /// Left-balanced tree construction routine
877  void buildLB(IndexType idx, size_t depth,
878  typename std::vector<IndexType>::iterator base,
879  typename std::vector<IndexType>::iterator rangeStart,
880  typename std::vector<IndexType>::iterator rangeEnd,
881  typename std::vector<IndexType> &permutation) {
882  m_depth = std::max(depth, m_depth);
883 
884  IndexType count = (IndexType) (rangeEnd-rangeStart);
885  SAssert(count > 0);
886 
887  if (count == 1) {
888  /* Create a leaf node */
889  m_nodes[*rangeStart].setLeaf(true);
890  permutation[idx] = *rangeStart;
891  return;
892  }
893 
894  typename std::vector<IndexType>::iterator split
895  = rangeStart + leftSubtreeSize(count);
896  int axis = m_aabb.getLargestAxis();
897  std::nth_element(rangeStart, split, rangeEnd,
898  CoordinateOrdering(m_nodes, axis));
899 
900  NodeType &splitNode = m_nodes[*split];
901  splitNode.setAxis(axis);
902  splitNode.setLeaf(false);
903  permutation[idx] = *split;
904 
905  /* Recursively build the children */
906  Scalar temp = m_aabb.max[axis],
907  splitPos = splitNode.getPosition()[axis];
908  m_aabb.max[axis] = splitPos;
909  buildLB(2*idx+1, depth+1, base, rangeStart, split, permutation);
910  m_aabb.max[axis] = temp;
911 
912  if (split+1 != rangeEnd) {
913  temp = m_aabb.min[axis];
914  m_aabb.min[axis] = splitPos;
915  buildLB(2*idx+2, depth+1, base, split+1, rangeEnd, permutation);
916  m_aabb.min[axis] = temp;
917  }
918  }
919 
920  /// Default tree construction routine
921  void build(size_t depth,
922  typename std::vector<IndexType>::iterator base,
923  typename std::vector<IndexType>::iterator rangeStart,
924  typename std::vector<IndexType>::iterator rangeEnd) {
925  m_depth = std::max(depth, m_depth);
926 
927  IndexType count = (IndexType) (rangeEnd-rangeStart);
928  SAssert(count > 0);
929 
930  if (count == 1) {
931  /* Create a leaf node */
932  m_nodes[*rangeStart].setLeaf(true);
933  return;
934  }
935 
936  int axis = 0;
937  typename std::vector<IndexType>::iterator split;
938 
939  switch (m_heuristic) {
940  case EBalanced: {
941  split = rangeStart + count/2;
942  axis = m_aabb.getLargestAxis();
943  std::nth_element(rangeStart, split, rangeEnd,
944  CoordinateOrdering(m_nodes, axis));
945  };
946  break;
947 
948  case ELeftBalanced: {
949  split = rangeStart + leftSubtreeSize(count);
950  axis = m_aabb.getLargestAxis();
951  std::nth_element(rangeStart, split, rangeEnd,
952  CoordinateOrdering(m_nodes, axis));
953  };
954  break;
955 
956  case ESlidingMidpoint: {
957  /* Sliding midpoint rule: find a split that is close to the spatial median */
958  axis = m_aabb.getLargestAxis();
959 
960  Scalar midpoint = (Scalar) 0.5f
961  * (m_aabb.max[axis]+m_aabb.min[axis]);
962 
963  size_t nLT = std::count_if(rangeStart, rangeEnd,
964  LessThanOrEqual(m_nodes, axis, midpoint));
965 
966  /* Re-adjust the split to pass through a nearby point */
967  split = rangeStart + nLT;
968 
969  if (split == rangeStart)
970  ++split;
971  else if (split == rangeEnd)
972  --split;
973 
974  std::nth_element(rangeStart, split, rangeEnd,
975  CoordinateOrdering(m_nodes, axis));
976  };
977  break;
978 
979  case EVoxelVolume: {
980  Float bestCost = std::numeric_limits<Float>::infinity();
981 
982  for (int dim=0; dim<PointType::dim; ++dim) {
983  std::sort(rangeStart, rangeEnd,
984  CoordinateOrdering(m_nodes, dim));
985 
986  size_t numLeft = 1, numRight = count-2;
987  AABBType leftAABB(m_aabb), rightAABB(m_aabb);
988  Float invVolume = 1.0f / m_aabb.getVolume();
989  for (typename std::vector<IndexType>::iterator it = rangeStart+1;
990  it != rangeEnd; ++it) {
991  ++numLeft; --numRight;
992  Float pos = m_nodes[*it].getPosition()[dim];
993  leftAABB.max[dim] = rightAABB.min[dim] = pos;
994 
995  Float cost = (numLeft * leftAABB.getVolume()
996  + numRight * rightAABB.getVolume()) * invVolume;
997  if (cost < bestCost) {
998  bestCost = cost;
999  axis = dim;
1000  split = it;
1001  }
1002  }
1003  }
1004  std::nth_element(rangeStart, split, rangeEnd,
1005  CoordinateOrdering(m_nodes, axis));
1006  };
1007  break;
1008  }
1009 
1010  NodeType &splitNode = m_nodes[*split];
1011  splitNode.setAxis(axis);
1012  splitNode.setLeaf(false);
1013 
1014  if (split+1 != rangeEnd)
1015  splitNode.setRightIndex((IndexType) (rangeStart - base),
1016  (IndexType) (split + 1 - base));
1017  else
1018  splitNode.setRightIndex((IndexType) (rangeStart - base), 0);
1019 
1020  splitNode.setLeftIndex((IndexType) (rangeStart - base),
1021  (IndexType) (rangeStart + 1 - base));
1022  std::iter_swap(rangeStart, split);
1023 
1024  /* Recursively build the children */
1025  Scalar temp = m_aabb.max[axis],
1026  splitPos = splitNode.getPosition()[axis];
1027  m_aabb.max[axis] = splitPos;
1028  build(depth+1, base, rangeStart+1, split+1);
1029  m_aabb.max[axis] = temp;
1030 
1031  if (split+1 != rangeEnd) {
1032  temp = m_aabb.min[axis];
1033  m_aabb.min[axis] = splitPos;
1034  build(depth+1, base, split+1, rangeEnd);
1035  m_aabb.min[axis] = temp;
1036  }
1037  }
1038 protected:
1039  std::vector<NodeType> m_nodes;
1041  EHeuristic m_heuristic;
1042  size_t m_depth;
1043 };
1044 
1046 
1047 #endif /* __MITSUBA_CORE_KDTREE_H_ */
void setLeftIndex(IndexType self, IndexType value)
Given the current node&#39;s index, set the left child index.
Definition: kdtree.h:154
uint32_t IndexType
Definition: kdtree.h:47
bool isLeaf() const
Check whether this is a leaf node.
Definition: kdtree.h:172
_PointType PointType
Definition: kdtree.h:129
bool hasRightChild(IndexType index) const
Return whether or not the inner node of the specified index has a right child node.
Definition: kdtree.h:806
void permute_inplace(DataType *data, std::vector< IndexType > &perm)
Apply an arbitrary permutation to an array in linear time.
Definition: util.h:238
Left-balanced kd-tree node for use with PointKDTree.
Definition: kdtree.h:128
size_t executeModifier(const PointType &p, Float searchRadius, Functor &functor)
Execute a search query and run the specified functor on them, which potentially modifies the nodes th...
Definition: kdtree.h:606
const PointType & getPosition() const
Return the position associated with this node.
Definition: kdtree.h:187
SimpleKDNode(const DataRecord &data)
Initialize a KD-tree node with the given data record.
Definition: kdtree.h:66
LeftBalancedKDNode(const DataRecord &data)
Initialize a KD-tree node with the given data record.
Definition: kdtree.h:148
void setAABB(const AABBType &aabb)
Set the AABB of the underlying point data.
Definition: kdtree.h:317
TAABB< PointType > AABBType
Definition: kdtree.h:224
size_t nnSearch(const PointType &p, Float &_sqrSearchRadius, size_t k, SearchResult *results) const
Run a k-nearest-neighbor search query.
Definition: kdtree.h:397
IndexType getLeftIndex(IndexType self) const
Given the current node&#39;s index, return the index of the left child.
Definition: kdtree.h:75
size_t search(const PointType &p, Float searchRadius, std::vector< IndexType > &results) const
Run a search query.
Definition: kdtree.h:742
void build(bool recomputeAABB=false)
Construct the KD-tree hierarchy.
Definition: kdtree.h:326
bool operator==(const SearchResult &r) const
Definition: kdtree.h:268
Internal data record used by Photon.
Definition: photon.h:38
DataRecord & getData()
Return the data record associated with this node.
Definition: kdtree.h:192
PointType::Scalar Scalar
Definition: kdtree.h:222
void setDepth(size_t depth)
Set the depth of the constructed KD-tree (be careful with this)
Definition: kdtree.h:323
std::vector< NodeType > m_nodes
Definition: kdtree.h:1039
void setAxis(uint8_t axis)
Set the split flags associated with this node.
Definition: kdtree.h:97
IndexType right
Definition: kdtree.h:58
#define SLog(level, fmt,...)
Write a Log message to the console (static version - to be used outside of classes that derive from O...
Definition: logger.h:49
const AABBType & getAABB() const
Return the AABB of the underlying point data.
Definition: kdtree.h:319
size_t m_depth
Definition: kdtree.h:1042
Debug message, usually turned off.
Definition: formatter.h:30
NodeType::PointType PointType
Definition: kdtree.h:220
PointKDTree(size_t nodes=0, EHeuristic heuristic=ESlidingMidpoint)
Create an empty KD-tree that can hold the specified number of points.
Definition: kdtree.h:288
void push_back(const NodeType &node)
Append a kd-tree node to the node array.
Definition: kdtree.h:305
const DataRecord & getData() const
Return the data record associated with this node (const version)
Definition: kdtree.h:107
void setRightIndex(IndexType self, IndexType value)
Given the current node&#39;s index, set the right child index.
Definition: kdtree.h:164
#define MTS_NAMESPACE_BEGIN
Definition: platform.h:137
DataRecord data
Definition: kdtree.h:142
Result data type for k-nn queries.
Definition: kdtree.h:252
bool operator()(const IndexType &i1, const IndexType &i2) const
Definition: kdtree.h:818
PointType::Scalar Scalar
Definition: kdtree.h:132
_NodeType NodeType
Definition: kdtree.h:219
Use the sliding midpoint tree construction rule. This ensures that cells do not become overly elongat...
Definition: kdtree.h:238
PointType::VectorType VectorType
Definition: kdtree.h:223
void setAxis(uint8_t axis)
Set the split flags associated with this node.
Definition: kdtree.h:184
_PointType PointType
Definition: kdtree.h:45
_DataRecord DataRecord
Definition: kdtree.h:130
Float distSquared
Definition: kdtree.h:253
uint32_t IndexType
Definition: kdtree.h:131
IndexType getRightIndex(IndexType self) const
Given the current node&#39;s index, return the index of the right child.
Definition: kdtree.h:162
size_t getDepth() const
Return the depth of the constructed KD-tree.
Definition: kdtree.h:321
bool operator()(const IndexType &i) const
Definition: kdtree.h:830
void buildLB(IndexType idx, size_t depth, typename std::vector< IndexType >::iterator base, typename std::vector< IndexType >::iterator rangeStart, typename std::vector< IndexType >::iterator rangeEnd, typename std::vector< IndexType > &permutation)
Left-balanced tree construction routine.
Definition: kdtree.h:877
NodeType::IndexType IndexType
Definition: kdtree.h:221
void resize(size_t size)
Resize the kd-tree array.
Definition: kdtree.h:297
size_t size() const
Return the size of the kd-tree.
Definition: kdtree.h:301
size_t nnSearchCollectStatistics(const PointType &p, Float &sqrSearchRadius, size_t k, SearchResult *results, size_t &traversalSteps) const
Run a k-nearest-neighbor search query and record statistics.
Definition: kdtree.h:495
#define SAssert(cond)
``Static&#39;&#39; assertion (to be used outside of classes that derive from Object)
Definition: logger.h:79
AABBType m_aabb
Definition: kdtree.h:1040
uint8_t flags
Definition: kdtree.h:143
void setLeaf(bool value)
Specify whether this is a leaf node.
Definition: kdtree.h:174
#define SIZE_T_FMT
Definition: platform.h:92
Reference counting helper.
Definition: ref.h:40
Warning message.
Definition: formatter.h:32
PointType position
Definition: kdtree.h:141
SearchResult()
Definition: kdtree.h:256
Memory-efficient photon representation for use with PointKDTree.
Definition: photon.h:57
IndexType getRightIndex(IndexType self) const
Given the current node&#39;s index, return the index of the right child.
Definition: kdtree.h:70
uint16_t getAxis() const
Return the split axis associated with this node.
Definition: kdtree.h:95
bool operator()(const SearchResult &a, const SearchResult &b) const
Definition: kdtree.h:278
SimpleKDNode()
Initialize a KD-tree node.
Definition: kdtree.h:63
size_t executeQuery(const PointType &p, Float searchRadius, Functor &functor) const
Execute a search query and run the specified functor on them.
Definition: kdtree.h:675
MTS_EXPORT_CORE std::string memString(size_t size, bool precise=false)
Turn a memory size into a human-readable string.
const DataRecord & getData() const
Return the data record associated with this node (const version)
Definition: kdtree.h:194
void setData(const DataRecord &val)
Set the data record associated with this node.
Definition: kdtree.h:196
Platform independent milli/micro/nanosecond timerThis class implements a simple cross-platform timer ...
Definition: timer.h:37
Error message, causes an exception to be thrown.
Definition: formatter.h:33
const PointType & getPosition() const
Return the position associated with this node.
Definition: kdtree.h:100
PointType::Scalar Scalar
Definition: kdtree.h:48
std::string toString() const
Definition: kdtree.h:261
uint16_t getAxis() const
Return the split axis associated with this node.
Definition: kdtree.h:182
Generic multi-dimensional kd-tree data structure for point data.
Definition: kdtree.h:217
void build(size_t depth, typename std::vector< IndexType >::iterator base, typename std::vector< IndexType >::iterator rangeStart, typename std::vector< IndexType >::iterator rangeEnd)
Default tree construction routine.
Definition: kdtree.h:921
LeftBalancedKDNode()
Initialize a KD-tree node.
Definition: kdtree.h:146
LessThanOrEqual(const std::vector< NodeType > &nodes, int axis, Scalar value)
Definition: kdtree.h:828
size_t capacity() const
Return the capacity of the kd-tree.
Definition: kdtree.h:303
PointType min
Component-wise minimum.
Definition: aabb.h:424
void setLeftIndex(IndexType self, IndexType value)
Given the current node&#39;s index, set the left child index.
Definition: kdtree.h:77
void setPosition(const PointType &value)
Set the position associated with this node.
Definition: kdtree.h:102
CoordinateOrdering(const std::vector< NodeType > &nodes, int axis)
Definition: kdtree.h:816
DataRecord & getData()
Return the data record associated with this node.
Definition: kdtree.h:105
void setLeaf(bool value)
Specify whether this is a leaf node.
Definition: kdtree.h:87
size_t nnSearch(const PointType &p, size_t k, SearchResult *results) const
Run a k-nearest-neighbor search query without any search radius threshold.
Definition: kdtree.h:588
void setRightIndex(IndexType self, IndexType value)
Given the current node&#39;s index, set the right child index.
Definition: kdtree.h:72
Comparison functor for nearest-neighbor search queries.
Definition: kdtree.h:275
Definition: fwd.h:100
uint8_t flags
Definition: kdtree.h:60
bool isLeaf() const
Check whether this is a leaf node.
Definition: kdtree.h:85
Scalar getVolume() const
Calculate the n-dimensional volume of the bounding box.
Definition: aabb.h:107
DataRecord data
Definition: kdtree.h:59
Simple kd-tree node for use with PointKDTree.
Definition: kdtree.h:44
SearchResult(Float distSquared, IndexType index)
Definition: kdtree.h:258
void setPosition(const PointType &value)
Set the position associated with this node.
Definition: kdtree.h:189
_DataRecord DataRecord
Definition: kdtree.h:46
IndexType index
Definition: kdtree.h:254
NodeType & operator[](size_t idx)
Return one of the KD-tree nodes by index.
Definition: kdtree.h:310
const NodeType & operator[](size_t idx) const
Return one of the KD-tree nodes by index (const version)
Definition: kdtree.h:312
void reserve(size_t size)
Reserve a certain amount of memory for the kd-tree array.
Definition: kdtree.h:299
Create a left-balanced tree.
Definition: kdtree.h:232
IndexType leftSubtreeSize(IndexType count) const
Definition: kdtree.h:854
#define MTS_NAMESPACE_END
Definition: platform.h:138
EHeuristic m_heuristic
Definition: kdtree.h:1041
void clear()
Clear the kd-tree array.
Definition: kdtree.h:295
PointType position
Definition: kdtree.h:57
IndexType getLeftIndex(IndexType self) const
Given the current node&#39;s index, return the index of the left child.
Definition: kdtree.h:152
void setData(const DataRecord &val)
Set the data record associated with this node.
Definition: kdtree.h:109