diff --git a/src/layout/geometry/shape.rs b/src/layout/geometry/shape.rs index 7bfc7de..9ff939e 100644 --- a/src/layout/geometry/shape.rs +++ b/src/layout/geometry/shape.rs @@ -7,9 +7,10 @@ use crate::math::{self, Circle}; #[enum_dispatch] pub trait ShapeTrait { fn priority(&self) -> u64; + fn inflate(&self, margin: f64) -> Shape; fn center(&self) -> Point; fn intersects(&self, other: &Shape) -> bool; - fn envelope(&self) -> AABB<[f64; 2]>; + fn envelope(&self, margin: f64) -> AABB<[f64; 2]>; fn width(&self) -> f64; fn length(&self) -> f64; } @@ -33,6 +34,15 @@ impl ShapeTrait for DotShape { 3 } + fn inflate(&self, margin: f64) -> Shape { + Shape::Dot(DotShape { + c: Circle { + pos: self.c.pos, + r: self.c.r + margin, + }, + }) + } + fn center(&self) -> Point { self.c.pos } @@ -63,10 +73,16 @@ impl ShapeTrait for DotShape { } } - fn envelope(&self) -> AABB<[f64; 2]> { + fn envelope(&self, margin: f64) -> AABB<[f64; 2]> { AABB::from_corners( - [self.c.pos.x() - self.c.r, self.c.pos.y() - self.c.r], - [self.c.pos.x() + self.c.r, self.c.pos.y() + self.c.r], + [ + self.c.pos.x() - self.c.r - margin, + self.c.pos.y() - self.c.r - margin, + ], + [ + self.c.pos.x() + self.c.r + margin, + self.c.pos.y() + self.c.r + margin, + ], ) } @@ -108,6 +124,16 @@ impl ShapeTrait for SegShape { 2 } + fn inflate(&self, margin: f64) -> Shape { + let mag = (self.to - self.from).euclidean_distance(&point! {x: 0.0, y: 0.0}); + + Shape::Seg(SegShape { + from: self.from + (self.from - self.to) / mag * margin, + to: self.to + (self.to - self.from) / mag * margin, + width: self.width + 2.0 * margin, + }) + } + fn center(&self) -> Point { (self.from + self.to) / 2.0 } @@ -143,14 +169,20 @@ impl ShapeTrait for SegShape { } } - fn envelope(&self) -> AABB<[f64; 2]> { + fn envelope(&self, margin: f64) -> AABB<[f64; 2]> { let points: Vec<[f64; 2]> = self .polygon() .exterior() .points() .map(|p| [p.x(), p.y()]) .collect(); - AABB::<[f64; 2]>::from_points(points.iter()) + + let aabb = AABB::<[f64; 2]>::from_points(points.iter()); + + // Inflate. + let lower = [aabb.lower()[0] - margin, aabb.lower()[1] - margin]; + let upper = [aabb.upper()[0] + margin, aabb.upper()[1] + margin]; + AABB::<[f64; 2]>::from_corners(lower, upper) } fn width(&self) -> f64 { @@ -203,6 +235,18 @@ impl ShapeTrait for BendShape { 1 } + fn inflate(&self, margin: f64) -> Shape { + Shape::Bend(BendShape { + from: self.from, // TODO: Is not inflated for now. + to: self.to, // TODO: Is not inflated for now. + c: Circle { + pos: self.c.pos, + r: self.c.r - margin, + }, + width: self.width + 2.0 * margin, + }) + } + fn center(&self) -> Point { let sum = (self.from - self.c.pos) + (self.to - self.c.pos); self.c.pos + (sum / sum.euclidean_distance(&point! {x: 0.0, y: 0.0})) * self.c.r @@ -245,7 +289,7 @@ impl ShapeTrait for BendShape { } } - fn envelope(&self) -> AABB<[f64; 2]> { + fn envelope(&self, margin: f64) -> AABB<[f64; 2]> { let halfwidth = self.c.r + self.width; AABB::from_corners( [self.c.pos.x() - halfwidth, self.c.pos.y() - halfwidth], @@ -258,6 +302,9 @@ impl ShapeTrait for BendShape { } fn length(&self) -> f64 { + // TODO: Not valid for inflated bends, as currently `from` and `to` of these don't lie on + // teir circles. + // We obtain the angle from the law of cosines and multiply with radius to get the length. let d = self.to.euclidean_distance(&self.from); @@ -272,6 +319,6 @@ impl ShapeTrait for BendShape { impl RTreeObject for Shape { type Envelope = AABB<[f64; 2]>; fn envelope(&self) -> Self::Envelope { - return ShapeTrait::envelope(self); + return ShapeTrait::envelope(self, 0.0); } } diff --git a/src/layout/layout.rs b/src/layout/layout.rs index f23ff93..d43c8da 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -901,20 +901,33 @@ impl Layout { node: GeometryIndex, except: &[GeometryIndex], ) -> Option { - let shape = node.primitive(self).shape(); + let limiting_shape = node + .primitive(self) + .shape() + .inflate(self.rules.clearance_net_limit(node.primitive(self).net())); + let mut inflated_shape = limiting_shape; // Unused temporary value just for initialization. + let conditions = node.primitive(self).conditions(); self.geometry_with_rtree .rtree() - .locate_in_envelope_intersecting(&RTreeObject::envelope(&shape)) + .locate_in_envelope_intersecting(&RTreeObject::envelope(&limiting_shape)) .filter(|wrapper| !self.are_connectable(node, wrapper.data)) .filter(|wrapper| !except.contains(&wrapper.data)) - .filter(|wrapper| shape.intersects(wrapper.geom())) + .filter(|wrapper| { + let infringee_conditions = wrapper.data.primitive(self).conditions(); + + inflated_shape = node + .primitive(self) + .shape() + .inflate(self.rules.clearance(&conditions, &infringee_conditions)); + + inflated_shape.intersects(wrapper.geom()) + }) .map(|wrapper| wrapper.data) .next() - .and_then(|infringee| Some(Infringement(shape, infringee))) + .and_then(|infringee| Some(Infringement(inflated_shape, infringee))) } - // TODO: Collision and infringement are the same for now. Change this. #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] fn detect_collision(&self, node: GeometryIndex) -> Option { diff --git a/src/layout/rules.rs b/src/layout/rules.rs index 7a657af..b46dcbd 100644 --- a/src/layout/rules.rs +++ b/src/layout/rules.rs @@ -16,10 +16,5 @@ pub struct Conditions { pub trait RulesTrait { fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64; - /*fn clearance_limit( - &self, - layer: String, - netclass: String, - conditions: &PrimitiveConditions, - ) -> f64;*/ + fn clearance_net_limit(&self, net: i64) -> f64; } diff --git a/src/main.rs b/src/main.rs index 44a0445..2f59ac3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,14 +70,17 @@ impl RulesTrait for SimpleRules { .unwrap_or(&10.0) } - /*fn clearance_limit( - &self, - _layer: String, - _netclass: String, - _conditions: &PrimitiveConditions, - ) -> f64 { - 3.0 - }*/ + fn clearance_net_limit(&self, net: i64) -> f64 { + let mut highest_clearance = 0.0; + + for ((net1, net2), clearance) in self.net_clearances.iter() { + if *net1 == net || *net2 == net { + highest_clearance = *clearance; + } + } + + highest_clearance + } } // Clunky enum to work around borrow checker. @@ -805,7 +808,7 @@ fn render_shape(canvas: &mut CanvasRenderingContext2D, shape: &Shape, color: Col canvas.stroke_path(path); } } - let envelope = ShapeTrait::envelope(shape); + let envelope = ShapeTrait::envelope(shape, 0.0); // XXX: points represented as arrays can't be conveniently converted to vector types let topleft = vec2f(envelope.lower()[0] as f32, envelope.lower()[1] as f32); let bottomright = vec2f(envelope.upper()[0] as f32, envelope.upper()[1] as f32);