GDI画圆

来源:互联网 发布:淘宝卖家信息怎么修改 编辑:程序博客网 时间:2024/05/16 12:16
最近在看游戏编程的书,看到其中一句:在80年代,如果你能画圆,那你真是聪明极了。

这句话让我跃跃欲试,但是应该怎么画呢?

第一个想法就是按照屏幕水平扫描的方向画直线,然后可以画出一个实心的圆,下面是关键代码部分:

void UseLineDrawRound()
{
    int ir, ixo, iyo, ix1, ix2, iy1, iy2, ix;
    HDC gdc = GetDC(g_hwnd);
    HPEN hpen, old_hpen;

    ixo = 50;
    iyo = 50;
    ir = 50;
    iy1 = iyo - ir;
    iy2 = iyo + ir;
    hpen = CreatePen(PS_DASH, 1, RGB(0,0,255));
    old_hpen = (HPEN)SelectObject(gdc, hpen);
    for(int y=iy1; y<=iy2; y++)
    {
        ix = (int)sqrt( pow(ir, 2) - pow(y-iyo, 2) );
        ix1 = ixo - ix;
        ix2 = ixo + ix;

        MoveToEx(gdc, ix1, y, NULL);
        LineTo(gdc, ix2, y);
    }
    DeleteObject(hpen);
    SelectObject(gdc, old_hpen);
    ReleaseDC(g_hwnd, gdc);
}

好了,现在已经可以画实心的圆了,那如果我要画一个空心的呢?

马上想到用点来画,代码如下:

void UsePixelDrawRound()
{
    int ir, ixo, iyo, ix1, ix2, iy1, iy2, ix;
    HDC gdc = GetDC(g_hwnd);

    ixo = 150;
    iyo = 150;
    ir = 50;
    iy1 = iyo - ir;
    iy2 = iyo + ir;
    for(int y=iy1; y<=iy2; y++)
    {
        ix = (int)sqrt( pow(ir, 2) - pow(y-iyo, 2) );
        ix1 = ixo - ix;
        ix2 = ixo + ix;

        SetPixel(gdc, ix1, y, RGB(255,0,0));
        SetPixel(gdc, ix2, y, RGB(255,0,0));
    }
    ReleaseDC(g_hwnd, gdc);
}

如果你运行了上面的代码,你会发现有些点没有画出来,原因是计算出来的x,y都是int类型,小数部分被舍去,也就是精度上的问题。还有什么办法可以改进一下这个算法吗?应该可以。我们可以模仿画多边形,把圆看成是一个正n边形,而当这个n趋于无穷大的时候,这个圆看上去就会很完美了,至少这样可以解决点与点之间不连续的问题。

void UseLineDrawRound2()
{
    int ir, ixo, iyo, ix1, ix2, iy1, iy2, ix;
    HDC gdc = GetDC(g_hwnd);
    HPEN hpen, old_hpen;
    static int sx = 0;
    static int sy = 0;

    ixo = 250;
    iyo = 250;
    ir = 50;
    iy1 = iyo - ir;
    iy2 = iyo + ir;
    hpen = CreatePen(PS_SOLID, 1, RGB(0,0,255));
    old_hpen = (HPEN)SelectObject(gdc, hpen);
    for(int y=iy1; y<=iy2; y++)
    {
        ix = (int)sqrt( pow(ir, 2) - pow(y-iyo, 2) );
        ix1 = ixo - ix;
        ix2 = ixo + ix;

        if(y==iy1) // (sx==0 && sy==0)
        {
            MoveToEx(gdc, ix1, y, NULL);
        }
        else
        {
            LineTo(gdc, sx, sy);
        }
        sx = ix1;
        sy = y;

    }

    for(y=iy2; y>=iy1; y--)
    {
        ix = (int)sqrt( pow(ir, 2) - pow(y-iyo, 2) );
        ix1 = ixo - ix;
        ix2 = ixo + ix;

        LineTo(gdc, ix2, y);
    }

    DeleteObject(hpen);
    SelectObject(gdc, old_hpen);
    ReleaseDC(g_hwnd, gdc);
}

全部代码如下:

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
HINSTANCE hInstance_app;
HWND g_hwnd;

void UseLineDrawRound()
{
    int ir, ixo, iyo, ix1, ix2, iy1, iy2, ix;
    HDC gdc = GetDC(g_hwnd);
    HPEN hpen, old_hpen;

    ixo = 50;
    iyo = 50;
    ir = 50;
    iy1 = iyo - ir;
    iy2 = iyo + ir;
    hpen = CreatePen(PS_DASH, 1, RGB(0,0,255));
    old_hpen = (HPEN)SelectObject(gdc, hpen);
    for(int y=iy1; y<=iy2; y++)
    {
        ix = (int)sqrt( pow(ir, 2) - pow(y-iyo, 2) );
        ix1 = ixo - ix;
        ix2 = ixo + ix;

        MoveToEx(gdc, ix1, y, NULL);
        LineTo(gdc, ix2, y);
    }
    DeleteObject(hpen);
    SelectObject(gdc, old_hpen);
    ReleaseDC(g_hwnd, gdc);
}

void UsePixelDrawRound()
{
    int ir, ixo, iyo, ix1, ix2, iy1, iy2, ix;
    HDC gdc = GetDC(g_hwnd);

    ixo = 150;
    iyo = 150;
    ir = 50;
    iy1 = iyo - ir;
    iy2 = iyo + ir;
    for(int y=iy1; y<=iy2; y++)
    {
        ix = (int)sqrt( pow(ir, 2) - pow(y-iyo, 2) );
        ix1 = ixo - ix;
        ix2 = ixo + ix;

        SetPixel(gdc, ix1, y, RGB(255,0,0));
        SetPixel(gdc, ix2, y, RGB(255,0,0));
    }
    ReleaseDC(g_hwnd, gdc);
}

void UseLineDrawRound2()
{
    int ir, ixo, iyo, ix1, ix2, iy1, iy2, ix;
    HDC gdc = GetDC(g_hwnd);
    HPEN hpen, old_hpen;
    static int sx = 0;
    static int sy = 0;

    ixo = 250;
    iyo = 250;
    ir = 50;
    iy1 = iyo - ir;
    iy2 = iyo + ir;
    hpen = CreatePen(PS_SOLID, 1, RGB(0,0,255));
    old_hpen = (HPEN)SelectObject(gdc, hpen);
    for(int y=iy1; y<=iy2; y++)
    {
        ix = (int)sqrt( pow(ir, 2) - pow(y-iyo, 2) );
        ix1 = ixo - ix;
        ix2 = ixo + ix;

        if(y==iy1)//(sx==0 && sy==0)
        {
            MoveToEx(gdc, ix1, y, NULL);
        }
        else
        {
            LineTo(gdc, sx, sy);
        }
        sx = ix1;
        sy = y;
    }

    for(y=iy2; y>=iy1; y--)
    {
        ix = (int)sqrt( pow(ir, 2) - pow(y-iyo, 2) );
        ix1 = ixo - ix;
        ix2 = ixo + ix;

        LineTo(gdc, ix2, y);
    }

    DeleteObject(hpen);
    SelectObject(gdc, old_hpen);
    ReleaseDC(g_hwnd, gdc);
}

LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    switch (msg)
    {
    case WM_CREATE:
        return 0;
        break;

    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);

        UseLineDrawRound();
        UsePixelDrawRound();
        UseLineDrawRound2();

        EndPaint(hWnd, &ps);
        return 0;
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
        break;

    default:
        break;
    }

    return DefWindowProc(hWnd, msg, wparam, lparam);

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
    HWND hwnd;
    WNDCLASSEX winclass;

    MSG msg;

    hInstance_app = hInstance;
   
    winclass.cbClsExtra = 0;
    winclass.cbSize = sizeof(WNDCLASSEX);
    winclass.cbWndExtra = 0;
    winclass.hbrBackground = (HBRUSH)GetStockBrush(BLACK_BRUSH);
    winclass.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(CURSOR_CROSSHAIR));
    winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    winclass.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(ICON_T3DX));
    winclass.hInstance = hInstance;
    winclass.lpfnWndProc = WinProc;
    winclass.lpszClassName = "WINCLASS1";
    winclass.lpszMenuName = NULL;
    winclass.style = CS_VREDRAW|CS_HREDRAW|CS_OWNDC|CS_DBLCLKS;

    if( !RegisterClassEx(&winclass) )
    {
        return 0;
    }

    hwnd = CreateWindowEx(WS_EX_TOPMOST,
                            "WINCLASS1",
                            "My First Window",
                            WS_POPUP/*WS_OVERLAPPEDWINDOW*/|WS_VISIBLE,
                            0,
                            0,
                            GetSystemMetrics(SM_CXSCREEN),
                            GetSystemMetrics(SM_CYSCREEN),
                            NULL,
                            NULL,
                            hInstance,
                            NULL);
    if( hwnd == NULL )
    {
        return 0;
    }
    g_hwnd = hwnd;
/*
    while( GetMessage(&msg, NULL, 0, 0) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
        if( KEY_DOWN(VK_ESCAPE) )
        {
            PostMessage(hwnd, WM_DESTROY, 0, 0);
        }
    }
*/

    while(TRUE)
    {
        if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
        {
            if(msg.message == WM_QUIT)
            {
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            if( KEY_DOWN(VK_ESCAPE) )
            {
                PostMessage(hwnd, WM_DESTROY, 0, 0);
            }
        }
    }

    return msg.wParam;
}
原创粉丝点击