{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:55.060748Z",
     "start_time": "2025-06-13T12:32:55.051984Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Default units:\n",
      "angular = degree\n",
      "distance = yard\n",
      "velocity = fps\n",
      "pressure = inHg\n",
      "temperature = fahrenheit\n",
      "diameter = inch\n",
      "length = inch\n",
      "weight = grain\n",
      "adjustment = mil\n",
      "drop = inch\n",
      "energy = foot-pound\n",
      "ogw = pound\n",
      "sight_height = inch\n",
      "target_height = inch\n",
      "twist = inch\n",
      "time = second\n"
     ]
    }
   ],
   "source": [
    "import copy\n",
    "import logging\n",
    "import math\n",
    "import pandas\n",
    "from matplotlib import pyplot as plt\n",
    "from py_ballisticcalc import TableG7, TableG1\n",
    "from py_ballisticcalc import Ammo, Atmo, Wind, TrajFlag\n",
    "from py_ballisticcalc import Weapon, Shot, Calculator\n",
    "from py_ballisticcalc import PreferredUnits\n",
    "from py_ballisticcalc.drag_model import *\n",
    "from py_ballisticcalc.unit import *\n",
    "from py_ballisticcalc.logger import logger\n",
    "logger.setLevel(logging.WARNING)\n",
    "print(\"Default units:\\n\"+str(PreferredUnits))  # Print default units"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Simple Zero"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:55.183676Z",
     "start_time": "2025-06-13T12:32:55.145006Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Barrel elevation for 100.0yd zero: 1.334mil\n"
     ]
    }
   ],
   "source": [
    "# Establish 100-yard zero for a standard .308, G7 BC=0.22, muzzle velocity 2600fps\n",
    "zero = Shot(weapon=Weapon(sight_height=Distance.Inch(2)), ammo=Ammo(DragModel(0.22, TableG7), mv=Velocity.FPS(2600)))\n",
    "calc = Calculator()\n",
    "zero_distance = Distance.Yard(100)\n",
    "zero_elevation = calc.set_weapon_zero(zero, zero_distance)\n",
    "print(f'Barrel elevation for {zero_distance} zero: {zero_elevation << PreferredUnits.adjustment}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Plot Trajectory with Danger Space"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:55.682190Z",
     "start_time": "2025-06-13T12:32:55.205206Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Danger space at 300.0yd for 19.7inch tall target ranges from 217.1yd to 355.7yd\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 53240 characters]",
      "text/plain": [
       "<Figure size 640x480 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot trajectory out to 500 yards\n",
    "shot_result = calc.fire(zero, trajectory_range=Distance.Yard(500),\n",
    "                        trajectory_step=Distance.Yard(10), flags=TrajFlag.ALL)\n",
    "ax = shot_result.plot()\n",
    "# Find danger space for a half-meter tall target at 300 yards\n",
    "danger_space = shot_result.danger_space(Distance.Yard(300), Distance.Meter(.5))\n",
    "print(danger_space)\n",
    "danger_space.overlay(ax)  # Highlight danger space on the plot\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Print Range Card"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:55.879153Z",
     "start_time": "2025-06-13T12:32:55.728814Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>time</th>\n",
       "      <th>velocity</th>\n",
       "      <th>mach</th>\n",
       "      <th>height</th>\n",
       "      <th>drop_angle</th>\n",
       "      <th>windage</th>\n",
       "      <th>windage_angle</th>\n",
       "      <th>angle</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>distance</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0.0 yd</th>\n",
       "      <td>0.000 s</td>\n",
       "      <td>2600.0 ft/s</td>\n",
       "      <td>2.33 mach</td>\n",
       "      <td>-2.0 inch</td>\n",
       "      <td>0.000 mil</td>\n",
       "      <td>0.0 inch</td>\n",
       "      <td>0.000 mil</td>\n",
       "      <td>0.0750 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>100.0 yd</th>\n",
       "      <td>0.120 s</td>\n",
       "      <td>2398.2 ft/s</td>\n",
       "      <td>2.15 mach</td>\n",
       "      <td>-0.0 inch</td>\n",
       "      <td>-0.000 mil</td>\n",
       "      <td>0.4 inch</td>\n",
       "      <td>0.119 mil</td>\n",
       "      <td>-0.0137 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>200.0 yd</th>\n",
       "      <td>0.251 s</td>\n",
       "      <td>2205.6 ft/s</td>\n",
       "      <td>1.98 mach</td>\n",
       "      <td>-4.1 inch</td>\n",
       "      <td>-0.574 mil</td>\n",
       "      <td>1.7 inch</td>\n",
       "      <td>0.247 mil</td>\n",
       "      <td>-0.1184 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>300.0 yd</th>\n",
       "      <td>0.393 s</td>\n",
       "      <td>2022.5 ft/s</td>\n",
       "      <td>1.81 mach</td>\n",
       "      <td>-15.3 inch</td>\n",
       "      <td>-1.441 mil</td>\n",
       "      <td>4.1 inch</td>\n",
       "      <td>0.386 mil</td>\n",
       "      <td>-0.2424 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>400.0 yd</th>\n",
       "      <td>0.548 s</td>\n",
       "      <td>1847.8 ft/s</td>\n",
       "      <td>1.66 mach</td>\n",
       "      <td>-35.0 inch</td>\n",
       "      <td>-2.478 mil</td>\n",
       "      <td>7.6 inch</td>\n",
       "      <td>0.537 mil</td>\n",
       "      <td>-0.3905 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>500.0 yd</th>\n",
       "      <td>0.718 s</td>\n",
       "      <td>1680.4 ft/s</td>\n",
       "      <td>1.51 mach</td>\n",
       "      <td>-65.0 inch</td>\n",
       "      <td>-3.677 mil</td>\n",
       "      <td>12.4 inch</td>\n",
       "      <td>0.703 mil</td>\n",
       "      <td>-0.5687 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>600.0 yd</th>\n",
       "      <td>0.906 s</td>\n",
       "      <td>1519.8 ft/s</td>\n",
       "      <td>1.36 mach</td>\n",
       "      <td>-107.3 inch</td>\n",
       "      <td>-5.060 mil</td>\n",
       "      <td>18.8 inch</td>\n",
       "      <td>0.886 mil</td>\n",
       "      <td>-0.7854 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>700.0 yd</th>\n",
       "      <td>1.114 s</td>\n",
       "      <td>1366.4 ft/s</td>\n",
       "      <td>1.22 mach</td>\n",
       "      <td>-164.7 inch</td>\n",
       "      <td>-6.658 mil</td>\n",
       "      <td>27.0 inch</td>\n",
       "      <td>1.090 mil</td>\n",
       "      <td>-1.0520 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>800.0 yd</th>\n",
       "      <td>1.346 s</td>\n",
       "      <td>1221.7 ft/s</td>\n",
       "      <td>1.09 mach</td>\n",
       "      <td>-240.9 inch</td>\n",
       "      <td>-8.519 mil</td>\n",
       "      <td>37.2 inch</td>\n",
       "      <td>1.317 mil</td>\n",
       "      <td>-1.3837 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>900.0 yd</th>\n",
       "      <td>1.606 s</td>\n",
       "      <td>1093.5 ft/s</td>\n",
       "      <td>0.98 mach</td>\n",
       "      <td>-340.4 inch</td>\n",
       "      <td>-10.702 mil</td>\n",
       "      <td>50.0 inch</td>\n",
       "      <td>1.571 mil</td>\n",
       "      <td>-1.7997 °</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1000.0 yd</th>\n",
       "      <td>1.890 s</td>\n",
       "      <td>1029.8 ft/s</td>\n",
       "      <td>0.92 mach</td>\n",
       "      <td>-468.8 inch</td>\n",
       "      <td>-13.263 mil</td>\n",
       "      <td>64.8 inch</td>\n",
       "      <td>1.834 mil</td>\n",
       "      <td>-2.2945 °</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              time     velocity       mach       height     drop_angle  \\\n",
       "distance                                                               \n",
       "0.0 yd     0.000 s  2600.0 ft/s  2.33 mach    -2.0 inch    0.000 mil   \n",
       "100.0 yd   0.120 s  2398.2 ft/s  2.15 mach    -0.0 inch   -0.000 mil   \n",
       "200.0 yd   0.251 s  2205.6 ft/s  1.98 mach    -4.1 inch   -0.574 mil   \n",
       "300.0 yd   0.393 s  2022.5 ft/s  1.81 mach   -15.3 inch   -1.441 mil   \n",
       "400.0 yd   0.548 s  1847.8 ft/s  1.66 mach   -35.0 inch   -2.478 mil   \n",
       "500.0 yd   0.718 s  1680.4 ft/s  1.51 mach   -65.0 inch   -3.677 mil   \n",
       "600.0 yd   0.906 s  1519.8 ft/s  1.36 mach  -107.3 inch   -5.060 mil   \n",
       "700.0 yd   1.114 s  1366.4 ft/s  1.22 mach  -164.7 inch   -6.658 mil   \n",
       "800.0 yd   1.346 s  1221.7 ft/s  1.09 mach  -240.9 inch   -8.519 mil   \n",
       "900.0 yd   1.606 s  1093.5 ft/s  0.98 mach  -340.4 inch  -10.702 mil   \n",
       "1000.0 yd  1.890 s  1029.8 ft/s  0.92 mach  -468.8 inch  -13.263 mil   \n",
       "\n",
       "             windage windage_angle      angle  \n",
       "distance                                     \n",
       "0.0 yd      0.0 inch   0.000 mil   0.0750 °  \n",
       "100.0 yd    0.4 inch   0.119 mil  -0.0137 °  \n",
       "200.0 yd    1.7 inch   0.247 mil  -0.1184 °  \n",
       "300.0 yd    4.1 inch   0.386 mil  -0.2424 °  \n",
       "400.0 yd    7.6 inch   0.537 mil  -0.3905 °  \n",
       "500.0 yd   12.4 inch   0.703 mil  -0.5687 °  \n",
       "600.0 yd   18.8 inch   0.886 mil  -0.7854 °  \n",
       "700.0 yd   27.0 inch   1.090 mil  -1.0520 °  \n",
       "800.0 yd   37.2 inch   1.317 mil  -1.3837 °  \n",
       "900.0 yd   50.0 inch   1.571 mil  -1.7997 °  \n",
       "1000.0 yd  64.8 inch   1.834 mil  -2.2945 °  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Range card for this zero with 5mph cross-wind from left to right\n",
    "zero.winds = [Wind(Velocity.MPH(5), Angular.OClock(3))]\n",
    "range_card = calc.fire(zero, trajectory_range=1000, trajectory_step=100)\n",
    "# for p in range_card: print(p.formatted())\n",
    "range_card.dataframe().to_clipboard()\n",
    "range_card.dataframe(True).drop(['slant_height', 'slant_distance', 'density_ratio', 'drag', 'energy', 'ogw', 'flag'], axis=1).set_index('distance')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Firing Solutions\n",
    "\n",
    "## Different Distance, from Range Card\n",
    "\n",
    "First approach here shows getting firing solution by looking up the adjustment in the Range Card:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:56.016400Z",
     "start_time": "2025-06-13T12:32:55.895829Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Zero trajectory hits -65.0inch at 500.0yd\n",
      "Sight adjustment to hit 500.0yd target is -3.677mil\n",
      "After adjustment: drop at 500.0yd is -0.0inch\n"
     ]
    }
   ],
   "source": [
    "# Now shooter is sighting a target at look-distance 500 yard (zero.look-angle):\n",
    "new_target_distance = Distance.Yard(500)\n",
    "# Get row for this distance from the range card\n",
    "new_target = range_card.get_at('distance', new_target_distance)\n",
    "print(f'Zero trajectory hits {new_target.slant_height << PreferredUnits.drop}'\n",
    "      f' at {(new_target.distance << PreferredUnits.distance)}')\n",
    "\n",
    "# Shooter looks up adjustment to hit new target:\n",
    "hold = new_target.drop_angle  # << Firing solution\n",
    "\n",
    "print(f'Sight adjustment to hit {(new_target.distance << PreferredUnits.distance)} target'\n",
    "      f' is {(hold << PreferredUnits.adjustment)}')\n",
    "# Shooter dials that hold value for a 500-yard shot.  Verification:\n",
    "new_shot = copy.copy(zero)\n",
    "new_shot.relative_angle = Angular(-hold.unit_value, hold.units)\n",
    "adjusted_result = calc.fire(new_shot, trajectory_range=1000, trajectory_step=100)\n",
    "trajectory_adjusted = adjusted_result.get_at('distance', new_target_distance)\n",
    "print(f'After adjustment: drop at {trajectory_adjusted.distance << PreferredUnits.distance}'\n",
    "      f' is {trajectory_adjusted.slant_height << PreferredUnits.drop}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Different Look Angle\n",
    "\n",
    "Second approach here shows solving for barrel elevation to hit new target, then adjusting by the difference between that and the zero barrel elevation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:56.410591Z",
     "start_time": "2025-06-13T12:32:56.064462Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "To hit target at look-distance of 500.0yd sighted at a 25.84° look-angle, barrel elevation=4.513mil\n",
      "Current zero has barrel elevated 1.334mil so hold for new shot is 3.18mil\n",
      "(Horizontal component of distance to this target is 450.0yd)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>time</th>\n",
       "      <th>velocity</th>\n",
       "      <th>mach</th>\n",
       "      <th>slant_height</th>\n",
       "      <th>drop_angle</th>\n",
       "      <th>windage</th>\n",
       "      <th>windage_angle</th>\n",
       "      <th>slant_distance</th>\n",
       "      <th>angle</th>\n",
       "      <th>density_ratio</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>distance</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0.0 yd</th>\n",
       "      <td>0.000 s</td>\n",
       "      <td>2600.0 ft/s</td>\n",
       "      <td>2.33 mach</td>\n",
       "      <td>-1.8 inch</td>\n",
       "      <td>0.000 mil</td>\n",
       "      <td>0.0 inch</td>\n",
       "      <td>0.000 mil</td>\n",
       "      <td>-0.0 yd</td>\n",
       "      <td>26.0939 °</td>\n",
       "      <td>1.00002e+00</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50.0 yd</th>\n",
       "      <td>0.066 s</td>\n",
       "      <td>2485.7 ft/s</td>\n",
       "      <td>2.23 mach</td>\n",
       "      <td>6.3 inch</td>\n",
       "      <td>3.225 mil</td>\n",
       "      <td>0.1 inch</td>\n",
       "      <td>0.072 mil</td>\n",
       "      <td>55.6 yd</td>\n",
       "      <td>26.0511 °</td>\n",
       "      <td>9.97881e-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>100.0 yd</th>\n",
       "      <td>0.134 s</td>\n",
       "      <td>2374.5 ft/s</td>\n",
       "      <td>2.13 mach</td>\n",
       "      <td>12.9 inch</td>\n",
       "      <td>3.284 mil</td>\n",
       "      <td>0.5 inch</td>\n",
       "      <td>0.147 mil</td>\n",
       "      <td>111.3 yd</td>\n",
       "      <td>26.0042 °</td>\n",
       "      <td>9.95742e-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>150.0 yd</th>\n",
       "      <td>0.206 s</td>\n",
       "      <td>2266.5 ft/s</td>\n",
       "      <td>2.03 mach</td>\n",
       "      <td>17.8 inch</td>\n",
       "      <td>3.013 mil</td>\n",
       "      <td>1.2 inch</td>\n",
       "      <td>0.226 mil</td>\n",
       "      <td>166.9 yd</td>\n",
       "      <td>25.9528 °</td>\n",
       "      <td>9.93612e-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>200.0 yd</th>\n",
       "      <td>0.282 s</td>\n",
       "      <td>2161.6 ft/s</td>\n",
       "      <td>1.94 mach</td>\n",
       "      <td>20.7 inch</td>\n",
       "      <td>2.638 mil</td>\n",
       "      <td>2.2 inch</td>\n",
       "      <td>0.308 mil</td>\n",
       "      <td>222.5 yd</td>\n",
       "      <td>25.8964 °</td>\n",
       "      <td>9.91491e-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>250.0 yd</th>\n",
       "      <td>0.361 s</td>\n",
       "      <td>2059.9 ft/s</td>\n",
       "      <td>1.85 mach</td>\n",
       "      <td>21.6 inch</td>\n",
       "      <td>2.202 mil</td>\n",
       "      <td>3.5 inch</td>\n",
       "      <td>0.393 mil</td>\n",
       "      <td>278.1 yd</td>\n",
       "      <td>25.8343 °</td>\n",
       "      <td>9.89378e-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>300.0 yd</th>\n",
       "      <td>0.444 s</td>\n",
       "      <td>1961.0 ft/s</td>\n",
       "      <td>1.76 mach</td>\n",
       "      <td>20.3 inch</td>\n",
       "      <td>1.719 mil</td>\n",
       "      <td>5.1 inch</td>\n",
       "      <td>0.483 mil</td>\n",
       "      <td>333.6 yd</td>\n",
       "      <td>25.7658 °</td>\n",
       "      <td>9.87275e-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>350.0 yd</th>\n",
       "      <td>0.531 s</td>\n",
       "      <td>1864.7 ft/s</td>\n",
       "      <td>1.67 mach</td>\n",
       "      <td>16.4 inch</td>\n",
       "      <td>1.191 mil</td>\n",
       "      <td>7.1 inch</td>\n",
       "      <td>0.576 mil</td>\n",
       "      <td>389.1 yd</td>\n",
       "      <td>25.6902 °</td>\n",
       "      <td>9.85183e-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>400.0 yd</th>\n",
       "      <td>0.622 s</td>\n",
       "      <td>1770.9 ft/s</td>\n",
       "      <td>1.59 mach</td>\n",
       "      <td>9.7 inch</td>\n",
       "      <td>0.619 mil</td>\n",
       "      <td>9.5 inch</td>\n",
       "      <td>0.674 mil</td>\n",
       "      <td>444.6 yd</td>\n",
       "      <td>25.6064 °</td>\n",
       "      <td>9.83101e-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>450.0 yd</th>\n",
       "      <td>0.719 s</td>\n",
       "      <td>1679.4 ft/s</td>\n",
       "      <td>1.51 mach</td>\n",
       "      <td>0.0 inch</td>\n",
       "      <td>0.000 mil</td>\n",
       "      <td>12.4 inch</td>\n",
       "      <td>0.777 mil</td>\n",
       "      <td>500.0 yd</td>\n",
       "      <td>25.5134 °</td>\n",
       "      <td>9.81030e-01</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>500.0 yd</th>\n",
       "      <td>0.820 s</td>\n",
       "      <td>1590.2 ft/s</td>\n",
       "      <td>1.43 mach</td>\n",
       "      <td>-13.1 inch</td>\n",
       "      <td>-0.669 mil</td>\n",
       "      <td>15.7 inch</td>\n",
       "      <td>0.886 mil</td>\n",
       "      <td>555.4 yd</td>\n",
       "      <td>25.4098 °</td>\n",
       "      <td>9.78972e-01</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             time     velocity       mach slant_height    drop_angle    windage  \\\n",
       "distance                                                                        \n",
       "0.0 yd    0.000 s  2600.0 ft/s  2.33 mach    -1.8 inch   0.000 mil   0.0 inch   \n",
       "50.0 yd   0.066 s  2485.7 ft/s  2.23 mach     6.3 inch   3.225 mil   0.1 inch   \n",
       "100.0 yd  0.134 s  2374.5 ft/s  2.13 mach    12.9 inch   3.284 mil   0.5 inch   \n",
       "150.0 yd  0.206 s  2266.5 ft/s  2.03 mach    17.8 inch   3.013 mil   1.2 inch   \n",
       "200.0 yd  0.282 s  2161.6 ft/s  1.94 mach    20.7 inch   2.638 mil   2.2 inch   \n",
       "250.0 yd  0.361 s  2059.9 ft/s  1.85 mach    21.6 inch   2.202 mil   3.5 inch   \n",
       "300.0 yd  0.444 s  1961.0 ft/s  1.76 mach    20.3 inch   1.719 mil   5.1 inch   \n",
       "350.0 yd  0.531 s  1864.7 ft/s  1.67 mach    16.4 inch   1.191 mil   7.1 inch   \n",
       "400.0 yd  0.622 s  1770.9 ft/s  1.59 mach     9.7 inch   0.619 mil   9.5 inch   \n",
       "450.0 yd  0.719 s  1679.4 ft/s  1.51 mach     0.0 inch   0.000 mil  12.4 inch   \n",
       "500.0 yd  0.820 s  1590.2 ft/s  1.43 mach   -13.1 inch  -0.669 mil  15.7 inch   \n",
       "\n",
       "         windage_angle slant_distance      angle density_ratio  \n",
       "distance                                                      \n",
       "0.0 yd     0.000 mil        -0.0 yd  26.0939 °   1.00002e+00  \n",
       "50.0 yd    0.072 mil        55.6 yd  26.0511 °   9.97881e-01  \n",
       "100.0 yd   0.147 mil       111.3 yd  26.0042 °   9.95742e-01  \n",
       "150.0 yd   0.226 mil       166.9 yd  25.9528 °   9.93612e-01  \n",
       "200.0 yd   0.308 mil       222.5 yd  25.8964 °   9.91491e-01  \n",
       "250.0 yd   0.393 mil       278.1 yd  25.8343 °   9.89378e-01  \n",
       "300.0 yd   0.483 mil       333.6 yd  25.7658 °   9.87275e-01  \n",
       "350.0 yd   0.576 mil       389.1 yd  25.6902 °   9.85183e-01  \n",
       "400.0 yd   0.674 mil       444.6 yd  25.6064 °   9.83101e-01  \n",
       "450.0 yd   0.777 mil       500.0 yd  25.5134 °   9.81030e-01  \n",
       "500.0 yd   0.886 mil       555.4 yd  25.4098 °   9.78972e-01  "
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Calculate elevation for a new shot at a different look-angle\n",
    "new_shot = copy.copy(zero)  # Copy the zero properties; NB: Not a deepcopy!\n",
    "new_shot.look_angle = Angular.Degree(25.84)\n",
    "new_elevation = calc.barrel_elevation_for_target(shot=new_shot, target_distance=new_target_distance)\n",
    "# Firing solution:\n",
    "hold = Angular.Mil((new_elevation >> Angular.Mil) - (zero.weapon.zero_elevation >> Angular.Mil))\n",
    "\n",
    "print(f'To hit target at look-distance of {new_target_distance << PreferredUnits.distance}'\n",
    "      f' sighted at a {new_shot.look_angle << PreferredUnits.angular} look-angle,' \n",
    "      f' barrel elevation={new_elevation << PreferredUnits.adjustment}')\n",
    "print(f'Current zero has barrel elevated {zero.weapon.zero_elevation << PreferredUnits.adjustment}'\n",
    "      f' so hold for new shot is {hold << PreferredUnits.adjustment}')      \n",
    "horizontal = Distance(math.cos(new_shot.look_angle >> Angular.Radian)\n",
    "                      * new_target_distance.unit_value, new_target_distance.units)\n",
    "print(f'(Horizontal component of distance to this target is {horizontal})')\n",
    "\n",
    "# Plot this shot\n",
    "new_shot.relative_angle = hold\n",
    "card = calc.fire(new_shot, trajectory_range=500, trajectory_step=50)\n",
    "card.dataframe(True).drop(['height', 'energy', 'ogw', 'drag', 'flag'], axis=1).set_index('distance')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Complex example\n",
    "\n",
    "Now we'll switch to metric units and:\n",
    "* Define a standard .50BMG\n",
    "* Enable and define Ammo model of powder temperature sensitivity.\n",
    "* Zeroed for a distance of 500 meters, in a 5°C atmosphere at altitude 1000ft ASL."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:56.643328Z",
     "start_time": "2025-06-13T12:32:56.481812Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Barrel elevation for 500.0m zero: 4.691mil\n",
      "Muzzle velocity at zero temperature 41.0°F is 829.0m/s\n"
     ]
    }
   ],
   "source": [
    "PreferredUnits.distance = Unit.Meter\n",
    "PreferredUnits.velocity = Unit.MPS\n",
    "PreferredUnits.drop = Unit.Meter\n",
    "PreferredUnits.sight_height = Unit.Centimeter\n",
    "\n",
    "# Standard .50BMG\n",
    "dm = DragModel(0.62, TableG1, 661, 0.51, 2.3)\n",
    "ammo=Ammo(dm, 850, Temperature.Celsius(15), use_powder_sensitivity=True)\n",
    "ammo.calc_powder_sens(820, Temperature.Celsius(0))\n",
    "weapon = Weapon(sight_height=9, twist=15)\n",
    "atmo = Atmo(altitude=Distance.Foot(1000), temperature=Unit.Celsius(5), humidity=.5)\n",
    "zero = Shot(weapon=weapon, ammo=ammo, atmo=atmo)\n",
    "zero_distance = Distance.Meter(500)\n",
    "calc = Calculator()\n",
    "zero_elevation = calc.set_weapon_zero(zero, zero_distance)\n",
    "print(f'Barrel elevation for {zero_distance} zero: {zero_elevation << PreferredUnits.adjustment}')\n",
    "print(f'Muzzle velocity at zero temperature {atmo.temperature} is {ammo.get_velocity_for_temp(atmo.temperature) << PreferredUnits.velocity}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:58.110721Z",
     "start_time": "2025-06-13T12:32:56.844992Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "To hit target at look-distance of 700.0m sighted at a 30.0° look-angle, barrel elevation=6.147mil\n",
      "\t(horizontal distance to this target is 606.2m)\n",
      "Current zero has barrel elevated 4.691mil so hold for new shot is 1.456mil\n",
      "Danger space at 700.0m for 2.2m tall target at 30.0° look-angle ranges from 464.1m to 812.4m\n",
      "\t(horizontal 401.4m to 704.1m)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 62528 characters]",
      "text/plain": [
       "<Figure size 640x480 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Firing solution for 700m target at 30°\n",
    "new_shot = copy.copy(zero)  # Copy the zero properties; NB: Not a deepcopy!\n",
    "new_shot.look_angle = Angular.Degree(30)\n",
    "new_target_distance = Distance.Meter(700)\n",
    "new_elevation = calc.barrel_elevation_for_target(shot=new_shot, target_distance=new_target_distance)\n",
    "horizontal = Distance(math.cos(new_shot.look_angle >> Angular.Radian)\n",
    "                      * new_target_distance.unit_value, new_target_distance.units)\n",
    "print(f'To hit target at look-distance of {new_target_distance << PreferredUnits.distance}'\n",
    "      f' sighted at a {new_shot.look_angle << PreferredUnits.angular} look-angle,' \n",
    "      f' barrel elevation={new_elevation << PreferredUnits.adjustment}'\n",
    "      f'\\n\\t(horizontal distance to this target is {horizontal})')\n",
    "\n",
    "# Firing solution:\n",
    "hold = Angular.Mil((new_elevation >> Angular.Mil) - (zero.weapon.zero_elevation >> Angular.Mil))\n",
    "print(f'Current zero has barrel elevated {zero.weapon.zero_elevation << PreferredUnits.adjustment}'\n",
    "      f' so hold for new shot is {hold << PreferredUnits.adjustment}')      \n",
    "\n",
    "# Plot this shot\n",
    "new_shot.relative_angle = hold\n",
    "adjusted_result = calc.fire(new_shot, trajectory_range=Distance.Meter(1200),\n",
    "                            trajectory_step=Distance.Meter(10), flags=TrajFlag.ALL)\n",
    "ax = adjusted_result.plot()\n",
    "# Find danger space for a 4-meter tall target\n",
    "danger_space = adjusted_result.danger_space(at_range=new_target_distance, target_height=Distance.Meter(2.2))\n",
    "print(danger_space)\n",
    "# Highlight danger space on the plot\n",
    "danger_space.overlay(ax, f\"Danger Space\\n({danger_space.target_height << PreferredUnits.distance} Target)\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Multiple Winds"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:58.576358Z",
     "start_time": "2025-06-13T12:32:58.145534Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 46196 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "new_shot.winds = [Wind(Velocity.MPS(4), Angular.OClock(9), until_distance=Distance.Meter(400)),\n",
    "                  Wind(Velocity.MPS(4), Angular.OClock(3), until_distance=Distance.Meter(800)),\n",
    "                  Wind(Velocity.MPS(4), Angular.OClock(9), until_distance=Distance.Meter(1200)),]\n",
    "wind_result = calc.fire(new_shot, trajectory_range=Distance.Meter(1500), trajectory_step=Distance.Meter(5))\n",
    "ax = wind_result.dataframe().plot(x='windage', y='distance', ylabel=f'Distance ({PreferredUnits.distance.key}s)', xlabel=f'Windage ({PreferredUnits.distance.key}s)', label='Deflection with winds')\n",
    "no_wind = adjusted_result.dataframe()\n",
    "ax.plot(no_wind.windage, no_wind.distance, label='No wind (spin drift only)')\n",
    "plt.legend(loc=\"upper center\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Plot Drag Curve"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:58.676509Z",
     "start_time": "2025-06-13T12:32:58.581670Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 26664 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "df = pandas.DataFrame(TableG7)\n",
    "ax = df.plot(x='Mach', y='CD', ylabel='Cd', legend=False)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Multiple-BC\n",
    "In the old days, even a G7 projectile like the 168gr .308 OTM was quoted with a G1 BC.  Then Sierra offered a multiple-BC model.  Later, Litz published a multiple-BC G7 model.  Here's how they compare."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:58.894058Z",
     "start_time": "2025-06-13T12:32:58.738531Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 64068 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Single G1 BC\n",
    "dm1 = DragModelMultiBC([BCPoint(.462, Mach=1)], TableG1, weight=168, diameter=.308)\n",
    "# Sierra's G1 BC: 0.462 above 2600 fps, 0.447 above 2100 fps, 0.424 above 1600 fps, and .405 below that.\n",
    "dm2 = DragModelMultiBC([BCPoint(.462, V=Velocity.FPS(2600)), BCPoint(.462-(.462-.447)/2, V=Velocity.FPS(2350)), BCPoint(.424-(.424-.405)/2, V=Velocity.FPS(1850)), BCPoint(.405, V=Velocity.FPS(1600))],\n",
    "                       TableG1, weight=168, diameter=.308)\n",
    "# Single G7 BC\n",
    "dm3 = DragModelMultiBC([BCPoint(.224, Mach=1)], TableG7, weight=168, diameter=.308)\n",
    "# Litz's G7 multi-BC:\n",
    "dm4 = DragModelMultiBC([BCPoint(.211, V=Velocity.FPS(1500)), BCPoint(.214, V=Velocity.FPS(2000)), BCPoint(.222, V=Velocity.FPS(2500)), BCPoint(.226, V=Velocity.FPS(3000))],\n",
    "                       TableG7, weight=168, diameter=.308)\n",
    "ax = pandas.DataFrame(dm1.drag_table).plot(x='Mach', y='CD', ylabel='Drag Coefficient', label='G1 Single BC (Baseline)')\n",
    "pandas.DataFrame(dm2.drag_table).plot(x='Mach', y='CD', label='G1 Multiple BC (Sierra)', linestyle='dashed', linewidth=2, ax=ax)\n",
    "pandas.DataFrame(dm3.drag_table).plot(x='Mach', y='CD', label='G7 Single BC', linestyle='dashdot', ax=ax)\n",
    "pandas.DataFrame(dm4.drag_table).plot(x='Mach', y='CD', label='G7 Multiple BC (Litz)', linestyle='dotted', linewidth=3, ax=ax)\n",
    "ax.spines[['right', 'top']].set_visible(False)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:59.488680Z",
     "start_time": "2025-06-13T12:32:58.910777Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>time</th>\n",
       "      <th>velocity</th>\n",
       "      <th>mach</th>\n",
       "      <th>height</th>\n",
       "      <th>drag</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>distance</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>500.0 yd</th>\n",
       "      <td>0.606 s</td>\n",
       "      <td>2043.6 ft/s</td>\n",
       "      <td>1.83 mach</td>\n",
       "      <td>-63.5 inch</td>\n",
       "      <td>2.784e-04</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1000.0 yd</th>\n",
       "      <td>1.527 s</td>\n",
       "      <td>1318.1 ft/s</td>\n",
       "      <td>1.18 mach</td>\n",
       "      <td>-349.1 inch</td>\n",
       "      <td>2.855e-04</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              time     velocity       mach       height       drag\n",
       "distance                                                          \n",
       "500.0 yd   0.606 s  2043.6 ft/s  1.83 mach   -63.5 inch  2.784e-04\n",
       "1000.0 yd  1.527 s  1318.1 ft/s  1.18 mach  -349.1 inch  2.855e-04"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>time</th>\n",
       "      <th>velocity</th>\n",
       "      <th>mach</th>\n",
       "      <th>height</th>\n",
       "      <th>drag</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>distance</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>500.0 yd</th>\n",
       "      <td>0.607 s</td>\n",
       "      <td>2028.2 ft/s</td>\n",
       "      <td>1.82 mach</td>\n",
       "      <td>-63.6 inch</td>\n",
       "      <td>3.009e-04</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1000.0 yd</th>\n",
       "      <td>1.561 s</td>\n",
       "      <td>1240.1 ft/s</td>\n",
       "      <td>1.11 mach</td>\n",
       "      <td>-357.8 inch</td>\n",
       "      <td>3.069e-04</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              time     velocity       mach       height       drag\n",
       "distance                                                          \n",
       "500.0 yd   0.607 s  2028.2 ft/s  1.82 mach   -63.6 inch  3.009e-04\n",
       "1000.0 yd  1.561 s  1240.1 ft/s  1.11 mach  -357.8 inch  3.069e-04"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>time</th>\n",
       "      <th>velocity</th>\n",
       "      <th>mach</th>\n",
       "      <th>height</th>\n",
       "      <th>drag</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>distance</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>500.0 yd</th>\n",
       "      <td>0.611 s</td>\n",
       "      <td>2015.0 ft/s</td>\n",
       "      <td>1.80 mach</td>\n",
       "      <td>-64.1 inch</td>\n",
       "      <td>2.898e-04</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1000.0 yd</th>\n",
       "      <td>1.563 s</td>\n",
       "      <td>1228.4 ft/s</td>\n",
       "      <td>1.10 mach</td>\n",
       "      <td>-359.5 inch</td>\n",
       "      <td>3.737e-04</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              time     velocity       mach       height       drag\n",
       "distance                                                          \n",
       "500.0 yd   0.611 s  2015.0 ft/s  1.80 mach   -64.1 inch  2.898e-04\n",
       "1000.0 yd  1.563 s  1228.4 ft/s  1.10 mach  -359.5 inch  3.737e-04"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>time</th>\n",
       "      <th>velocity</th>\n",
       "      <th>mach</th>\n",
       "      <th>height</th>\n",
       "      <th>drag</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>distance</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>500.0 yd</th>\n",
       "      <td>0.611 s</td>\n",
       "      <td>2002.4 ft/s</td>\n",
       "      <td>1.79 mach</td>\n",
       "      <td>-64.1 inch</td>\n",
       "      <td>3.042e-04</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1000.0 yd</th>\n",
       "      <td>1.586 s</td>\n",
       "      <td>1179.8 ft/s</td>\n",
       "      <td>1.06 mach</td>\n",
       "      <td>-365.3 inch</td>\n",
       "      <td>3.997e-04</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              time     velocity       mach       height       drag\n",
       "distance                                                          \n",
       "500.0 yd   0.611 s  2002.4 ft/s  1.79 mach   -64.1 inch  3.042e-04\n",
       "1000.0 yd  1.586 s  1179.8 ft/s  1.06 mach  -365.3 inch  3.997e-04"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "PreferredUnits.distance = Unit.Yard\n",
    "PreferredUnits.velocity = Unit.FPS\n",
    "PreferredUnits.drop = Unit.Inch\n",
    "\n",
    "for dm in [dm1, dm2, dm3, dm4]:\n",
    "    zero = Shot(weapon=Weapon(sight_height=2), ammo=Ammo(dm, mv=Velocity.FPS(3000)))\n",
    "    calc = Calculator()\n",
    "    shot_result = calc.fire(zero, trajectory_range=1000, trajectory_step=500)\n",
    "    display(shot_result.dataframe(True)[['distance', 'time', 'velocity', 'mach', 'height', 'drag']].set_index('distance')[1:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Working With Units"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T12:32:59.550554Z",
     "start_time": "2025-06-13T12:32:59.533898Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Default distance unit: Foot\n",
      "\tInstantiated from float (5): 5.0ft\n",
      "\tInstantiated from Distance.Line(200): 1.67ft\n",
      "100 meters: 100.0m\n",
      "100 meters in yard: 109.4yd\n",
      "100 meters, value in km: 0.09999999999999999  (value type is <class 'float'>)\n",
      "100 meters in raw value: 3937.0078740157483  (raw type is <class 'float'>)\n",
      "Comparison: 109.4yd == 100.0cm: False\n",
      "Comparison: 109.4yd > .1*109.4yd: True\n",
      "Restored default distance unit: Yard\n"
     ]
    }
   ],
   "source": [
    "initial_distance_unit = PreferredUnits.distance\n",
    "PreferredUnits.distance = Unit.Foot\n",
    "print(f'Default distance unit: {PreferredUnits.distance.name}')\n",
    "# Can create value in default unit with either float or another unit of same type\n",
    "print(f'\\tInstantiated from float (5): {PreferredUnits.distance(5)}')\n",
    "print(f'\\tInstantiated from Distance.Line(200): {PreferredUnits.distance(Distance.Line(200))}')\n",
    "\n",
    "# Ways to define value in units\n",
    "# 1. old syntax\n",
    "unit_in_meter = Distance(100, Distance.Meter)\n",
    "# 2. short syntax by Unit type class\n",
    "unit_in_meter = Distance.Meter(100)\n",
    "# 3. by Unit enum class\n",
    "unit_in_meter = Unit.Meter(100)\n",
    "print(f'100 meters: {unit_in_meter}')\n",
    "# >>> 100 meters: 100.0m\n",
    "\n",
    "# Convert unit\n",
    "# 1. by .convert()\n",
    "unit_in_yards = unit_in_meter.convert(Distance.Yard)\n",
    "# 2. using shift syntax\n",
    "unit_in_yards = unit_in_meter << Distance.Yard  # '<<=' operator also supports\n",
    "print(f'100 meters in {unit_in_yards.units.key}: {unit_in_yards}')\n",
    "# >>> 100 meters in yard: 109.4yd\n",
    "\n",
    "# Get value in specified units (as float)\n",
    "# 1. by .get_in()\n",
    "value_in_km = unit_in_yards.get_in(Distance.Kilometer)\n",
    "# 2. by shift syntax\n",
    "value_in_km = unit_in_yards >> Distance.Kilometer  # '>>=' operator also supports\n",
    "print(f'100 meters, value in km: {value_in_km}  (value type is {type(value_in_km)})')\n",
    "# >>> 100 meters, value in km: 0.1  (value type is <class 'float'>)\n",
    "\n",
    "# Getting unit raw value (a float)\n",
    "rvalue = Distance.Meter(100).raw_value\n",
    "rvalue = float(Distance.Meter(100))\n",
    "print(f'100 meters in raw value: {rvalue}  (raw type is {type(rvalue)})')\n",
    "# >>> 100 meters in raw value: 3937.0078740157483  (raw type is <class 'float'>)\n",
    "\n",
    "# Comparison operators supported: < > <= >= == !=\n",
    "print(f'Comparison: {unit_in_meter} == {Distance.Centimeter(100)}: {unit_in_meter == Distance.Centimeter(100)}')  # >>> False, compare two units by raw value\n",
    "print(f'Comparison: {unit_in_meter} > .1*{unit_in_meter}: {unit_in_meter > .1*unit_in_meter.raw_value}')  # >>> True, compare unit with float by raw value\n",
    "\n",
    "PreferredUnits.distance = initial_distance_unit  # Restore default unit\n",
    "print(f'Restored default distance unit: {PreferredUnits.distance.name}')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py-ballisticcalc",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
