Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Tk_raytrace.py
- import math
- import time
- from Tkinter import *
- def oRGB(r,g,b): # pass
- return "#%02x%02x%02x" % (r,g,b)
- ww = 640
- hh = 360
- root = Tk()
- root.title("Tk_raytrace")
- root.geometry("%dx%d+0+0"%(ww,hh))
- canvas = Canvas(root, width=ww, height=hh, bg='black')
- canvas.grid()
- # mouse position
- mouse_pos = (0, 0)
- def handle_input(event):
- global mouse_pos
- mouse_pos = event.x, event.y
- update()
- canvas.bind('<Button-1>',handle_input)
- canvas.bind('<B1-Motion>',handle_input)
- segments = [
- # Border
- {"a":{"x":0,"y":0}, "b":{"x":640,"y":0}},
- {"a":{"x":640,"y":0}, "b":{"x":640,"y":360}},
- {"a":{"x":640,"y":360}, "b":{"x":0,"y":360}},
- {"a":{"x":0,"y":360}, "b":{"x":0,"y":0}},
- # Polygon #1
- {"a":{"x":100,"y":150}, "b":{"x":120,"y":50}},
- {"a":{"x":120,"y":50}, "b":{"x":200,"y":80}},
- {"a":{"x":200,"y":80}, "b":{"x":140,"y":210}},
- {"a":{"x":140,"y":210}, "b":{"x":100,"y":150}},
- # Polygon #2
- {"a":{"x":100,"y":200}, "b":{"x":120,"y":250}},
- {"a":{"x":120,"y":250}, "b":{"x":60,"y":300}},
- {"a":{"x":60,"y":300}, "b":{"x":100,"y":200}},
- # Polygon #3
- {"a":{"x":200,"y":260}, "b":{"x":220,"y":150}},
- {"a":{"x":220,"y":150}, "b":{"x":300,"y":200}},
- {"a":{"x":300,"y":200}, "b":{"x":350,"y":320}},
- {"a":{"x":350,"y":320}, "b":{"x":200,"y":260}},
- # Polygon #4
- {"a":{"x":340,"y":60}, "b":{"x":360,"y":40}},
- {"a":{"x":360,"y":40}, "b":{"x":370,"y":70}},
- {"a":{"x":370,"y":70}, "b":{"x":340,"y":60}},
- # Polygon #5
- {"a":{"x":450,"y":190}, "b":{"x":560,"y":170}},
- {"a":{"x":560,"y":170}, "b":{"x":540,"y":270}},
- {"a":{"x":540,"y":270}, "b":{"x":430,"y":290}},
- {"a":{"x":430,"y":290}, "b":{"x":450,"y":190}},
- # Polygon #6
- {"a":{"x":400,"y":95}, "b":{"x":580,"y":50}},
- {"a":{"x":580,"y":50}, "b":{"x":480,"y":150}},
- {"a":{"x":480,"y":150}, "b":{"x":400,"y":95}}
- ]
- # Intersects
- intersects = []
- # Points
- points = []
- def draw_polygon(polygon, color):
- # collect coordinates for a giant polygon
- points = []
- for intersect in polygon:
- points.append((intersect['x'], intersect['y']))
- # draw as a giant polygon
- canvas.create_polygon(points, fill='yellow')
- def update():
- # Clear old points
- points = []
- # Get all unique points
- for segment in segments:
- points.append((segment['a'], segment['b']))
- unique_points = []
- for point in points:
- if point not in unique_points:
- unique_points.append(point)
- # Get all angles
- unique_angles = []
- for point in unique_points:
- angle = math.atan2(point[0]["y"]-mouse_pos[1], point[0]["x"]-mouse_pos[0])
- point[0]["angle"] = angle
- unique_angles.append(angle-0.00001)
- unique_angles.append(angle)
- unique_angles.append(angle+0.00001)
- # RAYS IN ALL DIRECTIONS
- intersects = []
- for angle in unique_angles:
- # Calculate dx & dy from angle
- dx = math.cos(angle)
- dy = math.sin(angle)
- # Ray from center of screen to mouse
- ray = {
- "a": {"x": mouse_pos[0], "y": mouse_pos[1]},
- "b": {"x": mouse_pos[0]+dx, "y": mouse_pos[1]+dy}
- }
- # Find CLOSEST intersection
- closest_intersect = None
- for segment in segments:
- intersect = get_intersection(ray, segment)
- if not intersect: continue
- if not closest_intersect or intersect["param"] < closest_intersect["param"]:
- closest_intersect = intersect
- # Intersect angle
- if not closest_intersect: continue
- closest_intersect["angle"] = angle
- # Add to list of intersects
- intersects.append(closest_intersect)
- # Sort intersects by angle
- intersects = sorted(intersects, key=lambda k: k['angle'])
- render_frame(intersects)
- def render_frame(intersects):
- canvas.delete('all')
- # draw segments
- for segment in segments:
- canvas.create_line((segment['a']['x'], segment['a']['y']), (segment['b']['x'], segment['b']['y']), fill='green')
- draw_polygon(intersects, oRGB(221, 56, 56))
- # draw debug lines
- for intersect in intersects:
- canvas.create_line( mouse_pos, (intersect['x'], intersect['y']), fill='gold')
- # update screen
- canvas.update()
- def get_intersection(ray, segment):
- ''' Find intersection of RAY & SEGMENT '''
- # RAY in parametric: Point + Direction*T1
- r_px = ray['a']['x']
- r_py = ray['a']['y']
- r_dx = ray['b']['x'] - ray['a']['x']
- r_dy = ray['b']['y'] - ray['a']['y']
- # SEGMENT in parametric: Point + Direction*T2
- s_px = segment['a']['x']
- s_py = segment['a']['y']
- s_dx = segment['b']['x'] - segment['a']['x']
- s_dy = segment['b']['y'] - segment['a']['y']
- # Are they parallel? If so, no intersect
- r_mag = math.sqrt(r_dx*r_dx+r_dy*r_dy)
- s_mag = math.sqrt(s_dx*s_dx+s_dy*s_dy)
- if r_dx/r_mag == s_dx/s_mag and r_dy/r_mag == s_dy/s_mag:
- return None
- # SOLVE FOR T1 & T2
- # r_px+r_dx*T1 = s_px+s_dx*T2 && r_py+r_dy*T1 = s_py+s_dy*T2
- # ==> T1 = (s_px+s_dx*T2-r_px)/r_dx = (s_py+s_dy*T2-r_py)/r_dy
- # ==> s_px*r_dy + s_dx*T2*r_dy - r_px*r_dy = s_py*r_dx + s_dy*T2*r_dx - r_py*r_dx
- # ==> T2 = (r_dx*(s_py-r_py) + r_dy*(r_px-s_px))/(s_dx*r_dy - s_dy*r_dx)
- # todo: fix zerodivision error handling
- try:
- T2 = (r_dx*(s_py-r_py) + r_dy*(r_px-s_px))/(s_dx*r_dy - s_dy*r_dx)
- except ZeroDivisionError:
- T2 = (r_dx*(s_py-r_py) + r_dy*(r_px-s_px))/(s_dx*r_dy - s_dy*r_dx-0.01)
- try:
- T1 = (s_px+s_dx*T2-r_px)/r_dx
- except ZeroDivisionError:
- T1 = (s_px+s_dx*T2-r_px)/(r_dx-0.01)
- # Must be within parametic whatevers for RAY/SEGMENT
- if T1 < 0: return None
- if T2 < 0 or T2>1: return None
- # Return the POINT OF INTERSECTION
- return {
- "x": r_px+r_dx*T1,
- "y": r_py+r_dy*T1,
- "param": T1
- }
- update()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement