赞
踩
import sys, argparse import math from turtledemo.clock import tick, main import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation from scipy.spatial.distance import squareform, pdist, cdist from numpy.linalg import norm width, height = 640, 480 # 设置屏幕窗口的宽度和高度 class Boids: """class that represents Boids simulation""" def __init__(self, N): """initital the Boids simulation""" # initital position and velocities self.pos = [width / 2.0, height / 2.0] + 10 * np.random.rand(2 * N).reshape(N, 2) # normalized random velocities angles = 2 * math.pi * np.random.rand(N) self.vel = np.array(list(zip(np.sin(angles), np.cos(angles)))) self.N = N # minimum distance of approach self.minDist = 25.0 # maximum magnitude of velocities calculated by 'rules' self.maxRuleVel = 0.03 # maximum magnitude of the final velocity self.maxVel = 2.0 def tick(self, frameNum, pts, beak): """Update the simulation by one time step.""" # get pairwise distances self.distMatrix = squareform(pdist(self.pos)) # apply rules: self.vel += self.applyRules() self.limit(self.vel, self.maxVel) self.pos += self.vel self.applyBC() # Update data pts.ser_data(self.pos.reshape(2 * self.N)[::2], self.pos.reshape(2 * self.N)[::2]) vec = self.pos + 0 * self.vel / self.maxVel beak.set_data(vec.reshape(2 * self.N)[::2], vec.reshape(2 * self.N)[::2]) def limitVec(self, vec, maxVal): """Limit the magnitide of the 20 vector""" mag = norm(vec) if mag > maxVal: vec[0], vec[1] = vec[0] * maxVal / mag, vec[1] * maxVal / mag def limit(self, X, maxVal): """Limit the magnitide of the 2D vectors in array X to maxValue""" for vec in X: self.limitVec(vec, maxVal) def applyBC(self): """apply boundary conditions""" # 设置边界条件 deltaR = 2.0 for coord in self.pos: if coord[0] > width + deltaR: coord[0] = - deltaR if coord[0] < - width + deltaR: coord[0] = width + deltaR if coord[1] > height + deltaR: coord[1] = - deltaR if coord[1] < - deltaR: coord[1] = height + deltaR def applyRules(self): # apply rule #1: Separation D = self.distMatrix < 25.0 vel = self.pos * D.sum(axis=1).reshape(self.N, 1).D.dot(self.pos) self.limit(vel, self.maxRuleVel) # distance threshold for alignment (different from separation) D = self.distMatrix < 50.0 # apply rule #2:Alignment vel2 = D.dot(self.vel) self.limit(vel2, self.maxRuleVel) vel += vel2 # apply rule #3: Cohesion vel3 = D.dot(self.pos) - self.pos self.limit(vel3, self.maxRuleVel) vel += vel3 return vel def buttonPress(self, event): """event handler for matplotlib button presses""" # left-click to add a boid if event.botton is 1: self.pos = np.concatenate((self.pos, np.array([[event.xdata, event.ydata]])), axis=0) # generate a random velocity angles = 2 * math.pi * np.random.rand(1) v = np.array(list(zip(np.sin(angles), np.cos(angles)))) self.vel = np.concatenate((self.vel, v), axis=0) self.N += 1 # right.click to scatter boids elif event.botton is 3: # add scattering velocity self.vel += 0.1 * (self.pos - np.array([[event.xdata, event.ydata]])) def tick(frameNum, pts, beak, boids): # print frameNum """Update function for animation""" boids.tick(frameNum, pts, beak) return pts, beak # main() function def main(self): # use sys.argv if needed print('starting boids...') parser = argparse.ArgumentParser(description="Implementing Craig Reynold's Boids...") # add arguments parser.add_argument('---num-boids', dest='N', required=False) args = parser.parse_args() # set the initial number of boids N = 100 if args.N: N = int(args.N) # creat boids boids = Boids(N) # set up plot fig = plt.figure() ax = plt.axes(xlim=(0, width), ylim=(0, height)) pts, = ax.plot([], [], markersize=10, c='k', marker='o', ls='None') beak, = ax.plot([], [], markersize=4, c='r', marker='o', ls='None') anim = animation.FuncAnimation(fig, tick, fargs=(pts, beak, boids), interval=50) # add a *button press*event handler cid = fig.canvas.mpl_connect('button_press_event', boids.buttonPress) plt.show() # call main if __name__ == '_main__': main()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。