Skip to content

Commit f09ee08

Browse files
committed
Add support for Z order
1 parent 49a9f08 commit f09ee08

File tree

6 files changed

+138
-11
lines changed

6 files changed

+138
-11
lines changed

src/coord/ranged3d/cartesian3d.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,8 @@ impl<X: Ranged, Y: Ranged, Z: Ranged> CoordTranslate for Cartesian3d<X, Y, Z> {
102102
let pixel_coord_3d = self.map_3d(&coord.0, &coord.1, &coord.2);
103103
self.projection * pixel_coord_3d
104104
}
105+
106+
fn depth(&self, coord: &Self::From) -> i32 {
107+
self.projected_depth(&coord.0, &coord.1, &coord.2)
108+
}
105109
}

src/coord/translate.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ pub trait CoordTranslate {
77

88
/// Translate the guest coordinate to the guest coordinate
99
fn translate(&self, from: &Self::From) -> BackendCoord;
10+
11+
/// Get the Z-value of current coordinate
12+
fn depth(&self, _from: &Self::From) -> i32 {
13+
0
14+
}
1015
}
1116

1217
impl<C, T> CoordTranslate for T

src/drawing/area.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::coord::cartesian::{Cartesian2d, MeshLine};
22
use crate::coord::ranged1d::{KeyPointHint, Ranged};
33
use crate::coord::{CoordTranslate, Shift};
4-
use crate::element::{Drawable, PointCollection};
4+
use crate::element::{CoordMapper, Drawable, PointCollection};
55
use crate::style::text_anchor::{HPos, Pos, VPos};
66
use crate::style::{Color, SizeDesc, TextStyle};
77

@@ -17,7 +17,7 @@ use std::rc::Rc;
1717

1818
/// The representation of the rectangle in backend canvas
1919
#[derive(Clone, Debug)]
20-
struct Rect {
20+
pub struct Rect {
2121
x0: i32,
2222
y0: i32,
2323
x1: i32,
@@ -104,7 +104,7 @@ impl Rect {
104104
}
105105

106106
/// Make the coordinate in the range of the rectangle
107-
fn truncate(&self, p: (i32, i32)) -> (i32, i32) {
107+
pub fn truncate(&self, p: (i32, i32)) -> (i32, i32) {
108108
(p.0.min(self.x1).max(self.x0), p.1.min(self.y1).max(self.y0))
109109
}
110110
}
@@ -308,14 +308,15 @@ impl<DB: DrawingBackend, CT: CoordTranslate> DrawingArea<DB, CT> {
308308
}
309309

310310
/// Draw an high-level element
311-
pub fn draw<'a, E>(&self, element: &'a E) -> Result<(), DrawingAreaError<DB>>
311+
pub fn draw<'a, E, B>(&self, element: &'a E) -> Result<(), DrawingAreaError<DB>>
312312
where
313-
&'a E: PointCollection<'a, CT::From>,
314-
E: Drawable<DB>,
313+
B: CoordMapper,
314+
&'a E: PointCollection<'a, CT::From, B>,
315+
E: Drawable<DB, B>,
315316
{
316317
let backend_coords = element.point_iter().into_iter().map(|p| {
317318
let b = p.borrow();
318-
self.rect.truncate(self.coord.translate(b))
319+
B::map(&self.coord, b, &self.rect)
319320
});
320321
self.backend_ops(move |b| element.draw(backend_coords, b, self.dim_in_pixel()))
321322
}

src/drawing/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ about the [coordinate abstraction](../coord/index.html) and [element system](../
1313
mod area;
1414
mod backend_impl;
1515

16-
pub use area::{DrawingArea, DrawingAreaErrorKind, IntoDrawingArea};
16+
pub use area::{DrawingArea, DrawingAreaErrorKind, IntoDrawingArea, Rect};
1717

1818
pub use backend_impl::*;

src/element/basic_shapes_3d.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use super::{BackendCoordAndZ, Drawable, PointCollection};
2+
use crate::style::ShapeStyle;
3+
use plotters_backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
4+
5+
pub struct Cubiod<X, Y, Z> {
6+
face_style: ShapeStyle,
7+
edge_style: ShapeStyle,
8+
vert: [(X, Y, Z); 8],
9+
}
10+
11+
impl<X: Clone, Y: Clone, Z: Clone> Cubiod<X, Y, Z> {
12+
pub fn new<FS: Into<ShapeStyle>, ES: Into<ShapeStyle>>(
13+
[(x0, y0, z0), (x1, y1, z1)]: [(X, Y, Z); 2],
14+
face_style: FS,
15+
edge_style: ES,
16+
) -> Self {
17+
Self {
18+
face_style: face_style.into(),
19+
edge_style: edge_style.into(),
20+
vert: [
21+
(x0.clone(), y0.clone(), z0.clone()),
22+
(x0.clone(), y0.clone(), z1.clone()),
23+
(x0.clone(), y1.clone(), z0.clone()),
24+
(x0.clone(), y1.clone(), z1.clone()),
25+
(x1.clone(), y0.clone(), z0.clone()),
26+
(x1.clone(), y0.clone(), z1.clone()),
27+
(x1.clone(), y1.clone(), z0.clone()),
28+
(x1.clone(), y1.clone(), z1.clone()),
29+
],
30+
}
31+
}
32+
}
33+
34+
impl<'a, X: 'a, Y: 'a, Z: 'a> PointCollection<'a, (X, Y, Z), BackendCoordAndZ>
35+
for &'a Cubiod<X, Y, Z>
36+
{
37+
type Point = &'a (X, Y, Z);
38+
type IntoIter = &'a [(X, Y, Z)];
39+
fn point_iter(self) -> Self::IntoIter {
40+
&self.vert
41+
}
42+
}
43+
44+
impl<X, Y, Z, DB: DrawingBackend> Drawable<DB, BackendCoordAndZ> for Cubiod<X, Y, Z> {
45+
fn draw<I: Iterator<Item = (BackendCoord, i32)>>(
46+
&self,
47+
points: I,
48+
backend: &mut DB,
49+
_: (u32, u32),
50+
) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
51+
let vert: Vec<_> = points.collect();
52+
let mut polygon = vec![];
53+
for mask in vec![1, 2, 4] {
54+
let mask_a = if mask == 4 { 1 } else { mask * 2 };
55+
let mask_b = if mask == 1 { 4 } else { mask / 2 };
56+
let a = 0;
57+
let b = a | mask_a;
58+
let c = a | mask_a | mask_b;
59+
let d = a | mask_b;
60+
polygon.push([vert[a], vert[b], vert[c], vert[d]]);
61+
polygon.push([
62+
vert[a | mask],
63+
vert[b | mask],
64+
vert[c | mask],
65+
vert[d | mask],
66+
]);
67+
}
68+
polygon.sort_by_cached_key(|t| std::cmp::Reverse(t[0].1 + t[1].1 + t[2].1 + t[3].1));
69+
70+
for p in polygon {
71+
backend.fill_polygon(p.iter().map(|(coord, _)| *coord), &self.face_style)?;
72+
backend.draw_path(
73+
p.iter()
74+
.map(|(coord, _)| *coord)
75+
.chain(std::iter::once(p[0].0)),
76+
&self.edge_style,
77+
)?;
78+
}
79+
80+
Ok(())
81+
}
82+
}

src/element/mod.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ use std::borrow::Borrow;
160160
mod basic_shapes;
161161
pub use basic_shapes::*;
162162

163+
mod basic_shapes_3d;
164+
pub use basic_shapes_3d::*;
165+
163166
mod text;
164167
pub use text::*;
165168

@@ -192,6 +195,9 @@ pub use self::image::BitMapElement;
192195
mod dynelem;
193196
pub use dynelem::{DynElement, IntoDynElement};
194197

198+
use crate::coord::CoordTranslate;
199+
use crate::drawing::Rect;
200+
195201
/// A type which is logically a collection of points, under any given coordinate system.
196202
/// Note: Ideally, a point collection trait should be any type of which coordinate elements can be
197203
/// iterated. This is similar to `iter` method of many collection types in std.
@@ -220,7 +226,7 @@ pub use dynelem::{DynElement, IntoDynElement};
220226
///
221227
/// TODO: Once GAT is ready on stable Rust, we should simplify the design.
222228
///
223-
pub trait PointCollection<'a, Coord> {
229+
pub trait PointCollection<'a, Coord, CM = BackendCoordOnly> {
224230
/// The item in point iterator
225231
type Point: Borrow<Coord> + 'a;
226232

@@ -231,13 +237,42 @@ pub trait PointCollection<'a, Coord> {
231237
fn point_iter(self) -> Self::IntoIter;
232238
}
233239
/// The trait indicates we are able to draw it on a drawing area
234-
pub trait Drawable<DB: DrawingBackend> {
240+
pub trait Drawable<DB: DrawingBackend, CM: CoordMapper = BackendCoordOnly> {
235241
/// Actually draws the element. The key points is already translated into the
236242
/// image coordinate and can be used by DC directly
237-
fn draw<I: Iterator<Item = BackendCoord>>(
243+
fn draw<I: Iterator<Item = CM::Output>>(
238244
&self,
239245
pos: I,
240246
backend: &mut DB,
241247
parent_dim: (u32, u32),
242248
) -> Result<(), DrawingErrorKind<DB::ErrorType>>;
243249
}
250+
251+
pub trait CoordMapper {
252+
type Output;
253+
fn map<CT: CoordTranslate>(coord_trans: &CT, from: &CT::From, rect: &Rect) -> Self::Output;
254+
}
255+
256+
pub struct BackendCoordOnly;
257+
258+
impl CoordMapper for BackendCoordOnly {
259+
type Output = BackendCoord;
260+
fn map<CT: CoordTranslate>(coord_trans: &CT, from: &CT::From, rect: &Rect) -> BackendCoord {
261+
rect.truncate(coord_trans.translate(from))
262+
}
263+
}
264+
265+
pub struct BackendCoordAndZ;
266+
267+
impl CoordMapper for BackendCoordAndZ {
268+
type Output = (BackendCoord, i32);
269+
fn map<CT: CoordTranslate>(
270+
coord_trans: &CT,
271+
from: &CT::From,
272+
rect: &Rect,
273+
) -> (BackendCoord, i32) {
274+
let coord = rect.truncate(coord_trans.translate(from));
275+
let z = coord_trans.depth(from);
276+
(coord, z)
277+
}
278+
}

0 commit comments

Comments
 (0)