diff --git a/src/main/java/com/thealgorithms/geometry/MidpointCircle.java b/src/main/java/com/thealgorithms/geometry/MidpointCircle.java new file mode 100644 index 000000000000..803e8bb42b53 --- /dev/null +++ b/src/main/java/com/thealgorithms/geometry/MidpointCircle.java @@ -0,0 +1,85 @@ +package com.thealgorithms.geometry; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Class to represent the Midpoint Circle Algorithm. + * This algorithm calculates points on the circumference of a circle + * using integer arithmetic for efficient computation. + */ +public final class MidpointCircle { + + private MidpointCircle() { + // Private Constructor to prevent instantiation. + } + + /** + * Generates points on the circumference of a circle using the midpoint circle algorithm. + * + * @param centerX The x-coordinate of the circle's center. + * @param centerY The y-coordinate of the circle's center. + * @param radius The radius of the circle. + * @return A list of points on the circle, each represented as an int[] with 2 elements [x, y]. + */ + public static List generateCirclePoints(int centerX, int centerY, int radius) { + List points = new ArrayList<>(); + + // Special case for radius 0, only the center point should be added. + if (radius == 0) { + points.add(new int[] {centerX, centerY}); + return points; + } + + // Start at (radius, 0) + int x = radius; + int y = 0; + + // Decision parameter + int p = 1 - radius; + + // Add the initial points in all octants + addSymmetricPoints(points, centerX, centerY, x, y); + + // Iterate while x > y + while (x > y) { + y++; + + if (p <= 0) { + // Midpoint is inside or on the circle + p = p + 2 * y + 1; + } else { + // Midpoint is outside the circle + x--; + p = p + 2 * y - 2 * x + 1; + } + + // Add points for this (x, y) + addSymmetricPoints(points, centerX, centerY, x, y); + } + + return points; + } + + /** + * Adds the symmetric points in all octants of the circle based on the current x and y values. + * + * @param points The list to which symmetric points will be added. + * @param centerX The x-coordinate of the circle's center. + * @param centerY The y-coordinate of the circle's center. + * @param x The current x-coordinate on the circumference. + * @param y The current y-coordinate on the circumference. + */ + private static void addSymmetricPoints(Collection points, int centerX, int centerY, int x, int y) { + // Octant symmetry points + points.add(new int[] {centerX + x, centerY + y}); + points.add(new int[] {centerX - x, centerY + y}); + points.add(new int[] {centerX + x, centerY - y}); + points.add(new int[] {centerX - x, centerY - y}); + points.add(new int[] {centerX + y, centerY + x}); + points.add(new int[] {centerX - y, centerY + x}); + points.add(new int[] {centerX + y, centerY - x}); + points.add(new int[] {centerX - y, centerY - x}); + } +} diff --git a/src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java b/src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java new file mode 100644 index 000000000000..24370cd43b25 --- /dev/null +++ b/src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java @@ -0,0 +1,55 @@ +package com.thealgorithms.geometry; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/** + * Test class for the {@code MidpointCircle} class + */ +class MidpointCircleTest { + + /** + * Parameterized test to check the generated points for different circles. + * The points are checked based on the expected center and radius. + * + * @param centerX The x-coordinate of the circle's center. + * @param centerY The y-coordinate of the circle's center. + * @param radius The radius of the circle. + */ + @ParameterizedTest + @CsvSource({ + "0, 0, 3", // Circle centered at (0, 0) with radius 3 + "10, 10, 2" // Circle centered at (10, 10) with radius 2 + }) + void + testGenerateCirclePoints(int centerX, int centerY, int radius) { + List points = MidpointCircle.generateCirclePoints(centerX, centerY, radius); + + // Ensure that all points satisfy the circle equation (x - centerX)^2 + (y - centerY)^2 = radius^2 + for (int[] point : points) { + int x = point[0]; + int y = point[1]; + + int dx = x - centerX; + int dy = y - centerY; + int distanceSquared = dx * dx + dy * dy; + + assertTrue(Math.abs(distanceSquared - radius * radius) <= 1, "Point (" + x + ", " + y + ") does not satisfy the circle equation."); + } + } + + /** + * Test to ensure the algorithm generates points for a zero-radius circle. + */ + @Test + void testZeroRadiusCircle() { + List points = MidpointCircle.generateCirclePoints(0, 0, 0); + + // A zero-radius circle should only have one point: (0, 0) + assertTrue(points.size() == 1 && points.get(0)[0] == 0 && points.get(0)[1] == 0, "Zero-radius circle did not generate the correct point."); + } +}