diff --git a/crates/topola-egui/src/painter.rs b/crates/topola-egui/src/painter.rs index 429aad8..2fc54e4 100644 --- a/crates/topola-egui/src/painter.rs +++ b/crates/topola-egui/src/painter.rs @@ -114,4 +114,25 @@ impl<'a> Painter<'a> { stroke, )); } + + pub fn paint_text( + &mut self, + pos: Point, + anchor: egui::Align2, + text: &str, + color: egui::epaint::Color32, + ) { + let text = self.ui.painter().fonts(|fonts| { + egui::Shape::text( + fonts, + self.transform + .mul_pos([pos.x() as f32, -pos.y() as f32].into()), + anchor, + text, + egui::FontId::default(), + color, + ) + }); + self.ui.painter().add(text); + } } diff --git a/crates/topola-egui/src/viewport.rs b/crates/topola-egui/src/viewport.rs index 0c7e5bc..71cd668 100644 --- a/crates/topola-egui/src/viewport.rs +++ b/crates/topola-egui/src/viewport.rs @@ -11,7 +11,9 @@ use rstar::{Envelope, AABB}; use topola::{ autorouter::{ execution::Command, - invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles}, + invoker::{ + GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetNavmeshDebugTexts, GetObstacles, + }, }, board::AccessMesadata, drawing::{ @@ -22,6 +24,7 @@ use topola::{ graph::MakeRef, layout::{poly::MakePolygon, via::ViaWeight}, math::{Circle, RotationSense}, + router::navmesh::NavvertexIndex, }; use crate::{config::Config, menu_bar::MenuBar, painter::Painter, workspace::Workspace}; @@ -265,6 +268,50 @@ impl Viewport { }; painter.paint_edge(from, to, stroke); + + if let Some(text) = activity + .navedge_debug_text((edge.source(), edge.target())) + { + painter.paint_text( + (from + to) / 2.0, + egui::Align2::LEFT_BOTTOM, + text, + egui::Color32::from_rgb(255, 255, 255), + ); + } + } + + for index in navmesh.graph().node_indices() { + let navvertex = NavvertexIndex(index); + if let Some(text) = activity.navvertex_debug_text(navvertex) + { + let mut pos = PrimitiveIndex::from( + navmesh.node_weight(navvertex).unwrap().node, + ) + .primitive(board.layout().drawing()) + .shape() + .center(); + + pos += match navmesh + .node_weight(navvertex) + .unwrap() + .maybe_sense + { + Some(RotationSense::Counterclockwise) => { + [0.0, 150.0].into() + } + Some(RotationSense::Clockwise) => { + [-0.0, -150.0].into() + } + None => [0.0, 0.0].into(), + }; + painter.paint_text( + pos, + egui::Align2::LEFT_BOTTOM, + text, + egui::Color32::from_rgb(255, 255, 255), + ); + } } } } diff --git a/crates/topola-egui/src/workspace.rs b/crates/topola-egui/src/workspace.rs index 82d3230..0020760 100644 --- a/crates/topola-egui/src/workspace.rs +++ b/crates/topola-egui/src/workspace.rs @@ -19,7 +19,7 @@ use crate::{ translator::Translator, }; -/// A loaded design and associated structures +/// A loaded design and associated structures. pub struct Workspace { pub design: SpecctraDesign, pub appearance_panel: AppearancePanel, @@ -50,7 +50,7 @@ impl Workspace { interactor: Interactor::new(board).map_err(|err| { format!( "{}; {}", - tr.text("tr-error_unable-to-initialize-overlay"), + tr.text("tr-error-unable-to-initialize-overlay"), err ) })?, diff --git a/src/autorouter/autoroute.rs b/src/autorouter/autoroute.rs index 4a1a0f9..2257a70 100644 --- a/src/autorouter/autoroute.rs +++ b/src/autorouter/autoroute.rs @@ -14,12 +14,16 @@ use crate::{ drawing::{band::BandTermsegIndex, graph::PrimitiveIndex, Collect}, geometry::primitive::PrimitiveShape, layout::LayoutEdit, - router::{navcord::NavcordStepper, navmesh::Navmesh, RouteStepper, Router}, + router::{ + navcord::NavcordStepper, + navmesh::{Navmesh, NavvertexIndex}, + RouteStepper, Router, + }, stepper::Step, }; use super::{ - invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles}, + invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetNavmeshDebugTexts, GetObstacles}, Autorouter, AutorouterError, AutorouterOptions, }; @@ -159,29 +163,37 @@ impl Step, Option, AutorouteContinu } impl GetMaybeNavmesh for AutorouteExecutionStepper { - /// Retrieves an optional reference to the navigation mesh from the current route. fn maybe_navmesh(&self) -> Option<&Navmesh> { self.route.as_ref().map(|route| route.navmesh()) } } impl GetMaybeNavcord for AutorouteExecutionStepper { - /// Retrieves an optional reference to the navcord from the current route. fn maybe_navcord(&self) -> Option<&NavcordStepper> { self.route.as_ref().map(|route| route.navcord()) } } impl GetGhosts for AutorouteExecutionStepper { - /// Retrieves ghost shapes from the current route. fn ghosts(&self) -> &[PrimitiveShape] { self.route.as_ref().map_or(&[], |route| route.ghosts()) } } impl GetObstacles for AutorouteExecutionStepper { - /// Retrieves obstacles encountered during routing. fn obstacles(&self) -> &[PrimitiveIndex] { self.route.as_ref().map_or(&[], |route| route.obstacles()) } } + +impl GetNavmeshDebugTexts for AutorouteExecutionStepper { + fn navvertex_debug_text(&self, _navvertex: NavvertexIndex) -> Option<&str> { + // Add debug text here. + None + } + + fn navedge_debug_text(&self, _navedge: (NavvertexIndex, NavvertexIndex)) -> Option<&str> { + // Add debug text here. + None + } +} diff --git a/src/autorouter/compare_detours.rs b/src/autorouter/compare_detours.rs index 42f919a..6a410a6 100644 --- a/src/autorouter/compare_detours.rs +++ b/src/autorouter/compare_detours.rs @@ -14,13 +14,17 @@ use crate::{ drawing::graph::PrimitiveIndex, geometry::{primitive::PrimitiveShape, shape::MeasureLength}, graph::MakeRef, - router::{navcord::NavcordStepper, navmesh::Navmesh}, + router::{ + navcord::NavcordStepper, + navmesh::{Navmesh, NavvertexIndex}, + }, stepper::Step, }; use super::{ autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper}, - invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles}, + invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetNavmeshDebugTexts, GetObstacles}, + remove_bands::RemoveBandsExecutionStepper, Autorouter, AutorouterError, AutorouterOptions, }; @@ -123,3 +127,13 @@ impl GetObstacles for CompareDetoursExecutionStepper { self.autoroute.obstacles() } } + +impl GetNavmeshDebugTexts for CompareDetoursExecutionStepper { + fn navvertex_debug_text(&self, _navvertex: NavvertexIndex) -> Option<&str> { + None + } + + fn navedge_debug_text(&self, _navedge: (NavvertexIndex, NavvertexIndex)) -> Option<&str> { + None + } +} diff --git a/src/autorouter/execution.rs b/src/autorouter/execution.rs index ae323e9..e59297b 100644 --- a/src/autorouter/execution.rs +++ b/src/autorouter/execution.rs @@ -35,7 +35,13 @@ pub enum Command { MeasureLength(BandSelection), } -#[enum_dispatch(GetMaybeNavmesh, GetMaybeNavcord, GetGhosts, GetObstacles)] +#[enum_dispatch( + GetMaybeNavmesh, + GetMaybeNavcord, + GetGhosts, + GetObstacles, + GetNavmeshDebugTexts +)] pub enum ExecutionStepper { Autoroute(AutorouteExecutionStepper), PlaceVia(PlaceViaExecutionStepper), diff --git a/src/autorouter/invoker.rs b/src/autorouter/invoker.rs index 051fe13..0dc0a7d 100644 --- a/src/autorouter/invoker.rs +++ b/src/autorouter/invoker.rs @@ -15,7 +15,10 @@ use crate::{ board::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::{edit::ApplyGeometryEdit, primitive::PrimitiveShape}, - router::{navcord::NavcordStepper, navmesh::Navmesh}, + router::{ + navcord::NavcordStepper, + navmesh::{Navmesh, NavvertexIndex}, + }, stepper::Step, }; @@ -31,63 +34,59 @@ use super::{ }; #[enum_dispatch] -/// Getter trait to obtain Navigation Mesh -/// -/// Navigation Mesh is possible routes between -/// two points +/// Trait for getting the navmesh to display it on the debug overlay. pub trait GetMaybeNavmesh { - /// Returns Navigation Mesh if possible fn maybe_navmesh(&self) -> Option<&Navmesh>; } #[enum_dispatch] -/// Getter for Navigation Cord -/// -/// Navigation Cord is the possible path of -/// ongoing autorouting process +/// Trait for getting the navcord to display it on the debug overlay. pub trait GetMaybeNavcord { - /// Gets the Navigation Cord if possible fn maybe_navcord(&self) -> Option<&NavcordStepper>; } #[enum_dispatch] -/// Requires Ghosts implementations -/// -/// Ghosts are possible shapes of routing -/// bands +/// Trait for getting ghosts to display on the debug overlay. Ghosts are the +/// shapes that Topola attempted to create but failed due to them infringing on +/// other shapes. pub trait GetGhosts { - /// Retrieves the ghosts associated with the execution. fn ghosts(&self) -> &[PrimitiveShape]; } #[enum_dispatch] -/// Getter for the Obstacles -/// -/// Obstacles are shapes of existing bands -/// to be avoided by the new band +/// Trait for getting the obstacles that prevented Topola from creating +/// new objects (the shapes of these objects can be obtained with the above +/// `GetGhosts` trait), for the purpose of displaying these obstacles on the +/// debug overlay. pub trait GetObstacles { - /// Returns possible Obstacles fn obstacles(&self) -> &[PrimitiveIndex]; } -/// Error types that can occur during the invocation of commands +#[enum_dispatch] +/// Trait for getting text strings with debug information attached to navmesh +/// edges and vertices. +pub trait GetNavmeshDebugTexts { + fn navvertex_debug_text(&self, navvertex: NavvertexIndex) -> Option<&str>; + fn navedge_debug_text(&self, navedge: (NavvertexIndex, NavvertexIndex)) -> Option<&str>; +} + +/// Error types that can occur during the invocation of commands. #[derive(Error, Debug, Clone)] pub enum InvokerError { - /// Wraps errors related to command history operations + /// Wraps errors related to command history operations. #[error(transparent)] History(#[from] HistoryError), - /// Wraps errors related to autorouter operations + /// Wraps errors related to autorouter operations. #[error(transparent)] Autorouter(#[from] AutorouterError), } #[derive(Getters, Dissolve)] -/// Structure that manages the execution and history of commands within the autorouting system pub struct Invoker { - /// Instance for executing desired autorouting commands + /// Instance for executing desired autorouting commands. pub(super) autorouter: Autorouter, - /// History of executed commands + /// History of executed commands. pub(super) history: History, /// Currently ongoing command type. pub(super) ongoing_command: Option, @@ -109,10 +108,10 @@ impl Invoker { } //#[debug_requires(self.ongoing_command.is_none())] - /// Executes a command, managing the command status and history + /// Executes a command, managing the command status and history. /// /// This function is used to pass the [`Command`] to [`Invoker::execute_stepper`] - /// function, and control its execution status + /// function, and control its execution status. pub fn execute(&mut self, command: Command) -> Result<(), InvokerError> { let mut execute = self.execute_stepper(command)?; @@ -127,9 +126,9 @@ impl Invoker { } #[debug_requires(self.ongoing_command.is_none())] - /// Pass given command to be executed + /// Pass given command to be executed. /// - /// Function used to set given [`Command`] to ongoing state, dispatch and execute it + /// Function used to set given [`Command`] to ongoing state, dispatch and execute it. pub fn execute_stepper(&mut self, command: Command) -> Result { let execute = self.dispatch_command(&command); self.ongoing_command = Some(command); @@ -174,7 +173,7 @@ impl Invoker { } #[debug_requires(self.ongoing_command.is_none())] - /// Undo last command + /// Undo last command. pub fn undo(&mut self) -> Result<(), InvokerError> { let last_done = self.history.last_done()?; @@ -186,7 +185,7 @@ impl Invoker { } //#[debug_requires(self.ongoing_command.is_none())] - /// Redo last command + /// Redo last command. pub fn redo(&mut self) -> Result<(), InvokerError> { let last_undone = self.history.last_undone()?; @@ -198,7 +197,7 @@ impl Invoker { } #[debug_requires(self.ongoing_command.is_none())] - /// Replay last command + /// Replay last command. pub fn replay(&mut self, history: History) { let (done, undone) = history.dissolve(); diff --git a/src/autorouter/measure_length.rs b/src/autorouter/measure_length.rs index 07425eb..59cced3 100644 --- a/src/autorouter/measure_length.rs +++ b/src/autorouter/measure_length.rs @@ -11,11 +11,15 @@ use crate::{ drawing::graph::PrimitiveIndex, geometry::{primitive::PrimitiveShape, shape::MeasureLength as MeasureLengthTrait}, graph::MakeRef, - router::{navcord::NavcordStepper, navmesh::Navmesh}, + router::{ + navcord::NavcordStepper, + navmesh::{Navmesh, NavvertexIndex}, + }, }; use super::{ - invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles}, + invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetNavmeshDebugTexts, GetObstacles}, + remove_bands::RemoveBandsExecutionStepper, selection::BandSelection, Autorouter, AutorouterError, }; @@ -78,3 +82,13 @@ impl GetObstacles for MeasureLengthExecutionStepper { &[] } } + +impl GetNavmeshDebugTexts for MeasureLengthExecutionStepper { + fn navvertex_debug_text(&self, _navvertex: NavvertexIndex) -> Option<&str> { + None + } + + fn navedge_debug_text(&self, _navedge: (NavvertexIndex, NavvertexIndex)) -> Option<&str> { + None + } +} diff --git a/src/autorouter/place_via.rs b/src/autorouter/place_via.rs index 9425cba..86eb074 100644 --- a/src/autorouter/place_via.rs +++ b/src/autorouter/place_via.rs @@ -11,11 +11,14 @@ use crate::{ drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, layout::{via::ViaWeight, LayoutEdit}, - router::{navcord::NavcordStepper, navmesh::Navmesh}, + router::{ + navcord::NavcordStepper, + navmesh::{Navmesh, NavvertexIndex}, + }, }; use super::{ - invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles}, + invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetNavmeshDebugTexts, GetObstacles}, Autorouter, AutorouterError, }; @@ -75,3 +78,13 @@ impl GetObstacles for PlaceViaExecutionStepper { &[] } } + +impl GetNavmeshDebugTexts for PlaceViaExecutionStepper { + fn navvertex_debug_text(&self, _navvertex: NavvertexIndex) -> Option<&str> { + None + } + + fn navedge_debug_text(&self, _navedge: (NavvertexIndex, NavvertexIndex)) -> Option<&str> { + None + } +} diff --git a/src/autorouter/remove_bands.rs b/src/autorouter/remove_bands.rs index 7d201ec..32b4d64 100644 --- a/src/autorouter/remove_bands.rs +++ b/src/autorouter/remove_bands.rs @@ -9,11 +9,14 @@ use crate::{ drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, layout::LayoutEdit, - router::{navcord::NavcordStepper, navmesh::Navmesh}, + router::{ + navcord::NavcordStepper, + navmesh::{Navmesh, NavvertexIndex}, + }, }; use super::{ - invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles}, + invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetNavmeshDebugTexts, GetObstacles}, selection::BandSelection, Autorouter, AutorouterError, }; @@ -74,3 +77,13 @@ impl GetObstacles for RemoveBandsExecutionStepper { &[] } } + +impl GetNavmeshDebugTexts for RemoveBandsExecutionStepper { + fn navvertex_debug_text(&self, _navvertex: NavvertexIndex) -> Option<&str> { + None + } + + fn navedge_debug_text(&self, _navedge: (NavvertexIndex, NavvertexIndex)) -> Option<&str> { + None + } +} diff --git a/src/interactor/activity.rs b/src/interactor/activity.rs index ba4a8c7..5647bd2 100644 --- a/src/interactor/activity.rs +++ b/src/interactor/activity.rs @@ -12,14 +12,18 @@ use crate::{ autorouter::{ execution::ExecutionStepper, invoker::{ - GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles, Invoker, InvokerError, + GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetNavmeshDebugTexts, GetObstacles, + Invoker, InvokerError, }, }, board::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, interactor::interaction::{InteractionError, InteractionStepper}, - router::{navcord::NavcordStepper, navmesh::Navmesh}, + router::{ + navcord::NavcordStepper, + navmesh::{Navmesh, NavvertexIndex}, + }, stepper::{Abort, Step}, }; @@ -44,7 +48,13 @@ pub enum ActivityError { } /// An activity is either an interaction or an execution -#[enum_dispatch(GetMaybeNavmesh, GetMaybeNavcord, GetGhosts, GetObstacles)] +#[enum_dispatch( + GetMaybeNavmesh, + GetMaybeNavcord, + GetGhosts, + GetObstacles, + GetNavmeshDebugTexts +)] pub enum ActivityStepper { Interaction(InteractionStepper), Execution(ExecutionStepper), @@ -137,3 +147,13 @@ impl GetObstacles for ActivityStepperWithStatus { self.activity.obstacles() } } + +impl GetNavmeshDebugTexts for ActivityStepperWithStatus { + fn navvertex_debug_text(&self, navvertex: NavvertexIndex) -> Option<&str> { + self.activity.navvertex_debug_text(navvertex) + } + + fn navedge_debug_text(&self, navedge: (NavvertexIndex, NavvertexIndex)) -> Option<&str> { + self.activity.navedge_debug_text(navedge) + } +} diff --git a/src/interactor/interaction.rs b/src/interactor/interaction.rs index 9578d94..8b6946e 100644 --- a/src/interactor/interaction.rs +++ b/src/interactor/interaction.rs @@ -7,11 +7,16 @@ use std::ops::ControlFlow; use thiserror::Error; use crate::{ - autorouter::invoker::{GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetObstacles}, + autorouter::invoker::{ + GetGhosts, GetMaybeNavcord, GetMaybeNavmesh, GetNavmeshDebugTexts, GetObstacles, + }, board::AccessMesadata, drawing::graph::PrimitiveIndex, geometry::primitive::PrimitiveShape, - router::{navcord::NavcordStepper, navmesh::Navmesh}, + router::{ + navcord::NavcordStepper, + navmesh::{Navmesh, NavvertexIndex}, + }, stepper::{Abort, Step}, }; @@ -70,3 +75,13 @@ impl GetObstacles for InteractionStepper { todo!() } } + +impl GetNavmeshDebugTexts for InteractionStepper { + fn navvertex_debug_text(&self, navvertex: NavvertexIndex) -> Option<&str> { + todo!() + } + + fn navedge_debug_text(&self, navedge: (NavvertexIndex, NavvertexIndex)) -> Option<&str> { + todo!() + } +} diff --git a/src/router/navmesh.rs b/src/router/navmesh.rs index e07a333..c11433e 100644 --- a/src/router/navmesh.rs +++ b/src/router/navmesh.rs @@ -39,7 +39,7 @@ use crate::{ use super::RouterOptions; #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] -pub struct NavvertexIndex(NodeIndex); +pub struct NavvertexIndex(pub NodeIndex); impl core::fmt::Debug for NavvertexIndex { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -152,7 +152,7 @@ pub enum NavmeshError { /// when going directly to destination) on the layout for each leap and /// along-edge crossing. /// -/// The name "navmesh" is a shortening of "navigation mesh". +/// The name "navmesh" is a blend of "navigation mesh". #[derive(Debug, Clone)] pub struct Navmesh { graph: UnGraph,