2 // ********************************************************************
3 // * License and Disclaimer *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
26 // $Id: G4KDTree.icc 93883 2015-11-03 08:25:04Z gcosmo $
28 // Author: Mathieu Karamitros (kara (AT) cenbg . in2p3 . fr)
32 // 10 Oct 2011 M.Karamitros created
34 // -------------------------------------------------------------------
36 * Based on ``kdtree'', a library for working with kd-trees.
37 * Copyright (C) 2007-2009 John Tsiombikas <nuclear@siggraph.org>
38 * The original open-source version of this code
39 * may be found at http://code.google.com/p/kdtree/
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions are
44 * 1. Redistributions of source code must retain the above copyright
46 * list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
49 * this list of conditions and the following disclaimer in the
51 * and/or other materials provided with the distribution.
52 * 3. The name of the author may not be used to endorse or promote products
53 * derived from this software without specific prior written permission.
55 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
56 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
57 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
58 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
59 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
60 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
61 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
62 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
63 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 /* single nearest neighbor search written by Tamas Nepusz
66 * <tamas@cs.rhul.ac.uk>
69 template<typename PointT>
70 G4KDNode_Base* G4KDTree::InsertMap(PointT* point)
72 G4KDNode<PointT>* node = new G4KDNode<PointT>(this, point, 0);
73 this->__InsertMap(node);
77 template<typename PointT>
78 G4KDNode_Base* G4KDTree::Insert(PointT* pos)
80 G4KDNode_Base* node = 0;
83 fRoot = new G4KDNode<PointT>(this, pos, 0);
91 if ((node = fRoot->Insert<PointT>(pos)))
100 fRect = new HyperRect(fDim);
101 fRect->SetMinMax(*pos, *pos);
111 template<typename PointT>
112 G4KDNode_Base* G4KDTree::Insert(const PointT& pos)
114 G4KDNode_Base* node = 0;
117 fRoot = new G4KDNodeCopy<PointT>(this, pos, 0);
125 if ((node = fRoot->Insert<PointT>(pos)))
134 fRect = new HyperRect(fDim);
135 fRect->SetMinMax(pos, pos);
145 //__________________________________________________________________
146 template<typename Position>
147 int G4KDTree::__NearestInRange(G4KDNode_Base* node,
149 const double& range_sq,
151 G4KDTreeResult& list,
153 G4KDNode_Base *source_node)
157 double dist_sq(DBL_MAX), dx(DBL_MAX);
158 int ret(-1), added_res(0);
160 if (node->IsValid() && node != source_node)
162 bool do_break = false;
164 for (size_t i = 0; i < fDim; i++)
166 dist_sq += sqr((*node)[i] - pos[i]);
167 if (dist_sq > range_sq)
173 if (!do_break && dist_sq <= range_sq)
175 list.Insert(dist_sq, node);
180 dx = pos[node->GetAxis()] - (*node)[node->GetAxis()];
182 ret = __NearestInRange(dx <= 0.0 ? node->GetLeft() : node->GetRight(), pos,
183 range_sq, range, list, ordered, source_node);
184 if (ret >= 0 && std::fabs(dx) <= range)
187 ret = __NearestInRange(dx <= 0.0 ? node->GetRight() : node->GetLeft(),
188 pos, range_sq, range, list, ordered, source_node);
200 //__________________________________________________________________
201 template<typename Position>
202 void G4KDTree::__NearestToPosition(G4KDNode_Base *node,
204 G4KDNode_Base *&result,
205 double *result_dist_sq,
208 int dir = node->GetAxis();
209 double dummy(0.), dist_sq(-1.);
210 G4KDNode_Base* nearer_subtree(0), *farther_subtree(0);
211 double *nearer_hyperrect_coord(0), *farther_hyperrect_coord(0);
213 /* Decide whether to go left or right in the tree */
214 dummy = pos[dir] - (*node)[dir];
217 nearer_subtree = node->GetLeft();
218 farther_subtree = node->GetRight();
220 nearer_hyperrect_coord = rect->GetMax() + dir;
221 farther_hyperrect_coord = rect->GetMin() + dir;
225 nearer_subtree = node->GetRight();
226 farther_subtree = node->GetLeft();
227 nearer_hyperrect_coord = rect->GetMin() + dir;
228 farther_hyperrect_coord = rect->GetMax() + dir;
233 /* Slice the hyperrect to get the hyperrect of the nearer subtree */
234 dummy = *nearer_hyperrect_coord;
235 *nearer_hyperrect_coord = (*node)[dir];
236 /* Recurse down into nearer subtree */
237 __NearestToPosition(nearer_subtree, pos, result, result_dist_sq, rect);
239 *nearer_hyperrect_coord = dummy;
242 /* Check the distance of the point at the current node, compare it
243 * with our best so far */
244 if (node->IsValid()) // TODO
247 bool do_break = false;
248 for (size_t i = 0; i < fDim; i++)
250 dist_sq += sqr((*node)[i] - pos[i]);
251 if (dist_sq > *result_dist_sq)
257 if (!do_break && dist_sq < *result_dist_sq)
260 *result_dist_sq = dist_sq;
266 /* Get the hyperrect of the farther subtree */
267 dummy = *farther_hyperrect_coord;
268 *farther_hyperrect_coord = (*node)[dir];
269 /* Check if we have to recurse down by calculating the closest
270 * point of the hyperrect and see if it's closer than our
271 * minimum distance in result_dist_sq. */
272 if (rect->CompareDistSqr(pos, result_dist_sq))
274 /* Recurse down into farther subtree */
275 __NearestToPosition(farther_subtree, pos, result, result_dist_sq, rect);
277 /* Undo the slice on the hyperrect */
278 *farther_hyperrect_coord = dummy;
282 template<typename Position>
283 G4KDTreeResultHandle G4KDTree::Nearest(const Position& pos)
285 // G4cout << "Nearest(pos)" << G4endl ;
287 if (!fRect) return 0;
289 G4KDNode_Base *result(0);
290 double dist_sq = DBL_MAX;
292 /* Duplicate the bounding hyperrectangle, we will work on the copy */
293 HyperRect* newrect = new HyperRect(*fRect);
295 /* Our first estimate is the root node */
296 /* Search for the nearest neighbour recursively */
297 __NearestToPosition(fRoot, pos, result, &dist_sq, newrect);
299 /* Free the copy of the hyperrect */
302 /* Store the result */
305 G4KDTreeResultHandle rset = new G4KDTreeResult(this);
306 rset->Insert(dist_sq, result);
316 //__________________________________________________________________
317 template<typename Position>
318 void G4KDTree::__NearestToNode(G4KDNode_Base* source_node,
321 std::vector<G4KDNode_Base*>& result,
322 double *result_dist_sq,
326 int dir = node->GetAxis();
327 double dummy, dist_sq;
328 G4KDNode_Base *nearer_subtree(0), *farther_subtree(0);
329 double *nearer_hyperrect_coord(0), *farther_hyperrect_coord(0);
331 /* Decide whether to go left or right in the tree */
332 dummy = pos[dir] - (*node)[dir];
335 nearer_subtree = node->GetLeft();
336 farther_subtree = node->GetRight();
337 nearer_hyperrect_coord = rect->GetMax() + dir;
338 farther_hyperrect_coord = rect->GetMin() + dir;
342 nearer_subtree = node->GetRight();
343 farther_subtree = node->GetLeft();
344 nearer_hyperrect_coord = rect->GetMin() + dir;
345 farther_hyperrect_coord = rect->GetMax() + dir;
350 /* Slice the hyperrect to get the hyperrect of the nearer subtree */
351 dummy = *nearer_hyperrect_coord;
352 *nearer_hyperrect_coord = (*node)[dir];
353 /* Recurse down into nearer subtree */
354 __NearestToNode(source_node, nearer_subtree, pos, result, result_dist_sq,
357 *nearer_hyperrect_coord = dummy;
360 /* Check the distance of the point at the current node, compare it
361 * with our best so far */
362 if (node->IsValid() && node != source_node)
365 bool do_break = false;
366 for (size_t i = 0; i < fDim; i++)
368 dist_sq += sqr((*node)[i] - pos[i]);
369 if (dist_sq > *result_dist_sq)
377 if (dist_sq < *result_dist_sq)
381 result.push_back(node);
382 *result_dist_sq = dist_sq;
384 else if (dist_sq == *result_dist_sq)
386 result.push_back(node);
394 /* Get the hyperrect of the farther subtree */
395 dummy = *farther_hyperrect_coord;
396 *farther_hyperrect_coord = (*node)[dir];
397 /* Check if we have to recurse down by calculating the closest
398 * point of the hyperrect and see if it's closer than our
399 * minimum distance in result_dist_sq. */
400 // if (hyperrect_dist_sq(rect, pos) < *result_dist_sq)
401 if (rect->CompareDistSqr(pos, result_dist_sq))
403 /* Recurse down into farther subtree */
404 __NearestToNode(source_node, farther_subtree, pos, result,
405 result_dist_sq, rect, nbresult);
407 /* Undo the slice on the hyperrect */
408 *farther_hyperrect_coord = dummy;
412 template<typename Position>
413 G4KDTreeResultHandle G4KDTree::NearestInRange(const Position& pos,
418 const double range_sq = sqr(range);
420 G4KDTreeResultHandle rset = new G4KDTreeResult(this);
421 if ((ret = __NearestInRange(fRoot, pos, range_sq, range, *(rset()), 0)) == -1)