Skip to content

Commit

Permalink
Zero given elevation (#15)
Browse files Browse the repository at this point in the history
* updated zero_given_elevation function
* max distance fix
* fix with number of lines in output
* updated CI scripts
* tests backend changed to pytest
* tests moved out of library sources
* added pandas/matplotlib output
  • Loading branch information
o-murphy authored Oct 10, 2023
1 parent 73e6122 commit 3f39370
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 152 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ jobs:
pip install pylint
- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')
#pylint $(git ls-files '*.py')
pylint ./py_ballisticcalc
16 changes: 10 additions & 6 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.9", "3.10", "3.11"]

steps:
Expand All @@ -21,14 +22,17 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install build-essential -y
python -m pip install --upgrade pip
python -m pip install flake8
# python -m pip install flake8
python -m pip install cython
python -m pip install pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
sudo apt-get update
sudo apt-get install build-essential -y
python setup.py build_ext --inplace
# python setup.py build_ext --inplace
- name: Run unittest tests
run: |
# python -m unittest discover -s . -p "test_*.py"
python -m unittest discover -s . -p "tests*.py"
# python -m unittest discover -s . -p "tests*.py"
pytest tests --no-header --no-summary -v
57 changes: 28 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,40 @@
# BallisticCalculator
LGPL library for small arms ballistic calculations (Python 3.9+)
#### LGPL library for small arms ballistic calculations (Python 3.9+)

### Table of contents
## Table of contents
* [Installation](#installation)
* [Latest stable](#latest-stable-release-from-pypi)
* [From sources](#installing-from-sources)
* [Clone and build](#clone-and-build)
* [Usage](#usage)
* [Units of measure](#unit-manipulation-syntax)
* [An example of calculations](#an-example-of-calculations)
* [Output example](#example-of-the-formatted-output)
* [Contributors](#contributors)
* [About project](#about-project)

### Installation
#### Latest stable release from pypi**
## Installation
**Stable release from pypi, installing from binaries**

(Contains c-extensions which offer higher performance)
```shell
pip install py-ballisticcalc
```
#### Installing from sources
**MSVC** or **GCC** required
* Download and install **MSVC** or **GCC** depending on target platform
* Use one of the references you need:
```shell
# no binary from PyPi
pip install py-ballisticcalc --no-binary :all:

# master brunch
pip install git+https://github.com/o-murphy/py_ballisticcalc
**Build wheel package for your interpreter version by pypi sdist**

# specific branch
pip install git+https://github.com/o-murphy/py_ballisticcalc.git@<target_branch_name>
Download and install MSVC or GCC depending on target platform
```shell
pip install Cython>=3.0.0a10
pip install py-ballisticcalc --no-binary :all:
```

#### Clone and build
**MSVC** or **GCC** required
**Also use `git clone` to build your own package**

(Contains cython files to build your own c-extensions)
```shell
git clone https://github.com/o-murphy/py_ballisticcalc
cd py_ballisticcalc
python -m venv venv
. venv/bin/activate
pip install cython
python setup.py build_ext --inplace
```

### Usage

## Usage

The library supports all the popular units of measurement, and adds different built-in methods to define and manipulate it
#### Unit manipulation syntax:
Expand Down Expand Up @@ -111,13 +102,13 @@ weapon = Weapon(9, 100, 2)
dm = DragModel(0.223, TableG7, weight, diameter)

ammo = Ammo(dm, length, 2750, 15)
ammo.calc_powder_sens(2723, 0) # optional, uses if USE_POWDER_SENSITIVITY flag enabled
ammo.calc_powder_sens(2723, 0)

zero_atmo = Atmo.icao()

# defining calculator instance
calc = Calculator(weapon, ammo, zero_atmo)
calc.update_elevation() # calculates zero barrel elevation
calc.update_elevation()

shot = Shot(1500, 100)

Expand All @@ -144,7 +135,15 @@ python -m py_ballisticcalc.example
['0.95 s', '600.000 m', '1571.4 ft/s', '1.41 mach', '-279.503 cm', '-4.74 mil', '-144.759 cm', '-2.46 mil', '1249 J']
```

### About project
## Contributors
### This project exists thanks to all the people who contribute.
#### Special thanks to:
- **[David Bookstaber](https://github.com/dbookstaber)** - Ballistics Expert, Financial Engineer \
*For the help in understanding and improvement of some calculation methods*
- **[Nikolay Gekht](https://github.com/nikolaygekht)** \
*For the sources code on C# and GO-lang from which this project firstly was forked from*

## About project

The library provides trajectory calculation for projectiles including for various
applications, including air rifles, bows, firearms, artillery and so on.
Expand Down
4 changes: 2 additions & 2 deletions py_ballisticcalc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
__author__ = "o-murphy"
__copyright__ = ("",)

__credits__ = ["O-Murphy"]
__version__ = "1.1.0b5"
__credits__ = ["o-murphy"]
__version__ = "1.1.0b7"

from .drag_model import * # pylint: disable=import-error
from .drag_tables import *
Expand Down
79 changes: 71 additions & 8 deletions py_ballisticcalc/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from .conditions import Atmo, Wind, Shot
from .munition import Weapon, Ammo
from .settings import Settings as Set
from .trajectory_calc import TrajectoryCalc # pylint: disable=import-error
# pylint: disable=import-error,no-name-in-module
from .trajectory_calc import TrajectoryCalc
from .trajectory_data import TrajectoryData, TrajFlag
from .unit import Angular, Distance, is_unit

Expand Down Expand Up @@ -53,19 +54,19 @@ def trajectory(self, shot: Shot, current_atmo: Atmo, winds: list[Wind]) -> list:
data = self._calc.trajectory(self.weapon, current_atmo, shot, winds)
return data

def zero_given_elevation(self, elevation: [float, Angular] = 0,
def zero_given_elevation(self, shot: Shot,
winds: list[Wind] = None) -> TrajectoryData:
"""Find the zero distance for a given barrel elevation"""
self._calc = TrajectoryCalc(self.ammo)
if not winds:
winds = [Wind()]

elevation = elevation if is_unit(elevation) else Set.Units.angular
shot = Shot(1000, Distance.Foot(100), sight_angle=elevation)
data = self._calc.trajectory(self.weapon, self.zero_atmo, shot, winds,
brake_flags=TrajFlag.ZERO)
# No downrange zero found, so just return starting row
return data[-1]
data = self._calc.trajectory(
self.weapon, self.zero_atmo, shot, winds,
filter_flags=(TrajFlag.ZERO_UP | TrajFlag.ZERO_DOWN).value)
if len(data) < 1:
raise ArithmeticError("Can't found zero crossing points")
return data

@staticmethod
def danger_space(trajectory: TrajectoryData, target_height: [float, Distance]) -> Distance:
Expand All @@ -87,3 +88,65 @@ def danger_space(trajectory: TrajectoryData, target_height: [float, Distance]) -
else Set.Units.target_height(target_height)) >> Distance.Yard
traj_angle_tan = math.tan(trajectory.angle >> Angular.Radian)
return Distance.Yard(-(target_height / traj_angle_tan))

@staticmethod
def to_dataframe(trajectory: list[TrajectoryData]):
import pandas as pd
col_names = TrajectoryData._fields
trajectory = [p.in_def_units() for p in trajectory]
return pd.DataFrame(trajectory, columns=col_names)

def show_plot(self, shot, winds):
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('TkAgg')
self._calc = TrajectoryCalc(self.ammo)
# self.update_elevation()
data = self._calc.trajectory(self.weapon, self.zero_atmo, shot, winds,
TrajFlag.ALL.value) # Step in 10-yard increments to produce smoother curves
df = self.to_dataframe(data)
ax = df.plot(x='distance', y=['drop'], ylabel=Set.Units.drop.symbol)

# zero_d = self.weapon.zero_distance >> Set.Units.distance
# zero = ax.plot([zero_d, zero_d], [df['drop'].min(), df['drop'].max()], linestyle='--')

for p in data:

if TrajFlag(p.flag) & TrajFlag.ZERO:
ax.plot([p.distance >> Set.Units.distance, p.distance >> Set.Units.distance],
[df['drop'].min(), p.drop >> Set.Units.drop], linestyle=':')
if TrajFlag(p.flag) & TrajFlag.MACH:
ax.plot([p.distance >> Set.Units.distance, p.distance >> Set.Units.distance],
[df['drop'].min(), p.drop >> Set.Units.drop], linestyle='--', label='mach')
ax.text(p.distance >> Set.Units.distance, df['drop'].min(), " Mach")

sh = self.weapon.sight_height >> Set.Units.drop

# # scope line
x_values = [0, df.distance.max()] # Adjust these as needed
# y_values = [sh, sh - df.distance.max() * math.tan(self.elevation >> Angular.Degree)] # Adjust these as needed
y_values = [0, 0] # Adjust these as needed
ax.plot(x_values, y_values, linestyle='--', label='scope line')
ax.text(df.distance.max() - 100, -100, "Scope")

# # # barrel line
# elevation = self.elevation >> Angular.Degree
#
# y = sh / math.cos(elevation)
# x0 = sh / math.sin(elevation)
# x1 = sh * math.sin(elevation)
# x_values = [0, x0]
# y_values = [-sh, 0]
# ax.plot(x_values, y_values, linestyle='-.', label='barrel line')

df.plot(x='distance', xlabel=Set.Units.distance.symbol,
y=['velocity'], ylabel=Set.Units.velocity.symbol,
secondary_y=True,
ylim=[0, df['velocity'].max()], ax=ax)
plt.title = f"{self.weapon.sight_height} {self.weapon.zero_distance}"

plt.show()
# ax = df.plot(y=[c.tableCols['Drop'][0]], ylabel=UNIT_DISPLAY[c.heightUnits].units)
# df.plot(y=[c.tableCols['Velocity'][0]], ylabel=UNIT_DISPLAY[c.bullet.velocityUnits].units, secondary_y=True,
# ylim=[0, df[c.tableCols['Velocity'][0]].max()], ax=ax)
# plt.show()
3 changes: 2 additions & 1 deletion py_ballisticcalc/multiple_bc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from typing import NamedTuple, Iterable

from .conditions import Atmo
from .drag_model import make_data_points # pylint: disable=import-error
# pylint: disable=import-error,no-name-in-module
from .drag_model import make_data_points
from .settings import Settings as Set
from .unit import Distance, Weight, Velocity, is_unit

Expand Down
3 changes: 2 additions & 1 deletion py_ballisticcalc/munition.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import math
from dataclasses import dataclass, field

from .drag_model import DragModel # pylint: disable=import-error
# pylint: disable=import-error,no-name-in-module
from .drag_model import DragModel
from .settings import Settings as Set
from .unit import TypedUnits, Velocity, Temperature, is_unit, Distance

Expand Down
Loading

0 comments on commit 3f39370

Please sign in to comment.