北美程序员面试干货程序员

二维观察

2016-04-28  本文已影响292人  Gaolex
二维观察
希望大家喜欢,点赞哦

思维导图的矢量图 访问密码 e9ed

深入讨论在输出设备上显示二维图形的问题

[TOC]

1. 二维观察流水线

世界坐标系的位置首先转到与我们要对场景进行观察所对应的观察坐标系,然后,对象位置变换到该场景的一个二维投影,该投影对应于我们在输出屏幕上看到的结果。然后将该场景存入规范化坐标系(规范化设备坐标系),最后,图形经扫描转换到光栅系统的刷新缓存中进行显示。显示设备的坐标系称为设备坐标系(屏幕坐标系)

2. 裁剪窗口

应用程序要得到特殊的裁剪效果,可通过选择裁剪窗口的不同性质、大小和方向来实现

2.1 观察坐标系裁剪窗口

二维观察变换的一般方法是在世界坐标系中制定一个观察坐标。以该标系为参考通过选定方向和位置来制定矩形裁剪窗口。

二维观察坐标系的确定:

2.2 世界坐标系裁剪窗口

如果要旋转一个二维场景,可以简单地在世界坐标系中将对象旋转(可能有平移)到所需位置并建立裁剪窗口;(步骤同上)

3. 规范化和视口变换

规范化和窗口-视口转换合并成一步/规范化和裁剪在窗口-视口转换之前进行

3.1 裁剪窗口到规范化视口的映射

  1. 以点(xwmin,ywmin)为中心执行缩放变换,将窗口变幻成视口的大小
  2. 将(xwmin,ywmin)移到(xvmin,yvmin

3.2 裁剪窗口到规范化正方形的映射

二维观察的另一种方法是先将裁剪窗口变换到规范正方形,在规范化坐标系中进行裁剪,然后将场景描述变换到屏幕坐标系中指定的视口中

3.3 字符串的显示

  • 保持字符串的大小不变 ==》 点阵字体

3.4 分画面效果和多输出设备

工作站变换:到所选输出设备的映射
工作站函数

  1. 用于为选定输出设备制定裁剪窗口,用工作站号来标识;
  2. 用来为该设计建立相应的视口

4. OpenGL二维观察函数

GLU库函数提供了制定二维裁剪窗口的函数;GLUT库提供了处理显示窗口的函数。

4.1 OpenGL投影模式

//下列定义裁剪窗口和视口的函数将应用于投影矩阵
glMatrixMode(GL_PROJECTION);//制定投影矩阵作为当前矩阵,它原来设定为单位矩阵
glLoadIdentity();//矩阵重新设定为单位矩阵

4.2 GLU裁剪窗口函数

gluOrtho2D(xwmin,xwmax,ywmin,ywmax);//定义一个二维裁剪窗口、该函数给出了将场景映射到屏幕的正交投影

4.3 OpenGL视口函数

glViewport(xvmin,yvmin,vpWidth,vpHeight);//指定视口参数
glGetIntegerv(GL_VIEWPORT,vpArray);//获取当前活动视口参数的查询函数,在交互式应用中,我们可以使用该函数获得光标所在视口的参数

4.4 建立GLUT显示窗口

//初始化glut
glutInit(&argc,argv);
//定义显示窗口并选择其尺寸及位置
glutInitWindowPosition(xTopLeft,yTopLeft);//位置
glutInitWindowSize(dwWidth,dwHeight);//宽高
glutCreateWindow("Title of Display Window");//标题

4.5 设定GLUT显示窗口的模式和颜色

//显示窗口的参数有下列函数选择
glutInitDisplayMode(mode);/*选择颜色模式(RGB或索引号)和不同的缓存组合,所选参数以逻辑‘或操作方式组合’ 默认模式是但缓存和RGB(或RGBA)颜色模式。eg:glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); */
glClearColor(red,greeb,blue,alpha);//显示窗口的背景颜色(RGB模式)
glClearIndex(index);//显示窗口的背景颜色(颜色索引模式)

4.6 GLUT显示窗口标识

windowID = glutCreatWindow("A Display Window");//记录窗口的标识

4.7 删除GLUT显示窗口

glutDestroyWindow(windowID)

4.8 当前GLUT显示窗口

glutSetWindow(windowID);//指定显示窗口
currentWindowID = glutGetWindow();//询问系统当前显示窗口

4.9 修改GLUT显示窗口的位置和大小

glutPositionWindow(xNewTopLeft,yNewTopLeft);//改变当前显示窗口的位置
glutReshapeWindow(dwNewWidth);//设定当前显示窗口的尺寸
glutFullScreen();//将当前显示窗口扩展到整个屏幕
glutReshapeFunc(winReshapeFun);//调整显示窗口的变化   4.16

4.10 管理多个GLUT显示窗口

glutIconifyWindow();//将当前显示窗口变为一个图符,该图符将使用赋予该窗口的名字来标记
glutSetIconTitle("Icon Name");//改变上面的图符名字
glutSetWindowTitle("New window Name");//改变显示窗口的名字
glutSetWindow(windowID);//制定某个显示窗口为当前窗口
glutPopWindow();//使当前窗口成为所有其他窗口之前的窗口
glutPushWindow();//使当前窗口成为所有其他窗口之后的窗口
glutHideWindow();//让当前窗口从屏幕消失

glutShowWindow();//将隐藏的或变为图符的显示窗口指定为当前显示窗口并调研该函数让它重新显示

4.11 GLUT子窗口

glutCreateSubWindow(windowID,xBottomLeft,yBottomLeft,width,height);//创建子窗口

4.12 显示窗口屏幕光标形状的选择

glutSetCursor(shape);//为当前窗口选择平模光标的形状。shape为符号常量

4.13 在GLUT显示窗口中观察图形对象

glutDisplayFunc(pictureDescrip);//指定当前窗口的显示内容,pictureDescrip是一种回调函数
glutPostRedisplay();//指出当前显示窗口的内容应该更新

4.14 执行应用程序

glutMainLoop();//启动程序执行

4.15 其他GLUT函数

glutIdleFunc(function);//没有其他时间需要处理是可以指定其运行,该函数的参数可以是一个背景函数或更新一个动画参数的过程
glutGet(stateParam);//查询系统某些参数的当前值

4.16 OpenGL的二维观察程序例

#include <GL/glut.h>

class wcPt2D {
public:
    GLfloat x, y;
};

void init(void)
{
    /*  Set color of display window to white.  */
    //设置背景为白
    glClearColor(1.0, 1.0, 1.0, 0.0);

    /*  Set parameters for world-coordinate clipping window.  */
    glMatrixMode(GL_PROJECTION);//GL_PROJECTION,对投影矩阵应用随后的矩阵操作.
    gluOrtho2D(-100.0, 100.0, -100.0, 100.0);

    /*  Set mode for constructing geometric transformation matrix.  */

    glMatrixMode(GL_MODELVIEW); //GL_MODELVIEW, 对模型视景矩阵堆栈应用随后的矩阵操作.
}

void triangle(wcPt2D *verts)
{
    GLint k;

    glBegin(GL_TRIANGLES);
    for (k = 0; k < 3; k++)
        glVertex2f(verts[k].x, verts[k].y);
    glEnd();
}

void displayFcn(void)
{
    /*  Define initial position for triangle.  */
    wcPt2D verts[3] = { { -50.0, -25.0 },{ 50.0, -25.0 },{ 0.0, 50.0 } };

    glClear(GL_COLOR_BUFFER_BIT);   //  Clear display window.
    //把整个窗口清除为当前的清除颜色
    glColor3f(0.0, 0.0, 1.0);       //  Set fill color to blue.
    
    glViewport(0, 0, 300, 300);     //  Set left viewport.
    /*
    glViewport(GLint x, GLint y, GLsizei width, GLsizei height)为其函数原型。
        X,Y————以像素为单位,指定了视口的左下角(在第一象限内,以(0,0)为原点的)位置。
        width,height————表示这个视口矩形的宽度和高度,根据窗口的实时变化重绘窗口。
    */
    triangle(verts);                //  Display triangle.

                                    /*  Rotate triangle and display in right half of display window.  */
    glColor3f(1.0, 0.0, 0.0);         //  Set fill color to red. 
    glViewport(300, 0, 300, 300);     //  Set right viewport.  
    glRotatef(90.0, 0.0, 0.0, 1.0);   //  Rotate about z axis.  
    //当前坐标系统关于Z轴旋转90度
    triangle(verts);           //  Display red rotated triangle.

    glFlush();//强制刷新缓冲,保证绘图命令将被执行,而不是存储在缓冲区中等待其他的OpenGL命令。
}

void main(int argc, char ** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowPosition(50, 50);
    glutInitWindowSize(600, 300);
    glutCreateWindow("Split-Screen Example");

    init();
    glutDisplayFunc(displayFcn);

    glutMainLoop();
}


5. 裁剪算法

6. 二维点裁剪

xwmin =< x =< xwmax
ywmin =< y =< ywmax
若点不满足这四个等式中任何一个,即裁剪掉改点

7. 二维线段裁剪

线段裁剪算法通过一系列的测试和求交计算来判断是否整条线段或其中的某部分可以保存下来

7.1 Cohen-Sutherland线段裁剪算法

该算法通过初始测试来减少交点计算,从而减少线段裁剪算法所用的时间

区域码 窗口及区域编码 裁剪 算法的步骤
通过一个矩形的裁剪区域将整个屏幕分成9个部分,并为每一个部分赋予相应的区域码,然后根据端点的位置确定这个端点的区域码。
先判断能否完全接受或者完全排除一条线段,若以上2个判断无法直接得出,则逐步裁剪,选取一个位于裁剪区外的端点,把端点的区域码和裁剪边界的区域码进行逻辑与运算,若结果为真,则端点在该裁剪边界外部,这时将端点移向线段和该边界的交点处,如此循环,直到裁剪结束。
#include <Windows.h>
#include <gl/glut.h>
//////////////////////////////////////////////////////////////////////////
//区域码
const GLint leftBitCode=0x1;
const GLint rightBitCode=0x2;
const GLint buttonBitCode=0x4;
const GLint topBitCode=0x8;
GLint winWidth=640,winHeight=480;
class screenPT
{
public:
    GLfloat x,y;
};
inline GLint inside(GLint code){return GLint(!code);}   //判断点是否在裁剪区内
inline GLint reject(GLint code1,GLint code2){return GLint(code1&code2);}    //判断能否完全排除一条线段
inline GLint accept(GLint code1,GLint code2){return GLint(!(code1 | code2));}   //判断能否完全接受一条线段
inline void swapPT(screenPT& a,screenPT& b){screenPT t=a;a=b;b=t;}  //交换两个点
inline void swapCode(GLubyte& a,GLubyte& b){GLubyte t=a;a=b;b=t;}   //交换两个区域码
//确定一个点所在位置的区域码
GLubyte encode(const screenPT& p,const screenPT& winMin,const screenPT& winMax)
{
    GLubyte code=0x00;
    if(p.x<winMin.x)
        code |= leftBitCode;
    if(p.x>winMax.x)
        code |= rightBitCode;
    if(p.y<winMin.y)
        code |= buttonBitCode;
    if(p.y>winMax.y)
        code |= topBitCode;
    return code;
}
//在屏幕上画一条未裁剪的线,由裁剪函数调用
void drawOneLine(const screenPT& a,const screenPT& b)
{
    glBegin(GL_LINES);
        glVertex2f(a.x,a.y);
        glVertex2f(b.x,b.y);
    glEnd();
}
//裁剪函数
void lineClip(screenPT winMin,screenPT winMax,screenPT lineBegin,screenPT lineEnd)
{
    GLubyte code1,code2;    //保存两个端点的区域码
    GLboolean done=false,plotLine=false;    //判断裁剪是否结束和是否要绘制直线
    GLfloat k;              //斜率
    while(!done)
    {
        code1 = encode(lineBegin,winMin,winMax);
        code2 = encode(lineEnd,winMin,winMax);
        if(accept(code1,code2))         //当前直线能完全绘制
        {
            done=true;
            plotLine=true;
        }
        else
        {
            if(reject(code1,code2))     //当前直线能完全排除
                done = true;
            else
            {
                if(inside(code1))   //若lineBegin端点在裁剪区内则交换两个端点使它在裁剪区外
                {
                    swapPT(lineBegin,lineEnd);
                    swapCode(code1,code2);
                }
                //计算斜率
                if(lineBegin.x != lineEnd.x)
                    k = (lineEnd.y-lineBegin.y)/(lineEnd.x-lineBegin.x);
                //开始裁剪,以下与运算若结果为真,
                //则lineBegin在边界外,此时将lineBegin移向直线与该边界的交点
                if(code1 & leftBitCode)
                {
                    lineBegin.y += (winMin.x-lineBegin.x)*k;
                    lineBegin.x = winMin.x;
                }
                else if(code1 & rightBitCode)
                {
                    lineBegin.y += (winMax.x-lineBegin.x)*k;
                    lineBegin.x = winMax.x;
                }
                else if(code1 & buttonBitCode)
                {
                    if(lineBegin.x != lineEnd.x)
                        lineBegin.x += (winMin.y-lineBegin.y)/k;
                    lineBegin.y = winMin.y;
                }
                else if(code1 & topBitCode)
                {
                    if(lineBegin.x != lineEnd.x)
                        lineBegin.x += (winMax.y-lineBegin.y)/k;
                    lineBegin.y = winMax.y;
                }
            }
        }
    }
    if(plotLine)
        drawOneLine(lineBegin,lineEnd); //绘制裁剪好的直线
}
//////////////////////////////////////////////////////////////////////////
void rect(screenPT winMin,screenPT winMax)
{
    glBegin(GL_LINE_LOOP);
        glVertex2f(winMin.x,winMin.y);
        glVertex2f(winMax.x,winMin.y);
        glVertex2f(winMax.x,winMax.y);
        glVertex2f(winMin.x,winMax.y);
    glEnd();
}
void init()
{
    glViewport(0,0,winWidth,winHeight);
    glClearColor(1.0,1.0,1.0,0.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0,winWidth,0,winHeight);
    glMatrixMode(GL_MODELVIEW);
}
void display()
{
    screenPT winMin,winMax,lineBegin,lineEnd;
    winMin.x=100.0; winMin.y=50.0;
    winMax.x=400.0; winMax.y=300.0;
    lineBegin.x=0.0;    lineBegin.y=0.0;
    lineEnd.x=winWidth; lineEnd.y=winHeight;
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0,0.0,0.0);
    rect(winMin,winMax);    //为裁剪区域绘制一个边框
    lineClip(winMin,winMax,lineBegin,lineEnd);  
    lineBegin.y=240.0;  lineEnd.y=240.0;
    lineClip(winMin,winMax,lineBegin,lineEnd);  
    lineBegin.x=320.0;  lineBegin.y=0.0;
    lineEnd.x=320.0;    lineEnd.y=winHeight;
    lineClip(winMin,winMax,lineBegin,lineEnd);
    glFlush();
}
int main(int argc,char** argv)
{
    glutInit(&argc,argv);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(winWidth,winHeight);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutCreateWindow("my app");
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

7.2 梁友栋-Barsky 线段裁剪算法

Cyrus和Beck用参数化方法提出了比Cohen-Sutherland更有效的算法。后来梁友栋和Barsky独立地提出了更快的参数化线段裁剪算法,也称为Liany-Barsky(LB)算法。

xmin≤x1+ u·Δx≤xmax

ymin≤y1+ u·Δy≤ymax

这四个不等式可以表示为:u·pk ≤qk , k=1,2,3,4

其中,p、q定义为:

p1=-Δx, q1=x1-xmin
p2= Δx, q2=xmax-x1
p3=-Δy, q3=y1-ymin
p4= Δy, q4=ymax-y1

可得:

任何平行于窗口某边界的直线,其pk=0,k值对应于相应的边界(k=1,2,3,4对应于左、右、下、上边界)。如果还满足qk<0,则线段完全在边界外,应舍弃该线段。如果pk=0并且qk≥0,则线段平行于窗口某边界并在窗口内.
1、当pk<0时,线段从裁剪边界延长线的外部延伸到内部;
2、当pk>0时,线段从裁剪边界延长线的内部延伸到外部;

梁友栋-Barsky 线段裁剪算法实现步骤
1、 初始化线段交点的参数:u1=0,u2=1;
2、 计算出各个裁剪边界的p、q值;
3、 根据p、q来判断:是舍弃线段还是改变交点的参数。
(1) 当p<0时,参数r用于更新u1;      (u1=max{u1,…,rk})
(2) 当p>0时,参数r用于更新u2。      (u2=min{u2,…,rk})
(3) 如果更新了u1或u2后,使u1>u2,则舍弃该线段。
(4) 当p=0且q<0时,因为线段平行于边界并且位于边界之外,则舍弃该线段。见下图所示。
4、 p、q的四个值经判断后,如果该线段未被舍弃,则裁剪线段的端点坐标由参数u1和u2的值决定。

代码:

class wcPt2D 
{
   private:
      GLfloat x, y;
   public:
   /*  Default Constructor: initialize position as (0.0, 0.0).  */
   wcPt3D ( ) {x = y = 0.0;}
   
   setCoords (GLfloat xCoord, GLfloat yCoord) {
      x = xCoord;
      y = yCoord;
   }

   GLfloat getx ( ) const {
      return x;
   }

   GLfloat gety ( ) const {
      return y;
   }
};

inline GLint round (const GLfloat a)  { return GLint (a + 0.5); }

GLint clipTest (GLfloat p, GLfloat q, GLfloat * u1, GLfloat * u2)
{
    GLfloat r;
    GLint returnValue = true;

    if (p < 0.0) 
    {
        r = q / p;
        if (r > *u2)
            returnValue = false;
        else if (r > *u1)
            *u1 = r;
    }
    else if (p > 0.0) 
    {
        r = q / p;
        if (r < *u1)
            returnValue = false;
        else if (r < *u2)
            *u2 = r;
    }
    else
    /*  Thus p = 0 and line is parallel to clipping boundary.  */
        if (q < 0.0)
        /*  Line is outside clipping boundary.  */
            returnValue = false;

    return (returnValue);
}

void lineClipLiangBarsk (wcPt2D winMin, wcPt2D winMax, wcPt2D p1, wcPt2D p2)
{
    GLfloat u1 = 0.0, u2 = 1.0, dx = p2.getx ( ) - p1.getx ( ), dy;

    if (clipTest (-dx, p1.getx ( ) - winMin.getx ( ), &u1, &u2))
        if (clipTest (dx, winMax.getx ( ) - p1.getx ( ), &u1, &u2)) 
        {
            dy = p2.gety ( ) - p1.gety ( );
            if (clipTest (-dy, p1.gety ( ) - winMin.gety ( ), &u1, &u2))
            if (clipTest (dy, winMax.gety ( ) - p1.gety ( ), &u1, &u2)) 
            {
                if (u2 < 1.0)
                {
                    p2.setCoords (p1.getx ( ) + u2 * dx, p1.gety ( ) + u2 * dy);
                }
            if (u1 > 0.0) 
            {
                p1.setCoords (p1.getx ( ) + u1 * dx, p1.gety ( ) + u1 * dy);
            }
            lineBres (round (p1.getx ( )), round (p1.gety ( )),round (p2.getx ( )), round (p2.gety ( )));
            }
        }
}

示例

梁友栋-Barsky 线段裁剪算法示例 线段的参数方程 结果

梁友栋-Barsky 线段裁剪算法比Cohen-Sutherland线段裁剪算法更有效率,因为减少了交点次数计算

7.3 Nicholl-Lee-Nicholl 线段裁剪算法

7.4 非矩形多边形裁剪窗口的线段裁剪

  1. 基于参数化直线方程的算法
  2. 对于凹多边形:

7.5 非线性裁剪窗口边界的线段裁剪

也可以使用园或者其他期限边界进行裁剪,但使用这些区域的裁剪算法的速度较慢

8. 多边形填充区裁剪

对于多边形,线段裁剪进行处理后的多边形边界显示为不连接的线段

直接采用直线段裁剪的结果 正确的裁剪结果

8.1 Sutherland-Hodgman 多边形裁剪

基本思想:以多边形顶点为初始集合, 首先用窗口左边界剪裁多边形,产生新的顶点序列。新的顶点集依次传给下边界、右边界和上边界进行处理。 SH算法最终输出定义剪裁后的多边形边界的顶点序列

用左边界裁剪 输入:ABCDEFGH 输出:A12DEFGH 用下边界裁剪 输入:A12DEFGH 输出:A134D56FGH 用右边界裁剪 输入:A134D56FGH 输出:A134D5678GH 用上边界裁剪 输入:A134D5678GH 输出:K34D56789IHJ

沿着多边形依次处理顶点的情况
1、 若第一点在窗口边界外、第二点在窗口边界内,将交点I与窗口内的点P输入顶点表

输出I、P

2、 若两顶点都在窗口边界内,只将第二点输入顶点表,如P

输出P

3、若第一点在窗口边界内、第二点在窗口边界外,将交点I输入顶点表

输出I

4、若两点均在窗口边界外,不输入任何点

不输出

代码:

typedef enum { Left, Right, Bottom, Top } Boundary;
const GLint nClip = 4;
//检验某点是否在内部
GLint inside (wcPt2D p, Boundary b, wcPt2D wMin, wcPt2D wMax)
{
    switch (b)
    {
        case Left:   if (p.x < wMin.x) return (false); break;
        case Right:  if (p.x > wMax.x) return (false); break;
        case Bottom: if (p.y < wMin.y) return (false); break;
        case Top:    if (p.y > wMax.y) return (false); break;
    }
    return (true);
}
//检验线段是否与边界相交
GLint cross (wcPt2D p1, wcPt2D p2, Boundary winEdge, wcPt2D wMin, wcPt2D wMax)
{
    if (inside (p1, winEdge, wMin, wMax) == inside (p2, winEdge, wMin, wMax))
        return (false);
    else 
        return (true);
}
//intersect(vt.  横断,横切,横穿;vt.& vi.  (指线条、道路等)相交,交叉;)
wcPt2D intersect (wcPt2D p1, wcPt2D p2, Boundary winEdge, wcPt2D wMin, wcPt2D wMax)
{
    wcPt2D iPt;
    GLfloat m;

    if (p1.x != p2.x) 
        m = (p1.y - p2.y) / (p1.x - p2.x);
    switch (winEdge) 
    {
        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);
}

void clipPoint (wcPt2D p, Boundary winEdge, wcPt2D wMin, wcPt2D wMax,wcPt2D * pOut, int * cnt, wcPt2D * first[], wcPt2D * s)
{
    wcPt2D iPt;

    /* If no previous point exists for this clipping boundary,
    * save this point.
    */
    if (!first[winEdge])
        first[winEdge] = &p;
    else
        /*  Previous point exists.  If p and previous point cross
        *  this clipping boundary, find intersection.  Clip against
        *  next boundary, if any.  If no more clip boundaries, add
        *  intersection to output list.  
        */
        if (cross (p, s[winEdge], winEdge, wMin, wMax))
        {
            iPt = intersect (p, s[winEdge], winEdge, wMin, wMax);
            if (winEdge < Top)
                clipPoint (iPt, b+1, wMin, wMax, pOut, cnt, first, s);
                else 
                {
                    pOut[*cnt] = iPt;  (*cnt)++; 
                }
        }

    /*  Save p as most recent point for this clip boundary.  */
    s[winEdge] = p;  

    /*  For all, if point inside, proceed to next boundary, if any.  */
    if (inside (p, winEdge, wMin, wMax))
        if (winEdge < Top)
            clipPoint (p, winEdge + 1, wMin, wMax, pOut, cnt, first, s);
        else 
        {
            pOut[*cnt] = p;  (*cnt)++;
        }
}

void closeClip (wcPt2D wMin, wcPt2D wMax, wcPt2D * pOut,GLint * cnt, wcPt2D * first [ ], wcPt2D * s)
{
    wcPt2D pt;
    Boundary winEdge;

    for (winEdge = Left; winEdge <= Top; winEdge++)
    {
        if (cross (s[winEdge], *first[winEdge], winEdge, wMin, wMax)) 
        {
            pt = intersect (s[winEdge], *first[winEdge], winEdge, wMin, wMax);
            if (winEdge < Top)
                clipPoint (pt, winEdge + 1, wMin, wMax, pOut, cnt, first, s);
            else 
            {
                pOut[*cnt] = pt;  (*cnt)++;
            }
        }
    }
}

GLint polygonClipSuthHodg (wcPt2D wMin, wcPt2D wMax, GLint n, wcPt2D * pIn, wcPt2D * pOut)
{
    /*  Parameter "first" holds pointer to first point processed for 
    *  a boundary; "s" holds most recent point processed for boundary.  
    */
    wcPt2D * first[nClip] = { 0, 0, 0, 0 }, s[nClip];//指针数组
    GLint k, cnt = 0;

    for (k = 0; k < n; k++)
        clipPoint (pIn[k], Left, wMin, wMax, pOut, &cnt, first, s);

    closeClip (wMin, wMax, pOut, &cnt, first, s);
    return (cnt);
}

缺点:对凹多边形裁剪会出现多余的线

8.2 Weiler-Atherton多边形裁剪

基本思想:有时延多边形某一条边的方向来处理顶点,有时沿窗口的边界方向处理。一般按逆时针(顺时针)以及当前处理多边形顶点对是由外到内还是由内到外

裁剪前 裁剪后

8.3 非矩形的多边形窗口的多边形裁剪

  1. 梁友栋-Barsky 线段裁剪算法
  2. Weiler-Atherton多边形裁剪

8.4 非线性裁剪窗口边界的多边形裁剪

  1. 先用直线逼近边界,然后使用一般的多边形裁剪窗口算法对其进行处理
  2. 使用线段裁剪中讨论的通用算法

9. 曲线的裁剪

使用类似上一节的方法进行裁剪

10. 文字的裁剪

  1. 全部保留或者全部舍弃字符串的裁剪策略,速度最快


    裁剪前
裁剪后
  1. 全部保留或者舍弃字符
裁剪前 裁剪后
  1. 裁剪单个字符的组成部分
裁剪前 裁剪后

11. 小结

谢谢观看
希望大家喜欢,点赞哦

上一篇 下一篇

猜你喜欢

热点阅读