Rotation matrix that minimizes distance - math

Let's say I have two points in 3D space (a and b) and a fixed axis/unit vector called n.
I want to create a rotation matrix that minimizes the euclidan distance between point a (unrotated) and the rotated point b.
E.g:
Q := matrix_from_axis_and_angle (n, alpha);
find the unknown alpha that minimizes sqrt(|a - b*Q|)
Btw - If a solution/algorithm can be easier expressed with unit-quaternions go ahead and use them. I just used matrices to formulate my question because they're more widely used.
Oh - I know there are some degenerated cases ( a or b lying exactly in line with n ect.) These can be ignored. I'm just looking for the case where a single solution can be calculated.

sounds fairly easy. Assume unit vector n implies rotation around a line parallel to n through point x0. If x0 != the origin, translate the coordinate system by -x0 to get points a' and b' relative to new coordinate system origin 0, and use those 2 points instead of a and b.
1) calculate vector ry = n x a
2) calculate unit vector uy = unit vector in direction ry
3) calculate unit vector ux = uy x n
You now have a triplet of mutually perpendicular unit vectors ux, uy, and n, which form a right-handed coordinate system. It can be shown that:
a = dot(a,n) * n + dot(a,ux) * ux
This is because unit vector uy is parallel to ry which is perpendicular to both a and n. (from step 1)
4) Calculate components of b along unit vectors ux, uy. a's components are (ax,0) where ax = dot(a,ux). b's components are (bx,by) where bx = dot(b,ux), by = dot(b,uy). Because of the right-handed coordinate system, ax is always positive so you don't actually need to calculate it.
5) Calculate theta = atan2(by, bx).
Your rotation matrix is the one which rotates by angle -theta relative to coordinate system (ux,uy,n) around the n-axis.
This yields degenerate answers if a is parallel to n (steps 1 and 2) or if b is parallel to n (steps 4, 5).

I think you can rephrase the question to:
what is the distance from a point to a 2d circle in 3d space.
the answer can be found here
so the steps needed are as following:
rotating the point b around a vector n gives you a 2d circle in 3d space
using the above, find the distance to that circle (and the point on the circle)
the point on the circle is the rotated point b you are looking for.
deduce the rotated angle
...or something ;^)

The distance will be minimized when the vector from a to the line along n lines up with the vector from b to the line along n.
Project a and b into the plane perpendicular to n and solve the problem in 2 dimensions. The rotation you get there is the rotation you need to minimize the distance.

Let P be the plane that is perpendicular to n.
We can find the projection of a into the P-plane, (and similarly for b):
a' = a - (dot(a,n)) n
b' = b - (dot(b,n)) n
where dot(a,n) is the dot-product of a and n
a' and b' lie in the P-plane.
We've now reduced the problem to 2 dimensions. Yay!
The angle (of rotation) between a' and b' equals the angle (of rotation) needed to swing b around the n-axis so as to be closest to a. (Think about the shadows b would cast on the P-plane).
The angle between a' and b' is easy to find:
dot(a',b') = |a'| * |b'| * cos(theta)
Solve for theta.
Now you can find the rotation matrix given theta and n here:
http://en.wikipedia.org/wiki/Rotation_matrix
Jason S rightly points out that once you know theta, you must still decide to rotate b clockwise or counterclockwise about the n-axis.
The quantity, dot((a x b),n), will be a positive quantity if (a x b) lies in the same direction as n, and negative if (a x b) lies in the opposite direction. (It is never zero as long as neither a nor b is collinear with n.)
If (a x b) lies in the same direction as n, then b has to be rotated clockwise by the angle theta about the n-axis.
If (a x b) lies in the opposite direction, then b has to be rotated clockwise by the angle -theta about the n-axis.

Related

Panning via normal vector and plane

I have got a camera and the direction it is looking at. Therefore I can create a plane out of this direction vector if I take it as a normal vector. So now I want to move my camera which should be on this plane along the plane. Everything's in 3D but I couldn't come up with an idea how to do so. How can I implement the navigational method of panning - so moving in this specific plane?
To pan your camera to the left and to the right you need to know not only lookAt direction, but also up direction for the camera. Then you can calculate cross product of lookAt and upAxis and this gives you direction to the right, negated vector gives you direction to the left.
Definition: A vector N that is orthogonal to every vector in a plane is called a normal vector to the plane.
An equation of the plane containing the point (x0, y0, z0) with normal vector N = (A, B, C), is A(x − x0) + B(y − y0) + C(z − z0) = 0.
Note: The equation of any plane can be expressed as Ax + By + Cz = D.
This is called the standard form of the equation of a plane. From the eqn you can get any other point you want on the plane.
Example: A plane passing through the point P = (1, 6, 4) and the normal vector, R = (2, - 3, - 1). Then the eqn is,
2(x-1) - 3(y-6) - (z-4) = 0
=> 2x - 3y - z = -20

Point to the left or right of 3D vector in a specifc plane?

I am not sure if a question like this was asked before but i searched and didn't found what i am looking for.
I know how to determine if a point is to the left or right of a 2D line. but suppose we have a vector in 3D. of course a 3D vector passes through infinite planes, but suppose we chose one plane of them in which we are interested, and we have a specific point on this plane which we want to know if it lies to the left or right or on our vector (with respect to the chosen plane). how to do this ?
You should explicitly define orientation of that plane - for example, define main (forward) normal N - like OZ axis is normal for OXY plane.
If you have A,B,C triangle and claim that it is oriented counterclockwise, you can calculate forward plane normal as N = AB x BC
For points A, B, D in given plane calculate mixed product (vector product of AB and AD, then scalar product of result and N)
mp = (AB x AD) . dot. N
Sign of this value is positive, if vectors AB, AD, N form right-handed triplet and D lies left to AB direction
An intuitive solution is to define a coordinate system for the plane as follows. Let's normalize the 3d vector in your question and call the resulting unit vector v, and let x be a point on your plane, whose unit normal we will denote as n. You can now chose a coordinate system centered at x, that is made by the three 3*1 unit vectors v, n and b=v.crossProduct(n).
The idea is that if you express a point in this coordinate system, then if its b coordinate is negative, you can says that it is, say, on the left. So, if its b coordinate is positive, it will be on the right.
Obviously, if you have a point q expressed in this coordinates system, you can write its expression q_w in world coordinates using
q_w=R*q+x
where the rotation matrix R is the matrix whose columns are the unit axes of the plane coordinate system:
R=[v n b]
So, if you have a point Q in world coordinates, using the inverse of the relation above, you compute transpose(R)*(Q-x), and look at whether the b coordinate is positive or negative.

how to get a vector from an angle

I'm making a game in pygame and I want a spaceship to move in the direction it's facing. I have the angle and the magnitude, how can I get the direction in the form of a normalized vector that I can then add to the spaceship's x and y to make it move?
What you want to do is change polar coordinates to Cartesian coordinates.
So as I see it you are in 2D. Now you can not avoid using trigonometry.
Let's assume that you are facing with an α angle beginning from the x axis, and growing towards y. Let d be the magnitude.
Vx = cos(α) * d
Vy = sin(α) * d
Now this is not normalized, as I have already multiplied it with d, the magnitude of the speed.
Please check what type of angle your sin and cos functions take, and give matching inputs (it can be radians or degrees). An easy way to check this is to print out sin(30). If it is 0.5, you are in degrees. If it is -0.988... you are in radians.

Finding the angle between vectors [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Finding Signed Angle Between Vectors
I'm in need of help with a little math issue.
So, I got a vector v, representing an orientation, and two points s and t. What I what to do, is to find the rotation to apply to my vector v, in order to make it parallel with the vector defined by the two given points.
currently I'm somewhat achieving this, that is, I'm able to find the angle, just not the way to apply it (clockwise or counter clockwise).
Currently I'm just calculating the acos to the dot product of the vectors.
Any input is welcome.
Let's say acos gives you a value between 0 and pi.
Let's also say the vector from s to t is called u. As you have already computed,
acos((v . u)/(|v| * |u|))
gives you an angle alpha. Now in truth, v could be u rotated by alpha to one or the other direction.
You probably need this in 2D, but I'll go on in 3D first.
The rotation should be around a vector that is perpendicular to both v and u. This vector is of course the cross product of the two: u x v
Let's see an example:
/ v
/
/\ alpha
/ )
------------ u
In this case, u x v gives a vector towards the outside of your monitor. At the same time, you can see that the ration alpha should take place counterclockwise to make v parallel to u.
That is, in 3D, you have to compute w = u x v and always rotate v by alpha counterclockwise with respect to w. Alternatively, you can rotate v by alpha clockwise with respect to -w (which is v x u).
In 2D, I assume you want to rotate around z and you don't know which direction. You can apply the same method as above:
Compute w = u x v
If w has positive z (the x and y will be zero)
then, v should be rotated counterclockwise.
else, v should be rotated clockwise.

Transform 3D points to 2D

I have a set of points (x1, x2,..xn) that lie on the plane define by Ax+ By+Cz+d=0.
I would like to find the transformation matrix to translate and rotate to XY plane. So, the new point coordinate will be x1'=(xnew, ynew,0).
A lot of answer give quaternion, dot or cross product matrix. I am not sure which one is the correct way.
Thank you
First of all, unless in your plane equation, d=0, there is no linear transformation you can apply. You need to instead perform an affine transformation.
One way to do this is to determine an angle and vector about which to rotate to make your pointset lie in a plane parallel to the XY plane (ie. the Z component of your transformed pointset to all have the same values). Then you simply drop the Z component.
For this, let V be the normalized plane normal for the plane containing your points. For convenience define from your plane equation above Ax+By+Cz+d=0:
V = (A, B, C)
V' = V / ||V|| = (A', B', C')
Z = (0, 0, 1)
where
A' = A / ||V||
B' = B / ||V||
C' = C / ||V||
||V|| = (A2+B2+C2)1/2
The angle will simply be:
θ = cos-1(Z∙V / ||V||)
= cos-1(Z∙V')
= cos-1(C')
The axis R about which to rotate is just the cross product of the normalized plane normal V' and Z. That is
R = V'×Z
= (B', -A', 0)
You can now use this angle / axis pair to build the quaternion rotation needed to rotate all of the points in your dataset to a plane parallel to the XY plane. Then, a I said earlier, just drop the Z component to perform an orthogonal projection onto the XY plane.
Update: antonakos makes a good point about normalizing the R before using an API taking axis / angle pairs.

Resources