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 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()
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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))?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue