use precinct::{AxisBox, Region, RegionIndex, SearchParams};
fn l2(a: &[f32], b: &[f32]) -> f32 {
a.iter()
.zip(b)
.map(|(x, y)| (x - y).powi(2))
.sum::<f32>()
.sqrt()
}
#[test]
fn nearest_region_uses_surface_distance_not_center() {
let mut idx = RegionIndex::new(2, Default::default()).unwrap();
let a = AxisBox::new(vec![-5.0, 0.5], vec![5.0, 3.0]);
let b = AxisBox::new(vec![-0.05, 0.95], vec![0.05, 1.05]);
idx.add(0, a.clone()).unwrap();
idx.add(1, b.clone()).unwrap();
for i in 2..16u32 {
let o = 50.0 + (i as f32) * 5.0;
idx.add(i, AxisBox::new(vec![o, o], vec![o + 1.0, o + 1.0]))
.unwrap();
}
idx.build().unwrap();
let q = [0.0_f32, 0.0];
assert!(
a.distance_to_point(&q) < b.distance_to_point(&q),
"setup: A surface ({}) must be nearer than B surface ({})",
a.distance_to_point(&q),
b.distance_to_point(&q)
);
assert!(
l2(b.center(), &q) < l2(a.center(), &q),
"setup: B center ({}) must be nearer than A center ({})",
l2(b.center(), &q),
l2(a.center(), &q)
);
let params = SearchParams {
ef: 200,
overretrieve: 16,
};
let approx = idx.search(&q, 1, params).unwrap();
assert_eq!(approx.len(), 1);
assert_eq!(
approx[0].0, 0,
"nearest region must be the wide slab (id 0), not the close-centered box (id 1)"
);
assert!(
(approx[0].1 - a.distance_to_point(&q)).abs() < 1e-6,
"reported distance {} must equal A's true surface distance {}",
approx[0].1,
a.distance_to_point(&q)
);
let exact = idx.search_exhaustive(&q, 1);
assert_eq!(exact[0].0, 0);
assert_eq!(approx[0].0, exact[0].0);
}