feat(topola-egui): Display guide-bitangents on debug overlay

This commit is contained in:
Mikolaj Wielgus 2025-08-16 01:17:29 +02:00
parent 7fbfed710c
commit 5fd4926fb6
4 changed files with 78 additions and 34 deletions

View File

@ -167,6 +167,7 @@ pub struct ViewActions {
pub show_ratsnest: Switch,
pub show_navmesh: Switch,
pub show_guide_circles: Switch,
pub show_guide_bitangents: Switch,
pub show_triangulation: Switch,
pub show_triangulation_constraints: Switch,
pub show_pathfinding_scores: Switch,
@ -184,6 +185,10 @@ impl ViewActions {
show_navmesh: Action::new_keyless(tr.text("tr-menu-view-show-navmesh")).into_switch(),
show_guide_circles: Action::new_keyless(tr.text("tr-menu-view-show-guide-circles"))
.into_switch(),
show_guide_bitangents: Action::new_keyless(
tr.text("tr-menu-view-show-guide-bitangents"),
)
.into_switch(),
show_triangulation: Action::new_keyless(tr.text("tr-menu-view-show-triangulation"))
.into_switch(),
show_triangulation_constraints: Action::new_keyless(
@ -224,6 +229,8 @@ impl ViewActions {
self.show_navmesh.checkbox(ui, &mut menu_bar.show_navmesh);
self.show_guide_circles
.checkbox(ui, &mut menu_bar.show_guide_circles);
self.show_guide_bitangents
.checkbox(ui, &mut menu_bar.show_guide_bitangents);
self.show_triangulation
.checkbox(ui, &mut menu_bar.show_triangulation);
self.show_triangulation_constraints

View File

@ -4,12 +4,13 @@
use petgraph::{
data::DataMap,
graph::NodeIndex,
visit::{EdgeRef, IntoEdgeReferences},
};
use rstar::AABB;
use topola::{
autorouter::invoker::GetDebugOverlayData,
board::AccessMesadata,
board::{AccessMesadata, Board},
drawing::{
bend::BendIndex,
dot::DotIndex,
@ -21,9 +22,10 @@ use topola::{
graph::MakeRef,
interactor::{activity::ActivityStepper, interaction::InteractionStepper},
layout::poly::MakePolygon,
math::{Circle, RotationSense},
math::{self, Circle, RotationSense},
router::{
navmesh::{BinavnodeNodeIndex, NavnodeIndex},
navcord::Navcord,
navmesh::{BinavnodeNodeIndex, Navmesh, NavnodeIndex},
ng::pie,
prenavmesh::PrenavmeshConstraint,
},
@ -53,7 +55,7 @@ impl<'a> Displayer<'a> {
self.display_ratsnest();
}
if menu_bar.show_navmesh || menu_bar.show_guide_circles {
if menu_bar.show_navmesh || menu_bar.show_guide_circles || menu_bar.show_guide_bitangents {
self.display_navmesh_or_guides(menu_bar);
}
@ -227,6 +229,27 @@ impl<'a> Displayer<'a> {
self.painter.paint_line_segment(from, to, stroke);
}
if menu_bar.show_guide_bitangents {
if let Some(navcord) = activity.maybe_navcord() {
if let (Some(from_circle), Some(to_circle)) = (
Self::node_guide_circle(board, navmesh, navcord, edge.source().0),
Self::node_guide_circle(board, navmesh, navcord, edge.target().0),
) {
if let Ok(tangents) =
math::tangent_segments(from_circle, None, to_circle, None)
{
for tangent in tangents {
self.painter.paint_line_segment(
tangent.start_point(),
tangent.end_point(),
egui::Stroke::new(1.0, egui::Color32::WHITE),
)
}
}
}
}
}
if let Some(text) = activity.navedge_debug_text((edge.source(), edge.target()))
{
self.painter.paint_text(
@ -239,6 +262,20 @@ impl<'a> Displayer<'a> {
}
for index in navmesh.graph().node_indices() {
if menu_bar.show_guide_circles {
if let Some(navcord) = activity.maybe_navcord() {
if let Some(circle) =
Self::node_guide_circle(board, navmesh, navcord, index)
{
self.painter.paint_hollow_circle(
circle,
1.0,
egui::epaint::Color32::WHITE,
);
}
}
}
let navnode = NavnodeIndex(index);
let primitive =
PrimitiveIndex::from(navmesh.node_weight(navnode).unwrap().node);
@ -247,36 +284,6 @@ impl<'a> Displayer<'a> {
.shape()
.center();
if menu_bar.show_guide_circles {
if let Some(navcord) = activity.maybe_navcord() {
if let Ok(dot) = DotIndex::try_from(primitive) {
let drawing = board.layout().drawing();
self.painter.paint_hollow_circle(
drawing.dot_circle(
dot,
navcord.width,
drawing.conditions(navcord.head.face().into()).as_ref(),
),
1.0,
egui::epaint::Color32::WHITE,
);
} else if let Ok(bend) = BendIndex::try_from(primitive) {
let drawing = board.layout().drawing();
self.painter.paint_hollow_circle(
drawing.bend_circle(
bend,
navcord.width,
drawing.conditions(navcord.head.face().into()).as_ref(),
),
1.0,
egui::epaint::Color32::WHITE,
);
}
}
}
pos += match navmesh.node_weight(navnode).unwrap().maybe_sense {
Some(RotationSense::Counterclockwise) => [0.0, 150.0].into(),
Some(RotationSense::Clockwise) => [-0.0, -150.0].into(),
@ -306,6 +313,33 @@ impl<'a> Displayer<'a> {
}
}
fn node_guide_circle(
board: &Board<impl AccessMesadata>,
navmesh: &Navmesh,
navcord: &Navcord,
index: NodeIndex<usize>,
) -> Option<Circle> {
let drawing = board.layout().drawing();
let navnode = NavnodeIndex(index);
let primitive = PrimitiveIndex::from(navmesh.node_weight(navnode).unwrap().node);
if let Ok(dot) = DotIndex::try_from(primitive) {
Some(drawing.dot_circle(
dot,
navcord.width,
drawing.conditions(navcord.head.face().into()).as_ref(),
))
} else if let Ok(bend) = BendIndex::try_from(primitive) {
Some(drawing.bend_circle(
bend,
navcord.width,
drawing.conditions(navcord.head.face().into()).as_ref(),
))
} else {
None
}
}
fn display_triangulation(&mut self) {
let board = self.workspace.interactor.invoker().autorouter().board();

View File

@ -30,6 +30,7 @@ pub struct MenuBar {
pub show_ratsnest: bool,
pub show_navmesh: bool,
pub show_guide_circles: bool,
pub show_guide_bitangents: bool,
pub show_triangulation: bool,
pub show_triangulation_constraints: bool,
pub show_pathfinding_scores: bool,
@ -56,6 +57,7 @@ impl MenuBar {
show_ratsnest: true,
show_navmesh: false,
show_guide_circles: false,
show_guide_bitangents: false,
show_triangulation: false,
show_triangulation_constraints: false,
show_pathfinding_scores: false,

View File

@ -23,6 +23,7 @@ tr-menu-view-zoom-to-fit = Zoom to Fit
tr-menu-view-show-ratsnest = Show Ratsnest
tr-menu-view-show-navmesh = Show Navmesh
tr-menu-view-show-guide-circles = Show Guide-Circles
tr-menu-view-show-guide-bitangents = Show Guide-Bitangents
tr-menu-view-show-triangulation = Show Triangulation
tr-menu-view-show-triangulation-constraints = Show Triangulation Constraints
tr-menu-view-show-pathfinding-scores = Show Pathfinding Scores