pixel_canvas/
math.rs

1//! Useful common math operations for doing art.
2use std::ops::{Add, Div, Mul, Range, RangeFrom, RangeInclusive, RangeToInclusive, Sub};
3
4/// Represent types that can be restricted by a given range type.
5///
6/// This would've been called `Clamp`, except that there's a standard library
7/// method called `clamp`.
8pub trait Restrict<RangeType> {
9    /// Restrict a value into a given range.
10    ///
11    /// If a value is below the minimum bound, it should be clamped to that
12    /// value, and if it's above its max value it should be clamped to that.
13    /// This is only provided for inclusive ranges, since the behavior for
14    /// exclusive ranges of some types are less immediately clear.
15    fn restrict(self, range: RangeType) -> Self;
16}
17
18impl<T> Restrict<RangeInclusive<T>> for T
19where
20    T: PartialOrd,
21{
22    fn restrict(self, range: RangeInclusive<T>) -> T {
23        let (start, end) = range.into_inner();
24        if self > end {
25            return end;
26        }
27        if self < start {
28            return start;
29        }
30        self
31    }
32}
33
34impl<T> Restrict<RangeToInclusive<T>> for T
35where
36    T: PartialOrd,
37{
38    fn restrict(self, range: RangeToInclusive<T>) -> T {
39        if self > range.end {
40            return range.end;
41        }
42        self
43    }
44}
45
46impl<T> Restrict<RangeFrom<T>> for T
47where
48    T: PartialOrd,
49{
50    fn restrict(self, range: RangeFrom<T>) -> T {
51        if self < range.start {
52            return range.start;
53        }
54        self
55    }
56}
57
58/// Represents a type that can be mapped between two ranges.
59pub trait Remap
60where
61    Self: Sized,
62{
63    /// Remap a value from one range to another. A value outside the bounds of
64    /// one range will be similarly outside the bounds of the other.
65    /// ```rust
66    /// # use pixel_canvas::prelude::*;
67    /// assert_eq!(5.remap(-10..10, -100..100), 50);
68    /// assert_eq!(0.5.remap(0.0..1.0, -1.0..1.0), 0.0);
69    /// ```
70    fn remap(self, from: Range<Self>, onto: Range<Self>) -> Self;
71}
72
73impl<T> Remap for T
74where
75    T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + Copy,
76{
77    fn remap(self, from: Range<Self>, onto: Range<Self>) -> Self {
78        let from_size = from.end - from.start;
79        let onto_size = onto.end - onto.start;
80        ((self - from.start) * onto_size / from_size) + onto.start
81    }
82}