from sympy import latex, S
from perfect_physics import World, Circle, Wall, Timeline
from perfect_physics._timeline import Collision
def run_in_place(world, steps, target, fig_factor=1, clear=True):
if clear:
js.document.getElementById(target).innerHTML = ''
world.run_in_place(steps, show=True,
show_fun=lambda figure: display(figure, target=target, append=True),
figsize=(19.2 / 4, 10.8 / 4 * fig_factor)
)
def count_collisions(right_mass, target, show=False, font_scale=.5, clear=True):
if clear:
js.document.getElementById(target).innerHTML = ''
show_fun=lambda figure: display(figure, target=target, append=True)
world_width = 5
left = Circle(x=2, y=0, r=1, vx=0, vy=0, m=1)
right = Circle(x=6 if right_mass > 1 else 5, y=0, r=2 if right_mass > 1 else 1, vx=-1, vy=0, m=right_mass)
circle_list = [left, right]
wall_list = [ Wall(x0=0, y0=0, x1=0, y1=1)]
world = World(circle_list, wall_list, xlim=(-1, world_width + 1), ylim=(-1 - 1, 1 + 1))
count = 0
world.show(show=show, font_scale=font_scale)
hint_ssca_list = []
timeline = Timeline()
while True:
ss_calist, hint_ssca_list = world._tick(timeline, hint_ssca_list, default_tick=0)
world.show(
show=show and ss_calist[0] is not S.Zero,
font_scale=font_scale,
show_fun=show_fun,
)
world._tock(ss_calist, timeline)
world.show(show=show, font_scale=font_scale)
# print(f"x {timeline.events[-1]}")
if not isinstance(timeline.events[-1],Collision):
break
count += 1
return count
packages = ["matplotlib", "pandas", "seaborn", "cloudpickle",
"perfect-physics==0.1.9"]
Carl M. Kadie
Perfect Physics: Live Demo
Perfect Physics
is a Python physics simulator that uses
computer algebra (SymPy )
to do all calculations exactly. For details, read
"Perfect,
Infinite-Precision, Game Physics in Python"
in Towards Data Science or watch the
PyData Conference Presentation .
This page lets you run your own simulations in the browser.
Just press a green
arrow (and wait a while). If you like, you can change the examples completely and run
arbitrary Python code.
The outputs shows snapshots at the next collision(s) with a "Clock".
(Full animations are not yet available.)
The page uses PyScript .
Its source code is
simple.
Newton's Cradle
To run, click the triangle or press shift-enter. May take 10's of seconds to run.
Ideas: Change the number of balls or number of steps.
circle_list = [Circle(x=1, y=0, r=1, vx=1, vy=0, m=1)]
for i in range(1, 5):
circle_list.append(Circle(x=i * 2 + 4, y=0, r=1, vx=0, vy=0, m=1))
wall_list = [Wall(x0=0, y0=0, x1=0, y1=1), Wall(x0=20, y0=0, x1=20, y1=1)]
world = World(circle_list, wall_list, xlim=(-1, 21), ylim=(-2, 2))
run_in_place(world, steps=5, target="newtonOutput", fig_factor=0.5)
clear
Tennis Ball and Basketball
It prints the velocity of the tennis ball at the end.
Ideas: Change 'big_radius', the size of the basketball, or the number of steps.
big_radius = 10
world_width = 40
big = Circle(x=world_width // 2, y=0, r=big_radius, vx=1, vy=0, m=big_radius**3)
little = Circle(x=big.x - big_radius - 1, y=0, r=1, vx=1, vy=0, m=1)
circle_list = [big, little]
wall_list = [Wall(x0=0, y0=0, x1=0, y1=1), Wall(x0=world_width, y0=0, x1=world_width, y1=1)]
world = World(circle_list, wall_list, xlim=(-1, world_width + 1), ylim=(-big_radius - 1, big_radius + 1))
run_in_place(world, steps=2, target="tennisOutput")
display(f"little vx is {little.vx} (approx. {float(little.vx):.2f})", target="tennisOutput", append=True)
clear
Three Circles on a Line
It runs with two different seeds.
This is based on an example from Prof. Edward A. Lee's
Fundamental Limits of Cyber-Physical Systems Modeling .
Ideas: Change the mass of the right ball.
js.document.getElementById("onLineOutput").innerHTML = ''
for seed in [0,1]:
left = Circle(x=-3, y=0, r=1, vx=1, vy=0, m=1, id="left")
middle = Circle(x=0, y=0, r=1, vx=0, vy=0, m=1, id="middle")
right = Circle(x=4, y=0, r=2, vx=-1, vy=0, m=4, id="right")
world = World([left, middle, right], rng=seed, xlim=(-10, 10), ylim=(-3, 3))
display(f"seed {seed}", target="onLineOutput", append=True)
run_in_place(world, steps=3, target="onLineOutput", fig_factor=.66, clear=False)
clear
Billiards
Ideas: Change the # of rows or number of steps.
rows = -2 # positive for a 1st ball of triangle
seed = 0
world = World.billiards(rows=rows, rng=seed)
run_in_place(world, steps=5, target="billiardsOutput")
clear
Computing π with Collisions
According to a paper by G. Galperin ,
two
videos by 3Blue1Brown,
and a New York Times item ,
you can compute π by counting the number of collisions between two balls
of different mass and a wall.
larger_mass = 1 # try 100 and 10_000
show = False
count_collisions(larger_mass, target="piOutput", show=show)
clear