Skip to content

Commit

Permalink
Handle ShotViewer instantiation internally
Browse files Browse the repository at this point in the history
  • Loading branch information
ekiefl committed Sep 15, 2024
1 parent 42c35d8 commit f9a70cc
Show file tree
Hide file tree
Showing 14 changed files with 83 additions and 43 deletions.
3 changes: 1 addition & 2 deletions docs/examples/30_degree_rule.pct.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,7 @@
# If you have a graphics card, you can immediately visualize this shot in 3D with
#
# ```python
# gui = pt.ShotViewer()
# gui.show(system)
# pt.show(system)
# ```
#
# 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.
Expand Down
3 changes: 1 addition & 2 deletions docs/examples/straight_shot.pct.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,7 @@ def create_system(d, D):
# If you have a graphics card, you can visualize the system in 3D with
#
# ```python
# gui = pt.ShotViewer()
# gui.show(system)
# pt.show(system)
# ```
#
# ## Simulating a shot
Expand Down
3 changes: 1 addition & 2 deletions docs/getting_started/interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ In the next section you'll become more familiar with the Python API, however bel
import pooltool as pt
system = pt.System.example()
pt.simulate(system, inplace=True)
gui = pt.ShotViewer()
gui.show(system)
pt.show(system)
```

Once a shot is visualized in the interface, all of the controls related to camera movement and animation control are applicable. If a multisystem is being visualized, different shots can be toggled by pressing *n* (next) and *p* (previous).
Expand Down
8 changes: 3 additions & 5 deletions docs/getting_started/script.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ shot.cue.set_state(V0=8, phi=pt.aim.at_ball(shot, "1"))
pt.simulate(shot, inplace=True)

# Open up the shot in the GUI
interface = pt.ShotViewer()
interface.show(shot)
pt.show(shot)
```

For those interested in some exposition, below is a line-by-line explanation.
Expand Down Expand Up @@ -80,12 +79,11 @@ pt.simulate(shot, inplace=True)

The system has now been evolved from its initial to its final state.

To visualize the shot, open the GUI with {py:class}`pooltool.ShotViewer`:
To visualize the shot, open the GUI with {py:func}`pooltool.show`:

```python
# Open up the shot in the GUI
interface = pt.ShotViewer()
interface.show(shot)
pt.show(shot)
```

## Next
Expand Down
4 changes: 2 additions & 2 deletions pooltool/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from pooltool.events import EventType
from pooltool.evolution import continuize, simulate
from pooltool.game.datatypes import GameType
from pooltool.interact import Game, ShotViewer
from pooltool.interact import Game, show
from pooltool.layouts import generate_layout, get_rack
from pooltool.objects import (
Ball,
Expand Down Expand Up @@ -84,7 +84,7 @@
"Table",
"TableType",
"Game",
"ShotViewer",
"show",
"EventType",
# functions
"get_rack",
Expand Down
61 changes: 60 additions & 1 deletion pooltool/interact.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,67 @@
"""An endpoint for classes that enable interaction"""

from typing import Optional, Union

from pooltool.ani.animate import Game, ShotViewer
from pooltool.ani.camera import CameraState
from pooltool.system.datatypes import MultiSystem, System

_shot_viewer: Optional[ShotViewer] = None


def show(
shot_or_shots: Union[System, MultiSystem],
title: str = "",
camera_state: Optional[CameraState] = None,
):
"""Opens the interactive interface for one or more shots.
Important:
For instructions on how to use the interactive interface, see :doc:`The
Interface </getting_started/interface>`.
Args:
shot_or_shots:
The shot or collection of shots to visualize. This can be a single
:class:`pooltool.system.datatypes.System` object or a
:class:`pooltool.system.datatypes.MultiSystem` object containing
multiple systems.
Note:
If a multisystem is passed, the systems can be scrolled through by
pressing *n* (next) and *p* (previous).
title:
The title to display in the visualization. Defaults to an empty string.
camera_state:
The initial camera state that the visualization is rendered with.
Example:
This example visualizes a single shot.
>>> import pooltool as pt
>>> system = pt.System.example()
Make sure the shot is simulated, otherwise it will make for a boring
visualization:
>>> pt.simulate(system, inplace=True)
Now visualize the shot:
>>> pt.show(system)
(Press *escape* to exit the interface and continue script execution)
"""
global _shot_viewer

if _shot_viewer is None:
_shot_viewer = ShotViewer()

_shot_viewer.show(shot_or_shots, title, camera_state)


__all__ = [
"ShotViewer",
"Game",
"show",
]
9 changes: 3 additions & 6 deletions pooltool/system/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ class System:
This ``system`` can also be visualized in the GUI:
>>> gui = pt.ShotViewer()
>>> gui.show(system)
>>> pt.show(system)
"""

cue: Cue = field()
Expand Down Expand Up @@ -572,8 +571,7 @@ def example(cls) -> System:
It can be simulated and visualized:
>>> pt.simulate(system, inplace=True)
>>> gui = pt.ShotViewer()
>>> gui.show(system)
>>> pt.show(system)
"""
system = cls(
cue=Cue.default(),
Expand Down Expand Up @@ -642,8 +640,7 @@ class MultiSystem:
Now visualize the multisystem:
>>> gui = pt.ShotViewer()
>>> gui.show(multisystem, title="Press 'n' for next, 'p' for previous")
>>> pt.show(multisystem, title="Press 'n' for next, 'p' for previous")
"""

multisystem: List[System] = field(factory=list)
Expand Down
4 changes: 1 addition & 3 deletions sandbox/arena.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ def place_ball(i, balls, table):


def main(args):
if not args.no_viz:
interface = pt.ShotViewer()
while True:
# Setup the system
table = pt.Table.from_table_specs(pt.objects.BilliardTableSpecs(l=4, w=2))
Expand All @@ -47,7 +45,7 @@ def main(args):
pt.simulate(shot, continuous=False, inplace=True)

if not args.no_viz:
interface.show(shot)
pt.show(shot)


if __name__ == "__main__":
Expand Down
5 changes: 1 addition & 4 deletions sandbox/break.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@


def main(args):
if not args.no_viz:
interface = pt.ShotViewer()

if args.seed:
np.random.seed(args.seed)

Expand Down Expand Up @@ -66,7 +63,7 @@ def main(args):
pt.simulate(shot, inplace=True)

if not args.no_viz:
interface.show(shot)
pt.show(shot)

if args.save:
shot.save(args.save)
Expand Down
7 changes: 4 additions & 3 deletions sandbox/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
json_path = Path(__file__).parent / "collection.json"
collection.save(json_path)
new_collection = pt.MultiSystem.load(json_path)
assert new_collection == collection

interface = pt.ShotViewer()
interface.show(new_collection)
for old_system, new_system in zip(collection.multisystem, new_collection.multisystem):
assert old_system == new_system

pt.show(new_collection)
9 changes: 3 additions & 6 deletions sandbox/copy_save_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@


def main():
# Initialize the GUI
interface = pt.ShotViewer()

# Create a system
shot = pt.System(
table=(table := pt.Table.default()),
Expand All @@ -23,19 +20,19 @@ def main():
pt.simulate(shot, inplace=True)

# Visualize it
interface.show(shot, title="Original system state")
pt.show(shot, title="Original system state")

# You can copy it and visualize the copy
new = shot.copy()
interface.show(new, title="A deep-ish copy of the original")
pt.show(new, title="A deep-ish copy of the original")

# You can also save it to a file, and load it up again.
with tempfile.TemporaryDirectory() as tmp_dir:
path = Path(tmp_dir) / "shot.json"
new.save(path)
newer = pt.System.load(path)

interface.show(newer, title="A copy of the original, loaded from the disk space")
pt.show(newer, title="A copy of the original, loaded from the disk space")


if __name__ == "__main__":
Expand Down
3 changes: 1 addition & 2 deletions sandbox/custom_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ def main():
pt.simulate(system, inplace=True)

# Now visualize it
interface = pt.ShotViewer()
interface.show(system)
pt.show(system)


if __name__ == "__main__":
Expand Down
3 changes: 1 addition & 2 deletions sandbox/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@


def main(args):
interface = pt.ShotViewer()
interface.show(pt.System.load(args.path))
pt.show(pt.System.load(args.path))


if __name__ == "__main__":
Expand Down
4 changes: 1 addition & 3 deletions sandbox/serialize/demo_round_trip.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import pooltool as pt
from pooltool.system import System

interface = pt.ShotViewer()

shot = System(
cue=pt.Cue(cue_ball_id="cue"),
table=(table := pt.Table.default()),
Expand All @@ -29,4 +27,4 @@
msgpack_hydrated = System.load(msgpack_path)
assert json_hydrated == msgpack_hydrated == shot

interface.show(shot, title="Serialized/deserialized shot")
pt.show(shot, title="Serialized/deserialized shot")

0 comments on commit f9a70cc

Please sign in to comment.