web-dev-qa-db-ja.com

atan2を使用して2つのベクトル間の角度を見つける

という事は承知しています:

atan2(vector.y, vector.x) = ベクトルとX軸の間の角度。

しかし、atan2を使用して2つのベクトルの間の角度を取得する方法を知りたいと思いました。だから私はこの解決策に出くわしました:

_atan2(vector1.y - vector2.y, vector1.x - vector2.x)
_

私の質問は非常に簡単です:

次の2つの式は同じ数を生成しますか?

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

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

そうでない場合:どのベクトルが減算で最初に来るかをどうやって知るのですか?

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

差分ベクトル(vector2とvector1を接続)とx軸の間の角度です。これはおそらく意図したものではありません。

Vector1からvector2への(有向)角度は、次のように計算できます。

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

また、範囲[0、2π)に正規化することもできます。

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

または範囲(-π、π]:

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

これを行う適切な方法は、外積を使用して角度の正弦を見つけ、ドット積を使用して角度の余弦を見つけ、その2つをAtan2()関数と組み合わせることです。

C# これは

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
    }
}

上記のGeoGebraのテストケースを参照してください。

GeoGebra

37
ja72

より良い式がここに投稿されたと思います: http://www.mathworks.com/matlabcentral/answers/16243-angle-between-two-vectors-in-3d

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

したがって、この式は2次元または3次元で機能します。 2次元の場合、この式は上記の式に単純化されます。

15
Klaus

単一のベクトルがあり、X軸からのベクトルの角度を見つけたい場合、atan2()への引数が実際に線の勾配、または(delta Y /デルタX)。したがって、勾配がわかっている場合は、次のことができます。

与えられた:

A =決定するベクトル/ラインの角度(X軸から)。

m =ベクトル/線の符号付き勾配。

その後:

A = atan2(m、1)

非常に便利!

7
sbus

小さな角度の精度に関心がある場合は、これを使用する必要があります。

角度= 2 * atan2(|| || b || a a || b ||、|| || b || a + || a || b ||)

ここで、「||」絶対値、つまり「ベクトルの長さ」を意味します。 ---(https://math.stackexchange.com/questions/1143354/numerically-stable-method-for-angle-between-3d-vectors/1782769 を参照してください

ただし、これには2次元では角度の符号が失われるという欠点があります。

2
D0SBoots

haveを使用してatan2を使用して2つのベクトル間の角度を計算することはできません。最速の方法が必要な場合は、dot(v1, v2)=|v1|*|v2|*cos Aを使用して取得できます

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

ここで、Pythonの小さなプログラムは、ベクトル間の角度を使用して、ポイントが特定のポリゴンの内側か外側かを判断します

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

送信した式angle(vector.b,vector.a)は、結果を与えます

4つの象限で、任意の座標xa,yaおよびxb,yb

座標の場合xa=ya=0およびまたはxb=yb=0未定義です。

角度はpiより大きくても小さくてもよく、正でもかまいません

または負。

0

@ martin-rの答えを補完するものとして、アークタンジェントに和/差の式を使用できることに注意する必要があります。

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
  • 警告1:角度が-pi ... + pi内にあることを確認してください
  • 警告2:ベクトルが非常に類似している場合は注意してください。最初の引数が消滅し、数値が不正確になる可能性があります
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およびxa、yaは、2つのベクトルの座標です

0