feat(drawing/query): Don't infringe or collide primitives on different layers

This commit is contained in:
Mikolaj Wielgus 2025-09-22 01:27:08 +02:00
parent f4b78749b1
commit 00aa79ff31
5 changed files with 25 additions and 20 deletions

View File

@ -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<f64> {
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<usize>) -> f64 {

View File

@ -26,11 +26,10 @@ pub struct Conditions<'a> {
#[serde(borrow)]
pub maybe_region: Option<Cow<'a, str>>,
#[serde(borrow)]
pub maybe_layer: Option<Cow<'a, str>>,
pub maybe_layer: Option<usize>,
}
pub trait AccessRules {
fn clearance(&self, conditions1: &Conditions<'_>, conditions2: &Conditions<'_>) -> f64;
fn clearance(&self, conditions1: &Conditions<'_>, conditions2: &Conditions<'_>) -> Option<f64>;
fn largest_clearance(&self, net: Option<usize>) -> f64;
}

View File

@ -195,7 +195,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
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),
}
}

View File

@ -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<Conditions<'a>> {
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()),
})
}
}

View File

@ -228,12 +228,16 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
&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<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
})
.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) {