mirror of https://codeberg.org/topola/topola.git
feat(autorouter/ratsnest): Have one terminating dot for each layer of ratvertex
Some routes projects still crash while autorouting, but we are progressing.
This commit is contained in:
parent
d53aa2a678
commit
b50e58b0fa
|
|
@ -11,17 +11,18 @@ use specctra_core::mesadata::AccessMesadata;
|
|||
|
||||
use crate::{
|
||||
autorouter::{ratline::RatlineIndex, Autorouter},
|
||||
board::edit::BoardEdit,
|
||||
drawing::{
|
||||
dot::FixedDotIndex,
|
||||
graph::{GetMaybeNet, MakePrimitiveRef},
|
||||
primitive::MakePrimitiveShape,
|
||||
},
|
||||
geometry::GetLayer,
|
||||
geometry::{GenericNode, GetLayer},
|
||||
graph::{GenericIndex, GetIndex, MakeRef},
|
||||
layout::{
|
||||
poly::{MakePolygon, PolyWeight},
|
||||
via::ViaWeight,
|
||||
CompoundWeight, LayoutEdit,
|
||||
CompoundWeight,
|
||||
},
|
||||
math::Circle,
|
||||
};
|
||||
|
|
@ -53,15 +54,23 @@ impl Anterouter {
|
|||
let endpoint_indices = ratline.ref_(autorouter).endpoint_indices();
|
||||
let endpoint_dots = ratline.ref_(autorouter).endpoint_dots();
|
||||
|
||||
autorouter
|
||||
.ratsnest
|
||||
.assign_layer_to_ratline(*ratline, *layer);
|
||||
|
||||
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::ExistingFixedDot(terminating_dot) => {
|
||||
autorouter.ratsnest.assign_terminating_dot_to_ratvertex(
|
||||
endpoint_indices.0,
|
||||
*layer,
|
||||
*terminating_dot,
|
||||
)
|
||||
}
|
||||
TerminatingScheme::Anteroute(pin_bbox_to_anchor) => self
|
||||
.anteroute_dot_to_anchor(
|
||||
autorouter,
|
||||
|
|
@ -79,9 +88,13 @@ impl Anterouter {
|
|||
.get(&endpoint_dots.1)
|
||||
{
|
||||
match terminating_scheme {
|
||||
TerminatingScheme::ExistingFixedDot(terminating_dot) => autorouter
|
||||
.ratsnest
|
||||
.assign_terminating_dot_to_ratvertex(endpoint_indices.1, *terminating_dot),
|
||||
TerminatingScheme::ExistingFixedDot(terminating_dot) => {
|
||||
autorouter.ratsnest.assign_terminating_dot_to_ratvertex(
|
||||
endpoint_indices.1,
|
||||
*layer,
|
||||
*terminating_dot,
|
||||
)
|
||||
}
|
||||
TerminatingScheme::Anteroute(pin_bbox_to_anchor) => self
|
||||
.anteroute_dot_to_anchor(
|
||||
autorouter,
|
||||
|
|
@ -170,10 +183,10 @@ impl Anterouter {
|
|||
|
||||
//let via_bbox_to_anchor = [-pin_bbox_to_anchor[0], -pin_bbox_to_anchor[1]];
|
||||
|
||||
let mut layout_edit = LayoutEdit::new();
|
||||
let mut board_edit = BoardEdit::new();
|
||||
|
||||
if let Ok((.., dots)) = autorouter.board.layout_mut().add_via(
|
||||
&mut layout_edit,
|
||||
if let Ok((.., dots)) = autorouter.board.add_via(
|
||||
&mut board_edit,
|
||||
ViaWeight {
|
||||
from_layer: std::cmp::min(pin_layer, to_layer),
|
||||
to_layer: std::cmp::max(pin_layer, to_layer),
|
||||
|
|
@ -183,6 +196,10 @@ impl Anterouter {
|
|||
},
|
||||
maybe_net: pin_maybe_net,
|
||||
},
|
||||
autorouter
|
||||
.board()
|
||||
.node_pinname(&GenericNode::Primitive(dot.into()))
|
||||
.cloned(),
|
||||
) {
|
||||
let terminating_dot = dots
|
||||
.iter()
|
||||
|
|
@ -193,9 +210,11 @@ impl Anterouter {
|
|||
.layer()
|
||||
})
|
||||
.unwrap();
|
||||
autorouter
|
||||
.ratsnest
|
||||
.assign_terminating_dot_to_ratvertex(ratvertex, *terminating_dot);
|
||||
autorouter.ratsnest.assign_terminating_dot_to_ratvertex(
|
||||
ratvertex,
|
||||
to_layer,
|
||||
*terminating_dot,
|
||||
);
|
||||
}
|
||||
/*let bbox = if let Some(poly) = autorouter.board().layout().drawing().geometry().compounds(dot).find(|(_, compound_weight)| {
|
||||
matches!(compound_weight, CompoundWeight::Poly(..))
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ use geo::Point;
|
|||
use petgraph::graph::NodeIndex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use spade::InsertionError;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::collections::BTreeSet;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
autorouter::{
|
||||
anterouter::AnterouterPlan, multilayer_autoroute::MultilayerAutorouteExecutionStepper,
|
||||
multilayer_autoroute::MultilayerAutorouteExecutionStepper,
|
||||
permutator::PlanarAutorouteExecutionPermutator, planner::Planner,
|
||||
},
|
||||
board::{AccessMesadata, Board},
|
||||
|
|
@ -213,22 +213,22 @@ impl<M: AccessMesadata> Autorouter<M> {
|
|||
active_layer,
|
||||
allowed_edges,
|
||||
ratlines.into_iter().filter_map(|ratline| {
|
||||
let (source, target) = ratline.ref_(self).terminating_dots();
|
||||
let (origin, destination) = ratline.ref_(self).terminating_dots();
|
||||
|
||||
if navmesh
|
||||
.as_ref()
|
||||
.node_data(&NavmeshIndex::Primal(source))
|
||||
.node_data(&NavmeshIndex::Primal(origin))
|
||||
.is_none()
|
||||
|| navmesh
|
||||
.as_ref()
|
||||
.node_data(&NavmeshIndex::Primal(target))
|
||||
.node_data(&NavmeshIndex::Primal(destination))
|
||||
.is_none()
|
||||
{
|
||||
// e.g. due to wrong active layer
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.board.band_between_nodes(source, target).is_some() {
|
||||
if self.board.band_between_nodes(origin, destination).is_some() {
|
||||
// already connected
|
||||
return None;
|
||||
}
|
||||
|
|
@ -236,8 +236,8 @@ impl<M: AccessMesadata> Autorouter<M> {
|
|||
got_any_valid_goals = true;
|
||||
|
||||
Some(ng::Goal {
|
||||
source,
|
||||
target,
|
||||
source: origin,
|
||||
target: destination,
|
||||
width,
|
||||
})
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ impl<M: AccessMesadata + Clone> ExecutionStepper<M> {
|
|||
for (ep, band) in &autoroute.last_bands {
|
||||
let (source, target) = ep.end_points.into();
|
||||
autorouter.board.try_set_band_between_nodes(
|
||||
&mut autoroute.last_recorder.data_edit,
|
||||
&mut autoroute.last_recorder.board_data_edit,
|
||||
source,
|
||||
target,
|
||||
*band,
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, PlanarAutorouteCo
|
|||
self.curr_ratline_index += 1;
|
||||
|
||||
if let Some(new_ratline) = self.ratlines.get(self.curr_ratline_index) {
|
||||
let (source, target) = new_ratline.ref_(autorouter).terminating_dots();
|
||||
let (origin, destination) = new_ratline.ref_(autorouter).terminating_dots();
|
||||
let mut router =
|
||||
Router::new(autorouter.board.layout_mut(), self.options.router_options);
|
||||
|
||||
|
|
@ -216,8 +216,8 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, PlanarAutorouteCo
|
|||
|
||||
self.route = Some(router.route(
|
||||
recorder,
|
||||
source,
|
||||
target,
|
||||
origin,
|
||||
destination,
|
||||
self.options.router_options.routed_band_width,
|
||||
)?);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ impl Planner {
|
|||
None
|
||||
}
|
||||
})
|
||||
.map_or(TerminatingScheme::Anteroute([-1.0, -1.0]), |dot| {
|
||||
.map_or(TerminatingScheme::Anteroute([-2.0, 0.0]), |dot| {
|
||||
TerminatingScheme::ExistingFixedDot(dot)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
dot::FixedDotIndex,
|
||||
graph::{GetMaybeNet, MakePrimitiveRef, PrimitiveIndex},
|
||||
},
|
||||
geometry::{shape::MeasureLength, GetLayer},
|
||||
geometry::shape::MeasureLength,
|
||||
graph::MakeRef,
|
||||
triangulation::GetTrianvertexNodeIndex,
|
||||
};
|
||||
|
|
@ -23,6 +23,7 @@ pub type RatlineIndex = EdgeIndex<usize>;
|
|||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct RatlineWeight {
|
||||
pub layer: usize,
|
||||
pub band_termseg: Option<BandTermsegIndex>,
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +103,9 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> {
|
|||
.graph()
|
||||
.node_weight(source)
|
||||
.unwrap()
|
||||
.maybe_terminating_dot
|
||||
.layer_terminating_dots
|
||||
.get(&self.layer())
|
||||
.copied()
|
||||
.unwrap_or(self.endpoint_dots().0);
|
||||
let target_dot = self
|
||||
.autorouter
|
||||
|
|
@ -110,17 +113,25 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> {
|
|||
.graph()
|
||||
.node_weight(target)
|
||||
.unwrap()
|
||||
.maybe_terminating_dot
|
||||
.layer_terminating_dots
|
||||
.get(&self.layer())
|
||||
.copied()
|
||||
.unwrap_or(self.endpoint_dots().1);
|
||||
|
||||
(source_dot, target_dot)
|
||||
}
|
||||
|
||||
pub fn layer(&self) -> usize {
|
||||
self.endpoint_dots()
|
||||
.0
|
||||
.primitive_ref(self.autorouter.board().layout().drawing())
|
||||
.layer()
|
||||
self.autorouter
|
||||
.ratsnest()
|
||||
.graph()
|
||||
.edge_weight(self.index)
|
||||
.unwrap()
|
||||
.layer
|
||||
/*self.endpoint_dots()
|
||||
.0
|
||||
.primitive_ref(self.autorouter.board().layout().drawing())
|
||||
.layer()*/
|
||||
}
|
||||
|
||||
pub fn net(&self) -> usize {
|
||||
|
|
|
|||
|
|
@ -48,11 +48,11 @@ impl From<RatvertexNodeIndex> for crate::layout::NodeIndex {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RatvertexWeight {
|
||||
vertex: RatvertexNodeIndex,
|
||||
pub pos: Point,
|
||||
pub maybe_terminating_dot: Option<FixedDotIndex>,
|
||||
pub layer_terminating_dots: BTreeMap<usize, FixedDotIndex>,
|
||||
}
|
||||
|
||||
impl GetTrianvertexNodeIndex<RatvertexNodeIndex> for RatvertexWeight {
|
||||
|
|
@ -118,11 +118,11 @@ impl Ratsnest {
|
|||
|
||||
let mut triangulations = BTreeMap::new();
|
||||
|
||||
this.add_layer_to_ratsnest(board, &mut triangulations, principal_layer);
|
||||
this.add_layer_to_ratsnest_triangulations(board, &mut triangulations, principal_layer);
|
||||
|
||||
for layer in 0..board.layout().drawing().layer_count() {
|
||||
if layer != principal_layer {
|
||||
this.add_layer_to_ratsnest(board, &mut triangulations, layer);
|
||||
this.add_layer_to_ratsnest_triangulations(board, &mut triangulations, layer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ impl Ratsnest {
|
|||
Ok(this)
|
||||
}
|
||||
|
||||
fn add_layer_to_ratsnest(
|
||||
fn add_layer_to_ratsnest_triangulations(
|
||||
&mut self,
|
||||
board: &Board<impl AccessMesadata>,
|
||||
triangulations: &mut BTreeMap<
|
||||
|
|
@ -190,7 +190,7 @@ impl Ratsnest {
|
|||
triangulation.add_vertex(RatvertexWeight {
|
||||
vertex,
|
||||
pos,
|
||||
maybe_terminating_dot: None,
|
||||
layer_terminating_dots: BTreeMap::new(),
|
||||
})?;
|
||||
Ok(())
|
||||
};
|
||||
|
|
@ -229,12 +229,18 @@ impl Ratsnest {
|
|||
pub fn assign_terminating_dot_to_ratvertex(
|
||||
&mut self,
|
||||
node_index: NodeIndex<usize>,
|
||||
layer: usize,
|
||||
terminating_dot: FixedDotIndex,
|
||||
) {
|
||||
self.graph
|
||||
.node_weight_mut(node_index)
|
||||
.unwrap()
|
||||
.maybe_terminating_dot = Some(terminating_dot)
|
||||
.layer_terminating_dots
|
||||
.insert(layer, terminating_dot);
|
||||
}
|
||||
|
||||
pub fn assign_layer_to_ratline(&mut self, ratline: RatlineIndex, layer: usize) {
|
||||
self.graph.edge_weight_mut(ratline).unwrap().layer = layer;
|
||||
}
|
||||
|
||||
pub fn assign_band_termseg_to_ratline(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ impl Edit for BoardDataEdit {
|
|||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct BoardEdit {
|
||||
pub data_edit: BoardDataEdit,
|
||||
pub board_data_edit: BoardDataEdit,
|
||||
pub layout_edit: LayoutEdit,
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ impl BoardEdit {
|
|||
|
||||
pub fn new_from_edits(data_edit: BoardDataEdit, layout_edit: LayoutEdit) -> Self {
|
||||
Self {
|
||||
data_edit,
|
||||
board_data_edit: data_edit,
|
||||
layout_edit,
|
||||
}
|
||||
}
|
||||
|
|
@ -48,12 +48,12 @@ impl BoardEdit {
|
|||
|
||||
impl Edit for BoardEdit {
|
||||
fn reverse_inplace(&mut self) {
|
||||
self.data_edit.reverse_inplace();
|
||||
self.board_data_edit.reverse_inplace();
|
||||
self.layout_edit.reverse_inplace();
|
||||
}
|
||||
|
||||
fn merge(&mut self, edit: Self) {
|
||||
self.data_edit.merge(edit.data_edit);
|
||||
self.board_data_edit.merge(edit.board_data_edit);
|
||||
self.layout_edit.merge(edit.layout_edit);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ use crate::{
|
|||
dot::{FixedDotIndex, FixedDotWeight},
|
||||
graph::PrimitiveIndex,
|
||||
seg::{FixedSegIndex, FixedSegWeight},
|
||||
DrawingException,
|
||||
DrawingException, Infringement,
|
||||
},
|
||||
geometry::{edit::ApplyGeometryEdit, GenericNode, GetLayer},
|
||||
graph::{GenericIndex, MakeRef},
|
||||
layout::{poly::PolyWeight, CompoundWeight, Layout, NodeIndex},
|
||||
layout::{poly::PolyWeight, via::ViaWeight, CompoundWeight, Layout, NodeIndex},
|
||||
router::ng::EtchedPath,
|
||||
};
|
||||
|
||||
|
|
@ -105,6 +105,24 @@ impl<M> Board<M> {
|
|||
}
|
||||
|
||||
impl<M: AccessMesadata> Board<M> {
|
||||
pub fn add_via(
|
||||
&mut self,
|
||||
recorder: &mut BoardEdit,
|
||||
weight: ViaWeight,
|
||||
maybe_pin: Option<String>,
|
||||
) -> Result<(GenericIndex<ViaWeight>, Vec<FixedDotIndex>), Infringement> {
|
||||
let (weight, dots) = self.layout.add_via(&mut recorder.layout_edit, weight)?;
|
||||
|
||||
if let Some(pin) = maybe_pin {
|
||||
for dot in dots.clone() {
|
||||
self.pinname_nodes
|
||||
.insert(pin.clone(), GenericNode::Primitive(dot.into()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok((weight, dots))
|
||||
}
|
||||
|
||||
/// Adds a new fixed dot with an optional pin name.
|
||||
///
|
||||
/// Inserts the dot into the layout and, if a pin name is provided, maps it to the created dot's node.
|
||||
|
|
@ -295,7 +313,7 @@ impl<M: AccessMesadata> Board<M> {
|
|||
}
|
||||
|
||||
recorder
|
||||
.data_edit
|
||||
.board_data_edit
|
||||
.bands
|
||||
.insert(bandname, (maybe_band, None));
|
||||
|
||||
|
|
@ -328,7 +346,7 @@ impl<M: AccessMesadata> Board<M> {
|
|||
}
|
||||
|
||||
pub fn apply_edit(&mut self, edit: &BoardEdit) {
|
||||
for (bandname, (maybe_old_band_uid, ..)) in &edit.data_edit.bands {
|
||||
for (bandname, (maybe_old_band_uid, ..)) in &edit.board_data_edit.bands {
|
||||
if maybe_old_band_uid.is_some() {
|
||||
self.band_bandname.remove_by_right(bandname);
|
||||
}
|
||||
|
|
@ -336,7 +354,7 @@ impl<M: AccessMesadata> Board<M> {
|
|||
|
||||
self.layout_mut().apply(&edit.layout_edit);
|
||||
|
||||
for (bandname, (.., maybe_new_band_uid)) in &edit.data_edit.bands {
|
||||
for (bandname, (.., maybe_new_band_uid)) in &edit.board_data_edit.bands {
|
||||
if let Some(band_uid) = maybe_new_band_uid {
|
||||
self.band_bandname.insert(*band_uid, bandname.clone());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ impl<
|
|||
|
||||
pub fn remove_primitive(&mut self, primitive: PI) {
|
||||
let maybe_removed = self.graph.remove_node(primitive.index().into());
|
||||
debug_assert!(maybe_removed.is_some());
|
||||
assert!(maybe_removed.is_some());
|
||||
}
|
||||
|
||||
pub fn move_dot(&mut self, dot: DI, to: Point) {
|
||||
|
|
@ -356,7 +356,7 @@ impl<
|
|||
.find(|edge| matches!(edge.weight(), GeometryLabel::Outer))
|
||||
{
|
||||
let maybe_removed = self.graph.remove_edge(old_inner_edge.id());
|
||||
debug_assert!(maybe_removed.is_some());
|
||||
assert!(maybe_removed.is_some());
|
||||
}
|
||||
|
||||
if let Some(new_inner) = maybe_new_inner {
|
||||
|
|
@ -656,7 +656,7 @@ impl<PW: Copy + Retag<Index = PI>, DW, SW, BW, CW: Clone, Cel: Copy, PI: Copy, D
|
|||
|
||||
fn remove_compound(&mut self, compound: GenericIndex<CW>) {
|
||||
let maybe_removed = self.graph.remove_node(compound.index().into());
|
||||
debug_assert!(maybe_removed.is_some());
|
||||
assert!(maybe_removed.is_some());
|
||||
}
|
||||
|
||||
fn add_to_compound<I>(&mut self, primitive: I, entry_label: Cel, compound: GenericIndex<CW>)
|
||||
|
|
|
|||
|
|
@ -192,6 +192,8 @@ impl Prenavmesh {
|
|||
let primitive = node.primitive_ref(layout.drawing());
|
||||
|
||||
let Some(primitive_net) = primitive.maybe_net() else {
|
||||
assert_ne!(node, origin.into());
|
||||
assert_ne!(node, destination.into());
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -215,6 +217,10 @@ impl Prenavmesh {
|
|||
// false positives in some cases, so in the future, instead of this,
|
||||
// create a fillet compound type and check for compound membership.
|
||||
if Self::is_fixed_dot_filleted(layout, dot) {
|
||||
// FIXME: anteroute dot may get skipped here, which
|
||||
// results in a panic.
|
||||
assert_ne!(origin, dot);
|
||||
assert_ne!(destination, dot);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue