changeset 0:919a9eff76a3

Initial import
author Josef "Jeff" Sipek <jeffpc@optonline.net>
date Thu, 07 Jul 2005 01:00:05 +0000
parents
children 4c7bb645fd75
files atc.py atc_colors.py atc_message.py atc_plane.py atc_utils.py
diffstat 5 files changed, 356 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atc.py	Thu Jul 07 01:00:05 2005 +0000
@@ -0,0 +1,74 @@
+try:
+	import sys
+	import threading
+	import pygame
+	
+	import atc_colors
+	import atc_utils
+	import atc_plane
+	import atc_message
+except ImportError, err:
+	print "Couldn't load module %s" % (err)
+	sys.exit()
+
+size = width, height = 800, 600
+
+def main():
+	""" Main fn to run the main thread """
+	
+	# Init
+	pygame.init()
+	screen = pygame.display.set_mode(size)
+	pygame.display.set_caption('Air Traffic Controller')
+	
+	# background music
+	pygame.mixer.init()
+	#pygame.mixer.music.load('data/music.mp3')
+	#pygame.mixer.music.set_volume(0.1)
+	#pygame.mixer.music.play()
+
+	# Set background
+	background = pygame.Surface(screen.get_size()).convert()
+	background.fill(atc_colors.black)
+	
+	(back_image, back_rect) = atc_utils.load_png('background.png')
+	background.blit(back_image, (0, 0))
+
+	# Some text
+#	font = pygame.font.Font(None, 36)
+#	text = font.render("Air Traffic Controller", 1, atc_colors.red)
+#	textpos = text.get_rect()
+#	textpos.centerx = background.get_rect().centerx
+#	background.blit(text, textpos)
+
+	#blit!
+	screen.blit(background, (0, 0))
+	pygame.display.flip()
+
+	planes = []
+	planes.append(atc_plane.Plane(callsign="N12422",vel=(atc_plane.m2pix(50), atc_plane.m2pix(50), atc_plane.m2pix(10))))
+	planes.append(atc_plane.Plane(callsign="N48975",pos=(400, 30, 500),vel=(atc_plane.m2pix(-50), atc_plane.m2pix(50), atc_plane.m2pix(10))))
+	planes.append(atc_plane.Plane(callsign="N86124",pos=(400, 400, 500),vel=(atc_plane.m2pix(-50), atc_plane.m2pix(-50), atc_plane.m2pix(-1500))))
+	planes.append(atc_plane.Plane(callsign="N64554",pos=(30, 400, 500),vel=(atc_plane.m2pix(50), atc_plane.m2pix(-50), atc_plane.m2pix(-2000))))
+	
+	mess = atc_message.Message()
+	
+	while 1:
+		for event in pygame.event.get():
+			if event.type == pygame.QUIT:
+				mess.pickup_kill = 1
+				sys.exit()
+		
+		screen.blit(background, (0, 0))
+		
+		for plane in planes:
+			plane.display(screen)
+			plane.update()
+			if (plane.status == atc_plane.plane_CRASHED):
+				mess.write(screen,plane.callsign + ": PLANE CRASHED")
+				plane.status = atc_plane.plane_DEAD
+		
+		pygame.display.flip()
+
+if (__name__ == '__main__'):
+	main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atc_colors.py	Thu Jul 07 01:00:05 2005 +0000
@@ -0,0 +1,14 @@
+black	= 0, 0, 0
+blue1	= 0, 182, 227
+blue2	= 57, 108, 149
+brown	= 199, 103, 0
+gray	= 131, 131, 131
+green1	= 0, 227, 0
+green2	= 0, 149, 0
+red	= 255, 0, 0
+snow	= 227, 227, 227
+white	= 255, 255, 255
+
+planeinfo_ok		= green1
+planeinfo_crashed	= red
+background		= black
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atc_message.py	Thu Jul 07 01:00:05 2005 +0000
@@ -0,0 +1,101 @@
+import pygame
+import threading
+
+class Message:
+	""" Interface to display a message and beep it off in morse code """
+	def __init__(self):
+		""" Set up everything """
+		self.snd = {}
+		self.snd["."] = pygame.mixer.Sound('data/sbeep.wav')
+		self.snd["."].set_volume(0.4)
+		self.snd["-"] = pygame.mixer.Sound('data/lbeep.wav')
+		self.snd["-"].set_volume(0.4)
+		self.snd[" "] = pygame.mixer.Sound('data/nosnd.wav')
+		self.snd[" "].set_volume(0.4)
+		
+		self.delay = {}
+		self.delay["."] = 250
+		self.delay["-"] = 400
+		self.delay[" "] = 330
+		
+		self.morse = {}
+		self.morse["A"] = ".-"
+		self.morse["B"] = "-..."
+		self.morse["C"] = "-.-."
+		self.morse["D"] = "-.."
+		self.morse["E"] = "."
+		self.morse["F"] = "..-."
+		self.morse["G"] = "--."
+		self.morse["H"] = "...."
+		self.morse["I"] = ".."
+		self.morse["J"] = ".---"
+		self.morse["K"] = "-.-"
+		self.morse["L"] = ".-.."
+		self.morse["M"] = "--"
+		self.morse["N"] = "-."
+		self.morse["O"] = "---"
+		self.morse["P"] = ".--."
+		self.morse["Q"] = "--.-"
+		self.morse["R"] = ".-."
+		self.morse["S"] = "..."
+		self.morse["T"] = "-"
+		self.morse["U"] = "..-"
+		self.morse["V"] = "...-"
+		self.morse["W"] = ".--"
+		self.morse["X"] = "-..-"
+		self.morse["Y"] = "-.--"
+		self.morse["Z"] = "--.."
+		self.morse["1"] = ".----"
+		self.morse["2"] = "..---"
+		self.morse["3"] = "...--"
+		self.morse["4"] = "....-"
+		self.morse["5"] = "....."
+		self.morse["6"] = "-...."
+		self.morse["7"] = "--..."
+		self.morse["8"] = "---.."
+		self.morse["9"] = "----."
+		self.morse["0"] = "-----"
+		self.morse[" "] = " "
+		self.morse[":"] = ""
+
+		self.statusmess = ""
+		
+		self.messages = []
+		
+		self.pickup_kill = 0
+		self.pickup_thread = threading.Timer(0, self.__pickup)
+		self.pickup_thread.start()
+
+	def write(self,screen,mess):
+		""" Add message to the queue """
+		code = ""
+		for letter in mess:
+			code += self.morse[letter] + " "
+
+		self.messages.append(code)
+
+	def __beep(self,char):
+		""" Beep one . or - """
+		self.snd[char].play()
+
+	def __beeper(self,mess):
+		""" Beep out all . and - in a message """
+		for char in mess:
+			self.__beep(char)
+			pygame.time.delay(self.delay[char])
+
+	def __pickup(self):
+		""" The message pickup thread code, it picks up new messages
+		and calls the appropreate functions to beep them out """
+		while(not self.pickup_kill):
+			try:
+				message = self.messages.pop()
+				self.statusmess = message
+				self.__beeper(message)
+				pygame.time.delay(1400)
+				self.statusmess = ""
+			except IndexError:
+				pass
+			
+			pygame.time.delay(100)
+		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atc_plane.py	Thu Jul 07 01:00:05 2005 +0000
@@ -0,0 +1,146 @@
+import os
+import sys
+import pygame
+from math import *
+
+import atc_colors
+import atc_utils
+
+mperpix		= 750.0
+
+def m2pix(m):
+	""" Meters to pixels conversion fn """
+	return m/mperpix
+
+def pix2m(pix):
+	""" Pixels to meters conversion fn """
+	return pix*mperpix
+
+plane_OK	= 0
+plane_RANGE	= 1
+plane_CRASHED	= 2
+plane_STALL	= 3
+plane_DEAD	= 4
+plane_PROXY	= 5
+
+plane_PROP	= 16.667 # meters/sec
+plane_JET	= 62.572
+
+
+class Plane(pygame.sprite.Sprite):
+	""" Class to manage one plane's motion """
+	def __init__(self,callsign,pos=(0.0, 0.0, 0.0),vel=(0.0, 0.0, 0.0)):
+		""" Set up everything """
+		pygame.sprite.Sprite.__init__(self)
+		
+		# screen
+		screen = pygame.display.get_surface()
+		self.area = screen.get_rect()
+		
+		# plane image
+		(self.image, self.rect) = atc_utils.load_png('plane.png')
+		
+		# call sign
+		self.callsign	= callsign
+		
+		# position
+		self.X		= pos[0]
+		self.Y		= pos[1]
+		self.Z		= pos[2]
+		
+		# velocity
+		self.i		= vel[0]
+		self.j		= vel[1]
+		self.k		= vel[2]
+		
+		# plane specs
+		self.stallspeed	= m2pix(plane_PROP)
+		
+		# status flag
+		self.status	= plane_OK
+	
+	def update(self):
+		""" Move the plane, and check for collisions """
+		if (self.status != plane_OK):
+			return
+		
+		self.X += self.i
+		self.Y += self.j
+		self.Z += self.k
+		
+		if (self.X <= 0) or (self.Y <= 0): # FIXME: max values
+			self.status = plane_RANGE
+		
+		if (self.Z <= 0):
+			self.i = 0
+			self.j = 0
+			self.k = 0
+			self.status = plane_CRASHED
+		
+		if (self.calc_vel()<self.stallspeed) and (not self.status==plane_CRASHED):
+			self.status = plane_STALL
+		
+		self.rect.move(self.i,self.j)
+	
+	def calc_vel(self):
+		""" Calculate magnitude of the velocity """
+		return sqrt(self.i**2 + self.j**2 + self.k**2)
+	
+	def calc_head(self):
+		""" Calculate heading of the airplane """
+		if (self.i == self.j == 0): # no movement
+			return 0
+		
+		try:
+			head = fabs(atan(self.i/-self.j))
+		except ZeroDivisionError:
+			if (self.i>0):
+				return pi/2	# east
+			return 3*pi/2		# west
+		
+		if (self.i>0) and (-self.j>0):	# east and north
+			return pi/2 - head
+		if (self.i<0) and (-self.j>0):	# west and north
+			return head + 3*pi/2
+		if (self.i>0) and (-self.j<0):	# east and south
+			return head + pi/2
+		if (self.i==0) and (-self.j>0):	# north
+			return head
+		return head + pi		# west and south / south
+	
+	def calc_rc(self):
+		""" Calculate rate of climb """
+		return atan(self.k/self.i)	# REDO!!
+	
+	def recalc_vel(self,vel,heading,rc):
+		""" Set velocity to new value """
+		self.i = vel*cos(rc)
+		self.j = vel*cos(heading)
+		self.k = vel*sin(rc)
+
+	def display(self,screen):
+		""" Put everything onto the screen """
+		screen.blit(self.image, (int(self.X), int(self.Y)))
+		
+		# Plane info
+		font = pygame.font.Font(None, 16)
+		
+		color = atc_colors.planeinfo_ok
+		if (self.status == plane_CRASHED) or (self.status == plane_DEAD):
+			color = atc_colors.planeinfo_crashed
+		
+		x = int(self.X) + 10
+		y = int(self.Y) - 5
+		
+		strings = (	self.callsign + str(self.status),
+				"Alt:  " + str(int(self.Z)),
+				"Lat:  " + str(int(self.X)),
+				"Long: " + str(int(self.Y)),
+				"Head: " + str(int(atc_utils.todeg(self.calc_head()))))
+		
+		for stri in strings:
+			alt = font.render(stri, 1, color)
+			altpos = alt.get_rect()
+			altpos.topleft = (x,y)
+			screen.blit(alt, altpos)
+			(x,y) = (x,y+10)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/atc_utils.py	Thu Jul 07 01:00:05 2005 +0000
@@ -0,0 +1,21 @@
+import pygame
+import os
+from math import *
+
+def load_png(name):
+	""" Load image and return image object"""
+	fullname = os.path.join('data', name)
+	try:
+		image = pygame.image.load(fullname)
+		if image.get_alpha() is None:
+			image = image.convert()
+		else:
+			image = image.convert_alpha()
+	except pygame.error, message:
+        	print 'Cannot load image:', fullname
+        	raise SystemExit, message
+	return image, image.get_rect()
+
+def todeg(rad):
+	""" Convert radians to degrees """
+	return rad*180.0/pi