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.
Related
I am working on a program which draws shapes based on a cgm file input. I am trying to draw elliptical arc and it gives the opening portion in terms of a start and end vector from the center of the arc. I need help calculating the angle to the vector so I can draw.
I have been trying to use the standard atan2(y/x) but then I found it is valid for circles and not ellipses.
This image gives an example of what I'm trying to do. I am looking for angles A and B.
edit: This is related to my other question here. (Also note, this question is based on the math behind my problem while the other question was for programming help with qt.)
The wiki page on ellipses kind of shows why the math isn't working but I'm not sure how to implement it.
The angles A and B you were drawing in your picture in fact have nothing to do with the ellipse.
Just calculate once the angle between the x-axis and the line from origin to point (75,50). This is given by arctan(50/75) = 33.69°. And by symmetry, it is the same as the angle to point (75, -50).
Then, by simple trigonometry, for angle A you get A = 360° - 33.69°, whereas for B you get B= 180° + 33.69°.
Considering A, this is the same information that is obtained by atan2(-50, 75). However, the result of atan2 is in (i) in radians and (ii) in the range [-pi, pi]. You could add 2*pi and express it in angles and you get the same result as above.
I have a set of points on the unit sphere and a corresponding set of values being equal, for simplicity, to 0 and 1. Thus I'm constructing the characteristic function of a set on the sphere. Typically, I have several such sets, which form a partition of the sphere. An example is given in the figure.
I was wondering if paraview can find boundaries between the cells and compute the length and the curvature of the boundaries.
I read in a paper that using gradient reconstruction the guys managed to find the curvature of such contours. I imagine that if the curvature can be found, the length should be somewhat simpler. If the answer to the above question is yes, where should I look for the corresponding documentation?
For points on the sphere if they are build based on great-circle distance principle, it means all lines connecting points are of a shortest distance and plane goes through sphere center. In such case angle could be computed as arccos of scalar product.
R = 1;
angle = arccos(x1*x2 + y1*y2 + z1*z2);
length = R*angle;
And parametric line from p1 to p2 could be build using slerp interpolation.
slerp(t) = sin((1.0-t)*angle)/sin(angle)*p1 + sin(t*angle)/sin(angle)*p2;
where t is in [0...1] range
In such case curvature is 1/R for all great circle lines. That would be first thing I would try - try to match actual boundaries with those made from great-circle approach. If they match, that's the answer
Links
https://en.wikipedia.org/wiki/Great_circle
https://en.wikipedia.org/wiki/Great-circle_distance
https://en.wikipedia.org/wiki/Slerp
UPDATE
In case of non-great arcs I would propose following modification. Build great arc plane which goes through sphere center and on intersection with surface makes great arc between the points. Fix axis as a line going through those two points. Start rotating great arc plane along above mentioned axis till you get the exactly your arc of circle connecting two points. At this moment you could get rotation angle, compute your circle plane position and radius r, curvature as 1/r etc
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
I'm trying to find the intersection between a line segment and a quadratic bezier triangle for my OpenCL real time raytracer.
This question Detect&find intersection ray vs. cubic bezier triangle talks about finding the collision point between a ray and a cubic bezier triangle and the main recomendations are to try subdivision, or tensor product bezier patches.
I've read in a few places that when testing a line segment against a quadratic bezier triangle, that you just end up having to solve a quadratic equation, but I haven't found any information on what that equation actually is and am starting to wonder if it's true. My attempts to find it also have come up short so far :P
Does anyone know if this is true or how to solve it besides using subdivision or tensor product bezier patches?
Here's the equation for a quadratic bezier triangle:
AS^2 + 2*DST + 2*ESU + B*T^2 + 2*FTU + C*U^2
Where S,T,U are the parameters to the triangle. You could replace U with (1-S-T) since they are barycentric coordinates.
A,B,C are the corners of the triangle, and D,E,F are the control points along the edges.
Super stumped on this one!
Line segment has parametric equation P = P0+(P1-P0)*v=P0+d*v, where v is parameter [0..1]
To find intersection with brute force, you have to solve system of three quadratic equations like
x0+dx*v=AxS^2 + 2*Dx*S*T + 2*Ex*S*U + Bx*T^2 + 2*Fx*T*U + Cx*U^2
This system has 8 possible solutions, and intersection(s) exists only if resulted v,s,t lie in range 0..1 simultaneously. It's not easy to solve this system (possible approaches - Gröbner basis, numerical methods, and solution process might be numerically unstable). That is why subdivision method is sometimes recommended.
when your bezier patch has more than 3 sides, ray-intersection is no longer analytic (even if the splines on the side are only quadratic) and a precise enough iterative approach is significantly slower. Bezier patches are pathetic in terms of performance due to inherent recursion, you may want to do FFT for fourier-patches instead. Shadertoy.com [iq] has various "twisted cube intersection"s (that are not iterated by sphere-tracking==raymarching, which is efficient, but also causes MANY low-precision-cases-artifacts, where ever convergence of iteration is too slow).
yes, triangular-bezierpatch intersections has only analytic quadratic complexity (with quadratic beziers on the borders), but it involves some pre-computation (unless it is already in barycentric coordinates), that significantly lower the resulting precision (barycentric adds 1 division globally, and sums up over all domains)
This was solved (poorly, as in it has 1 error case and too low precision) on shadertoy in opengl in 2019:
https://www.shadertoy.com/view/XsjSDt
and i optimized it slightly (fixed precision issues, added camera and culling):
https://www.shadertoy.com/view/ttjSzw + https://www.shadertoy.com/view/wlSyzd
also see,
https://www.reddit.com/r/askmath/comments/sfn8mk/analytic_intersection_ray/
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).