scaled/
lib.rs

1//! Euclid points and vectors with fixed-point scalars
2
3#![feature(associated_type_defaults)]
4
5use fixed::traits::{FixedSigned, FromFixed, ToFixed};
6pub use fixed_sqrt::FixedSqrt;
7
8#[allow(unused_macros)]
9macro_rules! show {
10  ($e:expr) => { println!("{}: {:?}", stringify!($e), $e); }
11}
12
13pub mod wrapped;
14
15pub trait Space2d : Sized {
16  type Scalar : FixedSqrt;
17  type Point  : Point2d  <Self::Scalar, Self> =
18    euclid::Point2D <Self::Scalar, Self>;
19  type Vector : Vector2d <Self::Scalar, Self> =
20    euclid::Vector2D <Self::Scalar, Self>;
21}
22
23pub trait Point2d <S : FixedSqrt, U> : Sized + Clone + Copy + Default {
24  // required
25  fn new (x : S, y : S) -> Self;
26  fn map <F, T> (self, f : F) -> euclid::Point2D <T, U> where
27    F : FnMut (S) -> T;
28  // provided
29  fn origin() -> Self {
30    Self::default()
31  }
32  fn from_num <N : ToFixed> (num : euclid::Point2D <N, U>) -> Self {
33    Self::new (num.x.to_fixed(), num.y.to_fixed())
34  }
35  fn wrapping_from_num <N : ToFixed> (num : euclid::Point2D <N, U>) -> Self {
36    Self::new (num.x.wrapping_to_fixed(), num.y.wrapping_to_fixed())
37  }
38  fn from_bits (bits : euclid::Point2D <S::Bits, U>) -> Self {
39    Self::new (S::from_bits (bits.x), S::from_bits (bits.y))
40  }
41  fn to_num <N : FromFixed> (self) -> euclid::Point2D <N, U> {
42    self.map (S::to_num)
43  }
44  fn to_bits (self) -> euclid::Point2D <S::Bits, U> {
45    self.map (S::to_bits)
46  }
47}
48
49pub trait Vector2d <S : FixedSqrt, U> : Sized + Clone + Copy + Default {
50  // required
51  fn new (x : S, y : S) -> Self;
52  fn map <F, T> (self, f : F) -> euclid::Vector2D <T, U> where
53    F : FnMut (S) -> T;
54  fn magnitude2 (self) -> Option <S>;
55  fn norm (self) -> Norm <S> where S : FixedSigned;
56  // provided
57  fn zero() -> Self {
58    Self::default()
59  }
60  fn from_num <N : ToFixed> (num : euclid::Vector2D <N, U>) -> Self {
61    Self::new (num.x.to_fixed(), num.y.to_fixed())
62  }
63  fn wrapping_from_num <N : ToFixed> (num : euclid::Vector2D <N, U>) -> Self {
64    Self::new (num.x.wrapping_to_fixed(), num.y.wrapping_to_fixed())
65  }
66  fn from_bits (bits : euclid::Vector2D <S::Bits, U>) -> Self {
67    Self::new (S::from_bits (bits.x), S::from_bits (bits.y))
68  }
69  fn to_num <N : FromFixed> (self) -> euclid::Vector2D <N, U> {
70    self.map (N::from_fixed)
71  }
72  fn to_bits (self) -> euclid::Vector2D <S::Bits, U> {
73    self.map (S::to_bits)
74  }
75  fn scale (self, s : S) -> Self {
76    let new = self.map (|x| x * s);
77    Self::new (new.x, new.y)
78  }
79  fn magnitude (self) -> Option <S> {
80    self.magnitude2().map (FixedSqrt::sqrt)
81  }
82  fn normalized (mut self) -> Self {
83    let magnitude = loop {
84      match self.magnitude() {
85        Some (s) => break s,
86        None => {
87          let new = self.map (|s| s >> 1);
88          self = Self::new (new.x, new.y);
89        }
90      }
91    };
92    // TODO: make this static or const ?
93    let one = S::from_num (1usize);
94    self.scale (one / magnitude)
95  }
96}
97
98impl <S, U> Point2d <S, U> for euclid::Point2D <S, U> where S : FixedSqrt {
99  fn new (x : S, y : S) -> Self {
100    euclid::Point2D::new (x, y)
101  }
102  fn map <F, T> (self, mut f : F) -> euclid::Point2D <T, U> where
103    F : FnMut (S) -> T
104  {
105    euclid::Point2D::new (f (self.x), f (self.y))
106  }
107}
108
109impl <S, U> Vector2d <S, U> for euclid::Vector2D <S, U> where S : FixedSqrt {
110  fn new (x : S, y : S) -> Self {
111    euclid::Vector2D::new (x, y)
112  }
113  fn map <F, T> (self, mut f : F) -> euclid::Vector2D <T, U> where
114    F : FnMut (S) -> T
115  {
116    euclid::Vector2D::new (f (self.x), f (self.y))
117  }
118  fn magnitude2 (self) -> Option <S> {
119    let x2 = self.x.checked_mul (self.x)?;
120    let y2 = self.y.checked_mul (self.y)?;
121    x2.checked_add (y2)
122  }
123  fn norm (self) -> Norm <S> where S : FixedSigned {
124    if let Some (magnitude) = self.magnitude() {
125      return Norm::Euclidean (magnitude)
126    }
127    if let Some (sum) = self.x.checked_abs()
128      .and_then (|x| self.y.checked_abs().and_then (|y| x.checked_add (y)))
129    {
130      return Norm::Taxicab (sum)
131    }
132    Norm::Maximum (self.x.saturating_abs().max (self.y.saturating_abs()))
133  }
134}
135
136pub enum Norm <S> {
137  /// 2-norm
138  Euclidean (S),
139  /// 1-norm
140  Taxicab   (S),
141  /// Infinity-norm
142  Maximum   (S)
143}
144
145#[cfg(test)]
146mod tests {
147  use fixed;
148  use euclid;
149  use super::*;
150
151  #[test]
152  #[should_panic]
153  fn test_overflow() {
154    struct World;
155    impl Space2d for World {
156      type Scalar = fixed::types::I4F4;
157      type Point  = euclid::Point2D  <Self::Scalar, Self>;
158      type Vector = euclid::Vector2D <Self::Scalar, Self>;
159    }
160    type Scalar = <World as Space2d>::Scalar;
161    type Point  = <World as Space2d>::Point;
162    //type Vector = <World as Space2d>::Vector;
163
164    let p = Point::new (Scalar::MIN, Scalar::MIN);
165    let q = Point::new (Scalar::MAX, Scalar::MAX);
166    show!(p);
167    show!(q);
168    show!(q - p);
169    show!(p - q);
170  }
171
172  #[test]
173  fn test_norm_positive() {
174    struct World;
175    impl Space2d for World {
176      type Scalar = fixed::types::I4F4;
177      type Point  = euclid::Point2D  <Self::Scalar, Self>;
178      type Vector = euclid::Vector2D <Self::Scalar, Self>;
179    }
180    type Scalar = <World as Space2d>::Scalar;
181    //type Point  = <World as Space2d>::Point;
182    type Vector = <World as Space2d>::Vector;
183    let mut x = Scalar::MIN;
184    loop {
185      let mut y = Scalar::MIN;
186      loop {
187        let norm = match Vector::new (x, y).norm() {
188          Norm::Euclidean (n) => n,
189          Norm::Taxicab   (n) => n,
190          Norm::Maximum   (n) => n
191        };
192        show!(norm);
193        assert!(norm >= Scalar::from_bits (0));
194        if y == Scalar::MAX {
195          break
196        }
197        y += Scalar::from_bits (1);
198      }
199      if x == Scalar::MAX {
200        break
201      }
202      x += Scalar::from_bits (1);
203    }
204  }
205
206}