Загрузка данных
```cpp
#include <windows.h>
#include <vector>
struct Point
{
float x, y;
};
std::vector<Point> polygon =
{
{300, 100},
{400, 100},
{400, 250},
{550, 250},
{550, 350},
{400, 350},
{400, 500},
{300, 500},
{300, 350},
{150, 350},
{150, 250},
{300, 250}
};
RECT clipRect = {250, 180, 550, 400};
bool dragging = false;
POINT dragOffset;
bool insideLeft(Point p, RECT r)
{
return p.x >= r.left;
}
bool insideRight(Point p, RECT r)
{
return p.x <= r.right;
}
bool insideTop(Point p, RECT r)
{
return p.y >= r.top;
}
bool insideBottom(Point p, RECT r)
{
return p.y <= r.bottom;
}
Point intersectLeft(Point s, Point e, RECT r)
{
float t = (r.left - s.x) / (e.x - s.x);
return {
(float)r.left,
s.y + (e.y - s.y) * t
};
}
Point intersectRight(Point s, Point e, RECT r)
{
float t = (r.right - s.x) / (e.x - s.x);
return {
(float)r.right,
s.y + (e.y - s.y) * t
};
}
Point intersectTop(Point s, Point e, RECT r)
{
float t = (r.top - s.y) / (e.y - s.y);
return {
s.x + (e.x - s.x) * t,
(float)r.top
};
}
Point intersectBottom(Point s, Point e, RECT r)
{
float t = (r.bottom - s.y) / (e.y - s.y);
return {
s.x + (e.x - s.x) * t,
(float)r.bottom
};
}
template<typename InsideFunc, typename IntersectFunc>
std::vector<Point> clipEdge(
const std::vector<Point>& input,
InsideFunc inside,
IntersectFunc intersect)
{
std::vector<Point> output;
if (input.empty())
return output;
Point S = input.back();
for (auto E : input)
{
bool Ein = inside(E);
bool Sin = inside(S);
if (Ein)
{
if (!Sin)
output.push_back(intersect(S, E));
output.push_back(E);
}
else if (Sin)
{
output.push_back(intersect(S, E));
}
S = E;
}
return output;
}
std::vector<Point> clipPolygon(
const std::vector<Point>& poly,
RECT rect)
{
auto out = poly;
out = clipEdge(
out,
[&](Point p){ return insideLeft(p, rect); },
[&](Point s, Point e){ return intersectLeft(s, e, rect); }
);
out = clipEdge(
out,
[&](Point p){ return insideRight(p, rect); },
[&](Point s, Point e){ return intersectRight(s, e, rect); }
);
out = clipEdge(
out,
[&](Point p){ return insideTop(p, rect); },
[&](Point s, Point e){ return intersectTop(s, e, rect); }
);
out = clipEdge(
out,
[&](Point p){ return insideBottom(p, rect); },
[&](Point s, Point e){ return intersectBottom(s, e, rect); }
);
return out;
}
void drawPolygon(
HDC hdc,
const std::vector<Point>& pts,
COLORREF color,
bool filled = false)
{
if (pts.empty())
return;
HPEN pen = CreatePen(PS_SOLID, 2, color);
HBRUSH brush;
if (filled)
brush = CreateSolidBrush(RGB(0,255,0));
else
brush = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
SelectObject(hdc, pen);
SelectObject(hdc, brush);
POINT* winPts = new POINT[pts.size()];
for (size_t i = 0; i < pts.size(); ++i)
{
winPts[i].x = (LONG)pts[i].x;
winPts[i].y = (LONG)pts[i].y;
}
Polygon(hdc, winPts, (int)pts.size());
delete[] winPts;
DeleteObject(pen);
if (filled)
DeleteObject(brush);
}
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
{
int x = LOWORD(lParam);
int y = HIWORD(lParam);
if (x >= clipRect.left &&
x <= clipRect.right &&
y >= clipRect.top &&
y <= clipRect.bottom)
{
dragging = true;
dragOffset.x = x - clipRect.left;
dragOffset.y = y - clipRect.top;
}
return 0;
}
case WM_LBUTTONUP:
{
dragging = false;
return 0;
}
case WM_MOUSEMOVE:
{
if (dragging)
{
int x = LOWORD(lParam);
int y = HIWORD(lParam);
int width = clipRect.right - clipRect.left;
int height = clipRect.bottom - clipRect.top;
clipRect.left = x - dragOffset.x;
clipRect.top = y - dragOffset.y;
clipRect.right = clipRect.left + width;
clipRect.bottom = clipRect.top + height;
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
}
case WM_KEYDOWN:
{
if (wParam == VK_DELETE)
{
clipRect = {0,0,0,0};
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
auto clipped = clipPolygon(polygon, clipRect);
drawPolygon(hdc, polygon, RGB(0,0,255));
Rectangle(
hdc,
clipRect.left,
clipRect.top,
clipRect.right,
clipRect.bottom
);
drawPolygon(hdc, clipped, RGB(0,255,0), true);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE,
LPSTR,
int nCmdShow)
{
const wchar_t CLASS_NAME[] = L"ClipWindow";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0,
CLASS_NAME,
L"Weiler-Atherton Clipping",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
1000,
700,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, nCmdShow);
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
```