use std::f64::consts::PI;
use typst_syntax::Span;
use crate::foundations::{Content, NativeElement, Smart, elem, func, scope};
use crate::layout::{Axes, Em, Length, Rel};
use crate::visualize::{FillRule, Paint, Stroke};
#[elem(scope)]
pub struct PolygonElem {
pub fill: Option<Paint>,
#[default]
pub fill_rule: FillRule,
#[fold]
pub stroke: Smart<Option<Stroke>>,
#[variadic]
pub vertices: Vec<Axes<Rel<Length>>>,
}
#[scope]
impl PolygonElem {
#[func(title = "Regular Polygon")]
pub fn regular(
span: Span,
#[named]
fill: Option<Option<Paint>>,
#[named]
stroke: Option<Smart<Option<Stroke>>>,
#[named]
#[default(Em::one().into())]
size: Length,
#[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.fill.set(fill);
}
if let Some(stroke) = stroke {
elem.stroke.set(stroke);
}
elem.pack().spanned(span)
}
}