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/
Related
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).
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 am trying to extract the curvature of a pulse along its profile (see the picture below). The pulse is calculated on a grid of length and height: 150 x 100 cells by using Finite Differences, implemented in C++.
I extracted all the points with the same value (contour/ level set) and marked them as the red continuous line in the picture below. The other colors are negligible.
Then I tried to find the curvature from this already noisy (due to grid discretization) contour line by the following means:
(moving average already applied)
1) Curvature via Tangents
The curvature of the line at point P is defined by:
So the curvature is the limes of angle delta over the arclength between P and N. Since my points have a certain distance between them, I could not approximate the limes enough, so that the curvature was not calculated correctly. I tested it with a circle, which naturally has a constant curvature. But I could not reproduce this (only 1 significant digit was correct).
2) Second derivative of the line parametrized by arclength
I calculated the first derivative of the line with respect to arclength, smoothed with a moving average and then took the derivative again (2nd derivative). But here I also got only 1 significant digit correct.
Unfortunately taking a derivative multiplies the already inherent noise to larger levels.
3) Approximating the line locally with a circle
Since the reciprocal of the circle radius is the curvature I used the following approach:
This worked best so far (2 correct significant digits), but I need to refine even further. So my new idea is the following:
Instead of using the values at the discrete points to determine the curvature, I want to approximate the pulse profile with a 3 dimensional spline surface. Then I extract the level set of a certain value from it to gain a smooth line of points, which I can find a nice curvature from.
So far I could not find a C++ library which can generate such a Bezier spline surface. Could you maybe point me to any?
Also do you think this approach is worth giving a shot, or will I lose too much accuracy in my curvature?
Do you know of any other approach?
With very kind regards,
Jan
edit: It seems I can not post pictures as a new user, so I removed all of them from my question, even though I find them important to explain my issue. Is there any way I can still show them?
edit2: ok, done :)
There is ALGLIB that supports various flavours of interpolation:
Polynomial interpolation
Rational interpolation
Spline interpolation
Least squares fitting (linear/nonlinear)
Bilinear and bicubic spline interpolation
Fast RBF interpolation/fitting
I don't know whether it meets all of your requirements. I personally have not worked with this library yet, but I believe cubic spline interpolation could be what you are looking for (two times differentiable).
In order to prevent an overfitting to your noisy input points you should apply some sort of smoothing mechanism, e.g. you could try if things like Moving Window Average/Gaussian/FIR filters are applicable. Also have a look at (Cubic) Smoothing Splines.
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.
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).