• 仿真鸟群-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

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

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

     

    源代码

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

    源代码如下:

    1. """
    2. boids.py
    3. Implementation of Craig Reynold's BOIDs
    4. Author: Mahesh Venkitachalam
    5. """
    6. import sys, argparse
    7. import math
    8. import numpy as np
    9. import matplotlib.pyplot as plt
    10. import matplotlib.animation as animation
    11. from scipy.spatial.distance import squareform, pdist, cdist
    12. from numpy.linalg import norm
    13. width, height = 640, 480
    14. class Boids:
    15.     """Class that represents Boids simulation"""
    16.     def __init__(self, N):
    17.         """ initialize the Boid simulation"""
    18.         # init position & velocities
    19.         self.pos = [width/2.0, height/2.0] + 10*np.random.rand(2*N).reshape(N, 2)
    20.         # normalized random velocities
    21.         angles = 2*math.pi*np.random.rand(N)
    22.         self.vel = np.array(list(zip(np.sin(angles), np.cos(angles))))
    23.         self.N = N
    24.         # min dist of approach
    25.         self.minDist = 25.0
    26.         # max magnitude of velocities calculated by "rules"
    27.         self.maxRuleVel = 0.03
    28.         # max maginitude of final velocity
    29.         self.maxVel = 2.0
    30.     def tick(self, frameNum, pts, beak):
    31.         """Update the simulation by one time step."""
    32.         # get pairwise distances
    33.         self.distMatrix = squareform(pdist(self.pos))
    34.         # apply rules:
    35.         self.vel += self.applyRules()
    36.         self.limit(self.vel, self.maxVel)
    37.         self.pos += self.vel
    38.         self.applyBC()
    39.         # update data
    40.         pts.set_data(self.pos.reshape(2*self.N)[::2],
    41.                      self.pos.reshape(2*self.N)[1::2])
    42.         vec = self.pos + 10*self.vel/self.maxVel
    43.         beak.set_data(vec.reshape(2*self.N)[::2],
    44.                       vec.reshape(2*self.N)[1::2])
    45.     def limitVec(self, vec, maxVal):
    46.         """limit magnitide of 2D vector"""
    47.         mag = norm(vec)
    48.         if mag > maxVal:
    49.             vec[0], vec[1] = vec[0]*maxVal/mag, vec[1]*maxVal/mag
    50.     
    51.     def limit(self, X, maxVal):
    52.         """limit magnitide of 2D vectors in array X to maxValue"""
    53.         for vec in X:
    54.             self.limitVec(vec, maxVal)
    55.             
    56.     def applyBC(self):
    57.         """apply boundary conditions"""
    58.         deltaR = 2.0
    59.         for coord in self.pos:
    60.             if coord[0] > width + deltaR:
    61.                 coord[0] = - deltaR
    62.             if coord[0] < - deltaR:
    63.                 coord[0] = width + deltaR    
    64.             if coord[1] > height + deltaR:
    65.                 coord[1] = - deltaR
    66.             if coord[1] < - deltaR:
    67.                 coord[1] = height + deltaR
    68.     
    69.     def applyRules(self):
    70.         # apply rule #1 - Separation
    71.         D = self.distMatrix < 25.0
    72.         vel = self.pos*D.sum(axis=1).reshape(self.N, 1) - D.dot(self.pos)
    73.         self.limit(vel, self.maxRuleVel)
    74.         # different distance threshold
    75.         D = self.distMatrix < 50.0
    76.         # apply rule #2 - Alignment
    77.         vel2 = D.dot(self.vel)
    78.         self.limit(vel2, self.maxRuleVel)
    79.         vel += vel2;
    80.         # apply rule #1 - Cohesion
    81.         vel3 = D.dot(self.pos) - self.pos
    82.         self.limit(vel3, self.maxRuleVel)
    83.         vel += vel3
    84.         return vel
    85.     def buttonPress(self, event):
    86.         """event handler for matplotlib button presses"""
    87.         # left click - add a boid
    88.         if event.button is 1:
    89.             self.pos = np.concatenate((self.pos,
    90.                                        np.array([[event.xdata, event.ydata]])),
    91.                                       axis=0)
    92.             # random velocity
    93.             angles = 2*math.pi*np.random.rand(1)
    94.             v = np.array(list(zip(np.sin(angles), np.cos(angles))))
    95.             self.vel = np.concatenate((self.vel, v), axis=0)
    96.             self.N += 1
    97.         # right click - scatter
    98.         elif event.button is 3:
    99.             # add scattering velocity
    100.             self.vel += 0.1*(self.pos - np.array([[event.xdata, event.ydata]]))
    101.         
    102. def tick(frameNum, pts, beak, boids):
    103.     #print frameNum
    104.     """update function for animation"""
    105.     boids.tick(frameNum, pts, beak)
    106.     return pts, beak
    107. # main() function
    108. def main():
    109.   # use sys.argv if needed
    110.   print('starting boids...')
    111.   parser = argparse.ArgumentParser(description="Implementing Craig Reynold's Boids...")
    112.   # add arguments
    113.   parser.add_argument('--num-boids', dest='N', required=False)
    114.   args = parser.parse_args()
    115.   # number of boids
    116.   N = 100
    117.   if args.N:
    118.       N = int(args.N)
    119.   # create boids
    120.   boids = Boids(N)
    121.   # setup plot
    122.   fig = plt.figure()
    123.   ax = plt.axes(xlim=(0, width), ylim=(0, height))
    124.   pts, = ax.plot([], [], markersize=10,
    125.                   c='k', marker='o', ls='None')
    126.   beak, = ax.plot([], [], markersize=4,
    127.                   c='r', marker='o', ls='None')
    128.   anim = animation.FuncAnimation(fig, tick, fargs=(pts, beak, boids),
    129.                                  interval=50)
    130.   # add a "button press" event handler
    131.   cid = fig.canvas.mpl_connect('button_press_event', boids.buttonPress)
    132.   plt.show()
    133. # call main
    134. if __name__ == '__main__':
    135.   main()

    运行结果

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

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

     

     

     

  • 相关阅读:
    【Arduino环境下驱动合宙esp32c3单片机基本外设】
    GCC优化
    MySQL数据库期末考试试题及参考答案(05)
    oculus quest2手势交互
    CF120F Spiders
    【回归预测-FNN预测】基于粒子群优化前馈网络实现对婚姻和离婚数据回归预测附matlab代码
    Pytorch面试题面经
    react useState基本使用
    剑指 Offer II 018. 有效的回文
    代码随想录一刷打卡——.二叉树的层次遍历(十题特别版)
  • 原文地址:https://blog.csdn.net/Alexabc3000/article/details/126512405