How to offset a cubic bezier curve? - graphics

I'm trying to create a "parrallel" bezier curve. In my attempts I've gotten close but no cigar. I'm trying to keep a solid 1px offset between the 2 curves (red,blue).
My main goal is use a edge offseting algorythm to expand/shrink a svg path.
Solution
For anyone else who is looking for a solution, I've create a AS3 version.
http://seant23.wordpress.com/2010/11/12/offset-bezier-curves/

I hope you found my math paper useful
Quadratic bezier offsetting with selective subdivision
https://microbians.com/mathcode

From wikipedia: ( http://en.wikipedia.org/wiki/B%C3%A9zier_curve )
The curve at a fixed offset from a given Bézier curve, often called an offset curve (lying "parallel" to the original curve, like the offset between rails in a railroad track), cannot be exactly formed by a Bézier curve (except in some trivial cases). However, there are heuristic methods that usually give an adequate approximation for practical purposes.
You might also see the paper indicated here:
Outline of cubic bezier curve stroke

What you ask for is called a parallel or offset curve in mathematics. The Wikipedia article (quoted above by others) on Bezier curves failed to link to the right article for "offset curve", but I've fixed that a few seconds ago. In the world of vector graphics, that same notion is called stroking the path.
In general, for cubic/Bezier curve the offset curve is a 10th order polynomial! Source: Kilgard, p. 28
If all you want to do is rasterize such offset curves, rather than compute their analytic form, you can for example look at the sources of ghostscript. You could also look at this patent application to see how NV_path_rendering does it.
If you want to covert/approximate the offset curves, then the TUG paper on MetaFog for covering METAFONT to PostScript fonts is a good reading. The METAFONT system, which predated PostScript allowed fonts to be described by the (more mathematically complex) operation of stroking, but PostScript Type 1 fonts only allow filling to be used (unlike PostScript drawings in general) for reasons of speed.
Another algorithm for approximating the offsets as (just two) Beziers (one on each side), with code in PostScript, is given in section 7 of this paper by Gernot Hoffmann. (Hat tip to someone on the OpenGL forum for finding it.)
There are in fact a lot of such algorithms. I found a 1997 survey of various algorithms for approximating offset curves. They assume the progenitor curves are Beziers or NURBS.

It's not possible in general to represent the offset of a cubic Bezier curve as a cubic Bezier curve (specifically, this is problematic when you have cusps or radius of curvature close to the offset distance). However, you can approximate the offset to any level of accuracy.
Try this:
Offset the Beziers in question (what you have already seems pretty decent)
Measure the difference between each original curve and corresponding offset curves. I'd try something like 10 samples and see if it works well.
For any offset that's outside of tolerance, subdivide (using the deCastlejau algorithm for Beziers) and iterate.
I haven't implemented an offset (because the kernels I use already have one), but this seems like something to try.

Related

Perspective transform for SVG path with Bezier curves

I followed this thread here (unfortunately its very old, ancient I would say):
Perspective transform of SVG paths (four corner distort)
And this thread contains great pdf explaining how calcuations are done (see below).
Question: in the original post author says the approach will work for simple paths but not arcs. Can someone help me understand - would the approach work for Bezier curves? The font used in the example obviously is using curves though...
One can apply affine transformations to the control points of Bezier curve and get transformed Bezier curve.
But perspective transformations are not applicable to "usual" (used in fonts) Bezier curves - they produce rational Bezier curves.

Find the closest point on a curve to a given point

The curve is in fact the trajectory of a bus, the curve is represented by many (up to a few thousand) discrete points on the curve (the points were recorded by a GPS device installed on the bus).
Input a point P, I need to find the closest point on the curve to the point P. The point P is usually no more than 30m away from the trajectory of the bus. Note, the closest point isn't necessary a point recorded by the GPS device, it could be a point somewhere between two recorded points.
First I need an algorithm to recover the trajectory from those recorded points. It would be great if the interpolated curve could show sharp turns made by the bus. Which curve is best for such task ? Is Bezier curve good enough ? And finally I have to calculate the closest point on the curve, of course the algorithm completely depends on the kind of curve chosen.
I'm doing some research, and don't have much knowledge in curve interpolation, so any suggestions are welcome.
For computing the trajectory from recorded points, I recommended using the centripetal or chord-length Catmull-Rom splines. See link for more details. Catmll-Rom splines are in fact special cubic Hermite curves, which can be easily converted into cubic Bezier curves. Please note that the result from Catmull-Rom spline is a G1 curve only in general. If you want the trajectory to be with higher continuity (such as C2), you can go with natural cubic splines or general B-spline interpolation. Whatever approach you take, it is advised to keep the spline's degree no higher than 5. Degree 3 is a popular choice.
Once you have the mathematical representation for the trajectory, you can compute the minimum distance between a given point P and the trajectory. In general, the squared distance between point P and a curve C(t) is represented as D(t) = |P-C(t)|^2. The minimum of D will happen at where its first derivative is zero, which means we have to find the root for the following equation:
dD/dt = 2*(P-C(t)).C'(t) =0
When C(t) is of degree 3, dD/dt will be of degree 5. This is the reason why it is recommended to use a low degree curve earlier.
There are many literatures or online materials talking about how to find the root of a polynomial (of any degree) efficiently and robustly. Here is another SO post that might be useful.

Choosing step for Bezier curve drawing

Bezier curve is a parametric curve, meaning that there is a paramater t at which one can evaluate the polynomials in order to find out the positions of points laying on the curve.
Polynomials for some common cases can be found at en.wikipedia.org/wiki/B%C3%A9zier_curve#Specific_cases
To draw a Bezier curve on screen, one could evaluate the polynomials from 0 to 1 at ever increasing t by tiny little steps. However, that would very wasteful because, in general, the parameter "space" does not correspond to screen "space", i.e. several little steps may fall onto just one pixel.
My question is: how to find the smallest step which increases Cartesian distance from previous point at least by 1 pixel?
To put it in other way: I would like to draw a Bezier curve on screen. How to choose the (uniform) step by which t should grow so that I never draw at one pixel more the once? I don't mind the "holes" when the t grows too quickly, I just don't want to redraw already drawn pixels.
Edit
By "how to find" I mean O(1). Yes, I could use De Casteljau's algorithm but I was hoping there is a way to "guess" the optimal t step quickly.
The comment above (jozxyqk) gives you a hint. I would give it a try with a recursive binary division of the spline drawing.
Lets say you start with a coarse resolution of the parameter space (delta_t = 0.1), that gives you 11 points on the spline curve s , s(t=0), s(t=0.1), ..., s(t=0.9), s(t=1).
Calculate the distance between s(t_i) and s(t_i+1). If it is >1 than make a binary subdivision between those two points. And so on...
But honestly, I guess it is faster to calculate all points a a higher resolution without any recursive loops or subdivisions. Especially if you are using multithread programming.

How to get the outline of a stroke? [duplicate]

This question already has answers here:
svg: generate 'outline path'
(2 answers)
Closed 5 years ago.
I want to convert a stroked path to a filled object. (Programmatically, in JavaScript.)
The line is just a simple curved line, a sequence of coordinates. I can render this line as a path, and give it a stroke of a certain thickness... but I'm trying to get a filled shape rather than a stroked line, so that I can do further modifications on it, such as warping it, so the resulting 'stroke' might vary in thickness or have custom bits cut out of it (neither of these things are possible with a real SVG stroke, as far as I can tell).
So I'm trying to manually 'thicken' a line into a solid shape. I can't find any function that does this – I've looked through the docs of D3.js and Raphaël, but no luck. Does anyone know of a library/function that would do this?
Or, even better: if someone could explain to me the geometry theory about how I would do this task manually, by taking the list of line coordinates I have and working out a new path that effectively 'strokes' it, that would be amazing. To put it another way, what does the browser do when you tell it to stroke a path – how does it work out what shape the stroke should be?
There has been a similar question recently:
svg: generate 'outline path'
All in all, this is a non-trivial task. As mentioned in my answer to the linked question, PostScript has a command for generating paths that produce basically the same output as a stroke, called strokepath. If you look at what Ghostscript spits out when you run the code I posted at the linked question, it's pretty ugly. And even Inkscape doesn't really do a good job. I just tried Path => Outline stroke in Inkscape (I think that's what the English captions should say), and what came out didn't really look the same as the stroked path.
The "simplest" case would be if you only have non-self-intersecting polylines, polygons or paths that don't contain curves because in general, you can't draw exact "parallel" Bézier curves to the right and the left of a non-trivial Bézier curve that would delimit the stroked area - it's mathematically non-existent. So you would have to approximate it one way or the other. For straight line segments, the exact solution can be found comparatively easily.
The classic way of rendering vector paths with curves/arcs in them is to approximate everything with a polyline that is sufficiently smooth. De Casteljau's Algorithm is typically used for turning Bézier curves into line segments. (That's also basically what comes out when you use the strokepath command in Ghostscript.) You can then find delimiting parallel line segments, but have to join them correctly, using the appropriate linejoin and miterlimit rules. Of course, don't forget the linecaps.
I thought that self-intersecting paths might be tricky because you might get hollow areas inside the path, i.e. the "crossing area" of a black path might become white. This might not be an issue for open paths when using nonzero winding rule, but I'd be cautious about this. For closed paths, you probably need the two "delimiting" paths to run in opposite orientation. But I'm not sure right now whether this really covers all the potential pitfalls.
Sorry if I cause a lot of confusion with this and maybe am not of much help.
This page has a fairly good tutorial on bezier curves in general with a nice section on offset curves.
http://pomax.github.io/bezierinfo/
A less precise but possibly faster method can be found here.
http://seant23.wordpress.com/2010/11/12/offset-bezier-curves/
There is no mathematical answer, because the curve parallel to a bezier curve is not generally a bezier curve. Most methods have degenerate cases, especially when dealing with a series of curves.
Think of a simple curve as one with no trouble spots. No cusps, no loops, no inflections, and ideally a strictly increasing curvature. Chop up all the starting curves into these simple curves. Find all the offset curves of these simple curves. Put all the offset curves back together dealing with gaps and intersections. Quadratic curves are much more tractable if you have the option to work with them.
I think most browsers do something similar to processingjs, as they have degenerate cases even with quadratic curves. For example, look at the curve 200,300 719,301 500,300 with a thickness of 100 or more.
The standard method is the Tiller-Hanson algorithm (Offsets of Two-Dimensional Profiles, 1984, which irritatingly is not on line for free) which creates a good approximation. The idea is that because the control points of each Bezier curve lie on lines tangent to the start and end of the curve, a parallel curve will have the same property. So we offset the start and the end of the curve, then find new control points using these intersections. However, that gives very bad results for sharp curves, so the first step is to bisect the original curve, which is very easy to do to Bezier curves, until it turns through a sufficiently small angle.
Other refinements are needed to deal with (i) intersections between the parallels, on the inside of each vertex; (ii) inserting an arc of a circle to fill the gap on the outside of each vertex; and (iii) adding end-caps - square, butt or circular.
Tiller-Hanson is difficult to implement, but there's a good open-source implementation in the FreeType library, in ftstroke.c (http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/base/ftstroke.c).
I'm sorry to say that it can be quite difficult to integrate this code, but I have used it successfully, and it works well.

How to calculate control points for cubic curve, which approximates an elliptic arc?

Almost all vector graphics applications (like Corel) approximate elliptic arcs with several cubic Bezier curves. I need to add similar functionality to my application. So my question is: how to calculate control points of that Bezier curve?
There are lots of pages explaining how to do this. This paper by Don Lancaster, for example, gives control parameters for divisions of an ellipse into between 2 and 8 cubic splines, with a detailed analysis of the 4-spline case.

Resources