Cohen-Sutherland 窗口裁剪线段算法

算法简介

Cohen-Sutherland端点编码法是由Dan Cohen与Ivan Sutherland提出的窗口裁剪线段的算法。

算法思路

  1. 计算线段端点P1、P2的码字,码字(code)用四位二进制表示,1234
  2. 针对P1,P2,先进行以下判断:
    P是否在窗口左边? 
    P是否在窗口上边?
    P是否在窗口右边?
    P是否在窗口下边?
    根据这四个问题,只可能得到9种编码(对应9宫格):
    TTFF  |  FTFF  |  FTTF
    TFFF  |  FFFF  |  FFTF
    TFFT  |   FFFT |  FFTT
    转换成二进制,就是9个值:
    1100  |  0100  |  0110
    1000  |  0000  |  0010
    1001  |  0001  |  0011
  3.  如果(P1 | P2)== 0,则表示线段在窗口内,无须裁剪。
  4.  如果 (P1&P2)  !=  0,则表示线段在窗口一侧,无须裁剪
  5. 否则,线段需要裁剪

编码实现

nt 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).


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值