layout: inflate infringement-testing shapes and bboxes

This results in unintentional infringements of linked traces. I'll fix
this in subsequent commits by increasing the number of
This commit is contained in:
Mikolaj Wielgus 2024-02-10 00:41:46 +00:00
parent b66995b30c
commit d5d2ffd9d8
4 changed files with 86 additions and 28 deletions

View File

@ -7,9 +7,10 @@ use crate::math::{self, Circle};
#[enum_dispatch] #[enum_dispatch]
pub trait ShapeTrait { pub trait ShapeTrait {
fn priority(&self) -> u64; fn priority(&self) -> u64;
fn inflate(&self, margin: f64) -> Shape;
fn center(&self) -> Point; fn center(&self) -> Point;
fn intersects(&self, other: &Shape) -> bool; 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 width(&self) -> f64;
fn length(&self) -> f64; fn length(&self) -> f64;
} }
@ -33,6 +34,15 @@ impl ShapeTrait for DotShape {
3 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 { fn center(&self) -> Point {
self.c.pos 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( 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 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 { fn center(&self) -> Point {
(self.from + self.to) / 2.0 (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 let points: Vec<[f64; 2]> = self
.polygon() .polygon()
.exterior() .exterior()
.points() .points()
.map(|p| [p.x(), p.y()]) .map(|p| [p.x(), p.y()])
.collect(); .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 { fn width(&self) -> f64 {
@ -203,6 +235,18 @@ impl ShapeTrait for BendShape {
1 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 { fn center(&self) -> Point {
let sum = (self.from - self.c.pos) + (self.to - self.c.pos); 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 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; let halfwidth = self.c.r + self.width;
AABB::from_corners( AABB::from_corners(
[self.c.pos.x() - halfwidth, self.c.pos.y() - halfwidth], [self.c.pos.x() - halfwidth, self.c.pos.y() - halfwidth],
@ -258,6 +302,9 @@ impl ShapeTrait for BendShape {
} }
fn length(&self) -> f64 { 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. // 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); let d = self.to.euclidean_distance(&self.from);
@ -272,6 +319,6 @@ impl ShapeTrait for BendShape {
impl RTreeObject for Shape { impl RTreeObject for Shape {
type Envelope = AABB<[f64; 2]>; type Envelope = AABB<[f64; 2]>;
fn envelope(&self) -> Self::Envelope { fn envelope(&self) -> Self::Envelope {
return ShapeTrait::envelope(self); return ShapeTrait::envelope(self, 0.0);
} }
} }

View File

@ -901,20 +901,33 @@ impl<R: RulesTrait> Layout<R> {
node: GeometryIndex, node: GeometryIndex,
except: &[GeometryIndex], except: &[GeometryIndex],
) -> Option<Infringement> { ) -> Option<Infringement> {
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 self.geometry_with_rtree
.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| !self.are_connectable(node, wrapper.data))
.filter(|wrapper| !except.contains(&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) .map(|wrapper| wrapper.data)
.next() .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().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()))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))]
fn detect_collision(&self, node: GeometryIndex) -> Option<Collision> { fn detect_collision(&self, node: GeometryIndex) -> Option<Collision> {

View File

@ -16,10 +16,5 @@ pub struct Conditions {
pub trait RulesTrait { pub trait RulesTrait {
fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64; fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64;
/*fn clearance_limit( fn clearance_net_limit(&self, net: i64) -> f64;
&self,
layer: String,
netclass: String,
conditions: &PrimitiveConditions,
) -> f64;*/
} }

View File

@ -70,14 +70,17 @@ impl RulesTrait for SimpleRules {
.unwrap_or(&10.0) .unwrap_or(&10.0)
} }
/*fn clearance_limit( fn clearance_net_limit(&self, net: i64) -> f64 {
&self, let mut highest_clearance = 0.0;
_layer: String,
_netclass: String, for ((net1, net2), clearance) in self.net_clearances.iter() {
_conditions: &PrimitiveConditions, if *net1 == net || *net2 == net {
) -> f64 { highest_clearance = *clearance;
3.0 }
}*/ }
highest_clearance
}
} }
// Clunky enum to work around borrow checker. // 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); 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 // 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 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); let bottomright = vec2f(envelope.upper()[0] as f32, envelope.upper()[1] as f32);