Merge pull request #5698 from acemod/ab-trajectory-refinement

Advanced Ballistics - Trajectory refinement
This commit is contained in:
ulteq 2017-11-10 17:29:32 +01:00 committed by GitHub
commit 9d69961d5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 137 additions and 150 deletions

Binary file not shown.

Binary file not shown.

View File

@ -112,7 +112,9 @@ if (_caliber > 0 && _bulletLength > 0 && _bulletMass > 0 && _barrelTwist > 0) th
GVAR(currentbulletID) = (GVAR(currentbulletID) + 1) % 10000; GVAR(currentbulletID) = (GVAR(currentbulletID) + 1) % 10000;
"ace_advanced_ballistics" callExtension format["new:%1:%2:%3:%4:%5:%6:%7:%8:%9:%10:%11:%12:%13:%14:%15:%16:%17", GVAR(currentbulletID), _airFriction, _ballisticCoefficients, _velocityBoundaries, _atmosphereModel, _dragModel, _stabilityFactor, _twistDirection, _transonicStabilityCoef, getPosASL _projectile, _bulletVelocity, EGVAR(common,mapLatitude), EGVAR(weather,currentTemperature), EGVAR(common,mapAltitude), EGVAR(weather,currentHumidity), EGVAR(weather,currentOvercast), CBA_missionTime toFixed 6]; private _ammoCount = _unit ammo _muzzle;
"ace_advanced_ballistics" callExtension format["new:%1:%2:%3:%4:%5:%6:%7:%8:%9:%10:%11:%12:%13:%14:%15:%16:%17:%18", GVAR(currentbulletID), _ammoCount, _airFriction, _ballisticCoefficients, _velocityBoundaries, _atmosphereModel, _dragModel, _stabilityFactor, _twistDirection, _transonicStabilityCoef, getPosASL _projectile, _bulletVelocity, EGVAR(common,mapLatitude), EGVAR(weather,currentTemperature), EGVAR(common,mapAltitude), EGVAR(weather,currentHumidity), EGVAR(weather,currentOvercast), CBA_missionTime toFixed 6];
GVAR(allBullets) pushBack [_projectile, _caliber, _bulletTraceVisible, GVAR(currentbulletID)]; GVAR(allBullets) pushBack [_projectile, _caliber, _bulletTraceVisible, GVAR(currentbulletID)];

View File

@ -16,7 +16,6 @@
#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\main\script_macros.hpp"
#define GRAVITY 9.80665
#define ABSOLUTE_ZERO_IN_CELSIUS -273.15 #define ABSOLUTE_ZERO_IN_CELSIUS -273.15
#define KELVIN(t) (t - ABSOLUTE_ZERO_IN_CELSIUS) #define KELVIN(t) (t - ABSOLUTE_ZERO_IN_CELSIUS)
#define CELSIUS(t) (t + ABSOLUTE_ZERO_IN_CELSIUS) #define CELSIUS(t) (t + ABSOLUTE_ZERO_IN_CELSIUS)

View File

@ -58,7 +58,7 @@ private _bulletPos = [0, 0, 0];
private _bulletVelocity = [0, 0, 0]; private _bulletVelocity = [0, 0, 0];
private _bulletAccel = [0, 0, 0]; private _bulletAccel = [0, 0, 0];
private _bulletSpeed = 0; private _bulletSpeed = 0;
private _gravity = [0, sin(_scopeBaseAngle + _inclinationAngle) * -9.80665, cos(_scopeBaseAngle + _inclinationAngle) * -9.80665]; private _gravity = [0, sin(_scopeBaseAngle + _inclinationAngle) * -GRAVITY, cos(_scopeBaseAngle + _inclinationAngle) * -GRAVITY];
private _deltaT = 1 / _simSteps; private _deltaT = 1 / _simSteps;
private _elevation = 0; private _elevation = 0;
@ -95,7 +95,7 @@ if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) t
private _eoetvoesMultiplier = 0; private _eoetvoesMultiplier = 0;
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {
_eoetvoesMultiplier = 2 * (0.0000729 * _muzzleVelocity / -9.80665) * cos(_latitude) * sin(_directionOfFire); _eoetvoesMultiplier = 2 * (0.0000729 * _muzzleVelocity / -GRAVITY) * cos(_latitude) * sin(_directionOfFire);
}; };
_bulletPos set [0, 0]; _bulletPos set [0, 0];

View File

@ -109,6 +109,8 @@
#define TRACE_10(MESSAGE,A,B,C,D,E,F,G,H,I,J) /* disabled */ #define TRACE_10(MESSAGE,A,B,C,D,E,F,G,H,I,J) /* disabled */
#endif #endif
#define GRAVITY 9.8066
// Angular unit conversion // Angular unit conversion
#define MRAD_TO_MOA(d) ((d) * 3.43774677) // Conversion factor: 54 / (5 * PI) #define MRAD_TO_MOA(d) ((d) * 3.43774677) // Conversion factor: 54 / (5 * PI)
#define MOA_TO_MRAD(d) ((d) * 0.29088821) // Conversion factor: (5 * PI) / 54 #define MOA_TO_MRAD(d) ((d) * 0.29088821) // Conversion factor: (5 * PI) / 54

View File

@ -46,7 +46,7 @@ private _bulletPos = [0, 0, 0];
private _bulletVelocity = [0, 0, 0]; private _bulletVelocity = [0, 0, 0];
private _bulletAccel = [0, 0, 0]; private _bulletAccel = [0, 0, 0];
private _bulletSpeed = 0; private _bulletSpeed = 0;
private _gravity = [0, sin(_scopeBaseAngle) * -9.80665, cos(_scopeBaseAngle) * -9.80665]; private _gravity = [0, sin(_scopeBaseAngle) * -GRAVITY, cos(_scopeBaseAngle) * -GRAVITY];
private _deltaT = 1 / _simSteps; private _deltaT = 1 / _simSteps;
private _speedOfSound = 0; private _speedOfSound = 0;
if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then { if (missionNamespace getVariable [QEGVAR(advanced_ballistics,enabled), false]) then {

View File

@ -8,8 +8,10 @@
#include <cmath> #include <cmath>
#include <sstream> #include <sstream>
#define DELTA_T 0.02f #include "vector.hpp"
#define GRAVITY 9.80665f
#define DELTA_T 0.005
#define GRAVITY 9.8066f
#define DEGREES(X) (X * 180 / M_PI) #define DEGREES(X) (X * 180 / M_PI)
#define ABSOLUTE_ZERO_IN_CELSIUS -273.15f #define ABSOLUTE_ZERO_IN_CELSIUS -273.15f
#define KELVIN(t) (t - ABSOLUTE_ZERO_IN_CELSIUS) #define KELVIN(t) (t - ABSOLUTE_ZERO_IN_CELSIUS)
@ -39,8 +41,8 @@ struct Bullet {
double stabilityFactor; double stabilityFactor;
double twistDirection; double twistDirection;
double transonicStabilityCoef; double transonicStabilityCoef;
std::vector<double> bulletVelocity; ace::vector3<double> bulletVelocityPreviousFrame;
std::vector<double> origin; ace::vector3<double> origin;
double latitude; double latitude;
double temperature; double temperature;
double altitude; double altitude;
@ -48,7 +50,6 @@ struct Bullet {
double overcast; double overcast;
double startTime; double startTime;
double lastFrame; double lastFrame;
double bcDegradation;
unsigned randSeed; unsigned randSeed;
std::default_random_engine randGenerator; std::default_random_engine randGenerator;
}; };
@ -138,7 +139,7 @@ double calculateRetard(int DragFunction, double DragCoefficient, double Velocity
int idx = std::max(0, std::min(DragFunction, 9)); int idx = std::max(0, std::min(DragFunction, 9));
double m = Velocity / Mach; double m = Velocity / Mach;
for (int i = 0; i < machNumbers[idx].size(); i++) { for (int i = 0; i < (int)machNumbers[idx].size(); i++) {
if (machNumbers[idx][i] >= m) { if (machNumbers[idx][i] >= m) {
int previousIdx = std::max(0, i - 1); int previousIdx = std::max(0, i - 1);
double previousDragCoefficient = dragCoefficients[idx][previousIdx]; double previousDragCoefficient = dragCoefficients[idx][previousIdx];
@ -153,6 +154,7 @@ double calculateRetard(int DragFunction, double DragCoefficient, double Velocity
double calculateVanillaZeroAngle(double zeroRange, double muzzleVelocity, double airFriction, double boreHeight) { double calculateVanillaZeroAngle(double zeroRange, double muzzleVelocity, double airFriction, double boreHeight) {
double zeroAngle = 0.0f; double zeroAngle = 0.0f;
double deltaT = 1.0 / std::max(100.0, zeroRange);
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
double lx = 0.0f; double lx = 0.0f;
@ -181,14 +183,14 @@ double calculateVanillaZeroAngle(double zeroRange, double muzzleVelocity, double
ax += gx; ax += gx;
ay += gy; ay += gy;
px += vx * DELTA_T * 0.5; px += vx * deltaT * 0.5;
py += vy * DELTA_T * 0.5; py += vy * deltaT * 0.5;
vx += ax * DELTA_T; vx += ax * deltaT;
vy += ay * DELTA_T; vy += ay * deltaT;
px += vx * DELTA_T * 0.5; px += vx * deltaT * 0.5;
py += vy * DELTA_T * 0.5; py += vy * deltaT * 0.5;
tof += DELTA_T; tof += deltaT;
} }
double y = ly + (zeroRange - lx) * (py - ly) / (px - lx); double y = ly + (zeroRange - lx) * (py - ly) / (px - lx);
@ -205,6 +207,7 @@ double calculateVanillaZeroAngle(double zeroRange, double muzzleVelocity, double
double calculateZeroAngle(double zeroRange, double muzzleVelocity, double boreHeight, double temperature, double pressure, double humidity, double ballisticCoefficient, int dragModel, char* atmosphereModel) { double calculateZeroAngle(double zeroRange, double muzzleVelocity, double boreHeight, double temperature, double pressure, double humidity, double ballisticCoefficient, int dragModel, char* atmosphereModel) {
double zeroAngle = 0.0f; double zeroAngle = 0.0f;
double deltaT = 1.0 / std::max(100.0, zeroRange);
ballisticCoefficient = calculateAtmosphericCorrection(ballisticCoefficient, temperature, pressure, humidity, atmosphereModel); ballisticCoefficient = calculateAtmosphericCorrection(ballisticCoefficient, temperature, pressure, humidity, atmosphereModel);
@ -236,14 +239,14 @@ double calculateZeroAngle(double zeroRange, double muzzleVelocity, double boreHe
ax += gx; ax += gx;
ay += gy; ay += gy;
px += vx * DELTA_T * 0.5; px += vx * deltaT * 0.5;
py += vy * DELTA_T * 0.5; py += vy * deltaT * 0.5;
vx += ax * DELTA_T; vx += ax * deltaT;
vy += ay * DELTA_T; vy += ay * deltaT;
px += vx * DELTA_T * 0.5; px += vx * deltaT * 0.5;
py += vy * DELTA_T * 0.5; py += vy * deltaT * 0.5;
tof += DELTA_T; tof += deltaT;
} }
double y = ly + (zeroRange - lx) * (py - ly) / (px - lx); double y = ly + (zeroRange - lx) * (py - ly) / (px - lx);
@ -322,6 +325,7 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function)
EXTENSION_RETURN(); EXTENSION_RETURN();
} else if (!strcmp(mode, "new")) { } else if (!strcmp(mode, "new")) {
unsigned int index = 0; unsigned int index = 0;
unsigned int ammoCount = 0;
double airFriction = 0.0; double airFriction = 0.0;
char* ballisticCoefficientArray; char* ballisticCoefficientArray;
char* ballisticCoefficient; char* ballisticCoefficient;
@ -348,6 +352,7 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function)
double tickTime = 0.0; double tickTime = 0.0;
index = strtol(strtok_s(NULL, ":", &next_token), NULL, 10); index = strtol(strtok_s(NULL, ":", &next_token), NULL, 10);
ammoCount = strtol(strtok_s(NULL, ":", &next_token), NULL, 10);
airFriction = strtod(strtok_s(NULL, ":", &next_token), NULL); airFriction = strtod(strtok_s(NULL, ":", &next_token), NULL);
ballisticCoefficientArray = strtok_s(NULL, ":", &next_token); ballisticCoefficientArray = strtok_s(NULL, ":", &next_token);
ballisticCoefficientArray++; ballisticCoefficientArray++;
@ -406,8 +411,8 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function)
bulletDatabase[index].stabilityFactor = stabilityFactor; bulletDatabase[index].stabilityFactor = stabilityFactor;
bulletDatabase[index].twistDirection = twistDirection; bulletDatabase[index].twistDirection = twistDirection;
bulletDatabase[index].transonicStabilityCoef = transonicStabilityCoef; bulletDatabase[index].transonicStabilityCoef = transonicStabilityCoef;
bulletDatabase[index].bulletVelocity = bulletVelocity; bulletDatabase[index].bulletVelocityPreviousFrame = { bulletVelocity[0], bulletVelocity[1], bulletVelocity[2] };
bulletDatabase[index].origin = origin; bulletDatabase[index].origin = { origin[0], origin[1], origin[2] };
bulletDatabase[index].latitude = latitude / 180 * M_PI; bulletDatabase[index].latitude = latitude / 180 * M_PI;
bulletDatabase[index].temperature = temperature; bulletDatabase[index].temperature = temperature;
bulletDatabase[index].altitude = altitude; bulletDatabase[index].altitude = altitude;
@ -415,8 +420,12 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function)
bulletDatabase[index].overcast = overcast; bulletDatabase[index].overcast = overcast;
bulletDatabase[index].startTime = tickTime; bulletDatabase[index].startTime = tickTime;
bulletDatabase[index].lastFrame = tickTime; bulletDatabase[index].lastFrame = tickTime;
bulletDatabase[index].bcDegradation = 1.0; if (transonicStabilityCoef < 1) {
bulletDatabase[index].randSeed = 0; unsigned int k1 = (unsigned)round(tickTime / 2);
unsigned int k2 = ammoCount;
bulletDatabase[index].randSeed = (unsigned int)(0.5 * (k1 + k2) * (k1 + k2 + 1) + k2);
bulletDatabase[index].randGenerator.seed(bulletDatabase[index].randSeed);
}
strncpy_s(output, outputSize, "", _TRUNCATE); strncpy_s(output, outputSize, "", _TRUNCATE);
EXTENSION_RETURN(); EXTENSION_RETURN();
@ -454,164 +463,139 @@ void __stdcall RVExtension(char *output, int outputSize, const char *function)
heightAGL = strtod(strtok_s(NULL, ":", &next_token), NULL); heightAGL = strtod(strtok_s(NULL, ":", &next_token), NULL);
tickTime = strtod(strtok_s(NULL, ":", &next_token), NULL); tickTime = strtod(strtok_s(NULL, ":", &next_token), NULL);
if (bulletDatabase[index].randSeed == 0) { ace::vector3<double> bulletVelocityCurrentFrame = { velocity[0], velocity[1], velocity[2] };
int angle = (int)round(atan2(velocity[0], velocity[1]) * 360 / M_PI); ace::vector3<double> bulletPosition = { position[0], position[1], position[2] };
bulletDatabase[index].randSeed = (unsigned)(720 + angle) % 720; ace::vector3<double> windVelocity = { wind[0], wind[1], wind[2] };
bulletDatabase[index].randSeed *= 3; ace::vector3<double> gravityAccel = { 0, 0, -GRAVITY };
bulletDatabase[index].randSeed += (unsigned)round(abs(velocity[2]) / 2);
bulletDatabase[index].randSeed *= 3;
bulletDatabase[index].randSeed += (unsigned)round(abs(bulletDatabase[index].origin[0] / 2));
bulletDatabase[index].randSeed *= 3;
bulletDatabase[index].randSeed += (unsigned)round(abs(bulletDatabase[index].origin[1] / 2));
bulletDatabase[index].randSeed *= 3;
bulletDatabase[index].randSeed += (unsigned)abs(bulletDatabase[index].temperature) * 10;
bulletDatabase[index].randSeed *= 3;
bulletDatabase[index].randSeed += (unsigned)abs(bulletDatabase[index].humidity) * 10;
bulletDatabase[index].randGenerator.seed(bulletDatabase[index].randSeed);
}
double ballisticCoefficient = 1.0; double ballisticCoefficient = 1.0;
double dragRef = 0.0; double dragRef = 0.0;
double drag = 0.0; double drag = 0.0;
double accelRef[3] = { 0.0, 0.0, 0.0 };
double accel[3] = { 0.0, 0.0, 0.0 };
double TOF = tickTime - bulletDatabase[index].startTime; double TOF = tickTime - bulletDatabase[index].startTime;
double deltaT = tickTime - bulletDatabase[index].lastFrame; double deltaT = tickTime - bulletDatabase[index].lastFrame;
double trueVelocity[3] = { 0.0, 0.0, 0.0 }; ace::vector3<double> trueVelocity;
double trueSpeed = 0.0; double temperature = bulletDatabase[index].temperature - 0.0065 * bulletPosition.z();
double temperature = bulletDatabase[index].temperature - 0.0065 * position[2]; double pressure = (1013.25 - 10 * bulletDatabase[index].overcast) * pow(1 - (0.0065 * (bulletDatabase[index].altitude + bulletPosition.z())) / (KELVIN(temperature) + 0.0065 * bulletDatabase[index].altitude), 5.255754495);
double pressure = (1013.25 - 10 * bulletDatabase[index].overcast) * pow(1 - (0.0065 * (bulletDatabase[index].altitude + position[2])) / (KELVIN(temperature) + 0.0065 * bulletDatabase[index].altitude), 5.255754495); ace::vector3<double> velocityOffset;
double windSpeed = 0.0;
double windAttenuation = 1.0;
double velocityOffset[3] = { 0.0, 0.0, 0.0 };
double bulletSpeed = sqrt(pow(bulletDatabase[index].bulletVelocity[0], 2) + pow(bulletDatabase[index].bulletVelocity[1], 2) + pow(bulletDatabase[index].bulletVelocity[2], 2));
bulletDatabase[index].lastFrame = tickTime; bulletDatabase[index].lastFrame = tickTime;
windSpeed = sqrt(pow(wind[0], 2) + pow(wind[1], 2) + pow(wind[2], 2)); if (windVelocity.magnitude() > 0.1) {
if (windSpeed > 0.1) { double windAttenuation = 1.0;
double windSourceTerrain[3]; ace::vector3<double> windSourceTerrain;
windSourceTerrain[0] = position[0] - wind[0] / windSpeed * 100; windSourceTerrain = bulletPosition - windVelocity.normalize() * 100;
windSourceTerrain[1] = position[1] - wind[1] / windSpeed * 100;
windSourceTerrain[2] = position[2] - wind[2] / windSpeed * 100;
int gridX = (int)floor(windSourceTerrain[0] / 50); int gridX = (int)floor(windSourceTerrain.x() / 50);
int gridY = (int)floor(windSourceTerrain[1] / 50); int gridY = (int)floor(windSourceTerrain.y() / 50);
int gridCell = gridX * map->mapGrids + gridY; int gridCell = gridX * map->mapGrids + gridY;
if (gridCell >= 0 && (std::size_t)gridCell < map->gridHeights.size() && (std::size_t)gridCell < map->gridBuildingNums.size()) { if (gridCell >= 0 && (std::size_t)gridCell < map->gridHeights.size() && (std::size_t)gridCell < map->gridBuildingNums.size()) {
double gridHeight = map->gridHeights[gridCell]; double gridHeight = map->gridHeights[gridCell];
if (gridHeight > position[2]) { if (gridHeight > bulletPosition.z()) {
double angle = atan((gridHeight - position[2]) / 100); double angle = atan((gridHeight - bulletPosition.z()) / 100);
windAttenuation *= pow(abs(cos(angle)), 2); windAttenuation *= pow(abs(cos(angle)), 2);
} }
} }
}
if (windSpeed > 0.1) {
double windSourceObstacles[3];
windSourceObstacles[0] = position[0] - wind[0] / windSpeed * 25;
windSourceObstacles[1] = position[1] - wind[1] / windSpeed * 25;
windSourceObstacles[2] = position[2] - wind[2] / windSpeed * 25;
if (heightAGL > 0 && heightAGL < 20) { if (heightAGL > 0 && heightAGL < 20) {
double roughnessLength = calculateRoughnessLength(windSourceObstacles[0], windSourceObstacles[1]); ace::vector3<double> windSourceObstacles;
windSourceObstacles = bulletPosition - windVelocity.normalize() * 25;
double roughnessLength = calculateRoughnessLength(windSourceObstacles.x(), windSourceObstacles.y());
windAttenuation *= abs(log(heightAGL / roughnessLength) / log(20 / roughnessLength)); windAttenuation *= abs(log(heightAGL / roughnessLength) / log(20 / roughnessLength));
} }
windVelocity = windVelocity * windAttenuation;
} }
if (windAttenuation < 1) { ace::vector3<double> bulletVelocity = bulletDatabase[index].bulletVelocityPreviousFrame;
wind[0] *= windAttenuation; double time = 0.0;
wind[1] *= windAttenuation;
wind[2] *= windAttenuation; while (time < deltaT) {
windSpeed = sqrt(pow(wind[0], 2) + pow(wind[1], 2) + pow(wind[2], 2)); double dt = std::min(deltaT - time, DELTA_T);
dragRef = -bulletDatabase[index].airFriction * bulletVelocity.magnitude_squared();
ace::vector3<double> accelRef = bulletVelocity.normalize() * dragRef;
velocityOffset += accelRef * dt;
bulletVelocity -= accelRef * dt;
bulletVelocity += gravityAccel * dt;
time += dt;
} }
trueVelocity[0] = bulletDatabase[index].bulletVelocity[0] - wind[0]; bulletVelocity = bulletDatabase[index].bulletVelocityPreviousFrame;
trueVelocity[1] = bulletDatabase[index].bulletVelocity[1] - wind[1]; time = 0.0;
trueVelocity[2] = bulletDatabase[index].bulletVelocity[2] - wind[2]; TOF -= deltaT;
trueSpeed = sqrt(pow(trueVelocity[0], 2) + pow(trueVelocity[1], 2) + pow(trueVelocity[2], 2));
if (bulletDatabase[index].transonicStabilityCoef < 1.0f && trueSpeed - 60 < SPEED_OF_SOUND(temperature) && trueSpeed > SPEED_OF_SOUND(temperature)) { while (time < deltaT) {
double dt = std::min(deltaT - time, DELTA_T * 2);
trueVelocity = bulletVelocity - windVelocity;
if (bulletDatabase[index].transonicStabilityCoef < 1.0f && trueVelocity.magnitude() < 1.2 * SPEED_OF_SOUND(temperature) && trueVelocity.magnitude() > SPEED_OF_SOUND(temperature)) {
std::uniform_real_distribution<double> distribution(-10.0, 10.0); std::uniform_real_distribution<double> distribution(-10.0, 10.0);
ace::vector3<double> offset(distribution(bulletDatabase[index].randGenerator), distribution(bulletDatabase[index].randGenerator), distribution(bulletDatabase[index].randGenerator));
double coef = 1.0f - bulletDatabase[index].transonicStabilityCoef; double coef = 1.0f - bulletDatabase[index].transonicStabilityCoef;
trueVelocity[0] += distribution(bulletDatabase[index].randGenerator) * coef; double trueSpeed = trueVelocity.magnitude();
trueVelocity[1] += distribution(bulletDatabase[index].randGenerator) * coef; trueVelocity += offset * coef;
trueVelocity[2] += distribution(bulletDatabase[index].randGenerator) * coef; trueVelocity = trueVelocity.normalize() * trueSpeed;
double speed = sqrt(pow(trueVelocity[0], 2) + pow(trueVelocity[1], 2) + pow(trueVelocity[2], 2));
trueVelocity[0] *= trueSpeed / speed;
trueVelocity[1] *= trueSpeed / speed;
trueVelocity[2] *= trueSpeed / speed;
bulletDatabase[index].bcDegradation *= pow(0.993, coef);
}; };
dragRef = -bulletDatabase[index].airFriction * bulletSpeed * bulletSpeed;
accelRef[0] = (bulletDatabase[index].bulletVelocity[0] / bulletSpeed) * dragRef;
accelRef[1] = (bulletDatabase[index].bulletVelocity[1] / bulletSpeed) * dragRef;
accelRef[2] = (bulletDatabase[index].bulletVelocity[2] / bulletSpeed) * dragRef;
velocityOffset[0] += accelRef[0] * deltaT;
velocityOffset[1] += accelRef[1] * deltaT;
velocityOffset[2] += accelRef[2] * deltaT;
if (bulletDatabase[index].ballisticCoefficients.size() == bulletDatabase[index].velocityBoundaries.size() + 1) { if (bulletDatabase[index].ballisticCoefficients.size() == bulletDatabase[index].velocityBoundaries.size() + 1) {
ballisticCoefficient = bulletDatabase[index].ballisticCoefficients[0]; ballisticCoefficient = bulletDatabase[index].ballisticCoefficients[0];
for (int i = (int)bulletDatabase[index].velocityBoundaries.size() - 1; i >= 0; i = i - 1) { for (int i = (int)bulletDatabase[index].velocityBoundaries.size() - 1; i >= 0; i = i - 1) {
if (trueSpeed < bulletDatabase[index].velocityBoundaries[i]) { if (trueVelocity.magnitude() < bulletDatabase[index].velocityBoundaries[i]) {
ballisticCoefficient = bulletDatabase[index].ballisticCoefficients[i + 1]; ballisticCoefficient = bulletDatabase[index].ballisticCoefficients[i + 1];
break; break;
} }
} }
ballisticCoefficient = calculateAtmosphericCorrection(ballisticCoefficient, temperature, pressure, bulletDatabase[index].humidity, bulletDatabase[index].atmosphereModel); ballisticCoefficient = calculateAtmosphericCorrection(ballisticCoefficient, temperature, pressure, bulletDatabase[index].humidity, bulletDatabase[index].atmosphereModel);
ballisticCoefficient *= bulletDatabase[index].bcDegradation;
drag = calculateRetard(bulletDatabase[index].dragModel, ballisticCoefficient, trueSpeed, SPEED_OF_SOUND(temperature)); drag = calculateRetard(bulletDatabase[index].dragModel, ballisticCoefficient, trueVelocity.magnitude(), SPEED_OF_SOUND(temperature));
} else { } else {
double airDensity = calculateAirDensity(temperature, pressure, bulletDatabase[index].humidity); double airDensity = calculateAirDensity(temperature, pressure, bulletDatabase[index].humidity);
double airFriction = bulletDatabase[index].airFriction * airDensity / STD_AIR_DENSITY_ICAO; double airFriction = bulletDatabase[index].airFriction * airDensity / STD_AIR_DENSITY_ICAO;
drag = -airFriction * trueSpeed * trueSpeed; drag = -airFriction * trueVelocity.magnitude_squared();
} }
accel[0] = (trueVelocity[0] / trueSpeed) * drag; ace::vector3<double> accel = trueVelocity.normalize() * drag;
accel[1] = (trueVelocity[1] / trueSpeed) * drag;
accel[2] = (trueVelocity[2] / trueSpeed) * drag;
velocityOffset[0] -= accel[0] * deltaT; velocityOffset -= accel * dt;
velocityOffset[1] -= accel[1] * deltaT; bulletVelocity -= accel * dt;
velocityOffset[2] -= accel[2] * deltaT;
if (TOF > 0) { if (TOF > 0) {
double bulletDir = atan2(bulletDatabase[index].bulletVelocity[0], bulletDatabase[index].bulletVelocity[1]); double bulletDir = atan2(bulletVelocity.x(), bulletVelocity.y());
double driftAccel = bulletDatabase[index].twistDirection * (0.0482251 * (bulletDatabase[index].stabilityFactor + 1.2)) / pow(TOF, 0.17); double driftAccel = bulletDatabase[index].twistDirection * (0.0482251 * (bulletDatabase[index].stabilityFactor + 1.2)) / pow(TOF, 0.17);
double driftVelocity = 0.0581025 *(bulletDatabase[index].stabilityFactor + 1.2) * pow(TOF, 0.83); double driftVelocity = 0.0581025 *(bulletDatabase[index].stabilityFactor + 1.2) * pow(TOF, 0.83);
double dragCorrection = (driftVelocity / trueSpeed) * drag * deltaT; double dragCorrection = (driftVelocity / trueVelocity.magnitude()) * drag;
velocityOffset[0] += sin(bulletDir + M_PI / 2) * (driftAccel * deltaT + dragCorrection); double magnitude = (driftAccel + dragCorrection) * dt;
velocityOffset[1] += cos(bulletDir + M_PI / 2) * (driftAccel * deltaT + dragCorrection); ace::vector3<double> offset(sin(bulletDir + M_PI / 2) * magnitude, cos(bulletDir + M_PI / 2) * magnitude, 0);
velocityOffset += offset;
bulletVelocity += offset;
} }
double lat = bulletDatabase[index].latitude; double lat = bulletDatabase[index].latitude;
accel[0] = 2 * EARTH_ANGULAR_SPEED * +(bulletDatabase[index].bulletVelocity[1] * sin(lat) - bulletDatabase[index].bulletVelocity[2] * cos(lat)); accel.x(2 * EARTH_ANGULAR_SPEED * +(bulletVelocity.y() * sin(lat) - bulletVelocity.z() * cos(lat)));
accel[1] = 2 * EARTH_ANGULAR_SPEED * -(bulletDatabase[index].bulletVelocity[0] * sin(lat)); accel.y(2 * EARTH_ANGULAR_SPEED * -(bulletVelocity.x() * sin(lat)));
accel[2] = 2 * EARTH_ANGULAR_SPEED * +(bulletDatabase[index].bulletVelocity[0] * cos(lat)); accel.z(2 * EARTH_ANGULAR_SPEED * +(bulletVelocity.x() * cos(lat)));
velocityOffset[0] += accel[0] * deltaT; velocityOffset += accel * dt;
velocityOffset[1] += accel[1] * deltaT; bulletVelocity += accel * dt + gravityAccel * dt;
velocityOffset[2] += accel[2] * deltaT;
bulletDatabase[index].bulletVelocity[0] = velocity[0] + velocityOffset[0]; TOF += dt;
bulletDatabase[index].bulletVelocity[1] = velocity[1] + velocityOffset[1]; time += dt;
bulletDatabase[index].bulletVelocity[2] = velocity[2] + velocityOffset[2]; }
outputStr << "[" << velocityOffset[0] << "," << velocityOffset[1] << "," << velocityOffset[2] << "]"; bulletDatabase[index].bulletVelocityPreviousFrame = bulletVelocityCurrentFrame + velocityOffset;
outputStr << "[" << velocityOffset.x() << "," << velocityOffset.y() << "," << velocityOffset.z() << "]";
strncpy_s(output, outputSize, outputStr.str().c_str(), _TRUNCATE); strncpy_s(output, outputSize, outputStr.str().c_str(), _TRUNCATE);
EXTENSION_RETURN(); EXTENSION_RETURN();
} else if (!strcmp(mode, "set")) { } else if (!strcmp(mode, "set")) {

View File

@ -61,7 +61,7 @@ double traceBullet(double initSpeed, double airFriction, double angle, double an
posX += velX * simulationStep * 0.5; posX += velX * simulationStep * 0.5;
posY += velY * simulationStep * 0.5; posY += velY * simulationStep * 0.5;
velX += simulationStep * (velX * velMag * airFriction); velX += simulationStep * (velX * velMag * airFriction);
velY += simulationStep * (velY * velMag * airFriction - 9.80665); velY += simulationStep * (velY * velMag * airFriction - 9.8066);
posX += velX * simulationStep * 0.5; posX += velX * simulationStep * 0.5;
posY += velY * simulationStep * 0.5; posY += velY * simulationStep * 0.5;
if (posX >= posTargetX) { break; } if (posX >= posTargetX) { break; }