from __future__ import division from math import sqrt, ceil import random, pygame, sys import os import json from pygame.locals import * pygame.init() GRAY = ( 182, 182, 182) VIOLET = (150, 100, 190) RED = (150, 0, 0) GREEN = (0, 150, 0) BLUE = (30, 30, 180) VERYLIGHT = (210, 210, 210) BLACK = (0,0,0) WHITE = (255, 255, 255) TIME_STEP = 0.01 K = 10000 X_SCREEN_BORDER = 1200 Y_SCREEN_BORDER = 800 INITIAL_SPEED_X = 50 INITIAL_SPEED_Y = 0 INITIAL_Y = 400 DEFAULT_OLD_X = 2 - INITIAL_SPEED_X*TIME_STEP DEFAULT_OLD_Y = INITIAL_Y - INITIAL_SPEED_Y*TIME_STEP def main(): #create the screen window = pygame.display.set_mode((1200, 800)) colors = [GRAY, VIOLET, RED, GREEN, BLUE, VERYLIGHT, BLACK] global INITIAL_SPEED_X global INITIAL_SPEED_Y global INITIAL_Y #Initialize universe with some atoms atom1 = Particle(1000, Vector2(500,500), Vector2(500,500), 20, BLUE) atom2 = Particle(1, Vector2(2,400), Vector2(2-TIME_STEP*INITIAL_SPEED_X, INITIAL_Y- TIME_STEP*INITIAL_SPEED_Y), 1, RED) universe = Universe([atom1, atom2]) screen = Screen(window, colors, universe) screen.draw_surface() keep_running = True while keep_running: screen.draw_surface() universe.update_positions() for event in pygame.event.get(): if event.type == pygame.QUIT: keep_running = False elif event.type == pygame.KEYUP: if event.key == K_UP : INITIAL_Y -= 10 elif event.key == K_DOWN: INITIAL_Y += 10 elif event.key == K_RIGHT: INITIAL_SPEED_X += 20 elif event.key == K_LEFT: INITIAL_SPEED_X -= 20 if(INITIAL_SPEED_X < 0): INITIAL_SPEED_X = 0 elif event.key == K_SPACE: universe.add_particle(Particle(1, Vector2(2,INITIAL_Y), Vector2(2-TIME_STEP*INITIAL_SPEED_X, INITIAL_Y- TIME_STEP*INITIAL_SPEED_Y), 1, random.choice(colors))) print "Pygame thread exited." class Screen: def __init__(self, window, colors, universe): self.communicates = [] self.communicates.append("Rutherford scattering") self.window = window self.universe = universe self.colors = colors self.color = WHITE def change_color(self): self.color = random.choice(self.colors) def draw_universe(self): self.draw_guide() for particle in self.universe.particles: self.draw_particle(particle) def draw_particle(self, particle): position = (int(ceil(particle.position.x)), int(ceil(particle.position.y))) pygame.draw.circle(self.window, particle.color, position, 6+ int(particle.mass/100) ) def draw_guide(self): pygame.draw.line(self.window, BLACK, (0, INITIAL_Y), (X_SCREEN_BORDER,INITIAL_Y), 2) def draw_surface(self): self.window.fill(self.color) self.draw_universe() for i, text in enumerate(self.communicates): self.print_text(text, 20, 20 + i*20, (0, 0, 0), 30, self.window) pygame.display.flip() def print_text(self, text,xx,yy,color,text_size, screen): font = pygame.font.SysFont(None,text_size) ren = font.render(text,1,color) screen.blit(ren, (xx,yy)) class Vector2: def __init__(self, x, y): self.x = x self.y = y class Particle: def __init__(self, mass, position, old_position, charge, color): self.mass = mass self.position = position self.old_position = old_position self.acc = Vector2(0,0) self.color = color self.charge = charge class Universe: def __init__(self, particles): self.particles = particles print("Universe has just been created!") def update_accelerations(self): for particle in self.particles: particle.acc = Vector2(0,0) for x in range(1, len(self.particles)): accelerations = self.compute_acc(self.particles[x], self.particles[0]) self.particles[x].acc = accelerations[0] def update_positions(self): self.update_accelerations() for particle in self.particles: temporary_x = particle.position.x temporary_y = particle.position.y particle.position.x = 2 * particle.position.x - particle.old_position.x particle.position.x += particle.acc.x * TIME_STEP * TIME_STEP particle.position.y = 2 * particle.position.y - particle.old_position.y particle.position.y += particle.acc.y * TIME_STEP * TIME_STEP particle.old_position.x = temporary_x particle.old_position.y = temporary_y particle = self.limit_position(particle) def limit_position(self, particle): if(particle.position.x > X_SCREEN_BORDER or particle.position.y > Y_SCREEN_BORDER or particle.position.x < 0 or particle.position.y < 0): random_offset = random.randrange(-20, 20) particle.position.x = 2 particle.old_position.x = 2 - INITIAL_SPEED_X*TIME_STEP particle.position.y = INITIAL_Y + random_offset particle.old_position.y = INITIAL_Y - INITIAL_SPEED_Y*TIME_STEP + random_offset return particle def compute_acc(self, particle1, particle2): vertical_distance = particle1.position.y - particle2.position.y horizontal_distance = particle1.position.x - particle2.position.x distance = sqrt((vertical_distance)**2 + (horizontal_distance)**2) force = particle1.charge * particle2.charge *K/distance**2 acc1x = force/particle1.mass*horizontal_distance/distance acc1y = force/particle1.mass*vertical_distance/distance acc2x = -force/particle2.mass*horizontal_distance/distance acc2y = -force/particle2.mass*vertical_distance/distance return [Vector2(acc1x, acc1y), Vector2(acc2x, acc2y)] def add_particle(self, particle): self.particles.append(particle) if __name__ == '__main__': main()