Skip to content

Commit 91e21f4

Browse files
committed
feat: Add midpoint circle algorithm
1 parent 2a518e3 commit 91e21f4

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.thealgorithms.geometry;
2+
3+
import java.awt.Point;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
/**
8+
* The {@code MidpointCircle} class implements the Midpoint Circle algorithm,
9+
* which is an efficient way to determine the points of a circle
10+
* centered at a given point with a specified radius in a 2D space.
11+
*
12+
* <p>This algorithm uses integer arithmetic to calculate the points,
13+
* making it suitable for rasterization in computer graphics.</p>
14+
*/
15+
public final class MidpointCircle {
16+
17+
private MidpointCircle() {
18+
// Private constructor to prevent instantiation.
19+
}
20+
21+
/**
22+
* Finds the list of points that form a circle centered at (xc, yc)
23+
* with a given radius r.
24+
*
25+
* @param xc the x-coordinate of the center point
26+
* @param yc the y-coordinate of the center point
27+
* @param r the radius of the circle
28+
* @return a {@code List<Point>} containing all points on the circle
29+
*/
30+
public static List<Point> drawCircle(int xc, int yc, int r) {
31+
List<Point> circlePoints = new ArrayList<>();
32+
33+
int x = 0;
34+
int y = r;
35+
int p = 1 - r; // Initial decision parameter
36+
37+
// Function to add points based on symmetry
38+
addCirclePoints(circlePoints, xc, yc, x, y);
39+
40+
while (x < y) {
41+
x++;
42+
43+
// Update decision parameter
44+
if (p < 0) {
45+
p += 2 * x + 1; // Midpoint is inside the circle
46+
} else {
47+
y--; // Midpoint is outside the circle
48+
p += 2 * x - 2 * y + 1;
49+
}
50+
51+
// Add points based on symmetry
52+
addCirclePoints(circlePoints, xc, yc, x, y);
53+
}
54+
55+
return circlePoints; // Return the list of points forming the circle
56+
}
57+
58+
/**
59+
* Adds points to the list based on symmetry in all octants.
60+
*
61+
* @param points the list of points to add to
62+
* @param xc the x-coordinate of the center point
63+
* @param yc the y-coordinate of the center point
64+
* @param x current x coordinate in circle drawing
65+
* @param y current y coordinate in circle drawing
66+
*/
67+
private static void addCirclePoints(List<Point> points, int xc, int yc, int x, int y) {
68+
points.add(new Point(xc + x, yc + y));
69+
points.add(new Point(xc - x, yc + y));
70+
points.add(new Point(xc + x, yc - y));
71+
points.add(new Point(xc - x, yc - y));
72+
points.add(new Point(xc + y, yc + x));
73+
points.add(new Point(xc - y, yc + x));
74+
points.add(new Point(xc + y, yc - x));
75+
points.add(new Point(xc - y, yc - x));
76+
}
77+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.thealgorithms.geometry;
2+
3+
import java.awt.Point;
4+
import java.util.Collection;
5+
import java.util.List;
6+
import java.util.stream.Stream;
7+
import org.junit.jupiter.api.Assertions;
8+
import org.junit.jupiter.params.ParameterizedTest;
9+
import org.junit.jupiter.params.provider.Arguments;
10+
import org.junit.jupiter.params.provider.MethodSource;
11+
12+
/**
13+
* The {@code MidpointCircleTest} class contains unit tests for the
14+
* {@code MidpointCircle} class, specifically testing the
15+
* {@code drawCircle} method.
16+
*
17+
* <p>This class uses parameterized tests to validate the output of
18+
* the Midpoint Circle algorithm for various input parameters.</p>
19+
*/
20+
class MidpointCircleTest {
21+
22+
/**
23+
* Provides test cases for the parameterized test.
24+
*
25+
* <p>Each test case includes center coordinates, radius,
26+
* and the expected collection of points that should be generated by the
27+
* {@code drawCircle} method.</p>
28+
*
29+
* @return a stream of arguments containing test cases
30+
*/
31+
static Stream<Arguments> circlePointsProvider() {
32+
return Stream.of(
33+
Arguments.of(0, 0, 1, List.of(new Point(0, 1), new Point(1, 0), new Point(0, -1), new Point(-1, 0), new Point(1, 1), new Point(-1, -1), new Point(1, -1), new Point(-1, 1))),
34+
Arguments.of(0, 0, 2, List.of(new Point(0, 2), new Point(2, 0), new Point(0, -2), new Point(-2, 0), new Point(2, 2), new Point(-2, -2), new Point(2, -2), new Point(-2, 2))),
35+
Arguments.of(1, 1, 3, List.of(new Point(1, 4), new Point(4, 1), new Point(1, -2), new Point(-2, 1), new Point(4, 4), new Point(-2, -2), new Point(4, -2), new Point(-2, 4))),
36+
Arguments.of(-3, -3, 4, List.of(new Point(-3, 1), new Point(1, -3), new Point(-3, -7), new Point(-7, -3), new Point(1, 1), new Point(-7, -7), new Point(1, -7), new Point(-7, 1)))
37+
);
38+
}
39+
40+
/**
41+
* Tests the {@code drawCircle} method of the {@code MidpointCircle} class.
42+
*
43+
* <p>This parameterized test runs multiple times with different sets of
44+
* center coordinates and radii to validate that the generated points
45+
* match the expected output.</p>
46+
*
47+
* @param xc the x-coordinate of the center point
48+
* @param yc the y-coordinate of the center point
49+
* @param r the radius of the circle
50+
* @param expected a collection of expected points that should form a circle
51+
*/
52+
@ParameterizedTest
53+
@MethodSource("circlePointsProvider")
54+
void testDrawCircle(int xc, int yc, int r, Collection<Point> expected) {
55+
List<Point> actual = MidpointCircle.drawCircle(xc, yc, r);
56+
Assertions.assertEquals(expected.size(), actual.size(), "The size of the points list should match.");
57+
Assertions.assertTrue(expected.containsAll(actual) && actual.containsAll(expected), "The points generated should match the expected points.");
58+
}
59+
}

0 commit comments

Comments
 (0)