Files
Marcos Paulo fe7f042a18
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
fix(whiteboard): lines and arrows follow the drag in every direction; dashed/dotted patterns start where the pattern says; single stroke pass when dashed; solid arrowheads
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 14:00:58 -03:00

39 lines
1.9 KiB
Rust

//! Dashed and dotted strokes are evenly spaced along the whole line, in any direction.
use notescraft_whiteboard::{StrokeStyle, rough::dash};
fn length(piece: &[[f32; 2]]) -> f32 {
piece.windows(2).map(|pair| ((pair[1][0] - pair[0][0]).powi(2) + (pair[1][1] - pair[0][1]).powi(2)).sqrt()).sum()
}
#[test]
fn dashes_start_where_the_pattern_says_not_at_the_line_start() {
let pieces = dash(&[vec![[0.0, 0.0], [100.0, 0.0]]], StrokeStyle::Dashed);
assert_eq!(pieces.len(), 9);
for (index, piece) in pieces.iter().enumerate() {
let start = f32::from(u8::try_from(index).unwrap_or(0)) * 12.0;
assert!((piece[0][0] - start).abs() < 1e-3, "dash {index} starts at {} not {start}", piece[0][0]);
assert!(length(piece) <= 8.001, "dash {index} is {} long", length(piece));
}
}
#[test]
fn dots_are_short_and_spaced_in_every_direction() {
for (dx, dy) in [(80.0, 60.0), (-80.0, 60.0), (80.0, -60.0), (-80.0, -60.0), (0.0, 100.0), (-100.0, 0.0)] {
let pieces = dash(&[vec![[0.0, 0.0], [dx, dy]]], StrokeStyle::Dotted);
assert!(pieces.len() >= 20, "{dx},{dy}: {} dots", pieces.len());
assert!(pieces.iter().all(|piece| length(piece) <= 1.001), "{dx},{dy}: every dot is at most 1 long");
let gaps: Vec<f32> = pieces.windows(2).map(|pair| length(&[*pair[0].last().unwrap_or(&[0.0, 0.0]), pair[1][0]])).collect();
assert!(gaps.iter().all(|gap| (gap - 3.0).abs() < 0.05), "{dx},{dy}: uneven gaps {gaps:?}");
}
}
#[test]
fn a_pattern_continues_around_a_corner() {
let pieces = dash(&[vec![[0.0, 0.0], [5.0, 0.0], [5.0, 15.0]]], StrokeStyle::Dashed);
let total: f32 = pieces.iter().map(|piece| length(piece)).sum();
// 20 units of line: 0..8 on, 8..12 off, 12..20 on.
assert!((total - 16.0).abs() < 0.1, "drawn length {total}");
assert!(pieces.first().is_some_and(|piece| piece.contains(&[5.0, 0.0])), "the first dash bends around the corner");
}