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.0.tar.gz (40.9 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.0-cp312-cp312-win_amd64.whl (126.0 kB view details)

Uploaded CPython 3.12Windows x86-64

ballistic_solver-0.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (150.9 kB view details)

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

ballistic_solver-0.6.0-cp312-cp312-macosx_10_13_universal2.whl (239.4 kB view details)

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

ballistic_solver-0.6.0-cp311-cp311-win_amd64.whl (124.9 kB view details)

Uploaded CPython 3.11Windows x86-64

ballistic_solver-0.6.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (149.7 kB view details)

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

ballistic_solver-0.6.0-cp311-cp311-macosx_10_9_universal2.whl (239.1 kB view details)

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

ballistic_solver-0.6.0-cp310-cp310-win_amd64.whl (124.0 kB view details)

Uploaded CPython 3.10Windows x86-64

ballistic_solver-0.6.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (147.9 kB view details)

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

ballistic_solver-0.6.0-cp310-cp310-macosx_10_9_universal2.whl (236.7 kB view details)

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

File details

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

File metadata

  • Download URL: ballistic_solver-0.6.0.tar.gz
  • Upload date:
  • Size: 40.9 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.0.tar.gz
Algorithm Hash digest
SHA256 847cacba3c0efc046c1a99b2881e09c518865d8debf5c456f4c693b8ec5e7c6b
MD5 6fe7f3dd64ab6910125005de53840fdf
BLAKE2b-256 d2f00c9992fa9ce7e202a703552c746911588a22239f7f61d96a30e5863392b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0.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.0-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 86ae5a84820d115978d1fc570d32360a9ef170d3ad9e34480f2cf61fe4472723
MD5 5d3d2314878da9e63be3f186dffa0084
BLAKE2b-256 424027f63176c29116240ba2c5d5d1d394f518297eaa40b849b6f0716a37cd69

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0-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.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c6b75334404f9c5080801b19fb649bace83722b7277c4a5173832874018c6c93
MD5 122aae99e758daa9cea1789af672d2f5
BLAKE2b-256 317beb03fbbdd7ee6899119be98a09c7d9e00dab4315cb6e0ed0aace6ead2857

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0-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.0-cp312-cp312-macosx_10_13_universal2.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.0-cp312-cp312-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 6f87f570564fec695a2520cc21189460115be2791b7cdb43684f15f12942741b
MD5 6ddef2509eb6b31dc46dd7f2de30296b
BLAKE2b-256 830d92d1665fc84be765c34effc0d872b4efdf7f787af269488e6440eee955c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0-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.0-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 93541466362c9dc7264532ccd25ebac3fc9070191bcbf51f179341f112c41d39
MD5 b622e8922885fa923d0a04030e2454a1
BLAKE2b-256 fe91be305cac5191864dc2ee2b36f1e284d5ff04981f16f83a9688765d4e782b

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0-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.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ec23b0fabdc73a5e6d29c10c13c18200cca9b166febb6f4e45de4a060ac5d08f
MD5 14e0ce341e994e6233ff882f9d450b4a
BLAKE2b-256 c4351c351c01c7732b78e8412c5a44721c6049b480df09d5162d687e9daafdf9

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0-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.0-cp311-cp311-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.0-cp311-cp311-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 7b0d27e929974c62fccd6858a586274da9b3abf12125285d5a58318bdead9bf9
MD5 a1d1f0f1681b8710e908fa6201a65086
BLAKE2b-256 c367079051abf4f64859088b9474eced0e331e2a5038f3c352403bc4d547f50a

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0-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.0-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 d3bff2965c6c29244564ed0c56ebf458af955ab054e6909ee7cffced6dffd732
MD5 9544cb07180ca9f10b8c41a913c40963
BLAKE2b-256 dcf335319302ffa3dc60e5ba78b815138dd53ffd6b6809f15293132271357e08

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0-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.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 59c5c4cc2dcde32fb8bae3e9cd264a4202cb2ece0d16ef20ac6e92d46934b171
MD5 fc9d0f5f7be39d80e50e01db9b30e8f3
BLAKE2b-256 f79bd41d02c66a5994ae040d15d9c14aa9332eb162718a14e6fd171bf9fc4421

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0-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.0-cp310-cp310-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for ballistic_solver-0.6.0-cp310-cp310-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 e0fb54ebf2b18c990362411fab83f9b9b5eac428d7e8e919c43dddea509696e2
MD5 ef1f49c126137527ef66d510d4478a59
BLAKE2b-256 d1458622175c0bb60269f2b2a538f1a3c452900317f541944b75590852e67b5d

See more details on using hashes here.

Provenance

The following attestation bundles were made for ballistic_solver-0.6.0-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