""" Light ray manipulation. Pew. Pew. Pew. Wommmm. """
+import math
+
import pymunk
import pymunk.autogeometry
import pymunk.pygame_util
yield pymunk.Vec2d(x, bottom)
-@debug_timer("rays.calculate_ray_polys", True)
+@debug_timer("rays.calculate_ray_polys")
def calculate_ray_polys(space, position, light_filter):
+ """ Calculate a set of convex RayPolys that cover all the areas that light
+ can reach from the given position, taking into account the obstacles
+ present in the space.
+ """
position = pymunk.Vec2d(position)
vertices = [position]
start, end = None, None
query_prev = trial_poly.point_query(end)
query_pos = trial_poly.point_query(position)
if query_prev.distance < -0.01 or query_pos.distance < -0.01:
- ray_polys.append(RayPoly(start, end, vertices[:-1]))
+ ray_polys.append(RayPoly(
+ start - position, end - position, vertices[:-1]))
start = vertices[-1]
vertices = [position, start]
else:
return ray_polys
+def to_pymunk_radians(deg):
+ """ Convert degrees in [0, 360] to radians in (-pi, pi].
+
+ Return None if degrees is None.
+ """
+ if deg is None:
+ return None
+ deg = deg * math.pi / 180.0
+ if deg > math.pi:
+ deg -= 2 * math.pi
+ return deg
+
+
class RayPolyManager(object):
def __init__(self, body, ray_filter):
self._body = body
self._ray_filter = ray_filter
self._rays = []
+ self._angle_limits = (None, None)
+ self._poly_cache = None
+ self._pygame_poly_cache = None
def generate_rays(self, space, position):
self._rays = calculate_ray_polys(space, position, self._ray_filter)
+ self._poly_cache = None
+ self._pygame_poly_cache = None
+
+ def set_angle_limits(self, angle_limits):
+ start, end = angle_limits
+ self._angle_limits = (
+ to_pymunk_radians(start), to_pymunk_radians(end))
+ self._poly_cache = None
+ self._pygame_poly_cache = None
def polys(self):
- return [rp.poly(self._body, self._ray_filter) for rp in self._rays]
+ if self._poly_cache is None:
+ print "===="
+ self._poly_cache = [
+ rp.poly(self._body, self._ray_filter) for rp in self._rays
+ if rp.within_limits(*self._angle_limits)
+ ]
+ print "===="
+
+ return self._poly_cache
def pygame_polys(self, surface):
- return [rp.pygame_poly(surface) for rp in self._rays]
+ if self._pygame_poly_cache is None:
+ print "REGEN ...", self._angle_limits
+ self._pygame_poly_cache = [
+ [
+ pymunk.pygame_util.to_pygame(v, surface)
+ for v in poly.get_vertices()
+ ]
+ for poly in self.polys()
+ ]
+ return self._pygame_poly_cache
class RayPoly(object):
- def __init__(self, start, end, vertices):
- self.start = start
- self.end = end
+ def __init__(self, start_vec, end_vec, vertices):
+ self.start = start_vec # vector from position to first point
+ self.end = end_vec # vector from position to last point
self.vertices = vertices
def poly(self, body, filter):
shape.filter = filter
return shape
- def pygame_poly(self, surface):
- return [
- pymunk.pygame_util.to_pygame(v, surface)
- for v in self.vertices
- ]
+ def within_limits(self, start_limit, end_limit):
+ if start_limit is None or end_limit is None:
+ return True
+ print "----"
+ print "LIM: ", start_limit, end_limit
+ print "ANG: ", self.start.angle, self.end.angle
+ n1 = self.start.normalized()
+ n2 = self.end.normalized()
+ s = pymunk.Vec2d(1, 0).rotated(start_limit)
+ e = pymunk.Vec2d(1, 0).rotated(end_limit)
+ n1bet = s.dot(e) < s.dot(n1) and s.dot(e) < s.dot(n1)
+ n2bet = s.dot(e) < e.dot(n2) and s.dot(e) < e.dot(n2)
+ print "DOTS n1: ", n1.dot(n2), n1.dot(s), n2.dot(s)
+ print "DOTS n2: ", n1.dot(n2), n1.dot(e), n2.dot(e)
+ print "BET: ", n1bet, n2bet
+ if n1bet:
+ print "TRUE\n----"
+ return True
+ return False