Given a unit vector find the two angles of rotation that aligns that vector with an axis
Taking advantage of the fixed target alignment, this can be done in a straightforward manner with just trigonometry:
import mathdef to_y(x,y,z): rx=-math.atan2(z,y) # or +math.atan2(z,-y) y2=y*math.cos(rx)-z*math.sin(rx) # -> (x,y2,0) return rx,math.atan2(x,y2)
The rotations are defined as counterclockwise when looking at the origin from +x or +z (the right-hand rule); the rotation direction is always that with the smaller magnitude, but it may be possible to find a physically smaller rotation as indicated in the comment. Note that the input need not be normalized, and NaN is never produced (unless it appears in the input).
Hum, non-standard problem, required thinking a little.
Given v1
and v2
you want to rotate_z(rotate_x(v1, alpha), beta)
to be on the same direction as v2
.
We know that the aligned vector can be obtained by simply scaling scaling v2
, this will gives x1,y3,z3 = v3 = v2 * |v1| / |v2|
. Since rotation around z-axis, does not affect the z coordinate, we can determine alpha such that the z coordinate of rotate_x(v1, alpha)
equals z3
. After that we determine the angle beta
to align place the X and Y coordinates properly
import numpy as npdef alignment_angles(v1, v2): x1,y1,z1 = v1 # initial vector x2,y2,z2 = v2 # reference vector # magnitude of the two vectors r1 = np.sqrt(x1**2 + y1**2 + z1**2) r2 = np.sqrt(x2**2 + y2**2 + z2**2) # this will be the result when aligning v1 to v2 # it has the magnitude of v1 and the direction of v2 x3,y3,z3 = x2*r1/r2, y2*r1/r2, z2*r1/r2 # the rotation in x must set the z coordinate to the # final value, since the rotation over the z axis will # not affect the z coordinate (this have two solutions) rho1 = np.sqrt(z1**2 + y1**2) if(abs(z3 / rho1) > 1): raise ValueError('Cannot align these vectors') alpha = np.arcsin(z3 / rho1) - np.arctan2(z1, y1); # apply the rotation to make easier to calcualte the next stage y1, z1 = (y1 * np.cos(alpha) - z1 * np.sin(alpha), y1 * np.sin(alpha) + z1 * np.cos(alpha)) np.allclose(rho1, np.sqrt(z1**2 + y1**2)) #assert(np.allclose(z1, z3)) # now it is just a matter of aligning (x1, y1) to (x3, y3) beta = np.arctan2(y3, x3) - np.arctan2(y1, x1) x1, y1 = (x1 * np.cos(beta) - y1 * np.sin(beta), x1 * np.sin(beta) + y1 * np.cos(beta)) # ensure the fotated v1 was correctly aligned assert(np.allclose([x1, y1, z1], [x3, y3, z3])) return alpha, beta
Then you just call
alignment_angles((1,2,3), (3,4,5))
or you can also use numpy arrays with 3 rows.
Initially I thought it would be an application of spherical coordinates, that would be the case if the axis for the second rotation was the z-axis rotated accordingly to the first rotation.
Edit
There are some vectors that cannot be aligned with a rotation on x and a rotation on y.Suppose you want to align the vector v1 = (1, 0, 0)
to the vector v2 = (0, 0, 1)
the rotation in x will not affect v1, it will always point in the direction x, then when you rotate around the z axis it will always be on the XY plan.
The example you gave was really giving the wrong answer because asin
is not injective.
I changed the function to raise a value error when you cannot align the given vectors.