BallPhysicsEngine

BallPhysicsEngine is the 9-Dimensional aerodynamic and multi-surface contact simulator in PadelKit. It integrates gravity, felt-adjusted quadratic air drag, and non-linear Spindt Magnus lift via 4th-order Runge-Kutta (RK4), and resolves collisions against the floor, stepped walls/fences, and catenary net of a Court.

RK4 Simulated Spin Trajectories
Side-elevation trajectories simulated via BallPhysicsEngine.simulate() contrasting topspin smash, flat drive, and backspin bandeja rebounds.

Properties

  • Name
    court
    Type
    Court
    Description

    The Court geometry defining floor bounds, stepped wall/glass heights (3m vs 4m), metallic fences, and net profile.

  • Name
    ball
    Type
    BallProperties
    Description

    Physical ball specification (mass, radius, drag and felt fuzz coefficients). See BallProperties.

  • Name
    environment
    Type
    EnvironmentConditions
    Description

    Atmospheric conditions (gravity, air density, temperature, altitude, wind velocity). See EnvironmentConditions.

  • Name
    surfaces
    Type
    SurfaceMaterials
    Description

    Coefficients of restitution (COR) and Coulomb friction (mu) for floor, glass, wall, fence, and net. See SurfaceMaterials.


methodengine.simulate()

Simulate a Trajectory

Integrates a BallState forward in time using RK4 (dt = 0.002s by default), resolving all court surface rebounds and recording every BounceEvent. Returns a BallTrajectory.

Arguments

  • Name
    initial_state
    Type
    BallState
    Description

    Initial 9D state [x, y, z, vx, vy, vz, wx, wy, wz].

  • Name
    duration
    Type
    float
    Description

    Maximum simulation duration in seconds.

  • Name
    dt
    Type
    float
    Description

    Integration time step in seconds (500 Hz default).

  • Name
    stop_on_net
    Type
    bool
    Description

    If True, stops the simulation immediately after a net collision.

  • Name
    max_bounces
    Type
    int | None
    Description

    Optional maximum number of bounces before terminating early.

  • Name
    stop_below_speed
    Type
    float
    Description

    Stops simulation when ball speed drops below this threshold (m/s) on the floor.

Usage

method
simulate
from padelkit import BallPhysicsEngine, BallState

engine = BallPhysicsEngine()
shot = BallState.from_shot(
    position=(0.0, -7.0, 1.1),
    velocity=(1.5, 19.0, 3.2),
    topspin_rpm=2200.0,
)

trajectory = engine.simulate(shot, duration=2.5, max_bounces=3)
print(f"Samples: {len(trajectory.times)}, Bounces: {len(trajectory.bounces)}")

Output

Samples: 842, Bounces: 3

methodengine.simulate_batch()

Vectorized Batch Simulation

Simulates N independent 9D ball trajectories simultaneously using vectorized NumPy arrays. Ideal for Monte Carlo shot dispersion analysis, reinforcement learning rollouts, and synthetic dataset generation.

Arguments

  • Name
    initial_states
    Type
    np.ndarray | Sequence[BallState]
    Description

    Array of shape (N, 9) or sequence of N BallState instances.

  • Name
    duration
    Type
    float
    Description

    Total simulation duration in seconds.

  • Name
    dt
    Type
    float
    Description

    RK4 integration time step in seconds.

Returns

  • Name
    times
    Type
    np.ndarray
    Description

    1D array of timestamps in seconds of shape (T,).

  • Name
    states
    Type
    np.ndarray
    Description

    3D float64 tensor of shape (N, T, 9) containing [x, y, z, vx, vy, vz, wx, wy, wz] for all N trajectories across all T steps.

Batch Simulation

method
simulate_batch
import numpy as np
from padelkit import BallPhysicsEngine

engine = BallPhysicsEngine()

# 100 shots with randomized launch angles and topspin
n_shots = 100
states_0 = np.zeros((n_shots, 9), dtype=np.float64)
states_0[:, 1] = -8.0                        # y0 = -8m
states_0[:, 2] = 1.2                         # z0 = 1.2m
states_0[:, 4] = np.linspace(14.0, 22.0, n_shots)  # vy
states_0[:, 5] = 3.5                         # vz
states_0[:, 6] = 200.0                       # topspin wx (rad/s)

times, batch_states = engine.simulate_batch(states_0, duration=2.0)

Output

# batch_states.shape
(100, 1001, 9)

methodengine.step() / resolve_collision()

Single-Step & Collision Primitives

For custom control loops or frame-by-frame interactive games, BallPhysicsEngine exposes its low-level physics primitives directly:

  • Name
    step(state, dt=0.002, t=0.0)
    Type
    tuple[BallState, BounceEvent | None]
    Description

    Advances a BallState by a single timestep dt using RK4 and resolves any court surface collision.

  • Name
    compute_acceleration(velocity, angular_velocity)
    Type
    np.ndarray
    Description

    Computes the instantaneous 3D acceleration vector (ax, ay, az) in m/s^2 combining gravity, quadratic drag, and Spindt Magnus lift.

  • Name
    resolve_collision(velocity, angular_velocity, normal, surface)
    Type
    tuple[np.ndarray, np.ndarray, ContactRegime]
    Description

    Computes post-impact linear velocity v', angular velocity w', and ContactRegime (SLIDING, ROLLING, or DAMPED) against a unit surface normal n.

Low-Level Step

method
step
import numpy as np
from padelkit import BallPhysicsEngine, SurfaceType

engine = BallPhysicsEngine()

# Inspect post-bounce velocity & spin on turf floor
v_in = np.array([0.0, 15.0, -8.0])
w_in = np.array([-250.0, 0.0, 0.0])  # heavy backspin
normal = np.array([0.0, 0.0, 1.0])

v_out, w_out, regime = engine.resolve_collision(
    v_in, w_in, normal, SurfaceType.FLOOR
)

Was this page helpful?