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]
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);
}
}

View File

@ -901,20 +901,33 @@ impl<R: RulesTrait> Layout<R> {
node: GeometryIndex,
except: &[GeometryIndex],
) -> 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
.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<Collision> {

View File

@ -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;
}

View File

@ -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);