Calculation of cubic Bézier with known halfway point - math

I know:
The control points a and d (start and end point of a 2D cubic bezier curve)
The slopes a->b, c->d, and b->c (b,c the other control points)
Where the halfway point of the Bézier curve is.
Now, given this information, what is the formula for the positions of control points b and c ?

I know this question is old, but there is no correct or complete answer provided, so I thought I'd chime in with a solution. Note that David's calculations contain several errors and his solution is incomplete even if these errors are corrected.
First, define vectors T0, T1 and T2 using the three slopes:
T0 = ( b - a ) / u0
T1 = ( c - b ) / u1
T2 = ( d - c ) / u2
If we knew both the direction and distance between each pair of control points then we would not need the scale factors u0, u1 and u2. Since we only know slope then u0, u1 and u2 are unknown scalar quantities. Also, we assume that u0, u1 and u2 are nonzero since slope is defined.
We can rewrite these equations in several different ways to obtain expressions for each control point in terms of the other control points. For example:
b = a + T0*u0
c = b + T1*u1
d = c + T2*u2
The question also states that we have the "halfway point" of the cubic Bezier curve. I take this to mean we have the point at the midpoint of the curve's parameter range. I will call this point p:
p = ( a + 3*b + 3*c + d ) / 8
Rewriting with unknowns on the left hand side yields:
b + c = ( 8*p - a - d ) / 3
We can now substitute for b and c in various ways using the earlier expressions. It turns out that ambiguities arise when we have parallel vectors T0, T1 or T2. There are four cases to consider.
Case 1: T0 is not parallel to T1
Substitute b = a + T0*u0 and c = a + T0*u0 + T1*u1 and solve for u0 and u1:
2*T0*u0 + T1*u1 = ( 8*p - 7*a - d ) / 3
This is two equations and two unknowns since T0 and T1 are vectors. Substitute u0 and u1 back into b = a + T0*u0 and c = a + T0*u0 + T1*u1 to obtain the missing control points b and c.
Case 2: T1 is not parallel to T2
Substitute c = d - T2*u2 and b = d - T2*u2 - T1*u1 and solve for u1 and u2:
T1*u1 + 2*T2*u2 = ( a + 7*d - 8*p ) / 3
Case 3: T0 is not parallel to T2
Substitute b = a + T0*u0 and c = d - T2*u2 and solve for u0 and u2:
T0*u0 - T2*u2 = ( 8*p - 4*a - 4*d ) / 3
Case 4: T0, T1 and T2 are all parallel
In this case a, b, c and d are all collinear and T0, T1 and T2 are all equivalent to within a scale factor. There is not enough information to obtain a unique solution. One simple solution would be to simply pick b by setting u0 = 1:
b = a + T0
(a + T0) + c = ( 8*p - a - d ) / 3
c = ( 8*p - 4*a - d - 3*T0 ) / 3
An infinite number of solutions exist. In essence, picking b defines c or picking c will define b.
Extending to 3D
The question specifically asked about planar Bezier curves, but I think it's interesting to note that the point p is not necessary when extending this problem to a non-planar 3D cubic Bezier curve. In this case, we can simply solve this equation for u0, u1 and u2:
T0*u0 + T1*u1 + T2*u2 = d - a
This is three equations (the vectors are 3D) and three unknowns (u0, u1 and u2). Substitution into b = a + T0*u0 and c = b + T1*u1 or c = d - T2*u2 yields b and c.

Let's say your slopes are normalized, then for some u,v you have
u * slope(a->b)+a = b, v * slope(c->d)+d = c
you know the values of a,d, and q:=(a+b+c+d)/8 (the halfway point of the curve)
so c = 8(q-a-d-b)
plugging the above equations in the last one you get
v * slope(c->d)+d = 8(q-a-d-a-u * slope(a->b))
which is 2 equations (a 2d vector equation) in two variables (u,v)
You don't need the third slope.

Related

Find line that is tangent to 2 given circles

I've got a situation in which I have 2 circles (C1 and C2)
and i need to find the line equation for the line that is tangent to both of these circles.
So as far as i'm aware, given a single point (P1) and C2's point and radius it is possible to quite easily get 2 possible points of tangency for C2 and P1 to make 2 line equations. But as i don't have P1, only the knowledge that the point will be one of a possible 2 points on C1, i'm not sure how to calculate this.
I assume it will be something along the lines of getting the 2 tangent line equations of C1 that are equal to the same of C2.
Both circles can have any radius, they could be the same or they could be hugely different. They will also never overlap (they can still touch though). And I'm looking for the 2 possible internal tangents.
Oh, and also, visuals would be very helpful haha :)
Let O be the intersection point between the line through the centers and the tangent.
Let d be the distance between the centers and h1, h2 be the distances between O and the centers. By similarity, these are proportional to the radii.
Hence,
h1 / h2 = r1 / r2 = m,
h1 + h2 = d,
giving
h1 = m d / (1 + m),
h2 = d / (1 + m).
Then the coordinates of O are found by interpolating between the centers
xo = (h2.x1 + h1.x2) / d
yo = (h2.y1 + h1.y2) / d
and the angle of the tangent is that of the line through the centers plus or minus the angle between this line and the tangent,
a = arctan((y2 - y1)/(x2 - x1)) +/- arcsin(r1 / h1).
You can write the implicit equation of the tangent as
cos(a).y - sin(a).x = cos(a).yo - sin(a).xo.
(source: imag.fr)
So we are going to use a homothetic transformation. If the circles C and C' have respectively centres O and O', and radius r and r', then we know there exists a unique homothetic transformation with centre J and ratio a, such that :
a = |JO|/|JO'| = r/r'
Noting AB is the vector from A to B, and |z| the norm of a vector z.
Hence you get J, knowing that it is between O and O' which we both already know.
Then with u the projection of JR on JO', and v the decomposition on its orthogonal, and considering the sine s and cosine c of the angle formed by O'JR, we have
|u| = |JR| * c
|v| = |JR| * s
c^2 + s^2 = 1
And finally because the triangle JRO' is right-angled in R :
s = r' / |JO|'
Putting all of this together, we get :
J = O + OO' / |OO'| * a / (a+1)
if |OJ| == r and |O'J| == r' then
return the orthogonal line to (OO') passing through J
|JR| = √( |JO'|^ - r'^2 )
s = r' / |JO'|
c = √( 1 - s^2 )
u = c * |JR| * OO' / |OO'|
w = (-u.y, u.x) % any orthogonal vector to u
v = s * |JR| * w / |w|
return lines corresponding to parametric equations J+t*(u+v) and J+t*(u-v)

Curve Fit 5 points

I am trying to curve fit 5 points in C. I have used this code from a previous post (Can sombody simplify this equation for me?) to do 4 points, but now I need to add another point.
// Input data: arrays x[] and y[]
// x[1],x[2],x[3],x[4] - X values
// y[1],y[2],y[3],y[4] - Y values
// Calculations
A = 0
B = 0
C = 0
D = 0
S1 = x[1] + x[2] + x[3] + x[4]
S2 = x[1]*x[2] + x[1]*x[3] + x[1]*x[4] + x[2]*x[3] + x[2]*x[4] + x[3]*x[4]
S3 = x[1]*x[2]*x[3] + x[1]*x[2]*x[4] + x[1]*x[3]*x[4] + x[2]*x[3]*x[4]
for i = 1 to 4 loop
C0 = y[i]/(((4*x[i]-3*S1)*x[i]+2*S2)*x[i]-S3)
C1 = C0*(S1 - x[i])
C2 = S2*C0 - C1*x[i]
C3 = S3*C0 - C2*x[i]
A = A + C0
B = B - C1
C = C + C2
D = D - C3
end-loop
// Result: A, B, C, D
I have been trying to covert this to a 5 point curve fit, but am having trouble figuring out what goes inside the loop:
// Input data: arrays x[] and y[]
// x[1],x[2],x[3],x[4],x[5] - X values
// y[1],y[2],y[3],y[4],y[5] - Y values
// Calculations
A = 0
B = 0
C = 0
D = 0
E = 0
S1 = x[1] + x[2] + x[3] + x[4]
S2 = x[1]*x[2] + x[1]*x[3] + x[1]*x[4] + x[2]*x[3] + x[2]*x[4] + x[3]*x[4]
S3 = x[1]*x[2]*x[3] + x[1]*x[2]*x[4] + x[1]*x[3]*x[4] + x[2]*x[3]*x[4]
S4 = x[1]*x[2]*x[3]*x[4] + x[1]*x[2]*x[3]*[5] + x[1]*x[2]*x[4]*[5] + x[1]*x[3]*x[4]*[5] + x[2]*x[3]*x[4]*[5]
for i = 1 to 4 loop
C0 = ??
C1 = ??
C2 = ??
C3 = ??
C4 = ??
A = A + C0
B = B - C1
C = C + C2
D = D - C3
E = E + C4
end-loop
// Result: A, B, C, D, E
any help in filling out the C0...C4 would be appreciated. I know this has to do with the matrices but I have not been able to figure it out. examples with pseudo code or real code would be most helpful.
thanks
I refuse to miss this opportunity to generalize. :)
Instead, we're going to learn a little bit about Lagrange polynomials and the Newton Divided Difference Method of their computation.
Lagrange Polynomials
Given n+1 data points, the interpolating polynomial is
where l_j(i) is
.
What this means is that we can find the polynomial approximating the n+1 points, regardless of spacing, etc, by just summing these polynomials. However, this is a bit of a pain and I wouldn't want to do it in C. Let's take a look at Newton Polynomials.
Newton Polynomials
Same start, given n+1 data points, the approximating polynomial is going to be
where each n(x) is
with a coefficient of
, being the divided difference.
The final form end's up looking like
.
As you can see, the formula is pretty easy given the divided difference values. You just do each new divided difference and multiply by each point so far. It should be noted that you'll end up with a polynomial of degree n from n+1 points.
Divided Difference
All that's left is to define the divided difference which is really best explained by these two pictures:
and
.
With this information, a C implementation should be reasonable to do. I hope this helps and I hope you learned something! :)
If the x values are equally spaced with x2-x1=h, x3-x2=h, x4-x3=h and x5-x4=h then
C0 = y1;
C1 = -(25*y1-48*y2+36*y3-16*y4+3*y5)/(12*h);
C2 = (35*y1-104*y2+114*y3-56*y4+11*y5)/(24*h*h);
C3 = -(5*y1-18*y2+24*y3-14*y4+3*y5)/(12*h*h*h);
C4 = (y1-4*y2+6*y3-4*y4+y5)/(24*h*h*h*h);
y(x) = C0+C1*(x-x1)+C2*(x-x1)^2+C3*(x-x1)^3+C4*(x-x1)^4
// where `^` denotes exponentiation (and not XOR).

Calculating the level of insertion based on the size of the tree

If I have a graph structure that looks like the following
a level-1
b c level-2
c d e level-3
e f g h level-4
...... level-n
a points to b and c
b points to c and d
c points to d and e
and so on
how can i calculate the n from the size(number of existing nodes) of the graph/tree?
The number of nodes present if the height is h is given by
1 + 2 + 3 + ... + h = h(h + 1) / 2
This means that one simple option would be to take the total number of nodes n and do a simple binary search to find the right value of h that such that h(h + 1) / 2 = n.
Alternatively, since n = h(h + 1) / 2, you can note that
n = h(h + 1) / 2
2n = h2 + h
0 = h2 + h - 2n
Now you have a quadratic equation (in h) that you can solve to directly get back the value of h. The solution is
h = (-1 ± √(1 + 8n)) / 2
If you take the minus branch, you'll get back a negative number, so you should take the positive branch and compute
(-1 + √(1 + 8n)) / 2
to directly get back h.
Hope this helps!

collision detection between two lines

This is a fairly simple question. I need need an equation to determine whether two 2 dimensional lines collide with each other. If they do I also need to know the X and Y position of the collision.
Put them both in general form. If A and B are the same then they're parallel. Otherwise, create two simultaneous equations and solve for x and y.
Let A and B represented by this parametric form : y = mx + b
Where m is the slope of the line
Now in the case of parallelism of A and B their slope should be equal
Else they will collide with each other at point T(x,y)
For finding the coordinates of point T you have to solve an easy equation:
A: y = mx + b
B: y = Mx + B
y(A) = y(B) means : mx + b = Mx + B which yields to x = (B - b)/(m - M) and by putting
the x to the line A we find y = ((m*(B - b))/(m - M)) + b
so : T : ((B - b)/(m - M) , ((m*(B - b))/(m - M)) + b)

Line of intersection between two planes

How can I find the line of intersection between two planes?
I know the mathematics idea, and I did the cross product between the the planes normal vectors
but how to get the line from the resulted vector programmatically
The equation of the plane is ax + by + cz + d = 0, where (a,b,c) is the plane's normal, and d is the distance to the origin. This means that every point (x,y,z) that satisfies that equation is a member of the plane.
Given two planes:
P1: a1x + b1y + c1z + d1 = 0
P2: a2x + b2y + c2z + d2 = 0
The intersection between the two is the set of points that verifies both equations. To find points along this line, you can simply pick a value for x, any value, and then solve the equations for y and z.
y = (-c1z -a1x -d1) / b1
z = ((b2/b1)*(a1x+d1) -a2x -d2)/(c2 - c1*b2/b1)
If you make x=0, this gets simpler:
y = (-c1z -d1) / b1
z = ((b2/b1)*d1 -d2)/(c2 - c1*b2/b1)
Finding the line between two planes can be calculated using a simplified version of the 3-plane intersection algorithm.
The 2'nd, "more robust method" from bobobobo's answer references the 3-plane intersection.
While this works well for 2 planes (where the 3rd plane can be calculated using the cross product of the first two), the problem can be further reduced for the 2-plane version.
No need to use a 3x3 matrix determinant,instead we can use the squared length of the cross product between the first and second plane (which is the direction of the 3'rd plane).
No need to include the 3rd planes distance,(calculating the final location).
No need to negate the distances.Save some cpu-cycles by swapping the cross product order instead.
Including this code-example, since it may not be immediately obvious.
// Intersection of 2-planes: a variation based on the 3-plane version.
// see: Graphics Gems 1 pg 305
//
// Note that the 'normal' components of the planes need not be unit length
bool isect_plane_plane_to_normal_ray(
const Plane& p1, const Plane& p2,
// output args
Vector3f& r_point, Vector3f& r_normal)
{
// logically the 3rd plane, but we only use the normal component.
const Vector3f p3_normal = p1.normal.cross(p2.normal);
const float det = p3_normal.length_squared();
// If the determinant is 0, that means parallel planes, no intersection.
// note: you may want to check against an epsilon value here.
if (det != 0.0) {
// calculate the final (point, normal)
r_point = ((p3_normal.cross(p2.normal) * p1.d) +
(p1.normal.cross(p3_normal) * p2.d)) / det;
r_normal = p3_normal;
return true;
}
else {
return false;
}
}
Adding this answer for completeness, since at time of writing, none of the answers here contain a working code-example which directly addresses the question.
Though other answers here already covered the principles.
Finding a point on the line
To get the intersection of 2 planes, you need a point on the line and the direction of that line.
Finding the direction of that line is really easy, just cross the 2 normals of the 2 planes that are intersecting.
lineDir = n1 × n2
But that line passes through the origin, and the line that runs along your plane intersections might not. So, Martinho's answer provides a great start to finding a point on the line of intersection (basically any point that is on both planes).
In case you wanted to see the derivation for how to solve this, here's the math behind it:
First let x=0. Now we have 2 unknowns in 2 equations instead of 3 unknowns in 2 equations (we arbitrarily chose one of the unknowns).
Then the plane equations are (A terms were eliminated since we chose x=0):
B1y + C1z + D1 = 0
B2y + C2z + D2 = 0
We want y and z such that those equations are both solved correctly (=0) for the B1, C1 given.
So, just multiply the top eq by (-B2/B1) to get
-B2y + (-B2/B1)*C1z + (-B2/B1)*D1 = 0
B2y + C2z + D2 = 0
Add the eqs to get
z = ( (-B2/B1)*D1 - D2 ) / (C2 * B2/B1)*C1)
Throw the z you find into the 1st equation now to find y as
y = (-D1 - C1z) / B1
Note the best variable to make 0 is the one with the lowest coefficients, because it carries no information anyway. So if C1 and C2 were both 0, choosing z=0 (instead of x=0) would be a better choice.
The above solution can still screw up if B1=0 (which isn't that unlikely). You could add in some if statements that check if B1=0, and if it is, be sure to solve for one of the other variables instead.
Solution using intersection of 3 planes
From user's answer, a closed form solution for the intersection of 3 planes was actually in Graphics Gems 1. The formula is:
P_intersection = (( point_on1 • n1 )( n2 × n3 ) + ( point_on2 • n2 )( n3 × n1 ) + ( point_on3 • n3 )( n1 × n2 )) / det(n1,n2,n3)
Actually point_on1 • n1 = -d1 (assuming you write your planes Ax + By + Cz + D=0, and not =-D). So, you could rewrite it as:
P_intersection = (( -d1 )( n2 × n3 ) + ( -d2 )( n3 × n1 ) + ( -d3 )( n1 × n2 )) / det(n1,n2,n3)
A function that intersects 3 planes:
// Intersection of 3 planes, Graphics Gems 1 pg 305
static Vector3f getIntersection( const Plane& plane1, const Plane& plane2, const Plane& plane3 )
{
float det = Matrix3f::det( plane1.normal, plane2.normal, plane3.normal ) ;
// If the determinant is 0, that means parallel planes, no intn.
if( det == 0.f ) return 0 ; //could return inf or whatever
return ( plane2.normal.cross( plane3.normal )*-plane1.d +
plane3.normal.cross( plane1.normal )*-plane2.d +
plane1.normal.cross( plane2.normal )*-plane3.d ) / det ;
}
Proof it works (yellow dot is intersection of rgb planes here)
Getting the line
Once you have a point of intersection common to the 2 planes, the line just goes
P + t*d
Where P is the point of intersection, t can go from (-inf, inf), and d is the direction vector that is the cross product of the normals of the two original planes.
The line of intersection between the red and blue planes looks like this
Efficiency and stability
The "robust" (2nd way) takes 48 elementary ops by my count, vs the 36 elementary ops that the 1st way (isolation of x,y) uses. There is a trade off between stability and # computations between these 2 ways.
It'd be pretty catastrophic to get (0,inf,inf) back from a call to the 1st way in the case that B1 was 0 and you didn't check. So adding in if statements and making sure not to divide by 0 to the 1st way may give you the stability at the cost of code bloat, and the added branching (which might be quite expensive). The 3 plane intersection method is almost branchless and won't give you infinities.
This method avoids division by zero as long as the two planes are not parallel.
If these are the planes:
A1*x + B1*y + C1*z + D1 = 0
A2*x + B2*y + C2*z + D2 = 0
1) Find a vector parallel to the line of intersection. This is also the normal of a 3rd plane which is perpendicular to the other two planes:
(A3,B3,C3) = (A1,B1,C1) cross (A2,B2,C2)
2) Form a system of 3 equations. These describe 3 planes which intersect at a point:
A1*x1 + B1*y1 + C1*z1 + D1 = 0
A2*x1 + B2*y1 + C2*z1 + D2 = 0
A3*x1 + B3*y1 + C3*z1 = 0
3) Solve them to find x1,y1,z1. This is a point on the line of intersection.
4) The parametric equations of the line of intersection are:
x = x1 + A3 * t
y = y1 + B3 * t
z = z1 + C3 * t
The determinant-based approach is neat, but it's hard to follow why it works.
Here's another way that's more intuitive.
The idea is to first go from the origin to the closest point on the first plane (p1), and then from there go to the closest point on the line of intersection of the two planes. (Along a vector that I'm calling v below.)
Given
=====
First plane: n1 • r = k1
Second plane: n2 • r = k2
Working
=======
dir = n1 × n2
p1 = (k1 / (n1 • n1)) * n1
v = n1 × dir
pt = LineIntersectPlane(line = (p1, v), plane = (n2, k2))
LineIntersectPlane
==================
#We have n2 • (p1 + lambda * v) = k2
lambda = (k2 - n2 • p1) / (n2 • v)
Return p1 + lambda * v
Output
======
Line where two planes intersect: (pt, dir)
This should give the same point as the determinant-based approach. There's almost certainly a link between the two. At least the denominator, n2 • v, is the same, if we apply the "scalar triple product" rule. So these methods are probably similar as far as condition numbers go.
Don't forget to check for (almost) parallel planes. For example: if (dir • dir < 1e-8) should work well if unit normals are used.
You can find the formula for the intersection line of two planes in this link.
P1: a1x + b1y + c1z = d1
P2: a2x + b2y + c2z = d2
n1=(a1,b1,c1); n2=(a2,b2,c2); n12=Norm[Cross[n1,n2]]^2
If n12 != 0
a1 = (d1*Norm[n2]^2 - d2*n1.n2)/n12;
a2 = (d2*Norm[n1]^2 - d1*n1.n2)/n12;
P = a1 n1 + a2 n2;
(*formula for the intersection line*)
Li[t_] := P + t*Cross[n1, n2];
The cross product of the line is the direction of the intersection line. Now you need a point in the intersection.
You can do this by taking a point on the cross product, then subtracting Normal of plane A * distance to plane A and Normal of plane B * distance to plane b. Cleaner:
p = Point on cross product
intersection point = ([p] - ([Normal of plane A] * [distance from p to plane A]) - ([Normal of plane B] * [distance from p to plane B]))
Edit:
You have two planes with two normals:
N1 and N2
The cross product is the direction of the Intersection Line:
C = N1 x N2
The class above has a function to calculate the distance between a point and a plane. Use it to get the distance of some point p on C to both planes:
p = C //p = 1 times C to get a point on C
d1 = plane1.getDistance(p)
d2 = plane2.getDistance(p)
Intersection line:
resultPoint1 = (p - (d1 * N1) - (d2 * N2))
resultPoint2 = resultPoint1 + C

Resources