diff options
author | Arnur Nigmetov <a.nigmetov@gmail.com> | 2018-01-20 19:11:29 +0100 |
---|---|---|
committer | Arnur Nigmetov <a.nigmetov@gmail.com> | 2018-01-20 19:11:29 +0100 |
commit | 0cc35ad04f9c2997014d7cf62a12f697e79fb534 (patch) | |
tree | 744c07bc2c12fba193934ac98417c5063bead189 /geom_bottleneck/bottleneck/src/ann | |
parent | 3552ce68bc7654df35da471bd937b09a9fde101f (diff) |
Major rewrite, templatized version
Diffstat (limited to 'geom_bottleneck/bottleneck/src/ann')
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/ANN.cpp | 239 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/bd_fix_rad_search.cpp | 64 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/bd_pr_search.cpp | 66 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/bd_search.cpp | 64 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/bd_tree.cpp | 422 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/kd_dump.cpp | 458 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/kd_fix_rad_search.cpp | 185 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/kd_pr_search.cpp | 221 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/kd_search.cpp | 298 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/kd_split.cpp | 632 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/kd_tree.cpp | 566 | ||||
-rw-r--r-- | geom_bottleneck/bottleneck/src/ann/kd_util.cpp | 441 |
12 files changed, 0 insertions, 3656 deletions
diff --git a/geom_bottleneck/bottleneck/src/ann/ANN.cpp b/geom_bottleneck/bottleneck/src/ann/ANN.cpp deleted file mode 100644 index 83c7ef6..0000000 --- a/geom_bottleneck/bottleneck/src/ann/ANN.cpp +++ /dev/null @@ -1,239 +0,0 @@ -//---------------------------------------------------------------------- -// File: ANN.cpp -// Programmer: Sunil Arya and David Mount -// Description: Methods for ANN.h and ANNx.h -// Last modified: 01/27/10 (Version 1.1.2) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2010 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 0.1 03/04/98 -// Initial release -// Revision 1.0 04/01/05 -// Added performance counting to annDist() -// Revision 1.1.2 01/27/10 -// Fixed minor compilation bugs for new versions of gcc -//---------------------------------------------------------------------- - -#ifdef _WIN32 -#include <ciso646> // make VS more conformal -#endif - -#include <stdexcept> -#include <cstdlib> // C standard lib defs -#include <ANN/ANNx.h> // all ANN includes -#include <ANN/ANNperf.h> // ANN performance -#include "def_debug_bt.h" - - - -using namespace std; // make std:: accessible - - -namespace geom_bt { -//---------------------------------------------------------------------- -// Point methods -//---------------------------------------------------------------------- - -//---------------------------------------------------------------------- -// Distance utility. -// (Note: In the nearest neighbor search, most distances are -// computed using partial distance calculations, not this -// procedure.) -//---------------------------------------------------------------------- - -ANNdist annDist( // interpoint squared distance - int dim, - ANNpoint p, - ANNpoint q) -{ - register int d; - register ANNcoord diff; - register ANNcoord dist; - - dist = 0; - for (d = 0; d < dim; d++) { - diff = p[d] - q[d]; - dist = ANN_SUM(dist, ANN_POW(diff)); - } - ANN_FLOP(3*dim) // performance counts - ANN_PTS(1) - ANN_COORD(dim) - return dist; -} - -//---------------------------------------------------------------------- -// annPrintPoint() prints a point to a given output stream. -//---------------------------------------------------------------------- - -void annPrintPt( // print a point - ANNpoint pt, // the point - int dim, // the dimension - std::ostream &out) // output stream -{ -#ifndef FOR_R_TDA - for (int j = 0; j < dim; j++) { - out << pt[j]; - if (j < dim-1) out << " "; - } -#endif -} - -//---------------------------------------------------------------------- -// Point allocation/deallocation: -// -// Because points (somewhat like strings in C) are stored -// as pointers. Consequently, creating and destroying -// copies of points may require storage allocation. These -// procedures do this. -// -// annAllocPt() and annDeallocPt() allocate a deallocate -// storage for a single point, and return a pointer to it. -// -// annAllocPts() allocates an array of points as well a place -// to store their coordinates, and initializes the points to -// point to their respective coordinates. It allocates point -// storage in a contiguous block large enough to store all the -// points. It performs no initialization. -// -// annDeallocPts() should only be used on point arrays allocated -// by annAllocPts since it assumes that points are allocated in -// a block. -// -// annCopyPt() copies a point taking care to allocate storage -// for the new point. -// -// annAssignRect() assigns the coordinates of one rectangle to -// another. The two rectangles must have the same dimension -// (and it is not possible to test this here). -//---------------------------------------------------------------------- - -ANNpoint annAllocPt(int dim, ANNcoord c) // allocate 1 point -{ - ANNpoint p = new ANNcoord[dim]; - for (int i = 0; i < dim; i++) p[i] = c; - return p; -} - -ANNpointArray annAllocPts(int n, int dim) // allocate n pts in dim -{ - ANNpointArray pa = new ANNpoint[n]; // allocate points - ANNpoint p = new ANNcoord[n*dim]; // allocate space for coords - for (int i = 0; i < n; i++) { - pa[i] = &(p[i*dim]); - } - return pa; -} - -void annDeallocPt(ANNpoint &p) // deallocate 1 point -{ - delete [] p; - p = NULL; -} - -void annDeallocPts(ANNpointArray &pa) // deallocate points -{ - delete [] pa[0]; // dealloc coordinate storage - delete [] pa; // dealloc points - pa = NULL; -} - -ANNpoint annCopyPt(int dim, ANNpoint source) // copy point -{ - ANNpoint p = new ANNcoord[dim]; - for (int i = 0; i < dim; i++) p[i] = source[i]; - return p; -} - - // assign one rect to another -void annAssignRect(int dim, ANNorthRect &dest, const ANNorthRect &source) -{ - for (int i = 0; i < dim; i++) { - dest.lo[i] = source.lo[i]; - dest.hi[i] = source.hi[i]; - } -} - - // is point inside rectangle? -ANNbool ANNorthRect::inside(const int dim, ANNpoint p) const -{ - for (int i = 0; i < dim; i++) { - if (p[i] < lo[i] || p[i] > hi[i]) return ANNfalse; - } - return ANNtrue; -} - -bool ANNorthRect::contains(const int dim, const ANNorthRect& r) const -{ - return this->inside(dim, r.hi) and this->inside(dim, r.lo); -} - -bool ANNorthRect::intersects(const int dim, const ANNorthRect& r) const -{ - assert(dim == 2); // works for plane only - const ANNpoint otherLo = r.lo; - const ANNpoint otherHi = r.hi; - if ( otherLo[0] > hi[0] or - otherLo[1] > hi[1] or - otherHi[0] < lo[0] or - otherHi[1] < lo[1]) { - return false; - } else { - return true; - } -} - -//---------------------------------------------------------------------- -// Error handler -//---------------------------------------------------------------------- - -void annError(const char* msg, ANNerr level) -{ - if (level == ANNabort) { -#ifndef FOR_R_TDA - cerr << "ANN: ERROR------->" << msg << "<-------------ERROR\n"; -#endif - throw std::runtime_error(std::string("ANN: Error: ") + std::string(msg)); - //exit(1); - } - else { -#ifndef FOR_R_TDA - cerr << "ANN: WARNING----->" << msg << "<-------------WARNING\n"; -#endif - } -} - -//---------------------------------------------------------------------- -// Limit on number of points visited -// We have an option for terminating the search early if the -// number of points visited exceeds some threshold. If the -// threshold is 0 (its default) this means there is no limit -// and the algorithm applies its normal termination condition. -// This is for applications where there are real time constraints -// on the running time of the algorithm. -//---------------------------------------------------------------------- - -int ANNmaxPtsVisited = 0; // maximum number of pts visited -int ANNptsVisited; // number of pts visited in search - -//---------------------------------------------------------------------- -// Global function declarations -//---------------------------------------------------------------------- - -void annMaxPtsVisit( // set limit on max. pts to visit in search - int maxPts) // the limit -{ - ANNmaxPtsVisited = maxPts; -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/bd_fix_rad_search.cpp b/geom_bottleneck/bottleneck/src/ann/bd_fix_rad_search.cpp deleted file mode 100644 index fe8ab78..0000000 --- a/geom_bottleneck/bottleneck/src/ann/bd_fix_rad_search.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//---------------------------------------------------------------------- -// File: bd_fix_rad_search.cpp -// Programmer: David Mount -// Description: Standard bd-tree search -// Last modified: 05/03/05 (Version 1.1) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 1.1 05/03/05 -// Initial release -//---------------------------------------------------------------------- - -#include "bd_tree.h" // bd-tree declarations -#include "kd_fix_rad_search.h" // kd-tree FR search declarations - -namespace geom_bt { - -//---------------------------------------------------------------------- -// Approximate searching for bd-trees. -// See the file kd_FR_search.cpp for general information on the -// approximate nearest neighbor search algorithm. Here we -// include the extensions for shrinking nodes. -//---------------------------------------------------------------------- - -//---------------------------------------------------------------------- -// bd_shrink::ann_FR_search - search a shrinking node -//---------------------------------------------------------------------- - -void ANNbd_shrink::ann_FR_search(ANNdist box_dist) -{ - // check dist calc term cond. - if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return; - - ANNdist inner_dist = 0; // distance to inner box - for (int i = 0; i < n_bnds; i++) { // is query point in the box? - if (bnds[i].out(ANNkdFRQ)) { // outside this bounding side? - // add to inner distance - inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdFRQ)); - } - } - if (inner_dist <= box_dist) { // if inner box is closer - child[ANN_IN]->ann_FR_search(inner_dist);// search inner child first - child[ANN_OUT]->ann_FR_search(box_dist);// ...then outer child - } - else { // if outer box is closer - child[ANN_OUT]->ann_FR_search(box_dist);// search outer child first - child[ANN_IN]->ann_FR_search(inner_dist);// ...then outer child - } - ANN_FLOP(3*n_bnds) // increment floating ops - ANN_SHR(1) // one more shrinking node -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/bd_pr_search.cpp b/geom_bottleneck/bottleneck/src/ann/bd_pr_search.cpp deleted file mode 100644 index fb9dea6..0000000 --- a/geom_bottleneck/bottleneck/src/ann/bd_pr_search.cpp +++ /dev/null @@ -1,66 +0,0 @@ -//---------------------------------------------------------------------- -// File: bd_pr_search.cpp -// Programmer: David Mount -// Description: Priority search for bd-trees -// Last modified: 01/04/05 (Version 1.0) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -//History: -// Revision 0.1 03/04/98 -// Initial release -//---------------------------------------------------------------------- - -#include "bd_tree.h" // bd-tree declarations -#include "kd_pr_search.h" // kd priority search declarations - - -namespace geom_bt { - -//---------------------------------------------------------------------- -// Approximate priority searching for bd-trees. -// See the file kd_pr_search.cc for general information on the -// approximate nearest neighbor priority search algorithm. Here -// we include the extensions for shrinking nodes. -//---------------------------------------------------------------------- - -//---------------------------------------------------------------------- -// bd_shrink::ann_search - search a shrinking node -//---------------------------------------------------------------------- - -void ANNbd_shrink::ann_pri_search(ANNdist box_dist) -{ - ANNdist inner_dist = 0; // distance to inner box - for (int i = 0; i < n_bnds; i++) { // is query point in the box? - if (bnds[i].out(ANNprQ)) { // outside this bounding side? - // add to inner distance - inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNprQ)); - } - } - if (inner_dist <= box_dist) { // if inner box is closer - if (child[ANN_OUT] != KD_TRIVIAL) // enqueue outer if not trivial - ANNprBoxPQ->insert(box_dist,child[ANN_OUT]); - // continue with inner child - child[ANN_IN]->ann_pri_search(inner_dist); - } - else { // if outer box is closer - if (child[ANN_IN] != KD_TRIVIAL) // enqueue inner if not trivial - ANNprBoxPQ->insert(inner_dist,child[ANN_IN]); - // continue with outer child - child[ANN_OUT]->ann_pri_search(box_dist); - } - ANN_FLOP(3*n_bnds) // increment floating ops - ANN_SHR(1) // one more shrinking node -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/bd_search.cpp b/geom_bottleneck/bottleneck/src/ann/bd_search.cpp deleted file mode 100644 index 2935bcb..0000000 --- a/geom_bottleneck/bottleneck/src/ann/bd_search.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//---------------------------------------------------------------------- -// File: bd_search.cpp -// Programmer: David Mount -// Description: Standard bd-tree search -// Last modified: 01/04/05 (Version 1.0) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 0.1 03/04/98 -// Initial release -//---------------------------------------------------------------------- - -#include "bd_tree.h" // bd-tree declarations -#include "kd_search.h" // kd-tree search declarations - -namespace geom_bt { - -//---------------------------------------------------------------------- -// Approximate searching for bd-trees. -// See the file kd_search.cpp for general information on the -// approximate nearest neighbor search algorithm. Here we -// include the extensions for shrinking nodes. -//---------------------------------------------------------------------- - -//---------------------------------------------------------------------- -// bd_shrink::ann_search - search a shrinking node -//---------------------------------------------------------------------- - -void ANNbd_shrink::ann_search(ANNdist box_dist) -{ - // check dist calc term cond. - if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return; - - ANNdist inner_dist = 0; // distance to inner box - for (int i = 0; i < n_bnds; i++) { // is query point in the box? - if (bnds[i].out(ANNkdQ)) { // outside this bounding side? - // add to inner distance - inner_dist = (ANNdist) ANN_SUM(inner_dist, bnds[i].dist(ANNkdQ)); - } - } - if (inner_dist <= box_dist) { // if inner box is closer - child[ANN_IN]->ann_search(inner_dist); // search inner child first - child[ANN_OUT]->ann_search(box_dist); // ...then outer child - } - else { // if outer box is closer - child[ANN_OUT]->ann_search(box_dist); // search outer child first - child[ANN_IN]->ann_search(inner_dist); // ...then outer child - } - ANN_FLOP(3*n_bnds) // increment floating ops - ANN_SHR(1) // one more shrinking node -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/bd_tree.cpp b/geom_bottleneck/bottleneck/src/ann/bd_tree.cpp deleted file mode 100644 index a5dd69c..0000000 --- a/geom_bottleneck/bottleneck/src/ann/bd_tree.cpp +++ /dev/null @@ -1,422 +0,0 @@ -//---------------------------------------------------------------------- -// File: bd_tree.cpp -// Programmer: David Mount -// Description: Basic methods for bd-trees. -// Last modified: 01/04/05 (Version 1.0) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 0.1 03/04/98 -// Initial release -// Revision l.0 04/01/05 -// Fixed centroid shrink threshold condition to depend on the -// dimension. -// Moved dump routine to kd_dump.cpp. -//---------------------------------------------------------------------- - -#include "bd_tree.h" // bd-tree declarations -#include "kd_util.h" // kd-tree utilities -#include "kd_split.h" // kd-tree splitting rules - -#include <ANN/ANNperf.h> // performance evaluation -#include "def_debug_bt.h" - -namespace geom_bt { -//---------------------------------------------------------------------- -// Printing a bd-tree -// These routines print a bd-tree. See the analogous procedure -// in kd_tree.cpp for more information. -//---------------------------------------------------------------------- - -void ANNbd_shrink::print( // print shrinking node - int level, // depth of node in tree - ostream &out) // output stream -{ -#ifndef FOR_R_TDA - child[ANN_OUT]->print(level+1, out); // print out-child - - out << " "; - for (int i = 0; i < level; i++) // print indentation - out << ".."; - out << "Shrink"; - for (int j = 0; j < n_bnds; j++) { // print sides, 2 per line - if (j % 2 == 0) { - out << "\n"; // newline and indentation - for (int i = 0; i < level+2; i++) out << " "; - } - out << " ([" << bnds[j].cd << "]" - << (bnds[j].sd > 0 ? ">=" : "< ") - << bnds[j].cv << ")"; - } - out << "\n"; - - child[ANN_IN]->print(level+1, out); // print in-child -#endif -} - -//---------------------------------------------------------------------- -// kd_tree statistics utility (for performance evaluation) -// This routine computes various statistics information for -// shrinking nodes. See file kd_tree.cpp for more information. -//---------------------------------------------------------------------- - -void ANNbd_shrink::getStats( // get subtree statistics - int dim, // dimension of space - ANNkdStats &st, // stats (modified) - ANNorthRect &bnd_box) // bounding box -{ - ANNkdStats ch_stats; // stats for children - ANNorthRect inner_box(dim); // inner box of shrink - - annBnds2Box(bnd_box, // enclosing box - dim, // dimension - n_bnds, // number of bounds - bnds, // bounds array - inner_box); // inner box (modified) - // get stats for inner child - ch_stats.reset(); // reset - child[ANN_IN]->getStats(dim, ch_stats, inner_box); - st.merge(ch_stats); // merge them - // get stats for outer child - ch_stats.reset(); // reset - child[ANN_OUT]->getStats(dim, ch_stats, bnd_box); - st.merge(ch_stats); // merge them - - st.depth++; // increment depth - st.n_shr++; // increment number of shrinks -} - -//---------------------------------------------------------------------- -// bd-tree constructor -// This is the main constructor for bd-trees given a set of points. -// It first builds a skeleton kd-tree as a basis, then computes the -// bounding box of the data points, and then invokes rbd_tree() to -// actually build the tree, passing it the appropriate splitting -// and shrinking information. -//---------------------------------------------------------------------- - -ANNkd_ptr rbd_tree( // recursive construction of bd-tree - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices to store in subtree - int n, // number of points - int dim, // dimension of space - int bsp, // bucket space - ANNorthRect &bnd_box, // bounding box for current node - ANNkd_splitter splitter, // splitting routine - ANNshrinkRule shrink); // shrinking rule - -ANNbd_tree::ANNbd_tree( // construct from point array - ANNpointArray pa, // point array (with at least n pts) - int n, // number of points - int dd, // dimension - int bs, // bucket size - ANNsplitRule split, // splitting rule - ANNshrinkRule shrink) // shrinking rule - : ANNkd_tree(n, dd, bs) // build skeleton base tree -{ - pts = pa; // where the points are - if (n == 0) return; // no points--no sweat - - ANNorthRect bnd_box(dd); // bounding box for points - // construct bounding rectangle - annEnclRect(pa, pidx, n, dd, bnd_box); - // copy to tree structure - bnd_box_lo = annCopyPt(dd, bnd_box.lo); - bnd_box_hi = annCopyPt(dd, bnd_box.hi); - - switch (split) { // build by rule - case ANN_KD_STD: // standard kd-splitting rule - root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split, shrink); - break; - case ANN_KD_MIDPT: // midpoint split - root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split, shrink); - break; - case ANN_KD_SUGGEST: // best (in our opinion) - case ANN_KD_SL_MIDPT: // sliding midpoint split - root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split, shrink); - break; - case ANN_KD_FAIR: // fair split - root = rbd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split, shrink); - break; - case ANN_KD_SL_FAIR: // sliding fair split - root = rbd_tree(pa, pidx, n, dd, bs, - bnd_box, sl_fair_split, shrink); - break; - default: - annError("Illegal splitting method", ANNabort); - } -} - -//---------------------------------------------------------------------- -// Shrinking rules -//---------------------------------------------------------------------- - -enum ANNdecomp {SPLIT, SHRINK}; // decomposition methods - -//---------------------------------------------------------------------- -// trySimpleShrink - Attempt a simple shrink -// -// We compute the tight bounding box of the points, and compute -// the 2*dim ``gaps'' between the sides of the tight box and the -// bounding box. If any of the gaps is large enough relative to -// the longest side of the tight bounding box, then we shrink -// all sides whose gaps are large enough. (The reason for -// comparing against the tight bounding box, is that after -// shrinking the longest box size will decrease, and if we use -// the standard bounding box, we may decide to shrink twice in -// a row. Since the tight box is fixed, we cannot shrink twice -// consecutively.) -//---------------------------------------------------------------------- -const float BD_GAP_THRESH = 0.5; // gap threshold (must be < 1) -const int BD_CT_THRESH = 2; // min number of shrink sides - -ANNdecomp trySimpleShrink( // try a simple shrink - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices to store in subtree - int n, // number of points - int dim, // dimension of space - const ANNorthRect &bnd_box, // current bounding box - ANNorthRect &inner_box) // inner box if shrinking (returned) -{ - int i; - // compute tight bounding box - annEnclRect(pa, pidx, n, dim, inner_box); - - ANNcoord max_length = 0; // find longest box side - for (i = 0; i < dim; i++) { - ANNcoord length = inner_box.hi[i] - inner_box.lo[i]; - if (length > max_length) { - max_length = length; - } - } - - int shrink_ct = 0; // number of sides we shrunk - for (i = 0; i < dim; i++) { // select which sides to shrink - // gap between boxes - ANNcoord gap_hi = bnd_box.hi[i] - inner_box.hi[i]; - // big enough gap to shrink? - if (gap_hi < max_length*BD_GAP_THRESH) - inner_box.hi[i] = bnd_box.hi[i]; // no - expand - else shrink_ct++; // yes - shrink this side - - // repeat for high side - ANNcoord gap_lo = inner_box.lo[i] - bnd_box.lo[i]; - if (gap_lo < max_length*BD_GAP_THRESH) - inner_box.lo[i] = bnd_box.lo[i]; // no - expand - else shrink_ct++; // yes - shrink this side - } - - if (shrink_ct >= BD_CT_THRESH) // did we shrink enough sides? - return SHRINK; - else return SPLIT; -} - -//---------------------------------------------------------------------- -// tryCentroidShrink - Attempt a centroid shrink -// -// We repeatedly apply the splitting rule, always to the larger subset -// of points, until the number of points decreases by the constant -// fraction BD_FRACTION. If this takes more than dim*BD_MAX_SPLIT_FAC -// splits for this to happen, then we shrink to the final inner box -// Otherwise we split. -//---------------------------------------------------------------------- - -const float BD_MAX_SPLIT_FAC = 0.5; // maximum number of splits allowed -const float BD_FRACTION = 0.5; // ...to reduce points by this fraction - // ...This must be < 1. - -ANNdecomp tryCentroidShrink( // try a centroid shrink - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices to store in subtree - int n, // number of points - int dim, // dimension of space - const ANNorthRect &bnd_box, // current bounding box - ANNkd_splitter splitter, // splitting procedure - ANNorthRect &inner_box) // inner box if shrinking (returned) -{ - int n_sub = n; // number of points in subset - int n_goal = (int) (n*BD_FRACTION); // number of point in goal - int n_splits = 0; // number of splits needed - // initialize inner box to bounding box - annAssignRect(dim, inner_box, bnd_box); - - while (n_sub > n_goal) { // keep splitting until goal reached - int cd; // cut dim from splitter (ignored) - ANNcoord cv; // cut value from splitter (ignored) - int n_lo; // number of points on low side - // invoke splitting procedure - (*splitter)(pa, pidx, inner_box, n_sub, dim, cd, cv, n_lo); - n_splits++; // increment split count - - if (n_lo >= n_sub/2) { // most points on low side - inner_box.hi[cd] = cv; // collapse high side - n_sub = n_lo; // recurse on lower points - } - else { // most points on high side - inner_box.lo[cd] = cv; // collapse low side - pidx += n_lo; // recurse on higher points - n_sub -= n_lo; - } - } - if (n_splits > dim*BD_MAX_SPLIT_FAC)// took too many splits - return SHRINK; // shrink to final subset - else - return SPLIT; -} - -//---------------------------------------------------------------------- -// selectDecomp - select which decomposition to use -//---------------------------------------------------------------------- - -ANNdecomp selectDecomp( // select decomposition method - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices to store in subtree - int n, // number of points - int dim, // dimension of space - const ANNorthRect &bnd_box, // current bounding box - ANNkd_splitter splitter, // splitting procedure - ANNshrinkRule shrink, // shrinking rule - ANNorthRect &inner_box) // inner box if shrinking (returned) -{ - ANNdecomp decomp = SPLIT; // decomposition - - switch (shrink) { // check shrinking rule - case ANN_BD_NONE: // no shrinking allowed - decomp = SPLIT; - break; - case ANN_BD_SUGGEST: // author's suggestion - case ANN_BD_SIMPLE: // simple shrink - decomp = trySimpleShrink( - pa, pidx, // points and indices - n, dim, // number of points and dimension - bnd_box, // current bounding box - inner_box); // inner box if shrinking (returned) - break; - case ANN_BD_CENTROID: // centroid shrink - decomp = tryCentroidShrink( - pa, pidx, // points and indices - n, dim, // number of points and dimension - bnd_box, // current bounding box - splitter, // splitting procedure - inner_box); // inner box if shrinking (returned) - break; - default: - annError("Illegal shrinking rule", ANNabort); - } - return decomp; -} - -//---------------------------------------------------------------------- -// rbd_tree - recursive procedure to build a bd-tree -// -// This is analogous to rkd_tree, but for bd-trees. See the -// procedure rkd_tree() in kd_split.cpp for more information. -// -// If the number of points falls below the bucket size, then a -// leaf node is created for the points. Otherwise we invoke the -// procedure selectDecomp() which determines whether we are to -// split or shrink. If splitting is chosen, then we essentially -// do exactly as rkd_tree() would, and invoke the specified -// splitting procedure to the points. Otherwise, the selection -// procedure returns a bounding box, from which we extract the -// appropriate shrinking bounds, and create a shrinking node. -// Finally the points are subdivided, and the procedure is -// invoked recursively on the two subsets to form the children. -//---------------------------------------------------------------------- - -ANNkd_ptr rbd_tree( // recursive construction of bd-tree - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices to store in subtree - int n, // number of points - int dim, // dimension of space - int bsp, // bucket space - ANNorthRect &bnd_box, // bounding box for current node - ANNkd_splitter splitter, // splitting routine - ANNshrinkRule shrink) // shrinking rule -{ - ANNdecomp decomp; // decomposition method - - ANNorthRect inner_box(dim); // inner box (if shrinking) - - if (n <= bsp) { // n small, make a leaf node - if (n == 0) // empty leaf node - return KD_TRIVIAL; // return (canonical) empty leaf - else // construct the node and return - return new ANNkd_leaf(n, pidx); - } - - decomp = selectDecomp( // select decomposition method - pa, pidx, // points and indices - n, dim, // number of points and dimension - bnd_box, // current bounding box - splitter, shrink, // splitting/shrinking methods - inner_box); // inner box if shrinking (returned) - - if (decomp == SPLIT) { // split selected - int cd; // cutting dimension - ANNcoord cv; // cutting value - int n_lo; // number on low side of cut - // invoke splitting procedure - (*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo); - - ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension - ANNcoord hv = bnd_box.hi[cd]; - - bnd_box.hi[cd] = cv; // modify bounds for left subtree - ANNkd_ptr lo = rbd_tree( // build left subtree - pa, pidx, n_lo, // ...from pidx[0..n_lo-1] - dim, bsp, bnd_box, splitter, shrink); - bnd_box.hi[cd] = hv; // restore bounds - - bnd_box.lo[cd] = cv; // modify bounds for right subtree - ANNkd_ptr hi = rbd_tree( // build right subtree - pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1] - dim, bsp, bnd_box, splitter, shrink); - bnd_box.lo[cd] = lv; // restore bounds - // create the splitting node - return new ANNkd_split(cd, cv, lv, hv, lo, hi); - } - else { // shrink selected - int n_in; // number of points in box - int n_bnds; // number of bounding sides - - annBoxSplit( // split points around inner box - pa, // points to split - pidx, // point indices - n, // number of points - dim, // dimension - inner_box, // inner box - n_in); // number of points inside (returned) - - ANNkd_ptr in = rbd_tree( // build inner subtree pidx[0..n_in-1] - pa, pidx, n_in, dim, bsp, inner_box, splitter, shrink); - ANNkd_ptr out = rbd_tree( // build outer subtree pidx[n_in..n] - pa, pidx+n_in, n - n_in, dim, bsp, bnd_box, splitter, shrink); - - ANNorthHSArray bnds = NULL; // bounds (alloc in Box2Bnds and - // ...freed in bd_shrink destroyer) - - annBox2Bnds( // convert inner box to bounds - inner_box, // inner box - bnd_box, // enclosing box - dim, // dimension - n_bnds, // number of bounds (returned) - bnds); // bounds array (modified) - - // return shrinking node - return new ANNbd_shrink(n_bnds, bnds, in, out); - } -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/kd_dump.cpp b/geom_bottleneck/bottleneck/src/ann/kd_dump.cpp deleted file mode 100644 index ecaf7ea..0000000 --- a/geom_bottleneck/bottleneck/src/ann/kd_dump.cpp +++ /dev/null @@ -1,458 +0,0 @@ -//---------------------------------------------------------------------- -// File: kd_dump.cc -// Programmer: David Mount -// Description: Dump and Load for kd- and bd-trees -// Last modified: 01/04/05 (Version 1.0) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 0.1 03/04/98 -// Initial release -// Revision 1.0 04/01/05 -// Moved dump out of kd_tree.cc into this file. -// Added kd-tree load constructor. -//---------------------------------------------------------------------- -// This file contains routines for dumping kd-trees and bd-trees and -// reloading them. (It is an abuse of policy to include both kd- and -// bd-tree routines in the same file, sorry. There should be no problem -// in deleting the bd- versions of the routines if they are not -// desired.) -//---------------------------------------------------------------------- - -#include "kd_tree.h" // kd-tree declarations -#include "bd_tree.h" // bd-tree declarations -#include "def_debug_bt.h" - -using namespace std; // make std:: available - -namespace geom_bt { - - //---------------------------------------------------------------------- - // Constants - //---------------------------------------------------------------------- - - const int STRING_LEN = 500; // maximum string length - const double EPSILON = 1E-5; // small number for float comparison - - enum ANNtreeType { KD_TREE, BD_TREE }; // tree types (used in loading) - - //---------------------------------------------------------------------- - // Procedure declarations - //---------------------------------------------------------------------- - - static ANNkd_ptr annReadDump( // read dump file - istream &in, // input stream - ANNtreeType tree_type, // type of tree expected - ANNpointArray &the_pts, // new points (if applic) - ANNidxArray &the_pidx, // point indices (returned) - int &the_dim, // dimension (returned) - int &the_n_pts, // number of points (returned) - int &the_bkt_size, // bucket size (returned) - ANNpoint &the_bnd_box_lo, // low bounding point - ANNpoint &the_bnd_box_hi); // high bounding point - - static ANNkd_ptr annReadTree( // read tree-part of dump file - istream &in, // input stream - ANNtreeType tree_type, // type of tree expected - ANNidxArray the_pidx, // point indices (modified) - int &next_idx); // next index (modified) - - //---------------------------------------------------------------------- - // ANN kd- and bd-tree Dump Format - // The dump file begins with a header containing the version of - // ANN, an optional section containing the points, followed by - // a description of the tree. The tree is printed in preorder. - // - // Format: - // #ANN <version number> <comments> [END_OF_LINE] - // points <dim> <n_pts> (point coordinates: this is optional) - // 0 <xxx> <xxx> ... <xxx> (point indices and coordinates) - // 1 <xxx> <xxx> ... <xxx> - // ... - // tree <dim> <n_pts> <bkt_size> - // <xxx> <xxx> ... <xxx> (lower end of bounding box) - // <xxx> <xxx> ... <xxx> (upper end of bounding box) - // If the tree is null, then a single line "null" is - // output. Otherwise the nodes of the tree are printed - // one per line in preorder. Leaves and splitting nodes - // have the following formats: - // Leaf node: - // leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]> - // Splitting nodes: - // split <cut_dim> <cut_val> <lo_bound> <hi_bound> - // - // For bd-trees: - // - // Shrinking nodes: - // shrink <n_bnds> - // <cut_dim> <cut_val> <side> - // <cut_dim> <cut_val> <side> - // ... (repeated n_bnds times) - //---------------------------------------------------------------------- - -#ifndef FOR_R_TDA - void ANNkd_tree::Dump( // dump entire tree - ANNbool with_pts, // print points as well? - ostream &out) // output stream - { - out << "#ANN " << ANNversion << "\n"; - out.precision(ANNcoordPrec); // use full precision in dumping - if (with_pts) { // print point coordinates - out << "points " << dim << " " << n_pts << "\n"; - for (int i = 0; i < n_pts; i++) { - out << i << " "; - annPrintPt(pts[i], dim, out); - out << "\n"; - } - } - out << "tree " // print tree elements - << dim << " " - << n_pts << " " - << bkt_size << "\n"; - - annPrintPt(bnd_box_lo, dim, out); // print lower bound - out << "\n"; - annPrintPt(bnd_box_hi, dim, out); // print upper bound - out << "\n"; - - if (root == NULL) // empty tree? - out << "null\n"; - else { - root->dump(out); // invoke printing at root - } - out.precision(0); // restore default precision - } -#endif - - void ANNkd_split::dump( // dump a splitting node - ostream &out) // output stream - { -#ifndef FOR_R_TDA - out << "split " << cut_dim << " " << cut_val << " "; - out << cd_bnds[ANN_LO] << " " << cd_bnds[ANN_HI] << "\n"; - - child[ANN_LO]->dump(out); // print low child - child[ANN_HI]->dump(out); // print high child -#endif - } - - void ANNkd_leaf::dump( // dump a leaf node - ostream &out) // output stream - { -#ifndef FOR_R_TDA - if (this == KD_TRIVIAL) { // canonical trivial leaf node - out << "leaf 0\n"; // leaf no points - } - else { - out << "leaf " << n_pts; - for (int j = 0; j < n_pts; j++) { - out << " " << bkt[j]; - } - out << "\n"; - } -#endif - } - - void ANNbd_shrink::dump( // dump a shrinking node - ostream &out) // output stream - { -#ifndef FOR_R_TDA - out << "shrink " << n_bnds << "\n"; - for (int j = 0; j < n_bnds; j++) { - out << bnds[j].cd << " " << bnds[j].cv << " " << bnds[j].sd << "\n"; - } - child[ANN_IN]->dump(out); // print in-child - child[ANN_OUT]->dump(out); // print out-child -#endif - } - - //---------------------------------------------------------------------- - // Load kd-tree from dump file - // This rebuilds a kd-tree which was dumped to a file. The dump - // file contains all the basic tree information according to a - // preorder traversal. We assume that the dump file also contains - // point data. (This is to guarantee the consistency of the tree.) - // If not, then an error is generated. - // - // Indirectly, this procedure allocates space for points, point - // indices, all nodes in the tree, and the bounding box for the - // tree. When the tree is destroyed, all but the points are - // deallocated. - // - // This routine calls annReadDump to do all the work. - //---------------------------------------------------------------------- - - ANNkd_tree::ANNkd_tree( // build from dump file - istream &in) // input stream for dump file - { - int the_dim; // local dimension - int the_n_pts; // local number of points - int the_bkt_size; // local number of points - ANNpoint the_bnd_box_lo; // low bounding point - ANNpoint the_bnd_box_hi; // high bounding point - ANNpointArray the_pts; // point storage - ANNidxArray the_pidx; // point index storage - ANNkd_ptr the_root; // root of the tree - - the_root = annReadDump( // read the dump file - in, // input stream - KD_TREE, // expecting a kd-tree - the_pts, // point array (returned) - the_pidx, // point indices (returned) - the_dim, the_n_pts, the_bkt_size, // basic tree info (returned) - the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned) - - // create a skeletal tree - SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx); - - bnd_box_lo = the_bnd_box_lo; - bnd_box_hi = the_bnd_box_hi; - - root = the_root; // set the root - } - - ANNbd_tree::ANNbd_tree( // build bd-tree from dump file - istream &in) : ANNkd_tree() // input stream for dump file - { - int the_dim; // local dimension - int the_n_pts; // local number of points - int the_bkt_size; // local number of points - ANNpoint the_bnd_box_lo; // low bounding point - ANNpoint the_bnd_box_hi; // high bounding point - ANNpointArray the_pts; // point storage - ANNidxArray the_pidx; // point index storage - ANNkd_ptr the_root; // root of the tree - - the_root = annReadDump( // read the dump file - in, // input stream - BD_TREE, // expecting a bd-tree - the_pts, // point array (returned) - the_pidx, // point indices (returned) - the_dim, the_n_pts, the_bkt_size, // basic tree info (returned) - the_bnd_box_lo, the_bnd_box_hi); // bounding box info (returned) - - // create a skeletal tree - SkeletonTree(the_n_pts, the_dim, the_bkt_size, the_pts, the_pidx); - bnd_box_lo = the_bnd_box_lo; - bnd_box_hi = the_bnd_box_hi; - - root = the_root; // set the root - } - - //---------------------------------------------------------------------- - // annReadDump - read a dump file - // - // This procedure reads a dump file, constructs a kd-tree - // and returns all the essential information needed to actually - // construct the tree. Because this procedure is used for - // constructing both kd-trees and bd-trees, the second argument - // is used to indicate which type of tree we are expecting. - //---------------------------------------------------------------------- - - static ANNkd_ptr annReadDump( - istream &in, // input stream - ANNtreeType tree_type, // type of tree expected - ANNpointArray &the_pts, // new points (returned) - ANNidxArray &the_pidx, // point indices (returned) - int &the_dim, // dimension (returned) - int &the_n_pts, // number of points (returned) - int &the_bkt_size, // bucket size (returned) - ANNpoint &the_bnd_box_lo, // low bounding point (ret'd) - ANNpoint &the_bnd_box_hi) // high bounding point (ret'd) - { - int j; - char str[STRING_LEN]; // storage for string - char version[STRING_LEN]; // ANN version number - ANNkd_ptr the_root = NULL; - - //------------------------------------------------------------------ - // Input file header - //------------------------------------------------------------------ - in >> str; // input header - if (strcmp(str, "#ANN") != 0) { // incorrect header - annError("Incorrect header for dump file", ANNabort); - } - in.getline(version, STRING_LEN); // get version (ignore) - - //------------------------------------------------------------------ - // Input the points - // An array the_pts is allocated and points are read from - // the dump file. - //------------------------------------------------------------------ - in >> str; // get major heading - if (strcmp(str, "points") == 0) { // points section - in >> the_dim; // input dimension - in >> the_n_pts; // number of points - // allocate point storage - the_pts = annAllocPts(the_n_pts, the_dim); - for (int i = 0; i < the_n_pts; i++) { // input point coordinates - ANNidx idx; // point index - in >> idx; // input point index - if (idx < 0 || idx >= the_n_pts) { - annError("Point index is out of range", ANNabort); - } - for (j = 0; j < the_dim; j++) { - in >> the_pts[idx][j]; // read point coordinates - } - } - in >> str; // get next major heading - } - else { // no points were input - annError("Points must be supplied in the dump file", ANNabort); - } - - //------------------------------------------------------------------ - // Input the tree - // After the basic header information, we invoke annReadTree - // to do all the heavy work. We create our own array of - // point indices (so we can pass them to annReadTree()) - // but we do not deallocate them. They will be deallocated - // when the tree is destroyed. - //------------------------------------------------------------------ - if (strcmp(str, "tree") == 0) { // tree section - in >> the_dim; // read dimension - in >> the_n_pts; // number of points - in >> the_bkt_size; // bucket size - the_bnd_box_lo = annAllocPt(the_dim); // allocate bounding box pts - the_bnd_box_hi = annAllocPt(the_dim); - - for (j = 0; j < the_dim; j++) { // read bounding box low - in >> the_bnd_box_lo[j]; - } - for (j = 0; j < the_dim; j++) { // read bounding box low - in >> the_bnd_box_hi[j]; - } - the_pidx = new ANNidx[the_n_pts]; // allocate point index array - int next_idx = 0; // number of indices filled - // read the tree and indices - the_root = annReadTree(in, tree_type, the_pidx, next_idx); - if (next_idx != the_n_pts) { // didn't see all the points? - annError("Didn't see as many points as expected", ANNwarn); - } - } - else { - annError("Illegal dump format. Expecting section heading", ANNabort); - } - return the_root; - } - - //---------------------------------------------------------------------- - // annReadTree - input tree and return pointer - // - // annReadTree reads in a node of the tree, makes any recursive - // calls as needed to input the children of this node (if internal). - // It returns a pointer to the node that was created. An array - // of point indices is given along with a pointer to the next - // available location in the array. As leaves are read, their - // point indices are stored here, and the point buckets point - // to the first entry in the array. - // - // Recall that these are the formats. The tree is given in - // preorder. - // - // Leaf node: - // leaf <n_pts> <bkt[0]> <bkt[1]> ... <bkt[n-1]> - // Splitting nodes: - // split <cut_dim> <cut_val> <lo_bound> <hi_bound> - // - // For bd-trees: - // - // Shrinking nodes: - // shrink <n_bnds> - // <cut_dim> <cut_val> <side> - // <cut_dim> <cut_val> <side> - // ... (repeated n_bnds times) - //---------------------------------------------------------------------- - - static ANNkd_ptr annReadTree( - istream &in, // input stream - ANNtreeType tree_type, // type of tree expected - ANNidxArray the_pidx, // point indices (modified) - int &next_idx) // next index (modified) - { - char tag[STRING_LEN]; // tag (leaf, split, shrink) - int n_pts; // number of points in leaf - int cd; // cut dimension - ANNcoord cv; // cut value - ANNcoord lb; // low bound - ANNcoord hb; // high bound - int n_bnds; // number of bounding sides - int sd; // which side - - in >> tag; // input node tag - - if (strcmp(tag, "null") == 0) { // null tree - return NULL; - } - //------------------------------------------------------------------ - // Read a leaf - //------------------------------------------------------------------ - if (strcmp(tag, "leaf") == 0) { // leaf node - - in >> n_pts; // input number of points - int old_idx = next_idx; // save next_idx - if (n_pts == 0) { // trivial leaf - return KD_TRIVIAL; - } - else { - for (int i = 0; i < n_pts; i++) { // input point indices - in >> the_pidx[next_idx++]; // store in array of indices - } - } - return new ANNkd_leaf(n_pts, &the_pidx[old_idx]); - } - //------------------------------------------------------------------ - // Read a splitting node - //------------------------------------------------------------------ - else if (strcmp(tag, "split") == 0) { // splitting node - - in >> cd >> cv >> lb >> hb; - - // read low and high subtrees - ANNkd_ptr lc = annReadTree(in, tree_type, the_pidx, next_idx); - ANNkd_ptr hc = annReadTree(in, tree_type, the_pidx, next_idx); - // create new node and return - return new ANNkd_split(cd, cv, lb, hb, lc, hc); - } - //------------------------------------------------------------------ - // Read a shrinking node (bd-tree only) - //------------------------------------------------------------------ - else if (strcmp(tag, "shrink") == 0) { // shrinking node - if (tree_type != BD_TREE) { - annError("Shrinking node not allowed in kd-tree", ANNabort); - } - - in >> n_bnds; // number of bounding sides - // allocate bounds array - ANNorthHSArray bds = new ANNorthHalfSpace[n_bnds]; - for (int i = 0; i < n_bnds; i++) { - in >> cd >> cv >> sd; // input bounding halfspace - // copy to array - bds[i] = ANNorthHalfSpace(cd, cv, sd); - } - // read inner and outer subtrees - ANNkd_ptr ic = annReadTree(in, tree_type, the_pidx, next_idx); - ANNkd_ptr oc = annReadTree(in, tree_type, the_pidx, next_idx); - // create new node and return - return new ANNbd_shrink(n_bnds, bds, ic, oc); - } - else { - annError("Illegal node type in dump file", ANNabort); -#ifndef FOR_R_TDA - exit(0); // to keep the compiler happy -#endif - } - } -} diff --git a/geom_bottleneck/bottleneck/src/ann/kd_fix_rad_search.cpp b/geom_bottleneck/bottleneck/src/ann/kd_fix_rad_search.cpp deleted file mode 100644 index 1a4749e..0000000 --- a/geom_bottleneck/bottleneck/src/ann/kd_fix_rad_search.cpp +++ /dev/null @@ -1,185 +0,0 @@ -//---------------------------------------------------------------------- -// File: kd_fix_rad_search.cpp -// Programmer: Sunil Arya and David Mount -// Description: Standard kd-tree fixed-radius kNN search -// Last modified: 05/03/05 (Version 1.1) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 1.1 05/03/05 -// Initial release -//---------------------------------------------------------------------- - -#include "kd_fix_rad_search.h" // kd fixed-radius search decls - -namespace geom_bt { -//---------------------------------------------------------------------- -// Approximate fixed-radius k nearest neighbor search -// The squared radius is provided, and this procedure finds the -// k nearest neighbors within the radius, and returns the total -// number of points lying within the radius. -// -// The method used for searching the kd-tree is a variation of the -// nearest neighbor search used in kd_search.cpp, except that the -// radius of the search ball is known. We refer the reader to that -// file for the explanation of the recursive search procedure. -//---------------------------------------------------------------------- - -//---------------------------------------------------------------------- -// To keep argument lists short, a number of global variables -// are maintained which are common to all the recursive calls. -// These are given below. -//---------------------------------------------------------------------- - -int ANNkdFRDim; // dimension of space -ANNpoint ANNkdFRQ; // query point -ANNdist ANNkdFRSqRad; // squared radius search bound -double ANNkdFRMaxErr; // max tolerable squared error -ANNpointArray ANNkdFRPts; // the points -ANNmin_k* ANNkdFRPointMK; // set of k closest points -int ANNkdFRPtsVisited; // total points visited -int ANNkdFRPtsInRange; // number of points in the range - -//---------------------------------------------------------------------- -// annkFRSearch - fixed radius search for k nearest neighbors -//---------------------------------------------------------------------- - -int ANNkd_tree::annkFRSearch( - ANNpoint q, // the query point - ANNdist sqRad, // squared radius search bound - int k, // number of near neighbors to return - ANNidxArray nn_idx, // nearest neighbor indices (returned) - ANNdistArray dd, // the approximate nearest neighbor - double eps) // the error bound -{ - ANNkdFRDim = dim; // copy arguments to static equivs - ANNkdFRQ = q; - ANNkdFRSqRad = sqRad; - ANNkdFRPts = pts; - ANNkdFRPtsVisited = 0; // initialize count of points visited - ANNkdFRPtsInRange = 0; // ...and points in the range - - ANNkdFRMaxErr = ANN_POW(1.0 + eps); - ANN_FLOP(2) // increment floating op count - - ANNkdFRPointMK = new ANNmin_k(k); // create set for closest k points - // search starting at the root - root->ann_FR_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim)); - - for (int i = 0; i < k; i++) { // extract the k-th closest points - if (dd != NULL) - dd[i] = ANNkdFRPointMK->ith_smallest_key(i); - if (nn_idx != NULL) - nn_idx[i] = ANNkdFRPointMK->ith_smallest_info(i); - } - - delete ANNkdFRPointMK; // deallocate closest point set - return ANNkdFRPtsInRange; // return final point count -} - -//---------------------------------------------------------------------- -// kd_split::ann_FR_search - search a splitting node -// Note: This routine is similar in structure to the standard kNN -// search. It visits the subtree that is closer to the query point -// first. For fixed-radius search, there is no benefit in visiting -// one subtree before the other, but we maintain the same basic -// code structure for the sake of uniformity. -//---------------------------------------------------------------------- - -void ANNkd_split::ann_FR_search(ANNdist box_dist) -{ - // check dist calc term condition - if (ANNmaxPtsVisited != 0 && ANNkdFRPtsVisited > ANNmaxPtsVisited) return; - - // distance to cutting plane - ANNcoord cut_diff = ANNkdFRQ[cut_dim] - cut_val; - - if (cut_diff < 0) { // left of cutting plane - child[ANN_LO]->ann_FR_search(box_dist);// visit closer child first - - ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdFRQ[cut_dim]; - if (box_diff < 0) // within bounds - ignore - box_diff = 0; - // distance to further box - box_dist = (ANNdist) ANN_SUM(box_dist, - ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); - - // visit further child if in range - if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad) - child[ANN_HI]->ann_FR_search(box_dist); - - } - else { // right of cutting plane - child[ANN_HI]->ann_FR_search(box_dist);// visit closer child first - - ANNcoord box_diff = ANNkdFRQ[cut_dim] - cd_bnds[ANN_HI]; - if (box_diff < 0) // within bounds - ignore - box_diff = 0; - // distance to further box - box_dist = (ANNdist) ANN_SUM(box_dist, - ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); - - // visit further child if close enough - if (box_dist * ANNkdFRMaxErr <= ANNkdFRSqRad) - child[ANN_LO]->ann_FR_search(box_dist); - - } - ANN_FLOP(13) // increment floating ops - ANN_SPL(1) // one more splitting node visited -} - -//---------------------------------------------------------------------- -// kd_leaf::ann_FR_search - search points in a leaf node -// Note: The unreadability of this code is the result of -// some fine tuning to replace indexing by pointer operations. -//---------------------------------------------------------------------- - -void ANNkd_leaf::ann_FR_search(ANNdist box_dist) -{ - register ANNdist dist; // distance to data point - register ANNcoord* pp; // data coordinate pointer - register ANNcoord* qq; // query coordinate pointer - register ANNcoord t; - register int d; - - for (int i = 0; i < n_pts; i++) { // check points in bucket - - pp = ANNkdFRPts[bkt[i]]; // first coord of next data point - qq = ANNkdFRQ; // first coord of query point - dist = 0; - - for(d = 0; d < ANNkdFRDim; d++) { - ANN_COORD(1) // one more coordinate hit - ANN_FLOP(5) // increment floating ops - - t = *(qq++) - *(pp++); // compute length and adv coordinate - // exceeds dist to k-th smallest? - if( (dist = ANN_SUM(dist, ANN_POW(t))) > ANNkdFRSqRad) { - break; - } - } - - if (d >= ANNkdFRDim && // among the k best? - (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem - // add it to the list - ANNkdFRPointMK->insert(dist, bkt[i]); - ANNkdFRPtsInRange++; // increment point count - } - } - ANN_LEAF(1) // one more leaf node visited - ANN_PTS(n_pts) // increment points visited - ANNkdFRPtsVisited += n_pts; // increment number of points visited -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/kd_pr_search.cpp b/geom_bottleneck/bottleneck/src/ann/kd_pr_search.cpp deleted file mode 100644 index 73d643f..0000000 --- a/geom_bottleneck/bottleneck/src/ann/kd_pr_search.cpp +++ /dev/null @@ -1,221 +0,0 @@ -//---------------------------------------------------------------------- -// File: kd_pr_search.cpp -// Programmer: Sunil Arya and David Mount -// Description: Priority search for kd-trees -// Last modified: 01/04/05 (Version 1.0) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 0.1 03/04/98 -// Initial release -//---------------------------------------------------------------------- - -#include "kd_pr_search.h" // kd priority search declarations - -namespace geom_bt { -//---------------------------------------------------------------------- -// Approximate nearest neighbor searching by priority search. -// The kd-tree is searched for an approximate nearest neighbor. -// The point is returned through one of the arguments, and the -// distance returned is the SQUARED distance to this point. -// -// The method used for searching the kd-tree is called priority -// search. (It is described in Arya and Mount, ``Algorithms for -// fast vector quantization,'' Proc. of DCC '93: Data Compression -// Conference}, eds. J. A. Storer and M. Cohn, IEEE Press, 1993, -// 381--390.) -// -// The cell of the kd-tree containing the query point is located, -// and cells are visited in increasing order of distance from the -// query point. This is done by placing each subtree which has -// NOT been visited in a priority queue, according to the closest -// distance of the corresponding enclosing rectangle from the -// query point. The search stops when the distance to the nearest -// remaining rectangle exceeds the distance to the nearest point -// seen by a factor of more than 1/(1+eps). (Implying that any -// point found subsequently in the search cannot be closer by more -// than this factor.) -// -// The main entry point is annkPriSearch() which sets things up and -// then call the recursive routine ann_pri_search(). This is a -// recursive routine which performs the processing for one node in -// the kd-tree. There are two versions of this virtual procedure, -// one for splitting nodes and one for leaves. When a splitting node -// is visited, we determine which child to continue the search on -// (the closer one), and insert the other child into the priority -// queue. When a leaf is visited, we compute the distances to the -// points in the buckets, and update information on the closest -// points. -// -// Some trickery is used to incrementally update the distance from -// a kd-tree rectangle to the query point. This comes about from -// the fact that which each successive split, only one component -// (along the dimension that is split) of the squared distance to -// the child rectangle is different from the squared distance to -// the parent rectangle. -//---------------------------------------------------------------------- - -//---------------------------------------------------------------------- -// To keep argument lists short, a number of global variables -// are maintained which are common to all the recursive calls. -// These are given below. -//---------------------------------------------------------------------- - -double ANNprEps; // the error bound -int ANNprDim; // dimension of space -ANNpoint ANNprQ; // query point -double ANNprMaxErr; // max tolerable squared error -ANNpointArray ANNprPts; // the points -ANNpr_queue *ANNprBoxPQ; // priority queue for boxes -ANNmin_k *ANNprPointMK; // set of k closest points - -//---------------------------------------------------------------------- -// annkPriSearch - priority search for k nearest neighbors -//---------------------------------------------------------------------- - -void ANNkd_tree::annkPriSearch( - ANNpoint q, // query point - int k, // number of near neighbors to return - ANNidxArray nn_idx, // nearest neighbor indices (returned) - ANNdistArray dd, // dist to near neighbors (returned) - double eps) // error bound (ignored) -{ - // max tolerable squared error - ANNprMaxErr = ANN_POW(1.0 + eps); - ANN_FLOP(2) // increment floating ops - - ANNprDim = dim; // copy arguments to static equivs - ANNprQ = q; - ANNprPts = pts; - ANNptsVisited = 0; // initialize count of points visited - - ANNprPointMK = new ANNmin_k(k); // create set for closest k points - - // distance to root box - ANNdist box_dist = annBoxDistance(q, - bnd_box_lo, bnd_box_hi, dim); - - ANNprBoxPQ = new ANNpr_queue(n_pts);// create priority queue for boxes - ANNprBoxPQ->insert(box_dist, root); // insert root in priority queue - - while (ANNprBoxPQ->non_empty() && - (!(ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited))) { - ANNkd_ptr np; // next box from prior queue - - // extract closest box from queue - ANNprBoxPQ->extr_min(box_dist, (void *&) np); - - ANN_FLOP(2) // increment floating ops - if (box_dist*ANNprMaxErr >= ANNprPointMK->max_key()) - break; - - np->ann_pri_search(box_dist); // search this subtree. - } - - for (int i = 0; i < k; i++) { // extract the k-th closest points - dd[i] = ANNprPointMK->ith_smallest_key(i); - nn_idx[i] = ANNprPointMK->ith_smallest_info(i); - } - - delete ANNprPointMK; // deallocate closest point set - delete ANNprBoxPQ; // deallocate priority queue -} - -//---------------------------------------------------------------------- -// kd_split::ann_pri_search - search a splitting node -//---------------------------------------------------------------------- - -void ANNkd_split::ann_pri_search(ANNdist box_dist) -{ - ANNdist new_dist; // distance to child visited later - // distance to cutting plane - ANNcoord cut_diff = ANNprQ[cut_dim] - cut_val; - - if (cut_diff < 0) { // left of cutting plane - ANNcoord box_diff = cd_bnds[ANN_LO] - ANNprQ[cut_dim]; - if (box_diff < 0) // within bounds - ignore - box_diff = 0; - // distance to further box - new_dist = (ANNdist) ANN_SUM(box_dist, - ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); - - if (child[ANN_HI] != KD_TRIVIAL)// enqueue if not trivial - ANNprBoxPQ->insert(new_dist, child[ANN_HI]); - // continue with closer child - child[ANN_LO]->ann_pri_search(box_dist); - } - else { // right of cutting plane - ANNcoord box_diff = ANNprQ[cut_dim] - cd_bnds[ANN_HI]; - if (box_diff < 0) // within bounds - ignore - box_diff = 0; - // distance to further box - new_dist = (ANNdist) ANN_SUM(box_dist, - ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); - - if (child[ANN_LO] != KD_TRIVIAL)// enqueue if not trivial - ANNprBoxPQ->insert(new_dist, child[ANN_LO]); - // continue with closer child - child[ANN_HI]->ann_pri_search(box_dist); - } - ANN_SPL(1) // one more splitting node visited - ANN_FLOP(8) // increment floating ops -} - -//---------------------------------------------------------------------- -// kd_leaf::ann_pri_search - search points in a leaf node -// -// This is virtually identical to the ann_search for standard search. -//---------------------------------------------------------------------- - -void ANNkd_leaf::ann_pri_search(ANNdist box_dist) -{ - register ANNdist dist; // distance to data point - register ANNcoord* pp; // data coordinate pointer - register ANNcoord* qq; // query coordinate pointer - register ANNdist min_dist; // distance to k-th closest point - register ANNcoord t; - register int d; - - min_dist = ANNprPointMK->max_key(); // k-th smallest distance so far - - for (int i = 0; i < n_pts; i++) { // check points in bucket - - pp = ANNprPts[bkt[i]]; // first coord of next data point - qq = ANNprQ; // first coord of query point - dist = 0; - - for(d = 0; d < ANNprDim; d++) { - ANN_COORD(1) // one more coordinate hit - ANN_FLOP(4) // increment floating ops - - t = *(qq++) - *(pp++); // compute length and adv coordinate - // exceeds dist to k-th smallest? - if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) { - break; - } - } - - if (d >= ANNprDim && // among the k best? - (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem - // add it to the list - ANNprPointMK->insert(dist, bkt[i]); - min_dist = ANNprPointMK->max_key(); - } - } - ANN_LEAF(1) // one more leaf node visited - ANN_PTS(n_pts) // increment points visited - ANNptsVisited += n_pts; // increment number of points visited -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/kd_search.cpp b/geom_bottleneck/bottleneck/src/ann/kd_search.cpp deleted file mode 100644 index f559eb9..0000000 --- a/geom_bottleneck/bottleneck/src/ann/kd_search.cpp +++ /dev/null @@ -1,298 +0,0 @@ -//---------------------------------------------------------------------- -// File: kd_search.cpp -// Programmer: Sunil Arya and David Mount -// Description: Standard kd-tree search -// Last modified: 01/04/05 (Version 1.0) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 0.1 03/04/98 -// Initial release -// Revision 1.0 04/01/05 -// Changed names LO, HI to ANN_LO, ANN_HI -// -------------------------------------------------------------------- -// 2015 - modified by A. Nigmetov to support deletion of points -//---------------------------------------------------------------------- - -#include "kd_search.h" // kd-search declarations - -namespace geom_bt { -//---------------------------------------------------------------------- -// Approximate nearest neighbor searching by kd-tree search -// The kd-tree is searched for an approximate nearest neighbor. -// The point is returned through one of the arguments, and the -// distance returned is the squared distance to this point. -// -// The method used for searching the kd-tree is an approximate -// adaptation of the search algorithm described by Friedman, -// Bentley, and Finkel, ``An algorithm for finding best matches -// in logarithmic expected time,'' ACM Transactions on Mathematical -// Software, 3(3):209-226, 1977). -// -// The algorithm operates recursively. When first encountering a -// node of the kd-tree we first visit the child which is closest to -// the query point. On return, we decide whether we want to visit -// the other child. If the box containing the other child exceeds -// 1/(1+eps) times the current best distance, then we skip it (since -// any point found in this child cannot be closer to the query point -// by more than this factor.) Otherwise, we visit it recursively. -// The distance between a box and the query point is computed exactly -// (not approximated as is often done in kd-tree), using incremental -// distance updates, as described by Arya and Mount in ``Algorithms -// for fast vector quantization,'' Proc. of DCC '93: Data Compression -// Conference, eds. J. A. Storer and M. Cohn, IEEE Press, 1993, -// 381-390. -// -// The main entry points is annkSearch() which sets things up and -// then call the recursive routine ann_search(). This is a recursive -// routine which performs the processing for one node in the kd-tree. -// There are two versions of this virtual procedure, one for splitting -// nodes and one for leaves. When a splitting node is visited, we -// determine which child to visit first (the closer one), and visit -// the other child on return. When a leaf is visited, we compute -// the distances to the points in the buckets, and update information -// on the closest points. -// -// Some trickery is used to incrementally update the distance from -// a kd-tree rectangle to the query point. This comes about from -// the fact that which each successive split, only one component -// (along the dimension that is split) of the squared distance to -// the child rectangle is different from the squared distance to -// the parent rectangle. -//---------------------------------------------------------------------- - -//---------------------------------------------------------------------- -// To keep argument lists short, a number of global variables -// are maintained which are common to all the recursive calls. -// These are given below. -//---------------------------------------------------------------------- - -int ANNkdDim; // dimension of space -ANNpoint ANNkdQ; // query point -double ANNkdMaxErr; // max tolerable squared error -ANNpointArray ANNkdPts; // the points -ANNmin_k *ANNkdPointMK; // set of k closest points - -//---------------------------------------------------------------------- -// annkSearch - search for the k nearest neighbors -//---------------------------------------------------------------------- - -void ANNkd_tree::annkSearch( - ANNpoint q, // the query point - int k, // number of near neighbors to return - ANNidxArray nn_idx, // nearest neighbor indices (returned) - ANNdistArray dd, // the approximate nearest neighbor - double eps) // the error bound -{ - - ANNkdDim = dim; // copy arguments to static equivs - ANNkdQ = q; - ANNkdPts = pts; - ANNptsVisited = 0; // initialize count of points visited - - if (k > actual_num_points) { // too many near neighbors? - annError("Requesting more near neighbors than data points", ANNabort); - } - - ANNkdMaxErr = ANN_POW(1.0 + eps); - ANN_FLOP(2) // increment floating op count - - ANNkdPointMK = new ANNmin_k(k); // create set for closest k points - // search starting at the root - root->ann_search(annBoxDistance(q, bnd_box_lo, bnd_box_hi, dim)); - - for (int i = 0; i < k; i++) { // extract the k-th closest points - dd[i] = ANNkdPointMK->ith_smallest_key(i); - nn_idx[i] = ANNkdPointMK->ith_smallest_info(i); - } - delete ANNkdPointMK; // deallocate closest point set -} - -//---------------------------------------------------------------------- -// kd_split::ann_search - search a splitting node -//---------------------------------------------------------------------- - -void ANNkd_split::ann_search(ANNdist box_dist) -{ - // check if the subtree is empty - if (0 == actual_num_points) return; - // check dist calc term condition - if (ANNmaxPtsVisited != 0 && ANNptsVisited > ANNmaxPtsVisited) return; - - // distance to cutting plane - ANNcoord cut_diff = ANNkdQ[cut_dim] - cut_val; - - if (cut_diff < 0) { // left of cutting plane - child[ANN_LO]->ann_search(box_dist);// visit closer child first - - ANNcoord box_diff = cd_bnds[ANN_LO] - ANNkdQ[cut_dim]; - if (box_diff < 0) // within bounds - ignore - box_diff = 0; - // distance to further box - box_dist = (ANNdist) ANN_SUM(box_dist, - ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); - - // visit further child if close enough - if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key()) - child[ANN_HI]->ann_search(box_dist); - - } - else { // right of cutting plane - child[ANN_HI]->ann_search(box_dist);// visit closer child first - - ANNcoord box_diff = ANNkdQ[cut_dim] - cd_bnds[ANN_HI]; - if (box_diff < 0) // within bounds - ignore - box_diff = 0; - // distance to further box - box_dist = (ANNdist) ANN_SUM(box_dist, - ANN_DIFF(ANN_POW(box_diff), ANN_POW(cut_diff))); - - // visit further child if close enough - if (box_dist * ANNkdMaxErr < ANNkdPointMK->max_key()) - child[ANN_LO]->ann_search(box_dist); - - } - ANN_FLOP(10) // increment floating ops - ANN_SPL(1) // one more splitting node visited -} - -//---------------------------------------------------------------------- -// kd_leaf::ann_search - search points in a leaf node -// Note: The unreadability of this code is the result of -// some fine tuning to replace indexing by pointer operations. -//---------------------------------------------------------------------- - -void ANNkd_leaf::ann_search(ANNdist box_dist) -{ - register ANNdist dist; // distance to data point - register ANNcoord* pp; // data coordinate pointer - register ANNcoord* qq; // query coordinate pointer - register ANNdist min_dist; // distance to k-th closest point - register ANNcoord t; - register int d; - - min_dist = ANNkdPointMK->max_key(); // k-th smallest distance so far - - for (int i = 0; i < n_pts; i++) { // check points in bucket - - pp = ANNkdPts[bkt[i]]; // first coord of next data point - qq = ANNkdQ; // first coord of query point - dist = 0; - - for(d = 0; d < ANNkdDim; d++) { - ANN_COORD(1) // one more coordinate hit - ANN_FLOP(4) // increment floating ops - - t = *(qq++) - *(pp++); // compute length and adv coordinate - // exceeds dist to k-th smallest? - if( (dist = ANN_SUM(dist, ANN_POW(t))) > min_dist) { - break; - } - } - - if (d >= ANNkdDim && // among the k best? - (ANN_ALLOW_SELF_MATCH || dist!=0)) { // and no self-match problem - // add it to the list - ANNkdPointMK->insert(dist, bkt[i]); - min_dist = ANNkdPointMK->max_key(); - } - } - ANN_LEAF(1) // one more leaf node visited - ANN_PTS(n_pts) // increment points visited - ANNptsVisited += n_pts; // increment number of points visited -} - - - -//////////////////////////////////////////////// -// range search -// //////////////////////////////////////////// - -void ANNkd_tree::range_search(const ANNorthRect& region, - std::vector<size_t>& point_indices) -{ - - // get bounding box of the root - ANNorthRect bnd_box = ANNorthRect(dim, bnd_box_lo, bnd_box_hi); - root->range_search(region, dim, pts, bnd_box, point_indices); -} - -void ANNkd_split::range_search(const ANNorthRect& region, - int ANNkdDim, - ANNpointArray ANNkdPts, - ANNorthRect& bnd_box, - std::vector<size_t>& point_indices) -{ - // check if the subtree is empty - if (0 == actual_num_points) return; - - // process left child - ANNcoord old_bnd_box_val = bnd_box.hi[cut_dim]; - bnd_box.hi[cut_dim] = cut_val; - if (region.contains(ANNkdDim, bnd_box)) { - child[ANN_LO]->range_search_add(point_indices); - } else if (region.intersects(ANNkdDim, bnd_box)) { - child[ANN_LO]->range_search(region, ANNkdDim, ANNkdPts, bnd_box, point_indices); - } - // restore bounding box - bnd_box.hi[cut_dim] = old_bnd_box_val; - // process right child - old_bnd_box_val = bnd_box.lo[cut_dim]; - bnd_box.lo[cut_dim] = cut_val; - if (region.contains(ANNkdDim, bnd_box)) { - child[ANN_HI]->range_search_add(point_indices); - } else if (region.intersects(ANNkdDim, bnd_box)) { - child[ANN_HI]->range_search(region, ANNkdDim, ANNkdPts, bnd_box, point_indices); - } - // restore bounding box - bnd_box.lo[cut_dim] = old_bnd_box_val; -} - -void ANNkd_leaf::range_search(const ANNorthRect& region, - int ANNkdDim, - ANNpointArray ANNkdPts, - ANNorthRect&, // nameless parameter to suppress - // warnings and allow recursion - // in splitting node - std::vector<size_t>& point_indices) -{ - for (int i = 0; i < n_pts; i++) { // check points in bucket - if (region.inside(ANNkdDim, ANNkdPts[bkt[i]]) == ANNtrue) { - //std::cout << "adding point, i = " << i; - //std::cout << ", x = " << ANNkdPts[bkt[i]][0]; - //std::cout << ", y = " << ANNkdPts[bkt[i]][1] << std::endl; - point_indices.push_back(bkt[i]); - } - } -} - -void ANNkd_split::range_search_add(std::vector<size_t>& point_indices) -{ - if ( 0 == actual_num_points ) - return; - child[ANN_LO]->range_search_add(point_indices); - child[ANN_HI]->range_search_add(point_indices); -} - -void ANNkd_leaf::range_search_add(std::vector<size_t>& point_indices) -{ - if ( 0 == actual_num_points ) - return; - for (int i = 0; i < n_pts; i++) { // add all points in a bucket - //std::cout << "adding point without checking, i = " << i <<", bkt[i] = " << bkt[i] << std::endl; - point_indices.push_back(bkt[i]); - } -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/kd_split.cpp b/geom_bottleneck/bottleneck/src/ann/kd_split.cpp deleted file mode 100644 index 7979aaa..0000000 --- a/geom_bottleneck/bottleneck/src/ann/kd_split.cpp +++ /dev/null @@ -1,632 +0,0 @@ -//---------------------------------------------------------------------- -// File: kd_split.cpp -// Programmer: Sunil Arya and David Mount -// Description: Methods for splitting kd-trees -// Last modified: 01/04/05 (Version 1.0) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 0.1 03/04/98 -// Initial release -// Revision 1.0 04/01/05 -//---------------------------------------------------------------------- - -#include "kd_tree.h" // kd-tree definitions -#include "kd_util.h" // kd-tree utilities -#include "kd_split.h" // splitting functions - -namespace geom_bt { -//---------------------------------------------------------------------- -// Constants -//---------------------------------------------------------------------- - -const double ERR = 0.001; // a small value -const double FS_ASPECT_RATIO = 3.0; // maximum allowed aspect ratio - // in fair split. Must be >= 2. - -//---------------------------------------------------------------------- -// NOTE: Virtually all point indexing is done through an index (i.e. -// permutation) array pidx. Consequently, a reference to the d-th -// coordinate of the i-th point is pa[pidx[i]][d]. The macro PA(i,d) -// is a shorthand for this. -//---------------------------------------------------------------------- - // standard 2-d indirect indexing -#define PA(i,d) (pa[pidx[(i)]][(d)]) - // accessing a single point -#define PP(i) (pa[pidx[(i)]]) - - -//---------------------------------------------------------------------- -// kd_split - Bentley's standard splitting routine for kd-trees -// Find the dimension of the greatest spread, and split -// just before the median point along this dimension. -//---------------------------------------------------------------------- - -void kd_split( - ANNpointArray pa, // point array (permuted on return) - ANNidxArray pidx, // point indices - const ANNorthRect &bnds, // bounding rectangle for cell - int n, // number of points - int dim, // dimension of space - int &cut_dim, // cutting dimension (returned) - ANNcoord &cut_val, // cutting value (returned) - int &n_lo) // num of points on low side (returned) -{ - // find dimension of maximum spread - cut_dim = annMaxSpread(pa, pidx, n, dim); - n_lo = n/2; // median rank - // split about median - annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); -} - -//---------------------------------------------------------------------- -// midpt_split - midpoint splitting rule for box-decomposition trees -// -// This is the simplest splitting rule that guarantees boxes -// of bounded aspect ratio. It simply cuts the box with the -// longest side through its midpoint. If there are ties, it -// selects the dimension with the maximum point spread. -// -// WARNING: This routine (while simple) doesn't seem to work -// well in practice in high dimensions, because it tends to -// generate a large number of trivial and/or unbalanced splits. -// Either kd_split(), sl_midpt_split(), or fair_split() are -// recommended, instead. -//---------------------------------------------------------------------- - -void midpt_split( - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices (permuted on return) - const ANNorthRect &bnds, // bounding rectangle for cell - int n, // number of points - int dim, // dimension of space - int &cut_dim, // cutting dimension (returned) - ANNcoord &cut_val, // cutting value (returned) - int &n_lo) // num of points on low side (returned) -{ - int d; - - ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; - for (d = 1; d < dim; d++) { // find length of longest box side - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - if (length > max_length) { - max_length = length; - } - } - ANNcoord max_spread = -1; // find long side with most spread - for (d = 0; d < dim; d++) { - // is it among longest? - if (double(bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) { - // compute its spread - ANNcoord spr = annSpread(pa, pidx, n, d); - if (spr > max_spread) { // is it max so far? - max_spread = spr; - cut_dim = d; - } - } - } - // split along cut_dim at midpoint - cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim]) / 2; - // permute points accordingly - int br1, br2; - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - //------------------------------------------------------------------ - // On return: pa[0..br1-1] < cut_val - // pa[br1..br2-1] == cut_val - // pa[br2..n-1] > cut_val - // - // We can set n_lo to any value in the range [br1..br2]. - // We choose split so that points are most evenly divided. - //------------------------------------------------------------------ - if (br1 > n/2) n_lo = br1; - else if (br2 < n/2) n_lo = br2; - else n_lo = n/2; -} - -//---------------------------------------------------------------------- -// sl_midpt_split - sliding midpoint splitting rule -// -// This is a modification of midpt_split, which has the nonsensical -// name "sliding midpoint". The idea is that we try to use the -// midpoint rule, by bisecting the longest side. If there are -// ties, the dimension with the maximum spread is selected. If, -// however, the midpoint split produces a trivial split (no points -// on one side of the splitting plane) then we slide the splitting -// (maintaining its orientation) until it produces a nontrivial -// split. For example, if the splitting plane is along the x-axis, -// and all the data points have x-coordinate less than the x-bisector, -// then the split is taken along the maximum x-coordinate of the -// data points. -// -// Intuitively, this rule cannot generate trivial splits, and -// hence avoids midpt_split's tendency to produce trees with -// a very large number of nodes. -// -//---------------------------------------------------------------------- - -void sl_midpt_split( - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices (permuted on return) - const ANNorthRect &bnds, // bounding rectangle for cell - int n, // number of points - int dim, // dimension of space - int &cut_dim, // cutting dimension (returned) - ANNcoord &cut_val, // cutting value (returned) - int &n_lo) // num of points on low side (returned) -{ - int d; - - ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; - for (d = 1; d < dim; d++) { // find length of longest box side - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - if (length > max_length) { - max_length = length; - } - } - ANNcoord max_spread = -1; // find long side with most spread - for (d = 0; d < dim; d++) { - // is it among longest? - if ((bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) { - // compute its spread - ANNcoord spr = annSpread(pa, pidx, n, d); - if (spr > max_spread) { // is it max so far? - max_spread = spr; - cut_dim = d; - } - } - } - // ideal split at midpoint - ANNcoord ideal_cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim])/2; - - ANNcoord min, max; - annMinMax(pa, pidx, n, cut_dim, min, max); // find min/max coordinates - - if (ideal_cut_val < min) // slide to min or max as needed - cut_val = min; - else if (ideal_cut_val > max) - cut_val = max; - else - cut_val = ideal_cut_val; - - // permute points accordingly - int br1, br2; - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - //------------------------------------------------------------------ - // On return: pa[0..br1-1] < cut_val - // pa[br1..br2-1] == cut_val - // pa[br2..n-1] > cut_val - // - // We can set n_lo to any value in the range [br1..br2] to satisfy - // the exit conditions of the procedure. - // - // if ideal_cut_val < min (implying br2 >= 1), - // then we select n_lo = 1 (so there is one point on left) and - // if ideal_cut_val > max (implying br1 <= n-1), - // then we select n_lo = n-1 (so there is one point on right). - // Otherwise, we select n_lo as close to n/2 as possible within - // [br1..br2]. - //------------------------------------------------------------------ - if (ideal_cut_val < min) n_lo = 1; - else if (ideal_cut_val > max) n_lo = n-1; - else if (br1 > n/2) n_lo = br1; - else if (br2 < n/2) n_lo = br2; - else n_lo = n/2; -} - -//---------------------------------------------------------------------- -// fair_split - fair-split splitting rule -// -// This is a compromise between the kd-tree splitting rule (which -// always splits data points at their median) and the midpoint -// splitting rule (which always splits a box through its center. -// The goal of this procedure is to achieve both nicely balanced -// splits, and boxes of bounded aspect ratio. -// -// A constant FS_ASPECT_RATIO is defined. Given a box, those sides -// which can be split so that the ratio of the longest to shortest -// side does not exceed ASPECT_RATIO are identified. Among these -// sides, we select the one in which the points have the largest -// spread. We then split the points in a manner which most evenly -// distributes the points on either side of the splitting plane, -// subject to maintaining the bound on the ratio of long to short -// sides. To determine that the aspect ratio will be preserved, -// we determine the longest side (other than this side), and -// determine how narrowly we can cut this side, without causing the -// aspect ratio bound to be exceeded (small_piece). -// -// This procedure is more robust than either kd_split or midpt_split, -// but is more complicated as well. When point distribution is -// extremely skewed, this degenerates to midpt_split (actually -// 1/3 point split), and when the points are most evenly distributed, -// this degenerates to kd-split. -//---------------------------------------------------------------------- - -void fair_split( - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices (permuted on return) - const ANNorthRect &bnds, // bounding rectangle for cell - int n, // number of points - int dim, // dimension of space - int &cut_dim, // cutting dimension (returned) - ANNcoord &cut_val, // cutting value (returned) - int &n_lo) // num of points on low side (returned) -{ - int d; - ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; - cut_dim = 0; - for (d = 1; d < dim; d++) { // find length of longest box side - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - if (length > max_length) { - max_length = length; - cut_dim = d; - } - } - - ANNcoord max_spread = 0; // find legal cut with max spread - cut_dim = 0; - for (d = 0; d < dim; d++) { - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - // is this side midpoint splitable - // without violating aspect ratio? - if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) { - // compute spread along this dim - ANNcoord spr = annSpread(pa, pidx, n, d); - if (spr > max_spread) { // best spread so far - max_spread = spr; - cut_dim = d; // this is dimension to cut - } - } - } - - max_length = 0; // find longest side other than cut_dim - for (d = 0; d < dim; d++) { - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - if (d != cut_dim && length > max_length) - max_length = length; - } - // consider most extreme splits - ANNcoord small_piece = max_length / FS_ASPECT_RATIO; - ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut - ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut - - int br1, br2; - // is median below lo_cut ? - if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) { - cut_val = lo_cut; // cut at lo_cut - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - n_lo = br1; - } - // is median above hi_cut? - else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) { - cut_val = hi_cut; // cut at hi_cut - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - n_lo = br2; - } - else { // median cut preserves asp ratio - n_lo = n/2; // split about median - annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); - } -} - -//---------------------------------------------------------------------- -// sl_fair_split - sliding fair split splitting rule -// -// Sliding fair split is a splitting rule that combines the -// strengths of both fair split with sliding midpoint split. -// Fair split tends to produce balanced splits when the points -// are roughly uniformly distributed, but it can produce many -// trivial splits when points are highly clustered. Sliding -// midpoint never produces trivial splits, and shrinks boxes -// nicely if points are highly clustered, but it may produce -// rather unbalanced splits when points are unclustered but not -// quite uniform. -// -// Sliding fair split is based on the theory that there are two -// types of splits that are "good": balanced splits that produce -// fat boxes, and unbalanced splits provided the cell with fewer -// points is fat. -// -// This splitting rule operates by first computing the longest -// side of the current bounding box. Then it asks which sides -// could be split (at the midpoint) and still satisfy the aspect -// ratio bound with respect to this side. Among these, it selects -// the side with the largest spread (as fair split would). It -// then considers the most extreme cuts that would be allowed by -// the aspect ratio bound. This is done by dividing the longest -// side of the box by the aspect ratio bound. If the median cut -// lies between these extreme cuts, then we use the median cut. -// If not, then consider the extreme cut that is closer to the -// median. If all the points lie to one side of this cut, then -// we slide the cut until it hits the first point. This may -// violate the aspect ratio bound, but will never generate empty -// cells. However the sibling of every such skinny cell is fat, -// and hence packing arguments still apply. -// -//---------------------------------------------------------------------- - -void sl_fair_split( - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices (permuted on return) - const ANNorthRect &bnds, // bounding rectangle for cell - int n, // number of points - int dim, // dimension of space - int &cut_dim, // cutting dimension (returned) - ANNcoord &cut_val, // cutting value (returned) - int &n_lo) // num of points on low side (returned) -{ - int d; - ANNcoord min, max; // min/max coordinates - int br1, br2; // split break points - - ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; - cut_dim = 0; - for (d = 1; d < dim; d++) { // find length of longest box side - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - if (length > max_length) { - max_length = length; - cut_dim = d; - } - } - - ANNcoord max_spread = 0; // find legal cut with max spread - cut_dim = 0; - for (d = 0; d < dim; d++) { - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - // is this side midpoint splitable - // without violating aspect ratio? - if (((double) max_length)*2.0/((double) length) <= FS_ASPECT_RATIO) { - // compute spread along this dim - ANNcoord spr = annSpread(pa, pidx, n, d); - if (spr > max_spread) { // best spread so far - max_spread = spr; - cut_dim = d; // this is dimension to cut - } - } - } - - max_length = 0; // find longest side other than cut_dim - for (d = 0; d < dim; d++) { - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - if (d != cut_dim && length > max_length) - max_length = length; - } - // consider most extreme splits - ANNcoord small_piece = max_length / FS_ASPECT_RATIO; - ANNcoord lo_cut = bnds.lo[cut_dim] + small_piece;// lowest legal cut - ANNcoord hi_cut = bnds.hi[cut_dim] - small_piece;// highest legal cut - // find min and max along cut_dim - annMinMax(pa, pidx, n, cut_dim, min, max); - // is median below lo_cut? - if (annSplitBalance(pa, pidx, n, cut_dim, lo_cut) >= 0) { - if (max > lo_cut) { // are any points above lo_cut? - cut_val = lo_cut; // cut at lo_cut - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - n_lo = br1; // balance if there are ties - } - else { // all points below lo_cut - cut_val = max; // cut at max value - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - n_lo = n-1; - } - } - // is median above hi_cut? - else if (annSplitBalance(pa, pidx, n, cut_dim, hi_cut) <= 0) { - if (min < hi_cut) { // are any points below hi_cut? - cut_val = hi_cut; // cut at hi_cut - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - n_lo = br2; // balance if there are ties - } - else { // all points above hi_cut - cut_val = min; // cut at min value - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - n_lo = 1; - } - } - else { // median cut is good enough - n_lo = n/2; // split about median - annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); - } -} - - -///////////////////////////////////////////////////////////////////////////////// -// for kd-trees with deletion -// -//---------------------------------------------------------------------- -// kd_split - Bentley's standard splitting routine for kd-trees -// Find the dimension of the greatest spread, and split -// just before the median point along this dimension. -//---------------------------------------------------------------------- - -void kd_split_wd( - ANNpointArray pa, // point array (permuted on return) - ANNidxArray pidx, // point indices - const ANNorthRect &bnds, // bounding rectangle for cell - int n, // number of points - int dim, // dimension of space - int &cut_dim, // cutting dimension (returned) - ANNcoord &cut_val, // cutting value (returned) - int &n_lo, // num of points on low side (returned) - int &cut_pt_idx) // index of cutting point (returned) -{ - // find dimension of maximum spread - cut_dim = annMaxSpread(pa, pidx, n, dim); - n_lo = n/2; // median rank - // split about median - annMedianSplit(pa, pidx, n, cut_dim, cut_val, n_lo); - cut_pt_idx = n_lo; - cut_val = PA(cut_pt_idx, cut_dim); -} - -//---------------------------------------------------------------------- -// midpt_split - midpoint splitting rule for box-decomposition trees -// -// This is the simplest splitting rule that guarantees boxes -// of bounded aspect ratio. It simply cuts the box with the -// longest side through its midpoint. If there are ties, it -// selects the dimension with the maximum point spread. -// -// WARNING: This routine (while simple) doesn't seem to work -// well in practice in high dimensions, because it tends to -// generate a large number of trivial and/or unbalanced splits. -// Either kd_split(), sl_midpt_split(), or fair_split() are -// recommended, instead. -//---------------------------------------------------------------------- - -void midpt_split_wd( - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices (permuted on return) - const ANNorthRect &bnds, // bounding rectangle for cell - int n, // number of points - int dim, // dimension of space - int &cut_dim, // cutting dimension (returned) - ANNcoord &cut_val, // cutting value (returned) - int &n_lo, // num of points on low side (returned) - int &cut_pt_idx) // index of cutting point (returned) -{ - int d; - - ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; - for (d = 1; d < dim; d++) { // find length of longest box side - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - if (length > max_length) { - max_length = length; - } - } - ANNcoord max_spread = -1; // find long side with most spread - for (d = 0; d < dim; d++) { - // is it among longest? - if (double(bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) { - // compute its spread - ANNcoord spr = annSpread(pa, pidx, n, d); - if (spr > max_spread) { // is it max so far? - max_spread = spr; - cut_dim = d; - } - } - } - // split along cut_dim at midpoint - cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim]) / 2; - // permute points accordingly - int br1, br2; - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - //------------------------------------------------------------------ - // On return: pa[0..br1-1] < cut_val - // pa[br1..br2-1] == cut_val - // pa[br2..n-1] > cut_val - // - // We can set n_lo to any value in the range [br1..br2]. - // We choose split so that points are most evenly divided. - //------------------------------------------------------------------ - if (br1 > n/2) n_lo = br1; - else if (br2 < n/2) n_lo = br2; - else n_lo = n/2; - - cut_pt_idx = n_lo; - cut_val = PA(cut_pt_idx, cut_dim); - -} - -//---------------------------------------------------------------------- -// sl_midpt_split - sliding midpoint splitting rule -// -// This is a modification of midpt_split, which has the nonsensical -// name "sliding midpoint". The idea is that we try to use the -// midpoint rule, by bisecting the longest side. If there are -// ties, the dimension with the maximum spread is selected. If, -// however, the midpoint split produces a trivial split (no points -// on one side of the splitting plane) then we slide the splitting -// (maintaining its orientation) until it produces a nontrivial -// split. For example, if the splitting plane is along the x-axis, -// and all the data points have x-coordinate less than the x-bisector, -// then the split is taken along the maximum x-coordinate of the -// data points. -// -// Intuitively, this rule cannot generate trivial splits, and -// hence avoids midpt_split's tendency to produce trees with -// a very large number of nodes. -// -//---------------------------------------------------------------------- - -void sl_midpt_split_wd( - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices (permuted on return) - const ANNorthRect &bnds, // bounding rectangle for cell - int n, // number of points - int dim, // dimension of space - int &cut_dim, // cutting dimension (returned) - ANNcoord &cut_val, // cutting value (returned) - int &n_lo, // num of points on low side (returned) - int &cut_pt_idx) // index of cutting point (returned) -{ - int d; - - ANNcoord max_length = bnds.hi[0] - bnds.lo[0]; - for (d = 1; d < dim; d++) { // find length of longest box side - ANNcoord length = bnds.hi[d] - bnds.lo[d]; - if (length > max_length) { - max_length = length; - } - } - ANNcoord max_spread = -1; // find long side with most spread - for (d = 0; d < dim; d++) { - // is it among longest? - if ((bnds.hi[d] - bnds.lo[d]) >= (1-ERR)*max_length) { - // compute its spread - ANNcoord spr = annSpread(pa, pidx, n, d); - if (spr > max_spread) { // is it max so far? - max_spread = spr; - cut_dim = d; - } - } - } - // ideal split at midpoint - ANNcoord ideal_cut_val = (bnds.lo[cut_dim] + bnds.hi[cut_dim])/2; - - ANNcoord min, max; - annMinMax(pa, pidx, n, cut_dim, min, max); // find min/max coordinates - - if (ideal_cut_val < min) // slide to min or max as needed - cut_val = min; - else if (ideal_cut_val > max) - cut_val = max; - else - cut_val = ideal_cut_val; - - // permute points accordingly - int br1, br2; - annPlaneSplit(pa, pidx, n, cut_dim, cut_val, br1, br2); - //------------------------------------------------------------------ - // On return: pa[0..br1-1] < cut_val - // pa[br1..br2-1] == cut_val - // pa[br2..n-1] > cut_val - // - // We can set n_lo to any value in the range [br1..br2] to satisfy - // the exit conditions of the procedure. - // - // if ideal_cut_val < min (implying br2 >= 1), - // then we select n_lo = 1 (so there is one point on left) and - // if ideal_cut_val > max (implying br1 <= n-1), - // then we select n_lo = n-1 (so there is one point on right). - // Otherwise, we select n_lo as close to n/2 as possible within - // [br1..br2]. - //------------------------------------------------------------------ - if (ideal_cut_val < min) n_lo = 1; - else if (ideal_cut_val > max) n_lo = n-1; - else if (br1 > n/2) n_lo = br1; - else if (br2 < n/2) n_lo = br2; - else n_lo = n/2; -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/kd_tree.cpp b/geom_bottleneck/bottleneck/src/ann/kd_tree.cpp deleted file mode 100644 index e8f7f63..0000000 --- a/geom_bottleneck/bottleneck/src/ann/kd_tree.cpp +++ /dev/null @@ -1,566 +0,0 @@ -//---------------------------------------------------------------------- -// File: kd_tree.cpp -// Programmer: Sunil Arya and David Mount -// Description: Basic methods for kd-trees. -// Last modified: 01/04/05 (Version 1.0) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 0.1 03/04/98 -// Initial release -// Revision 1.0 04/01/05 -// Increased aspect ratio bound (ANN_AR_TOOBIG) from 100 to 1000. -// Fixed leaf counts to count trivial leaves. -// Added optional pa, pi arguments to Skeleton kd_tree constructor -// for use in load constructor. -// Added annClose() to eliminate KD_TRIVIAL memory leak. -// -------------------------------------------------------------------- -// 2015 - modified by A. Nigmetov to support deletion of points -//---------------------------------------------------------------------- - -#ifdef _WIN32 -#include <ciso646> // make VS more conformal -#endif - -#include "kd_tree.h" // kd-tree declarations -#include "kd_split.h" // kd-tree splitting rules -#include "kd_util.h" // kd-tree utilities -#include <ANN/ANNperf.h> // performance evaluation -#include "def_debug_bt.h" - -namespace geom_bt { -//---------------------------------------------------------------------- -// Global data -// -// For some splitting rules, especially with small bucket sizes, -// it is possible to generate a large number of empty leaf nodes. -// To save storage we allocate a single trivial leaf node which -// contains no points. For messy coding reasons it is convenient -// to have it reference a trivial point index. -// -// KD_TRIVIAL is allocated when the first kd-tree is created. It -// must *never* deallocated (since it may be shared by more than -// one tree). -//---------------------------------------------------------------------- -static int IDX_TRIVIAL[] = {0}; // trivial point index -ANNkd_leaf *KD_TRIVIAL = NULL; // trivial leaf node - -//---------------------------------------------------------------------- -// Printing the kd-tree -// These routines print a kd-tree in reverse inorder (high then -// root then low). (This is so that if you look at the output -// from the right side it appear from left to right in standard -// inorder.) When outputting leaves we output only the point -// indices rather than the point coordinates. There is an option -// to print the point coordinates separately. -// -// The tree printing routine calls the printing routines on the -// individual nodes of the tree, passing in the level or depth -// in the tree. The level in the tree is used to print indentation -// for readability. -//---------------------------------------------------------------------- - -void ANNkd_split::print( // print splitting node - int level, // depth of node in tree - ostream &out) // output stream -{ -#ifndef FOR_R_TDA - child[ANN_HI]->print(level+1, out); // print high child - out << " "; - for (int i = 0; i < level; i++) // print indentation - out << ".."; - out << "Split cd=" << cut_dim << " cv=" << cut_val; - out << " lbnd=" << cd_bnds[ANN_LO]; - out << " hbnd=" << cd_bnds[ANN_HI]; - out << " np=" << actual_num_points; - out << "\n"; - child[ANN_LO]->print(level+1, out); // print low child -#endif -} - -void ANNkd_leaf::print( // print leaf node - int level, // depth of node in tree - ostream &out) // output stream -{ -#ifndef FOR_R_TDA - out << " "; - for (int i = 0; i < level; i++) // print indentation - out << ".."; - - if (this == KD_TRIVIAL) { // canonical trivial leaf node - out << "Leaf (trivial)\n"; - } - else{ - out << "Leaf n=" << n_pts << " <"; - for (int j = 0; j < n_pts; j++) { - out << bkt[j]; - if (j < n_pts-1) out << ","; - } - out << ">\n"; - } -#endif -} - -#ifndef FOR_R_TDA -void ANNkd_tree::Print( // print entire tree - ANNbool with_pts, // print points as well? - ostream &out) // output stream -{ - out << "ANN Version " << ANNversion << "\n"; - if (with_pts) { // print point coordinates - out << " Points:\n"; - for (int i = 0; i < n_pts; i++) { - out << "\t" << i << ": "; - annPrintPt(pts[i], dim, out); - out << "\n"; - } - } - if (root == NULL) // empty tree? - out << " Null tree.\n"; - else { - root->print(0, out); // invoke printing at root - } -} -#endif - -//---------------------------------------------------------------------- -// kd_tree statistics (for performance evaluation) -// This routine compute various statistics information for -// a kd-tree. It is used by the implementors for performance -// evaluation of the data structure. -//---------------------------------------------------------------------- - -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -void ANNkdStats::merge(const ANNkdStats &st) // merge stats from child -{ - n_lf += st.n_lf; n_tl += st.n_tl; - n_spl += st.n_spl; n_shr += st.n_shr; - depth = MAX(depth, st.depth); - sum_ar += st.sum_ar; -} - -//---------------------------------------------------------------------- -// Update statistics for nodes -//---------------------------------------------------------------------- - -const double ANN_AR_TOOBIG = 1000; // too big an aspect ratio - -void ANNkd_leaf::getStats( // get subtree statistics - int dim, // dimension of space - ANNkdStats &st, // stats (modified) - ANNorthRect &bnd_box) // bounding box -{ - st.reset(); - st.n_lf = 1; // count this leaf - if (this == KD_TRIVIAL) st.n_tl = 1; // count trivial leaf - double ar = annAspectRatio(dim, bnd_box); // aspect ratio of leaf - // incr sum (ignore outliers) - st.sum_ar += float(ar < ANN_AR_TOOBIG ? ar : ANN_AR_TOOBIG); -} - -void ANNkd_split::getStats( // get subtree statistics - int dim, // dimension of space - ANNkdStats &st, // stats (modified) - ANNorthRect &bnd_box) // bounding box -{ - ANNkdStats ch_stats; // stats for children - // get stats for low child - ANNcoord hv = bnd_box.hi[cut_dim]; // save box bounds - bnd_box.hi[cut_dim] = cut_val; // upper bound for low child - ch_stats.reset(); // reset - child[ANN_LO]->getStats(dim, ch_stats, bnd_box); - st.merge(ch_stats); // merge them - bnd_box.hi[cut_dim] = hv; // restore bound - // get stats for high child - ANNcoord lv = bnd_box.lo[cut_dim]; // save box bounds - bnd_box.lo[cut_dim] = cut_val; // lower bound for high child - ch_stats.reset(); // reset - child[ANN_HI]->getStats(dim, ch_stats, bnd_box); - st.merge(ch_stats); // merge them - bnd_box.lo[cut_dim] = lv; // restore bound - - st.depth++; // increment depth - st.n_spl++; // increment number of splits -} - -//---------------------------------------------------------------------- -// getStats -// Collects a number of statistics related to kd_tree or -// bd_tree. -//---------------------------------------------------------------------- - -void ANNkd_tree::getStats( // get tree statistics - ANNkdStats &st) // stats (modified) -{ - st.reset(dim, n_pts, bkt_size); // reset stats - // create bounding box - ANNorthRect bnd_box(dim, bnd_box_lo, bnd_box_hi); - if (root != NULL) { // if nonempty tree - root->getStats(dim, st, bnd_box); // get statistics - st.avg_ar = st.sum_ar / st.n_lf; // average leaf asp ratio - } -} - -//---------------------------------------------------------------------- -// kd_tree destructor -// The destructor just frees the various elements that were -// allocated in the construction process. -//---------------------------------------------------------------------- - -ANNkd_tree::~ANNkd_tree() // tree destructor -{ - if (root != NULL and root != KD_TRIVIAL) delete root; - if (pidx != NULL) delete [] pidx; - if (bnd_box_lo != NULL) annDeallocPt(bnd_box_lo); - if (bnd_box_hi != NULL) annDeallocPt(bnd_box_hi); -} - -//---------------------------------------------------------------------- -// This is called with all use of ANN is finished. It eliminates the -// minor memory leak caused by the allocation of KD_TRIVIAL. -//---------------------------------------------------------------------- -void annClose() // close use of ANN -{ - if (KD_TRIVIAL != NULL) { - delete KD_TRIVIAL; - KD_TRIVIAL = NULL; - } -} - -//---------------------------------------------------------------------- -// kd_tree constructors -// There is a skeleton kd-tree constructor which sets up a -// trivial empty tree. The last optional argument allows -// the routine to be passed a point index array which is -// assumed to be of the proper size (n). Otherwise, one is -// allocated and initialized to the identity. Warning: In -// either case the destructor will deallocate this array. -// -// As a kludge, we need to allocate KD_TRIVIAL if one has not -// already been allocated. (This is because I'm too dumb to -// figure out how to cause a pointer to be allocated at load -// time.) -//---------------------------------------------------------------------- - -void ANNkd_tree::SkeletonTree( // construct skeleton tree - int n, // number of points - int dd, // dimension - int bs, // bucket size - ANNpointArray pa, // point array - ANNidxArray pi) // point indices -{ - dim = dd; // initialize basic elements - n_pts = n; - bkt_size = bs; - pts = pa; // initialize points array - - root = NULL; // no associated tree yet - - if (pi == NULL) { // point indices provided? - pidx = new ANNidx[n]; // no, allocate space for point indices - for (int i = 0; i < n; i++) { - pidx[i] = i; // initially identity - } - } - else { - pidx = pi; // yes, use them - } - - bnd_box_lo = bnd_box_hi = NULL; // bounding box is nonexistent - if (KD_TRIVIAL == NULL) // no trivial leaf node yet? - KD_TRIVIAL = new ANNkd_leaf(0, IDX_TRIVIAL); // allocate it - - // for deletion - pointToLeafVec.clear(); - pointToLeafVec.reserve(n_pts); - for(int k = 0; k < n_pts; ++k) { - pointToLeafVec.push_back(NULL); - } -} - -ANNkd_tree::ANNkd_tree( // basic constructor - int n, // number of points - int dd, // dimension - int bs) // bucket size -{ SkeletonTree(n, dd, bs); } // construct skeleton tree - - - -//---------------------------------------------------------------------- -// rkd_tree - recursive procedure to build a kd-tree -// -// Builds a kd-tree for points in pa as indexed through the -// array pidx[0..n-1] (typically a subarray of the array used in -// the top-level call). This routine permutes the array pidx, -// but does not alter pa[]. -// -// The construction is based on a standard algorithm for constructing -// the kd-tree (see Friedman, Bentley, and Finkel, ``An algorithm for -// finding best matches in logarithmic expected time,'' ACM Transactions -// on Mathematical Software, 3(3):209-226, 1977). The procedure -// operates by a simple divide-and-conquer strategy, which determines -// an appropriate orthogonal cutting plane (see below), and splits -// the points. When the number of points falls below the bucket size, -// we simply store the points in a leaf node's bucket. -// -// One of the arguments is a pointer to a splitting routine, -// whose prototype is: -// -// void split( -// ANNpointArray pa, // complete point array -// ANNidxArray pidx, // point array (permuted on return) -// ANNorthRect &bnds, // bounds of current cell -// int n, // number of points -// int dim, // dimension of space -// int &cut_dim, // cutting dimension -// ANNcoord &cut_val, // cutting value -// int &n_lo) // no. of points on low side of cut -// -// This procedure selects a cutting dimension and cutting value, -// partitions pa about these values, and returns the number of -// points on the low side of the cut. -//---------------------------------------------------------------------- - -ANNkd_ptr rkd_tree( // recursive construction of kd-tree - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices to store in subtree - int n, // number of points - int dim, // dimension of space - int bsp, // bucket space - ANNorthRect &bnd_box, // bounding box for current node - ANNkd_splitter splitter, // splitting routine - vector<ANNkd_leaf*>* ppointToLeafVec) -{ - if (n <= bsp) { // n small, make a leaf node - if (n == 0) // empty leaf node - return KD_TRIVIAL; // return (canonical) empty leaf - else { // construct the node and return - ANNkd_leaf* res = new ANNkd_leaf(n, pidx); - if ( 1 == bsp) { - (*ppointToLeafVec)[*pidx] = res; - } - return res; - } - } - else { // n large, make a splitting node - int cd; // cutting dimension - ANNcoord cv; // cutting value - int n_lo; // number on low side of cut - ANNkd_node *lo, *hi; // low and high children - - // invoke splitting procedure - (*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo); - - ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension - ANNcoord hv = bnd_box.hi[cd]; - - bnd_box.hi[cd] = cv; // modify bounds for left subtree - lo = rkd_tree( // build left subtree - pa, pidx, n_lo, // ...from pidx[0..n_lo-1] - dim, bsp, bnd_box, splitter, ppointToLeafVec); - bnd_box.hi[cd] = hv; // restore bounds - - bnd_box.lo[cd] = cv; // modify bounds for right subtree - hi = rkd_tree( // build right subtree - pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1] - dim, bsp, bnd_box, splitter, ppointToLeafVec); - bnd_box.lo[cd] = lv; // restore bounds - - // create the splitting node - ANNkd_split *ptr = new ANNkd_split(cd, cv, lv, hv, lo, hi); - if (lo != KD_TRIVIAL) - lo->setParent(ptr); - if (hi != KD_TRIVIAL) - hi->setParent(ptr); - ptr->setNumPoints(lo->getNumPoints() + hi->getNumPoints()); - - return ptr; // return pointer to this node - } -} - -// for kd-trees with deletion -/* -ANNkd_ptr rkd_tree_wd( // recursive construction of kd-tree - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices to store in subtree - int n, // number of points - int dim, // dimension of space - int bsp, // bucket space - ANNorthRect &bnd_box, // bounding box for current node - ANNkd_splitter_wd splitter) // splitting routine -{ - ANNidx cut_pt_idx; - if (n <= bsp) { // n small, make a leaf node - if (n == 0) // empty leaf node - return KD_TRIVIAL; // return (canonical) empty leaf - else // construct the node and return - return new ANNkd_leaf(n, pidx); - } - else { // n large, make a splitting node - int cd; // cutting dimension - ANNcoord cv; // cutting value - int n_lo; // number on low side of cut - ANNkd_node *lo, *hi; // low and high children - - // invoke splitting procedure - (*splitter)(pa, pidx, bnd_box, n, dim, cd, cv, n_lo, cut_pt_idx); - - ANNcoord lv = bnd_box.lo[cd]; // save bounds for cutting dimension - ANNcoord hv = bnd_box.hi[cd]; - - bnd_box.hi[cd] = cv; // modify bounds for left subtree - lo = rkd_tree_wd( // build left subtree - pa, pidx, n_lo, // ...from pidx[0..n_lo-1] - dim, bsp, bnd_box, splitter); - bnd_box.hi[cd] = hv; // restore bounds - - bnd_box.lo[cd] = cv; // modify bounds for right subtree - hi = rkd_tree_wd( // build right subtree - pa, pidx + n_lo, n-n_lo,// ...from pidx[n_lo..n-1] - dim, bsp, bnd_box, splitter); - bnd_box.lo[cd] = lv; // restore bounds - - // create the splitting node - ANNkd_split *ptr = new ANNkd_split(cd, cv, lv, hv, lo, hi, cut_pt_idx); - - return ptr; // return pointer to this node - } -} -*/ - -//---------------------------------------------------------------------- -// kd-tree constructor -// This is the main constructor for kd-trees given a set of points. -// It first builds a skeleton tree, then computes the bounding box -// of the data points, and then invokes rkd_tree() to actually -// build the tree, passing it the appropriate splitting routine. -//---------------------------------------------------------------------- - -ANNkd_tree::ANNkd_tree( // construct from point array - ANNpointArray pa, // point array (with at least n pts) - int n, // number of points - int dd, // dimension - int bs, // bucket size - ANNsplitRule split) // splitting method -{ - SkeletonTree(n, dd, bs); // set up the basic stuff - pts = pa; // where the points are - actual_num_points = n; - if (n == 0) return; // no points--no sweat - - ANNorthRect bnd_box(dd); // bounding box for points - annEnclRect(pa, pidx, n, dd, bnd_box);// construct bounding rectangle - // copy to tree structure - bnd_box_lo = annCopyPt(dd, bnd_box.lo); - bnd_box_hi = annCopyPt(dd, bnd_box.hi); - - switch (split) { // build by rule - case ANN_KD_STD: // standard kd-splitting rule - root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, kd_split, &pointToLeafVec); - break; - case ANN_KD_MIDPT: // midpoint split - root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split, &pointToLeafVec); - break; - case ANN_KD_FAIR: // fair split - root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split, &pointToLeafVec); - break; - case ANN_KD_SUGGEST: // best (in our opinion) - case ANN_KD_SL_MIDPT: // sliding midpoint split - root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_midpt_split, &pointToLeafVec); - break; - case ANN_KD_SL_FAIR: // sliding fair split - root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_fair_split, &pointToLeafVec); - break; - // for kd-trees with deletion - /* - //case ANN_KD_SUGGEST: - case ANN_KD_STD_WD: - root = rkd_tree_wd(pa, pidx, n, dd, bs, bnd_box, kd_split_wd); - break; - case ANN_KD_MIDPT_WD: - root = rkd_tree_wd(pa, pidx, n, dd, bs, bnd_box, kd_split_wd); - break; - case ANN_KD_SL_MIDPT_WD: - root = rkd_tree_wd(pa, pidx, n, dd, bs, bnd_box, kd_split_wd); - break; - */ - default: - annError("Illegal splitting method", ANNabort); - } -} - - -// deletion code -// -// -// -// -// -void ANNkd_tree::delete_point(const int point_idx) -{ - // range check - assert(0 <= point_idx and point_idx < n_pts); - assert(actual_num_points > 0); - // if this is the first deletion, - // initialize isDeleted vector - if (isDeleted.empty()) { - isDeleted.reserve(n_pts); - for(size_t k = 0; k < n_pts; ++k) { - isDeleted.push_back(false); - } - } - // points shouldn't be deleted twice - assert(!isDeleted[point_idx]); - assert(root != NULL); - ANNkd_leaf* leafWithPoint = pointToLeafVec.at(point_idx); - assert(leafWithPoint != NULL); - // if leafWithPoint != root, - // its parent will delete the leaf - pointToLeafVec.at(point_idx)->delete_point(point_idx, leafWithPoint != root); - if (leafWithPoint == root) { - // we had only one point, - // so the tree must delete it - root = KD_TRIVIAL; - delete leafWithPoint; - } - isDeleted[point_idx] = true; - actual_num_points--; -} - -void ANNkd_leaf::delete_point(const int point_idx, const bool killYourself) -{ - assert(n_pts == 1); - assert(bkt[0] == point_idx); - ANNkd_split* myPar = parent; - while(myPar != NULL) { - myPar->decNumPoints(); - myPar = myPar->getParent(); - } - if (parent != NULL) - parent->delete_leaf(this); - if (killYourself) - delete this; -} - -void ANNkd_split::delete_leaf(ANNkd_leaf* childToDelete) -{ - assert(child[ANN_LO] == childToDelete or child[ANN_HI] == childToDelete); - if (child[ANN_LO] == childToDelete) - child[ANN_LO] = KD_TRIVIAL; - else - child[ANN_HI] = KD_TRIVIAL; -} -} diff --git a/geom_bottleneck/bottleneck/src/ann/kd_util.cpp b/geom_bottleneck/bottleneck/src/ann/kd_util.cpp deleted file mode 100644 index 02b35c4..0000000 --- a/geom_bottleneck/bottleneck/src/ann/kd_util.cpp +++ /dev/null @@ -1,441 +0,0 @@ -//---------------------------------------------------------------------- -// File: kd_util.cpp -// Programmer: Sunil Arya and David Mount -// Description: Common utilities for kd-trees -// Last modified: 01/04/05 (Version 1.0) -//---------------------------------------------------------------------- -// Copyright (c) 1997-2005 University of Maryland and Sunil Arya and -// David Mount. All Rights Reserved. -// -// This software and related documentation is part of the Approximate -// Nearest Neighbor Library (ANN). This software is provided under -// the provisions of the Lesser GNU Public License (LGPL). See the -// file ../ReadMe.txt for further information. -// -// The University of Maryland (U.M.) and the authors make no -// representations about the suitability or fitness of this software for -// any purpose. It is provided "as is" without express or implied -// warranty. -//---------------------------------------------------------------------- -// History: -// Revision 0.1 03/04/98 -// Initial release -//---------------------------------------------------------------------- - -#include "kd_util.h" // kd-utility declarations - -#include <ANN/ANNperf.h> // performance evaluation - -namespace geom_bt { -//---------------------------------------------------------------------- -// The following routines are utility functions for manipulating -// points sets, used in determining splitting planes for kd-tree -// construction. -//---------------------------------------------------------------------- - -//---------------------------------------------------------------------- -// NOTE: Virtually all point indexing is done through an index (i.e. -// permutation) array pidx. Consequently, a reference to the d-th -// coordinate of the i-th point is pa[pidx[i]][d]. The macro PA(i,d) -// is a shorthand for this. -//---------------------------------------------------------------------- - // standard 2-d indirect indexing -#define PA(i,d) (pa[pidx[(i)]][(d)]) - // accessing a single point -#define PP(i) (pa[pidx[(i)]]) - -//---------------------------------------------------------------------- -// annAspectRatio -// Compute the aspect ratio (ratio of longest to shortest side) -// of a rectangle. -//---------------------------------------------------------------------- - -double annAspectRatio( - int dim, // dimension - const ANNorthRect &bnd_box) // bounding cube -{ - ANNcoord length = bnd_box.hi[0] - bnd_box.lo[0]; - ANNcoord min_length = length; // min side length - ANNcoord max_length = length; // max side length - for (int d = 0; d < dim; d++) { - length = bnd_box.hi[d] - bnd_box.lo[d]; - if (length < min_length) min_length = length; - if (length > max_length) max_length = length; - } - return max_length/min_length; -} - -//---------------------------------------------------------------------- -// annEnclRect, annEnclCube -// These utilities compute the smallest rectangle and cube enclosing -// a set of points, respectively. -//---------------------------------------------------------------------- - -void annEnclRect( - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices - int n, // number of points - int dim, // dimension - ANNorthRect &bnds) // bounding cube (returned) -{ - for (int d = 0; d < dim; d++) { // find smallest enclosing rectangle - ANNcoord lo_bnd = PA(0,d); // lower bound on dimension d - ANNcoord hi_bnd = PA(0,d); // upper bound on dimension d - for (int i = 0; i < n; i++) { - if (PA(i,d) < lo_bnd) lo_bnd = PA(i,d); - else if (PA(i,d) > hi_bnd) hi_bnd = PA(i,d); - } - bnds.lo[d] = lo_bnd; - bnds.hi[d] = hi_bnd; - } -} - -void annEnclCube( // compute smallest enclosing cube - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices - int n, // number of points - int dim, // dimension - ANNorthRect &bnds) // bounding cube (returned) -{ - int d; - // compute smallest enclosing rect - annEnclRect(pa, pidx, n, dim, bnds); - - ANNcoord max_len = 0; // max length of any side - for (d = 0; d < dim; d++) { // determine max side length - ANNcoord len = bnds.hi[d] - bnds.lo[d]; - if (len > max_len) { // update max_len if longest - max_len = len; - } - } - for (d = 0; d < dim; d++) { // grow sides to match max - ANNcoord len = bnds.hi[d] - bnds.lo[d]; - ANNcoord half_diff = (max_len - len) / 2; - bnds.lo[d] -= half_diff; - bnds.hi[d] += half_diff; - } -} - -//---------------------------------------------------------------------- -// annBoxDistance - utility routine which computes distance from point to -// box (Note: most distances to boxes are computed using incremental -// distance updates, not this function.) -//---------------------------------------------------------------------- - -ANNdist annBoxDistance( // compute distance from point to box - const ANNpoint q, // the point - const ANNpoint lo, // low point of box - const ANNpoint hi, // high point of box - int dim) // dimension of space -{ - register ANNdist dist = 0.0; // sum of squared distances - register ANNdist t; - - for (register int d = 0; d < dim; d++) { - if (q[d] < lo[d]) { // q is left of box - t = ANNdist(lo[d]) - ANNdist(q[d]); - dist = ANN_SUM(dist, ANN_POW(t)); - } - else if (q[d] > hi[d]) { // q is right of box - t = ANNdist(q[d]) - ANNdist(hi[d]); - dist = ANN_SUM(dist, ANN_POW(t)); - } - } - ANN_FLOP(4*dim) // increment floating op count - - return dist; -} - -//---------------------------------------------------------------------- -// annSpread - find spread along given dimension -// annMinMax - find min and max coordinates along given dimension -// annMaxSpread - find dimension of max spread -//---------------------------------------------------------------------- - -ANNcoord annSpread( // compute point spread along dimension - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices - int n, // number of points - int d) // dimension to check -{ - ANNcoord min = PA(0,d); // compute max and min coords - ANNcoord max = PA(0,d); - for (int i = 1; i < n; i++) { - ANNcoord c = PA(i,d); - if (c < min) min = c; - else if (c > max) max = c; - } - return (max - min); // total spread is difference -} - -void annMinMax( // compute min and max coordinates along dim - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices - int n, // number of points - int d, // dimension to check - ANNcoord &min, // minimum value (returned) - ANNcoord &max) // maximum value (returned) -{ - min = PA(0,d); // compute max and min coords - max = PA(0,d); - for (int i = 1; i < n; i++) { - ANNcoord c = PA(i,d); - if (c < min) min = c; - else if (c > max) max = c; - } -} - -int annMaxSpread( // compute dimension of max spread - ANNpointArray pa, // point array - ANNidxArray pidx, // point indices - int n, // number of points - int dim) // dimension of space -{ - int max_dim = 0; // dimension of max spread - ANNcoord max_spr = 0; // amount of max spread - - if (n == 0) return max_dim; // no points, who cares? - - for (int d = 0; d < dim; d++) { // compute spread along each dim - ANNcoord spr = annSpread(pa, pidx, n, d); - if (spr > max_spr) { // bigger than current max - max_spr = spr; - max_dim = d; - } - } - return max_dim; -} - -//---------------------------------------------------------------------- -// annMedianSplit - split point array about its median -// Splits a subarray of points pa[0..n] about an element of given -// rank (median: n_lo = n/2) with respect to dimension d. It places -// the element of rank n_lo-1 correctly (because our splitting rule -// takes the mean of these two). On exit, the array is permuted so -// that: -// -// pa[0..n_lo-2][d] <= pa[n_lo-1][d] <= pa[n_lo][d] <= pa[n_lo+1..n-1][d]. -// -// The mean of pa[n_lo-1][d] and pa[n_lo][d] is returned as the -// splitting value. -// -// All indexing is done indirectly through the index array pidx. -// -// This function uses the well known selection algorithm due to -// C.A.R. Hoare. -//---------------------------------------------------------------------- - - // swap two points in pa array -#define PASWAP(a,b) { int tmp = pidx[a]; pidx[a] = pidx[b]; pidx[b] = tmp; } - -void annMedianSplit( - ANNpointArray pa, // points to split - ANNidxArray pidx, // point indices - int n, // number of points - int d, // dimension along which to split - ANNcoord &cv, // cutting value - int n_lo) // split into n_lo and n-n_lo -{ - int l = 0; // left end of current subarray - int r = n-1; // right end of current subarray - while (l < r) { - register int i = (r+l)/2; // select middle as pivot - register int k; - - if (PA(i,d) > PA(r,d)) // make sure last > pivot - PASWAP(i,r) - PASWAP(l,i); // move pivot to first position - - ANNcoord c = PA(l,d); // pivot value - i = l; - k = r; - for(;;) { // pivot about c - while (PA(++i,d) < c) ; - while (PA(--k,d) > c) ; - if (i < k) PASWAP(i,k) else break; - } - PASWAP(l,k); // pivot winds up in location k - - if (k > n_lo) r = k-1; // recurse on proper subarray - else if (k < n_lo) l = k+1; - else break; // got the median exactly - } - if (n_lo > 0) { // search for next smaller item - ANNcoord c = PA(0,d); // candidate for max - int k = 0; // candidate's index - for (int i = 1; i < n_lo; i++) { - if (PA(i,d) > c) { - c = PA(i,d); - k = i; - } - } - PASWAP(n_lo-1, k); // max among pa[0..n_lo-1] to pa[n_lo-1] - } - // cut value is midpoint value - cv = (PA(n_lo-1,d) + PA(n_lo,d))/2.0; -} - -//---------------------------------------------------------------------- -// annPlaneSplit - split point array about a cutting plane -// Split the points in an array about a given plane along a -// given cutting dimension. On exit, br1 and br2 are set so -// that: -// -// pa[ 0 ..br1-1] < cv -// pa[br1..br2-1] == cv -// pa[br2.. n -1] > cv -// -// All indexing is done indirectly through the index array pidx. -// -//---------------------------------------------------------------------- - -void annPlaneSplit( // split points by a plane - ANNpointArray pa, // points to split - ANNidxArray pidx, // point indices - int n, // number of points - int d, // dimension along which to split - ANNcoord cv, // cutting value - int &br1, // first break (values < cv) - int &br2) // second break (values == cv) -{ - int l = 0; - int r = n-1; - for(;;) { // partition pa[0..n-1] about cv - while (l < n && PA(l,d) < cv) l++; - while (r >= 0 && PA(r,d) >= cv) r--; - if (l > r) break; - PASWAP(l,r); - l++; r--; - } - br1 = l; // now: pa[0..br1-1] < cv <= pa[br1..n-1] - r = n-1; - for(;;) { // partition pa[br1..n-1] about cv - while (l < n && PA(l,d) <= cv) l++; - while (r >= br1 && PA(r,d) > cv) r--; - if (l > r) break; - PASWAP(l,r); - l++; r--; - } - br2 = l; // now: pa[br1..br2-1] == cv < pa[br2..n-1] -} - - -//---------------------------------------------------------------------- -// annBoxSplit - split point array about a orthogonal rectangle -// Split the points in an array about a given orthogonal -// rectangle. On exit, n_in is set to the number of points -// that are inside (or on the boundary of) the rectangle. -// -// All indexing is done indirectly through the index array pidx. -// -//---------------------------------------------------------------------- - -void annBoxSplit( // split points by a box - ANNpointArray pa, // points to split - ANNidxArray pidx, // point indices - int n, // number of points - int dim, // dimension of space - ANNorthRect &box, // the box - int &n_in) // number of points inside (returned) -{ - int l = 0; - int r = n-1; - for(;;) { // partition pa[0..n-1] about box - while (l < n && box.inside(dim, PP(l))) l++; - while (r >= 0 && !box.inside(dim, PP(r))) r--; - if (l > r) break; - PASWAP(l,r); - l++; r--; - } - n_in = l; // now: pa[0..n_in-1] inside and rest outside -} - -//---------------------------------------------------------------------- -// annSplitBalance - compute balance factor for a given plane split -// Balance factor is defined as the number of points lying -// below the splitting value minus n/2 (median). Thus, a -// median split has balance 0, left of this is negative and -// right of this is positive. (The points are unchanged.) -//---------------------------------------------------------------------- - -int annSplitBalance( // determine balance factor of a split - ANNpointArray pa, // points to split - ANNidxArray pidx, // point indices - int n, // number of points - int d, // dimension along which to split - ANNcoord cv) // cutting value -{ - int n_lo = 0; - for(int i = 0; i < n; i++) { // count number less than cv - if (PA(i,d) < cv) n_lo++; - } - return n_lo - n/2; -} - -//---------------------------------------------------------------------- -// annBox2Bnds - convert bounding box to list of bounds -// Given two boxes, an inner box enclosed within a bounding -// box, this routine determines all the sides for which the -// inner box is strictly contained with the bounding box, -// and adds an appropriate entry to a list of bounds. Then -// we allocate storage for the final list of bounds, and return -// the resulting list and its size. -//---------------------------------------------------------------------- - -void annBox2Bnds( // convert inner box to bounds - const ANNorthRect &inner_box, // inner box - const ANNorthRect &bnd_box, // enclosing box - int dim, // dimension of space - int &n_bnds, // number of bounds (returned) - ANNorthHSArray &bnds) // bounds array (returned) -{ - int i; - n_bnds = 0; // count number of bounds - for (i = 0; i < dim; i++) { - if (inner_box.lo[i] > bnd_box.lo[i]) // low bound is inside - n_bnds++; - if (inner_box.hi[i] < bnd_box.hi[i]) // high bound is inside - n_bnds++; - } - - bnds = new ANNorthHalfSpace[n_bnds]; // allocate appropriate size - - int j = 0; - for (i = 0; i < dim; i++) { // fill the array - if (inner_box.lo[i] > bnd_box.lo[i]) { - bnds[j].cd = i; - bnds[j].cv = inner_box.lo[i]; - bnds[j].sd = +1; - j++; - } - if (inner_box.hi[i] < bnd_box.hi[i]) { - bnds[j].cd = i; - bnds[j].cv = inner_box.hi[i]; - bnds[j].sd = -1; - j++; - } - } -} - -//---------------------------------------------------------------------- -// annBnds2Box - convert list of bounds to bounding box -// Given an enclosing box and a list of bounds, this routine -// computes the corresponding inner box. It is assumed that -// the box points have been allocated already. -//---------------------------------------------------------------------- - -void annBnds2Box( - const ANNorthRect &bnd_box, // enclosing box - int dim, // dimension of space - int n_bnds, // number of bounds - ANNorthHSArray bnds, // bounds array - ANNorthRect &inner_box) // inner box (returned) -{ - annAssignRect(dim, inner_box, bnd_box); // copy bounding box to inner - - for (int i = 0; i < n_bnds; i++) { - bnds[i].project(inner_box.lo); // project each endpoint - bnds[i].project(inner_box.hi); - } -} -} |