From 00aa79ff3120073f34448401a848626ac44711fd Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Mon, 22 Sep 2025 01:27:08 +0200 Subject: [PATCH] feat(drawing/query): Don't infringe or collide primitives on different layers --- crates/specctra-core/src/mesadata.rs | 20 +++++++++----------- crates/specctra-core/src/rules.rs | 5 ++--- src/drawing/guide.rs | 2 +- src/drawing/primitive.rs | 6 +++--- src/drawing/query.rs | 12 ++++++++++-- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/crates/specctra-core/src/mesadata.rs b/crates/specctra-core/src/mesadata.rs index 7ba0a22..8ceb6fc 100644 --- a/crates/specctra-core/src/mesadata.rs +++ b/crates/specctra-core/src/mesadata.rs @@ -162,13 +162,7 @@ impl SpecctraMesadata { } } - /// Retrieves the Specctra routing rule associated with a specified net ID. - /// - /// This function looks up the routing rule for a given net ID. It first checks if the net is - /// associated with a net class. If a net class is found, it retrieves the corresponding rule - /// from the class rules. If no class is associated, or if the class does not have a defined rule, - /// it defaults to the general structure rule. - pub fn get_rule(&self, net: usize) -> &SpecctraRule { + pub fn rule(&self, net: usize) -> &SpecctraRule { self.net_netclass .get(&net) .and_then(|netclass| self.class_rules.get(netclass)) @@ -177,11 +171,15 @@ impl SpecctraMesadata { } impl AccessRules for SpecctraMesadata { - fn clearance(&self, conditions1: &Conditions<'_>, conditions2: &Conditions<'_>) -> f64 { - let clearance1 = self.get_rule(conditions1.net).clearance; - let clearance2 = self.get_rule(conditions2.net).clearance; + fn clearance(&self, conditions1: &Conditions<'_>, conditions2: &Conditions<'_>) -> Option { + if conditions1.maybe_layer != conditions2.maybe_layer { + return None; + } - f64::max(clearance1, clearance2) + let clearance1 = self.rule(conditions1.net).clearance; + let clearance2 = self.rule(conditions2.net).clearance; + + Some(f64::max(clearance1, clearance2)) } fn largest_clearance(&self, _maybe_net: Option) -> f64 { diff --git a/crates/specctra-core/src/rules.rs b/crates/specctra-core/src/rules.rs index 2336838..d23e392 100644 --- a/crates/specctra-core/src/rules.rs +++ b/crates/specctra-core/src/rules.rs @@ -26,11 +26,10 @@ pub struct Conditions<'a> { #[serde(borrow)] pub maybe_region: Option>, - #[serde(borrow)] - pub maybe_layer: Option>, + pub maybe_layer: Option, } pub trait AccessRules { - fn clearance(&self, conditions1: &Conditions<'_>, conditions2: &Conditions<'_>) -> f64; + fn clearance(&self, conditions1: &Conditions<'_>, conditions2: &Conditions<'_>) -> Option; fn largest_clearance(&self, net: Option) -> f64; } diff --git a/src/drawing/guide.rs b/src/drawing/guide.rs index 23ca707..4e045d7 100644 --- a/src/drawing/guide.rs +++ b/src/drawing/guide.rs @@ -195,7 +195,7 @@ impl Drawing { fn clearance(&self, lhs: Option<&Conditions<'_>>, rhs: Option<&Conditions<'_>>) -> f64 { match (lhs, rhs) { (None, _) | (_, None) => 0.0, - (Some(lhs), Some(rhs)) => self.rules().clearance(lhs, rhs), + (Some(lhs), Some(rhs)) => self.rules().clearance(lhs, rhs).unwrap_or(0.0), } } diff --git a/src/drawing/primitive.rs b/src/drawing/primitive.rs index 78a518a..0b88e42 100644 --- a/src/drawing/primitive.rs +++ b/src/drawing/primitive.rs @@ -219,13 +219,13 @@ where impl<'a, W, CW, Cel, R> GetConditions<'a> for &GenericPrimitive<'a, W, CW, Cel, R> where - GenericPrimitive<'a, W, CW, Cel, R>: GetMaybeNet, + GenericPrimitive<'a, W, CW, Cel, R>: GetMaybeNet + GetLayer, { fn conditions(self) -> Option> { self.maybe_net().map(|net| Conditions { net, - maybe_region: Some("A".into()), - maybe_layer: Some("F.Cu".into()), + maybe_region: Some("A".into()), // TODO. + maybe_layer: Some(self.layer()), }) } } diff --git a/src/drawing/query.rs b/src/drawing/query.rs index b7feea2..58b3ae9 100644 --- a/src/drawing/query.rs +++ b/src/drawing/query.rs @@ -228,12 +228,16 @@ impl Drawing { &conditions, infringee_conditions, ) { - (None, _) | (_, None) => 0.0, + (None, _) | (_, None) => return None, (Some(lhs), Some(rhs)) => { + let Some(clearance) = self.rules().clearance(lhs, &rhs) else { + return None; + }; + // Note the epsilon comparison. // XXX: Epsilon is probably too large. But what should // it be exactly then? - (self.rules().clearance(lhs, &rhs) - epsilon).clamp(0.0, f64::INFINITY) + (clearance - epsilon).clamp(0.0, f64::INFINITY) } }); @@ -298,6 +302,10 @@ impl Drawing { }) .filter(|collidee| predicate(&self, collider, *collidee)) .find_map(|collidee| { + if collider.primitive_ref(self).layer() != collidee.primitive_ref(self).layer() { + return None; + } + let collidee_shape = collidee.primitive_ref(self).shape(); if collider_shape.intersects(&collidee_shape) {