summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst-library/src/visualize/polygon.rs74
-rw-r--r--tests/ref/visualize/polygon.pngbin1957 -> 3865 bytes
-rw-r--r--tests/typ/visualize/polygon.typ4
3 files changed, 78 insertions, 0 deletions
diff --git a/crates/typst-library/src/visualize/polygon.rs b/crates/typst-library/src/visualize/polygon.rs
index d2d3132a..b244b2e9 100644
--- a/crates/typst-library/src/visualize/polygon.rs
+++ b/crates/typst-library/src/visualize/polygon.rs
@@ -1,3 +1,5 @@
+use std::f64::consts::PI;
+
use crate::prelude::*;
/// A closed polygon.
@@ -19,6 +21,10 @@ use crate::prelude::*;
/// Display: Polygon
/// Category: visualize
#[element(Layout)]
+#[scope(
+ scope.define("regular", polygon_regular_func());
+ scope
+)]
pub struct PolygonElem {
/// How to fill the polygon. See the
/// [rectangle's documentation]($func/rect.fill) for more details.
@@ -91,3 +97,71 @@ impl Layout for PolygonElem {
Ok(Fragment::frame(frame))
}
}
+
+/// A regular polygon, defined by its size and number of vertices.
+///
+/// ## Example { #example }
+/// ```example
+/// #polygon.regular(
+/// fill: blue.lighten(80%),
+/// stroke: blue,
+/// size: 30pt,
+/// vertices: 3,
+/// )
+/// ```
+///
+/// Display: Regular Polygon
+/// Category: visualize
+#[func]
+pub fn polygon_regular(
+ /// How to fill the polygon. See the general
+ /// [polygon's documentation]($func/polygon.fill) for more details.
+ #[named]
+ fill: Option<Option<Paint>>,
+
+ /// How to stroke the polygon. See the general
+ /// [polygon's documentation]($func/polygon.stroke) for more details.
+ #[named]
+ stroke: Option<Smart<Option<PartialStroke>>>,
+
+ /// The diameter of the circumcircle of the regular polygon (https://en.wikipedia.org/wiki/Circumcircle).
+ #[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()
+}
diff --git a/tests/ref/visualize/polygon.png b/tests/ref/visualize/polygon.png
index 2ffd7f8a..234aeb14 100644
--- a/tests/ref/visualize/polygon.png
+++ b/tests/ref/visualize/polygon.png
Binary files differ
diff --git a/tests/typ/visualize/polygon.typ b/tests/typ/visualize/polygon.typ
index 9f40d7fd..cad62497 100644
--- a/tests/typ/visualize/polygon.typ
+++ b/tests/typ/visualize/polygon.typ
@@ -8,6 +8,7 @@
#polygon()
#polygon((0em, 0pt))
#polygon((0pt, 0pt), (10pt, 0pt))
+#polygon.regular(size: 0pt, vertices: 9)
#polygon((5pt, 0pt), (0pt, 10pt), (10pt, 10pt))
#polygon(
@@ -27,6 +28,9 @@
// Self-intersections
#polygon((0pt, 10pt), (30pt, 20pt), (0pt, 30pt), (20pt, 0pt), (20pt, 35pt))
+// Regular polygon; should have equal side lengths
+#for k in range(3, 9) {polygon.regular(size: 30pt, vertices: k,)}
+
---
// Error: 10-17 point array must contain exactly two entries
#polygon((50pt,))