cubo5.py

Created by cpaulof

Created on March 17, 2023

12.5 KB

Uma abordagem à visualização 3D numa calculadora. Usem as teclas que estão descritas no principio do código. ou então testem as teclas todas até perceberem o que cada uma faz. (não vale analisar o código) Está nos meus planos fazer uns vídeos para o youtube sobre isto, mas é melhor aguardar. Não usar sem no mínimo fazer referência ao autor.


# Título #####################################################
#
#   cubo5
#   Versão: 16-03-2023
#   
#   usar teclas +,-, 1,2,3,4,5,6
#               9 < > alpha shift       
##############################################################
#
#  (c) Carlos Paulo A. Freitas (cpaulof@gmail.com)
#  https://zonaexacta.blogspot.com
#  https://sites.google.com/view/cpaulof-prog-calc
#
############################################################## 
from math import *
from ion import *
import time
import kandinsky
zz=1/25
#Cores: vou deixar 8 cores
F=255
cores = [
 [0,0,0], #0 preto
 [F,F,F], #1 branco
 [F,0,0], #2 vermelho
 [0,F,0], #3 verde
 [0,0,F], #4 azul
 [F,0,F], #5 violeta
 [F,F,0], #6 vermelho+verde=
 [0,F,F], #7
 [204,153,0] #8
]
N_COLORS=9
#Ecrã
LARGURA=320
ALTURA=240
#########################
alpha,phi,theta=0,0,0
olho=[0,1,0]
X_MIN = -3
X_MAX = 3
deltaX=(X_MAX-X_MIN)/(LARGURA-1)
Y_MIN =-ALTURA/2*(X_MAX-X_MIN)/LARGURA
Y_MAX = ALTURA/2*(X_MAX-X_MIN)/LARGURA
VY=(Y_MAX-Y_MIN)/2
ZF=0.9
deltaY=(Y_MAX-Y_MIN)/(ALTURA-1)
class Poliedro:
    def __init__(s, v, normais, arestas, faces, nv, na, nf, nl):
        s.v = v
        s.normais = normais
        s.arestas = arestas
        s.faces = faces
        s.nv = nv
        s.na = na
        s.nf = nf
        s.nl = nl

def descarregaPoliedro(p):
    p.nv = 0
    p.na = 0
    p.nf = 0
    p.nl = 0
    del p.v
    del p.arestas
    del p.faces
    del p.normais

def Tetraedro():
    vertices = [
        [0, 0, 1.0],
        [2*sqrt(2)/3.0, 0, -1.0/3.0],
        [-sqrt(2)/3.0, sqrt(6)/3.0, -1.0/3.0],
        [-sqrt(2)/3.0, -sqrt(6)/3.0, -1.0/3.0]
    ]
    normais = [
        [-sqrt(2)/3.0, -sqrt(6)/3.0, -1.0/3.0],
        [-sqrt(2)/3.0, sqrt(6)/3.0, -1.0/3.0],
        [2*sqrt(2)/3.0, 0, -1.0/3.0],
        [0, 0, 1]
    ]
    arestas = [0,1,0,2,0,3,1,2,2,3,3,1]
    faces = [0,1,2,0,1,3,0,3,2,1,2,3]
    p=Poliedro(vertices, normais, arestas, faces, 4, 6, 4, 3)
    return p

def Cubo():
    l = 1.0 / sqrt(3.0)
    vertices = [[-l,-l,-l],
                 [l,-l,-l],
                 [l,l,-l],
                 [-l,l,-l],
                 [-l,l,l],
                 [-l,-l,l],
                 [l,-l,l],
                 [l,l,l]]
    arestas = [0,1,1,2,2,3,3,0,5,6,6,7,7,4,4,5,1,6,2,7,3,4,0,5]
    faces = [0,1,2,3,0,1,6,5,5,6,7,4,3,2,7,4,1,2,7,6,0,3,4,5]
    normais = [[0,0,-1],[0,-1,0],[0,0,1],[0,1,0],[1,0,0],[-1,0,0]]
    p=Poliedro(vertices, normais, arestas, faces, 8, 12, 6, 4)
    return p

def Octaedro():
    vertices = [ [0,0,1], [1,0,0], [0,1,0], [-1,0,0], [0,-1,0], [0,0,-1] ]
    arestas = [0,1,0,2,0,3,0,4,1,2,2,3,3,4,4,1,1,5,2,5,3,5,4,5]
    faces = [0,1,2,0,2,3,0,3,4,0,4,1,5,1,2,5,2,3,5,3,4,5,4,1]
    normais = [[1.0, 1.0, 1],[-1.0, 1.0, 1],[-1.0, -1.0, 1],[1.0, -1.0, 1],[1.0, 1.0, -1],[-1.0, 1.0, -1],[-1.0, -1.0, -1],[1.0, -1.0, -1]]
    p=Poliedro(vertices, normais, arestas, faces, 6, 12, 8, 3)
    return p

def Dodecaedro():
    g=(1+sqrt(5.0))/2.0
    v = [[0, 0, 1],
            [2/3, 0, sqrt(5)/3],
            [sqrt(5)/3, sqrt(3)/3, 1/3],
            [(2-g)/3, sqrt(3)/3*g, 1/3],
            [-1/3, sqrt(3)/3, sqrt(5)/3],
            [-1/3, -sqrt(3)/3, sqrt(5)/3],
            [sqrt(5)/3, -sqrt(3)/3, 1/3],
            [(2-g)/3, -sqrt(3)/3*g, 1/3],
            [-(g+1)/3, (1-g)*sqrt(3)/3, 1/3],
            [-(g+1)/3, (-1+g)*sqrt(3)/3, 1/3],
            [-sqrt(5)/3, sqrt(3)/3, -1/3],
            [(g-2)/3, sqrt(3)/3*g, -1/3],
            [(g-2)/3, -sqrt(3)/3*g, -1/3],
            [-sqrt(5)/3, -sqrt(3)/3, -1/3],
            [(g+1)/3, (g-1)*sqrt(3)/3, -1/3],
            [(g+1)/3, -(g-1)*sqrt(3)/3, -1/3],
            [1/3, -sqrt(3)/3, -sqrt(5)/3],
            [0, 0, -1],
            [1/3, sqrt(3)/3, -sqrt(5)/3],
            [-2/3, 0, -sqrt(5)/3]]
    arestas = [0, 1, 0, 4, 0, 5, 1, 2, 2, 3, 3, 4, 1, 6, 6, 7, 7, 5, 5, 8, 8, 9, 9, 4, 9, 10, 11, 10, 11, 3, 7, 12, 12, 13, 13, 8, 2, 14, 14, 15, 15, 6, 12, 16, 11, 18, 14, 18, 13, 19, 19, 10, 19, 17, 16, 17, 15, 16, 17, 18]
    faces = [0,1,2,3,4, 0,4,9,8,5, 0,5,7,6,1, 3,11,10,9,4, 5,8,13,12,7, 1,6,15,14,2, 6,7,12,16,15, 2,14,18,11,3, 8,9,10,19,13, 12,13,19,17,16, 11,18,17,19,10, 14,15,16,17,18]
    normais = []
    for i in range(12):
      j, k, l, m, n = faces[5*i:5*i+5]
      normal = [v[j][0] + v[k][0] + v[l][0] + v[m][0] + v[n][0],
              v[j][1] + v[k][1] + v[l][1] + v[m][1] + v[n][1],
              v[j][2] + v[k][2] + v[l][2] + v[m][2] + v[n][2]]
      normais.append(normal)
      p=Poliedro(v, normais, arestas, faces, 20, 30, 12, 5)
    return p

def Icosaedro():
  g=(1+sqrt(5.0))/2.0
  v = [[0, 0, 1]]
  r = 2*sqrt(2-g)/(3-g)
  #vertices
  for i in range(5):
    theta = 2*i*pi/5
    v.append([cos(theta)*r, sin(theta)*r, (g-1)/(3-g)])
  for i in range(5):
    theta = (2*i+1)*pi/5
    v.append([cos(theta)*r, sin(theta)*r, -(g-1)/(3-g)])    
  v.append([0, 0, -1])
  # arestas
  a=array(60)
  # (piramide superior)
  for i in range(0, 10, 2):
    a[i] = 0
    a[i+1] = (i+2) // 2
  for i in range(1, 6):
    a[2*i+8] = i
    a[2*i+9] = i % 5 + 1
  a[19] = a[10]
  # (piramide inferior)
  for i in range(0, 10, 2):
    a[59-i] = 11
    a[58-i] = 10 - i // 2
  for i in range(0, 10, 2):
    a[49-i] = i // 2 + 6
    a[48-i] = a[49-i] + 1
  a[40] = a[49]
  # (cilindro central)
  for i in range(1, 6):
    a[20+2*(i-1)] = i
    a[20+2*i-1] = i+5
  for i in range(1, 6):
    a[30+2*(i-1)] = i
    a[30+2*i-1] = 6 + (i+3) % 5
  faces = [0,1,2,0,2,3,0,3,4,0,4,5,0,5,1,2,1,6,3,2,7,4,3,8,5,4,9,1,5,10,1,10,6,2,6,7,3,7,8,4,8,9,5,9,10,6,7,11,7,8,11,8,9,11,9,10,11,10,6,11]
  # normais
  normais=[]
  for i in range(20):
    j = faces[3 * i]
    k = faces[3 * i + 1]
    l = faces[3 * i + 2]
    normais.append([v[j][0]+v[k][0]+v[l][0], v[j][1]+v[k][1]+v[l][1], v[j][2]+v[k][2]+v[l][2]])
  p=Poliedro(v, normais, a, faces, 12, 30, 20, 3)
  return p

def xy2D_To_xz3D(v,s):
  c,f,dim=0.5,-0.5,len(v)
  _v=[]
  for i in range(dim):
    _v.append([v[i][0]*s,c*s ,v[i][1]*s])
  for i in range(dim):
    _v.append([v[i][0]*s,f*s,v[i][1]*s])
  return _v

def _PolyPi():
  c,f=0.5,-0.5
  v=[[-1,-1],
     [0,-1],
     [0,3],
     [1,2],
     [1,-1],
     [2,-1],
     [2,2],
     [3,3],
     [3,4],
     [2,3],
     [1,3],
     [0,4],
     [-1,4],
     [-2,3],
     [-2,2],
     [-1,3]
   ]
  v=xy2D_To_xz3D(v,0.25)
  a=array(96)
  for i in range(16):
    a[2*i],a[2*i+1]=i,(i+1)%16 #face frente
    a[2*i+32],a[2*i+33]=i%16+16,(i+1)%16+16#face trás
    a[2*i+64],a[2*i+65]=i,i%16+16 #faces laterais
    normais=[]
    faces=[]
  p=Poliedro(v, normais, a, faces, 32, 48, 0, 0)
  return p
_B,_C=1,0
BACKGROUND,COR=1,0
INVERT=0
def plot(x,y,cor):
  c = int(LARGURA*((x - X_MIN)/(X_MAX - X_MIN))) 
  l = int(ALTURA*(1-(y - Y_MIN)/(Y_MAX - Y_MIN))) 
  if(0 <= l < ALTURA):
    if(0 <= c < LARGURA):
      col = kandinsky.color(cores[cor][0],cores[cor][1],cores[cor][2])
      kandinsky.set_pixel(c,l,col)
def fill_rect(x,y,L,A,cor):
  c = int(LARGURA*((x - X_MIN)/(X_MAX - X_MIN))) 
  l = int(ALTURA*(1-(y - Y_MIN)/(Y_MAX - Y_MIN)))
  _L = int(L*(LARGURA+0.0)/(X_MAX - X_MIN))
  _A = int(A*(ALTURA+0.0)/(Y_MAX - Y_MIN))
  kandinsky.fill_rect(c,l,_L,_A,cores[cor])

def clr():
   kandinsky.fill_rect(0,0,LARGURA,ALTURA+20,cores[BACKGROUND])
   
def draw_line(x1, y1, x2, y2):
    dx = x2 - x1
    dy = y2 - y1
    steps = max(abs(dx), abs(dy))
    if(steps!=0):
      x_step = dx / steps
      y_step = dy / steps
      for i in range(steps + 1):
        x = floor(x1 + i * x_step)
        y = floor(y1 + i * y_step)
        kandinsky.set_pixel(x, y, cores[COR])
def Fline(x,y,a,b):
    c1 = int(LARGURA*((x - X_MIN)/(X_MAX - X_MIN))) 
    l1 = int(ALTURA*(1-(y - Y_MIN)/(Y_MAX - Y_MIN)))
    c2 = int(LARGURA*((a - X_MIN)/(X_MAX - X_MIN))) 
    l2 = int(ALTURA*(1-(b - Y_MIN)/(Y_MAX - Y_MIN)))
    draw_line(c1,l1,c2,l2)

from math import *
#Algebra Linear e Geometria Analitica
def array(n):
  res=[]
  for i in range(n):
    res.append(0)
  return res

def matriz(l,c):
  res=[]
  for i in range(l):
    res.append(array(c))
  return res
  
def produtoMat(a,b): #AB=C
  c=[]
  la,ca,cb=len(a),len(a[0]),len(b[0])
  c=matriz(la,cb)
  for i in range(la):
    for j in range(cb):
      for k in range(ca):
        c[i][j]+=a[i][k]*b[k][j]
  return c

def produtoMQVector(a,b):#AB=C, A matriz quadrada, B e C vectores
  dim=len(a)
  c=[]
  for i in range(dim):
      c.append(0)
  for i in range(dim):
    for j in range(dim):
      c[i]+=a[i][j]*b[j]
  return c

def somaMat(a,b):#c=a+b
  l,col=len(a),len(a[0])
  c=matriz(l,col)
  for i in range(l):
    for j in range(col):
      c[i][j]=a[i][j]+b[i][j]

def RotX(a):
  c,s=cos(a),sin(a)
  Rx=[
      [1,0,0],
      [0,c,-s],
      [0,s,c]
      ]
  return Rx

def RotY(a):
  c,s=cos(a),sin(a)
  Ry=[
      [c,0,s],
      [0,1,0],
      [-s,0,c]
  ]
  return Ry
    
def RotZ(a):
  c,s=cos(a),sin(a)
  Rz=[
      [c,-s,0],
      [s,c,0],
      [0,0,1]
     ]
  return Rz
    
def somaVect(a,b):
    dim=len(a)
    c=array(dim)
    for i in range(dim):
        c[i]=a[i]+b[i]

def subtrVect(a,b):
    dim=len(a)
    c=array(dim)
    for i in range(dim):
        c[i]=a[i]-b[i]

def prodEscalar(u,v):
    dim=len(u)
    res=0
    for i in range(dim):
        res+=u[i]*v[i]
    return res

def norm2Vect(v):
    dim=len(v)
    res=0
    for i in range(dim):
        res+=v[i]*v[i]
    return sqrt(res)
#############################################

phi,theta,alpha,w=0,0,0,2
R,Rx,Ry,Rz,aux=[],[],[],[],[]
x=array(3)
wireframe=0
alter=[0,0,0]
p=Cubo()
v=matriz(p.nv,3)
RUN=True
while RUN==True:
    if keydown(KEY_ALPHA):
      INVERT,alter[0],alter[1]=1,1,0
    if keydown(KEY_BACKSPACE):
      alter[1]=(1+alter[1])%5
    if keydown(KEY_SHIFT):
      INVERT,alter[0]=0,1
    elif keydown(KEY_ZERO):
      alter,w=[1,0,0],2
      BACKGROUND,COR,INVERT=1,0,0
    elif keydown(KEY_ONE):
      descarregaPoliedro(p)
      p=Tetraedro()
      v=matriz(p.nv,3)
    elif keydown(KEY_TWO):
      descarregaPoliedro(p)
      p=Cubo()
      v=matriz(p.nv,3)      
    elif keydown(KEY_THREE):
      descarregaPoliedro(p)
      p=Octaedro()
      v=matriz(p.nv,3)      
    elif keydown(KEY_FOUR):
      descarregaPoliedro(p)
      p=Dodecaedro()
      v=matriz(p.nv,3)
    elif keydown(KEY_FIVE):
      descarregaPoliedro(p)
      p=Icosaedro()
      v=matriz(p.nv,3) 
    elif keydown(KEY_SIX):
          descarregaPoliedro(p)
          p=_PolyPi()
          v=matriz(p.nv,3)
          wireframe=1
          alter[2]=1   
    elif keydown(KEY_NINE):
      if(p.nf > 0):
            wireframe=1-wireframe
    if keydown(KEY_PLUS):
        X_MIN *= ZF
        X_MAX *= ZF
        Y_MIN *= ZF
        Y_MAX *= ZF
    if keydown(KEY_MINUS):
        X_MIN /= ZF
        X_MAX /= ZF
        Y_MIN /= ZF
        Y_MAX /= ZF
    if keydown(KEY_UP):
      if alter[1]==1:
        zz+=0.05
      elif alter[1]==0:
        w+=2
    if keydown(KEY_DOWN):
      if alter[1]==1:
        zz-=0.05
      elif alter[1]==0:
        w=max((w-2,0))
    if keydown(KEY_LEFT):
      alter[2]=(alter[2]+1)%3
    if keydown(KEY_RIGHT):
      __C=_C
      _C=(_C+1)%len(cores)
      if _C==_B:
        _C=(_C+1)%len(cores)
      if __C==COR:
        BACKGROUND,COR=_B,_C
      else:
        BACKGROUND,COR=_C,_B
        
    if(alter[0]==1):    
      if(INVERT==1):
        BACKGROUND,COR,INVERT=_C,_B,0
        alter[0]=0
      else:
        BACKGROUND,COR=_B,_C
      
      
    if alter[2]!=1:
      Rz=RotZ(-(phi/180.0)*pi)
      Rx=RotX(-(alpha/180.0)*pi)
      Ry=RotY(theta*pi/180.0)
      aux=produtoMat(Ry,Rx)
      R=produtoMat(Rz,aux)
    else:
      Rz=RotZ(-(phi/180.0-0.5)*pi)
      Rx=RotX(-(theta/180.0-0.5)*pi)
      Ry=RotY(alpha*pi/180.0)
      aux=produtoMat(Rx,Rz)
      R=produtoMat(Ry,aux)
      Rz=RotZ((phi/180.0-0.5)*pi)
      Rx=RotX((theta/180.0-0.5)*pi)
      aux=produtoMat(Rx,R)
      R=produtoMat(Rz,aux)
    for k in range(p.nv):
        for i in range(3):
            x[i]=p.v[k][i]
            r=produtoMQVector(R,x)
        for i in range(3):
            v[k][i]=r[i]
    if wireframe==1:
        for k in range(p.na):
            i=p.arestas[k*2+0]
            j=p.arestas[k*2+1]
            Fline(v[i][0],v[i][2],v[j][0],v[j][2]);
    else:
      for k in range(p.nf):
        for i in range(3):
            x[i]=p.normais[k][i]
        r=produtoMQVector(R,x)
        if(prodEscalar(r,olho)>0):
            for l in range(p.nl):
                   i=p.faces[k*p.nl+l]
                   j=p.faces[k*p.nl+(l+1)%(p.nl)]
                   Fline(v[i][0],v[i][2],v[j][0],v[j][2])    
    time.sleep(zz)
    clr()
    if alter[2]==0 or alter[2]==2: #vou juntar +alguns
      phi,theta,alpha=(phi+w)%360,(theta+w)%360,(alpha+w)%360
    elif alter[2]==1:
      phi,theta,alpha=(phi+2)%360,0,0
    elif alter[2]==3:
      phi,theta,alpha=0,(theta+w)%360,0
    elif alter[2]==4:
      phi,theta,alpha=0,0,(alpha+w)%360

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.