use std::collections::HashMap; use bimap::BiHashMap; use crate::{ board::mesadata::MesadataTrait, drawing::rules::{Conditions, RulesTrait}, dsn::structure::Pcb, }; #[derive(Debug)] pub struct DsnRule { pub width: f64, pub clearance: f64, } impl DsnRule { fn from_dsn(rule: &super::structure::Rule) -> Self { Self { width: rule.width as f64, clearance: rule.clearance_vec[0].value as f64, // picks the generic clearance only for now } } } #[derive(Debug)] pub struct DsnMesadata { structure_rule: DsnRule, // net class name -> rule class_rules: HashMap, // layername <-> layer for Layout pub layer_layername: BiHashMap, // netname <-> net for Layout pub net_netname: BiHashMap, // net -> netclass net_netclass: HashMap, } impl DsnMesadata { pub fn from_pcb(pcb: &Pcb) -> Self { let layer_layername = BiHashMap::from_iter( pcb.structure .layer_vec .iter() .map(|layer| (layer.property.index as u64, layer.name.clone())), ); // keeping this as a separate iter pass because it might be moved into a different struct later? let net_netname = BiHashMap::from_iter( pcb.network .class_vec .iter() .flat_map(|class| &class.net_vec) .enumerate() .map(|(net, netname)| (net, netname.clone())), ); let mut net_netclass = HashMap::new(); let class_rules = HashMap::from_iter( pcb.network .class_vec .iter() .inspect(|class| { for netname in &class.net_vec { let net = net_netname.get_by_right(netname).unwrap(); net_netclass.insert(*net, class.name.clone()); } }) .map(|class| (class.name.clone(), DsnRule::from_dsn(&class.rule))), ); Self { structure_rule: DsnRule::from_dsn(&pcb.structure.rule), class_rules, layer_layername, net_netname, net_netclass, } } pub fn get_rule(&self, net: usize) -> &DsnRule { if let Some(netclass) = self.net_netclass.get(&net) { self.class_rules .get(netclass) .unwrap_or(&self.structure_rule) } else { &self.structure_rule } } } impl RulesTrait for DsnMesadata { fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64 { let (Some(net1), Some(net2)) = (conditions1.maybe_net, conditions2.maybe_net) else { return 0.0; }; let clr1 = self.get_rule(net1).clearance; let clr2 = self.get_rule(net2).clearance; if clr1 > clr2 { clr1 } else { clr2 } } fn largest_clearance(&self, maybe_net: Option) -> f64 { let mut largest: f64 = 0.0; for (class, rule) in &self.class_rules { if rule.clearance > largest { largest = rule.clearance; } } largest } } impl MesadataTrait for DsnMesadata { fn bename_layer(&mut self, layer: u64, layername: String) { self.layer_layername.insert(layer, layername); } fn layer_layername(&self, layer: u64) -> Option<&str> { self.layer_layername.get_by_left(&layer).map(|s| s.as_str()) } fn layername_layer(&self, layername: &str) -> Option { self.layer_layername.get_by_right(layername).copied() } fn bename_net(&mut self, net: usize, netname: String) { self.net_netname.insert(net, netname); } fn net_netname(&self, net: usize) -> Option<&str> { self.net_netname.get_by_left(&net).map(|s| s.as_str()) } fn netname_net(&self, netname: &str) -> Option { self.net_netname.get_by_right(netname).copied() } }