如何在Python中编写螺旋函数?
我想在Python里写一个函数,这个函数需要接收两个参数 (x,y)
,然后返回一个以度数表示的螺旋方向的角度。
假设螺旋的中心在位置 (x0,y0)
。那么如果输入 (0,0)
,它会返回 45
。如果输入的是另一个点,比如 (0,90)
,这个点在y轴上是从顶部数来的第二个交点,返回的角度大约是 170
。对于任何不在红线上面的点,它应该返回一个你预期的方向角度。这个螺旋只是用来表示角度的方向。
有没有人知道怎么写这样一个函数呢?
谢谢
5 个回答
在编程中,有时候我们会遇到一些问题,特别是在使用某些工具或库的时候。这些问题可能会让我们感到困惑,尤其是当我们刚开始学习编程的时候。比如,有人可能会在使用某个特定的功能时,发现它并没有按照预期工作。这种情况很常见,很多人都会经历。
解决这些问题的第一步是理解错误信息。错误信息就像是程序在告诉你:“嘿,我遇到麻烦了!”它们通常会给出一些线索,帮助你找到问题所在。即使这些信息看起来有点复杂,但只要仔细阅读,通常能找到解决方案。
另外,查阅相关的文档和社区论坛也是个不错的主意。在这些地方,你可以找到其他人遇到类似问题时的解决办法,或者直接向他们提问。记住,编程是一个不断学习的过程,遇到问题是很正常的,关键是要保持耐心,慢慢解决。
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()
如果有人能确认一下这个内容,我会很感激。
这个解决方案让你可以设置一个半径,它的增长速度和角度的增长速度不一样。
半径:
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))
为了找到一个t的值,使得它离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))
你想要一个向量场,其中一条轨迹是阿基米德螺旋线。
如果你使用这个螺旋线的公式:
x = θ cos θ, y = θ sin θ
这是来自legends2k的回答。然后计算它的切线,你会得到:
vx = cos θ - θ sin θ, vy = sin θ + θ cos θ
用最简单的方法消去θ,得到的就是一般的向量场:
vx = x/r - y, vy = y/r + x,其中r=sqrt(x^2+y^2)。
然后,向量场的角度可以通过atan2(vy, vx)来获得。
(我觉得这个螺旋图像比帮助更让人困惑...)
对于一个点 (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... 到 +180 度);而我们想要的范围是 (0.. 359.9...) 度:
theta = (degrees(atan2(y, x)) + 360.0) % 360.0
这是一种阿基米德螺旋曲线。页面上说,这个曲线在极坐标下的公式是 r = aθ,通常这个数字 a
是 1,也就是 r = θ。极坐标转成直角坐标的公式是
x = r cos θ, y = r sin θ
所以
x = θ cos θ, y = θ sin θ
把 θ 从 0 变到 6π,就能得到你想要的曲线。当你改变 θ 的值并计算出 x 和 y 的值时,这些值是相对于原点 (0, 0) 的。对于你的情况,你需要进行平移,也就是把这些点按照 x 和 y 的偏移量移动到合适的位置。如果你想要同样曲线的更大版本,你需要先进行缩放,也就是把 x 和 y 的值都乘以一个常数。