#!/usr/bin/env python3
import argparse
from itertools import accumulate, count, cycle, repeat, takewhile
from math import cos, gcd, pi, sin
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
parser = argparse.ArgumentParser()
parser.add_argument('v0', help = '初速度', type = float)
parser.add_argument('theta', help = '入射角', type = float)
parser.add_argument('-w', '--width', help = '横軸', type = int, default = 8)
parser.add_argument('--height', help = '縦軸', type = int, default = 6)
parser.add_argument('-dt', help = '微小時間', type = float, default = 0.04)
parser.add_argument('-y0', help = '初期位置(高さ)', type = float, default = 0)
parser.add_argument('-s', '--scale', help = '倍率', type = int, default = 10)
if __name__ == '__main__':
args = parser.parse_args()
width, height = args.width * args.scale, args.height * args.scale
# Figure と Axes
fig, ax = plt.subplots()
ax.grid()
ax.set(xlim = [0, width], ylim = [-height//2, height//2], xlabel = 'x', ylabel = 'y')
# 初期条件設定
dt = args.dt
y0 = args.y0
v0 = args.v0
degree = args.theta * pi / 180
g = -9.8
# x, y 座標計算
positions = takewhile(
lambda r: r[0] >= 0 and r[0] <= width and
r[1] >= - height/2 and r[1] <= height / 2,
accumulate(
zip(
repeat(v0 * cos(degree)),
accumulate(
count(),
func = lambda v, n: v + g * dt,
initial = v0 * sin(degree) + 0.5 * g * dt
)
),
func = lambda r, v: (r[0] + v[0] * dt, r[1] + v[1] * dt),
initial = (0, y0)
)
)
# ボールの作成
ball = ax.scatter(*next(positions), 5, color = "r", label = f'v0 = {v0} m/s')
# ボールの更新関数
def update(frame):
ball.set_offsets(frame)
return (ball,)
# アニメーション作成
anim = FuncAnimation(
fig,
update,
frames = positions,
interval = 1000 * dt,
blit = True
)
fig.suptitle("Projectile Motion")
# anim.save('projectile.gif') # gifアニメを作る
plt.show()
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoKaW1wb3J0IGFyZ3BhcnNlCmZyb20gaXRlcnRvb2xzIGltcG9ydCBhY2N1bXVsYXRlLCBjb3VudCwgY3ljbGUsIHJlcGVhdCwgdGFrZXdoaWxlCmZyb20gbWF0aCBpbXBvcnQgY29zLCBnY2QsIHBpLCBzaW4KaW1wb3J0IG1hdHBsb3RsaWIucHlwbG90IGFzIHBsdApmcm9tIG1hdHBsb3RsaWIuYW5pbWF0aW9uIGltcG9ydCBGdW5jQW5pbWF0aW9uCgpwYXJzZXIgPSBhcmdwYXJzZS5Bcmd1bWVudFBhcnNlcigpCnBhcnNlci5hZGRfYXJndW1lbnQoJ3YwJywgaGVscCA9ICfliJ3pgJ/luqYnLCB0eXBlID0gZmxvYXQpCnBhcnNlci5hZGRfYXJndW1lbnQoJ3RoZXRhJywgaGVscCA9ICflhaXlsITop5InLCB0eXBlID0gZmxvYXQpCnBhcnNlci5hZGRfYXJndW1lbnQoJy13JywgJy0td2lkdGgnLCBoZWxwID0gJ+aoqui7uCcsIHR5cGUgPSBpbnQsIGRlZmF1bHQgPSA4KQpwYXJzZXIuYWRkX2FyZ3VtZW50KCctLWhlaWdodCcsIGhlbHAgPSAn57im6Lu4JywgdHlwZSA9IGludCwgZGVmYXVsdCA9IDYpCnBhcnNlci5hZGRfYXJndW1lbnQoJy1kdCcsIGhlbHAgPSAn5b6u5bCP5pmC6ZaTJywgdHlwZSA9IGZsb2F0LCBkZWZhdWx0ID0gMC4wNCkKcGFyc2VyLmFkZF9hcmd1bWVudCgnLXkwJywgaGVscCA9ICfliJ3mnJ/kvY3nva4o6auY44GVKScsIHR5cGUgPSBmbG9hdCwgZGVmYXVsdCA9IDApCnBhcnNlci5hZGRfYXJndW1lbnQoJy1zJywgJy0tc2NhbGUnLCBoZWxwID0gJ+WAjeeOhycsIHR5cGUgPSBpbnQsIGRlZmF1bHQgPSAxMCkKCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6CiAgICBhcmdzID0gcGFyc2VyLnBhcnNlX2FyZ3MoKQogICAgd2lkdGgsIGhlaWdodCA9IGFyZ3Mud2lkdGggKiBhcmdzLnNjYWxlLCBhcmdzLmhlaWdodCAqIGFyZ3Muc2NhbGUKICAgIAogICAgIyBGaWd1cmUg44GoIEF4ZXMKICAgIGZpZywgYXggPSBwbHQuc3VicGxvdHMoKQogICAgYXguZ3JpZCgpCiAgICBheC5zZXQoeGxpbSA9IFswLCB3aWR0aF0sIHlsaW0gPSBbLWhlaWdodC8vMiwgaGVpZ2h0Ly8yXSwgeGxhYmVsID0gJ3gnLCB5bGFiZWwgPSAneScpCgogICAgIyDliJ3mnJ/mnaHku7boqK3lrpoKICAgIGR0ID0gYXJncy5kdAogICAgeTAgPSBhcmdzLnkwCiAgICB2MCA9IGFyZ3MudjAKICAgIGRlZ3JlZSA9IGFyZ3MudGhldGEgKiBwaSAvIDE4MAogICAgZyA9IC05LjgKCiAgICAjIHgsIHkg5bqn5qiZ6KiI566XCiAgICBwb3NpdGlvbnMgPSB0YWtld2hpbGUoCiAgICAgICAgbGFtYmRhIHI6IHJbMF0gPj0gMCBhbmQgclswXSA8PSB3aWR0aCBhbmQKICAgICAgICByWzFdID49IC0gaGVpZ2h0LzIgYW5kIHJbMV0gPD0gaGVpZ2h0IC8gMiwKICAgICAgICBhY2N1bXVsYXRlKAogICAgICAgICAgICB6aXAoCiAgICAgICAgICAgICAgICByZXBlYXQodjAgKiBjb3MoZGVncmVlKSksCiAgICAgICAgICAgICAgICBhY2N1bXVsYXRlKAogICAgICAgICAgICAgICAgICAgIGNvdW50KCksCiAgICAgICAgICAgICAgICAgICAgZnVuYyA9IGxhbWJkYSB2LCBuOiB2ICsgZyAqIGR0LAogICAgICAgICAgICAgICAgICAgIGluaXRpYWwgPSB2MCAqIHNpbihkZWdyZWUpICsgMC41ICogZyAqIGR0CiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgKSwKICAgICAgICAgICAgZnVuYyA9IGxhbWJkYSByLCB2OiAoclswXSArIHZbMF0gKiBkdCwgclsxXSArIHZbMV0gKiBkdCksCiAgICAgICAgICAgIGluaXRpYWwgPSAoMCwgeTApCiAgICAgICAgICAgICkKICAgICAgICApCgogICAgIyDjg5zjg7zjg6vjga7kvZzmiJAKICAgIGJhbGwgPSBheC5zY2F0dGVyKCpuZXh0KHBvc2l0aW9ucyksIDUsIGNvbG9yID0gInIiLCBsYWJlbCA9IGYndjAgPSB7djB9IG0vcycpCgogICAgIyDjg5zjg7zjg6vjga7mm7TmlrDplqLmlbAKICAgIGRlZiB1cGRhdGUoZnJhbWUpOgogICAgICAgIGJhbGwuc2V0X29mZnNldHMoZnJhbWUpCiAgICAgICAgcmV0dXJuIChiYWxsLCkKCiAgICAjIOOCouODi+ODoeODvOOCt+ODp+ODs+S9nOaIkAogICAgYW5pbSA9IEZ1bmNBbmltYXRpb24oCiAgICAgICAgZmlnLAogICAgICAgIHVwZGF0ZSwKICAgICAgICBmcmFtZXMgPSBwb3NpdGlvbnMsCiAgICAgICAgaW50ZXJ2YWwgPSAxMDAwICogZHQsCiAgICAgICAgYmxpdCA9IFRydWUKICAgICAgICApCgogICAgZmlnLnN1cHRpdGxlKCJQcm9qZWN0aWxlIE1vdGlvbiIpCiAgICAjIGFuaW0uc2F2ZSgncHJvamVjdGlsZS5naWYnKSAjIGdpZuOCouODi+ODoeOCkuS9nOOCiwogICAgcGx0LnNob3coKQo=