19-中点分割裁剪算法

参考https://www.bilibili.com/video/BV1AP411n7xb

算法原理

算法设计

源码

// 19-中点分割裁剪算法
// 参考 https://www.bilibili.com/video/BV1AP411n7xb
#define UNICODE
#include <Windows.h>
#include <Windowsx.h>
#include <math.h>
#define WINDOW_TEXT L"19-中点分割裁剪算法"
#define ROUND(d) int(floor(d)+0.5)  // 四舍五入
#define PI 3.1415926

#define LEFT   1 // 0001
#define RIGHT  2 // 0010
#define BOTTOM 4 // 0100
#define TOP    8 // 1000

struct Point2  // 二维点
{
    double       x;
    double       y;
    unsigned int rc;// 直线编码
    Point2() :x(0), y(0), rc(0) {}
    Point2(double x, double y) :x(x), y(y), rc(0) {}
    friend Point2 operator+(Point2 p0 , Point2 p1)
    {
        return Point2(p0.x + p1.x, p0.y + p1.y);
    }
    friend Point2 operator/(Point2 p, double n)
    {
        return Point2(p.x/2, p.y / 2);
    }

    
};

class TrimLine
{
public:
    int wxl; //窗口左
    int wxr; //窗口右
    int wyt; //窗口上
    int wyb; //窗口下

public:
    TrimLine()
    {
        wxl = -300;
        wxr = 300;
        wyt = 100;
        wyb = -100;
    };
    ~TrimLine() {};
  
    void MidPointDivider(Point2& P0, Point2& P1)   // 中点分割
    {
        Point2 p0 = P0;  
        Point2 p1 = P1;
        Point2 pm = (p0 + p1) / 2;
        Encode(pm);
        while (fabs(pm.x-p0.x)> 1e-4 ||fabs(pm.y-p0.y)>1e-4) // 判断算法结束
        {
            if ((p0.rc & pm.rc) != 0)
            {
                p0 = pm;
            }
            else
            {
                p1 = pm;
            }
            pm = (p0 + p1) / 2;
            Encode(pm);
        }
        P0 = pm;
    }
    // 引用 & 改变实参的值 
    void Cohen_Sutherland(Point2& p0, Point2& p1) // 裁剪线段
    {
        Encode(p0); Encode(p1);  
        while (p0.rc != 0 || p1.rc != 0) // 至少一个端点在窗口之外的情况
        {
            if ((p0.rc & p1.rc) != 0)    // 两个端点在窗口之外 简弃
            {
                p0 = p1 = Point2(0, 0);
                return;
            }

            if (0 == p0.rc) //确保p0 位于窗口之外
            {
                Point2  pTemp = p0;
                p0 = p1;
                p1 = pTemp;
            }

            MidPointDivider(p0,p1);
          
        }

    }
    void DrawClipWindow(HDC hdc)
    {
        HPEN newPen = CreatePen(PS_SOLID, 3, RGB(0, 0, 128));
        HGDIOBJ oldPen = SelectObject(hdc, newPen);

        MoveToEx(hdc, wxl, wyb, NULL);
        LineTo(hdc, wxr, wyb);
        LineTo(hdc, wxr, wyt);
        LineTo(hdc, wxl, wyt);
        LineTo(hdc, wxl, wyb);

        SelectObject(hdc, oldPen);
        DeletePen(newPen);

    }

    void Encode(Point2& pt) // 编码函数
    {
        pt.rc = 0;
        if (pt.x < wxl)
            pt.rc |= LEFT;
        else if (pt.x > wxr)
            pt.rc |= RIGHT;
        else if (pt.y < wyb)
            pt.rc |= BOTTOM;
        else if (pt.y > wyt)
            pt.rc |= TOP;
    }

};

static bool     m_Play = false;
static wchar_t* m_str = L"左键 - 裁剪 | 恢复";

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:
        m_Play = !m_Play;
        InvalidateRect(hwnd, NULL, TRUE);
        return 0;

    case WM_PAINT:
    {
        hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rc);

        // 内存DC
        HDC     memDC = CreateCompatibleDC(hdc);                               // 创建兼容DC 画板
        HBITMAP newBitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);  // 创建画布
        HGDIOBJ oldBitmap = SelectObject(memDC, newBitmap);                    // 将画布选入画板
        FillRect(memDC, &rc, (HBRUSH)(COLOR_WINDOW + 1));
        DrawText(memDC, m_str, wcslen(m_str), &rc, NULL);

        SetMapMode(memDC, MM_ANISOTROPIC);
        SetWindowExtEx(memDC, rc.right, -rc.bottom, NULL);
        SetViewportExtEx(memDC, rc.right, -rc.bottom, NULL);
        SetViewportOrgEx(memDC, rc.right / 2, rc.bottom / 2, NULL);

        // 绘制图形
        {
            TrimLine trim;

            trim.DrawClipWindow(memDC);

            Point2 p0(-400, -200);
            Point2 p1(400, 200);
            if (m_Play)
            {
                trim.Cohen_Sutherland(p0, p1); // 裁剪直线
            }

            MoveToEx(memDC, ROUND(p0.x), ROUND(p0.y), NULL);
            LineTo(memDC, ROUND(p1.x), ROUND(p1.y));
        }

        // 内存dc复制到设备
        BitBlt(hdc, rc.left, rc.top, rc.right, rc.bottom, memDC, ROUND(-rc.right / 2), ROUND(-rc.bottom / 2), SRCCOPY);

        SelectObject(memDC, oldBitmap);

        DeleteObject(newBitmap);
        DeleteDC(memDC);

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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值