|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Physics::Ballistics::External;  | 
| 
2
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
118861
 | 
 use strict;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
    | 
| 
3
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
6
 | 
 use warnings;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
82
 | 
    | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 require Exporter;  | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our @ISA = qw(Exporter);  | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our @EXPORT = qw(ebc flight_simulator g1_drag muzzle_energy muzzle_velocity_from_energy);  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = '1.03';  | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
9
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
537
 | 
 use Math::Trig qw(tan asin acos atan pi);  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12582
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
105
 | 
    | 
| 
10
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
422
 | 
 use Physics::Ballistics;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3120
 | 
    | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Physics::Ballistics::External -- External ballistics formulae.  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 ABSTRACT  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 External ballistics is the study of projectiles in flight, from the time they  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 leave the barrel (or hand, or trebuchet, or whatever), to the moment before  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 they strike their target.  This module implements mathematical formulae and  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 functions useful in the analysis and prediction of external ballistic behavior.  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 ANNOTATIONS OF SOURCES  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Regarding their source, these functions fall into three categories:  Some are  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 simple encodings of basic physics (like energy = 1/2 * mass * velocity**2),  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 and these will not be cited.  Others are from published works, such as books  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 or trade journals, and these will be cited when possible.  A few are products  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 of my own efforts, and will be thus annotated.  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 OOP INTERFACE  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A more integrated, object-oriented interface for these functions is under  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 development.  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 FUNCTIONS  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 ebc (mass_grains, diameter_inches, [shape,] [form_factor])  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Attempts to predict the G1 ballistic coefficient of a projectile, based on its  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 mass, width, and shape.  Useful for predicting the ballistic behavior of  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 hypothetical or new, untested projectiles.  When compared against the known G1  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 BC's of well-understood projectiles, its predictions usually come within 5% of  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 actual.  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The "shape" parameter indicates that the hypothetical projectile is closest in  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 its shape, composition, and quality of manufacture to the named entity.  Some  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 shapes are very general ("hollowpoint", "fmj") while others are very specific  | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 to product families manufactured by particular companies ("scenar", "amax").  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The "shape" parameter maps to a numerical form base (see table below), which  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 gets tweaked a little by other factors to derive a form factor.  The form  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 factor has an inverse impact on ballistic coefficient (higher form factor  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 means a lower coefficient).  In lieu of depending on the "shape" parameter, a  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 form factor may be specified as a parameter (mostly useful for debugging or  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 deriving new entries in the shape table).  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 When no shape or form factor are provided, the "default" shape is used, which  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has a form base chosen to minimize the error produced by this function when  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 its output is compared to entries in http://www.frfrogspad.com/g1bclist.xls  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 not already covered in the shape table.  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A hashfile including all of the information from g1bclist.xls with "shape"  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 entries matching the names from the shape table below may be found here:  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 http://ciar.org/ttk/mbt/guns/table.bc.hash  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This function is the original work of the module's author.  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) mass of the projectile (in grains)  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) diameter of the projectile (in inches)  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (str) OPTIONAL: shape/composition of the projectile (see table below, default is "default")  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) OPTIONAL: custom form-factor of the projectile, unnecessary if "shape" is provided.  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 returns: a list, containing the following values:  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * The estimated G1 ballistic coefficient,  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * The form factor (suitable for use as as form_factor parameter)  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * The "very short factor" (1.0 for most well-proportioned bullets)  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * The shape parameter used  | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The shape table currently contains the following entities, with the given form bases:  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '7n14'              => 111, # Very deep ogival shape and boat-tail with tight tolerances, used in military 7.62x54R specifically for sniping.  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'scenar'            => 124, # Scenar, by Lapua  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'scenar_s'          => 124, # Scenar Silver, by Lapua, appears ballistically indistinguishable from Scenar  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '7n1'               => 125, # Very deep ogival shape and boat-tail, used in military 7.62x54R.  qv http://7.62x54r.net/MosinID/MosinAmmo007.htm  | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '7n6'               => 125, # Very deep ogival shape and boat-tail, used in military 5.45x39mm  qv http://7.62x54r.net/MosinID/MosinAmmo007.htm  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '7n6m'              => 125, # Synonym for 7N6  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'amax'              => 127, # A-Max, by Hornady  | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'boat_tail_og'      => 128, # Catch-all for many boat-tailed projectiles with long, pointed ogival nose shapes  | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'hollowpoint_ct'    => 131, # CT variation of hollowpoint "match" projectiles, by Nosler  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'bst'               => 136, # A type of flat-bottomed ogival, by Nosler  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'spire_point'       => 138, # A type of flat-bottomed ogival, by Speer  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'boat_tail_nosler'  => 138, # Nosler's line of boat-tails perform more poorly than others for some reason  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'boat_tail_ct'      => 139, # Nosler's CT variation of boat-tail  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'spitzer'           => 139, # Another flat-bottomed ogival, by Speer.  Good fit to many military bullets.  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'hollowpoint_match' => 140, # Catch-all for many hollowpoint "match" projectiles  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'accubond'          => 142, # An expansive line by Nosler offering controlled terminal expansion  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'interbond'         => 142, # A line of polymer-tipped bullets by Hornady optimized for terminal cohesion  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'vmax'              => 145, # A line of polymer-tipped bullets by Hornady optimized for terminal expansion / fragmentation  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'gold_match'        => 147, # A type of wadcutter, by Speer  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'grand_slam'        => 159, # Another wadcutter, by Speer, with less streamlined nose shape for higher overall mass  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'hollowpoint'       => 176, # Catch-all for many large-game hollowpoint projectiles  | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'default'           => 179, # Catch-all for unknown/unspecified shapes; derived via best-fit to ballistic table  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'fmj'               => 187, # Catch-all for military full metal jacket with boat-tail and short nose  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'mag_tip'           => 190, # Another wadcutter, by Speer  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'afss'              => 202,  | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'tsx_fb'            => 205,   | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'plinker'           => 205, # Typical of short, underweight, round-nosed, non-streamlined projectiles,  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'semispitzer'       => 224, # A foreshortened, flat-bottomed projectile, by Speer  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'round_nose'        => 228, # Catch-all for many flat-bottomed, hemispherical-nosed projectiles  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'varminter'         => 232, # Catch-all for many light hollowpoints with very large expanding cavities, for varminting  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'fmj_2'             => 268  # Woodleigh's FMJ projectiles, which are shape-optimized for travel in big game meat and bone, instead of air.  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This hash table is exported as %Physics::Ballistics::External::Bullet_Form_Factors_H,  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 so that users and modules may easily modify/add its content without resorting  | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 to editing sources.  | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our %Bullet_Form_Factors_H = (  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '7n14'              => 111, # Very, very deep ogival shape and boat-tail with tight tolerances, used in military 7.62x54R specifically for sniping.  | 
| 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '7n10'              => 118, # 7n6 with enhanced penetration and different weight distribution  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'scenar'            => 124, # Scenar, by Lapua  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'scenar_s'          => 124, # Scenar Silver, by Lapua, appears ballistically indistinguishable from Scenar  | 
| 
133
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '7n1'               => 125, # Russian boat-tail military bullet with very, very deep ogival shape  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '7n6'               => 125, # Russian boat-tail military bullet with very, very deep ogival shape  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     '7n6m'              => 125, # Synonym for 7N6  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'amax'              => 127, # A-Max, by Hornady  | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'boat_tail_og'      => 128, # Catch-all for many boat-tailed projectiles with long, pointed ogival nose shapes  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'hollowpoint_ct'    => 131, # CT variation of hollowpoint "match" projectiles, by Nosler  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'mk318'             => 133, # USMC 5.56x45mm Mk318 Mod 0 SOST open-tip/boattail 62gr half-lead/half-copper  | 
| 
140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'bst'               => 135, # A type of flat-bottomed ogival, by Nosler  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'btsp'              => 137, # Boat-tailed spire-point from Hornady  | 
| 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'spire_point'       => 138, # A type of flat-bottomed ogival, by Speer  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'boat_tail_nosler'  => 138, # Nosler's line of boat-tails perform more poorly than others for some reason  | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'boat_tail_ct'      => 139, # Nosler's CT variation of boat-tail  | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'spitzer'           => 139, # Another flat-bottomed ogival, by Speer  | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'hollowpoint_match' => 140, # Catch-all for many hollowpoint "match" projectiles  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'accubond'          => 142, # An expansive line by Nosler  | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'interbond'         => 142, # An expansive line by Hornady  | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'tts'               => 143, # Tipped Triple Shock, another line of all-copper bullets from Barnes  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'vmax'              => 145, # A line of polymer-tipped bullets by Hornady optimized for terminal expansion / fragmentation  | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'gold_match'        => 147, # A type of wadcutter, by Speer  | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'tsx'               => 151, # Another line of all-copper hunting bullets from Barnes  | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'partition'         => 152, # A crappy hunting bullet by Nosler  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'spbt'              => 152.5, # Soft-Point Boat-Tail  | 
| 
155
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'grand_slam'        => 159, # Another wadcutter, by Speer  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'barnes_xxx'        => 161, # Flat-bottomed all-copper hunting round, by Barnes  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'hollowpoint'       => 176, # Catch-all for many large-game hollowpoint projectiles  | 
| 
158
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'sp'                => 177, # Catch-all for many softpoint hunting projectiles without sharp points  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'default'           => 179, # Catch-all for unknown/unspecified shapes; derived via best-fit to ballistic table  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'fmj'               => 187, # Catch-all for military full metal jacket with boat-tail and short nose  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'mag_tip'           => 190, # Another wadcutter, by Speer  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'afss'              => 202,  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'tsx_fb'            => 205,   | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'plinker'           => 205, # Typical of short, underweight, round-nosed, non-streamlined projectiles,  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'rws_ks'            => 210,  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'semispitzer'       => 224, # A foreshortened, flat-bottomed projectile, by Speer  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'round_nose'        => 228, # Catch-all for many flat-bottomed, hemispherical-nosed projectiles  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'varminter'         => 232, # Catch-all for many light hollowpoints with very large expanding cavities, for varminting  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'fmj_2'             => 268, # Woodleigh's FMJ projectiles, which are shape-optimized for travel in big game meat and bone, instead of air.  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'flat_nose'         => 299  # Flat-nosed bullets for tubular magazines  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # TODO: Contact Geoffrey Kolbe (Inventor at Border Barrels Limited) and ask for permission to publish his splendid implementations:  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #    * Bullet drag calculator - http://www.border-barrels.com/cgi-bin/drag_working.cgi  | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #    * Barrel weight calculator - http://www.border-barrels.com/cgi-bin/swamped_barrel_weight.cgi  | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # His drag calculator appears far superior to my own ebc function.  | 
| 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub ebc { # estimate ballistic coefficient (G1) from mass, diameter, and shape or form factor  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Form factor is based on shape (nose, tail, distance between them), and has inverse impact on BC (higher form factor == lower BC).  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Form factor is subject to some modification:  | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #    * adjusted for diameter (normalizing on .308 inch diameters)  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #    * adjusted upward at very small L/D (very short shapes)  | 
| 
184
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
1
  
 | 
1701
 | 
     my ($mass_gr, $diam_in, $shape, $ff) = @_;  | 
| 
185
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     die("bc, form-factor, very-small-factor, shape = ebc(mass_gr, diam_in[, shape[, form-factor]])") unless (defined($diam_in));  | 
| 
186
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     my $vsf = 1; # "very small" factor -- a penalty incurred when length/diameter is too small.  | 
| 
187
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     $shape = "default" unless (defined($shape));  | 
| 
188
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     if (!defined($ff)) {  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Form factors of various commercial shapes.  Higher ff implies more drag.  | 
| 
190
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         my $vsthreshold = 4480; # determined empirically, looking at 45gr 0.224" spitzer, which looks to be just beyond the threshold, and 40gr 0.224" spire_point, which is significantly beyond it.  | 
| 
191
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
         my $LD  = $mass_gr / $diam_in**3;  | 
| 
192
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
         $vsf = ($vsthreshold / $LD) if ($LD < $vsthreshold);  | 
| 
193
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
         my $ff_base = undef;  | 
| 
194
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
15
 | 
         if (defined($Physics::Ballistics::External::Bullet_Form_Factors_H{$shape})) {  | 
| 
195
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
               $ff_base = $Physics::Ballistics::External::Bullet_Form_Factors_H{$shape};  | 
| 
196
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
197
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
               $ff_base = $Physics::Ballistics::External::Bullet_Form_Factors_H{'default'};  | 
| 
198
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
               $ff_base = 179 unless (defined($ff_base));  | 
| 
199
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
               print STDERR "ebc: warning: unknown shape '$shape' and no form factor explicitly provided; assuming default (ff=$ff_base)\n";  | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
201
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
         my $diameter_factor = ($diam_in / .308)**0.541;  | 
| 
202
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
         $ff = $vsf * $ff_base * $diameter_factor;  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # END of if !$ff  | 
| 
204
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     my $bc = ($mass_gr**1.25 / (10*$diam_in)**2) / $ff;  | 
| 
205
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
     return {bc => $bc, ff => $ff, vsf => $vsf, shape => $shape};  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
207
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
208
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ############## BEGIN port of GNU-Ballistics gebc-1.07 lib/ballistics/ballistics.cpp  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # TODO: Incorporate wobble estimation function (used by improved penetration estimator).  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # TODO: Port bugfixes and enhancements to Inline::C.  The pure-perl performance is horrible.  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $GRAVITY        = -32.194;  | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $BCOMP_MAXRANGE =    2000;  | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Specialty angular conversion functions, straightforward PP port of GNU-Ballistics gebc-1.07 lib/ballistics/ballistics.cpp  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub DegtoMOA {  | 
| 
218
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($deg) = @_;  | 
| 
219
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $deg*60;  | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub DegtoRad {  | 
| 
222
 | 
33
 | 
 
 | 
 
 | 
  
33
  
 | 
  
0
  
 | 
120
 | 
     my ($deg) = @_;  | 
| 
223
 | 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
235
 | 
     return $deg*pi/180;  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub MOAtoDeg {  | 
| 
226
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($moa) = @_;  | 
| 
227
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $moa/60;  | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub MOAtoRad {   | 
| 
230
 | 
30
 | 
 
 | 
 
 | 
  
30
  
 | 
  
0
  
 | 
102
 | 
     my ($moa) = @_;  | 
| 
231
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
178
 | 
     return $moa/60*pi/180;  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub RadtoDeg {   | 
| 
234
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
2
 | 
     my ($rad) = @_;  | 
| 
235
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     return $rad*180/pi;  | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub RadtoMOA {  | 
| 
238
 | 
601
 | 
 
 | 
 
 | 
  
601
  
 | 
  
0
  
 | 
4262
 | 
     my ($rad) = @_;  | 
| 
239
 | 
601
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1397
 | 
     return $rad*60*180/pi;  | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Functions for correcting for atmosphere, straightforward PP port of GNU-Ballistics gebc-1.07 lib/ballistics/ballistics.cpp  | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub calcFR {  | 
| 
245
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($Temperature, $Pressure, $RelativeHumidity) = @_;  | 
| 
246
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $VPw = (4e-6) * $Temperature**3 - 0.0004 * $Temperature**2 + 0.0234 * $Temperature - 0.2517;  | 
| 
247
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $FRH = 0.995 * $Pressure / ($Pressure - 0.3783 * $RelativeHumidity * $VPw);  | 
| 
248
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $FRH;  | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub calcFP {  | 
| 
252
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($Pressure) = @_;  | 
| 
253
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $Pstd = 29.53; # inches-hg  | 
| 
254
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $FP = ($Pressure - $Pstd) / $Pstd;  | 
| 
255
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $FP;  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub calcFT {  | 
| 
259
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($Temperature, $Altitude) = @_;  | 
| 
260
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $Tstd = -0.0036 * $Altitude + 59;  | 
| 
261
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $FT = ($Temperature - $Tstd) / (459.6 + $Tstd);  | 
| 
262
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $FT;  | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub calcFA {  | 
| 
266
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($Altitude) = @_;  | 
| 
267
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $fa = (-4e-15) * $Altitude**3 + (4e-10) * $Altitude**2 - (3e-5) * $Altitude + 1;  | 
| 
268
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return 1/$fa;  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub AtmCorrect {  | 
| 
272
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($DragCoefficient, $Altitude, $Barometer, $Temperature, $RelativeHumidity) = @_;  | 
| 
273
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $FA = calcFA($Altitude);  | 
| 
274
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $FT = calcFT($Temperature, $Altitude);  | 
| 
275
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $FR = calcFR($Temperature, $Barometer, $RelativeHumidity);  | 
| 
276
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $FP = calcFP($Barometer);  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Calculate the atmospheric correction factor  | 
| 
279
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $CD = $FA * (1 + $FT - $FP) * $FR;  | 
| 
280
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $DragCoefficient * $CD;  | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Function for correcting for ballistic drag, straightforward PP port of GNU-Ballistics gebc-1.07 lib/ballistics/ballistics.cpp  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub velocity_loss {  | 
| 
285
 | 
24717
 | 
 
 | 
 
 | 
  
24717
  
 | 
  
0
  
 | 
47572
 | 
     my ($DragFunction, $DragCoefficient, $Velocity) = @_;  | 
| 
286
 | 
24717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36108
 | 
     my $vp  = $Velocity;       | 
| 
287
 | 
24717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33708
 | 
     my $val = -1;  | 
| 
288
 | 
24717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31942
 | 
     my $A   = -1;  | 
| 
289
 | 
24717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32891
 | 
     my $M   = -1;  | 
| 
290
 | 
24717
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
45543
 | 
     if ($DragFunction eq 'G1') {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
291
 | 
24717
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
118115
 | 
         if    ($vp > 4230) { $A = 1.477404177730177e-04; $M = 1.9565; }  | 
| 
 
 | 
  
0
  
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
292
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 3680) { $A = 1.920339268755614e-04; $M = 1.925 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
293
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 3450) { $A = 2.894751026819746e-04; $M = 1.875 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
294
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 3295) { $A = 4.349905111115636e-04; $M = 1.825 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
295
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 3130) { $A = 6.520421871892662e-04; $M = 1.775 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
296
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 2960) { $A = 9.748073694078696e-04; $M = 1.725 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
297
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 2830) { $A = 1.453721560187286e-03; $M = 1.675 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
298
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 2680) { $A = 2.162887202930376e-03; $M = 1.625 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
299
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 2460) { $A = 3.209559783129881e-03; $M = 1.575 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
300
 | 
6704
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10115
 | 
         elsif ($vp > 2225) { $A = 3.904368218691249e-03; $M = 1.55  ; }  | 
| 
 
 | 
6704
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9715
 | 
    | 
| 
301
 | 
8358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11924
 | 
         elsif ($vp > 2015) { $A = 3.222942271262336e-03; $M = 1.575 ; }  | 
| 
 
 | 
8358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11547
 | 
    | 
| 
302
 | 
5040
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7707
 | 
         elsif ($vp > 1890) { $A = 2.203329542297809e-03; $M = 1.625 ; }  | 
| 
 
 | 
5040
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6131
 | 
    | 
| 
303
 | 
3289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4805
 | 
         elsif ($vp > 1810) { $A = 1.511001028891904e-03; $M = 1.675 ; }  | 
| 
 
 | 
3289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4597
 | 
    | 
| 
304
 | 
1326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1914
 | 
         elsif ($vp > 1730) { $A = 8.609957592468259e-04; $M = 1.75  ; }  | 
| 
 
 | 
1326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1869
 | 
    | 
| 
305
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1595) { $A = 4.086146797305117e-04; $M = 1.85  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
306
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1520) { $A = 1.954473210037398e-04; $M = 1.95  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
307
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1420) { $A = 5.431896266462351e-05; $M = 2.125 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
308
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1360) { $A = 8.847742581674416e-06; $M = 2.375 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
309
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1315) { $A = 1.456922328720298e-06; $M = 2.625 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
310
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1280) { $A = 2.419485191895565e-07; $M = 2.875 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
311
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1220) { $A = 1.657956321067612e-08; $M = 3.25  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
312
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1185) { $A = 4.745469537157371e-10; $M = 3.75  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
313
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1150) { $A = 1.379746590025088e-11; $M = 4.25  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
314
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1100) { $A = 4.070157961147882e-13; $M = 4.75  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
315
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1060) { $A = 2.938236954847331e-14; $M = 5.125 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
316
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1025) { $A = 1.228597370774746e-14; $M = 5.25  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
317
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  980) { $A = 2.916938264100495e-14; $M = 5.125 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
318
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  945) { $A = 3.855099424807451e-13; $M = 4.75  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
319
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  905) { $A = 1.185097045689854e-11; $M = 4.25  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
320
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  860) { $A = 3.566129470974951e-10; $M = 3.75  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
321
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  810) { $A = 1.045513263966272e-08; $M = 3.25  ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
322
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  780) { $A = 1.291159200846216e-07; $M = 2.875 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
323
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  750) { $A = 6.824429329105383e-07; $M = 2.625 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
324
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  700) { $A = 3.569169672385163e-06; $M = 2.375 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
325
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  640) { $A = 1.839015095899579e-05; $M = 2.125 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
326
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  600) { $A = 5.71117468873424e-05 ; $M = 1.950 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
327
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  550) { $A = 9.226557091973427e-05; $M = 1.875 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
328
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  250) { $A = 9.337991957131389e-05; $M = 1.875 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
329
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  100) { $A = 7.225247327590413e-05; $M = 1.925 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
330
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >   65) { $A = 5.792684957074546e-05; $M = 1.975 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
331
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >    0) { $A = 5.206214107320588e-05; $M = 2.000 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     elsif ($DragFunction eq 'G2') {  | 
| 
335
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         if    ($vp > 1674 ) { $A = .0079470052136733   ;  $M = 1.36999902851493; }  | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
336
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1172 ) { $A = 1.00419763721974e-03;  $M = 1.65392237010294; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
337
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1060 ) { $A = 7.15571228255369e-23;  $M = 7.91913562392361; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
338
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  949 ) { $A = 1.39589807205091e-10;  $M = 3.81439537623717; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
339
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  670 ) { $A = 2.34364342818625e-04;  $M = 1.71869536324748; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
340
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  335 ) { $A = 1.77962438921838e-04;  $M = 1.76877550388679; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
341
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >    0 ) { $A = 5.18033561289704e-05;  $M = 1.98160270524632; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     elsif ($DragFunction eq 'G5') {  | 
| 
345
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         if    ($vp > 1730 ){ $A = 7.24854775171929e-03; $M = 1.41538574492812; }  | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
346
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1228 ){ $A = 3.50563361516117e-05; $M = 2.13077307854948; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
347
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1116 ){ $A = 1.84029481181151e-13; $M = 4.81927320350395; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
348
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1004 ){ $A = 1.34713064017409e-22; $M = 7.8100555281422 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
349
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  837 ){ $A = 1.03965974081168e-07; $M = 2.84204791809926; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
350
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  335 ){ $A = 1.09301593869823e-04; $M = 1.81096361579504; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
351
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >    0 ){ $A = 3.51963178524273e-05; $M = 2.00477856801111; }    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
354
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     elsif ($DragFunction eq 'G6') {  | 
| 
355
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         if    ($vp > 3236 ) { $A = 0.0455384883480781   ; $M = 1.15997674041274; }  | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
356
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 2065 ) { $A = 7.167261849653769e-02; $M = 1.10704436538885; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
357
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1311 ) { $A = 1.66676386084348e-03 ; $M = 1.60085100195952; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
358
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1144 ) { $A = 1.01482730119215e-07 ; $M = 2.9569674731838 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
359
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1004 ) { $A = 4.31542773103552e-18 ; $M = 6.34106317069757; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
360
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  670 ) { $A = 2.04835650496866e-05 ; $M = 2.11688446325998; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
361
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >    0 ) { $A = 7.50912466084823e-05 ; $M = 1.92031057847052; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     elsif ($DragFunction eq 'G7') {  | 
| 
365
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         if    ($vp > 4200 ) { $A = 1.29081656775919e-09; $M = 3.24121295355962; }  | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
366
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 3000 ) { $A = 0.0171422231434847  ; $M = 1.27907168025204; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
367
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1470 ) { $A = 2.33355948302505e-03; $M = 1.52693913274526; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
368
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1260 ) { $A = 7.97592111627665e-04; $M = 1.67688974440324; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
369
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1110 ) { $A = 5.71086414289273e-12; $M = 4.3212826264889 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
370
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  960 ) { $A = 3.02865108244904e-17; $M = 5.99074203776707; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
371
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  670 ) { $A = 7.52285155782535e-06; $M = 2.1738019851075 ; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
372
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  540 ) { $A = 1.31766281225189e-05; $M = 2.08774690257991; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
373
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >    0 ) { $A = 1.34504843776525e-05; $M = 2.08702306738884; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
374
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     elsif ($DragFunction eq 'G8') {  | 
| 
377
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         if    ($vp > 3571 ) { $A = .0112263766252305   ; $M = 1.33207346655961; }  | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
378
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1841 ) { $A = .0167252613732636   ; $M = 1.28662041261785; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
379
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1120 ) { $A = 2.20172456619625e-03; $M = 1.55636358091189; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
380
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp > 1088 ) { $A = 2.0538037167098e-16 ; $M = 5.80410776994789; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
381
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >  976 ) { $A = 5.92182174254121e-12; $M = 4.29275576134191; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
382
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         elsif ($vp >    0 ) { $A = 4.3917343795117e-05 ; $M = 1.99978116283334; }  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
383
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
384
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
385
 | 
24717
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
138524
 | 
     if ($A != -1 && $M != -1 && $vp > 0 && $vp < 10000 ) {  | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
386
 | 
24717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
51395
 | 
         $val = $A * $vp**$M / $DragCoefficient;  | 
| 
387
 | 
24717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59950
 | 
         return $val;  | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
389
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return -1;  | 
| 
390
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
392
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub Windage {  | 
| 
393
 | 
300
 | 
 
 | 
 
 | 
  
300
  
 | 
  
0
  
 | 
573
 | 
     my ($WindSpeed, $Vi, $xx, $t) = @_;  | 
| 
394
 | 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
448
 | 
     my $Vw = $WindSpeed * 17.60; # Convert to inches per second.  | 
| 
395
 | 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
723
 | 
     return $Vw * ($t - $xx / $Vi);  | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
397
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Headwind is positive at WindAngle=0  | 
| 
399
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub HeadWind {  | 
| 
400
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($WindSpeed, $WindAngle) = @_;  | 
| 
401
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $Wangle = DegtoRad($WindAngle);  | 
| 
402
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return cos($Wangle) * $WindSpeed;  | 
| 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
405
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Positive is from Shooter's Right to Left (Wind from 90 degree)  | 
| 
406
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub CrossWind {  | 
| 
407
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
  
0
  
 | 
0
 | 
     my ($WindSpeed, $WindAngle) = @_;  | 
| 
408
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     my $Wangle = DegtoRad($WindAngle);  | 
| 
409
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return sin($Wangle) * $WindSpeed;  | 
| 
410
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Equivalent to, but slightly faster than, calling HeadWind and CrossWind separately.  | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Perl suffers from a couple thousand clock cycles of overhead per function call (about  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # 1 microsecond of wallclock time on typical 2010's hardware), so consolidating similar  | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # functions is a performance win.  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub HeadAndCrossWind {  | 
| 
417
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
3
 | 
     my ($WindSpeed, $WindAngle) = @_;  | 
| 
418
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $Wangle = DegtoRad($WindAngle);  | 
| 
419
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     return (cos($Wangle) * $WindSpeed, sin($Wangle) * $WindSpeed);  | 
| 
420
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
422
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Straightforward PP port from GNU-Ballistics gebc-1.07 lib/ballistics/ballistics.cpp  | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub ZeroAngle {  | 
| 
424
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
4
 | 
     my ($DragFunction, $DragCoefficient, $Vi, $SightHeight, $ZeroRange, $yIntercept) = @_;  | 
| 
425
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Numerical Integration variables  | 
| 
427
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $t  = 0;  | 
| 
428
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $dt = 1/$Vi; # The solution accuracy generally doesn't suffer if its within a foot for each second of time.  | 
| 
429
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $y  = -1 * $SightHeight / 12;  | 
| 
430
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $x  = 0;  | 
| 
431
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $da; # The change in the bore angle used to iterate in on the correct zero angle.  | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
433
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # State variables for each integration loop.  | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # velocity:  | 
| 
435
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $v  = 0;  | 
| 
436
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $vx = 0;  | 
| 
437
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $vy = 0;  | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Last frame's velocity, used for computing average velocity:  | 
| 
439
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $vx1 = 0;  | 
| 
440
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $vy1 = 0;  | 
| 
441
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # acceleration:  | 
| 
442
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $dv  = 0;  | 
| 
443
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $dvx = 0;  | 
| 
444
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $dvy = 0;  | 
| 
445
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Gravitational acceleration:  | 
| 
446
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $Gx = 0;  | 
| 
447
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $Gy = 0;  | 
| 
448
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
449
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $angle = 0; # The actual angle of the bore.  | 
| 
450
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
451
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $quit = 0; # We know it's time to quit our successive approximation loop when this is 1.  | 
| 
452
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
453
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Start with a very coarse angular change, to quickly solve even large launch angle problems.  | 
| 
454
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     $da = DegtoRad(14);  | 
| 
455
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
456
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # The general idea here is to start at 0 degrees elevation, and increase the elevation by 14 degrees  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # until we are above the correct elevation.  Then reduce the angular change by half, and begin reducing  | 
| 
458
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # the angle.  Once we are again below the correct angle, reduce the angular change by half again, and go  | 
| 
459
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # back up.  This allows for a fast successive approximation of the correct elevation, usually within less  | 
| 
460
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # than 20 iterations.  | 
| 
461
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     for ($angle = 0; $quit == 0; $angle = $angle + $da) {  | 
| 
462
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
126
 | 
         $vy = $Vi * sin($angle);  | 
| 
463
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
117
 | 
         $vx = $Vi * cos($angle);  | 
| 
464
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68
 | 
         $Gx = $GRAVITY * sin($angle);  | 
| 
465
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
76
 | 
         $Gy = $GRAVITY * cos($angle);  | 
| 
466
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
467
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
121
 | 
         for (($t, $x, $y) = (0, 0, -1 * $SightHeight/12); $x <= $ZeroRange*3; $t += $dt) {  | 
| 
468
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32880
 | 
             $vy1 = $vy;  | 
| 
469
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29503
 | 
             $vx1 = $vx;  | 
| 
470
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
51556
 | 
             $v   = ($vx**2 + $vy**2)**0.5;  | 
| 
471
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33397
 | 
             $dt  = 1/$v;  | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               | 
| 
473
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42813
 | 
             $dv = velocity_loss ($DragFunction, $DragCoefficient, $v);  | 
| 
474
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42487
 | 
             $dvy = -1 * $dv * $vy / $v * $dt;  | 
| 
475
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33448
 | 
             $dvx = -1 * $dv * $vx / $v * $dt;  | 
| 
476
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
477
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30570
 | 
             $vx = $vx + $dvx;  | 
| 
478
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29121
 | 
             $vy = $vy + $dvy;  | 
| 
479
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31800
 | 
             $vy = $vy + $dt * $Gy;  | 
| 
480
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36838
 | 
             $vx = $vx + $dt * $Gx;  | 
| 
481
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               | 
| 
482
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35708
 | 
             $x += $dt * ($vx + $vx1) / 2;  | 
| 
483
 | 
22912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33201
 | 
             $y += $dt * ($vy + $vy1) / 2;  | 
| 
484
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Break early to save CPU time if we won't find a solution.  | 
| 
485
 | 
22912
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
58162
 | 
             last if ($vy < 0 && $y < $yIntercept);  | 
| 
486
 | 
22898
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
65681
 | 
             last if ($vy>3 * $vx);  | 
| 
487
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
488
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
489
 | 
30
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
155
 | 
         $da = -1 * $da / 2 if ($y > $yIntercept && $da > 0);  | 
| 
490
 | 
30
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
159
 | 
         $da = -1 * $da / 2 if ($y < $yIntercept && $da < 0);  | 
| 
491
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
492
 | 
30
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
200
 | 
         $quit = 1 if (abs($da) < MOAtoRad(0.01)); # If our accuracy is sufficient, we can stop approximating.  | 
| 
493
 | 
30
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
132
 | 
         $quit = 1 if ($angle   > DegtoRad(45));   # If we exceed the 45 degree launch $angle, then the projectile just won't get there, so we stop trying.  | 
| 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
495
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     return RadtoDeg($angle); # Convert to degrees for return value.  | 
| 
496
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
497
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
498
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 flight_simulator (drag_function, ballistic_coefficient, muzzle_velocity_fps, sight_height_inches, shot_angle_deg, [bore_to_sight_angle_deg,] zero_range_yards, wind_speed_fps, wind_angle_deg, [max_range_yards])  | 
| 
499
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
500
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Attempts to predict the flight characteristics of a projectile in flight, providing a data point for every yard of progress it makes downrange.  | 
| 
501
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This is a pure-perl port of the "SolveAll" function from GNU-Ballistics gebc-1.07 lib/ballistics/ballistics.cpp, and as slow as one might expect from a pure-perl port of an arithmetic-intensive algorithm.  | 
| 
503
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
504
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 On my system it takes about an eighth of a second to simulate a 1200-yard flight.  This may be supplemented at some point with an Inline::C equivalent.  | 
| 
505
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
506
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Note that most manufacturers report G1 ballistic coefficients.  Using the wrong drag function for a given ballistic coefficient will produce ludicrously incorrect results.  | 
| 
507
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
508
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 To ascertain the correct bore elevation to hit a target at a specific distance, change the shot_angle_deg parameter on successive calls to flight_simulator(), and converge on drop_inches == 0.0 at the given range via binary search.  I should get around to providing a function for that at some point (GNU-Ballistics has such a function, I just didn't port it).  | 
| 
509
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
510
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4  | 
| 
511
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
512
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (str) drag_function is exactly one of: 'G1', 'G2', 'G5', 'G6', 'G7', 'G8'.  | 
| 
513
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
514
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) ballistic_coefficient, qv: http://en.wikipedia.org/wiki/Ballistic_coefficient  | 
| 
515
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
516
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) muzzle_velocity_fps is the velocity of the projectile at time=0 (feet per second)  | 
| 
517
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
518
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) sight_height_inches is the distance from the center of the sight to the center of the bore (inches)  | 
| 
519
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
520
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) shot_angle_deg is the bore elevation (degrees, 0 = horizontal, 90 = vertical)  | 
| 
521
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
522
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) OPTIONAL: bore_to_sight_angle_deg is the difference in angle between the bore elevation and the sight elevation.  Set to undef or -1 to have flight_simulator() calculate it for you from the zero_range_yards parameter (degrees)  | 
| 
523
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
524
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) wind_speed_fps is the velocity of the wind (feet per second)  | 
| 
525
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
526
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) wind_angle_deg is the direction the wind is blowing (degrees, 0 = shooting directly into wind, 90 = wind is blowing from the right, perpendicular to flight path, -90 = wind is blowing from the left, perpendicular to flight path)  | 
| 
527
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
528
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) OPTIONAL: max_range_yards is the maximum range to which the flight will be simulated (yards, default is 2000)  | 
| 
529
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
530
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 returns: a reference to an array of hash references, one per yard, denoting the projectile's disposition when it reaches that range.  All data fields are floating-point numbers:  | 
| 
531
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
532
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     range_yards     How far downrange the projectile has travelled, in yards.  | 
| 
533
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     drop_inches     How far below the horizontal plane intersecting the muzzle the projectile has travelled, in inches.  | 
| 
534
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     correction_moa  The angle from the muzzle to the projectile in the vertical plane, relative to the path from the muzzle to the target, in minutes.  | 
| 
535
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     time_seconds    How much time has elapsed since leaving the muzzle, in seconds.  | 
| 
536
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     windage_inches  How far in the horizontal plane the projectile has moved due to wind, in inches.  | 
| 
537
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     windage_moa     The angle from the muzzle to the projectile in the horzontal plane, relative to the path from the muzzle to the target, in minutes.  | 
| 
538
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     vel_fps         The velocity of the projectile, in feet per second.  | 
| 
539
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     vel_horiz_fps   The horizontal component of the velocity of the projectile, in feet per second.  | 
| 
540
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     vel_vert_fps    The vertical component of the velocity of the projectile, in feet per second.  | 
| 
541
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
542
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back  | 
| 
543
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
544
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
545
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
546
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # The solve-all solution.  | 
| 
547
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # PP port of "SolveAll" from GNU-Ballistics gebc-1.07 lib/ballistics/ballistics.cpp  | 
| 
548
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $DragFunction is one of 'G1', 'G2', 'G5', 'G6', 'G7', 'G8'  | 
| 
549
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $DragCoefficient is the ballistic coefficient  | 
| 
550
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $Vi is the muzzle velocity of the projectile, feet per second  | 
| 
551
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $SightHeight is the height of the scope in inches  | 
| 
552
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $ShootingAngle is the bore elevation (angle)  | 
| 
553
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $ZAngle is the bore-to-sight angle, or -1 to calculate from $ZRange  | 
| 
554
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $ZRange is the range, in yards, to which the rifle is sighted-in.  | 
| 
555
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $WindSpeed is the speed of the wind, in feet per second  | 
| 
556
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $WindAngle is the angle of the wind relative to the shooter -- coming from the right is positive, coming from the left is negative.  | 
| 
557
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # $MaxRange is the maximum range, in yards, to simulate (defaults to $BCOMP_MAXRANGE if -1 or undef)  | 
| 
558
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub flight_simulator {  | 
| 
559
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
1
  
 | 
518
 | 
     my ($DragFunction, $DragCoefficient, $Vi, $SightHeight, $ShootingAngle, $ZAngle, $ZRange, $WindSpeed, $WindAngle, $MaxRange) = @_;  | 
| 
560
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $ptr = {};  | 
| 
561
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
562
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     die("usage: ar = flight_simulator(DragFunction, DragCoefficient, Vel_fps, SightHeight_inches, ShootingAngle_deg, ZAngle_deg, ZRange_yards, WindSpeed_fps, WindAngle_deg, MaxRange_yards)\n") unless(defined($DragCoefficient));  | 
| 
563
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
564
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $t   = 0;  | 
| 
565
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $dt  = 0.5 / $Vi;  | 
| 
566
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $v   = 0;  | 
| 
567
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $vx  = 0;  # horizontal velocity, feet per second, at beginning of quantum  | 
| 
568
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $vx1 = 0;  # horizontal velocity, feet per second, at end of quantum  | 
| 
569
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $vy  = 0;  | 
| 
570
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $vy1 = 0;  | 
| 
571
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $dv  = 0;  | 
| 
572
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my $dvx = 0;  | 
| 
573
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $dvy = 0;  | 
| 
574
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
     my $x   = 0;  | 
| 
575
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $y   = 0;  | 
| 
576
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
577
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # print ("fs: 0010 ShootingAngle=$ShootingAngle  ZAngle=$ZAngle\n");  | 
| 
578
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
579
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
9
 | 
     $ZAngle = ZeroAngle($DragFunction, $DragCoefficient, $Vi, $SightHeight, $ZRange, 0) if ($ZAngle == -1 || !defined($ZAngle));  | 
| 
580
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
10
 | 
     $MaxRange = $BCOMP_MAXRANGE unless (defined($MaxRange) && $MaxRange >= 0);  | 
| 
581
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     $MaxRange *= 3; # Convert yards to feet.  | 
| 
582
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
583
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # print ("fs: 0020 ShootingAngle=$ShootingAngle  ZAngle=$ZAngle  MaxRange=$MaxRange\n");  | 
| 
584
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
585
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     my ($headwind, $crosswind) = HeadAndCrossWind($WindSpeed, $WindAngle);  | 
| 
586
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     my $Radians = DegtoRad($ShootingAngle + $ZAngle);  | 
| 
587
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $CosRadians = cos($Radians);  | 
| 
588
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $SinRadians = sin($Radians);  | 
| 
589
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $Gy = $GRAVITY * $CosRadians;  | 
| 
590
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $Gx = $GRAVITY * $SinRadians;  | 
| 
591
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
592
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # $vx = $Vi * cos(DegtoRad($ZAngle));  | 
| 
593
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # $vy = $Vi * sin(DegtoRad($ZAngle));  | 
| 
594
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     $vx   = $Vi * $CosRadians;  | 
| 
595
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     $vy   = $Vi * $SinRadians;  | 
| 
596
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
597
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # print ("fs: 0030 vx=$vx vy=$vy\n");  | 
| 
598
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
599
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     $y = -1 * $SightHeight / 12;  | 
| 
600
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
601
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $yards_downrange = 0;  | 
| 
602
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     my $rv = [];  | 
| 
603
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     for ($t = 0; 1; $t += $dt) {  | 
| 
604
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2542
 | 
         $vx1 = $vx;  | 
| 
605
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2376
 | 
         $vy1 = $vy;  | 
| 
606
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3877
 | 
         $v  = ($vx**2 + $vy**2)**0.5;  | 
| 
607
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2700
 | 
         $dt = 0.5 / $v;  | 
| 
608
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
609
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # print ("fs: 0040 vx=$vx vy=$vy\n");  | 
| 
610
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
611
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Compute acceleration using the drag function retardation       | 
| 
612
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3742
 | 
         $dv = velocity_loss($DragFunction, $DragCoefficient, $v + $headwind);  | 
| 
613
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3238
 | 
         $dvx = -1 * ($vx / $v) * $dv;  | 
| 
614
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3031
 | 
         $dvy = -1 * ($vy / $v) * $dv;  | 
| 
615
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
616
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Compute velocity, including the resolved gravity vectors.      | 
| 
617
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2856
 | 
         $vx = $vx + $dt * $dvx + $dt * $Gx;  | 
| 
618
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2592
 | 
         $vy = $vy + $dt * $dvy + $dt * $Gy;  | 
| 
619
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
620
 | 
1805
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
3840
 | 
         if ($x/3 >= $yards_downrange) {  | 
| 
621
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
525
 | 
             my $hr = {};  | 
| 
622
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
761
 | 
             $hr->{range_yards}    = $x / 3;  | 
| 
623
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
567
 | 
             $hr->{drop_inches}    = $y * -12;  | 
| 
624
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
601
 | 
             $hr->{correction_moa} = 0;  | 
| 
625
 | 
301
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1195
 | 
             $hr->{correction_moa} = -1 * RadtoMOA(atan($y / $x)) if ($x > 0);  | 
| 
626
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
656
 | 
             $hr->{time_seconds}   = $t + $dt;  | 
| 
627
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
485
 | 
             $hr->{windage_inches} = 0;  | 
| 
628
 | 
301
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
840
 | 
             $hr->{windage_inches} = Windage($crosswind, $Vi, $x, $t + $dt) if ($x > 0);  | 
| 
629
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
580
 | 
             $hr->{windage_moa}    = 0;  | 
| 
630
 | 
301
 | 
  
 50
  
 | 
  
100
  
 | 
 
 | 
 
 | 
1241
 | 
             $hr->{windage_moa}    = RadtoMOA(atan(($hr->{windage_inches} / 12) / (($hr->{range_yards} * 3) || 0.1))) if ($crosswind > 0);  | 
| 
631
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
646
 | 
             $hr->{vel_fps}        = $v;  | 
| 
632
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
983
 | 
             $hr->{vel_horiz_fps}  = $vx;  | 
| 
633
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
898
 | 
             $hr->{vel_vert_fps}   = $vy;  | 
| 
634
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
430
 | 
             push (@{$rv}, $hr);  | 
| 
 
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
625
 | 
    | 
| 
635
 | 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
585
 | 
             $yards_downrange++;  | 
| 
636
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }         | 
| 
637
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
638
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Compute position based on average velocity.  | 
| 
639
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3242
 | 
         $x += $dt * ($vx + $vx1) / 2;  | 
| 
640
 | 
1805
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2925
 | 
         $y += $dt * ($vy + $vy1) / 2;  | 
| 
641
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
642
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # last if (abs($vy) > abs(3 * $vx));  | 
| 
643
 | 
1805
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3518
 | 
         last if ($t > 3600);  | 
| 
644
 | 
1805
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
4068
 | 
         last if ($x >= $MaxRange+1.0);  | 
| 
645
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
646
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     return $rv;  | 
| 
647
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
648
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
649
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ################# no functions ported from GNU-Ballistics gebc-1.07 lib/ballistics/ballistics.cpp after this line ##################  | 
| 
650
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
651
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 g1_drag (velocity_fps)  | 
| 
652
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
653
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The canonical function for computing instantaneous velocity drop at a given velocity, per the G1 drag model.  | 
| 
654
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
655
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4  | 
| 
656
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
657
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) velocity_fps is the velocity of the projectile (in feet per second)  | 
| 
658
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
659
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 returns: (float) the deceleration of the projectile from drag (in feet per second per second)  | 
| 
660
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
661
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back  | 
| 
662
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
663
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
664
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
665
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # PP implementation of G1 drag model.  | 
| 
666
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Multiply by G1 ballistic coefficient to get instantaneous velocity drop.  | 
| 
667
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub g1_drag {  | 
| 
668
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
1
  
 | 
3788
 | 
     my ($fps) = @_;  | 
| 
669
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
140
 | 
     if    ($fps > 4230) { return (1.477404177730177E-04) * ($fps**1.9565); }  | 
| 
 
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
35
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
670
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 3680) { return (1.920339268755614E-04) * ($fps**1.925); }  | 
| 
671
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     elsif ($fps > 3450) { return (2.894751026819746E-04) * ($fps**1.875); }  | 
| 
672
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 3295) { return (4.349905111115636E-04) * ($fps**1.825); }  | 
| 
673
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 3130) { return (6.520421871892662E-04) * ($fps**1.775); }  | 
| 
674
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 2960) { return (9.748073694078696E-04) * ($fps**1.725); }  | 
| 
675
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 2830) { return (1.453721560187286E-03) * ($fps**1.675); }  | 
| 
676
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 2680) { return (2.162887202930376E-03) * ($fps**1.625); }  | 
| 
677
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     elsif ($fps > 2460) { return (3.209559783129881E-03) * ($fps**1.575); }  | 
| 
678
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 2225) { return (3.904368218691249E-03) * ($fps**1.550); }  | 
| 
679
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 2015) { return (3.222942271262336E-03) * ($fps**1.575); }  | 
| 
680
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1890) { return (2.203329542297809E-03) * ($fps**1.625); }  | 
| 
681
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1810) { return (1.511001028891904E-03) * ($fps**1.675); }  | 
| 
682
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1730) { return (8.609957592468259E-04) * ($fps**1.750); }  | 
| 
683
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1595) { return (4.086146797305117E-04) * ($fps**1.850); }  | 
| 
684
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1520) { return (1.954473210037398E-04) * ($fps**1.950); }  | 
| 
685
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     elsif ($fps > 1420) { return (5.431896266462351E-05) * ($fps**2.125); }  | 
| 
686
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1360) { return (8.847742581674416E-06) * ($fps**2.375); }  | 
| 
687
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1315) { return (1.456922328720298E-06) * ($fps**2.625); }  | 
| 
688
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1280) { return (2.419485191895565E-07) * ($fps**2.875); }  | 
| 
689
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1220) { return (1.657956321067612E-08) * ($fps**3.250); }  | 
| 
690
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1185) { return (4.745469537157371E-10) * ($fps**3.750); }  | 
| 
691
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1150) { return (1.379746590025088E-11) * ($fps**4.250); }  | 
| 
692
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1100) { return (4.070157961147882E-13) * ($fps**4.750); }  | 
| 
693
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1060) { return (2.938236954847331E-14) * ($fps**5.125); }  | 
| 
694
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps > 1025) { return (1.228597370774746E-14) * ($fps**5.250); }  | 
| 
695
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  980) { return (2.916938264100495E-14) * ($fps**5.125); }  | 
| 
696
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  945) { return (3.855099424807451E-13) * ($fps**4.750); }  | 
| 
697
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  905) { return (1.185097045689854E-11) * ($fps**4.250); }  | 
| 
698
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  860) { return (3.566129470974951E-10) * ($fps**3.750); }  | 
| 
699
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  810) { return (1.045513263966272E-08) * ($fps**3.250); }  | 
| 
700
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  780) { return (1.291159200846216E-07) * ($fps**2.875); }  | 
| 
701
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  750) { return (6.824429329105383E-07) * ($fps**2.625); }  | 
| 
702
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  700) { return (3.569169672385163E-06) * ($fps**2.375); }  | 
| 
703
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  640) { return (1.839015095899579E-05) * ($fps**2.125); }  | 
| 
704
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  600) { return (5.711174688734240E-05) * ($fps**1.950); }  | 
| 
705
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  550) { return (9.226557091973427E-05) * ($fps**1.875); }  | 
| 
706
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     elsif ($fps >  250) { return (9.337991957131389E-05) * ($fps**1.875); }  | 
| 
707
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >  100) { return (7.225247327590413E-05) * ($fps**1.925); }  | 
| 
708
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >   65) { return (5.792684957074546E-05) * ($fps**1.975); }  | 
| 
709
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     elsif ($fps >    0) { return (5.206214107320588E-05) * ($fps**2.000); }  | 
| 
710
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return 0.0;  | 
| 
711
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
712
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
713
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 muzzle_energy (mass_grains, velocity_fps, [want_joules_bool])  | 
| 
714
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
715
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A convenience function for computing kinetic energy from mass and velocity.  | 
| 
716
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Despite its name, it is useful for computing the kinetic energy of a projectile  | 
| 
717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 at any point during its flight.  | 
| 
718
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
719
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4  | 
| 
720
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
721
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) mass_grains is the mass of the projectile (in grains)  | 
| 
722
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
723
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) velocity_fps is the velocity of the projectile (in feet per second)  | 
| 
724
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
725
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (boolean) OPTIONAL: set want_joules_bool to a True value to get Joules instead of foot-pounds (boolean, default=False)  | 
| 
726
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
727
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 returns: (float) the kinetic energy of the projectile (in foot-pounds or Joules)  | 
| 
728
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
729
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back  | 
| 
730
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
731
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
732
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
733
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub muzzle_energy {  | 
| 
734
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
836
 | 
     my ($grains, $fps, $wantJ) = @_;  | 
| 
735
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     die("footpounds = muzzle_energy(grains, fps[, want_Joules])") unless(defined($fps));  | 
| 
736
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     my $nrg = 0.5 * $grains * $fps * $fps / 225312.839; # footpounds  | 
| 
737
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
6
 | 
        $nrg *= 1.3558 if ($wantJ);  | 
| 
738
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     return int(100 * $nrg + 0.5) / 100;  | 
| 
739
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
740
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
741
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 muzzle_velocity_from_energy (mass_grains, energy_ftlbs)  | 
| 
742
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
743
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A convenience function for computing velocity from mass and kinetic energy.  | 
| 
744
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Despite its name, it is useful for computing the velocity of a projectile  | 
| 
745
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 at any point during its flight.  | 
| 
746
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
747
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If all you have is Joules, divide by 1.3558179 to get foot-pounds.  | 
| 
748
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
749
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4  | 
| 
750
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
751
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) mass_grains is the mass of the projectile (in grains)  | 
| 
752
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
753
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter: (float) energy_ftlbs is the kinetic energy of the projectile (in foot-pounds)  | 
| 
754
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
755
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 returns: (float) the velocity of the projectile (in feet per second)  | 
| 
756
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
757
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back  | 
| 
758
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
759
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
760
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
761
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub muzzle_velocity_from_energy {  | 
| 
762
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
1
  
 | 
423
 | 
     my ($grains, $footpounds) = @_;  | 
| 
763
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     die("feet/second = muzzle_velocity_from_energy(grains, footpounds)") unless(defined($footpounds));  | 
| 
764
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     my $fps = (450625.678 * $footpounds / $grains) ** 0.5;  | 
| 
765
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     return int(100 * $fps + 0.5) / 100;  | 
| 
766
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
767
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
768
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
769
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
770
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 TODO  | 
| 
771
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
772
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Contact Geoffrey Kolbe (Inventor at Border Barrels Limited) and ask for permission to publish his splendid implementations:  | 
| 
773
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
774
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  * Bullet drag calculator - http://www.border-barrels.com/cgi-bin/drag_working.cgi  | 
| 
775
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
776
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  * Barrel weight calculator - http://www.border-barrels.com/cgi-bin/swamped_barrel_weight.cgi  | 
| 
777
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
778
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 His drag calculator seems better than my own ebc function.  | 
| 
779
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
780
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  |