Add support for dashed lines with offset (#3720)

<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/master/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to add commits to your PR.
* Remember to run `cargo fmt` and `cargo cranky`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

Closes <https://github.com/emilk/egui/issues/3677>.

This can naturally be obtained by starting the drawing a bit "later",
but providing support for this directly will simplify interleaved
drawing of dashed lines.

An even more general approach would be to allow passing an even-length
vector of lengths and gaps, in addition to offset. Primarily thinking if
it is better to go even further if a new dashed-line-method is
introduced. The second commit introduce this (I can naturally squash
these!).
This commit is contained in:
Oscar Gustafsson 2023-12-23 16:17:04 +01:00 committed by GitHub
parent 76025f2c15
commit fc18d6f8f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 71 additions and 8 deletions

View File

@ -144,12 +144,39 @@ impl Shape {
gap_length: f32,
) -> Vec<Self> {
let mut shapes = Vec::new();
dashes_from_line(path, stroke.into(), dash_length, gap_length, &mut shapes);
dashes_from_line(
path,
stroke.into(),
&[dash_length],
&[gap_length],
&mut shapes,
0.,
);
shapes
}
/// Turn a line into dashes with different dash/gap lengths and a start offset.
pub fn dashed_line_with_offset(
path: &[Pos2],
stroke: impl Into<Stroke>,
dash_lengths: &[f32],
gap_lengths: &[f32],
dash_offset: f32,
) -> Vec<Self> {
let mut shapes = Vec::new();
dashes_from_line(
path,
stroke.into(),
dash_lengths,
gap_lengths,
&mut shapes,
dash_offset,
);
shapes
}
/// Turn a line into dashes. If you need to create many dashed lines use this instead of
/// [`Self::dashed_line`]
/// [`Self::dashed_line`].
pub fn dashed_line_many(
points: &[Pos2],
stroke: impl Into<Stroke>,
@ -157,7 +184,34 @@ impl Shape {
gap_length: f32,
shapes: &mut Vec<Shape>,
) {
dashes_from_line(points, stroke.into(), dash_length, gap_length, shapes);
dashes_from_line(
points,
stroke.into(),
&[dash_length],
&[gap_length],
shapes,
0.,
);
}
/// Turn a line into dashes with different dash/gap lengths and a start offset. If you need to
/// create many dashed lines use this instead of [`Self::dashed_line_with_offset`].
pub fn dashed_line_many_with_offset(
points: &[Pos2],
stroke: impl Into<Stroke>,
dash_lengths: &[f32],
gap_lengths: &[f32],
dash_offset: f32,
shapes: &mut Vec<Shape>,
) {
dashes_from_line(
points,
stroke.into(),
dash_lengths,
gap_lengths,
shapes,
dash_offset,
);
}
/// A convex polygon with a fill and optional stroke.
@ -775,12 +829,16 @@ fn points_from_line(
fn dashes_from_line(
path: &[Pos2],
stroke: Stroke,
dash_length: f32,
gap_length: f32,
dash_lengths: &[f32],
gap_lengths: &[f32],
shapes: &mut Vec<Shape>,
dash_offset: f32,
) {
let mut position_on_segment = 0.0;
assert_eq!(dash_lengths.len(), gap_lengths.len());
let mut position_on_segment = dash_offset;
let mut drawing_dash = false;
let mut step = 0;
let steps = dash_lengths.len();
path.windows(2).for_each(|window| {
let (start, end) = (window[0], window[1]);
let vector = end - start;
@ -792,11 +850,16 @@ fn dashes_from_line(
if drawing_dash {
// This is the end point.
shapes.push(Shape::line_segment([start_point, new_point], stroke));
position_on_segment += gap_length;
position_on_segment += gap_lengths[step];
// Increment step counter
step += 1;
if step >= steps {
step = 0;
}
} else {
// Start a new dash.
start_point = new_point;
position_on_segment += dash_length;
position_on_segment += dash_lengths[step];
}
drawing_dash = !drawing_dash;
}