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
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use super::generators::{IndexedPolygon, SharedVertex};
use super::Polygon::PolyTri;
use super::{Polygon, Triangle};
use std::f32::consts::PI;
use Vertex;

/// Represents a circle in the XY plane with radius of 1, centered at (0, 0, 0)
#[derive(Clone, Copy)]
pub struct Circle {
    u: usize,
    sub_u: usize,
}

impl Circle {
    /// Create a new sphere.
    /// `u` is the number of points around the circle, must be > 3
    pub fn new(u: usize) -> Self {
        assert!(u > 3);
        Circle { u: 1, sub_u: u }
    }

    fn vert(&self, u: usize) -> Vertex {
        if u == 0 {
            Vertex {
                pos: [0., 0., 0.].into(),
                normal: [0., 0., 1.].into(),
            }
        } else {
            let u = ((u - 1) as f32 / self.sub_u as f32) * PI * 2.;

            let p = [u.cos(), u.sin(), 0.];
            Vertex {
                pos: p.into(),
                normal: [0., 0., 1.].into(),
            }
        }
    }
}

impl Iterator for Circle {
    type Item = Polygon<Vertex>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.sub_u, Some(self.sub_u))
    }

    fn next(&mut self) -> Option<Self::Item> {
        if self.u > self.sub_u {
            None
        } else if self.u == self.sub_u {
            self.u += 1;
            Some(PolyTri(Triangle::new(
                self.vert(0),
                self.vert(self.u - 1),
                self.vert(1),
            )))
        } else {
            self.u += 1;
            Some(PolyTri(Triangle::new(
                self.vert(0),
                self.vert(self.u - 1),
                self.vert(self.u),
            )))
        }
    }
}

impl SharedVertex<Vertex> for Circle {
    fn shared_vertex(&self, idx: usize) -> Vertex {
        self.vert(idx)
    }

    fn shared_vertex_count(&self) -> usize {
        self.sub_u + 1
    }
}

impl IndexedPolygon<Polygon<usize>> for Circle {
    fn indexed_polygon(&self, idx: usize) -> Polygon<usize> {
        if idx == self.sub_u - 1 {
            PolyTri(Triangle::new(0, self.sub_u, 1))
        } else {
            PolyTri(Triangle::new(
                0,
                (idx + 1) % (self.sub_u + 1),
                (idx + 2) % (self.sub_u + 1),
            ))
        }
    }

    fn indexed_polygon_count(&self) -> usize {
        self.sub_u
    }
}

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

    #[test]
    fn test_circle() {
        let circle = Circle::new(8);
        assert_eq!((8, Some(8)), circle.size_hint());
        assert_eq!(9, circle.shared_vertex_count());
        assert_eq!(8, circle.indexed_polygon_count());
        assert_eq!(
            Some(&Vertex {
                pos: [0.707107, -0.70710653, 0.0].into(),
                normal: [0., 0., 1.].into()
            }),
            circle.shared_vertex_iter().collect::<Vec<_>>().last()
        );
        let polys = circle.indexed_polygon_iter().collect::<Vec<_>>();
        assert_eq!(PolyTri(Triangle { x: 0, y: 1, z: 2 }), polys[0]);
        assert_eq!(Some(&PolyTri(Triangle { x: 0, y: 8, z: 1 })), polys.last());
    }
}