原理:马华东老师的课件
#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);
}