-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from Divyesh000/ellipse
implementation of midpoint ellipse algorithm and tests for the algorithm
- Loading branch information
Showing
2 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
103 changes: 103 additions & 0 deletions
103
src/main/java/com/github/creme332/algorithms/EllipseAlgorithm.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package com.github.creme332.algorithms; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class EllipseAlgorithm { | ||
|
||
private EllipseAlgorithm() { | ||
|
||
} | ||
|
||
/** | ||
* This method calculates the pixel coordinates of an ellipse using the Midpoint | ||
* Ellipse Algorithm. | ||
* | ||
* @param centerX X-coordinate of the ellipse's center | ||
* @param centerY Y-coordinate of the ellipse's center | ||
* @param rx Radius of the ellipse along the X-axis (horizontal radius) | ||
* @param ry Radius of the ellipse along the Y-axis (vertical radius) | ||
* @return A list of integer arrays representing the x-y coordinates of each | ||
* pixel of the ellipse | ||
* @throws IllegalArgumentException if rx or ry are non-positive | ||
*/ | ||
public static List<int[]> drawEllipse(int centerX, int centerY, int rx, int ry) { | ||
if (rx <= 0 || ry <= 0) { | ||
throw new IllegalArgumentException("Radii must be positive values."); | ||
} | ||
|
||
List<int[]> pixels = new ArrayList<>(); | ||
|
||
int x = 0; | ||
int y = ry; | ||
|
||
int rx2 = rx * rx; | ||
int ry2 = ry * ry; | ||
int tworx2 = 2 * rx2; | ||
int twory2 = 2 * ry2; | ||
|
||
int p = (int) (ry2 - (rx2 * ry) + (0.25 * rx2)); // Initial decision parameter | ||
|
||
int px = 0; | ||
int py = tworx2 * y; | ||
|
||
// Region 1 | ||
while (px < py) { | ||
addPixels(pixels, centerX, centerY, x, y); | ||
x++; | ||
px += twory2; | ||
if (p < 0) { | ||
p += ry2 + px; | ||
} else { | ||
y--; | ||
py -= tworx2; | ||
p += ry2 + px - py; | ||
} | ||
} | ||
|
||
// Region 2 | ||
p = (int) (ry2 * (x + 0.5) * (x + 0.5) + rx2 * (y - 1) * (y - 1) - rx2 * ry2); | ||
while (y >= 0) { | ||
addPixels(pixels, centerX, centerY, x, y); | ||
y--; | ||
py -= tworx2; | ||
if (p > 0) { | ||
p += rx2 - py; | ||
} else { | ||
x++; | ||
px += twory2; | ||
p += rx2 - py + px; | ||
} | ||
} | ||
return pixels; | ||
} | ||
|
||
private static void addPixels(List<int[]> pixels, int centerX, int centerY, int x, int y) { | ||
|
||
// when x = 0, (-x, y)= (x, y) and (-x, -y) = (x, -y) | ||
// plot only pixels in 2 quadrants | ||
if (x == 0) { | ||
addPixel(pixels, centerX + x, centerY + y); | ||
addPixel(pixels, centerX + x, centerY - y); | ||
return; | ||
} | ||
|
||
// when y = 0, (x, -y)= (x, y) and (-x, y) = (-x, y) | ||
// plot only pixels in 2 quadrants | ||
if (y == 0) { | ||
addPixel(pixels, centerX + x, centerY + y); | ||
addPixel(pixels, centerX - x, centerY + y); | ||
return; | ||
} | ||
|
||
// else plot a pixel in each quadrant | ||
addPixel(pixels, centerX + x, centerY + y); | ||
addPixel(pixels, centerX + x, centerY - y); | ||
addPixel(pixels, centerX - x, centerY + y); | ||
addPixel(pixels, centerX - x, centerY - y); | ||
} | ||
|
||
private static void addPixel(List<int[]> pixels, int x, int y) { | ||
pixels.add(new int[] { x, y }); | ||
} | ||
} |
115 changes: 115 additions & 0 deletions
115
src/test/java/com/github/creme332/tests/algorithms/EllipseAlgorithmTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package com.github.creme332.tests.algorithms; | ||
|
||
import org.junit.Test; | ||
import static org.junit.Assert.*; | ||
import com.github.creme332.algorithms.EllipseAlgorithm; | ||
import com.github.creme332.tests.utils.TestHelper; | ||
|
||
import java.util.List; | ||
|
||
public class EllipseAlgorithmTest { | ||
|
||
@Test | ||
public void testEllipseCenteredAtOrigin() { | ||
List<int[]> pixels = EllipseAlgorithm.drawEllipse(0, 0, 3, 2); | ||
|
||
int[][] expectedArray = { | ||
// Quadrant 1 | ||
{ 0, 2 }, { 1, 2 }, { 2, 1 }, | ||
// Quadrant 2 | ||
{ 3, 0 }, { 2, -1 }, { 1, -2 }, | ||
// Quadrant 3 | ||
{ 0, -2 }, { -1, -2 }, { -2, -1 }, | ||
// Quadrant 4 | ||
{ -3, 0 }, { -2, 1 }, { -1, 2 } | ||
}; | ||
|
||
TestHelper.assert2DArrayEquals(expectedArray, pixels.toArray(new int[pixels.size()][])); | ||
} | ||
|
||
@Test | ||
public void testEllipseNotAtOrigin() { | ||
int centerX = 5; | ||
int centerY = 7; | ||
|
||
// coordinates if ellipse with rx = 8 and ry = 6 was centered at origin | ||
int[][] expectedArray = { | ||
// Quadrant 1 | ||
{ 0, 6 }, { 1, 6 }, { 2, 6 }, { 3, 6 }, { 4, 5 }, { 5, 5 }, { 6, 4 }, { 7, 3 }, { 8, 2 }, { 8, 1 }, | ||
{ 8, 0 }, | ||
// Quadrant 2 | ||
{ 8, -1 }, { 8, -2 }, { 7, -3 }, { 6, -4 }, { 5, -5 }, { 4, -5 }, { 3, -6 }, { 2, -6 }, { 1, -6 }, | ||
{ 0, -6 }, | ||
// Quadrant 3 | ||
{ -1, -6 }, { -2, -6 }, { -3, -6 }, { -4, -5 }, { -5, -5 }, { -6, -4 }, { -7, -3 }, { -8, -2 }, | ||
{ -8, -1 }, { -8, 0 }, | ||
// Quadrant 4 | ||
{ -8, 1 }, { -8, 2 }, { -7, 3 }, { -6, 4 }, { -5, 5 }, { -4, 5 }, { -3, 6 }, { -2, 6 }, { -1, 6 } | ||
}; | ||
// perform translation | ||
for (int i = 0; i < expectedArray.length; i++) { | ||
expectedArray[i][0] += centerX; | ||
expectedArray[i][1] += centerY; | ||
} | ||
|
||
List<int[]> pixels = EllipseAlgorithm.drawEllipse(centerX, centerY, 8, 6); | ||
TestHelper.assert2DArrayEquals(expectedArray, pixels.toArray(new int[pixels.size()][])); | ||
} | ||
|
||
@Test | ||
public void testZeroRadii() { | ||
try { | ||
EllipseAlgorithm.drawEllipse(10, 10, 0, 0); | ||
fail("Expected IllegalArgumentException for zero radii"); | ||
} catch (IllegalArgumentException e) { | ||
assertEquals("Radii must be positive values.", e.getMessage()); | ||
} | ||
} | ||
|
||
@Test | ||
public void testNegativeRadii() { | ||
try { | ||
EllipseAlgorithm.drawEllipse(10, 10, -5, -3); | ||
fail("Expected IllegalArgumentException for negative radii"); | ||
} catch (IllegalArgumentException e) { | ||
assertEquals("Radii must be positive values.", e.getMessage()); | ||
} | ||
} | ||
|
||
@Test | ||
public void testHorizontalEllipseAtOrigin() { | ||
List<int[]> pixels = EllipseAlgorithm.drawEllipse(0, 0, 7, 3); | ||
|
||
int[][] expectedArray = { | ||
// Quadrant 1 | ||
{ 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 }, { 4, 2 }, { 5, 2 }, { 6, 2 }, { 7, 1 }, | ||
// Quadrant 2 | ||
{ 7, 0 }, { 7, -1 }, { 6, -2 }, { 5, -2 }, { 4, -2 }, { 3, -3 }, { 2, -3 }, { 1, -3 }, { 0, -3 }, | ||
// Quadrant 3 | ||
{ -1, -3 }, { -2, -3 }, { -3, -3 }, { -4, -2 }, { -5, -2 }, { -6, -2 }, { -7, -1 }, | ||
// Quadrant 4 | ||
{ -7, 0 }, { -7, 1 }, { -6, 2 }, { -5, 2 }, { -4, 2 }, { -3, 3 }, { -2, 3 }, { -1, 3 } | ||
}; | ||
|
||
TestHelper.assert2DArrayEquals(expectedArray, pixels.toArray(new int[pixels.size()][])); | ||
} | ||
|
||
@Test | ||
public void testVerticalEllipseAtOrigin() { | ||
List<int[]> pixels = EllipseAlgorithm.drawEllipse(0, 0, 3, 7); | ||
|
||
int[][] expectedArray = { | ||
// Quadrant 1 | ||
{ 0, 7 }, { 1, 7 }, { 2, 6 }, { 2, 5 }, { 2, 4 }, { 3, 3 }, { 3, 2 }, { 3, 1 }, { 3, 0 }, | ||
// Quadrant 2 | ||
{ 3, -1 }, { 3, -2 }, { 3, -3 }, { 2, -4 }, { 2, -5 }, { 2, -6 }, { 1, -7 }, { 0, -7 }, | ||
// Quadrant 3 | ||
{ -1, -7 }, { -2, -6 }, { -2, -5 }, { -2, -4 }, { -3, -3 }, { -3, -2 }, { -3, -1 }, { -3, 0 }, | ||
// Quadrant 4 | ||
{ -3, 1 }, { -3, 2 }, { -3, 3 }, { -2, 4 }, { -2, 5 }, { -2, 6 }, { -1, 7 } | ||
}; | ||
|
||
TestHelper.assert2DArrayEquals(expectedArray, pixels.toArray(new int[pixels.size()][])); | ||
} | ||
|
||
} |