pizarra 2.0.0

The backend for a simple vector hand-drawing application
Documentation
use crate::point::{Vec2D, WorldUnit, ScreenUnit};
use crate::shape::{ShapeBuilder, ShapeFinished};
use crate::shape::stored::ellipse::Ellipse;
use crate::draw_commands::{DrawCommand, circle_helper, cancel_helper};
use crate::transform::Transform;
use crate::geom::{self, Angle, circle_through_three_points};
use crate::style::Style;

#[derive(Debug, Copy, Clone)]
enum State {
    One(Vec2D<WorldUnit>),
    Two(Vec2D<WorldUnit>, Vec2D<WorldUnit>),
    Three(Vec2D<WorldUnit>, Vec2D<WorldUnit>, Vec2D<WorldUnit>),
}

#[derive(Debug)]
pub struct CircleThroughThreePointsBuilder {
    state: State,
    style: Style<WorldUnit>,
}

impl CircleThroughThreePointsBuilder {
    pub fn start(initial: Vec2D<WorldUnit>, style: Style<WorldUnit>) -> CircleThroughThreePointsBuilder {
        CircleThroughThreePointsBuilder {
            state: State::One(initial),
            style,
        }
    }
}

impl ShapeBuilder for CircleThroughThreePointsBuilder {
    fn handle_mouse_moved(&mut self, pos: Vec2D<ScreenUnit>, t: Transform, _snap: ScreenUnit) {
        match self.state {
            State::One(_) => {
                self.state = State::One(t.to_world_coordinates(pos));
            }
            State::Two(p1, _) => {
                self.state = State::Two(p1, t.to_world_coordinates(pos));
            }
            State::Three(p1, p2, _) => {
                self.state = State::Three(p1, p2, t.to_world_coordinates(pos));
            }
        }
    }

    fn handle_button_pressed(&mut self, _pos: Vec2D<ScreenUnit>, _t: Transform, _snap: ScreenUnit) {}

    fn handle_button_released(&mut self, pos: Vec2D<ScreenUnit>, t: Transform, snap: ScreenUnit) -> ShapeFinished {
        self.handle_mouse_moved(pos, t, snap);

        match self.state {
            State::One(p1) => {
                self.state = State::Two(p1, t.to_world_coordinates(pos));

                ShapeFinished::No
            }
            State::Two(p1, p2) => {
                if t.to_screen_coordinates(p1).distance(pos) < snap {
                    return ShapeFinished::Cancelled;
                }
                self.state = State::Three(p1, p2, t.to_world_coordinates(pos));

                ShapeFinished::No
            }
            State::Three(p1, p2, p3) => {
                let (center, radius) = circle_through_three_points(p1, p2, p3);

                ShapeFinished::Yes(vec![Box::new(
                    Ellipse::from_parts(
                        center,
                        radius,
                        radius,
                        Angle::from_radians(0.0),
                        self.style,
                    )
                )])
            }
        }
    }

    fn draw_commands(&self, t: Transform, snap: ScreenUnit) -> Vec<DrawCommand> {
        match self.state {
            State::One(p1) => vec![
                circle_helper(t.to_screen_coordinates(p1), snap),
            ],
            State::Two(p1, p2) => vec![
                cancel_helper(p1, p2, t, snap),
            ],
            State::Three(p1, p2, p3) => {
                let (center, radius) = circle_through_three_points(p1, p2, p3);

                vec![
                    DrawCommand::Ellipse {
                        ellipse: geom::Ellipse {
                            center,
                            semimajor: radius,
                            semiminor: radius,
                            angle: Angle::from_radians(0.0),
                        },
                        style: self.style,
                    },

                    circle_helper(t.to_screen_coordinates(p1), snap),
                    circle_helper(t.to_screen_coordinates(p2), snap),
                    circle_helper(t.to_screen_coordinates(p3), snap),
                ]
            }
        }
    }
}