diff --git a/crates/topola-egui/src/actions.rs b/crates/topola-egui/src/actions.rs index ffd1378..7eb394d 100644 --- a/crates/topola-egui/src/actions.rs +++ b/crates/topola-egui/src/actions.rs @@ -407,6 +407,7 @@ pub struct DebugActions { pub show_topo_navmesh: Switch, pub show_bboxes: Switch, pub show_primitive_indices: Switch, + pub show_endpoint_tangents: Switch, pub fix_update_timestep: Switch, } @@ -440,6 +441,10 @@ impl DebugActions { tr.text("tr-menu-debug-show-primitive-indices"), ) .into_switch(), + show_endpoint_tangents: Action::new_keyless( + tr.text("tr-menu-debug-show-bend-endpoint-tangents"), + ) + .into_switch(), fix_update_timestep: Action::new_keyless(tr.text("tr-menu-debug-fix-step-rate")) .into_switch(), } @@ -465,6 +470,8 @@ impl DebugActions { self.show_bboxes.checkbox(ui, &mut menu_bar.show_bboxes); self.show_primitive_indices .checkbox(ui, &mut menu_bar.show_primitive_indices); + self.show_endpoint_tangents + .checkbox(ui, &mut menu_bar.show_bend_endpoint_tangents); ui.separator(); diff --git a/crates/topola-egui/src/displayer.rs b/crates/topola-egui/src/displayer.rs index ba5c436..09f902f 100644 --- a/crates/topola-egui/src/displayer.rs +++ b/crates/topola-egui/src/displayer.rs @@ -18,7 +18,7 @@ use topola::{ head::GetFace, primitive::MakePrimitiveShape, }, - geometry::{shape::AccessShape, GenericNode}, + geometry::{primitive::PrimitiveShape, shape::AccessShape, GenericNode}, graph::{GetIndex, MakeRef}, interactor::{activity::ActivityStepper, interaction::InteractionStepper}, layout::poly::MakePolygon, @@ -78,6 +78,10 @@ impl<'a> Displayer<'a> { self.display_activity(menu_bar); + if menu_bar.show_bend_endpoint_tangents { + self.display_bend_endpoint_tangents(menu_bar); + } + if menu_bar.show_primitive_indices { self.display_primitive_indices(menu_bar); } @@ -606,6 +610,50 @@ impl<'a> Displayer<'a> { } } + fn display_bend_endpoint_tangents(&mut self, menu_bar: &MenuBar) { + let board = self.workspace.interactor.invoker().autorouter().board(); + + for primitive in board + .layout() + .drawing() + .layer_primitive_nodes(menu_bar.multilayer_autoroute_options.planar.principal_layer) + { + let PrimitiveShape::Bend(bend_shape) = + primitive.primitive_ref(board.layout().drawing()).shape() + else { + continue; + }; + + self.painter.paint_solid_circle( + Circle { + pos: bend_shape.from, + r: 50.0, + }, + egui::Color32::from_rgb(0, 0, 255), + ); + + self.painter.paint_line_segment( + bend_shape.from, + bend_shape.from + bend_shape.from_tangent_ray(), + egui::Stroke::new(3.0, egui::Color32::from_rgb(0, 0, 255)), + ); + + self.painter.paint_solid_circle( + Circle { + pos: bend_shape.to, + r: 50.0, + }, + egui::Color32::from_rgb(0, 0, 255), + ); + + self.painter.paint_line_segment( + bend_shape.to, + bend_shape.to + bend_shape.to_tangent_ray(), + egui::Stroke::new(3.0, egui::Color32::from_rgb(0, 0, 255)), + ); + } + } + fn display_primitive_indices(&mut self, menu_bar: &MenuBar) { let board = self.workspace.interactor.invoker().autorouter().board(); diff --git a/crates/topola-egui/src/menu_bar.rs b/crates/topola-egui/src/menu_bar.rs index 2751acd..b077282 100644 --- a/crates/topola-egui/src/menu_bar.rs +++ b/crates/topola-egui/src/menu_bar.rs @@ -42,6 +42,7 @@ pub struct MenuBar { pub show_bboxes: bool, pub show_origin_destination: bool, pub show_primitive_indices: bool, + pub show_bend_endpoint_tangents: bool, pub show_appearance_panel: bool, pub fix_step_rate: bool, pub step_rate: f32, @@ -87,6 +88,7 @@ impl MenuBar { show_bboxes: false, show_origin_destination: true, show_primitive_indices: false, + show_bend_endpoint_tangents: false, show_appearance_panel: true, fix_step_rate: false, step_rate: 1.0, diff --git a/locales/en-US/main.ftl b/locales/en-US/main.ftl index 4dfcd5d..b7ef7d3 100644 --- a/locales/en-US/main.ftl +++ b/locales/en-US/main.ftl @@ -48,6 +48,7 @@ tr-menu-debug-show-pathfinding-scores = Show Pathfinding Scores tr-menu-debug-show-topo-navmesh = Show Topological Navmesh tr-menu-debug-show-bboxes = Show BBoxes tr-menu-debug-show-primitive-indices = Show Primitive Indices +tr-menu-debug-show-bend-endpoint-tangents = Show Bend Endpoint Tangents tr-menu-debug-fix-step-rate = Fix Step Rate tr-menu-debug-step-rate = Step Rate tr-menu-debug-step-rate-unit = steps/s diff --git a/src/geometry/primitive.rs b/src/geometry/primitive.rs index ea532e3..0b0d0ba 100644 --- a/src/geometry/primitive.rs +++ b/src/geometry/primitive.rs @@ -291,6 +291,28 @@ impl BendShape { ) } + /// Determines if the provided point lies in the swept region between the rays cast by tangents + /// to the arc endpoints of the bend's outer circle, starting at `from` and `to`. + pub fn between_tangent_rays(&self, point: Point) -> bool { + math::between_vectors(point, self.from_tangent_ray(), self.to_tangent_ray()) + } + + pub fn from_tangent_ray(&self) -> Point { + // 90-degree CW rotation. + let center = self.inner_circle.pos; + let v_from = self.from - center; + + Point::new(v_from.y(), -v_from.x()) + } + + pub fn to_tangent_ray(&self) -> Point { + // 90-degree CCW rotation. + let center = self.inner_circle.pos; + let v_to = self.to - center; + + Point::new(-v_to.y(), v_to.x()) + } + pub fn start_angle(&self) -> f64 { let r = self.from - self.inner_circle.pos; math::vector_angle(r)