General formula to generate a cubic bezier elliptical arc? - c++

How could I implement in C a simple way to generate the 2 missing control points for an elliptic arc given a start and end point? I don't need fancy error estimation, just something that can take points A and D and generate the control points B and C for the elliptical arc where I can then use the cubic bezier interpolation algorithm to generate the curve.
something like
void GetArcControlPoints(Point a, Point &b, Point &c, Point d)
{
.....
b = ...
c = ....
}
Thanks

There are some flaws in the math behind your question:
Bézier curves are polynomial functions of a parameter t in the unit interval [0;1]. Ellipses are defined using the trigonometrical functions, which are transcendental, thus, not algebraic, thus, not polynomial. You cannot generate an ellipse arc using Bézier curves (neither cubic nor of any degree n). But let's suppose you just want to approximate an ellipse arc. Since you have not specified how good the approximation has to be, there is no way to ensure the Bézier curve will be "ellipse enough" for you. In fewer terms: You need an error parameter.
There are infinite ellipse arcs passing through two given points. Thus, the two points give not enough information to specify an ellipse, an arc of which which could then be approximated using a Bézier curve. To make things worse, since you want an ellipse arc, not the whole ellipse, you also have to specify how much of the ellipse has to be "covered" by the arc, in percentage (100% = the whole ellipse), radians (2*pi = the whole ellipse), whatever. In fewer terms: You need even more (input) parameters, just to specify a single arc of a single ellipse.
Until the math is done right, you cannot go to the next step (coding).
EDIT:
Since you need a whole ellipse, I would recommend using two or four Bézier patches instead of a single Bézier curve.
You can think of the ellipse as a circle that was "stretched" on one of the dimensions. Now, since "stretch" transforms are linear and Bézier functions are linear on the control points, you can calculate the control points for a Bézier curve approximating a 90 degree circle arc, then apply the "stretch" transform to the control points, and voilà, you get the control points for a Bézier curve approximating a "90 degree" ellipse arc. Getting the whole ellipse is just repeating the procedure four times.

Here is a derivation for the control points of a unit circle segment:
http://www.whizkidtech.redprince.net/bezier/circle/kappa/
Every possible ellipse can be generated by applying the appropriate affine transformation.

The kappa formula is just an approximation. This one is a good approximation for drawing a circle or ellipse with 4 cubic Bezier: it matches exactly on 8 points (those on the two axis and on the two main diagonals, the only points considered in the kappa formula), but there are differences everywhere else.
However, even if we can't use such splines to draw circles or ellipses with Beziers, there does exist an "exact" approximation (up to 1 half-pixel of difference) using only arithmetic operations to draw a circle incrementally pixel by pixel, based on the Bresenham algorithm (such approximation is possible because we can compute exactly, using only additions, the square distance of points to the center of the circle or the sum of distances to the two focal points of an ellipse and check if a pixel is "inside" or "outside" of it, and because we know the exact position of a starting point on the circle or ellipse, so we can just test which one of the two possible neighbours, in any one of the 8 sectors, are best approximating the circle or ellipse).
Such incremental algorithm approximating of elliptic arcs is completely different from those used to for Bezier splines but it is very efficient too (and in fact even faster than when drawing arbitrary Beziers splines).

Related

Which algorithm or idea to find the convex envelope of a set of curves?

Let's define a curve as set of 2D points which can be computed to arbitrary precision. For instance, this is a curve:
A set of N intersecting curves is given (N can be arbitrarily large), like in the following image:
How to find the perimeter of the connected area (a bounding box is given if necessary) which is delimited by the set of curves; or, given the example above, the red curve? Note that the perimeter can be concave and it has no obvious parametrization.
A starting point of the red curve can be given
I am interested in efficient ideas to build up a generic algorithm however...
I am coding in C++ and I can use any opensource library to help with this
I do not know if this problem has a name or if there is a ready-made solution, in case please let me know and I will edit the title and the tags.
Additional notes:
The solution is unique as in the region of interest there is only a single connected area which is free from any curve, but of course I can only compute a finite number of curves.
The curves are originally parametrized (and then affine transformations are applied), so I can add as many point as I want. I can compute distances, lengths and go along with them. Intersections are also feasible. Basically any geometric operation that can be built up from point coordinates is acceptable.
I have found that a similar problem is encountered when "cutting" gears eg. https://scialert.net/fulltext/?doi=jas.2014.362.367, but still I do not see how to solve it in a decently efficient way.
If the curves are given in order, you can find the pairwise intersections between successive curves. Depending on their nature, an analytical or numerical solution will do.
Then a first approximation of the envelope is the polyline through these points.
Another approximation can be obtained by drawing the common tangent to successive curves, and by intersecting those tangents pairwise. The common tangent problem is more difficult, anyway.
If the equations of the curves are known in terms of a single parameter, you can find the envelope curve by solving a differential equation, obtained by eliminating the parameter between the implicit equation of the curve and this equation differentiated wrt the parameter. You can integrate this equation numerically.
When I have got such problems (maths are not enough or are terribly tricky) I decompose each curve into segments.
Then, I search segment-segment intersections. For example, a segment in curve Ci with all of segments in curve Cj. Even you can replace a segment with its bounding box and do box-box intersection for quick discard, focusing in those boxes that have intersection.
This gives a rough aproximation of curve-curve intersections.
Apart from intersections you can search for max/min coordinates, aproximated also with segments or boxes.
Once you get a decent aproximation, you can refine it by reducing the length/size of segments and boxes and repeating the intersection (or max/min) checks.
You can have an approximate solution using the grids. First, find a bounding box for the curves. And then griding inside the bounding box. and then search over the cells to find the specified area. And finally using the number of cells over the perimeter approximate the value of the perimeter (as the size of the cells is known).

Deconstruct Bezier Curve into Line Segments with Equally Spaced Slopes

I'm currently working on a program that takes a scale SVG file of a race track and uses the data to approximate the track as an array of points. Ideally, the absolute value of the slopes between any two consecutive points would be identical, as this would allow me to approximate the angle, arc length and radius to a known accuracy for use in calculating the maximum velocity around the curve.
The SVG uses a Bezier approximation with 2 control points. I have a function that takes a start point, 2 control points and an end point as well as the parametric variable t. I found the code for this here:
Drawing Bezier curves using De Casteljau Algorithm in C++ , OpenGL
The result I'd like is that straights would consist of very few line segments (slope changes very little), while sharp turns would consist of many line segments (slope changes sharply). This would keep a constant accuracy in the calculations.
Using a constant step for t doesn't provide a constant slope between two points, which is a huge issue for the calculations. Is there any way to find the correct t value knowing the desired slope of the resulting line segment?
After much searching and refining of terms, I've found a site that explains in depth the answer to my problem. Turns out that my problem is the same faced by rendering engines for drawing Bezier curves, and the Anti-Grain Rendering Engine has a wonderful tutorial on subdividing Bezier curves to approximate all kinds of twists and turns.
https://web.archive.org/web/20180307160123/http://antigrain.com/research/adaptive_bezier/index.html

Fit a circle or a spline into a bunch of 3D Points

I have some 3D Points that roughly, but clearly form a segment of a circle. I now have to determine the circle that fits best all the points. I think there has to be some sort of least squares best fit but I cant figure out how to start.
The points are sorted the way they would be situated on the circle. I also have an estimated curvature at each point.
I need the radius and the plane of the circle.
I have to work in c/c++ or use an extern script.
You could use a Principal Component Analysis (PCA) to map your coordinates from three dimensions down to two dimensions.
Compute the PCA and project your data onto the first to principal components. You can then use any 2D algorithm to find the centre of the circle and its radius. Once these have been found/fitted, you can project the centre back into 3D coordinates.
Since your data is noisy, there will still be some data in the third dimension you squeezed out, but bear in mind that the PCA chooses this dimension such as to minimize the amount of data lost, i.e. by maximizing the amount of data that is represented in the first two components, so you should be safe.
A good algorithm for such data fitting is RANSAC (Random sample consensus). You can find a good description in the link so this is just a short outline of the important parts:
In your special case the model would be the 3D circle. To build this up pick three random non-colinear points from your set, compute the hyperplane they are embedded in (cross product), project the random points to the plane and then apply the usual 2D circle fitting. With this you get the circle center, radius and the hyperplane equation. Now it's easy to check the support by each of the remaining points. The support may be expressed as the distance from the circle that consists of two parts: The orthogonal distance from the plane and the distance from the circle boundary inside the plane.
Edit:
The reason because i would prefer RANSAC over ordinary Least-Squares(LS) is its superior stability in the case of heavy outliers. The following image is showing an example comparision of LS vs. RANSAC. While the ideal model line is created by RANSAC the dashed line is created by LS.
The arguably easiest algorithm is called Least-Square Curve Fitting.
You may want to check the math,
or look at similar questions, such as polynomial least squares for image curve fitting
However I'd rather use a library for doing it.

Estimating equation for plane if distances to various points on it are known

I know the distance to various points on a plane, as it is being viewed from an angle. I want to find the equation for this plane from just that information (5 to 15 different points, as many as necessary).
I will later use the equation for the plane to estimate what the distance to the plane should be at different points; in order to prove that it is roughly flat.
Unfortunately, a google search doesn't bring much up. :(
If you, indeed, know distances and not coordinates, then it is ill-posed problem - there is infinite number of planes that will have points with any number of given distances from origin.
This is easy to verify. Let's take shortest distance D0, from set of given distances {D0..DN-1} , and construct a plane with normal vector {D0,0,0} (vector of length D0 along x-axis). For each of remaining lengths we now have infinite number of points that will lie in this plane (forming circles in-plane around (D0,0,0) point). Moreover, we can rotate all vectors by an arbitrary angle and get a new plane.
Here is simple picture in 2D (distances to a line; it's simpler to draw ;) ).
As we can see, there are TWO points on the line for each distance D1..DN-1 > D0 - one is shown for D1 and D2, and the two other for these distances would be placed in 4th quadrant (+x, -y). Moreover, we can rotate our line around origin by an arbitrary angle and still satisfy given distances.
I'm going to skip over the process of finding the best fit plane, it's been handled in some other answers, and talk about something else.
"Prove" takes us into statistical inference. The way this is done is you make a formal hypothesis "the surface is flat" and then see if the data supports rejecting this hypothesis at some confidence level.
So you can wind up saying "I'm not even 1% sure that the surface isn't flat" -- but you can't ever prove that it's flat.
Geometry? Sounds like a job for math.SE! What form will the equation take? Will it be a plane?
I will assume you want an accurate solution.
Find the absolute positions with geometry
Make a best fit regression line in C++ in 2 of the 3 dimensions.

Drawing sections of a Bezier curve

I was writing code to approximate a quarter ellipse to a Bézier curve.
Now having done that, I am encountering trouble drawing sections of this curve.
I need some help choosing the control points.
Initially, I had taken the ratio of distance of control point to distance of start of curve as 0.51.
Edited:
pseudo code
import cairo [...]
ctx.moveto(0,y1)
ctx.curveto(0,y1/2,x1/2,0,x1,0)
This will result in an approximately elliptical curve from (0,y1) to (x1,0) with the ellipse center at (x1,y1).
Notice the parametric angle swept is pi/2.
If suppose I wish to draw it in sections more like a dashed pattern, then how do I do it? For example, from t = pi/6 to t = pi/3? How do I choose the control points?
To approximate a circle quarter using a single cubic arc what is normally done is making the middle point being exactly on the circle and using tangent starting and ending directions.
This is not formally the "best" approximation in any reasonable metric but is very easy to compute... for example the magic number for a circle quarter is 0.5522847498. See this page for some detail...
To draw an ellipse arc instead you can just stretch the control points of the circular arc (once again not something that would qualify mathematically as "best approximation").
The generic angle case
The best arc for a generic angle under this definition (i.e. having the middle point of the bezier being on the middle of the arc) can be computed using the following method...
1. The maximum height of a symmetrical cubic bezier arc is 3/4 H where H is the height of the control point
This should be clear considering how the middle point of a bezier cubic is computed with the De Casteljau's algorithm or my answer about explicit computation of a bezier curve; see also the following picture:
y_mid = ((0+H)/2 + (H+H)/2) / 2 = 3/4 H
2. The angle at the center for a circle cord is twice the angle at the base
See any elementary geometry text for a proof.
Finally naming L the distance between the extremes, S the (unknown) control arm of the symmetric Bezier, 2*alpha the angle of circle to approximate we can compute that
3. S = L (2/3) (1-cos(alpha)) / (sin(alpha)**2)
This follows from the above equations and from some computation; see the following picture for a description.
I think you should use the control points of the whole curve. One way to do this would be to determine a parametric equation version of bezier -- see How to find the mathematical function defining a bezier curve.
Next, figure out what part of 0 <= t <= 1 in the parametric equation the section defined by the angle p1/6 <= ө <= pi/3 represents and then run that range of values through it.
There are ways of computing each point along some kinds of parametrically-defined curves which is applicable here and ought to make the drawing of a dashed pattern fairly straight forward and fast.
This Link has a good explanation of Bezier Curves. It goes over the basic math principles, and also provides sample code.
Because Bezier Curves are typically implemented using a parametric equation, you can just draw line segments between each sample point. Your step size will affect the smoothness of your curve if you draw them in this way.