lob 0.13.0
Exterior ballistics library — API + technical reference
Loading...
Searching...
No Matches
Getting Started

Getting Started

This is the shortest path from nothing to a trajectory. Build instructions for the library itself live in the repository's build document; this page covers getting a number out of it.

The shape of every call

Every lob call has the same three moves, whatever you are asking for.

Configure a builder, build a context from it, then solve against that context. The builder is the only mutable thing and it is mutable only during configuration. Once you have a context, it is fixed, and you can solve against it as many times as you like.

#include "lob/lob.hpp"
const lob::Context kContext = lob::Builder()
.Build();
Builder class for constructing Context objects with a friendly interface.
Definition lob.hpp:221
Context Build()
Builds the Context object with the configured parameters.
Definition lob.hpp:877
Builder & InitialVelocityFps(uint16_t value)
Sets the initial velocity of the projectile in feet per second.
Definition lob.hpp:547
Builder & BallisticCoefficientPsi(double value)
Sets the ballistic coefficient (Psi).
Definition lob.hpp:259
Builder & ZeroDistanceYds(double value)
Sets the zero distance in yards.
Definition lob.hpp:591
Structure of parameters consumed by the solver.
Definition lob.hpp:116

That is already a complete, if minimal, problem definition: a bullet with this ballistic coefficient, leaving the muzzle at this velocity, zeroed at this distance. Everything you leave out takes a documented default, so this builds successfully.

Your first forward solve

A forward solve answers "where does this land". You give it ranges, it gives you back a result for each.

#include <array>
#include <cstdint>
#include <iostream>
#include "lob/lob.hpp"
const lob::Context kContext = lob::Builder()
.Build();
int main() {
if (kContext.error != lob::ErrorT::kNone) {
return 1; // configuration was rejected; see the error code
}
const std::array<uint32_t, 3> kRanges = {300U, 600U, 900U};
std::array<lob::Output, 3> kResults = {};
const size_t solved = lob::Solve(kContext, kRanges, &kResults);
for (size_t i = 0; i < solved; i++) {
std::cout << "At " << kResults[i].range << " ft: "
<< kResults[i].elevation << " inches\n";
}
}
@ kNone
Definition lob.hpp:63
size_t Solve(const Context &ctx, const uint32_t *pranges, Output *pouts, size_t size)
Solves the exterior ballistics problem for a given set of ranges. Results contain a forward-solution.
Definition lob.hpp:899
ErrorT error
Error status after build.
Definition lob.hpp:137

The array overloads exist so that the sizes cannot disagree with each other. Raw pointer forms are available and take an explicit count.

Always check the context's error before solving, and always use the count that comes back rather than assuming every range was solved.

Now the inverse

An inverse solve answers the question a shooter actually has: what do I hold or wind by at this range. The inputs are the same ranges; the outputs are now adjustments rather than raw drop and drift.

const std::array<uint32_t, 3> kRanges = {300U, 600U, 900U};
std::array<lob::Output, 3> kResults = {};
const size_t solved = lob::SolveInverse(kContext, kRanges, &kResults);
size_t SolveInverse(const Context &ctx, const uint32_t *pranges, Output *pouts, size_t size)
Solves the exterior ballistics problem for a given set of ranges. Results contain an inverse-solution...
Definition lob.hpp:999

Same context, same ranges, different question. The elevation that came back in inches is now an adjustment in minutes of arc measured from the zero.

Ranges must be in increasing order. A table that is not is rejected rather than quietly sorted, so that a mistake shows up as a mistake.

Adding real data

The minimal example is deliberately sparse. A fuller description comes from describing the bullet properly, because the more you say, the more of lob's models can engage.

Bullet geometry, such as its diameter, length, nose profile, meplat and base, unlocks the higher-fidelity spin corrections and the velocity-band drag transformation. A muzzle crosswind is needed before aerodynamic jump can be computed at all. Weather conditions replace the standard atmosphere defaults, and every one of them can be specified independently, with the rest defaulted.

If you have a manufacturer's velocity-dependent coefficients, supply them as bands rather than picking one. That is the difference between a proportionally scaled standard curve and a curve shaped like your bullet.

Units

Builder setters name their unit. There is no setter that takes a bare double, so the compiler will stop you from passing feet where inches were meant, and from passing a mass where a length was meant.

Solutions come back in American customary units, the convention lob is built around. The C layer exposes unit conversions for callers who need to work in something else.

Where to go next

For what the numbers mean and how they are computed, the ballistic model chapter is the reference. For why the library is shaped this way, the design decisions chapter. For what has and has not been verified, and the list of things that are still unproven, read the validation page before relying on a result for anything that matters.