参考:https://www.bilibili.com/video/BV1yd4y197mG/
1.重心坐标定义
2.重心坐标与面积关系
3.计算重心坐标(通过大三角形与小三角形面积比求出)
满足公式条件:P点在三角形内部。
4.三角形包围盒
算法设计
完整代码
// 11-重心坐标填充算法
// 参考 https://www.bilibili.com/video/BV1yd4y197mG/
#define UNICODE
#include <Windows.h>
#include <math.h>
#define WINDOW_TEXT L"11-重心坐标填充算法"
#define ROUND(d) int(floor(d)+0.5) // 四舍五入
#define RGB2RGB(c) RGB(c.red*255,c.green*255,c.blue*255)
struct RGB24 // RGB颜色
{
public:
RGB24() :red(0), green(0), blue(0) {};
RGB24(double red, double green, double blue) :red(red), green(green), blue(blue) {};
friend RGB24 operator + (const RGB24& clr0, const RGB24& clr1)
{
return RGB24(clr0.red + clr1.red, clr0.green + clr1.green, clr0.blue + clr1.blue);
};
friend RGB24 operator * (const RGB24& clr, double scalar)
{
return RGB24(clr.red * scalar, clr.green * scalar, clr.blue * scalar);
}
friend RGB24 operator * (double scalar, const RGB24& clr)
{
return clr * scalar;
}
public:
double red;
double green;
double blue;
};
struct Point2 // 带颜色二维点
{
Point2() :x(0), y(0) {}
Point2(double x, double y) :x(x), y(y) {}
Point2(double x, double y, RGB24 c) :x(x), y(y), c(c) {}
double x;
double y;
RGB24 c;
};
class Triangle // 填充三角形
{
public:
Point2 _P0; // 顶点1
Point2 _P1; // 顶点2
Point2 _P2; // 顶点3
public:
Triangle(){};
Triangle(Point2 p0, Point2 p1, Point2 p2)
{
_P0 = p0;
_P1 = p1;
_P2 = p2;
}
~Triangle() {};
void Fill(HDC hdc)
{
// 计算包围盒
int xMin=ROUND(min(min(_P0.x, _P1.x), _P2.x));
int yMin=ROUND(min(min(_P0.y, _P1.y), _P2.y));
int xMax=ROUND(max(max(_P0.x, _P1.x), _P2.x));
int yMax=ROUND(max(max(_P0.y, _P1.y), _P2.y));
for (int y = yMin; y < yMax; y++)
{
for (int x = xMin; x < xMax; x++)
{
double area = _P0.x * _P1.y + _P1.x * _P2.y + _P2.x * _P0.y - _P2.x * _P1.y - _P1.x * _P0.y - _P0.x * _P2.y;
double area0 = x * _P1.y + _P1.x * _P2.y + _P2.x * y - _P2.x * _P1.y - _P1.x * y - x * _P2.y;
double area1 = _P0.x * y + x * _P2.y + _P2.x * _P0.y - _P2.x * y - x * _P0.y - _P0.x * _P2.y;
double area2 = _P0.x * _P1.y + _P1.x * y + x * _P0.y - x * _P1.y - _P1.x * _P0.y - _P0.x * y;
double alpha = area0 / area;
double beta = area1 / area;
double gamma = area2 / area;
if (alpha >=0&& beta>=0&&gamma>=0)
{
RGB24 crColor = alpha * _P0.c + beta * _P1.c + gamma * _P2.c;
SetPixel(hdc,x,y,RGB2RGB(crColor));
}
}
}
}
};
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);
Triangle* triange = new Triangle(
Point2( 0, 150,RGB24(1.0, 0, 0)),
Point2(-200, -150,RGB24( 0, 1.0, 0)),
Point2(200, -150,RGB24( 0, 0, 1.0))
);
triange->Fill(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;
}