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