ballistics-ng 0.1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|