#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
Со временем вы можете меняться, чтобы заставить линию перемещаться. И т.д.