Run build.sh in the root directory to build and install the library. Include the main header in your source files:
#include <libshotscope.hpp>
The library uses a phase-based flight simulation architecture that automatically transitions between aerial, bounce, and roll phases. A complete simulation requires initializing four components:
const golfBall ball{0.0, 0.0, 0.0, 160.0, 11.0, 0.0, 3000.0, 0.0};
const atmosphericData atmos{70.0, 0.0, 0.0, 0.0, 0.0, 50.0, 29.92};
Field definitions are documented in include/golf_ball.hpp and include/atmosphere.hpp. Parameter validation is the responsibility of the calling code. In production use, these values typically originate from launch monitors or environmental sensors.
GroundSurface ground; // Uses default fairway properties
The GroundSurface struct defines physical surface characteristics that affect bounce and roll behavior. Default values represent typical fairway conditions. See include/ground_surface.hpp for available parameters including restitution coefficient, friction coefficients, firmness, and spin retention.
For simulations requiring different ground types throughout the trajectory (e.g., fairway → rough → green), implement the GroundProvider interface:
class MyGroundProvider : public GroundProvider {
public:
GroundSurface getGroundAt(float x, float y) const override {
// Return different surfaces based on position
// x = lateral position (feet)
// y = downrange position (feet)
}
};
MyGroundProvider provider;
FlightSimulator sim(physVars, ball, atmos, provider);
See Ground Providers Guide for details.
GolfBallPhysicsVariables physVars(ball, atmos);
This class computes derived aerodynamic coefficients from the ball and atmospheric parameters.
FlightSimulator sim(physVars, ball, atmos, ground);
The simulator manages phase transitions and numerical integration throughout the ball’s trajectory.
Create the initial ball state from sensor data. All ball parameters (position, velocity, spin) must be explicitly provided:
const float v0_fps = ball.exitSpeed * physics_constants::MPH_TO_FT_PER_S;
Vector3D start_pos{
ball.x0 * physics_constants::YARDS_TO_FEET,
ball.y0 * physics_constants::YARDS_TO_FEET,
ball.z0 * physics_constants::YARDS_TO_FEET
};
BallState initialState = BallState::fromLaunchParameters(
v0_fps,
ball.launchAngle,
ball.direction,
start_pos,
physics_constants::GRAVITY_FT_PER_S2,
physVars.getROmega() // Initial spin from backspin/sidespin
);
sim.initialize(initialState);
The fromLaunchParameters() factory method converts launch speed (ft/s), angle (degrees), and direction (degrees) into velocity components. The initial position must be converted from yards to feet. Spin magnitude is derived from the ball’s backspin and sidespin values via physVars.getROmega(). Initialization is required before advancing the simulation.
Advance the simulation using a time-stepping loop:
const float dt = 0.01F; // 10ms time step
while (!sim.isComplete())
{
sim.step(dt);
}
const BallState& finalState = sim.getState();
The step() method advances the simulation by one time increment and automatically handles phase transitions. The isComplete() method returns true when the ball has come to rest.
To capture the complete flight path for visualization or analysis:
std::vector<Vector3D> trajectory;
const float dt = 0.01F;
while (!sim.isComplete())
{
const BallState& state = sim.getState();
trajectory.push_back(state.position);
sim.step(dt);
}
trajectory.push_back(sim.getState().position); // Final position
See examples/calculate_ball_trajectory.cpp for a complete implementation.
For applications requiring only the final position:
const float dt = 0.01F;
while (!sim.isComplete())
{
sim.step(dt);
}
const BallState& finalState = sim.getState();
Vector3D landingPosition = finalState.position;
See examples/calculate_ball_landing.cpp for a complete implementation.
The library uses a right-handed coordinate system:
All position and velocity components are in feet. Use physics_constants::YARDS_TO_FEET for unit conversion when needed.
The simulator automatically manages three flight phases:
Phase transitions occur automatically based on physical conditions. The current phase can be queried using sim.getCurrentPhaseName().
When using a GroundProvider instead of a single GroundSurface, the simulator automatically queries ground properties at the ball’s current position during phase transitions. This enables realistic modeling of:
Ground is queried before each bounce and periodically during rolling (every 0.1s), so the ball automatically picks up surface changes as it moves. See the Ground Providers Guide for details.
The examples/ directory contains complete working implementations: