commit:36ec354a092ca1c7e560265b2837c38010bde6a1
author:Chip Black
committer:Chip Black
date:Wed Jul 16 00:35:25 2008 -0500
parents:e2500a3f325d9cae304f48138beb456ff55d95de
Changed SurfaceSet to use QuadTreeR instead of a list
diff --git a/Richter/Surface.py b/Richter/Surface.py
line changes: +44/-40
index c15f365..4117307
--- a/Richter/Surface.py
+++ b/Richter/Surface.py
@@ -1,9 +1,9 @@
 import pygame
 from OpenGL.GL import *
+from util import QuadTreeR
 import math
 
 class Surface:
-	fuzz = 20
 	def __init__(self, p1, p2):
 		self.p1 = p1
 		self.p2 = p2
@@ -23,10 +23,8 @@ class Surface:
 		# A collision rect for fast collision culling. Only surfaces
 		# whose initial rect collision check passes will run the
 		# detailed check
-		self.rect = pygame.Rect(p1,(self.dx,self.dy))
-		self.rect.normalize()
-		#self.rect.width += 1
-		#self.rect.height += 1
+		self.bbox = pygame.Rect(p1,(self.dx,self.dy))
+		self.bbox.normalize()
 
 
 	def lineSideTest(self, point):
@@ -48,12 +46,12 @@ class Surface:
 
 
 	def collidePoint(self, point):
-		if self.rect.collidepoint(point[0],point[1]):
+		if self.bbox.collidepoint(point[0],point[1]):
 			return self.lineSideTest(point)
 
 
 	def collideRect(self, rect):
-		if not self.rect.colliderect(rect):
+		if not self.bbox.colliderect(rect):
 			return False
 		#print self.collidePoint(rect.bottomleft), self.collidePoint(rect.bottomright), self.collidePoint(rect.topright), self.collidePoint(rect.topright)
 		return self.lineSideTest(rect.bottomleft) or \
@@ -74,13 +72,13 @@ class Surface:
 		glDisable(GL_TEXTURE_2D)
 
 		if self.dx > 0:
-			py = self.rect.top	# rects are upside-down in our space
+			py = self.bbox.top	# rects are upside-down in our space
 		else:
-			py = self.rect.bottom - 1
+			py = self.bbox.bottom - 1
 		if self.dy > 0:
-			px = self.rect.right - 1
+			px = self.bbox.right - 1
 		else:
-			px = self.rect.left
+			px = self.bbox.left
 		glColor4f(1.0,0.0,0.0,0.25)
 		glBegin(GL_TRIANGLES)
 		glVertex3f(self.p2[0], self.p2[1], 0)
@@ -92,8 +90,8 @@ class Surface:
 		glBegin(GL_LINES)
 		glVertex3f(self.p1[0],self.p1[1],0)
 		glVertex3f(self.p2[0],self.p2[1],0)
-		glVertex3f(self.rect.centerx, self.rect.centery, 0)
-		glVertex3f(self.rect.centerx + anglepoint[0], self.rect.centery + anglepoint[1], 0)
+		glVertex3f(self.bbox.centerx, self.bbox.centery, 0)
+		glVertex3f(self.bbox.centerx + anglepoint[0], self.bbox.centery + anglepoint[1], 0)
 		glEnd()
 
 		glPopMatrix()
@@ -103,6 +101,7 @@ class Solid:
 	def __init__(self, p1, p2):
 		self.rect = pygame.Rect(p1,(p2[0]-p1[0],p2[1]-p1[1]))
 		self.rect.normalize()
+		self.bbox = self.rect
 	
 
 	def collidePoint(self, point):
@@ -136,17 +135,19 @@ class Solid:
 class SurfaceSet:
 	surfaces = None
 
-	def __init__(self, file = None):
-		self.surfaces = []
-		if file is not None:
-			self.parse(file)
+	def __init__(self, f):
+		if isinstance(f, str) or isinstance(f, unicode):
+			fo = open(f, 'r')
+			self.parse(fo)
+			fo.close()
+		else:
+			self.parse(f)
 	
 
-	def parse(self, file):
-		self.surfaces = []
+	def parse(self, f):
+		surfaces = []
 
 		mf = (1,1)
-		f = open(file,'r')
 		for line in f:
 			args = line.split()
 			if not args:
@@ -158,42 +159,45 @@ class SurfaceSet:
 			elif cmd == 'surface':
 				p1 = (int(args[0])*mf[0],int(args[1])*mf[1])
 				p2 = (int(args[2])*mf[0],int(args[3])*mf[1])
-				self.surfaces.append(Surface(p1,p2))
+				surfaces.append(Surface(p1,p2))
 			elif cmd == 'solid':
 				p1 = (int(args[0])*mf[0],int(args[1])*mf[1])
 				p2 = (int(args[2])*mf[0],int(args[3])*mf[1])
-				self.surfaces.append(Solid(p1,p2))
+				surfaces.append(Solid(p1,p2))
 		f.close()
-	
+
+		# calculate bounding box for all surfaces
+		bbox = surfaces[0].bbox.unionall([s.bbox for s in surfaces[1:]])
+		self.surfaces = QuadTreeR(bbox)
+		for s in surfaces:
+			self.surfaces.add(s.bbox, s)
+
 
 	def collidePoint(self,point):
-		colliders = filter(lambda x: x.rect.collidepoint(point), self.surfaces)
-		if not colliders:
-			return False
-		for c in colliders:
-			if not c.collidePoint(point):
-				return False
-		return True
+		colliders = self.surfaces.collidePointWalk(point)
+		#if not colliders:
+		#	return False
+		for s in colliders:
+			if s.collidePoint(point):
+				return True
+		return False
 
 
 	def collideRect(self, rect):
-		colliders = filter(lambda x: x.rect.colliderect(rect), self.surfaces)
-		if not colliders:
-			return False
-		#print [(c,c.rect,c.collideRect(rect)) for c in colliders]
-		for c in colliders:
-			if not c.collideRect(rect):
-				return False
-		return True
+		for s in self.surfaces.collideRectWalk(rect):
+			if s.collideRect(rect):
+				return True
+		return False
 
 
 	def draw(self):
 		for s in self.surfaces:
 			s.draw()
+		self.surfaces.draw()
 	
 
-	def append(self, s):
-		return self.surfaces.append(s)
+	def add(self, s):
+		return self.surfaces.add(s.bbox, s)
 
 
 	def remove(self, s):

diff --git a/Richter/util.py b/Richter/util.py
line changes: +38/-5
index 47bcfbc..58c6047
--- a/Richter/util.py
+++ b/Richter/util.py
@@ -52,6 +52,25 @@ class QuadTreeR:
 				self.rects.append((pygame.Rect(rect), obj))
 	
 
+	def remove(self, obj):
+		for (r, o) in self.rects:
+			if o == obj:
+				self.rects.remove((r, o))
+				return
+		if self.subregions:
+			for s in self.subregions:
+				s.remove(obj)
+
+
+	def __iter__(self):
+		for (r, o) in self.rects:
+			yield o
+		if self.subregions:
+			for s in self.subregions:
+				for o in s:
+					yield o
+
+
 	def collideRectWalk(self, rect):
 		"""generator that walks through the QuadTree, returning rects
 		that collide with the given rect"""
@@ -60,16 +79,30 @@ class QuadTreeR:
 				yield o
 		if self.subregions:
 			for s in self.subregions:
-				if s.bbox.contains(rect):
+				if s.bbox.colliderect(rect):
 					for o in s.collideRectWalk(rect):
 						yield o
 	
 
 	def collideRect(self, rect):
-		for o in self.collisionWalk(rect):
-			return o
-		else:
-			return None
+		return [o for o in self.collideRectWalk(rect)]
+
+
+	def collidePointWalk(self, point):
+		"""generator that walks through the QuadTree, returning rects
+		that collide with the given point"""
+		for (r, o) in self.rects:
+			if r.collidepoint(point):
+				yield o
+		if self.subregions:
+			for s in self.subregions:
+				if s.bbox.collidepoint(point):
+					for o in s.collidePointWalk(point):
+						yield o
+
+
+	def collidePoint(self, point):
+		return [o for o in self.collidePointWalk(point)]
 
 
 	def draw(self, rect = None):