ballistics-engine 0.30.1 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/ballistics_engine.d.ts +16 -0
- package/ballistics_engine.js +28 -0
- package/ballistics_engine_bg.wasm +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,15 @@ A high-performance ballistics trajectory calculation engine with comprehensive p
|
|
|
10
10
|
- **Advanced Drag Models** - Full standard-projectile family (G1, G2, G5, G6, G7, G8, GI, GS, and the British RA4 reference function), each backed by its own real Mach-indexed table with automatic transonic corrections, plus user-supplied custom Cd(Mach) drag tables (`--drag-table`, used as-is with endpoint hold outside their measured domain, no transonic correction applied — see [CLI_USAGE.md](CLI_USAGE.md#custom-drag-tables); `bc_value` is ignored while a custom table is active), with an optional `--cd-scale <FACTOR>` whole-curve truing multiplier (Hornady AFF / AB CDF style; `1.0` = neutral, typical range 0.90-1.10; requires `--drag-table` — see [CLI_USAGE.md](CLI_USAGE.md#whole-curve-drag-scale---cd-scale)). `true-velocity`/`plan-truing`'s forward model is deliberately G1/G7 only. GL is out of scope — its only public source is velocity-domain data, which doesn't fit this engine's Mach-indexed table format.
|
|
11
11
|
- **Automatic Zeroing** - Calculate sight adjustments and apply zero angles automatically; `trajectory` echoes the solved bore angle (degrees, additive across table/JSON/CSV) whenever auto-zero ran, and `zero --from-angle <DEGREES>` solves the zero RANGE(S) a previously solved/stored bore angle produces — a bore angle generally implies two zeros (the classic 25/300-yard relationship), so both are reported rather than one being silently picked — so the angle can be captured once and reused later, independent of the day it was solved — see [CLI_USAGE.md](CLI_USAGE.md#solving-range-from-a-stored-angle---from-angle)
|
|
12
12
|
- **Canted-Rifle Modeling** - Model a rifle zeroed level but fired canted (`--cant <DEGREES>`, alias `--cant-angle`, on `trajectory`/`monte-carlo`); clockwise cant shifts point of impact right and low downrange for a rifle with an upward zero correction — see [CLI_USAGE.md](CLI_USAGE.md#canted-shooting)
|
|
13
|
+
- **Deliberate Zero POI Offset** - Record that the rifle is deliberately zeroed off — e.g. 0.1 in high / 0.2 in left at the zero range (Kestrel ZH/ZO semantics) — and shift the whole solution by the equivalent angular bias (`--zero-poi-up`/`--zero-poi-right`, inches imperial / cm metric, on `trajectory` and every zero-solving subcommand; solve-json `shot.zero_poi_up_m`/`zero_poi_right_m`; saved-profile fields; `.a7p` zero click counts convertible via `profile import --zero-click`) — see [CLI_USAGE.md](CLI_USAGE.md#sight-geometry-and-zero-state)
|
|
14
|
+
- **Lateral Sight Offset** - Model offset-mounted optics (`--sight-offset`, inches imperial / mm metric, positive = sight right of bore): the bullet starts that far left of the sight line and the windage zero converges it onto the sight line at the zero range — physical mount geometry, distinct from and additive with the zero POI offset (solve-json `rifle.sight_offset_lateral_m`; saved-profile field; also on `monte-carlo`/WEZ mirroring `--cant`) — see [CLI_USAGE.md](CLI_USAGE.md#sight-geometry-and-zero-state)
|
|
15
|
+
- **Multiple Named Zeroes / Per-Load Offsets in Profiles** - Store alternate zero conditions on a saved profile (Lapua Sight-In POI / ATrag zero-zone class): each named set carries an optional zero distance plus constant per-load dial corrections in mils (`profile zero-set add|remove|list`; `--zero-set NAME` on `trajectory`/`come-ups`/`wind-card`/`range-table`/`dsf`/`plan-truing`; corrections are added to total-correction dial outputs before the tracking-CF division; profile-CSV `V_OFFSET_MIL`/`H_OFFSET_MIL` columns and `.a7p --zero-click` import feed sets automatically; unknown names fail loudly listing the available sets) — see [CLI_USAGE.md](CLI_USAGE.md#named-zero-sets-and-per-load-offsets-profile-zero-set---zero-set)
|
|
16
|
+
- **Drops Reference: LOS vs Target Plane** - Reference sampled drops to the line of sight (default, unchanged) or to the vertical target plane on steep inclined shots (`trajectory --drops-reference target`: drop ÷ cos(shooting angle), JBM's "target plane" checkbox; sampled table/CSV column relabeled `Drop (target)`/`drop_target_in`; solve-json `shot.drops_reference`) — see [CLI_USAGE.md](CLI_USAGE.md#drops-reference-los-vs-target-plane---drops-reference--mba-1403)
|
|
17
|
+
- **Scope Tracking Correction Factors** - Compensate turrets that don't track their nominal click value: derive `CF = actual/dialed` from a tall-target test (`tall-target` subcommand, pure arithmetic), then `--elevation-cf`/`--windage-cf` (or validated saved-profile fields) DIVIDE every dial-unit output once at the shared conversion boundary — come-ups, range/compare/wind cards, mover lead/Ring, PDF dope card, zero MOA/mrad — never raw inches (an under-tracking scope, CF < 1, needs more dial); `true-velocity` multiplies dialed observations by the CF (scope-dial to true angular) so scope error is not baked into trued MV/BC — see [CLI_USAGE.md](CLI_USAGE.md#scope-tracking-correction-factors---elevation-cf---windage-cf-tall-target--mba-1358)
|
|
18
|
+
- **Equivalent Horizontal Range (BDC shoot-to)** - Inclined zeroed shots print the flat range whose angular correction against the same zero matches the inclined solution (SIG AMR / Leica EHR / Gunwerks style, angular-match inversion over one flat re-solve — not the rifleman's-rule cosine), so fixed BDC turrets/reticles can dial as if flat (`trajectory` summary line; solve-json `summary.equivalent_horizontal_range_m`; public `TrajectorySolver::equivalent_horizontal_range`) — see [CLI_USAGE.md](CLI_USAGE.md#equivalent-horizontal-range-bdc-shoot-to--mba-1395)
|
|
19
|
+
- **Reticle Hold Points** - Place a firing solution where you actually read it: a point in your own reticle, FFP/SFP aware with second-focal-plane subtensions rescaled for the magnification in use (`reticle hold`, native + browser terminal + a new appended C ABI export; `reticle generate mil-grid|tree|bdc` builds descriptions in one shared serde schema that saved profiles, `--reticle-json` and solve-json's optional `reticle` block all speak). Horus/TREMOR grid layouts, wind-dot calibration and any vendor catalog are deliberately excluded — see [CLI_USAGE.md](CLI_USAGE.md#reticle-hold-points-reticle--mba-1361)
|
|
20
|
+
- **Reticle/BDC Inverse Solvers** - Three read-only solvers over an existing load, sharing one drop-vs-range root find: `mark-to-range` maps each reticle subtension to the range where it lands (Nightforce / Nikon Spot On / Swarovski / TRACT), reporting marks the load cannot reach rather than dropping them; `bdc-match` fits the magnification that makes an SFP BDC reticle match the load (Zeiss Rapid-Z; closed-form least squares, with a residual warning when nothing fits); `optimal-zero` min-max searches the one zero that minimizes the largest hold a whole target list needs and reports whether a dead-center hold keeps each inside its vital zone (GeoBallistics HDZ). CLI-only this train — see [CLI_USAGE.md](CLI_USAGE.md#reticlebdc-inverse-solvers--mba-1362)
|
|
21
|
+
- **Robust Hold Corridors** - Solve a bounded set of NAMED segmented-wind scenarios at once (`hold-corridor --scenarios set.json --ranges 200,400,600 [--target rect:WxH|circle:D]`) and get, at every range, each scenario's hold, the min/max corridor they span, the minimax (Chebyshev-center) hold, the worst-case miss from it, and whether one hold keeps every scenario inside the target — with a versioned `RobustHoldReportV1` JSON form. Caps (≤8 scenarios, ≤64 ranges) and malformed segments are structured errors raised *before* any solving, and reordering scenarios cannot change the answer. No probabilities are assigned anywhere: the corridor is the span of the hypotheses you supplied, not a confidence interval — see [CLI_USAGE.md](CLI_USAGE.md#robust-hold-corridors-hold-corridor--mba-1349)
|
|
13
22
|
- **Moving-Target Lead** - Wind-aware hold tables for targets moving at a constant speed/angle, with iterative intercept-range correction for non-perpendicular motion (`lead` subcommand; public `ballistics_engine::calculate_lead` API) — see [CLI_USAGE.md](CLI_USAGE.md#moving-target-lead)
|
|
14
23
|
- **Mover Ring** - Field-tested alternative for engaging movers: a per-point ring radius (`target_speed × time-of-flight`) falls out of an already-solved trajectory with no second command or re-entered ballistic data (`trajectory --target-speed`, additive across table/JSON/CSV output); `lead` also gained `trajectory`'s powder-temperature flags for muzzle-velocity parity between the two — see [CLI_USAGE.md](CLI_USAGE.md#mover-ring---target-speed)
|
|
15
24
|
- **Side-by-Side Load Comparison** - Compare 2-8 loads at identical conditions with per-load independent zeroing (`compare --load "NAME:DRAG:BC:MASS:VELOCITY[:DIAMETER]"`, mixable with saved profiles); JSON/CSV output carries per-row deltas against the first load — see [CLI_USAGE.md](CLI_USAGE.md#load-comparison-compare)
|
|
@@ -17,6 +26,8 @@ A high-performance ballistics trajectory calculation engine with comprehensive p
|
|
|
17
26
|
- **Unit Conversion** - Seamless switching between Imperial (default) and Metric units
|
|
18
27
|
- **BC Segmentation** - Velocity-dependent ballistic coefficient modeling with automatic estimation
|
|
19
28
|
- **Atmospheric Modeling** - Temperature, pressure, humidity, and altitude effects with ICAO standard atmosphere; also accepts a single **density altitude** reading (`trajectory --density-altitude`, feet imperial / meters metric) as a direct alternative to entering altitude/pressure/temperature separately — back-solves an ISA-equivalent atmosphere (preserving Mach/lapse-rate/segmented-atmosphere behavior, not a density-only shortcut) and supersedes `--altitude`/`--pressure`/`--pressure-type` entirely, with an explicit `--temperature` still honored for correct powder-temperature sensitivity — see [CLI_USAGE.md](CLI_USAGE.md#density-altitude-as-a-direct-input---density-altitude)
|
|
29
|
+
- **Clock-Position Wind Entry** - Enter wind direction as the dominant field convention: marked clock positions (`--wind-direction 3oc`, `10h30`, or `10:30`; 12 o'clock = headwind, minutes count 0.5°) alongside plain degrees on every wind-direction flag and the WASM terminal; inside `--wind-segment` the colon-free forms apply (`10:3oc:400`) while `10:30:400` keeps its numeric SPEED:ANGLE:DIST meaning; bare numbers stay degrees everywhere — see [CLI_USAGE.md](CLI_USAGE.md#wind-direction-entry-degrees-clock-positions--mba-1367)
|
|
30
|
+
- **Earth-Fixed Compass Wind Bearings** - Store wind as absolute compass bearings and let the solver re-reference them against the shot azimuth (`--wind-ref compass` + `--shot-direction` on `trajectory`/`monte-carlo`; covers the single direction, location-CSV WIND_DIR, and every `--wind-segment` angle; Monte Carlo converts before dispersion sampling; solve-json `wind.wind_reference`; WASM builder `setWindReference`/`setShotDirection`; wind FROM north on a shot due north = pure headwind, pinned) — see [CLI_USAGE.md](CLI_USAGE.md#earth-fixed-compass-bearings---wind-ref-compass--mba-1368)
|
|
20
31
|
- **Wind Effects** - 3D wind calculations with altitude-dependent wind shear modeling, **downrange-segmented wind** (`--wind-segment SPEED:ANGLE:DIST[:VERTICAL]`, repeatable — model wind that varies along the path, e.g. muzzle plus downrange sensor readings), and **vertical wind** (`--wind-vertical <SPEED>` on `trajectory`/`monte-carlo`, or the segment's optional 4th field; positive = updraft, raises point of impact) — see [CLI_USAGE.md](CLI_USAGE.md#vertical-wind)
|
|
21
32
|
- **Oblique Wind-Drift Cards** - Wind dope cards at any wind-FROM angle, not just full-value 90° crosswind (`wind-card --wind-angle <DEG>` or `--wind-angles <CSV>` for one card per angle); each cell is a real trajectory solve, default (no flags) unchanged from the classic full-value 90° card — see [CLI_USAGE.md](CLI_USAGE.md#wind-card)
|
|
22
33
|
- **Monte Carlo Simulations** - Statistical analysis with parameter uncertainties
|
|
@@ -31,6 +42,7 @@ A high-performance ballistics trajectory calculation engine with comprehensive p
|
|
|
31
42
|
- **Multiple Output Formats** - JSON, CSV, formatted tables, and printable PDF dope cards
|
|
32
43
|
- **Terminal Chart** - Inline drop, drift, velocity, and energy vs. range charts right in the terminal (`trajectory --plot`, Unicode braille-dot canvas by default, `--plot ascii` fallback); pure Rust, zero new dependencies, no ANSI colors — see [CLI_USAGE.md](CLI_USAGE.md#terminal-chart---plot)
|
|
33
44
|
- **Profile import**: `ballistics profile import file.a7p` — imports ArcherBC2 `.a7p` profiles (rifle, bullet, atmosphere, zero) with a full mapping report; `--dry-run` previews without saving
|
|
45
|
+
- **Online Reverse Solvers** - Optional `login` + `recommend-powder`/`recommend-twist`/`recommend-col`/`calibrate-bc` subcommands query the hosted service for load, twist, cartridge-overall-length, and BC suggestions using a CLI access token saved from your ballisticsinsight.com account (`BALLISTICS_API_TOKEN` env var, or `~/.ballistics/credentials.toml`); all local subcommands work offline with no token — see [CLI_USAGE.md](CLI_USAGE.md#online-reverse-solvers)
|
|
34
46
|
|
|
35
47
|
## Installation
|
|
36
48
|
|
|
@@ -433,6 +445,31 @@ propagated drop bands. Declared sigmas are treated as absolute known errors, so
|
|
|
433
445
|
covariance is not rescaled by residual RMS. With no uncertainty flags, the existing
|
|
434
446
|
point estimate and output schema are unchanged.
|
|
435
447
|
|
|
448
|
+
### Wind-Call Truing (`true-wind`)
|
|
449
|
+
|
|
450
|
+
`true-velocity` trues the vertical axis; `true-wind` (MBA-1392) trues the other one.
|
|
451
|
+
Give it where your groups actually landed left/right of the aim point and it back-solves
|
|
452
|
+
the crosswind that reproduces that miss through the real forward model, plus a wind-call
|
|
453
|
+
correction factor against the wind you *called*:
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
./ballistics true-wind \
|
|
457
|
+
--miss 500:14.0 --miss 700:29.5 \
|
|
458
|
+
-v 2700 -b 0.475 -m 168 -d 0.308 --drag-model g7 \
|
|
459
|
+
--twist-rate 11 --called-wind 9
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
A horizontal miss is not purely wind, so the command separates it: `--twist-rate` is
|
|
463
|
+
**required** and gyroscopic spin drift is always modelled and subtracted (a 1:11" .308
|
|
464
|
+
drifts ~3.5 in right at 700 yd — read as wind, that alone is several mph of error), and
|
|
465
|
+
`--latitude` with `--shot-direction` adds Coriolis. Anything the model had no data for
|
|
466
|
+
stays absorbed in the solved wind and is named in the report, so a contaminated number is
|
|
467
|
+
never presented as pure wind. Signs are documented in one block: `--miss` positive =
|
|
468
|
+
impact **right** of aim, solved wind positive = wind **from the shooter's left**
|
|
469
|
+
(9 o'clock) pushing impacts right. `--miss` values are linear inches off the target, not
|
|
470
|
+
dial readings, so scope tracking correction factors deliberately do not apply.
|
|
471
|
+
See [CLI_USAGE.md](CLI_USAGE.md#wind-call-truing-true-wind--mba-1392).
|
|
472
|
+
|
|
436
473
|
### DSF (Drop-Scale-Factor) Truing
|
|
437
474
|
|
|
438
475
|
Second stage of the Applied Ballistics-style two-stage truing workflow (MBA-1357).
|
package/ballistics_engine.d.ts
CHANGED
|
@@ -45,10 +45,24 @@ export class Calculator {
|
|
|
45
45
|
setMass(mass_grains: number): Calculator;
|
|
46
46
|
setMaxRange(range_yards: number): Calculator;
|
|
47
47
|
setPressure(pressure_inhg: number): Calculator;
|
|
48
|
+
/**
|
|
49
|
+
* MBA-1368: compass bearing of the shot (degrees, 0 = north, 90 = east) —
|
|
50
|
+
* required by `setWindReference("compass")`; also feeds Coriolis when enabled.
|
|
51
|
+
*/
|
|
52
|
+
setShotDirection(bearing_deg: number): Calculator;
|
|
48
53
|
setSightHeight(height_inches: number): Calculator;
|
|
49
54
|
setTemperature(temp_f: number): Calculator;
|
|
50
55
|
setVelocity(velocity_fps: number): Calculator;
|
|
51
56
|
setWind(speed_mph: number, direction_deg: number): Calculator;
|
|
57
|
+
/**
|
|
58
|
+
* MBA-1368: choose the wind entry frame — "shooter" (default; wind-FROM angles
|
|
59
|
+
* relative to the line of fire) or "compass" (earth-fixed bearings, 0 = north,
|
|
60
|
+
* covering `setWind` AND every `addWindSegment` direction, re-referenced against
|
|
61
|
+
* the shot azimuth at solve time). Compass mode requires `setShotDirection`;
|
|
62
|
+
* invalid values surface when the command runs. Additive method — no existing
|
|
63
|
+
* signature changed.
|
|
64
|
+
*/
|
|
65
|
+
setWindReference(mode: string): Calculator;
|
|
52
66
|
setZeroRange(range_yards: number): Calculator;
|
|
53
67
|
}
|
|
54
68
|
|
|
@@ -150,10 +164,12 @@ export interface InitOutput {
|
|
|
150
164
|
readonly calculator_setMass: (a: number, b: number) => number;
|
|
151
165
|
readonly calculator_setMaxRange: (a: number, b: number) => number;
|
|
152
166
|
readonly calculator_setPressure: (a: number, b: number) => number;
|
|
167
|
+
readonly calculator_setShotDirection: (a: number, b: number) => number;
|
|
153
168
|
readonly calculator_setSightHeight: (a: number, b: number) => number;
|
|
154
169
|
readonly calculator_setTemperature: (a: number, b: number) => number;
|
|
155
170
|
readonly calculator_setVelocity: (a: number, b: number) => number;
|
|
156
171
|
readonly calculator_setWind: (a: number, b: number, c: number) => number;
|
|
172
|
+
readonly calculator_setWindReference: (a: number, b: number, c: number) => number;
|
|
157
173
|
readonly calculator_setZeroRange: (a: number, b: number) => number;
|
|
158
174
|
readonly wasmballistics_clearDragTable: (a: number) => number;
|
|
159
175
|
readonly wasmballistics_hasBc5dTable: (a: number) => number;
|
package/ballistics_engine.js
CHANGED
|
@@ -175,6 +175,17 @@ export class Calculator {
|
|
|
175
175
|
const ret = wasm.calculator_setPressure(ptr, pressure_inhg);
|
|
176
176
|
return Calculator.__wrap(ret);
|
|
177
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* MBA-1368: compass bearing of the shot (degrees, 0 = north, 90 = east) —
|
|
180
|
+
* required by `setWindReference("compass")`; also feeds Coriolis when enabled.
|
|
181
|
+
* @param {number} bearing_deg
|
|
182
|
+
* @returns {Calculator}
|
|
183
|
+
*/
|
|
184
|
+
setShotDirection(bearing_deg) {
|
|
185
|
+
const ptr = this.__destroy_into_raw();
|
|
186
|
+
const ret = wasm.calculator_setShotDirection(ptr, bearing_deg);
|
|
187
|
+
return Calculator.__wrap(ret);
|
|
188
|
+
}
|
|
178
189
|
/**
|
|
179
190
|
* @param {number} height_inches
|
|
180
191
|
* @returns {Calculator}
|
|
@@ -212,6 +223,23 @@ export class Calculator {
|
|
|
212
223
|
const ret = wasm.calculator_setWind(ptr, speed_mph, direction_deg);
|
|
213
224
|
return Calculator.__wrap(ret);
|
|
214
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* MBA-1368: choose the wind entry frame — "shooter" (default; wind-FROM angles
|
|
228
|
+
* relative to the line of fire) or "compass" (earth-fixed bearings, 0 = north,
|
|
229
|
+
* covering `setWind` AND every `addWindSegment` direction, re-referenced against
|
|
230
|
+
* the shot azimuth at solve time). Compass mode requires `setShotDirection`;
|
|
231
|
+
* invalid values surface when the command runs. Additive method — no existing
|
|
232
|
+
* signature changed.
|
|
233
|
+
* @param {string} mode
|
|
234
|
+
* @returns {Calculator}
|
|
235
|
+
*/
|
|
236
|
+
setWindReference(mode) {
|
|
237
|
+
const ptr = this.__destroy_into_raw();
|
|
238
|
+
const ptr0 = passStringToWasm0(mode, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
239
|
+
const len0 = WASM_VECTOR_LEN;
|
|
240
|
+
const ret = wasm.calculator_setWindReference(ptr, ptr0, len0);
|
|
241
|
+
return Calculator.__wrap(ret);
|
|
242
|
+
}
|
|
215
243
|
/**
|
|
216
244
|
* @param {number} range_yards
|
|
217
245
|
* @returns {Calculator}
|
|
Binary file
|
package/package.json
CHANGED