wake-up-neo.com

Verwenden Sie atan2, um den Winkel zwischen zwei Vektoren zu ermitteln

Ich verstehe das:

atan2(vector.y, vector.x) = der Winkel zwischen dem Vektor und der X-Achse .

Aber ich wollte wissen, wie man mit atan2 den Winkel zwischen zwei Vektoren ermittelt. Also bin ich auf diese Lösung gestoßen:

atan2(vector1.y - vector2.y, vector1.x - vector2.x)

Meine Frage ist sehr einfach:

Werden die beiden folgenden Formeln dieselbe Zahl ergeben?

  • atan2(vector1.y - vector2.y, vector1.x - vector2.x)

  • atan2(vector2.y - vector1.y, vector2.x - vector1.x)

Wenn nicht: Woher weiß ich, welcher Vektor bei den Subtraktionen an erster Stelle steht?

Vielen Dank

31
user3150201
 atan2(vector1.y - vector2.y, vector1.x - vector2.x)

ist der Winkel zwischen dem Differenzvektor (Verbindungsvektor2 und Vektor1) und der x-Achse, Dies ist wahrscheinlich nicht das, was Sie meinten.

Der (gerichtete) Winkel von Vektor1 zu Vektor2 kann als berechnet werden

angle = atan2(vector2.y, vector2.x) - atan2(vector1.y, vector1.x);

und Sie können es auf den Bereich [0, 2 π) normieren:

if (angle < 0) { angle += 2 * M_PI; }

oder zum Bereich (-π, π]:

if (angle > M_PI)        { angle -= 2 * M_PI; }
else if (angle <= -M_PI) { angle += 2 * M_PI; }
79
Martin R

Der richtige Weg, dies zu tun, besteht darin, den Sinus des Winkels mithilfe des Kreuzprodukts und den Cosinus des Winkels mit dem Punktprodukt zu ermitteln und die beiden mit der Funktion Atan2() zu kombinieren.

In C# ist dies 

public struct Vector2
{
    public double X, Y;

    /// <summary>
    /// Returns the angle between two vectos
    /// </summary>
    public static double GetAngle(Vector2 A, Vector2 B)
    {
        // |A·B| = |A| |B| COS(θ)
        // |A×B| = |A| |B| SIN(θ)

        return Math.Atan2(Cross(A,B), Dot(A,B));
    }

    public double Magnitude { get { return Math.Sqrt(Dot(this,this)); } }

    public static double Dot(Vector2 A, Vector2 B)
    {
        return A.X*B.X+A.Y*B.Y;
    }
    public static double Cross(Vector2 A, Vector2 B)
    {
        return A.X*B.Y-A.Y*B.X;
    }
}
class Program
{
    static void Main(string[] args)
    {
        Vector2 A=new Vector2() { X=5.45, Y=1.12};
        Vector2 B=new Vector2() { X=-3.86, Y=4.32 };

        double angle=Vector2.GetAngle(A, B) * 180/Math.PI;
        // angle = 120.16850967865749
    }
}

Siehe Testfall oben in GeoGebra.

GeoGebra

33
ja72

Ich denke, eine bessere Formel wurde hier veröffentlicht: http://www.mathworks.com/matlabcentral/answers/16243-angle-between-two-vectors-in-3d

angle = atan2(norm(cross(a,b)), dot(a,b))

Diese Formel funktioniert also in 2 oder 3 Dimensionen ..__ Für 2 Dimensionen vereinfacht diese Formel die oben angegebene.

10
Klaus

Niemand hat darauf hingewiesen, dass, wenn Sie einen einzelnen Vektor haben und den Winkel des Vektors von der X-Achse aus ermitteln möchten, Sie die Tatsache ausnutzen können, dass das Argument von atan2 () tatsächlich die Steigung der Linie oder (Delta) ist Y/Delta X). Wenn Sie also die Steigung kennen, können Sie Folgendes tun:

gegeben:

A = Winkel des Vektors/der Linie, die Sie bestimmen möchten (von der X-Achse).

m = vorzeichenbehaftete Steigung des Vektors/der Linie.

dann:

A = atan2 (m, 1)

Sehr hilfreich!

6
sbus

Wenn Sie Wert auf Genauigkeit bei kleinen Winkeln legen, möchten Sie Folgendes verwenden:

winkel = 2 * atan2 (|| || b || a - || a || b ||, || || b || a + || a || b ||)

Wo "||" bedeutet absoluter Wert, AKA "Länge des Vektors". Siehe https://math.stackexchange.com/questions/1143354/numerically-stable-method-for-angle- zwischen-3d-vectors/1782769

Dies hat jedoch den Nachteil, dass es in zwei Dimensionen das Vorzeichen des Winkels verliert.

2
D0SBoots

Sie haben nicht , um mit atan2 den Winkel zwischen zwei Vektoren zu berechnen. Wenn Sie nur den schnellsten Weg wollen, können Sie dot(v1, v2)=|v1|*|v2|*cos A verwenden

A = Math.acos( dot(v1, v2)/(v1.length()*v2.length()) );
1
user3502079

Hier ein kleines Programm in Python, das den Winkel zwischen Vektoren verwendet, um festzustellen, ob ein Punkt innerhalb oder außerhalb eines bestimmten Polygons liegt

import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from shapely.geometry import Point, Polygon
from pprint import pprint

# Plot variables
x_min, x_max = -6, 12
y_min, y_max = -3, 8
tick_interval = 1
FIG_SIZE = (10, 10)
DELTA_ERROR = 0.00001
IN_BOX_COLOR = 'yellow'
OUT_BOX_COLOR = 'black'


def angle_between(v1, v2):
    """ Returns the angle in radians between vectors 'v1' and 'v2'
        The sign of the angle is dependent on the order of v1 and v2
        so acos(norm(dot(v1, v2))) does not work and atan2 has to be used, see:
        https://stackoverflow.com/questions/21483999/using-atan2-to-find-angle-between-two-vectors
    """
    arg1 = np.cross(v1, v2)
    arg2 = np.dot(v1, v2)
    angle = np.arctan2(arg1, arg2)
    return angle


def point_inside(point, border):
    """ Returns True if point is inside border polygon and False if not
        Arguments:
        :point: x, y in shapely.geometry.Point type
        :border: [x1 y1, x2 y2, ... , xn yn] in shapely.geomettry.Polygon type
    """    
    assert len(border.exterior.coords) > 2,\
        'number of points in the polygon must be > 2'

    point = np.array(point)
    side1 = np.array(border.exterior.coords[0]) - point
    sum_angles = 0
    for border_point in border.exterior.coords[1:]:
        side2 = np.array(border_point) - point
        angle = angle_between(side1, side2)
        sum_angles += angle
        side1 = side2

    # if wn is 1 then the point is inside
    wn = sum_angles / 2 / np.pi
    if abs(wn - 1) < DELTA_ERROR:
        return True
    else:
        return False


class MainMap():

    @classmethod
    def settings(cls, fig_size):
        # set the plot outline, including axes going through the Origin
        cls.fig, cls.ax = plt.subplots(figsize=fig_size)
        cls.ax.set_xlim(-x_min, x_max)
        cls.ax.set_ylim(-y_min, y_max)
        cls.ax.set_aspect(1)
        tick_range_x = np.arange(round(x_min + (10*(x_max - x_min) % tick_interval)/10, 1),
            x_max + 0.1, step=tick_interval)
        tick_range_y = np.arange(round(y_min + (10*(y_max - y_min) % tick_interval)/10, 1), 
            y_max + 0.1, step=tick_interval)
        cls.ax.set_xticks(tick_range_x)
        cls.ax.set_yticks(tick_range_y)
        cls.ax.tick_params(axis='both', which='major', labelsize=6)
        cls.ax.spines['left'].set_position('zero')
        cls.ax.spines['right'].set_color('none')
        cls.ax.spines['bottom'].set_position('zero')
        cls.ax.spines['top'].set_color('none')

    @classmethod
    def get_ax(cls):
        return cls.ax

    @staticmethod
    def plot():
        plt.tight_layout()
        plt.show()


class PlotPointandRectangle(MainMap):

    def __init__(self, start_point, rectangle_polygon, tolerance=0):

        self.current_object = None
        self.currently_dragging = False
        self.fig.canvas.mpl_connect('key_press_event', self.on_key)
        self.plot_types = ['o', 'o-']
        self.plot_type = 1
        self.rectangle = rectangle_polygon

        # define a point that can be moved around
        self.point = patches.Circle((start_point.x, start_point.y), 0.10,
            alpha=1)
        if point_inside(start_point, self.rectangle):
            _color = IN_BOX_COLOR
        else:
            _color = OUT_BOX_COLOR
        self.point.set_color(_color)
        self.ax.add_patch(self.point)
        self.point.set_picker(tolerance)
        cv_point = self.point.figure.canvas
        cv_point.mpl_connect('button_release_event', self.on_release)
        cv_point.mpl_connect('pick_event', self.on_pick)
        cv_point.mpl_connect('motion_notify_event', self.on_motion)

        self.plot_rectangle()

    def plot_rectangle(self):
        x = [point[0] for point in self.rectangle.exterior.coords]
        y = [point[1] for point in self.rectangle.exterior.coords]
        # y = self.rectangle.y
        self.rectangle_plot, = self.ax.plot(x, y,
            self.plot_types[self.plot_type], color='r', lw=0.4, markersize=2)

    def on_release(self, event):
        self.current_object = None
        self.currently_dragging = False

    def on_pick(self, event):
        self.currently_dragging = True
        self.current_object = event.artist

    def on_motion(self, event):
        if not self.currently_dragging:
            return
        if self.current_object == None:
            return

        point = Point(event.xdata, event.ydata)
        self.current_object.center = point.x, point.y
        if point_inside(point, self.rectangle):
            _color = IN_BOX_COLOR
        else:
            _color = OUT_BOX_COLOR
        self.current_object.set_color(_color)

        self.point.figure.canvas.draw()

    def remove_rectangle_from_plot(self):
        try:
            self.rectangle_plot.remove()
        except ValueError:
            pass

    def on_key(self, event):
        # with 'space' toggle between just points or points connected with
        # lines
        if event.key == ' ':
            self.plot_type = (self.plot_type + 1) % 2
            self.remove_rectangle_from_plot()
            self.plot_rectangle()
            self.point.figure.canvas.draw()


def main(start_point, rectangle):

    MainMap.settings(FIG_SIZE)
    plt_me = PlotPointandRectangle(start_point, rectangle)  #pylint: disable=unused-variable
    MainMap.plot()

if __== "__main__":
    try:
        start_point = Point([float(val) for val in sys.argv[1].split()])
    except IndexError:
        start_point= Point(0, 0)

    border_points = [(-2, -2),
                     (1, 1),
                     (3, -1),
                     (3, 3.5),
                     (4, 1),
                     (5, 1),
                     (4, 3.5),
                     (5, 6),
                     (3, 4),
                     (3, 5),
                     (-0.5, 1),
                     (-3, 1),
                     (-1, -0.5),
                    ]               

    border_points_polygon = Polygon(border_points)
    main(start_point, border_points_polygon)
0
Bruno Vermeulen

Die von mir gesendete Formel angle(vector.b,vector.a) gibt Ergebnisse 

in den vier Quadranten und für beliebige Koordinaten xa,ya und xb,yb.

Für Koordinaten xa=ya=0 und oder xb=yb=0 ist undefined .

Der Winkel kann größer oder kleiner als pi sein und kann positiv sein

oder negativ.

0

Als Ergänzung zur Antwort von @ martin-r sollte beachtet werden, dass die Summen/Differenz-Formel für Arcus-Tangens verwendet werden kann.

angle = atan2(vec2.y, vec2.x) - atan2(vec1.y, vec1.x);
angle = -atan2(vec1.x * vec2.y - vec1.y * vec2.x, dot(vec1, vec2))
        where dot = vec1.x * vec2.x  + vec1.y * vec2.y
  • Vorbehalt 1 : Stellen Sie sicher, dass der Winkel innerhalb von -pi ... + pi bleibt
  • Caveat 2 : Achtung, wenn sich die Vektoren sehr ähnlich werden, kann es sein, dass Sie im ersten Argument aussterben und numerische Ungenauigkeiten verursachen
0
Ichthyo
angle(vector.b,vector.a)=pi/2*((1+sgn(xa))*(1-sgn(ya^2))-(1+sgn(xb))*(1-sgn(yb^2)))

+pi/4*((2+sgn(xa))*sgn(ya)-(2+sgn(xb))*sgn(yb))

+sgn(xa*ya)*atan((abs(xa)-abs(ya))/(abs(xa)+abs(ya)))

-sgn(xb*yb)*atan((abs(xb)-abs(yb))/(abs(xb)+abs(yb)))

xb, yb und xa, ya sind die Koordinaten der beiden Vektoren

0