0

Let's say that I have two vectors around a unit sphere, like the black vectors in the figure. I would like to apply the same rotation on another vector that is always [1, 0, 0] (blue one in the figure). enter image description here I already got quite a lot of code for doing that, however it's not perfectly. working. It seems to work when the distance between the two vector is <45 degree, for example: enter image description here which looks ok. However, with another pair of vectors, I get: enter image description here enter image description here

Which is wrong. Why do I think it's wrong? I would think that applying the rotation between the two black vectors to the blue vector would result in a new rotation that is on the same latitude. However, this is clearly not the case

This is the code I am using. Sorry for the length, but most of it it's used for plotting: (you need the pyquaternion library: http://kieranwynn.github.io/pyquaternion/ )

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
from pyquaternion import Quaternion
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

plt.close('all')
fig = plt.figure(figsize=(10, 10))
ax = fig.gca(projection='3d')
# draw sphere
u, v = np.mgrid[0:2*np.pi:20j, 0:np.pi:10j]
x = np.cos(u)*np.sin(v)
y = np.sin(u)*np.sin(v)
z = np.cos(v)
ax.plot_wireframe(x, y, z, color=[1, 0, 0, 0.2])

# draw a point
ax.scatter([0], [0], [0], color="g", s=100)

# draw a vector
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d


class Arrow3D(FancyArrowPatch):
    def __init__(self, xs, ys, zs, *args, **kwargs):
        FancyArrowPatch.__init__(self, (0, 0), (0, 0), *args, **kwargs)
        self._verts3d = xs, ys, zs

    def draw(self, renderer):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
        self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
        FancyArrowPatch.draw(self, renderer)

def norm_v(v):
    return v / np.linalg.norm(v)

def add_norm_vector(u, col="k", norm=True):
    if norm:
        u = norm_v(u)
    vh = Arrow3D([0, u[0]], [0, u[1]], [0, u[2]], mutation_scale=20,
            lw=1, arrowstyle="-|>", color=col)
    ax.add_artist(vh)
    return vh

def rotation_v_respect_to_u(v, u):
    rot = Quaternion(axis=np.cross(v, u), angle=np.arccos(np.dot(u, v))).normalised
    vv = rot.rotate([1, 0, 0])
    return vv

## THIS ONE IS CORRECT
a=[0, 1, 0]
b = [-0.671868,  2.399499  , -0.04294401]

distance = rotation_v_respect_to_u(a, b)
add_norm_vector([1, 0, 0], 'b')

add_norm_vector(a)
add_norm_vector(b)
add_norm_vector(distance, 'r')

## THIS ONE IS NOT CORRECT!
a=[0, 1, 0]
b = [-3.7956853 , -3.90564173, -1.713661]

distance = rotation_v_respect_to_u(a, b)
add_norm_vector([1, 0, 0], 'b')

add_norm_vector(a)
add_norm_vector(b)
add_norm_vector(distance, 'r')

The important bit is in the function rotation_v_respect_to_u. The formula is taken from this post: Finding quaternion representing the rotation from one vector to another

Vaaal88
  • 591
  • 1
  • 7
  • 25
  • Your third image does look correct like you say. Try capturing a gif to rotate it for us like you mentioned. Would also be nice if you supplied a full list of packages to install; `pip install pyquaternion, matplotlib, etc...` – Mandera Nov 09 '20 at 12:30
  • Thanks, I updated the image from a new viewpoint, and also added a reason of why I think it's wrong. I may however have a different interpretation of "wrong", and maybe I want to accomplish something different to what my code is doing. – Vaaal88 Nov 09 '20 at 12:35
  • Isn't there a normalization step missing after the dot products but before the arccos function? Seems like you are applying it afterwards. PS: My bad you do mention that they lie on the unit sphere – Milton Llera Nov 09 '20 at 16:47

0 Answers0