The algorithm can be extended to cover gradients between 0 and -1 by checking whether y needs to increase or decrease (i.e. dy < 0)
plotLineLow(x0,y0, x1,y1) dx = x1 - x0 dy = y1 - y0 yi = 1 if dy < 0 yi = -1 dy = -dy end if D = 2*dy - dx y = y0 for x from x0 to x1 plot(x,y) if D > 0 y = y + yi D = D - 2*dx end if D = D + 2*dy
By switching the x and y axis an implementation for positive or negative steep gradients can be written as
plotLineHigh(x0,y0, x1,y1) dx = x1 - x0 dy = y1 - y0 xi = 1 if dx < 0 xi = -1 dx = -dx end if D = 2*dx - dy x = x0 for y from y0 to y1 plot(x,y) if D > 0 x = x + xi D = D - 2*dy end if D = D + 2*dx
A complete solution would need to detect whether x1 > x0 or y1 > y0 and reverse the input coordinates before drawing, thus
plotLine(x0,y0, x1,y1) if abs(y1 - y0) < abs(x1 - x0) if x0 > x1 plotLineLow(x1, y1, x0, y0) else plotLineLow(x0, y0, x1, y1) end if else if y0 > y1 plotLineHigh(x1, y1, x0, y0) else plotLineHigh(x0, y0, x1, y1) end if end if
Reference:
https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
https://en.wikipedia.org/wiki/Midpoint_circle_algorithm
C语言版本
// 交换整数 a 、b 的值 inline void swap_int(int *a, int *b) { *a ^= *b; *b ^= *a; *a ^= *b; } // Bresenham's line algorithm void draw_line(IMAGE *img, int x1, int y1, int x2, int y2, unsigned long c) { // 参数 c 为颜色值 int dx = abs(x2 - x1), dy = abs(y2 - y1), yy = 0; if (dx < dy) { yy = 1; swap_int(&x1, &y1); swap_int(&x2, &y2); swap_int(&dx, &dy); } int ix = (x2 - x1) > 0 ? 1 : -1, iy = (y2 - y1) > 0 ? 1 : -1, cx = x1, cy = y1, n2dy = dy * 2, n2dydx = (dy - dx) * 2, d = dy * 2 - dx; if (yy) { // 如果直线与 x 轴的夹角大于 45 度 while (cx != x2) { if (d < 0) { d += n2dy; } else { cy += iy; d += n2dydx; } putpixel(img, cy, cx, c); cx += ix; } } else { // 如果直线与 x 轴的夹角小于 45 度 while (cx != x2) { if (d < 0) { d += n2dy; } else { cy += iy; d += n2dydx; } putpixel(img, cx, cy, c); cx += ix; } } }
Python Implementation
def draw_line(self, p1, p2, c): """draws a line from point p1 to p2 with color c. p1 and p2 can be outside of the cube, but it will only draw the line that fall inside the cube""" current_point = Vertex(p1.x, p1.y, p1.z) dx = p2.x - p1.x dy = p2.y - p1.y dz = p2.z - p1.z x_inc = -1 if dx < 0 else 1 l = abs(dx) y_inc = -1 if dy < 0 else 1 m = abs(dy) z_inc = -1 if dz < 0 else 1 n = abs(dz) dx2 = l * 2 dy2 = m * 2 dz2 = n * 2 if (l >= m) and (l >= n): err_1 = dy2 - l err_2 = dz2 - l for i in range(0, l): self.set_pixel(current_point, c) if err_1 > 0: current_point.y = current_point.y + y_inc err_1 = err_1 - dx2 if err_2 > 0: current_point.z = current_point.z + z_inc err_2 = err_2 - dx2 err_1 = err_1 + dy2 err_2 = err_2 + dz2 current_point.x = current_point.x + x_inc elif m >= l and m >= n: err_1 = dx2 - m err_2 = dz2 - m for i in range(0, m): self.set_pixel(current_point, c) if err_1 > 0: current_point.x = current_point.x + x_inc err_1 = err_1 - dy2 if err_2 > 0: current_point.z = current_point.z + z_inc err_2 = err_2 - dy2 err_1 = err_1 + dx2 err_2 = err_2 + dz2 current_point.y = current_point.y + y_inc else: err_1 = dy2 - n err_2 = dx2 - n for i in range(0,n): self.set_pixel(current_point, c) if err_1 > 0: current_point.y = current_point.y + y_inc err_1 = err_1 - dz2 if err_2 > 0: current_point.x = current_point.x + x_inc err_2 = err_2 - dz2 err_1 = err_1 + dy2 err_2 = err_2 + dx2 current_point.z = current_point.z + z_inc self.set_pixel(current_point, c)
Bresenham’s line algorithm