Protocol
EngineProtocol
¶
Bases: Protocol
Protocol defining the interface for ballistic trajectory calculation engines.
This protocol outlines the methods that any concrete ballistic engine implementation should provide to perform trajectory calculations, retrieve drag model information, and determine zeroing angles for firearms.
All engines implementing this protocol can be used interchangeably with the Calculator interface, enabling a modular architecture for different numerical integration methods and calculation approaches.
Class Type Parameters:
| Name | Bound or Constraints | Description | Default |
|---|---|---|---|
ConfigT
|
The configuration type used by this engine implementation. Must be covariant to support configuration inheritance. |
required |
Required Methods
- integrate: Perform ballistic trajectory calculation.
- zero_angle / find_zero_angle: Calculate a zero angle.
- zero_point / find_zero_point: Calculate a zero angle and retain its terminal trajectory point.
Examples:
from py_ballisticcalc.engines.base_engine import BaseEngineConfigDict
class MyEngine(EngineProtocol):
def __init__(self, config: BaseEngineConfigDict):
self.config = config
def integrate(self, shot_info, max_range, **kwargs):
# Implementation here
pass
def zero_angle(self, shot_info, distance):
# Implementation here
pass
def zero_point(self, shot_info, distance):
# Implementation here
pass
def find_zero_angle(self, shot_info, distance, lofted=False):
# Implementation here
pass
def find_zero_point(self, shot_info, distance, lofted=False):
# Implementation here
pass
config = BaseEngineConfigDict(cStepMultiplier=1.0)
engine = MyEngine(config)
isinstance(engine, EngineProtocol) # True
See Also
- py_ballisticcalc.engines.base_engine.BaseIntegrationEngine: Base implementation
- py_ballisticcalc.interface.Calculator: Uses EngineProtocol implementations
Note
This protocol uses structural subtyping (duck typing) which means any class that implements the required methods will be considered compatible, even if it doesn't explicitly inherit from EngineProtocol. The @runtime_checkable decorator enables isinstance() checks at runtime.
Methods:
| Name | Description |
|---|---|
integrate |
Perform ballistic trajectory calculation from shot parameters to maximum range. |
zero_angle |
Calculate launch angle required to hit target at specified distance. |
zero_point |
Calculate the lower zero and return its angle and terminal point. |
find_zero_angle |
Calculate the lower or lofted zero angle at a specific distance. |
find_zero_point |
Calculate the lower or lofted zero and return its angle and terminal point. |
integrate
¶
integrate(
shot_info: Shot,
max_range: Distance,
dist_step: Distance | None = None,
time_step: float = 0.0,
filter_flags: TrajFlag | int = NONE,
dense_output: bool = False,
**kwargs: Any,
) -> HitResult
Perform ballistic trajectory calculation from shot parameters to maximum range.
This method integrates the projectile's equations of motion to generate a complete trajectory from muzzle to the specified maximum range, accounting for gravitational acceleration, atmospheric drag, and environmental conditions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shot_info
|
Shot
|
Complete shot configuration containing projectile data, environmental conditions, sight configuration, and firing parameters. Must include muzzle velocity, ballistic coefficient, atmospheric conditions, and sight height information. |
required |
max_range
|
Distance
|
Maximum distance for trajectory calculation. The integration continues until the projectile reaches this range or impacts the ground. |
required |
dist_step
|
Distance | None
|
Distance interval between trajectory data points. If None, engine uses default step size for optimal accuracy/performance balance. |
None
|
time_step
|
float
|
Time interval for integration steps. Zero means engine determines optimal step size automatically. |
0.0
|
filter_flags
|
TrajFlag | int
|
Trajectory flags to control which data points are included in the output. Use TrajFlag values to filter specific conditions. |
NONE
|
dense_output
|
bool
|
If True, return trajectory data at every integration step. If False, return data only at specified distance intervals. |
False
|
**kwargs
|
Any
|
Additional engine-specific parameters for specialized calculations. |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
HitResult |
HitResult
|
Complete trajectory calculation parameters and results. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If shot_info contains invalid or inconsistent parameters. |
RuntimeError
|
If the numerical integration fails to converge. |
OutOfRangeError
|
If the requested max_range exceeds computational limits. |
Mathematical Background
The integration solves the vector differential equation for projectile motion under the influence of gravity and atmospheric drag:
dV/dt = D * |V| * (V - W) - g
Where:
- V = (v_x, v_y, v_z) is velocity relative to the ground
- W = (w_x, w_y, w_z) is wind velocity vector relative to the ground
- D = drag factor, which is a function of velocity, atmosphere, and
projectile characteristics that include shape and mass
- g is gravitational acceleration
Typical implementation steps
- Initialize state vectors from shot_info parameters
- Set up integration bounds and step size parameters
- Begin numerical integration loop using chosen method
- At each step, calculate drag forces from atmospheric conditions
- Update position and velocity using integration formulae
- Check termination conditions (range limit, ground impact)
- Store trajectory points at specified intervals
- Return complete trajectory data structure
Source code in py_ballisticcalc/generics/engine.py
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | |
zero_angle
¶
Calculate launch angle required to hit target at specified distance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shot_info
|
Shot
|
Complete shot configuration containing projectile data, environmental conditions, sight configuration, and target information. Must include muzzle velocity, ballistic coefficient, atmospheric conditions, sight height, and target height. |
required |
distance
|
Distance
|
Horizontal distance to target. Must be within the effective range of the projectile under the given conditions. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Angular |
Angular
|
Launch angle required to hit the target. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If shot_info contains invalid parameters or distance is negative or unreasonably large. |
ZeroFindingError
|
If the iterative algorithm fails to converge. |
OutOfRangeError
|
If the target distance exceeds maximum effective range. |
Note
This method returns the lower of the two ballistic solutions hit a target point.
To get the higher ("lofted") solution we have been adding a .find_zero_angle()
method that offers a lofted: bool parameter to select between the two.
Mathematical Background
The method solves the equation f(θ) = 0 where:
f(θ) = y(target_distance, θ) - target_height
Where y(x, θ) is the trajectory height function at distance x for
launch angle θ. This requires iterative solution since the trajectory
equation cannot be solved analytically for arbitrary drag functions.
Typical implementation approach
- Establish reasonable bounds for elevation angle search
- Define target function: trajectory_height(distance) - target_height
- Use root-finding algorithm (bisection, Newton, etc.)
- For each iteration, calculate trajectory to target distance
- Evaluate height difference at target distance
- Adjust angle estimate based on convergence strategy
- Continue until convergence tolerance is met
- Return final angle estimate
Source code in py_ballisticcalc/generics/engine.py
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | |
zero_point
¶
zero_point(
shot_info: Shot, distance: Distance
) -> tuple[Angular, TrajectoryData]
Calculate the lower zero and return its angle and terminal point.
The returned point is the terminal RANGE point evaluated by the
successful zero-finding iteration; implementations must not perform a
separate final trajectory integration to obtain it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shot_info
|
Shot
|
Complete shot configuration used for the zero solve. |
required |
distance
|
Distance
|
Slant distance from the sight to the requested zero point. |
required |
Returns:
| Type | Description |
|---|---|
Angular
|
A pair of the lower-arc barrel elevation and the corresponding |
TrajectoryData
|
terminal trajectory point. |
Raises:
| Type | Description |
|---|---|
SolverRuntimeError
|
If a zero-angle fast path did not evaluate a trajectory point. |
Source code in py_ballisticcalc/generics/engine.py
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | |
find_zero_angle
¶
Calculate the lower or lofted zero angle at a specific distance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shot_info
|
Shot
|
Complete shot configuration used for the zero solve. |
required |
distance
|
Distance
|
Slant distance from the sight to the requested zero point. |
required |
lofted
|
bool
|
If True, select the higher trajectory that reaches the zero point; otherwise select the lower trajectory. |
False
|
Returns:
| Type | Description |
|---|---|
Angular
|
Barrel elevation needed to hit the zero point. |
Source code in py_ballisticcalc/generics/engine.py
236 237 238 239 240 241 242 243 244 245 246 247 248 | |
find_zero_point
¶
find_zero_point(
shot_info: Shot,
distance: Distance,
lofted: bool = False,
) -> tuple[Angular, TrajectoryData]
Calculate the lower or lofted zero and return its angle and terminal point.
The returned point is the terminal RANGE point evaluated by the
successful zero-finding iteration; implementations must not perform a
separate final trajectory integration to obtain it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shot_info
|
Shot
|
Complete shot configuration used for the zero solve. |
required |
distance
|
Distance
|
Slant distance from the sight to the requested zero point. |
required |
lofted
|
bool
|
If True, select the higher trajectory that reaches the zero point; otherwise select the lower trajectory. |
False
|
Returns:
| Type | Description |
|---|---|
Angular
|
A pair of the selected barrel elevation and the corresponding |
TrajectoryData
|
terminal trajectory point. |
Raises:
| Type | Description |
|---|---|
SolverRuntimeError
|
If a zero-angle fast path did not evaluate a trajectory point. |
Source code in py_ballisticcalc/generics/engine.py
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | |
EngineFactoryProtocol
¶
Bases: Protocol[ConfigT]
Methods:
| Name | Description |
|---|---|
__call__ |
Make any Engine constructor or factory to match this signature |
__call__
¶
__call__(config: ConfigT | None) -> EngineProtocol
Make any Engine constructor or factory to match this signature
Source code in py_ballisticcalc/generics/engine.py
282 283 284 | |