如何在Python中编写螺旋函数?

4 投票
5 回答
7341 浏览
提问于 2025-04-18 01:37

我想在Python里写一个函数,这个函数需要接收两个参数 (x,y),然后返回一个以度数表示的螺旋方向的角度。

假设螺旋的中心在位置 (x0,y0)。那么如果输入 (0,0),它会返回 45。如果输入的是另一个点,比如 (0,90),这个点在y轴上是从顶部数来的第二个交点,返回的角度大约是 170。对于任何不在红线上面的点,它应该返回一个你预期的方向角度。这个螺旋只是用来表示角度的方向。

有没有人知道怎么写这样一个函数呢?

谢谢

在这里输入图片描述 在这里输入图片描述

5 个回答

-1

在编程中,有时候我们会遇到一些问题,特别是在使用某些工具或库的时候。这些问题可能会让我们感到困惑,尤其是当我们刚开始学习编程的时候。比如,有人可能会在使用某个特定的功能时,发现它并没有按照预期工作。这种情况很常见,很多人都会经历。

解决这些问题的第一步是理解错误信息。错误信息就像是程序在告诉你:“嘿,我遇到麻烦了!”它们通常会给出一些线索,帮助你找到问题所在。即使这些信息看起来有点复杂,但只要仔细阅读,通常能找到解决方案。

另外,查阅相关的文档和社区论坛也是个不错的主意。在这些地方,你可以找到其他人遇到类似问题时的解决办法,或者直接向他们提问。记住,编程是一个不断学习的过程,遇到问题是很正常的,关键是要保持耐心,慢慢解决。

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()
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))

为了找到一个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))

1

你想要一个向量场,其中一条轨迹是阿基米德螺旋线。

如果你使用这个螺旋线的公式:

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)来获得。

1

(我觉得这个螺旋图像比帮助更让人困惑...)

对于一个点 (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
2

这是一种阿基米德螺旋曲线。页面上说,这个曲线在极坐标下的公式是 r = aθ,通常这个数字 a1,也就是 r = θ。极坐标转成直角坐标的公式是

x = r cos θ, y = r sin θ

所以

x = θ cos θ, y = θ sin θ

把 θ 从 0 变到 6π,就能得到你想要的曲线。当你改变 θ 的值并计算出 x 和 y 的值时,这些值是相对于原点 (0, 0) 的。对于你的情况,你需要进行平移,也就是把这些点按照 x 和 y 的偏移量移动到合适的位置。如果你想要同样曲线的更大版本,你需要先进行缩放,也就是把 x 和 y 的值都乘以一个常数。

撰写回答