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;}
否则,如果(角度正确的方法是使用叉积求角度的正弦,使用点积求角度的余弦,并使用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)
非常有用!我认为这里发布了一个更好的公式:
所以这个公式适用于2维或3维。
对于2维,此公式简化为上述公式。如果您关心小角度的精度,请使用以下公式:
角度=2*atan2(| | | | | | | b | | a-| | a | | | b | | | | | | | b |)
其中“| |”表示绝对值,也称为“向量长度”。请参阅
但是,这样做的缺点是,在二维空间中,它会丢失角度符号。你不必使用atan2来计算两个向量之间的角度。如果你只需要最快的方法,你可以使用点(v1,v2)=| v1 |*| v2 |*cos A
得到
作为对@martin-r答案的补充,我们应该注意,可以使用arcus tangens的和/差公式
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:当心向量变得非常相似时,您可能会在第一个参数中消失,从而导致数值不准确
xb,yb和xa,ya是两个向量的坐标我发送的公式,角度(vector.b,vector.a)
,给出结果
在四个象限中,对于任何坐标xa,ya
和xb,yb
对于坐标xa=ya=0
和或xb=yb=0
是未定义的
角度可以大于或小于pi,并且可以为正
或者是负数。这里有一个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 __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)
导入系统
将numpy作为np导入
将matplotlib.pyplot作为plt导入
将matplotlib.patches导入为修补程序
从shapely.geometry导入点,多边形
从pprint导入pprint
#绘图变量
最小x_,最大x_=-6,12
y_最小值,y_最大值=-3,8
勾选间隔=1
图_尺寸=(10,10)
DELTA_误差=0.00001
盒内颜色='黄色'
外盒颜色=‘黑色’
(v1,v2)之间的def角度_:
“”“返回向量“v1”和“v2”之间的角度(以弧度为单位)
角度的符号取决于v1和v2的顺序
因此acos(norm(dot(v1,v2))不起作用,必须使用atan2,请参见:
https://stackoverflow.com/questions/21483999/using-atan2-to-find-angle-between-two-vectors
"""
arg1=np.交叉(v1,v2)
arg2=np.点(v1,v2)
角度=np.arctan2(arg1,arg2)
返回角
def点_内部(点、边框):
“”“如果点位于边界多边形内,则返回True;否则返回False。”
论据:
:点:x,y在shapely.geometry.point类型中
:边框:[x1 y1,x2 y2,…,xn yn]为shapely.geomettry.Polygon类型
"""
断言len(border.external.coords)>2\
'多边形中的点数必须大于2'
点=np.数组(点)
side1=np.array(border.external.coords[0])-点
和角=0
对于border.exterior.coords[1:]:
side2=np.数组(边界点)-点
角度=之间的角度_(侧1,侧2)
角度总和+=角度
侧1=侧2
#如果wn为1,则该点位于内部
wn=角度总和/2/np.pi
如果abs(wn-1)A = Math.acos( dot(v1, v2)/(v1.length()*v2.length()) );
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)