mirror of https://codeberg.org/topola/topola.git
182 lines
6.2 KiB
Rust
182 lines
6.2 KiB
Rust
// SPDX-FileCopyrightText: 2025 Topola contributors
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
use derive_getters::{Dissolve, Getters};
|
|
use enum_dispatch::enum_dispatch;
|
|
use petgraph::{algo::tarjan_scc, graph::NodeIndex};
|
|
use specctra_core::mesadata::AccessMesadata;
|
|
|
|
use crate::{
|
|
autorouter::{ratline::RatlineIndex, Autorouter},
|
|
geometry::shape::MeasureLength,
|
|
graph::MakeRef,
|
|
};
|
|
|
|
#[enum_dispatch]
|
|
pub trait PresortRatlines {
|
|
fn presort_ratlines(
|
|
&self,
|
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
|
ratlines: &[RatlineIndex],
|
|
) -> Vec<RatlineIndex>;
|
|
}
|
|
|
|
#[enum_dispatch(PresortRatlines)]
|
|
pub enum RatlinesPresorter {
|
|
SccIntersectionsLength(SccIntersectionsAndLengthPresorter),
|
|
}
|
|
|
|
#[derive(Getters, Dissolve)]
|
|
pub struct SccIntersectionsAndLengthPresorter {
|
|
sccs: Vec<Vec<NodeIndex<usize>>>,
|
|
}
|
|
|
|
impl SccIntersectionsAndLengthPresorter {
|
|
pub fn new(
|
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
|
ratlines: &[RatlineIndex],
|
|
) -> Self {
|
|
// FIXME: Unnecessary copy.
|
|
let mut filtered_ratsnest = autorouter.ratsnest().graph().clone();
|
|
filtered_ratsnest.retain_edges(|_g, i| ratlines.contains(&i));
|
|
|
|
let mut sccs = tarjan_scc(&filtered_ratsnest);
|
|
|
|
sccs.sort_unstable_by(|a, b| {
|
|
// FIXME: These calculations should probably be stored somewhere
|
|
// instead of being done every time.
|
|
|
|
let mut a_intersector_count = 0;
|
|
let mut b_intersector_count = 0;
|
|
let mut a_length = 0.0;
|
|
let mut b_length = 0.0;
|
|
|
|
// FIXME: It's inefficient to iterate over the ratlines on every
|
|
// sort comparison. But this is the simplest solution I arrived
|
|
// at after realizing that `.tarjan_scc(...)` does not sort nodes
|
|
// inside components.
|
|
for ratline in ratlines.iter() {
|
|
if a.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().0)
|
|
&& a.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1)
|
|
{
|
|
a_length += ratline.ref_(autorouter).length();
|
|
a_intersector_count +=
|
|
ratline.ref_(autorouter).interiorly_cut_ratlines().count();
|
|
a_intersector_count +=
|
|
ratline.ref_(autorouter).cut_other_net_primitives().count();
|
|
}
|
|
}
|
|
|
|
for ratline in ratlines.iter() {
|
|
if b.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().0)
|
|
&& b.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1)
|
|
{
|
|
b_length += ratline.ref_(autorouter).length();
|
|
b_intersector_count +=
|
|
ratline.ref_(autorouter).interiorly_cut_ratlines().count();
|
|
b_intersector_count +=
|
|
ratline.ref_(autorouter).cut_other_net_primitives().count();
|
|
}
|
|
}
|
|
|
|
let primary_ordering = a_intersector_count.cmp(&b_intersector_count);
|
|
|
|
if primary_ordering != Ordering::Equal {
|
|
primary_ordering
|
|
} else {
|
|
let secondary_ordering = a_length.total_cmp(&b_length);
|
|
|
|
secondary_ordering
|
|
}
|
|
|
|
// Below is how I tried to do this before I realized that
|
|
// `.tarjan_scc(...)` does not sort nodes inside components.
|
|
|
|
/*let a_intersector_count: usize = a
|
|
.windows(2)
|
|
.map(|window| {
|
|
let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap();
|
|
ratline
|
|
.ref_(autorouter)
|
|
.interior_obstacle_ratlines()
|
|
.count()
|
|
})
|
|
.sum();
|
|
let b_intersector_count: usize = b
|
|
.windows(2)
|
|
.map(|window| {
|
|
let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap();
|
|
ratline
|
|
.ref_(autorouter)
|
|
.interior_obstacle_ratlines()
|
|
.count()
|
|
})
|
|
.sum();
|
|
|
|
let primary_ordering = a_intersector_count.cmp(&b_intersector_count);
|
|
|
|
if primary_ordering != Ordering::Equal {
|
|
primary_ordering
|
|
} else {
|
|
let a_length: f64 = a
|
|
.windows(2)
|
|
.map(|window| {
|
|
let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap();
|
|
ratline.ref_(autorouter).length()
|
|
})
|
|
.sum();
|
|
let b_length: f64 = b
|
|
.windows(2)
|
|
.map(|window| {
|
|
let ratline = filtered_ratsnest.find_edge(window[0], window[1]).unwrap();
|
|
ratline.ref_(autorouter).length()
|
|
})
|
|
.sum();
|
|
|
|
let secondary_ordering = a_length.total_cmp(&b_length);
|
|
|
|
secondary_ordering
|
|
}*/
|
|
});
|
|
|
|
Self { sccs }
|
|
}
|
|
}
|
|
|
|
impl PresortRatlines for SccIntersectionsAndLengthPresorter {
|
|
fn presort_ratlines(
|
|
&self,
|
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
|
ratlines: &[RatlineIndex],
|
|
) -> Vec<RatlineIndex> {
|
|
let mut presorted_ratlines = vec![];
|
|
|
|
for scc in self.sccs.iter() {
|
|
for ratline in ratlines.iter() {
|
|
if scc.contains(
|
|
&autorouter
|
|
.ratsnest()
|
|
.graph()
|
|
.edge_endpoints(*ratline)
|
|
.unwrap()
|
|
.0,
|
|
) && scc.contains(
|
|
&autorouter
|
|
.ratsnest()
|
|
.graph()
|
|
.edge_endpoints(*ratline)
|
|
.unwrap()
|
|
.1,
|
|
) {
|
|
presorted_ratlines.push(*ratline);
|
|
}
|
|
}
|
|
}
|
|
|
|
presorted_ratlines
|
|
}
|
|
}
|