World Builder  1.1.0-pre
A geodynamic initial conditions generator
kd_tree.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2018-2024 by the authors of the World Builder code.
3 
4  This file is part of the World Builder.
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation, either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19 
20 #include "world_builder/kd_tree.h"
21 #include <algorithm>
22 #include <utility>
23 
24 namespace WorldBuilder
25 {
26  namespace KDTree
27  {
28  KDTree::KDTree(std::vector<Node> point_list)
29  : nodes(std::move(std::move(point_list)))
30  {}
31 
32 
33  void
34  KDTree::create_tree(const size_t left,
35  const size_t right,
36  const bool y_axis)
37  {
38  const size_t mid=(left+right)>>1;
39  std::nth_element(nodes.begin()+static_cast<long int>(left),nodes.begin()+static_cast<long int>(mid),nodes.begin()+static_cast<long int>(right)+1,
40  [y_axis](Node& i, Node& j) -> bool
41  {
42  return i[y_axis] < j[y_axis];
43  });
44 
45  if (left<mid)
46  create_tree(left,mid-1,!y_axis);
47  if (right>mid)
48  create_tree(mid+1,right,!y_axis);
49  }
50 
51 
52  const std::vector<Node> &
54  {
55  return nodes;
56  }
57 
58 
60  KDTree::find_closest_point(const Point<2> &check_point) const
61  {
62  const size_t start_node_index = 0;
63  IndexDistance index_distance = {start_node_index,
64  std::numeric_limits<double>::max()
65  };
66 
67  find_closest_point_recursive(check_point,0,nodes.size()-1,false,index_distance);
68 
69  return index_distance;
70  }
71 
72 
73  void
75  const size_t left,
76  const size_t right,
77  const bool y_axis,
78  IndexDistance &index_distance) const
79  {
80  // Calculate the index of this node
81  const size_t mid=(left+right)>>1;
82  const Node &node = nodes[mid];
83  if (check_point[static_cast<size_t>(y_axis)] < node[y_axis])
84  {
85  // Traverse left child
86  if (left<mid)
87  {
88  find_closest_point_recursive(check_point,left,mid-1,!y_axis,index_distance);
89  }
90 
91  // Compare node's point to current closest point
92  const double distance = sqrt((node[false]-check_point[0])*(node[false]-check_point[0])
93  +(node[true]-check_point[1])*(node[true]-check_point[1]));
94  if (index_distance.distance > distance)
95  {
96  index_distance.index = mid;
97  index_distance.distance = distance;
98  }
99 
100  // Traverse right child
101  if (right>mid)
102  {
103  if ((node[y_axis]-check_point[static_cast<size_t>(y_axis)]) < index_distance.distance)
104  {
105  find_closest_point_recursive(check_point,mid+1,right,!y_axis,index_distance);
106  }
107  }
108  }
109  else
110  {
111  // Traverse right child
112  if (right>mid)
113  find_closest_point_recursive(check_point,mid+1,right,!y_axis,index_distance);
114 
115  // Compare node's point to current closest point
116  const double distance = sqrt((node[false]-check_point[0])*(node[false]-check_point[0])
117  +(node[true]-check_point[1])*(node[true]-check_point[1]));
118  if (index_distance.distance > distance)
119  {
120  index_distance.index = mid;
121  index_distance.distance = distance;
122  }
123 
124  // Traverse left child
125  if (left<mid)
126  if ((node[y_axis]-check_point[static_cast<size_t>(y_axis)]) < index_distance.distance)
127  find_closest_point_recursive(check_point,left,mid-1,!y_axis,index_distance);
128  }
129  }
130 
131 
132 
134  KDTree::find_closest_points(const Point<2> &check_point) const
135  {
136  const size_t start_node_index = 0;
137  IndexDistances index_distances = {start_node_index,
138  std::numeric_limits<double>::max(),
139  {}
140  };
141  index_distances.vector.reserve(nodes.size());
142 
143  find_closest_points_recursive(check_point,0,nodes.size()-1,false,index_distances);
144 
145  return index_distances;
146  }
147 
148 
149  void
151  const size_t left,
152  const size_t right,
153  const bool y_axis,
154  IndexDistances &index_distances) const
155  {
156  // Calculate the index of this node
157  const size_t mid=(left+right)>>1;
158  const Node &node = nodes[mid];
159  if (check_point[static_cast<size_t>(y_axis)] < node[y_axis])
160  {
161  // Traverse left child
162  if (left<mid)
163  {
164  find_closest_points_recursive(check_point,left,mid-1,!y_axis,index_distances);
165  }
166 
167  // Compare node's point to current closest point
168  const double distance = sqrt((node[false]-check_point[0])*(node[false]-check_point[0])
169  +(node[true]-check_point[1])*(node[true]-check_point[1]));
170  if (index_distances.min_distance > distance)
171  {
172  index_distances.min_index = mid;
173  index_distances.min_distance = distance;
174  }
175 
176  index_distances.vector.emplace_back(IndexDistance {mid, distance});
177 
178  // Traverse right child
179  if (right>mid)
180  {
181  if ((node[y_axis]-check_point[static_cast<size_t>(y_axis)]) < index_distances.min_distance)
182  {
183  find_closest_points_recursive(check_point,mid+1,right,!y_axis,index_distances);
184  }
185  }
186  }
187  else
188  {
189  // Traverse right child
190  if (right>mid)
191  find_closest_points_recursive(check_point,mid+1,right,!y_axis,index_distances);
192 
193  // Compare node's point to current closest point
194  const double distance = sqrt((node[false]-check_point[0])*(node[false]-check_point[0])
195  +(node[true]-check_point[1])*(node[true]-check_point[1]));
196  if (index_distances.min_distance > distance)
197  {
198  index_distances.min_index = mid;
199  index_distances.min_distance = distance;
200  }
201 
202  index_distances.vector.emplace_back(IndexDistance {mid, distance});
203 
204  // Traverse left child
205  if (left<mid)
206  if ((node[y_axis]-check_point[static_cast<size_t>(y_axis)]) < index_distances.min_distance)
207  find_closest_points_recursive(check_point,left,mid-1,!y_axis,index_distances);
208  }
209  }
210  } // namespace KDTree
211 } // namespace WorldBuilder
std::vector< Node > nodes
Definition: kd_tree.h:157
std::vector< IndexDistance > vector
Definition: kd_tree.h:54
void find_closest_points_recursive(const Point< 2 > &check_point, const size_t left, const size_t right, const bool y_axis, IndexDistances &index_distances) const
Definition: kd_tree.cc:150
const std::vector< Node > & get_nodes() const
Definition: kd_tree.cc:53
void create_tree(const size_t left, const size_t right, const bool x_axis)
Definition: kd_tree.cc:34
IndexDistance find_closest_point(const Point< 2 > &check_point) const
Definition: kd_tree.cc:60
IndexDistances find_closest_points(const Point< 2 > &check_point) const
Definition: kd_tree.cc:134
void find_closest_point_recursive(const Point< 2 > &check_point, const size_t left, const size_t right, const bool y_axis, IndexDistance &index_distance) const
Definition: kd_tree.cc:74