99
1010#include " CDTUtils.h"
1111
12- #include < cassert>
1312#include < limits>
1413
1514namespace CDT
@@ -192,8 +191,12 @@ class KDTree
192191 value_type out;
193192 int iTask = -1 ;
194193 coord_type minDistSq = std::numeric_limits<coord_type>::max ();
195- m_tasksStack[++iTask] =
196- NearestTask (m_root, m_min, m_max, m_rootDir, minDistSq);
194+ m_tasksStack[++iTask] = NearestTask (
195+ m_root,
196+ m_min,
197+ m_max,
198+ m_rootDir,
199+ distanceSquaredToBox (point, m_min, m_max));
197200 while (iTask != -1 )
198201 {
199202 const NearestTask t = m_tasksStack[iTask--];
@@ -217,35 +220,65 @@ class KDTree
217220 else
218221 {
219222 coord_type mid (0 );
220- NodeSplitDirection::Enum newDir;
221- point_type newMin, newMax;
222- calcSplitInfo (t.min , t.max , t.dir , mid, newDir, newMin, newMax);
223-
224- const coord_type distToMid = t.dir == NodeSplitDirection::X
225- ? (point.x - mid)
226- : (point.y - mid);
227- const coord_type toMidSq = distToMid * distToMid;
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 ();
226+ switch (t.dir )
227+ {
228+ case NodeSplitDirection::X:
229+ {
230+ mid = (t.min .x + t.max .x ) / coord_type (2 );
231+ newDir = NodeSplitDirection::Y;
232+ newMin.x = mid;
233+ newMax.x = mid;
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 )),
237+ point.y - t.max .y );
238+ dSqFarther = dx * dx + dy * dy;
239+ break ;
240+ }
241+ case NodeSplitDirection::Y:
242+ {
243+ mid = (t.min .y + t.max .y ) / coord_type (2 );
244+ newDir = NodeSplitDirection::X;
245+ newMin.y = mid;
246+ newMax.y = mid;
247+ const coord_type dx = std::max (
248+ std::max (t.min .x - point.x , coord_type (0 )),
249+ point.x - t.max .x );
250+ const coord_type dy = point.y - mid;
251+ dSqFarther = dx * dx + dy * dy;
252+ break ;
253+ }
254+ }
228255
229- const std::size_t iChild = whichChild (point, mid, t.dir );
230256 if (iTask + 2 >= static_cast <int >(m_tasksStack.size ()))
231257 {
232258 m_tasksStack.resize (
233259 m_tasksStack.size () + StackDepthIncrement);
234260 }
235- // node containing point should end up on top of the stack
236- if (iChild == 0 )
261+
262+ // put the closest node on top of the stack
263+ if (isAfterSplit (point, mid, t.dir ))
237264 {
265+ if (dSqFarther <= minDistSq)
266+ {
267+ m_tasksStack[++iTask] = NearestTask (
268+ n.children [0 ], t.min , newMax, newDir, dSqFarther);
269+ }
238270 m_tasksStack[++iTask] = NearestTask (
239- n.children [1 ], newMin, t.max , newDir, toMidSq);
240- m_tasksStack[++iTask] = NearestTask (
241- n.children [0 ], t.min , newMax, newDir, toMidSq);
271+ n.children [1 ], newMin, t.max , newDir, t.distSq );
242272 }
243273 else
244274 {
275+ if (dSqFarther <= minDistSq)
276+ {
277+ m_tasksStack[++iTask] = NearestTask (
278+ n.children [1 ], newMin, t.max , newDir, dSqFarther);
279+ }
245280 m_tasksStack[++iTask] = NearestTask (
246- n.children [0 ], t.min , newMax, newDir, toMidSq);
247- m_tasksStack[++iTask] = NearestTask (
248- n.children [1 ], newMin, t.max , newDir, toMidSq);
281+ n.children [0 ], t.min , newMax, newDir, t.distSq );
249282 }
250283 }
251284 }
@@ -261,15 +294,22 @@ class KDTree
261294 return newNodeIndex;
262295 }
263296
297+ static bool isAfterSplit (
298+ const point_type& point,
299+ const coord_type& split,
300+ const NodeSplitDirection::Enum dir)
301+ {
302+ return dir == NodeSplitDirection::X ? point.x > split : point.y > split;
303+ }
304+
264305 // / Test which child point belongs to after the split
265306 // / @returns 0 if first child, 1 if second child
266- std::size_t whichChild (
307+ static std::size_t whichChild (
267308 const point_type& point,
268309 const coord_type& split,
269- const NodeSplitDirection::Enum dir) const
310+ const NodeSplitDirection::Enum dir)
270311 {
271- return static_cast <size_t >(
272- dir == NodeSplitDirection::X ? point.x > split : point.y > split);
312+ return isAfterSplit (point, split, dir);
273313 }
274314
275315 // / Calculate split location, direction, and children boxes
@@ -320,21 +360,29 @@ class KDTree
320360 {
321361 case NodeSplitDirection::X:
322362 m_rootDir = NodeSplitDirection::Y;
323- point.y < m_min.y ? m_nodes[newRoot].setChildren (newLeaf, m_root)
324- : m_nodes[newRoot].setChildren (m_root, newLeaf);
325363 if (point.y < m_min.y )
364+ {
326365 m_min.y -= m_max.y - m_min.y ;
327- else if (point.y > m_max.y )
366+ m_nodes[newRoot].setChildren (newLeaf, m_root);
367+ }
368+ else
369+ {
328370 m_max.y += m_max.y - m_min.y ;
371+ m_nodes[newRoot].setChildren (m_root, newLeaf);
372+ }
329373 break ;
330374 case NodeSplitDirection::Y:
331375 m_rootDir = NodeSplitDirection::X;
332- point.x < m_min.x ? m_nodes[newRoot].setChildren (newLeaf, m_root)
333- : m_nodes[newRoot].setChildren (m_root, newLeaf);
334376 if (point.x < m_min.x )
377+ {
335378 m_min.x -= m_max.x - m_min.x ;
336- else if (point.x > m_max.x )
379+ m_nodes[newRoot].setChildren (newLeaf, m_root);
380+ }
381+ else
382+ {
337383 m_max.x += m_max.x - m_min.x ;
384+ m_nodes[newRoot].setChildren (m_root, newLeaf);
385+ }
338386 break ;
339387 }
340388 m_root = newRoot;
@@ -368,6 +416,18 @@ class KDTree
368416 m_isRootBoxInitialized = true ;
369417 }
370418
419+ static coord_type distanceSquaredToBox (
420+ const point_type& p,
421+ const point_type& min,
422+ const point_type& max)
423+ {
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;
429+ }
430+
371431private:
372432 node_index m_root;
373433 std::vector<Node> m_nodes;
@@ -389,16 +449,16 @@ class KDTree
389449 : dir(NodeSplitDirection::X)
390450 {}
391451 NearestTask (
392- const node_index node_ ,
393- const point_type& min_ ,
394- const point_type& max_ ,
395- const NodeSplitDirection::Enum dir_ ,
396- const coord_type distSq_ )
397- : node(node_ )
398- , min(min_ )
399- , max(max_ )
400- , dir(dir_ )
401- , distSq(distSq_ )
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() )
457+ : node(node )
458+ , min(min )
459+ , max(max )
460+ , dir(dir )
461+ , distSq(distSq )
402462 {}
403463 };
404464 // allocated in class (not in the 'nearest' method) for better performance
0 commit comments