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
= (0, 0, 0, 255)
BLACK = (255, 255, 255, 0)
WHITE = (255, 0, 0, 255)
RED = (0, 255, 0, 255)
GREEN = (0, 0, 255, 255)
BLUE
def load_image(name):
= pygame.image.load(name)
image return image
class MyCircle(pygame.sprite.Sprite):
def __init__(self, color, width, height, alpha=255):
__init__(self)
pygame.sprite.Sprite.
self.image = pygame.Surface([width, height], flags=pygame.SRCALPHA)
self.rect = self.image.get_rect()
= self.rect.centerx
cx = self.rect.centery
cy self.image, color, (width/2, height/2), cx, cy)
pygame.draw.circle(# 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):
__init__(self)
pygame.sprite.Sprite.
self.image = pygame.Surface([width, height], flags=pygame.SRCALPHA)
self.rect = self.image.get_rect()
self.image, color, self.rect)
pygame.draw.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):
= self.font.render(str1, self.antialias, self.color, self.background)
text 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
= 'Mass-Spring System'
title
# initializing pygame
pygame.init()
# clock object that ensure that animation has the same
# on all machines, regardless of the actual machine speed.
= pygame.time.Clock()
clock
# fonts
= util.MyText(util.BLACK)
text
# setting up a sprite group, which will be drawn on the
# screen
= util.MyRect(color=util.BLUE, width=32, height=32)
ball = util.MyRect(color=util.RED, width=4, height=4)
center = util.MyRect(color=util.BLACK, width=620, height=1)
x_axis = util.MyRect(color=util.BLACK, width=1, height=460)
y_axis = pygame.sprite.Group([x_axis, y_axis, ball, center])
my_group
# set up drawing canvas
# top left corner is (0,0) top right (640,0) bottom left (0,480)
# and bottom right is (640,480).
= 640
win_width = 480
win_height = pygame.display.set_mode((win_width, win_height))
screen
pygame.display.set_caption(title)
# setting up simulation
= Simulation.Simulation(title)
sim # sim.init(state=np.array([200,200,0,0], dtype='float32'), mass=100., k=.01, l=200.) Try some other values
=np.array([200,200,0,0], dtype='float32'), mass=10., k=10, l=200.)
sim.init(state0.0)
sim.set_time(0.1)
sim.set_dt(
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
0, 0, win_width, win_height))
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(
while True:
# 30 fps
30)
clock.tick(
# update sprite x, y position using values
# returned from the simulation
0], sim.state[1], win_width, win_height))
ball.set_pos(util.to_screen(sim.state[
= pygame.event.poll()
event if event.type == pygame.QUIT:
pygame.quit()0)
sys.exit(
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):
= True
ball.picked elif event.type == pygame.MOUSEMOTION:
if ball.picked:
= util.from_screen(event.pos[0], event.pos[1], win_width, win_height)
x, y 0, 0], dtype='float32'))
sim.set_state(np.array([x, y, elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
if ball.picked:
= False
ball.picked 0, 0], dtype='float32'))
sim.set_state(np.array([x, y, else:
pass
# clear the background, and draw the sprites
screen.fill(util.WHITE)
my_group.update()
my_group.draw(screen)"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))
text.draw(if ball.picked:
"Picked. (Simulation disabled)", screen, (10,100))
text.draw(
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()0)
sys.exit(
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
pass
We will run your code as follows:
$ python mass-spring-2d.py
Nothing to submit. Please show your work to the instructor. Due in class.