diff --git a/committed.toml b/committed.toml index 88cc23f..0b9e7a6 100644 --- a/committed.toml +++ b/committed.toml @@ -18,7 +18,7 @@ allowed_scopes = [ # Originally generated using # `find src -type f | awk '!/lib.rs|mod.rs/ { print "\"" substr($1, 1 + 4, length($1) - 4 - 3) "\","; }' | sort`. - "autorouter/autoroute", + "autorouter/anterouter", "autorouter/autorouter", "autorouter/compare_detours", "autorouter/conncomps", @@ -26,9 +26,12 @@ allowed_scopes = [ "autorouter/history", "autorouter/invoker", "autorouter/measure_length", + "autorouter/multilayer_autoroute", "autorouter/permutator", "autorouter/permuter", "autorouter/place_via", + "autorouter/planar_autoroute", + "autorouter/planner", "autorouter/pointroute", "autorouter/presorter", "autorouter/ratsnest", diff --git a/crates/topola-egui/src/actions.rs b/crates/topola-egui/src/actions.rs index 68dd0eb..5539e40 100644 --- a/crates/topola-egui/src/actions.rs +++ b/crates/topola-egui/src/actions.rs @@ -299,6 +299,7 @@ impl PlaceActions { pub struct RouteActions { pub autoroute: Trigger, + pub planar_autoroute: Trigger, pub topo_autoroute: Trigger, } @@ -311,6 +312,12 @@ impl RouteActions { egui::Key::R, ) .into_trigger(), + planar_autoroute: Action::new( + tr.text("tr-menu-route-planar-autoroute"), + egui::Modifiers::CTRL, + egui::Key::P, + ) + .into_trigger(), topo_autoroute: Action::new( tr.text("tr-menu-route-topo-autoroute"), egui::Modifiers::CTRL | egui::Modifiers::SHIFT, @@ -332,6 +339,7 @@ impl RouteActions { ui.add_enabled_ui(have_workspace, |ui| { ui.add_enabled_ui(workspace_activities_enabled, |ui| { self.autoroute.button(ctx, ui); + self.planar_autoroute.button(ctx, ui); self.topo_autoroute.button(ctx, ui); }); ui.separator(); diff --git a/crates/topola-egui/src/menu_bar.rs b/crates/topola-egui/src/menu_bar.rs index db992d1..204b8a1 100644 --- a/crates/topola-egui/src/menu_bar.rs +++ b/crates/topola-egui/src/menu_bar.rs @@ -354,6 +354,17 @@ impl MenuBar { }); } } else if actions.route.autoroute.consume_key_triggered(ctx, ui) { + schedule(error_dialog, workspace, |selection| { + Command::MultilayerAutoroute( + selection.pin_selection, + self.autorouter_options, + ) + }); + } else if actions + .route + .planar_autoroute + .consume_key_triggered(ctx, ui) + { schedule(error_dialog, workspace, |selection| { Command::Autoroute(selection.pin_selection, self.autorouter_options) }); diff --git a/locales/en-US/main.ftl b/locales/en-US/main.ftl index 6b628aa..82b4058 100644 --- a/locales/en-US/main.ftl +++ b/locales/en-US/main.ftl @@ -41,6 +41,7 @@ tr-menu-place-place-route-plan = Place Route Plan tr-menu-route = Route tr-menu-route-autoroute = Autoroute +tr-menu-route-planar-autoroute = Planar Autoroute tr-menu-route-topo-autoroute = Topological single-layer Autoroute tr-menu-route-routed-band-width = Routed Band Width diff --git a/src/autorouter/anterouter.rs b/src/autorouter/anterouter.rs new file mode 100644 index 0000000..9893666 --- /dev/null +++ b/src/autorouter/anterouter.rs @@ -0,0 +1,208 @@ +// SPDX-FileCopyrightText: 2025 Topola contributors +// +// SPDX-License-Identifier: MIT + +use std::collections::BTreeMap; + +use geo::point; +use petgraph::graph::NodeIndex; +use rstar::{Envelope, RTreeObject, AABB}; +use specctra_core::mesadata::AccessMesadata; + +use crate::{ + autorouter::{ratline::RatlineIndex, Autorouter}, + drawing::{ + dot::FixedDotIndex, + graph::{GetMaybeNet, MakePrimitiveRef}, + primitive::MakePrimitiveShape, + }, + geometry::GetLayer, + graph::{GenericIndex, GetIndex, MakeRef}, + layout::{ + poly::{MakePolygon, PolyWeight}, + via::ViaWeight, + CompoundWeight, LayoutEdit, + }, + math::Circle, +}; + +#[derive(Clone, Copy, Debug)] +pub enum TerminatingScheme { + ExistingFixedDot(FixedDotIndex), + Anteroute([f64; 2]), +} + +#[derive(Clone, Debug)] +pub struct AnterouterPlan { + pub layer_map: BTreeMap, + pub ratline_endpoint_dot_to_terminating_scheme: BTreeMap, +} + +pub struct Anterouter { + plan: AnterouterPlan, +} + +impl Anterouter { + pub fn new(plan: AnterouterPlan) -> Self { + Self { plan } + } + + pub fn anteroute(&mut self, autorouter: &mut Autorouter) { + // PERF: Unnecessary clone. + for (ratline, layer) in self.plan.layer_map.clone().iter() { + let endpoint_indices = ratline.ref_(autorouter).endpoint_indices(); + let endpoint_dots = ratline.ref_(autorouter).endpoint_dots(); + + if let Some(terminating_scheme) = self + .plan + .ratline_endpoint_dot_to_terminating_scheme + .get(&endpoint_dots.0) + { + match terminating_scheme { + TerminatingScheme::ExistingFixedDot(terminating_dot) => autorouter + .ratsnest + .assign_terminating_dot_to_ratvertex(endpoint_indices.0, *terminating_dot), + TerminatingScheme::Anteroute(pin_bbox_to_anchor) => self + .anteroute_dot_to_anchor( + autorouter, + endpoint_indices.0, + endpoint_dots.0, + *layer, + *pin_bbox_to_anchor, + ), + } + } + + if let Some(terminating_scheme) = self + .plan + .ratline_endpoint_dot_to_terminating_scheme + .get(&endpoint_dots.1) + { + match terminating_scheme { + TerminatingScheme::ExistingFixedDot(terminating_dot) => autorouter + .ratsnest + .assign_terminating_dot_to_ratvertex(endpoint_indices.1, *terminating_dot), + TerminatingScheme::Anteroute(pin_bbox_to_anchor) => self + .anteroute_dot_to_anchor( + autorouter, + endpoint_indices.1, + endpoint_dots.1, + *layer, + *pin_bbox_to_anchor, + ), + } + } + } + } + + fn anteroute_dot_to_anchor( + &mut self, + autorouter: &mut Autorouter, + ratvertex: NodeIndex, + dot: FixedDotIndex, + to_layer: usize, + endpoint_dot_bbox_to_anchor: [f64; 2], + ) { + self.place_assignment_via_on_anchor( + autorouter, + ratvertex, + dot, + to_layer, + endpoint_dot_bbox_to_anchor, + ) + } + + fn place_assignment_via_on_anchor( + &mut self, + autorouter: &mut Autorouter, + ratvertex: NodeIndex, + dot: FixedDotIndex, + to_layer: usize, + endpoint_dot_bbox_to_anchor: [f64; 2], + ) { + let pin_layer = autorouter.board().layout().drawing().primitive(dot).layer(); + let pin_maybe_net = autorouter + .board() + .layout() + .drawing() + .primitive(dot) + .maybe_net(); + + let pin_bbox = if let Some(poly) = autorouter + .board() + .layout() + .drawing() + .compounds(GenericIndex::<()>::new(dot.index())) + .find_map(|(_, compound)| { + if let CompoundWeight::Poly(_) = autorouter + .board() + .layout() + .drawing() + .compound_weight(compound) + { + Some(compound) + } else { + None + } + }) + .map(|compound| GenericIndex::::new(compound.index())) + { + let bbox = poly.ref_(autorouter.board().layout()).shape().envelope(); + AABB::<[f64; 2]>::from_corners( + [bbox.lower().x(), bbox.lower().y()], + [bbox.upper().x(), bbox.upper().y()], + ) + } else { + autorouter + .board() + .layout() + .drawing() + .primitive(dot) + .shape() + .envelope() + }; + + //let pin_bbox_anchor = pin_bbox.center() + (pin_bbox.upper() - pin_bbox.lower()) * pin_bbox_to_anchor; + let pin_bbox_anchor = point! { + x: pin_bbox.center()[0] + (pin_bbox.upper()[0] - pin_bbox.lower()[0]) / 2.0 * endpoint_dot_bbox_to_anchor[0], + y: pin_bbox.center()[1] + (pin_bbox.upper()[1] - pin_bbox.lower()[1]) / 2.0 * endpoint_dot_bbox_to_anchor[1], + }; + + //let via_bbox_to_anchor = [-pin_bbox_to_anchor[0], -pin_bbox_to_anchor[1]]; + + let mut layout_edit = LayoutEdit::new(); + + if let Ok((.., dots)) = autorouter.board.layout_mut().add_via( + &mut layout_edit, + ViaWeight { + from_layer: std::cmp::min(pin_layer, to_layer), + to_layer: std::cmp::max(pin_layer, to_layer), + circle: Circle { + pos: pin_bbox_anchor, + r: 100.0, + }, + maybe_net: pin_maybe_net, + }, + ) { + let terminating_dot = dots + .iter() + .find(|dot| { + to_layer + == dot + .primitive_ref(autorouter.board().layout().drawing()) + .layer() + }) + .unwrap(); + autorouter + .ratsnest + .assign_terminating_dot_to_ratvertex(ratvertex, *terminating_dot); + } + /*let bbox = if let Some(poly) = autorouter.board().layout().drawing().geometry().compounds(dot).find(|(_, compound_weight)| { + matches!(compound_weight, CompoundWeight::Poly(..)) + }) { + poly.ref_(autorouter.board().layout()).polygon() + } else { + // + }*/ + } +} diff --git a/src/autorouter/autorouter.rs b/src/autorouter/autorouter.rs index af169ff..55e76a1 100644 --- a/src/autorouter/autorouter.rs +++ b/src/autorouter/autorouter.rs @@ -7,11 +7,14 @@ use geo::Point; use petgraph::graph::NodeIndex; use serde::{Deserialize, Serialize}; use spade::InsertionError; -use std::collections::BTreeSet; +use std::collections::{BTreeMap, BTreeSet}; use thiserror::Error; use crate::{ - autorouter::permutator::AutorouteExecutionPermutator, + autorouter::{ + anterouter::AnterouterPlan, multilayer_autoroute::MultilayerAutorouteExecutionStepper, + permutator::PlanarAutorouteExecutionPermutator, planner::Planner, + }, board::{AccessMesadata, Board}, drawing::{band::BandTermsegIndex, Infringement}, graph::MakeRef, @@ -21,13 +24,13 @@ use crate::{ }; use super::{ - autoroute::AutorouteExecutionStepper, compare_detours::CompareDetoursExecutionStepper, measure_length::MeasureLengthExecutionStepper, place_via::PlaceViaExecutionStepper, + planar_autoroute::PlanarAutorouteExecutionStepper, pointroute::PointrouteExecutionStepper, ratline::RatlineIndex, - ratsnest::{Ratsnest, RatvertexIndex}, + ratsnest::{Ratsnest, RatvertexNodeIndex}, remove_bands::RemoveBandsExecutionStepper, selection::{BandSelection, PinSelection}, }; @@ -91,8 +94,8 @@ impl Autorouter { .unwrap() .node_index() { - RatvertexIndex::FixedDot(dot) => dot, - RatvertexIndex::Poly(poly) => poly.ref_(self.board.layout()).apex(), + RatvertexNodeIndex::FixedDot(dot) => dot, + RatvertexNodeIndex::Poly(poly) => poly.ref_(self.board.layout()).apex(), }; PointrouteExecutionStepper::new(self, origin_dot, point, options) @@ -105,27 +108,45 @@ impl Autorouter { .map_err(|_| AutorouterError::CouldNotRemoveBand(band)) } - pub fn autoroute( + pub fn multilayer_autoroute( &mut self, selection: &PinSelection, options: AutorouterOptions, - ) -> Result { - AutorouteExecutionPermutator::new(self, self.selected_ratlines(selection), options) + ) -> Result { + let planner = Planner::new(self, &self.selected_ratlines(selection)); + + MultilayerAutorouteExecutionStepper::new( + self, + self.selected_ratlines(selection), + planner.plan().clone(), + options, + ) } - pub(super) fn autoroute_ratlines( + pub fn planar_autoroute( + &mut self, + selection: &PinSelection, + options: AutorouterOptions, + ) -> Result { + PlanarAutorouteExecutionPermutator::new(self, self.selected_ratlines(selection), options) + } + + pub(super) fn planar_autoroute_ratlines( &mut self, ratlines: Vec, options: AutorouterOptions, - ) -> Result { - AutorouteExecutionStepper::new(self, ratlines, options) + ) -> Result { + PlanarAutorouteExecutionStepper::new(self, ratlines, options) } - pub fn undo_autoroute(&mut self, selection: &PinSelection) -> Result<(), AutorouterError> { - self.undo_autoroute_ratlines(self.selected_ratlines(selection)) + pub fn undo_planar_autoroute( + &mut self, + selection: &PinSelection, + ) -> Result<(), AutorouterError> { + self.undo_planar_autoroute_ratlines(self.selected_ratlines(selection)) } - pub(super) fn undo_autoroute_ratlines( + pub(super) fn undo_planar_autoroute_ratlines( &mut self, ratlines: Vec, ) -> Result<(), AutorouterError> { @@ -192,7 +213,7 @@ impl Autorouter { active_layer, allowed_edges, ratlines.into_iter().filter_map(|ratline| { - let (source, target) = ratline.ref_(self).endpoint_dots(); + let (source, target) = ratline.ref_(self).terminating_dots(); if navmesh .as_ref() diff --git a/src/autorouter/compare_detours.rs b/src/autorouter/compare_detours.rs index 3b8b704..ee65a2d 100644 --- a/src/autorouter/compare_detours.rs +++ b/src/autorouter/compare_detours.rs @@ -17,15 +17,15 @@ use crate::{ }; use super::{ - autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper}, invoker::GetDebugOverlayData, + planar_autoroute::{PlanarAutorouteContinueStatus, PlanarAutorouteExecutionStepper}, ratline::RatlineIndex, Autorouter, AutorouterError, AutorouterOptions, }; pub struct CompareDetoursExecutionStepper { - autoroute: AutorouteExecutionStepper, - next_autoroute: Option, + autoroute: PlanarAutorouteExecutionStepper, + next_autoroute: Option, ratline1: RatlineIndex, ratline2: RatlineIndex, total_length1: f64, @@ -41,8 +41,10 @@ impl CompareDetoursExecutionStepper { options: AutorouterOptions, ) -> Result { Ok(Self { - autoroute: autorouter.autoroute_ratlines(vec![ratline1, ratline2], options)?, - next_autoroute: Some(autorouter.autoroute_ratlines(vec![ratline2, ratline1], options)?), + autoroute: autorouter.planar_autoroute_ratlines(vec![ratline1, ratline2], options)?, + next_autoroute: Some( + autorouter.planar_autoroute_ratlines(vec![ratline2, ratline1], options)?, + ), ratline1, ratline2, total_length1: 0.0, @@ -67,9 +69,9 @@ impl Step, (f64, f64)> for CompareDetoursExecut match self.autoroute.step(autorouter)? { ControlFlow::Continue( - AutorouteContinueStatus::Running | AutorouteContinueStatus::Skipped(_), + PlanarAutorouteContinueStatus::Running | PlanarAutorouteContinueStatus::Skipped(_), ) => Ok(ControlFlow::Continue(())), - ControlFlow::Continue(AutorouteContinueStatus::Routed(band_termseg)) => { + ControlFlow::Continue(PlanarAutorouteContinueStatus::Routed(band_termseg)) => { let length = band_termseg .ref_(autorouter.board.layout().drawing()) .length(); @@ -84,13 +86,15 @@ impl Step, (f64, f64)> for CompareDetoursExecut } ControlFlow::Break(..) => { if let Some(next_autoroute) = self.next_autoroute.take() { - autorouter.undo_autoroute_ratlines(vec![self.ratline1, self.ratline2])?; + autorouter + .undo_planar_autoroute_ratlines(vec![self.ratline1, self.ratline2])?; self.autoroute = next_autoroute; Ok(ControlFlow::Continue(())) } else { self.done = true; - autorouter.undo_autoroute_ratlines(vec![self.ratline2, self.ratline1])?; + autorouter + .undo_planar_autoroute_ratlines(vec![self.ratline2, self.ratline1])?; Ok(ControlFlow::Break((self.total_length1, self.total_length2))) } diff --git a/src/autorouter/execution.rs b/src/autorouter/execution.rs index abc718a..741a699 100644 --- a/src/autorouter/execution.rs +++ b/src/autorouter/execution.rs @@ -8,7 +8,10 @@ use enum_dispatch::enum_dispatch; use serde::{Deserialize, Serialize}; use crate::{ - autorouter::permutator::AutorouteExecutionPermutator, + autorouter::{ + multilayer_autoroute::MultilayerAutorouteExecutionStepper, + permutator::PlanarAutorouteExecutionPermutator, + }, board::{edit::BoardEdit, AccessMesadata}, layout::via::ViaWeight, router::ng, @@ -29,7 +32,8 @@ type Type = PinSelection; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Command { - Autoroute(PinSelection, AutorouterOptions), + Autoroute(PinSelection, AutorouterOptions), // TODO: Rename to PlanarAutoroute. + MultilayerAutoroute(PinSelection, AutorouterOptions), TopoAutoroute { selection: PinSelection, #[serde(default, skip_serializing_if = "BTreeSet::is_empty")] @@ -45,7 +49,8 @@ pub enum Command { #[enum_dispatch(GetDebugOverlayData)] pub enum ExecutionStepper { - Autoroute(AutorouteExecutionPermutator), + MultilayerAutoroute(MultilayerAutorouteExecutionStepper), + PlanarAutoroute(PlanarAutorouteExecutionPermutator), TopoAutoroute(ng::AutorouteExecutionStepper), PlaceVia(PlaceViaExecutionStepper), RemoveBands(RemoveBandsExecutionStepper), @@ -59,10 +64,16 @@ impl ExecutionStepper { autorouter: &mut Autorouter, ) -> Result, String)>, InvokerError> { Ok(match self { - ExecutionStepper::Autoroute(autoroute) => match autoroute.step(autorouter)? { + ExecutionStepper::MultilayerAutoroute(autoroute) => match autoroute.step(autorouter)? { ControlFlow::Continue(..) => ControlFlow::Continue(()), ControlFlow::Break(edit) => { - ControlFlow::Break((edit, "finished autorouting".to_string())) + ControlFlow::Break((edit, "finished multilayer autorouting".to_string())) + } + }, + ExecutionStepper::PlanarAutoroute(autoroute) => match autoroute.step(autorouter)? { + ControlFlow::Continue(..) => ControlFlow::Continue(()), + ControlFlow::Break(edit) => { + ControlFlow::Break((edit, "finished planar autorouting".to_string())) } }, ExecutionStepper::TopoAutoroute(autoroute) => { @@ -156,12 +167,17 @@ impl Step, String> for ExecutionStepper impl Abort> for ExecutionStepper { fn abort(&mut self, invoker: &mut Invoker) { match self { + ExecutionStepper::MultilayerAutoroute(autoroute) => { + autoroute.abort(&mut invoker.autorouter) + } + ExecutionStepper::PlanarAutoroute(autoroute) => { + autoroute.abort(&mut invoker.autorouter) + } ExecutionStepper::TopoAutoroute(autoroute) => { autoroute.abort(&mut ()); // TODO: maintain topo-navmesh just like layout *invoker.autorouter.board.layout_mut() = autoroute.last_layout.clone(); } - ExecutionStepper::Autoroute(autoroute) => autoroute.abort(&mut invoker.autorouter), ExecutionStepper::PlaceVia(_place_via) => (), //place_via.abort(), ExecutionStepper::RemoveBands(_remove_bands) => (), //remove_bands.abort(), ExecutionStepper::CompareDetours(_compare_detours) => (), //compare_detours.abort(), @@ -177,7 +193,8 @@ impl EstimateProgress for ExecutionStepper { fn estimate_progress_value(&self) -> f64 { match self { - ExecutionStepper::Autoroute(autoroute) => autoroute.estimate_progress_value(), + ExecutionStepper::MultilayerAutoroute(autoroute) => autoroute.estimate_progress_value(), + ExecutionStepper::PlanarAutoroute(autoroute) => autoroute.estimate_progress_value(), ExecutionStepper::TopoAutoroute(toporoute) => toporoute.estimate_progress_value(), ExecutionStepper::PlaceVia(place_via) => place_via.estimate_progress_value(), ExecutionStepper::RemoveBands(remove_bands) => remove_bands.estimate_progress_value(), @@ -192,7 +209,10 @@ impl EstimateProgress for ExecutionStepper { fn estimate_progress_maximum(&self) -> f64 { match self { - ExecutionStepper::Autoroute(autoroute) => autoroute.estimate_progress_maximum(), + ExecutionStepper::MultilayerAutoroute(autoroute) => { + autoroute.estimate_progress_maximum() + } + ExecutionStepper::PlanarAutoroute(autoroute) => autoroute.estimate_progress_maximum(), ExecutionStepper::TopoAutoroute(toporoute) => toporoute.estimate_progress_maximum(), ExecutionStepper::PlaceVia(place_via) => place_via.estimate_progress_maximum(), ExecutionStepper::RemoveBands(remove_bands) => remove_bands.estimate_progress_maximum(), diff --git a/src/autorouter/invoker.rs b/src/autorouter/invoker.rs index 7e64084..33ac4f8 100644 --- a/src/autorouter/invoker.rs +++ b/src/autorouter/invoker.rs @@ -32,7 +32,8 @@ use super::{ execution::{Command, ExecutionStepper}, history::{History, HistoryError}, measure_length::MeasureLengthExecutionStepper, - permutator::AutorouteExecutionPermutator, + multilayer_autoroute::MultilayerAutorouteExecutionStepper, + permutator::PlanarAutorouteExecutionPermutator, place_via::PlaceViaExecutionStepper, remove_bands::RemoveBandsExecutionStepper, Autorouter, AutorouterError, @@ -166,8 +167,13 @@ impl Invoker { #[debug_requires(self.ongoing_command.is_none())] fn dispatch_command(&mut self, command: &Command) -> Result, InvokerError> { Ok(match command { - Command::Autoroute(selection, options) => { - ExecutionStepper::Autoroute(self.autorouter.autoroute(selection, *options)?) + Command::Autoroute(selection, options) => ExecutionStepper::PlanarAutoroute( + self.autorouter.planar_autoroute(selection, *options)?, + ), + Command::MultilayerAutoroute(selection, options) => { + ExecutionStepper::MultilayerAutoroute( + self.autorouter.multilayer_autoroute(selection, *options)?, + ) } Command::TopoAutoroute { selection, diff --git a/src/autorouter/mod.rs b/src/autorouter/mod.rs index 180fdbc..62d6ee3 100644 --- a/src/autorouter/mod.rs +++ b/src/autorouter/mod.rs @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -pub mod autoroute; +pub mod anterouter; mod autorouter; pub mod compare_detours; pub mod conncomps; @@ -10,9 +10,12 @@ pub mod execution; pub mod history; pub mod invoker; pub mod measure_length; +pub mod multilayer_autoroute; pub mod permutator; pub mod permuter; pub mod place_via; +pub mod planar_autoroute; +pub mod planner; pub mod pointroute; pub mod presorter; pub mod ratline; diff --git a/src/autorouter/multilayer_autoroute.rs b/src/autorouter/multilayer_autoroute.rs new file mode 100644 index 0000000..115f1e4 --- /dev/null +++ b/src/autorouter/multilayer_autoroute.rs @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: 2025 Topola contributors +// +// SPDX-License-Identifier: MIT + +use std::ops::ControlFlow; + +use specctra_core::mesadata::AccessMesadata; + +use crate::{ + autorouter::{ + anterouter::{Anterouter, AnterouterPlan}, + invoker::GetDebugOverlayData, + permutator::PlanarAutorouteExecutionPermutator, + planar_autoroute::PlanarAutorouteContinueStatus, + ratline::RatlineIndex, + Autorouter, AutorouterError, AutorouterOptions, + }, + board::edit::BoardEdit, + drawing::graph::PrimitiveIndex, + geometry::primitive::PrimitiveShape, + router::{navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper}, + stepper::{Abort, EstimateProgress, Step}, +}; + +pub struct MultilayerAutorouteExecutionStepper { + planar: PlanarAutorouteExecutionPermutator, +} + +impl MultilayerAutorouteExecutionStepper { + pub fn new( + autorouter: &mut Autorouter, + ratlines: Vec, + plan: AnterouterPlan, + options: AutorouterOptions, + ) -> Result { + let mut assigner = Anterouter::new(plan); + assigner.anteroute(autorouter); + + Ok(Self { + planar: PlanarAutorouteExecutionPermutator::new(autorouter, ratlines, options)?, + }) + } +} + +impl Step, Option, PlanarAutorouteContinueStatus> + for MultilayerAutorouteExecutionStepper +{ + type Error = AutorouterError; + + fn step( + &mut self, + autorouter: &mut Autorouter, + ) -> Result, PlanarAutorouteContinueStatus>, AutorouterError> + { + self.planar.step(autorouter) + } +} + +impl Abort> for MultilayerAutorouteExecutionStepper { + fn abort(&mut self, autorouter: &mut Autorouter) { + self.planar.abort(autorouter) + } +} + +impl EstimateProgress for MultilayerAutorouteExecutionStepper { + type Value = f64; + + fn estimate_progress_value(&self) -> f64 { + self.planar.estimate_progress_value() + } + + fn estimate_progress_maximum(&self) -> f64 { + self.planar.estimate_progress_maximum() + } +} + +impl GetDebugOverlayData for MultilayerAutorouteExecutionStepper { + fn maybe_thetastar(&self) -> Option<&ThetastarStepper> { + self.planar.maybe_thetastar() + } + + fn maybe_navcord(&self) -> Option<&Navcord> { + self.planar.maybe_navcord() + } + + fn ghosts(&self) -> &[PrimitiveShape] { + self.planar.ghosts() + } + + fn obstacles(&self) -> &[PrimitiveIndex] { + self.planar.obstacles() + } +} diff --git a/src/autorouter/permutator.rs b/src/autorouter/permutator.rs index fd7bdf8..f73ebbc 100644 --- a/src/autorouter/permutator.rs +++ b/src/autorouter/permutator.rs @@ -8,9 +8,9 @@ use specctra_core::mesadata::AccessMesadata; use crate::{ autorouter::{ - autoroute::{AutorouteContinueStatus, AutorouteExecutionStepper}, invoker::GetDebugOverlayData, permuter::{PermuteRatlines, RatlinesPermuter}, + planar_autoroute::{PlanarAutorouteContinueStatus, PlanarAutorouteExecutionStepper}, presorter::{PresortParams, PresortRatlines, SccIntersectionsAndLengthPresorter}, ratline::RatlineIndex, Autorouter, AutorouterError, AutorouterOptions, @@ -22,13 +22,13 @@ use crate::{ stepper::{Abort, EstimateProgress, Permutate, Step}, }; -pub struct AutorouteExecutionPermutator { - stepper: AutorouteExecutionStepper, +pub struct PlanarAutorouteExecutionPermutator { + stepper: PlanarAutorouteExecutionStepper, permuter: RatlinesPermuter, options: AutorouterOptions, } -impl AutorouteExecutionPermutator { +impl PlanarAutorouteExecutionPermutator { pub fn new( autorouter: &mut Autorouter, ratlines: Vec, @@ -49,7 +49,7 @@ impl AutorouteExecutionPermutator { let permuter = RatlinesPermuter::new(autorouter, ratlines, presorter, &options); Ok(Self { - stepper: AutorouteExecutionStepper::new( + stepper: PlanarAutorouteExecutionStepper::new( autorouter, initially_sorted_ratlines, options, @@ -61,15 +61,16 @@ impl AutorouteExecutionPermutator { } } -impl Step, Option, AutorouteContinueStatus> - for AutorouteExecutionPermutator +impl Step, Option, PlanarAutorouteContinueStatus> + for PlanarAutorouteExecutionPermutator { type Error = AutorouterError; fn step( &mut self, autorouter: &mut Autorouter, - ) -> Result, AutorouteContinueStatus>, AutorouterError> { + ) -> Result, PlanarAutorouteContinueStatus>, AutorouterError> + { match self.stepper.step(autorouter) { Ok(ok) => Ok(ok), Err(err) => { @@ -97,14 +98,14 @@ impl Step, Option, AutorouteContinue } } -impl Abort> for AutorouteExecutionPermutator { +impl Abort> for PlanarAutorouteExecutionPermutator { fn abort(&mut self, autorouter: &mut Autorouter) { //self.permutations_iter.all(|_| true); // Why did I add this code here??? self.stepper.abort(autorouter); } } -impl EstimateProgress for AutorouteExecutionPermutator { +impl EstimateProgress for PlanarAutorouteExecutionPermutator { type Value = f64; fn estimate_progress_value(&self) -> f64 { @@ -118,7 +119,7 @@ impl EstimateProgress for AutorouteExecutionPermutator { } } -impl GetDebugOverlayData for AutorouteExecutionPermutator { +impl GetDebugOverlayData for PlanarAutorouteExecutionPermutator { fn maybe_thetastar(&self) -> Option<&ThetastarStepper> { self.stepper.maybe_thetastar() } diff --git a/src/autorouter/permuter.rs b/src/autorouter/permuter.rs index fd8f501..62ac4bd 100644 --- a/src/autorouter/permuter.rs +++ b/src/autorouter/permuter.rs @@ -10,8 +10,9 @@ use specctra_core::mesadata::AccessMesadata; use crate::{ autorouter::{ - autoroute::AutorouteExecutionStepper, presorter::SccIntersectionsAndLengthPresorter, - ratline::RatlineIndex, scc::Scc, Autorouter, AutorouterOptions, + planar_autoroute::PlanarAutorouteExecutionStepper, + presorter::SccIntersectionsAndLengthPresorter, ratline::RatlineIndex, scc::Scc, Autorouter, + AutorouterOptions, }, drawing::graph::MakePrimitiveRef, geometry::{GenericNode, GetLayer}, @@ -23,7 +24,7 @@ pub trait PermuteRatlines { fn permute_ratlines( &mut self, autorouter: &mut Autorouter, - stepper: &AutorouteExecutionStepper, + stepper: &PlanarAutorouteExecutionStepper, ) -> Option>; } @@ -77,7 +78,7 @@ impl PermuteRatlines for SccPermutationsRatlinePermuter { fn permute_ratlines( &mut self, autorouter: &mut Autorouter, - _stepper: &AutorouteExecutionStepper, + _stepper: &PlanarAutorouteExecutionStepper, ) -> Option> { let scc_permutation = self.sccs_permutations_iter.next()?; let mut ratlines = vec![]; @@ -130,20 +131,20 @@ impl PermuteRatlines for RatlineCutsRatlinePermuter { fn permute_ratlines( &mut self, autorouter: &mut Autorouter, - stepper: &AutorouteExecutionStepper, + stepper: &PlanarAutorouteExecutionStepper, ) -> Option> { let curr_ratline = stepper.ratlines()[*stepper.curr_ratline_index()]; - let endpoint_dots = curr_ratline.ref_(autorouter).endpoint_dots(); + let terminating_dots = curr_ratline.ref_(autorouter).terminating_dots(); let bands_cut_by_ratline: Vec<_> = autorouter .board() .layout() .bands_between_nodes( - endpoint_dots + terminating_dots .0 .primitive_ref(autorouter.board().layout().drawing()) .layer(), - GenericNode::Primitive(endpoint_dots.0.into()), - GenericNode::Primitive(endpoint_dots.1.into()), + GenericNode::Primitive(terminating_dots.0.into()), + GenericNode::Primitive(terminating_dots.1.into()), ) .collect(); diff --git a/src/autorouter/autoroute.rs b/src/autorouter/planar_autoroute.rs similarity index 76% rename from src/autorouter/autoroute.rs rename to src/autorouter/planar_autoroute.rs index 220ee50..64a26fa 100644 --- a/src/autorouter/autoroute.rs +++ b/src/autorouter/planar_autoroute.rs @@ -30,7 +30,7 @@ use super::{ }; /// Represents the current status of the autoroute operation. -pub enum AutorouteContinueStatus { +pub enum PlanarAutorouteContinueStatus { /// The autoroute is currently running and in progress. Running, /// A specific segment has been successfully routed. @@ -41,7 +41,7 @@ pub enum AutorouteContinueStatus { /// Manages the autorouting process across multiple ratlines. #[derive(Getters)] -pub struct AutorouteExecutionStepper { +pub struct PlanarAutorouteExecutionStepper { /// The ratlines which we are routing. ratlines: Vec, /// Keeps track of the current ratline being routed, if one is active. @@ -56,7 +56,7 @@ pub struct AutorouteExecutionStepper { options: AutorouterOptions, } -impl AutorouteExecutionStepper { +impl PlanarAutorouteExecutionStepper { /// Initializes a new [`AutorouteExecutionStepper`] instance. /// /// This method sets up the routing process by accepting the execution properties. @@ -71,7 +71,7 @@ impl AutorouteExecutionStepper { return Err(AutorouterError::NothingToRoute); }; - let (origin, destination) = ratlines[0].ref_(autorouter).endpoint_dots(); + let (origin, destination) = ratlines[0].ref_(autorouter).terminating_dots(); let mut router = Router::new(autorouter.board.layout_mut(), options.router_options); Ok(Self { @@ -107,7 +107,7 @@ impl AutorouteExecutionStepper { autorouter.board.apply_edit(&board_edit.reverse()); - let (origin, destination) = self.ratlines[index].ref_(autorouter).endpoint_dots(); + let (origin, destination) = self.ratlines[index].ref_(autorouter).terminating_dots(); let mut router = Router::new(autorouter.board.layout_mut(), self.options.router_options); self.route = Some(router.route( @@ -129,15 +129,16 @@ impl AutorouteExecutionStepper { } } -impl Step, Option, AutorouteContinueStatus> - for AutorouteExecutionStepper +impl Step, Option, PlanarAutorouteContinueStatus> + for PlanarAutorouteExecutionStepper { type Error = AutorouterError; fn step( &mut self, autorouter: &mut Autorouter, - ) -> Result, AutorouteContinueStatus>, AutorouterError> { + ) -> Result, PlanarAutorouteContinueStatus>, AutorouterError> + { // TODO: Use a proper state machine here for better readability? if self.curr_ratline_index >= self.ratlines.len() { @@ -157,50 +158,56 @@ impl Step, Option, AutorouteContinue return Ok(ControlFlow::Break(None)); }; - let (source, target) = self.ratlines[self.curr_ratline_index] + let (origin, destination) = self.ratlines[self.curr_ratline_index] .ref_(autorouter) - .endpoint_dots(); + .terminating_dots(); - let ret = if let Some(band_termseg) = autorouter.board.band_between_nodes(source, target) { - AutorouteContinueStatus::Skipped(band_termseg[false]) - } else { - let band_termseg = { - let mut router = - Router::new(autorouter.board.layout_mut(), self.options.router_options); + let ret = + if let Some(band_termseg) = autorouter.board.band_between_nodes(origin, destination) { + PlanarAutorouteContinueStatus::Skipped(band_termseg[false]) + } else { + let band_termseg = { + let mut router = + Router::new(autorouter.board.layout_mut(), self.options.router_options); - let ControlFlow::Break(band_termseg) = route.step(&mut router)? else { - return Ok(ControlFlow::Continue(AutorouteContinueStatus::Running)); + let ControlFlow::Break(band_termseg) = route.step(&mut router)? else { + return Ok(ControlFlow::Continue( + PlanarAutorouteContinueStatus::Running, + )); + }; + band_termseg }; - band_termseg + + let band = autorouter + .board + .layout() + .drawing() + .find_loose_band_uid(band_termseg.into()) + .expect("a completely routed band should've Seg's as ends"); + + autorouter.ratsnest.assign_band_termseg_to_ratline( + self.ratlines[self.curr_ratline_index], + band_termseg, + ); + + let mut board_data_edit = BoardDataEdit::new(); + + autorouter.board.try_set_band_between_nodes( + &mut board_data_edit, + origin, + destination, + band, + ); + + self.board_data_edits.push(board_data_edit); + + PlanarAutorouteContinueStatus::Routed(band_termseg) }; - let band = autorouter - .board - .layout() - .drawing() - .find_loose_band_uid(band_termseg.into()) - .expect("a completely routed band should've Seg's as ends"); - - autorouter.ratsnest.assign_band_termseg_to_ratline( - self.ratlines[self.curr_ratline_index], - band_termseg, - ); - - let mut board_data_edit = BoardDataEdit::new(); - - autorouter - .board - .try_set_band_between_nodes(&mut board_data_edit, source, target, band); - - self.board_data_edits.push(board_data_edit); - - AutorouteContinueStatus::Routed(band_termseg) - }; - self.curr_ratline_index += 1; if let Some(new_ratline) = self.ratlines.get(self.curr_ratline_index) { - let (source, target) = new_ratline.ref_(autorouter).endpoint_dots(); + let (source, target) = new_ratline.ref_(autorouter).terminating_dots(); let mut router = Router::new(autorouter.board.layout_mut(), self.options.router_options); @@ -219,14 +226,14 @@ impl Step, Option, AutorouteContinue } } -impl Abort> for AutorouteExecutionStepper { +impl Abort> for PlanarAutorouteExecutionStepper { fn abort(&mut self, autorouter: &mut Autorouter) { self.backtrace_to_index(autorouter, 0); self.curr_ratline_index = self.ratlines.len(); } } -impl Permutate> for AutorouteExecutionStepper { +impl Permutate> for PlanarAutorouteExecutionStepper { type Index = RatlineIndex; type Output = Result<(), AutorouterError>; @@ -249,7 +256,7 @@ impl Permutate> for AutorouteExecutionStepper { } } -impl EstimateProgress for AutorouteExecutionStepper { +impl EstimateProgress for PlanarAutorouteExecutionStepper { type Value = f64; fn estimate_progress_value(&self) -> f64 { @@ -264,7 +271,7 @@ impl EstimateProgress for AutorouteExecutionStepper { } } -impl GetDebugOverlayData for AutorouteExecutionStepper { +impl GetDebugOverlayData for PlanarAutorouteExecutionStepper { fn maybe_thetastar(&self) -> Option<&ThetastarStepper> { self.route.as_ref().map(|route| route.thetastar()) } diff --git a/src/autorouter/planner.rs b/src/autorouter/planner.rs new file mode 100644 index 0000000..3430a3e --- /dev/null +++ b/src/autorouter/planner.rs @@ -0,0 +1,107 @@ +// SPDX-FileCopyrightText: 2025 Topola contributors +// +// SPDX-License-Identifier: MIT + +use std::collections::BTreeMap; + +use derive_getters::Getters; +use specctra_core::mesadata::AccessMesadata; + +use crate::{ + autorouter::{ + anterouter::{AnterouterPlan, TerminatingScheme}, + ratline::RatlineIndex, + Autorouter, + }, + drawing::{ + dot::FixedDotIndex, + graph::{MakePrimitiveRef, PrimitiveIndex}, + }, + geometry::{GenericNode, GetLayer}, + graph::MakeRef, +}; + +#[derive(Getters)] +pub struct Planner { + plan: AnterouterPlan, +} + +impl Planner { + pub fn new(autorouter: &Autorouter, ratlines: &[RatlineIndex]) -> Self { + let mut plan = AnterouterPlan { + layer_map: ratlines + .iter() + .enumerate() + .map(|(i, ratline)| (*ratline, i % 2)) + .collect(), + ratline_endpoint_dot_to_terminating_scheme: BTreeMap::new(), + }; + + for ratline in ratlines { + let layer = plan.layer_map[ratline]; + + if let Some(terminating_scheme) = Self::determine_terminating_scheme( + autorouter, + ratline.ref_(autorouter).endpoint_dots().0, + layer, + ) { + plan.ratline_endpoint_dot_to_terminating_scheme.insert( + ratline.ref_(autorouter).endpoint_dots().0, + terminating_scheme, + ); + } + + if let Some(terminating_scheme) = Self::determine_terminating_scheme( + autorouter, + ratline.ref_(autorouter).endpoint_dots().1, + layer, + ) { + plan.ratline_endpoint_dot_to_terminating_scheme.insert( + ratline.ref_(autorouter).endpoint_dots().1, + terminating_scheme, + ); + } + } + + Self { plan } + } + + fn determine_terminating_scheme( + autorouter: &Autorouter, + ratline_endpoint_dot: FixedDotIndex, + layer: usize, + ) -> Option { + if layer + == ratline_endpoint_dot + .primitive_ref(autorouter.board().layout().drawing()) + .layer() + { + return None; + } + + let pinname = autorouter + .board() + .node_pinname(&GenericNode::Primitive(ratline_endpoint_dot.into())) + .unwrap(); + + Some( + autorouter + .board() + .pinname_nodes(pinname) + .find_map(|node| { + if let GenericNode::Primitive(PrimitiveIndex::FixedDot(dot)) = node { + (layer + == dot + .primitive_ref(autorouter.board().layout().drawing()) + .layer()) + .then_some(dot) + } else { + None + } + }) + .map_or(TerminatingScheme::Anteroute([-1.0, -1.0]), |dot| { + TerminatingScheme::ExistingFixedDot(dot) + }), + ) + } +} diff --git a/src/autorouter/ratline.rs b/src/autorouter/ratline.rs index def84b4..9bb9f02 100644 --- a/src/autorouter/ratline.rs +++ b/src/autorouter/ratline.rs @@ -17,7 +17,7 @@ use crate::{ triangulation::GetTrianvertexNodeIndex, }; -use super::{ratsnest::RatvertexIndex, Autorouter}; +use super::{ratsnest::RatvertexNodeIndex, Autorouter}; pub type RatlineIndex = EdgeIndex; @@ -69,8 +69,8 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { .unwrap() .node_index() { - RatvertexIndex::FixedDot(dot) => dot, - RatvertexIndex::Poly(poly) => poly.ref_(self.autorouter.board.layout()).apex(), + RatvertexNodeIndex::FixedDot(dot) => dot, + RatvertexNodeIndex::Poly(poly) => poly.ref_(self.autorouter.board.layout()).apex(), }; let target_dot = match self @@ -81,13 +81,41 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { .unwrap() .node_index() { - RatvertexIndex::FixedDot(dot) => dot, - RatvertexIndex::Poly(poly) => poly.ref_(self.autorouter.board.layout()).apex(), + RatvertexNodeIndex::FixedDot(dot) => dot, + RatvertexNodeIndex::Poly(poly) => poly.ref_(self.autorouter.board.layout()).apex(), }; (source_dot, target_dot) } + pub fn terminating_dots(&self) -> (FixedDotIndex, FixedDotIndex) { + let (source, target) = self + .autorouter + .ratsnest + .graph() + .edge_endpoints(self.index) + .unwrap(); + + let source_dot = self + .autorouter + .ratsnest + .graph() + .node_weight(source) + .unwrap() + .maybe_terminating_dot + .unwrap_or(self.endpoint_dots().0); + let target_dot = self + .autorouter + .ratsnest + .graph() + .node_weight(target) + .unwrap() + .maybe_terminating_dot + .unwrap_or(self.endpoint_dots().1); + + (source_dot, target_dot) + } + pub fn layer(&self) -> usize { self.endpoint_dots() .0 @@ -172,7 +200,7 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { Line::new(source_pos, target_pos) } - fn endpoint_indices(&self) -> (NodeIndex, NodeIndex) { + pub fn endpoint_indices(&self) -> (NodeIndex, NodeIndex) { self.autorouter .ratsnest .graph() diff --git a/src/autorouter/ratsnest.rs b/src/autorouter/ratsnest.rs index 3b56a00..a285c0c 100644 --- a/src/autorouter/ratsnest.rs +++ b/src/autorouter/ratsnest.rs @@ -9,12 +9,11 @@ use std::{ use enum_dispatch::enum_dispatch; use geo::Point; -use petgraph::{data::Element, prelude::StableUnGraph}; +use petgraph::{data::Element, graph::NodeIndex, prelude::StableUnGraph}; use spade::{handles::FixedVertexHandle, HasPosition, InsertionError, Point2}; use specctra_core::mesadata::AccessMesadata; use crate::{ - autorouter::conncomps::ConncompsWithPrincipalLayer, board::Board, drawing::{ band::BandTermsegIndex, @@ -28,32 +27,36 @@ use crate::{ triangulation::{GetTrianvertexNodeIndex, Triangulation}, }; -use super::ratline::{RatlineIndex, RatlineWeight}; +use super::{ + conncomps::ConncompsWithPrincipalLayer, + ratline::{RatlineIndex, RatlineWeight}, +}; #[enum_dispatch(GetIndex)] #[derive(Debug, Clone, Copy, PartialEq)] -pub enum RatvertexIndex { +pub enum RatvertexNodeIndex { FixedDot(FixedDotIndex), Poly(GenericIndex), } -impl From for crate::layout::NodeIndex { - fn from(vertex: RatvertexIndex) -> crate::layout::NodeIndex { +impl From for crate::layout::NodeIndex { + fn from(vertex: RatvertexNodeIndex) -> crate::layout::NodeIndex { match vertex { - RatvertexIndex::FixedDot(dot) => crate::layout::NodeIndex::Primitive(dot.into()), - RatvertexIndex::Poly(poly) => crate::layout::NodeIndex::Compound(poly.into()), + RatvertexNodeIndex::FixedDot(dot) => crate::layout::NodeIndex::Primitive(dot.into()), + RatvertexNodeIndex::Poly(poly) => crate::layout::NodeIndex::Compound(poly.into()), } } } #[derive(Debug, Clone, Copy)] pub struct RatvertexWeight { - vertex: RatvertexIndex, + vertex: RatvertexNodeIndex, pub pos: Point, + pub maybe_terminating_dot: Option, } -impl GetTrianvertexNodeIndex for RatvertexWeight { - fn node_index(&self) -> RatvertexIndex { +impl GetTrianvertexNodeIndex for RatvertexWeight { + fn node_index(&self) -> RatvertexNodeIndex { self.vertex } } @@ -80,22 +83,22 @@ impl RatvertexToHandleMap { } } -impl Index for RatvertexToHandleMap { +impl Index for RatvertexToHandleMap { type Output = Option; - fn index(&self, ratvertex: RatvertexIndex) -> &Self::Output { + fn index(&self, ratvertex: RatvertexNodeIndex) -> &Self::Output { match ratvertex { - RatvertexIndex::FixedDot(dot) => &self.fixed_dot_to_handle[dot.index()], - RatvertexIndex::Poly(bend) => &self.poly_to_handle[bend.index()], + RatvertexNodeIndex::FixedDot(dot) => &self.fixed_dot_to_handle[dot.index()], + RatvertexNodeIndex::Poly(bend) => &self.poly_to_handle[bend.index()], } } } -impl IndexMut for RatvertexToHandleMap { - fn index_mut(&mut self, ratvertex: RatvertexIndex) -> &mut Self::Output { +impl IndexMut for RatvertexToHandleMap { + fn index_mut(&mut self, ratvertex: RatvertexNodeIndex) -> &mut Self::Output { match ratvertex { - RatvertexIndex::FixedDot(dot) => &mut self.fixed_dot_to_handle[dot.index()], - RatvertexIndex::Poly(bend) => &mut self.poly_to_handle[bend.index()], + RatvertexNodeIndex::FixedDot(dot) => &mut self.fixed_dot_to_handle[dot.index()], + RatvertexNodeIndex::Poly(bend) => &mut self.poly_to_handle[bend.index()], } } } @@ -160,12 +163,12 @@ impl Ratsnest { board: &Board, triangulations: &mut BTreeMap< usize, - Triangulation, + Triangulation, >, layer: usize, ) -> Result<(), InsertionError> { let mut handle_ratvertex_weight = - |maybe_net: Option, vertex: RatvertexIndex, pos: Point| { + |maybe_net: Option, vertex: RatvertexNodeIndex, pos: Point| { let Some(net) = maybe_net else { return Ok(()); }; @@ -184,7 +187,11 @@ impl Ratsnest { return Ok(()); } - triangulation.add_vertex(RatvertexWeight { vertex, pos })?; + triangulation.add_vertex(RatvertexWeight { + vertex, + pos, + maybe_terminating_dot: None, + })?; Ok(()) }; @@ -195,7 +202,7 @@ impl Ratsnest { if board.layout().drawing().compounds(dot).next().is_none() { handle_ratvertex_weight( board.layout().drawing().primitive(dot).maybe_net(), - RatvertexIndex::FixedDot(dot), + RatvertexNodeIndex::FixedDot(dot), node.primitive_ref(board.layout().drawing()) .shape() .center(), @@ -211,7 +218,7 @@ impl Ratsnest { .drawing() .compound_weight(poly.into()) .maybe_net(), - RatvertexIndex::Poly(poly), + RatvertexNodeIndex::Poly(poly), poly.ref_(board.layout()).shape().center(), )?; } @@ -219,6 +226,17 @@ impl Ratsnest { Ok(()) } + pub fn assign_terminating_dot_to_ratvertex( + &mut self, + node_index: NodeIndex, + terminating_dot: FixedDotIndex, + ) { + self.graph + .node_weight_mut(node_index) + .unwrap() + .maybe_terminating_dot = Some(terminating_dot) + } + pub fn assign_band_termseg_to_ratline( &mut self, ratline: RatlineIndex, diff --git a/src/layout/layout.rs b/src/layout/layout.rs index e608e46..010dcff 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -144,7 +144,7 @@ impl Layout { &mut self, recorder: &mut LayoutEdit, weight: ViaWeight, - ) -> Result, Infringement> { + ) -> Result<(GenericIndex, Vec), Infringement> { let compound = self.drawing.add_compound(recorder, weight.into()); let mut dots = vec![]; @@ -179,7 +179,7 @@ impl Layout { } } - Ok(GenericIndex::::new(compound.index())) + Ok((GenericIndex::::new(compound.index()), dots)) } pub fn add_fixed_dot( diff --git a/src/router/navmesh.rs b/src/router/navmesh.rs index 3071ee5..209c470 100644 --- a/src/router/navmesh.rs +++ b/src/router/navmesh.rs @@ -252,7 +252,7 @@ impl Navmesh { } // The existence of a constraint edge does not (!) guarantee that this - // edge exactly will be present in the triangulation. It appears that + // exact edge will be present in the triangulation. It appears that // Spade splits a constraint edge in two if an endpoint of another // constraint lies on it. // diff --git a/src/router/route.rs b/src/router/route.rs index c22c9d7..443a131 100644 --- a/src/router/route.rs +++ b/src/router/route.rs @@ -34,11 +34,11 @@ impl RouteStepper { pub fn new( router: &mut Router, recorder: LayoutEdit, - from: FixedDotIndex, - to: FixedDotIndex, + origin: FixedDotIndex, + destination: FixedDotIndex, width: f64, ) -> Result { - let navmesh = Navmesh::new(router.layout(), from, to, *router.options())?; + let navmesh = Navmesh::new(router.layout(), origin, destination, *router.options())?; Ok(Self::new_from_navmesh(router, recorder, navmesh, width)) } diff --git a/src/router/router.rs b/src/router/router.rs index 8962bce..9cc6d23 100644 --- a/src/router/router.rs +++ b/src/router/router.rs @@ -42,7 +42,7 @@ pub struct RouterOptions { pub struct RouterThetastarStrategy<'a, R> { pub layout: &'a mut Layout, pub navcord: &'a mut Navcord, - pub target: FixedDotIndex, + pub destination: FixedDotIndex, pub probe_ghosts: Vec, pub probe_obstacles: Vec, } @@ -52,7 +52,7 @@ impl<'a, R> RouterThetastarStrategy<'a, R> { Self { layout, navcord, - target, + destination: target, probe_ghosts: vec![], probe_obstacles: vec![], } @@ -79,7 +79,7 @@ impl ThetastarStrategy // without this, since A* will terminate now anyway. self.navcord.maybe_final_termseg = Some( self.layout - .finish(navmesh, self.navcord, self.target) + .finish(navmesh, self.navcord, self.destination) .map_err(|_| ())?, ); self.navcord.path.push(navnode); @@ -190,7 +190,7 @@ impl ThetastarStrategy let end_point = self .layout .drawing() - .primitive(self.target) + .primitive(self.destination) .shape() .center(); @@ -213,11 +213,11 @@ impl<'a, R: AccessRules> Router<'a, R> { pub fn route( &mut self, recorder: LayoutEdit, - from: FixedDotIndex, - to: FixedDotIndex, + origin: FixedDotIndex, + destination: FixedDotIndex, width: f64, ) -> Result { - RouteStepper::new(self, recorder, from, to, width) + RouteStepper::new(self, recorder, origin, destination, width) } pub fn layout_mut(&mut self) -> &mut Layout { diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 21bbc07..e1a7f98 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -139,7 +139,7 @@ pub fn assert_navnode_count( .iter() .find_map(|ratline| { let (candidate_origin, candidate_destination) = - ratline.ref_(autorouter).endpoint_dots(); + ratline.ref_(autorouter).terminating_dots(); let candidate_origin_pin = autorouter .board() .node_pinname(&GenericNode::Primitive(candidate_origin.into()))