polygon.rs 4.97 KB
//
// …
//
// Georg Hopp <georg@steffers.org>
//
// Copyright © 2019 Georg Hopp
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

use std::fmt::Debug;
use std::ops::{Add, Div, Sub};

use super::canvas::{Canvas, Vertex, Vertices};
use super::drawable::Drawable;
use super::fillable::Fillable;
use super::vertex_iterator::{Direction, VertexIterator};

#[derive(Debug, Clone)]
pub struct Polygon<T>(pub Vertices<T>);

impl<T> Polygon<T>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
       + Copy + Debug + From<i32> {
    #[inline]
    pub fn vertex(&self, v :usize) -> Vertex<T> {
        let Polygon(cs) = self;
        cs[v]
    }

    pub fn vert_min<'a>(&'a self, d :Direction) -> usize {
        let Polygon(cs) = self;

        type ICoord<'a, T> = (usize, &'a Vertex<T>);

        let fold = |acc :Option<ICoord<'a,T>>, x :ICoord<'a, T>|
                   match acc {
                       None    => Some(x),
                       Some(a) => {
                           let (_, ay, _) = a.1.as_tuple();
                           let (_, xy, _) = x.1.as_tuple();
                           if xy < ay {Some(x)} else {Some(a)}
                       },
                   };

        let mut  min = cs.iter().enumerate().fold(None, fold).unwrap().0;
        let mut next = self.step(min, d);

        while self.vertex(min).same_y(&self.vertex(next)) {
            min  = next;
            next = self.step(min, d);
        }

        min
    }

    fn left_edge(&self) -> VertexIterator<T> {
        VertexIterator::edge(self, Direction::Left)
    }

    fn right_edge(&self) -> VertexIterator<T> {
        VertexIterator::edge(self, Direction::Right)
    }

    fn left_vertices(&self) -> VertexIterator<T> {
        VertexIterator::line(self, Direction::Left)
    }

    fn right_vertices(&self) -> VertexIterator<T> {
        VertexIterator::line(self, Direction::Right)
    }

    fn left(&self, v :usize) -> usize {
        let Polygon(cs) = self;

        match v {
            0 => cs.len() - 1,
            _ => v - 1,
        }
    }

    fn right(&self, v :usize) -> usize {
        let Polygon(cs) = self;

        (v + 1) % cs.len()
    }

    fn step(&self, v :usize, d :Direction) -> usize {
        match d {
            Direction::Left  => self.left(v),
            Direction::Right => self.right(v),
        }
    }

    pub fn next_y(&self, c :usize, d :Direction) -> Option<usize> {
        fn inner<T>( p :&Polygon<T>
                   , c :usize
                   , n :usize
                   , d :Direction) -> Option<usize>
        where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
               + Copy + Debug + From<i32> {
            if c == n {
                None
            } else {
                let (_, cy, _) = p.vertex(c).as_tuple();
                let (_, ny, _) = p.vertex(n).as_tuple();

                if ny < cy { None } else { Some(n) }
            }
        }

        inner(self, c, self.step(c, d), d)
    }
}

impl<T> Drawable<T> for Polygon<T>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
       + Debug + Clone + Copy + From<i32> {
    fn plot(&self) -> Vertices<T> {
        let Polygon(cs) = self;

        match cs[..] {
            []     => Vec::<Vertex<T>>::new(),
            [a]    => vec!(a),
            [a, b] => a.line(b),
            _      => {
                let (a, b) = (cs[0], cs[1]);
                let mut r = a.line(b);
                let mut i = b;
                for j in cs[2..].iter() {
                    r.append(&mut i.line(*j)[1..].to_vec());
                    i = *j;
                }
                let mut j = a.line(i);
                let     l = j.len();
                if l > 1 {
                    r.append(&mut j[1..l-1].to_vec());
                }
                r
            },
        }
    }
}

impl<T> Fillable<T> for Polygon<T>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
       + Debug + Clone + Copy + From<i32> {
    fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32) {
        let scanlines = self.left_edge().zip(self.right_edge());
        let  vertices = |(l, r) :(Vertex<T>, Vertex<T>)| l.line_iter(r);

        for p in scanlines.flat_map(vertices) {
            canvas.set_pixel(p, color);
        }
    }
}

/*
impl<T> Display for Polygon<T> where T: Copy {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let Polygon(a) = self;
        write!(f, "Poly[{}]", a)
    }
}
*/