仿真鸟群-Python实现(Win11)

参考书籍《Python极客项目编程》。

运行环境

操作系统Win11。

Python 3.10.5 。

电脑连接互联网。

安装相关包

在命令行窗口使用pip命令(我的电脑上,”pip.exe”文件所在目录是”D:\Programs\Python\Python310\Scripts”)安装numpy、matplotlib、scipy 等相关包,命令如下:

pip install numpy

pip install matplotlib

pip install scipy

并根据提示使用如下命令升级:

D:\Programs\Python\Python310\python.exe -m pip install –upgrade pip

仿真鸟群-Python实现(Win11)

安装包相关信息的查看(以numpy为例)

启动python,进入python提示符,依次键入import numpy、print(numpy)、dir(numpy);或者help()、numpy ,显示该模块的相关信息。(help(numpy)也可以)。

仿真鸟群-Python实现(Win11)

仿真鸟群-Python实现(Win11)

源代码

源代码网址: pp/boids.py at master · electronut/pp · GitHub

源代码如下:

"""

boids.py

Implementation of Craig Reynold's BOIDs

Author: Mahesh Venkitachalam

"""

import sys, argparse

import math

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):

        """ initialize the Boid simulation"""

        # init position & 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

        # min dist of approach

        self.minDist = 25.0

        # max magnitude of velocities calculated by "rules"

        self.maxRuleVel = 0.03

        # max maginitude of 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.set_data(self.pos.reshape(2*self.N)[::2],

                     self.pos.reshape(2*self.N)[1::2])

        vec = self.pos + 10*self.vel/self.maxVel

        beak.set_data(vec.reshape(2*self.N)[::2],

                      vec.reshape(2*self.N)[1::2])

    def limitVec(self, vec, maxVal):

        """limit magnitide of 2D 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 magnitide of 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] < - 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)

        # different distance threshold

        D = self.distMatrix < 50.0

        # apply rule #2 - Alignment

        vel2 = D.dot(self.vel)

        self.limit(vel2, self.maxRuleVel)

        vel += vel2;

        # apply rule #1 - 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 - add a boid

        if event.button is 1:

            self.pos = np.concatenate((self.pos,

                                       np.array([[event.xdata, event.ydata]])),

                                      axis=0)

            # 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 - scatter

        elif event.button 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():

  # 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()

  # number of boids

  N = 100

  if args.N:

      N = int(args.N)

  # create boids

  boids = Boids(N)

  # setup 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()

运行结果

将上述代码保存为文件”d:\temp\boids.py”。

在命令行窗口执行命令 “python d:\temp\boids.py”,运行结果如下:

仿真鸟群-Python实现(Win11)

Original: https://blog.csdn.net/Alexabc3000/article/details/126512405
Author: Alexabc3000
Title: 仿真鸟群-Python实现(Win11)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/764413/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球