diff --git a/src/bin/topola-sdl2-demo/main.rs b/src/bin/topola-sdl2-demo/main.rs index 12cf93c..f36e54a 100644 --- a/src/bin/topola-sdl2-demo/main.rs +++ b/src/bin/topola-sdl2-demo/main.rs @@ -61,7 +61,7 @@ impl RulesTrait for SimpleRules { .unwrap_or(&10.0) } - fn clearance_net_limit(&self, net: i64) -> f64 { + fn largest_clearance(&self, net: i64) -> f64 { let mut highest_clearance = 0.0; for ((net1, net2), clearance) in self.net_clearances.iter() { diff --git a/src/dsn/design.rs b/src/dsn/design.rs index df90382..55b63e1 100644 --- a/src/dsn/design.rs +++ b/src/dsn/design.rs @@ -8,41 +8,38 @@ use crate::{ use super::{ de::{from_str, Error}, structure::Pcb, + rules::Rules, }; #[derive(Debug)] pub struct DsnDesign { pcb: Pcb, + rules: Rules, } impl DsnDesign { pub fn load_from_file(filename: &str) -> Result { let contents = std::fs::read_to_string(filename).unwrap(); // TODO: remove unwrap. + let pcb = from_str::(&contents)?; + + let rules = Rules::from_pcb(&pcb); Ok(Self { - pcb: from_str::(&contents)?, + pcb, + rules, }) } - pub fn make_layout(&self) -> Layout<&Pcb> { - let mut layout = Layout::new(&self.pcb); - - // this holds the mapping of net names to numerical IDs (here for now) - let net_ids: HashMap = HashMap::from_iter( - self.pcb.network.classes[0] - .nets - .iter() - .enumerate() - .map(|(id, net)| (net.clone(), id)), - ); + pub fn make_layout(&self) -> Layout<&Rules> { + let mut layout = Layout::new(&self.rules); // mapping of pin id -> net id prepared for adding pins let pin_nets = if let Some(nets) = self.pcb.network.nets.as_ref() { - HashMap::::from_iter( + HashMap::::from_iter( nets.iter() .map(|net| { // resolve the id so we don't work with strings - let net_id = net_ids.get(&net.name).unwrap(); + let net_id = self.rules.net_ids.get(&net.name).unwrap(); // take the list of pins // and for each pin id output (pin id, net id) @@ -52,7 +49,7 @@ impl DsnDesign { .flatten(), ) } else { - HashMap::::new() + HashMap::::new() }; // add pins from components @@ -70,7 +67,7 @@ impl DsnDesign { for pin in &image.pins { let pin_name = format!("{}-{}", place.name, pin.id); let net_id = pin_nets.get(&pin_name).unwrap(); - let continent = layout.add_continent(*net_id as i64); + let continent = layout.add_continent(*net_id); let padstack = &self .pcb @@ -102,8 +99,8 @@ impl DsnDesign { .vias .iter() .map(|via| { - let net_id = net_ids.get(&via.net.0).unwrap(); - let continent = layout.add_continent(*net_id as i64); + let net_id = self.rules.net_ids.get(&via.net.0).unwrap(); + let continent = layout.add_continent(*net_id); // find the padstack referenced by this via placement let padstack = &self @@ -128,8 +125,8 @@ impl DsnDesign { .collect(); for wire in self.pcb.wiring.wires.iter() { - let net_id = net_ids.get(&wire.net.0).unwrap(); - let continent = layout.add_continent(*net_id as i64); + let net_id = self.rules.net_ids.get(&wire.net.0).unwrap(); + let continent = layout.add_continent(*net_id); // add the first coordinate in the wire path as a dot and save its index let mut prev_index = layout diff --git a/src/dsn/rules.rs b/src/dsn/rules.rs index 5fcef0d..ef172f5 100644 --- a/src/dsn/rules.rs +++ b/src/dsn/rules.rs @@ -1,15 +1,97 @@ +use std::collections::HashMap; + use crate::layout::rules::{Conditions, RulesTrait}; use super::structure::Pcb; -impl<'a> RulesTrait for &'a Pcb { - fn clearance(&self, _conditions1: &Conditions, _conditions2: &Conditions) -> f64 { - // Placeholder for now. - 10.0 - } +#[derive(Debug)] +pub struct Rule { + pub width: f64, + pub clearance: f64, +} - fn clearance_net_limit(&self, _net: i64) -> f64 { - // Placeholder for now. - 10.0 +impl Rule { + fn from_dsn(rule: &super::structure::Rule) -> Self { + Self { + width: rule.width.0 as f64 / 100.0, + clearance: rule.clearances[0].value as f64 / 100.0, // picks the generic clearance only for now + } + } +} + +#[derive(Debug)] +pub struct Rules { + structure_rule: Rule, + // net class name -> rule + class_rules: HashMap, + + // net names -> net IDs for Layout + pub net_ids: HashMap, + // net ID -> net class + net_id_classes: HashMap, +} + +impl Rules { + pub fn from_pcb(pcb: &Pcb) -> Self { + let net_ids = HashMap::from_iter( + pcb.network.classes[0] + .nets + .iter() + .enumerate() + .map(|(id, net)| (net.clone(), id as i64)), + ); + + let mut net_id_classes = HashMap::new(); + let class_rules = HashMap::from_iter( + pcb.network.classes + .iter() + .inspect(|class| { + for net in &class.nets { + let net_id = net_ids.get(net).unwrap(); + net_id_classes.insert(*net_id, class.name.clone()); + } + }) + .map(|class| (class.name.clone(), Rule::from_dsn(&class.rule))) + ); + + Self { + structure_rule: Rule::from_dsn(&pcb.structure.rule), + class_rules, + net_ids, + net_id_classes, + } + } + + pub fn get_rule(&self, net: i64) -> &Rule { + if let Some(netclass) = self.net_id_classes.get(&net) { + self.class_rules.get(netclass).unwrap_or(&self.structure_rule) + } else { + &self.structure_rule + } + } +} + +impl<'a> RulesTrait for &'a Rules { + fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64 { + let clr1 = self.get_rule(conditions1.net).clearance; + let clr2 = self.get_rule(conditions2.net).clearance; + + if clr1 > clr2 { + clr1 + } else { + clr2 + } + } + + fn largest_clearance(&self, _net: i64) -> f64 { + let mut largest: f64 = 0.0; + + for (class, rule) in &self.class_rules { + if rule.clearance > largest { + largest = rule.clearance; + } + } + + largest } } diff --git a/src/layout/layout.rs b/src/layout/layout.rs index 57e1184..75e9c73 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -796,7 +796,7 @@ impl Layout { let limiting_shape = node .primitive(self) .shape() - .inflate(self.rules.clearance_net_limit(node.primitive(self).net())); + .inflate(self.rules.largest_clearance(node.primitive(self).net())); let mut inflated_shape = limiting_shape; // Unused temporary value just for initialization. let conditions = node.primitive(self).conditions(); diff --git a/src/layout/rules.rs b/src/layout/rules.rs index b46dcbd..094fab0 100644 --- a/src/layout/rules.rs +++ b/src/layout/rules.rs @@ -16,5 +16,5 @@ pub struct Conditions { pub trait RulesTrait { fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64; - fn clearance_net_limit(&self, net: i64) -> f64; + fn largest_clearance(&self, net: i64) -> f64; }