Draw curve -> Get equation - javascript

A part of the project I am working on requires an interface where a user draws a curve, and I want to output an approximate mathematical equation of that curve to perform a variety of tests on it.
I have thought of 2 approaches so far and was wondering if they are feasible or if there exists a better way of approaching the problem that I am missing/ cool mathematical trick that allows me to pull this off.
Approach 1:
Instead of having users draw a curve, give them the option of inserting bezier curve points and tweaking them to make their curve. Since bezier curves have a parametric equation that describes them, I could directly get the exact equation.
Cons:
-It's more cumbersome for users to tweak and make a bezier than simply draw a curve
Approach 2:
Get the curve drawn and extract 'n' points. (I don't think this should be hard to do).
Somehow go from these 'n' points to an equation of a curve passing through them. Naturally 'n' would be pretty large, say 100.
Is there a neat way to get an equation for the "simplest continuous function" passing through 'n' points?

Approach 1 -- insert Bezier points and tweak control points -- is used in a lot of vector drawing programs, especially CAD-type applications where precision is important and points are laid out on a grid, etc. It is a slower way to draw, but it's used in these situations, because it's really difficult to draw a freehand curve carefully.
Approach 2 -- just draw and get an smooth approximation -- is also pretty popular when precision isn't required. I'm not sure what methods are usually used for this, or even if there is a "usually", but I don't think it's particularly difficult to do a pretty good job. I would:
Connect all the points with line segments in the order in which they were drawn.
Apply the Ramer-Douglas-Peucker algorithm to reduce the number of points.
Interpolate the points with cubic spline interpolation. Be careful looking this up-there are many flavors of cubic spline interpolation and their names overlap. I would specifically prefer the versions that preserve 2nd derivative continuity.

Related

GC friendly convex clipping (union and difference) algorithm

I'm looking for algorithm that will cut my convex polygon based on another convex polygon. It is gonna be for destructible terrain (diff) and for creating terrain (union) in 2D map in game.
Algorithm has to be Garbage Collector friendly and the only boolean operations that are neccessary are Union & Difference.
I've done some research and there are some github projects, but all of them produce some garbage more or less.
https://github.com/tmpvar/2d-polygon-boolean
https://github.com/w8r/GreinerHormann
I guess the best solution would be to learn one of these and re-make it my way. But maybe you've heard about some that suits my needs?
Thanks.
This problem involves two subproblems
find the intersection points between the two outlines
join the vertices that mus be joined.
For 1. you can exploit convexity: see both polygons as two monotone chains. When you travel the chains of the twopolygons simultaneously, say by increasing x, the intersections are detected when the ordinates cross each other between two abscissas.
For 2. notice that the union or difference are made of portions of the outlines alternating between one polygon and the other, at every interesection point.
Note that in the case of the difference, there can be several disconnected pieces.
I guess that you can implement this without any allocation/deallocation at all (but for the output polygon).

How to reduce the number of points in bezier curve paths

I have a large svg path which has quadratice bezier curves.
The path data is used for drawing maps.
How to reduce the number of points of the bezier curve without distorting the overall shape?
You don't say whether you want to do this offline (pre-prepared paths) or online (on the fly). If offline is fine, use a tool like Inkscape.
If you want to calculate the simplified curve yourself, then the typical algorithm used to do this is also the same one that has been used for drawing bezier curves. The algorithm is called "flattening".
Basically the idea is to convert the bezier curves to a series of straight line segments. Because you don't want the the flatness of the line segments to be visible, you have to take into account the scale of the drawing and how curvy the bezier is. If the bezier is very curvy you have to use more line segments than if it is fairly straight.
What you typically do is divide each bezier into two using De Casteljau's algorithm. Then look at each of the two half bezier curves. If a bezier is straight enough to meet a flatness limit you decide on, then stop dividing. Otherwise, divide in half and try again.
At the end of the process you should get a polyline that is indistinguishable from the bezier version. Or if you use a "flatness test" that is a bit courser than that, you will get a rougher approximation of the shape. In your case a map.
If you google bezier flattening you can find a number of papers on the technique. And a few pages which describe how to do it in a more friendly accessible way. For example this one, which is about generating offset curves, but starts out by describing how to flatten a curve:
https://seant23.wordpress.com/2010/11/12/offset-bezier-curves/

Convert a B-Spline into Bezier curves

I have a B-Spline curve. I have all the knots, and the x,y coordinates of the Control Points.
I need to convert the B-Spline curve into Bezier curves.
My end goal is to be able to draw the shape on an html5 canvas element. The B-Spline is coming from a dxf file which doesn't support Beziers, while a canvas only supports Beziers.
I've found several articles which attempt to explain the process, however they are quite a bit over my head and really seem to be very theory intensive. I really need an example or step by step help.
Here's what I've found:
(Explains B-Splines),(Converting to Beziers),(Javascript Example)
The last link is nice because it contains actual code, however it doesn't seem to take into account the weight assigned by the nodes. I think this is kind of important as it seems to influence whether the curve passes through a control point.
I can share my Nodes or Control Points if that would be useful. If someone would point me to a step-by-step procedure or help me with some psuedo(or actual)code, I would be so grateful.
I wrote a simple Javascript implementation of Boehm's algorithm for cubic B-Splines a while back. It's a fairly straightforward implementation involving polar values, described here in section 6.3: Computer Aided Geometric Design- Sederberg
If you're just interested in the implementation, I've linked the classes I wrote here: bsplines.js
This could be helpful - https://github.com/Tagussan/BSpline
My project has moved on and I no longer need it, but this seems to be a pretty useful way to feed control points and have a curve drawn.

Plotting mathematical functions without rendering artefacts

I don't think there's a good answer to this, but I'd like to find out if there's a better way to do this.
I need to plot a mathematical function, which is nearly flat at one end of the display, and nearly vertical at the other end. The bottom left quadrant of a circle would be a good model. I can auto-generate as many points as required.
The problem is, I can't do this without all sorts of artefacts.
I haven't tried Bezier fitting; I don't think this would be even close. My understanding is that Bezier is for one-off manually-constructed pretty graphics, and not for real curve-fitting.
That leaves polylines. There are only 2 things I can do with polylines - I can select the line length (in other words, the number of points I auto-generate), and I can disable anti-aliasing (setAttributeNS(null, "shape-rendering", "crisp-edges").
If I generate lots of points, then I get jaggies everywhere, and the result is unusable. It can also look very much like it's oscillating, which makes it appear that I've incorrectly calculated the function. The anti-aliasing doesn't make any difference, since it doesn't operate across point boundaries.
The only solution I've got is to draw fewer points, so that it's obvious that I'm drawing segments. It's no longer smooth, but at least there are no jaggies or oscillation. I draw this with the default anti-aliasing.
Any ideas?
Edit:
It seems like the only answer to this is actually Bezier curve fitting. You have to preprocess to find the parameters of the required segments, and then plot the results. Google comes up with a number of hits on curve fitting with Beziers.
You have the mathematical function, and can therefore generate as many points as you need.
I assume the problem is that because you do not know the output resolution (SVG is device independent) you do not know how many points to generate. Otherwise you could just create a polyline where each line is approximately 1 pixel long.
Fitting your mathematical function to a bezier curve is (probably) not going to get a perfect match - just like a circle cannot be matched perfectly by a cubic bezier curve. And I think the task of fitting your function to a bezier curve would not be trivial (I've never done this).
Could you rather output your mathematical function to a canvas element? Then you could write some javascript code to plot your mathematical function dependant on the output resolution. Similar to how a graphics system renders a Bezier curve.
Do you know how graphics systems render Bezier curves? They approximate the bezier curve with a polyline, and then measure the error difference between the polyline and the bezier curve. If the difference is greater than a certain tolerance - where the tolerance is determined by the output resolution - the bezier is subdivided and the process repeated for each bezier curve. When the difference between beziers and polylines is below the tolerance, the polylines are drawn. http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Computer_graphics
I suppose you want to draw y=f(x) over a certain interval [a,b]
A classical solution is to take N points uniformly distributed over [a,b], to compute f over these points and draw lines (or polynoms).
It of course doesn't work in your case, since y is nearly vertical in certain area. But why don't you take more points in these areas (and less points where the function is nearly horizontal) ?
You can compute the derivative of your function (or approximate this derivative with (f(x+h)-f(x))/h and h small) and determine the step between two successive points with this derivative

how to "sort" polygons 3d?

I am still working on my "javascript 3d engine" (link inside stackoverflow).
at First, all my polygons were faces of cubes, so sorting them by average Z was working fine.
but now I've "evolved" and I want to draw my polygons (which may contain more than 4 vertices)
in the right order, namely, those who are close to the camera will be drawn last.
basically,
I know how to rotate them and "perspective"-ize them into 2D,
but don't know how to draw them in the right order.
just to clarify:
//my 3d shape = array of polygons
//polygon = array of vertices
//vertex = point with x,y,z
//rotation is around (0,0,0) and my view point is (0,0,something) I guess.
can anyone help?
p.s: some "catch phrases" I came up with, looking for the solution: z-buffering, ray casting (?!), plane equations, view vector, and so on - guess I need a simple to understand answer so that's why I asked this one. thanks.
p.s2: i don't mind too much about overlapping or intersecting polygons... so maybe the painter's algorthm indeed might be good. but: what is it exactly? how do I decide the distance of a polygon?? a polygon has many points.
The approach of sorting polygons and then drawing them bottom-to-top is called the "Painter's algorithm". Unfortunately the sorting step is in general an unsolvable problem, because it's possible for 3 polygons to overlap each other:
Thus there is not necessarily any polygon that is "on top". Alternate approaches such as using a Z buffer or BSP tree (which involves splitting polygons) don't suffer from this problem.
how do I decide the distance of a polygon?? a polygon has many points.
Painter's algorithm is the simplest to implement, but it works only in very simple cases because it assumes that there is only a single "distance" or z-value for each polygon (which you could approximate to be the average of z-values of all points in the polygon). Of course, this will produce wrong results if two polygons intersect each other.
In reality, there isn't a single distance value for a polygon -- each point on the surface of a polygon can be at a different distance from the viewer, so each point has its own "distance" or depth.
You already mentioned Z-buffering, and that is one way of doing this. I don't think you can implement this efficiently on a HTML canvas, but here's the general idea:
You need to maintain an additional canvas, the "z-buffer", where each pixel's colour represents the z-depth of the corresponding pixel on the main canvas.
To draw a polygon, you go through each point on its surface and draw only those points which are closer to the viewer than any previous objects, as indicated by the z-buffer.
I think you will have some ideas by investigating BSP tree ( binary spaces partition tree ), even if the algo will require to split some of your polygon in two.
Some example could be find here http://www.devmaster.net/articles/bsp-trees/ or by google for BSP tree. Posting some code as a reply is, in my opinion, not serious since is a complex topic.

Categories

Resources