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)
  • 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.107 ms, p95 0.233 ms, p95 miss 3.399e-02 m
balanced: median 0.219 ms, p95 0.492 ms, p95 miss 7.287e-03 m
precise:  median 0.265 ms, p95 0.583 ms, p95 miss 7.655e-06 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.5.1.tar.gz (40.0 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.5.1-cp312-cp312-win_amd64.whl (124.6 kB view details)

Uploaded CPython 3.12Windows x86-64

ballistic_solver-0.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (149.9 kB view details)

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

ballistic_solver-0.5.1-cp312-cp312-macosx_10_13_universal2.whl (237.7 kB view details)

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

ballistic_solver-0.5.1-cp311-cp311-win_amd64.whl (123.4 kB view details)

Uploaded CPython 3.11Windows x86-64

ballistic_solver-0.5.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (148.3 kB view details)

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

ballistic_solver-0.5.1-cp311-cp311-macosx_10_9_universal2.whl (237.3 kB view details)

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

ballistic_solver-0.5.1-cp310-cp310-win_amd64.whl (122.7 kB view details)

Uploaded CPython 3.10Windows x86-64

ballistic_solver-0.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (146.8 kB view details)

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

ballistic_solver-0.5.1-cp310-cp310-macosx_10_9_universal2.whl (235.2 kB view details)

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

File details

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

File metadata

  • Download URL: ballistic_solver-0.5.1.tar.gz
  • Upload date:
  • Size: 40.0 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.5.1.tar.gz
Algorithm Hash digest
SHA256 ee16432d3da7613412e0a653e80251437684876856faa6f9b696b74a38d09272
MD5 7957eda54d49066f72b25273b45d6b48
BLAKE2b-256 e1dfff41f3d5d9d917018d4e892edcab568e942d889f01445f014b33508be8ab

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ballistic_solver-0.5.1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 8e958d5ebd2b0f5523bae8bdb69ff825b875e970b1323484ab6540bcfcb4ac1d
MD5 3a0947d9761fce98651df4d602caed89
BLAKE2b-256 6fff07e894344fe828e2b31c05d07bd33a98271bc13be588b1281456cc3c1772

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ballistic_solver-0.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 26972468fc6044b1df0e19181f06a7540ce3d9e154a047971726034c7a3d3382
MD5 c90552c62d34b57469394ca021f5811c
BLAKE2b-256 f31c5514d1975d0c6d89b304857dfac3812ef009776db54061905a4312fddf27

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ballistic_solver-0.5.1-cp312-cp312-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 efed9c485bbd8d800c1359afb865ac4e49be9686ef3cb36b16f180f7c599a365
MD5 152cad58672bade7f32216c1e0a87a85
BLAKE2b-256 075c09985a1fb6ac3827e9c8baf03473538b33952ac1d5b4894880d314ac1c32

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ballistic_solver-0.5.1-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 0546d13f4ca6e27b3970dffc3fef082fa9658ce4bab9965c16383fd4d583a2fe
MD5 cfa833ea8c1d9f3867e9f3c137cc7891
BLAKE2b-256 5a45887181cffc02e5c7000c578c8bbed4b484a1135be393b509eff2aa8d237d

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ballistic_solver-0.5.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 de0906e838ac0e714507c4024349d5ca5d393521794462ae9ea3f7aa4fa91b19
MD5 bf83cb6b6155274ec2d1dfe57edfc4eb
BLAKE2b-256 78e0bde95f590403efb1fcdfe40a29add6ba312d4dbeebea3371c900c2eede8c

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ballistic_solver-0.5.1-cp311-cp311-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 e17f763101ea6514d319bf8c52b9c64988d687dea16aa2fe5446df6304705d4f
MD5 05a7237466345b125d830069ed5eabbc
BLAKE2b-256 cab101d32225f7b508f2d7f06c473550479389a0ead92c6aa77cb1aa644755bc

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ballistic_solver-0.5.1-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 025910fce114196f77892edd46b0ce8e101a6d5ceb78d9f958c004e6774c16fa
MD5 f421556b604dc94a6ad77626ba007d53
BLAKE2b-256 8a3f2f84ff8c285b8c4d038de8169c95f2e13bb501fb92e81d03cb965880dc66

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ballistic_solver-0.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 76e56a965e4dfff96d1cd6f737901356ede86dabb41d73d41c0603e11239a594
MD5 e2cd485b480553f9b8242ea9138fa8b3
BLAKE2b-256 4ab7ecb4feb151b62551e6d825e3e75e8ba51941bfa7134ddc3ec1c700abdbc3

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for ballistic_solver-0.5.1-cp310-cp310-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 d2cbeb6175b7501716da47d50cdf9e9d48caaa7e06fd615aa7773c53198eb30e
MD5 ad768de26b2ab40d8c7d93f929f3e96e
BLAKE2b-256 d4ecf6eec26377c75e3ab342f9904fa58c87dd607b3d5247c9391c8c69584c48

See more details on using hashes here.

Provenance

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