114 lines
3.1 KiB
Python
114 lines
3.1 KiB
Python
import tkinter as tk
|
|
import math
|
|
|
|
# Torus parameters
|
|
theta_spacing = 0.07
|
|
phi_spacing = 0.02
|
|
R1 = 1
|
|
R2 = 2
|
|
K2 = 5
|
|
|
|
chars = ".,-~:;=!*#$@" # luminance chars
|
|
|
|
# Base character grid (like "screen resolution")
|
|
screen_width = 80
|
|
screen_height = 24
|
|
|
|
# Tkinter setup
|
|
root = tk.Tk()
|
|
root.title("Spinning Torus Demo")
|
|
|
|
# Get window size and calculate scaling
|
|
window_width = 800
|
|
window_height = 400
|
|
root.geometry(f"{window_width}x{window_height}")
|
|
|
|
# Calculate character cell size to fit screen dimensions
|
|
cell_width = window_width // screen_width
|
|
cell_height = window_height // screen_height
|
|
font_size = min(cell_width, cell_height)
|
|
font = ("Courier", font_size)
|
|
|
|
canvas = tk.Canvas(root, width=window_width, height=window_height, bg="black")
|
|
canvas.pack()
|
|
|
|
# Pre-create text items for the character grid
|
|
text_items = []
|
|
for y in range(screen_height):
|
|
row = []
|
|
for x in range(screen_width):
|
|
item = canvas.create_text(
|
|
x*cell_width, y*cell_height,
|
|
text=' ',
|
|
anchor='nw',
|
|
fill='white',
|
|
font=font
|
|
)
|
|
row.append(item)
|
|
text_items.append(row)
|
|
|
|
# Calculate K1 based on screen width
|
|
K1 = screen_width * K2 * 3 / (8 * (R1 + R2))
|
|
|
|
def render_frame(A, B):
|
|
cosA = math.cos(A)
|
|
sinA = math.sin(A)
|
|
cosB = math.cos(B)
|
|
sinB = math.sin(B)
|
|
|
|
output = [[' ' for _ in range(screen_height)] for _ in range(screen_width)]
|
|
zbuffer = [[0 for _ in range(screen_height)] for _ in range(screen_width)]
|
|
|
|
theta = 0
|
|
while theta < 2 * math.pi:
|
|
costheta = math.cos(theta)
|
|
sintheta = math.sin(theta)
|
|
|
|
phi = 0
|
|
while phi < 2 * math.pi:
|
|
cosphi = math.cos(phi)
|
|
sinphi = math.sin(phi)
|
|
|
|
circlex = R2 + R1 * costheta
|
|
circley = R1 * sintheta
|
|
|
|
x = circlex * (cosB * cosphi + sinA * sinB * sinphi) - circley * cosA * sinB
|
|
y = circlex * (sinB * cosphi - sinA * cosB * sinphi) + circley * cosA * cosB
|
|
z = K2 + cosA * circlex * sinphi + circley * sinA
|
|
ooz = 1 / z
|
|
|
|
xp = int(screen_width / 2 + K1 * ooz * x)
|
|
yp = int(screen_height / 2 - K1 * ooz * y)
|
|
|
|
L = cosphi * costheta * sinB - cosA * costheta * sinphi - sinA * sintheta + cosB * (cosA * sintheta - costheta * sinA * sinphi)
|
|
|
|
if L > 0:
|
|
if 0 <= xp < screen_width and 0 <= yp < screen_height:
|
|
if ooz > zbuffer[xp][yp]:
|
|
zbuffer[xp][yp] = ooz
|
|
luminance_index = int(L * 8)
|
|
if luminance_index >= len(chars):
|
|
luminance_index = len(chars) - 1
|
|
output[xp][yp] = chars[luminance_index]
|
|
|
|
phi += phi_spacing
|
|
theta += theta_spacing
|
|
|
|
# Update Tkinter canvas
|
|
for y in range(screen_height):
|
|
for x in range(screen_width):
|
|
canvas.itemconfigure(text_items[y][x], text=output[x][y])
|
|
|
|
# Animation loop
|
|
A = 0
|
|
B = 0
|
|
def animate():
|
|
global A, B
|
|
render_frame(A, B)
|
|
A += 0.07
|
|
B += 0.03
|
|
root.after(30, animate)
|
|
|
|
animate()
|
|
root.mainloop()
|