• [图形学] 习题8.12 NLN二维线段裁剪算法实现


      Nicholl-Lee-Nicholl二维线段裁剪算法相对于Cohen-Sutherland和Liang-Barsky算法来说,在求交点之前进行了线段端点相对于几个区域的判断,可以确切的知道要求交点的边的信息。

      此方法只在二维空间裁剪时使用,C-S和L-B裁剪方法则可应用到三维空间。

     

    算法步骤:

    1   先使用C-S裁剪算法的区域码判断方法,去除一部分在裁剪区域外面的线段、显示在完全在裁剪区域内的线段。其他不能判断的情况,采用NLN算法进行裁剪。

    2   p1和p2若有一点在区域内,必要时交换端点以确保p1在区域内。

       分别计算p1到裁剪区域四个顶点斜率m1-m4(从左下端点顺时针的4个顶点),判断线段斜率m与m1-m4的关系,决定计算哪条边与线段的交点。交点值赋给p2.

    3   p1和p2有一个点在区域0001(左侧),必要时交换端点以确保p1在0001内。

       因为p2在区域内的情况被步骤2覆盖,因此p1为线段与左边界的交点。

       分别计算m1-m4,判断线段斜率m与m1-m4的关系,决定计算哪条边与线段的交点。此交点赋值给p2.

    4   p1和p2有一个点在区域1001(左上角),必要时交换端点以确保p1在1001内。

       同样p2在区域内的情况被步骤2覆盖。

       分别计算m1-m4,判断线段斜率m与m1-m4的关系(注意此处需要判断m2与m4的大小,决定计算哪条边与线段的交点)。分别计算p1和p2。

    5   对于其他6种情况,分别判断p1和p2的位置,在不同的区域,将线段裁剪区域旋转相应的角度,重复步骤2-4进行裁剪。裁剪完成后再将线段旋转回原来的位置。

      1 #include <GLUT/GLUT.h>
      2 #include <iostream>
      3 #include <math.h>
      4 #include "lineNLN.h"
      5 #include "linebres.h"
      6 
      7 GLfloat m1, m2, m3, m4;
      8 
      9 const GLint winLeftBitCode = 0x1; // 直接为1也没问题
     10 const GLint winRightBitCode = 0x2;
     11 const GLint winBottomBitCode = 0x4;
     12 const GLint winTopBitCode = 0x8;
     13 
     14 typedef GLfloat Matrix3x3 [3][3];
     15 Matrix3x3 matRotate;
     16 Matrix3x3 matComposite;
     17 const GLdouble pi = 3.14159;
     18 GLfloat delta;
     19 wcPt2D center;
     20 
     21 inline GLint inside (GLint code)
     22 {
     23     return GLint (!(code));
     24 }
     25 inline GLint reject (GLint code1, GLint code2)
     26 {
     27     return GLint (code1 & code2);
     28 }
     29 inline GLint accept (GLint code1, GLint code2)
     30 {
     31     return GLint (!(code1 | code2));
     32 }
     33 
     34 GLubyte encode (wcPt2D pt, wcPt2D winMin, wcPt2D winMax)
     35 {
     36     GLubyte code = 0x00;
     37     
     38     if(pt.getx() < winMin.getx())
     39         code = code | winLeftBitCode;
     40     if(pt.getx() > winMax.getx())
     41         code = code | winRightBitCode;
     42     if(pt.gety() < winMin.gety())
     43         code = code | winBottomBitCode;
     44     if(pt.gety() > winMax.gety())
     45         code = code | winTopBitCode;
     46     
     47     return code;
     48 }
     49 
     50 void swapPts (wcPt2D * p1, wcPt2D * p2) // TODO 为什么要用指针?
     51 {
     52     wcPt2D tmp;
     53     tmp = * p1; * p1 = * p2; * p2 = tmp;
     54 }
     55 
     56 void swapCode (GLubyte * c1, GLubyte * c2)
     57 {
     58     GLubyte tmp;
     59     tmp = * c1; * c1 = * c2; * c2 = tmp;
     60 }
     61 
     62 void renewWinVertexes (wcPt2D * winMin, wcPt2D * winMax)
     63 {
     64     wcPt2D tmp1, tmp2;
     65     tmp1.setCoords(fmin(winMin->getx(), winMax->getx()), fmin(winMin->gety(), winMax->gety()));
     66     tmp2.setCoords(fmax(winMin->getx(), winMax->getx()), fmax(winMin->gety(), winMax->gety()));
     67     * winMin = tmp1;
     68     * winMax = tmp2;
     69 }
     70 
     71 void matrix3x3SetIdentity (Matrix3x3 matIden3x3)
     72 {
     73     GLint row, col;
     74     for(row = 0; row < 3; row++)
     75     {
     76         for(col = 0; col < 3; col++)
     77         {
     78             matIden3x3[row][col] = (row == col);
     79         }
     80     }
     81 }
     82 
     83 void matrix3x3Premultiply (Matrix3x3 m1, Matrix3x3 m2)
     84 {
     85     GLint row, col;
     86     Matrix3x3 matTemp;
     87     
     88     for(row = 0; row < 3; row++)
     89     {
     90         for(col = 0; col < 3; col++)
     91         {
     92             matTemp[row][col] = m1[row][0] * m2 [0][col] + m1[row][1] * m2 [1][col] + m1[row][2] * m2 [2][col];
     93         }
     94     }
     95     
     96     for(row = 0; row < 3; row++)
     97     {
     98         for(col = 0; col < 3; col++)
     99         {
    100             m2[row][col] = matTemp[row][col];
    101         }
    102     }
    103 }
    104 
    105 void rotate2D (wcPt2D pivotPt, GLfloat theta)
    106 {
    107     matrix3x3SetIdentity(matRotate);
    108     
    109     matRotate[0][0] = cos(theta);
    110     matRotate[0][1] = -sin(theta);
    111     matRotate[0][2] = pivotPt.getx() * (1 - cos(theta)) + pivotPt.gety() * sin(theta);
    112     matRotate[1][0] = sin(theta);
    113     matRotate[1][1] = cos(theta);
    114     matRotate[1][2] = pivotPt.gety() * (1 - cos(theta)) + pivotPt.getx() * sin(theta);
    115 }
    116 
    117 void transformVerts2D (wcPt2D * verts)
    118 {
    119     GLfloat tempx, tempy;
    120     
    121     tempx = matRotate[0][0] * verts->getx() + matRotate[0][1] * verts->gety() + matRotate[0][2];
    122     tempy = matRotate[1][0] * verts->getx() + matRotate[1][1] * verts->gety() + matRotate[1][2];
    123     
    124     verts->setCoords(tempx, tempy);
    125 }
    126 
    127 void slopeWith4Vertexes (wcPt2D winMin, wcPt2D winMax, wcPt2D p1)
    128 {
    129     m1 = (p1.gety() - winMin.gety()) / (p1.getx() - winMin.getx());
    130     m2 = (p1.gety() - winMax.gety()) / (p1.getx() - winMin.getx());
    131     m3 = (p1.gety() - winMax.gety()) / (p1.getx() - winMax.getx());
    132     m4 = (p1.gety() - winMin.gety()) / (p1.getx() - winMax.getx());
    133     
    134 //    std::cout << "slope : m1 : " << m1 << " m2 : " << m2 << " m3 : " << m3 << " m4 : " << m4 << std::endl;
    135 }
    136 
    137 void lineClipNLN (wcPt2D winMin, wcPt2D winMax, wcPt2D p1, wcPt2D p2)
    138 {
    139     GLubyte code1, code2;
    140     GLint plotLine = false, done = false;
    141     GLfloat m = 0.0;
    142     
    143     while (!done)
    144     {
    145         code1 = encode(p1, winMin, winMax);
    146         code2 = encode(p2, winMin, winMax);
    147         if(accept(code1, code2))
    148         {
    149             plotLine = true;
    150             done = true;
    151         }
    152         else
    153         {
    154             if(reject(code1, code2))
    155             {
    156                 std::cout << "1 rejected line!" << std::endl;
    157                 done = true;
    158             }
    159             else
    160             {
    161                 // 有一个点在裁剪区域内
    162                 if(inside(code1) || inside(code2))
    163                 {
    164                     plotLine = true;
    165                     done = true;
    166                     if(!inside(code1))
    167                     {
    168                         swapPts(&p1, &p2);
    169                         swapCode(&code1, &code2);
    170                     }
    171                     wcPt2D topLeft, bottomRight;
    172                     topLeft.setCoords(winMin.getx(), winMax.gety());
    173                     bottomRight.setCoords(winMax.getx(), winMin.gety());
    174                     if(p1.equals(winMin) || p1.equals(winMax) || p1.equals(topLeft) || p1.equals(bottomRight))
    175                     {
    176                         p2.setCoords(p1.getx(), p1.gety());
    177                     }
    178                     else
    179                     {
    180                         slopeWith4Vertexes(winMin, winMax, p1);
    181                         
    182                         if(p1.getx() != p2.getx())
    183                         {
    184                             m = (p2.gety() - p1.gety()) / (p2.getx() - p1.getx());
    185                         
    186                             if(m <= m1 && m >= m2 && (code2 & winLeftBitCode))
    187                             {//L
    188                                 p2.setCoords(winMin.getx(), p1.gety() + m * (winMin.getx() - p1.getx()));
    189                             }
    190                             else if(m <= m3 && m >= m4 && (code2 & winRightBitCode))
    191                             {//R
    192                                 p2.setCoords(winMax.getx(), p1.gety() + m * (winMax.getx() - p1.getx()));
    193                             }
    194                             else if((m > m3 || m < m2) && (code2 & winTopBitCode))
    195                             {//T
    196                                 p2.setCoords(p1.getx() + (winMax.gety() - p1.gety())/m, winMax.gety());
    197                             }
    198                             else if((m > m1 || m < m4) && (code2 & winBottomBitCode))
    199                             {//B
    200                                 p2.setCoords(p1.getx() + (winMin.gety() - p1.gety())/m, winMin.gety());
    201                             }
    202                         }
    203                         else
    204                         {
    205                             if(p2.gety() > winMax.gety())
    206                             {
    207                                 p2.setCoords(p2.getx(), winMax.gety());
    208                             }
    209                             else
    210                             {
    211                                 p2.setCoords(p2.getx(), winMin.gety());
    212                             }
    213                         }
    214                     }
    215                 }
    216                 else
    217                 {
    218                     if(code1 == 0x01 || code2 == 0x01)
    219                     // 有一个点的区域码是0001,即在裁剪区域正左侧,L的情况在上一个if中包含,这里只会有LT,LR,LB和rejected的情况
    220                     {
    221                         if(code1 != 0x01)
    222                         {
    223                             swapPts(&p1, &p2);
    224                             swapCode(&code1, &code2);
    225                         }
    226                         slopeWith4Vertexes(winMin, winMax, p1);
    227                         if(p1.getx() != p2.getx())
    228                         {
    229                             m = (p2.gety() - p1.gety()) / (p2.getx() - p1.getx());
    230                         }
    231                         if(m < m1 || m > m2)
    232                         {
    233                             std::cout << "2 rejected line!" << std::endl;
    234                             done = true;
    235                         }
    236                         else
    237                         {
    238                             p1.setCoords(winMin.getx(), p1.gety() + m * (winMin.getx() - p1.getx()));
    239                             if((m <= m2 && m >= m3) && (code2 & winTopBitCode))
    240                             {//LT
    241                                 p2.setCoords(p1.getx() + (winMax.gety() - p1.gety())/m, winMax.gety());
    242                             }
    243                             else if((m < m3 && m >= m4) && (code2 & winRightBitCode))
    244                             {//LR
    245                                 p2.setCoords(winMax.getx(), p1.gety() + m * (winMax.getx() - p1.getx()));
    246                             }
    247                             else if((m < m4 && m >= m1) && (code2 & winBottomBitCode))
    248                             {//LB
    249                                 p2.setCoords(p1.getx() + (winMin.gety() - p1.gety())/m, winMin.gety());
    250                             }
    251                             plotLine = true;
    252                             done = true;
    253                         }
    254                     }
    255                     else if(code1 == (winLeftBitCode | winTopBitCode) || code2 == (winLeftBitCode | winTopBitCode))
    256                         // 有一个点在裁剪区域外左上角的情况,这里的L、T情况已经在第一个if里包含
    257                     {
    258                         if(code1 != (winLeftBitCode | winTopBitCode))
    259                         {
    260                             swapPts(&p1, &p2);
    261                             swapCode(&code1, &code2);
    262                         }
    263                         
    264                         slopeWith4Vertexes(winMin, winMax, p1);
    265                         if(p1.getx() != p2.getx())
    266                         {
    267                             m = (p2.gety() - p1.gety()) / (p2.getx() - p1.getx());
    268                         }
    269                         if(m > m3 || m < m1)
    270                         {
    271                             std::cout << "3 rejected line!" << std::endl;
    272                             done = true;
    273                         }
    274                         else
    275                         {
    276                             plotLine = true;
    277                             done = true;
    278                             if(m <= m3 && m >= m4)
    279                             {
    280                                 p2.setCoords(winMax.getx(), p1.gety() + m * (winMax.getx() - p1.getx()));
    281                                 if(m2 > m4 && m <= m2)
    282                                 {//LR
    283                                     p1.setCoords(winMin.getx(), p1.gety() + m * (winMin.getx() - p1.getx()));
    284                                 }
    285                                 else
    286                                 {//TR
    287                                     p1.setCoords(p1.getx() + (winMax.gety() - p1.gety())/m, winMax.gety());
    288                                 }
    289                             }
    290                             else if(m < m4 && m >= m1)
    291                             {
    292                                 p2.setCoords(p1.getx() + (winMin.gety() - p1.gety())/m, winMin.gety());
    293                                 if(m2 < m4 && m >= m2)
    294                                 {//TB
    295                                     p1.setCoords(p1.getx() + (winMax.gety() - p1.gety())/m, winMax.gety());
    296                                 }
    297                                 else
    298                                 {//LB
    299                                     p1.setCoords(winMin.getx(), p1.gety() + m * (winMin.getx() - p1.getx()));
    300                                 }
    301                             }
    302                         }
    303                     }
    304                     else
    305                     {
    306                         center.setCoords((winMin.getx() + winMax.getx())/2, (winMin.gety() + winMax.gety())/2);
    307                         
    308                         if(code1 == (winLeftBitCode | winBottomBitCode) || code2 == (winLeftBitCode | winBottomBitCode))
    309                         {//LB
    310                             delta = -pi/2;
    311                         }
    312                         else if(code1 == winBottomBitCode || code2 == winBottomBitCode)
    313                         {//B
    314                             delta = -pi/2;
    315                         }
    316                         else if(code1 == (winBottomBitCode | winRightBitCode) || code2 == (winBottomBitCode | winRightBitCode))
    317                         {//BR
    318                             delta = pi;
    319                         }
    320                         else if(code1 == winRightBitCode || code2 == winRightBitCode)
    321                         {//R
    322                             delta = pi;
    323                         }
    324                         else if(code1 == (winRightBitCode | winTopBitCode) || code2 == (winRightBitCode | winTopBitCode))
    325                         {//TR
    326                             delta = pi/2;
    327                         }
    328                         else if(code1 == winTopBitCode || code2 == winTopBitCode)
    329                         {//T
    330                             delta = pi/2;
    331                         }
    332                         rotate2D(center, delta);
    333                         transformVerts2D(&p1);
    334                         transformVerts2D(&p2);
    335                         transformVerts2D(&winMin);
    336                         transformVerts2D(&winMax);
    337                         renewWinVertexes(&winMin, &winMax);
    338                     }
    339                 }
    340             }
    341         }
    342     }
    343     
    344     if(plotLine)
    345     {
    346         if(delta != 0)
    347         {
    348             rotate2D(center, -delta);
    349             transformVerts2D(&p1);
    350             transformVerts2D(&p2);
    351         }
    352         lineBres(round(p1.getx()), round(p1.gety()), round(p2.getx()), round(p2.gety()));
    353     }
    354     delta = 0;
    355 }
    NLN二维线段裁剪算法

    完整代码路径:https://github.com/p0e0o0p0l0e0/Computer_Graphics/tree/f9a7ad1987586445d780de2461d423af0dd9ba6a

  • 相关阅读:
    hdu 4520 小Q系列故事——最佳裁判 解题报告
    hdu 4505 小Q系列故事——电梯里的爱情 解题报告
    hdu 4524 郑厂长系列故事——逃离迷宫 解题报告
    JAVA泛类型示例
    Perl多进程处理Web日志
    Perl单线程日志分析工具
    Perl DBI使用实例
    JAVA(时间对比排序程序)
    软件通信之HTTP通信协议
    Android中级之网络数据解析一之Json解析
  • 原文地址:https://www.cnblogs.com/p0e0o0p0l0e0/p/6931194.html
Copyright © 2020-2023  润新知