1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
// Copyright (c) 2020-2021 Thomas Kramer.
// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
//! Air wire router for visualizing component connectivity. Does not create a legal routing.
use crate::route::simple_router::{SimpleRoutedNet, SimpleRouter};
use libreda_db::layout::types::SInt;
use libreda_db::prelude::{Path, Point, Rect, SimpleRPolygon, TryBoundingBox};
use std::collections::HashMap;
/// Router that creates air wires between routing terminals in a star-topology.
/// This does not produce a legal routing and has
/// the only purpose to visualize the connectivity of components.
pub struct AirWireRouter {
/// Layer for the air wires.
air_wire_layer: u8,
/// Wire thickness.
wire_thickness: SInt,
/// Draw a full mesh instead of a star network.
full_mesh: bool,
}
impl AirWireRouter {
/// Create a default router.
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();
// Of each pin take the first terminal shape.
let terminals: Vec<_> = pins.iter().filter_map(|t| t.first()).collect();
// Compute the center of the terminals.
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
};
// Get some representative points of the terminals.
let terminal_points: Vec<_> = terminals
.iter()
// Get a point close to the center of all terminal shapes.
.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 {
// Draw star-network.
// Get the center of weight to create a star topology.
let sum: Point<_> = terminal_points.iter().copied().sum();
let center = sum / terminal_points.len() as SInt;
// Draw star network.
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
}
}