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 +7 -0
- data/README.md +12 -0
- data/Rakefile +51 -0
- data/examples/table.rb +10 -0
- data/ext/ballistics/ext.c +136 -0
- data/ext/ballistics/extconf.rb +3 -0
- data/ext/ballistics/gnu_ballistics.h +577 -0
- data/lib/ballistics.rb +77 -0
- data/lib/ballistics/atmosphere.rb +110 -0
- data/lib/ballistics/cartridge.rb +177 -0
- data/lib/ballistics/cartridges/300_blk.yaml +159 -0
- data/lib/ballistics/gun.rb +123 -0
- data/lib/ballistics/guns/pistols.yaml +6 -0
- data/lib/ballistics/guns/rifles.yaml +34 -0
- data/lib/ballistics/guns/shotguns.yaml +6 -0
- data/lib/ballistics/problem.rb +102 -0
- data/lib/ballistics/projectile.rb +165 -0
- data/lib/ballistics/projectiles/300_blk.yaml +321 -0
- data/lib/ballistics/util.rb +67 -0
- data/lib/ballistics/yaml.rb +57 -0
- data/test/atmosphere.rb +26 -0
- data/test/ballistics.rb +31 -0
- data/test/cartridge.rb +121 -0
- data/test/gun.rb +85 -0
- data/test/problem.rb +137 -0
- data/test/projectile.rb +163 -0
- data/test/util.rb +28 -0
- metadata +102 -0
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
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,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,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
|