Загрузка данных


```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;
}
```