A simple script heavily inspired by the “Light & Sight” tutorial, by N. Case It doesn’t run with Numworks’ official and NOT OPEN-SOURCE software. Please use Omega or Upsilon instead.
from math import * from kandinsky import * from ion import * class Point(): def __init__(self,x=0,y=0): self.x,self.y = x,y class Vector(): def __init__(self,i=0,j=0): self.i,self.j = i,j def isCollinear(self,vector): if self.i*vector.j == vector.i*self.j: return True return False class Line(): def __init__(self,point_a,point_b): self.point = point_a self.direction = Vector(point_b.x-point_a.x,point_b.y-point_a.y) def isParallelTo(self,line): if self.direction.isCollinear(line.direction): return True return False def contain(self,point_a): vector_a = Vector(point_a.x-self.point.x,point_a.y-self.point.y) if self.direction.isCollinear(vector_a): return True return False # Protected function def isIntersectionValid(self,T1,T2,line): return True def getIntersection(self,line): if self.isParallelTo(line): return None T2 = (self.direction.i*(line.point.y - self.point.y) + self.direction.j*(self.point.x - line.point.x))/(line.direction.i*self.direction.j - line.direction.j*self.direction.i) T1 = (line.direction.i*(self.point.y - line.point.y) + line.direction.j*(line.point.x - self.point.x))/(self.direction.i*line.direction.j - self.direction.j*line.direction.i) # T1 = (line.point.x + line.direction.i*T2 - self.point.x)/self.direction.i if self.isIntersectionValid(T1,T2,line): intersection = Point(self.point.x+self.direction.i*T1,self.point.y+self.direction.j*T1) return [intersection,T2] return None class Ray(Line): def __init__(self,endpoint,point_a): self.point = endpoint self.direction = Vector(point_a.x-endpoint.x,point_a.y-endpoint.y) def contain(self,point): if super().contain(point): if self.direction.i*(point.y-self.endpoint.y) >= 0: return True return False # Protected def isIntersectionValid(self,T1,T2,line): if type(line) == Line: if T1 < 0: return False elif type(line) == Ray: if T1 < 0 or T2 < 0: return False return True class Segment(Ray): def __init__(self,point_a,point_b): self.point = point_a self.direction = Vector(point_b.x-point_a.x,point_b.y-point_a.y) def getPoints(self): return [self.point,Point(self.point.x+self.direction.i,self.point.y+self.direction.j)] def contain(self,point): if super().contain(point): if self.direction.i*(point.y-self.endpoint.y) <= 1: return True return False def isIntersectionValid(self,T1,T2,line): if type(line) == Line: if T1 < 0 or T1 > 1: return False elif type(line) == Ray: if T1 < 0 or T1 > 1 or T2 < 0: return False elif type(line) == Segment: if T1 < 0 or T1 > 1 or T2 < 0 or T1 > 1: return False return True def __lt__(Segment1,Segment2): angle1 = atan2(Segment1.direction.j,Segment1.direction.i) angle2 = atan2(Segment2.direction.j,Segment2.direction.i) if angle1 < angle2: return True return False def getPolygonSegments(polygon): segments = [] for i in range(len(polygon)): if i < len(polygon)-1: segments.append(Segment(polygon[i],polygon[i+1])) else: segments.append(Segment(polygon[i],polygon[0])) return segments def draw_segment(segment): points = segment.getPoints() draw_line(int(points[0].x),int(points[0].y),int(points[1].x),int(points[1].y),[255,255,255]) def draw_polygon(polygon): segments = getPolygonSegments(polygon) for i in segments: draw_segment(i) POLYGONS = [ [Point(0,0),Point(318,0),Point(318,221),Point(0,221)], [Point(30,20),Point(60,60),Point(20,80)], [Point(200,50),Point(250,160),Point(180,100)], [Point(100,160),Point(120,180),Point(80,210)], [Point(100,100),Point(130,110),Point(105,140)], [Point(90,30),Point(120,20),Point(110,70),Point(90,50)]] def draw_scene(): for i in POLYGONS: draw_polygon(i) def draw_light(point): draw_circle(point.x,point.y,2,[255,100,100]) RAYS = [] for poly in POLYGONS: for endpoint in poly: angle = atan2(endpoint.y-point.y,endpoint.x-point.x) dx = cos(angle-0.0001) dy = sin(angle-0.0001) angle_point = Point(point.x+dx,point.y+dy) RAYS.append(Ray(point,angle_point)) RAYS.append(Ray(point,endpoint)) dx = cos(angle+0.0001) dy = sin(angle+0.0001) angle_point = Point(point.x+dx,point.y+dy) RAYS.append(Ray(point,angle_point)) SEGMENTS = [] for ray in RAYS: all_intersections = [] for poly in POLYGONS: segments = getPolygonSegments(poly) for seg in segments: intersection = seg.getIntersection(ray) if intersection != None: # print("New intersection") all_intersections.append(intersection) # draw_circle(int(intersection[0].x),int(intersection[0].y),2,[255,100,100]) if len(all_intersections) > 0: closest_intersection = all_intersections[0] for intersection in all_intersections: # print(str(intersection[1])) if intersection[1]**2 < closest_intersection[1]**2: closest_intersection = intersection closest_intersection = closest_intersection[0] light_ray = Segment(point,closest_intersection) SEGMENTS.append(light_ray) # draw_segment(light_ray) SEGMENTS.sort() for i in range(len(SEGMENTS)): if i < len(SEGMENTS)-1: fill_polygon([(int(point.x),int(point.y)),(int(SEGMENTS[i].point.x+SEGMENTS[i].direction.i),int(SEGMENTS[i].point.y+SEGMENTS[i].direction.j)),(int(SEGMENTS[i+1].point.x+SEGMENTS[i+1].direction.i),int(SEGMENTS[i+1].point.y+SEGMENTS[i+1].direction.j))],[255,255,255]) else: fill_polygon([(int(point.x),int(point.y)),(int(SEGMENTS[i].point.x+SEGMENTS[i].direction.i),int(SEGMENTS[i].point.y+SEGMENTS[i].direction.j)),(int(SEGMENTS[0].point.x+SEGMENTS[0].direction.i),int(SEGMENTS[0].point.y+SEGMENTS[0].direction.j))],[255,255,255]) draw_scene() x,y = 150,130 draw_light(Point(x,y)) while True: if keydown(KEY_RIGHT): x += 20 fill_rect(0,0,320,222,[0,0,0]) draw_scene() draw_light(Point(x,y)) if keydown(KEY_LEFT): x -= 20 fill_rect(0,0,320,222,[0,0,0]) draw_scene() draw_light(Point(x,y)) if keydown(KEY_DOWN): y += 20 fill_rect(0,0,320,222,[0,0,0]) draw_scene() draw_light(Point(x,y)) if keydown(KEY_UP): y -= 20 fill_rect(0,0,320,222,[0,0,0]) draw_scene() draw_light(Point(x,y))