47 typedef TCoordType coord_type;
50 typedef std::pair<point_type, point_index> value_type;
51 typedef std::vector<point_index> point_data_vec;
52 typedef point_data_vec::const_iterator pd_cit;
54 typedef CDT::array<node_index, 2> children_type;
65 data.reserve(NumVerticesInLeaf);
84 -std::numeric_limits<coord_type>::max(),
85 -std::numeric_limits<coord_type>::max()))
87 std::numeric_limits<coord_type>::max(),
88 std::numeric_limits<coord_type>::max()))
90 , m_isRootBoxInitialized(false)
91 , m_tasksStack(InitialStackDepth, NearestTask())
93 m_root = addNewNode();
97 KDTree(
const point_type& min,
const point_type& max)
102 , m_isRootBoxInitialized(true)
103 , m_tasksStack(InitialStackDepth, NearestTask())
105 m_root = addNewNode();
118 insert(
const point_index& iPoint,
const std::vector<point_type>& points)
122 const point_type& pos = points[iPoint];
123 while(!isInsideBox(pos, m_min, m_max))
128 node_index node = m_root;
129 point_type min = m_min;
130 point_type max = m_max;
131 NodeSplitDirection::Enum dir = m_rootDir;
134 NodeSplitDirection::Enum newDir(NodeSplitDirection::X);
136 point_type newMin, newMax;
139 if(m_nodes[node].isLeaf())
142 point_data_vec& pd = m_nodes[node].data;
143 if(pd.size() < NumVerticesInLeaf)
145 pd.push_back(iPoint);
149 if(!m_isRootBoxInitialized)
151 initializeRootBox(points);
156 calcSplitInfo(min, max, dir, mid, newDir, newMin, newMax);
157 const node_index c1 = addNewNode(), c2 = addNewNode();
158 Node& n = m_nodes[node];
160 point_data_vec& c1data = m_nodes[c1].data;
161 point_data_vec& c2data = m_nodes[c2].data;
163 for(pd_cit it = n.
data.begin(); it != n.
data.end(); ++it)
165 whichChild(points[*it], mid, dir) == 0
166 ? c1data.push_back(*it)
167 : c2data.push_back(*it);
169 n.
data = point_data_vec();
173 calcSplitInfo(min, max, dir, mid, newDir, newMin, newMax);
176 const std::size_t iChild = whichChild(points[iPoint], mid, dir);
177 iChild == 0 ? max = newMax : min = newMin;
178 node = m_nodes[node].children[iChild];
188 const point_type& point,
189 const std::vector<point_type>& points)
const
193 coord_type minDistSq = std::numeric_limits<coord_type>::max();
194 m_tasksStack[++iTask] = NearestTask(
199 distanceSquaredToBox(point, m_min, m_max));
202 const NearestTask t = m_tasksStack[iTask--];
203 if(t.distSq > minDistSq)
205 const Node& n = m_nodes[t.node];
208 for(pd_cit it = n.
data.begin(); it != n.
data.end(); ++it)
210 const point_type& p = points[*it];
212 if(distSq < minDistSq)
223 NodeSplitDirection::Enum newDir(NodeSplitDirection::X);
224 point_type newMin = t.min, newMax = t.max;
225 coord_type dSqFarther = std::numeric_limits<coord_type>::max();
228 case NodeSplitDirection::X:
230 mid = (t.min.
x + t.max.
x) / coord_type(2);
231 newDir = NodeSplitDirection::Y;
234 const coord_type dx = point.
x - mid;
235 const coord_type dy = std::max(
236 std::max(t.min.
y - point.
y, coord_type(0)),
238 dSqFarther = dx * dx + dy * dy;
241 case NodeSplitDirection::Y:
243 mid = (t.min.
y + t.max.
y) / coord_type(2);
244 newDir = NodeSplitDirection::X;
247 const coord_type dx = std::max(
248 std::max(t.min.
x - point.
x, coord_type(0)),
250 const coord_type dy = point.
y - mid;
251 dSqFarther = dx * dx + dy * dy;
256 if(iTask + 2 >=
static_cast<int>(m_tasksStack.size()))
259 m_tasksStack.size() + StackDepthIncrement);
263 if(isAfterSplit(point, mid, t.dir))
265 if(dSqFarther <= minDistSq)
267 m_tasksStack[++iTask] = NearestTask(
268 n.
children[0], t.min, newMax, newDir, dSqFarther);
270 m_tasksStack[++iTask] = NearestTask(
271 n.
children[1], newMin, t.max, newDir, t.distSq);
275 if(dSqFarther <= minDistSq)
277 m_tasksStack[++iTask] = NearestTask(
278 n.
children[1], newMin, t.max, newDir, dSqFarther);
280 m_tasksStack[++iTask] = NearestTask(
281 n.
children[0], t.min, newMax, newDir, t.distSq);
290 node_index addNewNode()
292 const node_index newNodeIndex =
static_cast<node_index
>(m_nodes.size());
293 m_nodes.push_back(Node());
297 static bool isAfterSplit(
298 const point_type& point,
299 const coord_type& split,
300 const NodeSplitDirection::Enum dir)
302 return dir == NodeSplitDirection::X ? point.x > split : point.y > split;
307 static std::size_t whichChild(
308 const point_type& point,
309 const coord_type& split,
310 const NodeSplitDirection::Enum dir)
312 return isAfterSplit(point, split, dir);
316 static void calcSplitInfo(
317 const point_type& min,
318 const point_type& max,
319 const NodeSplitDirection::Enum dir,
321 NodeSplitDirection::Enum& newDirOut,
322 point_type& newMinOut,
323 point_type& newMaxOut)
329 case NodeSplitDirection::X:
330 midOut = (min.x + max.x) / coord_type(2);
331 newDirOut = NodeSplitDirection::Y;
332 newMinOut.x = midOut;
333 newMaxOut.x = midOut;
335 case NodeSplitDirection::Y:
336 midOut = (min.y + max.y) / coord_type(2);
337 newDirOut = NodeSplitDirection::X;
338 newMinOut.y = midOut;
339 newMaxOut.y = midOut;
345 static bool isInsideBox(
347 const point_type& min,
348 const point_type& max)
350 return p.x >= min.x && p.x <= max.x && p.y >= min.y && p.y <= max.y;
355 void extendTree(
const point_type& point)
357 const node_index newRoot = addNewNode();
358 const node_index newLeaf = addNewNode();
361 case NodeSplitDirection::X:
362 m_rootDir = NodeSplitDirection::Y;
363 if(point.y < m_min.y)
365 m_min.y -= m_max.y - m_min.y;
366 m_nodes[newRoot].setChildren(newLeaf, m_root);
370 m_max.y += m_max.y - m_min.y;
371 m_nodes[newRoot].setChildren(m_root, newLeaf);
374 case NodeSplitDirection::Y:
375 m_rootDir = NodeSplitDirection::X;
376 if(point.x < m_min.x)
378 m_min.x -= m_max.x - m_min.x;
379 m_nodes[newRoot].setChildren(newLeaf, m_root);
383 m_max.x += m_max.x - m_min.x;
384 m_nodes[newRoot].setChildren(m_root, newLeaf);
392 void initializeRootBox(
const std::vector<point_type>& points)
394 const point_data_vec& data = m_nodes[m_root].data;
395 m_min = points[data.front()];
397 for(pd_cit it = data.begin(); it != data.end(); ++it)
399 const point_type& p = points[*it];
400 m_min = point_type(std::min(m_min.x, p.x), std::min(m_min.y, p.y));
401 m_max = point_type(std::max(m_max.x, p.x), std::max(m_max.y, p.y));
405 const TCoordType padding(1);
406 if(m_min.x == m_max.x)
411 if(m_min.y == m_max.y)
416 m_isRootBoxInitialized =
true;
419 static coord_type distanceSquaredToBox(
421 const point_type& min,
422 const point_type& max)
424 const coord_type dx =
425 std::max(std::max(min.x - p.x, coord_type(0)), p.x - max.x);
426 const coord_type dy =
427 std::max(std::max(min.y - p.y, coord_type(0)), p.y - max.y);
428 return dx * dx + dy * dy;
433 std::vector<Node> m_nodes;
434 NodeSplitDirection::Enum m_rootDir;
439 bool m_isRootBoxInitialized;
446 NodeSplitDirection::Enum dir;
449 : dir(NodeSplitDirection::X)
452 const node_index node,
453 const point_type& min,
454 const point_type& max,
455 const NodeSplitDirection::Enum dir,
456 const coord_type distSq = std::numeric_limits<coord_type>::max())
465 mutable std::vector<NearestTask> m_tasksStack;