aboutsummaryrefslogtreecommitdiff
path: root/src/element/basic_shapes_3d.rs
blob: 6dcab215734d73a710341a2713480b2cb4c6bf51 (plain)
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
use super::{BackendCoordAndZ, Drawable, PointCollection};
use crate::style::ShapeStyle;
use plotters_backend::{BackendCoord, DrawingBackend, DrawingErrorKind};

pub struct Cubiod<X, Y, Z> {
    face_style: ShapeStyle,
    edge_style: ShapeStyle,
    vert: [(X, Y, Z); 8],
}

impl<X: Clone, Y: Clone, Z: Clone> Cubiod<X, Y, Z> {
    pub fn new<FS: Into<ShapeStyle>, ES: Into<ShapeStyle>>(
        [(x0, y0, z0), (x1, y1, z1)]: [(X, Y, Z); 2],
        face_style: FS,
        edge_style: ES,
    ) -> Self {
        Self {
            face_style: face_style.into(),
            edge_style: edge_style.into(),
            vert: [
                (x0.clone(), y0.clone(), z0.clone()),
                (x0.clone(), y0.clone(), z1.clone()),
                (x0.clone(), y1.clone(), z0.clone()),
                (x0.clone(), y1.clone(), z1.clone()),
                (x1.clone(), y0.clone(), z0.clone()),
                (x1.clone(), y0.clone(), z1.clone()),
                (x1.clone(), y1.clone(), z0.clone()),
                (x1.clone(), y1.clone(), z1.clone()),
            ],
        }
    }
}

impl<'a, X: 'a, Y: 'a, Z: 'a> PointCollection<'a, (X, Y, Z), BackendCoordAndZ>
    for &'a Cubiod<X, Y, Z>
{
    type Point = &'a (X, Y, Z);
    type IntoIter = &'a [(X, Y, Z)];
    fn point_iter(self) -> Self::IntoIter {
        &self.vert
    }
}

impl<X, Y, Z, DB: DrawingBackend> Drawable<DB, BackendCoordAndZ> for Cubiod<X, Y, Z> {
    fn draw<I: Iterator<Item = (BackendCoord, i32)>>(
        &self,
        points: I,
        backend: &mut DB,
        _: (u32, u32),
    ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
        let vert: Vec<_> = points.collect();
        let mut polygon = vec![];
        for mask in vec![1, 2, 4] {
            let mask_a = if mask == 4 { 1 } else { mask * 2 };
            let mask_b = if mask == 1 { 4 } else { mask / 2 };
            let a = 0;
            let b = a | mask_a;
            let c = a | mask_a | mask_b;
            let d = a | mask_b;
            polygon.push([vert[a], vert[b], vert[c], vert[d]]);
            polygon.push([
                vert[a | mask],
                vert[b | mask],
                vert[c | mask],
                vert[d | mask],
            ]);
        }
        polygon.sort_by_cached_key(|t| std::cmp::Reverse(t[0].1 + t[1].1 + t[2].1 + t[3].1));

        for p in polygon {
            backend.fill_polygon(p.iter().map(|(coord, _)| *coord), &self.face_style)?;
            backend.draw_path(
                p.iter()
                    .map(|(coord, _)| *coord)
                    .chain(std::iter::once(p[0].0)),
                &self.edge_style,
            )?;
        }

        Ok(())
    }
}