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  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