layout,math: create some error types

We need this for debugging, as we need some better way to display what
intersects what at what moment. Otherwise it takes a lot of effort to
figure out what is going on.

I had to create some type annotations that appear superfluous. Might be
interference from the `contracts` library. This should be investigated.
This commit is contained in:
Mikolaj Wielgus 2023-12-21 03:17:53 +00:00
parent 9a755059c0
commit 59024d5e74
5 changed files with 178 additions and 87 deletions

View File

@ -9,7 +9,7 @@ use crate::{
WraparoundableIndex, WraparoundableIndex,
}, },
guide::{Guide, Head, HeadTrait, SegbendHead}, guide::{Guide, Head, HeadTrait, SegbendHead},
layout::Layout, layout::{Exception, Infringement, Layout},
math::Circle, math::Circle,
primitive::{GetOtherEnd, GetWeight}, primitive::{GetOtherEnd, GetWeight},
rules::{Conditions, Rules}, rules::{Conditions, Rules},
@ -32,7 +32,12 @@ impl<'a> Draw<'a> {
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 1))]
#[debug_ensures(ret.is_err() -> self.layout.node_count() == old(self.layout.node_count()))] #[debug_ensures(ret.is_err() -> self.layout.node_count() == old(self.layout.node_count()))]
pub fn finish_in_dot(&mut self, head: Head, into: FixedDotIndex, width: f64) -> Result<(), ()> { pub fn finish_in_dot(
&mut self,
head: Head,
into: FixedDotIndex,
width: f64,
) -> Result<(), Exception> {
let tangent = self let tangent = self
.guide(&Default::default()) .guide(&Default::default())
.head_into_dot_segment(&head, into, width)?; .head_into_dot_segment(&head, into, width)?;
@ -53,7 +58,7 @@ impl<'a> Draw<'a> {
)?; )?;
} }
} }
Ok(()) Ok::<(), Exception>(())
} }
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 1))]
@ -64,7 +69,7 @@ impl<'a> Draw<'a> {
into_bend: LooseBendIndex, into_bend: LooseBendIndex,
into: LooseDotIndex, into: LooseDotIndex,
width: f64, width: f64,
) -> Result<(), ()> { ) -> Result<(), Exception> {
let to_head = self.guide(&Default::default()).segbend_head(into); let to_head = self.guide(&Default::default()).segbend_head(into);
let to_cw = self let to_cw = self
.guide(&Default::default()) .guide(&Default::default())
@ -86,7 +91,7 @@ impl<'a> Draw<'a> {
into.into(), into.into(),
LooseSegWeight { band: head.band() }, LooseSegWeight { band: head.band() },
)?; )?;
Ok(()) Ok::<(), Exception>(())
} }
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))] #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))]
@ -96,7 +101,7 @@ impl<'a> Draw<'a> {
head: Head, head: Head,
around: FixedDotIndex, around: FixedDotIndex,
width: f64, width: f64,
) -> Result<SegbendHead, ()> { ) -> Result<SegbendHead, Exception> {
let mut tangents = self.guide(&Default::default()).head_around_dot_segments( let mut tangents = self.guide(&Default::default()).head_around_dot_segments(
&head, &head,
around.into(), around.into(),
@ -123,7 +128,11 @@ impl<'a> Draw<'a> {
) )
.ok() .ok()
}) })
.ok_or(()) // XXX: Use proper exceptions instead of this temporary.
.ok_or(Exception::Infringement(Infringement(
head.dot().into(),
head.dot().into(),
)))
} }
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))] #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))]
@ -133,7 +142,7 @@ impl<'a> Draw<'a> {
head: Head, head: Head,
around: BendIndex, around: BendIndex,
width: f64, width: f64,
) -> Result<SegbendHead, ()> { ) -> Result<SegbendHead, Exception> {
let mut tangents = self.guide(&Default::default()).head_around_bend_segments( let mut tangents = self.guide(&Default::default()).head_around_bend_segments(
&head, &head,
around.into(), around.into(),
@ -160,7 +169,11 @@ impl<'a> Draw<'a> {
) )
.ok() .ok()
}) })
.ok_or(()) // XXX: Use proper exceptions instead of this temporary.
.ok_or(Exception::Infringement(Infringement(
head.dot().into(),
head.dot().into(),
)))
} }
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))] #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))]
@ -173,13 +186,13 @@ impl<'a> Draw<'a> {
to: Point, to: Point,
cw: bool, cw: bool,
width: f64, width: f64,
) -> Result<SegbendHead, ()> { ) -> Result<SegbendHead, Exception> {
let head = self.extend_head(head, from)?; let head = self.extend_head(head, from)?;
self.segbend(head, around, to, cw, width) self.segbend(head, around, to, cw, width)
} }
#[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))] #[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))]
fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, ()> { fn extend_head(&mut self, head: Head, to: Point) -> Result<Head, Infringement> {
if let Head::Segbend(head) = head { if let Head::Segbend(head) = head {
self.layout.move_dot(head.dot, to)?; self.layout.move_dot(head.dot, to)?;
Ok(Head::Segbend(head)) Ok(Head::Segbend(head))
@ -197,7 +210,7 @@ impl<'a> Draw<'a> {
to: Point, to: Point,
cw: bool, cw: bool,
width: f64, width: f64,
) -> Result<SegbendHead, ()> { ) -> Result<SegbendHead, Exception> {
let segbend = self.layout.insert_segbend( let segbend = self.layout.insert_segbend(
head.dot(), head.dot(),
around, around,
@ -215,7 +228,7 @@ impl<'a> Draw<'a> {
cw, cw,
}, },
)?; )?;
Ok(SegbendHead { Ok::<SegbendHead, Exception>(SegbendHead {
dot: self.layout.primitive(segbend.bend).other_end(segbend.dot), dot: self.layout.primitive(segbend.bend).other_end(segbend.dot),
segbend, segbend,
band: head.band(), band: head.band(),

View File

@ -4,7 +4,7 @@ use geo::Line;
use crate::{ use crate::{
graph::{BendIndex, DotIndex, FixedDotIndex, GetBand, LooseDotIndex, MakePrimitive}, graph::{BendIndex, DotIndex, FixedDotIndex, GetBand, LooseDotIndex, MakePrimitive},
layout::Layout, layout::Layout,
math::{self, Circle}, math::{self, Circle, NoTangent},
primitive::{GetCore, GetInnerOuter, GetOtherEnd, GetWeight, MakeShape}, primitive::{GetCore, GetInnerOuter, GetOtherEnd, GetWeight, MakeShape},
rules::{Conditions, Rules}, rules::{Conditions, Rules},
segbend::Segbend, segbend::Segbend,
@ -77,7 +77,7 @@ impl<'a, 'b> Guide<'a, 'b> {
head: &Head, head: &Head,
into: FixedDotIndex, into: FixedDotIndex,
width: f64, width: f64,
) -> Result<Line, ()> { ) -> Result<Line, NoTangent> {
let from_circle = self.head_circle(head, width); let from_circle = self.head_circle(head, width);
let to_circle = Circle { let to_circle = Circle {
pos: self.layout.primitive(into).weight().circle.pos, pos: self.layout.primitive(into).weight().circle.pos,
@ -93,7 +93,7 @@ impl<'a, 'b> Guide<'a, 'b> {
head: &Head, head: &Head,
around: DotIndex, around: DotIndex,
width: f64, width: f64,
) -> Result<(Line, Line), ()> { ) -> Result<(Line, Line), NoTangent> {
let from_circle = self.head_circle(head, width); let from_circle = self.head_circle(head, width);
let to_circle = self.dot_circle(around, width); let to_circle = self.dot_circle(around, width);
@ -109,7 +109,7 @@ impl<'a, 'b> Guide<'a, 'b> {
around: DotIndex, around: DotIndex,
cw: bool, cw: bool,
width: f64, width: f64,
) -> Result<Line, ()> { ) -> Result<Line, NoTangent> {
let from_circle = self.head_circle(head, width); let from_circle = self.head_circle(head, width);
let to_circle = self.dot_circle(around, width); let to_circle = self.dot_circle(around, width);
@ -122,7 +122,7 @@ impl<'a, 'b> Guide<'a, 'b> {
head: &Head, head: &Head,
around: BendIndex, around: BendIndex,
width: f64, width: f64,
) -> Result<(Line, Line), ()> { ) -> Result<(Line, Line), NoTangent> {
let from_circle = self.head_circle(head, width); let from_circle = self.head_circle(head, width);
let to_circle = self.bend_circle(around, width); let to_circle = self.bend_circle(around, width);
@ -138,7 +138,7 @@ impl<'a, 'b> Guide<'a, 'b> {
around: BendIndex, around: BendIndex,
cw: bool, cw: bool,
width: f64, width: f64,
) -> Result<Line, ()> { ) -> Result<Line, NoTangent> {
let from_circle = self.head_circle(head, width); let from_circle = self.head_circle(head, width);
let to_circle = self.bend_circle(around, width); let to_circle = self.bend_circle(around, width);

View File

@ -1,4 +1,5 @@
use contracts::debug_invariant; use contracts::debug_invariant;
use enum_dispatch::enum_dispatch;
use geo::Point; use geo::Point;
use petgraph::stable_graph::StableDiGraph; use petgraph::stable_graph::StableDiGraph;
use petgraph::visit::EdgeRef; use petgraph::visit::EdgeRef;
@ -14,6 +15,7 @@ use crate::graph::{
Retag, SegWeight, Weight, WraparoundableIndex, Retag, SegWeight, Weight, WraparoundableIndex,
}; };
use crate::guide::Guide; use crate::guide::Guide;
use crate::math::NoTangent;
use crate::primitive::{ use crate::primitive::{
GenericPrimitive, GetConnectable, GetCore, GetEnds, GetFirstRail, GetInnerOuter, GetInterior, GenericPrimitive, GetConnectable, GetCore, GetEnds, GetFirstRail, GetInnerOuter, GetInterior,
GetOtherEnd, GetWeight, GetWraparound, MakeShape, GetOtherEnd, GetWeight, GetWraparound, MakeShape,
@ -23,7 +25,49 @@ use crate::shape::{Shape, ShapeTrait};
pub type RTreeWrapper = GeomWithData<Shape, Index>; pub type RTreeWrapper = GeomWithData<Shape, Index>;
#[derive(Debug)] #[enum_dispatch]
#[derive(Debug, Clone, Copy)]
pub enum Exception {
NoTangent(NoTangent),
Infringement(Infringement),
Collision(Collision),
AreConnected(AreConnected),
}
impl From<NoTangent> for Exception {
fn from(err: NoTangent) -> Self {
Exception::NoTangent(err)
}
}
impl From<Infringement> for Exception {
fn from(err: Infringement) -> Self {
Exception::Infringement(err)
}
}
impl From<Collision> for Exception {
fn from(err: Collision) -> Self {
Exception::Collision(err)
}
}
impl From<AreConnected> for Exception {
fn from(err: AreConnected) -> Self {
Exception::AreConnected(err)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Infringement(pub Index, pub Index);
#[derive(Debug, Clone, Copy)]
pub struct Collision(pub Index, pub Index);
#[derive(Debug, Clone, Copy)]
pub struct AreConnected(pub Weight, pub Index);
#[derive(Debug, Clone, Copy)]
pub struct Band { pub struct Band {
pub net: i64, pub net: i64,
pub width: f64, pub width: f64,
@ -89,7 +133,7 @@ impl Layout {
#[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count() + 1))]
#[debug_ensures(ret.is_err() -> self.graph.node_count() == old(self.graph.node_count()))] #[debug_ensures(ret.is_err() -> self.graph.node_count() == old(self.graph.node_count()))]
#[debug_ensures(self.graph.edge_count() == old(self.graph.edge_count()))] #[debug_ensures(self.graph.edge_count() == old(self.graph.edge_count()))]
pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result<FixedDotIndex, ()> { pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result<FixedDotIndex, Infringement> {
self.add_dot_infringably(weight, &[]) self.add_dot_infringably(weight, &[])
} }
@ -106,7 +150,7 @@ impl Layout {
&mut self, &mut self,
weight: W, weight: W,
infringables: &[Index], infringables: &[Index],
) -> Result<GenericIndex<W>, ()> ) -> Result<GenericIndex<W>, Infringement>
where where
GenericIndex<W>: Into<Index> + Copy, GenericIndex<W>: Into<Index> + Copy,
{ {
@ -115,7 +159,7 @@ impl Layout {
self.insert_into_rtree(dot.into()); self.insert_into_rtree(dot.into());
self.fail_and_remove_if_infringes_except(dot.into(), infringables)?; self.fail_and_remove_if_infringes_except(dot.into(), infringables)?;
Ok(dot) Ok::<GenericIndex<W>, Infringement>(dot)
} }
#[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count() + 1))]
@ -127,7 +171,7 @@ impl Layout {
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
) -> Result<FixedSegIndex, ()> { ) -> Result<FixedSegIndex, Infringement> {
self.add_seg_infringably(from, to, weight, &[]) self.add_seg_infringably(from, to, weight, &[])
} }
@ -142,7 +186,7 @@ impl Layout {
dot_weight: LooseDotWeight, dot_weight: LooseDotWeight,
seg_weight: LooseSegWeight, seg_weight: LooseSegWeight,
bend_weight: LooseBendWeight, bend_weight: LooseBendWeight,
) -> Result<Segbend, ()> { ) -> Result<Segbend, Exception> {
let maybe_wraparound = match around { let maybe_wraparound = match around {
WraparoundableIndex::FixedDot(around) => self.primitive(around).wraparound(), WraparoundableIndex::FixedDot(around) => self.primitive(around).wraparound(),
WraparoundableIndex::FixedBend(around) => self.primitive(around).wraparound(), WraparoundableIndex::FixedBend(around) => self.primitive(around).wraparound(),
@ -173,14 +217,14 @@ impl Layout {
} }
// Segs must not cross. // Segs must not cross.
if let Some(..) = self.detect_collision(segbend.seg.into()) { if let Some(collision) = self.detect_collision(segbend.seg.into()) {
let end = self.primitive(segbend.bend).other_end(segbend.dot); let end = self.primitive(segbend.bend).other_end(segbend.dot);
self.remove_interior(&segbend); self.remove_interior(&segbend);
self.remove(end.into()); self.remove(end.into());
return Err(()); return Err(collision.into());
} }
Ok(segbend) Ok::<Segbend, Exception>(segbend)
} }
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))] #[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]
@ -326,7 +370,7 @@ impl Layout {
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))] #[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]
#[debug_ensures(self.graph.edge_count() == old(self.graph.edge_count()))] #[debug_ensures(self.graph.edge_count() == old(self.graph.edge_count()))]
fn update_this_and_outward_bows(&mut self, around: LooseBendIndex) -> Result<(), ()> { fn update_this_and_outward_bows(&mut self, around: LooseBendIndex) -> Result<(), Exception> {
let mut maybe_rail = Some(around); let mut maybe_rail = Some(around);
while let Some(rail) = maybe_rail { while let Some(rail) = maybe_rail {
@ -374,7 +418,7 @@ impl Layout {
maybe_rail = self.primitive(rail).outer(); maybe_rail = self.primitive(rail).outer();
} }
Ok(()) Ok::<(), Exception>(())
} }
#[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count() + 4))] #[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count() + 4))]
@ -388,7 +432,7 @@ impl Layout {
dot_weight: LooseDotWeight, dot_weight: LooseDotWeight,
seg_weight: LooseSegWeight, seg_weight: LooseSegWeight,
bend_weight: LooseBendWeight, bend_weight: LooseBendWeight,
) -> Result<Segbend, ()> { ) -> Result<Segbend, Exception> {
self.add_segbend_infringably( self.add_segbend_infringably(
from, from,
around, around,
@ -411,29 +455,34 @@ impl Layout {
seg_weight: LooseSegWeight, seg_weight: LooseSegWeight,
bend_weight: LooseBendWeight, bend_weight: LooseBendWeight,
infringables: &[Index], infringables: &[Index],
) -> Result<Segbend, ()> { ) -> Result<Segbend, Exception> {
let seg_to = self.add_dot_infringably(dot_weight, infringables)?; let seg_to = self.add_dot_infringably(dot_weight, infringables)?;
let seg = self let seg = self
.add_seg_infringably(from, seg_to, seg_weight, infringables) .add_seg_infringably(from, seg_to, seg_weight, infringables)
.map_err(|_| { .map_err(|err| {
self.remove(seg_to.into()); self.remove(seg_to.into());
})?; err
})
.map_err(|err| Exception::Infringement(err))?;
let bend_to = self let bend_to = self
.add_dot_infringably(dot_weight, infringables) .add_dot_infringably(dot_weight, infringables)
.map_err(|_| { .map_err(|err| {
self.remove(seg.into()); self.remove(seg.into());
self.remove(seg_to.into()); self.remove(seg_to.into());
})?; err
})
.map_err(|err| Exception::Infringement(err))?;
let bend = self let bend = self
.add_loose_bend_infringably(seg_to, bend_to, around, bend_weight, infringables) .add_loose_bend_infringably(seg_to, bend_to, around, bend_weight, infringables)
.map_err(|_| { .map_err(|err| {
self.remove(bend_to.into()); self.remove(bend_to.into());
self.remove(seg.into()); self.remove(seg.into());
self.remove(seg_to.into()); self.remove(seg_to.into());
err
})?; })?;
Ok(Segbend { Ok::<Segbend, Exception>(Segbend {
seg, seg,
dot: seg_to, dot: seg_to,
bend, bend,
@ -449,7 +498,7 @@ impl Layout {
from: DotIndex, from: DotIndex,
to: LooseDotIndex, to: LooseDotIndex,
weight: LooseSegWeight, weight: LooseSegWeight,
) -> Result<LooseSegIndex, ()> { ) -> Result<LooseSegIndex, Infringement> {
self.add_seg_infringably(from, to, weight, &[]) self.add_seg_infringably(from, to, weight, &[])
} }
@ -463,7 +512,7 @@ impl Layout {
to: impl GetNodeIndex, to: impl GetNodeIndex,
weight: W, weight: W,
infringables: &[Index], infringables: &[Index],
) -> Result<GenericIndex<W>, ()> ) -> Result<GenericIndex<W>, Infringement>
where where
GenericIndex<W>: Into<Index> + Copy, GenericIndex<W>: Into<Index> + Copy,
{ {
@ -508,10 +557,13 @@ impl Layout {
around: WraparoundableIndex, around: WraparoundableIndex,
weight: LooseBendWeight, weight: LooseBendWeight,
infringables: &[Index], infringables: &[Index],
) -> Result<LooseBendIndex, ()> { ) -> Result<LooseBendIndex, Exception> {
// 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() { if self.bands[weight.band].net == around.primitive(self).net() {
return Err(()); return Err(Exception::AreConnected(AreConnected(
weight.into(),
around.into(),
)));
} }
// //
if let Some(wraparound) = match around { if let Some(wraparound) = match around {
@ -520,20 +572,23 @@ impl Layout {
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 self.bands[weight.band].net == wraparound.primitive(self).net() {
return Err(()); return Err(Exception::AreConnected(AreConnected(
weight.into(),
wraparound.into(),
)));
} }
} }
match around { match around {
WraparoundableIndex::FixedDot(core) => { WraparoundableIndex::FixedDot(core) => self
self.add_core_bend_infringably(from, to, core, weight, infringables) .add_core_bend_infringably(from, to, core, weight, infringables)
} .map_err(Into::into),
WraparoundableIndex::FixedBend(around) => { WraparoundableIndex::FixedBend(around) => self
self.add_outer_bend_infringably(from, to, around, weight, infringables) .add_outer_bend_infringably(from, to, around, weight, infringables)
} .map_err(Into::into),
WraparoundableIndex::LooseBend(around) => { WraparoundableIndex::LooseBend(around) => self
self.add_outer_bend_infringably(from, to, around, weight, infringables) .add_outer_bend_infringably(from, to, around, weight, infringables)
} .map_err(Into::into),
} }
} }
@ -548,7 +603,7 @@ impl Layout {
core: FixedDotIndex, core: FixedDotIndex,
weight: W, weight: W,
infringables: &[Index], infringables: &[Index],
) -> Result<LooseBendIndex, ()> ) -> Result<LooseBendIndex, Infringement>
where where
GenericIndex<W>: Into<Index> + Copy, GenericIndex<W>: Into<Index> + Copy,
{ {
@ -577,7 +632,7 @@ impl Layout {
inner: impl GetNodeIndex, inner: impl GetNodeIndex,
weight: W, weight: W,
infringables: &[Index], infringables: &[Index],
) -> Result<LooseBendIndex, ()> { ) -> Result<LooseBendIndex, Infringement> {
let core = *self let core = *self
.graph .graph
.neighbors(inner.node_index()) .neighbors(inner.node_index())
@ -607,7 +662,7 @@ impl Layout {
self.insert_into_rtree(bend.into()); self.insert_into_rtree(bend.into());
self.fail_and_remove_if_infringes_except(bend.into(), infringables)?; self.fail_and_remove_if_infringes_except(bend.into(), infringables)?;
Ok(bend) Ok::<LooseBendIndex, Infringement>(bend)
} }
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))] #[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]
@ -639,10 +694,10 @@ impl Layout {
&mut self, &mut self,
index: Index, index: Index,
except: &[Index], except: &[Index],
) -> Result<(), ()> { ) -> Result<(), Infringement> {
if let Some(..) = self.detect_infringement_except(index, except) { if let Some(infringement) = self.detect_infringement_except(index, except) {
self.remove(index); self.remove(index);
return Err(()); return Err(infringement);
} }
Ok(()) Ok(())
} }
@ -671,7 +726,7 @@ impl Layout {
#[debug_invariant(self.test_envelopes())] #[debug_invariant(self.test_envelopes())]
impl Layout { impl Layout {
pub fn move_dot(&mut self, dot: LooseDotIndex, to: Point) -> Result<(), ()> { pub fn move_dot(&mut self, dot: LooseDotIndex, to: Point) -> Result<(), Infringement> {
self.move_dot_infringably( self.move_dot_infringably(
dot, dot,
to, to,
@ -695,7 +750,7 @@ impl Layout {
dot: LooseDotIndex, dot: LooseDotIndex,
to: Point, to: Point,
infringables: &[Index], infringables: &[Index],
) -> Result<(), ()> { ) -> Result<(), Infringement> {
self.primitive(dot) self.primitive(dot)
.seg() .seg()
.map(|seg| self.remove_from_rtree(seg.into())); .map(|seg| self.remove_from_rtree(seg.into()));
@ -733,7 +788,7 @@ impl Layout {
GenericPrimitive::new(index, self) GenericPrimitive::new(index, self)
} }
fn detect_infringement_except(&self, index: Index, except: &[Index]) -> Option<Index> { fn detect_infringement_except(&self, index: Index, except: &[Index]) -> Option<Infringement> {
let shape = index.primitive(self).shape(); let shape = index.primitive(self).shape();
self.rtree self.rtree
@ -746,10 +801,11 @@ 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)))
} }
// TODO: Collision and infringement are the same for now. Change this. // TODO: Collision and infringement are the same for now. Change this.
fn detect_collision(&self, index: Index) -> Option<Index> { fn detect_collision(&self, index: Index) -> Option<Collision> {
let shape = index.primitive(self).shape(); let shape = index.primitive(self).shape();
self.rtree self.rtree
@ -761,6 +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)))
} }
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))] #[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]

View File

@ -1,6 +1,9 @@
use geo::{geometry::Point, point, EuclideanDistance, Line}; use geo::{geometry::Point, point, EuclideanDistance, Line};
use std::ops::Sub; use std::ops::Sub;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NoTangent(pub Circle, pub Circle);
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct CanonicalLine { pub struct CanonicalLine {
pub a: f64, pub a: f64,
@ -69,8 +72,8 @@ fn cast_point_to_canonical_line(pt: Point, line: CanonicalLine) -> Point {
.into(); .into();
} }
fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> Result<[(Point, Point); 4], ()> { fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> Result<[(Point, Point); 4], NoTangent> {
let tgs = _tangents(circle1, circle2)?; let tgs = _tangents(circle1, circle2).map_err(|_| NoTangent(circle1, circle2))?;
Ok([ Ok([
( (
@ -97,7 +100,7 @@ pub fn tangent_segments(
cw1: Option<bool>, cw1: Option<bool>,
circle2: Circle, circle2: Circle,
cw2: Option<bool>, cw2: Option<bool>,
) -> Result<impl Iterator<Item = Line>, ()> { ) -> Result<impl Iterator<Item = Line>, NoTangent> {
Ok(tangent_point_pairs(circle1, circle2)? Ok(tangent_point_pairs(circle1, circle2)?
.into_iter() .into_iter()
.filter_map(move |tangent_point_pair| { .filter_map(move |tangent_point_pair| {
@ -128,7 +131,7 @@ pub fn tangent_segment(
cw1: Option<bool>, cw1: Option<bool>,
circle2: Circle, circle2: Circle,
cw2: Option<bool>, cw2: Option<bool>,
) -> Result<Line, ()> { ) -> Result<Line, NoTangent> {
Ok(tangent_segments(circle1, cw1, circle2, cw2)? Ok(tangent_segments(circle1, cw1, circle2, cw2)?
.next() .next()
.unwrap()) .unwrap())

View File

@ -4,7 +4,7 @@ use crate::{
draw::Draw, draw::Draw,
graph::{FixedDotIndex, GetNet, LooseBendIndex}, graph::{FixedDotIndex, GetNet, LooseBendIndex},
guide::{BareHead, Head, SegbendHead}, guide::{BareHead, Head, SegbendHead},
layout::{Band, Layout}, layout::{Band, Exception, Layout},
mesh::{Mesh, VertexIndex}, mesh::{Mesh, VertexIndex},
primitive::{GetInnerOuter, GetWraparound}, primitive::{GetInnerOuter, GetWraparound},
rules::Rules, rules::Rules,
@ -42,7 +42,12 @@ impl<'a> Tracer<'a> {
} }
} }
pub fn finish(&mut self, trace: &mut Trace, into: FixedDotIndex, width: f64) -> Result<(), ()> { pub fn finish(
&mut self,
trace: &mut Trace,
into: FixedDotIndex,
width: f64,
) -> Result<(), Exception> {
self.draw().finish_in_dot(trace.head, into, width) self.draw().finish_in_dot(trace.head, into, width)
} }
@ -52,7 +57,7 @@ impl<'a> Tracer<'a> {
trace: &mut Trace, trace: &mut Trace,
path: &[VertexIndex], path: &[VertexIndex],
width: f64, width: f64,
) -> Result<(), ()> { ) -> Result<(), Exception> {
let prefix_length = trace let prefix_length = trace
.path .path
.iter() .iter()
@ -61,39 +66,54 @@ impl<'a> Tracer<'a> {
.count(); .count();
let length = trace.path.len(); let length = trace.path.len();
self.undo_path(trace, length - prefix_length)?; self.undo_path(trace, length - prefix_length);
self.path(trace, &path[prefix_length..], width) self.path(trace, &path[prefix_length..], width)
} }
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + path.len()))] #[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + path.len()))]
pub fn path(&mut self, trace: &mut Trace, path: &[VertexIndex], width: f64) -> Result<(), ()> { pub fn path(
&mut self,
trace: &mut Trace,
path: &[VertexIndex],
width: f64,
) -> Result<(), Exception> {
for (i, vertex) in path.iter().enumerate() { for (i, vertex) in path.iter().enumerate() {
if let Err(err) = self.step(trace, *vertex, width) { if let Err(err) = self.step(trace, *vertex, width) {
self.undo_path(trace, i)?; self.undo_path(trace, i);
return Err(err); return Err(err);
} }
} }
Ok(()) Ok(())
} }
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() - step_count))] #[debug_ensures(trace.path.len() == old(trace.path.len() - step_count))]
pub fn undo_path(&mut self, trace: &mut Trace, step_count: usize) -> Result<(), ()> { pub fn undo_path(&mut self, trace: &mut Trace, step_count: usize) {
for _ in 0..step_count { for _ in 0..step_count {
self.undo_step(trace)?; self.undo_step(trace);
} }
Ok(())
} }
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + 1))] #[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + 1))]
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))] #[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
pub fn step(&mut self, trace: &mut Trace, to: VertexIndex, width: f64) -> Result<(), ()> { pub fn step(
&mut self,
trace: &mut Trace,
to: VertexIndex,
width: f64,
) -> Result<(), Exception> {
trace.head = self.wrap(trace.head, to, width)?.into(); trace.head = self.wrap(trace.head, to, width)?.into();
trace.path.push(to); trace.path.push(to);
Ok(())
Ok::<(), Exception>(())
} }
fn wrap(&mut self, head: Head, around: VertexIndex, width: f64) -> Result<SegbendHead, ()> { fn wrap(
&mut self,
head: Head,
around: VertexIndex,
width: f64,
) -> Result<SegbendHead, Exception> {
match around { match around {
VertexIndex::FixedDot(dot) => self.wrap_around_fixed_dot(head, dot, width), VertexIndex::FixedDot(dot) => self.wrap_around_fixed_dot(head, dot, width),
VertexIndex::FixedBend(_fixed_bend) => todo!(), VertexIndex::FixedBend(_fixed_bend) => todo!(),
@ -108,7 +128,7 @@ impl<'a> Tracer<'a> {
head: Head, head: Head,
around: FixedDotIndex, around: FixedDotIndex,
width: f64, width: f64,
) -> Result<SegbendHead, ()> { ) -> Result<SegbendHead, Exception> {
let head = self.draw().segbend_around_dot(head, around.into(), width)?; let head = self.draw().segbend_around_dot(head, around.into(), width)?;
Ok(head) Ok(head)
} }
@ -118,7 +138,7 @@ impl<'a> Tracer<'a> {
head: Head, head: Head,
around: LooseBendIndex, around: LooseBendIndex,
width: f64, width: f64,
) -> Result<SegbendHead, ()> { ) -> Result<SegbendHead, Exception> {
let head = self let head = self
.draw() .draw()
.segbend_around_bend(head, around.into(), width)?; .segbend_around_bend(head, around.into(), width)?;
@ -126,17 +146,15 @@ impl<'a> Tracer<'a> {
Ok(head) Ok(head)
} }
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() - 1))] #[debug_ensures(trace.path.len() == old(trace.path.len() - 1))]
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))] pub fn undo_step(&mut self, trace: &mut Trace) {
pub fn undo_step(&mut self, trace: &mut Trace) -> Result<(), ()> {
if let Head::Segbend(head) = trace.head { if let Head::Segbend(head) = trace.head {
trace.head = self.draw().undo_segbend(head).unwrap(); trace.head = self.draw().undo_segbend(head).unwrap();
} else { } else {
return Err(()); panic!();
} }
trace.path.pop(); trace.path.pop();
Ok(())
} }
fn draw(&mut self) -> Draw { fn draw(&mut self) -> Draw {