Maybe some one can give me a little guidance on this.
Bezier Curve Handles
Sep 06 2019 06:04 PM
- Take the start and end points of whatever the player drew and use those to calculate a direction for a basic linear line.
- Then iterate the points recorded and calculate how far from that linear direction the current point is during that iteration. If the point is further away than the furthest currently calculated, remember it. I.e. just maintain a variable during the iterations that remembers the furthest away point.
- As soon as you reach either the end point or a point that's within reasonable range of the linear line, consider this to be the end of that 'wave' and whatever the current 'furthest away' reading is, that's where you need to calculate a handle.
- Make a new table and each time the above determines you're at a key point, log that in the table. I.e. your new table should end up with the starting point, the ending point, and any point between where the distance came close enough to 0 but only if the currently logged 'furthest away' point is outside of that range.
- So say you decide on a range of 10 pixels, (playing around with this figure should result in an optimal 'smoothness', what you're doing is iterating all of the points along the freedrawn route and looking for wave peaks that are further than 10 pixels from a pseudo line between the start and end points, then building a new path of just those peaks and the start and end points of those individual waves.
- Finally, iterate the new data to draw bezier curves between every 4th recorded point, using the 2nd and 3rd points to calculate handles assuming those 4 points equate to an S shape. If they don't then you'd use the 3rd point as the end for that curve I guess.
- The calculated handles of course need to result in the peak of the curve reaching the logged point, you can't just use the logged point as a position for the handle itself. Presumably this is simple math for anybody familiar with bezier curves, but not something I've looked at myself.
I hope this makes enough sense? Again it's just how I'd start to approach the project and is more my thinking out loud than a necessarily correct approach.
If it works, you'd then need to extend it to figure out multiple linear lines rather than just the one, to handle more complex shapes. For example of you drew a spiral or a horse shoe shape, you're no longer looking at waves alone a linear line.
non-trivial. i'd first suggest some sort of straight-line "pruning" pass of your raw points before you even begin (perhaps douglas-peucker) particularly if they're very "noisy" from user input. then i'd suggest fitting the curve with catmull-rom splines (because based only on the points themselves). then convert the cm splines to beziers (assuming you must have beziers). look for a cm implementation with an "s" or "tightness" parameter to correspond roughly as "bezier handle offset".
Richard & Dave,
Thanks for the help. Good suggestions.
Dave, I had tried the catmull-spline code, I will look that over again; I am sure I missed the fine points of that.
Richard, I actually did something very similar to your suggestion ( thought that was/is the way to go)
1. create the straight line from start-point to end-point
2. create a series of ref-points along that line from which I measured 'distance-from-refPoint-to-its-sister-point-in-the-drawn-line'.
3. store the distance value that was the greatest.
4. then if I have that point on the drawn-line I will need to figure the angle to extend to a point away from the curve at some distance and that would be the handle.
mostly I think I just have something wrong in the implementation of that pseudo code or the actual code, because I could not seem to find the furthest point. I was actually hoping there was a formula maybe out there almost custom made for this situation...
I am going to go apply your suggestions and work this out - I am sure these suggestions will help.
late add'l reply - an advantage of c-r splines will be if your paths will require multi-segment (aka composite) beziers to represent them. (ie, they're longer and more "curvy" than a single bezier segment could represent) the headache with beziers is joining them, as you've got to be tangent at both ends where they join or else you'll get a nasty cusp. cr-splines don't have that problem, as they're intrinsically smooth across multiple segments. converting them to bezier segments later is straightforward (if you require it) and potentially simpler than working with beziers alone (where you sort of have to solve the problem "backwards": adjust the handle positions until the curves are tangent = not "difficult" per se, but probably "non-intuitive"). hth
Thanks Dave .. I would look over all that today.
After input from Richard11 and StarCrunch and yourself, some of the comments had me remember a post I did read from 2012 .. just a couple days ago.
this does what i am trying to do, still not fully as smooth as I hope(but clearly cleaner then what a user might draw on screen). And I think it will work. However I still think I can make the line even smoother and cleaner.
I think some of the comments you make about the cr-splines might get the line even smoother... It may be something I add to the results I am getting from the link(quangnle.wordpress) code. (I think!)
I actually found this link several days ago and tried to apply it, but did something wrong and did not get the results I expected or hoped, so put it aside. But after the input from you (Dave, Richard & Star) over the last few days, it made me re-look at that 'Curve Fitting' code.
I just have to fine-tune that and hopefully find a way to make the result line it produces even smoother.
Thanks for taking time to look at this! All 3 of your guys are a great help to the Corona community.
Before I forget, I did grab Le's code from the last post and mess around with it. By doing a pass or two of weighted averaging on the interior points (.25 * previous + .5 * current + .25 * next) you get quite a smooth result. I fixed a minor bug (the break in the curve you see every now and then in the image at the linked page) and also went to town eliminating all the intermediate table garbage.
The updated code is attached, for anyone interested.
There is a little weirdness if you click rapidly / make small drags where it seems to produce a random segment (or from the last point in the previous curve?). Haven't had a chance to look much into it.
Edited by StarCrunch, 01 October 2019 - 12:28 PM.