1use num_traits::Float;
2
3pub fn distance_to_space<F, T>(p1: &[T], min_bounds: &[T], max_bounds: &[T], distance: &F) -> T
4where
5 F: Fn(&[T], &[T]) -> T,
6 T: Float,
7{
8 let mut p2 = vec![T::nan(); p1.len()];
9 for i in 0..p1.len() {
10 if p1[i] > max_bounds[i] {
11 p2[i] = max_bounds[i];
12 } else if p1[i] < min_bounds[i] {
13 p2[i] = min_bounds[i];
14 } else {
15 p2[i] = p1[i];
16 }
17 }
18 distance(p1, &p2[..])
19}
20
21#[cfg(test)]
22mod tests {
23 use super::distance_to_space;
24 use crate::distance::squared_euclidean;
25 use std::f64::{INFINITY, NEG_INFINITY};
26
27 #[test]
28 fn test_normal_distance_to_space() {
29 let dis = distance_to_space(&[0.0, 0.0], &[1.0, 1.0], &[2.0, 2.0], &squared_euclidean);
30 assert_eq!(dis, 2.0);
31 }
32
33 #[test]
34 fn test_distance_outside_inf() {
35 let dis = distance_to_space(&[0.0, 0.0], &[1.0, 1.0], &[INFINITY, INFINITY], &squared_euclidean);
36 assert_eq!(dis, 2.0);
37 }
38
39 #[test]
40 fn test_distance_inside_inf() {
41 let dis = distance_to_space(
42 &[2.0, 2.0],
43 &[NEG_INFINITY, NEG_INFINITY],
44 &[INFINITY, INFINITY],
45 &squared_euclidean,
46 );
47 assert_eq!(dis, 0.0);
48 }
49
50 #[test]
51 fn test_distance_inside_normal() {
52 let dis = distance_to_space(&[2.0, 2.0], &[0.0, 0.0], &[3.0, 3.0], &squared_euclidean);
53 assert_eq!(dis, 0.0);
54 }
55
56 #[test]
57 fn distance_to_half_space() {
58 let dis = distance_to_space(
59 &[-2.0, 0.0],
60 &[0.0, NEG_INFINITY],
61 &[INFINITY, INFINITY],
62 &squared_euclidean,
63 );
64 assert_eq!(dis, 4.0);
65 }
66}