15-内点表示的泛填充算法

参考 https://www.bilibili.com/video/BV1L24y1Z7Sz

八连接点

// 14-内点表示的泛填充算法
// 参考 https://www.bilibili.com/video/BV1L24y1Z7Sz

#define UNICODE
#include <Windows.h>
#include <Windowsx.h>
#define WINDOW_TEXT L"14 - 内点表示的泛填充算法"
#define ROUND(d) int(d+0.5)  // 四舍五入

struct Point2  // 二维点
{
    Point2() :x(0), y(0) {}
    Point2(int x, int y) :x(x), y(y) {}
    int    x;
    int    y;

};

struct Stack  // 栈
{
    Stack* pTop;  // 节点指针
    Stack* pNext; // 指针域
    Point2 Pixel; // 数据域

    Stack()
    {
        pTop = NULL;
        pNext = NULL;
        Pixel = Point2(0, 0);
    };
    ~Stack() {};

    void Push(Point2 point) // 入栈
    {
        pTop = new Stack;
        pTop->Pixel = point;
        pTop->pNext = this->pNext;
        this->pNext = pTop;
    }

    Point2 Pop()            // 出栈
    {
        Point2 point;
        if (this->pNext != NULL)
        {
            pTop = this->pNext;
            this->pNext = pTop->pNext;
            point = pTop->Pixel;
            delete pTop;
        }
        return point;
    }
};


class Fill
{
public:
    Stack*   _pHead;   // 栈  
    Point2   _seed;    // 种子像素
    COLORREF _newClr;  // 新颜色
    COLORREF _oldClr;  // 旧颜色
public:
    Fill()
    {
        _pHead  = NULL;       
        _newClr = RGB(0, 0, 255);
        _oldClr = RGB(128, 128, 128);

    };
    ~Fill() {};

    // 绘制四个正方形
    void DrawObject(HDC hdc)
    {
       
        HBRUSH oldBrush = CreateSolidBrush(_oldClr);
        HRGN hRgn;
        int hEdge = 100;//半边长
        Point2 p0;
        Point2 p1;

        // 左侧正方形
        p0.x = -3 * hEdge, p0.y = -hEdge;
        p1.x = -hEdge, p1.y = hEdge;
        hRgn = CreateRectRgn(p0.x, p0.y, p1.x, p1.y);
        FillRgn(hdc, hRgn, oldBrush);
        DeleteObject(hRgn);
       
        // 右侧正方形
        p0.x = 3 * hEdge, p0.y = -hEdge;
        p1.x = hEdge, p1.y = hEdge;
        hRgn = CreateRectRgn(p0.x, p0.y, p1.x, p1.y);
        FillRgn(hdc, hRgn, oldBrush);
        DeleteObject(hRgn);


        // 上正方形
        p0.x = -hEdge, p0.y = hEdge;
        p1.x = hEdge, p1.y = 3*hEdge;
        hRgn = CreateRectRgn(p0.x, p0.y, p1.x, p1.y);
        FillRgn(hdc, hRgn, oldBrush);
        DeleteObject(hRgn);
        

        // 下正方形
        p0.x = -hEdge, p0.y =- 3 * hEdge;
        p1.x = hEdge, p1.y = - hEdge;
        hRgn = CreateRectRgn(p0.x, p0.y, p1.x, p1.y);
        FillRgn(hdc, hRgn, oldBrush);
        DeleteObject(hRgn);

    }

    // 内点填充算法
    void FloodFill8(HWND hwnd, HDC hdc)
    {
        int x;
        int y;
        x = _seed.x - 1;

        RECT rect;
        GetClientRect(hwnd, &rect);
        int nClientLeft = -rect.right / 2;
        int nClientRight = rect.right / 2;
        int nClientTop = rect.bottom / 2;
        int nClientbottom = -rect.bottom / 2;

        while (_oldClr!=GetPixel(hdc,x,_seed.y))
        {
            x--;

            if (x <= nClientLeft) // 到达客户区左端
            {
                MessageBox(NULL, L"种子不在客户区域图形内", L"提示", MB_OK);
                return;
            }

        }

        x = _seed.x + 1;
        while (_oldClr != GetPixel(hdc, x, _seed.y)) // 是否位于多边形左侧
        {
            x++;
            if (x >= nClientRight) // 到达客户区右侧
            {
                MessageBox(NULL, L"种子不在客户区域图形内", L"提示", MB_OK);
                return;

            }
        }

        y = _seed.y + 1;
        while (_oldClr != GetPixel(hdc, _seed.x, y))
        {
            y++;
            if (y >= nClientTop) // 到达客户区上方
            {
                MessageBox(NULL, L"种子不在客户区域图形内", L"提示", MB_OK);
                return;
            }
        }

        y = _seed.y - 1;
        while (_oldClr != GetPixel(hdc, _seed.x, y) )
        {
            y--;
            if (y <= nClientbottom) // 到达客户区下方
            {
                MessageBox(NULL, L"种子不在客户区域图形内", L"提示", MB_OK);
                return;
            }
        }

        // 点位于 区域内
        _pHead = new Stack; // 建立栈头节点
        _pHead->pNext = NULL;

        Point2 left, top, right, bottom, topLeft, topRight, bottomLeft, bottomRight; // 种子八个邻节点
        _pHead->Push(_seed);

        while (NULL != _pHead->pNext)        // 栈不为空
        {
            Point2 popPoint = _pHead->Pop(); // 取出栈内点
            if (_newClr == GetPixel(hdc, popPoint.x, popPoint.y))
            {
                continue;  //加速
            }

            SetPixel(hdc, popPoint.x, popPoint.y, _newClr);

            top.x = popPoint.x;
            top.y = popPoint.y + 1;
            if (_oldClr == GetPixel(hdc, top.x, top.y))
            {
                _pHead->Push(top);       // 上像素入栈
            }

            bottom.x = popPoint.x;
            bottom.y = popPoint.y - 1;
            if (_oldClr == GetPixel(hdc, bottom.x, bottom.y))
            {
                _pHead->Push(bottom);     // 下方像素入栈
            }


            left.x = popPoint.x - 1;
            left.y = popPoint.y;
            if (_oldClr == GetPixel(hdc, left.x, left.y)) 
            {
                _pHead->Push(left);      // 左侧像素入栈
            }

            right.x = popPoint.x + 1;
            right.y = popPoint.y;
            if (_oldClr == GetPixel(hdc, right.x, right.y))
            {
                _pHead->Push(right);     // 右像素入栈
            }


            topLeft.x = popPoint.x - 1;
            topLeft.y = popPoint.y + 1;
            if (_oldClr == GetPixel(hdc, topLeft.x, topLeft.y))
            {
                _pHead->Push(topLeft);   // 左上像素入栈
            }

            topRight.x = popPoint.x + 1;
            topRight.y = popPoint.y + 1;
            if (_oldClr == GetPixel(hdc, topRight.x, topRight.y))
            {
                _pHead->Push(topRight);   // 右上像素入栈
            }
         
            bottomRight.x = popPoint.x + 1;
            bottomRight.y = popPoint.y - 1;
            if (_oldClr == GetPixel(hdc, bottomRight.x, bottomRight.y))
            {
                _pHead->Push(bottomRight); // 右像素入栈
            }
                      
            bottomLeft.x = popPoint.x - 1;
            bottomLeft.y = popPoint.y - 1;
            if (_oldClr == GetPixel(hdc, bottomLeft.x, bottomLeft.y))
            {
                _pHead->Push(bottomLeft); // 左下像素入栈
            }
        }

        TextOut(hdc, nClientLeft + 5, nClientTop - 10, L"填充完成", lstrlenW(L"填充完成"));
        delete _pHead;        
        _pHead = NULL;

    }

};


Fill g_Fill; // 填充

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rc;
    switch (uMsg)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_LBUTTONDOWN: // 点击左键填充多边形

        hdc = GetDC(hwnd);

        GetClientRect(hwnd, &rc);
        SetMapMode(hdc, MM_ANISOTROPIC);
        SetWindowExtEx(hdc, rc.right, rc.bottom, NULL);
        SetViewportExtEx(hdc, rc.right, -rc.bottom, NULL);
        SetViewportOrgEx(hdc, rc.right / 2, rc.bottom / 2, NULL);

        g_Fill._seed.x = GET_X_LPARAM(lParam) - rc.right / 2;
        g_Fill._seed.y = -(GET_Y_LPARAM(lParam) - rc.bottom / 2);

        g_Fill.FloodFill8(hwnd, hdc);

        ReleaseDC(hwnd, hdc);
        return 0;

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

        GetClientRect(hwnd, &rc);
        SetMapMode(hdc, MM_ANISOTROPIC);
        SetWindowExtEx(hdc, rc.right, rc.bottom, NULL);
        SetViewportExtEx(hdc, rc.right, -rc.bottom, NULL);
        SetViewportOrgEx(hdc, rc.right / 2, rc.bottom / 2, NULL);

        g_Fill.DrawObject(hdc);   // 绘制多边形线框  

        EndPaint(hwnd, &ps);
    }
    return 0;

    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    // Register the window class.
    const wchar_t CLASS_NAME[] = L"CAG";
    WNDCLASS wc = { };

    wc.style = CS_HREDRAW | CS_VREDRAW; // 重新绘制整个工作区
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = CLASS_NAME;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    RegisterClass(&wc);

    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        WINDOW_TEXT,                    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style

        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
    );

    if (hwnd == NULL)
    {
        return 0;
    }
    ShowWindow(hwnd, nCmdShow);


    MSG msg = { };
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值