Sutherland-Hodgeman多边形裁剪算法

实验目的:

用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();
}

实验结果及分析

原图形:

裁剪后的图形

分析:根据该多边形算法剪取的图形如上红色线框所示,是我们所想要得到的情况。每条边进行一次剪取就会重新获得一个顶点序列,四条边总共进行了四次,该算法的思想并不难,但是算法的实现麻烦一些,交点的计算也稍微有点困难。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值