@Override public void findNearest(P point, double maxDistance, int numNeighbors, FastQueue<NnData<P>> results) { results.reset(); if( maxDistance <= 0 ) searchN.setMaxDistance(Double.MAX_VALUE); else searchN.setMaxDistance(maxDistance); found.reset(); searchN.findNeighbor(point, numNeighbors, found); for( int i = 0; i < found.size; i++ ) { KdTreeResult k = found.get(i); NnData<P> r = results.grow(); r.point = (P)k.node.point; r.index = k.node.index; r.distance = k.distance; } } }
@Override public void findNearest(P point, double maxDistance, int numNeighbors, FastQueue<NnData<P>> results) { results.reset(); if( maxDistance <= 0 ) searchN.setMaxDistance(Double.MAX_VALUE); else searchN.setMaxDistance(maxDistance); found.reset(); searchN.findNeighbor(point, numNeighbors, found); for( int i = 0; i < found.size; i++ ) { KdTreeResult k = found.get(i); NnData<P> r = results.grow(); r.point = (P)k.node.point; r.index = k.node.index; r.distance = k.distance; } } }
/** * Randomly generate several searches and check the result */ @Test public void randomTests() { KdTreeSearchN<double[]> alg = createAlg(); KdTree tree = StandardKdTreeSearch1Tests.createTreeA(); alg.setTree(tree); List<double[]> data = new ArrayList<double[]>(); flattenTree(tree.root,data); for( int i = 0; i < 100; i++ ) { int searchN = rand.nextInt(data.size()+5)+1; double[] target = data.get( rand.nextInt(data.size())); double maxDistance = rand.nextDouble()*10; List<double[]> expected = findNeighbors(data,target,maxDistance,searchN); found.reset(); alg.setMaxDistance(maxDistance); alg.findNeighbor(target, searchN, found); assertEquals(expected.size(),found.size); for( int j = 0; j < expected.size(); j++ ) { checkContains(expected.get(j)); } } }
/** * Try several searches and see if they all produce good results. Just fine the nearest-neighbor */ @Test public void findClosest_basic_1() { KdTreeSearchN<double[]> alg = createAlg(); KdTree tree = StandardKdTreeSearch1Tests.createTreeA(); alg.setTree(tree); alg.setMaxDistance(Double.MAX_VALUE); // the first decision will be incorrect and it will need to back track found.reset(); alg.findNeighbor(new double[]{11, 8}, 1, found); assertEquals(1,found.size); assertTrue(found.data[0].node == tree.root.right.right); // the root will be the best found.reset(); alg.findNeighbor(new double[]{1.001, 1.99999}, 1, found); assertTrue(found.data[0].node == tree.root); // a point on the left branch will be a perfect fit found.reset(); alg.findNeighbor(new double[]{2, 0.8}, 1, found); assertTrue(found.data[0].node == tree.root.left.right); // a point way outside the tree's bounds found.reset(); alg.findNeighbor(new double[]{-10000, 0.5}, 1, found); assertTrue(found.data[0].node == tree.root.left.left); }
/** * The tree is empty and it should always fail */ @Test public void findClosest_empty() { KdTreeSearchN<double[]> alg = createAlg(); alg.setTree( new KdTree(2) ); found.reset(); alg.findNeighbor(new double[]{11, 8}, 2, found); assertEquals(0, found.size()); }
/** * The tree is a leaf and should always return the same result */ @Test public void findClosest_leaf() { KdTree tree = new KdTree(2); tree.root = new KdTree.Node(new double[]{1,2}); KdTreeSearchN<double[]> alg =createAlg(); alg.setTree( tree ); found.reset(); alg.findNeighbor(new double[]{11, 8}, 2, found); assertEquals(1,found.size); assertTrue(found.data[0].node == tree.root); found.reset(); alg.findNeighbor(new double[]{2, 5}, 2, found); assertEquals(1,found.size); assertTrue(found.data[0].node == tree.root); }
/** * See if max distance is being respected */ @Test public void findClosest_maxDistance() { KdTree tree = new KdTree(2); tree.root = new KdTree.Node(new double[]{1,2}); KdTreeSearchN<double[]> alg = createAlg(); alg.setTree( tree ); alg.setMaxDistance(2); found.reset(); alg.findNeighbor(new double[]{11, 8}, 1, found); assertEquals(0, found.size); found.reset(); alg.findNeighbor(new double[]{1, 1.5}, 1, found); assertEquals(1, found.size); assertTrue(found.data[0].node == tree.root); }
/** * See if it can handle a null leaf */ @Test public void findClosest_nullLeaf() { KdTreeSearchN<double[]> alg = createAlg(); KdTree tree = StandardKdTreeSearch1Tests.createTreeWithNull(); alg.setTree(tree); alg.setMaxDistance(Double.MAX_VALUE); // the first decision will be incorrect and it will need to back track found.reset(); alg.findNeighbor(new double[]{2, 3}, 1, found); assertTrue(found.get(0).node == tree.root); }
/** * See of it can handle duplicate values correctly */ @Test public void checkDuplicates() { KdTreeSearchN<double[]> alg = createAlg(); KdTree tree = createTreeDuplicates(); alg.setTree(tree); alg.setMaxDistance(Double.MAX_VALUE); double[] pt = new double[]{1,2}; found.reset(); alg.findNeighbor(pt, 3, found); assertEquals(3,found.size); // make sure each instance is unique for( int i = 0; i < 3; i++ ) { double[] a = (double[])found.get(i).node.point; for( int j = i+1; j < 3; j++ ) { assertTrue(found.get(j).node.point != a); } } }
/** * Make sure the distance it returns is correct */ @Test public void checkDistance() { KdTreeSearchN<double[]> alg = createAlg(); KdTree tree = StandardKdTreeSearch1Tests.createTreeA(); alg.setTree(tree); alg.setMaxDistance(Double.MAX_VALUE); double[] pt = new double[]{11.5,8.2}; found.reset(); alg.findNeighbor(pt, 1, found); assertEquals(1,found.size); double d0 = ((double[])found.get(0).node.point)[0]-pt[0]; double d1 = ((double[])found.get(0).node.point)[1]-pt[1]; assertEquals(d0*d0 + d1*d1,found.get(0).distance,1e-8); }