mirror of https://codeberg.org/topola/topola.git
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:
parent
b66995b30c
commit
d5d2ffd9d8
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
21
src/main.rs
21
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue