Graphics entry (1) - Linear Algorithm (DDA and Bresenham)

A new open pit, the recording process from scratch learning graphics, still are learning now sprouting new, badly written, please forgive me.

 

First generation straight start from the most basic algorithm, when we want to draw a line on the screen, because the screen is composed of a number of pixels, so straight in fact, the computer shows the approximate composition by a number of pixels, the straight line generation algorithm to solve how to choose the best set of pixels to display a line problem.

To this question, the method most violent first thought, of course, is to start from the linear order starting x or y incremented by 1 until the end, then rounded to the nearest integer per value calculating a function corresponding to the linear equation, to find a corresponding pixel but doing so every step must be floating-point multiplication, the efficiency is very low, so there are two types of linear DDA and Bresenham generation algorithm.

 

A, numerical differentiation (DDA algorithm)

DDA algorithm is the use of the idea increment through each of x and y while adding a small increment, the next calculation of x and y values.

 

 

According to the above equation $ \ bigtriangleup x $ = time 1, x increments every 1, y is incremented k, it is only necessary for the x and y continue to increase can be obtained function value point, thus avoiding each pixel using to calculate the linear equation, eliminating the floating-point multiplication.

Code:

 

#include<Windows.h>
#include<iostream>
#include<cmath>
using namespace std;

const int ScreenWidth = 500;
const int ScreenHeight = 500;

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }
    return 0;
}

void DDALine(int x0,int y0,int x1,int y1,HDC hdc)
{
    int i=1;
    float dx, dy, length, x, y;
    if (fabs(x1 - x0) >= fabs(y1 - y0))
        length = fabs(x1 - x0);
    else
        length = fabs(y1 - y0);
    dx = (x1 - x0) / length;
    dy = (y1 - y0) / length;
    x = x0;
    y = y0;
    while (i<=length)
    {
        SetPixel(hdc,int(x + 0.5), ScreenHeight-40-int(y + 0.5), RGB(0, 0, 0));
        x = x + dx;
        y = y + dy;
        i++;
    }
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nShowCmd)
{ 
    The WNDCLASS WCS; 
    wcs.cbClsExtra = 0 ;                                          // window class additional parameters   
    wcs.cbWndExtra = 0 ;                                          // Window additional parameters   
    wcs.hbrBackground = (HBRUSH) the GetStockObject (WHITE_BRUSH);     // window DC background   
    wcs.hCursor = LoadCursor ( hInstance, IDC_CROSS);              // mouse style   
    wcs.hIcon = the LoadIcon (NULL, IDI_WINLOGO);                     // window icon   
    wcs.hInstance = hInstance;                                   // application instance   
    wcs.lpfnWndProc = (WNDPROC) the WinProc;
    wcs.lpszClassName = "CG";
    wcs.lpszMenuName = NULL;
    wcs.style = CS_VREDRAW | CS_HREDRAW;
    RegisterClass(&wcs);
    HWND hWnd;
    hWnd = CreateWindow("CG","DrawLine", WS_OVERLAPPEDWINDOW, 200, 200, ScreenWidth, ScreenHeight, NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, nShowCmd);
    UpdateWindow(hWnd);
    MSG msg;

    // hdc init
    HDC = the HDC the GetDC (the hWnd);

    // drawing, drawn from a point (0,0) to (100,350) linearly 
    DDALine ( 0 , 0 , 100 , 350 , HDC); // message loop   
    the while (the GetMessage (& MSG, 0 , NULL, NULL)) { 
        TranslateMessage ( & MSG); 
        the DispatchMessage ( & MSG); 
    } 

    // Release 
    the ReleaseDC (the hWnd, HDC);
     return  0 ; 
}

 

 

These are the realization of DDA algorithm, WinMain and WinProc function is unique to Windows API programming, we only need to focus DDALine this drawing function, which passed the coordinates of two points to draw a straight line.

First, whether the difference between starting and end points x and y axes which span a greater axial direction (slope range), in order to prevent missing pixels, should allow a greater axial span of each increment 1, so that more accurate results can be obtained.

Then nothing to say, so that x and y together sequentially increment the line and then rounded, floating point rounding can be directly used int (x + 0.5) is calculated, the setPixel function is used to set the pixel color values ​​(need to pass the window hdc handle), because Windows window coordinate origin in the upper left corner, so get the window height minus the y value can be converted into ordinary habits of the lower left corner of the coordinate system.

operation result:

 

 

 

 

  

Two, Bresenham algorithm

Although the DDA algorithm eliminates the floating-point multiply operations, but there are still floating-point addition and rounding operation, efficiency is still to be improved, made in 1965 Bresenham's line drawing algorithm better, today became the most widely used graphics field line drawing algorithm incremental calculation, by means of a symbol error amount to determine the position of a pixel, the floating-point algorithm does not exist, only integer arithmetic, greatly improving the operating efficiency.

 We first consider only the case of a slope in between 0 and 1, the processing starts from the left end of the line, and gradually processing each subsequent column, the coordinates of each pixel to determine the current column $ (x_ {i}, y_ {i}) after $ , then the next step is to determine {i + 1} on the value of y $ $ X_ column, the value of y at this time is either unchanged or increased by 1, because the slope between 0-1, x growing faster than y, Therefore, each additional x 1, y is less than one increment.

The default for the left point coordinates for the pixel, the next pixel row is either right or upper right of the pixel, the pixel is provided to the upper right of the straight line distance d2, the distance to the right of the pixel line is d1, apparently only need to determine a straight line which pixels from the more recent is the symbol d1-d2 to find the best pixels.

 

 So you can launch the following equation:

 

 Where $ \ bigtriangleup x $ x-axis from the origin to the destination, $ \ bigtriangleup y $ y-axis is the distance, k = $ \ bigtriangleup y $ / $ \ bigtriangleup x $, c is a constant, regardless of the pixel position.

Calculated so $ e_ {i} $ = $ \ bigtriangleup x $ (d1-d2), the $ e_ {i} $ includes only integer arithmetic, is consistent with the symbol d1-d2, it referred to the amount of error parameters, when it is less than 0 , the right pixel is closer to a straight line, a straight line is closer to the upper right pixel is greater than 0.

Incrementing integer arithmetic can be used to obtain subsequent error amount parameter is calculated as follows:

 

 Therefore, when selecting the top right pixel ($ y_ {i + 1} $ - $ y_ {i} $ = 1):

 

 When choosing the right pixel ($ y_ {i + 1} $ - $ y_ {i} $ = 0):

 

 Initially, the k = $ \ bigtriangleup y $ / $ \ bigtriangleup x $ substituting $ \ first parameter bigtriangleup x $ (d1-d2) is obtained in an initial pixel:

 

Bresenham algorithm implemented in the slope of the code between 0-1 (alternative to the above procedure DDALine):

void Bresenham_Line(int x0, int y0, int x1, int y1, HDC hdc)
{
    int dx, dy, e, x=x0, y=y0;
    dx = x1 - x0; dy = y1 - y0;
    e = 2 * dy - dx;
    while (x<=x1)
    {
        SetPixel(hdc, x, ScreenHeight-40-y, RGB(0, 0, 0));
        if (e >= 0)//选右上方像素
        {
            e = e + 2 * dy - 2 * dx;
            y++;
        }
        else//选右方像素
        {
            e = e + 2 * dy;
        }
        x++;
    }
}

运行结果:

 

 

 

要实现任意方向的Bresenham算法也很容易,斜率在0-1之间意味着直线位于坐标系八象限中的第一象限,如果要绘制第二象限的直线,只需要利用这两个象限关于直线x=y对称的性质即可,可以先将x和y值互换先在第一象限进行计算,然后调用SetPixel时再将x和y值反过来,在第二象限中绘制,其他象限也是类似的思路。

绘制任意方向直线的Bresenham算法代码实现:

void Bresenham_Line(int x0, int y0, int x1, int y1, HDC hdc)
{
    int flag = 0;
    int dx = abs(x1 - x0);
    int dy = abs(y1 - y0);
    if (dx == 0 && dy == 0)   return;
    if (abs(x1 - x0) < abs(y1 - y0))
    {
        flag = 1;
        swap(x0, y0);
        swap(x1, y1);
        swap(dx, dy);
    }
    int tx = (x1 - x0) > 0 ? 1 : -1;
    int ty = (y1 - y0) > 0 ? 1 : -1;
    int x = x0;    
    int y = y0;
    int dS = 2 * dy;   int dT = 2 * (dy - dx);
    int e = dS - dx;
    SetPixel(hdc, x0, y0, RGB(0,0,0));
    while (x != x1)
    {
        if (e < 0)
            e += dS;
        else
        {
            y += ty;  e += dT;
        }
        x += tx;
        if (flag)
            SetPixel(hdc, y, ScreenHeight - 40 - x, RGB(0, 0, 0));
        else
            SetPixel(hdc, x, ScreenHeight - 40 - y, RGB(0, 0, 0));
    }
}

 

 

 

直线生成算法就到这里啦,接下来也要加油学习图形学~

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin www.cnblogs.com/LiveForGame/p/11706904.html