Как вычислить следующую точку отрезка

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 шт):

Автор решения: insolor

"Нормального" способа я не нашел, ниже "геометрический" способ (поделить линию на ее длину, потом умножить на длину + 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)
→ Ссылка
Автор решения: Stanislav Volodarskiy

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.

→ Ссылка