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 } }
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); } }
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 double *ss, // scaling coefficient int *tt, // topology of space int bs, // bucket size ANNsplitRule split) // splitting method { SkeletonTree(n, dd, bs); // set up the basic stuff pts = pa; // where the points are if (n == 0) return; // no points--no sweat Scale = new double [dim]; Topology = new int [dim]; TreeTopology = new int [dim]; TreeP3Topology = new int [dim]; for (int i = 0; i < dim; i++) { Scale[i] = ss[i]; Topology[i] = tt[i]; TreeTopology[i] = tt[i]; } for (int i = 0; i < dim; i++) { if (tt[i] != 3) TreeP3Topology[i] = 0; else { TreeP3Topology[i++] = 0; TreeP3Topology[i++] = 1; TreeP3Topology[i++] = 2; TreeP3Topology[i] = 3; } } 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); break; case ANN_KD_MIDPT: // midpoint split root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, midpt_split); break; case ANN_KD_FAIR: // fair split root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, fair_split); 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); break; case ANN_KD_SL_FAIR: // sliding fair split root = rkd_tree(pa, pidx, n, dd, bs, bnd_box, sl_fair_split); break; default: annError("Illegal splitting method", ANNabort); } delete [] TreeTopology; delete [] TreeP3Topology; }
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 { 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); 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); 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); bnd_box.lo[cd] = lv; // restore bounds // create the splitting node ANNkd_split *ptr; if (TreeTopology[cd] == 3) { if (TreeP3Topology[cd] == 0) ptr = new ANNkd_split(cd, cv, lv, hv, cd + 1, cd + 2, cd + 3, bnd_box.lo[cd + 1], bnd_box.hi[cd + 1], bnd_box.lo[cd + 2], bnd_box.hi[cd + 2], bnd_box.lo[cd + 3], bnd_box.hi[cd + 3], lo, hi); if (TreeP3Topology[cd] == 1) ptr = new ANNkd_split(cd, cv, lv, hv, cd - 1, cd + 1, cd + 2, bnd_box.lo[cd - 1], bnd_box.hi[cd - 1], bnd_box.lo[cd + 1], bnd_box.hi[cd + 1], bnd_box.lo[cd + 2], bnd_box.hi[cd + 2], lo, hi); if (TreeP3Topology[cd] == 2) ptr = new ANNkd_split(cd, cv, lv, hv, cd - 2, cd - 1, cd + 1, bnd_box.lo[cd - 2], bnd_box.hi[cd - 2], bnd_box.lo[cd - 1], bnd_box.hi[cd - 1], bnd_box.lo[cd + 1], bnd_box.hi[cd + 1], lo, hi); if (TreeP3Topology[cd] == 3) ptr = new ANNkd_split(cd, cv, lv, hv, cd - 3, cd - 2, cd - 1, bnd_box.lo[cd - 3], bnd_box.hi[cd - 3], bnd_box.lo[cd - 2], bnd_box.hi[cd - 2], bnd_box.lo[cd - 1], bnd_box.hi[cd - 1], lo, hi); } else { ptr = new ANNkd_split(cd, cv, lv, hv, lo, hi); } return ptr; // return pointer to this node } }