ballistics-ng 0.1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6cab378877c914007cb15e44240be0256b9bc837
4
+ data.tar.gz: e764833a574ad53b621db05e3a876a436c15f667
5
+ SHA512:
6
+ metadata.gz: 33685521c47161c77bdbdea0cb6edc597b30f721b3723efba9b5f6ed0e8ee9959fa2ba619e4e27d62cb041a1dd1f52ccf7ed1c20367085b451a288ddbe9b7ff0
7
+ data.tar.gz: a167d4e4de9c66ee10feba372b65ce83629d9922a8c3eeccb686d5c4716840f4a8be6d947f6027ec776d524d1cefb9f6281cf67a171ed26c50a6f3c40f63faf1
data/README.md ADDED
@@ -0,0 +1,12 @@
1
+ # Install
2
+
3
+ ```
4
+ # Note, this project is based on an abandoned gem and has not settled on
5
+ # a gem name yet
6
+
7
+ # So first, clone this repo; then:
8
+
9
+ cd ballistics
10
+ gem install rake-compiler
11
+ rake rebuild
12
+ ```
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ begin
2
+ require "rake/testtask"
3
+
4
+ # add test task
5
+ Rake::TestTask.new do |t|
6
+ t.test_files = FileList['test/**/*.rb']
7
+ end
8
+ desc "Run minitest tests"
9
+
10
+ task default: :test
11
+
12
+ @test_task = true
13
+ rescue Exception => e
14
+ warn "testtask error: #{e}"
15
+ @test_task = false
16
+ end
17
+
18
+ begin
19
+ gem "rake-compiler"
20
+ require "rake/extensiontask"
21
+
22
+ # add tasks for compilation
23
+ Rake::ExtensionTask.new "ballistics/ext" do |t|
24
+ t.lib_dir = "lib"
25
+ t.ext_dir = "ext/ballistics"
26
+ end
27
+
28
+ # add rebuild task
29
+ if @test_task
30
+ desc "clobber, compile, test"
31
+ task rebuild: [:clobber, :compile, :test]
32
+ else
33
+ desc "clobber, compile"
34
+ task rebuild: [:clobber, :compile]
35
+ end
36
+ rescue Exception => e
37
+ warn "rake-compiler error: #{e}"
38
+ end
39
+
40
+ begin
41
+ require 'buildar'
42
+
43
+ # add gem building tasks
44
+ Buildar.new do |b|
45
+ b.gemspec_file = 'ballistics-ng.gemspec'
46
+ b.version_file = 'VERSION'
47
+ b.use_git = true
48
+ end
49
+ rescue LoadError
50
+ # ok
51
+ end
data/examples/table.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'ballistics/problem'
2
+
3
+ prob = Ballistics::Problem.simple(gun_family: 'rifles',
4
+ gun_id: 'ar15_300_blk',
5
+ cart_id: 'barnes_110_vor_tx')
6
+
7
+ puts prob.report
8
+ puts
9
+ puts
10
+ puts prob.table
@@ -0,0 +1,136 @@
1
+ #include <ruby.h>
2
+ #include <gnu_ballistics.h>
3
+
4
+ VALUE method_zero_angle(VALUE self,
5
+ VALUE drag_function,
6
+ VALUE drag_coefficient,
7
+ VALUE velocity,
8
+ VALUE sight_height,
9
+ VALUE zero_range,
10
+ VALUE y_intercept) {
11
+ double angle = ZeroAngle(FIX2INT(drag_function),
12
+ NUM2DBL(drag_coefficient),
13
+ NUM2DBL(velocity),
14
+ NUM2DBL(sight_height),
15
+ NUM2DBL(zero_range),
16
+ NUM2DBL(y_intercept));
17
+ return rb_float_new(angle);
18
+ }
19
+
20
+ VALUE method_trajectory(VALUE self,
21
+ VALUE drag_function,
22
+ VALUE drag_coefficient,
23
+ VALUE velocity,
24
+ VALUE sight_height,
25
+ VALUE shooting_angle,
26
+ VALUE zero_angle,
27
+ VALUE wind_speed,
28
+ VALUE wind_angle,
29
+ VALUE max_range,
30
+ VALUE interval) {
31
+
32
+ /* cast ruby variables */
33
+ int DragFunction = FIX2INT(drag_function);
34
+ double DragCoefficient = NUM2DBL(drag_coefficient);
35
+ double Vi = NUM2DBL(velocity);
36
+ double SightHeight = NUM2DBL(sight_height);
37
+ double ShootingAngle = NUM2DBL(shooting_angle);
38
+ double ZAngle = NUM2DBL(zero_angle);
39
+ double WindSpeed = NUM2DBL(wind_speed);
40
+ double WindAngle = NUM2DBL(wind_angle);
41
+ int MaxRange = FIX2INT(max_range);
42
+ int Interval = FIX2INT(interval);
43
+
44
+ /* create ruby objects */
45
+ VALUE result_array = rb_ary_new2(MaxRange);
46
+
47
+
48
+ double t=0;
49
+ double dt=0.5/Vi;
50
+ double v=0;
51
+ double vx=0, vx1=0, vy=0, vy1=0;
52
+ double dv=0, dvx=0, dvy=0;
53
+ double x=0, y=0;
54
+
55
+ double headwind=HeadWind(WindSpeed, WindAngle);
56
+ double crosswind=CrossWind(WindSpeed, WindAngle);
57
+
58
+ double Gy=GRAVITY*cos(DegtoRad((ShootingAngle + ZAngle)));
59
+ double Gx=GRAVITY*sin(DegtoRad((ShootingAngle + ZAngle)));
60
+
61
+ vx=Vi*cos(DegtoRad(ZAngle));
62
+ vy=Vi*sin(DegtoRad(ZAngle));
63
+
64
+ y=-SightHeight/12;
65
+
66
+
67
+ int n=0;
68
+ for (t=0;;t=t+dt){
69
+
70
+ vx1=vx, vy1=vy;
71
+ v=pow(pow(vx,2)+pow(vy,2),0.5);
72
+ dt=0.5/v;
73
+
74
+ // Compute acceleration using the drag function retardation
75
+ dv = retard(DragFunction,DragCoefficient,v+headwind);
76
+ dvx = -(vx/v)*dv;
77
+ dvy = -(vy/v)*dv;
78
+
79
+ // Compute velocity, including the resolved gravity vectors.
80
+ vx=vx + dt*dvx + dt*Gx;
81
+ vy=vy + dt*dvy + dt*Gy;
82
+
83
+
84
+
85
+ int yards = (x/3);
86
+ if (yards>=n){
87
+ if (yards % Interval == 0){
88
+ VALUE entry = rb_hash_new();
89
+ double windage_value = Windage(crosswind,Vi,x,t+dt);
90
+ double moa_windage_value = windage_value / ((yards / 100.0) * 1.0465);
91
+ rb_hash_aset(entry,
92
+ rb_str_new2("range"),
93
+ rb_float_new((int)(yards)));
94
+ rb_hash_aset(entry,
95
+ rb_str_new2("path"),
96
+ rb_float_new(y*12));
97
+ rb_hash_aset(entry,
98
+ rb_str_new2("moa_correction"),
99
+ rb_float_new(-RadtoMOA(atan(y/x))));
100
+ rb_hash_aset(entry,
101
+ rb_str_new2("time"),
102
+ rb_float_new(t+dt));
103
+ rb_hash_aset(entry,
104
+ rb_str_new2("windage"),
105
+ rb_float_new(windage_value));
106
+ rb_hash_aset(entry,
107
+ rb_str_new2("moa_windage"),
108
+ rb_float_new(moa_windage_value));
109
+ rb_hash_aset(entry,
110
+ rb_str_new2("velocity"),
111
+ rb_float_new(v));
112
+ rb_ary_push(result_array, entry);
113
+ }
114
+ n++;
115
+ }
116
+
117
+ // Compute position based on average velocity.
118
+ x=x+dt*(vx+vx1)/2;
119
+ y=y+dt*(vy+vy1)/2;
120
+
121
+ if (fabs(vy)>fabs(3*vx)) break;
122
+ if (n>=MaxRange+1) break;
123
+ }
124
+
125
+ return result_array;
126
+ }
127
+
128
+ // create the modules and methods that are callable from ruby
129
+ VALUE cBallistics;
130
+ VALUE cExt;
131
+ void Init_ext() {
132
+ cBallistics = rb_define_module("Ballistics");
133
+ cExt = rb_define_module_under(cBallistics, "Ext");
134
+ rb_define_singleton_method(cExt, "zero_angle", method_zero_angle, 6);
135
+ rb_define_singleton_method(cExt, "trajectory", method_trajectory, 10);
136
+ }
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile('ballistics/ext')
@@ -0,0 +1,577 @@
1
+ // GNU Ballistics Library
2
+ // Originally created by Derek Yates
3
+ // Now available free under the GNU GPL
4
+
5
+
6
+
7
+ #ifndef __lib_ballistics__
8
+ #define __lib_ballistics__
9
+ #define __BCOMP_MAXRANGE__ 50001
10
+ #define GRAVITY (-32.194)
11
+ #include <math.h>
12
+ #include <stdlib.h>
13
+
14
+ enum __DragFunctions {G1=1,G2,G3,G4,G5,G6,G7,G8};
15
+
16
+ // Angular conversion functions to make things a little easier.
17
+ // Source is in _angle.c
18
+ double DegtoMOA(double deg); // Converts degrees to minutes of angle
19
+ double DegtoRad(double deg); // Converts degrees to radians
20
+ double MOAtoDeg(double moa); // Converts minutes of angle to degrees
21
+ double MOAtoRad(double moa); // Converts minutes of angle to radians
22
+ double RadtoDeg(double rad); // Converts radians to degrees
23
+ double RadtoMOA(double rad); // Converts radiants to minutes of angle
24
+
25
+
26
+ // A function to calculate ballistic retardation values based on standard drag functions.
27
+ // Source is in "_retard.c"
28
+ double retard(int DragFunction, double DragCoefficient, double Vi);
29
+ /* Arguments:
30
+ DragFunction: G1, G2, G3, G4, G5, G6, G7, or G8. All are enumerated above.
31
+ DragCoefficient: The coefficient of drag for the projectile for the given drag function.
32
+ Vi: The Velocity of the projectile.
33
+
34
+ Return Value:
35
+ The function returns the projectile drag retardation velocity, in ft/s per second.
36
+
37
+ */
38
+
39
+
40
+ // A function to correct a "standard" Drag Coefficient for differing atmospheric conditions.
41
+ // Returns the corrected drag coefficient for supplied drag coefficient and atmospheric conditions.
42
+ // Source is in "_atmosphere.c"
43
+ double AtmCorrect(double DragCoefficient, double Altitude, double Barometer, double Temperature, double RelativeHumidity);
44
+ /* Arguments:
45
+ DragCoefficient: The coefficient of drag for a given projectile.
46
+ Altitude: The altitude above sea level in feet. Standard altitude is 0 feet above sea level.
47
+ Barometer: The barometric pressure in inches of mercury (in Hg).
48
+ This is not "absolute" pressure, it is the "standardized" pressure reported in the papers and news.
49
+ Standard pressure is 29.53 in Hg.
50
+ Temperature: The temperature in Fahrenheit. Standard temperature is 59 degrees.
51
+ RelativeHumidity: The relative humidity fraction. Ranges from 0.00 to 1.00, with 0.50 being 50% relative humidity.
52
+ Standard humidity is 78%
53
+
54
+ Return Value:
55
+ The function returns a ballistic coefficient, corrected for the supplied atmospheric conditions.
56
+ */
57
+
58
+
59
+ // A function to compute the windage deflection for a given crosswind speed,
60
+ // given flight time in a vacuum, and given flight time in real life.
61
+ // Returns the windage correction needed in inches.
62
+ // Source is in "_windage.c"
63
+ double Windage(double WindSpeed, double Vi, double x, double t);
64
+ /* Arguments:
65
+ WindSpeed: The wind velocity in mi/hr.
66
+ Vi: The initial velocity of the projectile (muzzle velocity).
67
+ x: The range at which you wish to determine windage, in feet.
68
+ t: The time it has taken the projectile to traverse the range x, in seconds.
69
+
70
+ Return Value:
71
+ Returns the amount of windage correction, in inches, required to achieve zero on a target at the given range.
72
+
73
+ */
74
+
75
+ // Functions to resolve any wind / angle combination into headwind and crosswind components.
76
+ // Source is in "_windage.c"
77
+ double HeadWind(double WindSpeed, double WindAngle);
78
+ double CrossWind(double WindSpeed, double WindAngle);
79
+ /* Arguments:
80
+ WindSpeed: The wind velocity, in mi/hr.
81
+ WindAngle: The angle from which the wind is coming, in degrees.
82
+ 0 degrees is from straight ahead
83
+ 90 degrees is from right to left
84
+ 180 degrees is from directly behind
85
+ 270 or -90 degrees is from left to right.
86
+
87
+ Return value:
88
+ Returns the headwind or crosswind velocity component, in mi/hr.
89
+ */
90
+
91
+
92
+ // A function to determine the bore angle needed to achieve a target zero at Range yards
93
+ // (at standard conditions and on level ground.)
94
+ // Source is in "_zero.c"
95
+ double ZeroAngle(int DragFunction, double DragCoefficient, double Vi, double SightHeight, double ZeroRange, double yIntercept);
96
+ /* Arguments:
97
+ DragFunction: The drag function to use (G1, G2, G3, G5, G6, G7, G8)
98
+ DragCoefficient: The coefficient of drag for the projectile, for the supplied drag function.
99
+ Vi: The initial velocity of the projectile, in feet/s
100
+ SightHeight: The height of the sighting system above the bore centerline, in inches.
101
+ Most scopes fall in the 1.6 to 2.0 inch range.
102
+ ZeroRange: The range in yards, at which you wish the projectile to intersect yIntercept.
103
+ yIntercept: The height, in inches, you wish for the projectile to be when it crosses ZeroRange yards.
104
+ This is usually 0 for a target zero, but could be any number. For example if you wish
105
+ to sight your rifle in 1.5" high at 100 yds, then you would set yIntercept to 1.5, and ZeroRange to 100
106
+
107
+ Return Value:
108
+ Returns the angle of the bore relative to the sighting system, in degrees.
109
+ */
110
+
111
+
112
+ // A function to generate a ballistic solution table in 1 yard increments, up to __BCOMP_MAXRANGE__.
113
+ // Source is in "_solve.c"
114
+ int SolveAll(int DragFunction, double DragCoefficient, double Vi, double SightHeight, \
115
+ double ShootingAngle, double ZeroAngle, double WindSpeed, double WindAngle, double** Solution);
116
+ /* Arguments:
117
+ DragFunction: The drag function you wish to use for the solution (G1, G2, G3, G5, G6, G7, or G8)
118
+ DragCoefficient: The coefficient of drag for the projectile you wish to model.
119
+ Vi: The projectile initial velocity.
120
+ SightHeight: The height of the sighting system above the bore centerline.
121
+ Most scopes are in the 1.5"-2.0" range.
122
+ ShootingAngle: The uphill or downhill shooting angle, in degrees. Usually 0, but can be anything from
123
+ 90 (directly up), to -90 (directly down).
124
+ ZeroAngle: The angle of the sighting system relative to the bore, in degrees. This can be easily computed
125
+ using the ZeroAngle() function documented above.
126
+ WindSpeed: The wind velocity, in mi/hr
127
+ WindAngle: The angle at which the wind is approaching from, in degrees.
128
+ 0 degrees is a straight headwind
129
+ 90 degrees is from right to left
130
+ 180 degrees is a straight tailwind
131
+ -90 or 270 degrees is from left to right.
132
+ Solution: A pointer provided for accessing the solution after it has been generated.
133
+ Memory for this pointer is allocated in the function, so the user does not need
134
+ to worry about it. This solution can be passed to the retrieval functions to get
135
+ useful data from the solution.
136
+ Return Value:
137
+ This function returns an integer representing the maximum valid range of the
138
+ solution. This also indicates the maximum number of rows in the solution matrix,
139
+ and should not be exceeded in order to avoid a memory segmentation fault.
140
+
141
+ */
142
+
143
+
144
+ // Functions for retrieving data from a solution generated with SolveAll()
145
+ double GetRange(double* sln, int yardage); // Returns range, in yards.
146
+ double GetPath(double* sln, int yardage); // Returns projectile path, in inches, relative to the line of sight.
147
+ double GetMOA(double* sln, int yardage); // Returns an estimated elevation correction for achieving a zero at this range.
148
+ // this is useful for "click charts" and the like.
149
+ double GetTime(double* sln, int yardage);// Returns the projectile's time of flight to this range.
150
+ double GetWindage(double* sln, int yardage); // Returns the windage correction in inches required to achieve zero at this range.
151
+ double GetWindageMOA(double* sln, int yardage); // Returns an approximate windage correction in MOA to achieve a zero at this range.
152
+ double GetVelocity(double* sln, int yardage); // Returns the projectile's total velocity (Vector product of Vx and Vy)
153
+ double GetVx(double* sln, int yardage); // Returns the velocity of the projectile in the bore direction.
154
+ double GetVy(double* sln, int yardage); // Returns the velocity of the projectile perpendicular to the bore direction.
155
+
156
+ // For very steep shooting angles, Vx can actually become what you would think of as Vy relative to the ground,
157
+ // because Vx is referencing the bore's axis. All computations are carried out relative to the bore's axis, and
158
+ // have very little to do with the ground's orientation.
159
+
160
+
161
+ // I have split the source up into several files to make it easier for me to work on and refine.
162
+ // Some people hate this, but I find it is easier to work on the code in small chunks.
163
+
164
+ // Specialty angular conversion functions
165
+ double DegtoMOA(double deg){
166
+ return deg*60;
167
+ }
168
+ double DegtoRad(double deg){
169
+ return deg*M_PI/180;
170
+ }
171
+ double MOAtoDeg(double moa){
172
+ return moa/60;
173
+ }
174
+ double MOAtoRad(double moa){
175
+ return moa/60*M_PI/180;
176
+ }
177
+ double RadtoDeg(double rad){
178
+ return rad*180/M_PI;
179
+ }
180
+ double RadtoMOA(double rad){
181
+ return rad*60*180/M_PI;
182
+ }
183
+
184
+ double retard(int DragFunction, double DragCoefficient, double Velocity){
185
+
186
+ // printf("DF: %d, CD: %f, V: %f,);
187
+
188
+ double vp=Velocity;
189
+ double val=-1;
190
+ double A=-1;
191
+ double M=-1;
192
+ switch(DragFunction) {
193
+ case G1:
194
+ if (vp > 4230) { A = 1.477404177730177e-04; M = 1.9565; }
195
+ else if (vp> 3680) { A = 1.920339268755614e-04; M = 1.925 ; }
196
+ else if (vp> 3450) { A = 2.894751026819746e-04; M = 1.875 ; }
197
+ else if (vp> 3295) { A = 4.349905111115636e-04; M = 1.825 ; }
198
+ else if (vp> 3130) { A = 6.520421871892662e-04; M = 1.775 ; }
199
+ else if (vp> 2960) { A = 9.748073694078696e-04; M = 1.725 ; }
200
+ else if (vp> 2830) { A = 1.453721560187286e-03; M = 1.675 ; }
201
+ else if (vp> 2680) { A = 2.162887202930376e-03; M = 1.625 ; }
202
+ else if (vp> 2460) { A = 3.209559783129881e-03; M = 1.575 ; }
203
+ else if (vp> 2225) { A = 3.904368218691249e-03; M = 1.55 ; }
204
+ else if (vp> 2015) { A = 3.222942271262336e-03; M = 1.575 ; }
205
+ else if (vp> 1890) { A = 2.203329542297809e-03; M = 1.625 ; }
206
+ else if (vp> 1810) { A = 1.511001028891904e-03; M = 1.675 ; }
207
+ else if (vp> 1730) { A = 8.609957592468259e-04; M = 1.75 ; }
208
+ else if (vp> 1595) { A = 4.086146797305117e-04; M = 1.85 ; }
209
+ else if (vp> 1520) { A = 1.954473210037398e-04; M = 1.95 ; }
210
+ else if (vp> 1420) { A = 5.431896266462351e-05; M = 2.125 ; }
211
+ else if (vp> 1360) { A = 8.847742581674416e-06; M = 2.375 ; }
212
+ else if (vp> 1315) { A = 1.456922328720298e-06; M = 2.625 ; }
213
+ else if (vp> 1280) { A = 2.419485191895565e-07; M = 2.875 ; }
214
+ else if (vp> 1220) { A = 1.657956321067612e-08; M = 3.25 ; }
215
+ else if (vp> 1185) { A = 4.745469537157371e-10; M = 3.75 ; }
216
+ else if (vp> 1150) { A = 1.379746590025088e-11; M = 4.25 ; }
217
+ else if (vp> 1100) { A = 4.070157961147882e-13; M = 4.75 ; }
218
+ else if (vp> 1060) { A = 2.938236954847331e-14; M = 5.125 ; }
219
+ else if (vp> 1025) { A = 1.228597370774746e-14; M = 5.25 ; }
220
+ else if (vp> 980) { A = 2.916938264100495e-14; M = 5.125 ; }
221
+ else if (vp> 945) { A = 3.855099424807451e-13; M = 4.75 ; }
222
+ else if (vp> 905) { A = 1.185097045689854e-11; M = 4.25 ; }
223
+ else if (vp> 860) { A = 3.566129470974951e-10; M = 3.75 ; }
224
+ else if (vp> 810) { A = 1.045513263966272e-08; M = 3.25 ; }
225
+ else if (vp> 780) { A = 1.291159200846216e-07; M = 2.875 ; }
226
+ else if (vp> 750) { A = 6.824429329105383e-07; M = 2.625 ; }
227
+ else if (vp> 700) { A = 3.569169672385163e-06; M = 2.375 ; }
228
+ else if (vp> 640) { A = 1.839015095899579e-05; M = 2.125 ; }
229
+ else if (vp> 600) { A = 5.71117468873424e-05 ; M = 1.950 ; }
230
+ else if (vp> 550) { A = 9.226557091973427e-05; M = 1.875 ; }
231
+ else if (vp> 250) { A = 9.337991957131389e-05; M = 1.875 ; }
232
+ else if (vp> 100) { A = 7.225247327590413e-05; M = 1.925 ; }
233
+ else if (vp> 65) { A = 5.792684957074546e-05; M = 1.975 ; }
234
+ else if (vp> 0) { A = 5.206214107320588e-05; M = 2.000 ; }
235
+ break;
236
+
237
+ case G2:
238
+ if (vp> 1674 ) { A = .0079470052136733 ; M = 1.36999902851493; }
239
+ else if (vp> 1172 ) { A = 1.00419763721974e-03; M = 1.65392237010294; }
240
+ else if (vp> 1060 ) { A = 7.15571228255369e-23; M = 7.91913562392361; }
241
+ else if (vp> 949 ) { A = 1.39589807205091e-10; M = 3.81439537623717; }
242
+ else if (vp> 670 ) { A = 2.34364342818625e-04; M = 1.71869536324748; }
243
+ else if (vp> 335 ) { A = 1.77962438921838e-04; M = 1.76877550388679; }
244
+ else if (vp> 0 ) { A = 5.18033561289704e-05; M = 1.98160270524632; }
245
+ break;
246
+
247
+ case G5:
248
+ if (vp> 1730 ){ A = 7.24854775171929e-03; M = 1.41538574492812; }
249
+ else if (vp> 1228 ){ A = 3.50563361516117e-05; M = 2.13077307854948; }
250
+ else if (vp> 1116 ){ A = 1.84029481181151e-13; M = 4.81927320350395; }
251
+ else if (vp> 1004 ){ A = 1.34713064017409e-22; M = 7.8100555281422 ; }
252
+ else if (vp> 837 ){ A = 1.03965974081168e-07; M = 2.84204791809926; }
253
+ else if (vp> 335 ){ A = 1.09301593869823e-04; M = 1.81096361579504; }
254
+ else if (vp> 0 ){ A = 3.51963178524273e-05; M = 2.00477856801111; }
255
+ break;
256
+
257
+ case G6:
258
+ if (vp> 3236 ) { A = 0.0455384883480781 ; M = 1.15997674041274; }
259
+ else if (vp> 2065 ) { A = 7.167261849653769e-02; M = 1.10704436538885; }
260
+ else if (vp> 1311 ) { A = 1.66676386084348e-03 ; M = 1.60085100195952; }
261
+ else if (vp> 1144 ) { A = 1.01482730119215e-07 ; M = 2.9569674731838 ; }
262
+ else if (vp> 1004 ) { A = 4.31542773103552e-18 ; M = 6.34106317069757; }
263
+ else if (vp> 670 ) { A = 2.04835650496866e-05 ; M = 2.11688446325998; }
264
+ else if (vp> 0 ) { A = 7.50912466084823e-05 ; M = 1.92031057847052; }
265
+ break;
266
+
267
+ case G7:
268
+ if (vp> 4200 ) { A = 1.29081656775919e-09; M = 3.24121295355962; }
269
+ else if (vp> 3000 ) { A = 0.0171422231434847 ; M = 1.27907168025204; }
270
+ else if (vp> 1470 ) { A = 2.33355948302505e-03; M = 1.52693913274526; }
271
+ else if (vp> 1260 ) { A = 7.97592111627665e-04; M = 1.67688974440324; }
272
+ else if (vp> 1110 ) { A = 5.71086414289273e-12; M = 4.3212826264889 ; }
273
+ else if (vp> 960 ) { A = 3.02865108244904e-17; M = 5.99074203776707; }
274
+ else if (vp> 670 ) { A = 7.52285155782535e-06; M = 2.1738019851075 ; }
275
+ else if (vp> 540 ) { A = 1.31766281225189e-05; M = 2.08774690257991; }
276
+ else if (vp> 0 ) { A = 1.34504843776525e-05; M = 2.08702306738884; }
277
+ break;
278
+
279
+ case G8:
280
+ if (vp> 3571 ) { A = .0112263766252305 ; M = 1.33207346655961; }
281
+ else if (vp> 1841 ) { A = .0167252613732636 ; M = 1.28662041261785; }
282
+ else if (vp> 1120 ) { A = 2.20172456619625e-03; M = 1.55636358091189; }
283
+ else if (vp> 1088 ) { A = 2.0538037167098e-16 ; M = 5.80410776994789; }
284
+ else if (vp> 976 ) { A = 5.92182174254121e-12; M = 4.29275576134191; }
285
+ else if (vp> 0 ) { A = 4.3917343795117e-05 ; M = 1.99978116283334; }
286
+ break;
287
+
288
+ default:
289
+ break;
290
+
291
+ }
292
+
293
+ if (A!=-1 && M!=-1 && vp>0 && vp<10000){
294
+ val=A*pow(vp,M)/DragCoefficient;
295
+ return val;
296
+ }
297
+ else return -1;
298
+ }
299
+
300
+ double calcFR(double Temperature, double Pressure, double RelativeHumidity){
301
+ double VPw=4e-6*pow(Temperature,3) - 0.0004*pow(Temperature,2)+0.0234*Temperature-0.2517;
302
+ double FRH=0.995*(Pressure/(Pressure-(0.3783)*(RelativeHumidity)*VPw));
303
+ return FRH;
304
+ }
305
+
306
+ double calcFP(double Pressure){
307
+ double Pstd=29.53; // in-hg
308
+ double FP=0;
309
+ FP = (Pressure-Pstd)/(Pstd);
310
+ return FP;
311
+ }
312
+
313
+ double calcFT(double Temperature,double Altitude){
314
+ double Tstd=-0.0036*Altitude+59;
315
+ double FT = (Temperature-Tstd)/(459.6+Tstd);
316
+ return FT;
317
+ }
318
+
319
+ double calcFA(double Altitude){
320
+ double fa=0;
321
+ fa=-4e-15*pow(Altitude,3)+4e-10*pow(Altitude,2)-3e-5*Altitude+1;
322
+ return (1/fa);
323
+ }
324
+
325
+ double AtmCorrect(double DragCoefficient, double Altitude, double Barometer, double Temperature, double RelativeHumidity){
326
+
327
+ double FA = calcFA(Altitude);
328
+ double FT = calcFT(Temperature, Altitude);
329
+ double FR = calcFR(Temperature, Barometer, RelativeHumidity);
330
+ double FP = calcFP(Barometer);
331
+
332
+ // Calculate the atmospheric correction factor
333
+ double CD = (FA*(1+FT-FP)*FR);
334
+ return DragCoefficient*CD;
335
+
336
+ }
337
+
338
+ double Windage(double WindSpeed, double Vi, double xx, double t){
339
+ double Vw = WindSpeed*17.60; // Convert to inches per second.
340
+ return (Vw*(t-xx/Vi));
341
+ }
342
+
343
+
344
+ // Headwind is positive at WindAngle=0
345
+ double HeadWind(double WindSpeed, double WindAngle){
346
+ double Wangle = DegtoRad(WindAngle);
347
+ return (cos(Wangle)*WindSpeed);
348
+ }
349
+
350
+ // Positive is from Shooter's Right to Left (Wind from 90 degree)
351
+ double CrossWind(double WindSpeed, double WindAngle){
352
+ double Wangle = DegtoRad(WindAngle);
353
+ return (sin(Wangle)*WindSpeed);
354
+ }
355
+
356
+
357
+ double ZeroAngle(int DragFunction, double DragCoefficient, double Vi, double SightHeight, double ZeroRange, double yIntercept){
358
+
359
+ // Numerical Integration variables
360
+ double t=0;
361
+ double dt=1/Vi; // The solution accuracy generally doesn't suffer if its within a foot for each second of time.
362
+ double y=-SightHeight/12;
363
+ double x=0;
364
+ double da; // The change in the bore angle used to iterate in on the correct zero angle.
365
+
366
+ // State variables for each integration loop.
367
+ double v=0, vx=0, vy=0; // velocity
368
+ double vx1=0, vy1=0; // Last frame's velocity, used for computing average velocity.
369
+ double dv=0, dvx=0, dvy=0; // acceleration
370
+ double Gx=0, Gy=0; // Gravitational acceleration
371
+
372
+ double angle=0; // The actual angle of the bore.
373
+
374
+ int quit=0; // We know it's time to quit our successive approximation loop when this is 1.
375
+
376
+ // Start with a very coarse angular change, to quickly solve even large launch angle problems.
377
+ da=DegtoRad(14);
378
+
379
+
380
+ // The general idea here is to start at 0 degrees elevation, and increase the elevation by 14 degrees
381
+ // until we are above the correct elevation. Then reduce the angular change by half, and begin reducing
382
+ // the angle. Once we are again below the correct angle, reduce the angular change by half again, and go
383
+ // back up. This allows for a fast successive approximation of the correct elevation, usually within less
384
+ // than 20 iterations.
385
+ for (angle=0;quit==0;angle=angle+da){
386
+ vy=Vi*sin(angle);
387
+ vx=Vi*cos(angle);
388
+ Gx=GRAVITY*sin(angle);
389
+ Gy=GRAVITY*cos(angle);
390
+
391
+ for (t=0,x=0,y=-SightHeight/12;x<=ZeroRange*3;t=t+dt){
392
+ vy1=vy;
393
+ vx1=vx;
394
+ v=pow((pow(vx,2)+pow(vy,2)),0.5);
395
+ dt=1/v;
396
+
397
+ dv = retard(DragFunction, DragCoefficient, v);
398
+ dvy = -dv*vy/v*dt;
399
+ dvx = -dv*vx/v*dt;
400
+
401
+ vx=vx+dvx;
402
+ vy=vy+dvy;
403
+ vy=vy+dt*Gy;
404
+ vx=vx+dt*Gx;
405
+
406
+ x=x+dt*(vx+vx1)/2;
407
+ y=y+dt*(vy+vy1)/2;
408
+ // Break early to save CPU time if we won't find a solution.
409
+ if (vy<0 && y<yIntercept) {
410
+ break;
411
+ }
412
+ if (vy>3*vx) {
413
+ break;
414
+ }
415
+ }
416
+
417
+ if (y>yIntercept && da>0){
418
+ da=-da/2;
419
+ }
420
+
421
+ if (y<yIntercept && da<0){
422
+ da=-da/2;
423
+ }
424
+
425
+ if (fabs(da) < MOAtoRad(0.01)) quit=1; // If our accuracy is sufficient, we can stop approximating.
426
+ if (angle > DegtoRad(45)) quit=1; // If we exceed the 45 degree launch angle, then the projectile just won't get there, so we stop trying.
427
+
428
+ }
429
+
430
+
431
+ return RadtoDeg(angle); // Convert to degrees for return value.
432
+ }
433
+
434
+
435
+ int SolveAll(int DragFunction, double DragCoefficient, double Vi, double SightHeight, \
436
+ double ShootingAngle, double ZAngle, double WindSpeed, double WindAngle, double** Solution){
437
+
438
+ double* ptr;
439
+ ptr = (double*)malloc(10*__BCOMP_MAXRANGE__*sizeof(double)+2048);
440
+
441
+ double t=0;
442
+ double dt=0.5/Vi;
443
+ double v=0;
444
+ double vx=0, vx1=0, vy=0, vy1=0;
445
+ double dv=0, dvx=0, dvy=0;
446
+ double x=0, y=0;
447
+
448
+ double headwind=HeadWind(WindSpeed, WindAngle);
449
+ double crosswind=CrossWind(WindSpeed, WindAngle);
450
+
451
+ double Gy=GRAVITY*cos(DegtoRad((ShootingAngle + ZAngle)));
452
+ double Gx=GRAVITY*sin(DegtoRad((ShootingAngle + ZAngle)));
453
+
454
+ vx=Vi*cos(DegtoRad(ZAngle));
455
+ vy=Vi*sin(DegtoRad(ZAngle));
456
+
457
+ y=-SightHeight/12;
458
+
459
+ int n=0;
460
+ for (t=0;;t=t+dt){
461
+
462
+ vx1=vx, vy1=vy;
463
+ v=pow(pow(vx,2)+pow(vy,2),0.5);
464
+ dt=0.5/v;
465
+
466
+ // Compute acceleration using the drag function retardation
467
+ dv = retard(DragFunction,DragCoefficient,v+headwind);
468
+ dvx = -(vx/v)*dv;
469
+ dvy = -(vy/v)*dv;
470
+
471
+ // Compute velocity, including the resolved gravity vectors.
472
+ vx=vx + dt*dvx + dt*Gx;
473
+ vy=vy + dt*dvy + dt*Gy;
474
+
475
+
476
+
477
+ if (x/3>=n){
478
+ ptr[10*n+0]=x/3; // Range in yds
479
+ ptr[10*n+1]=y*12; // Path in inches
480
+ ptr[10*n+2]=-RadtoMOA(atan(y/x)); // Correction in MOA
481
+ ptr[10*n+3]=t+dt; // Time in s
482
+ ptr[10*n+4]=Windage(crosswind,Vi,x,t+dt); // Windage in inches
483
+ ptr[10*n+5]=RadtoMOA(atan(ptr[10*n+4])); // Windage in MOA
484
+ ptr[10*n+6]=v; // Velocity (combined)
485
+ ptr[10*n+7]=vx; // Velocity (x)
486
+ ptr[10*n+8]=vy; // Velocity (y)
487
+ ptr[10*n+9]=0; // Reserved
488
+ n++;
489
+ }
490
+
491
+ // Compute position based on average velocity.
492
+ x=x+dt*(vx+vx1)/2;
493
+ y=y+dt*(vy+vy1)/2;
494
+
495
+ if (fabs(vy)>fabs(3*vx)) break;
496
+ if (n>=__BCOMP_MAXRANGE__+1) break;
497
+ }
498
+
499
+ ptr[10*__BCOMP_MAXRANGE__+1]=(double)n;
500
+
501
+ *Solution = ptr;
502
+
503
+ return n;
504
+ }
505
+ double GetRange(double* sln, int yardage){
506
+ double size=sln[__BCOMP_MAXRANGE__*10+1];
507
+ if (yardage<size){
508
+ return sln[10*yardage];
509
+ }
510
+ else return 0;
511
+ }
512
+
513
+ double GetPath(double* sln, int yardage){
514
+ double size=sln[__BCOMP_MAXRANGE__*10+1];
515
+ if (yardage<size){
516
+ return sln[10*yardage+1];
517
+ }
518
+ else return 0;
519
+ }
520
+
521
+ double GetMOA(double* sln, int yardage){
522
+ double size=sln[__BCOMP_MAXRANGE__*10+1];
523
+ if (yardage<size){
524
+ return sln[10*yardage+2];
525
+ }
526
+ else return 0;
527
+ }
528
+
529
+
530
+ double GetTime(double* sln, int yardage){
531
+ double size=sln[__BCOMP_MAXRANGE__*10+1];
532
+ if (yardage<size){
533
+ return sln[10*yardage+3];
534
+ }
535
+ else return 0;
536
+ }
537
+
538
+ double GetWindage(double* sln, int yardage){
539
+ double size=sln[__BCOMP_MAXRANGE__*10+1];
540
+ if (yardage<size){
541
+ return sln[10*yardage+4];
542
+ }
543
+ else return 0;
544
+ }
545
+
546
+ double GetWindageMOA(double* sln, int yardage){
547
+ double size=sln[__BCOMP_MAXRANGE__*10+1];
548
+ if (yardage<size){
549
+ return sln[10*yardage+5];
550
+ }
551
+ else return 0;
552
+ }
553
+
554
+ double GetVelocity(double* sln, int yardage){
555
+ double size=sln[__BCOMP_MAXRANGE__*10+1];
556
+ if (yardage<size){
557
+ return sln[10*yardage+6];
558
+ }
559
+ else return 0;
560
+ }
561
+
562
+ double GetVx(double* sln, int yardage){
563
+ double size=sln[__BCOMP_MAXRANGE__*10+1];
564
+ if (yardage<size){
565
+ return sln[10*yardage+7];
566
+ }
567
+ else return 0;
568
+ }
569
+
570
+ double GetVy(double* sln, int yardage){
571
+ double size=sln[__BCOMP_MAXRANGE__*10+1];
572
+ if (yardage<size){
573
+ return sln[10*yardage+8];
574
+ }
575
+ else return 0;
576
+ }
577
+ #endif