Skip to content

Commit 348e0cf

Browse files
committed
Use straight lines for short links to avoid zig-zag curves
1 parent b1cddb3 commit 348e0cf

1 file changed

Lines changed: 58 additions & 8 deletions

File tree

src/path.rs

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,19 @@ pub fn generate_bezier_path(
1919
zoom: f32,
2020
min_offset: f32,
2121
) -> String {
22+
// If distance is very small, use a straight line to avoid zig-zags
23+
let dx = end_x - start_x;
24+
let dy = end_y - start_y;
25+
let dist_sq = dx * dx + dy * dy;
26+
let threshold = 10.0 * zoom;
27+
28+
if dist_sq < threshold * threshold {
29+
return format!("M {} {} L {} {}", start_x, start_y, end_x, end_y);
30+
}
31+
2232
// Calculate control point offset (horizontal bezier)
23-
let dx = (end_x - start_x).abs();
24-
let offset = (dx * 0.5).max(min_offset * zoom);
33+
let dx_abs = dx.abs();
34+
let offset = (dx_abs * 0.5).max(min_offset * zoom);
2535

2636
// Control points extend horizontally from start and end
2737
let ctrl1_x = start_x + offset;
@@ -72,9 +82,21 @@ pub fn generate_partial_bezier_path(
7282
return generate_bezier_path(start_x, start_y, end_x, end_y, zoom, min_offset);
7383
}
7484

85+
// If distance is very small, use a straight line
86+
let dx_full = end_x - start_x;
87+
let dy_full = end_y - start_y;
88+
let dist_sq = dx_full * dx_full + dy_full * dy_full;
89+
let threshold = 10.0 * zoom;
90+
91+
if dist_sq < threshold * threshold {
92+
let curr_x = start_x + dx_full * t;
93+
let curr_y = start_y + dy_full * t;
94+
return format!("M {} {} L {} {}", start_x, start_y, curr_x, curr_y);
95+
}
96+
7597
// Calculate full bezier control points
76-
let dx = (end_x - start_x).abs();
77-
let offset = (dx * 0.5).max(min_offset * zoom);
98+
let dx_abs = dx_full.abs();
99+
let offset = (dx_abs * 0.5).max(min_offset * zoom);
78100

79101
let p0 = (start_x, start_y);
80102
let p1 = (start_x + offset, start_y);
@@ -131,8 +153,22 @@ impl CubicBezier {
131153
zoom: f32,
132154
min_offset: f32,
133155
) -> Self {
134-
let dx = (end_x - start_x).abs();
135-
let offset = (dx * 0.5).max(min_offset * zoom);
156+
let dx = end_x - start_x;
157+
let dy = end_y - start_y;
158+
let dist_sq = dx * dx + dy * dy;
159+
let threshold = 10.0 * zoom;
160+
161+
if dist_sq < threshold * threshold {
162+
return CubicBezier {
163+
p0: (start_x, start_y),
164+
p1: (start_x, start_y),
165+
p2: (end_x, end_y),
166+
p3: (end_x, end_y),
167+
};
168+
}
169+
170+
let dx_abs = dx.abs();
171+
let offset = (dx_abs * 0.5).max(min_offset * zoom);
136172

137173
CubicBezier {
138174
p0: (start_x, start_y),
@@ -239,12 +275,26 @@ mod tests {
239275
assert!(path.ends_with("100 80"));
240276
}
241277

278+
#[test]
279+
fn test_bezier_path_small_distance() {
280+
// Distance is 5.0, threshold is 10.0
281+
let path = generate_bezier_path(0.0, 0.0, 5.0, 0.0, 1.0, 50.0);
282+
assert!(path.contains(" L "));
283+
assert!(!path.contains(" C "));
284+
285+
// Distance is 15.0, threshold is 10.0
286+
let path2 = generate_bezier_path(0.0, 0.0, 15.0, 0.0, 1.0, 50.0);
287+
assert!(path2.contains(" C "));
288+
assert!(!path2.contains(" L "));
289+
}
290+
242291
#[test]
243292
fn test_bezier_path_zero_distance() {
244-
// Start and end at same point - should still produce valid path
293+
// Start and end at same point - should produce a straight line (effectively a point)
245294
let path = generate_bezier_path(50.0, 50.0, 50.0, 50.0, 1.0, 50.0);
246295
assert!(path.starts_with("M "));
247-
assert!(path.contains(" C "));
296+
assert!(path.contains(" L "));
297+
assert!(!path.contains(" C "));
248298
}
249299

250300
#[test]

0 commit comments

Comments
 (0)