123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- import matplotlib.pyplot as plt
- import pygame
- import pygame.draw as draw
- import math
- from time import sleep
- pygame.init() # 初始化
- display = pygame.display
- screen = display.set_mode((640, 480), 0, 32)
- display.set_caption("物理: 弹簧实验")
- fontObj = pygame.font.Font('ZKST.ttf', 48) # 通过字体文件获得字体对象
- fontObj2 = pygame.font.Font('ZKST.ttf', 20) # 通过字体文件获得字体对象
- text_M = fontObj.render('M', True, (100, 255, 255)) # 配置要显示的文字
- v_list = [] # v-t图像的v
- t_list = [] # v-t图像和s-t图像的t
- s_list = [] # s-t图像的s
- dh_list = [] # dh-t图像的dh
- a_list = [] # a-t图像的a
- g = 9.8 # 重力加速度
- k = 0.4 # 弹簧劲度系数
- v = 0 # 物体速度
- m = 1 # 物体质量
- F = 0 # 物体受力
- h = 0 # 物体距离原来高度位置(弹簧伸缩量)
- gh = 8 # 距离弹簧对高度
- times = 0
- get_g = lambda m: g * m # 获取重力(重力方向为正方向)
- get_n = lambda h: 0 if h < gh else k * (h - gh) # 计算弹力
- get_f = lambda f1, f2: f1 + f2 # 计算力
- get_a = lambda f, m: f / m # 计算加速度
- get_v = lambda v, a, t: v + a * t # 计算速度
- get_s = lambda v, a, t: v * t + 0.5 * a * t ** 2 # 计算位移
- to_ypos = lambda y: int((y / 100) * 470 + 30) # 100是虚拟环境的高度,470是画布高度, 10是向下偏移
- time = 0.001
- now_draw = 0
- def sin(): # get sin
- a = 0
- for i in range(100):
- yield math.sin(a), a
- a += 1
- def draw_font(x, y, text, screen):
- tmp_text = fontObj2.render(text, True, (0, 0, 0)) # 配置要显示的文字
- tmp = tmp_text.get_rect() # 获得要显示的对象的rect
- tmp.center = (x, y) # 设置显示对象的坐标
- screen.blit(tmp_text, tmp) # 绘制字体
- def draw_(screen, display, h, v, a, n, mg, f, time): # 绘制受力分析图
- mh = 50
- mw = 60
- # 清空
- screen.fill((255, 255, 255))
- pygame.draw.line(screen, (0, 0, 0), (0, to_ypos(0)), (640, to_ypos(0)), 2) # 绘制最高线h
- pygame.draw.line(screen, (0, 0, 0), (0, to_ypos(h)), (640, to_ypos(h)), 1) # 绘制物体高度线:h
- draw_font(590, to_ypos(h) + 12, f'h = {h:4.2f}m', screen)
- draw_font(640 // 2, to_ypos(h) - 12, f'v = {v:4.2f}m/s, a = {a:4.2f}m/s^2', screen)
- pygame.draw.rect(screen, (0, 0, 0), (int(640 / 2 - mw / 2), to_ypos(h), mw, mh), 0)
- tmp = text_M.get_rect() # 获得要显示的对象的rect
- tmp.center = (640 // 2, to_ypos(h) + mh // 2) # 设置显示对象的坐标
- screen.blit(text_M, tmp) # 绘制字体
- if h > gh:
- max_h = h
- else:
- max_h = gh
- point_list = []
- for i in sin():
- x = int(i[0] / 2 * mw / 2 + (640 / 2 - 10) + mw / 8) # 换算, + mw / 8是让弹簧居中
- y = int(i[1] / 100 * (400 - to_ypos(max_h) - mh) + to_ypos(max_h) + mh) # 换算
- point_list.append((x, y))
- pygame.draw.lines(screen, (min(max_h / 60 * 255, 255), 0, 0), False, point_list, 2) # 绘制最高线h
- x = 60
- base_y = 270
- pygame.draw.circle(screen, (0, 0, 255), (x, base_y), 5)
- y = int(base_y + (mg / 20 * 150))
- pygame.draw.line(screen, (0, 0, 0), (x, base_y), (x, y), 3) # 绘制mg
- pygame.draw.lines(screen, (0, 0, 0), False, [(x - 5, y - 5), (x, y), (x + 5, y - 5)], 3)
- draw_font(x, y + 12, f'mg = {mg:4.2f}N', screen)
- if n < 0:
- y = int(base_y + (n / 20 * 150))
- pygame.draw.line(screen, (0, 0, 0), (x, base_y), (x, y), 3) # 绘制n
- pygame.draw.lines(screen, (0, 0, 0), False, [(x - 5, y + 5), (x, y), (x + 5, y + 5)], 3)
- draw_font(x, y - 12, f'N = {-n:4.2f}N', screen)
- else:
- draw_font(x, base_y - 12, f'N = 0N', screen)
- y = int(base_y + (f / 20 * 150))
- pygame.draw.line(screen, (250, 0, 0), (x, base_y), (x, base_y + int(f / 20 * 150)), 3) # 绘制最高线h
- pygame.draw.lines(screen, (0, 0, 0), False, [(x - 5, (y + 5) if f < 0 else (y - 5)), (x, y),
- (x + 5, (y + 5) if f < 0 else (y - 5))], 3)
- draw_font(x + x, y - 5, f'F = {f:4.2f}N', screen)
- draw_font(320, 440 - 12, f'time = {time:4.2f}s, g = {g}m/s^2, m(M) = {m}kg, k = {k}', screen)
- draw_font(320, 460 - 12, f'power by SuperHuan (https://www.songzh.website)', screen)
- display.update()
- # pygame.draw.rect(screen, (0, 0, 0), (5, a, 50, 50), 0)
- def is_quit():
- for event in pygame.event.get():
- if event.type == pygame.QUIT:
- return False
- elif event.type == pygame.KEYDOWN and event.key == pygame.K_g:
- get_new()
- return True
- def get_new(): # 获取新的数据
- try:
- type = int(input('''1)重力加速度g
- 2)劲度系数k
- 3)M的质量
- Please Enter The Number: '''))
- n = int(input("Please Enter The New Value: "))
- except ValueError:
- return False
- if type == 1:
- global g
- g = n
- elif type == 2:
- global k
- k = n
- elif type == 3:
- global m
- m = n
- return True
- if __name__ == "__main__":
- try:
- while is_quit():
- the_g = get_g(m)
- the_n = -get_n(h) # 重力方向为正方向
- the_f = get_f(the_n, the_g)
- the_a = get_a(the_f, m) # 获取当前的加速度
- times += time
- dh = get_s(v, the_a, time) # 计算位移增量
- new_v = get_v(v, the_a, time)
- if now_draw == 30:
- draw_(screen, display, h, v, the_a, the_n, the_g, the_f, times)
- now_draw = 0
- else:
- sleep(time)
- now_draw += 1
- v_list.append(v)
- s_list.append(dh + h)
- dh_list.append(dh)
- t_list.append(times)
- a_list.append(the_a)
- v = new_v
- h += dh
- plt.figure()
- size = (3, 2)
- dh_t = plt.subplot2grid(size, (0, 0), colspan=1, rowspan=1)
- s_t = plt.subplot2grid(size, (0, 1), colspan=1, rowspan=1)
- v_t = plt.subplot2grid(size, (1, 0), colspan=2, rowspan=1)
- a_t = plt.subplot2grid(size, (2, 0), colspan=2, rowspan=1)
- def set_plot(plot, title, ylabel, xlabel, line, y_list, x_list):
- plot.set_title(title)
- plot.set_ylabel(ylabel)
- plot.set_xlabel(xlabel)
- plot.plot(x_list, y_list, line, label=title)
- set_plot(v_t, 'v-t', 'v(m/s)', 't(s)', 'r', v_list, t_list)
- set_plot(s_t, 'h-t', 'h(m)', 't(s)', 'b', s_list, t_list)
- set_plot(dh_t, f'dh-t(dt = {time}s)', 'dh(m)', 't(s)', 'y', dh_list, t_list)
- set_plot(a_t, 'a-t', 'a(m/s^2)', 't(s)', 'g', a_list, t_list)
- v_t.grid()
- s_t.grid()
- dh_t.grid()
- a_t.grid()
- plt.show()
- except KeyboardInterrupt:
- pass
- print("Bye Bye(power by SuperHuan)!")
|