Question

J'ai un ensemble de points de données dans l'espace 3D qui, apparemment, tombent tous sur un plan spécifique. J'utilise PCA pour calculer les paramètres du plan. La 3ème composante de PCA me donne le vecteur normal du plan (composante la plus faible).

Ce que je veux faire ensuite est de transformer tous les points sur ledit plan et de le regarder en 2D.

Mon idée était la suivante:

  • Rechercher un point central (point moyen) dans le plan
  • Soustrayez-le de tous les points de données pour les organiser autour de l'origine
  • Faites pivoter la normale pour qu'elle devienne (0,0, -1)
  • Appliquez cette rotation à tous les points de données
  • Utiliser la projection orthogonale (fondamentalement, ignorer l'axe z)

Maintenant, je suis incapable de trouver la bonne opération de rotation. J'ai essayé de travailler avec acos ou atan et de mettre en place deux matrices de rotation. Il semble que les deux méthodes (utilisation d’acos, utilisation d’Atan) me donnent un résultat erroné. Peut-être que vous pouvez m'aider ici!

Le code Matlab suit:

b = atan(n(1) / n(2));
rotb = [cos(b) -sin(b) 0; sin(b) cos(b) 0; 0 0 1];
n2 = n * rotb;
a = atan(n(1) / n(3));
rota = [cos(a) 0 sin(a); 0 1 0; -sin(a) 0 cos(a)];
n3 = n2 * rotaows:

Je m'attends à ce que n2 ait une composante y de zéro. Cependant, cela échoue déjà pour le vecteur (-0,6367, 0,7697, 0,0467).

Était-ce utile?

La solution

Si vous avez un avion, vous avez un vecteur normal et une origine. Je ne ferais aucune "rotation". du tout. Vous n'êtes qu'à quelques opérations vectorielles de votre réponse.

  • Appelons le vecteur normal de votre avion le nouvel axe z.
  • Vous pouvez générer le nouvel axe y en croisant l'ancien axe x avec le nouvel axe z (la normale de votre plan).
  • Générez le nouvel axe x en croisant le nouveau z avec le nouveau y.
  • Transformez tous vos nouveaux vecteurs d'axes en vecteurs unitaires (longueur 1).
  • Pour chaque point que vous avez, créez un vecteur allant de votre nouvelle origine au point (soustraction vectorielle du point - plane_origin). Il suffit de point avec les nouveaux vecteurs x et y et vous obtenez une paire (x, y) que vous pouvez tracer!

Si vous avez déjà des fonctions de produit en croix et en points, il ne reste que quelques lignes de code. Je sais que cela fonctionne parce que la plupart des jeux vidéo 3D que j'ai écrits ont fonctionné de cette manière.

Astuces:

  • Faites attention aux directions que pointent vos vecteurs. S'ils pointent dans le mauvais sens, annulez le vecteur résultant ou modifiez l'ordre du produit croisé.
  • Vous rencontrez des problèmes si la normale de votre avion est exactement identique à votre axe x d'origine.

Autres conseils

Que diriez-vous de:

Décomposez le vecteur normal en un vecteur dans le plan XY et un vecteur Z. Appliquez ensuite une rotation autour de l'axe Z pour aligner le vecteur XY avec l'un des axes. Recherchez ensuite le produit scalaire de la normale avec l’axe des Z et faites-le pivoter le long de la distance de X, Y avec laquelle vous vous êtes aligné.

L’idée est d’aligner le vecteur normal avec Z et, ce faisant, votre plan est maintenant le plan XY.

Bien qu'il y ait eu d'autres réponses intéressantes, voici la solution que nous avons trouvée en attendant les réponses:

function roti = magic_cosini(n)
    b = acos(n(2) / sqrt(n(1)*n(1) + n(2)*n(2)));
    bwinkel = b * 360 / 2 / pi;
    if (n(1) >= 0)
        rotb = [cos(-b) -sin(-b) 0; sin(-b) cos(-b) 0; 0 0 1];
    else
        rotb = [cos(-b) sin(-b) 0; -sin(-b) cos(-b) 0; 0 0 1];
    end
    n2 = n * rotb;
    a = acos(n2(3) / sqrt(n2(2)*n2(2) + n2(3)*n2(3)));
    awinkel = a * 360 / 2 / pi;
    rota = [1 0 0; 0 cos(-a) -sin(-a); 0 sin(-a) cos(-a)];
    roti = rotb * rota;

(Cela retourne une matrice à double rotation, espérons-le, correcte)

La faille que nous avions avant et corrigée ici était d’espionner. traiter avec le signe de la composante X, qui n'a pas été couvert dans les calculs de cosinus. Cela nous a fait tourner dans le mauvais sens une fois (rotation avec un angle de 180 & # 176;).

J'espère trouver le temps nécessaire pour essayer la solution de Nosredna! Il est toujours bon d'éviter la trigonométrie.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top