use libreda_db::layout::types::{SInt};
use crate::route::simple_router::{SimpleRouter, SimpleRoutedNet};
use libreda_db::prelude::{SimpleRPolygon, Point, Path, Rect, TryBoundingBox};
use std::collections::HashMap;
pub struct AirWireRouter {
air_wire_layer: u8,
wire_thickness: SInt,
full_mesh: bool,
}
impl AirWireRouter {
pub fn new(air_wire_layer: u8, wire_thickness: SInt, full_mesh: bool) -> Self {
Self {
air_wire_layer,
wire_thickness,
full_mesh,
}
}
}
impl SimpleRouter for AirWireRouter {
fn name(&self) -> &str {
"AirWireRouter"
}
fn compute_routes_impl(&self,
_boundary: Rect<SInt>,
net_terminals: &HashMap<usize, Vec<Vec<(SimpleRPolygon<SInt>, u8)>>>,
_obstacles: &Vec<(SimpleRPolygon<SInt>, u8)>,
) -> HashMap<usize, SimpleRoutedNet> {
let mut result = HashMap::new();
for (net, pins) in net_terminals {
let mut net_wires = Vec::new();
let terminals: Vec<_> = pins.iter()
.filter_map(|t| t.first())
.collect();
let center = {
let mut num_elements = 0;
let sum: Point<_> = terminals.iter()
.filter_map(|(t, _)| t.try_bounding_box())
.map(|b| b.center())
.inspect(|_| num_elements += 1)
.sum();
sum / num_elements
};
let terminal_points: Vec<_> = terminals.iter()
.filter_map(|(t, _layer)| t.points()
.min_by_key(|&p| (p-center).norm1()))
.collect();
if self.full_mesh {
for (i, a) in terminal_points.iter().enumerate() {
for b in &terminal_points[i..] {
let ray = Path::new(vec![*a, *b], self.wire_thickness);
net_wires.push((self.air_wire_layer, ray.into()))
}
}
} else {
let sum: Point<_> = terminal_points.iter().copied().sum();
let center = sum / terminal_points.len() as SInt;
for p in terminal_points {
let ray = Path::new(vec![p, center], self.wire_thickness);
net_wires.push((self.air_wire_layer, ray.into()))
}
}
let routed_net = SimpleRoutedNet {
routes: net_wires,
vias: Default::default(),
};
result.insert(*net, routed_net);
}
result
}
}