140 lines
4.1 KiB
Rust
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()
|
|
}
|
|
}
|