Python 坐标旋转随着迭代变小

Python coordinate rotations becoming smaller with iterations

当我的程序通过坐标旋转算法迭代时,我的坐标变得无限小,我遇到了一个问题。我在下面放了一张 gif,以较慢的帧速率展示了这一点;随着它的继续,这条线最终消失了。

https://i.gyazo.com/368fbc65dbc5d3deaa282a4b72ec5d22.mp4

我认为问题在于 sin 和 cos 可能会截断数字,但我不确定

def run(root, canvas, line, x, y, width, height):
    # counter clockwise rotation of cartesian coordinates
    # X =  xcosθ + ysinθ
    # Y = -xsinθ + ycosθ

    theta = 1/8

    x, y = tk_to_cart(width/2, height/2, x, y)

    x =  x * cos(theta) + y * sin(theta)
    y = -x * sin(theta) + y * cos(theta)

    x, y = cart_to_tk(width/2, height/2, x, y)

    canvas.delete(line)
    line = canvas.create_line(width/2, height/2, x, y)

    root.after(20, lambda: run(root, canvas, line, x, y, width, height))

tk_to_cart 和 cart_to_tk 只是 canvas 的简单翻译,因为 tkinter 的坐标系在左上角有 0,0。

可能沿线某处精度下降,特别是如果 tk_to_cart and/or cart_to_tk 舍入或截断为整数。

几个想法:

  • 让数据仅在一个方向上流动(从模型到屏幕),而不是来回流动;而且,如果这没有帮助,
  • 避免重复旋转,而是增加角度并始终从原来的xy旋转。

类似于:

def run(root, canvas, line, x_cart, y_cart, width, height, theta=0):
    # counter clockwise rotation of cartesian coordinates
    # X =  xcosθ + ysinθ
    # Y = -xsinθ + ycosθ

    theta += 1/8

    x_rot =  x_cart * cos(theta) + y_cart * sin(theta)
    y_rot = -x_cart * sin(theta) + y_cart * cos(theta)

    x_tk, y_tl = cart_to_tk(width/2, height/2, x_rot, y_rot)

    canvas.delete(line)
    line = canvas.create_line(width/2, height/2, x_tk, y_tk)

    root.after(20, lambda: run(root, canvas, line, x_cart, y_cart, width, height, theta))

我想提出这个解决方案,使直线绕一个点。

基本三角函数

参考下图

您有某个 length 的片段,从点 x_o, y_o 到点 x_p, y_p。其中 x_o, y_o 是线段的旋转中心和翻译参考系的原点 x', y' 相对于 canva 参考系 x, y.

现在,x_o, y_olength 是输入数据,不会随时间改变(除非您决定改变)。

鉴于 x', y' 中的一些三角函数:

x_p = length * cos(theta)
y_p = length * sin(theta)

由于您的参照系已翻译,上述公式变为:

x_p = length * cos(theta) + x_o
y_p = length * sin(theta) + y_o

如您所见,您正在计算 x_p, y_p,因此此处的长度不会改变。


翻译成代码

让我们将 theta 表示为循环中更新的 math.pi 的倍数。

方法变为:

def draw_line(root, canvas, length, x_o=0, y_o=0, theta=0.1, rotation='cw', line=None):
    if line is not None:
        canvas.delete(line)
    
    x_p = length * math.cos(math.pi * theta) + x_o
    y_p = length * math.sin(math.pi * theta) + y_o

    k = {'ccw': -1, 'cw': 1}[rotation]
    theta = theta + k * 0.05 # or any non linear function to change the motion

    line = canvas.create_line(x_o, y_o, x_p, y_p)
    root.after(100, lambda: draw_line(root, canvas, length, x_o, y_o, theta, rotation, line))

因此,运行 进行测试:

import tkinter
import math

root = tkinter.Tk()
canvas = tkinter.Canvas(root)
canvas.pack()

length = 100
x_o = 100
y_o = 100
draw_line(root, canvas, x_o, y_o, length, rotation='ccw')

使用这种基本的三角方法可以更容易地控制运动。

您可以更改旋转方向 cwccw。您可以使用非线性函数计算 theta,以随时间改变 angular 速度。您可以添加一个速度参数作为参数。您可以随着时间的推移更改 x_o, y_o 以使该行四处移动。等等