Khác biệt giữa bản sửa đổi của “Giải thuật Bresenham vẽ đoạn thẳng”

Nội dung được xóa Nội dung được thêm vào
Trang mới: “'''Giải thuật vẽ đường thẳng Bresenham ''' là giải thuật xác định điểm nào nên được dựng để có thể xấp xỉ đường thẳng…”
(Không có sự khác biệt)

Phiên bản lúc 02:55, ngày 12 tháng 3 năm 2010

Giải thuật vẽ đường thẳng Bresenham là giải thuật xác định điểm nào nên được dựng để có thể xấp xỉ đường thẳng giữa 2 điểm cho trước. Giải thuật này thường được dùng để vẽ đường thẳng trong đồ họa máy tính, nó chỉ sử dụng lệnh cộng và trừ số học và lệnh trên pixel, giải thuật này có chi phí rẻ và phù hợp với kiến trúc sơ khai của máy tính. Đây là một trong những giải thuật phát triển sớm nhất của đồ họa máy tính. Sự mở rộng của nó là giải thuật cơ bản vẽ đường tròn.

Trong khi giảm thuật Xiaolin_Wu thường được sử dụng trên đồ họa máy tính hiện đại bởi tính năng khử răng cưa, thì tốc độ và sự đơn giản của giải thuật Bresenham khiến ta vẫn cần nó. Giải thuật còn được tích hợp trên phần cứng như chip đồ họa hoặc những card đồ họa hiện đại. Nó cũng được tìm thấy trên các phần mềm về thư viện đồ họa. Bởi vì nó cực kỳ đơn giản, nên nó thường được dùng để làm firmware hoặc tích hợp trong card đồ họa.

Giải thuật

 
Minh họa kết quả của giải thuật Bresenham. (0,0) là điểm trên cùng bên trái.

Đặc điểm cơ bản là các pixel có tọa độ tăng dần về phía dưới và phía phải, pixel ở giữa có tọa độ nguyên được dùng để vẽ.

Điểm đầu và cuối của đoạn thẳng tại (x0, y0) and (x1, y1), mỗi tọa độ là 1 cặp cột và dòng.

Giải thuật sẽ The algorithm will be initially presented only for the octant in which the segment goes down and to the right (x0x1 and y0y1), and its horizontal projection   is longer than the vertical projection   (the line has a slope less than 1 and greater than 0.) In this octant, for each column x between   and  , there is exactly one row y (computed by the algorithm) containing a pixel of the line, while each row between   and   may contain multiple rasterized pixels.

Bresenham's algorithm chooses the integer y corresponding to the pixel center that is closest to the ideal (fractional) y for the same x; on successive columns y can remain the same or increase by 1. The general equation of the line through the endpoints is given by:

 

Since we know the column, x, the pixel's row, y, is given by rounding this quantity to the nearest integer:

 

The slope   depends on the endpoint coordinates only and can be precomputed, and the ideal y for successive integer values of x can be computed starting from   and repeatedly adding the slope.

In practice, the algorithm can track, instead of possibly large y values, a small error value between −0.5 and 0.5: the vertical distance between the rounded and the exact y values for the current x. Each time x is increased, the error is increased by the slope; if it exceeds 0.5, the rasterization y is increased by 1 (the line continues on the next lower row of the raster) and the error is decremented by 1.0.

In the following pseudocode sample plot(x,y) plots a point and abs returns absolute value:

 function line(x0, x1, y0, y1)
     int deltax := x1 - x0
     int deltay := y1 - y0
     real error := 0
     real deltaerr := deltay / deltax    // Assume deltax != 0 (line is not vertical),
           // note that this division needs to be done in a way that preserves the fractional part
     int y := y0
     for x from x0 to x1
         plot(x,y)
         error := error + deltaerr
         if abs(error) ≥ 0.5 then
             y := y + 1
             error := error - 1.0

Generalization

The version above only handles lines that descend to the right. We would of course like to be able to draw all lines. The first case is allowing us to draw lines that still slope downwards but head in the opposite direction. This is a simple matter of swapping the initial points if x0 > x1. Trickier is determining how to draw lines that go up. To do this, we check if y0y1; if so, we step y by -1 instead of 1. Lastly, we still need to generalize the algorithm to drawing lines in all directions. Up until now we have only been able to draw lines with a slope less than one. To be able to draw lines with a steeper slope, we take advantage of the fact that a steep line can be reflected across the line y=x to obtain a line with a small slope. The effect is to switch the x and y variables throughout, including switching the parameters to plot. The code looks like this:

 function line(x0, x1, y0, y1)
     boolean steep := abs(y1 - y0) > abs(x1 - x0)
     if steep then
         swap(x0, y0)
         swap(x1, y1)
     if x0 > x1 then
         swap(x0, x1)
         swap(y0, y1)
     int deltax := x1 - x0
     int deltay := abs(y1 - y0)
     real error := 0
     real deltaerr := deltay / deltax
     int ystep
     int y := y0
     if y0 < y1 then ystep := 1 else ystep := -1
     for x from x0 to x1
         if steep then plot(y,x) else plot(x,y)
         error := error + deltaerr
         if error ≥ 0.5 then
             y := y + ystep
             error := error - 1.0

The function now handles all lines and implements the complete Bresenham's algorithm.

Optimization

The problem with this approach is that computers operate relatively slowly on fractional numbers like error and deltaerr; moreover, errors can accumulate over many floating-point additions. Working with integers will be both faster and more accurate. The trick we use is to multiply all the fractional numbers above by deltax, which enables us to express them as integers. The only problem remaining is the constant 0.5—to deal with this, we change the initialization of the variable error, and invert it for an additional small optimization. The new program looks like this:

 function line(x0, x1, y0, y1)
     boolean steep := abs(y1 - y0) > abs(x1 - x0)
     if steep then
         swap(x0, y0)
         swap(x1, y1)
     if x0 > x1 then
         swap(x0, x1)
         swap(y0, y1)
     int deltax := x1 - x0
     int deltay := abs(y1 - y0)
     int error := deltax / 2
     int ystep
     int y := y0
     if y0 < y1 then ystep := 1 else ystep := -1
     for x from x0 to x1
         if steep then plot(y,x) else plot(x,y)
         error := error - deltay
         if error < 0 then
             y := y + ystep
             error := error + deltax

History

The algorithm was developed by Jack E. Bresenham in 1962 at IBM. In 2001 Bresenham wrote:[1]

I was working in the computation lab at IBM's San Jose development lab. A Calcomp plotter had been attached to an IBM 1401 via the 1407 typewriter console. [The algorithm] was in production use by summer 1962, possibly a month or so earlier. Programs in those days were freely exchanged among corporations so Calcomp (Jim Newland and Calvin Hefte) had copies. When I returned to Stanford in Fall 1962, I put a copy in the Stanford comp center library. A description of the line drawing routine was accepted for presentation at the 1963 ACM national convention in Denver, Colorado. It was a year in which no proceedings were published, only the agenda of speakers and topics in an issue of Communications of the ACM. A person from the IBM Systems Journal asked me after I made my presentation if they could publish the paper. I happily agreed, and they printed it in 1965.

Bresenham's algorithm was later modified to produce circles, the resulting algorithm being sometimes known as either "Bresenham's circle algorithm" or midpoint circle algorithm.

Similar algorithms

The Bresenham algorithm can be interpreted as slightly modified DDA (using 0.5 as error threshold instead of 0, which is required for non-overlapping polygon rasterizing).

The principle of using an incremental error in place of division operations has other applications in graphics. It is possible to use this technique to calculate the U,V co-ordinates during raster scan of texture mapped polygons. The voxel heightmap software-rendering engines seen in some PC games also used this principle.

Bresenham also published a Run-Slice (as opposed to the Run-Length) computational algorithm.

An extension to the algorithm that handles thick lines was created by Alan Murphy at IBM.

  1. ^ Paul E. Black. Dictionary of Algorithms and Data Structures, NIST. http://www.nist.gov/dads/HTML/bresenham.html