Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First cut at stroke expansion #286

Merged
merged 9 commits into from
Jun 27, 2023
Merged

First cut at stroke expansion #286

merged 9 commits into from
Jun 27, 2023

Conversation

raphlinus
Copy link
Contributor

This is a starting point; no dashes, only butt and miter, and closed paths are also not yet implemented.

Also not tested yet.

Will close #285

This is a starting point; no dashes, only butt and miter.

Also not tested yet.

Will close #285
src/stroke.rs Outdated Show resolved Hide resolved
Fix some todo() items. Reverse forward and backward so area is positive. Implement line caps and joins.

Make end_point a public method of `PathEl`, as suggested.

Dashes remain, as well as closed paths.
Handle stroking of closed subpaths. This generates two closed subpaths as output, one for the inner contour, one for the outer.

Also apply a threshold for joins.
This should handle closed paths and phase, but do need to validate.
@raphlinus raphlinus marked this pull request as ready for review June 1, 2023 00:21
Add an additional argument to stroke expansion. It's designed so it can be Default::default() in the common case, and uses the builder pattern to add more options as needed without breaking semver.
Copy link
Contributor

@notgull notgull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to this. I need a stroking algorithm for my piet implementations that supports dashing. Both tiny-skia and zeno produce invalid output when I try to use them for all (although I may just be all thumbs in these cases).

@@ -17,6 +17,9 @@ features = ["mint", "schemars", "serde"]
default = ["std"]
std = []

[dependencies]
smallvec = "1.10"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think tinyvec would be better if possible since it has no unsafe code.

}

/// Collection of values representing lengths in a dash pattern.
pub type Dashes = SmallVec<[f64; 4]>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be better to do three dashes by default, since on 64 bit platforms there would be no wasted stack space compared to a Vec.

@notgull
Copy link
Contributor

notgull commented Jun 25, 2023

piet-glow-03-2 00

Looks like it's skipping some segments? For comparison, here's what piet-samples looks like:

sample

@notgull
Copy link
Contributor

notgull commented Jun 25, 2023

In addition, I'm getting stack overflows in this function under certain dash patterns. Standby for more details

@raphlinus
Copy link
Contributor Author

raphlinus commented Jun 25, 2023

Are you also patching #289 with the stack overflows? We need to get these landed, then consider more improvements on the remaining failures. That integration is now nontrivial, you have to explicitly opt in to the regularize behavior.

I'll also add, I appreciate clear actionable reports of any variance of the kurbo method from the accepted behavior - I've done a bit of manual testing but not a careful validation or test suite. (A test suite is also welcome)

Copy link
Contributor

@dfrg dfrg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really solid foundation! Let’s land it, propagate the stroke type through peniko, and hook it up to vello so we have a nice playground for working through the remaining issues.

src/stroke.rs Outdated
}

/// Expand a stroke into a fill.
pub fn stroke(path: impl IntoIterator<Item = PathEl>, style: &Stroke, tolerance: f64) -> BezPath {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we want to add an additional options parameter to this? I believe one use was to toggle optimal curve fitting.

src/stroke.rs Outdated
}
}
PathEl::CurveTo(p1, p2, p3) => {
if p1 != p0 && p2 != p0 && p3 != p0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per f2f this appears to be too strict. For example, there are valid cases where p1 == p0. Same above for the quad case.

}
PathEl::CurveTo(p1, p2, p3) => {
if p1 != p0 && p2 != p0 && p3 != p0 {
let c = CubicBez::new(p0, p1, p2, p3);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

friendly note: .regularize() :)

Wire up regularization in parallel curve generation (now merged into branch). Fix zero length segment detection (it was overly eager, also triggering on degenerate tangents).

In response to review comments.
src/stroke.rs Outdated
// while a value too small may fail to generate smooth curves. This is a somewhat
// arbitrary value, and should be revisited.
const DIM_TUNE: f64 = 0.25;
let co = CubicOffset::new_regularized(c, 0.5 * style.width, tolerance * DIM_TUNE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m confused as to why is this done here and only for the backward path? In my testing version, I called regularize on the initial cubic itself in stroke_undashed before computing the tangents for joins. My assumption was that regularize fixes zero length tangent vectors and we would want consistency there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simple brain fart error. I should have validated this more carefully before pushing. Thanks for the catch!

Copy link
Contributor

@dfrg dfrg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Let’s merge this and I’ll find some time soon to do serious stress testing and we’ll work out the remaining issues.

@raphlinus raphlinus merged commit aa999f7 into master Jun 27, 2023
13 checks passed
@raphlinus raphlinus deleted the stroke branch September 14, 2023 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Stroke expansion
4 participants