Advertisement
here2share

# anscii3DdonutAni.py

Jul 11th, 2020
1,502
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.13 KB | None | 0 0
  1. # anscii3DdonutAni.py
  2. # C version -- Ported from http://www.a1k0n.net/2011/07/20/donut-math.html
  3. # Javascript version -- https://codepen.io/Arnthor/pen/ugxcB
  4.  
  5. import math
  6. import os
  7.  
  8. theta_spacing = 0.07
  9. phi_spacing = 0.02
  10.  
  11. R1 = 1
  12. R2 = 2
  13. K2 = 5
  14.  
  15. # Calculate K1 based on screen size: the maximum x-distance occurs roughly at
  16. # the edge of the torus, which is at x=R1+R2, z=0.  we want that to be
  17. # displaced 3/8ths of the width of the screen, which is 3/4th of the way from
  18. # the center to the side of the screen.
  19. # screen_width*3/8 = K1*(R1+R2)/(K2+0)
  20. # screen_width*K2*3/(8*(R1+R2)) = K1
  21.  
  22. screen_width = 35
  23. screen_height = 35
  24.  
  25. K1 = screen_width*K2*3/(8*(R1+R2))
  26. lum = ':::::...,,,,-~+:;#%0$@'
  27. lum = lum+lum[::-1]
  28.  
  29. def render_frame(A, B):
  30.     # precompute sines and cosines of A and B
  31.     cosA = math.cos(A)
  32.     sinA = math.sin(A)
  33.     cosB = math.cos(B)
  34.     sinB = math.sin(B)
  35.  
  36.     char_output = []
  37.     zbuffer = []
  38.  
  39.     for i in range(screen_height + 1):
  40.         char_output.append([' '] * (screen_width + 0))
  41.         zbuffer.append([0] * (screen_width + 0))
  42.  
  43.     # theta goes around the cross-sectional circle of a torus
  44.     theta = 0
  45.     while (theta < 2* math.pi):
  46.         theta += theta_spacing
  47.  
  48.         # Precompute sines and cosines of theta
  49.         costheta = math.cos(theta)
  50.         sintheta = math.sin(theta)
  51.  
  52.         # phi goes around the center of revolution of a torus
  53.         phi = 0
  54.         while (phi < 2*math.pi):
  55.             phi += phi_spacing
  56.  
  57.             # precompute sines and cosines of phi
  58.             cosphi = math.cos(phi)
  59.             sinphi = math.sin(phi)
  60.  
  61.             # the x,y coordinate of the circle,
  62.             # before revolving (factored out of the above equations)
  63.             circlex = R2 + R1*costheta;
  64.             circley = R1*sintheta;
  65.  
  66.             # final 3D (x,y,z) coordinate after rotations, directly from our math above
  67.             x = circlex*(cosB*cosphi + sinA*sinB*sinphi) - circley*cosA*sinB;
  68.             y = circlex*(sinB*cosphi - sinA*cosB*sinphi) + circley*cosA*cosB;
  69.             z = K2 + cosA*circlex*sinphi + circley*sinA;
  70.             ooz = 1/z
  71.  
  72.             # x and y projection. y is negated here, because y goes up in
  73.             # 3D space but down on 2D displays.
  74.             xp = int(screen_width/2 + K1*ooz*x)
  75.             yp = int(screen_height/2 - K1*ooz*y)
  76.  
  77.             # calculate luminance
  78.             L = cosphi*costheta*sinB - cosA*costheta*sinphi - sinA*sintheta + cosB*(cosA*sintheta - costheta*sinA*sinphi)
  79.  
  80.             # L ranges from -sqrt(2) to +sqrt(2).  If it's < 0, the surface is
  81.             # pointing away from us, so we won't bother trying to plot it.
  82.             LL = L+1
  83.             if LL > 0:
  84.                 # test against the z-buffer.  larger 1/z means the pixel is closer to
  85.                 # the viewer than what's already plotted.
  86.                 if ooz > zbuffer[xp][yp]:
  87.                     zbuffer[xp][yp] = ooz
  88.                     luminance_index = LL*9   # this brings L into the range 0..11 (8*sqrt(2) = 11.3)
  89.  
  90.                     # now we lookup the character corresponding
  91.                     # to the luminance and plot it in our output
  92.                     char_output[xp][yp] = lum[int(luminance_index)]
  93.  
  94.     # now, dump char_output to the screen.
  95.     # bring cursor to "home" location, in just about any currently-used terminal emulation mode
  96.     print
  97.     sss = []
  98.     for i in range(screen_height):
  99.         s = ''
  100.         for j in range(screen_width):
  101.             s += char_output[i][j]
  102.         s = s.rstrip()
  103.         if s:
  104.             sss += [s]
  105.     print '\n'.join(sss)
  106.  
  107. A = 1.0
  108. B = 1.0
  109. for i in range(250):
  110.     os.system('cls')
  111.     render_frame(A, B)
  112.     A += 0.08
  113.     B += 0.03
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement