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<(), ()> {
let tangent = self
.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 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 tangent = self
.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 _to_head = self.extend_head(to_head, tangent.end_point())?;
@ -119,7 +119,7 @@ impl<'a> Draw<'a> {
) -> Result<SegbendHead, ()> {
let mut tangents = self
.guide(&Default::default())
.head_around_dot_segments(&head, around, width);
.head_around_dot_segments(&head, around, width)?;
let mut dirs = [true, false];
if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
@ -154,7 +154,7 @@ impl<'a> Draw<'a> {
) -> Result<SegbendHead, ()> {
let mut tangents = self
.guide(&Default::default())
.head_around_bend_segments(&head, around, width);
.head_around_bend_segments(&head, around, width)?;
let mut dirs = [true, false];
if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
@ -206,7 +206,7 @@ impl<'a> Draw<'a> {
let alternate_tangent = self
.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;

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 to_circle = Circle {
pos: self.layout.primitive(into).weight().circle.pos,
@ -39,14 +44,14 @@ impl<'a, 'b> Guide<'a, 'b> {
head: &Head,
around: DotIndex,
width: f64,
) -> (Line, Line) {
) -> Result<(Line, Line), ()> {
let from_circle = self.head_circle(head, width);
let to_circle = self.dot_circle(around, width);
let from_cw = self.head_cw(head);
let tangents: Vec<Line> =
math::tangent_segments(from_circle, from_cw, to_circle, None).collect();
(tangents[0], tangents[1])
math::tangent_segments(from_circle, from_cw, to_circle, None)?.collect();
Ok((tangents[0], tangents[1]))
}
pub fn head_around_dot_segment(
@ -55,7 +60,7 @@ impl<'a, 'b> Guide<'a, 'b> {
around: DotIndex,
cw: bool,
width: f64,
) -> Line {
) -> Result<Line, ()> {
let from_circle = self.head_circle(head, width);
let to_circle = self.dot_circle(around, width);
@ -68,14 +73,14 @@ impl<'a, 'b> Guide<'a, 'b> {
head: &Head,
around: BendIndex,
width: f64,
) -> (Line, Line) {
) -> Result<(Line, Line), ()> {
let from_circle = self.head_circle(head, width);
let to_circle = self.bend_circle(around, width);
let from_cw = self.head_cw(head);
let tangents: Vec<Line> =
math::tangent_segments(from_circle, from_cw, to_circle, None).collect();
(tangents[0], tangents[1])
math::tangent_segments(from_circle, from_cw, to_circle, None)?.collect();
Ok((tangents[0], tangents[1]))
}
pub fn head_around_bend_segment(
@ -84,7 +89,7 @@ impl<'a, 'b> Guide<'a, 'b> {
around: BendIndex,
cw: bool,
width: f64,
) -> Line {
) -> Result<Line, ()> {
let from_circle = self.head_circle(head, 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 dr = r2 - r1;
let norm = center.x() * center.x() + center.y() * center.y();
let discriminant = norm - dr * dr;
if discriminant < -epsilon {
panic!();
return Err(());
}
let sqrt_discriminant = f64::sqrt(f64::abs(discriminant));
CanonicalLine {
Ok(CanonicalLine {
a: (center.x() * dr + center.y() * sqrt_discriminant) / norm,
b: (center.y() * dr - center.x() * sqrt_discriminant) / norm,
c: r1,
}
})
}
fn _tangents(circle1: Circle, circle2: Circle) -> [CanonicalLine; 4] {
fn _tangents(circle1: Circle, circle2: Circle) -> Result<[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() {
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 {
@ -69,10 +69,10 @@ fn cast_point_to_canonical_line(pt: Point, line: CanonicalLine) -> Point {
.into();
}
fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] {
let tgs = _tangents(circle1, circle2);
fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> Result<[(Point, Point); 4], ()> {
let tgs = _tangents(circle1, circle2)?;
[
Ok([
(
cast_point_to_canonical_line(circle1.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(circle2.pos, tgs[3]),
),
]
])
}
pub fn tangent_segments(
@ -97,8 +97,8 @@ pub fn tangent_segments(
cw1: Option<bool>,
circle2: Circle,
cw2: Option<bool>,
) -> impl Iterator<Item = Line> {
tangent_point_pairs(circle1, circle2)
) -> Result<impl Iterator<Item = Line>, ()> {
Ok(tangent_point_pairs(circle1, circle2)?
.into_iter()
.filter_map(move |tangent_point_pair| {
if let Some(cw1) = cw1 {
@ -120,7 +120,7 @@ pub fn tangent_segments(
}
Some(Line::new(tangent_point_pair.0, tangent_point_pair.1))
})
}))
}
pub fn tangent_segment(
@ -128,8 +128,10 @@ pub fn tangent_segment(
cw1: Option<bool>,
circle2: Circle,
cw2: Option<bool>,
) -> Line {
tangent_segments(circle1, cw1, circle2, cw2).next().unwrap()
) -> Result<Line, ()> {
Ok(tangent_segments(circle1, cw1, circle2, cw2)?
.next()
.unwrap())
}
pub fn intersect_circles(circle1: &Circle, circle2: &Circle) -> Vec<Point> {