Как вычислить следующую точку отрезка
tkinter в python при рисовании линии
canvas.create_line(x1,y1,x2,y2)
рисует от x1,y1 (включительно) до x2,y2 (НЕвключительно).
Хочу рисовать линию line(x1,y1,x2,y2) до x2,y2 (включительно). Дорисовывать еще одну точку (другой линией) не вариант - получается два разных объекта. По каком алгоритму вычисляется предыдущая точка? Чтобы пересчитать x2,y2, так чтобы линия включала эту точку.
п.с. так не только tkinter рисует, но еще, например, winapi...
Ответы (2 шт):
"Нормального" способа я не нашел, ниже "геометрический" способ (поделить линию на ее длину, потом умножить на длину + 1):
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(bg="white")
canvas.pack()
def regular_line(x1, y1, x2, y2, **kwargs):
canvas.create_line(x1, y1, x2, y2, **kwargs)
def elongated_line(x1, y1, x2, y2, **kwargs):
Dx = x2 - x1
Dy = y2 - y1
length = (Dx**2 + Dy**2) ** 0.5
Dx = Dx / length * (length + 1)
Dy = Dy / length * (length + 1)
x2 = x1 + Dx
y2 = y1 + Dy
canvas.create_line(x1, y1, x2, y2, **kwargs)
x1, y1, x2, y2 = 10, 10, 300, 200
# Рисуем "удлиненную" красную линию, потом поверх нее неудлиненную
# (в идеале должен остаться виден только один красный пиксель,
# но в итоге красный будет местами просвечиваться по всей длине)
elongated_line(x1, y1, x2, y2, fill="red")
regular_line(x1, y1, x2, y2)
root.mainloop()
Увеличенный x4 результат:
Еще вариант просто через x2 += sgn(Dx), y2 += sgn(Dy):
import math
def sign(x):
# https://stackoverflow.com/a/1986718/4752653
return math.copysign(1, x)
def elongated_line2(x1, y1, x2, y2, **kwargs):
Dx = x2 - x1
Dy = y2 - y1
x2 += sign(Dx)
y2 += sign(Dy)
canvas.create_line(x1, y1, x2, y2, **kwargs)
capstyle=tk.PROJECTING дорисовывает недостающий пиксел:
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(bg="white")
canvas.pack()
x1, y1, x2, y2 = 10, 10, 300, 200
canvas.create_line(x1, y1, x2, y2, fill='red', capstyle=tk.PROJECTING)
canvas.create_line(x1, y1, x2, y2)
root.mainloop()
Дополнение
тесты на Windows показывают, что решение выше не работает. Можно нарисовать отрезок в двух направлениях. На Linux и на Windows работает:
# было так:
# canvas.create_line(x1, y1, x2, y2, fill='red', capstyle=tk.PROJECTING)
# стало так:
canvas.create_line(x1, y1, x2, y2, x1, y1, fill='red')
Спасибо пользователю insolor.

