feat: add bresenham's line drawing algorithm (#5779)

This commit is contained in:
Saahil Mahato
2024-10-15 14:57:58 +05:45
committed by GitHub
parent 32bf532133
commit be70801aa2
2 changed files with 126 additions and 0 deletions

View File

@ -0,0 +1,69 @@
package com.thealgorithms.geometry;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
/**
* The {@code BresenhamLine} class implements the Bresenham's line algorithm,
* which is an efficient way to determine the points of a straight line
* between two given points in a 2D space.
*
* <p>This algorithm uses integer arithmetic to calculate the points,
* making it suitable for rasterization in computer graphics.</p>
*
* For more information, please visit {@link https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm}
*/
public final class BresenhamLine {
private BresenhamLine() {
// Private constructor to prevent instantiation.
}
/**
* Finds the list of points that form a straight line between two endpoints.
*
* @param x0 the x-coordinate of the starting point
* @param y0 the y-coordinate of the starting point
* @param x1 the x-coordinate of the ending point
* @param y1 the y-coordinate of the ending point
* @return a {@code List<Point>} containing all points on the line
*/
public static List<Point> findLine(int x0, int y0, int x1, int y1) {
List<Point> line = new ArrayList<>();
// Calculate differences and steps for each axis
int dx = Math.abs(x1 - x0); // Change in x
int dy = Math.abs(y1 - y0); // Change in y
int sx = (x0 < x1) ? 1 : -1; // Step in x direction
int sy = (y0 < y1) ? 1 : -1; // Step in y direction
int err = dx - dy; // Initial error term
// Loop until we reach the endpoint
while (true) {
line.add(new Point(x0, y0)); // Add current point to the line
// Check if we've reached the endpoint
if (x0 == x1 && y0 == y1) {
break; // Exit loop if endpoint is reached
}
// Calculate error term doubled for decision making
final int e2 = err * 2;
// Adjust x coordinate if necessary
if (e2 > -dy) {
err -= dy; // Update error term
x0 += sx; // Move to next point in x direction
}
// Adjust y coordinate if necessary
if (e2 < dx) {
err += dx; // Update error term
y0 += sy; // Move to next point in y direction
}
}
return line; // Return the list of points forming the line
}
}

View File

@ -0,0 +1,57 @@
package com.thealgorithms.geometry;
import java.awt.Point;
import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
/**
* The {@code BresenhamLineTest} class contains unit tests for the
* {@code BresenhamLine} class, specifically testing the
* {@code findLine} method.
*
* <p>This class uses parameterized tests to validate the output of
* Bresenham's line algorithm for various input points.</p>
*/
class BresenhamLineTest {
/**
* Provides test cases for the parameterized test.
*
* <p>Each test case includes starting coordinates, ending coordinates,
* and the expected collection of points that should be generated by the
* {@code findLine} method.</p>
*
* @return a stream of arguments containing test cases
*/
static Stream<Arguments> linePointsProvider() {
return Stream.of(Arguments.of(0, 0, 5, 5, List.of(new Point(0, 0), new Point(1, 1), new Point(2, 2), new Point(3, 3), new Point(4, 4), new Point(5, 5))), Arguments.of(0, 0, 5, 0, List.of(new Point(0, 0), new Point(1, 0), new Point(2, 0), new Point(3, 0), new Point(4, 0), new Point(5, 0))),
Arguments.of(0, 0, 0, 5, List.of(new Point(0, 0), new Point(0, 1), new Point(0, 2), new Point(0, 3), new Point(0, 4), new Point(0, 5))), Arguments.of(-2, -2, -5, -5, List.of(new Point(-2, -2), new Point(-3, -3), new Point(-4, -4), new Point(-5, -5))),
Arguments.of(-1, -1, 2, 2, List.of(new Point(-1, -1), new Point(0, 0), new Point(1, 1), new Point(2, 2))), Arguments.of(2, -1, -1, -4, List.of(new Point(2, -1), new Point(1, -2), new Point(0, -3), new Point(-1, -4))));
}
/**
* Tests the {@code findLine} method of the {@code BresenhamLine} class.
*
* <p>This parameterized test runs multiple times with different sets of
* starting and ending coordinates to validate that the generated points
* match the expected output.</p>
*
* @param x0 the x-coordinate of the starting point
* @param y0 the y-coordinate of the starting point
* @param x1 the x-coordinate of the ending point
* @param y1 the y-coordinate of the ending point
* @param expected a collection of expected points that should form a line
*/
@ParameterizedTest
@MethodSource("linePointsProvider")
void testFindLine(int x0, int y0, int x1, int y1, Collection<Point> expected) {
List<Point> actual = BresenhamLine.findLine(x0, y0, x1, y1);
Assertions.assertEquals(expected.size(), actual.size(), "The size of the points list should match.");
Assertions.assertTrue(expected.containsAll(actual) && actual.containsAll(expected), "The points generated should match the expected points.");
}
}