Add polygon drawing primitive (#314)

This commit is contained in:
Olle Lögdahl 2023-03-28 16:43:16 +02:00 committed by GitHub
parent 628e589bcd
commit 44165d09a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 0 deletions

View File

@ -83,6 +83,7 @@ fn global(math: Module, calc: Module) -> Module {
global.define("square", visualize::SquareElem::func());
global.define("ellipse", visualize::EllipseElem::func());
global.define("circle", visualize::CircleElem::func());
global.define("polygon", visualize::PolygonElem::func());
// Meta.
global.define("document", meta::DocumentElem::func());

View File

@ -3,7 +3,9 @@
mod image;
mod line;
mod shape;
mod polygon;
pub use self::image::*;
pub use self::line::*;
pub use self::shape::*;
pub use self::polygon::*;

View File

@ -0,0 +1,71 @@
use crate::prelude::*;
/// A closed-path polygon.
///
/// ## Example
/// ```example
/// #polygon(fill: blue, (0pt, 0pt), (10pt, 0pt), (10pt, 10pt))
/// ```
///
/// 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.
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. The polygon automatically closes itself.
#[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 is more than zero points.
if points.len() > 0 {
let stroke = self.stroke(styles).map(|e| e.unwrap_or_default());
let fill = self.fill(styles);
// 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))
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -0,0 +1,31 @@
// Test polygons.
---
#set page(height: 220pt, width: 50pt)
#box({
set polygon(stroke: 0.75pt, fill: blue)
polygon((0em, 0pt))
// this should not give an error
polygon()
polygon((0pt, 0pt), (10pt, 0pt))
polygon((5pt, 0pt), (0pt, 10pt), (10pt, 10pt))
polygon(
(0pt, 0pt), (5pt, 5pt), (10pt, 0pt),
(15pt, 5pt),
(5pt, 10pt)
)
polygon(stroke: none, (5pt, 0pt), (0pt, 10pt), (10pt, 10pt))
polygon(stroke: 3pt, fill: none, (5pt, 0pt), (0pt, 10pt), (10pt, 10pt))
// relative size
polygon((0pt, 0pt), (100%, 5pt), (50%, 10pt))
// antiparallelogram
polygon((0pt, 5pt), (5pt, 0pt), (0pt, 10pt), (5pt, 15pt))
// self-intersections
polygon((0pt, 10pt), (30pt, 20pt), (0pt, 30pt), (20pt, 0pt), (20pt, 35pt))
})
---
// Test errors.
// Error: 10-17 point array must contain exactly two entries
#polygon((50pt,))