masterdanh's picture
chore(repo): normalize line endings with text=auto
2cfc662
Raw History Blame Contribute Delete
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}