GteNearestNeighborQuery.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
10 #include <LowLevel/GteLogger.h>
11 #include <Mathematics/GteVector.h>
12 #include <algorithm>
13 #include <limits>
14 #include <vector>
15 
16 namespace gte
17 {
18 
19 // Use a kd-tree for sorting used in a query for finding nearest neighbors
20 // of a point in a space of the specified dimension N. The split order is
21 // always 0,1,2,...,N-1. The number of sites at a leaf node is controlled
22 // by 'maxLeafSize' and the maximum level of the tree is controlled by
23 // 'maxLevels'. The points are of type Vector<N,Real>. The 'Site' is a
24 // structure of information that minimally implements the function
25 // 'Vector<N,Real> GetPosition () const'. The Site template parameter
26 // allows the query to be applied even when it has more local information
27 // than just point location.
28 template <int N, typename Real, typename Site, int MaxNeighbors>
30 {
31 public:
32  // Construction.
33  NearestNeighborQuery(std::vector<Site> const& sites, int maxLeafSize,
34  int maxLevel);
35 
36  // Member access.
37  inline int GetMaxLeafSize () const;
38  inline int GetMaxLevel () const;
39 
40  // Compute up to MaxNeighbor nearest neighbors within the specified radius
41  // of the point. The returned integer is the number of neighbors found,
42  // possibly zero. The neighbors array stores indices into the array
43  // passed to the constructor.
44  int FindNeighbors(Vector<N,Real> const& point, Real radius,
45  std::array<int, MaxNeighbors>& neighbors) const;
46 
47 private:
48  typedef std::pair<Vector<N, Real>, int> SortedPoint;
49 
50  struct Node
51  {
52  Real split;
53  int axis;
54  int numSites;
56  int left;
57  int right;
58  };
59 
60  // Populate the node so that it contains the points split along the
61  // coordinate axes.
62  void Build(int numSites, int siteOffset, int nodeIndex, int level);
63 
64  // Helper class for sorting along axes.
66  {
67  public:
68  inline SortFunctor(int axis);
69  inline bool operator()(SortedPoint const& sorted0,
70  SortedPoint const& sorted1) const;
71  private:
72  int mAxis;
73  };
74 
76  int mMaxLevel;
77  std::vector<SortedPoint> mSortedPoints;
78  std::vector<Node> mNodes;
79 };
80 
81 
82 template <int N, typename Real, typename Site, int MaxNeighbors>
84  std::vector<Site> const& sites, int maxLeafSize, int maxLevel)
85  :
86  mMaxLeafSize(maxLeafSize),
87  mMaxLevel(maxLevel),
88  mSortedPoints(sites.size())
89 {
90  int const numSites = static_cast<int>(sites.size());
91  for (int i = 0; i < numSites; ++i)
92  {
93  mSortedPoints[i] = std::make_pair(sites[i].GetPosition(), i);
94  }
95 
96  mNodes.push_back(Node());
97  Build(numSites, 0, 0, 0);
98 }
99 
100 template <int N, typename Real, typename Site, int MaxNeighbors> inline
102 {
103  return mMaxLeafSize;
104 }
105 
106 template <int N, typename Real, typename Site, int MaxNeighbors> inline
108 {
109  return mMaxLevel;
110 }
111 
112 template <int N, typename Real, typename Site, int MaxNeighbors>
114  Vector<N, Real> const& point, Real radius,
115  std::array<int, MaxNeighbors>& neighbors) const
116 {
117  Real sqrRadius = radius * radius;
118  int numNeighbors = 0;
119  std::array<int, MaxNeighbors + 1> localNeighbors;
120  std::array<Real, MaxNeighbors + 1> neighborSqrLength;
121  for (int i = 0; i <= MaxNeighbors; ++i)
122  {
123  localNeighbors[i] = -1;
124  neighborSqrLength[i] = std::numeric_limits<Real>::max();
125  }
126 
127  // The kd-tree construction is recursive, simulated here by using a stack.
128  // The maximum depth is limited to 32, because the number of sites is
129  // limited to 2^{32} (the number of 32-bit integer indices).
130  std::array<int, 32> stack;
131  int top = 0;
132  stack[0] = 0;
133 
134  while (top >= 0)
135  {
136  Node node = mNodes[stack[top--]];
137 
138  if (node.siteOffset != -1)
139  {
140  for (int i = 0, j = node.siteOffset; i < node.numSites; ++i, ++j)
141  {
142  Vector<N, Real> diff = mSortedPoints[j].first - point;
143  Real sqrLength = Dot(diff, diff);
144  if (sqrLength <= sqrRadius)
145  {
146  // Maintain the nearest neighbors.
147  int k;
148  for (k = 0; k < numNeighbors; ++k)
149  {
150  if (sqrLength <= neighborSqrLength[k])
151  {
152  for (int n = numNeighbors; n > k; --n)
153  {
154  localNeighbors[n] = localNeighbors[n - 1];
155  neighborSqrLength[n] = neighborSqrLength[n - 1];
156  }
157  break;
158  }
159  }
160  if (k < MaxNeighbors)
161  {
162  localNeighbors[k] = mSortedPoints[j].second;
163  neighborSqrLength[k] = sqrLength;
164  }
165  if (numNeighbors < MaxNeighbors)
166  {
167  ++numNeighbors;
168  }
169  }
170  }
171  }
172 
173  if (node.left != -1 && point[node.axis] - radius <= node.split)
174  {
175  stack[++top] = node.left;
176  }
177 
178  if (node.right != -1 && point[node.axis] + radius >= node.split)
179  {
180  stack[++top] = node.right;
181  }
182  }
183 
184  for (int i = 0; i < numNeighbors; ++i)
185  {
186  neighbors[i] = localNeighbors[i];
187  }
188 
189  return numNeighbors;
190 }
191 
192 template <int N, typename Real, typename Site, int MaxNeighbors>
194  int siteOffset, int nodeIndex, int level)
195 {
196  LogAssert(siteOffset != -1, "Invalid site offset.");
197  LogAssert(nodeIndex != -1, "Invalid node index.");
198  LogAssert(numSites > 0, "Empty point list.");
199 
200  Node& node = mNodes[nodeIndex];
201  node.numSites = numSites;
202 
203  if (numSites > mMaxLeafSize && level <= mMaxLevel)
204  {
205  int halfNumSites = numSites / 2;
206 
207  // The point set is too large for a leaf node, so split it at the
208  // median. The O(m log m) sort is not needed; rather, we locate the
209  // median using an order statistic construction that is expected
210  // time O(m).
211  int const axis = level % N;
212  SortFunctor sorter(axis);
213  auto begin = mSortedPoints.begin() + siteOffset;
214  auto mid = mSortedPoints.begin() + siteOffset + halfNumSites;
215  auto end = mSortedPoints.begin() + siteOffset + numSites;
216  std::nth_element(begin, mid, end, sorter);
217 
218  // Get the median position.
219  node.split = mSortedPoints[siteOffset + halfNumSites].first[axis];
220  node.axis = axis;
221  node.siteOffset = -1;
222 
223  // Apply a divide-and-conquer step.
224  int left = (int)mNodes.size(), right = left + 1;
225  node.left = left;
226  node.right = right;
227  mNodes.push_back(Node());
228  mNodes.push_back(Node());
229 
230  int nextLevel = level + 1;
231  Build(halfNumSites, siteOffset, left, nextLevel);
232  Build(numSites - halfNumSites, siteOffset + halfNumSites, right,
233  nextLevel);
234  }
235  else
236  {
237  // The number of points is small enough, so make this node a leaf.
238  node.split = std::numeric_limits<Real>::max();
239  node.axis = -1;
240  node.siteOffset = siteOffset;
241  node.left = -1;
242  node.right = -1;
243  }
244 }
245 
246 template <int N, typename Real, typename Site, int MaxNeighbors> inline
248 int axis)
249 :
250 mAxis(axis)
251 {
252 }
253 
254 template <int N, typename Real, typename Site, int MaxNeighbors> inline
256 operator()(SortedPoint const& sorted0, SortedPoint const& sorted1) const
257 {
258  return sorted0.first[mAxis] < sorted1.first[mAxis];
259 }
260 
261 
262 }
GLdouble n
Definition: glcorearb.h:2003
std::pair< Vector< N, Real >, int > SortedPoint
#define LogAssert(condition, message)
Definition: GteLogger.h:86
GLint level
Definition: glcorearb.h:103
GLint left
Definition: glcorearb.h:2000
GLsizeiptr size
Definition: glcorearb.h:659
void Build(int numSites, int siteOffset, int nodeIndex, int level)
std::vector< SortedPoint > mSortedPoints
bool operator()(SortedPoint const &sorted0, SortedPoint const &sorted1) const
GLuint GLuint end
Definition: glcorearb.h:470
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
GLdouble GLdouble right
Definition: glext.h:6472
int FindNeighbors(Vector< N, Real > const &point, Real radius, std::array< int, MaxNeighbors > &neighbors) const
NearestNeighborQuery(std::vector< Site > const &sites, int maxLeafSize, int maxLevel)
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:6472


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:01