extern crate kdtree; use kdtree::distance::squared_euclidean; use kdtree::ErrorKind; use kdtree::KdTree; static POINT_A: ([f64; 2], usize) = ([0f64, 0f64], 0); static POINT_B: ([f64; 2], usize) = ([1f64, 1f64], 1); static POINT_C: ([f64; 2], usize) = ([2f64, 2f64], 2); static POINT_D: ([f64; 2], usize) = ([3f64, 3f64], 3); #[test] fn it_works() { let dimensions = 2; let capacity_per_node = 2; let mut kdtree = KdTree::with_capacity(dimensions, capacity_per_node); kdtree.add(&POINT_A.0, POINT_A.1).unwrap(); kdtree.add(&POINT_B.0, POINT_B.1).unwrap(); kdtree.add(&POINT_C.0, POINT_C.1).unwrap(); kdtree.add(&POINT_D.0, POINT_D.1).unwrap(); assert_eq!(kdtree.size(), 4); assert_eq!(kdtree.nearest(&POINT_A.0, 0, &squared_euclidean).unwrap(), vec![]); assert_eq!( kdtree.nearest(&POINT_A.0, 1, &squared_euclidean).unwrap(), vec![(0f64, &0)] ); assert_eq!( kdtree.nearest(&POINT_A.0, 2, &squared_euclidean).unwrap(), vec![(0f64, &0), (2f64, &1)] ); assert_eq!( kdtree.nearest(&POINT_A.0, 3, &squared_euclidean).unwrap(), vec![(0f64, &0), (2f64, &1), (8f64, &2)] ); assert_eq!( kdtree.nearest(&POINT_A.0, 4, &squared_euclidean).unwrap(), vec![(0f64, &0), (2f64, &1), (8f64, &2), (18f64, &3)] ); assert_eq!( kdtree.nearest(&POINT_A.0, 5, &squared_euclidean).unwrap(), vec![(0f64, &0), (2f64, &1), (8f64, &2), (18f64, &3)] ); assert_eq!( kdtree.nearest(&POINT_B.0, 4, &squared_euclidean).unwrap(), vec![(0f64, &1), (2f64, &0), (2f64, &2), (8f64, &3)] ); assert_eq!( kdtree.within(&POINT_A.0, 0.0, &squared_euclidean).unwrap(), vec![(0.0, &0)] ); assert_eq!( kdtree.within(&POINT_B.0, 1.0, &squared_euclidean).unwrap(), vec![(0.0, &1)] ); assert_eq!( kdtree.within(&POINT_B.0, 2.0, &squared_euclidean).unwrap(), vec![(0.0, &1), (2.0, &2), (2.0, &0)] ); assert_eq!( kdtree .iter_nearest(&POINT_A.0, &squared_euclidean) .unwrap() .collect::>(), vec![(0f64, &0), (2f64, &1), (8f64, &2), (18f64, &3)] ); let iter = kdtree .iter_nearest_mut(&POINT_A.0, &squared_euclidean) .unwrap() .next() .unwrap(); *iter.1 = 10; assert_eq!( kdtree .iter_nearest(&POINT_A.0, &squared_euclidean) .unwrap() .collect::>(), vec![(0f64, &10), (2f64, &1), (8f64, &2), (18f64, &3)] ); } #[test] fn it_works_with_vec() { let dimensions = 2; let capacity_per_node = 2; let mut kdtree = KdTree::with_capacity(dimensions, capacity_per_node); kdtree.add(vec![0.0; 2], 0).unwrap(); kdtree.add(vec![1.0; 2], 1).unwrap(); kdtree.add(vec![2.0; 2], 2).unwrap(); kdtree.add(vec![3.0; 2], 3).unwrap(); assert_eq!(kdtree.size(), 4); assert_eq!(kdtree.nearest(&POINT_A.0, 0, &squared_euclidean).unwrap(), vec![]); assert_eq!( kdtree.nearest(&POINT_A.0, 1, &squared_euclidean).unwrap(), vec![(0f64, &0)] ); assert_eq!( kdtree.nearest(&POINT_A.0, 2, &squared_euclidean).unwrap(), vec![(0f64, &0), (2f64, &1)] ); assert_eq!( kdtree.nearest(&POINT_A.0, 3, &squared_euclidean).unwrap(), vec![(0f64, &0), (2f64, &1), (8f64, &2)] ); assert_eq!( kdtree.nearest(&POINT_A.0, 4, &squared_euclidean).unwrap(), vec![(0f64, &0), (2f64, &1), (8f64, &2), (18f64, &3)] ); assert_eq!( kdtree.nearest(&POINT_A.0, 5, &squared_euclidean).unwrap(), vec![(0f64, &0), (2f64, &1), (8f64, &2), (18f64, &3)] ); assert_eq!( kdtree.nearest(&POINT_B.0, 4, &squared_euclidean).unwrap(), vec![(0f64, &1), (2f64, &0), (2f64, &2), (8f64, &3)] ); } #[test] fn handles_zero_capacity() { let mut kdtree = KdTree::with_capacity(2, 0); assert_eq!(kdtree.add(&POINT_A.0, POINT_A.1), Err(ErrorKind::ZeroCapacity)); assert_eq!(kdtree.nearest(&POINT_A.0, 1, &squared_euclidean).unwrap(), vec![]); } #[test] fn handles_wrong_dimension() { let point = ([0f64], 0f64); let mut kdtree = KdTree::with_capacity(2, 1); assert_eq!(kdtree.add(&point.0, point.1), Err(ErrorKind::WrongDimension)); assert_eq!( kdtree.nearest(&point.0, 1, &squared_euclidean), Err(ErrorKind::WrongDimension) ); } #[test] fn handles_non_finite_coordinate() { let point_a = ([std::f64::NAN, std::f64::NAN], 0f64); let point_b = ([std::f64::INFINITY, std::f64::INFINITY], 0f64); let mut kdtree = KdTree::with_capacity(2, 1); assert_eq!(kdtree.add(&point_a.0, point_a.1), Err(ErrorKind::NonFiniteCoordinate)); assert_eq!(kdtree.add(&point_b.0, point_b.1), Err(ErrorKind::NonFiniteCoordinate)); assert_eq!( kdtree.nearest(&point_a.0, 1, &squared_euclidean), Err(ErrorKind::NonFiniteCoordinate) ); assert_eq!( kdtree.nearest(&point_b.0, 1, &squared_euclidean), Err(ErrorKind::NonFiniteCoordinate) ); } #[test] fn handles_singularity() { let mut kdtree = KdTree::with_capacity(2, 1); kdtree.add(&POINT_A.0, POINT_A.1).unwrap(); kdtree.add(&POINT_A.0, POINT_A.1).unwrap(); kdtree.add(&POINT_A.0, POINT_A.1).unwrap(); kdtree.add(&POINT_B.0, POINT_B.1).unwrap(); kdtree.add(&POINT_B.0, POINT_B.1).unwrap(); kdtree.add(&POINT_B.0, POINT_B.1).unwrap(); kdtree.add(&POINT_C.0, POINT_C.1).unwrap(); kdtree.add(&POINT_C.0, POINT_C.1).unwrap(); kdtree.add(&POINT_C.0, POINT_C.1).unwrap(); assert_eq!(kdtree.size(), 9); } #[test] fn handles_pending_order() { let item1 = ([0f64], 1); let item2 = ([100f64], 2); let item3 = ([45f64], 3); let item4 = ([55f64], 4); // Build a kd tree let dimensions = 1; let capacity_per_node = 2; let mut kdtree = KdTree::with_capacity(dimensions, capacity_per_node); kdtree.add(&item1.0, item1.1).unwrap(); kdtree.add(&item2.0, item2.1).unwrap(); kdtree.add(&item3.0, item3.1).unwrap(); kdtree.add(&item4.0, item4.1).unwrap(); assert_eq!( kdtree.nearest(&[51f64], 2, &squared_euclidean).unwrap(), vec![(16.0, &4), (36.0, &3)] ); assert_eq!( kdtree.nearest(&[51f64], 4, &squared_euclidean).unwrap(), vec![(16.0, &4), (36.0, &3), (2401.0, &2), (2601.0, &1)] ); assert_eq!( kdtree.nearest(&[49f64], 2, &squared_euclidean).unwrap(), vec![(16.0, &3), (36.0, &4)] ); assert_eq!( kdtree.nearest(&[49f64], 4, &squared_euclidean).unwrap(), vec![(16.0, &3), (36.0, &4), (2401.0, &1), (2601.0, &2)] ); assert_eq!( kdtree .iter_nearest(&[49f64], &squared_euclidean) .unwrap() .collect::>(), vec![(16.0, &3), (36.0, &4), (2401.0, &1), (2601.0, &2)] ); assert_eq!( kdtree .iter_nearest(&[51f64], &squared_euclidean) .unwrap() .collect::>(), vec![(16.0, &4), (36.0, &3), (2401.0, &2), (2601.0, &1)] ); assert_eq!(kdtree.within(&[50f64], 1.0, &squared_euclidean).unwrap(), vec![]); assert_eq!( kdtree.within(&[50f64], 25.0, &squared_euclidean).unwrap(), vec![(25.0, &3), (25.0, &4)] ); assert_eq!( kdtree.within(&[50f64], 30.0, &squared_euclidean).unwrap(), vec![(25.0, &3), (25.0, &4)] ); assert_eq!( kdtree.within(&[55f64], 5.0, &squared_euclidean).unwrap(), vec![(0.0, &4)] ); assert_eq!( kdtree.within(&[56f64], 5.0, &squared_euclidean).unwrap(), vec![(1.0, &4)] ); } #[test] fn handles_drops_correctly() { use std::ops::Drop; use std::sync::{Arc, Mutex}; // Mock up a structure to keep track of Drops struct Test(Arc>); impl PartialEq for Test { fn eq(&self, other: &Test) -> bool { *self.0.lock().unwrap() == *other.0.lock().unwrap() } } impl Drop for Test { fn drop(&mut self) { let mut drop_counter = self.0.lock().unwrap(); *drop_counter += 1; } } let drop_counter = Arc::new(Mutex::new(0)); let item1 = ([0f64, 0f64], Test(drop_counter.clone())); let item2 = ([1f64, 1f64], Test(drop_counter.clone())); let item3 = ([2f64, 2f64], Test(drop_counter.clone())); let item4 = ([3f64, 3f64], Test(drop_counter.clone())); { // Build a kd tree let dimensions = 2; let capacity_per_node = 1; let mut kdtree = KdTree::with_capacity(dimensions, capacity_per_node); kdtree.add(&item1.0, item1.1).unwrap(); kdtree.add(&item2.0, item2.1).unwrap(); kdtree.add(&item3.0, item3.1).unwrap(); kdtree.add(&item4.0, item4.1).unwrap(); // Pre-drop check assert_eq!(*drop_counter.lock().unwrap(), 0); } // Post-drop check assert_eq!(*drop_counter.lock().unwrap(), 4); } #[test] fn handles_remove_correctly() { let item1 = ([0f64], 1); let item2 = ([100f64], 2); let item3 = ([45f64], 3); let item4 = ([55f64], 4); // Build a kd tree let dimensions = 1; let capacity_per_node = 2; let mut kdtree = KdTree::with_capacity(dimensions, capacity_per_node); kdtree.add(&item1.0, item1.1).unwrap(); kdtree.add(&item2.0, item2.1).unwrap(); kdtree.add(&item3.0, item3.1).unwrap(); kdtree.add(&item4.0, item4.1).unwrap(); let num_removed = kdtree.remove(&&item3.0, &item3.1).unwrap(); assert_eq!(kdtree.size(), 3); assert_eq!(num_removed, 1); assert_eq!( kdtree.nearest(&[51f64], 2, &squared_euclidean).unwrap(), vec![(16.0, &4), (2401.0, &2)] ); } #[test] fn handles_remove_multiple_match() { let item1 = ([0f64], 1); let item2 = ([0f64], 1); let item3 = ([100f64], 2); let item4 = ([45f64], 3); // Build a kd tree let dimensions = 1; let capacity_per_node = 2; let mut kdtree = KdTree::with_capacity(dimensions, capacity_per_node); kdtree.add(&item1.0, item1.1).unwrap(); kdtree.add(&item2.0, item2.1).unwrap(); kdtree.add(&item3.0, item3.1).unwrap(); kdtree.add(&item4.0, item4.1).unwrap(); assert_eq!(kdtree.size(), 4); let num_removed = kdtree.remove(&&[0f64], &1).unwrap(); assert_eq!(kdtree.size(), 2); assert_eq!(num_removed, 2); assert_eq!( kdtree.nearest(&[45f64], 1, &squared_euclidean).unwrap(), vec![(0.0, &3)] ); } #[test] fn handles_remove_no_match() { let item1 = ([0f64], 1); let item2 = ([100f64], 2); let item3 = ([45f64], 3); let item4 = ([55f64], 4); // Build a kd tree let dimensions = 1; let capacity_per_node = 2; let mut kdtree = KdTree::with_capacity(dimensions, capacity_per_node); kdtree.add(&item1.0, item1.1).unwrap(); kdtree.add(&item2.0, item2.1).unwrap(); kdtree.add(&item3.0, item3.1).unwrap(); kdtree.add(&item4.0, item4.1).unwrap(); let num_removed = kdtree.remove(&&[1f64], &2).unwrap(); assert_eq!(kdtree.size(), 4); assert_eq!(num_removed, 0); assert_eq!( kdtree.nearest(&[51f64], 2, &squared_euclidean).unwrap(), vec![(16.0, &4), (36.0, &3)] ); }