Source code for pooltool.objects.table.specs

#! /usr/bin/env python

from __future__ import annotations

from typing import Protocol

from attrs import define, field

import pooltool.ani as ani
from pooltool.error import ConfigError
from pooltool.utils import panda_path, strenum


[docs] @define(frozen=True) class TableModelDescr: """A table model specifier Attributes: name: The name of the table model. """ name: str @property def path(self) -> str: """The path of the model The path is searched for in ``pooltool/models/table/{name}/{name}[_pbr].glb``. If physical based rendering (PBR) is requested, a model suffixed with _pbr will be looked for. Raises: ConfigError: If model path cannot be found from name. Returns: str: A filename specified with Panda3D filename syntax (see https://docs.panda3d.org/1.10/python/programming/advanced-loading/filename-syntax). """ if ani.settings.graphics.physical_based_rendering: path = ani.model_dir / "table" / self.name / (self.name + "_pbr.glb") else: path = ani.model_dir / "table" / self.name / (self.name + ".glb") if not path.exists(): raise ConfigError(f"Couldn't find table model with name: {self.name}") return panda_path(path) @staticmethod def null() -> TableModelDescr: return TableModelDescr(name="null")
[docs] class TableType(strenum.StrEnum): """An Enum describing the table type""" POCKET = strenum.auto() BILLIARD = strenum.auto() SNOOKER = strenum.auto() OTHER = strenum.auto()
class TableSpecs(Protocol): @property def table_type(self) -> TableType: ... @property def height(self) -> float: ... @property def lights_height(self) -> float: ... @property def model_descr(self) -> TableModelDescr: ...
[docs] @define(frozen=True) class PocketTableSpecs: """Parameter specifications for a pocket table. See Also: - See the :doc:`Table Specification </resources/table_specs>` resource for visualizations and descriptions of each attribute. - See :class:`BilliardTableSpecs` for billiard table specs. - See :class:`SnookerTableSpecs` for pocket table specs. """ # 7-foot table (78x39 in^2 playing surface) l: float = field(default=1.9812) # noqa E741 w: float = field(default=1.9812 / 2) cushion_width: float = field(default=2 * 2.54 / 100) cushion_height: float = field(default=0.64 * 2 * 0.028575) corner_pocket_width: float = field(default=0.118) corner_pocket_angle: float = field(default=5.3) # degrees corner_pocket_depth: float = field(default=0.0398) corner_pocket_radius: float = field(default=0.124 / 2) corner_jaw_radius: float = field(default=0.0419 / 2) side_pocket_width: float = field(default=0.137) side_pocket_angle: float = field(default=7.14) # degrees side_pocket_depth: float = field(default=0.00437) side_pocket_radius: float = field(default=0.129 / 2) side_jaw_radius: float = field(default=0.0159 / 2) # For visualization height: float = field(default=0.708) lights_height: float = field(default=1.99) model_descr: TableModelDescr = field(factory=TableModelDescr.null) table_type: TableType = field(init=False, default=TableType.POCKET)
[docs] @define(frozen=True) class BilliardTableSpecs: """Parameter specifications for a billiards (pocketless) table. See Also: - See the :doc:`Table Specification </resources/table_specs>` resource for visualizations and descriptions of each attribute. - See :class:`PocketTableSpecs` for billiard table specs. - See :class:`SnookerTableSpecs` for pocket table specs. """ # 10-foot table (imprecise) l: float = field(default=3.05) # noqa E741 w: float = field(default=3.05 / 2) cushion_width: float = field(default=2 * 2.54 / 100) # https://web.archive.org/web/20130801042614/http://www.umb.org/Rules/Carom_Rules.pdf cushion_height: float = field(default=0.037) # For visualization height: float = field(default=0.708) lights_height: float = field(default=1.99) model_descr: TableModelDescr = field(factory=TableModelDescr.null) table_type: TableType = field(init=False, default=TableType.BILLIARD)
[docs] @define(frozen=True) class SnookerTableSpecs: """Parameter specifications for a snooker table. See Also: - See the :doc:`Table Specification </resources/table_specs>` resource for visualizations and descriptions of each attribute. - See :class:`BilliardTableSpecs` for billiard table specs. - See :class:`PocketTableSpecs` for pocket table specs. Note: Currently, this class is an identical clone of :class:`PocketTableSpecs`, but with different defaults. That's not very useful, but it's likely that some time in the future, snooker tables may have some parameters distinct from standard pool tables (*e.g.* directional cloth), causing these classes to diverge. """ # https://wpbsa.com/rules/ # The playing area is within the cushion faces and shall measure # 11 ft 8½ in x 5 ft 10 in (3569 mm x 1778 mm) with a tolerance on both dimensions of +/- ½ in (13 mm). l: float = field(default=3.5445) # noqa E741 w: float = field(default=1.7465) cushion_width: float = field(default=1.55 * 25.4 / 1000) cushion_height: float = field(default=0.028) corner_pocket_width: float = field(default=0.083) corner_pocket_angle: float = field(default=0) corner_pocket_depth: float = field(default=0.036) corner_pocket_radius: float = field(default=4 * 25.4 / 1000) corner_jaw_radius: float = field(default=4 * 25.4 / 1000) side_pocket_width: float = field(default=0.087) side_pocket_angle: float = field(default=0) side_pocket_depth: float = field(default=0.95 * 25.4 / 1000) side_pocket_radius: float = field(default=1.68 * 25.4 / 1000) side_jaw_radius: float = field(default=2.5 * 25.4 / 1000) # For visualization height: float = field(default=0.708) lights_height: float = field(default=1.99) model_descr: TableModelDescr = field(factory=TableModelDescr.null) table_type: TableType = field(init=False, default=TableType.SNOOKER)