79 votes

Rotation d'un vecteur 3D ?

J'ai deux vecteurs sous forme de listes Python et un angle. Par exemple :

v = [3,5,0]
axis = [4,4,1]
theta = 1.2 #radian

Quelle est la meilleure façon d'obtenir le vecteur résultant lors de la rotation du vecteur v autour de l'axe ?

La rotation doit apparaître dans le sens inverse des aiguilles d'une montre pour un observateur vers lequel pointe le vecteur de l'axe. C'est ce qu'on appelle le règle de la main droite

14 votes

Je trouve très surprenant qu'il n'y ait pas de fonctionnalité pour cela dans SciPy (ou un paquetage similaire facilement accessible) ; la rotation de vecteurs n'est pas si exotique.

3 votes

Aujourd'hui, c'est le cas : scipy.spatial.transform.Rotation.from_rotvec

7voto

Morten Lind Points 73

J'ai créé une bibliothèque assez complète de mathématiques 3D pour Python{2,3}. Elle n'utilise toujours pas Cython, mais s'appuie fortement sur l'efficacité de numpy. Vous pouvez la trouver ici avec pip :

python[3] -m pip install math3d

Ou jetez un coup d'œil à mon gitweb http://git.automatics.dyndns.dk/?p=pymath3d.git et maintenant aussi sur github : https://github.com/mortlind/pymath3d .

Une fois installé, en python, vous pouvez créer l'objet orientation qui peut faire tourner des vecteurs, ou faire partie d'objets de transformation. Par exemple, l'extrait de code suivant compose une orientation qui représente une rotation de 1 rad autour de l'axe [1,2,3], l'applique au vecteur [4,5,6] et imprime le résultat :

import math3d as m3d
r = m3d.Orientation.new_axis_angle([1,2,3], 1)
v = m3d.Vector(4,5,6)
print(r * v)

Le résultat serait

<Vector: (2.53727, 6.15234, 5.71935)>

Cette méthode est plus efficace, d'un facteur d'environ quatre, d'après ce que j'ai pu observer, que la méthode oneliner utilisant scipy postée par B. M. ci-dessus. Cependant, il nécessite l'installation de mon paquetage math3d.

0 votes

Je sais que c'est très bizarre, mais je n'arrive pas à trouver un autre moyen de vous contacter. Serait-il possible d'utiliser la bibliothèque math3d pour créer plus facilement des projections 2D de fonctions 3D sur un axe arbitraire ? Par exemple, imaginez la projection d'une distribution normale sur le plan xy à partir de l'axe z. Imaginez maintenant que vous vous éloignez de l'axe z par l'angle polaire thêta (comme dans la notation des coordonnées sphériques) et que vous projetez la distribution normale sur un plan qui est également tourné par thêta en référence à xy ? C'est comme la projection orthogonale + l'intégration. Je peux ouvrir une nouvelle question à ce sujet si vous le souhaitez.

0 votes

Bonjour, ljetbo, je pense que cela semble difficile, ou simplement pas très facile avec math3d. La fonction impliquerait, je suppose, une fonction analytique, alors que math3d fonctionne mieux avec des ensembles de points. De plus, vous semblez parler d'un champ scalaire sur le plan (R(2)), alors que math3d traite du groupe euclidien spécial (SE+(3)). Il est peut-être possible de faire ce que vous souhaitez, mais je n'ai pas d'idée immédiate sur la manière d'intégrer une fonction analytique dans math3d.

5voto

Fermi paradox Points 2930

Utilisez la fonction Rotation.from_rotvec() . L'argument est le vecteur de rotation (un vecteur unitaire) multiplié par l'angle de rotation en rads.

from scipy.spatial.transform import Rotation
from numpy.linalg import norm

v = [3, 5, 0]
axis = [4, 4, 1]
theta = 1.2

axis = axis / norm(axis)  # normalize the rotation vector first
rot = Rotation.from_rotvec(theta * axis)

new_v = rot.apply(v)  
print(new_v)    # results in [2.74911638 4.77180932 1.91629719]

Il existe plusieurs autres façons d'utiliser Rotation en fonction des données dont vous disposez sur la rotation :

  • from_quat Initialisé à partir des quaternions.

  • from_dcm Initialisé à partir des matrices cosinus directionnelles.

  • from_euler Initialisé à partir des angles d'Euler.


<strong>Note hors sujet : </strong>Le code d'une ligne est <em>no </em>nécessairement un meilleur code comme l'ont laissé entendre certains utilisateurs.

0 votes

@smoothumut heureux d'être utile, mon ami.

3voto

Guillaume Mougeot Points 103

Il peut également être résolu à l'aide de la théorie des quaternions :

def angle_axis_quat(theta, axis):
    """
    Given an angle and an axis, it returns a quaternion.
    """
    axis = np.array(axis) / np.linalg.norm(axis)
    return np.append([np.cos(theta/2)],np.sin(theta/2) * axis)

def mult_quat(q1, q2):
    """
    Quaternion multiplication.
    """
    q3 = np.copy(q1)
    q3[0] = q1[0]*q2[0] - q1[1]*q2[1] - q1[2]*q2[2] - q1[3]*q2[3]
    q3[1] = q1[0]*q2[1] + q1[1]*q2[0] + q1[2]*q2[3] - q1[3]*q2[2]
    q3[2] = q1[0]*q2[2] - q1[1]*q2[3] + q1[2]*q2[0] + q1[3]*q2[1]
    q3[3] = q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1] + q1[3]*q2[0]
    return q3

def rotate_quat(quat, vect):
    """
    Rotate a vector with the rotation defined by a quaternion.
    """
    # Transfrom vect into an quaternion 
    vect = np.append([0],vect)
    # Normalize it
    norm_vect = np.linalg.norm(vect)
    vect = vect/norm_vect
    # Computes the conjugate of quat
    quat_ = np.append(quat[0],-quat[1:])
    # The result is given by: quat * vect * quat_
    res = mult_quat(quat, mult_quat(vect,quat_)) * norm_vect
    return res[1:]

v = [3, 5, 0]
axis = [4, 4, 1]
theta = 1.2 

print(rotate_quat(angle_axis_quat(theta, axis), v))
# [2.74911638 4.77180932 1.91629719]

2voto

Dr.PP Points 581

L'utilisation de pyquaternion est extrêmement simple ; pour l'installer (tout en restant en python), lancez dans votre console :

import pip;
pip.main(['install','pyquaternion'])

Une fois installé :

  from pyquaternion import Quaternion
  v = [3,5,0]
  axis = [4,4,1]
  theta = 1.2 #radian
  rotated_v = Quaternion(axis=axis,angle=theta).rotate(v)

2voto

Mr Z Points 151

Clause de non-responsabilité : je suis l'auteur de ce paquet

Bien que des classes spéciales pour les rotations puissent être pratiques, dans certains cas on a besoin de matrices de rotation (par exemple pour travailler avec d'autres bibliothèques comme les fonctions affine_transform de scipy). Pour éviter que tout le monde n'implémente ses propres fonctions de génération de matrices, il existe un petit paquetage en python pur qui ne fait rien d'autre que de fournir des fonctions pratiques de génération de matrices de rotation. Ce paquetage se trouve sur github ( mgen ) et peut être installé via pip :

pip install mgen

Exemple d'utilisation copié à partir du fichier readme :

import numpy as np
np.set_printoptions(suppress=True)

from mgen import rotation_around_axis
from mgen import rotation_from_angles
from mgen import rotation_around_x

matrix = rotation_from_angles([np.pi/2, 0, 0], 'XYX')
matrix.dot([0, 1, 0])
# array([0., 0., 1.])

matrix = rotation_around_axis([1, 0, 0], np.pi/2)
matrix.dot([0, 1, 0])
# array([0., 0., 1.])

matrix = rotation_around_x(np.pi/2)
matrix.dot([0, 1, 0])
# array([0., 0., 1.])

Notez que les matrices sont des tableaux numpy ordinaires, donc aucune nouvelle structure de données n'est introduite lors de l'utilisation de ce paquet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X