In SVG:
1. is it possible to create a bezier curve of exactly 180 degrees?
2. can bezier curves commands C and Q do what Arc commands can do?
3. is it possible to create half of a circle using only the following commands: M, m, C, c, Q, q?
My experiments so far show that C commands can create arcs but not perferc arcs like an A command would create.
Exactly? No. The mathematical definition of a Bezier curve means it cannot reproduce a circular arc, no matter how small, perfectly. There's always an error. The first comment to your question links to useful a resource on the issue, http://pomax.github.io/bezierinfo/#circles has an intereactive visual + math explanation.
Based on (1), no. But practically: yes, as long as you use single Bezier curves for small arcs: quadratic curves can only reasonably approximate 1/8th of a full circle before looking wrong, cubic curves can approximate close to 1/3rd before looking wrong. Generally you use a cubic curve for a quarter circle, and then just mirror its coordinates about both axes to get all four sections you need.
Stop asking questions that are ruled out by (1). No, but practically yes; see the links in your comment and this answer =)
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.
In a project of mine I'm drawing a bunch of custom Path2D shapes onto a Canvas. Since I need it to be extensible, to be able to do stuff like perform hit detection on them, and interact with other elements, I need to be able to detect the size of a given Path2D.
As far as I can tell there's no way to do this through Path2D's interface (yet, it's still experimental), does anyone know how I might achieve this, short of requiring the user to specify the width and length themselves when subclassing my class?
Thanks.
For hit detection, you can use context.isPointInPath.
You're correct about Path2D total lengths & bounding boxes...
There's no native Path2D (or html5 canvas) method like SVG's .getTotalLength or .getPointAtLength. Therefore, to calculate total length or bounding boxes you'll have to calculate points along each component of the path.
You probably know (or can Google) that the line has a simple geometric solution to calculate length & bounds given the starting and ending points on the line segment. And the arc has an equally simple geometric arc-length calculation and a simple trigonometric solution to plot points given the center point, radius and the beginning / ending arc angles. Hint: an arc's bounds can be calculated by finding the minimum & maximum x,y values of: the arc's centerpoint and any existing point on the arc at 0, 90, 180 & 270 degrees.
Bezier curves are a bit harder to plot, so here's a hint: Cubic Bezier curves can be plotted using De Casteljau's algorithm. Quadratic Bezier curves can also be plotted using De Casteljau's algorithm--just set the 2 middle control points equal to each other and a Cubic Bezier curve becomes a Quadratic Bezier curve. This is a "brute force" method but a fairly accurate measurement can be obtained by sampling as few as 20 intervals along the curve.
If your design requirements allow more rough approximates, then you will find that cubic Bezier curves are always contained within their control points.
If you're more mathematically inclined, you can also use first derivative roots to more directly calculate the bounds of Bezier curves. For more information, there is an excellent treatise on Bezier Curves here: http://pomax.github.io/bezierinfo/
I am building a 2D cad-like application in Javascript using WebGL and need to allow users to draw cubic bezier curves. My problem is that, as far as I know, WebGL doesn't have any easy way to draw anything but lines and filled triangles.
What makes it more complicated is that I want 'X' number of pixels per segment, and thus will not be able to just iterate through every 1% along the line.
I imagine that this would go something like:
Calculate the total length of the bezier curve
Divide that number by the segments per pixel
Iterate through the bezier curve by the previous number
This is an extremely high performance situation (hundreds of curves at a time), so I can't afford to use a constant number of segments for every curve.
So, my questions are:
Is there any native way to draw a cubic bezier in WebGL?
If not, can anyone help me with the calculations mentioned above, particularly the total length of a cubic bezier curve?
There's no direct way to tell WebGL to "draw a Curve". Just triangles (and lines).
So I think your general approach (Estimate length, divide for desired smoothness, walk the curve) will be good.
You could use a Vertex Shader to do some of the calculations, though. Depending on your data set, and how much it changes, it might be a win.
In WebGL, the vertex shader takes a list of points as input, and produces a same-sized list of points as output, after some transformation. The list cannot change size, so you'll need to figure out the number of subdivisions up in JS land.
The vertex shader could calculate the curve positions, if you assigned each point an attribute "t" between 0 and 1 for the parametric version of the Bezier. Might be handy.
From wikipedia,
As for Bezier length, if we describe it as (p0, p1, p2, p3) where p0 and p3 are the end points and p1 and p2 are the control points, we can quickly say that the Bezier length is at least dist(p0,p3), and at most dist(p0,p1)+dist(p1,p2)+dist(p2,p3).
Could make a fast-guess based on that.
A more thorough discussion for numerical solution is at https://math.stackexchange.com/questions/338463/length-of-bezier-curve-with-simpsons-rule.
There's no closed form solution.
Possibly of interest, I rendered a little Bezier animation for a blog post
I just wanted to add that clearly, we've been rasterizing Bézier curves for a long time, so in addition to the steve.hollasch.net link (http://steve.hollasch.net/cgindex/curves/cbezarclen.html) I pulled from a linked page in #davidvanbrink's answer, I figured there ought to be other resources for this...obviously WebGL/OpenGL adds another dimensional component into finding the appropriate resolution, but this cannot be something that hasn't been attempted before. I think the following links might prove useful.
http://en.wikipedia.org/wiki/NURBS (Non-uniform rational B-spline)
http://antigrain.com/research/adaptive_bezier/index.html (Adaptive Subdivision of Bezier Curves: An attempt to achieve perfect result in Bezier curve approximation)
http://www.neuroproductions.be/experiments/nurbs/
http://threejs.org/examples/webgl_geometry_nurbs.html
This question may be a little difficult to formulate, but here goes:
When using bezierCurveTo in KineticJS, you give it the coordinates of the ending point for the curve as well as for the control points. Is there a simple way to have the curve not actually continue to the specified ending point, but instead stop at another point along the curve?
The reason I ask is because I want to draw a bezier curve and then another on top of it that follows the same curve but doesn't go all the way to the end. Right now all I know how to do is draw a new curve with the new ending point and then guess and check control points until the two curves match up. But this is time consuming and never looks quite perfect.
I don't know about partial Bezier curves, but you could accomplish the same effect by drawing one curve with a stroke gradient. Create two stops at the same point in the gradient to create a hard color line.
var grd=ctx.createLinearGradient(bezStartX,bezStartY,bezEndX,bezEndX);
grd.addColorStop(0,"black");
grd.addColorStop("0.5","black");
grd.addColorStop("0.5","blue");
grd.addColorStop("1","blue");
ctx.strokeStyle=grd;
ctx.beginPath();
ctx.moveTo(bezStartX,bezStartY);
ctx.bezierCurveTo(bexCtrl1X,bezCtrl1Y,bexCtrl2X,bexCtrl2Y,bezEndX,bezEndX);
ctx.stroke();
Edit: This answer shows how to section a Bezier curve.
I'm using javascript with RaphaelJS to draw a smooth line through random points with output to SVG.
The line goes strictly horizontally, without returning back in axis X.
Currently, I'm using cubic Bezier curves to draw the line from one point to another.
Problem is, the line doesn't look good enough. Two curves have an unsightly join at a point, where one curve ends and another curve starts, with quite random angle in the joint.
How do I get the previous curve to transform into next one smoothly, while still keeping the line passing through given point?
Catmull-Rom curves work well for going through points. http://schepers.cc/getting-to-the-point
Cubic splines
If you want to draw lines through points, then you want interpolation. Beziers are cubic curves with off-curve control nodes, but a cubic spline is a set of cubic curves through n points, with smooth changes from each to the next. See the Wikipedia article for more detail on the maths.
To construct a cubic spline through a set of points, you unfortunately have to perform an iterative procedure; you are essentially making n-1 cubic curves and matching their parameters together, which gives you n+1 simultaneous equations to solve. Once you have done that once, as you move the points you can use your previous solution as a starting point.
To do this in Raphael you'll need to generate the cubic spline, then calculate the equivalent Bezier control values for each segment.
There are pieces of javascript out there to calculate cubic splines for you, for example
Cubic splines in JavaScript (via CoffeeScript).
Piecewise polynomial
An alternative to cubic splines is to fit a cubic (or higher) polynomial to each set of a few points; e.g. cubic to each 4 points, including overlaps. So points 10-13 make the cubic for the line from 11 to 12. It will not be as smooth as a cubic spline, but it should be much closer. This is pretty similar to cubic spline, but without equation solve for the curve parameters to make everything smooth.
The problem with piecewise polynomial is that it uses higher order polynomials, which are unstable, and you can get large kinks and wiggles when the points don't lie on polynomial lines or when the points are close together.
To draw this in Raphael you are probably best just sampling the line more frequently and using straight lines to draw it.
Line shape
One big consideration is what kind of line you want to draw. If you just want a smooth line, do cubic spline. But if you are drawing statistics or some other specific kind of line you may be better off looking into gaussian decomposition or other things: Cubic splines are cubic polynomials (ax3 + bx2 + cx + d = 0), so you cannot approximate sine curves very well (audio/signals), or Gaussians (signals/statistics), or exponentials (decay curves, long tail statistics).
What about averaging the angles of the tangents at your points? This gets rid of the 'unsightly joint'.
I recommend you pull out your Foley and van Dam Fundamentals of Interactive Computer Graphics and take a look at the Hermite form for a parametric curve. The Hermite curve is defined by two end-points (which the curve passes through) and two tangent vectors controlling the direction of the curve as it passes through those points. It is readily convertible into Bezier form with a few matrix multiplications, but the advantage is: for smooth joins, adjacent sections of the curve will use exactly the same tangents at coinciding points, whereas with Beziers you have to force three points to be collinear.