#[derive(Debug, Clone, Copy, PartialEq)]
pub enum SnapZoneType {
Snap,
Dead,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SnapZone<T> {
pub target: T,
pub threshold: T,
pub zone_type: SnapZoneType,
}
impl<T> SnapZone<T>
where
T: Copy + PartialOrd + core::ops::Sub<Output = T> + core::ops::Add<Output = T>,
{
pub const fn new(target: T, threshold: T, zone_type: SnapZoneType) -> Self {
Self {
target,
threshold,
zone_type,
}
}
pub fn contains(&self, value: T) -> bool {
let min = self.target - self.threshold;
let max = self.target + self.threshold;
value >= min && value <= max
}
pub fn apply(&self, _value: T, last_output: T) -> T {
match self.zone_type {
SnapZoneType::Snap => self.target,
SnapZoneType::Dead => last_output,
}
}
pub fn overlaps(&self, other: &SnapZone<T>) -> bool {
let self_min = self.target - self.threshold;
let self_max = self.target + self.threshold;
let other_min = other.target - other.threshold;
let other_max = other.target + other.threshold;
!(self_max < other_min || other_max < self_min)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_snap_zone_contains() {
let zone = SnapZone::new(0.5, 0.1, SnapZoneType::Snap);
assert!(zone.contains(0.4)); assert!(zone.contains(0.5)); assert!(zone.contains(0.6)); assert!(!zone.contains(0.39)); assert!(!zone.contains(0.61)); }
#[test]
fn test_snap_zone_apply() {
let zone = SnapZone::new(0.5, 0.1, SnapZoneType::Snap);
assert_eq!(zone.apply(0.45, 0.0), 0.5);
assert_eq!(zone.apply(0.55, 0.0), 0.5);
}
#[test]
fn test_dead_zone_apply() {
let zone = SnapZone::new(0.5, 0.1, SnapZoneType::Dead);
assert_eq!(zone.apply(0.45, 0.3), 0.3);
assert_eq!(zone.apply(0.55, 0.7), 0.7);
}
#[test]
fn test_snap_zone_overlaps() {
let zone1 = SnapZone::new(0.0, 0.05, SnapZoneType::Snap); let zone2 = SnapZone::new(0.5, 0.05, SnapZoneType::Snap); let zone3 = SnapZone::new(0.03, 0.03, SnapZoneType::Snap);
assert!(!zone1.overlaps(&zone2)); assert!(!zone2.overlaps(&zone3)); assert!(zone1.overlaps(&zone3)); assert!(zone3.overlaps(&zone1)); }
#[test]
fn test_snap_zone_edge_cases() {
let zone = SnapZone::new(0.0, 0.02, SnapZoneType::Snap);
assert!(zone.contains(0.0));
assert!(zone.contains(0.02));
}
}