# pack circles from Tkinter import * from Canvas import * from whrandom import uniform from math import * class Drag: None def ctor(cx, cy): rx = (cx - width/2) / zoom + xc ry = (cy - height/2) / zoom + yc return rx, ry def rtoc(rx, ry): cx = (rx - xc) * zoom + width/2 cy = (ry - yc) * zoom + height/2 return cx, cy max_radius = 1e4 class Body: by_id = {} def __init__(self, x, y): self.x = x self.y = y self.vx = 0 self.vy = 0 cx, cy = rtoc(x, y) self.item = Oval(canvas, cx-5, cy-5, cx+5, cy+5, fill="red") self.dragging = 0 self.item.bind("<1>", self.drag_start) self.item.bind("", self.drag) self.item.bind("", self.drag_stop) self.item.bind("<3>", self.remove) Body.by_id["%s" % self.item.id] = self def force(b1, b2): dx = b2.x - b1.x dy = b2.y - b1.y d2 = dx*dx + dy*dy d = sqrt(d2) a = 1/d2 - 10/d2/d ax = a * dx / d ay = a * dy / d b1.vx = b1.vx + ax*dt b1.vy = b1.vy + ay*dt b2.vx = b2.vx - ax*dt b2.vy = b2.vy - ay*dt def slow(self): # ax = - resist * self.vx # ay = - resist * self.vy r = pow(1-resist, dt) self.vx = self.vx * r self.vy = self.vy * r def move(self): if not self.dragging: if (self.x*self.x + self.y*self.y > max_radius*max_radius): self.remove() else: self.x = self.x + self.vx*dt self.y = self.y + self.vy*dt x, y = rtoc(self.x, self.y) self.item.coords([(x-5, y-5), (x+5, y+5)]) def drag_start(self, event): if self == focus: return ex,ey = ctor(event.x, event.y) Drag.dx = self.x - ex Drag.dy = self.y - ey self.dragging = 1 def drag(self, event): if self == focus: return ex,ey = ctor(event.x, event.y) self.x = ex + Drag.dx self.y = ey + Drag.dy x, y = rtoc(self.x, self.y) self.item.coords([(x-5, y-5), (x+5, y+5)]) def drag_stop(self, event): if self == focus: return self.dragging = 0 self.vx = 0 self.vy = 0 # if focus == "cog": # focus_cog() def remove(self, event=None): global bodies canvas.delete(self.item) self.item = None # signal to main loop to remove this body def create(event): ex,ey = ctor(event.x, event.y) id = canvas.find_withtag("current") if not id: bodies.append(Body(ex, ey)) # if focus == "cog": # focus_cog() def center(event): global focus ex,ey = ctor(event.x, event.y) id = canvas.find_withtag("current") if id: focus = Body.by_id["%s" % id] # we follow this body else: if focus == "cog": focus = None else: focus = "cog" # focus_cog() def focus_cog(): n = len(bodies) if n == 0: return # center the system av_x = av_y = av_vx = av_vy = 0 for body in bodies: av_x = av_x + body.x av_y = av_y + body.y av_vx = av_vx + body.vx av_vy = av_vy + body.vy av_x = av_x / n av_y = av_y / n av_vx = av_vx / n av_vy = av_vy / n for body in bodies: body.x = body.x - av_x body.y = body.y - av_y body.vx = body.vx - av_vx body.vy = body.vy - av_vy def get_width_height(event): global width, height width = canvas.winfo_width() height = canvas.winfo_height() tk = Tk() frame = Frame(tk) width = height = 300 scale_dt = Scale(frame, showvalue=N) scale_dt['from'] = 8 scale_dt['to'] = -8 scale_dt['resolution'] = 0.0001 scale_dt.pack(side=LEFT, fill=Y, expand=N) scale_dt.set(0) canvas = Canvas(frame, width=width, height=height, background="blue") canvas.pack(side=LEFT, fill=BOTH, expand=Y) canvas.bind("", get_width_height) scale_zoom = Scale(frame, showvalue=N) scale_zoom['from'] = 2 scale_zoom['to'] = -2 scale_zoom['resolution'] = 0.0001 scale_zoom.pack(side=RIGHT, fill=Y, expand=N) scale_zoom.set(0) scale_resist = Scale(frame, showvalue=N) scale_resist['from'] = -6 scale_resist['to'] = 0 scale_resist['resolution'] = 0.0001 scale_resist.pack(side=RIGHT, fill=Y, expand=N) scale_resist.set(-3) frame.pack(fill=BOTH, expand=Y) n = 0 bodies = [] for i in range(0, n): bodies.append(Body(uniform(-width/2,width/2), uniform(-height/2,height/2))) canvas.bind("<1>", create) canvas.bind("<2>", center) xc = yc = 0 focus = None #bounds = Oval(canvas, 0, 0, 0, 0) #bounds.lower("all") while 1: resist = pow(10, scale_resist.get()) zoom = pow(10, scale_zoom.get()) dt = scale_dt.get() # dt = pow(10, abs(dt)-2) # if dt < 0 tk.update() bodies = filter(lambda(body): body.item != None, bodies) if focus == "cog": focus_cog() # bounds.coords([rtoc(-max_radius, -max_radius), rtoc(max_radius, max_radius)]) if focus and focus != "cog": xc = focus.x yc = focus.y else: xc = yc = 0 for i in range(0, len(bodies)): for j in range(i+1, len(bodies)): Body.force(bodies[i], bodies[j]) bodies[i].move() bodies[i].slow()