Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # tk_Superellipsoid.py
- import tkinter as tk
- import math
- import random
- import array
- import struct
- WIDTH, HEIGHT = 600, 600
- LINEWIDTH = 2
- FOV = 700.0
- SCALE = 220.0
- U_STEPS = 44
- V_STEPS = 22
- EPS1 = 0.65
- EPS2 = 0.65
- ANGLE_STEPS = 1440
- _step = 2 * math.pi / ANGLE_STEPS
- x_cache = [(math.cos(i * _step), math.sin(i * _step)) for i in range(ANGLE_STEPS)]
- y_cache = x_cache
- z_cache = x_cache
- def sgn(x):
- return 1.0 if x >= 0 else -1.0
- def spow(v, p):
- return sgn(v) * (abs(v) ** p)
- def superellipsoid_point(u, v, e1=EPS1, e2=EPS2):
- cu, su = math.cos(u), math.sin(u)
- cv, sv = math.cos(v), math.sin(v)
- x = spow(cv, e1) * spow(cu, e2)
- y = spow(cv, e1) * spow(su, e2)
- z = spow(sv, e1)
- return x, y, z
- def orange_depth(d):
- t = max(0.0, min(1.0, d))
- r = int(70 + 185 * t)
- g = int(25 + 120 * t)
- b = int(0 + 30 * t)
- return f'#{r:02x}{g:02x}{b:02x}'
- color_cache = [orange_depth(i / 255) for i in range(256)]
- root = tk.Tk()
- root.title("Superellipsoid")
- root.geometry("+-5+0")
- root.resizable(False, False)
- canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg="black", highlightthickness=0)
- canvas.pack()
- W2 = WIDTH * 0.5
- H2 = HEIGHT * 0.5
- verts = []
- for iv in range(V_STEPS + 1):
- v = -math.pi / 2 + math.pi * iv / V_STEPS
- for iu in range(U_STEPS):
- u = 2 * math.pi * iu / U_STEPS
- verts.append(superellipsoid_point(u, v))
- VCOUNT = len(verts)
- raw = array.array('d')
- for x, y, z in verts:
- raw.extend((x, y, z))
- RAW_FMT = f'{VCOUNT * 3}d'
- edges = set()
- for iv in range(V_STEPS + 1):
- for iu in range(U_STEPS):
- a = iv * U_STEPS + iu
- b = iv * U_STEPS + ((iu + 1) % U_STEPS)
- edges.add(tuple(sorted((a, b))))
- if iv < V_STEPS:
- c = (iv + 1) * U_STEPS + iu
- edges.add(tuple(sorted((a, c))))
- edges = sorted(edges)
- ECOUNT = len(edges)
- _px = array.array('d', bytes(VCOUNT * 8))
- _py = array.array('d', bytes(VCOUNT * 8))
- _dep = array.array('B', bytes(VCOUNT))
- lines = [
- canvas.create_line(0, 0, 1, 1, fill=color_cache[128], width=LINEWIDTH, capstyle=tk.ROUND)
- for _ in range(ECOUNT)
- ]
- ix = random.randrange(ANGLE_STEPS)
- iy = random.randrange(ANGLE_STEPS)
- iz = random.randrange(ANGLE_STEPS)
- _coords = canvas.coords
- _config = canvas.itemconfig
- _after = root.after
- _unpack = struct.unpack
- _randint = random.randint
- def rotate():
- return _randint(8, 20)
- def draw_frame():
- global ix, iy, iz
- ix = (ix + rotate()) % ANGLE_STEPS
- iy = (iy + rotate()) % ANGLE_STEPS
- iz = (iz + rotate()) % ANGLE_STEPS
- cx, sx = x_cache[ix]
- cy, sy = y_cache[iy]
- cz, sz = z_cache[iz]
- m00 = cy*cz; m01 = cz*sx*sy - cx*sz; m02 = cx*cz*sy + sx*sz
- m10 = cy*sz; m11 = cx*cz + sx*sy*sz; m12 = cx*sy*sz - cz*sx
- m20 = -sy; m21 = cy*sx; m22 = cx*cy
- pts = _unpack(RAW_FMT, raw)
- for i in range(VCOUNT):
- j = i * 3
- x = pts[j]; y = pts[j + 1]; z = pts[j + 2]
- rx = m00*x + m01*y + m02*z
- ry = m10*x + m11*y + m12*z
- rz = m20*x + m21*y + m22*z
- f = FOV / (rz + FOV) * SCALE
- _px[i] = rx * f + W2
- _py[i] = -ry * f + H2
- d = int((rz + 1.7) * 75.0)
- _dep[i] = 255 if d > 255 else (0 if d < 0 else d)
- for i, (a, b) in enumerate(edges):
- _coords(lines[i], _px[a], _py[a], _px[b], _py[b])
- _config(lines[i], fill=color_cache[(_dep[a] + _dep[b]) >> 1])
- _after(1, draw_frame)
- draw_frame()
- root.mainloop()
Advertisement