Find how much to rotate given a box and a point A, such that an arbitrary vector within the box points towards point A

222 Views Asked by At

In a 3D world, given a box B, a pivot P, and a direction vector V, how can I find out how much to rotate at P such that V points towards an arbitrary point A?

Problem source:

I am a software developer that come across the need to rotate an object in the above manner, where a 3d model need to be rotated in this way for the user to interact with.

Current Attempts:

I tried using an offset between the direction vector and the pivot, and calculate the rotation required between the offseted target and the pivot.

However all my current attempts is done in code, and I left the mathematical calculation to the libraries due to my limited knowledge - which means to be honest I am not very clear what they actually do.

Note:

  1. B can be of any arbitrary size,
  2. P can be anywhere within the box
  3. V can be anywhere within the box
  4. A can be anywhere in the world

An illustration of what I am aiming for in 2D

2

There are 2 best solutions below

3
On

There is probably a better way of accomplishing this, but this is one method of calculating the quaternion of rotation:

We represent everything as a quaternion. That means instead of 3 coordinates, it will have 4, the first of which is $0$. In handling quaternions, addition and multiplication are defined by $$(a,b,c,d) + (w, x, y, z) = (a + w, b + x, c+y, d + z)$$ $$\begin{align}(a,b,c,d)(w, x, y, z) =\, (&aw - bx - cy - dz, \\&ax + bw + cz - dy, \\&ay - bz + cw + dx, \\&az + by - cx + dw)\end{align}$$Yes, the multiplication formula is a bit of a mess, but you only have to program it once. A real number $t$ is identified with the "scalar" quaternion $(t, 0, 0, 0)$ and a vector $V = (v_1, v_2, v_3)$ is identified with the "vector" quaternion $(0,v_1, v_2, v_3)$. Thus we can say that $$q = (t , v_1, v_2, v_3) = t + v$$where $t$ is the "scalar part of $q$", and $v$ is the "vector part $q$". Quaternions have conjugates defined by negating the vector part: $\bar q = t - v$. You can show that the product $q\bar q$ always has non-negative scalar part, and zero vector part, so we consider it to be just a real number. The absolute value, or norm, of a quaternion is $|q| = \sqrt{q\bar q} = \sqrt{t^2 + v_1^2 + v_2^2 + v_3^2}$. It follows that the inverse of a quaternion $q$ is $$\frac 1q = \frac {\bar q}{q\bar q} = \frac {\bar q}{|q|^2}$$

  1. First convert your point/vector information to quaternions with $0$ scalar part: $$P \to (0, P_1, P_2, P_3)\\A \to (0, A_1, A_2, A_3)\\V \to (0, V_1, V_2, V_3)$$
  2. We need not $A$, but the vector from $P$ to $A$, which is $N = A- P$. But we are only concerned about direction, not length, so we need a unit vector/quaternion. Divide $N$ by its length to get the target quaternion for the rotation: $T = \frac 1{|N|} N$
  3. $V$ is already a vector, so you don't need to subtract $P$ from it. Since you call it a direction vector, I assume it is already a unit vector. If not, divide it by its norm to turn it into a unit vector.
  4. We are looking for the rotation that carries $V$ to $T$. Multiply them together and break the result into scalar and vector parts: $VT = d + W$. The real number $d = -\cos \theta$, where $\theta$ is the angle between the vectors $V$ and $T$ (if $V$ and $T$ were not unit vectors, then $d$ would also be multiplied by the product of their lengths). $W$ is a vector perpendicular to both $V$ and $T$ and provides the axis we need to rotate around.
  5. If $|W| = 0$, then either $V = T$ or $V = -T$. Which is easily determined by comparing their coordinates. In the first case, you need do nothing, so the quaternion of rotation is just $1 = (1, 0, 0, 0)$. In the second case, it is $-1 = (-1, 0, 0, 0)$. The remainder of this can then be skipped.
  6. If $|W| \ne 0$, then let $U = \frac 1{|W|}W$, the unit vector in the same direction.
  7. Set $\theta = \arccos d$. You can also use $\theta = \text{atan2}(d, |W|)$, which might be a little more stable (I haven't investigated that, though).
  8. The quaternion of rotation will be $$q = \cos\frac \theta 2 + \sin\frac \theta 2 U$$

To rotate an arbitrary vector $S$, the result is just $$S' = qSq^{-1}$$ To rotate a point $B$, the process is $$B' = P + q(B - P)q^{-1}$$

2
On

This is not the most elegant method possible, as it does not provide an exact solution, but it would be close enough for practical purposes. There might be an exact solution, but it is eluding me.

That the point $P$ is anywhere within the box is unimportant, as is the length of the vector $\mathbf{v},$ as is the fact that the vector is inside the box - except for the very important fact that once you have chosen $\mathbf{v},$ it is "tacked down" to that point in the box and is not allowed to move; this is different from a regular vector. The mathematical problem at hand is this: given a rotation point $P$, vector $\mathbf{v}$ with tail at the point $Q,$ and a target point $A,$ find the angle $\theta$ through which and axis $\mathbf{x}$ about which to rotate vector $\mathbf{v}$ such that $\mathbf{v}$ points to $A.$

The first step is to find the axis about which to rotate. The straight-forward answer to this is that if we find the plane containing $\mathbf{v}$ and $A,$ then we want to rotate about an axis perpendicular to that plane and going through the point $P.$ This is not terribly difficult to determine: we use the cross-product to find the appropriate vector. Let $\mathbf{P}$ be the vector to point $P,$ $\mathbf{Q}$ the vector to point $Q,$ and $\mathbf{A}$ the vector to point $A,$ all from the origin. Then the axis of rotation, which we will call $\mathbf{x},$ is given by $$\mathbf{x}=\frac{\mathbf{v}\times(\mathbf{A}-\mathbf{Q})}{\|\mathbf{v}\times(\mathbf{A}-\mathbf{Q})\|}, $$ assuming that the angle between $\mathbf{v}$ and $(\mathbf{A}-\mathbf{Q})$ is not a multiple of $\pi.$ If the angle is zero, we actually have nothing to do: $\mathbf{v}$ is already pointed to $A!$ if the angle is $\pi,$ then we have the situation that $\mathbf{v}$ is pointed directly away from $A.$ In that case, it doesn't matter what the axis of rotation is, although we still need to find the angle through which to rotate (it isn't necessarily $\pi$). We can let the axis of rotation just be the $x$ axis: $\langle 1,0,0\rangle.$ If the cross product is not zero, then the result is a vector perpendicular to both $\mathbf{v}$ and $\mathbf{A}-\mathbf{Q},$ which makes it normal to the plane containing $\mathbf{v}$ and $A.$

Very well, we have the axis about which to rotate the vector $\mathbf{v}:$ in general, it's the line described by the vector $\mathbf{x}$ going through point $P.$

Quaternions have an advantage over rotation matrices for describing rotations: no gimbal lock. They can also handle rotation about arbitrary axes more easily than rotation matrices. So we choose quaternions. Here are the relevant points about quaternions: let $\mathbf{u}$ be a unit vector (the rotation axis), and let \begin{align*} r&=\cos(\alpha/2)+\mathbf{u}\sin(\alpha/2)\\ &=\cos(\alpha/2)+\mathbf{i}\,u_x\sin(\alpha/2)+\mathbf{j}\,u_y\sin(\alpha/2)+\mathbf{k}\,u_z\sin(\alpha/2). \end{align*} If we take the vector $\mathbf{v}$ and push it into quaternion land $v_q$: $$v_q=0+\mathbf{i}\,v_x+\mathbf{j}\,v_y+\mathbf{k}\,v_z, $$ then the equation $v_q'=rv_qr^{-1}$ yields the quaternion version of the vector $\mathbf{v}$ rotated about the axis $\mathbf{u}$ through the angle $\alpha.$

Now then, what follows is an algorithmic method to do the rotation. It turns out that if two vectors are parallel, their cross product is zero, and that fact corresponds to the quaternion representations commuting under quaternion multiplication. That is, $\|\mathbf{a}\times\mathbf{b}\|=0$ if and only if $ab-ba=0.$ Now we expect there to be two angles we could rotate by: one would make $v'$ pointing towards $A,$ and one would make $v'$ pointing away from $A.$ We would need a criterion for between-ness to distinguish between the two; in both cases, $v'(a-q)-(a-q)v'=0.$ So, we just minimize this condition: $$\min_\alpha\left\|rv_qr^{-1}\!\left(a-rqr^{-1}\right)-\left(a-rqr^{-1}\right)\!rv_qr^{-1}\right\|$$ subject to the condition that the point of $v'$ (which is $r(q+v_q)r^{-1}$) be in-between the tail of $v'$ (which is $rqr^{-1}$) and $A.$ Notice we have to rotate $q$ to $rqr^{-1}$ to make this work.

Just to be clear, $\alpha$ is the rotation angle used to produce $r$ according to the above equation, $a$ is the vector quaternion corresponding to $A,$ $q$ is the vector quaternion corresponding to $Q,$ and $v_q$ is the vector quaternion corresponding to the original $\mathbf{v}$ vector.

You can use this Stack Exchange question to determine between-ness.

A slight simplification of the above minimization problem: $$\min_\alpha\left\|rv_qr^{-1}a-rv_qqr^{-1}-arv_qr^{-1}+rqv_qr^{-1}\right\|. $$