use std::f64::consts::{PI, TAU}; use eframe::{ egui::{remap, Stroke, Ui}, epaint::CircleShape, }; use egui_plot::{PlotPoints, PlotUi, Polygon}; use crate::{ application::CanvasColour, geometry::{ClipperPath, ClipperPaths}, }; use super::super::{ helpers::{create_circular_path, CircleSegment}, point::{convert_to_unit, Point}, DrawableRaw, Unit, }; #[derive(Debug, Clone)] pub struct Circle { pub position: Point, pub diameter: f64, pub hole_diameter: Option, pub outline: ClipperPath, } impl Circle { pub fn new(position: impl Into, diameter: f64, hole_diameter: Option) -> Self { let position = position.into(); Self { position: position, diameter, hole_diameter, outline: create_circular_path(&position, diameter, CircleSegment::Full).into(), } } pub fn from_aperture_circle(aperture: &gerber_types::Circle, position: Point) -> Self { Self::new(position, aperture.diameter, aperture.hole_diameter) } pub fn to_unit(&self, origin: Unit, to: Unit) -> Self { let position = self.position.to_unit(origin, to); let diameter = convert_to_unit(self.diameter, origin, to); Self { position, diameter, outline: create_circular_path(&position, diameter, CircleSegment::Full).into(), hole_diameter: self.hole_diameter.map(|hd| convert_to_unit(hd, origin, to)), } } fn draw_circle(&self, ui: &mut PlotUi, colour: CanvasColour, selected: bool) { // let n = 512; // let circle_points: PlotPoints = (0..=n) // .map(|i| { // let t = remap(i as f64, 0.0..=(n as f64), 0.0..=TAU); // let r = self.diameter / 2.; // [ // r * t.cos() + self.position.x as f64, // r * t.sin() + self.position.y as f64, // ] // }) // .collect(); let circle_points = PlotPoints::from(Self::circle_segment_points( self.position, self.diameter, 1.0, 0.0, )); ui.polygon( Polygon::new(circle_points) .fill_color(colour.to_colour32(selected)) .stroke(Stroke::NONE), ); } pub fn circle_segment_points( position: Point, diameter: f64, segment_width: f64, rotation: f64, ) -> Vec<[f64; 2]> { let segment_width = segment_width.clamp(0.0, 1.0); let n = (512. * segment_width) as i32; let circle_points = (0..=n) .map(|i| { let t = remap(i as f64, 0.0..=(n as f64), 0.0..=TAU * segment_width) + rotation * (PI / 180.); let r = diameter / 2.; [r * t.cos() + position.x, r * t.sin() + position.y] }) .collect(); circle_points } } impl DrawableRaw for Circle { fn canvas_pos(&self) -> Point { self.position } fn draw_egui(&self, ui: &mut Ui, selected: bool) { ui.painter().add(CircleShape::filled( self.position.invert_y().into(), self.diameter as f32 / 2., CanvasColour::Copper.to_colour32(selected), )); } fn draw_egui_plot(&self, ui: &mut egui_plot::PlotUi, colour: CanvasColour, selected: bool) { // let circle_points: Vec<[f64; 2]> = // create_circular_path(&self.position, self.diameter, CircleSegment::Full) // .iter() // .map(|(x, y)| [*x, *y]) // .collect(); // let polygon = Polygon::new(PlotPoints::from(circle_points)) // .fill_color(if selected { // COPPER_COLOR_SELECTED // } else { // COPPER_COLOR // }) // .stroke(Stroke::new(0., Color32::TRANSPARENT)); // ui.polygon(polygon); self.draw_circle(ui, colour, selected); } fn to_paths(&self) -> ClipperPaths { ClipperPaths::new(vec![self.outline.clone()]) } fn outline(&self) -> ClipperPath { self.outline.clone() } }