gon 0.1.0

Easy polygon drawing built on top of lyon.
Documentation
use crate::{
    options::{Options, StrokeOptions},
    tess, PolyBuilder,
};
use gee::{Point, Rect};

#[derive(Clone, Debug)]
pub enum ControlPoint {
    Quadratic(Point),
    Cubic(Point, Point),
}

#[derive(Clone, Debug)]
pub struct BezierSegment {
    end: Point,
    ctrl: ControlPoint,
}

impl BezierSegment {
    pub fn new(end: Point, ctrl: ControlPoint) -> Self {
        Self { end, ctrl }
    }

    pub fn quadratic(end: Point, ctrl: Point) -> Self {
        Self::new(end, ControlPoint::Quadratic(ctrl))
    }

    pub fn cubic(end: Point, ctrl1: Point, ctrl2: Point) -> Self {
        Self::new(end, ControlPoint::Cubic(ctrl1, ctrl2))
    }
}

#[derive(Clone, Debug, Default)]
pub struct BezierBuilder {
    start: Point,
    segments: Vec<BezierSegment>,
    open: bool,
    options: Options,
}

impl BezierBuilder {
    pub fn new(start: Point) -> Self {
        Self::default().with_start(start)
    }

    pub fn from_bezier_segment(start: Point, segment: BezierSegment) -> Self {
        Self::new(start).with_bezier_segment(segment)
    }

    pub fn from_bezier_segments(
        start: Point,
        segments: impl IntoIterator<Item = BezierSegment>,
    ) -> Self {
        Self::new(start).with_bezier_segments(segments)
    }

    pub fn from_quadratic_segment(start: Point, end: Point, ctrl: Point) -> Self {
        Self::from_bezier_segment(start, BezierSegment::quadratic(end, ctrl))
    }

    pub fn from_cubic_segment(start: Point, end: Point, ctrl1: Point, ctrl2: Point) -> Self {
        Self::from_bezier_segment(start, BezierSegment::cubic(end, ctrl1, ctrl2))
    }

    pub fn with_start(mut self, start: Point) -> Self {
        self.start = start;
        self
    }

    pub fn with_bezier_segment(mut self, segment: BezierSegment) -> Self {
        self.segments.push(segment);
        self
    }

    pub fn with_bezier_segments(
        mut self,
        segments: impl IntoIterator<Item = BezierSegment>,
    ) -> Self {
        self.segments.extend(segments);
        self
    }

    pub fn with_quadratic_segment(self, end: Point, ctrl: Point) -> Self {
        self.with_bezier_segment(BezierSegment::quadratic(end, ctrl))
    }

    pub fn with_cubic_segment(self, end: Point, ctrl1: Point, ctrl2: Point) -> Self {
        self.with_bezier_segment(BezierSegment::cubic(end, ctrl1, ctrl2))
    }

    pub fn with_stroke(mut self, stroke_width: f32, open: bool) -> Self {
        self.open = open;
        self._with_stroke(stroke_width)
    }

    pub fn with_stroke_open(self, stroke_width: f32) -> Self {
        self.with_stroke(stroke_width, true)
    }

    pub fn with_stroke_closed(self, stroke_width: f32) -> Self {
        self.with_stroke(stroke_width, false)
    }

    pub fn with_stroke_opts(mut self, stroke_options: StrokeOptions, open: bool) -> Self {
        self.open = open;
        self._with_stroke_opts(stroke_options)
    }

    pub fn with_stroke_opts_open(self, stroke_options: StrokeOptions) -> Self {
        self.with_stroke_opts(stroke_options, true)
    }

    pub fn with_stroke_opts_closed(self, stroke_options: StrokeOptions) -> Self {
        self.with_stroke_opts(stroke_options, false)
    }

    stroke!(private);

    fill!();

    build!();
}

impl PolyBuilder for BezierBuilder {
    fn options(&self) -> &Options {
        &self.options
    }

    fn bounding_rect(&self) -> Rect {
        todo!("bézier curves can't be filled")
    }

    fn build<B: tess::path::traits::PathBuilder>(self, builder: &mut B) {
        builder.begin(self.start.into());
        for segment in self.segments {
            match segment.ctrl {
                ControlPoint::Quadratic(ctrl) => {
                    builder.quadratic_bezier_to(ctrl.into(), segment.end.into());
                }
                ControlPoint::Cubic(ctrl1, ctrl2) => {
                    builder.cubic_bezier_to(ctrl1.into(), ctrl2.into(), segment.end.into());
                }
            }
        }
        builder.end(!self.open);
    }
}