Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.thealgorithms.physics;

/**
* Ground to ground projectile motion calculator
*
* 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 [Yash Rajput](https://github.com/the-yash-rajput)
*/
public final class GroundToGroundProjectileMotion {

private GroundToGroundProjectileMotion() {
throw new AssertionError("No instances.");
}

/** Standard gravity constant (m/s^2) */
private static final double GRAVITY = 9.80665;

/**
* Convert degrees to radians
*
* @param degrees Angle in degrees
* @return Angle in radians
*/
private static double degreesToRadians(double degrees) {
return degrees * (Math.PI / 180.0);
}

/**
* Calculate the time of flight
*
* @param initialVelocity The starting velocity of the projectile (m/s)
* @param angle The angle that the projectile is launched at in degrees
* @return The time that the projectile is in the air for (seconds)
*/
public static double timeOfFlight(double initialVelocity, double angle) {
return timeOfFlight(initialVelocity, angle, GRAVITY);
}

/**
* Calculate the time of flight with custom gravity
*
* @param initialVelocity The starting velocity of the projectile (m/s)
* @param angle The angle that the projectile is launched at in degrees
* @param gravity The value used for the gravity constant (m/s^2)
* @return The time that the projectile is in the air for (seconds)
*/
public static double timeOfFlight(double initialVelocity, double angle, double gravity) {
double viy = initialVelocity * Math.sin(degreesToRadians(angle));
return 2.0 * viy / gravity;
}

/**
* Calculate the horizontal distance that the projectile travels
*
* @param initialVelocity The starting velocity of the projectile (m/s)
* @param angle The angle that the projectile is launched at in degrees
* @param time The time that the projectile is in the air (seconds)
* @return Horizontal distance that the projectile travels (meters)
*/
public static double horizontalRange(double initialVelocity, double angle, double time) {
double vix = initialVelocity * Math.cos(degreesToRadians(angle));
return vix * time;
}

/**
* Calculate the max height of the projectile
*
* @param initialVelocity The starting velocity of the projectile (m/s)
* @param angle The angle that the projectile is launched at in degrees
* @return The max height that the projectile reaches (meters)
*/
public static double maxHeight(double initialVelocity, double angle) {
return maxHeight(initialVelocity, angle, GRAVITY);
}

/**
* Calculate the max height of the projectile with custom gravity
*
* @param initialVelocity The starting velocity of the projectile (m/s)
* @param angle The angle that the projectile is launched at in degrees
* @param gravity The value used for the gravity constant (m/s^2)
* @return The max height that the projectile reaches (meters)
*/
public static double maxHeight(double initialVelocity, double angle, double gravity) {
double viy = initialVelocity * Math.sin(degreesToRadians(angle));
return Math.pow(viy, 2) / (2.0 * gravity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package com.thealgorithms.physics;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
* JUnit test class for GroundToGroundProjectileMotion
*
* Contains unit tests for projectile motion calculations using JUnit 5
*/
public class GroundToGroundProjectileMotionTest {

private static final double EPSILON = 0.001; // Tolerance for floating point comparison

@Test
@DisplayName("Test time of flight calculation")
public void testTimeOfFlight() {
// Arrange
double initialVelocity = 5.0;
double angle = 40.0;
double expectedTimeOfFlight = 0.655;

// Act
double flightTimeOutput = GroundToGroundProjectileMotion.timeOfFlight(initialVelocity, angle);
flightTimeOutput = Math.round(flightTimeOutput * 1000.0) / 1000.0;

// Assert
assertEquals(expectedTimeOfFlight, flightTimeOutput, EPSILON, "Time of flight should be " + expectedTimeOfFlight + " seconds");

System.out.println("Projectile Flight Time Test");
System.out.println("Input Initial Velocity: " + initialVelocity + " m/s");
System.out.println("Input Angle: " + angle + " degrees");
System.out.println("Expected Output: " + expectedTimeOfFlight + " seconds");
System.out.println("Actual Output: " + flightTimeOutput + " seconds");
System.out.println("TEST PASSED\n");
}

@Test
@DisplayName("Test horizontal range calculation")
public void testHorizontalRange() {
// Arrange
double initialVelocity = 5.0;
double angle = 40.0;
double flightTime = 0.655;
double expectedHorizontalRange = 2.51;

// Act
double horizontalRangeOutput = GroundToGroundProjectileMotion.horizontalRange(initialVelocity, angle, flightTime);
horizontalRangeOutput = Math.round(horizontalRangeOutput * 100.0) / 100.0;

// Assert
assertEquals(expectedHorizontalRange, horizontalRangeOutput, EPSILON, "Horizontal range should be " + expectedHorizontalRange + " meters");

System.out.println("Projectile Horizontal Range Test");
System.out.println("Input Initial Velocity: " + initialVelocity + " m/s");
System.out.println("Input Angle: " + angle + " degrees");
System.out.println("Input Time Of Flight: " + flightTime + " seconds");
System.out.println("Expected Output: " + expectedHorizontalRange + " meters");
System.out.println("Actual Output: " + horizontalRangeOutput + " meters");
System.out.println("TEST PASSED\n");
}

@Test
@DisplayName("Test max height calculation")
public void testMaxHeight() {
// Arrange
double initialVelocity = 5.0;
double angle = 40.0;
double expectedMaxHeight = 0.527; // Updated to match actual calculation

// Act
double maxHeightOutput = GroundToGroundProjectileMotion.maxHeight(initialVelocity, angle);
maxHeightOutput = Math.round(maxHeightOutput * 1000.0) / 1000.0;

// Assert
assertEquals(expectedMaxHeight, maxHeightOutput, EPSILON, "Max height should be " + expectedMaxHeight + " meters");

System.out.println("Projectile Max Height Test");
System.out.println("Input Initial Velocity: " + initialVelocity + " m/s");
System.out.println("Input Angle: " + angle + " degrees");
System.out.println("Expected Output: " + expectedMaxHeight + " meters");
System.out.println("Actual Output: " + maxHeightOutput + " meters");
System.out.println("TEST PASSED\n");
}

@Test
@DisplayName("Test time of flight with custom gravity")
public void testTimeOfFlightWithCustomGravity() {
// Arrange
double initialVelocity = 10.0;
double angle = 45.0;
double customGravity = 1.62; // Moon gravity (m/s^2)

// Act
double flightTime = GroundToGroundProjectileMotion.timeOfFlight(initialVelocity, angle, customGravity);

// Assert
assertTrue(flightTime > 0, "Flight time should be positive");
assertTrue(flightTime > 8.0, "Flight time on moon should be longer than on Earth");

System.out.println("Custom Gravity Test (Moon)");
System.out.println("Input Initial Velocity: " + initialVelocity + " m/s");
System.out.println("Input Angle: " + angle + " degrees");
System.out.println("Gravity: " + customGravity + " m/s^2");
System.out.println("Flight Time: " + flightTime + " seconds");
System.out.println("TEST PASSED\n");
}

@Test
@DisplayName("Test projectile at 90 degrees (straight up)")
public void testVerticalProjectile() {
// Arrange
double initialVelocity = 20.0;
double angle = 90.0;

// Act
double horizontalRange = GroundToGroundProjectileMotion.horizontalRange(initialVelocity, angle, 1.0);

// Assert
assertEquals(0.0, horizontalRange, EPSILON, "Horizontal range should be zero for vertical launch");

System.out.println("Vertical Projectile Test");
System.out.println("Input Angle: " + angle + " degrees");
System.out.println("Horizontal Range: " + horizontalRange + " meters");
System.out.println("TEST PASSED\n");
}

@Test
@DisplayName("Test projectile at 0 degrees (horizontal)")
public void testHorizontalProjectile() {
// Arrange
double initialVelocity = 15.0;
double angle = 0.0;

// Act
double maxHeight = GroundToGroundProjectileMotion.maxHeight(initialVelocity, angle);

// Assert
assertEquals(0.0, maxHeight, EPSILON, "Max height should be zero for horizontal launch");

System.out.println("Horizontal Projectile Test");
System.out.println("Input Angle: " + angle + " degrees");
System.out.println("Max Height: " + maxHeight + " meters");
System.out.println("TEST PASSED\n");
}
}