vertex_iterator.rs 3.66 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, Sub, Div};

use super::line_iterator::LineIterator;
use super::canvas::Vertex;
use super::polygon::Polygon;

#[derive(Debug, Clone, Copy)]
pub enum Direction {
    Left,
    Right,
}

#[derive(Debug, Clone)]
enum VertexIteratorMode {
    Line,
    Edge
}

#[derive(Debug, Clone)]
pub struct VertexIterator<'a, T> where T: Debug {
    p         :&'a Polygon<T>,
    top       :usize,
    current   :Option<usize>,
    edge      :Option<LineIterator<T>>,
    mode      :VertexIteratorMode,
    direction :Direction,
}

impl<'a, T> VertexIterator<'a, T>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
       + Debug + Copy + From<i32> {
    pub fn line(p :&'a Polygon<T>, direction :Direction) -> Self {
        let top  = p.vert_min(direction);
        let next = p.next_y(top, direction);

        VertexIterator { p:         p
                       , top:       top
                       , current:   next
                       , edge:      None
                       , mode:      VertexIteratorMode::Line
                       , direction: direction }
    }

    pub fn edge(p :&'a Polygon<T>, direction :Direction) -> Self {
        let mut vi = Self::line(p, direction);

        vi.mode = VertexIteratorMode::Edge;
        vi.edge = match vi.current {
            None       => None,
            Some(next) => Some(p.vertex(vi.top).edge_iter(p.vertex(next))),
        };

        vi
    }

    // if this yields "None" we are finished.
    fn next_edge(&mut self) -> Option<LineIterator<T>> {
        let current  = self.current?;
        let next     = self.p.next_y(current, self.direction)?;
        let mut edge = self.p.vertex(current).edge_iter(self.p.vertex(next));

        match edge.next() {
            // It should be impossible that a new edge iterator has no values
            // at all… anyway, just in case I handle it here.
            None    => self.next_edge(),
            Some(_) => {
                self.current = Some(next);
                self.edge    = Some(edge);
                self.edge
            },
        }
    }
}

impl<'a,T> Iterator for VertexIterator<'a,T>
where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
       + Debug + Copy + From<i32> {
    type Item = Vertex<T>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.mode {
            VertexIteratorMode::Edge => {
                // if for whatever reason edge is "None" finish this iterator.
                let next = self.edge.as_mut()?.next();

                match next {
                    Some(_) => next,
                    None    => {
                        self.next_edge()?;
                        self.next()
                    },
                }
            },
            VertexIteratorMode::Line => {
                let current  = self.current?;
                self.current = self.p.next_y(current, self.direction);
                Some(self.p.vertex(current))
            },
        }
    }
}