"""
(C) Steven Byrnes, 2014. This code is released under the MIT license
http://opensource.org/licenses/MIT
This code should work in Python 2.7 or 3.3. It requires imagemagick to be
installed; that's how it assembles images into animated GIFs.
"""
from __future__ import division, print_function
import pygame as pg
from math import pi
from cmath import exp
import subprocess, os
directory_now = os.path.dirname(os.path.realpath(__file__))
frames_in_anim = 200
animation_loop_seconds = 5 #time in seconds for animation to loop one cycle
bgcolor = (255,255,255) #white
circle_radius = 12
img_height = 300
img_width = 1000
# pygame draws pixel-art, not smoothed. Therefore I am drawing it
# bigger, then smoothly shrinking it down
final_width = int(round(0.3 * img_width))
final_height = int(round(0.3 * img_height))
# Constants and function for calculating electron motion
def coef(n):
""" f(t) = sum of Re[coef(n) * e^(int)] """
return 0 if n % 2 == 0 else -1j / n
def exact(phase):
""" exact square wave function """
if phase == 0 or phase == pi:
return 0
if (phase % (2*pi)) < pi:
return pi/4
return -pi/4
center_x = 500
scale = 450 # scale multiplies all horizontal distances
def draw_arrow(surf, tail_xy, head_xy, width=2, color=(0,0,0)):
"""
draw a horizontal arrow
"""
# tail_xy and head_xy are 2-tuples. Unpack them first
tail_x, tail_y = tail_xy
head_x, head_y = head_xy
assert head_y == tail_y
h = 16 # arrowhead height
b = 18 # arrowhead half-base
if tail_x < head_x:
# rightward arrow
triangle = [(head_x, head_y),
(head_x - h, head_y - b),
(head_x - h, head_y + b)]
else:
# leftward arrow
triangle = [(head_x, head_y),
(head_x + h, head_y - b),
(head_x + h, head_y + b)]
pg.draw.line(surf, color, (tail_x, tail_y), (head_x, head_y), width)
pg.draw.polygon(surf, color, triangle, 0)
def main():
""" function for creating the animated GIF """
# Make and save a drawing for each frame
filename_list = [os.path.join(directory_now, 'temp' + str(n) + '.png')
for n in range(frames_in_anim)]
for frame in range(frames_in_anim):
phase = 2 * pi * frame / frames_in_anim
# initialize surface
surf = pg.Surface((img_width,img_height))
surf.fill(bgcolor)
# draw all the arrows
x_now = center_x
y_now = 30
for n in range(1,13,2):
new_term = (scale * coef(n) * exp(n * 1j * phase)).real
draw_arrow(surf, (x_now, y_now), (x_now + new_term, y_now), width=8)
x_now += new_term
y_now += 30
# draw the two circles
pg.draw.circle(surf, (100,0,100),
(int(round(x_now)),int(round(y_now + 10))),
circle_radius, 0)
pg.draw.circle(surf, (50,50,150),
(int(round(center_x + scale * exact(phase))),
int(round(y_now + 40))),
circle_radius, 0)
# scale down then save the surface
shrunk_surface = pg.transform.smoothscale(surf, (final_width, final_height))
pg.image.save(shrunk_surface, filename_list[frame])
seconds_per_frame = animation_loop_seconds / frames_in_anim
frame_delay = str(int(seconds_per_frame * 100))
command_list = ['convert', '-delay', frame_delay, '-loop', '0'] + filename_list + ['anim.gif']
# Use the "convert" command (part of ImageMagick) to build the animation
subprocess.call(command_list, cwd=directory_now)
# Earlier, we saved an image file for each frame of the animation. Now
# that the animation is assembled, we can (optionally) delete those files
if True:
for filename in filename_list:
os.remove(filename)
return
main()
You must be logged in to post a comment.