Skip to main content

Numerical launch-angle solver for moving targets under gravity and quadratic drag.

Project description

Official repository notice

This is the only official repository for ballistic-solver.

Official repository: https://github.com/ujinf74/ballistic-solver

Do not download ZIP files, binaries, or installers from third-party copies, mirrors, or reuploads. Use only the Releases page of this repository.

banner

CI Release Native + PyPI PyPI License

ballistic-solver is a native C/C++ numerical solver that computes launch angles to intercept moving targets under gravity and quadratic air drag, with optional wind.

Unlike vacuum / closed-form solvers, this project simulates the projectile and solves the intercept numerically, aiming for robust real-time use even when trajectories are strongly curved.


Quick start

Python (PyPI)

pip install ballistic-solver

Requires Python >= 3.10.

import ballistic_solver as bs

result = bs.solve(
    relPos0=(120, 30, 5),
    relVel=(2, -1, 0),
    v0=90,
    kDrag=0.002,
)

print(result["theta"], result["phi"], result["miss"])
print(result["success"], result["status"], result["message"])

For tighter convergence without manually tuning every knob:

params = bs.params_preset("precise")
result = bs.solve((120, 30, 5), (2, -1, 0), 90, 0.002, params=params)

For repeated solves, Python also provides a thin convenience wrapper:

solver = bs.Solver.preset("precise")
result = solver.solve((120, 30, 5), (2, -1, 0), 90, 0.002)

Demo (Unity)

Highly curved trajectories under strong air drag, still converging to a hit against moving targets.

https://github.com/user-attachments/assets/c0c69cdd-0dd4-4606-9c7d-f21dd002d7f7


Why this solver

Many launch-angle solvers depend on vacuum assumptions or partially linearized models. This project instead simulates the projectile and solves the intercept numerically, targeting robustness in real-time simulations and integration scenarios.


Key properties

  • Moving targets supported
  • Constant-acceleration targets supported via the extended API
  • Strong air resistance (quadratic drag) supported
  • Low / High arc selection (since v0.2)
  • Wind vector supported (since v0.3)
  • Extended C ABI utilities (since v0.4)
  • Quartic vacuum-lead initialization for moving targets (since v0.6)
  • Fast / balanced / precise solver presets
  • Physical drag helper: kDrag = 0.5 * rho * Cd * area / mass
  • Robust in strongly nonlinear regimes (no analytic assumptions)
  • Best-effort result returned even without perfect convergence
  • Explicit success / failure reporting (+ diagnostic message)
  • Stable C ABI for multi-language use
  • Header-only C++ core
  • Easy install via PyPI: pip install ballistic-solver

Python API

solve(...)

solve(relPos0, relVel, v0, kDrag, arcMode=0, params=None) -> dict
  • relPos0: target relative position at t=0 (x,y,z)
  • relVel: target relative velocity (x,y,z)
  • v0: muzzle speed (scalar)
  • kDrag: quadratic drag coefficient
  • arcMode: 0/1 or "low"/"high" (case-insensitive)
  • params: optional BallisticParams for advanced tuning (gravity, wind, integrator and solver knobs)

Returned dict keys include:

  • success (bool)
  • theta, phi (radians)
  • miss (closest-approach distance)
  • tStar (time of closest approach)
  • relMissAtStar (3-vector miss at tStar)
  • status (SolveStatus integer)
  • message (short diagnostic string)
  • plus convergence diagnostics (iterations, acceptedSteps, lastLambda, lastAlpha)

Utilities

params = bs.params_preset("fast")  # or "balanced", "precise"
kDrag = bs.k_drag_from_physical(
    airDensity=1.225,
    dragCoefficient=0.30,
    area=0.00426,
    mass=0.145,
)

For constant-acceleration targets:

result = bs.solve_accel(
    relPos0=(120, 30, 5),
    relVel=(2, -1, 0),
    relAcc=(0, 0.2, 0),
    v0=90,
    kDrag=0.002,
    params=bs.params_preset("precise"),
)

Solver validity note

The solver internally integrates projectile motion using:

  • 4th-order Runge–Kutta (RK4)
  • Fixed timestep dt
  • Quadratic drag: a = (0, 0, -g) - kDrag * |v - wind| * (v - wind)
  • Wind as air velocity

To match in-game ballistics, your runtime simulation must use the same physical model and integrator configuration.

If your game uses a different integrator (e.g., Euler) or a different timestep, the computed launch angles may not hit even if the solver reports success.


C ABI (stable interface)

Primary intercept API:

void ballistic_inputs_init(BallisticInputs* in);
int32_t ballistic_solve(const BallisticInputs* in, BallisticOutputs* out);

Return value policy:

  • 0: API call completed and out was filled.
  • <0: API-level failure, such as null pointers or an internal exception.
  • Numerical solve success is reported separately by out->success and out->status.
  • ABI v3 adds convergence diagnostics to BallisticOutputs: iterations, acceptedSteps, lastLambda, and lastAlpha.

Callers should check both:

int32_t rc = ballistic_solve(&in, &out);
if (rc != 0) {
    /* API call failed */
}
if (!out.success) {
    /* Solver ran but did not satisfy the requested tolerance. */
}

Since v0.4.0, additional utility functions are available:

void ballistic_rk4_step(...);

int32_t ballistic_simulate_trajectory(...);
int32_t ballistic_simulate_trajectory_from_angles(...);

int32_t ballistic_find_closest_approach(...);

int32_t ballistic_vacuum_arc_angles_to_point(...);
void ballistic_initial_guess_vacuum_lead(...);

Additional extended APIs include:

void ballistic_accel_inputs_init(BallisticAccelInputs* in);
int32_t ballistic_solve_accel(const BallisticAccelInputs* in, BallisticOutputs* out);
int32_t ballistic_inputs_apply_preset(BallisticInputs* in, int32_t preset);
int32_t ballistic_k_drag_from_physical(...);
int32_t ballistic_make_relative_motion(...);

See ballistic_solver_c_api.h for full signatures and parameter definitions.

This enables usage from:

  • C / C++
  • Python (ctypes via the C ABI)
  • C# / .NET / Unity (P/Invoke)
  • Unity (UnityEngine.Vector3 wrapper example)
  • Godot 4 (GDExtension addon-style example)
  • Others via FFI

Prebuilt native binaries are provided via GitHub Releases.


Arc mode (since v0.2)

C ABI convention:

  • arcMode = 0 → Low
  • arcMode = 1 → High

High arc example:

https://github.com/user-attachments/assets/4334ed87-597e-4ad4-b21e-c1a1a17e8cd8


Wind (since v0.3)

C ABI convention:

  • wind[3] = air velocity vector (same frame as relPos0/relVel)
  • Drag uses relative airspeed: v_rel = v_projectile - wind

Wind demo:

https://github.com/user-attachments/assets/1cd998cf-34db-4a74-8817-c6393227ef4e


Using prebuilt binaries (C ABI)

Download the archive for your platform from Releases.

Each release contains:

  • Shared library

    • Windows: ballistic_solver.dll
    • Linux: libballistic_solver.so
    • macOS: libballistic_solver.dylib
  • C ABI header: ballistic_solver_c_api.h


C# / Unity usage

A C# P/Invoke example is available in:

examples/dotnet/

On Windows, place ballistic_solver.dll next to the executable (or ensure it is discoverable via PATH), then call ballistic_solve via DllImport.

This works directly inside Unity.


How it works (high level)

  1. Simulate projectile motion using RK4 integration with drag (+ wind)
  2. Track the closest approach between projectile and target
  3. Express the miss at closest approach as an angular residual
  4. Solve the nonlinear system using damped least squares (Levenberg–Marquardt)
  5. Accelerate Jacobian updates with Broyden-style refinement
  6. Return the best solution found

Failure cases are explicitly detected and reported.


When solving can fail

The solver returns a best-effort result even when it cannot satisfy tolMiss. Common causes include:

  • invalid inputs (v0 <= 0, non-positive g, dt, tMax, or maxIter)
  • geometrically unreachable vacuum targets
  • targets that require an intercept beyond tMax
  • strong drag or high-arc cases where the selected arc branch cannot be maintained
  • iteration limits that are too tight for the requested tolerance

Use success, status, message, and miss together when deciding whether to accept a solution.


Status codes (SolveStatus)

BallisticOutputs.status / Python result["status"] corresponds to:

  • 0 = Ok
  • 1 = InvalidInput
  • 2 = InitialResidualFailed
  • 3 = JacobianFailed
  • 4 = LMStepSingular
  • 5 = ResidualFailedDuringSearch
  • 6 = LineSearchRejected
  • 7 = LambdaTriesExhausted
  • 8 = MaxIterReached

message contains a short diagnostic string.


Build from source

cmake -S . -B build
cmake --build build -j
ctest --test-dir build

The shared library target is ballistic_solver.

Regression and benchmark

Distributed regression and benchmark scripts are available:

python tests/random_regression.py
python benchmarks/linear_cases.py

The CI workflow runs CTest smoke coverage plus the Python regression script. The regression script includes analytic vacuum checks, constructed moving-target vacuum cases, unreachable-target checks, randomized linear cases, and constant-acceleration API smoke coverage.

Experimental solver-variant benchmarks live under tools/bench_variants/. They are local development tools and are intentionally excluded from source distributions.

Benchmark numbers depend on CPU, OS, compiler, build type, Python version, and whether native or Python entrypoints are measured. Record those fields when publishing comparisons.

Reference result from a local Windows Release build, 500 generated linear-target cases:

fast:     median 0.094 ms, p95 0.228 ms, p95 miss 3.834e-02 m
balanced: median 0.182 ms, p95 0.452 ms, p95 miss 5.351e-03 m
precise:  median 0.199 ms, p95 0.569 ms, p95 miss 5.742e-06 m

High-arc moving-target convergence update, local Windows Release build, 500 generated cases:

Solver configuration Success Median runtime P95 runtime P95 miss
Previous core path 382/500 (76.40%) 4.301 ms 27.124 ms 3.227e+02 m
v0.6.0 defaults 490/500 (98.00%) 1.845 ms 2.535 ms 8.809e-03 m

ABI notes

  • Plain C layout across the ABI boundary
  • Fixed-size arrays only
  • No dynamic allocation across the boundary

License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ballistic_solver-0.6.1.tar.gz (43.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

ballistic_solver-0.6.1-cp312-cp312-win_amd64.whl (136.5 kB view details)

Uploaded CPython 3.12Windows x86-64

ballistic_solver-0.6.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (165.0 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

ballistic_solver-0.6.1-cp312-cp312-macosx_10_13_universal2.whl (268.5 kB view details)

Uploaded CPython 3.12macOS 10.13+ universal2 (ARM64, x86-64)

ballistic_solver-0.6.1-cp311-cp311-win_amd64.whl (135.2 kB view details)

Uploaded CPython 3.11Windows x86-64

ballistic_solver-0.6.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (163.5 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

ballistic_solver-0.6.1-cp311-cp311-macosx_10_9_universal2.whl (268.1 kB view details)

Uploaded CPython 3.11macOS 10.9+ universal2 (ARM64, x86-64)

ballistic_solver-0.6.1-cp310-cp310-win_amd64.whl (134.4 kB view details)

Uploaded CPython 3.10Windows x86-64

ballistic_solver-0.6.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (161.8 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

ballistic_solver-0.6.1-cp310-cp310-macosx_10_9_universal2.whl (265.7 kB view details)

Uploaded CPython 3.10macOS 10.9+ universal2 (ARM64, x86-64)

File details

Details for the file ballistic_solver-0.6.1.tar.gz.

File metadata

  • Download URL: ballistic_solver-0.6.1.tar.gz
  • Upload date:
  • Size: 43.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ballistic_solver-0.6.1.tar.gz
Algorithm Hash digest
SHA256 75bea87d1f4492a6c4baac1ba49758aa40b85738d925deb95b0b06d513d27f45
MD5 f9d6db3ade2d1f029b5af26d2d3badca
BLAKE2b-256 0eb7ac1db4b872d0c41aaa43a54c17e8f653727d001e84e752e72a6dbc565a05

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1.tar.gz:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ballistic_solver-0.6.1-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 c0b0dc89268571ef1d9a7cacd407bd677a00ceb9d419de04ede156dfe9e93f49
MD5 9c8d1780f193b06b5cdd11b8207126e0
BLAKE2b-256 5701cc7357bc1303e722de27bd3f14527596785e65f1769101d61a9e498ca309

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1-cp312-cp312-win_amd64.whl:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ballistic_solver-0.6.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 660801a8cda604194e9a186b55fb8db19d0b2fe690e51cec07c0706c1933b83b
MD5 b24f29375086e6d7889e1daf4f411ffa
BLAKE2b-256 9eda96a70d3a59cbbfe114a9c7e4f4cad14aab7868b0c035214e62c35cf06942

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ballistic_solver-0.6.1-cp312-cp312-macosx_10_13_universal2.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.1-cp312-cp312-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 636a24065e87eaa92f38f6165ce933e890cb55e4ccf35993006c28086cafaa88
MD5 0e97db0bc1862a88097c4230b3225134
BLAKE2b-256 a65249d8353738f907d89a121f3b9f45eeaf7b5bec3dac94033e78a9f604c70e

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1-cp312-cp312-macosx_10_13_universal2.whl:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ballistic_solver-0.6.1-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.1-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 f30789828cbc6ec8359118681d6ff0af0c574e1bf3e032bf47271bc2c962acbc
MD5 09b47ae27b668bfdecf9480d45239314
BLAKE2b-256 6265325c37af98d3a2207a354db47850490dbf3b1ccbe377f983b28c788acfac

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1-cp311-cp311-win_amd64.whl:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ballistic_solver-0.6.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 bcae9bf1948fe0138852f512033aaea694e58a4bf269a60467ae2d2331fb750d
MD5 b0cc944edb836c454ac1f9b5b3e4391b
BLAKE2b-256 a85a1502ae2fdbe8b354a405fb9b27e4adda301695ab5f4d9c6eedf1eaf18df2

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ballistic_solver-0.6.1-cp311-cp311-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.1-cp311-cp311-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 fa661dc4d1903fc66ab6b352a15a5639dac8b5b7101a7facaa5a5faad490b66d
MD5 59f618d01172d7b137a4172af7c4a575
BLAKE2b-256 1f03ce7f38c62caf08ea999cfa19a26b487e28eb9a1a06e44d32a11271b79286

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1-cp311-cp311-macosx_10_9_universal2.whl:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ballistic_solver-0.6.1-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.1-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 0ab4bcc28f040d0b841c561e6532ce594a96802862a7113b0ffc89b42f3bcd31
MD5 2f3062230d0170365f5a9902a293d02e
BLAKE2b-256 32e77d4d9f068ab90f0ac68a87314bbf52ef07dfd6b438fd04b2b2a7df938920

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1-cp310-cp310-win_amd64.whl:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ballistic_solver-0.6.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 3b17eba86456ee69659d0e565cfa8184b8d23fc5c369f129db069638bd944503
MD5 f9a9c591805e62403a639e9812106c19
BLAKE2b-256 6c8c44197515370564ef7af046476dc4329ac9bf4456113c6949feeee41eb4c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ballistic_solver-0.6.1-cp310-cp310-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.1-cp310-cp310-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 133f99da6ce9211c59cb536910e5c65bf545f5329ac14c0c19e0a92c342342b7
MD5 881f61014db818397fe385d93b39d561
BLAKE2b-256 fbdc270064406d9c52a068ffc0a1f04eb7141363de0acdaa57f5f214d53969f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.1-cp310-cp310-macosx_10_9_universal2.whl:

Publisher: release.yml on ujinf74/ballistic-solver

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page