mirror of https://codeberg.org/topola/topola.git
119 lines
3.9 KiB
Rust
119 lines
3.9 KiB
Rust
use geo::{CoordsIter, Point, Polygon};
|
|
use rstar::AABB;
|
|
use topola::{
|
|
geometry::primitive::{AccessPrimitiveShape, PrimitiveShape},
|
|
math::Circle,
|
|
};
|
|
|
|
pub struct Painter<'a> {
|
|
ui: &'a mut egui::Ui,
|
|
transform: egui::emath::TSTransform,
|
|
paint_bboxes: bool,
|
|
}
|
|
|
|
impl<'a> Painter<'a> {
|
|
pub fn new(
|
|
ui: &'a mut egui::Ui,
|
|
transform: egui::emath::TSTransform,
|
|
paint_bboxes: bool,
|
|
) -> Self {
|
|
Self {
|
|
ui,
|
|
transform,
|
|
paint_bboxes,
|
|
}
|
|
}
|
|
|
|
pub fn paint_primitive(&mut self, shape: &PrimitiveShape, color: egui::epaint::Color32) {
|
|
let epaint_shape = match shape {
|
|
PrimitiveShape::Dot(dot) => self.dot_shape(dot.circle, color),
|
|
PrimitiveShape::Seg(seg) => egui::Shape::line_segment(
|
|
[
|
|
self.transform
|
|
.mul_pos([seg.from.x() as f32, -seg.from.y() as f32].into()),
|
|
self.transform
|
|
.mul_pos([seg.to.x() as f32, -seg.to.y() as f32].into()),
|
|
],
|
|
egui::Stroke::new(seg.width as f32 * self.transform.scaling, color),
|
|
),
|
|
PrimitiveShape::Bend(bend) => {
|
|
let circle = bend.circle();
|
|
|
|
let angle_from = bend.start_angle();
|
|
let angle_step = bend.spanned_angle() / 100.0;
|
|
|
|
let mut points: Vec<egui::Pos2> = vec![];
|
|
|
|
for i in 0..=100 {
|
|
let x = circle.pos.x() + circle.r * (angle_from + i as f64 * angle_step).cos();
|
|
let y = circle.pos.y() + circle.r * (angle_from + i as f64 * angle_step).sin();
|
|
points.push(self.transform.mul_pos([x as f32, -y as f32].into()));
|
|
}
|
|
|
|
egui::Shape::line(
|
|
points,
|
|
egui::Stroke::new(bend.width as f32 * self.transform.scaling, color),
|
|
)
|
|
}
|
|
};
|
|
|
|
self.ui.painter().add(epaint_shape);
|
|
|
|
if self.paint_bboxes {
|
|
self.paint_bbox(AccessPrimitiveShape::bbox(shape, 0.0));
|
|
}
|
|
}
|
|
|
|
pub fn paint_bbox(&mut self, bbox: AABB<[f64; 2]>) {
|
|
let rect = egui::epaint::Rect {
|
|
min: [bbox.lower()[0] as f32, -bbox.upper()[1] as f32].into(),
|
|
max: [bbox.upper()[0] as f32, -bbox.lower()[1] as f32].into(),
|
|
};
|
|
self.ui.painter().add(egui::Shape::rect_stroke(
|
|
self.transform * rect,
|
|
egui::Rounding::ZERO,
|
|
egui::Stroke::new(1.0, egui::Color32::GRAY),
|
|
));
|
|
}
|
|
|
|
pub fn paint_dot(&mut self, circle: Circle, color: egui::epaint::Color32) {
|
|
let shape = self.dot_shape(circle, color);
|
|
self.ui.painter().add(shape);
|
|
}
|
|
|
|
fn dot_shape(&mut self, circle: Circle, color: egui::epaint::Color32) -> egui::Shape {
|
|
egui::Shape::circle_filled(
|
|
self.transform
|
|
.mul_pos([circle.pos.x() as f32, -circle.pos.y() as f32].into()),
|
|
circle.r as f32 * self.transform.scaling,
|
|
color,
|
|
)
|
|
}
|
|
|
|
pub fn paint_polygon(&mut self, polygon: &Polygon, color: egui::epaint::Color32) {
|
|
self.ui.painter().add(egui::Shape::convex_polygon(
|
|
polygon
|
|
.exterior_coords_iter()
|
|
.map(|coords| {
|
|
self.transform
|
|
.mul_pos([coords.x as f32, -coords.y as f32].into())
|
|
})
|
|
.collect(),
|
|
color,
|
|
egui::Stroke::default(),
|
|
));
|
|
}
|
|
|
|
pub fn paint_edge(&mut self, from: Point, to: Point, stroke: egui::Stroke) {
|
|
self.ui.painter().add(egui::Shape::line_segment(
|
|
[
|
|
self.transform
|
|
.mul_pos([from.x() as f32, -from.y() as f32].into()),
|
|
self.transform
|
|
.mul_pos([to.x() as f32, -to.y() as f32].into()),
|
|
],
|
|
stroke,
|
|
));
|
|
}
|
|
}
|