diff --git a/src/main/java/com/github/creme332/algorithms/CircleAlgorithm.java b/src/main/java/com/github/creme332/algorithms/CircleAlgorithm.java new file mode 100644 index 00000000..b277fcc0 --- /dev/null +++ b/src/main/java/com/github/creme332/algorithms/CircleAlgorithm.java @@ -0,0 +1,69 @@ +package com.github.creme332.algorithms; + +import java.util.ArrayList; +import java.util.List; + +public class CircleAlgorithm { + + private CircleAlgorithm() { + + } + + public static int[][] drawCircle(int centerX, int centerY, int radius) { + if (radius <= 0) { + throw new IllegalArgumentException("Radius must be positive"); + } + + List pixelList = new ArrayList<>(); + + int x = 0; + int y = radius; + int decisionParameter = 1 - radius; + + while (x <= y) { + plotCirclePoints(pixelList, centerX, centerY, x, y); + x++; + + if (decisionParameter < 0) { + decisionParameter += 2 * x + 1; + } else { + y--; + decisionParameter += 2 * (x - y) + 1; + } + } + + return pixelList.toArray(new int[pixelList.size()][]); + } + + private static void plotCirclePoints(List pixelList, int centerX, int centerY, int x, int y) { + if (x == 0) { + addUniquePixel(pixelList, centerX + x, centerY + y); + addUniquePixel(pixelList, centerX + y, centerY + x); + addUniquePixel(pixelList, centerX + x, centerY - y); + addUniquePixel(pixelList, centerX - y, centerY + x); + return; + } + + if (x == y) { + addUniquePixel(pixelList, centerX + x, centerY + y); + addUniquePixel(pixelList, centerX - x, centerY + y); + addUniquePixel(pixelList, centerX + x, centerY - y); + addUniquePixel(pixelList, centerX - x, centerY - y); + return; + } + + addUniquePixel(pixelList, centerX + x, centerY + y); + addUniquePixel(pixelList, centerX - x, centerY + y); + addUniquePixel(pixelList, centerX + x, centerY - y); + addUniquePixel(pixelList, centerX - x, centerY - y); + + addUniquePixel(pixelList, centerX + y, centerY + x); + addUniquePixel(pixelList, centerX - y, centerY + x); + addUniquePixel(pixelList, centerX + y, centerY - x); + addUniquePixel(pixelList, centerX - y, centerY - x); + } + + private static void addUniquePixel(List pixelList, int x, int y) { + pixelList.add(new int[] { x, y }); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/creme332/tests/algorithms/CircleAlgorithmTest.java b/src/test/java/com/github/creme332/tests/algorithms/CircleAlgorithmTest.java new file mode 100644 index 00000000..39e4b4d2 --- /dev/null +++ b/src/test/java/com/github/creme332/tests/algorithms/CircleAlgorithmTest.java @@ -0,0 +1,95 @@ +package com.github.creme332.tests.algorithms; + +import org.junit.Test; +import com.github.creme332.algorithms.CircleAlgorithm; +import com.github.creme332.tests.utils.TestHelper; + +import static org.junit.Assert.*; + +public class CircleAlgorithmTest { + + @Test + public void testValidCircleCenteredOrigin() { + int centerX = 0; + int centerY = 0; + int radius = 10; + int[][] actualPixels = CircleAlgorithm.drawCircle(centerX, centerY, radius); + + int[][] expectedPixels = { + // Octant 1: (x, y) + { 0, 10 }, { 1, 10 }, { 2, 10 }, { 3, 10 }, { 4, 9 }, { 5, 9 }, { 6, 8 }, { 7, 7 }, + // Octant 2: (y, x) + { 10, 0 }, { 10, 1 }, { 10, 2 }, { 10, 3 }, { 9, 4 }, { 9, 5 }, { 8, 6 }, + // Octant 3: (y, -x) + { 10, -1 }, { 10, -2 }, { 10, -3 }, { 9, -4 }, { 9, -5 }, { 8, -6 }, { 7, -7 }, + // Octant 4: (x, -y) + { 0, -10 }, { 1, -10 }, { 2, -10 }, { 3, -10 }, { 4, -9 }, { 5, -9 }, { 6, -8 }, + // Octant 5: (-x, -y) + { -1, -10 }, { -2, -10 }, { -3, -10 }, { -4, -9 }, { -5, -9 }, { -6, -8 }, { -7, -7 }, + // Octant 6: (-y, -x) + { -10, 0 }, { -10, -1 }, { -10, -2 }, { -10, -3 }, { -9, -4 }, { -9, -5 }, { -8, -6 }, + // Octant 7: (-y, x) + { -10, 1 }, { -10, 2 }, { -10, 3 }, { -9, 4 }, { -9, 5 }, { -8, 6 }, { -7, 7 }, + // Octant 8: (-x, y) + { -1, 10 }, { -2, 10 }, { -3, 10 }, { -4, 9 }, { -5, 9 }, { -6, 8 }, + }; + + // Using the helper method for assertion + TestHelper.assert2DArrayEquals(expectedPixels, actualPixels); + } + + @Test + public void testZeroRadiusCenteredOrigin() { + int centerX = 0; + int centerY = 0; + int radius = 0; + + try { + CircleAlgorithm.drawCircle(centerX, centerY, radius); + fail("Expected IllegalArgumentException for zero radii"); + } catch (IllegalArgumentException e) { + assertEquals("Radius must be positive", e.getMessage()); + } + } + + @Test + public void testNegativeRadiusCenteredOrigin() { + int centerX = 0; + int centerY = 0; + int radius = -5; + try { + CircleAlgorithm.drawCircle(centerX, centerY, radius); + fail("Expected IllegalArgumentException for negative radii"); + } catch (IllegalArgumentException e) { + assertEquals("Radius must be positive", e.getMessage()); + } + } + + @Test + public void testCircleCenteredOriginRadiusOne() { + int centerX = 0; + int centerY = 0; + int radius = 1; + int[][] actualPixels = CircleAlgorithm.drawCircle(centerX, centerY, radius); + + int[][] expectedPixels = { + { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } + }; + + TestHelper.assert2DArrayEquals(expectedPixels, actualPixels); + } + + @Test + public void testCircleNotCenteredOriginRadiusOne() { + int centerX = 5; + int centerY = 5; + int radius = 1; + int[][] actualPixels = CircleAlgorithm.drawCircle(centerX, centerY, radius); + + int[][] expectedPixels = { + { 6, 5 }, { 4, 5 }, { 5, 6 }, { 5, 4 } + }; + + TestHelper.assert2DArrayEquals(expectedPixels, actualPixels); + } +} diff --git a/src/test/java/com/github/creme332/tests/algorithms/EllipseAlgorithmTest.java b/src/test/java/com/github/creme332/tests/algorithms/EllipseAlgorithmTest.java index 9cceb404..89b81f75 100644 --- a/src/test/java/com/github/creme332/tests/algorithms/EllipseAlgorithmTest.java +++ b/src/test/java/com/github/creme332/tests/algorithms/EllipseAlgorithmTest.java @@ -2,6 +2,7 @@ import org.junit.Test; import static org.junit.Assert.*; + import com.github.creme332.algorithms.EllipseAlgorithm; import com.github.creme332.tests.utils.TestHelper; @@ -111,5 +112,4 @@ public void testVerticalEllipseAtOrigin() { TestHelper.assert2DArrayEquals(expectedArray, pixels.toArray(new int[pixels.size()][])); } - }