You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/examples/30_degree_rule.pct.py
+27-30Lines changed: 27 additions & 30 deletions
Original file line number
Diff line number
Diff line change
@@ -75,7 +75,7 @@
75
75
#
76
76
# We'll start with a table. Since we don't want collisions with cushions to interfere with our trajectory, let's make an unrealistically large $10\text{m} \times 10\text{m}$ [Table](../autoapi/pooltool/index.rst#pooltool.Table).
# Next, we'll create two [Ball](../autoapi/pooltool/index.rst#pooltool.Ball) objects.
87
87
88
-
# %% trusted=true
88
+
# %%
89
89
cue_ball=pt.Ball.create("cue", xy=(2.5, 1.5))
90
90
obj_ball=pt.Ball.create("obj", xy=(2.5, 3.0))
91
91
92
92
# %% [markdown]
93
93
# Next, we'll need a [Cue](../autoapi/pooltool/index.rst#pooltool.Cue).
94
94
95
-
# %% trusted=true
95
+
# %%
96
96
cue=pt.Cue(cue_ball_id="cue")
97
97
98
98
# %% [markdown]
99
99
# Finally, we'll need to wrap these objects up into a [System](../autoapi/pooltool/index.rst#pooltool.System). We'll call this our system *template*, with the intention of reusing it for many different shots.
100
100
101
-
# %% trusted=true
101
+
# %%
102
102
system_template=pt.System(
103
103
table=table,
104
104
cue=cue,
@@ -112,7 +112,7 @@
112
112
#
113
113
# So in the function call below, `pt.aim.at_ball(system, "obj", cut=30)` returns the angle `phi` that the cue ball should be directed at such that a cut angle of 30 degrees with the object ball is achieved.
114
114
115
-
# %% trusted=true
115
+
# %%
116
116
# Creates a deep copy of the template
117
117
system=system_template.copy()
118
118
@@ -122,7 +122,7 @@
122
122
# %% [markdown]
123
123
# Now, we [simulate](../autoapi/pooltool/index.rst#pooltool.simulate) the shot and then [continuize](../autoapi/pooltool/evolution/continuize/index.html#pooltool.evolution.continuize.continuize) it to store ball state data (like coordinates) in $10\text{ms}$ timestep intervals.
124
124
125
-
# %% trusted=true
125
+
# %%
126
126
# Create a default physics engine and overwrite ball-ball model with frictionless, elastic model.
# Since that can't be embedded into the documentation, we'll instead plot the trajectory of the cue ball and object ball by accessing ther historical states.
146
146
147
-
# %% trusted=true
147
+
# %%
148
148
cue_ball=system.balls["cue"]
149
149
obj_ball=system.balls["obj"]
150
150
cue_history=cue_ball.history_cts
@@ -154,7 +154,7 @@
154
154
# %% [markdown]
155
155
# The [BallHistory](../autoapi/pooltool/objects/index.rst#pooltool.objects.BallHistory) holds the ball's historical states, each stored as a [BallState](../autoapi/pooltool/objects/index.rst#pooltool.objects.BallState) object. Each attribute of the ball states can be concatenated into numpy arrays with the [BallHistory.vectorize](../autoapi/pooltool/objects/index.rst#pooltool.objects.BallHistory.vectorize) method.
156
156
157
-
# %% trusted=true
157
+
# %%
158
158
rvw_cue, s_cue, t_cue=cue_history.vectorize()
159
159
rvw_obj, s_obj, t_obj=obj_history.vectorize()
160
160
@@ -165,12 +165,12 @@
165
165
# %% [markdown]
166
166
# We can grab the xy-coordinates from the `rvw` array by with the following.
# As mentioned before, the carom angle is the angle between the cue ball velocity right before collision, and the cue ball velocity post-collision, once the ball has stopped sliding on the cloth. Hidden somewhere in the system **event list** one can find the events corresponding to these precise moments in time:
205
205
206
-
# %% trusted=true
206
+
# %%
207
207
system.events[:6]
208
208
209
209
# %% [markdown]
210
210
# Programatically, we can pick out these two events of interest with event selection syntax.
211
211
#
212
212
# Since there is only one ball-ball collision, it's easy to select with [filter_type](../autoapi/pooltool/events/index.rst#pooltool.events.filter_type):
# But there are many sliding to rolling transition events, and to make matters worse, they are shared by both the cue ball and the object ball. What we need is the **first** **sliding to rolling** transition that the **cue ball** undergoes **after** the **ball-ball** collision. We can achieve this multi-criteria query with [filter_events](../autoapi/pooltool/events/index.rst#pooltool.events.filter_events):
226
226
227
-
# %% trusted=true
227
+
# %%
228
228
transition=pt.events.filter_events(
229
229
system.events,
230
230
pt.events.by_time(t=collision.time, after=True),
@@ -236,16 +236,13 @@
236
236
# %% [markdown]
237
237
# Now, we can dive into these two events and pull out the cue ball velocities we need to calculate the carom angle.
238
238
239
-
# %% trusted=true
239
+
# %%
240
240
# Velocity prior to impact
241
-
foragentincollision.agents:
242
-
ifagent.id=="cue":
243
-
# agent.initial is a copy of the Ball before resolving the collision
# We calculated the carom angle for a single cut angle, 30 degrees. Let's write a function called `get_carom_angle` so we can do that repeatedly for different cut angles.
# `get_carom_angle` assumes the passed system has already been simulated, so we'll need another function to take care of that. We'll cue stick speed and cut angle as parameters.
# From this dataframe we can make some plots. On top of the ball-hit fraction, plot, I'll create a box between a $1/4$ ball hit and a $3/4$ ball hit, since this is the carom angle range that the 30-degree rule is defined with respect to.
0 commit comments