rust/integral-geometry/src/lib.rs
author alfadur
Thu, 18 Oct 2018 06:46:32 +0300
changeset 13938 1fa905aa4cdb
parent 13937 7f1c178506bb
child 13941 3f69a70063a5
permissions -rw-r--r--
move point struct into integral-geometry and use it to refactor a bit
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
     1
use std::cmp;
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
     2
use std::ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
     3
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
     4
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
     5
pub struct Point {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
     6
    pub x: i32,
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
     7
    pub y: i32,
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
     8
}
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
     9
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    10
impl Point {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    11
    #[inline]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    12
    pub fn new(x: i32, y: i32) -> Self {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    13
        Self {x, y}
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    14
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    15
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    16
    #[inline]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    17
    pub fn zero() -> Self {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    18
        Self::new(0, 0)
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    19
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    20
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    21
    #[inline]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    22
    pub fn signum(self) -> Self {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    23
        Self::new(self.x.signum(), self.y.signum())
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    24
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    25
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    26
    #[inline]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    27
    pub fn abs(self) -> Self {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    28
        Self::new(self.x.abs(), self.y.abs())
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    29
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    30
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    31
    #[inline]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    32
    pub fn dot(self, other: Point) -> i32 {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    33
        self.x * other.x + self.y * other.y
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    34
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    35
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    36
    #[inline]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    37
    pub fn max_norm(self) -> i32 {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    38
        std::cmp::max(self.x.abs(), self.y.abs())
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    39
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    40
}
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    41
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    42
macro_rules! bin_op_impl {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    43
    ($op: ty, $name: tt) => {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    44
        impl $op for Point {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    45
            type Output = Self;
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    46
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    47
            #[inline]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    48
            fn $name(self, rhs: Self) -> Self::Output {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    49
                Self::new(self.x.$name(rhs.x),
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    50
                          self.y.$name(rhs.y))
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    51
            }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    52
        }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    53
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    54
}
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    55
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    56
macro_rules! bin_assign_op_impl {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    57
    ($op: ty, $name: tt) => {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    58
        impl $op for Point {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    59
            #[inline]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    60
            fn $name(&mut self, rhs: Self){
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    61
                self.x.$name(rhs.x);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    62
                self.y.$name(rhs.y);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    63
            }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    64
        }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    65
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    66
}
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    67
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    68
bin_op_impl!(Add, add);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    69
bin_op_impl!(Sub, sub);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    70
bin_op_impl!(Mul, mul);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    71
bin_op_impl!(Div, div);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    72
bin_assign_op_impl!(AddAssign, add_assign);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    73
bin_assign_op_impl!(SubAssign, sub_assign);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    74
bin_assign_op_impl!(MulAssign, mul_assign);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    75
bin_assign_op_impl!(DivAssign, div_assign);
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    76
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    77
pub struct LinePoints {
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    78
    accumulator: Point,
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    79
    direction: Point,
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    80
    sign: Point,
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    81
    current: Point,
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    82
    total_steps: i32,
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    83
    step: i32,
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    84
}
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    85
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    86
impl LinePoints {
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    87
    pub fn new(from: Point, to: Point) -> Self {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    88
        let dir = to - from;
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    89
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    90
        Self {
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    91
            accumulator: Point::zero(),
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    92
            direction: dir.abs(),
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    93
            sign: dir.signum(),
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    94
            current: from,
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    95
            total_steps: dir.max_norm(),
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
    96
            step: 0,
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    97
        }
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    98
    }
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
    99
}
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   100
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   101
impl Iterator for LinePoints {
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   102
    type Item = Point;
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   103
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   104
    fn next(&mut self) -> Option<Self::Item> {
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   105
        if self.step <= self.total_steps {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   106
            self.accumulator += self.direction;
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   107
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   108
            if self.accumulator.x > self.total_steps {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   109
                self.accumulator.x -= self.total_steps;
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   110
                self.current.x += self.sign.x;
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   111
            }
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   112
            if self.accumulator.y > self.total_steps {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   113
                self.accumulator.y -= self.total_steps;
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   114
                self.current.y += self.sign.y;
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   115
            }
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   116
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   117
            self.step += 1;
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   118
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   119
            Some(self.current)
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   120
        } else {
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   121
            None
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   122
        }
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   123
    }
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   124
}
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   125
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   126
#[cfg(test)]
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   127
mod tests {
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   128
    use super::*;
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   129
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   130
    fn get_points(coords: &[(i32, i32)]) -> Vec<Point> {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   131
        coords.iter().map(|(x, y)| Point::new(*x, *y)).collect()
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   132
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   133
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   134
    #[test]
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   135
    fn basic() {
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   136
        let line = LinePoints::new(Point::new(0, 0), Point::new(3, 3));
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   137
        let v = get_points(&[(0, 0), (1, 1), (2, 2), (3, 3), (123, 456)]);
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   138
13938
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   139
        for (&a, b) in v.iter().zip(line) {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   140
            assert_eq!(a, b);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   141
        }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   142
    }
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   143
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   144
    #[test]
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   145
    fn skewed() {
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   146
        let line = LinePoints::new(Point::new(0, 0), Point::new(5, -7));
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   147
        let v = get_points(&[(0, 0), (1, -1), (2, -2), (2, -3), (3, -4), (4, -5), (4, -6), (5, -7)]);
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   148
1fa905aa4cdb move point struct into integral-geometry and use it to refactor a bit
alfadur
parents: 13937
diff changeset
   149
        for (&a, b) in v.iter().zip(line) {
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   150
            assert_eq!(a, b);
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   151
        }
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   152
    }
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
diff changeset
   153
}