在VisualSudio上实现Cohen-Southerland线段裁剪算法

直线绘制:

首先现在MFC文件中的xxxView.h头文件中添加一个直线的结构体(xxx表示你MFC文件的名字)

typedef struct       //线段结构
{
    CPoint startpoint;
    CPoint endpoint;
}  LINE;

还是在头文件里,加入下面那部分的代码(从CArry开始),encode函数是Cohen-Southerland算法实现编码的函数的定义,具体的代码在cpp文件里写

在菜单(Menu)文件中添加两个事件处理程序(注意:添加时要写到View类里去),一个线段绘制,一个线段裁剪

 

扫描二维码关注公众号,回复: 11248463 查看本文章

 因为画线是通过鼠标左键来实现的,所以在View类里要添加一个消息(WM_LBUTTONDOWN),并加上代码

 之前不是添加了两个事件处理程序吗,所以在第一个,也就是线段绘制函数添加代码(这里我把函数名改成了DrawLine)

 最后在cpp文件中的OnDraw函数中添加划线的代码

 现在启动应用,点击绘制线段应该是可以画出直线的

Cohen-Southerland算法

在cpp文件里最上面定义下

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

 接着编写编码函数

 为了能够裁剪成功,并重新画出裁剪后的直线,所以要绘制一个矩形框

int XL = 100, XR = 300, YB = 100, YT = 200;
//(x1,y1)、(x2,y2)为直线段的端点,XL为左边界,XR为右边界,YB为下边界,YT为上边

同时在OnDraw函数中绘制出矩形框(写在OnDraw函数里)

  CPen newpen(PS_SOLID, 3, RGB(0, 255, 0));
    CPen *old = pDC->SelectObject(&newpen);
    pDC->MoveTo(100, 100);
    pDC->LineTo(100, 200);

    pDC->MoveTo(100, 200);
    pDC->LineTo(300, 200);

    pDC->MoveTo(300, 200);
    pDC->LineTo(300, 100);

    pDC->MoveTo(300, 100);
    pDC->LineTo(100, 100);
    pDC->SelectObject(old);

接下来到了最关键的Cohen-Southerland算法

在第二个事件处理程序,也就是线段裁剪的函数里添加代码(函数名称没改,就是默认的ID号)

void CCGTestView::On32786() //线段裁剪
{
    // TODO: 在此添加命令处理程序代码
    int code1, code2, code;
    int x, y;
    int i;
    int x1, y1, x2, y2;
    for (int i = 0; i < LineSet.GetSize(); i++) //绘制多条直线时,一条一条得实现
    {
        x1 = LineSet.GetAt(i).startpoint.x;
        y1 = LineSet.GetAt(i).startpoint.y;
        x2 = LineSet.GetAt(i).endpoint.x;
        y2 = LineSet.GetAt(i).endpoint.y;
        encode(x1, y1, code1); //分别求出端点所在的区号
        encode(x2, y2, code2);

        while (code1 != 0 || code2 != 0)//只有两个端点全在中心区内(直接保留完整线端,否则进入循环)
        {
            if (code1 &code2) //说明两个端点全在非中心区的区域,直接不画)
                return;
            if (code1 != 0) //如果端点1不在中心区
                code = code1; //使端点1与边界交换
            else  //说明端点1在中心区,端点2不在中心区
                code = code2;  //使端点2与边界交点交换

            if (code & LEFT)  //线端与左边界相交,条件成立,点必定在左边界左侧
            {
                x = XL; //求为与左边界相交的点的x值
                y = y1 + (y2 - y1)*(XL - x1) / (x2 - x1); //斜率((y2 - y1)/(x2 - x1))
            }
            else if (code & RIGHT)//线段与右边界相交,条件成立,点必定在右边界右侧
            {
                x = XR; //求出右边界的交点x值
                y = y1 + (y2 - y1)*(XR - x1) / (x2 - x1);
            }
            else if (code & BOTTOM) //线段与下边界相交
            {
                y = YB;
                x = x1 + (x2 - x1)*(YB - y1) / (y2 - y1);
            }
            else if (code & TOP) //线段与上边界相交
            {
                y = YT;
                x = x1 + (x2 - x1)*(YT - y1) / (y2 - y1);
            }

            //将端点与边界交点转换
            if (code == code1)
            {
                x1 = x;
                y1 = y;
                encode(x1, y1, code1);//如果交换成功,新编码为0000
            }
            else
            {
                x2 = x;
                y2 = y;
                encode(x2, y2, code2); //交换成功,新编码为0000
            }



        }
        //绘制线段
        CDC *pDC = this->GetDC();
        CPen newpen(PS_SOLID, 3, RGB(255, 255, 0));
        CPen *old = pDC->SelectObject(&newpen);
        pDC->MoveTo(x1, y1);
        pDC->LineTo(x2, y2);
        pDC->SelectObject(old);
        ReleaseDC(pDC);
        

    }
    

}

运行结果:

 

------------------------------------------------------------------------

(在下写博客,是记下平时学习程中常遇到的问题,代码中若有不合理之处,还望各位大佬指正)

猜你喜欢

转载自www.cnblogs.com/djlobster/p/12937735.html