Не получается нарисовать куб

Я использую tkinter только чтобы отрисовать куб, в этом проблем нету. Поэтому tkinter к вопросу вообще не относится. Программа косячит в вычислениях... Вот:

from math import atan;

def XYZtoXY(x, y, z, camera_x, camera_y, camera_z, fov, width, height):
    pitch = atan((x - camera_x) // (y - camera_y));
    yaw   = atan((z - camera_z) // (y - camera_y));
    x = round(width // 2 + (pitch * (width // fov)));
    y = round(height // 2 + (yaw * (height // fov)));
    return (x, y);
 
__position__ = (0, 0, 0);
__fov__ = 1;
 
def camera(x=0, y=0, z=0, fov=180):
    global __position__, __fov__;
    __position__ = (x, y, z);
    __fov__ = fov;
def cube(canvas, x, y, z, width, height, length):
    coords = [];
    coords.append((x - width // 2, y + height // 2, z - length // 2));
    coords.append((x + width // 2, y + height // 2, z - length // 2));
    coords.append((x - width // 2, y - height // 2, z - length // 2));
    coords.append((z + width // 2, y - height // 2, z - length // 2));
    coords2D = map(lambda xyz: XYZtoXY(*xyz, *__position__, __fov__, canvas.winfo_width(), canvas.winfo_height()), coords);
    canvas.create_polygon(*coords2D);
 
import tkinter as tk;
 
root = tk.Tk();
canv = tk.Canvas(bg='white');
canv.pack(expand=True, fill=tk.BOTH);
camera(1, 1, 1, 1);
cube(canv, 50, 50, 50, 100, 100, 100);
root.mainloop();

Ответы (1 шт):

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

У вас функция cube вызывается до фактического создания окна, поэтому canvas возвращает размеры 1 x 1 пиксель. Можно добавить задержку:

root.after(50, lambda: cube(canv, 50, 50, 50, 100, 100, 100))

Или добавить вызов root.update() до вызова функции cube.

Если что-то "косячит", нужно проверять входные-выходные данные функций, например с помощью отладочного вывода. Пример:

def XYZtoXY(x, y, z, camera_x, camera_y, camera_z, fov, width, height):
    print(x, y, z, camera_x, camera_y, camera_z, fov, width, height)
    ...
    return (x, y);
 
__position__ = (0, 0, 0);
__fov__ = 1;
 
def camera(x=0, y=0, z=0, fov=180):
    global __position__, __fov__;
    __position__ = (x, y, z);
    __fov__ = fov;
def cube(canvas, x, y, z, width, height, length):
    print(x, y, z, width, height, length)
    coords = [];
    ...
    print(coords)
    coords2D = ...;
    coords2D = list(coords2D)
    print(coords2D)
    canvas.create_polygon(*coords2D);

При запуске программа дает такой вывод:

50 50 50 100 100 100
[(0, 100, 0), (100, 100, 0), (0, 0, 0), (100, 0, 0)]
0 100 0 1 1 1 1 1 1
100 100 0 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1
100 0 0 1 1 1 1 1 1
[(-1, -1), (1, -1), (1, 1), (-2, 1)]

Тут видно, что в XYZtoXY размеры холста приходят 1 x 1 пиксель (последние две единицы в строках типа 0 100 0 1 1 1 1 1 1). Если добавить задержку, размеры приходят уже более реалистичные:

50 50 50 100 100 100
[(0, 100, 0), (100, 100, 0), (0, 0, 0), (100, 0, 0)]
0 100 0 1 1 1 1 380 267
100 100 0 1 1 1 1 380 267
0 0 0 1 1 1 1 380 267
100 0 0 1 1 1 1 380 267
[(-108, -77), (488, -77), (488, 343), (-403, 343)]
→ Ссылка