본문 바로가기

진리는어디에

Bresenham's algorithm

한국어 버전 보기

Bresenham's algorithm is an algorithm designed to draw straight lines only by counting integers, excluding real number calculations that make complex and slow calculations in computer graphics. The coordinates calculated using the formula of a straight line are rounded off or rounded to an integer in order to be displayed on the screen. Let's take a look at the process of converting these discarded complex calculations with decimals into simple integer operations using Bresenham's formula.

First, the equation of a straight line passing through two points is as follows:

y - y1 = (x2 - x1) / (y2 - y1) * (x - x1>)
y = (x2 - x1)/(y2 - y1) * (x - x1) + y1

For example, among the points on a straight line passing through (2, 1) and (6, 4), when x is 3, the value of y is..

y - 1 = (6 - 2) / (4 - 1) * (3 - 2)
y = 4 / 3 * 1 + 1
y = 2.333333...

It can come out like and is usually expressed as a formula like y = mx + n . where m is the slope of the line and n is the value of the y-intercept.

Numerous points on a straight line can be expressed as real values, but what can be displayed on the screen is an integer value.

When the two points on the y-axis are somewhere between yi and yi + 1, select the closest one. In the example above, 2.333... This means that you can specify the y-coordinate to the nearest 2 out of 2 and 3

d1 = y - yi
d2 = yi + 1 - y

If d1 - d2 is less than 0, it is closer to yi, and if is greater than y It's closer to the i + 1 side. What we need here is whether d1 - d2 is greater than or less than 0, not the actual value.

Let's go back to the Bresenham algorithm. The first step in Bresenham's algorithm is to select the axis with the largest displacement at the start and end of the straight line among the x-axis and y-axis. It is to find the nearest integer value of the value of the other axis, increasing by 1 from the start to the end based on the axis with the largest displacement.

In the above examples (2, 1) and (6, 4), the displacement on the x-axis is larger, so let's see how to find the y value by increasing by 1 on the x-axis. If the y-axis displacement is larger, you can think of x and y inversely.

d1 = y - yi
      = m((xi + 1) - x1) + y1 - yi

The reason why it became m(x+1) instead of mx is to find the y at the x-axis incremented by 1. And d2 can be defined as follows.

d2 = (yi + 1) - y = yi + 1 - (m((xi + 1) -x1) + y1)
     = yi - m((xi + 1) - x1) - y1 + 1
반응형

Now let's find the difference between the two distances.

d1 - d2 = m((xi +1) - x1) + y1 - yi - (yi - m((xi + 1) - x1) - y1 + 1)
              = m((xi + 1) - x1) + y1 - yi - yi + m((xi + 1) - x1) + y1 - 1
              = 2m((xi + 1) - x1) + 2y1 - 2yi - 1

Also, as already mentioned above, m is the gradient dy/dx, so

d1 -d2 = 2(dy/dx)((xi+1) - x1) + 2y1 - 2yi - 1

is defined as above.

Above, dx represents displacement, so it is unconditionally positive, and what we are curious about is whether d1 - d2 is positive or negative. Even if the dx value is multiplied by both sides and eliminated from the right term, the result does not change, so we will remove the division part by multiplying both sides by dx.

dx(d1 - d2) = 2dy((xi+1) -x1) + 2dxy1 - 2dxyi - dx
                   = 2dyxi + 2dy - 2dyx1 + 2dxy1 - 2dxyi - dx
                   = 2dyxi - 2dxyi + 2dy - 2dyx1 + 2dxy1 - dx

In the above formula, I tried to organize the variable part into xi or yi part and the constant part that does not need to be recalculated once it is calculated. The part written in bold is the constant part that has the same value after one calculation. Since the constant part is C and only the sign is needed, not the actual value, I'll define it as dx(d1 - d2) is simplified variable pi.

pi = 2dyxi - 2dxyi + C

Above, if 'd1 - d2 is less than 0, it is closer to yi, and if is greater than It's closer to the yi + 1 side'. If pi is negative, then y becomes yi , if positive, then yi + 1.

The following pi+1 can be obtained as 2dyxi+1 - 2dxyi+1 + C .

But here x increases by 1. Therefore, the previous xi+1 - xi becomes 1, so it is possible to change the above 2dyxi+1 part to just dy . And now we are solving the equation. Equations need only satisfy the condition that both terms in the middle are equal. So we replace the previous formula '2dyxi - 2dxyi + C' with '2dyxi+1 - 2dxyi+1< /sub> + C' and subtract pi from pi+1 to fit the equation. This way we can simplify the expression. The resulting formula is below.

pi+1 - pi = 2dyxi+1 - 2dxyi+1 + C - (2dyxi - 2dxyi + C)
             = 2dyxi+1 - 2dxyi+1 + C - 2dyxi + 2dxyi - C
             = 2dy(xi+1 - xi) - 2dx(yi+1 - yi)

As already said above

xi+1 - Since xi is 1, it can be arranged as follows.

pi+1 - pi = 2dy(xi+1- xi) - 2dx(yi+1- yi)
             = 2dy - 2dx(yi+1- yi)

Now, if we only get the value of pi+1,

pi+1 = pi + 2dy - 2dx(yi+1- yi)

pi+1 = 2dyxi+1 - 2dxyi+1 + C is the formula pi+1</sub > = pi + 2dy - 2dx(yi+1- yi) It still looks complicated, but if you recall that the screen coordinates are integers and the difference between yi+1 and yi is 0 or 1.

  • If the value of i is positive, d2 is closer, so the next point will have a value 1 greater than the current yi. So,
    pi+1 = pi + 2dy - 2dx
    becomes,
  • If the value of pi is negative, d1 is closer, so the next point equals the value of yi and yi+1 - yi equals 0, so
    pi+1 = pi + 2dy

It will be something like

 

The pi+1 value calculated above becomes the pi value of the next loop, so if you keep using it in the loop , find the first p0, substitute it with the next pi value, find the location, and dot the dots.

using System;
using System.Collections;

public class Bresenham2D : IEnumerable
{
    Position start; // http://kukuta.tistory.com/185
    Position end;
        
    public Bresenham2D(Position start, Position end)
    {
        this.start = start;
        this.end = end;
    }
    
    public IEnumerator GetEnumerator()
    {
        int dx = Math.Abs(end.x - start.x); // 시작 점과 끝 점의 각 x 좌표의 거리
        int dy = Math.Abs(end.y - start.y); // 시작 점과 끝 점의 각 y 좌표의 거리
        
        if (dy <= dx)
        {
            int p = 2 * (dy - dx);
            int y = start.y;
            
            int inc_x = 1;
            if (end.x < start.x)
            {
                inc_x = -1;
            }
            
            int inc_y = 1;
            if (end.y < start.y)
            {
                inc_y = -1;
            }
            
            for (int x = start.x; (start.x <= end.x ? x <= end.x : x >= end.x); x += inc_x)
            {
                if (0 >= p)
                {
                    p += 2 * dy;
                }
                else
                {
                    p += 2 * (dy - dx);
                    y += inc_y;
                }
                yield return new Position(x, y);
            }
        }
        else
        {
            int p = 2 * (dx - dy);
            int x = start.x;
            
            int inc_x = 1;
            if (end.x < start.x)
            {
                inc_x = -1;
            }
            
            int inc_y = 1;
            if (end.y < start.y)
            {
                inc_y = -1;
            }
            
            for (int y = start.y; (start.y <= end.y ? y <= end.y : y >= end.y); y += inc_y)
            {
                if (0 >= p)
                {
                    p += 2 * dx;
                }
                else
                {
                    p += 2 * (dx - dy);
                    x += inc_x;
                }
                yield return new Position(x, y);
            }
        }
    }
 }

 

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!