Generating a 'natural path' along a spline - math

I need a way to get an orientation (local x/y/z axes) at any point along a spline... where the z-axis is always the spline tangent and x/y are perpendicular to each other and z.
One common technique is to calculate one axis vector as the rate of change of the tangent, i.e. x(t) = z(t) X z(t+dt)
Then y is simply x X z.
However I am not sure this gives what I'd call the 'natural' orientation path. What I mean by that is, imagine I have a rigid steel rod which is bend into some set of curls and I then advance a flexible hose along this rod. If friction is neglible, the 'natural' path would mean the hose ends up with minimum torque at any point, as it would 'untwist' itself to get a lower-energy state.
Is there any way to do this which doesn't mean traversing the spline's length from 0-t to find the transform at a given point t?

It seems that you are looking for Frenet frame - moving trihedron with unit tangent, normal and binormal vectors
Addition.
simple example:
X = 2*t^2-t+5
Y = t^3+t^2+2*t - 1
Z = -t^3 - 2*Sin(t)
X'(t) = 4*t-1; X'' = 4
Y'=3*t^2 + 2*t + 2; Y'' = 6*t+2
Z'= -3*t^2-2*Cos(t); Z'' = -6*t+2*Sin(t)
At parameter t = 0:
X' = -1; Y' = 2; Z' = -2; |R'| = Sqrt(1 + 4 + 4) = 3
T = (-1/3, 2/3, - 2/3)
and so on...

Related

Scaling a bezier graph to starting and ending points

I have a graph like this:
And I want to be able to convert the position of P1 aka the ball you can drag around to scale with different starting and ending points on my screen.
I esentially want to make it so that the curve dot is around the same position no matter where the starting and ending positions are for the curve
So if I had a different points on my screen it would look the same as the graph
This is what I tried to do but it didn't work
function bezier.scale(startingPosition : Vector2, endingPosition : Vector2)
local screenSize = workspace.CurrentCamera.ViewportSize
local lengthX = (endingPosition.X - startingPosition.X)
local lengthY = (endingPosition.Y - startingPosition.Y)
local screenRelativeX = (screenSize.X - startingPosition.X) + lengthX
local screenRelativeY = (screenSize.Y - startingPosition.Y) + lengthY
local scaleX = (screenRelativeX / graphBackground.Size.X.Offset)
local scaleY = (screenRelativeY / graphBackground.Size.Y.Offset)
local x = (bezierPoint.Position.X.Offset * scaleX)
local y = (bezierPoint.Position.Y.Offset * scaleY)
return Vector2.new(x, y)
end
so your input is 4 2D points ... first 2 points p0,p1 are constant refer to your BEZIER start and end points and the next 2 q0,q1 are start and end point for your animation. So you want affine transform mapping between the two pairs. For that you need rotation and scale and offset...
Scale
is Easy its just ratio between line sizes so:
scale = |q1-q0| / |p1-p0|
Rotation
you can exploit dot product:
ang = acos( dot(p1-p0,q1-q0)/(|p1-p0|*|q1-q0|) )
the sign can be determined by 3D cross product (using z=0) for example:
if (cross(p1-p0,q1-q0).z >=0 ) ang=-ang;
however note that >=0 or <=0 depends on yoru coordinate system and rotation formula so it might be reversed in your case.
offset
simply apply the #1,#2 on p0 lets call the result P0 then the offset is easy:
offset = p0-P0
Putting all toghether
so transforming point p=(x,y) will be:
// #1 apply scale
x' = x*scale
y' = y*scale
// #2 apply rotation
x = x'*cos(ang) + y'*sin(ang)
y =-x'*sin(ang) + y'*cos(ang)
// #3 apply offset
x = x + offset.x
y = y + offset.y
Do not forget to use temp variables x',y' for the rotation! You might also construct 3x3 transform matrix for this instead.
For more info about transform matrices and vector math (dot and cross product included) see:
Understanding 4x4 homogenous transform matrices

Get corresponding Y position on cubic bezier when given X position [duplicate]

Let's say I have a Bezier curve with two fixed endpoints, one at x(0), y(1) and one at x(1), y(0) (bottom left corner and upper right corner)
Now let's say I have two control points, which can be at any locations between x(0), x(1), y(0), and y(1). For this question, I'll just say that control point #1 is at x(0.1) y(0.6) and control point #2 is at x(0.9) and at y(0.4). (This assumes a "from upper left" coordinate system)
Here's a small illustration of our curve:
Now let's say I'm given a y position of 0.7. What would the math look like to figure out what the corresponding x position is to the point at y(0.7)? How would I do this?
Sorry if this question doesn't belong here, but I figured this is a common problem faced in coding and that it's likely that many of you have the answer I'm looking for.
You have cubic equation for functions X(t) and Y(t) where t is curve parameter (range 0..1 for points on curve). In Bernstein polynomial basis (usual form for curve definition):
X(t) = P0.X*(1-t)^3+3*P1.X*(1-t)^2*t+3*P2.X*(1-t)*t^2+P3.X*t^3
Y(t) = P0.Y*(1-t)^3+3*P1.Y*(1-t)^2*t+3*P2.Y*(1-t)*t^2+P3.Y*t^3
Having Y value, we can find corresponding t parameters - note there might be from 0 to 3 possible roots in range 0..1. Representation of Y-component in power basis:
Y(t) = P0.Y*(1-t)^3+3*P1.Y*(1-t)^2*t+3*P2.Y*(1-t)*t^2+P3.Y*t^3 =
t^3*(P3Y-3P2Y+3P1Y-P0Y) + t^2*(3P2Y-6P1Y+3P0Y) + t^2*(3P1Y-3P0Y) + (P0Y) =
t^3*a + t^2*b + t^2*c + d' = y_position
and finally cubic equation is:
t^3*a + t^2*b + t^2*c + d = 0
where
a = P3.Y-3*P2.Y+3*P1.Y-P0.Y
b = 3*P2.Y-6*P1.Y+3*P0.Y
c = 3*P1.Y-3*P0.Y
d = P0.Y - y_position
Solve cubic equation to calculate t (perhaps some values for wavy curves)
Then for given t calculate corresponding X value:
X(t) = P0.X*(1-t)^3+3*P1.X*(1-t)^2*t+3*P2.X*(1-t)*t^2+P3.X*t^3

Given a cubic Bezier curve with fixed endpoints, how can I find the x position of a point along it when given a y position to check?

Let's say I have a Bezier curve with two fixed endpoints, one at x(0), y(1) and one at x(1), y(0) (bottom left corner and upper right corner)
Now let's say I have two control points, which can be at any locations between x(0), x(1), y(0), and y(1). For this question, I'll just say that control point #1 is at x(0.1) y(0.6) and control point #2 is at x(0.9) and at y(0.4). (This assumes a "from upper left" coordinate system)
Here's a small illustration of our curve:
Now let's say I'm given a y position of 0.7. What would the math look like to figure out what the corresponding x position is to the point at y(0.7)? How would I do this?
Sorry if this question doesn't belong here, but I figured this is a common problem faced in coding and that it's likely that many of you have the answer I'm looking for.
You have cubic equation for functions X(t) and Y(t) where t is curve parameter (range 0..1 for points on curve). In Bernstein polynomial basis (usual form for curve definition):
X(t) = P0.X*(1-t)^3+3*P1.X*(1-t)^2*t+3*P2.X*(1-t)*t^2+P3.X*t^3
Y(t) = P0.Y*(1-t)^3+3*P1.Y*(1-t)^2*t+3*P2.Y*(1-t)*t^2+P3.Y*t^3
Having Y value, we can find corresponding t parameters - note there might be from 0 to 3 possible roots in range 0..1. Representation of Y-component in power basis:
Y(t) = P0.Y*(1-t)^3+3*P1.Y*(1-t)^2*t+3*P2.Y*(1-t)*t^2+P3.Y*t^3 =
t^3*(P3Y-3P2Y+3P1Y-P0Y) + t^2*(3P2Y-6P1Y+3P0Y) + t^2*(3P1Y-3P0Y) + (P0Y) =
t^3*a + t^2*b + t^2*c + d' = y_position
and finally cubic equation is:
t^3*a + t^2*b + t^2*c + d = 0
where
a = P3.Y-3*P2.Y+3*P1.Y-P0.Y
b = 3*P2.Y-6*P1.Y+3*P0.Y
c = 3*P1.Y-3*P0.Y
d = P0.Y - y_position
Solve cubic equation to calculate t (perhaps some values for wavy curves)
Then for given t calculate corresponding X value:
X(t) = P0.X*(1-t)^3+3*P1.X*(1-t)^2*t+3*P2.X*(1-t)*t^2+P3.X*t^3

Understanding & Deriving Jacobian Determinant Scaling Factor

I have been trying to understand Jacobian Determinant.
I hope someone is able to give me a pointer.
Most material that I found on Internet didn't provide
derivation of Jacobian Determinant.
One such web site is:
http://tutorial.math.lamar.edu
(Which I find quite good, otherwise.)
I spent a lot of time trying to deepen my understanding of
Jacobian Determinant.
I played with Transformations that define uv-axes and
how integration of a function over a Region/area would work
with the Transformations.
For example, when I started with simple Transformations of:
u = ( x - y )/√2
v = ( x + y )/2√2
which is uv-axes rotated -45° from Cartesian xy-axes,
and with v-axis at 2 times the scale,
that is, v = 1 maps to 2 units length in xy-coords.
So, I say that uscale = 1, vscale = 2,
for the above transformations.
With this uv-axes, I can simplify a 10x20 rectangle Region
which is rotated at 45° from x-axis,
such that the longer dimension points at 45° from x-axis.
With such examples, I begin to develop intuition
how Jacobian Determinant works.
I understand Jacobian Determinant to be a Scaling Factor
to convert area measurement in uv-axes to xy-dimensions.
Area measurement in uv-axes is given simply by formula
Δu x Δv, where Δu = 10, Δv = 10, because vscale = 2).
Jacobian Determinant Scaling Factor = uscale x vscale
(quite intuitively).
Area in xy-dimensions = Δu x Δv x (uscale x vscale)
= 10 x 10 x 1 x 2 = 200.
Integration of volume over such a simpler uv Square,
could be easier than over the same xy Region,
appearing at an angle.
With the above initial understanding,
I am trying to work out how Jacobian Determinant is derived.
Deriving from the above Transformations formula:
dx/du = √2 / 2
dx/dv = √2
dy/du = -√2 / 2
dy/dv = √2
I can also derive from Geometry that:
dx/du = uscale cos Θ
dy/du = uscale sin Θ
dx/dv = vscale cos (90° - Θ)
dy/dv = vscale sin (90° - Θ)
I could get:
areaInXY / areaInUV = uscale x vscale
which matches my understanding.
However, Jacobian Determinant formula is:
∂(x, y) / ∂(u, v) = ∂x/∂u ∂y/∂v - ∂x/∂v ∂y/∂u
= uscale * vscale * cos 2Θ
This leaves me quite puzzled why I have the extra cos 2Θ factor
which isn't making intuitive sense -- why would the
area Scaling Factor depends on how the rectangle is rotated
and thus how uv-axes are rotated?!
Anybody can see where my reasoning went wrong above?
Let me try to explain what basically the Jacobian determinant does. This is true in general for smooth functions mapping from R^n to R^n, but for the sake of simplicity, assume we are working on R^2. Let F(x,y) a smooth R^2 to R^2 function. Then we can say that F(x,y) sends the x coordinate to f1(x,y) and the y coordiate to f2(x,y) at point (x,y). Then think about an infinitesimal rectangular area, defined by the points (x,y),(x+dx,y),(x,y+dy) and (x+dx,y+dy). Now, the area of this infinitesimal rectangle is dxdy. What happens to this rectangle when it goes through the F(x,y) transformation? We apply F(x,y) to each of the four coordinates and obtain the following points:
A:(x,y)->(f1(x,y),f2(x,y))
B:(x+dx,y) -> (f1(x+dx,y),f2(x+dx,y)) (approx.)= (f1(x,y) + (∂f1/∂x)dx,f2(x,y) + (∂f2/∂x)dx)
C:(x,y+dy) -> (f1(x,y+dy),f2(x,y+dy)) (approx.)= (f1(x,y) + (∂f1/∂y)dy,f2(x,y) + (∂f2/∂y)dy)
D:(x+dx,y+dy) -> (f1(x+dx,y+dy),f2(x+dx,y+dy)) (approx.)=(f1(x,y) + (∂f1/∂x)dx + (∂f1/∂y)dy,f2(x,y) + (∂f2/∂x)dx + (∂f2/∂y)dy)
The equalities are approximately equal and exactly hold in the limit where dx and dy goes to 0, they are the best linear approximation to the function F at new points. (We obtain these from the first order parts of the Taylor approximation of the functions f1 and f2).
If we look to the new (approximated) area under the transformation F(x,y), we see the new distance vectors between the transformed points a:
B-A:((∂f1/∂x)dx,(∂f2/∂x)dx)
C-A:((∂f1/∂y)dy,(∂f2/∂y)dy)
D-C:((∂f1/∂x)dx,(∂f2/∂x)dx)
D-B:((∂f1/∂y)dy,(∂f2/∂y)dy)
As you can see, the newly transformed infinitesimal area is a parallelogram. Let:
u=((∂f1/∂x)dx,(∂f2/∂x)dx)
v=((∂f1/∂y)dy,(∂f2/∂y)dy)
These vectors constitute the edges of our parallelogram. It can be shown with the help of the cross product between u and v, that the area of the parallelogram is:
area^2 = (u1v2 - u2v1)^2 = ((∂f1/∂x)(∂f2/∂y)dxdy - (∂f2/∂x)(∂f1/∂y)dxdy)^2
area^2 = ((∂f1/∂x)(∂f2/∂y) - (∂f2/∂x)(∂f1/∂y))^2 (dxdy)^2
area = |(∂f1/∂x)(∂f2/∂y) - (∂f2/∂x)(∂f1/∂y)|dxdy (dx and dy are positive)
area = |det([∂f1/∂x, ∂f1/∂y],[∂f2/∂x, ∂f2/∂y])|dxdy
So, the matrix we are going to take the determinant of is simply the Jacobian matrix. Like I said in the beginning, this derivation can be extended to arbitrary dimensions of n,given the coordinate transformation function F is smooth and the Jacobian matrix is hence invertible, with non-zero determinant.
A good visual explanation of this is given at: http://mathinsight.org/double_integral_change_variables_introduction

axes separated by angles

I'm trying to generate some axis vectors from parameters commonly used to specify crystallographic unit cells. These parameters consist of the length of the three axes: a,b,c and the angles between them: alpha,beta,gamma. By convention alpha is the angle between the b and c axes, beta is between a and c, and gamma between a and b.
Now getting vector representations for the first two is easy. I can arbitrarily set the the a axis to the x axis, so a_axis = [a,0,0]. I then need to rotate b away from a by the angle gamma, so I can stay in the x-y plane to do so, and b_axis = [b*cos(gamma),b*sin(gamma),0].
The problem is the third vector. I can't figure out a nice clean way to determine it. I've figured out some different interpretations but none of them have panned out. One is imagining the there are two cones around the axes axis_a and axis_b whose sizes are specified by the angles alpha and beta. The intersection of these cones create two lines, the one in the positive z direction can be used as the direction for axis_c, of length c.
Does someone know how I should go about determining the axis_c?
Thanks.
The angle alpha between two vectors u,v of known length can be found from their inner (dot) product <u,v>:
cos(alpha) = <u,v>/(||u|| ||v||)
That is, the cosine of alpha is the inner product of the two vectors divided by the product of their lengths.
So the z-component of your third can be any nonzero value. Scaling any or all of the axis vectors after you get the angles right won't change the angles, so let's assume (say) Cz = 1.
Now the first two vectors might as well be A = (1,0,0) and B = (cos(gamma),sin(gamma),0). Both of these have length 1, so the two conditions to satisfy with choosing C are:
cos(alpha) = <B,C>/||C||
cos(beta) = <A,C>/||C||
Now we have only two unknowns, Cx and Cy, to solve for. To keep things simple I'm going to just refer to them as x and y, i.e. C = (x,y,1). Thus:
cos(alpha) = [cos(gamma)*x + sin(gamma)*y]/sqrt(x^2 + y^2 + 1)
cos(beta) = x/(sqrt(x^2 + y^2 + 1)
Dividing the first equation by the second (assuming beta not a right angle!), we get:
cos(alpha)/cos(beta) = cos(gamma) + sin(gamma)*(y/x)
which is a linear equation to solve for the ratio r = y/x. Once you have that, substituting y = rx in the second equation above and squaring gives a quadratic equation for x:
cos^2(beta)*((1+r^2)x^2 + 1) = x^2
cos^2(beta) = (1 - cos^2(beta)*(1 + r^2))x^2
x^2 = cos^2(beta)/[(1 - cos^2(beta)*(1 + r^2))]
By squaring the equation we introduced an artifact root, corresponding to choosing the sign of x. So check the solutions for x you get from this in the "original" second equation to make sure you get the right sign for cos(beta).
Added:
If beta is a right angle, things are simpler than the above. x = 0 is forced, and we have only to solve the first equation for y:
cos(alpha) = sin(gamma)*y/sqrt(y^2 + 1)
Squaring and multiplying away the denominator gives a quadratic for y, similar to what we did before. Remember to check your choice of a sign for y:
cos^2(alpha)*(y^2 + 1) = sin^2(gamma)*y^2
cos^2(alpha) = [sin^2(gamma) - cos^2(alpha)]*y^2
y^2 = cos^2(alpha)/[sin^2(gamma) - cos^2(alpha)]
Actually if one of the angles alpha, beta, gamma is a right angle, it might be best to label that angle gamma (between the first two vectors A,B) to simplify the computation.
Here is a way to find all Cx, Cy, Cz (first two are the same as in the other answer), given that A = (Ax,0,0), B = (Bx, By, 0), and assuming that |C| = 1
1) cos(beta) = AC/(|A||C|) = AxCx/|A| => Cx = |A|cos(beta)/Ax = cos(beta)
2) cos(alpha) = BC/(|B||C|) = (BxCx+ByCy)/|B| => Cy = (|B|cos(alpha)-Bx cos(beta))/By
3) To find Cz let O be the point at (0,0,0), T the point at (Cx,Cy,Cz), P be the projection of T on Oxy and Q be the projection of T on Ox. So P is the point at (Cx,Cy,0) and Q is the point at (Cx,0,0). Thus from the right angle triangle OQT we get
tan(beta) = |QT|/||OQ| = |QT|/Cx
and from the right triangle TPQ we get |TP|^2 + |PQ|^2 = |QT|^2. So
Cz = |TP| = sqrt(|QT|^2 - |PQ|^2) = sqrt( Cx^2 tan(beta)^2 - Cy^2 )
I'm not sure if this is correct but I might as well take a shot. Hopefully I won't get a billion down votes...
I'm too lazy to scale the vectors by the necessary amounts, so I'll assume they are all normalized to have a length of 1. You can make some simple modifications to the calculation to account for the varying sizes. Also, I'll use * to represent the dot product.
A = (1, 0, 0)
B = (cos(g), sin(g), 0)
C = (Cx, Cy, Cz)
A * C = cos(beta) //This is just a definition of the dot product. I'm assuming that the magnitudes are 1, so I can skip that portion, and you said that beta was the angle between A and C.
A * C = Cx //I did this by multiplying each corresponding value, and the Cy and Cz were ignored because they were being multiplied by 0
cos(beta) = Cx //Combine the previous two equations
B * C = cos(alpha)
B * C = Cx*cos(g) + Cy*sin(g) = cos(beta) * cos(g) + Cy*sin(g)
(cos(alpha) - cos(beta) * cos(g))/(sin(g)) = Cy
To be honest, I'm not sure how to get the z component of vector C, but I would expect it to be one more relatively easy step. If I can figure it out, I'll edit my post.

Resources