Trajectory tracing and ball-to-ball collisions

Now we introduce one of the more difficult behaviors in our simulation of ever increasing complexity the mid-air collision.

The hardest thing when you are debugging a program is to try to hold in your short term memory some recently observed behavior and compare it meaningfully with present behavior. This kind of memory is an imperfect recorder. The way to overcome this is to create a graphic form of memory some sort of picture that shows accurately what has been happening in the past. In the same way that military cannon aimers use glowing tracer projectiles to adjust their aim, a graphic programmer can use trajectory traces to examine the history of execution.

How to do it...

In our new code there is a new function called detect_ball_collision (ball_1, ball_2) whose job is to anticipate imminent collisions between the two balls no matter where they are. The collisions will come from any direction and therefore we need to be able to test all possible collision scenarios and examine the behavior of each one and see if it does not work as planned. This can be too difficult unless we create tools to test the outcome. In this recipe, the tool for testing outcomes is a graphic trajectory trace. It is a line that trails behind the path of the ball and shows exactly where it went right since the beginning of the simulation. The result is shown in the following screenshot, showing the bouncing with ball-to-ball collision rebounds.

How to do it...
# kinetic_gravity_balls_1.py
animationmid-air collision# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
from Tkinter import *
import math
root = Tk()
root.title("Balls bounce off each other")
cw = 300 # canvas width
ch = 200 # canvas height
GRAVITY = 1.5
chart_1 = Canvas(root, width=cw, height=ch, background="white")
chart_1.grid(row=0, column=0)
cycle_period = 80 # Time between new positions of the ball # (milliseconds).
time_scaling = 0.2 # The size of the differential steps
# The parameters determining the dimensions of the ball and its # position.
ball_1 = {'posn_x':25.0,
'posn_y':25.0,
'velocity_x':65.0,
'velocity_y':50.0,
'ball_width':20.0,
'ball_height':20.0,
'color':"SlateBlue1",
'coef_restitution':0.90}
ball_2 = {'posn_x':180.0,
'posn_y':ch- 25.0,
'velocity_x':-50.0,
'velocity_y':-70.0,
'ball_width':30.0,
'ball_height':30.0,
'color':"maroon1",
'coef_restitution':0.90}
def detect_wall_collision(ball):
animationmid-air collision# detect ball-to-wall collision
if ball['posn_x'] > cw - ball['ball_width']: # Right-hand wall.
ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ 
estitution']
ball['posn_x'] = cw - ball['ball_width']
if ball['posn_x'] < 1: # Left-hand wall.
ball['velocity_x'] = -ball['velocity_x'] * ball['coef_ 
estitution']
ball['posn_x'] = 2
if ball['posn_y'] < ball['ball_height'] : # Ceiling.
ball['velocity_y'] = -ball['velocity_y'] * ball['coef_ 
estitution']
ball['posn_y'] = ball['ball_height']
if ball['posn_y'] > ch - ball['ball_height'] : # Floor
ball['velocity_y'] = - ball['velocity_y'] * ball['coef_ 
estitution']
ball['posn_y'] = ch - ball['ball_height']
def detect_ball_collision(ball_1, ball_2):
#detect ball-to-ball collision
# firstly: is there a close approach in the horizontal direction
if math.fabs(ball_1['posn_x'] - ball_2['posn_x']) < 25:
# secondly: is there also a close approach in the vertical # direction.
if math.fabs(ball_1['posn_y'] - ball_2['posn_y']) < 25:
ball_1['velocity_x'] = -ball_1['velocity_x'] # reverse # direction.
ball_1['velocity_y'] = -ball_1['velocity_y']
ball_2['velocity_x'] = -ball_2['velocity_x']
ball_2['velocity_y'] = -ball_2['velocity_y']
# to avoid internal rebounding inside balls
ball_1['posn_x'] += ball_1['velocity_x'] * time_scaling
ball_1['posn_y'] += ball_1['velocity_y'] * time_scaling
ball_2['posn_x'] += ball_2['velocity_x'] * time_scaling
ball_2['posn_y'] += ball_2['velocity_y'] * time_scaling
animationmid-air collisiondef diff_equation(ball):
x_old = ball['posn_x']
y_old = ball['posn_y']
ball['posn_x'] += ball['velocity_x'] * time_scaling
ball['velocity_y'] = ball['velocity_y'] + GRAVITY
ball['posn_y'] += ball['velocity_y'] * time_scaling
chart_1.create_oval( ball['posn_x'], ball['posn_y'],
ball['posn_x'] + ball['ball_width'],
ball['posn_y'] + ball['ball_height'],
fill= ball['color'], tags="ball_tag")
chart_1.create_line( x_old, y_old, ball['posn_x'],  ball ['posn_y'], fill= ball['color'])
detect_wall_collision(ball) # Has the ball # collided with any container wall?
for i in range(1,5000):
diff_equation(ball_1)
diff_equation(ball_2)
detect_ball_collision(ball_1, ball_2)
chart_1.update()
chart_1.after(cycle_period)
chart_1.delete("ball_tag") # Erase the balls but # leave the trajectories
root.mainloop()

How it works...

Mid-air ball against ball collisions are done in two steps. In the first step, we test whether the two balls are close to each other inside a vertical strip defined by if math.fabs(ball_1['posn_x'] - ball_2['posn_x']) < 25. In plain English, this asks "Is the horizontal distance between the balls less than 25 pixels?" If the answer is yes, then the region of examination is narrowed down to a small vertical distance less than 25 pixels by the statement if math.fabs(ball_1['posn_y'] - ball_2['posn_y']) < 25. So every time the loop is executed, we sweep the entire canvas to see if the two balls are both inside an area where their bottom-left corners are closer than 25 pixels to each other. If they are that close then we simply cause a rebound off each other by reversing their direction of travel in both the horizontal and vertical directions.

There's more...

Simply reversing the direction is not the mathematically correct way to reverse the direction of colliding balls. Certainly billiard balls do not behave that way. The law of physics that governs colliding spheres demands that momentum be conserved. This requires more complicated mathematics not covered in this book.

Why do we sometimes get tkinter.TckErrors?

If we click the close window button (the X in the top right) while Python is paused, when Python revives and then calls on Tcl (Tkinter) to draw something on the canvas we will get an error message. What probably happens is that the application has already shut down, but Tcl has unfinished business. If we allow the program to run to completion before trying to shut the window then termination is orderly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.0.145