guide: Return Err(...) instead of panicking

This commit is contained in:
Mikolaj Wielgus 2023-10-17 05:17:07 +00:00
parent 087d1deea0
commit 177b8cb231
3 changed files with 40 additions and 33 deletions

View File

@ -76,7 +76,7 @@ impl<'a> Draw<'a> {
fn finish_in_dot(&mut self, head: Head, into: DotIndex, width: f64) -> Result<(), ()> { fn finish_in_dot(&mut self, head: Head, into: DotIndex, width: f64) -> Result<(), ()> {
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)?;
let head = self.extend_head(head, tangent.start_point())?; let head = self.extend_head(head, tangent.start_point())?;
let net = self.layout.primitive(head.dot()).weight().net; let net = self.layout.primitive(head.dot()).weight().net;
@ -98,7 +98,7 @@ impl<'a> Draw<'a> {
let to_cw = self.guide(&Default::default()).head_cw(&to_head).unwrap(); let to_cw = self.guide(&Default::default()).head_cw(&to_head).unwrap();
let tangent = self let tangent = self
.guide(&Default::default()) .guide(&Default::default())
.head_around_bend_segment(&head, into_bend, to_cw, width); .head_around_bend_segment(&head, into_bend, to_cw, width)?;
let head = self.extend_head(head, tangent.start_point())?; let head = self.extend_head(head, tangent.start_point())?;
let _to_head = self.extend_head(to_head, tangent.end_point())?; let _to_head = self.extend_head(to_head, tangent.end_point())?;
@ -119,7 +119,7 @@ impl<'a> Draw<'a> {
) -> Result<SegbendHead, ()> { ) -> Result<SegbendHead, ()> {
let mut tangents = self let mut tangents = self
.guide(&Default::default()) .guide(&Default::default())
.head_around_dot_segments(&head, around, width); .head_around_dot_segments(&head, around, width)?;
let mut dirs = [true, false]; let mut dirs = [true, false];
if tangents.1.euclidean_length() < tangents.0.euclidean_length() { if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
@ -154,7 +154,7 @@ impl<'a> Draw<'a> {
) -> Result<SegbendHead, ()> { ) -> Result<SegbendHead, ()> {
let mut tangents = self let mut tangents = self
.guide(&Default::default()) .guide(&Default::default())
.head_around_bend_segments(&head, around, width); .head_around_bend_segments(&head, around, width)?;
let mut dirs = [true, false]; let mut dirs = [true, false];
if tangents.1.euclidean_length() < tangents.0.euclidean_length() { if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
@ -206,7 +206,7 @@ impl<'a> Draw<'a> {
let alternate_tangent = self let alternate_tangent = self
.guide(&Default::default()) .guide(&Default::default())
.head_around_dot_segment(&prev_head, around, cw, 5.0); .head_around_dot_segment(&prev_head, around, cw, 5.0)?;
let segbend_dot_pos = self.layout.primitive(head.segbend.dot).weight().circle.pos; let segbend_dot_pos = self.layout.primitive(head.segbend.dot).weight().circle.pos;

View File

@ -23,7 +23,12 @@ impl<'a, 'b> Guide<'a, 'b> {
} }
} }
pub fn head_into_dot_segment(&self, head: &Head, into: DotIndex, width: f64) -> Line { pub fn head_into_dot_segment(
&self,
head: &Head,
into: DotIndex,
width: f64,
) -> Result<Line, ()> {
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,
@ -39,14 +44,14 @@ impl<'a, 'b> Guide<'a, 'b> {
head: &Head, head: &Head,
around: DotIndex, around: DotIndex,
width: f64, width: f64,
) -> (Line, Line) { ) -> Result<(Line, Line), ()> {
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);
let from_cw = self.head_cw(head); let from_cw = self.head_cw(head);
let tangents: Vec<Line> = let tangents: Vec<Line> =
math::tangent_segments(from_circle, from_cw, to_circle, None).collect(); math::tangent_segments(from_circle, from_cw, to_circle, None)?.collect();
(tangents[0], tangents[1]) Ok((tangents[0], tangents[1]))
} }
pub fn head_around_dot_segment( pub fn head_around_dot_segment(
@ -55,7 +60,7 @@ impl<'a, 'b> Guide<'a, 'b> {
around: DotIndex, around: DotIndex,
cw: bool, cw: bool,
width: f64, width: f64,
) -> Line { ) -> Result<Line, ()> {
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);
@ -68,14 +73,14 @@ impl<'a, 'b> Guide<'a, 'b> {
head: &Head, head: &Head,
around: BendIndex, around: BendIndex,
width: f64, width: f64,
) -> (Line, Line) { ) -> Result<(Line, Line), ()> {
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);
let from_cw = self.head_cw(head); let from_cw = self.head_cw(head);
let tangents: Vec<Line> = let tangents: Vec<Line> =
math::tangent_segments(from_circle, from_cw, to_circle, None).collect(); math::tangent_segments(from_circle, from_cw, to_circle, None)?.collect();
(tangents[0], tangents[1]) Ok((tangents[0], tangents[1]))
} }
pub fn head_around_bend_segment( pub fn head_around_bend_segment(
@ -84,7 +89,7 @@ impl<'a, 'b> Guide<'a, 'b> {
around: BendIndex, around: BendIndex,
cw: bool, cw: bool,
width: f64, width: f64,
) -> Line { ) -> Result<Line, ()> {
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

@ -25,38 +25,38 @@ impl Sub for Circle {
} }
} }
fn _tangent(center: Point, r1: f64, r2: f64) -> CanonicalLine { fn _tangent(center: Point, r1: f64, r2: f64) -> Result<CanonicalLine, ()> {
let epsilon = 1e-9; let epsilon = 1e-9;
let dr = r2 - r1; let dr = r2 - r1;
let norm = center.x() * center.x() + center.y() * center.y(); let norm = center.x() * center.x() + center.y() * center.y();
let discriminant = norm - dr * dr; let discriminant = norm - dr * dr;
if discriminant < -epsilon { if discriminant < -epsilon {
panic!(); return Err(());
} }
let sqrt_discriminant = f64::sqrt(f64::abs(discriminant)); let sqrt_discriminant = f64::sqrt(f64::abs(discriminant));
CanonicalLine { Ok(CanonicalLine {
a: (center.x() * dr + center.y() * sqrt_discriminant) / norm, a: (center.x() * dr + center.y() * sqrt_discriminant) / norm,
b: (center.y() * dr - center.x() * sqrt_discriminant) / norm, b: (center.y() * dr - center.x() * sqrt_discriminant) / norm,
c: r1, c: r1,
} })
} }
fn _tangents(circle1: Circle, circle2: Circle) -> [CanonicalLine; 4] { fn _tangents(circle1: Circle, circle2: Circle) -> Result<[CanonicalLine; 4], ()> {
let mut tgs: [CanonicalLine; 4] = [ let mut tgs: [CanonicalLine; 4] = [
_tangent((circle2 - circle1).pos, -circle1.r, -circle2.r), _tangent((circle2 - circle1).pos, -circle1.r, -circle2.r)?,
_tangent((circle2 - circle1).pos, -circle1.r, circle2.r), _tangent((circle2 - circle1).pos, -circle1.r, circle2.r)?,
_tangent((circle2 - circle1).pos, circle1.r, -circle2.r), _tangent((circle2 - circle1).pos, circle1.r, -circle2.r)?,
_tangent((circle2 - circle1).pos, circle1.r, circle2.r), _tangent((circle2 - circle1).pos, circle1.r, circle2.r)?,
]; ];
for tg in tgs.iter_mut() { for tg in tgs.iter_mut() {
tg.c -= tg.a * circle1.pos.x() + tg.b * circle1.pos.y(); tg.c -= tg.a * circle1.pos.x() + tg.b * circle1.pos.y();
} }
return tgs; Ok(tgs)
} }
fn cast_point_to_canonical_line(pt: Point, line: CanonicalLine) -> Point { fn cast_point_to_canonical_line(pt: Point, line: CanonicalLine) -> Point {
@ -69,10 +69,10 @@ fn cast_point_to_canonical_line(pt: Point, line: CanonicalLine) -> Point {
.into(); .into();
} }
fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] { fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> Result<[(Point, Point); 4], ()> {
let tgs = _tangents(circle1, circle2); let tgs = _tangents(circle1, circle2)?;
[ Ok([
( (
cast_point_to_canonical_line(circle1.pos, tgs[0]), cast_point_to_canonical_line(circle1.pos, tgs[0]),
cast_point_to_canonical_line(circle2.pos, tgs[0]), cast_point_to_canonical_line(circle2.pos, tgs[0]),
@ -89,7 +89,7 @@ fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> [(Point, Point); 4]
cast_point_to_canonical_line(circle1.pos, tgs[3]), cast_point_to_canonical_line(circle1.pos, tgs[3]),
cast_point_to_canonical_line(circle2.pos, tgs[3]), cast_point_to_canonical_line(circle2.pos, tgs[3]),
), ),
] ])
} }
pub fn tangent_segments( pub fn tangent_segments(
@ -97,8 +97,8 @@ pub fn tangent_segments(
cw1: Option<bool>, cw1: Option<bool>,
circle2: Circle, circle2: Circle,
cw2: Option<bool>, cw2: Option<bool>,
) -> impl Iterator<Item = Line> { ) -> Result<impl Iterator<Item = Line>, ()> {
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| {
if let Some(cw1) = cw1 { if let Some(cw1) = cw1 {
@ -120,7 +120,7 @@ pub fn tangent_segments(
} }
Some(Line::new(tangent_point_pair.0, tangent_point_pair.1)) Some(Line::new(tangent_point_pair.0, tangent_point_pair.1))
}) }))
} }
pub fn tangent_segment( pub fn tangent_segment(
@ -128,8 +128,10 @@ pub fn tangent_segment(
cw1: Option<bool>, cw1: Option<bool>,
circle2: Circle, circle2: Circle,
cw2: Option<bool>, cw2: Option<bool>,
) -> Line { ) -> Result<Line, ()> {
tangent_segments(circle1, cw1, circle2, cw2).next().unwrap() Ok(tangent_segments(circle1, cw1, circle2, cw2)?
.next()
.unwrap())
} }
pub fn intersect_circles(circle1: &Circle, circle2: &Circle) -> Vec<Point> { pub fn intersect_circles(circle1: &Circle, circle2: &Circle) -> Vec<Point> {