사용자 도구

사이트 도구


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 sys
import math
import time
from IPython import embed
import random
import numpy as np
 
import plotille
from plotille import Canvas
 
 
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. """
        x = self.x - 0.5
        y = self.y - 0.5
        z = self.z
        factor = fov / (viewer_distance + z)
        x = x * factor + win_width / 2
        y = -y * factor + win_height / 2
        return Point3D(x / win_width, y / win_height, 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(0.25, 0.75, 0.25),  # Point3D(-20,20,-20),
    Point3D(0.75, 0.75, 0.25),  # Point3D(20,20,-20),
    Point3D(0.75, 0.25, 0.25),  # Point3D(20,-20,-20),
    Point3D(0.25, 0.25, 0.25),  # Point3D(-20,-20,-20),
    Point3D(0.25, 0.75, 0.75),  # Point3D(-20,20,20),
    Point3D(0.75, 0.75, 0.75),  # Point3D(20,20,20),
    Point3D(0.75, 0.25, 0.75),  # Point3D(20,-20,20),
    Point3D(0.25, 0.25, 0.75),  # 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()
    projection = False
 
    # 변환 행렬
    TR = T(0.5, 0.5, 0.5) @ R(2, 3, 5) @ T(-0.5, -0.5, -0.5)
 
    while True:
        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)
            if projection:
                # Transform the point from 3D to 2D
                v = v.project(
                    win_width=50, 
                    win_height=50, 
                    fov=50, 
                    viewer_distance=1
                )
            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)
            canvas.line(t[f[1]].x, t[f[1]].y, t[f[2]].x, t[f[2]].y)
            canvas.line(t[f[2]].x, t[f[2]].y, t[f[3]].x, t[f[3]].y)
            canvas.line(t[f[3]].x, t[f[3]].y, t[f[0]].x, t[f[0]].y)
 
        screen.write(canvas.plot())
plotille/rotating_cube.1592325826.txt.gz · 마지막으로 수정됨: (바깥 편집)