outlinify/src/geometry/elements/circle.rs
2024-08-15 18:34:13 +02:00

140 lines
4.1 KiB
Rust

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<f64>,
pub outline: ClipperPath,
}
impl Circle {
pub fn new(position: impl Into<Point>, diameter: f64, hole_diameter: Option<f64>) -> 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()
}
}