• 仿真鸟群-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”,运行结果如下:

     

     

     

  • 相关阅读:
    内网渗透学习 day1
    米哈游、复旦发布,具备感知、大脑、行动的大语言模型“智能体”
    java基础语法,,220811,,
    EWSD交换机加电过程
    “非旺玖原装的PL2303,......“解决办法
    c++day3
    AWS考试认证学习
    Python可视化应用实战案例30篇(一)-基础绘图命令详解含大量示例代码(附Python代码)
    在人物第一次死亡后会退出第一个循环,图片却一直卡在人物死亡的画面不动而不是重新开始(标签-游戏)
    JAVA基础算法(8)----- 设计循环双端队列
  • 原文地址:https://blog.csdn.net/Alexabc3000/article/details/126512405