Spaces:
Sleeping
Sleeping
Download src/poolcoach_sim/table.py from masterdanh/poolcoach-analyzer: direct link, hf CLI and curl.
- Browser
- Download file 2.31 kB
-
https://huggingface.co/spaces/masterdanh/poolcoach-analyzer/resolve/main/src/poolcoach_sim/table.py
- Command line
-
hf download hf://spaces/masterdanh/poolcoach-analyzer/src/poolcoach_sim/table.py
-
curl -L -o table.py https://huggingface.co/spaces/masterdanh/poolcoach-analyzer/resolve/main/src/poolcoach_sim/table.py
2.31 kB
| """Table geometry read straight from pooltool -- a facts layer, no rules. | |
| Why it exists: the front-end sizes its canvas from the real table and maps | |
| broadcast coordinates (2.54 x 1.27 m) onto the app table with a single | |
| similarity factor, so ``/api/table`` has to return w/l/ball_r/pockets. The | |
| previous repository took those numbers from ``PositionPlayEnv`` (the RL | |
| environment), which is not ported here -- and hard-coding them would let | |
| them drift away from the table specs. This module reads the same source the | |
| environment read: ``pt.Table.default()``. | |
| pooltool is imported LAZILY inside the function: the app imports this module | |
| at startup while importing pooltool costs ~20s (Numba), so the call happens | |
| on the background thread of ``app/main.py``, and the contract tests (which | |
| stub pooltool) can import this module without pulling anything in. | |
| """ | |
| from __future__ import annotations | |
| BALL_R = 0.028575 # ball radius (m) -- the pooltool default, the same | |
| # number as ``poolcoach_cv.broadcast.BALL_R_M`` | |
| def pocket_name(w: float, l: float, xy) -> str: | |
| """Pocket name derived from its centre, same rule as the previous | |
| repository (``poolcoach_rl.recommend.geometry.pocket_name``). Nothing in | |
| the Analyzer front-end renders it -- it is kept because the field is | |
| part of the /api/table contract and it makes the payload readable.""" | |
| lr = "left" if xy[0] < w / 2 else "right" | |
| if xy[1] < l / 3: | |
| return f"bottom-{lr} corner" | |
| if xy[1] > 2 * l / 3: | |
| return f"top-{lr} corner" | |
| return f"{lr} side" | |
| def table_facts() -> dict: | |
| """``{w, l, ball_r, pockets: [{x, y, r, name}]}`` of the default table. | |
| Call it on a background thread (importing pooltool is heavy). Pocket | |
| order follows pooltool's ``table.pockets`` -- the same order the | |
| previous repository returned.""" | |
| import pooltool as pt | |
| table = pt.Table.default() | |
| w, l = float(table.w), float(table.l) | |
| pockets = [] | |
| for p in table.pockets.values(): | |
| xy = (float(p.center[0]), float(p.center[1])) | |
| pockets.append({"x": xy[0], "y": xy[1], | |
| "r": float(getattr(p, "radius", 2 * BALL_R)), | |
| "name": pocket_name(w, l, xy)}) | |
| return {"w": w, "l": l, "ball_r": BALL_R, "pockets": pockets} | |