mirror of
https://github.com/typst/typst
synced 2025-06-28 00:03:17 +08:00
Add polygon drawing primitive (#314)
This commit is contained in:
parent
628e589bcd
commit
44165d09a9
@ -83,6 +83,7 @@ fn global(math: Module, calc: Module) -> Module {
|
|||||||
global.define("square", visualize::SquareElem::func());
|
global.define("square", visualize::SquareElem::func());
|
||||||
global.define("ellipse", visualize::EllipseElem::func());
|
global.define("ellipse", visualize::EllipseElem::func());
|
||||||
global.define("circle", visualize::CircleElem::func());
|
global.define("circle", visualize::CircleElem::func());
|
||||||
|
global.define("polygon", visualize::PolygonElem::func());
|
||||||
|
|
||||||
// Meta.
|
// Meta.
|
||||||
global.define("document", meta::DocumentElem::func());
|
global.define("document", meta::DocumentElem::func());
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
mod image;
|
mod image;
|
||||||
mod line;
|
mod line;
|
||||||
mod shape;
|
mod shape;
|
||||||
|
mod polygon;
|
||||||
|
|
||||||
pub use self::image::*;
|
pub use self::image::*;
|
||||||
pub use self::line::*;
|
pub use self::line::*;
|
||||||
pub use self::shape::*;
|
pub use self::shape::*;
|
||||||
|
pub use self::polygon::*;
|
71
library/src/visualize/polygon.rs
Normal file
71
library/src/visualize/polygon.rs
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
BIN
tests/ref/visualize/polygon.png
Normal file
BIN
tests/ref/visualize/polygon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.4 KiB |
31
tests/typ/visualize/polygon.typ
Normal file
31
tests/typ/visualize/polygon.typ
Normal 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,))
|
Loading…
x
Reference in New Issue
Block a user