Math 使用atan2查找两个向量之间的角度

Math 使用atan2查找两个向量之间的角度,math,vector,geometry,Math,Vector,Geometry,我明白: atan2(vector.y,vector.x)=矢量与x轴之间的角度 但我想知道如何使用atan2获得两个向量之间的角度。所以我找到了这个解决方案: atan2(vector1.y - vector2.y, vector1.x - vector2.x) 我的问题很简单: 以下两个公式会产生相同的数字吗 atan2(vector1.y-vector2.y,vector1.x-vector2.x) atan2(vector2.y-vector1.y,vector2.x-vector1

我明白:

atan2(vector.y,vector.x)
=矢量与x轴之间的角度

但我想知道如何使用atan2获得两个向量之间的角度。所以我找到了这个解决方案:

atan2(vector1.y - vector2.y, vector1.x - vector2.x)
我的问题很简单:

以下两个公式会产生相同的数字吗

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

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

如果没有:如何知道减法中哪个向量排在第一位?

 atan2(vector1.y - vector2.y, vector1.x - vector2.x)
是差分向量(连接向量2和向量1)与x轴之间的角度, 这可能不是你的意思

从矢量1到矢量2的(定向)角度可计算为

angle = atan2(vector2.y, vector2.x) - atan2(vector1.y, vector1.x);
您可能希望将其规格化为范围[0,2π):

if(角度<0){angle+=2*M_-PI;}
或到范围(-π,π]:

if (angle > M_PI)        { angle -= 2 * M_PI; }
else if (angle <= -M_PI) { angle += 2 * M_PI; }
if(angle>M_-PI){angle-=2*M_-PI;}
否则,如果(角度
是差分向量(连接向量2和向量1)与x轴之间的角度,
这可能不是你的意思

从矢量1到矢量2的(定向)角度可计算为

angle = atan2(vector2.y, vector2.x) - atan2(vector1.y, vector1.x);
您可能希望将其规格化为范围[0,2π):

if(角度<0){angle+=2*M_-PI;}
或到范围(-π,π]:

if (angle > M_PI)        { angle -= 2 * M_PI; }
else if (angle <= -M_PI) { angle += 2 * M_PI; }
if(angle>M_-PI){angle-=2*M_-PI;}

否则,如果(角度正确的方法是使用叉积求角度的正弦,使用点积求角度的余弦,并使用
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
    }
}
公共结构向量2
{
公共双X,Y;
/// 
///返回两个向量之间的角度
/// 
公共静态双GetAngle(矢量2A,矢量2B)
{
//|A·B |=|A | B | COS(θ)
//|A×B |=|A | B | SIN(θ)
返回Math.Atan2(交叉(A,B),点(A,B));
}
公共双量级{get{return Math.Sqrt(Dot(this,this));}
公共静态双点(矢量2A,矢量2B)
{
返回A.X*B.X+A.Y*B.Y;
}
公共静态双交叉(矢量2 A、矢量2 B)
{
返回A.X*B.Y-A.Y*B.X;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
Vector2A=新Vector2(){X=5.45,Y=1.12};
vector2b=newvector2(){X=-3.86,Y=4.32};
双角度=矢量2.GetAngle(A,B)*180/Math.PI;
//角度=120.16850967865749
}
}
参见GeoGebra中的上述测试用例


正确的方法是使用叉积求角度的正弦,使用点积求角度的余弦,并使用
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
    }
}
公共结构向量2
{
公共双X,Y;
/// 
///返回两个向量之间的角度
/// 
公共静态双GetAngle(矢量2A,矢量2B)
{
//|A·B |=|A | B | COS(θ)
//|A×B |=|A | B | SIN(θ)
返回Math.Atan2(交叉(A,B),点(A,B));
}
公共双量级{get{return Math.Sqrt(Dot(this,this));}
公共静态双点(矢量2A,矢量2B)
{
返回A.X*B.X+A.Y*B.Y;
}
公共静态双交叉(矢量2 A、矢量2 B)
{
返回A.X*B.Y-A.Y*B.X;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
Vector2A=新Vector2(){X=5.45,Y=1.12};
vector2b=newvector2(){X=-3.86,Y=4.32};
双角度=矢量2.GetAngle(A,B)*180/Math.PI;
//角度=120.16850967865749
}
}
参见GeoGebra中的上述测试用例


没有人指出,如果你有一个向量,并且想要找到向量相对于X轴的角度,你可以利用atan2()的参数实际上是直线的斜率,或者(δY/δX)。因此,如果你知道斜率,你可以做以下事情:

鉴于:

A=要确定的矢量/线的角度(从X轴)

m=向量/直线的有符号斜率

然后:

A=atan2(m,1)


非常有用!

没有人指出,如果你有一个向量,并且想要找到向量与X轴的角度,你可以利用atan2()的参数实际上是直线的斜率,或者(δY/δX)。因此,如果你知道斜率,你可以做以下操作:

鉴于:

A=要确定的矢量/线的角度(从X轴)

m=向量/直线的有符号斜率

然后:

A=atan2(m,1)


非常有用!

我认为这里发布了一个更好的公式:

所以这个公式适用于2维或3维。
对于二维,此公式简化为上述公式。

我认为此处发布了一个更好的公式:

所以这个公式适用于2维或3维。
对于2维,此公式简化为上述公式。

如果您关心小角度的精度,请使用以下公式:

角度=2*atan2(| | | | | | | b | | a-| | a | | | b | | | | | | | b |)

其中“| |”表示绝对值,也称为“向量长度”。请参阅


但是,这样做的缺点是,在二维空间中,它会丢失角度的符号。

如果您关心小角度的精度,请使用以下方法:

角度=2*atan2(| | | | | | | b | | a-| | a | | | b | | | | | | | b |)

其中“| |”表示绝对值,也称为“向量长度”。请参阅

但是,这样做的缺点是,在二维空间中,它会丢失角度符号。

你不必使用atan2来计算两个向量之间的角度。如果你只需要最快的方法,你可以使用
点(v1,v2)=| v1 |*| v2 |*cos A
得到

你不必使用atan2来计算两个向量之间的角度。如果你只是想用最快的方法,你可以
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
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)))
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 __name__ == "__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)