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
83
|
use crate::prelude::*;
/// A closed polygon.
///
/// The polygon is defined by its corner points and is closed automatically.
///
/// ## Example
/// ```example
/// #polygon(
/// fill: red,
/// stroke: 2pt + black,
/// (0pt, 0pt),
/// (50%, 0pt),
/// (50%, 4cm),
/// (20%, 4cm),
/// )
/// ```
///
/// Display: Polygon
/// Category: visualize
#[element(Layout)]
pub struct PolygonElem {
/// How to fill the polygon. See the
/// [rectangle's documentation]($func/rect.fill) for more details.
///
/// Currently all polygons are filled according to the
/// [non-zero winding rule](https://en.wikipedia.org/wiki/Nonzero-rule).
pub fill: Option<Paint>,
/// How to stroke the polygon. See the [lines's
/// documentation]($func/line.stroke) for more details.
#[resolve]
#[fold]
pub stroke: Option<PartialStroke>,
/// The vertices of the polygon. Each point is specified as an array of two
/// [relative lengths]($type/relative-length).
#[variadic]
pub vertices: Vec<Axes<Rel<Length>>>,
}
impl Layout for PolygonElem {
fn layout(
&self,
_: &mut Vt,
styles: StyleChain,
regions: Regions,
) -> SourceResult<Fragment> {
let points: Vec<Point> = self
.vertices()
.iter()
.map(|c| {
c.resolve(styles)
.zip(regions.base())
.map(|(l, b)| l.relative_to(b))
.to_point()
})
.collect();
let size = points.iter().fold(Point::zero(), |max, c| c.max(max)).to_size();
let target = regions.expand.select(regions.size, size);
let mut frame = Frame::new(target);
// Only create a path if there are more than zero points.
if !points.is_empty() {
let fill = self.fill(styles);
let stroke = self.stroke(styles).map(PartialStroke::unwrap_or_default);
// Construct a closed path given all points.
let mut path = Path::new();
path.move_to(points[0]);
for &point in &points[1..] {
path.line_to(point);
}
path.close_path();
let shape = Shape { geometry: Geometry::Path(path), stroke, fill };
frame.push(Point::zero(), FrameItem::Shape(shape, self.span()));
}
Ok(Fragment::frame(frame))
}
}
|