zng_unit/
distance_key.rs

1use crate::{Px, PxPoint, PxRect};
2
3use serde::{Deserialize, Serialize};
4
5/// Comparable key that represents the absolute distance between two pixel points.
6///
7/// Computing the actual distance only for comparison is expensive, this key avoids the conversion to float and square-root operation.
8#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, bytemuck::Zeroable, bytemuck::Pod)]
9#[repr(transparent)]
10#[serde(transparent)]
11pub struct DistanceKey(u64);
12impl DistanceKey {
13    /// Value that is always greater than any distance key.
14    pub const NONE_MAX: DistanceKey = DistanceKey(u64::MAX);
15
16    /// Value that is always smaller than any distance key.
17    pub const NONE_MIN: DistanceKey = DistanceKey(0);
18
19    /// Maximum distance.
20    pub const MAX: DistanceKey = DistanceKey((Px::MAX.0 as u64).pow(2));
21
22    /// Minimum distance.
23    pub const MIN: DistanceKey = DistanceKey(1);
24
25    /// New distance key computed from two points.
26    pub fn from_points(a: PxPoint, b: PxPoint) -> Self {
27        let pa = ((a.x - b.x).0.unsigned_abs() as u64).pow(2);
28        let pb = ((a.y - b.y).0.unsigned_abs() as u64).pow(2);
29
30        Self((pa + pb) + 1)
31    }
32
33    /// New distance key computed from the nearest point inside `a` to `b`.
34    pub fn from_rect_to_point(a: PxRect, b: PxPoint) -> Self {
35        Self::from_points(b.clamp(a.min(), a.max()), b)
36    }
37
38    /// New distance key from already computed actual distance.
39    ///
40    /// Note that computing the actual distance is slower then using [`from_points`] to compute just the distance key.
41    ///
42    /// [`from_points`]: Self::from_points
43    pub fn from_distance(d: Px) -> Self {
44        let p = (d.0.unsigned_abs() as u64).pow(2);
45        Self(p + 1)
46    }
47
48    /// If the key is the [`NONE_MAX`] or [`NONE_MIN`].
49    ///
50    /// [`NONE_MAX`]: Self::NONE_MAX
51    /// [`NONE_MIN`]: Self::NONE_MIN
52    pub fn is_none(self) -> bool {
53        self == Self::NONE_MAX || self == Self::NONE_MIN
54    }
55
56    /// Completes the distance calculation.
57    pub fn distance(self) -> Option<Px> {
58        if self.is_none() {
59            None
60        } else {
61            let p = self.0 - 1;
62            let d = (p as f64).sqrt();
63
64            Some(Px(d.round() as i32))
65        }
66    }
67
68    /// Compares and returns the minimum distance.
69    pub fn min(self, other: Self) -> Self {
70        Self(self.0.min(other.0))
71    }
72
73    /// Compares and returns the maximum distance.
74    pub fn max(self, other: Self) -> Self {
75        Self(self.0.max(other.0))
76    }
77}