from visual import * from random import * from visual.controls import * import sys c=[] people=[] xrange=20 clabel=label(visible=0,text='',color=color.red,font='sansserif',align='center',opacity=0.1,linecolor=color.black,pos=(0,0,0)) def getheight(a): h=1.2*(a.height+2*a.border)*(2*xrange)/(scene.height) return h def getwidth(a): # How many characters long? Assume all of them have a 1:2.5 ratio w=1.2*(a.height*0.45*len(a.text)+2*a.border)*(2*xrange)/(scene.width) return w def personmass(p,m): if (m > 3): m=3 if (m < 1): m=1 p.m=m if (m <= 1): p.height=9 p.color=(0.5,0.5,1) if (m == 2): p.height=13 p.color=(0.3,0.3,1) if (m == 3): p.height=16 p.color=(0,0,1) p.w=getwidth(p) p.h=getheight(p) def person(newname,xpos=-100,ypos=-100,m=1): if ((xpos < -2*xrange) and (ypos < -2*xrange)): xpos=2*0.9*xrange*random()-xrange*0.9 ypos=2*0.9*xrange*random()-xrange*0.9 a=label(text=newname,color=color.blue,font='sansserif',align='center',opacity=0.1,linecolor=color.black,pos=(xpos,ypos,0)) a.p=vector(0,0,0) a.m=m personmass(a,m) a.connections=[] a.F=vector(0,0,0) a.w=getwidth(a) a.h=getheight(a) return a def findperson(pos,dmax=2): # Returns the index of the nearest person to a location, if the minimum distance is less # than dmax n=len(people) ifound=-1 for i in range(n): if (mag(pos-people[i].pos) < dmax): ifound=i return ifound def cupdate(con): p1=people[con.person1] p2=people[con.person2] pos1=p1.pos pos2=p2.pos pos1=p1.pos-norm(p1.pos-p2.pos) pos2=p2.pos-norm(p2.pos-p1.pos) con.pos[0]=pos1 con.pos[1]=pos2 con.pos1=(pos1+pos2)/2. return def connection(i1,i2,relation='??',strength=1): c1=curve(pos=[vector(0,0,0),vector(1,0,0)],color=(0.3,0.3,0.0),radius=0.03*strength) c1.pos1=(c1.pos[0]+c1.pos[1])/2. c1.person1=i1 c1.person2=i2 c1.strength=strength people[i1].connections.append(c1) people[i2].connections.append(c1) cupdate(c1) c1.description=relation; return c1 def findconnection(pos,dmax=2): # Returns the index of the nearest connection to a location, if # the minimum distance is less than dmax n=len(c) ifound=-1 for i in range(n): if (mag(pos-c[i].pos1) < dmax): ifound=i return ifound ############################################# scene.range=xrange scene.autoscale=0 scene.width=800 scene.height=800 scene.background=color.white tmpcurve=curve(pos=[(-2,0,0),(2,0,0)],color=color.black,visible=0) ism=0 # Done header #Initialize data iter=0 if (len(sys.argv) > 1): file=sys.argv[1] infile=open(file,"r") while infile: line=infile.readline() n=len(line) #print n if (n <= 2): iter=iter+1 if (iter == 2): break elif (iter == 0): name=line.rstrip() line=infile.readline() xpos=line.split()[0] ypos=line.split()[1] m=line.split()[2].rstrip() people.append(person(str(name),float(xpos),float(ypos),int(m))) elif (iter == 1): i1=int(line.split()[0]) i2=int(line.split()[1]) weight=int(line.split()[2]) line=infile.readline() c.append(connection(i1,i2,relation=str(line.rstrip()),strength=weight)) # Let's assume that everything is set up. We now run pfound=-1 cfound=-1 dt=0.1 id=0 pmove=-1 while (1): rate(10) # Let's do the dynamics for all of the people for i in range(len(people)): # Initialize by pulling everyone toward the center, and apply a small friction force people[i].F=-0.2*people[i].pos-2.*people[i].p/people[i].m for i in range(len(people)): for j in range (i,len(people)): # put in a basic force of repulsion. Relatively weak if (i != j): F12=200/sqrt(len(people))*(people[i].pos-people[j].pos)/pow(mag(people[i].pos-people[j].pos)+1,3) people[i].F=people[i].F+F12/2. people[j].F=people[j].F-F12/2. for k in range(len(c)): # All springs have constant 1 and length 2 for now p1=people[c[k].person1] p2=people[c[k].person2] l=mag(p1.pos-p2.pos) if (c[k].strength == 1): s0=1 k=0.1 elif (c[k].strength == 2): s0=1 k=1 elif (c[k].strength == 3): s0=1 k=2 F1=-k*(l-s0)*norm(p1.pos-p2.pos) p1.F=p1.F+F1 p2.F=p2.F-F1 # Finally, update the positions for i in range(len(people)): people[i].pos=people[i].pos+people[i].p*dt/people[i].m # Check for collisions or overlaps for i in range(len(people)): for j in range(i,len(people)): if (i != j): if (abs(people[i].pos.x-people[j].pos.x) < 3*(people[i].w+people[j].w)/2.) and (abs(people[i].pos.y-people[j].pos.y) < 3*(people[i].h+people[j].h)/2.): # We have an overlap, or will soon u=abs((people[i].pos.x-people[j].pos.x)/((people[i].w+people[j].w)/2.)) F=3*exp(-pow(u,6)) sgn=(people[i].pos.x-people[j].pos.x)/abs(people[i].pos.x-people[j].pos.x) people[i].p.x=people[i].p.x+F*sgn*dt people[j].p.x=people[j].p.x-F*sgn*dt # Now do the y-direction u=abs((people[i].pos.y-people[j].pos.y)/((people[i].h+people[j].h)/2.)) F=10*exp(-pow(u,6)) sgn=(people[i].pos.y-people[j].pos.y)/abs(people[i].pos.y-people[j].pos.y) people[i].p.y=people[i].p.y+F*sgn*dt people[j].p.y=people[j].p.y-F*sgn*dt for i in range(len(people)): people[i].p=people[i].p+people[i].F*dt # And update the connections for k in range(len(c)): cupdate(c[k]) # Update the temporary curve if (tmpcurve.visible == 1): tmpcurve.pos[1]=scene.mouse.pos if (pmove >= 0): people[pmove].pos=scene.mouse.pos if scene.kb.keys: # event waiting to be processed? s = scene.kb.getkey() # get keyboard info if (s == 'q'): # quit scene.visible=0 if (s == 'p'): # Print out current status for i in range(len(people)): print people[i].text print people[i].pos.x,people[i].pos.y,people[i].m print ' ' for i in range(len(c)): print c[i].person1,c[i].person2,c[i].strength,'#',people[c[i].person1].text,people[c[i].person2].text print c[i].description print ' ' if (s == '+'): # add a new person loc=scene.mouse.pos dum=0 people.append(person("|",loc.x,loc.y,1)) n=len(people) fscale=1 f=people[n-1] f.color=(0.5,0.5,0.5) while (dum == 0): r = scene.kb.getkey() if (r == '\n'): personmass(f,f.m) dum=1 t=f.text f.text=t[0:len(t)-1] f.h=getheight(f) f.w=getwidth(f) elif (r == '\t'): dum=1 people[len(people)-1].visible=0 people.pop() elif (r == 'backspace'): t=f.text f.text=t[0:len(t)-2]+'|' else: t=f.text f.text=t[0:len(t)-1]+r+'|' if (s == '-'): # Delete something. For now, only connections i=findconnection(scene.mouse.pos) if (i >=0): p1=people[c[i].person1] p2=people[c[i].person2] isdone=0 for j in range(len(p1.connections)): if (isdone == 0): if (p1.connections[j] == c[i]): p1.connections[j]=p1.connections[len(p1.connections)-1] p1.connections.pop() isdone=1 isdone=0 for j in range(len(p2.connections)): if (isdone == 0): if (p2.connections[j] == c[i]): p2.connections[j]=p2.connections[len(p2.connections)-1] p2.connections.pop() isdone=1 c[i].visible=0 n=len(c) c[i]=c[n-1] c.pop() if (s == 'right'): i=findperson(scene.mouse.pos) if (i >= 0): personmass(people[i],people[i].m+1) i=findconnection(scene.mouse.pos) if (i >= 0): scur=c[i].strength if (scur < 3): c[i].strength=scur+1 c[i].radius=0.03*(scur+1) if (s == 'left'): i=findperson(scene.mouse.pos) if (i >= 0): personmass(people[i],people[i].m-1) i=findconnection(scene.mouse.pos) if (i >= 0): scur=c[i].strength if (scur > 1): c[i].strength=scur-1 c[i].radius=0.03*(scur-1) if (s == 'm'): ism=1 if scene.mouse.events: m1 = scene.mouse.getevent() if (m1.press): pfound=findperson(m1.pos) cfound=findconnection(m1.pos) if (ism == 1): pmove=pfound print people[pfound].text else: if (pfound >= 0): # Then we've found an existing person tmpcurve.pos[0]=m1.pos tmpcurve.pos[1]=m1.pos tmpcurve.visible=1 id=1 if (m1.release): if (pmove >= 0): pmove=-1 ism=0 else: id=0 tmpcurve.visible=0 if (pfound >= 0): pfound1=findperson(scene.mouse.pos,4) if ((pfound1 >= 0) and (pfound1 != pfound)): # Create a new connector # First, check to see if there is a connection n=len(people[pfound].connections) isconnected=0 for j in range(n): if ((people[pfound].connections[j].person1 == pfound1) or (people[pfound].connections[j].person2 == pfound1)): isconnected=1 if (isconnected == 0): c.append(connection(pfound,pfound1)) elif (pfound1 == pfound): f=people[pfound] f.color=(0.5,0.5,0.5) f.text=f.text+'|' dum=0 while (dum == 0): r=scene.kb.getkey() if (r == '\n'): personmass(f,f.m) dum=1 t=f.text f.text=t[0:len(t)-1] elif (r == 'backspace'): t=f.text f.text=t[0:len(t)-2]+'|' else: t=f.text f.text=t[0:len(t)-1]+r+'|' if (cfound >= 0): cfound1=findconnection(scene.mouse.pos,4) if (cfound == cfound1): #print "display information about connection" clabel.pos=c[cfound].pos1 clabel.text=c[cfound].description+'|' clabel.visible=1 # now allow us to edit it dum=0 while (dum == 0): r=scene.kb.getkey() if (r == '\n'): t=clabel.text c[cfound].description=t[0:len(t)-1] dum=1 clabel.visible=0 elif (r == 'backspace'): t=clabel.text clabel.text=t[0:len(t)-2]+'|' else: t=clabel.text clabel.text=t[0:len(t)-1]+r+'|' pfound=-1 cfound=-1