diff --git a/crates/specctra-core/src/mesadata.rs b/crates/specctra-core/src/mesadata.rs index 305d596..7ba0a22 100644 --- a/crates/specctra-core/src/mesadata.rs +++ b/crates/specctra-core/src/mesadata.rs @@ -168,7 +168,6 @@ impl SpecctraMesadata { /// 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 { self.net_netclass .get(&net) @@ -179,10 +178,10 @@ impl SpecctraMesadata { impl AccessRules for SpecctraMesadata { fn clearance(&self, conditions1: &Conditions<'_>, conditions2: &Conditions<'_>) -> f64 { - let clr1 = self.get_rule(conditions1.net).clearance; - let clr2 = self.get_rule(conditions2.net).clearance; + let clearance1 = self.get_rule(conditions1.net).clearance; + let clearance2 = self.get_rule(conditions2.net).clearance; - f64::max(clr1, clr2) + f64::max(clearance1, clearance2) } fn largest_clearance(&self, _maybe_net: Option) -> f64 { diff --git a/src/autorouter/presorter.rs b/src/autorouter/presorter.rs index 0f1e817..38f4234 100644 --- a/src/autorouter/presorter.rs +++ b/src/autorouter/presorter.rs @@ -63,10 +63,10 @@ impl SccIntersectionsAndLengthPresorter { && a.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1) { a_length += ratline.ref_(autorouter).length(); - a_intersector_count += ratline - .ref_(autorouter) - .interior_obstacle_ratlines() - .count(); + a_intersector_count += + ratline.ref_(autorouter).interiorly_cut_ratlines().count(); + a_intersector_count += + ratline.ref_(autorouter).cut_other_net_primitives().count(); } } @@ -75,10 +75,10 @@ impl SccIntersectionsAndLengthPresorter { && b.contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1) { b_length += ratline.ref_(autorouter).length(); - b_intersector_count += ratline - .ref_(autorouter) - .interior_obstacle_ratlines() - .count(); + b_intersector_count += + ratline.ref_(autorouter).interiorly_cut_ratlines().count(); + b_intersector_count += + ratline.ref_(autorouter).cut_other_net_primitives().count(); } } diff --git a/src/autorouter/ratline.rs b/src/autorouter/ratline.rs index 3efbda9..d32a452 100644 --- a/src/autorouter/ratline.rs +++ b/src/autorouter/ratline.rs @@ -7,8 +7,12 @@ use petgraph::graph::{EdgeIndex, NodeIndex}; use specctra_core::mesadata::AccessMesadata; use crate::{ - drawing::{band::BandTermsegIndex, dot::FixedDotIndex}, - geometry::shape::MeasureLength, + drawing::{ + band::BandTermsegIndex, + dot::FixedDotIndex, + graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex}, + }, + geometry::{shape::MeasureLength, GetLayer}, graph::MakeRef, triangulation::GetTrianvertexNodeIndex, }; @@ -84,16 +88,40 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { (source_dot, target_dot) } - pub fn closure_obstacle_ratlines(&self) -> impl Iterator + '_ { - self.intersecting_ratlines() + pub fn layer(&self) -> usize { + self.endpoint_dots() + .0 + .primitive(self.autorouter.board().layout().drawing()) + .layer() } - pub fn interior_obstacle_ratlines(&self) -> impl Iterator + '_ { - self.intersecting_ratlines() - .filter(|index| !self.is_pin_cutter(*index)) + pub fn net(&self) -> usize { + self.endpoint_dots() + .0 + .primitive(self.autorouter.board().layout().drawing()) + .maybe_net() + .unwrap() } - fn intersecting_ratlines(&self) -> impl Iterator + '_ { + fn cut_primitives(&self) -> impl Iterator + '_ { + self.autorouter + .board() + .layout() + .drawing() + .cut(self.line_segment(), 0.0, self.layer()) + } + + pub fn cut_other_net_primitives(&self) -> impl Iterator + '_ { + self.cut_primitives().filter(|primitive_node| { + primitive_node + .primitive(self.autorouter.board().layout().drawing()) + .maybe_net() + .map(|net| net != self.net()) + .unwrap_or(true) + }) + } + + pub fn interiorly_cut_ratlines(&self) -> impl Iterator + '_ { let self_line_segment = self.line_segment(); self.autorouter @@ -112,29 +140,18 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { .filter(move |other| { let other_line_segment = other.ref_(self.autorouter).line_segment(); - line_intersection(self_line_segment, other_line_segment).is_some() + if let Some(LineIntersection::SinglePoint { is_proper, .. }) = + line_intersection(self_line_segment, other_line_segment) + { + // It would make more sense to check for non-internality only in + // self, but this gives me the result I want too for now. + !is_proper + } else { + false + } }) } - fn is_pin_cutter(&self, other: RatlineIndex) -> bool { - // TODO: For now, instead of detecting whether endpoint ratvertex pins - // are cut, we only check if the intersection between self and the - // supposed cutter is not internal. - - let self_line_segment = self.line_segment(); - let other_line_segment = other.ref_(self.autorouter).line_segment(); - - if let Some(LineIntersection::SinglePoint { is_proper, .. }) = - line_intersection(self_line_segment, other_line_segment) - { - // It would make more sense to check for non-internality only in - // self, but this gives me the result I want too for now. - !is_proper - } else { - false - } - } - pub fn line_segment(&self) -> Line { let (source, target) = self.endpoint_indices(); let source_pos = self diff --git a/src/drawing/query.rs b/src/drawing/query.rs index eb75772..6b11cca 100644 --- a/src/drawing/query.rs +++ b/src/drawing/query.rs @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: MIT +use geo::Line; use petgraph::visit::Walker; use specctra_core::rules::GetConditions; @@ -11,7 +12,10 @@ use crate::{ primitive::MakePrimitiveShape, Collision, Infringement, }, - geometry::{primitive::AccessPrimitiveShape, GenericNode, GetLayer}, + geometry::{ + primitive::{AccessPrimitiveShape, PrimitiveShape, SegShape}, + GenericNode, GetLayer, + }, graph::GenericIndex, }; @@ -112,6 +116,36 @@ impl Drawing { v } + pub fn cut( + &self, + line: Line, + width: f64, + layer: usize, + ) -> impl Iterator + '_ { + let limiting_shape = PrimitiveShape::Seg(SegShape { + from: line.start_point(), + to: line.end_point(), + width, + }) + .inflate(self.rules().largest_clearance(None)); + + self.recording_geometry_with_rtree() + .rtree() + .locate_in_envelope_intersecting(&limiting_shape.envelope_3d(width, layer)) + .filter_map(|wrapper| { + if let GenericNode::Primitive(primitive_node) = wrapper.data { + Some(primitive_node) + } else { + None + } + }) + .filter_map(move |primitive_node| { + limiting_shape + .intersects(&primitive_node.primitive(self).shape()) + .then_some(primitive_node) + }) + } + pub(super) fn find_infringement_except<'a>( &'a self, infringer: PrimitiveIndex, diff --git a/src/geometry/primitive.rs b/src/geometry/primitive.rs index 11701fd..ea532e3 100644 --- a/src/geometry/primitive.rs +++ b/src/geometry/primitive.rs @@ -38,6 +38,7 @@ pub trait AccessPrimitiveShape: AccessShape + GetWidth { [ envelope.upper()[0], envelope.upper()[1], + // XXX: Why isn't floating point infinity used here? (layer_count - 1) as f64, ], )