// https://phys.libretexts.org/Bookshelves/University_Physics/Physics_(Boundless)/3%3A_Two-Dimensional_Kinematics/3.3%3A_Projectile_Motion
#pragma once
class ClassicalBallistics
{
public:
ClassicalBallistics(void);
~ClassicalBallistics(void);
// analytical formula for maximum height
double H(double V0, double theta0, double g);
// analytical formula for flight time
double T(double H, double g);
// analytical formula for velocity at apex
double Va(double V0, double theta0);
// analytical formula for the range
double L(double Va, double T);
// analytical formula for time to apex
double ta(double T);
// analytical formula for range to apex
double xa(double L);
double xa(double H, double L, double theta0);
double Theta1(double theta0);
double Theta1(double H, double L, double xa);
double ClassicalBallistics::V1(double V0);
};
#include "StdAfx.h"
#include "ClassicalBallistics.h"
#include <math.h>
ClassicalBallistics::ClassicalBallistics(void)
{
}
ClassicalBallistics::~ClassicalBallistics(void)
{
}
// analytical formula for maximum height
double ClassicalBallistics::H(double V0, double theta0, double g)
{
double V02 = V0 * V0, sinTheta0 = sin(theta0);
double sinTheta02 = sinTheta0 * sinTheta0;
return V02 * sinTheta02 / (g * 2.0);
}
// analytical formula for flight time
double ClassicalBallistics::T(double H, double g)
{
return 2.0 * sqrt(2.0 * H / g);
}
// analytical formula for velocity at apex
double ClassicalBallistics::Va(double V0, double theta0)
{
double cosTheta0 = cos(theta0);
double V02 = V0 * V0;
return V0 * cosTheta0;
}
// analytical formula for the range
double ClassicalBallistics::L(double Va, double T)
{
return Va * T;
}
// analytical formula for time to apex
double ClassicalBallistics::ta(double T)
{
return 0.5 * T;
}
// analytical formula for range to apex
double ClassicalBallistics::xa(double L)
{
return 0.5 * L;
}
double ClassicalBallistics::xa(double H, double L, double theta0)
{
return sqrt(L * H / tan(theta0));
}
double ClassicalBallistics::Theta1(double theta0)
{
return -theta0;
}
double ClassicalBallistics::Theta1(double H, double L, double xa)
{
return atan(L * H / pow(L - xa, 2.0));
}
double ClassicalBallistics::V1(double V0)
{
return V0;
}
// http://www.lajpe.org/sep13/04-LAJPE-782_Chudinov.pdf
#pragma once
const double g = 9.81;
// accleration due to gravity in Metric (SI) Units
const double k = 0.000625;
// k is typical for a baseball
class DragBallistics
{
public:
DragBallistics(void);
~DragBallistics(void);
double f(double theta);
// analytical formula for maximum height
double H(double V0, double theta0, double g, double k);
// analytical formula for flight time
double T(double H, double g);
// analytical formula for velocity at apex
double Va(double V0, double theta0, double k);
// analytical formula for the range
double L(double Va, double T);
double ta(double H, double T, double Va, double k);
double xa(double H, double L, double theta0);
double Theta1(double H, double L, double xa);
double V1(double V0, double theta0, double theta1, double k);
};
#include "StdAfx.h"
#include "DragBallistics.h"
#include <math.h>
DragBallistics::DragBallistics(void)
{
}
DragBallistics::~DragBallistics(void)
{
}
double DragBallistics::f(double theta)
{
double pi = 4.0 * atan(1.0);
double sinTheta = sin(theta), cosTheta = cos(theta),
cosTheta2 = cosTheta * cosTheta;
return (sinTheta / cosTheta2) + log(tan(0.5 * theta + pi / 4.0));
}
// analytical formula for maximum height
double DragBallistics::H(double V0, double theta0, double g, double k)
{
double V02 = V0 * V0, sinTheta0 = sin(theta0),
sinTheta02 = sinTheta0 * sinTheta0;
return V02 * sinTheta02 / (g * (2.0 + k * V02 * sinTheta0));
}
// analytical formula for flight time
double DragBallistics::T(double H, double g)
{
return 2.0 * sqrt(2.0 * H / g);
}
// analytical formula for velocity at apex
double DragBallistics::Va(double V0, double theta0, double k)
{
double pi = 4.0 * atan(1.0);
double cosTheta0 = cos(theta0), cosTheta02 = cosTheta0 * cosTheta0;
double V02 = V0 * V0, sinTheta0 = sin(theta0);
return V0 * cosTheta0 / sqrt(1.0 + k * V02 * (sinTheta0 +
cosTheta02 * log(tan(0.5 * theta0 + pi / 4.0))));
}
// analytical formula for the range
double DragBallistics::L(double Va, double T)
{
return Va * T;
}
double DragBallistics::ta(double H, double T, double Va, double k)
{
return 0.5 * (T - k * H * Va);
}
double DragBallistics::xa(double H, double L, double theta0)
{
return sqrt(L * H / tan(theta0));
}
double DragBallistics::Theta1(double H, double L, double xa)
{
return -atan(L * H / pow(L - xa, 2.0));
}
double DragBallistics::V1(double V0, double theta0, double theta1, double k)
{
double V02 = V0 * V0;
double sinTheta0 = sin(theta0), cosTheta0 = cos(theta0),
cosTheta02 = cosTheta0 * cosTheta0;
return V0 * cosTheta0 / (cos(theta1) * sqrt(1.0 + k *
V02 * cosTheta02 * (f(theta0) - f(theta1))));
}
// BaseballBallisticsWin32Console.cpp
// Translated from August 2017 C# application
// May 21, 2025 (c) James Pate Williams, Jr.
#include "stdafx.h"
#include "ClassicalBallistics.h"
#include "DragBallistics.h"
#include <iomanip>
#include <iostream>
#include <math.h>
void PrintResults(char title[],
double H, double T, double Va,
double L, double Ta, double xa,
double Theta1, double V1)
{
std::cout << title << std::endl;
std::cout << std::fixed << std::setprecision(2);
std::cout << "H = " << H << std::endl;
std::cout << "T = " << T << std::endl;
std::cout << "Va = " << Va << std::endl;
std::cout << "L = " << L << std::endl;
std::cout << "Ta = " << Ta << std::endl;
std::cout << "xa = " << xa << std::endl;
std::cout << "theta1 = " << Theta1 << std::endl;
std::cout << "V1 = " << V1 << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
while (true)
{
char line[128] = { };
std::cout << "V0 (m / s) or 0 to quit: ";
std::cin.getline(line, 128);
double V0 = atof(line);
if (V0 == 0)
{
break;
}
std::cout << "Enter angle in degrees: ";
std::cin.getline(line, 128);
double theta0 = atof(line);
double pi = 4.0 * atan(1.0);
theta0 *= pi / 180.0;
ClassicalBallistics cBall;
DragBallistics dBall;
double cH = cBall.H(V0, theta0, g);
double dH = dBall.H(V0, theta0, g, k);
double cT = cBall.T(cH, g);
double dT = dBall.T(dH, g);
double cVa = cBall.Va(V0, theta0);
double dVa = dBall.Va(V0, theta0, k);
double cL = cBall.L(cVa, cT);
double dL = dBall.L(dVa, dT);
double cta = cBall.ta(cT);
double dta = dBall.ta(dH, dT, dVa, k);
double cxa = cBall.xa(cL);
double dxa = dBall.xa(dH, dL, theta0);
double cTheta1 = 180.0 * cBall.Theta1(theta0) / pi;
double dTheta1 = 180.0 * dBall.Theta1(dH, dL, dxa) / pi;
double cV1 = cBall.V1(V0);
double dV1 = dBall.V1(V0, theta0, pi * dTheta1 / 180.0, k);
PrintResults("Classical Ballistics",
cH, cT, cVa, cL, cta, cxa, cTheta1, cV1);
PrintResults("Drag Ballistics",
dH, dT, dVa, dL, dta, dxa, dTheta1, dV1);
}
return 0;
}