Simulation and Modeling (CSCI 3010U)
Faculty of Science, Ontario Tech University
http://vclab.science.ontariotechu.ca
Discuss in class
Consider a mass-spring system that lives in a flat (2D) world. One
end of the spring is connected to a fixed hinge sitting at location
\((0,0)\). The other end of the spring
is connected to a mass \(m\). The rest
length of this spring is \(l\), and the
Hooke’s coefficient is \(k\). Provide
the Simulation class that simulates this mass spring
system.

The following files are provided for you, which will use the
Simulation class provided by you. It assumes that your
class is available in file sim.py.
Includes routines used by mass-spring-2d.py file.
"""
author: Faisal Z. Qureshi
email: faisal.qureshi@uoit.ca
website: http://www.vclab.ca
license: BSD
"""
import pygame
# set up the colors
BLACK = (0, 0, 0, 255)
WHITE = (255, 255, 255, 0)
RED = (255, 0, 0, 255)
GREEN = (0, 255, 0, 255)
BLUE = (0, 0, 255, 255)
def load_image(name):
image = pygame.image.load(name)
return image
class MyCircle(pygame.sprite.Sprite):
def __init__(self, color, width, height, alpha=255):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width, height], flags=pygame.SRCALPHA)
self.rect = self.image.get_rect()
cx = self.rect.centerx
cy = self.rect.centery
pygame.draw.circle(self.image, color, (width/2, height/2), cx, cy)
# self.rect = self.image.get_rect()
self.picked = False
def set_pos(self, pos):
self.rect.x = pos[0] - self.rect.width//2
self.rect.y = pos[1] - self.rect.height//2
def update(self):
pass
class MyRect(pygame.sprite.Sprite):
def __init__(self, color, width, height, alpha=255):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([width, height], flags=pygame.SRCALPHA)
self.rect = self.image.get_rect()
pygame.draw.rect(self.image, color, self.rect)
self.picked = False
def set_pos(self, pos):
self.rect.x = pos[0] - self.rect.width//2
self.rect.y = pos[1] - self.rect.height//2
def update(self):
pass
def to_screen(x, y, win_width, win_height):
return win_width//2 + x, win_height//2 - y
def from_screen(x, y, win_width, win_height):
return x - win_width//2, win_height//2 - y
class MyText():
def __init__(self, color, background=WHITE, antialias=True, fontname="comicsansms", fontsize=16):
pygame.font.init()
self.font = pygame.font.SysFont(fontname, fontsize)
self.color = color
self.background = background
self.antialias = antialias
def draw(self, str1, screen, pos):
text = self.font.render(str1, self.antialias, self.color, self.background)
screen.blit(text, pos)Calls your Simulation class to do the heaving lifting.
"""
author: Faisal Z. Qureshi
email: faisal.qureshi@uoit.ca
website: http://www.vclab.ca
license: BSD
"""
import pygame, sys
import matplotlib.pyplot as plt
import numpy as np
# import sim_rk4 as Simulation
import sim as Simulation
import util
def main():
# sim title
title = 'Mass-Spring System'
# initializing pygame
pygame.init()
# clock object that ensure that animation has the same
# on all machines, regardless of the actual machine speed.
clock = pygame.time.Clock()
# fonts
text = util.MyText(util.BLACK)
# setting up a sprite group, which will be drawn on the
# screen
ball = util.MyRect(color=util.BLUE, width=32, height=32)
center = util.MyRect(color=util.RED, width=4, height=4)
x_axis = util.MyRect(color=util.BLACK, width=620, height=1)
y_axis = util.MyRect(color=util.BLACK, width=1, height=460)
my_group = pygame.sprite.Group([x_axis, y_axis, ball, center])
# set up drawing canvas
# top left corner is (0,0) top right (640,0) bottom left (0,480)
# and bottom right is (640,480).
win_width = 640
win_height = 480
screen = pygame.display.set_mode((win_width, win_height))
pygame.display.set_caption(title)
# setting up simulation
sim = Simulation.Simulation(title)
# sim.init(state=np.array([200,200,0,0], dtype='float32'), mass=100., k=.01, l=200.) Try some other values
sim.init(state=np.array([200,200,0,0], dtype='float32'), mass=10., k=10, l=200.)
sim.set_time(0.0)
sim.set_dt(0.1)
print ('--------------------------------')
print ('Usage:')
print ('Press (r) to start/resume simulation')
print ('Press (p) to pause simulation')
print ('Press (q) to quit')
print ('Press (space) to step forward simulation when paused')
print ('Use mouse left button down to move mass around (only when simulation paused)')
print ('--------------------------------')
# Transformation to screen coordinates
# Here 0,0 refers to simulation coordinates
center.set_pos(util.to_screen(0, 0, win_width, win_height))
x_axis.set_pos(util.to_screen(0, 0, win_width, win_height))
y_axis.set_pos(util.to_screen(0, 0, win_width, win_height))
while True:
# 30 fps
clock.tick(30)
# update sprite x, y position using values
# returned from the simulation
ball.set_pos(util.to_screen(sim.state[0], sim.state[1], win_width, win_height))
event = pygame.event.poll()
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(0)
if event.type == pygame.KEYDOWN and event.key == pygame.K_p:
sim.pause()
continue
elif event.type == pygame.KEYDOWN and event.key == pygame.K_r:
if not ball.picked:
sim.resume()
continue
elif event.type == pygame.KEYDOWN and event.key == pygame.K_q:
break
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: # LEFT=1
if sim.paused:
if ball.rect.collidepoint(event.pos):
ball.picked = True
elif event.type == pygame.MOUSEMOTION:
if ball.picked:
x, y = util.from_screen(event.pos[0], event.pos[1], win_width, win_height)
sim.set_state(np.array([x, y, 0, 0], dtype='float32'))
elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
if ball.picked:
ball.picked = False
sim.set_state(np.array([x, y, 0, 0], dtype='float32'))
else:
pass
# clear the background, and draw the sprites
screen.fill(util.WHITE)
my_group.update()
my_group.draw(screen)
text.draw("Time = %f" % sim.cur_time, screen, (10,10))
text.draw("x = %f" % sim.state[0], screen, (10,40))
text.draw("y = %f" % sim.state[1], screen, (10,70))
if ball.picked:
text.draw("Picked. (Simulation disabled)", screen, (10,100))
pygame.display.flip()
# update simulation
if not sim.paused:
sim.step()
elif not ball.picked and event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
sim.step()
else:
pass
pygame.quit()
sys.exit(0)
if __name__ == '__main__':
main()Starter code for your simulation class.
"""
author: Faisal Qureshi
email: faisal.qureshi@uoit.ca
website: http://www.vclab.ca
license: BSD
"""
import numpy as np
class Simulation:
def __init__(self, title):
self.paused = True # starting in paused mode
self.title = title
self.cur_time = 0
self.dt = 0.033 # 33 millisecond, which corresponds to 30 fps
# Fix this
def init(self, state, mass, k, l):
# Fix this
pass
def set_state(self, state):
# Fix this
pass
def set_time(self, cur_time=0):
self.cur_time = cur_time
def set_dt(self, dt=0.033):
self.dt = dt
def step(self):
# Fix this
pass
def pause(self):
self.paused = True
def resume(self):
self.paused = False
def save(self, filename):
# Ignore this
pass
def load(self, filename):
# Ignore this
passWe will run your code as follows:
$ python mass-spring-2d.pyNothing to submit. Please show your work to the instructor. Due in class.