use std::collections::HashMap; use crate::{ board::mesadata::MesadataTrait, drawing::{ band::BandIndex, dot::{FixedDotIndex, FixedDotWeight}, graph::{GetLayer, GetMaybeNet, PrimitiveIndex}, seg::{FixedSegIndex, FixedSegWeight}, Infringement, }, geometry::{shape::ShapeTrait, GenericNode}, graph::GenericIndex, layout::{ zone::{GetMaybeApex, MakePolyShape, ZoneWeight}, Layout, NodeIndex, }, math::Circle, router::{navmesh::Navmesh, Router, RouterError, RouterObserverTrait}, }; #[derive(Debug)] pub struct Board { layout: Layout, node_to_pinname: HashMap, pinname_pair_to_band: HashMap<(String, String), BandIndex>, } impl Board { pub fn new(layout: Layout) -> Self { Self { layout, node_to_pinname: HashMap::new(), pinname_pair_to_band: HashMap::new(), } } pub fn add_fixed_dot_infringably( &mut self, weight: FixedDotWeight, maybe_pin: Option, ) -> FixedDotIndex { let dot = self.layout.add_fixed_dot_infringably(weight); if let Some(ref pin) = maybe_pin { self.node_to_pinname .insert(GenericNode::Primitive(dot.into()), pin.clone()); } dot } pub fn add_zone_fixed_dot_infringably( &mut self, weight: FixedDotWeight, zone: GenericIndex, ) -> FixedDotIndex { let dot = self.layout.add_zone_fixed_dot_infringably(weight, zone); if let Some(pin) = self.node_pinname(GenericNode::Compound(zone.into())) { self.node_to_pinname .insert(GenericNode::Primitive(dot.into()), pin.to_string()); } dot } pub fn add_fixed_seg_infringably( &mut self, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, maybe_pin: Option, ) -> FixedSegIndex { let seg = self.layout.add_fixed_seg_infringably(from, to, weight); if let Some(pin) = maybe_pin { self.node_to_pinname .insert(GenericNode::Primitive(seg.into()), pin.to_string()); } seg } pub fn add_zone_fixed_seg_infringably( &mut self, from: FixedDotIndex, to: FixedDotIndex, weight: FixedSegWeight, zone: GenericIndex, ) -> FixedSegIndex { let seg = self .layout .add_zone_fixed_seg_infringably(from, to, weight, zone); if let Some(pin) = self.node_pinname(GenericNode::Compound(zone.into())) { self.node_to_pinname .insert(GenericNode::Primitive(seg.into()), pin.to_string()); } seg } pub fn add_zone( &mut self, weight: ZoneWeight, maybe_pin: Option, ) -> GenericIndex { let zone = self.layout.add_zone(weight); if let Some(pin) = maybe_pin { self.node_to_pinname .insert(GenericNode::Compound(zone.into()), pin.to_string()); } zone } pub fn route_band( &mut self, navmesh: Navmesh, width: f64, observer: &mut impl RouterObserverTrait, ) -> Result { let source_pinname = self .node_pinname(GenericNode::Primitive(navmesh.source().into())) .unwrap() .to_string(); let target_pinname = self .node_pinname(GenericNode::Primitive(navmesh.target().into())) .unwrap() .to_string(); let mut router = Router::new_from_navmesh(self.layout_mut(), navmesh); let result = router.route_band(100.0, observer); if let Ok(band) = result { self.pinname_pair_to_band .insert((source_pinname, target_pinname), band); } result } pub fn zone_apex(&mut self, zone: GenericIndex) -> FixedDotIndex { if let Some(apex) = self.layout.zone(zone).maybe_apex() { apex } else { self.add_zone_fixed_dot_infringably( FixedDotWeight { circle: Circle { pos: self.layout.zone(zone).shape().center(), r: 100.0, }, layer: self.layout.zone(zone).layer(), maybe_net: self.layout.zone(zone).maybe_net(), }, zone, ) } } pub fn node_pinname(&self, node: NodeIndex) -> Option<&String> { self.node_to_pinname.get(&node) } pub fn band_between_pins(&self, pinname1: &str, pinname2: &str) -> Option { if let Some(band) = self .pinname_pair_to_band .get(&(pinname1.to_string(), pinname2.to_string())) { Some(*band) } else if let Some(band) = self .pinname_pair_to_band .get(&(pinname2.to_string(), pinname1.to_string())) { Some(*band) } else { None } } pub fn layout(&self) -> &Layout { &self.layout } pub fn layout_mut(&mut self) -> &mut Layout { &mut self.layout } }