How to find a random unit vector orthogonal to a random unit vector in 3D?

5k Views Asked by At

I have a unit circle with the center at the origin $O=(0, 0, 0)$ and a random unit vector $\bar U = (a, b, c)$, in the Cartesian coordinate system. How can I find a random unit vector orthogonal to $\bar U$?

My try was to find an intersection of my sphere and plane, which passes through the origin and has $\bar U$ as a normal vector, and then to define a point on this unit circle randomly.

So I have the system of equations: \begin{cases} x^2 + y^2 + z^2 = 1, \\ ax + by + cz = 0, \end{cases} and I wanted to set the solutions of this system parametrically but I got stuck. I know how to set the solutions in particular cases (e.g. when $a=c\neq0$) but I have no idea for the general one.

5

There are 5 best solutions below

3
On BEST ANSWER

If you are only interested in a numerical solution rather than a parametric one you can do the following:

If we call $\vec{n}=(a,b,c)$ than the corresponding unit vector is $\hat{n} = \frac{\vec{n}}{| \vec{n}|}$. Now generate a uniformly distributed random point $\vec{r}$ inside a sphere of radius 1.

Form the vector $\vec{u} = \vec{r} - \left( \vec{r}.\hat{n} \right) \hat{n}$. It is easy to see that this vector is perpendicular to $\vec{n}$. So if you normalise it you get a random unitvector $\hat{u}$ that is perpendicular to the normal of your circle.

There is of course a slight numerical problem if the random vector $\vec{r}$ is almost parallel to the normal. You could repeat generating the random vector $\vec{r}$ until the angle it makes with the normal is sufficiently large.

For a parametric solution, use a simple perpendicular vector $\vec{u} = (b, -a,0)$ and calculate the cross product $\vec{v} = \vec{n} \times \vec{u}$, normalise both and take a linear combination $\hat{w} = \cos \theta \hat{u} + \sin \theta \hat{v}$ with a uniformly distributed random $\theta \in [0,2 \pi]$.

4
On

Orthogonal is equivalent to dot product being zero. Doesn't $\dfrac{1}{\sqrt{a^2+b^2}}(-b,a,0)$ work?

0
On

At least two of $(b,-a,0)$, $(c,0,-a)$ and $(0,c,-b)$ will be nonzero, so you can normalise one of them.

There is no continuous map $f$ from unit vectors to unit vectors with $v\cdot f(v)=0$. This is the Hairy Ball Theorem. This means there probably won't be a "nice" closed formula for a perpendicular unit vector.

0
On

Assume your reference vector be $\mathbb{x}=(1,0,0)$, then the normal unit vector would be $\mathbf{n} =(0,\cos{t},\sin{t}) \quad |\; -\pi<t \le \pi$, where $t$ is a parameter.
So, for $t$ uniformly distributed in its range,
$$ \bbox[lightyellow] { \mathbf n \; \text{is a "unit random vector", normal to }\; \mathbf x }$$ (if I understood what you mean by that).

Now, instead, your reference vector is $\mathbf {v}=(a,b,c)$, with $|\mathbf {v}|=1$, which can be written in terms of polar angles as $\mathbf {v}=(cos{\theta}cos{\phi},cos{\theta}sin{\phi},sin{\theta})$, with: $$ \left\{ \matrix{ - \pi < \varphi = \arctan _4 (a,b) \le \pi \hfill \cr - \pi /2 \le \vartheta = \arctan \left( {{c \over {\sqrt {a^{\,2} + b^{\,2} } }}} \right) \le \pi /2 \hfill \cr} \right. $$

The Rotation Matrices giving a rotation with angles $\theta$ and $\phi$ (with sign taken according to the right hand rule) respectively around the $y$ and the $z$ axis are: $$ R_{\,z} (\varphi ) = \left( {\matrix{ {\cos \varphi } & { - \sin \varphi } & 0 \cr {\sin \varphi } & {\cos \varphi } & 0 \cr 0 & 0 & 1 \cr } } \right)\quad R_{\,y} (\vartheta ) = \left( {\matrix{ {\cos \vartheta } & 0 & {\sin \vartheta } \cr 0 & 1 & 0 \cr { - \sin \vartheta } & 0 & {\cos \vartheta } \cr } } \right) $$

Therefore $$ {\bf v} = R_{\,z} (\varphi )\;R_{\,y} ( - \vartheta )\;{\bf x} $$

and the vector $\mathbf{n}'$ you are looking for is equivalently given by: $$ \bbox[lightyellow] { {\bf n}'(t) = R_{\,z} (\varphi )\;R_{\,y} ( - \vartheta )\;{\bf n}(t) }$$

0
On

I know this is an old-ish question, but here is a solution that is rather simple and always works.

Let's denote a generic unit vector $ \boldsymbol{u} = (a, b, c)$, such that $|i|\neq 1$, for $i = a, b, c$. It is easy to show that, no matter the choice of $ \boldsymbol{u} $, the following three vectors are always orthogonal to $\boldsymbol{u}$:

\begin{equation} \boldsymbol{v}_a = \begin{pmatrix} 0 \\ c \\ -b \end{pmatrix} \quad \boldsymbol{v}_b = \begin{pmatrix} -c \\ 0 \\ a \end{pmatrix} \quad \boldsymbol{v}_c = \begin{pmatrix} b \\ -a \\ 0 \end{pmatrix} \end{equation}

Furthermore, using the cross product, one can find a third set of vectors $\boldsymbol{w}_i$ that are orthogonal to $\boldsymbol{u}$ and $\boldsymbol{v}_i$:

\begin{equation} \boldsymbol{w}_a = \begin{pmatrix} a^2 - 1 \\ ab \\ ac \end{pmatrix} \quad \boldsymbol{w}_b = \begin{pmatrix} ab \\ b^2-1 \\ bc \end{pmatrix} \quad \boldsymbol{w}_c = \begin{pmatrix} ac \\ bc \\ c^2-1 \end{pmatrix} \end{equation}

Each triplet $(\boldsymbol{u}, \boldsymbol{v}_i, \boldsymbol{w}_i)$ is a basis of orthogonal vectors by construction. Finally, it can be shown that the expression

\begin{equation} \boldsymbol{p}_i = \boldsymbol{v}_i \frac{\cos\theta}{\sqrt{1-i^2}} + \boldsymbol{w}_i \frac{\sin\theta}{\sqrt{1-i^2}} \end{equation}

generates all unit vectors that are orthogonal to $\boldsymbol{u}$ when changing $\theta$ between $0$ and $2\pi$ - this is the parameteric solution that OP was looking for.

Note that the procedure above provides 3 distinct parameterizations. However, each of them has a singularity when $i^2 = 1$, in which case $\boldsymbol{v}_i$ and $\boldsymbol{w}_i$ both become null - this is why I initially added the hypothesis that $|a|\neq 1$, $|b|\neq 1$ and $|c|\neq 1$. However, only one of the three triplets can be singular at a time. The "bullet-proof strategy" is to select as $i$ the closest to zero between $a$, $b$ and $c$.

Here is a Python-NumPy code that calculates the vectors:

def get_vw(u):
    # Make a permutation of the indices so that the least value is always "a"
    i = np.argmin(np.abs(u))
    a, b, c = np.roll(u.copy(), -i)
    
    # Calculate v and w using the formulae for v_a and w_a 
    d = np.sqrt(1 - a**2)
    v = np.array([0, c/d, -b/d])
    w = np.array([-d, a*b/d, a*c/d])

    # Perform the inverse permutation when returning the result
    return np.roll(v, i), np.roll(w, i)
```