it-swarm.com.de

Signierter Winkel zwischen zwei 3D-Vektoren mit gleichem Ursprung in derselben Ebene

Was ich brauche, ist ein vorzeichenbehafteter Drehwinkel zwischen zwei Vektoren Va und Vb, die in derselben 3D-Ebene liegen und denselben Ursprung haben, wobei ich weiß, dass:

  1. Die Ebene, die beide Vektoren enthält, ist willkürlich und ist nicht parallel zu XY oder einer anderen Kardinalebene
  2. Vn - ist eine Flächennormale
  3. Beide Vektoren haben zusammen mit dem Normalen den gleichen Ursprung O = {0, 0, 0}
  4. Va - ist eine Referenz zum Messen der Linksdrehung bei Vn

Der Winkel sollte so gemessen werden, dass, wenn die Ebene eine XY-Ebene sein würde, Va für den X-Achsen-Einheitsvektor davon stehen würde.

Ich denke, ich sollte eine Art Koordinatenraumtransformation durchführen, indem ich Va als X-Achse und das Kreuzprodukt von Vb und Vn als Y-Achse und dann einfach eine 2d-Methode wie bei atan2 () oder so etwas verwende. Irgendwelche Ideen? Formeln

43

Verwenden Sie das Kreuzprodukt der beiden Vektoren, um die Normalen der durch die beiden Vektoren gebildeten Ebene zu erhalten. Überprüfen Sie dann das Punktprodukt zwischen diesem und der ursprünglichen Normalenebene, um zu sehen, ob sie in dieselbe Richtung zeigen.

angle = acos(dotProduct(Va.normalize(), Vb.normalize()));
cross = crossProduct(Va, Vb);
if (dotProduct(Vn, cross) < 0) { // Or > 0
  angle = -angle;
}
54
msell

Die Lösung, die ich derzeit verwende, scheint hier zu fehlen. Unter der Annahme, dass die Ebenennormale normalisiert ist (|Vn| == 1), Lautet der vorzeichenbehaftete Winkel einfach:

atan2((Vb x Va) . Vn, Va . Vb)

dies gibt einen Winkel im Bereich [-PI, + PI] zurück (oder was auch immer die verfügbare atan2-Implementierung zurückgibt).

. Und x sind das Punkt- bzw. Kreuzprodukt.

Es ist keine explizite Verzweigung und keine Division/Vektorlängenberechnung erforderlich. Verwenden Sie Va x Vb Für die Rechtsdrehung anstelle der Linken

Erklärung, warum dies funktioniert: Sei alpha der direkte Winkel zwischen den Vektoren (0 ° bis 180 °) und beta der gesuchte Winkel (0 ° bis 360 °) mit beta == alpha Oder beta == 360° - alpha

Va . Vb == |Va| * |Vb| * cos(alpha)    (by definition) 
        == |Va| * |Vb| * cos(beta)     (cos(alpha) == cos(-alpha) == cos(360° - alpha)


Va x Vb == |Va| * |Vb| * sin(alpha) * n1  
    (by definition; n1 is a unit vector perpendicular to Va and Vb with 
     orientation matching the right-hand rule)

Therefore (again assuming Vn is normalized):
   n1 . Vn == 1 when beta < 180
   n1 . Vn == -1 when beta > 180

==>  (Va x Vb) . Vn == |Va| * |Vb| * sin(beta)

Endlich

tan(beta) = sin(beta) / cos(beta) == ((Va x Vb) . Vn) / (Va . Vb)
33
Adrian Leonhard

Sie können dies in zwei Schritten tun:

  1. Bestimmen Sie den Winkel zwischen den beiden Vektoren

    theta = acos (Punktprodukt von Va, Vb). Angenommen, Va, Vb sind normalisiert. Dies ergibt den minimalen Winkel zwischen den beiden Vektoren

  2. Bestimmen Sie das Vorzeichen des Winkels

    Findet den Vektor V3 = Kreuzprodukt von Va, Vb. (die Reihenfolge ist wichtig)

    Wenn (Punktprodukt von V3, Vn) negativ ist, ist Theta negativ. Ansonsten ist Theta positiv.

12
Parag

Mit dem dot Produkt können Sie den Winkel zum Vorzeichen aufzeichnen. Um das Vorzeichen des Winkels zu erhalten, nehmen Sie das Zeichen von Vn * (Va x Vb). Im Sonderfall der XY-Ebene reduziert sich dies auf Va_x*Vb_y - Va_y*Vb_x.

7
Stephen Canon

Kreuzen Sie einen Vektor in den anderen und normalisieren Sie den Einheitsvektor.

Der Sinus des Winkels zwischen den beiden Vektoren entspricht der Größe des Kreuzprodukts geteilt durch die Größen der beiden Vektoren:

http://mathworld.wolfram.com/CrossProduct.html

2
duffymo

Sei theta der Winkel zwischen den Vektoren. Sei C = Va das Produkt Vb. Dann 

sin theta = Länge (C)/(Länge (Va) * Länge (Vb))

Um zu bestimmen, ob Theta positiv oder negativ ist, denken Sie daran, dass C senkrecht zu Va und Vb in die durch die Rechtshandregel bestimmte Richtung zeigt. Insbesondere ist C also parallel zu Vn. Wenn C in Ihrem Fall in dieselbe Richtung zeigt wie Vn, dann ist Theta negativ, da Sie eine Linkshänder-Drehung wünschen. Der einfachste Weg, um schnell zu prüfen, ob Vn und C in die gleiche Richtung zeigen, ist wahrscheinlich das Punktprodukt. Wenn es positiv ist, zeigen sie in dieselbe Richtung.

All dies ergibt sich aus den elementaren Eigenschaften des cross-Produkts .

1
David Norman

Der erweiterte Kunde stellte die folgende Lösung bereit (ursprünglich eine Bearbeitung der Frage):

SOLUTION:

sina = |Va x Vb| / ( |Va| * |Vb| )
cosa = (Va . Vb) / ( |Va| * |Vb| )

angle = atan2( sina, cosa )

sign = Vn . ( Va x Vb )
if(sign<0)
{
    angle=-angle
}
1
Peter O.

Angenommen, Vx ist die x-Achse. Wenn Sie das normale Vn verwenden, können Sie die y-Achse durch ein Kreuzprodukt erhalten. Sie können den Vektor Vb nach Vx und Vy projizieren (durch das Punktprodukt können Sie die Projektionslänge von Vb erhalten Vx und Vy) Bei gegebener (x, y) -Koordinate auf der Ebene können Sie mit atan2 (y, x) den Winkel im Bereich [-pi, + pi] berechnen.

1
LittleSweet

Dies ist der Matlab-Code, um den vorzeichenbehafteten Winkel zwischen zwei Vektoren u, v entweder in 2D oder in 3D zu berechnen. Der Code ist selbsterklärend. Die Vorzeichenkonvention ist so, dass ein positiver + 90 ° zwischen ix und iy ([1,0,0], [0,1,0]) oder iy und iz ([0,1,0], [0, 0,1])

function thetaDEG = angDist2Vecs(u,v)

if length(u)==3
    %3D, can use cross to resolve sign
    uMod = sqrt(sum(u.^2));
    vMod = sqrt(sum(v.^2));
    uvPr = sum(u.*v);
    costheta = min(uvPr/uMod/vMod,1);

    thetaDEG = acos(costheta)*180/pi;

    %resolve sign
    cp=(cross(u,v));
    idxM=find(abs(cp)==max(abs(cp)));
    s=sign(cp(idxM(1)));
    if s < 0
        thetaDEG = -thetaDEG;
    end
elseif length(u)==2
    %2D use atan2
    thetaDEG = (atan2(v(2),v(1))-atan2(u(2),u(1)))*180/pi;
else
    error('u,v must be 2D or 3D vectors');
end
0
Massimo