参考:https://www.bilibili.com/video/BV1ta41137JZ/
完整代码
// 12-边填充算法
// 参考 https://www.bilibili.com/video/BV1ta41137JZ/
#define UNICODE
#include <Windows.h>
#define WINDOW_TEXT L"12-边填充算法"
#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;
};
class Fill
{
public:
int _xMin;
int _xMax;
int _yMin;
int _yMax;
Point2 _P[7];
COLORREF _foreClr; // 前景色
COLORREF _backClr; // 背景色
public:
Fill()
{
_xMin=0;
_xMax=0;
_yMin=0;
_yMax=0;
_P[0] = Point2( 50, 70);
_P[1] = Point2(-150, 270);
_P[2] = Point2(-250, 20);
_P[3] = Point2(-150, -280);
_P[4] = Point2( 0, -80);
_P[5] = Point2( 100, -280);
_P[6] = Point2( 300, 120);
_foreClr = RGB(255, 0, 0);
_backClr = RGB(255, 255, 255);
};
~Fill() {};
// 绘制线框模型及包围盒
void DrawObject(HDC hdc)
{
_xMin = _xMax = _P[0].x;
_yMin = _yMax = _P[0].y;
for (int i = 0; i < 7; i++) // 计算包围盒
{
if (_P[i].x < _xMin)
{
_xMin = _P[i].x;
}
if (_P[i].x > _xMax)
{
_xMax = _P[i].x;
}
if (_P[i].y < _yMin)
{
_yMin = _P[i].y;
}
if (_P[i].y > _yMax)
{
_yMax = _P[i].y;
}
}
Point2 pTemp;
for (int i = 0; i < 7; i++)
{
if (0 == i)
{
MoveToEx(hdc, _P[i].x, _P[i].y, NULL);
pTemp = _P[i];
}
else
{
LineTo(hdc,_P[i].x,_P[i].y);
}
}
LineTo(hdc, pTemp.x, pTemp.y); // 闭合线框
HPEN bluePen = CreatePen(PS_SOLID,1,RGB(0,0,255));
HGDIOBJ oldPen = SelectObject(hdc, bluePen);
// 绘制包围盒
MoveToEx(hdc,_xMin,_yMin,NULL);
LineTo(hdc,_xMin,_yMax);
LineTo(hdc,_xMax,_yMax);
LineTo(hdc, _xMax, _yMin);
LineTo(hdc, _xMin, _yMin);
SelectObject(hdc, oldPen);
DeleteObject(bluePen);
}
// 边填充算法
void EdgeFill(HDC hdc)
{
int yMin; // 边最小值
int yMax; // 边最大值
double x_yMin; // 边低端x坐标
double m; // 斜率倒数
for (int i = 0; i < 7; i++) // 循环多边形所有边
{
int j = (i + 1) % 7;
m = double(_P[i].x - _P[j].x) / double(_P[i].y - _P[j].y); // 1/k
if (_P[i].y < _P[j].y)// 得到每条边y的最大值与最小值
{
yMin = _P[i].y;
yMax = _P[j].y;
x_yMin=_P[i].x;
}
else
{
yMin = _P[j].y;
yMax = _P[i].y;
x_yMin = _P[j].x;
}
for (int y = yMin; y < yMax; y++)
{
for (int x = ROUND(x_yMin); x < _xMax; x++) // 对每条扫描线与边交点的左侧
{
if (_foreClr == GetPixel(hdc, x, y))
{
SetPixel(hdc, x, y, _backClr);
}
else
{
SetPixel(hdc, x, y, _foreClr);
}
}
x_yMin += m; // 下一条扫描线x起点坐标
}
}
DrawObject(hdc);
}
};
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_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);
g_Fill.EdgeFill(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;
}