mirror of https://codeberg.org/topola/topola.git
autorouter: split selection into pin selection and band selection
This commit is contained in:
parent
3bf4d2cdb1
commit
b568f2d790
|
|
@ -3,12 +3,6 @@ use spade::InsertionError;
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
autorouter::{
|
||||
autoroute::Autoroute,
|
||||
place_via::PlaceVia,
|
||||
ratsnest::{Ratsnest, RatvertexIndex},
|
||||
selection::Selection,
|
||||
},
|
||||
board::{mesadata::AccessMesadata, Board},
|
||||
drawing::{dot::FixedDotIndex, Infringement},
|
||||
layout::via::ViaWeight,
|
||||
|
|
@ -16,6 +10,13 @@ use crate::{
|
|||
triangulation::GetTrianvertexNodeIndex,
|
||||
};
|
||||
|
||||
use super::{
|
||||
autoroute::Autoroute,
|
||||
place_via::PlaceVia,
|
||||
ratsnest::{Ratsnest, RatvertexIndex},
|
||||
selection::{BandSelection, PinSelection},
|
||||
};
|
||||
|
||||
#[derive(Error, Debug, Clone)]
|
||||
pub enum AutorouterError {
|
||||
#[error("nothing to route")]
|
||||
|
|
@ -44,7 +45,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
|||
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)?;
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
pub fn undo_autoroute(&mut self, selection: &Selection) {
|
||||
pub fn undo_autoroute(&mut self, selection: &PinSelection) {
|
||||
for ratline in self.selected_ratlines(selection).iter() {
|
||||
let band = self
|
||||
.ratsnest
|
||||
|
|
@ -120,7 +124,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
|||
(source_dot, target_dot)
|
||||
}
|
||||
|
||||
fn selected_ratlines(&self, selection: &Selection) -> Vec<EdgeIndex<usize>> {
|
||||
fn selected_ratlines(&self, selection: &PinSelection) -> Vec<EdgeIndex<usize>> {
|
||||
self.ratsnest
|
||||
.graph()
|
||||
.edge_indices()
|
||||
|
|
|
|||
|
|
@ -4,13 +4,6 @@ use serde::{Deserialize, Serialize};
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
autorouter::{
|
||||
autoroute::Autoroute,
|
||||
history::{History, HistoryError},
|
||||
place_via::PlaceVia,
|
||||
selection::Selection,
|
||||
Autorouter, AutorouterError, AutorouterStatus,
|
||||
},
|
||||
board::mesadata::AccessMesadata,
|
||||
drawing::graph::PrimitiveIndex,
|
||||
geometry::primitive::PrimitiveShape,
|
||||
|
|
@ -18,6 +11,14 @@ use crate::{
|
|||
router::{navmesh::Navmesh, trace::Trace},
|
||||
};
|
||||
|
||||
use super::{
|
||||
autoroute::Autoroute,
|
||||
history::{History, HistoryError},
|
||||
place_via::PlaceVia,
|
||||
selection::{BandSelection, PinSelection},
|
||||
Autorouter, AutorouterError, AutorouterStatus,
|
||||
};
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait GetMaybeNavmesh {
|
||||
fn maybe_navmesh(&self) -> Option<&Navmesh>;
|
||||
|
|
@ -54,7 +55,7 @@ pub enum InvokerStatus {
|
|||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Command {
|
||||
Autoroute(Selection),
|
||||
Autoroute(PinSelection),
|
||||
PlaceVia(ViaWeight),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::collections::HashSet;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
board::{mesadata::AccessMesadata, Board},
|
||||
board::{mesadata::AccessMesadata, BandName, Board},
|
||||
drawing::{
|
||||
band::BandUid,
|
||||
graph::{GetLayer, MakePrimitive, PrimitiveIndex},
|
||||
|
|
@ -14,117 +14,28 @@ use crate::{
|
|||
};
|
||||
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Selector {
|
||||
pub struct PinSelector {
|
||||
pin: String,
|
||||
layer: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Selection {
|
||||
selectors: HashSet<Selector>,
|
||||
#[serde(skip)]
|
||||
selected_bands: HashSet<BandUid>,
|
||||
pub struct PinSelection {
|
||||
selectors: HashSet<PinSelector>,
|
||||
}
|
||||
|
||||
impl Selection {
|
||||
impl PinSelection {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
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(
|
||||
&self,
|
||||
board: &Board<impl AccessMesadata>,
|
||||
node: NodeIndex,
|
||||
) -> Option<Selector> {
|
||||
) -> Option<PinSelector> {
|
||||
let layer = match node {
|
||||
NodeIndex::Primitive(primitive) => {
|
||||
primitive.primitive(board.layout().drawing()).layer()
|
||||
|
|
@ -146,7 +57,7 @@ impl Selection {
|
|||
board.node_pinname(node),
|
||||
board.layout().rules().layer_layername(layer),
|
||||
) {
|
||||
Some(Selector {
|
||||
Some(PinSelector {
|
||||
pin: pinname.to_string(),
|
||||
layer: layername.to_string(),
|
||||
})
|
||||
|
|
@ -154,4 +65,108 @@ impl Selection {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,7 +207,8 @@ impl Top {
|
|||
let selection = overlay.selection().clone();
|
||||
overlay.clear_selection();
|
||||
maybe_execute.insert(ExecuteWithStatus::new(
|
||||
invoker.execute_walk(Command::Autoroute(selection))?,
|
||||
invoker
|
||||
.execute_walk(Command::Autoroute(selection.pin_selection))?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::{cmp::Ordering, collections::HashMap};
|
||||
|
||||
use bimap::BiHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
board::mesadata::AccessMesadata,
|
||||
|
|
@ -19,7 +20,7 @@ use crate::{
|
|||
math::Circle,
|
||||
};
|
||||
|
||||
#[derive(Debug, Hash, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BandName(String, String);
|
||||
|
||||
impl BandName {
|
||||
|
|
@ -151,6 +152,10 @@ impl<M: AccessMesadata> Board<M> {
|
|||
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(
|
||||
&mut self,
|
||||
source: FixedDotIndex,
|
||||
|
|
|
|||
Loading…
Reference in New Issue