Welcome, guest | Sign In | My Account | Store | Cart

It simulates reflections of a ball on a billiards table that has one or more circular obstacles. (This can also be thought as a 2d ray-tracing.)

Most of the time the path of the ball would be chaotic (meaning, if another ball started from any slightly different location or direction then its path would be very different after a short while).

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89``` ```# Dynamical Billiards Simulation # FB - 201010295 # See Wikipedia for more info: # http://en.wikipedia.org/wiki/Dynamical_billiards import math import random from PIL import Image, ImageDraw imgx = 800 imgy = 600 image = Image.new("RGB", (imgx, imgy)) draw = ImageDraw.Draw(image) # Only 1 ball is used! maxSteps = 20000 # of steps of ball motion (in constant speed) n = random.randint(1, 7) # of circular obstacles crMax = int(min(imgx - 1, imgy - 1) / 4) # max circle radius crMin = 10 # min circle radius # create circular obstacle(s) cxList = [] cyList = [] crList = [] for i in range(n): while(True): # circle(s) must not overlap cr = random.randint(crMin, crMax) # circle radius cx = random.randint(cr, imgx - 1 - cr) # circle center x cy = random.randint(cr, imgy - 1 - cr) # circle center y flag = True if i > 0: for j in range(i): if math.hypot(cx - cxList[j], cy - cyList[j]) < cr + crList[j]: flag = False break if flag == True: break draw.ellipse((cx - cr, cy - cr, cx + cr, cy + cr)) cxList.append(cx) cyList.append(cy) crList.append(cr) # initial location of the ball must be outside of the circle(s) while(True): x = float(random.randint(0, imgx - 1)) y = float(random.randint(0, imgy - 1)) flag = False for i in range(n): if math.hypot(x - cxList[i], y - cyList[i]) <= crList[i]: flag = True break if flag == False: break # initial direction of the ball a = 2.0 * math.pi * random.random() s = math.sin(a) c = math.cos(a) for i in range(maxSteps): image.putpixel((int(x), int(y)), (255, 255, 255)) xnew = x + c ynew = y + s # reflection from the walls if xnew < 0 or xnew > imgx - 1: c = -c xnew = x if ynew < 0 or ynew > imgy - 1: s = -s ynew = y # reflection from the circle(s) for i in range(n): if math.hypot(xnew - cxList[i], ynew - cyList[i]) <= crList[i]: # angle of the circle point ca = math.atan2(ynew - cyList[i], xnew - cxList[i]) # reversed collision angle of the ball rca = math.atan2(-s, -c) # reflection angle of the ball rab = rca + (ca - rca) * 2 s = math.sin(rab) c = math.cos(rab) xnew = x ynew = y x = xnew y = ynew image.save("Dynamical_Billiards.png", "PNG") ``` Created by Steve Wadley on Thu, 20 Jun 2013 (MIT)