Skip to content

Commit be70801

Browse files
feat: add bresenham's line drawing algorithm (TheAlgorithms#5779)
1 parent 32bf532 commit be70801

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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 BresenhamLine} class implements the Bresenham's line algorithm,
9+
* which is an efficient way to determine the points of a straight line
10+
* between two given points 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+
* For more information, please visit {@link https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm}
16+
*/
17+
public final class BresenhamLine {
18+
19+
private BresenhamLine() {
20+
// Private constructor to prevent instantiation.
21+
}
22+
23+
/**
24+
* Finds the list of points that form a straight line between two endpoints.
25+
*
26+
* @param x0 the x-coordinate of the starting point
27+
* @param y0 the y-coordinate of the starting point
28+
* @param x1 the x-coordinate of the ending point
29+
* @param y1 the y-coordinate of the ending point
30+
* @return a {@code List<Point>} containing all points on the line
31+
*/
32+
public static List<Point> findLine(int x0, int y0, int x1, int y1) {
33+
List<Point> line = new ArrayList<>();
34+
35+
// Calculate differences and steps for each axis
36+
int dx = Math.abs(x1 - x0); // Change in x
37+
int dy = Math.abs(y1 - y0); // Change in y
38+
int sx = (x0 < x1) ? 1 : -1; // Step in x direction
39+
int sy = (y0 < y1) ? 1 : -1; // Step in y direction
40+
int err = dx - dy; // Initial error term
41+
42+
// Loop until we reach the endpoint
43+
while (true) {
44+
line.add(new Point(x0, y0)); // Add current point to the line
45+
46+
// Check if we've reached the endpoint
47+
if (x0 == x1 && y0 == y1) {
48+
break; // Exit loop if endpoint is reached
49+
}
50+
51+
// Calculate error term doubled for decision making
52+
final int e2 = err * 2;
53+
54+
// Adjust x coordinate if necessary
55+
if (e2 > -dy) {
56+
err -= dy; // Update error term
57+
x0 += sx; // Move to next point in x direction
58+
}
59+
60+
// Adjust y coordinate if necessary
61+
if (e2 < dx) {
62+
err += dx; // Update error term
63+
y0 += sy; // Move to next point in y direction
64+
}
65+
}
66+
67+
return line; // Return the list of points forming the line
68+
}
69+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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 BresenhamLineTest} class contains unit tests for the
14+
* {@code BresenhamLine} class, specifically testing the
15+
* {@code findLine} method.
16+
*
17+
* <p>This class uses parameterized tests to validate the output of
18+
* Bresenham's line algorithm for various input points.</p>
19+
*/
20+
class BresenhamLineTest {
21+
22+
/**
23+
* Provides test cases for the parameterized test.
24+
*
25+
* <p>Each test case includes starting coordinates, ending coordinates,
26+
* and the expected collection of points that should be generated by the
27+
* {@code findLine} method.</p>
28+
*
29+
* @return a stream of arguments containing test cases
30+
*/
31+
static Stream<Arguments> linePointsProvider() {
32+
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))),
33+
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))),
34+
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))));
35+
}
36+
37+
/**
38+
* Tests the {@code findLine} method of the {@code BresenhamLine} class.
39+
*
40+
* <p>This parameterized test runs multiple times with different sets of
41+
* starting and ending coordinates to validate that the generated points
42+
* match the expected output.</p>
43+
*
44+
* @param x0 the x-coordinate of the starting point
45+
* @param y0 the y-coordinate of the starting point
46+
* @param x1 the x-coordinate of the ending point
47+
* @param y1 the y-coordinate of the ending point
48+
* @param expected a collection of expected points that should form a line
49+
*/
50+
@ParameterizedTest
51+
@MethodSource("linePointsProvider")
52+
void testFindLine(int x0, int y0, int x1, int y1, Collection<Point> expected) {
53+
List<Point> actual = BresenhamLine.findLine(x0, y0, x1, y1);
54+
Assertions.assertEquals(expected.size(), actual.size(), "The size of the points list should match.");
55+
Assertions.assertTrue(expected.containsAll(actual) && actual.containsAll(expected), "The points generated should match the expected points.");
56+
}
57+
}

0 commit comments

Comments
 (0)