仿真鸟群-Python实现(Win11)

本文档展示了如何使用 Python 和相关库(numpy, matplotlib, scipy)实现 Craig Reynolds 的 Boids 模型,这是一个模拟鸟群行为的算法。首先介绍了所需的运行环境和安装包的步骤,然后提供了源代码,包括 Boids 类的定义和相关规则的实现。代码运行后,会在图形界面上展示鸟群的动态行为,用户还可以通过点击事件添加或改变鸟的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考书籍《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

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

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

 

源代码

源代码网址: 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”,运行结果如下:

 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alexabc3000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值