Calculate rotation around specific axis necessary to align with askew plane

61 Views Asked by At

Forgive me in advance for my nomenclature, I'm sure there are specific terms for the things I'm about to describe, but that's part of the reason I'm here. I'm not hugely skilled in geometry and if I knew the proper terms I'd probably be able to find the answer myself.

Consider the following object I've mocked up digitally: Cylinders

It's comprised of the thicker cylinder, which I'll call A and the thinner cylinder which I'll call B. These cylinders actually represent lines, so their thickness isn't important, but depicting them this way helps me think. In my application, I'm considering B as an offshoot, coming off of A.

The ground plane is also visible here and is relevant. A is "pocking through" the ground at an angle. And the intersection point of A and B is on that plane.

Here is my task. I need to line up the center of B so that it is aligned with the ground plane, but only by rotating the entire object along the central axis of A. No other rotation/translation.

The end result would look like this: Aligned cylinders

My problem is I need to determine the angle of rotation needed around A to align B with the ground. And well... I can't figure out how to do that. I can intuit that because A and B intersect on the plane, that there must be exactly two correct angles (provided the angle between A and the ground is greater than 0 and lesser than 90, which we can assume for this).

I have both A and B as 3D vectors. Mathematically, how can I calculate the angle around A I need to rotate B so that it aligns completely with the ground plane (where the vertical aspect of the B vector would be 0)? I might not need exact formulas so much as a general procedure, we'll see.

3

There are 3 best solutions below

0
On

Treating the cylinders as vectors as you say, let's call $O$ the intersection point between $\vec{A}$ and $\vec{B}$ on the ground plane, and $\vec{C}$ the final version of $\vec{B}$ after it has been rotated. We want to find the angle between $\vec{B}$ and $\vec{C}$, which can be calculated as, $$\theta = \cos^{-1} \left(\frac{\vec{B} \cdot \vec{C}}{||\vec{B}|| \; ||\vec{C}||}\right) \tag{1}\label{eq1}$$

So we need to find $\vec{C}$. We know $\vec{C}$'s tail is at $O$, since we are rotating about $\vec{A}$. We also know 1) $\vec{B}$ and $\vec{C}$ should have the same length, 2) the dot product with $\vec{A}$ should be the same since we are rotating about $\vec{A}$, and 3) $\vec{C}$ lies in the ground plane (since both the tail and centre lie in the ground plane, the whole vector lies in it). This gives us 3 equations on the three unknowns for direction components of $\vec{C}$, $$ ||\vec{C}|| = ||\vec{B}|| \\ \vec{C} \cdot \vec{A} = \vec{B} \cdot \vec{A} \\ \vec{C} \cdot \vec{e}_z = 0 $$

This should be solvable by hand (though the expressions may get ugly), and then you can plug into Eq. \eqref{eq1}.

0
On

Let unit vector $A$ be the axis of the cylinder $A$, and unit vector $B$ be the axis of cylinder $B$. Create two unit vectors $u_1, u_2$ that are perpendicular to $A$, and two each other, such that $A = u_1 \times u_2 $. Define the matrix

$R = [u_1,u_2, A]$

Then the coordinates of $B$ with respect to this new basis is

$B' = (x'_B, y'_B, z'_B) = R^T B $

If cylinder $B$ is perpendicular to cylinder $A$ we will have $z'_B = 0 $.

Now we want to rotate $B$ about $A$. This is equivalent to rotating $B'$ about the $z'$ axis. The rotation matrix about the $z'$ axis is given by

$ R_{z'} = \begin{bmatrix} \cos \theta && - \sin \theta && 0 \\ \sin \theta && \cos \theta && 0 \\ 0 && 0 && 1 \end{bmatrix} $

So the new coordinates of the rotated vector in our basis are

$ C' = R_{z'} B' $

And the corresponding coordinates of $C'$ in world coordinates are

$ C = R C' = R R_{z'} B' $

Now,

$ R R_{z'} = [u_1, u_2, A] R_{z'} = [ \cos \theta \ u_1 + \sin \theta \ u_2 , \ -\sin \theta \ u_1 + \cos \theta \ u_2 , A ] $

Hence, vector $C$ (in world coordinates) is

$ C = x'_B (\cos \theta \ u_1 + \sin \theta \ u_2) + y'_B (\ -\sin \theta \ u_1 + \cos \theta \ u_2 ) + z'_B A $

Since we're only interested in the $z$-coordinate of $C$ and we want it to be zero, then this gives us

$ 0 = C_z = x'_B (\cos \theta \ u_{1z} + \sin \theta \ u_{2z}) + y'_B (\ -\sin \theta \ u_{1z} + \cos \theta \ u_{2z} ) + z'_B A_z $

This equation is of the form

$ k_1 \cos \theta + k_2 \sin \theta = k_3 $

where

$ k_1 = x'_B \ u_{1z} + y'_B \ u_{2z} $

$ k_2 = x'_B \ u_{2z} - y'_B \ u_{1z} $

$ k_3 = - z'_B A_z $

This trigonometric equation in $\theta$ has the following (two) solutions:

$ \theta = \alpha \pm \beta $

Where $ \alpha = \text{ATAN2}(k_1, k_2) $ and $\beta = \cos^{-1} \left( \dfrac{k_3}{\sqrt{k_1^2 + k_2^2}} \right) $

Note that the $\text{ATAN2}(k_1, k_2)$ function returns an angle $\alpha$ whose tangent is $\dfrac{k_2}{k_1}$, and where the sign of $\cos \alpha$ is the same as that of $k_1$ and the sign of $\sin \alpha$ is the same as that of $k_2$.

0
On

Considering the elements

$$ \cases{ \vec a\ \ \ \ \text{thick cylinder axis}\\ \vec b\ \ \ \ \text{thin cylinder axis}\\ \vec n\ \ \ \ \text{normal direction to the plane}\\ \vec o = (0,0,0)\ \ \ \text{reference point }\\ p = (x,y,z)\ \ \text{generic point in }\mathbb{R}^3\\ \Pi\to (p-o)\cdot\vec n = 0\ \ \text{referential plane} } $$

using the Rodrigues rotation formula we have

$$\vec b_{rot}(\theta) = \vec b\cos\theta+\vec a\times\vec b \sin\theta+\vec a\cdot\vec b(1-\cos\theta)\vec a $$

so as $\vec b_{rot}(\theta)\in \Pi$ we need that

$$ (\vec b_{rot}(\theta)-o)\cdot\vec n=0 $$

thus determining $\theta^*$.

Follows a MATHEMATICA script making the necessary caculations and representation

n = {nx, ny, nz};
a = {ax, ay, az};
b = {bx, by, bz};
p = {x, y, z};
o = {0, 0, 0};
parms = {nx -> -1, ny -> 0, nz -> -1, ax -> 0, ay -> 1, az -> -1, bx -> 1, by -> 1, bz -> 1, ra -> 2, rb -> 1/2};
va = a / Norm[a];
rot[theta_] := b Cos[theta] + Cross[va, b] Sin[theta] + va.b (1 - Cos[theta]) va
equ = rot[theta].n /. parms;
soltheta = Solve[equ == 0, theta][[1]] /. {C[1] -> 0};
b0 = rot[theta] /. parms /. soltheta;

grcya = Graphics3D[Cylinder[{o - a, o + a}, ra] /. parms];
grcyb = Graphics3D[Cylinder[{o, o + 3 b}, rb] /. parms];
grcyb0 = Graphics3D[Cylinder[{o, o + 3 b0}, rb] /. parms];
pl = p.n /. parms
r = 6;
grpl = ContourPlot3D[pl == 0, {x, -r, r}, {y, -r, r}, {z, -r, r}, Mesh -> False, ContourStyle -> Directive[Orange, Opacity[0.4], Specularity[White, 30]]];
Show[grcya, grcyb, grcyb0, grpl]

enter image description here