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.
Related
Given an array of triangulate points int[][] so that every three points represents a triangle, how can I mark (identify) just one point for each triangle so that no individual triangle has more than one point marked.
I'm trying to add a z-value to each point so that every triangle only has one point elevated and the other points both have a z-value of 0. The reason I don't want any flat triangles is because then my light source will have little to no affect on the triangle because the normal angle is always facing the light.
Here's a video. The mouse cursor represents the light source above (ignore the beginning where the mouse doesn't affect the lighting). You'll notice some of the triangles have a constant color to them since all its point have a z-value of 0.
https://streamable.com/w5spi
I've tried just adding a point to the centroid of the triangle and creating three new triangles, but it messes with the uniformity of the triangle spacing.
Since Delaunay doesn't provide any simple mean to generate depth, I would suggest using a combination of a Simplex noise function and the Delaunay triangle points.
This way you can "map" the two on top of each other, extract a value underneath the normalized Delaunay triangle points from the Simplex noise function and use that for Z/elevation.
Principle: normalize triangle points from Delaunay, extract Z via the SN function using the normalized x/y position.
There are many Simplex Noise implementations out there for JavaScript. It's worth noting that the 3D version has a patent attached if using the techniques described within the patent. See OpenSimplex noise for an alternative if 3D is needed - npm - in this case though, the 2D version will probably be enough.
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
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 =)
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.