rust/integral-geometry/src/lib.rs
author unc0rr
Wed, 17 Oct 2018 22:45:33 +0200
changeset 13935 75eaf7c71789
child 13937 7f1c178506bb
permissions -rw-r--r--
Introduce integral-geometry crate, implement LinePoints iterator

use std::cmp;

pub struct LinePoints {
    e_x: i32,
    e_y: i32,
    d_x: i32,
    d_y: i32,
    s_x: i32,
    s_y: i32,
    x: i32,
    y: i32,
    d: i32,
    i: i32,
}

impl LinePoints {
    pub fn new(x1: i32, y1: i32, x2: i32, y2: i32) -> Self {
        let mut d_x: i32 = x2 - x1;
        let mut d_y: i32 = y2 - y1;
        let s_x: i32;
        let s_y: i32;

        if d_x > 0 {
            s_x = 1;
        } else if d_x < 0 {
            s_x = -1;
            d_x = -d_x;
        } else {
            s_x = d_x;
        }

        if d_y > 0 {
            s_y = 1;
        } else if d_y < 0 {
            s_y = -1;
            d_y = -d_y;
        } else {
            s_y = d_y;
        }

        Self {
            e_x: 0,
            e_y: 0,
            d_x,
            d_y,
            s_x,
            s_y,
            x: x1,
            y: y1,
            d: cmp::max(d_x, d_y),
            i: 0,
        }
    }
}

impl Iterator for LinePoints {
    type Item = (i32, i32);

    fn next(&mut self) -> Option<Self::Item> {
        if self.i <= self.d {
            self.e_x += self.d_x;
            self.e_y += self.d_y;

            if self.e_x > self.d {
                self.e_x -= self.d;
                self.x += self.s_x;
            }
            if self.e_y > self.d {
                self.e_y -= self.d;
                self.y += self.s_y;
            }

            self.i += 1;

            Some((self.x, self.y))
        } else {
            None
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn basic() {
        let v = vec![(0, 0), (1, 1), (2, 2), (3, 3)];

        for (&a, b) in v.iter().zip(LinePoints::new(0, 0, 3, 3)) {
            assert_eq!(a, b);
        }
    }
}