summaryrefslogtreecommitdiffstats
path: root/vendor/plotters/src/chart/context/cartesian3d/draw_impl.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/plotters/src/chart/context/cartesian3d/draw_impl.rs')
-rw-r--r--vendor/plotters/src/chart/context/cartesian3d/draw_impl.rs309
1 files changed, 309 insertions, 0 deletions
diff --git a/vendor/plotters/src/chart/context/cartesian3d/draw_impl.rs b/vendor/plotters/src/chart/context/cartesian3d/draw_impl.rs
new file mode 100644
index 000000000..fcc4c4f7b
--- /dev/null
+++ b/vendor/plotters/src/chart/context/cartesian3d/draw_impl.rs
@@ -0,0 +1,309 @@
+use std::cmp::Ordering;
+
+use plotters_backend::DrawingBackend;
+
+use crate::chart::ChartContext;
+use crate::coord::{
+ cartesian::Cartesian3d,
+ ranged1d::{KeyPointHint, Ranged},
+ CoordTranslate,
+};
+use crate::drawing::DrawingAreaErrorKind;
+use crate::element::{EmptyElement, PathElement, Polygon, Text};
+use crate::style::{
+ text_anchor::{HPos, Pos, VPos},
+ ShapeStyle, TextStyle,
+};
+
+use super::Coord3D;
+
+pub(crate) struct KeyPoints3d<X: Ranged, Y: Ranged, Z: Ranged> {
+ pub(crate) x_points: Vec<X::ValueType>,
+ pub(crate) y_points: Vec<Y::ValueType>,
+ pub(crate) z_points: Vec<Z::ValueType>,
+}
+
+impl<'a, DB, X: Ranged, Y: Ranged, Z: Ranged> ChartContext<'a, DB, Cartesian3d<X, Y, Z>>
+where
+ DB: DrawingBackend,
+ X::ValueType: Clone,
+ Y::ValueType: Clone,
+ Z::ValueType: Clone,
+{
+ pub(crate) fn get_key_points<XH: KeyPointHint, YH: KeyPointHint, ZH: KeyPointHint>(
+ &self,
+ x_hint: XH,
+ y_hint: YH,
+ z_hint: ZH,
+ ) -> KeyPoints3d<X, Y, Z> {
+ let coord = self.plotting_area().as_coord_spec();
+ let x_points = coord.logic_x.key_points(x_hint);
+ let y_points = coord.logic_y.key_points(y_hint);
+ let z_points = coord.logic_z.key_points(z_hint);
+ KeyPoints3d {
+ x_points,
+ y_points,
+ z_points,
+ }
+ }
+ #[allow(clippy::type_complexity)]
+ pub(crate) fn draw_axis_ticks(
+ &mut self,
+ axis: [[Coord3D<X::ValueType, Y::ValueType, Z::ValueType>; 3]; 2],
+ labels: &[(
+ [Coord3D<X::ValueType, Y::ValueType, Z::ValueType>; 3],
+ String,
+ )],
+ tick_size: i32,
+ style: ShapeStyle,
+ font: TextStyle,
+ ) -> Result<(), DrawingAreaErrorKind<DB::ErrorType>> {
+ let coord = self.plotting_area().as_coord_spec();
+ let begin = coord.translate(&Coord3D::build_coord([
+ &axis[0][0],
+ &axis[0][1],
+ &axis[0][2],
+ ]));
+ let end = coord.translate(&Coord3D::build_coord([
+ &axis[1][0],
+ &axis[1][1],
+ &axis[1][2],
+ ]));
+ let axis_dir = (end.0 - begin.0, end.1 - begin.1);
+ let (x_range, y_range) = self.plotting_area().get_pixel_range();
+ let x_mid = (x_range.start + x_range.end) / 2;
+ let y_mid = (y_range.start + y_range.end) / 2;
+
+ let x_dir = if begin.0 < x_mid {
+ (-tick_size, 0)
+ } else {
+ (tick_size, 0)
+ };
+
+ let y_dir = if begin.1 < y_mid {
+ (0, -tick_size)
+ } else {
+ (0, tick_size)
+ };
+
+ let x_score = (x_dir.0 * axis_dir.0 + x_dir.1 * axis_dir.1).abs();
+ let y_score = (y_dir.0 * axis_dir.0 + y_dir.1 * axis_dir.1).abs();
+
+ let dir = if x_score < y_score { x_dir } else { y_dir };
+
+ for (pos, text) in labels {
+ let logic_pos = Coord3D::build_coord([&pos[0], &pos[1], &pos[2]]);
+ let mut font = font.clone();
+
+ match dir.0.cmp(&0) {
+ Ordering::Less => font.pos = Pos::new(HPos::Right, VPos::Center),
+ Ordering::Greater => font.pos = Pos::new(HPos::Left, VPos::Center),
+ _ => (),
+ }
+
+ match dir.1.cmp(&0) {
+ Ordering::Less => font.pos = Pos::new(HPos::Center, VPos::Bottom),
+ Ordering::Greater => font.pos = Pos::new(HPos::Center, VPos::Top),
+ _ => (),
+ }
+
+ let element = EmptyElement::at(logic_pos)
+ + PathElement::new(vec![(0, 0), dir], style)
+ + Text::new(text.to_string(), (dir.0 * 2, dir.1 * 2), font);
+ self.plotting_area().draw(&element)?;
+ }
+ Ok(())
+ }
+ #[allow(clippy::type_complexity)]
+ pub(crate) fn draw_axis(
+ &mut self,
+ idx: usize,
+ panels: &[[[Coord3D<X::ValueType, Y::ValueType, Z::ValueType>; 3]; 2]; 3],
+ style: ShapeStyle,
+ ) -> Result<
+ [[Coord3D<X::ValueType, Y::ValueType, Z::ValueType>; 3]; 2],
+ DrawingAreaErrorKind<DB::ErrorType>,
+ > {
+ let coord = self.plotting_area().as_coord_spec();
+ let x_range = coord.logic_x.range();
+ let y_range = coord.logic_y.range();
+ let z_range = coord.logic_z.range();
+
+ let ranges: [[Coord3D<X::ValueType, Y::ValueType, Z::ValueType>; 2]; 3] = [
+ [Coord3D::X(x_range.start), Coord3D::X(x_range.end)],
+ [Coord3D::Y(y_range.start), Coord3D::Y(y_range.end)],
+ [Coord3D::Z(z_range.start), Coord3D::Z(z_range.end)],
+ ];
+
+ let (start, end) = {
+ let mut start = [&ranges[0][0], &ranges[1][0], &ranges[2][0]];
+ let mut end = [&ranges[0][1], &ranges[1][1], &ranges[2][1]];
+
+ let mut plan = vec![];
+
+ for i in 0..3 {
+ if i == idx {
+ continue;
+ }
+ start[i] = &panels[i][0][i];
+ end[i] = &panels[i][0][i];
+ for j in 0..3 {
+ if i != idx && i != j && j != idx {
+ for k in 0..2 {
+ start[j] = &panels[i][k][j];
+ end[j] = &panels[i][k][j];
+ plan.push((start, end));
+ }
+ }
+ }
+ }
+ plan.into_iter()
+ .min_by_key(|&(s, e)| {
+ let d = coord.projected_depth(s[0].get_x(), s[1].get_y(), s[2].get_z());
+ let d = d + coord.projected_depth(e[0].get_x(), e[1].get_y(), e[2].get_z());
+ let (_, y1) = coord.translate(&Coord3D::build_coord(s));
+ let (_, y2) = coord.translate(&Coord3D::build_coord(e));
+ let y = y1 + y2;
+ (d, y)
+ })
+ .unwrap()
+ };
+
+ self.plotting_area().draw(&PathElement::new(
+ vec![Coord3D::build_coord(start), Coord3D::build_coord(end)],
+ style,
+ ))?;
+
+ Ok([
+ [start[0].clone(), start[1].clone(), start[2].clone()],
+ [end[0].clone(), end[1].clone(), end[2].clone()],
+ ])
+ }
+
+ #[allow(clippy::type_complexity)]
+ pub(crate) fn draw_axis_panels(
+ &mut self,
+ bold_points: &KeyPoints3d<X, Y, Z>,
+ light_points: &KeyPoints3d<X, Y, Z>,
+ panel_style: ShapeStyle,
+ bold_grid_style: ShapeStyle,
+ light_grid_style: ShapeStyle,
+ ) -> Result<
+ [[[Coord3D<X::ValueType, Y::ValueType, Z::ValueType>; 3]; 2]; 3],
+ DrawingAreaErrorKind<DB::ErrorType>,
+ > {
+ let mut r_iter = (0..3).map(|idx| {
+ self.draw_axis_panel(
+ idx,
+ bold_points,
+ light_points,
+ panel_style,
+ bold_grid_style,
+ light_grid_style,
+ )
+ });
+ Ok([
+ r_iter.next().unwrap()?,
+ r_iter.next().unwrap()?,
+ r_iter.next().unwrap()?,
+ ])
+ }
+ #[allow(clippy::type_complexity)]
+ fn draw_axis_panel(
+ &mut self,
+ idx: usize,
+ bold_points: &KeyPoints3d<X, Y, Z>,
+ light_points: &KeyPoints3d<X, Y, Z>,
+ panel_style: ShapeStyle,
+ bold_grid_style: ShapeStyle,
+ light_grid_style: ShapeStyle,
+ ) -> Result<
+ [[Coord3D<X::ValueType, Y::ValueType, Z::ValueType>; 3]; 2],
+ DrawingAreaErrorKind<DB::ErrorType>,
+ > {
+ let coord = self.plotting_area().as_coord_spec();
+ let x_range = coord.logic_x.range();
+ let y_range = coord.logic_y.range();
+ let z_range = coord.logic_z.range();
+
+ let ranges: [[Coord3D<X::ValueType, Y::ValueType, Z::ValueType>; 2]; 3] = [
+ [Coord3D::X(x_range.start), Coord3D::X(x_range.end)],
+ [Coord3D::Y(y_range.start), Coord3D::Y(y_range.end)],
+ [Coord3D::Z(z_range.start), Coord3D::Z(z_range.end)],
+ ];
+
+ let (mut panel, start, end) = {
+ let vert_a = [&ranges[0][0], &ranges[1][0], &ranges[2][0]];
+ let mut vert_b = [&ranges[0][1], &ranges[1][1], &ranges[2][1]];
+ let mut vert_c = vert_a;
+ let vert_d = vert_b;
+
+ vert_b[idx] = &ranges[idx][0];
+ vert_c[idx] = &ranges[idx][1];
+
+ let (vert_a, vert_b) =
+ if coord.projected_depth(vert_a[0].get_x(), vert_a[1].get_y(), vert_a[2].get_z())
+ >= coord.projected_depth(
+ vert_c[0].get_x(),
+ vert_c[1].get_y(),
+ vert_c[2].get_z(),
+ )
+ {
+ (vert_a, vert_b)
+ } else {
+ (vert_c, vert_d)
+ };
+
+ let mut m = vert_a;
+ m[(idx + 1) % 3] = vert_b[(idx + 1) % 3];
+ let mut n = vert_a;
+ n[(idx + 2) % 3] = vert_b[(idx + 2) % 3];
+
+ (
+ vec![
+ Coord3D::build_coord(vert_a),
+ Coord3D::build_coord(m),
+ Coord3D::build_coord(vert_b),
+ Coord3D::build_coord(n),
+ ],
+ vert_a,
+ vert_b,
+ )
+ };
+ self.plotting_area()
+ .draw(&Polygon::new(panel.clone(), panel_style))?;
+ panel.push(panel[0].clone());
+ self.plotting_area()
+ .draw(&PathElement::new(panel, bold_grid_style))?;
+
+ for (kps, style) in vec![
+ (light_points, light_grid_style),
+ (bold_points, bold_grid_style),
+ ]
+ .into_iter()
+ {
+ for idx in (0..3).filter(|&i| i != idx) {
+ let kps: Vec<_> = match idx {
+ 0 => kps.x_points.iter().map(|x| Coord3D::X(x.clone())).collect(),
+ 1 => kps.y_points.iter().map(|y| Coord3D::Y(y.clone())).collect(),
+ _ => kps.z_points.iter().map(|z| Coord3D::Z(z.clone())).collect(),
+ };
+ for kp in kps.iter() {
+ let mut kp_start = start;
+ let mut kp_end = end;
+ kp_start[idx] = kp;
+ kp_end[idx] = kp;
+ self.plotting_area().draw(&PathElement::new(
+ vec![Coord3D::build_coord(kp_start), Coord3D::build_coord(kp_end)],
+ style,
+ ))?;
+ }
+ }
+ }
+
+ Ok([
+ [start[0].clone(), start[1].clone(), start[2].clone()],
+ [end[0].clone(), end[1].clone(), end[2].clone()],
+ ])
+ }
+}