Skip to content

Commit 9557c60

Browse files
committed
partial revert, making the fix minimal
1 parent 67c2bdd commit 9557c60

File tree

2 files changed

+39
-73
lines changed

2 files changed

+39
-73
lines changed

plotters-backend/src/rasterizer/path.rs

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,13 @@ fn get_dir_vector(from: BackendCoord, to: BackendCoord, flag: bool) -> ((f64, f6
1414
}
1515
}
1616

17-
/// Consider two line segments between three points: t1-t2-t3
18-
/// Imagine the line bends to the right, and we run along the line on the right hand side.
19-
/// In that case, we make an "inside corner" at t2.
20-
/// This function would compute the point close to t2 that makes the line have thickness `d`
21-
///
22-
/// For "outside corners" (the line bends to the left), we sometimes get too pointy corners
23-
/// if there is just one new point. In that case, we add a cap to make the corner look better.
24-
/// In that case, the function emits two points.
25-
///
26-
/// The function will return values via the `buf` parameter, after clearing it.
27-
///
28-
/// d can be negative, this will emit a vertex on the other side of the line.
29-
///
17+
// Compute the polygonized vertex of the given angle
18+
// d is the distance between the polygon edge and the actual line.
19+
// d can be negative, this will emit a vertex on the other side of the line.
3020
fn compute_polygon_vertex(triple: &[BackendCoord; 3], d: f64, buf: &mut Vec<BackendCoord>) {
3121
buf.clear();
3222

33-
// Compute the tangential and normal vectors of the given straight line.
23+
// Compute the tanginal and normal vectors of the given straight line.
3424
let (a_t, a_n) = get_dir_vector(triple[0], triple[1], false);
3525
let (b_t, b_n) = get_dir_vector(triple[2], triple[1], true);
3626

@@ -44,7 +34,13 @@ fn compute_polygon_vertex(triple: &[BackendCoord; 3], d: f64, buf: &mut Vec<Back
4434
f64::from(triple[1].1) + d * b_n.1,
4535
);
4636

47-
// We want to compute the intersection of two lines:
37+
// Check if 3 points are colinear, up to precision. If so, just emit the point.
38+
if (a_t.1 * b_t.0 - a_t.0 * b_t.1).abs() <= f64::EPSILON {
39+
buf.push((a_p.0 as i32, a_p.1 as i32));
40+
return;
41+
}
42+
43+
// So we are actually computing the intersection of two lines:
4844
// a_p + u * a_t and b_p + v * b_t.
4945
// We can solve the following vector equation:
5046
// u * a_t + a_p = v * b_t + b_p
@@ -65,38 +61,24 @@ fn compute_polygon_vertex(triple: &[BackendCoord; 3], d: f64, buf: &mut Vec<Back
6561
let b1 = -b_t.1;
6662
let c1 = b_p.1 - a_p.1;
6763

68-
// If the determinant is 0, then we cannot actually get an intersection point.
69-
// In that case, the two lines are parallel and we just emit the point a_p, which is
70-
// approximately equal to b_p
71-
if (a0 * b1 - a1 * b0).abs() <= f64::EPSILON {
72-
buf.push((a_p.0 as i32, a_p.1 as i32));
73-
return;
74-
} else {
75-
let u = (c0 * b1 - c1 * b0) / (a0 * b1 - a1 * b0);
76-
let x = a_p.0 + u * a_t.0;
77-
let y = a_p.1 + u * a_t.1;
78-
79-
let cross_product = a_t.0 * b_t.1 - a_t.1 * b_t.0;
80-
let is_outside_the_angle =
81-
(cross_product < 0.0 && d < 0.0) || (cross_product > 0.0 && d > 0.0);
82-
if is_outside_the_angle {
83-
// We are at the outer side of the angle, so we need to consider a cap.
84-
let dist_square = (x - triple[1].0 as f64).powi(2) + (y - triple[1].1 as f64).powi(2);
85-
let needs_capping = dist_square > d * d * 16.0;
86-
if needs_capping {
87-
// If the point is too far away from the line, we need to cap it to make it look okay
88-
buf.push((a_p.0.round() as i32, a_p.1.round() as i32));
89-
buf.push((b_p.0.round() as i32, b_p.1.round() as i32));
90-
return;
91-
} else {
92-
// We are at the outer side of the angle, at an appropriate distance, so we just emit the point.
93-
buf.push((x.round() as i32, y.round() as i32));
94-
}
95-
} else {
96-
// We are at the inner side of the angle, so we just emit the point.
97-
buf.push((x.round() as i32, y.round() as i32));
64+
// Since the points are not collinear, the determinant is not 0, and we can get a intersection point.
65+
let u = (c0 * b1 - c1 * b0) / (a0 * b1 - a1 * b0);
66+
let x = a_p.0 + u * a_t.0;
67+
let y = a_p.1 + u * a_t.1;
68+
69+
let cross_product = a_t.0 * b_t.1 - a_t.1 * b_t.0;
70+
if (cross_product < 0.0 && d < 0.0) || (cross_product > 0.0 && d > 0.0) {
71+
// Then we are at the outer side of the angle, so we need to consider a cap.
72+
let dist_square = (x - triple[1].0 as f64).powi(2) + (y - triple[1].1 as f64).powi(2);
73+
// If the point is too far away from the line, we need to cap it.
74+
if dist_square > d * d * 16.0 {
75+
buf.push((a_p.0.round() as i32, a_p.1.round() as i32));
76+
buf.push((b_p.0.round() as i32, b_p.1.round() as i32));
77+
return;
9878
}
9979
}
80+
81+
buf.push((x.round() as i32, y.round() as i32));
10082
}
10183

10284
fn traverse_vertices<'a>(
@@ -162,11 +144,11 @@ pub fn polygonize(vertices: &[BackendCoord], stroke_width: u32) -> Vec<BackendCo
162144
ret
163145
}
164146

165-
166147
#[cfg(test)]
167148
mod test
168149
{
169150
use super::*;
151+
170152
/// Test for regression with respect to https://github.com/plotters-rs/plotters/issues/562
171153
#[test]
172154
fn test_no_inf_in_compute_polygon_vertex() {
@@ -177,4 +159,15 @@ mod test
177159
let nani32 = f64::INFINITY as i32;
178160
assert!(!buf.iter().any(|&v| v.0 == nani32 || v.1 == nani32));
179161
}
162+
163+
/// Correct 90 degree turn to the right
164+
#[test]
165+
fn standard_corner() {
166+
let path = [(10, 10), (20, 10), (20, 20)];
167+
let mut buf = Vec::new();
168+
compute_polygon_vertex(&path, 2.0, buf.as_mut());
169+
assert!(!buf.is_empty());
170+
let buf2 = vec![(18, 12)];
171+
assert_eq!(buf,buf2);
172+
}
180173
}

plotters/examples/thick_lines.rs

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)