Cohen-Sutherland算法

算法思路


分别判断直线 ( 线段 ) 的两个端点落在哪个区域。判断的方法是将端点和裁剪框的边界比较。然后确定线段与矩形框上边界的交点 ( 四舍五入取整 ) ,端点落在 C 区域无需求交点,落在其他区域需要。当端点落在 N S W E 区域时只要将裁剪框边界值带入直线方程即可。当某端点落在 NW NE SW SE 区域时有两个交点 C D B 端点位于 S SW 区域类似)。如图:

C D 选正确的。

两个端点确定了位置之后,有下面几种情况:


1.       两个端点位于裁剪框边界同一侧,无法裁剪。


2.       端点都在 C 区域,无需裁剪。

具体算法

//返回0-成功,1-无法裁剪,线段不在裁剪框中,-1失败
//使用两点式求交点 y-y0 = (x-x0)*(y1-y0)/(x1-x0)
//y = (x-x0)*(y1-y0)/(x1-x0) + y0;
//x = (y-y0)*(x1-x0)/(y1-y0) + x0;
//浮点数+0.5再赋给整数即可将浮点数四舍五入
int Cohen_Sutherland::Clip_line(int LineX1,int LineY1,int LineX2,int LineY2 ,
                            int RectX1,int RectY1,int RectX2,int RectY2 ,
                            int &LineX3,int &LineY3,int &LineX4,int &LineY4 )
{
#define CLIP_CODE_C        0x0000
#define CLIP_CODE_W        0x0001
#define CLIP_CODE_E        0x0002
#define CLIP_CODE_S        0x0004
#define CLIP_CODE_N        0x0008
#define CLIP_CODE_SW       0x0005
#define CLIP_CODE_SE       0x0006
#define CLIP_CODE_NW       0x0009
#define CLIP_CODE_NE       0x000a

    int Code1 = 0,Code2 = 0,Temp = -1;

    LineX3 = LineX1;
    LineY3 = LineY1;
    LineX4 = LineX2;
    LineY4 = LineY2;

    if (RectX1 > RectX2)
    {
        Temp = RectX2;
        RectX2 = RectX1;
        RectX1 = Temp;
    }
    if (RectY1 > RectY2)
    {
        Temp = RectY2;
        RectY2 = RectY1;
        RectY1 = Temp;
    }

    if (LineX1 < RectX1)
    {
        Code1 |= CLIP_CODE_W;
    }
    if (LineX1 > RectX2)
    {
        Code1 |= CLIP_CODE_E;
    }
    if (LineY1 < RectY1)
    {
        Code1 |= CLIP_CODE_N;
    }
    if (LineY1 > RectY2)
    {
        Code1 |= CLIP_CODE_S;
    }
    if (LineX2 < RectX1)
    {
        Code2 |= CLIP_CODE_W;
    }
    if (LineX2 > RectX2)
    {
        Code2 |= CLIP_CODE_E;
    }
    if (LineY2 < RectY1)
    {
        Code2 |= CLIP_CODE_N;
    }
    if (LineY2 > RectY2)
    {
        Code2 |= CLIP_CODE_S;
    }

    if (Code1 & Code2)
    {
        return 1;
    }
    if (Code1==0 && Code2==0)
    {
        return 0;
    }
    switch(Code1)
    {
    case CLIP_CODE_C:
        break;
    case CLIP_CODE_W:
        {
            LineX3 = RectX1;
            LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            break;
        }
    case CLIP_CODE_E:
        {
            LineX3 = RectX2;
            LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            break;
        }
    case CLIP_CODE_S:
        {
            LineY3 = RectY2;
            LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            break;
        }
    case CLIP_CODE_N:
        {
            LineY3 = RectY1;
            LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            break;
        }
    case CLIP_CODE_SW:
        {
            LineY3 = RectY2;
            LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            if (LineX3 < RectX1)
            {
                LineX3 = RectX1;
                LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            }
            break;
        }
    case CLIP_CODE_SE:
        {
            LineY3 = RectY2;
            LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            if (LineX3 > RectX2)
            {
                LineX3 = RectX2;
                LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            }
            break;
        }
    case CLIP_CODE_NW:
        {
            LineY3 = RectY1;
            LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            if (LineX3 < RectX1)
            {
                LineX3 = RectX1;
                LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            }
            break;
        }
    case CLIP_CODE_NE:
        {
            LineY3 = RectY1;
            LineX3 = (LineY3-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            if (LineX3 > RectX2)
            {
                LineX3 = RectX2;
                LineY3 = (LineX3-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            }
            break;
        }
    }

    switch(Code2)
    {
    case CLIP_CODE_C:
        break;
    case CLIP_CODE_W:
        {
            LineX4 = RectX1;
            LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            break;
        }
    case CLIP_CODE_E:
        {
            LineX4 = RectX2;
            LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            break;
        }
    case CLIP_CODE_S:
        {
            LineY4 = RectY2;
            LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            break;
        }
    case CLIP_CODE_N:
        {
            LineY4 = RectY1;
            LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            break;
        }
    case CLIP_CODE_SW:
        {
            LineY4 = RectY2;
            LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            if (LineX4 < RectX1)
            {
                LineX4 = RectX1;
                LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            }
            break;
        }
    case CLIP_CODE_SE:
        {
            LineY4 = RectY2;
            LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            if (LineX4 > RectX2)
            {
                LineX4 = RectX2;
                LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            }
            break;
        }
    case CLIP_CODE_NW:
        {
            LineY4 = RectY1;
            LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            if (LineX4 < RectX1)
            {
                LineX4 = RectX1;
                LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            }
            break;
        }
    case CLIP_CODE_NE:
        {
            LineY4 = RectY1;
            LineX4 = (LineY4-LineY1)*(LineX2-LineX1)/(LineY2-LineY1) + LineX1 + 0.5;
            if (LineX4 > RectX2)
            {
                LineX4 = RectX2;
                LineY4 = (LineX4-LineX1)*(LineY2-LineY1)/(LineX2-LineX1) + LineY1 + 0.5;
            }
            break;
        }
    }

    if (LineX3<RectX1 || LineX3>RectX2
        || LineX4<RectX1 || LineX4>RectX2
        || LineY3<RectY1 || LineY4>RectY2
        || LineX4<RectY1 || LineY4>RectY2)
    {
        return 1;
    }

    return 0;
}

值得注意的地方:

四舍五入取整可以将浮点数 +0.5 赋给整型实现。

两点式直线方程 ,y-y0 = (x-x0)*(y1-y0)/(x1-x0).

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Cohen-Sutherland算法是一种用于线段裁剪的计算机图形学算法。它可以快速地判断一条直线是否在一个矩形裁剪窗口内,并对其进行裁剪或保留。 该算法将矩形窗口划分成9个区域:左、右、上、下和四个角落。然后,对于每条线段的两个端点,算法确定它们位于哪个区域内,以此判断线段是否在窗口内。如果两个端点都位于窗口内,那么线段完全在窗口内部,无需裁剪;如果两个端点都位于窗口外,那么线段完全在窗口外部,同样无需裁剪;否则,线段与窗口边界相交,需要进行裁剪。 具体来说,算法将窗口分成了以下几个区域: 1. 左:x坐标小于裁剪窗口的左边界 2. 右:x坐标大于裁剪窗口的右边界 3. 下:y坐标小于裁剪窗口的下边界 4. 上:y坐标大于裁剪窗口的上边界 5. 左下:同时满足左和下的条件 6. 左上:同时满足左和上的条件 7. 右下:同时满足右和下的条件 8. 右上:同时满足右和上的条件 9. 内部:线段的两个端点都在窗口内部 当一条线段与窗口边界相交时,算法会根据线段所在的位置将其裁剪成两个部分,然后继续对这两部分进行裁剪,直到整个线段都在窗口内或窗口外为止。 Cohen-Sutherland算法是一个简单而有效的裁剪算法,适用于计算机图形学中许多不同的应用场景。 ### 回答2: Cohen-Sutherland算法是一种计算机图形学中常用的二维线段裁剪算法,用于确定一个给定的矩形区域和一个线段是否相交,如果相交,则求出相交的区域或者将线段裁剪成在矩形内的部分。 这个算法可分为以下四个步骤: 1. 定义区域编码:定义一些二进制码来标识点的位置关系。比如,将一个图形视为四个象限,则左上象限的二进制码为“1001”,右上象限的二进制码为“0101”,左下象限的二进制码为“1010”,右下象限的二进制码为“0010”。 2. 计算区域编码:将需要裁剪的线段的两个端点分别计算它们的区域编码,即确定它们在矩形的哪个位置。如果点在矩形内部,则编码为0,否则根据其位置关系编码为不同的二进制码。 3. 判断线段是否在矩形内部:对于每一个点的区域编码,将它们进行逻辑“与”操作,如果结果为0,则说明线段完全在矩形内部,不需要裁剪。 4. 裁剪线段:如果线段不在矩形内部,则需要对其进行裁剪。这时需要根据相交的位置来确定裁剪线段的位置。如果一个点的编码是00,则说明它在线段内部,则保留该点,否则需将该点延伸至与矩形边界相交的位置。然后继续计算其它点的编码,重复这个过程,直到结束。 总之,Cohen-Sutherland算法是一种高效而可靠的线段裁剪算法,可以用于在计算机图形学中进行各种图像裁剪操作。 ### 回答3: Cohen-Sutherland算法是一种常用于计算机图形学中线段裁剪的算法,它的主要目的是减少显示裁剪窗口以外的线段,从而节省计算资源,同时也提高图像的显示效果。该算法是由 Ivan Sutherland 和 Danny Cohen 于1967年提出。 Cohen-Sutherland算法基于对窗口边界的划分,可以将窗口边界划分为9个区域,包括内部、左、右、上、下、左上、右上、左下和右下,每个区域用一个4位二进制数表示。当线段的两个端点都落在同一个区域内时,该线段完全在该区域之内,可以直接绘制,并将该区域的二进制码作为该线段端点的编码。当线段的两个端点落在不同的区域时,该线段可能会穿过区域的边界,需要进行裁剪。此时将两个端点的编码进行逻辑运算,以判断该线段与窗口边界是否相交。如果两个端点的编码逻辑与运算结果为0,则该线段完全在窗口内部,可以绘制;否则需要进行裁剪。 当需要裁剪时,Cohen-Sutherland算法会先找到与线段相交的边界。如果线段与一条竖直边界相交,则在该边界上找到交点后,将该点的纵坐标修改,使其与原线段交点横坐标相同;如果线段与一条水平边界相交,则在该边界上找到交点后,将该点的横坐标修改,使其与原线段交点纵坐标相同。经过多次裁剪后,就可以得到一个位于窗口内部的线段,从而完成裁剪。 总之,Cohen-Sutherland算法是一种快速而高效的线段裁剪算法,可以有效地减少计算量和减少不必要的绘制,从而提高计算机图形学中图像的显示质量和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值