ACE3/extensions/fcs/ace_fcs.cpp

126 lines
3.6 KiB
C++
Raw Normal View History

2015-01-16 23:09:19 +00:00
/*
* ace_fcs.cpp
*
* Calculates firing solution.
*
* Takes:
* initSpeed,airFriction,angle,distance as string
* Example: "900,-0.0004,2,1050"
*
* Returns:
* Correction to angle
*/
#include "ace_common.h"
2015-01-16 23:09:19 +00:00
#define _USE_MATH_DEFINES
#include <math.h>
#include <sstream>
#include <vector>
#include <string>
#define MAXELEVATION 20
#define MAXITERATIONS 600
2015-01-16 23:09:19 +00:00
#define PRECISION 0.1
#define RADIANS(X) (X / (180 / M_PI))
static char version[] = "1.0";
extern "C" {
__declspec (dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function);
};
std::vector<std::string> splitString(std::string input) {
std::istringstream ss(input);
std::string token;
std::vector<std::string> output;
while (std::getline(ss, token, ',')) {
output.push_back(token);
}
return output;
}
double traceBullet(double initSpeed, double airFriction, double angle, double angleTarget, double distance) {
double velX, velY, posX, posY, lastPosX, lastPosY, posTargetX, posTargetY, velMag;
2015-01-16 23:09:19 +00:00
velX = cos(RADIANS(angle)) * initSpeed;
velY = sin(RADIANS(angle)) * initSpeed;
posX = 0;
posY = 0;
posTargetX = cos(RADIANS(angleTarget)) * distance;
posTargetY = sin(RADIANS(angleTarget)) * distance;
double simulationStep = 0.05;
2015-01-16 23:09:19 +00:00
int i = 0;
while (i < MAXITERATIONS) {
lastPosX = posX;
lastPosY = posY;
2015-01-16 23:09:19 +00:00
velMag = sqrt(pow(velX, 2) + pow(velY, 2));
2015-04-06 21:43:32 +00:00
posX += velX * simulationStep * 0.5;
posY += velY * simulationStep * 0.5;
velX += simulationStep * (velX * velMag * airFriction);
2015-04-06 21:43:32 +00:00
velY += simulationStep * (velY * velMag * airFriction - 9.80665);
posX += velX * simulationStep * 0.5;
posY += velY * simulationStep * 0.5;
2015-01-16 23:09:19 +00:00
if (posX >= posTargetX) { break; }
i++;
}
double coef = (posTargetX - lastPosX) / (posX - lastPosX);
return (lastPosY + (posY - lastPosY) * coef) - posTargetY;
2015-01-16 23:09:19 +00:00
}
double getSolution(double initSpeed, double airFriction, double angleTarget, double distance) {
double posTargetX, posTargetY;
posTargetX = cos(RADIANS(angleTarget)) * distance;
posTargetY = sin(RADIANS(angleTarget)) * distance;
if (traceBullet(initSpeed, airFriction, MAXELEVATION, angleTarget, distance) < 0) {
return MAXELEVATION - angleTarget;
}
double a1 = angleTarget;
double a2 = MAXELEVATION;
double f1, f2, tmp;
f1 = traceBullet(initSpeed, airFriction, a1, angleTarget, distance);
if (fabs(f1) <= PRECISION) { return 0; }
while (fabs(f1) > PRECISION) {
f2 = traceBullet(initSpeed, airFriction, a2, angleTarget, distance);
tmp = a2 - f2 * (a2 - a1) / (f2 - f1);
a1 = a2;
a2 = tmp;
f1 = f2;
}
return a2 - angleTarget;
}
// i like to live dangerously. jk, fix strncpy sometime pls.
#pragma warning( push )
#pragma warning( disable : 4996 )
void __stdcall RVExtension(char *output, int outputSize, const char *function) {
if (!strcmp(function, "version")) {
strncpy(output, version, outputSize);
} else {
std::vector<std::string> argStrings = splitString(function);
double initSpeed = std::stod(argStrings[0]);
double airFriction = std::stod(argStrings[1]);
double angleTarget = std::stod(argStrings[2]);
double distance = std::stod(argStrings[3]);
double result = getSolution(initSpeed, airFriction, angleTarget, distance);
std::stringstream sstream;
sstream << result;
strcpy(output, sstream.str().c_str());
2015-01-16 23:09:19 +00:00
output[outputSize - 1] = '\0';
}
}
#pragma warning( pop )