Trajectory DataΒΆ
Data structures and helpers for computed trajectories:
TrajFlag: Flags marking events (ZERO_UP,ZERO_DOWN,MACH,RANGE,APEX, etc.).BaseTrajData: Minimal record of integration steps that can be used to interpolate for anyTrajectoryDatapoint.TrajectoryData: Rich unit-aware rows for presentation/analysis.HitResult: Container with convenience lookups and plotting/dataframe helpers.DangerSpace: Analyze tolerance to ranging error at a given distance and target height.
HitResult output viewsΒΆ
HitResult exposes the same calculation through three views. Choose the
view by the question being asked, rather than relying on an implicit
time-tolerance merge between a scheduled row and a physical event.
| View | Contents | Use it for |
|---|---|---|
records |
The complete, exact chronological output stream: every scheduled sample and every physical event, each its own row. | len(result), iteration, indexing, dataframe(), plot() β anything that wants full fidelity. |
samples |
Deterministic scheduled RANGE/TIME samples. A sample is annotated with an event's flag only when the two are the same instant to floating-point precision β never merely the nearest one. | Comparing output across engines or solver tolerances, where accepted-step timing differs but the requested schedule does not (its cardinality tracks the schedule, not the integrator's internal steps). |
events |
Exact interpolated physical events: ZERO, MACH, APEX, and MRT. | The physical time, position, velocity, or other state at an event. |
records backs the everyday container protocol, so len(result),
iteration, indexing, dataframe(), and plot() all see every exact event
row in its own chronological position β nothing is folded onto a
neighboring sample. Use samples instead when you specifically need a
table whose row count doesn't change with solver internals (e.g.
test_cashkarp_tolerance_controls_adaptive_step_count relies on this to
compare a tight- and loose-tolerance run row-for-row). A samples row
annotated with an event flag is still a scheduled sample; its data must not
be treated as the exact event root β use events for that.
samples never annotates a sample just because it's the closest one β
only when the sample and the event are, in effect, the same instant (an
HitResult.samples-level math.isclose() check, independent of any
engine's own tolerance settings, which use incompatible units β feet,
state-error rtol, step multiplier β none of them a time tolerance). With a
coarse schedule this matters: trajectory_range == trajectory_step leaves
only the launch and terminal samples, so an APEX or ZERO in between is not
genuinely close to either one β it stays unannotated in samples (visible
only in events) rather than getting glued onto whichever endpoint
bisection happens to prefer, which would otherwise misrepresent that
endpoint's own state as the event's.
result = calc.fire(shot, trajectory_range=Distance.Yard(1_000), flags=TrajFlag.ALL)
# Full-fidelity output: every event gets its own exact row.
for row in result: # equivalent to `for row in result.records`
print(row.distance, row.flag)
# Exact event state.
zero_down = result.flag(TrajFlag.ZERO_DOWN)
mach_transition = result.flag(TrajFlag.MACH)
all_events = result.events
# Deterministic schedule table, e.g. to compare two engines row-for-row.
schedule = result.samples
HitResult.trajectory is deprecated
Before this release's records/samples/events split, trajectory
was the only view, and it had samples' semantics (event flags folded
onto the nearest scheduled row). HitResult.trajectory is now a
deprecated alias for records β kept so old code still runs, but with
records' row count/order, not the old trajectory's. Code that
indexed .trajectory assuming a fixed RANGE/TIME-schedule cardinality
should switch to .samples; code that just wanted every point should
switch to .records (or drop the attribute and iterate the
HitResult directly).
This deprecation applies only to the .trajectory property on an
existing HitResult. The constructor itself takes records as an
ordinary parameter β there is no trajectory= constructor spelling β
since HitResult is built internally by the engines, not by user code.