Finding dimensions of a Path2D - javascript

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/

Related

How to mark only one vertex from every triangle in a Delaunay triangulation

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.

Auto adjusting the length of a Bézier curve to meet a predefined length without moving its end points

I'm working on an SVG graphics program where the user can draw a Bézier curve and then define its length with text. By default, when the user defines its new length, I want the endpoints to stay in the same position, and for the curvature of the line to adjust to accommodate the new length (for example, for a cubic bezier curve with points P0,...P3, I want P0 and P3 to stay stationary while the control points move, here's a supporting wikipedia image: http://upload.wikimedia.org/wikipedia/commons/thumb/d/d0/Bezier_curve.svg/600px-Bezier_curve.svg.png).
I am already able to calculate the current length of the curve with svg.js, and have set up a function that will scale length of each control line (P0 -> P1, and P3 -> P2) by a constant to achieve the desired length. This approach has mostly given me the results I'm looking for, but it seems like my scaling factor is off. Based on reading A Primer on Bézier Curves, I have tried using newLength/oldLength as the scaling factor, and I have also tried (newLength/oldLength)^2, both of which got me closer to the user entered length, however I had to do this process 4-5 times to get me closer to the answer I was looking for. I also recognize that this approach (control length scaling) is not full proof, and that there are several edge cases here that this doesn't account for, but I want to conditionally scale the length of this line based on whether the angle and/or length of the control lines is fixed.
I should add that the number of control points that the Bézier curve has is not necessarily fixed, but right now I'm only looking at the cubic case. Higher precision and accuracy is ideal, however it's fine if it's off by a few pixels.

Vectorize Cubic Bezier for 2D WebGL

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

Determining coordinates of quadratic Bezier curve control point given start and end coordinates

I'm working with JavaScript/HTML5 Canvas to recreate an old DOS game, and I'm having trouble with trajectories. I know I'll be using quadraticCurveTo() to draw a quadratic Bezier curve to the canvas, but I'm not great with math, and I'm having trouble determining the coordinates of the control point.
I have the starting coordinates, and I've been able to calculate the distance traveled by the projectile, so I also have the ending coordinates.
So, with these two points, as well as the initial angle, velocity, and gravity, how can I determine the coordinates of the control point?
Disclaimer: This is for my university coursework, and I'd like to stay away from jQuery and other such frameworks

Draw good-looking Bezier Curve through random points

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.

Categories