二维图形裁剪

原理:马华东老师的课件

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8
#define PT_LINE_NUM 5
#define PT_POLY_NUM 6
int XL, XR, YT, YB;    //窗口区域
CPoint pt_line[PT_LINE_NUM][2];  //要裁剪的直线
CPoint pt_poly[PT_POLY_NUM];     //要裁剪的多边形

//将端点编码
int encode(CPoint &p)
{
    int code = 0;
    if(p.x < XL)
        code |= LEFT;
    if(p.x > XR)
        code |= RIGHT;
    if(p.y < YT)
        code |= TOP;
    if(p.y > YB)
        code |= BOTTOM;
    return code;
}

//根据直线与窗口的关系,赋予新的坐标,使之位于窗口内
//p1, p2 为直线的两个端点,code为p1或p2的编码
CPoint newXY(CPoint &p1, CPoint &p2, int code)
{
    CPoint p;
    if(LEFT & code)       //线段与左边界相交
    {
        p.x = XL;
        p.y = p1.y + (p2.y - p1.y) * (XL - p1.x) / (p2.x - p1.x);
    }
    else if(RIGHT & code) //线段与右边界相交
    {
        p.x = XR;
        p.y = p1.y + (p2.y - p1.y) * (XR - p1.x) / (p2.x - p1.x);
    }
    else if(BOTTOM & code) //线段与下边界相交
    {
        p.y = YB;
        p.x = p1.x + (p2.x - p1.x) * (YB - p1.y) / (p2.y - p1.y);
    }
    else if(TOP & code )   //线段与上边界相交
    {
        p.y = YT;
        p.x = p1.x + (p2.x - p1.x) * (YT - p1.y) / (p2.y - p1.y);
    }
    return p;
}

//裁剪直线
void cutLine(CDC *pdc)
{
    CPen newpen(PS_SOLID, 2, RGB(255, 0, 0)), *oldpen;
    oldpen = pdc->SelectObject(&newpen);

    for(int i=0; i<PT_LINE_NUM; i++)
    {
        //将直线的两个端点编码
        int code1 = encode(pt_line[i][0]);
        int code2 = encode(pt_line[i][1]);

        //如果线段在同一侧,不显示
        if(code1 & code2)
            continue; 

        //如果线段与区域相交
        if(code1 != 0)
            pt_line[i][0] = newXY(pt_line[i][0], pt_line[i][1], code1);
        if(code2 != 0)
            pt_line[i][1] = newXY(pt_line[i][0], pt_line[i][1], code2);

        //绘制该直线
        pdc->MoveTo(pt_line[i][0]);
        pdc->LineTo(pt_line[i][1]);
    }

    pdc->SelectObject(oldpen);
}

//在多边形中,根据直线与窗口某一边界的关系,生成新的坐标,新的坐标放在ptNew中
void solve(int &k, int i, int code1, int code2, CPoint *ptNew, CPoint *ptOld)
{
    if(code1 != 0 && code2 == 0)       //起点在边界外
    {
        ptNew[k] = newXY(ptOld[i], ptOld[i+1], code1);
        ptNew[k+1] = ptOld[i+1];
        k += 2;
    }
    else if(code1 == 0 && code2 != 0)  //终点在边界外
    {
        ptNew[k] = newXY(ptOld[i], ptOld[i+1], code2);
        k++;
    }
    else if(code1 == 0 && code2 == 0)  //两点都在边界内
    {
        if(k == 0)
        {
            ptNew[k] = ptOld[i];
            ptNew[k+1] = ptOld[i+1];
            k += 2;
        }
        else
        {
            ptNew[k] = ptOld[i+1];
            k++;
        }
    }
}

//裁剪多边形
void cutPoly(CDC *pdc)
{
    CPen newpen(PS_SOLID, 2, RGB(255, 0, 0)), *oldpen;
    CBrush brush(HS_CROSS, RGB(255, 0, 0));
    oldpen = pdc->SelectObject(&newpen);
    pdc->SelectObject(&brush);

    //定义4个点数组,存放被裁减后的新点
    CPoint ptNew1[100], ptNew2[100], ptNew3[100], ptNew4[100];

    int k = 0, m;
    //一、用左边界XL确定可见点
    for(int i=0; i<PT_POLY_NUM-1; i++)
    {
        int code1 = pt_poly[i].x < XL ? LEFT : 0;
        int code2 = pt_poly[i+1].x < XL ? LEFT : 0;
        solve(k, i, code1, code2, ptNew1, pt_poly);
    }
    //对最后一个点的处理
    ptNew1[k] = ptNew1[0];
    m = k + 1;

    //二、用下边界YB确定可见顶点
    k = 0;
    for(i=0; i<m-1; i++)
    {
        int code1 = ptNew1[i].y > YB ? BOTTOM : 0;
        int code2 = ptNew1[i+1].y > YB ? BOTTOM : 0;
        solve(k, i, code1, code2, ptNew2, ptNew1);
    }
    //对最后一个点的处理
    ptNew2[k] = ptNew2[0];
    m = k + 1;

    //三、用右边界XR确定可见顶点
    k = 0;
    for(i=0; i<m-1; i++)
    {
        int code1 = ptNew2[i].x > XR ? RIGHT : 0;
        int code2 = ptNew2[i+1].x > XR ? RIGHT : 0;
        solve(k, i, code1, code2, ptNew3, ptNew2);
    }
    //对最后一个点的处理
    ptNew3[k] = ptNew3[0];
    m = k + 1;

    //四、用上边界YT确定可见顶点
    k = 0;
    for(i=0; i<m-1; i++)
    {
        int code1 = ptNew3[i].y < YT ? TOP : 0;
        int code2 = ptNew3[i+1].y < YT ? TOP : 0;
        solve(k, i, code1, code2, ptNew4, ptNew3);
    }
    //对最后一个点的处理
    ptNew4[k] = ptNew4[0];
    m = k + 1;

    //绘制裁剪后的多边形
    pdc->Polygon(ptNew4, m-1);
    pdc->SelectObject(oldpen); 
}

void CCutView::OnDraw(CDC* pDC)
{
    CCutDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here

    //初始化直线
    pt_line[0][0] = CPoint(100, 50);  pt_line[0][1] = CPoint(100, 250);
    pt_line[1][0] = CPoint(250, 250); pt_line[1][1] = CPoint(270, 100);
    pt_line[2][0] = CPoint(270, 100); pt_line[2][1] = CPoint(310, 350);
    pt_line[3][0] = CPoint(310, 350); pt_line[3][1] = CPoint(390, 10);
    pt_line[4][0] = CPoint(100, 200); pt_line[4][1] = CPoint(450, 200);

    //初始化裁剪窗口
    XL = 150;
    XR = 400;
    YT = 100;
    YB = 300;

    //绘制裁剪窗口
    pDC->MoveTo(XL, YT); pDC->LineTo(XR, YT);
    pDC->MoveTo(XR, YT); pDC->LineTo(XR, YB);
    pDC->MoveTo(XR, YB); pDC->LineTo(XL, YB);
    pDC->MoveTo(XL, YB); pDC->LineTo(XL, YT);

    /*
    //绘制初始直线
    for(int i=0; i<PT_LINE_NUM; i++)
    {
        pDC->MoveTo(pt_line[i][0]);
        pDC->LineTo(pt_line[i][1]);
    }

    //裁剪直线
    cutLine(pDC);  
    */

    //初始化多边形
    pt_poly[0] = CPoint(150, 50);
    pt_poly[1] = CPoint(250, 250);
    pt_poly[2] = CPoint(450, 300);
    pt_poly[3] = CPoint(350, 150);
    pt_poly[4] = CPoint(400, 10);
    pt_poly[5] = CPoint(150, 50);

    //绘制多边形
    pDC->Polygon(pt_poly,  PT_POLY_NUM);

    //裁剪多边形
    cutPoly(pDC);

}

这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值