Вращение координат Python уменьшается с итерациями

#python #tkinter #coordinates #trigonometry #cartesian-coordinates

#python #tkinter #координаты #тригонометрия #декартовы координаты

Вопрос:

У меня возникла проблема с тем, что мои координаты становятся бесконечно малыми по мере того, как моя программа повторяет алгоритм поворота координат. Я поместил ниже 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 — это просто простые переводы по холсту из-за системы координат tkinter, имеющей 0,0 в верхнем левом углу.

Комментарии:

1. Я не уверен, что это решение, но, возможно, ваш сценарий вращения неверен. Проверьте этот веб-сайт: academo.org/demos/rotation-about-point . Кажется, это отличается от вашего.

2. @PythonPikachu8 Эта формула предназначена только для движения против часовой стрелки. Я тоже пробовал это. Проблема сохраняется независимо от того, идет ли она против часовой стрелки или по часовой стрелке.

3. Вы округляете / усекаете координаты до целых чисел в tk_to_cart и / или cart_to_tk ?

4. Вспомните теорему Пифагора, и у вас все получится

5. В любом случае, вероятно, поможет поток данных только в одном направлении (от модели к экрану), а не в обратном направлении…

Ответ №1:

Вероятно, потеря точности где-то по ходу строки, особенно если tk_to_cart и / или cart_to_tk округлять или усекать до целого числа.

Пара идей:

  • поток данных должен быть только в одном направлении (от модели к экрану), а не в обратном направлении; и, если это не поможет,
  • избегайте многократного поворота, вместо этого увеличивайте угол и всегда поворачивайте от исходного x и y .

Что — то вроде:

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

Комментарии:

1. Вращение от исходных x и y решает проблему. Спасибо.

Ответ №2:

Я хотел бы предложить это решение, чтобы заставить линию поворачиваться вокруг точки.

Базовая тригонометрия

Обратитесь к следующей схеме

тригонометрическая диаграмма

У вас есть свой определенный сегмент length , идущий от точки x_o, y_o к точке x_p, y_p . Где x_o, y_o находится центр вращения сегмента и начало координат переведенной системы отсчета x', y' относительно системы canva отсчета, которая есть x, y .

Теперь x_o, y_o и length являются входными данными и не меняются со временем (если вы не решите).

Учитывая, что с некоторой тригонометрией в 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')
 

Используя этот базовый тригонометрический способ, легче управлять движением.

Вы можете изменить сторону вращения cw или ccw . Вы можете вычислить тэту с помощью нелинейной функции, чтобы изменить угловую скорость с течением времени. Вы можете добавить параметр скорости в качестве аргумента. x_o, y_o Со временем вы можете меняться, чтобы заставить линию перемещаться. И т.д.