autorouter: split selection into pin selection and band selection

This commit is contained in:
Mikolaj Wielgus 2024-07-24 14:59:28 +02:00
parent 3bf4d2cdb1
commit b568f2d790
5 changed files with 142 additions and 116 deletions

View File

@ -3,12 +3,6 @@ use spade::InsertionError;
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
autorouter::{
autoroute::Autoroute,
place_via::PlaceVia,
ratsnest::{Ratsnest, RatvertexIndex},
selection::Selection,
},
board::{mesadata::AccessMesadata, Board}, board::{mesadata::AccessMesadata, Board},
drawing::{dot::FixedDotIndex, Infringement}, drawing::{dot::FixedDotIndex, Infringement},
layout::via::ViaWeight, layout::via::ViaWeight,
@ -16,6 +10,13 @@ use crate::{
triangulation::GetTrianvertexNodeIndex, triangulation::GetTrianvertexNodeIndex,
}; };
use super::{
autoroute::Autoroute,
place_via::PlaceVia,
ratsnest::{Ratsnest, RatvertexIndex},
selection::{BandSelection, PinSelection},
};
#[derive(Error, Debug, Clone)] #[derive(Error, Debug, Clone)]
pub enum AutorouterError { pub enum AutorouterError {
#[error("nothing to route")] #[error("nothing to route")]
@ -44,7 +45,7 @@ impl<M: AccessMesadata> Autorouter<M> {
Ok(Self { board, ratsnest }) Ok(Self { board, ratsnest })
} }
pub fn autoroute(&mut self, selection: &Selection) -> Result<(), AutorouterError> { pub fn autoroute(&mut self, selection: &PinSelection) -> Result<(), AutorouterError> {
let mut autoroute = self.autoroute_walk(selection)?; let mut autoroute = self.autoroute_walk(selection)?;
loop { loop {
@ -59,11 +60,14 @@ impl<M: AccessMesadata> Autorouter<M> {
} }
} }
pub fn autoroute_walk(&mut self, selection: &Selection) -> Result<Autoroute, AutorouterError> { pub fn autoroute_walk(
&mut self,
selection: &PinSelection,
) -> Result<Autoroute, AutorouterError> {
Autoroute::new(self, self.selected_ratlines(selection)) Autoroute::new(self, self.selected_ratlines(selection))
} }
pub fn undo_autoroute(&mut self, selection: &Selection) { pub fn undo_autoroute(&mut self, selection: &PinSelection) {
for ratline in self.selected_ratlines(selection).iter() { for ratline in self.selected_ratlines(selection).iter() {
let band = self let band = self
.ratsnest .ratsnest
@ -120,7 +124,7 @@ impl<M: AccessMesadata> Autorouter<M> {
(source_dot, target_dot) (source_dot, target_dot)
} }
fn selected_ratlines(&self, selection: &Selection) -> Vec<EdgeIndex<usize>> { fn selected_ratlines(&self, selection: &PinSelection) -> Vec<EdgeIndex<usize>> {
self.ratsnest self.ratsnest
.graph() .graph()
.edge_indices() .edge_indices()

View File

@ -4,13 +4,6 @@ use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
autorouter::{
autoroute::Autoroute,
history::{History, HistoryError},
place_via::PlaceVia,
selection::Selection,
Autorouter, AutorouterError, AutorouterStatus,
},
board::mesadata::AccessMesadata, board::mesadata::AccessMesadata,
drawing::graph::PrimitiveIndex, drawing::graph::PrimitiveIndex,
geometry::primitive::PrimitiveShape, geometry::primitive::PrimitiveShape,
@ -18,6 +11,14 @@ use crate::{
router::{navmesh::Navmesh, trace::Trace}, router::{navmesh::Navmesh, trace::Trace},
}; };
use super::{
autoroute::Autoroute,
history::{History, HistoryError},
place_via::PlaceVia,
selection::{BandSelection, PinSelection},
Autorouter, AutorouterError, AutorouterStatus,
};
#[enum_dispatch] #[enum_dispatch]
pub trait GetMaybeNavmesh { pub trait GetMaybeNavmesh {
fn maybe_navmesh(&self) -> Option<&Navmesh>; fn maybe_navmesh(&self) -> Option<&Navmesh>;
@ -54,7 +55,7 @@ pub enum InvokerStatus {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Command { pub enum Command {
Autoroute(Selection), Autoroute(PinSelection),
PlaceVia(ViaWeight), PlaceVia(ViaWeight),
} }

View File

@ -3,7 +3,7 @@ use std::collections::HashSet;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
board::{mesadata::AccessMesadata, Board}, board::{mesadata::AccessMesadata, BandName, Board},
drawing::{ drawing::{
band::BandUid, band::BandUid,
graph::{GetLayer, MakePrimitive, PrimitiveIndex}, graph::{GetLayer, MakePrimitive, PrimitiveIndex},
@ -14,117 +14,28 @@ use crate::{
}; };
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub struct Selector { pub struct PinSelector {
pin: String, pin: String,
layer: String, layer: String,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Selection { pub struct PinSelection {
selectors: HashSet<Selector>, selectors: HashSet<PinSelector>,
#[serde(skip)]
selected_bands: HashSet<BandUid>,
} }
impl Selection { impl PinSelection {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
selectors: HashSet::new(), selectors: HashSet::new(),
selected_bands: HashSet::new(),
} }
} }
pub fn new_select_all(board: &Board<impl AccessMesadata>) -> Self {
let mut this = Self::new();
for node in board.layout().drawing().primitive_nodes() {
if let Some(selector) = this.node_selector(board, GenericNode::Primitive(node)) {
if !this.contains_node(board, GenericNode::Primitive(node)) {
this.select(board, selector);
}
}
}
this
}
pub fn new_select_layer(board: &Board<impl AccessMesadata>, layer: usize) -> Self {
let mut this = Self::new();
for node in board.layout().drawing().layer_primitive_nodes(layer) {
if let Some(selector) = this.node_selector(board, GenericNode::Primitive(node)) {
if !this.contains_node(board, GenericNode::Primitive(node)) {
this.select(board, selector);
}
}
}
this
}
pub fn toggle_at_node(&mut self, board: &Board<impl AccessMesadata>, node: NodeIndex) {
if let Some(selector) = self.node_selector(board, node) {
if self.contains_node(board, node) {
self.deselect(board, &selector);
} else {
self.select(board, selector);
}
} else if let Some(band) = self.node_band(board, node) {
if self.contains_node(board, node) {
self.deselect_band(board, band);
} else {
self.select_band(board, band);
}
}
}
fn select(&mut self, _board: &Board<impl AccessMesadata>, selector: Selector) {
self.selectors.insert(selector);
}
fn deselect(&mut self, _board: &Board<impl AccessMesadata>, selector: &Selector) {
self.selectors.remove(selector);
}
fn select_band(&mut self, board: &Board<impl AccessMesadata>, band: BandUid) {
self.selected_bands.insert(band);
}
fn deselect_band(&mut self, board: &Board<impl AccessMesadata>, band: BandUid) {
self.selected_bands.remove(&band);
}
pub fn contains_node(&self, board: &Board<impl AccessMesadata>, node: NodeIndex) -> bool {
if let Some(selector) = self.node_selector(board, node) {
self.selectors.contains(&selector)
} else if let Some(band) = self.node_band(board, node) {
self.selected_bands.contains(&band)
} else {
false
}
}
fn node_band(&self, board: &Board<impl AccessMesadata>, node: NodeIndex) -> Option<BandUid> {
let NodeIndex::Primitive(primitive) = node else {
return None;
};
let loose = match primitive {
PrimitiveIndex::LooseDot(dot) => dot.into(),
PrimitiveIndex::LoneLooseSeg(seg) => seg.into(),
PrimitiveIndex::SeqLooseSeg(seg) => seg.into(),
PrimitiveIndex::LooseBend(bend) => bend.into(),
_ => return None,
};
Some(board.layout().drawing().collect().loose_band_uid(loose))
}
fn node_selector( fn node_selector(
&self, &self,
board: &Board<impl AccessMesadata>, board: &Board<impl AccessMesadata>,
node: NodeIndex, node: NodeIndex,
) -> Option<Selector> { ) -> Option<PinSelector> {
let layer = match node { let layer = match node {
NodeIndex::Primitive(primitive) => { NodeIndex::Primitive(primitive) => {
primitive.primitive(board.layout().drawing()).layer() primitive.primitive(board.layout().drawing()).layer()
@ -146,7 +57,7 @@ impl Selection {
board.node_pinname(node), board.node_pinname(node),
board.layout().rules().layer_layername(layer), board.layout().rules().layer_layername(layer),
) { ) {
Some(Selector { Some(PinSelector {
pin: pinname.to_string(), pin: pinname.to_string(),
layer: layername.to_string(), layer: layername.to_string(),
}) })
@ -154,4 +65,108 @@ impl Selection {
None None
} }
} }
fn select(&mut self, selector: PinSelector) {
self.selectors.insert(selector);
}
fn deselect(&mut self, selector: &PinSelector) {
self.selectors.remove(selector);
}
pub fn contains_node(&self, board: &Board<impl AccessMesadata>, node: NodeIndex) -> bool {
self.node_selector(board, node)
.map_or(false, |selector| self.selectors.contains(&selector))
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub struct BandSelector {
band: BandName,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BandSelection {
selectors: HashSet<BandSelector>,
}
impl BandSelection {
pub fn new() -> Self {
Self {
selectors: HashSet::new(),
}
}
fn node_selector(
&self,
board: &Board<impl AccessMesadata>,
node: NodeIndex,
) -> Option<BandSelector> {
let NodeIndex::Primitive(primitive) = node else {
return None;
};
let loose = match primitive {
PrimitiveIndex::LooseDot(dot) => dot.into(),
PrimitiveIndex::LoneLooseSeg(seg) => seg.into(),
PrimitiveIndex::SeqLooseSeg(seg) => seg.into(),
PrimitiveIndex::LooseBend(bend) => bend.into(),
_ => return None,
};
Some(BandSelector {
band: board
.band_bandname(board.layout().drawing().collect().loose_band_uid(loose))?
.clone(),
})
}
fn select(&mut self, selector: BandSelector) {
self.selectors.insert(selector);
}
fn deselect(&mut self, selector: &BandSelector) {
self.selectors.remove(&selector);
}
pub fn contains_node(&self, board: &Board<impl AccessMesadata>, node: NodeIndex) -> bool {
self.node_selector(board, node)
.map_or(false, |selector| self.selectors.contains(&selector))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Selection {
pub pin_selection: PinSelection,
pub band_selection: BandSelection,
}
impl Selection {
pub fn new() -> Self {
Self {
pin_selection: PinSelection::new(),
band_selection: BandSelection::new(),
}
}
pub fn toggle_at_node(&mut self, board: &Board<impl AccessMesadata>, node: NodeIndex) {
if let Some(selector) = self.pin_selection.node_selector(board, node) {
if self.pin_selection.contains_node(board, node) {
self.pin_selection.deselect(&selector);
} else {
self.pin_selection.select(selector);
}
} else if let Some(selector) = self.band_selection.node_selector(board, node) {
if self.band_selection.contains_node(board, node) {
self.band_selection.deselect(&selector);
} else {
self.band_selection.select(selector);
}
}
}
pub fn contains_node(&self, board: &Board<impl AccessMesadata>, node: NodeIndex) -> bool {
self.pin_selection.contains_node(board, node)
|| self.band_selection.contains_node(board, node)
}
} }

View File

@ -207,7 +207,8 @@ impl Top {
let selection = overlay.selection().clone(); let selection = overlay.selection().clone();
overlay.clear_selection(); overlay.clear_selection();
maybe_execute.insert(ExecuteWithStatus::new( maybe_execute.insert(ExecuteWithStatus::new(
invoker.execute_walk(Command::Autoroute(selection))?, invoker
.execute_walk(Command::Autoroute(selection.pin_selection))?,
)); ));
} }
} }

View File

@ -1,6 +1,7 @@
use std::{cmp::Ordering, collections::HashMap}; use std::{cmp::Ordering, collections::HashMap};
use bimap::BiHashMap; use bimap::BiHashMap;
use serde::{Deserialize, Serialize};
use crate::{ use crate::{
board::mesadata::AccessMesadata, board::mesadata::AccessMesadata,
@ -19,7 +20,7 @@ use crate::{
math::Circle, math::Circle,
}; };
#[derive(Debug, Hash, Clone, PartialEq, Eq)] #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BandName(String, String); pub struct BandName(String, String);
impl BandName { impl BandName {
@ -151,6 +152,10 @@ impl<M: AccessMesadata> Board<M> {
self.node_to_pinname.get(&node) self.node_to_pinname.get(&node)
} }
pub fn band_bandname(&self, band: BandUid) -> Option<&BandName> {
self.band_bandname.get_by_left(&band)
}
pub fn try_set_band_between_nodes( pub fn try_set_band_between_nodes(
&mut self, &mut self,
source: FixedDotIndex, source: FixedDotIndex,