I'm trying to decompose a b-spline to a set of circle definitions.
I'm trying to generate G-code; the idea here is to segment a b-spline into a number of circular interpolations [ G02 ]. Using PythonOCC I can break up the b-spline into a number of beziers curves, but I don't know how to translate the bezier into circular sections.
Thanks
Maybe not the most scientific approach but it worth a look: http://rocksolidperspective.com/2010/02/17/making-splines-work-in-manufacturing/
Related
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.
Given an ordered list of points, I want to draw a smooth curve that passes through all of them. Each part of the curve can either be horizontal, vertical, or an arc with given radius r (all arcs will have the same radius). The transitions should be smooth, i.e., the heading at the end of one part should be the same as the heading at the beginning of the next part. There can be any number of arcs or straight line segments between any two consecutive input points.
It's sort of like a train track that should run orthogonally or along sections with fixed curvature.
Is there a good algorithm to construct such a curve? (or, in cases where such a line is not possible, I would like to know that.)
I looked into Bezier curves, but that seems like overkill and I couldn't find a good way to enforce my constraints.
What you are asking for above implies to me that you seek tangent continuity of your curve across points (similar to a spline with tangent continuity at knots). The train track analogy at least conveys this requirement. Given the strict limitations of straight lines, and fixed radius circular arcs I am fairly certain that you will not be able to do this. Why not consider a spline interpolation of your points if you require such smoothness instead?
To see why consider the following image:
Consider replacing the line segment between B and C with a circular arc. You can do it to make the join continuous, but to make it tangent continuous, you would need a great deal of good fortune as there is only one circle that is tangent continuous to the line segment AB that also touches point C. The chances of that circle having tangent at C matching the tangent of line CD is remote. It is possible that your data will line up like this but you cannot rely on it.
If I have misunderstood your question please let me know and I will adjust the answer.
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.
I have a Cubic Bézier curve. But I have a problem when I need only one point. I have only value from the X-axis and want to find a value that coresponds to Y-axis to that point. Or find the t step, from it I can easely calculate the Y-axis.
Any clue how to do it? Or is there any formula to do this?
Any solution will have to deal with the fact that there may be multiple solutions if the curve is not X monotone. Consider the cubic bezier (0,0),(2,0),(-1,1),(1,1):
As you can see, there are 4 parameter values (and Y coordinates) at which X==1/2.
This means that if you use subdivision (which is probably your simplest solution), then you need to be careful that your initial bounding t values only surround the point you want.
You can also guess what this implies about the order of an algebraic solution.
A parametric curve extends to any dimension by adding coefficients for those dimensions. Are you sure you've got things straight? It seems like you are using the x-axis as the curve parameter t. The t parameter controls the computations of X- and Y-coordinates by having two cubic equations. Take a look at Wikipedia which provides some pretty neat explanations for the 2D case.
Edit:
Solve as a general third-degree polynomial. Beware that it might have 3 solutions, though.
I'm trying to find/make an algorithm to compute the intersection (a new filled object) of two arbitrary filled 2D objects. The objects are defined using either lines or cubic beziers and may have holes or self-intersect. I'm aware of several existing algorithms doing the same with polygons, listed here. However, I'd like to support beziers without subdividing them into polygons, and the output should have roughly the same control points as the input in areas where there are no intersections.
This is for an interactive program to do some CSG but the clipping doesn't need to be real-time. I've searched for a while but haven't found good starting points.
I found the following publication to be the best of information regarding Bezier Clipping:
T. W. Sederberg, BYU, Computer Aided Geometric Design Course Notes
Chapter 7 that talks about Curve Intersection is available online. It outlines 4 different approaches to find intersections and describes Bezier Clipping in detail:
https://scholarsarchive.byu.edu/cgi/viewcontent.cgi?article=1000&context=facpub
I know I'm at risk of being redundant, but I was investigating the same issue and found a solution that I'd read in academic papers but hadn't found a working solution for.
You can rewrite the bezier curves as a set of two bi-variate cubic equations like this:
∆x = ax₁*t₁^3 + bx₁*t₁^2 + cx₁*t₁ + dx₁ - ax₂*t₂^3 - bx₂*t₂^2 - cx₂*t₂ - dx₂
∆y = ay₁*t₁^3 + by₁*t₁^2 + cy₁*t₁ + dy₁ - ay₂*t₂^3 - by₂*t₂^2 - cy₂*t₂ - dy₂
Obviously, the curves intersect for values of (t₁,t₂) where ∆x = ∆y = 0. Unfortunately, it's complicated by the fact that it is difficult to find roots in two dimensions, and approximate approaches tend to (as another writer put it) blow up.
But if you're using integers or rational numbers for your control points, then you can use Groebner bases to rewrite your bi-variate order-3 polynomials into a (possibly-up-to-order-9-thus-your-nine-possible-intersections) monovariate polynomial. After that you just need to find your roots (for, say t₂) in one dimension, and plug your results back into one of your original equations to find the other dimension.
Burchburger has a layman-friendly introduction to Groebner Bases called "Gröbner Bases: A Short Introduction for Systems Theorists" that was very helpful for me. Google it. The other paper that was helpful was one called "Fast, precise flattening of cubic Bézier path and offset curves" by TF Hain, which has lots of utility equations for bezier curves, including how to find the polynomial coefficients for the x and y equations.
As for whether the Bezier clipping will help with this particular method, I doubt it, but bezier clipping is a method for narrowing down where intersections might be, not for finding a final (though possibly approximate) answer of where it is. A lot of time with this method will be spent in finding the mono-variate equation, and that task doesn't get any easier with clipping. Finding the roots is by comparison trivial.
However, one of the advantages of this method is that it doesn't depend on recursively subdividing the curve, and the problem becomes a simple one-dimensional root-finding problem, which is not easy, but well documented. The major disadvantage is that computing Groebner bases is costly and becomes very unwieldy if you're dealing with floating point polynomials or using higher order Bezier curves.
If you want some finished code in Haskell to find the intersections, let me know.
I wrote code to do this a long, long time ago. The project I was working on defined 2D objects using piecewise Bezier boundaries that were generated as PostScipt paths.
The approach I used was:
Let curves p, q, be defined by Bezier control points. Do they intersect?
Compute the bounding boxes of the control points. If they don't overlap, then the two curves don't intersect. Otherwise:
p.x(t), p.y(t), q.x(u), q.y(u) are cubic polynomials on 0 <= t,u <= 1.0.
The distance squared (p.x - q.x) ** 2 + (p.y - q.y) ** 2 is a polynomial on (t,u).
Use Newton-Raphson to try and solve that for zero. Discard any solutions outside 0 <= t,u <= 1.0
N-R may or may not converge. The curves might not intersect, or N-R can just blow up when the two curves are nearly parallel. So cut off N-R if it's not converging after after some arbitrary number of iterations. This can be a fairly small number.
If N-R doesn't converge on a solution, split one curve (say, p) into two curves pa, pb at t = 0.5. This is easy, it's just computing midpoints, as the linked article shows. Then recursively test (q, pa) and (q, pb) for intersections. (Note that in the next layer of recursion that q has become p, so that p and q are alternately split on each ply of the recursion.)
Most of the recursive calls return quickly because the bounding boxes are non-overlapping.
You will have to cut off the recursion at some arbitrary depth, to handle weird cases where the two curves are parallel and don't quite touch, but the distance between them is arbitrarily small -- perhaps only 1 ULP of difference.
When you do find an intersection, you're not done, because cubic curves can have multiple crossings. So you have to split each curve at the intersecting point, and recursively check for more interections between (pa, qa), (pa, qb), (pb, qa), (pb, qb).
There are a number of academic research papers on doing bezier clipping:
http://www.andrew.cmu.edu/user/sowen/abstracts/Se306.html
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.61.6669
http://www.dm.unibo.it/~casciola/html/research_rr.html
I recommend the interval methods because as you describe, you don't have to divide down to polygons, and you can get guaranteed results as well as define your own arbitrary precision for the resultset. For more information on interval rendering, you may also refer to http://www.sunfishstudio.com