layout,main: display attempted shapes that caused probe to fail

This commit is contained in:
Mikolaj Wielgus 2023-12-23 02:32:43 +00:00
parent da8af817bf
commit 81e316397f
2 changed files with 89 additions and 75 deletions

View File

@ -31,7 +31,7 @@ pub enum LayoutException {
NoTangents(NoTangents), NoTangents(NoTangents),
Infringement(Infringement), Infringement(Infringement),
Collision(Collision), Collision(Collision),
AreConnected(AreConnected), IsConnected(IsConnected),
} }
impl From<NoTangents> for LayoutException { impl From<NoTangents> for LayoutException {
@ -52,20 +52,20 @@ impl From<Collision> for LayoutException {
} }
} }
impl From<AreConnected> for LayoutException { impl From<IsConnected> for LayoutException {
fn from(err: AreConnected) -> Self { fn from(err: IsConnected) -> Self {
LayoutException::AreConnected(err) LayoutException::IsConnected(err)
} }
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Infringement(pub Index, pub Index); pub struct Infringement(pub Shape, pub Index);
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Collision(pub Index, pub Index); pub struct Collision(pub Shape, pub Index);
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct AreConnected(pub Weight, pub Index); pub struct IsConnected(pub i64, pub Index);
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Band { pub struct Band {
@ -562,9 +562,11 @@ impl Layout {
infringables: &[Index], infringables: &[Index],
) -> Result<LooseBendIndex, LayoutException> { ) -> Result<LooseBendIndex, LayoutException> {
// It makes no sense to wrap something around or under one of its connectables. // It makes no sense to wrap something around or under one of its connectables.
if self.bands[weight.band].net == around.primitive(self).net() { let net = self.bands[weight.band].net;
return Err(LayoutException::AreConnected(AreConnected( //
weight.into(), if net == around.primitive(self).net() {
return Err(LayoutException::IsConnected(IsConnected(
net,
around.into(), around.into(),
))); )));
} }
@ -574,9 +576,9 @@ impl Layout {
WraparoundableIndex::FixedBend(around) => self.primitive(around).wraparound(), WraparoundableIndex::FixedBend(around) => self.primitive(around).wraparound(),
WraparoundableIndex::LooseBend(around) => self.primitive(around).wraparound(), WraparoundableIndex::LooseBend(around) => self.primitive(around).wraparound(),
} { } {
if self.bands[weight.band].net == wraparound.primitive(self).net() { if net == wraparound.primitive(self).net() {
return Err(LayoutException::AreConnected(AreConnected( return Err(LayoutException::IsConnected(IsConnected(
weight.into(), net,
wraparound.into(), wraparound.into(),
))); )));
} }
@ -799,7 +801,7 @@ impl Layout {
.filter(|wrapper| shape.intersects(wrapper.geom())) .filter(|wrapper| shape.intersects(wrapper.geom()))
.map(|wrapper| wrapper.data) .map(|wrapper| wrapper.data)
.next() .next()
.and_then(|infringee| Some(Infringement(index, infringee))) .and_then(|infringee| Some(Infringement(shape, infringee)))
} }
// TODO: Collision and infringement are the same for now. Change this. // TODO: Collision and infringement are the same for now. Change this.
@ -815,7 +817,7 @@ impl Layout {
.filter(|wrapper| shape.intersects(wrapper.geom())) .filter(|wrapper| shape.intersects(wrapper.geom()))
.map(|wrapper| wrapper.data) .map(|wrapper| wrapper.data)
.next() .next()
.and_then(|collidee| Some(Collision(index, collidee))) .and_then(|collidee| Some(Collision(shape, collidee)))
} }
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))] #[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]

View File

@ -39,7 +39,7 @@ use sdl2::video::{GLProfile, Window};
use sdl2::EventPump; use sdl2::EventPump;
use shape::{Shape, ShapeTrait}; use shape::{Shape, ShapeTrait};
use pathfinder_canvas::{ArcDirection, ColorU, FillRule}; use pathfinder_canvas::{ArcDirection, CanvasRenderingContext2D, ColorU, FillRule};
use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D}; use pathfinder_canvas::{Canvas, CanvasFontContext, Path2D};
use pathfinder_geometry::rect::RectF; use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::{vec2f, vec2i}; use pathfinder_geometry::vector::{vec2f, vec2i};
@ -116,6 +116,7 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
Some(tracer.mesh.clone()), Some(tracer.mesh.clone()),
&trace.path, &trace.path,
&[], &[],
&[],
40, 40,
); );
} }
@ -134,6 +135,7 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
Some(tracer.mesh.clone()), Some(tracer.mesh.clone()),
&path, &path,
&[], &[],
&[],
10, 10,
); );
} }
@ -145,15 +147,13 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
_edge: MeshEdgeReference, _edge: MeshEdgeReference,
result: Result<(), DrawException>, result: Result<(), DrawException>,
) { ) {
let highlight = match result { let (ghosts, highlighteds, delay) = match result {
Err(DrawException::CannotWrapAround( Err(DrawException::CannotWrapAround(
.., ..,
LayoutException::Infringement(Infringement(.., infringee1)), LayoutException::Infringement(Infringement(shape1, infringee1)),
LayoutException::Infringement(Infringement(.., infringee2)), LayoutException::Infringement(Infringement(shape2, infringee2)),
)) => { )) => (vec![shape1, shape2], vec![infringee1, infringee2], 30),
vec![infringee1, infringee2] _ => (vec![], vec![], 10),
}
_ => vec![],
}; };
render_times( render_times(
@ -166,8 +166,9 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
None, None,
Some(tracer.mesh.clone()), Some(tracer.mesh.clone()),
&trace.path, &trace.path,
&highlight, &ghosts,
10, &highlighteds,
delay,
); );
} }
@ -500,6 +501,7 @@ fn main() {
None, None,
&[], &[],
&[], &[],
&[],
-1, -1,
); );
@ -532,6 +534,7 @@ fn main() {
None, None,
&[], &[],
&[], &[],
&[],
-1, -1,
); );
@ -552,6 +555,7 @@ fn main() {
None, None,
&[], &[],
&[], &[],
&[],
-1, -1,
); );
} }
@ -566,7 +570,8 @@ fn render_times(
follower: Option<LooseDotIndex>, follower: Option<LooseDotIndex>,
mut mesh: Option<Mesh>, mut mesh: Option<Mesh>,
path: &[VertexIndex], path: &[VertexIndex],
highlight: &[Index], ghosts: &[Shape],
highlighteds: &[Index],
times: i64, times: i64,
) { ) {
let mut i = 0; let mut i = 0;
@ -621,62 +626,18 @@ fn render_times(
//let result = panic::catch_unwind(|| { //let result = panic::catch_unwind(|| {
for node in layout.nodes() { for node in layout.nodes() {
let color = if highlight.contains(&node) { let color = if highlighteds.contains(&node) {
ColorU::new(255, 100, 100, 255) ColorU::new(255, 100, 100, 255)
} else { } else {
ColorU::new(200, 52, 52, 255) ColorU::new(200, 52, 52, 255)
}; };
canvas.set_stroke_style(color);
canvas.set_fill_style(color);
let shape = node.primitive(layout).shape(); let shape = node.primitive(layout).shape();
render_shape(&mut canvas, &shape, color);
}
match shape { for ghost in ghosts {
Shape::Dot(dot) => { render_shape(&mut canvas, &ghost, ColorU::new(75, 75, 150, 255));
let mut path = Path2D::new();
path.ellipse(
vec2f(dot.c.pos.x() as f32, dot.c.pos.y() as f32),
dot.c.r as f32,
0.0,
0.0,
std::f32::consts::TAU,
);
canvas.fill_path(path, FillRule::Winding);
}
Shape::Seg(seg) => {
let mut path = Path2D::new();
path.move_to(vec2f(seg.from.x() as f32, seg.from.y() as f32));
path.line_to(vec2f(seg.to.x() as f32, seg.to.y() as f32));
canvas.set_line_width(seg.width as f32);
canvas.stroke_path(path);
}
Shape::Bend(bend) => {
let delta1 = bend.from - bend.c.pos;
let delta2 = bend.to - bend.c.pos;
let angle1 = delta1.y().atan2(delta1.x());
let angle2 = delta2.y().atan2(delta2.x());
let mut path = Path2D::new();
path.arc(
vec2f(bend.c.pos.x() as f32, bend.c.pos.y() as f32),
bend.circle().r as f32,
angle1 as f32,
angle2 as f32,
ArcDirection::CW,
);
canvas.set_line_width(bend.width as f32);
canvas.stroke_path(path);
}
}
let envelope = ShapeTrait::envelope(&shape);
// 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);
canvas.set_line_width(1.0);
canvas.set_stroke_style(ColorU::new(100, 100, 100, 255));
canvas.stroke_rect(RectF::new(topleft, bottomright - topleft));
} }
if let Some(ref mesh) = mesh { if let Some(ref mesh) = mesh {
@ -723,3 +684,54 @@ fn render_times(
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
} }
} }
fn render_shape(canvas: &mut CanvasRenderingContext2D, shape: &Shape, color: ColorU) {
canvas.set_stroke_style(color);
canvas.set_fill_style(color);
match shape {
Shape::Dot(dot) => {
let mut path = Path2D::new();
path.ellipse(
vec2f(dot.c.pos.x() as f32, dot.c.pos.y() as f32),
dot.c.r as f32,
0.0,
0.0,
std::f32::consts::TAU,
);
canvas.fill_path(path, FillRule::Winding);
}
Shape::Seg(seg) => {
let mut path = Path2D::new();
path.move_to(vec2f(seg.from.x() as f32, seg.from.y() as f32));
path.line_to(vec2f(seg.to.x() as f32, seg.to.y() as f32));
canvas.set_line_width(seg.width as f32);
canvas.stroke_path(path);
}
Shape::Bend(bend) => {
let delta1 = bend.from - bend.c.pos;
let delta2 = bend.to - bend.c.pos;
let angle1 = delta1.y().atan2(delta1.x());
let angle2 = delta2.y().atan2(delta2.x());
let mut path = Path2D::new();
path.arc(
vec2f(bend.c.pos.x() as f32, bend.c.pos.y() as f32),
bend.circle().r as f32,
angle1 as f32,
angle2 as f32,
ArcDirection::CW,
);
canvas.set_line_width(bend.width as f32);
canvas.stroke_path(path);
}
}
let envelope = ShapeTrait::envelope(shape);
// 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);
canvas.set_line_width(1.0);
canvas.set_stroke_style(ColorU::new(100, 100, 100, 255));
canvas.stroke_rect(RectF::new(topleft, bottomright - topleft));
}