实验目的:
用Sutherland-Hodgeman多边形裁剪算法对如图所示的多边形进行裁剪,要求画出每次裁剪对应的图形,并标明输入和输出的顶点。用自己编写的Sutherland-Hodgeman多边形裁剪程序予以验证
实验原理:
一次用窗口的一条边裁剪多边形。
考虑窗口的一条边以及延长线构成的裁剪线该线把平面分成两个部分:可见一侧;不可见一侧。多边形的各条边的两端点S、P。它们与裁剪线的位置关系只有四种
图一仅输出1个顶点P;
图二输出0个顶点;
图三输出线段SP与裁剪线的1个交点I;
图四输出线段SP与裁剪线的1个交点I和1个终点P;
三:实验步骤及源码
关键代码:
//判断点在线段的内侧还是外侧
int Inside(Point p, Boundary b, Point wMin, Point wMax)
{
switch (b)
{
case Left:
if (p.x < wMin.x) return (false);
break;
case Top:
if (p.y > wMax.y) return (false);
break;
case Right:
if (p.x > wMax.x) return (false);
break;
case Bottom:
if (p.y < wMin.y) return (false);
break;
}
return true;
}
//判断两点在同侧还是异侧
int Cross(Point p1, Point p2, Boundary b, Point wMin, Point wMax)
{
if (Inside(p1, b, wMin, wMax) == Inside(p2, b, wMin, wMax))
return (false);
else
return true;
}
//求交点
Point Intersect(Point p1, Point p2, Boundary b, Point wMin, Point wMax)
{
Point iPt = { 0,0 };
float m = 0;
if (p1.x != p2.x) m = (p2.y - p1.y) / (p2.x - p1.x);
switch (b)
{
case Left:
iPt.x = wMin.x;
iPt.y = p2.y + (wMin.x - p2.x) * m;
break;
case Right:
iPt.x = wMax.x;
iPt.y = p2.y + (wMax.x - p2.x) * m;
break;
case Bottom:
iPt.y = wMin.y;
if (p1.x != p2.x)iPt.x = p2.x + (wMin.y - p2.y) / m;
else iPt.x = p2.x;
break;
case Top:
iPt.y = wMax.y;
if (p1.x != p2.x) iPt.x = p2.x + (wMax.y - p2.y) / m;
else iPt.x = p2.x;
break;
}
return iPt;
}
//返回裁剪后的顶点个数
int edgeCliper(Boundary b, Point wMin, Point wMax, Point* pIn, int cnt, Point* pOut)
{
Point s;
int i, Outcnt = 0;
s = pIn[0];
for (i = 1; i <= cnt; i++)
{
if (!Inside(s, b, wMin, wMax) && Inside(pIn[i], b, wMin, wMax))
{
pOut[Outcnt] = Intersect(s, pIn[i], b, wMin, wMax);
Outcnt++;
pOut[Outcnt] = pIn[i];
Outcnt++;
}
else if (Inside(s, b, wMin, wMax) && Inside(pIn[i], b, wMin, wMax))
{
pOut[Outcnt] = pIn[i];
Outcnt++;
}
else if (Inside(s, b, wMin, wMax) && (!Inside(pIn[i], b, wMin, wMax)))
{
pOut[Outcnt] = Intersect(s, pIn[i], b, wMin, wMax);
Outcnt++;
}
s = pIn[i];
}
return (Outcnt);
}
void ClipPolygonSuthHodg(vector<VERTEX>& polygon)
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
int i, cnt, Outcnt, b;
Point points[6] = { {400, 100}, {500, 400}, {800, 100}, {600, 800}, {100, 500},{400, 100} };
cnt = 5;
Point pOut[20], pIn[20];
Point wMin = { 200, 200 }, wMax = { 600, 600 };
for (i = 0; i < 4 * cnt; i++)
{
pIn[i].x = 0.0;
pIn[i].y = 0.0;
pOut[i].x = 0.0;
pOut[i].y = 0.0;
}
for (i = 0; i <= cnt; i++) pIn[i] = points[i];
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINE_LOOP);
glVertex2f(wMin.x, wMin.y);
glVertex2f(wMax.x, wMin.y);
glVertex2f(wMax.x, wMax.y);
glVertex2f(wMin.x, wMax.y);
glEnd();
glLineWidth(1.0);
glLineStipple(1, 0x0F0F);
glBegin(GL_LINE_LOOP);
for (i = 0; i < cnt; i++)
glVertex2f(pIn[i].x, pIn[i].y);
glEnd();
for (b = 0; b < 4; b++)
{
Outcnt = edgeCliper(Boundary(b), wMin, wMax, pIn, cnt, pOut);
for (int i = 0; i < Outcnt; i++)
for (i = 0; i < Outcnt; i++)
pIn[i] = pOut[i];
pIn[Outcnt] = pOut[0];
cnt = Outcnt;
}
glDisable(GL_LINE_STIPPLE);
glLineWidth(2.0);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_LINE_LOOP);
for (i = 0; i < cnt; i++)
glVertex2f(pOut[i].x, pOut[i].y);
glEnd();
glFlush();
}
实验结果及分析
原图形:
裁剪后的图形
分析:根据该多边形算法剪取的图形如上红色线框所示,是我们所想要得到的情况。每条边进行一次剪取就会重新获得一个顶点序列,四条边总共进行了四次,该算法的思想并不难,但是算法的实现麻烦一些,交点的计算也稍微有点困难。