plotille:rotating_cube
Plotille: rotating cube
- rotating_cube.py
#!/usr/bin/env python # -*- coding: utf-8 -*- # original: https://github.com/asciimoo/drawille/blob/master/examples/rotating_cube.py # drawille의 rotating cube를 plotille를 사용하도록 포팅 import math import random import sys import threading import time from queue import Queue import numpy as np import plotille from IPython import embed from plotille import Canvas def keyboard(queue): import platform if platform.system() == 'Windows': import msvcrt from msvcrt import kbhit from msvcrt import getch while True: if msvcrt.kbhit(): queue.put(msvcrt.getch()) elif platform.system() == 'Linux': import curses import time stdscr = curses.initscr() stdscr.refresh() while True: queue.put(stdscr.getch()) class Screen: def __init__(self, width, height, fps=20): super().__init__() self.width = width self.height = height self.fps = fps def clear(self): sys.stdout.write('\x1b[2j\n\033c\n\x1bc') # clear sys.stdout.write('\u001b[1000D') # 커서 왼쪽으로 이동 sys.stdout.write(f'\u001b[1000A') # 커서 위로 이동 sys.stdout.flush() def write(self, content): sys.stdout.write('\u001b[1000D') # 커서 왼쪽으로 이동 sys.stdout.write(f'\u001b[{self.height}A') # 커서 위로 이동 sys.stdout.write(content) sys.stdout.flush() # 화면에 출력 time.sleep(1 / self.fps) class Point3D: def __init__(self, x, y, z): self.x, self.y, self.z = float(x), float(y), float(z) def transform(self, trans): p = np.ones(4) p[0] = self.x p[1] = self.y p[2] = self.z p_prime = trans @ p.reshape(-1, 1) # 변환 self.x = p_prime[0, 0] self.y = p_prime[1, 0] self.z = p_prime[2, 0] def project(self, win_width, win_height, fov, viewer_distance): """ Transforms this 3D point to 2D using a perspective projection. """ factor = fov / (viewer_distance + self.z) x = self.x * factor + win_width / 2 y = -self.y * factor + win_height / 2 return Point3D(x / win_height, y / win_width, 1) def __repr__(self): return f'{self.x:.2f}-{self.y:.2f}-{self.z:.2f}' def T(dx, dy, dz): " 이동 변환 " T = np.eye(4) T[0, 3] = dx T[1, 3] = dy T[2, 3] = dz return T def R(ax, ay, az): " 회전변환 " # X rad = np.radians(ax) cosa = math.cos(rad) sina = math.sin(rad) RX = np.eye(4) RX[1, 1] = cosa RX[1, 2] = -sina RX[2, 1] = sina RX[2, 2] = cosa # y rad = np.radians(ay) cosa = math.cos(rad) sina = math.sin(rad) RY = np.eye(4) RY[0, 0] = cosa RY[0, 2] = -sina RY[2, 0] = sina RY[2, 2] = cosa # z rad = np.radians(az) cosa = math.cos(rad) sina = math.sin(rad) RZ = np.eye(4) RZ[0, 0] = cosa RZ[0, 1] = sina RZ[1, 0] = -sina RZ[1, 1] = cosa return RZ @ RY @ RX vs = [ Point3D(-20,20,-20), Point3D(20,20,-20), Point3D(20,-20,-20), Point3D(-20,-20,-20), Point3D(-20,20,20), Point3D(20,20,20), Point3D(20,-20,20), Point3D(-20,-20,20) ] # Define the vertices that compose each of the 6 faces. These numbers are # indices to the vertices list defined above. faces = [ (0, 1, 2, 3), (1, 5, 6, 2), (5, 4, 7, 6), (4, 0, 3, 7), (0, 4, 5, 1), (3, 2, 6, 7) ] if __name__ == '__main__': screen = Screen(height=20, width=40, fps=20) screen.clear() # 변환 행렬 TR = R(2, 3, 5) @ T(0, 0, 0) key = Queue() threading.Thread(target=keyboard, args=(key,), daemon=True).start() colors = ['white', 'yellow', 'green', 'blue', 'red'] while True: if not key.empty() and key.get() == b' ': colors = colors[1:] + colors[:1] canvas = Canvas(height=screen.height, width=screen.width) t = list() for i, v in enumerate(vs): # Rotate the point around X axis, then around Y axis, and finally around Z axis. v.transform(TR) # Transform the point from 3D to 2D v = v.project( win_width=50, win_height=50, fov=50, viewer_distance=100 ) t.append(v) for f in faces: canvas.line(t[f[0]].x, t[f[0]].y, t[f[1]].x, t[f[1]].y, color=colors[0]) canvas.line(t[f[1]].x, t[f[1]].y, t[f[2]].x, t[f[2]].y, color=colors[0]) canvas.line(t[f[2]].x, t[f[2]].y, t[f[3]].x, t[f[3]].y, color=colors[0]) canvas.line(t[f[3]].x, t[f[3]].y, t[f[0]].x, t[f[0]].y, color=colors[0]) screen.write(canvas.plot())
plotille/rotating_cube.txt · 마지막으로 수정됨: 2024/03/23 02:42 저자 127.0.0.1