import sys import math import random from qt import * from qtcanvas import * class Person( QCanvasEllipse ): def __init__( self, canvas, x, y, color, scale ): QCanvasEllipse.__init__( self, canvas ) self.setBrush( QBrush( QColor( color.strip() ) ) ) # strip off newline self.size = 5 self.setSize( self.size, self.size ) self.setX( x ) self.setY( y ) self.scale = scale # the (length-)scale is the size of the room self.ideal = {} self.eps = 1.0 self.dt = 500 def setIdealDistance( self, other, val ): self.ideal[ other ] = val def mingle( self, people ): u0 = self.unhappiness( people, self.x(), self.y() ) ux = self.unhappiness( people, self.x() + self.eps, self.y() ) - u0 uy = self.unhappiness( people, self.x(), self.y() + self.eps ) - u0 ux /= -self.eps uy /= -self.eps self.dx = self.dt * ux self.dy = self.dt * uy def doStep( self ): x = self.x() + self.dx + 2*(random.random() - 0.5) y = self.y() + self.dy + 2*(random.random() - 0.5) # Restrict guests to the interior of the room... if( x < self.size ): x = self.size if( x > self.scale-self.size ) : x = self.scale - self.size if( y < self.size ): y = self.size if( y > self.scale-self.size ) : y = self.scale - self.size # self.leaveTrace( x, y ) self.move( x, y ) def leaveTrace( self, x, y ): tr = QCanvasLine( self.canvas() ) tr.setPoints( self.x(), self.y(), x, y ) tr.setPen( QPen( self.brush().color() ) ) tr.show() def unhappiness( self, people, x, y ): u = 0 for q in people: if( self == q ): continue # no self-interaction d = math.hypot( x - q.x(), y - q.y() ) # distance to person q u += self.fct( d - self.ideal[q] ) return u def fct( self, d ): s = d/self.scale; return 1 - 1.0/(1 + s*s) # Alternatively: # t = math.tanh( 5.0*s ) # return t*t class App( QApplication ): def __init__( self, args ): QApplication.__init__( self, args ) self.size = 400 # System size self.edge = 5 # Guests cannot come closer than this to the walls self.mw = QHBox() self.mw.setFixedWidth( self.size + self.edge ) self.mw.setFixedHeight( self.size + self.edge ) self.setMainWidget( self.mw ) # closing window terminates program self.canvas = QCanvas( self.size, self.size ) self.view = QCanvasView( self.canvas, self.mw ) self.initPeople() self.timer = QTimer( self ) # Update the system every 100 milliseconds self.timer.start( 100 ) QObject.connect( self.timer, SIGNAL( "timeout()" ), self.redraw ) self.mw.show() def redraw( self ): # First, find everyone's unhappiness based on the old positions... for p in self.people: p.mingle( self.people ) # ... then move everyone to their new posisitons for p in self.people: p.doStep() p.show() self.canvas.update() def initPeople( self ): self.people = [] matrix = [] for line in ( sys.stdin.readlines() ): fields = line.split( "\t" ) color = fields.pop() # remove the last entry from the line matrix.append( map( float, fields ) ) # transform input to numbers x = random.randrange( self.size ) # select initial position y = random.randrange( self.size ) self.people.append( Person( self.canvas, x, y, color, self.size ) ) # Let people know about their interactions with others: for i in xrange( len( self.people ) ): for j in xrange( len( self.people ) ): self.people[i].setIdealDistance(self.people[j], matrix[i][j]); app = App( sys.argv ) app.exec_loop()