参考 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;
}