1 use super::{BackendCoordAndZ, Drawable, PointCollection};
2 use crate::style::ShapeStyle;
3 use plotters_backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
4 
5 /**
6 Represents a cuboid, a six-faced solid.
7 
8 # Examples
9 
10 ```
11 use plotters::prelude::*;
12 let drawing_area = SVGBackend::new("cuboid.svg", (300, 200)).into_drawing_area();
13 drawing_area.fill(&WHITE).unwrap();
14 let mut chart_builder = ChartBuilder::on(&drawing_area);
15 let mut chart_context = chart_builder.margin(20).build_cartesian_3d(0.0..3.5, 0.0..2.5, 0.0..1.5).unwrap();
16 chart_context.configure_axes().x_labels(4).y_labels(3).z_labels(2).draw().unwrap();
17 let cubiod = Cubiod::new([(0.,0.,0.), (3.,2.,1.)], BLUE.mix(0.2), BLUE);
18 chart_context.draw_series(std::iter::once(cubiod)).unwrap();
19 ```
20 
21 The result is a semi-transparent cuboid with blue edges:
22 
23 ![](https://cdn.jsdelivr.net/gh/facorread/plotters-doc-data@b6703f7/apidoc/cuboid.svg)
24 */
25 pub struct Cubiod<X, Y, Z> {
26     face_style: ShapeStyle,
27     edge_style: ShapeStyle,
28     vert: [(X, Y, Z); 8],
29 }
30 
31 impl<X: Clone, Y: Clone, Z: Clone> Cubiod<X, Y, Z> {
32     /**
33     Creates a cuboid.
34 
35     See [`Cubiod`] for more information and examples.
36     */
37     #[allow(clippy::redundant_clone)]
new<FS: Into<ShapeStyle>, ES: Into<ShapeStyle>>( [(x0, y0, z0), (x1, y1, z1)]: [(X, Y, Z); 2], face_style: FS, edge_style: ES, ) -> Self38     pub fn new<FS: Into<ShapeStyle>, ES: Into<ShapeStyle>>(
39         [(x0, y0, z0), (x1, y1, z1)]: [(X, Y, Z); 2],
40         face_style: FS,
41         edge_style: ES,
42     ) -> Self {
43         Self {
44             face_style: face_style.into(),
45             edge_style: edge_style.into(),
46             vert: [
47                 (x0.clone(), y0.clone(), z0.clone()),
48                 (x0.clone(), y0.clone(), z1.clone()),
49                 (x0.clone(), y1.clone(), z0.clone()),
50                 (x0.clone(), y1.clone(), z1.clone()),
51                 (x1.clone(), y0.clone(), z0.clone()),
52                 (x1.clone(), y0.clone(), z1.clone()),
53                 (x1.clone(), y1.clone(), z0.clone()),
54                 (x1.clone(), y1.clone(), z1.clone()),
55             ],
56         }
57     }
58 }
59 
60 impl<'a, X: 'a, Y: 'a, Z: 'a> PointCollection<'a, (X, Y, Z), BackendCoordAndZ>
61     for &'a Cubiod<X, Y, Z>
62 {
63     type Point = &'a (X, Y, Z);
64     type IntoIter = &'a [(X, Y, Z)];
point_iter(self) -> Self::IntoIter65     fn point_iter(self) -> Self::IntoIter {
66         &self.vert
67     }
68 }
69 
70 impl<X, Y, Z, DB: DrawingBackend> Drawable<DB, BackendCoordAndZ> for Cubiod<X, Y, Z> {
draw<I: Iterator<Item = (BackendCoord, i32)>>( &self, points: I, backend: &mut DB, _: (u32, u32), ) -> Result<(), DrawingErrorKind<DB::ErrorType>>71     fn draw<I: Iterator<Item = (BackendCoord, i32)>>(
72         &self,
73         points: I,
74         backend: &mut DB,
75         _: (u32, u32),
76     ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
77         let vert: Vec<_> = points.collect();
78         let mut polygon = vec![];
79         for mask in [1, 2, 4].iter().cloned() {
80             let mask_a = if mask == 4 { 1 } else { mask * 2 };
81             let mask_b = if mask == 1 { 4 } else { mask / 2 };
82             let a = 0;
83             let b = a | mask_a;
84             let c = a | mask_a | mask_b;
85             let d = a | mask_b;
86             polygon.push([vert[a], vert[b], vert[c], vert[d]]);
87             polygon.push([
88                 vert[a | mask],
89                 vert[b | mask],
90                 vert[c | mask],
91                 vert[d | mask],
92             ]);
93         }
94         polygon.sort_by_cached_key(|t| std::cmp::Reverse(t[0].1 + t[1].1 + t[2].1 + t[3].1));
95 
96         for p in polygon {
97             backend.fill_polygon(p.iter().map(|(coord, _)| *coord), &self.face_style)?;
98             backend.draw_path(
99                 p.iter()
100                     .map(|(coord, _)| *coord)
101                     .chain(std::iter::once(p[0].0)),
102                 &self.edge_style,
103             )?;
104         }
105 
106         Ok(())
107     }
108 }
109