Skip to content

feat: Add midpoint circle algorithm #5868

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 26, 2024
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
85 changes: 85 additions & 0 deletions src/main/java/com/thealgorithms/geometry/MidpointCircle.java
Original file line number Diff line number Diff line change
@@ -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<int[]> generateCirclePoints(int centerX, int centerY, int radius) {
List<int[]> 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<int[]> 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});
}
}
Original file line number Diff line number Diff line change
@@ -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<int[]> 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<int[]> 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.");
}
}