1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// Regular ngons.

use crate::{Canvas, ClosedPath, FlatIterPath, Paint, Scale, Translate, P2, V2};

#[derive(Copy, Clone, Debug)]
pub struct Ngon {
    phase: f32,
    r: f32,
    n: usize,
    c: P2,
    i: usize,
}

impl Ngon {
    pub fn new(c: P2, n: usize, r: f32) -> Self {
        Self {
            phase: 0.,
            r,
            n,
            c,
            i: 0,
        }
    }

    pub fn triangle(c: P2, r: f32) -> Self { Self::new(c, 3, r) }

    pub fn square(c: P2, r: f32) -> Self {
        let mut diamond = Self::diamond(c, r);
        diamond.phase -= std::f32::consts::PI / 4.;
        diamond
    }

    pub fn diamond(c: P2, r: f32) -> Self { Self::new(c, 4, r) }

    pub fn rotate(&mut self, phase: f32) { self.phase += phase; }
}

impl Iterator for Ngon {
    type Item = P2;

    fn next(&mut self) -> Option<Self::Item> {
        if self.i == self.n {
            return None;
        }

        let completion = self.i as f32 / self.n as f32;
        let theta = (completion * std::f32::consts::PI * 2.0) + self.phase;
        self.i += 1;

        Some(P2::new(
            self.c.x + theta.sin() * self.r,
            self.c.y + theta.cos() * self.r,
        ))
    }
}

impl Scale for Ngon {
    fn scale(self, factor: f32) -> Self {
        Self {
            r: self.r * factor,
            ..self
        }
    }
}

impl Translate for Ngon {
    fn translate(self, translation: V2) -> Self {
        Self {
            c: self.c + translation,
            ..self
        }
    }
}

impl Paint for Ngon {
    fn paint(&self, comp: &mut Canvas) { comp.paint(ClosedPath::from(FlatIterPath::from(*self))) }
}