という事は承知しています:
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)
そうでない場合:どのベクトルが減算で最初に来るかをどうやって知るのですか?
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; }
これを行う適切な方法は、外積を使用して角度の正弦を見つけ、ドット積を使用して角度の余弦を見つけ、その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のテストケースを参照してください。
より良い式がここに投稿されたと思います: 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次元の場合、この式は上記の式に単純化されます。
単一のベクトルがあり、X軸からのベクトルの角度を見つけたい場合、atan2()への引数が実際に線の勾配、または(delta Y /デルタX)。したがって、勾配がわかっている場合は、次のことができます。
与えられた:
A =決定するベクトル/ラインの角度(X軸から)。
m =ベクトル/線の符号付き勾配。
その後:
A = atan2(m、1)
非常に便利!
小さな角度の精度に関心がある場合は、これを使用する必要があります。
角度= 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次元では角度の符号が失われるという欠点があります。
haveを使用してatan2を使用して2つのベクトル間の角度を計算することはできません。最速の方法が必要な場合は、dot(v1, v2)=|v1|*|v2|*cos A
を使用して取得できます
A = Math.acos( dot(v1, v2)/(v1.length()*v2.length()) );
ここで、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)
送信した式angle(vector.b,vector.a)
は、結果を与えます
4つの象限で、任意の座標xa,ya
およびxb,yb
。
座標の場合xa=ya=0
およびまたはxb=yb=0
は未定義です。
角度はpi
より大きくても小さくてもよく、正でもかまいません
または負。
@ 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
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つのベクトルの座標です