Add ball-table detection#298
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #298 +/- ##
==========================================
+ Coverage 47.81% 47.87% +0.06%
==========================================
Files 157 158 +1
Lines 10631 10658 +27
==========================================
+ Hits 5083 5103 +20
- Misses 5548 5555 +7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Summary
The previous PR added the ball-table resolver. This PR completes the
detector→resolver chain by adding a
BallTableDetectionstrategy that emitsBALL_TABLEevents when an airborne ball is on a trajectory to intersect thetable plane.
Nothing in
maincurrently produces airborne balls (no resolver writesconst.airbornefrom a non-airborne state), so the chain is wired butinert. 2D simulation output is byte-identical to before.
This PR also revisits and simplifies the
Dim-validation story aroundball-table that was introduced with the resolver, and patches a latent
NotImplementedErrorin the transition cache.What's in this PR
Ball-table detection
New
pooltool/evolution/event_based/detect/ball_table.py— mirrorsball_pocket.pystructurally. Single-ball iteration with a 1-tuple cache key(ball.id,). The cheap state-guard insideball_table_collision_timereturnsnp.inffor non-airborne balls, so the strategy is a fast no-op in 2D.New physics helper in
pooltool/physics/motion/solve.py:Just wraps
get_airborne_time(already inphysics/utils.pyfrom theairborne-primitives PR) with an airborne-state guard. Lives in
physics.motion.solvealongside the other*_collision_timehelpers.EventDetectorwiring (detect/detector.py):BallTableDetectionball_tablefield (afterball_pocket)ball_table.get_next(...)intoget_next_event's candidates listEventType.BALL_TABLEin_get_event_priority,mirroring the cushion-collision semantics. Carries a TODO comment noting
the choice is provisional — BALL_TABLE-vs-other ties only become real once
3D activation lands and airborne balls actually arise.
Re-exports in
detect/__init__.py:BallTableDetection,BallTableDetectionStrategy.INCLUDED_EVENTSinevent_based/config.py: addedEventType.BALL_TABLE.Harmless in 2D (detector never emits a finite-time event); correct for future
3D activation where
_SimulationState.includewould otherwise filter outBALL_TABLE at resolution time.
CollisionCache.timestype widened fromdict[EventType, dict[tuple[str, str], float]]todict[EventType, dict[tuple[str, ...], float]]. Ball-table uses a 1-tuplekey
(ball.id,)since the event involves a single ball, not a pair. Matchesthe 3d branch's precedent for the same reason.
Dimvalidation simplificationThe ball-table resolver PR introduced
Dim.THREE+DORMANT_IN_2Dto letthe validator accept a "3D-only" ball-table strategy in a 2D engine. On
reflection, that approach paid lip service to the Dim contract: in 2D the
tag was skipped (irrelevant), and in 3D the tag only ruled out a
Dim.TWOball-table strategy, which is a nonsensical configuration nobody would
write. The Dim taxonomy genuinely doesn't apply to ball-table — the slot
only conceptually exists in 3D.
Reframed this PR:
dimattribute at all. Removedfrom both protocols (
BallTableCollisionStrategy,BallTableDetectionStrategy) and both concrete resolver classes plusthe concrete detector.
_validate_dimensionalitysymmetric skip: wasif not self.is_3d and field.name in DORMANT_IN_2D: continue(asymmetric); nowif field.name in SKIP_DIMENSION: continue(applies in both modes)Dimdocstring + doc cleanupThe
Dimenum docstring previously framedDim.BOTHas "behaves identicallyin either mode," which is a stronger claim than the validator actually
requires. A
Dim.BOTHstrategy is allowed to take different code pathsdepending on its input (e.g. branch on
state == const.airborne) as long asneither path is incorrect for the mode it runs under. Updated the docstring
to frame
BOTHaround safety rather than behavioral equivalence, andmatched the wording in
docs/resources/custom_physics.md. As you can see,still sort of figuring this all out.
Side cleanup:
import pooltool as ptRemoved the
ptalias from three real-code files where it was used toaccess
pooltoolsymbols:tests/evolution/event_based/test_introspection.pytests/physics/resolve/ball_ball/test_frictional_mathavan.pypooltool/ani/constants.pyDocstring
>>>examples elsewhere that usept.*are deliberatelyunchanged — they show users the external import idiom, not the project's
internal convention.