Skip to content

Commit 5853144

Browse files
committed
Move ShotProps initializer from base_engine.py to trajectory_data.py
1 parent f1b7e8c commit 5853144

3 files changed

Lines changed: 56 additions & 45 deletions

File tree

py_ballisticcalc.exts/py_ballisticcalc_exts/base_engine.pyx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ from py_ballisticcalc_exts.v3d cimport (
3434
from py_ballisticcalc.unit import Angular, Unit, Velocity, Distance, Energy, Weight
3535
from py_ballisticcalc.exceptions import ZeroFindingError, RangeError, OutOfRangeError, SolverRuntimeError
3636
from py_ballisticcalc.engines.base_engine import create_base_engine_config
37-
from py_ballisticcalc.trajectory_data import HitResult, TrajFlag
37+
from py_ballisticcalc.trajectory_data import HitResult, TrajFlag, ShotProps
3838

3939

4040
__all__ = (
@@ -265,7 +265,9 @@ cdef class CythonizedBaseIntegrationEngine:
265265
self._init_trajectory(shot_info)
266266
object = self._integrate(range_limit_ft, range_step_ft, time_step, filter_flags, dense_output)
267267
self._free_trajectory()
268-
return HitResult(shot_info, object[0], filter_flags > 0, object[1])
268+
props = ShotProps.from_shot(shot_info)
269+
props.filter_flags = filter_flags
270+
return HitResult(props, object[0], filter_flags > 0, object[1])
269271

270272
cdef void _free_trajectory(CythonizedBaseIntegrationEngine self):
271273
if self._wind_sock is not NULL:

py_ballisticcalc/engines/base_engine.py

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@
88
from dataclasses import dataclass, asdict
99
from enum import Enum, auto
1010

11-
from typing_extensions import List, Optional, NamedTuple, Union, Tuple, Dict, TypedDict, TypeVar
11+
from typing_extensions import Optional, NamedTuple, Union, Tuple, Dict, TypedDict, TypeVar
1212

1313
from py_ballisticcalc.conditions import Shot, Wind
14-
from py_ballisticcalc.drag_model import DragDataPoint
1514
from py_ballisticcalc.exceptions import ZeroFindingError, OutOfRangeError, SolverRuntimeError
1615
from py_ballisticcalc.generics.engine import EngineProtocol
1716
from py_ballisticcalc.logger import logger
1817
from py_ballisticcalc.trajectory_data import *
19-
from py_ballisticcalc.unit import Distance, Angular, Velocity, Weight
18+
from py_ballisticcalc.unit import Distance, Angular
2019
from py_ballisticcalc.vector import Vector
2120

2221
__all__ = (
@@ -317,32 +316,16 @@ def get_calc_step(self) -> float:
317316
"""Get step size for integration."""
318317
return self._config.cStepMultiplier
319318

320-
def _init_trajectory(self, shot_info: Shot) -> ShotProps:
319+
def _init_trajectory(self, shot: Shot) -> ShotProps:
321320
"""
322321
Converts Shot properties into floats dimensioned in internal units.
323322
324323
Args:
325324
shot_info (Shot): Information about the shot.
326325
"""
327-
return ShotProps(
328-
shot=shot_info,
329-
bc=shot_info.ammo.dm.BC,
330-
curve=calculate_curve(shot_info.ammo.dm.drag_table),
331-
mach_list=_get_only_mach_data(shot_info.ammo.dm.drag_table),
332-
look_angle_rad=shot_info.look_angle >> Angular.Radian,
333-
twist_inch=shot_info.weapon.twist >> Distance.Inch,
334-
length_inch=shot_info.ammo.dm.length >> Distance.Inch,
335-
diameter_inch=shot_info.ammo.dm.diameter >> Distance.Inch,
336-
weight_grains=shot_info.ammo.dm.weight >> Weight.Grain,
337-
barrel_elevation_rad=shot_info.barrel_elevation >> Angular.Radian,
338-
barrel_azimuth_rad=shot_info.barrel_azimuth >> Angular.Radian,
339-
sight_height_ft=shot_info.weapon.sight_height >> Distance.Foot,
340-
cant_cosine=math.cos(shot_info.cant_angle >> Angular.Radian),
341-
cant_sine=math.sin(shot_info.cant_angle >> Angular.Radian),
342-
alt0_ft=shot_info.atmo.altitude >> Distance.Foot,
343-
calc_step=self.get_calc_step(),
344-
muzzle_velocity_fps=shot_info.ammo.get_velocity_for_temp(shot_info.atmo.powder_temp) >> Velocity.FPS,
345-
)
326+
props = ShotProps.from_shot(shot)
327+
props.calc_step = self.get_calc_step()
328+
return props
346329

347330
def find_max_range(self, shot_info: Shot, angle_bracket_deg: Tuple[float, float] = (0, 90)) -> Tuple[
348331
Distance, Angular]:
@@ -822,16 +805,3 @@ def _integrate(self, props: ShotProps, range_limit_ft: float, range_step_ft: flo
822805
HitResult: Object describing the trajectory.
823806
"""
824807
raise NotImplementedError
825-
826-
827-
def _get_only_mach_data(data: List[DragDataPoint]) -> List[float]:
828-
"""
829-
Extracts Mach values from a list of DragDataPoint objects.
830-
831-
Args:
832-
data (List[DragDataPoint]): A list of DragDataPoint objects.
833-
834-
Returns:
835-
List[float]: A list containing only the Mach values from the input data.
836-
"""
837-
return [dp.Mach for dp in data]

py_ballisticcalc/trajectory_data.py

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,9 @@ class ShotProps:
244244
cant_cosine: float # Cosine of the cant angle
245245
cant_sine: float # Sine of the cant angle
246246
alt0_ft: float # Initial altitude in feet
247-
calc_step: float # Calculation step size
248247
muzzle_velocity_fps: float # Muzzle velocity in feet per second
249248
stability_coefficient: float = field(init=False)
249+
calc_step: float = field(init=False) # Calculation step size
250250
filter_flags: Union[TrajFlag, int] = field(init=False)
251251

252252
def __post_init__(self):
@@ -260,6 +260,28 @@ def winds(self) -> Tuple[Wind, ...]:
260260
def look_angle(self) -> Angular:
261261
return Angular.Radian(self.look_angle_rad)
262262

263+
@classmethod
264+
def from_shot(cls, shot: Shot) -> 'ShotProps':
265+
"""Initializes a ShotProps instance from a Shot instance."""
266+
return cls(
267+
shot=shot,
268+
bc=shot.ammo.dm.BC,
269+
curve=calculate_curve(shot.ammo.dm.drag_table),
270+
mach_list=_get_only_mach_data(shot.ammo.dm.drag_table),
271+
look_angle_rad=shot.look_angle >> Angular.Radian,
272+
twist_inch=shot.weapon.twist >> Distance.Inch,
273+
length_inch=shot.ammo.dm.length >> Distance.Inch,
274+
diameter_inch=shot.ammo.dm.diameter >> Distance.Inch,
275+
weight_grains=shot.ammo.dm.weight >> Weight.Grain,
276+
barrel_elevation_rad=shot.barrel_elevation >> Angular.Radian,
277+
barrel_azimuth_rad=shot.barrel_azimuth >> Angular.Radian,
278+
sight_height_ft=shot.weapon.sight_height >> Distance.Foot,
279+
cant_cosine=math.cos(shot.cant_angle >> Angular.Radian),
280+
cant_sine=math.sin(shot.cant_angle >> Angular.Radian),
281+
alt0_ft=shot.atmo.altitude >> Distance.Foot,
282+
muzzle_velocity_fps=shot.ammo.get_velocity_for_temp(shot.atmo.powder_temp) >> Velocity.FPS,
283+
)
284+
263285
def drag_by_mach(self, mach: float) -> float:
264286
"""
265287
Calculates a standard drag factor (SDF) for the given Mach number. Where:
@@ -535,6 +557,18 @@ def calculate_curve(data_points: List[DragDataPoint]) -> List[CurvePoint]:
535557
return curve
536558

537559

560+
def _get_only_mach_data(data: List[DragDataPoint]) -> List[float]:
561+
"""
562+
Extracts Mach values from a list of DragDataPoint objects.
563+
564+
Args:
565+
data (List[DragDataPoint]): A list of DragDataPoint objects.
566+
567+
Returns:
568+
List[float]: A list containing only the Mach values from the input data.
569+
"""
570+
return [dp.Mach for dp in data]
571+
538572
# # use ._get_only_mach_data with ._calculate_by_curve_and_mach_list because it's faster
539573
# def calculate_by_curve(data: List[DragDataPoint], curve: List[CurvePoint], mach: float) -> float:
540574
# """
@@ -660,7 +694,7 @@ class HitResult:
660694
extra (bool): Whether special points (TrajFlag > 0) were requested.
661695
error (Optional[RangeError]): RangeError, if any.
662696
"""
663-
shot: ShotProps
697+
props: ShotProps
664698
trajectory: list[TrajectoryData] = field(repr=False)
665699
extra: bool = False
666700
error: Optional[RangeError] = None
@@ -681,6 +715,11 @@ def __check_extra__(self):
681715
f"Use Calculator.fire(..., extra_data=True)"
682716
)
683717

718+
def __check_flag__(self, flag: Union[TrajFlag, int]):
719+
if not self.props.filter_flags & flag:
720+
raise AttributeError(f"{TrajFlag.name(flag)} was not requested in trajectory. "
721+
f"Use Calculator.fire(..., extra_data=True)")
722+
684723
def zeros(self) -> list[TrajectoryData]:
685724
"""
686725
Returns:
@@ -690,7 +729,7 @@ def zeros(self) -> list[TrajectoryData]:
690729
AttributeError: If extra_data was not requested.
691730
ArithmeticError: If zero crossing points are not found.
692731
"""
693-
self.__check_extra__()
732+
self.__check_flag__(TrajFlag.ZERO)
694733
data = [row for row in self.trajectory if row.flag & TrajFlag.ZERO]
695734
if len(data) < 1:
696735
raise ArithmeticError("Can't find zero crossing points")
@@ -702,9 +741,9 @@ def flag(self, flag: Union[TrajFlag, int]) -> Optional[TrajectoryData]:
702741
TrajectoryData: First TrajectoryData row with the specified flag.
703742
704743
Raises:
705-
AttributeError: If extra_data was not requested.
744+
AttributeError: If flag was not requested.
706745
"""
707-
self.__check_extra__()
746+
self.__check_flag__(flag)
708747
for row in self.trajectory:
709748
if row.flag & flag:
710749
return row
@@ -934,7 +973,7 @@ def danger_space(self,
934973
target_height_half = target_height.raw_value / 2.0
935974

936975
target_row = self.get_at('slant_distance', target_at_range)
937-
is_climbing = target_row.angle.raw_value - self.shot.look_angle.raw_value > 0
976+
is_climbing = target_row.angle.raw_value - self.props.look_angle.raw_value > 0
938977
slant_height_begin = target_row.slant_height.raw_value + (-1 if is_climbing else 1) * target_height_half
939978
slant_height_end = target_row.slant_height.raw_value - (-1 if is_climbing else 1) * target_height_half
940979
try:
@@ -950,7 +989,7 @@ def danger_space(self,
950989
target_height,
951990
begin_row,
952991
end_row,
953-
self.shot.look_angle)
992+
self.props.look_angle)
954993

955994
def dataframe(self, formatted: bool = False) -> 'DataFrame': # type: ignore
956995
"""

0 commit comments

Comments
 (0)