summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/visualize/polygon.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-11-23 16:25:49 +0100
committerLaurenz <laurmaedje@gmail.com>2023-11-24 12:30:02 +0100
commit7eebafa7837ec173a7b2064ae60fd45b5413d17c (patch)
treeb63b302b6d7747bcbb28571713745b9ca1aa83a4 /crates/typst-library/src/visualize/polygon.rs
parent76e173b78b511b506b928c27ac360f75fa455747 (diff)
Merge `typst` and `typst-library`
Diffstat (limited to 'crates/typst-library/src/visualize/polygon.rs')
-rw-r--r--crates/typst-library/src/visualize/polygon.rs164
1 files changed, 0 insertions, 164 deletions
diff --git a/crates/typst-library/src/visualize/polygon.rs b/crates/typst-library/src/visualize/polygon.rs
deleted file mode 100644
index b1ed9eaa..00000000
--- a/crates/typst-library/src/visualize/polygon.rs
+++ /dev/null
@@ -1,164 +0,0 @@
-use std::f64::consts::PI;
-
-use crate::prelude::*;
-
-/// A closed polygon.
-///
-/// The polygon is defined by its corner points and is closed automatically.
-///
-/// # Example
-/// ```example
-/// #polygon(
-/// fill: blue.lighten(80%),
-/// stroke: blue,
-/// (20%, 0pt),
-/// (60%, 0pt),
-/// (80%, 2cm),
-/// (0%, 2cm),
-/// )
-/// ```
-#[elem(scope, Layout)]
-pub struct PolygonElem {
- /// How to fill the polygon.
- ///
- /// When setting a fill, the default stroke disappears. To create a
- /// rectangle with both fill and stroke, you have to configure both.
- ///
- /// 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]($stroke) the polygon. This can be:
- ///
- /// Can be set to `{none}` to disable the stroke or to `{auto}` for a
- /// stroke of `{1pt}` black if and if only if no fill is given.
- #[resolve]
- #[fold]
- pub stroke: Smart<Option<Stroke>>,
-
- /// The vertices of the polygon. Each point is specified as an array of two
- /// [relative lengths]($relative).
- #[variadic]
- pub vertices: Vec<Axes<Rel<Length>>>,
-}
-
-#[scope]
-impl PolygonElem {
- /// A regular polygon, defined by its size and number of vertices.
- ///
- /// ```example
- /// #polygon.regular(
- /// fill: blue.lighten(80%),
- /// stroke: blue,
- /// size: 30pt,
- /// vertices: 3,
- /// )
- /// ```
- #[func(title = "Regular Polygon")]
- pub fn regular(
- /// How to fill the polygon. See the general
- /// [polygon's documentation]($polygon.fill) for more details.
- #[named]
- fill: Option<Option<Paint>>,
-
- /// How to stroke the polygon. See the general
- /// [polygon's documentation]($polygon.stroke) for more details.
- #[named]
- stroke: Option<Smart<Option<Stroke>>>,
-
- /// The diameter of the [circumcircle](https://en.wikipedia.org/wiki/Circumcircle)
- /// of the regular polygon.
- #[named]
- #[default(Em::one().into())]
- size: Length,
-
- /// The number of vertices in the polygon.
- #[named]
- #[default(3)]
- vertices: u64,
- ) -> Content {
- let radius = size / 2.0;
- let angle = |i: f64| {
- 2.0 * PI * i / (vertices as f64) + PI * (1.0 / 2.0 - 1.0 / vertices as f64)
- };
- let (horizontal_offset, vertical_offset) = (0..=vertices)
- .map(|v| {
- (
- (radius * angle(v as f64).cos()) + radius,
- (radius * angle(v as f64).sin()) + radius,
- )
- })
- .fold((radius, radius), |(min_x, min_y), (v_x, v_y)| {
- (
- if min_x < v_x { min_x } else { v_x },
- if min_y < v_y { min_y } else { v_y },
- )
- });
- let vertices = (0..=vertices)
- .map(|v| {
- let x = (radius * angle(v as f64).cos()) + radius - horizontal_offset;
- let y = (radius * angle(v as f64).sin()) + radius - vertical_offset;
- Axes::new(x, y).map(Rel::from)
- })
- .collect();
-
- let mut elem = PolygonElem::new(vertices);
- if let Some(fill) = fill {
- elem.push_fill(fill);
- }
- if let Some(stroke) = stroke {
- elem.push_stroke(stroke);
- }
- elem.pack()
- }
-}
-
-impl Layout for PolygonElem {
- #[tracing::instrument(name = "PolygonElem::layout", skip_all)]
- fn layout(
- &self,
- _: &mut Vt,
- styles: StyleChain,
- regions: Regions,
- ) -> SourceResult<Fragment> {
- let points: Vec<Point> = self
- .vertices()
- .iter()
- .map(|c| {
- c.resolve(styles).zip_map(regions.base(), Rel::relative_to).to_point()
- })
- .collect();
-
- let size = points.iter().fold(Point::zero(), |max, c| c.max(max)).to_size();
- if !size.is_finite() {
- bail!(error!(self.span(), "cannot create polygon with infinite size"));
- }
- let mut frame = Frame::hard(size);
-
- // Only create a path if there are more than zero points.
- if points.is_empty() {
- return Ok(Fragment::frame(frame));
- }
-
- // Prepare fill and stroke.
- let fill = self.fill(styles);
- let stroke = match self.stroke(styles) {
- Smart::Auto if fill.is_none() => Some(FixedStroke::default()),
- Smart::Auto => None,
- Smart::Custom(stroke) => stroke.map(Stroke::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))
- }
-}