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

Offset gets really lumpy at large offset deltas. #8

Open
MatthewBlanchard opened this issue Feb 24, 2021 · 6 comments
Open

Offset gets really lumpy at large offset deltas. #8

MatthewBlanchard opened this issue Feb 24, 2021 · 6 comments

Comments

@MatthewBlanchard
Copy link

MatthewBlanchard commented Feb 24, 2021

Capture

The purple ribs here represent the offsets. I didn't really notice this problem until I got editing going in real time. This is with modifications that correct the divide point to be 1/2 of length instead of 1/2 of t, but the results are approximately the same either way.

Capture

This is with the constant inside curve.rs set to like .9999 too. It seems like this just makes the lumpiness higher frequency.

Capture

You can see here it shows up in more reasonable examples too.

I wonder if reducing the curvature of the output beziers as you get further from the curve itself could work? I'm going to try to come up with some method of bringing the handles closer to the output curve as they get farther from the input curve.

It also seems linked more with a change from start -> finish than with the actual value of offset itself as well.

@MatthewBlanchard MatthewBlanchard changed the title Offset gets REALLY lumpy at large offsets. Offset gets really lumpy at large offset deltas. Feb 25, 2021
@MatthewBlanchard
Copy link
Author

Lerping the handles toward the control points by 1. - min(start_offset, end_offset) / max(start_offset, end_offset) does work in getting rid of the lumpiness but it comes with a ton of problems of it's own that make it an unsuitable patch for this. I knew it was a bit naive, but I figured I'd report that I attempted it anyway.

@Logicalshift
Copy link
Owner

It looks like the scaling algorithm starts to break down the larger the difference in offsets: I think there's probably a critical ratio between the start and the end points where the control points start to overlap too much and this effect starts to show up. I suspect it's fixable but I'm going to need to spend some time on it.

In the meantime, though, I've just pushed a new offsetting routine I've been thinking of including for a while that uses the least-mean-squared curve fitting algorithm instead. This makes it possible to use any function for the offset and will always produce really good approximations, but is much slower than the scaling algorithm, and has a slight tendency to produce straight lines if you don't use enough subdivisions. It's called like this:

bezier::offset_lms_sampling(&initial_curve, |t| -((5.0-200.0)*t+200.0), 20, 4.0);

(We can use large values for max_error here I think as we expect the points to already roughly lie on a bezier curve)

Here's a side-by side comparison, old offset in green, new in red, slightly different offsets to make the differences more clear:

Screenshot 2021-02-26 at 21 20 32

@Logicalshift
Copy link
Owner

All that said, I just realised I was using the wrong scale factors for the control points when the offsets were changing. I've fixed this issue too, so the error of that algorithm is now much less. Here's the LMS and the newly fixed scaling algorithm overlaid on top of each other:

Screenshot 2021-02-26 at 22 11 54

I had much less pronounced 'lumpiness' in the example curve I chose, but you can see it has been eliminated here.

The issue was the routine was using the wrong scale factors for moving the control point - they should be scaled with the offsets at t=1/3 and t=2/3 rather than at the start and end of the curve.

@MatthewBlanchard
Copy link
Author

This is an update not to poorly describe another bug (lumpy is not exactly a technical term), but to thank you. The new offset_lms is absolutely fantastic, performant, and it's outputs are more stable as points change. Flo_curves is an awesome library and you are an awesome maintainer. You've replied to every one of my issues. I plan to move as much of my existing math code over to using flo_curve's primitives as they're higher quality than mine.

You mentioned it being slower than the other offset code, but on my system in release mode it takes <1ms to offset a piecewise collection of curves.

The addition of the closure to describe offsets over the curve allowed me to add cosine and cubic interpolation which seriously improves the output by removing discontinuities where the offsets meet. Here is your offset code + a bunch of code I wrote for our editor and stroking library in action:

Modular.Font.Editor.K.Glyph.editor.C__Users_Matt_Documents_GitHub_QStroke_l.glif.2021-03-04.17-49-18.mp4

The results are absolutely great, and the way the new offset handles cusps and strange curvature at control points is much better.

@MatthewBlanchard
Copy link
Author

On the topic of the new offset algorithm I'd definitely add a way to specify tangent offsets too. In my fork I simply made the closure return (f64, f64) and offset by the first along the normal, and the second along the tangent.

@Logicalshift
Copy link
Owner

Hi,

I've now added a function that can do this: distort_curve. It's not quite the same as what you've asked for here, as it just allows for arbitrary displacement along the usual x and y axis instead of the normal axis, but as it provides the t value as well as the location on the curve for each point, it should be reasonably simple to use the tangent and normal to get the effect you're looking for.

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

No branches or pull requests

2 participants