我正在尝试编写一个Python函数,它接受两个参数(x,y),并以螺旋方向返回角度。假设螺旋中心位于位置(x0,y0)。然后给定(0,0),它返回45度。对于其他一些点,如从y轴顶部开始的第二个交点(0,90),角度约为170度。对于不接触红线的任何点,它都应该返回您期望的方向角度。螺旋只是一个通用的东西,用来显示角度方向。是否有人知道如何编写这样的函数?谢谢。
x = r cos θ, y = r sin θ
x = θ cos θ, y = θ sin θ
(我认为螺旋图像比有用更加令人困惑...)
对于一个点 (x, y),您希望返回角度 theta(以度为单位),其中 (1,0) 位于 0 度,(0, 1) 位于 90 度。
因此,我们想要找到 theta。使用三角学,我们知道 x 是邻边,y 是对边,且 tan(theta) == y/x
。
这略微受到 tan() 每 180 度重复的影响 - tan(y/x) == tan(-y/-x)
。幸运的是,Python 有一个内置函数 atan2
来补偿这一点。它以弧度返回 theta,然后我们将其转换为度数,如下所示:
from math import atan2, degrees
x, y = (2, 2)
theta = degrees(atan2(y, x)) # => theta == 45.0
然而,atan2返回的值在-2*pi < theta <= 2*pi (-179.9... to +180 degrees)之间;你希望它以(0.. 359.9...)度为单位:
theta = (degrees(atan2(y, x)) + 360.0) % 360.0
如果有人能够验证这个,我会很感激。
这个解决方案允许你拥有一个半径,它的增长速度与角度不同。
半径:
r(t) = r_scalar * t
d(r(t))/dt = r_scaler
度数:
a(t) = a0 + a_scalar * t
d(a(t))/dt = a_scaler
位置:
x(t),y(t) = x0 + r(t)*cos(a(t)), y0 + r(t)*sin(a(t))
现在我们可以计算任何t的方向:
d(x(t))/dt = r(t)*(-sin(a(t))*d(a(t))/dt) + d(r(t))/dt*cos(a(t))
d(y(t))/dt = r(t)*(cos(a(t))*d(a(t))/dt) + d(r(t))/dt*cos(a(t))
这简化了:
d(x(t))/dt = r(t)*(-sin(a(t))*a_scaler) + r_scaler*cos(a(t))
d(y(t))/dt = r(t)*(cos(a(t))*a_scaler) + r_scaler*sin(a(t))
为了得到a、b的值,使得它们最接近x(t)和y(t),你可以先近似地认为距离x0,y0到x1,y1会满足r(t)。
t0 = sqrt((x0 - x2)^2 + (y0 - y1)^2)/r_scalar
由于螺旋线上最接近的点将在相同的角度处,因此微调t以满足角度要求。
t1 = t0-t2 where atan((y0 - y1)/(x0 - x2)) = (a0 + a_scalar * t0) % 2*pi - (a0 + a_scalar * t2)
因此
t2 = (((a0 + a_scalar * t0) % 2*pi) - atan((y0 - y1)/(x0 - x2)) + a0)/a_scalar
然后,最接近的方向角是atan((d(x(t0-t2))/dt / d(y(t0-t2))/dt))
import numpy as np
import matplotlib.pyplot as plt
import math
def fermat_spiral(dot):
data=[]
d=dot*0.1
for i in range(dot):
t = i / d * np.pi
x = (1 + t) * math.cos(t)
y = (1 + t) * math.sin(t)
data.append([x,y])
narr = np.array(data)
f_s = np.concatenate((narr,-narr))
return f_s
f_spiral = fermat_spiral(20000)
plt.scatter(f_spiral[len(f_spiral)//2:,0],f_spiral[len(f_spiral)//2:,1])
plt.scatter(f_spiral[:len(f_spiral)//2,0],f_spiral[:len(f_spiral)//2,1])
plt.show()