From 07427a3831cd32b204b5a7bee08de27f36596138 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Thu, 19 Mar 2026 22:37:33 +0100 Subject: [PATCH] Rename `NavmesherBoard` to `Autorouter`, move it to own file --- topola-egui/src/display.rs | 85 +++++++++------------ topola-egui/src/viewport.rs | 6 +- topola-egui/src/workspace.rs | 9 +-- topola/src/autorouter.rs | 141 +++++++++++++++++++++++++++++++++++ topola/src/lib.rs | 3 +- topola/src/navmesher.rs | 136 +-------------------------------- 6 files changed, 188 insertions(+), 192 deletions(-) create mode 100644 topola/src/autorouter.rs diff --git a/topola-egui/src/display.rs b/topola-egui/src/display.rs index 437ef1c..65cbb62 100644 --- a/topola-egui/src/display.rs +++ b/topola-egui/src/display.rs @@ -23,9 +23,10 @@ impl Display { self.display_layout(ctx, ui, /*menu_bar,*/ viewport, workspace); self.display_bboxes(ctx, ui, viewport, workspace); self.display_navmeshes(ctx, ui, viewport, workspace); + //self.display_ratsnest(ctx, ui, viewport, workspace); } - pub fn display_layout( + fn display_layout( &mut self, ctx: &egui::Context, ui: &egui::Ui, @@ -35,7 +36,7 @@ impl Display { ) { ui.painter().line( workspace - .navmesher_board + .autorouter .board() .layout() .boundary() @@ -48,13 +49,7 @@ impl Display { egui::Stroke::new(5.0 / viewport.scale_factor(), egui::Color32::WHITE), ); - for (joint_index, joint) in workspace - .navmesher_board - .board() - .layout() - .joints() - .collection() - { + for (joint_index, joint) in workspace.autorouter.board().layout().joints().collection() { if workspace.appearance_panel.visible[joint.layer] { self.paint_joint( ctx, @@ -63,21 +58,18 @@ impl Display { joint, workspace.appearance_panel.layer_color( ctx, - workspace.navmesher_board.board().layer_name(joint.layer), - workspace - .navmesher_board - .board() - .pin_selection_contains_joint( - &workspace.pin_selection, - JointId::new(joint_index), - ), + workspace.autorouter.board().layer_name(joint.layer), + workspace.autorouter.board().pin_selection_contains_joint( + &workspace.pin_selection, + JointId::new(joint_index), + ), ), ); } } for (segment_index, segment) in workspace - .navmesher_board + .autorouter .board() .layout() .segments() @@ -90,20 +82,17 @@ impl Display { viewport, segment, workspace - .navmesher_board + .autorouter .board() .layout() .segment_endpoints(SegmentId::new(segment_index)), workspace.appearance_panel.layer_color( ctx, - workspace.navmesher_board.board().layer_name(segment.layer), - workspace - .navmesher_board - .board() - .pin_selection_contains_segment( - &workspace.pin_selection, - SegmentId::new(segment_index), - ), + workspace.autorouter.board().layer_name(segment.layer), + workspace.autorouter.board().pin_selection_contains_segment( + &workspace.pin_selection, + SegmentId::new(segment_index), + ), ), ); } @@ -112,7 +101,7 @@ impl Display { // TODO: Vias. for (polygon_index, polygon) in workspace - .navmesher_board + .autorouter .board() .layout() .polygons() @@ -126,14 +115,11 @@ impl Display { polygon, workspace.appearance_panel.layer_color( ctx, - workspace.navmesher_board.board().layer_name(polygon.layer), - workspace - .navmesher_board - .board() - .pin_selection_contains_polygon( - &workspace.pin_selection, - PolygonId::new(polygon_index), - ), + workspace.autorouter.board().layer_name(polygon.layer), + workspace.autorouter.board().pin_selection_contains_polygon( + &workspace.pin_selection, + PolygonId::new(polygon_index), + ), ), ); } @@ -201,13 +187,7 @@ impl Display { viewport: &Viewport, workspace: &Workspace, ) { - for (_, joint) in workspace - .navmesher_board - .board() - .layout() - .joints() - .collection() - { + for (_, joint) in workspace.autorouter.board().layout().joints().collection() { if workspace.appearance_panel.visible[joint.layer] { ui.painter().rect_stroke( egui::Rect { @@ -228,7 +208,7 @@ impl Display { } for (i, segment) in workspace - .navmesher_board + .autorouter .board() .layout() .segments() @@ -236,7 +216,7 @@ impl Display { { if workspace.appearance_panel.visible[segment.layer] { let endpoints = workspace - .navmesher_board + .autorouter .board() .layout() .segment_endpoints(SegmentId::new(i)); @@ -256,7 +236,7 @@ impl Display { // TODO: vias. for (i, polygon) in workspace - .navmesher_board + .autorouter .board() .layout() .polygons() @@ -285,10 +265,10 @@ impl Display { viewport: &Viewport, workspace: &Workspace, ) { - for layer in 0..*workspace.navmesher_board.board().layout().layer_count() { + for layer in 0..*workspace.autorouter.board().layout().layer_count() { if workspace.appearance_panel.visible[layer] { for navmesh in - workspace.navmesher_board.navmesher().layer_navmeshers()[layer].navmeshes() + workspace.autorouter.navmesher().layer_navmeshers()[layer].navmeshes() { for edge_geom in navmesh .triangulation() @@ -335,4 +315,13 @@ impl Display { } } } + + fn display_ratsnest( + ctx: &egui::Context, + ui: &egui::Ui, + viewport: &Viewport, + workspace: &Workspace, + ) { + // + } } diff --git a/topola-egui/src/viewport.rs b/topola-egui/src/viewport.rs index 0590a4d..50fafca 100644 --- a/topola-egui/src/viewport.rs +++ b/topola-egui/src/viewport.rs @@ -54,7 +54,7 @@ impl Viewport { if response.clicked() { if let Some(pin_selector) = - workspace.navmesher_board.board().point_pin_selector( + workspace.autorouter.board().point_pin_selector( 0, Vector2::new( pointer_scene_pos.x as i64, @@ -113,14 +113,14 @@ impl Viewport { } fn boundary_bounding_box(workspace: &Workspace) -> egui::Rect { - let first = workspace.navmesher_board.board().layout().boundary()[0]; + let first = workspace.autorouter.board().layout().boundary()[0]; let mut min_x = first[0]; let mut max_x = first[0]; let mut min_y = first[1]; let mut max_y = first[1]; - for point in workspace.navmesher_board.board().layout().boundary()[1..].iter() { + for point in workspace.autorouter.board().layout().boundary()[1..].iter() { if point[0] < min_x { min_x = point[0]; } diff --git a/topola-egui/src/workspace.rs b/topola-egui/src/workspace.rs index 66cece9..80ec206 100644 --- a/topola-egui/src/workspace.rs +++ b/topola-egui/src/workspace.rs @@ -2,12 +2,12 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -use topola::{Board, NavmesherBoard, PinSelection}; +use topola::{Autorouter, Board, PinSelection}; use crate::{appearance_panel::AppearancePanel, translator::Translator}; pub struct Workspace { - pub navmesher_board: NavmesherBoard, + pub autorouter: Autorouter, pub appearance_panel: AppearancePanel, pub pin_selection: PinSelection, } @@ -17,14 +17,13 @@ impl Workspace { let appearance_panel = AppearancePanel::new(&board); Self { - navmesher_board: NavmesherBoard::with_board(board), + autorouter: Autorouter::with_board(board), appearance_panel, pin_selection: PinSelection::new(), } } pub fn update_appearance_panel(&mut self, ctx: &egui::Context) { - self.appearance_panel - .update(ctx, &self.navmesher_board.board()); + self.appearance_panel.update(ctx, &self.autorouter.board()); } } diff --git a/topola/src/autorouter.rs b/topola/src/autorouter.rs new file mode 100644 index 0000000..059bf33 --- /dev/null +++ b/topola/src/autorouter.rs @@ -0,0 +1,141 @@ +// SPDX-FileCopyrightText: 2026 Topola contributors +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use derive_getters::Getters; +use undoredo::Recorder; + +use crate::{ + Board, Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Vector2, Via, ViaId, + navmesher::{MultiObstacleId, Navmesher}, +}; + +#[derive(Clone, Debug, Getters)] +pub struct Autorouter { + navmesher: Navmesher, + board: Board, + + joint_multiobstacles: Recorder>, + segment_multiobstacles: Recorder>, + polygon_multiobstacles: Recorder>, +} + +impl Autorouter { + pub fn with_board(board: Board) -> Self { + let mut this = Self { + navmesher: Navmesher::new( + board + .layout() + .boundary() + .iter() + .map(|p| Vector2::new(p[0], p[1])), + *board.layout().layer_count(), + ), + board, + + joint_multiobstacles: Recorder::new(Vec::new()), + segment_multiobstacles: Recorder::new(Vec::new()), + polygon_multiobstacles: Recorder::new(Vec::new()), + }; + + for (i, joint) in this.board.layout().joints().collection() { + this.joint_multiobstacles.insert( + i, + this.navmesher + .insert_multiobstacle(joint.layer, Self::joint_bounding_octagon(*joint)), + ); + } + + for (i, segment) in this.board.layout().segments().collection() { + this.segment_multiobstacles.insert( + i, + this.navmesher.insert_multiobstacle( + segment.layer, + this.segment_bounding_rectangle(SegmentId::new(i), *segment), + ), + ); + } + + for (i, polygon) in this.board.layout().polygons().collection() { + this.polygon_multiobstacles.insert( + i, + this.navmesher + .insert_multiobstacle(polygon.layer, polygon.vertices.clone()), + ); + } + + this + } + + pub fn insert_joint(&mut self, joint: Joint) -> JointId { + let joint_id = self.board.add_joint(joint); + self.joint_multiobstacles.insert( + joint_id.index(), + self.navmesher + .insert_multiobstacle(joint.layer, Self::joint_bounding_octagon(joint)), + ); + + joint_id + } + + fn joint_bounding_octagon(joint: Joint) -> [Vector2; 8] { + let cx = joint.position.x; + let cy = joint.position.y; + let r = joint.radius as i64; + + [ + Vector2::new(cx + r, cy + r / 2), + Vector2::new(cx + r / 2, cy + r), + Vector2::new(cx - r / 2, cy + r), + Vector2::new(cx - r, cy + r / 2), + Vector2::new(cx - r, cy - r / 2), + Vector2::new(cx - r / 2, cy - r), + Vector2::new(cx + r / 2, cy - r), + Vector2::new(cx + r, cy - r / 2), + ] + } + + pub fn insert_segment(&mut self, segment: Segment) -> SegmentId { + let segment_id = self.board.add_segment(segment); + self.segment_multiobstacles.insert( + segment_id.index(), + self.navmesher.insert_multiobstacle( + segment.layer, + self.segment_bounding_rectangle(segment_id, segment), + ), + ); + + segment_id + } + + fn segment_bounding_rectangle( + &self, + segment_id: SegmentId, + segment: Segment, + ) -> [Vector2; 4] { + let endpoints = self.board.layout().segment_endpoints(segment_id); + crate::math::inflated_segment( + endpoints[0].x, + endpoints[0].y, + endpoints[1].x, + endpoints[1].y, + segment.half_width, + ) + } + + pub fn insert_via(&mut self, via: Via) -> ViaId { + // TODO: Insert into navmesh. + self.board.add_via(via) + } + + pub fn insert_polygon(&mut self, polygon: Polygon) -> PolygonId { + let polygon_id = self.board.add_polygon(polygon.clone()); + self.polygon_multiobstacles.insert( + polygon_id.index(), + self.navmesher + .insert_multiobstacle(polygon.layer, polygon.vertices), + ); + + polygon_id + } +} diff --git a/topola/src/lib.rs b/topola/src/lib.rs index dada36a..c37f5ad 100644 --- a/topola/src/lib.rs +++ b/topola/src/lib.rs @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 +mod autorouter; mod board; mod layout; mod math; @@ -11,10 +12,10 @@ mod ratsnest; mod selection; mod specctra; +pub use crate::autorouter::Autorouter; pub use crate::board::Board; pub use crate::layout::Layout; pub use crate::math::Vector2; -pub use crate::navmesher::NavmesherBoard; pub use crate::primitives::{ Joint, JointId, Polygon, PolygonId, PrimitiveId, Segment, SegmentId, Via, ViaId, }; diff --git a/topola/src/navmesher.rs b/topola/src/navmesher.rs index 26c6f08..1e39769 100644 --- a/topola/src/navmesher.rs +++ b/topola/src/navmesher.rs @@ -6,12 +6,8 @@ use dearcut::{RecordingTriangulator, VertexId}; use derive_getters::Getters; use derive_more::Constructor; use serde::{Deserialize, Serialize}; -use undoredo::Recorder; -use crate::{ - Board, Vector2, math, - primitives::{Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Via, ViaId}, -}; +use crate::Vector2; #[derive( Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, @@ -173,133 +169,3 @@ impl Navmesher { } } } - -#[derive(Clone, Debug, Getters)] -pub struct NavmesherBoard { - navmesher: Navmesher, - board: Board, - - joint_multiobstacles: Recorder>, - segment_multiobstacles: Recorder>, - polygon_multiobstacles: Recorder>, -} - -impl NavmesherBoard { - pub fn with_board(board: Board) -> Self { - let mut this = Self { - navmesher: Navmesher::new( - board - .layout() - .boundary() - .iter() - .map(|p| Vector2::new(p[0], p[1])), - *board.layout().layer_count(), - ), - board, - - joint_multiobstacles: Recorder::new(Vec::new()), - segment_multiobstacles: Recorder::new(Vec::new()), - polygon_multiobstacles: Recorder::new(Vec::new()), - }; - - for (i, joint) in this.board.layout().joints().collection() { - this.joint_multiobstacles.insert( - i, - this.navmesher - .insert_multiobstacle(joint.layer, Self::joint_bounding_octagon(*joint)), - ); - } - - for (i, segment) in this.board.layout().segments().collection() { - this.segment_multiobstacles.insert( - i, - this.navmesher.insert_multiobstacle( - segment.layer, - this.segment_bounding_rectangle(SegmentId::new(i), *segment), - ), - ); - } - - for (i, polygon) in this.board.layout().polygons().collection() { - this.polygon_multiobstacles.insert( - i, - this.navmesher - .insert_multiobstacle(polygon.layer, polygon.vertices.clone()), - ); - } - - this - } - - pub fn insert_joint(&mut self, joint: Joint) -> JointId { - let joint_id = self.board.add_joint(joint); - self.joint_multiobstacles.insert( - joint_id.index(), - self.navmesher - .insert_multiobstacle(joint.layer, Self::joint_bounding_octagon(joint)), - ); - - joint_id - } - - fn joint_bounding_octagon(joint: Joint) -> [Vector2; 8] { - let cx = joint.position.x; - let cy = joint.position.y; - let r = joint.radius as i64; - - [ - Vector2::new(cx + r, cy + r / 2), - Vector2::new(cx + r / 2, cy + r), - Vector2::new(cx - r / 2, cy + r), - Vector2::new(cx - r, cy + r / 2), - Vector2::new(cx - r, cy - r / 2), - Vector2::new(cx - r / 2, cy - r), - Vector2::new(cx + r / 2, cy - r), - Vector2::new(cx + r, cy - r / 2), - ] - } - - pub fn insert_segment(&mut self, segment: Segment) -> SegmentId { - let segment_id = self.board.add_segment(segment); - self.segment_multiobstacles.insert( - segment_id.index(), - self.navmesher.insert_multiobstacle( - segment.layer, - self.segment_bounding_rectangle(segment_id, segment), - ), - ); - - segment_id - } - - fn segment_bounding_rectangle( - &self, - segment_id: SegmentId, - segment: Segment, - ) -> [Vector2; 4] { - let endpoints = self.board.layout().segment_endpoints(segment_id); - math::inflated_segment( - endpoints[0].x, - endpoints[0].y, - endpoints[1].x, - endpoints[1].y, - segment.half_width, - ) - } - - pub fn insert_via(&mut self, via: Via) -> ViaId { - // TODO: Insert into navmesh. - self.board.add_via(via) - } - - pub fn insert_polygon(&mut self, polygon: Polygon) -> PolygonId { - let polygon_id = self.board.add_polygon(polygon.clone()); - self.polygon_multiobstacles.insert( - polygon_id.index(), - self.navmesher - .insert_multiobstacle(polygon.layer, polygon.vertices), - ); - - polygon_id - } -}