diff --git a/src/draw.rs b/src/draw.rs index abec51a..e52d6c0 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -1,21 +1,33 @@ use contracts::debug_ensures; -use enum_dispatch::enum_dispatch; + use geo::{EuclideanLength, Point}; use crate::{ graph::{ - BendIndex, DotIndex, FixedDotIndex, FixedSegWeight, GetBand, GetNet, Index, LooseBendIndex, + BendIndex, DotIndex, FixedDotIndex, FixedSegWeight, GetBand, GetNet, LooseBendIndex, LooseBendWeight, LooseDotIndex, LooseDotWeight, LooseSegWeight, MakePrimitive, WraparoundableIndex, }, guide::{Guide, Head, HeadTrait, SegbendHead}, - layout::{Exception, Infringement, Layout}, - math::Circle, - primitive::{GetOtherEnd, GetWeight}, + layout::{Infringement, Layout, LayoutException}, + math::{Circle, NoTangents}, + primitive::GetOtherEnd, rules::{Conditions, Rules}, - segbend::Segbend, }; +#[derive(Debug, Clone, Copy)] +pub enum DrawException { + NoTangents(NoTangents), + CannotFinishIn(FixedDotIndex, LayoutException), + CannotWrapAround(WraparoundableIndex, LayoutException, LayoutException), +} + +impl From for DrawException { + fn from(err: NoTangents) -> Self { + DrawException::NoTangents(err) + } +} + pub struct Draw<'a> { layout: &'a mut Layout, rules: &'a Rules, @@ -37,61 +49,30 @@ impl<'a> Draw<'a> { head: Head, into: FixedDotIndex, width: f64, - ) -> Result<(), Exception> { + ) -> Result<(), DrawException> { let tangent = self .guide(&Default::default()) - .head_into_dot_segment(&head, into, width)?; - let head = self.extend_head(head, tangent.start_point())?; + .head_into_dot_segment(&head, into, width) + .map_err(Into::::into)?; + let head = self + .extend_head(head, tangent.start_point()) + .map_err(|err| DrawException::CannotFinishIn(into, err.into()))?; let net = head.dot().primitive(self.layout).net(); match head.dot() { DotIndex::Fixed(dot) => { self.layout - .add_fixed_seg(into.into(), dot, FixedSegWeight { net, width })?; + .add_fixed_seg(into.into(), dot, FixedSegWeight { net, width }) + .map_err(|err| DrawException::CannotFinishIn(into, err.into()))?; } DotIndex::Loose(dot) => { - self.layout.add_loose_seg( - into.into(), - dot, - LooseSegWeight { band: head.band() }, - )?; + self.layout + .add_loose_seg(into.into(), dot, LooseSegWeight { band: head.band() }) + .map_err(|err| DrawException::CannotFinishIn(into, err.into()))?; } } - Ok::<(), Exception>(()) - } - - #[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()))] - pub fn finish_in_bend( - &mut self, - head: Head, - into_bend: LooseBendIndex, - into: LooseDotIndex, - width: f64, - ) -> Result<(), Exception> { - let to_head = self.guide(&Default::default()).segbend_head(into); - let to_cw = self - .guide(&Default::default()) - .head_cw(&to_head.into()) - .unwrap(); - let tangent = self.guide(&Default::default()).head_around_bend_segment( - &head, - into_bend.into(), - to_cw, - width, - )?; - - let head = self.extend_head(head, tangent.start_point())?; - let _to_head = self.extend_head(to_head.into(), tangent.end_point())?; - - let _net = head.dot().primitive(self.layout).net(); - self.layout.add_loose_seg( - head.dot(), - into.into(), - LooseSegWeight { band: head.band() }, - )?; - Ok::<(), Exception>(()) + Ok::<(), DrawException>(()) } #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))] @@ -101,7 +82,7 @@ impl<'a> Draw<'a> { head: Head, around: FixedDotIndex, width: f64, - ) -> Result { + ) -> Result { let mut tangents = self.guide(&Default::default()).head_around_dot_segments( &head, around.into(), @@ -114,25 +95,27 @@ impl<'a> Draw<'a> { dirs = [false, true]; } - [tangents.0, tangents.1] - .iter() - .enumerate() - .find_map(|(i, tangent)| { - self.segbend_around( - head, - around.into(), - tangent.start_point(), - tangent.end_point(), - dirs[i], - width, - ) - .ok() - }) - // XXX: Use proper exceptions instead of this temporary. - .ok_or(Exception::Infringement(Infringement( - head.dot().into(), - head.dot().into(), - ))) + let mut errs = vec![]; + + for (i, tangent) in [tangents.0, tangents.1].iter().enumerate() { + match self.segbend_around( + head, + around.into(), + tangent.start_point(), + tangent.end_point(), + dirs[i], + width, + ) { + Ok(ok) => return Ok(ok), + Err(err) => errs.push(err), + } + } + + Err(DrawException::CannotWrapAround( + around.into(), + errs[0], + errs[1], + )) } #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))] @@ -142,7 +125,7 @@ impl<'a> Draw<'a> { head: Head, around: BendIndex, width: f64, - ) -> Result { + ) -> Result { let mut tangents = self.guide(&Default::default()).head_around_bend_segments( &head, around.into(), @@ -155,25 +138,27 @@ impl<'a> Draw<'a> { dirs = [false, true]; } - [tangents.0, tangents.1] - .iter() - .enumerate() - .find_map(|(i, tangent)| { - self.segbend_around( - head, - around.into(), - tangent.start_point(), - tangent.end_point(), - dirs[i], - width, - ) - .ok() - }) - // XXX: Use proper exceptions instead of this temporary. - .ok_or(Exception::Infringement(Infringement( - head.dot().into(), - head.dot().into(), - ))) + let mut errs = vec![]; + + for (i, tangent) in [tangents.0, tangents.1].iter().enumerate() { + match self.segbend_around( + head, + around.into(), + tangent.start_point(), + tangent.end_point(), + dirs[i], + width, + ) { + Ok(ok) => return Ok(ok), + Err(err) => errs.push(err), + } + } + + Err(DrawException::CannotWrapAround( + around.into(), + errs[0], + errs[1], + )) } #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 4))] @@ -186,7 +171,7 @@ impl<'a> Draw<'a> { to: Point, cw: bool, width: f64, - ) -> Result { + ) -> Result { let head = self.extend_head(head, from)?; self.segbend(head, around, to, cw, width) } @@ -210,7 +195,7 @@ impl<'a> Draw<'a> { to: Point, cw: bool, width: f64, - ) -> Result { + ) -> Result { let segbend = self.layout.insert_segbend( head.dot(), around, @@ -228,7 +213,7 @@ impl<'a> Draw<'a> { cw, }, )?; - Ok::(SegbendHead { + Ok::(SegbendHead { dot: self.layout.primitive(segbend.bend).other_end(segbend.dot), segbend, band: head.band(), diff --git a/src/guide.rs b/src/guide.rs index 7726bc3..ef5bec0 100644 --- a/src/guide.rs +++ b/src/guide.rs @@ -4,7 +4,7 @@ use geo::Line; use crate::{ graph::{BendIndex, DotIndex, FixedDotIndex, GetBand, LooseDotIndex, MakePrimitive}, layout::Layout, - math::{self, Circle, NoTangent}, + math::{self, Circle, NoTangents}, primitive::{GetCore, GetInnerOuter, GetOtherEnd, GetWeight, MakeShape}, rules::{Conditions, Rules}, segbend::Segbend, @@ -77,7 +77,7 @@ impl<'a, 'b> Guide<'a, 'b> { head: &Head, into: FixedDotIndex, width: f64, - ) -> Result { + ) -> Result { let from_circle = self.head_circle(head, width); let to_circle = Circle { pos: self.layout.primitive(into).weight().circle.pos, @@ -93,7 +93,7 @@ impl<'a, 'b> Guide<'a, 'b> { head: &Head, around: DotIndex, width: f64, - ) -> Result<(Line, Line), NoTangent> { + ) -> Result<(Line, Line), NoTangents> { let from_circle = self.head_circle(head, width); let to_circle = self.dot_circle(around, width); @@ -109,7 +109,7 @@ impl<'a, 'b> Guide<'a, 'b> { around: DotIndex, cw: bool, width: f64, - ) -> Result { + ) -> Result { let from_circle = self.head_circle(head, width); let to_circle = self.dot_circle(around, width); @@ -122,7 +122,7 @@ impl<'a, 'b> Guide<'a, 'b> { head: &Head, around: BendIndex, width: f64, - ) -> Result<(Line, Line), NoTangent> { + ) -> Result<(Line, Line), NoTangents> { let from_circle = self.head_circle(head, width); let to_circle = self.bend_circle(around, width); @@ -138,7 +138,7 @@ impl<'a, 'b> Guide<'a, 'b> { around: BendIndex, cw: bool, width: f64, - ) -> Result { + ) -> Result { let from_circle = self.head_circle(head, width); let to_circle = self.bend_circle(around, width); diff --git a/src/layout.rs b/src/layout.rs index f983c5d..72e4aad 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -15,7 +15,7 @@ use crate::graph::{ Retag, SegWeight, Weight, WraparoundableIndex, }; use crate::guide::Guide; -use crate::math::NoTangent; +use crate::math::NoTangents; use crate::primitive::{ GenericPrimitive, GetConnectable, GetCore, GetEnds, GetFirstRail, GetInnerOuter, GetInterior, GetOtherEnd, GetWeight, GetWraparound, MakeShape, @@ -27,34 +27,34 @@ pub type RTreeWrapper = GeomWithData; #[enum_dispatch] #[derive(Debug, Clone, Copy)] -pub enum Exception { - NoTangent(NoTangent), +pub enum LayoutException { + NoTangents(NoTangents), Infringement(Infringement), Collision(Collision), AreConnected(AreConnected), } -impl From for Exception { - fn from(err: NoTangent) -> Self { - Exception::NoTangent(err) +impl From for LayoutException { + fn from(err: NoTangents) -> Self { + LayoutException::NoTangents(err) } } -impl From for Exception { +impl From for LayoutException { fn from(err: Infringement) -> Self { - Exception::Infringement(err) + LayoutException::Infringement(err) } } -impl From for Exception { +impl From for LayoutException { fn from(err: Collision) -> Self { - Exception::Collision(err) + LayoutException::Collision(err) } } -impl From for Exception { +impl From for LayoutException { fn from(err: AreConnected) -> Self { - Exception::AreConnected(err) + LayoutException::AreConnected(err) } } @@ -186,7 +186,7 @@ impl Layout { dot_weight: LooseDotWeight, seg_weight: LooseSegWeight, bend_weight: LooseBendWeight, - ) -> Result { + ) -> Result { let maybe_wraparound = match around { WraparoundableIndex::FixedDot(around) => self.primitive(around).wraparound(), WraparoundableIndex::FixedBend(around) => self.primitive(around).wraparound(), @@ -224,7 +224,7 @@ impl Layout { return Err(collision.into()); } - Ok::(segbend) + Ok::(segbend) } #[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))] @@ -370,7 +370,10 @@ impl Layout { #[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))] #[debug_ensures(self.graph.edge_count() == old(self.graph.edge_count()))] - fn update_this_and_outward_bows(&mut self, around: LooseBendIndex) -> Result<(), Exception> { + fn update_this_and_outward_bows( + &mut self, + around: LooseBendIndex, + ) -> Result<(), LayoutException> { let mut maybe_rail = Some(around); while let Some(rail) = maybe_rail { @@ -418,7 +421,7 @@ impl Layout { maybe_rail = self.primitive(rail).outer(); } - Ok::<(), Exception>(()) + Ok::<(), LayoutException>(()) } #[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count() + 4))] @@ -432,7 +435,7 @@ impl Layout { dot_weight: LooseDotWeight, seg_weight: LooseSegWeight, bend_weight: LooseBendWeight, - ) -> Result { + ) -> Result { self.add_segbend_infringably( from, around, @@ -455,7 +458,7 @@ impl Layout { seg_weight: LooseSegWeight, bend_weight: LooseBendWeight, infringables: &[Index], - ) -> Result { + ) -> Result { let seg_to = self.add_dot_infringably(dot_weight, infringables)?; let seg = self .add_seg_infringably(from, seg_to, seg_weight, infringables) @@ -463,7 +466,7 @@ impl Layout { self.remove(seg_to.into()); err }) - .map_err(|err| Exception::Infringement(err))?; + .map_err(|err| LayoutException::Infringement(err))?; let bend_to = self .add_dot_infringably(dot_weight, infringables) @@ -472,7 +475,7 @@ impl Layout { self.remove(seg_to.into()); err }) - .map_err(|err| Exception::Infringement(err))?; + .map_err(|err| LayoutException::Infringement(err))?; let bend = self .add_loose_bend_infringably(seg_to, bend_to, around, bend_weight, infringables) .map_err(|err| { @@ -482,7 +485,7 @@ impl Layout { err })?; - Ok::(Segbend { + Ok::(Segbend { seg, dot: seg_to, bend, @@ -557,10 +560,10 @@ impl Layout { around: WraparoundableIndex, weight: LooseBendWeight, infringables: &[Index], - ) -> Result { + ) -> Result { // It makes no sense to wrap something around or under one of its connectables. if self.bands[weight.band].net == around.primitive(self).net() { - return Err(Exception::AreConnected(AreConnected( + return Err(LayoutException::AreConnected(AreConnected( weight.into(), around.into(), ))); @@ -572,7 +575,7 @@ impl Layout { WraparoundableIndex::LooseBend(around) => self.primitive(around).wraparound(), } { if self.bands[weight.band].net == wraparound.primitive(self).net() { - return Err(Exception::AreConnected(AreConnected( + return Err(LayoutException::AreConnected(AreConnected( weight.into(), wraparound.into(), ))); diff --git a/src/math.rs b/src/math.rs index b63199c..54b03dd 100644 --- a/src/math.rs +++ b/src/math.rs @@ -2,7 +2,7 @@ use geo::{geometry::Point, point, EuclideanDistance, Line}; use std::ops::Sub; #[derive(Debug, Clone, Copy, PartialEq)] -pub struct NoTangent(pub Circle, pub Circle); +pub struct NoTangents(pub Circle, pub Circle); #[derive(Debug, Clone, Copy, PartialEq)] pub struct CanonicalLine { @@ -72,8 +72,11 @@ fn cast_point_to_canonical_line(pt: Point, line: CanonicalLine) -> Point { .into(); } -fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> Result<[(Point, Point); 4], NoTangent> { - let tgs = _tangents(circle1, circle2).map_err(|_| NoTangent(circle1, circle2))?; +fn tangent_point_pairs( + circle1: Circle, + circle2: Circle, +) -> Result<[(Point, Point); 4], NoTangents> { + let tgs = _tangents(circle1, circle2).map_err(|_| NoTangents(circle1, circle2))?; Ok([ ( @@ -100,7 +103,7 @@ pub fn tangent_segments( cw1: Option, circle2: Circle, cw2: Option, -) -> Result, NoTangent> { +) -> Result, NoTangents> { Ok(tangent_point_pairs(circle1, circle2)? .into_iter() .filter_map(move |tangent_point_pair| { @@ -131,7 +134,7 @@ pub fn tangent_segment( cw1: Option, circle2: Circle, cw2: Option, -) -> Result { +) -> Result { Ok(tangent_segments(circle1, cw1, circle2, cw2)? .next() .unwrap()) diff --git a/src/tracer.rs b/src/tracer.rs index f3b5962..c7a6d67 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -1,12 +1,11 @@ use contracts::debug_ensures; use crate::{ - draw::Draw, + draw::{Draw, DrawException}, graph::{FixedDotIndex, GetNet, LooseBendIndex}, guide::{BareHead, Head, SegbendHead}, - layout::{Band, Exception, Layout}, + layout::{Band, Layout, LayoutException}, mesh::{Mesh, VertexIndex}, - primitive::{GetInnerOuter, GetWraparound}, rules::Rules, }; @@ -47,7 +46,7 @@ impl<'a> Tracer<'a> { trace: &mut Trace, into: FixedDotIndex, width: f64, - ) -> Result<(), Exception> { + ) -> Result<(), DrawException> { self.draw().finish_in_dot(trace.head, into, width) } @@ -57,7 +56,7 @@ impl<'a> Tracer<'a> { trace: &mut Trace, path: &[VertexIndex], width: f64, - ) -> Result<(), Exception> { + ) -> Result<(), DrawException> { let prefix_length = trace .path .iter() @@ -76,7 +75,7 @@ impl<'a> Tracer<'a> { trace: &mut Trace, path: &[VertexIndex], width: f64, - ) -> Result<(), Exception> { + ) -> Result<(), DrawException> { for (i, vertex) in path.iter().enumerate() { if let Err(err) = self.step(trace, *vertex, width) { self.undo_path(trace, i); @@ -101,11 +100,11 @@ impl<'a> Tracer<'a> { trace: &mut Trace, to: VertexIndex, width: f64, - ) -> Result<(), Exception> { + ) -> Result<(), DrawException> { trace.head = self.wrap(trace.head, to, width)?.into(); trace.path.push(to); - Ok::<(), Exception>(()) + Ok::<(), DrawException>(()) } fn wrap( @@ -113,7 +112,7 @@ impl<'a> Tracer<'a> { head: Head, around: VertexIndex, width: f64, - ) -> Result { + ) -> Result { match around { VertexIndex::FixedDot(dot) => self.wrap_around_fixed_dot(head, dot, width), VertexIndex::FixedBend(_fixed_bend) => todo!(), @@ -128,7 +127,7 @@ impl<'a> Tracer<'a> { head: Head, around: FixedDotIndex, width: f64, - ) -> Result { + ) -> Result { let head = self.draw().segbend_around_dot(head, around.into(), width)?; Ok(head) } @@ -138,7 +137,7 @@ impl<'a> Tracer<'a> { head: Head, around: LooseBendIndex, width: f64, - ) -> Result { + ) -> Result { let head = self .draw() .segbend_around_bend(head, around.into(), width)?;