-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
ground_to_ground_projectile_motion.cpp
141 lines (127 loc) · 5.55 KB
/
ground_to_ground_projectile_motion.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/**
* @file
* @brief Ground to ground [projectile
* motion](https://en.wikipedia.org/wiki/Projectile_motion) equation
* implementations
* @details Ground to ground projectile motion is when a projectile's trajectory
* starts at the ground, reaches the apex, then falls back on the ground.
*
* @author [Focusucof](https://github.com/Focusucof)
*/
#include <cassert> /// for assert()
#define _USE_MATH_DEFINES
#include <cmath> /// for std::pow(), std::sin(), and std::cos()
#include <iostream> /// for IO operations
/**
* @namespace physics
* @brief Physics algorithms
*/
namespace physics {
/**
* @namespace ground_to_ground_projectile_motion
* @brief Functions for the Ground to ground [projectile
* motion](https://en.wikipedia.org/wiki/Projectile_motion) equation
*/
namespace ground_to_ground_projectile_motion {
/**
* @brief Convert radians to degrees
* @param radian Angle in radians
* @returns Angle in degrees
*/
double degrees_to_radians(double degrees){
double radians = degrees * (M_PI / 180);
return radians;
}
/**
* @brief Calculate the time of flight
* @param initial_velocity The starting velocity of the projectile
* @param angle The angle that the projectile is launched at in degrees
* @param gravity The value used for the gravity constant
* @returns The time that the projectile is in the air for
*/
template <typename T>
T time_of_flight(T initial_velocity, T angle, double gravity = 9.81) {
double Viy = initial_velocity * (std::sin(degrees_to_radians(angle))); // calculate y component of the initial velocity
return 2.0 * Viy / gravity;
}
/**
* @brief Calculate the horizontal distance that the projectile travels
* @param initial_velocity The starting velocity of the projectile
* @param time The time that the projectile is in the air
* @returns Horizontal distance that the projectile travels
*/
template <typename T>
T horizontal_range(T initial_velocity, T angle, T time) {
double Vix = initial_velocity * (std::cos(degrees_to_radians(angle))); // calculate x component of the initial velocity
return Vix * time;
}
/**
* @brief Calculate the max height of the projectile
* @param initial_velocity The starting velocity of the projectile
* @param angle The angle that the projectile is launched at in degrees
* @param gravity The value used for the gravity constant
* @returns The max height that the projectile reaches
*/
template <typename T>
T max_height(T initial_velocity, T angle, double gravity = 9.81) {
double Viy = initial_velocity * (std::sin(degrees_to_radians(angle))); // calculate y component of the initial velocity
return (std::pow(Viy, 2) / (2.0 * gravity));
}
} // namespace ground_to_ground_projectile_motion
} // namespace physics
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
// initial input variables
double initial_velocity = 5.0; // double initial_velocity input
double angle = 40.0; // double angle input
// 1st test
double expected_time_of_flight = 0.655; // expected time output
double flight_time_output =
std::round(physics::ground_to_ground_projectile_motion::time_of_flight(initial_velocity, angle) * 1000.0) /
1000.0; // round output to 3 decimal places
std::cout << "Projectile Flight Time (double)" << std::endl;
std::cout << "Input Initial Velocity: " << initial_velocity << std::endl;
std::cout << "Input Angle: " << angle << std::endl;
std::cout << "Expected Output: " << expected_time_of_flight << std::endl;
std::cout << "Output: " << flight_time_output << std::endl;
assert(flight_time_output == expected_time_of_flight);
std::cout << "TEST PASSED" << std::endl << std::endl;
// 2nd test
double expected_horizontal_range = 2.51; // expected range output
double horizontal_range_output =
std::round(physics::ground_to_ground_projectile_motion::horizontal_range(initial_velocity, angle,
flight_time_output) *
100.0) /
100.0; // round output to 2 decimal places
std::cout << "Projectile Horizontal Range (double)" << std::endl;
std::cout << "Input Initial Velocity: " << initial_velocity << std::endl;
std::cout << "Input Angle: " << angle << std::endl;
std::cout << "Input Time Of Flight: " << flight_time_output << std::endl;
std::cout << "Expected Output: " << expected_horizontal_range << std::endl;
std::cout << "Output: " << horizontal_range_output << std::endl;
assert(horizontal_range_output == expected_horizontal_range);
std::cout << "TEST PASSED" << std::endl << std::endl;
// 3rd test
double expected_max_height = 0.526; // expected height output
double max_height_output =
std::round(physics::ground_to_ground_projectile_motion::max_height(initial_velocity, angle) * 1000.0) /
1000.0; // round output to 3 decimal places
std::cout << "Projectile Max Height (double)" << std::endl;
std::cout << "Input Initial Velocity: " << initial_velocity << std::endl;
std::cout << "Input Angle: " << angle << std::endl;
std::cout << "Expected Output: " << expected_max_height << std::endl;
std::cout << "Output: " << max_height_output << std::endl;
assert(max_height_output == expected_max_height);
std::cout << "TEST PASSED" << std::endl << std::endl;
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementations
return 0;
}