計算機圖形學 opengl版本 第三版------胡事民 第三章更多的繪圖工具

opengl  計算機圖形學 第三版   第二部分   第三章更多的繪圖工具ios

3.1   概述c++

第2章中  咱們繪圖使用的是屏幕窗口的基礎座標系    以像素爲單位  算法

屏幕座標從左下角x從0延伸到screenWidth-1         y從0向上延伸到screenHeight-1       只能使用非負的x和ywindows

程序中用於描述對象幾何信息    此過程爲建模任務數組

在屏幕中如何將這個對象  按照必定比例顯示出來    是一個觀看的任務緩存

  使用最適合與手中問題的座標系來描述對象,而且能夠自動的縮放和平移圖片,使得其能正確地在屏幕窗口中顯示,這個描述對象的空間被稱爲世界座標系(場景中的物體在實際世界中的座標)。在合適的單位下,它就是數學中經常使用的笛卡爾xy座標系。框架

  世界窗口:在世界座標系中定義一個對齊的矩形     (矩形的邊與座標軸平行)        不必定是屏幕函數

  世界窗口指明瞭要繪製世界的哪一部分。對此能夠理解爲,任何在窗口中的部分須要被繪製,而窗口外的部分被裁減並不被繪製。  opengl會自動的裁減。工具

  顯示器的屏幕窗口上定義一個對齊的矩形的視口,不一樣於世界窗口     opengl會自動創建世界窗口和視口的變換(包括縮放和平移)。oop

   對象在世界窗口中顯示的部分會被自動的映射到視口中,也就是被映射到屏幕座標中。

對齊的矩形做爲窗口和視口(屏幕窗口)的形狀緣由:

  1.矩形僅須要四個參數描述

  2.檢測一個點的位置(窗口內外) 很容易,能夠簡化裁減算法。

  3.對齊的矩形爲凸   簡化繪製算法

  4.經過一個窗口取看被繪製的物體,  並價格窗口中可見的快照放到顯示器的視口中

  採用窗口/視口的聯合方式,  當兩個口被指定時,coder能夠編寫一個算法,不考慮圖片的大小和位置,全部潛在的操做(縮放、位置和裁減)都會自動完成,並將圖片放到視口中去。

 

3.2世界窗口和視口

  建立一個函數圖像以後,並不知道 圖像的位置和圖像的大小,因此使用世界窗口就很是的重要

  setWindow()用來創建世界窗口

  setViewport()來創建視口

  代碼中涉及的座標是在天然座標系中操做的   例如x在-4.0~4.0    變化的   關鍵問題是如何縮放和平移不一樣的(x,y)   使得圖像能在屏幕窗口中恰當的顯示。

  經過設置一個世界窗口和一個視口,並創建它們之間的一個合適的映射,就能夠完成適當的平移和縮放。視口和窗口是coder 指定的對齊的矩形。

  窗口爲世界座標系中

  視口爲屏幕窗口的一部分。

  

  前者爲世界窗口;後者爲在屏幕中劃出一部分區域爲屏幕窗口,在其中再畫出一部分爲視口。

3.2.1  窗口到視口的映射

  

  圖中的w和v都是GLfloat類型的數值,表明做標值,其中left  和right爲x軸的值   、 bottom和top爲y軸的值,綜合到一塊兒成爲了對齊的矩形

  世界窗口和視口  縱橫比不必定一致    若是不一致會致使圖像的拉伸,因此須要調整世界窗口和視口的縱橫比一致

  一個映射或者變換,即窗口到視口的映射,這個映射是基於一個等式,對每個在世界座標下的點(x,y),產生屏幕座標系中的一個點(sx,sy)。

  保持比例的性質  有下面的線性性質:

      sx=A*x+C

      sy=B*y+D

  其中A、B、C、D是常數,       A B縮放x和y的座標    而 C D用來平移它們。

  

  

 

a  若是x是窗口的左邊界    x=w.left         則sx爲視口的左邊界     sx=v.left

b  若是x是在窗口的右邊界x=w.right,則sx是在視口的右邊界    sx=v.right

c  對於某個比例f    若是x位於窗口的1/f處      則sx位於視口寬度的1/f處

d  若是x在窗口的左邊界外    x<w.left      則sx也在視口的的左邊界外     sx<v.left

 設立窗口到視口的映射

  opengl經過多個變換完成所須要的映射,自動的傳送給定的每個頂點   經過glVertex2*()命令

  二維圖形中,世界窗口由函數gluOrth2D()來設定    原型以下:

    void gluOrtho2D(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top);     

  三維的狀況  還有另外兩個參數須要設定    省略

  視口的設定:

    void glViewport(GLint x,GLint y,GLint width,GLint eight);          左下角的座標以及寬度和高度

  經過矩陣來完成全部的變換,所以gluOrtho2D()的調用必須在glMatrixModel(GL_PROJECTION)和glLoadIdentity()兩個函數以後完成

  因此創建窗口設視口之間的聯繫須要以下代碼:

  glMatrixModel(GL_PROJECTION;

  glLoadIdentity();

  gluOrtho2D(0.0,2.0,0.0,1.0);  設置窗口

  glViewport(40,60,360,240);   設置視口

  在此以後  每一個使用glVertex2*(x,y)發送給opengl的點,會進行等式的映射,而且在窗口的邊界處會被自動裁減掉邊緣。

  將設定窗口的函數放在setWindow()函數中     將glViewport()   放在setViewport函數中

  void setWindow(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)      設置窗口

  {

    glMatrixModel(GL_PROJECTION);

    glLoadIdentity();

    gluOrtho2D(left,right,bottom,top);

  }

   void setViewport(GLint left,GLint right,GLint bottom,GLint top)              設置視口

  {

    glViewport(left,bottom,right-left,top-bottom);

  }

 (1)在main()中

  glutInitWindowSize(640,480)      設置窗口大小

  沒有使用glViewport的命令   因此使用默認的視口,默認的視口就是整個屏幕窗口。

(2)在myInit()中

  glMatrixModel(GL_PROJECTION);

  glLoadIdentity();

  gluOrtho2D(0.0,640.0,0.0,480.0);      //關鍵的設置   與視口比較      以及縱橫比

  上面這些函數都是將世界窗口設置爲對齊的矩形,其兩個角的座標是(0,0)和(640.0,480.0)  正好與視口的大小相等。

  案例1:針對同一個圖案,使用不一樣的視口,能夠作到在屏幕窗口上的平鋪

   

   例如a所示的就是平鋪

  代碼以下:      將恐龍替換成矩形     代碼以下

setWindow(0,640.0,0,440.0)        //設置窗口
for(int i=0,i<5;i++)                     //每列
{
   for(int j=0;j<5;j++)                 //每行
    {
        glViewport(i*64,j*44,64,44)   //  視口的移動方向先第0列  再第1列 ...
        drawPolylineFile("dino.dat");//在繪製一遍
    }  
}                    
其中dino.dat爲折線的文件

//折線恐龍
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>
using namespace std;
const int screenWidth=250;
const int screenHeight=250;
void setWindow(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)        //設置窗口
{
    gluOrtho2D(left,right,bottom,top);//窗口到視口的轉換
}
void setViewport(GLint left,GLint right,GLint bottom,GLint top)      //設置視口
{
    glViewport(left,bottom,right-left,top-bottom);
}
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);              //背景顏色  白色    最亮
    glColor3f(0.0f,0.0f,0.0f);                  //線條顏色爲黑色
    glPointSize(10.0);                           //點像素大小
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    setWindow(0,60.0,0,60.0);//設置世界座標系中的窗口
}
void draw(void)             //畫圖函數
{
    glBegin(GL_LINE_LOOP);   //三角形的點
                glVertex2i(10,10);
                glVertex2i(10,50);
                glVertex2i(50,50);
    glEnd();
}
void myDisplay(void)    //註冊函數
{
   glClear(GL_COLOR_BUFFER_BIT);
   for(int i=0;i<5;i++)
   {
      for(int j=0;j<5;j++)
      {
       glViewport(i*50,j*50,50,50);         //設置視口
       draw();
      }
   }
    glFlush();
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowSize(screenWidth,screenHeight);
    glutInitWindowPosition(100,150);
    glutCreateWindow("折線矩形");
    glutDisplayFunc(myDisplay);
    myInit();
    glutMainLoop();
    return 0;
}

下圖爲執行效果圖:

 

b圖爲交替倒置  產生的效果

  判斷i+j是偶數和奇數,而後倒轉top和bottom的值   以實現視口的倒轉

  代碼以下:  

for(int i=0;i<5;i++)//
{
    for(int j=0;j<5;j++)//
    {
      if((i+j)%2==0)//i+j是偶數
        setWindow(0.0,640.0,0.0,440.0);//正常的世界窗口
      else //i+j爲奇數
        setWindow(0.0,640.0,440.0,0.0);//顛倒的世界窗口
      glViewport(i*64,j*44,64,44);//設置下一個視口
      drawPloylineFile("dino.dat");//再次繪製  
    }
}

完整代碼以下

//折線恐龍
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const int screenWidth=250;
const int screenHeight=250;

void setWindow(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)        //設置窗口
{
    glMatrixMode(GL_PROJECTION);                //如下這兩句必定要從myInit函數中抽出放到此位置
    glLoadIdentity();
    gluOrtho2D(left,right,bottom,top);          //窗口到視口的轉換
}
void setViewport(GLint left,GLint right,GLint bottom,GLint top)      //設置視口
{
    glViewport(left,bottom,right-left,top-bottom);
}

void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);              //背景顏色  白色    最亮
    glColor3f(0.0f,0.0f,0.0f);                  //線條顏色爲黑色
    glPointSize(10.0);                          //點像素大小
}
void draw(void)                                 //畫圖函數
{
    glBegin(GL_LINE_LOOP);
                glVertex2i(10,10);
                glVertex2i(10,50);
                glVertex2i(50,50);

    glEnd();
}
void myDisplay(void)    //註冊函數
{
   glClear(GL_COLOR_BUFFER_BIT);
   for(int i=0;i<5;i++)
   {
      for(int j=0;j<5;j++)
      {
        if((i+j)%2==0)//i+j是偶數
        setWindow(0.0,60.0,0.0,60.0);//正常的世界窗口
        else //i+j爲奇數
        setWindow(0.0,60.0,60.0,0.0);//顛倒的世界窗口
        glViewport(i*50,j*50,50,50); //設置視口
        draw();
      }
   }
    glFlush();
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowSize(screenWidth,screenHeight);
    glutInitWindowPosition(100,150);
    glutCreateWindow("折線矩形");
    glutDisplayFunc(myDisplay);
    myInit();
    glutMainLoop();
    return 0;
}

執行結果的圖片

 

裁減圖片的某部分

視口不變,改變世界窗口 用以顯示不一樣的圖案

上例中w1   和w2兩個不一樣的窗口       視口不變,當使用w1時屏幕視口中顯示的是w1中所裁切出的圖案,而使用w2時則屏幕顯示的是w2中裁切出的圖案。

代碼框架以下: 

setWindow(...);       //每張圖片都改變窗口
setViewport(...);     //每張圖片使用一樣的視口
hexSwirl();             //調用一樣的畫圖函數

座標系統繪製

 

//畫笛卡爾座標系

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const int screenWidth=1024;
const int screenHeight=768;

void setWindow(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(left,right,bottom,top);
}

void setViewport(GLint left,GLint right,GLint bottom,GLint top)
{
    glViewport(left,bottom,right-left,top-bottom);
}

void drawpolygon(void)
{
    setWindow(0,screenWidth,0,screenHeight);
    setViewport(0,screenWidth,0,screenHeight);
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POINTS);
        for(int x=0;x<=screenWidth;x++)
        glVertex2i(x,screenHeight/2);
        for(int y=0;y<=screenHeight;y++)
        glVertex2i(screenWidth/2,y);
    glEnd();
    glFlush();
}
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);
    glColor3f(0.0f,0.0f,0.0f);
    glPointSize(3.0);
}

int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowSize(screenWidth,screenHeight);
    glutInitWindowPosition(100,150);
    glutCreateWindow("畫座標系");
    glutDisplayFunc(drawpolygon);
    myInit();
    glutMainLoop();
    return 0;
}

 畫六邊形:

//畫笛卡爾座標系中的六邊形
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>
using namespace std;

typedef struct point{
GLdouble x;
GLdouble y;
}point;

const int screenWidth=500;
const int screenHeight=500;
const int N=6;
point sp[N];
point temp;     //全局變量
double pi=3.1415926;
double theta=2*pi/N;
double r=150;

void moveto(GLdouble x,GLdouble y)  //設置當前的筆觸到座標點
{
    temp.x=x;
    temp.y=y;
}

void lineto(GLdouble x,GLdouble y)//從當前的點畫線到指定的座標點  兩點間的連線
{
    glBegin(GL_LINES);
        glVertex2d(temp.x,temp.y);
        glVertex2d(x,y);
    glEnd();
    //glFlush();
    temp.x=x;   //從新設置當前虛擬筆觸的座標值
    temp.y=y;
}

void setWindow(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)   //設置窗口
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(left,right,bottom,top);
}
void setViewport(GLint left,GLint right,GLint bottom,GLint top) //設置視口
{
    glViewport(left,bottom,right-left,top-bottom);
}
int drawpolygon(struct point  p[],GLdouble theta,GLdouble r)//注意傳遞的參數   接收的參數
{
    setWindow(0,screenWidth,0,screenHeight);
    setViewport(0,screenWidth,0,screenHeight);
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POINTS);
        for(int x=0;x<=screenWidth;x++)       //畫座標系
        glVertex2i(x,screenHeight/2);
        for(int y=0;y<=screenHeight;y++)
        glVertex2i(screenWidth/2,y);
        for(int i=0;i<N;i++)
        {
            double x=r*cos(i*theta)+screenWidth/2;  //計算六個點的座標   並畫出
            double y=r*sin(i*theta)+screenHeight/2;
            glVertex2i(x,y);
           p[i].x=x;
           p[i].y=y;
        }
    glEnd();
    for(int i=0;i<N;i++)                    //畫線循環
    {
        moveto(sp[i].x,sp[i].y);    //利用全局變量   來畫六邊形
        lineto(sp[(i+1)%6].x,sp[(i+1)%6].y);//取模算餘數
    }
    glFlush();
    return 0;
}
void mydisplay(void)                //註冊的函數
{
    //
    drawpolygon(sp,theta,r);

}
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);
    glColor3f(0.0f,0.0f,0.6f);
    glPointSize(6.0);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowSize(screenWidth,screenHeight);
    glutInitWindowPosition(100,150);
    glutCreateWindow("畫六邊形");
    glutDisplayFunc(mydisplay);
    myInit();
    glutMainLoop();
    return 0;
}

 結果以下:

 多個六邊形

//多六邊形
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>
using namespace std;

typedef struct point{
GLdouble x;
GLdouble y;
}point;

const int screenWidth=500;
const int screenHeight=500;
const int N=6;
point sp[N];
point temp;     //全局變量
double pi=3.1415926;
double theta=2*pi/N;
double r=240;

void moveto(GLdouble x,GLdouble y)  //設置當前的筆觸到座標點
{
    temp.x=x;
    temp.y=y;
}

void lineto(GLdouble x,GLdouble y)//從當前的點畫線到指定的座標點  兩點間的連線
{
    glBegin(GL_LINES);
        glVertex2d(temp.x,temp.y);
        glVertex2d(x,y);
    glEnd();
    //glFlush();
    temp.x=x;   //從新設置當前虛擬筆觸的座標值
    temp.y=y;
}

void setWindow(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)   //設置窗口
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(left,right,bottom,top);
}
void setViewport(GLint left,GLint right,GLint bottom,GLint top) //設置視口
{
    glViewport(left,bottom,right-left,top-bottom);
}
int drawpolygon(struct point  p[],GLdouble tempt,GLdouble tempr)//注意傳遞的參數   接收的參數
{
    //setWindow(0,screenWidth,0,screenHeight);
    //setViewport(0,200,0,200);

    glBegin(GL_POINTS);
        //for(int x=0;x<=screenWidth;x++)       //畫座標系
        //glVertex2i(x,screenHeight/2);
        //for(int y=0;y<=screenHeight;y++)
        //glVertex2i(screenWidth/2,y);
        for(int i=0;i<N;i++)
        {
            double x=tempr*cos(i*tempt)+screenWidth/2;  //計算六個點的座標   並畫出
            double y=tempr*sin(i*tempt)+screenHeight/2;
            glVertex2i(x,y);
            p[i].x=x;
            p[i].y=y;
        }
    glEnd();
   for(int i=0;i<N;i++)                    //畫線循環
    {
        moveto(sp[i].x,sp[i].y);    //利用全局變量   來畫六邊形
        lineto(sp[(i+1)%6].x,sp[(i+1)%6].y);//取模算餘數
    }
   // for(int j=0;j<N;j++)

    return 0;
}
void mydisplay(void)                //註冊的函數
{
    glClear(GL_COLOR_BUFFER_BIT);
    setWindow(0,screenWidth,0,screenHeight);
    setViewport(0,screenWidth,0,screenHeight);
    while(r>0)                   //循環畫六邊形
        drawpolygon(sp,theta,r-=10);
    glFlush();
    cout<<sp[1].x<<endl;
}
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);
    glColor3f(0.0f,0.0f,0.6f);
    glPointSize(3.0);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowSize(screenWidth,screenHeight);
    glutInitWindowPosition(100,150);
    glutCreateWindow("畫六邊形");
    glutDisplayFunc(mydisplay);
    myInit();
    glutMainLoop();
    return 0;
}

結果:

 

 

 

縮放和漫遊

    將窗口變小則用於放大對象    相反窗口變大  至關於對象縮小。

    有時候漫遊也叫全視

在動畫中放大圖片

      同心的多個窗口   固定的縱橫比    窗口逐漸縮小   造成動畫,每一個窗口中顯示的圖片都是一幀     此過程相似與放大圖像

    繪製每一幀   都須要清一次屏幕   同時窗口愈來愈小  代碼以下:      

動畫1:

float cx=0.3,cy=0.2;//窗口中心
float H,W=1.2, aspect=0.7;//窗口性質
set the viewport    //設置視口
for(int frame=0;frame<NumFrames;frame++)//循環顯示每一幀圖像
{
    clear the screen       //每次循環都清除以前的圖案
    W*=0.7;
    H=W*aspect;          //保持縱橫比
    setWindow(cx-W,cx+W,cy-H,cy+H);//設置下一個窗口
    hexSwirl();
}

動畫2:

   動畫1的方式存在的問題

   過程以下:

    迅速擦除當前的圖像;而後新圖像被緩慢的重繪,由於僅僅有一個圖像的緩存

   解決上面問題的方法就是在用戶瀏覽當前圖像時,在一個「屏幕外內存」的地方繪製新的圖像,而後將新圖像顯示在顯示器上。

     opengl提供了雙緩存來完成任務,使用一個內存來模擬一個額外的屏幕,這個屏幕不顯示在真實的顯示器上,並全部的繪製都在這個緩存中進行。以後glutSwapBuufers()函數會將緩存中的圖片轉移到屏幕窗口上。

    設置單緩存:glutInitDisplayModel(GLUT_SINGLE | GLUT_RGB);   

   設置成雙緩存:glutInitDisplayModel(GLUT_DOUBLE | GLUT_RGB); 

練習:3.2.2迴旋的旋渦

      

  

3.3 裁減線

  圖形學中的基本任務,用於保持對象在給定的區域外的部分不被繪製

  opengl環境中,每一個對象都會被一個特殊的算法,自動的裁減到世界窗口      裁減器

3.3.1裁減一條線

  cohen-sutherland 裁減器  計算p1和p2兩個端點的線段的哪一部分位於世界窗口以內,並返回位於世界窗口內的部分的端點

  函數 int clipSegment(Point2& p1,Point2& p2,RealRect window)    參數爲兩個二維的點以及一個對齊的矩形    

  功能爲將p1和p2爲端點的線段裁減到窗口邊界處。若是線段的某一部分位於窗口內,則將新的端點存放在p1 和p2中,而且函數返回1,說明線段的某些部分是可見的。若是這條線溫泉被裁減掉了,函數返回0,說明沒有任何部分可見。

        案例1:

  

  典型的裁減器的狀況    :   clipsegment()函數對每條線段執行下列事件中的一件。

  1.若是整條線段都在窗口內(例如線段cd)    函數返回1    

  2.整條線段在窗口外    例如線段AB  函數返回0

  3.一個端點在窗口外,一個在窗口內    例如ED      函數將一個端點裁減   設置新的端點    而後返回1

  4.兩個端點都在窗口外,     可是此線段的一部分位於窗口內   例如線段AE    函數將裁減兩個端點   並返回1

  還有可能線段位於窗口的左側   右側    上面或者下面等等。

  爲了判斷線段的位置  而且作出相應的裁減    cohen-sutherland提供了一個快速的分治算法。

  3.3.2  cohen-sutherland裁減算法

  平凡接受和平凡拒絕兩種常見狀況

  

  圖中的AB整個線段位於窗口內     所以AB被平凡的接受,而不須要裁減,                    窗口很大時,大部分狀況都是平凡接受。

  圖中CD整個線段   兩個端點都位於W的另外一條邊外,則線段CD整個都在窗口外  此時CD就是平凡的拒絕。       窗口很小時,大部分狀況都是平凡拒絕。

檢測平凡接受或者平凡拒絕

  僅僅檢測端點便可

  

  對線段的每個端點計算一個「窗口內部/外部編碼」,用於後續的測試。

    四個編碼的位置信息從左到右分別爲    left     above     right     below       分別表明   在左面    上面    下面   右面;

  t表明true       f表明false

  若是點在窗口內部,則編碼表示爲FFFF;

  下圖爲點與窗口的位置關係   的9種可能性

  

  平凡接受:兩個碼字都是FFFF;

  平凡拒絕:兩個碼字在某一位元素上都是T   兩個點都是在窗口左邊,或者都在它上面,等等

  使用c/c++的位操做函數   能夠實現碼字的計算和測試。

沒有平凡接受和拒絕時的截斷

  

  若是沒有平凡接受或者拒絕時,此線段必定會被某個邊界分紅兩個部分

  do

  {

    設置p1   和p2的碼字;

    if(平凡接受)  return 1;

    if(平凡拒絕)  return 0;

    將線段在下一個窗口邊界處截斷;(從新設置p1或p2端點的位置)丟掉外面的部分;

  }while(1);

  最多四次循環就會終止,針對每一個點  對齊矩形的四條邊都會進行檢測   因此須要四次循環。也就會出現平凡接受或者平凡拒絕的狀況。

  

   已知:p1和p2的座標x和y       w.right     

   未知:A點的x=w.right     y=p1.y-d

    d/dely=e/delx

    delx=p2.x-p1.x;.........1

    dely=p2.y-p1.y;........2

    e=p1.x-w.right;.........3

   由1 2 3能夠計算出d的值   由此就能夠計算出A點的y值

  因此新p1.y  (點A)   

    p1.y+=(w.right-p1.x)*dely/delx

  剩餘的窗口的三個邊界的裁減方法相似。

  對於水平的線  dely=0 ;對於垂直的線   delx=0;    分母爲0的狀況不會發生

  僞代碼2:

  

int clipSegment(Point & p1,Point2& p2,RealRect W)
{
    
    do{
       if(平凡接受) return 1;
       if(平凡拒絕) return 0;
       if(p1在窗口外面)
       {
            if(p1在窗口左邊)   用左邊界截斷,更新p1;
            else if(p1在窗口右邊) 用右邊界截斷,更新p1;
            else if(p1在窗口下面) 用下邊界截斷,更新p1;
            else if(p1在窗口上面) 用上邊界截斷,更新p1;
       }
        else //p2在窗口外面
        {
            if(p2在窗口左邊)   用左邊界截斷,更新p2;
            else if(p2在窗口右邊) 用右邊界截斷,更新p2;
            else if(p2在窗口下面) 用下邊界截斷,更新p2;
            else if(p2在窗口上面) 用上邊界截斷,更新p2;
        }
    }while(1);
}
   

  每次執行循環時,每一個端點的碼字都會被從新計算和測試,每次都會對平凡接受和拒絕進行檢測  ,若是失敗,算法會檢測p1是否在窗口外,若是p1在窗口內,那麼p2必定在窗口外,針對在窗口外的點進行按邊裁減。

  裁減的順序爲左,右,下,上。

  

  第一次:p1變爲A

  第二次:p2變爲B

  第三次:A變爲C

  第四次:  B變爲D

 練習:3.3.1  手工模擬clipSegment   (略)

 3.3.2 除以0的狀況永遠不會發生。

 

3.4正多邊形、圓和圓弧

3.4.1正多邊形

  全部邊相等   內角相等  且邊只能在端點處接觸,稱n條邊的正多邊形爲正n邊形。頂點等距離排放

  

  半徑爲R的外接圓的圓心位於遠點,而第一個點p0位於x軸的正方向,其它的頂點位於下面等式指定的位置:pi=(R*cos(i*a),R*sin(i*a)),      i=1,2...5

  其中a=2π/6=π/3。

  1.若是圓心的座標爲(x,y),只要在上式中座標中分別加上x和y便可。

  2.若是將正六邊形縮放S倍,只須要將R乘上S。

  3.旋轉只須要在cos和sin函數的參數中增長A便可

3.4.2正n邊形的變種

  將正n邊形中的各個頂點均相連 會獲得花環 

 花環.cpp

//繪製sinc函數
#include <windows.h>
#include <iostream>
#include <math.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <gl/GLUT.h>


class GLintPoint        //點類
{
public:
    GLint x,y;
};

class Point2            //線段端點類
{
public:
    float x,y;
    void set(float dx,float dy){x=dx;y=dy;}     //內聯函數     且重載
    void set(Point2 &p){x=p.x;y=p.y;}           //內聯函數     重載    設置端點
    Point2(float xx,float yy){x=xx,y=yy;}       //構造函數   非默認
    Point2(){x=y=0;}                            //默認構造函數
};
Point2 currPos;                     //定義兩個端點類的對象
Point2 CP;

void moveTo(Point2 p)              //移動當前的虛擬筆觸   到一個端點
{
    CP.set(p);                      //設置當前點的座標
}

void lineTo(Point2 p)               //從當前點的位置cp     到參數給定的點劃線
{
    glBegin(GL_LINES);
        glVertex2f(CP.x,CP.y);
        glVertex2f(p.x,p.y);
    glEnd();
    glFlush();
    CP.set(p);                  //***從新設置當前的點  cp
}
//myInit
void myInit(void)           //初始化  窗口的個參數    背景顏色    線條顏色  以及寬度等等
{
    glClear(GL_COLOR_BUFFER_BIT);
    glClearColor(1.0,1.0,1.0,0.0);
    glColor3f(0.0f,0.0f,1.0f);
}

void rosette(int N,float radius)        //觸發的畫圖函數    參數爲點數 和 半徑值
{
    Point2 * pointlist=new Point2[N];       //建立數組用來存儲線段的端點
    GLfloat theta=(2.0f*3.1415926536)/N;    //360度除以點數   算出角度數
    for(int c=0;c<N;c++)
    {
        pointlist[c].set(radius*sin(theta*c),radius*cos(theta*c));//計算每一個點的x和y值   而且填入對象數組
    }
    for(int i=0;i<N;i++)//將數組中的全部點都鏈接起來
    {
        for(int j=0;j<N;j++)
        {
            moveTo(pointlist[i]);
            lineTo(pointlist[j]);
        }

    }
}

void render()//渲染
{
    glClear(GL_COLOR_BUFFER_BIT);//清除背景顏色
    glViewport(10,10,600,600);      //設置視口 *****  x,y    width   height
    rosette(10,.50f);            //畫圖    實參傳送
    glFlush();                  //傳送給opengl
}
//main
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glutInitWindowSize(600,600);
    glutCreateWindow("rosette");
    glutDisplayFunc(render);
    myInit();
    glutMainLoop();
    return 0;
}

 特例:    5花環 的特性

  體現不少黃金分割率φ

  

   每條線段要比短於它的線段長φ倍,並且因爲五角星的邊又構成了一個內五邊形,能夠實現一個無窮的嵌套。

例子:3.4.2基於兩個同心多邊形的圖形

   

    外半徑是R,內半徑是fR ,f是某個因子。每一個圖都使用了一個正n邊形的變種,其半徑在內徑和外徑之間交替。

    圖3.29a   代碼示例:

  

//3.2.9圖a

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const int N=6;
const double pi=3.1415926;
const double theta=2*pi/N;
const double R=200;
const double r=50;
const double screenWidth=500;
const double screenHeight=500;

class point
{
  public:
    GLdouble x;
    GLdouble y;
    void setp(GLdouble _x,GLdouble _y){x=_x;y=_y;};

};
point sp;
void moveTo(GLdouble x,GLdouble y)
{
   sp.setp(x,y);
}
void lineTo(GLdouble x,GLdouble y)
{
    glBegin(GL_LINES);
        glVertex2d(sp.x,sp.y);
        glVertex2d(x,y);
    glEnd();
    sp.x=x;
    sp.y=y;
}
void photo(void)
{
    class point p1[6];
    class point p2[6];
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POINTS);
    for(int i=0;i<N;i++)
    {
        GLdouble Rx=R*cos(i*theta)+screenWidth/2;
        GLdouble Ry=R*sin(i*theta)+screenHeight/2;
        p1[i].x=Rx;
        p1[i].y=Ry;
        GLdouble rx=r*cos(i*theta)+screenWidth/2;
        GLdouble ry=r*sin(i*theta)+screenHeight/2;
        p2[i].x=rx;
        p2[i].y=ry;
        glVertex2d(p1[i].x,p1[i].y);
        glVertex2d(p2[i].x,p2[i].y);
    }
    glEnd();
   for(int i=0;i<N;i+=2)
    {
        moveTo(p1[i].x,p1[i].y);
        lineTo(p1[(i+2)%N].x,p1[(i+2)%N].y);

    }
    for(int i=0;i<N;i+=2)
    {
        moveTo(p1[i].x,p1[i].y);
        lineTo(p2[(i+1)%N].x,p2[(i+1)%N].y);
        moveTo(p2[i+1].x,p2[i+1].y);
        lineTo(p1[(i+2)%N].x,p1[(i+2)%N].y);
    }
    glFlush();
}
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);      //background color
    glColor3f(0.0f,0.2f,0.6f);          //point color
    glPointSize(3.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,500,0.0,500);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(500,500);
    glutCreateWindow("內外圓多邊形");
    glutDisplayFunc(photo);
    myInit();
    glutMainLoop();
    return 0;
}

結果

 3.2.9圖B     僅將a圖代碼中的N改成10便可

//3.2.9圖b

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const int N=10;
const double pi=3.1415926;
const double theta=2*pi/N;
const double R=200;
const double r=50;
const double screenWidth=500;
const double screenHeight=500;

class point
{
  public:
    GLdouble x;
    GLdouble y;
    void setp(GLdouble _x,GLdouble _y){x=_x;y=_y;};

};
point sp;
void moveTo(GLdouble x,GLdouble y)
{
   sp.setp(x,y);
}
void lineTo(GLdouble x,GLdouble y)
{
    glBegin(GL_LINES);
        glVertex2d(sp.x,sp.y);
        glVertex2d(x,y);
    glEnd();
    sp.x=x;
    sp.y=y;
}
void photo(void)
{
    class point p1[N];
    class point p2[N];
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POINTS);
    for(int i=0;i<N;i++)
    {
        GLdouble Rx=R*cos(i*theta)+screenWidth/2;
        GLdouble Ry=R*sin(i*theta)+screenHeight/2;
        p1[i].x=Rx;
        p1[i].y=Ry;
        GLdouble rx=r*cos(i*theta)+screenWidth/2;
        GLdouble ry=r*sin(i*theta)+screenHeight/2;
        p2[i].x=rx;
        p2[i].y=ry;
        glVertex2d(p1[i].x,p1[i].y);
        glVertex2d(p2[i].x,p2[i].y);
    }
    glEnd();
   for(int i=0;i<N;i+=2)
    {
        moveTo(p1[i].x,p1[i].y);
        lineTo(p1[(i+2)%N].x,p1[(i+2)%N].y);

    }
    for(int i=0;i<N;i+=2)
    {
        moveTo(p1[i].x,p1[i].y);
        lineTo(p2[(i+1)%N].x,p2[(i+1)%N].y);
        moveTo(p2[i+1].x,p2[i+1].y);
        lineTo(p1[(i+2)%N].x,p1[(i+2)%N].y);
    }
    glFlush();
}
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);      //background color
    glColor3f(0.0f,0.2f,0.6f);          //point color
    glPointSize(3.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,500,0.0,500);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(500,500);
    glutCreateWindow("內外圓多邊形");
    glutDisplayFunc(photo);
    myInit();
    glutMainLoop();
    return 0;
}

代碼結果

 

 3.29圖c    修改N  去掉外框線

//3.2.9圖c

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const int N=14;
const double pi=3.1415926;
const double theta=2*pi/N;
const double R=200;
const double r=50;
const double screenWidth=500;
const double screenHeight=500;

class point
{
  public:
    GLdouble x;
    GLdouble y;
    void setp(GLdouble _x,GLdouble _y){x=_x;y=_y;};

};
point sp;
void moveTo(GLdouble x,GLdouble y)
{
   sp.setp(x,y);
}
void lineTo(GLdouble x,GLdouble y)
{
    glBegin(GL_LINES);
        glVertex2d(sp.x,sp.y);
        glVertex2d(x,y);
    glEnd();
    sp.x=x;
    sp.y=y;
}
void photo(void)
{
    class point p1[N];
    class point p2[N];
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POINTS);
    for(int i=0;i<N;i++)
    {
        GLdouble Rx=R*cos(i*theta)+screenWidth/2;
        GLdouble Ry=R*sin(i*theta)+screenHeight/2;
        p1[i].x=Rx;
        p1[i].y=Ry;
        GLdouble rx=r*cos(i*theta)+screenWidth/2;
        GLdouble ry=r*sin(i*theta)+screenHeight/2;
        p2[i].x=rx;
        p2[i].y=ry;
        glVertex2d(p1[i].x,p1[i].y);
        glVertex2d(p2[i].x,p2[i].y);
    }
    glEnd();
     for(int i=0;i<N;i+=2)
    {
        moveTo(p1[i].x,p1[i].y);
        lineTo(p2[(i+1)%N].x,p2[(i+1)%N].y);
        moveTo(p2[i+1].x,p2[i+1].y);
        lineTo(p1[(i+2)%N].x,p1[(i+2)%N].y);
    }
    glFlush();
}
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);      //background color
    glColor3f(0.0f,0.2f,0.6f);          //point color
    glPointSize(3.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,500,0.0,500);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(500,500);
    glutCreateWindow("內外圓多邊形");
    glutDisplayFunc(photo);
    myInit();
    glutMainLoop();
    return 0;
}

結果圖

3.29圖d   多加上一個畫內圓的代碼段

//3.2.9圖c

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const int N=14;
const double pi=3.1415926;
const double theta=2*pi/N;
const double R=200;
const double r=50;
const double screenWidth=500;
const double screenHeight=500;

class point
{
  public:
    GLdouble x;
    GLdouble y;
    void setp(GLdouble _x,GLdouble _y){x=_x;y=_y;};

};
point sp;
void moveTo(GLdouble x,GLdouble y)
{
   sp.setp(x,y);
}
void lineTo(GLdouble x,GLdouble y)
{
    glBegin(GL_LINES);
        glVertex2d(sp.x,sp.y);
        glVertex2d(x,y);
    glEnd();
    sp.x=x;
    sp.y=y;
}
void photo(void)
{
    class point p1[N];
    class point p2[N];
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POINTS);
    for(int i=0;i<N;i++)
    {
        GLdouble Rx=R*cos(i*theta)+screenWidth/2;
        GLdouble Ry=R*sin(i*theta)+screenHeight/2;
        p1[i].x=Rx;
        p1[i].y=Ry;
        GLdouble rx=r*cos(i*theta)+screenWidth/2;
        GLdouble ry=r*sin(i*theta)+screenHeight/2;
        p2[i].x=rx;
        p2[i].y=ry;
        glVertex2d(p1[i].x,p1[i].y);
        glVertex2d(p2[i].x,p2[i].y);
    }
    glEnd();
   for(int i=0;i<N;i+=2)//畫外框
    {
        moveTo(p1[i].x,p1[i].y);
        lineTo(p1[(i+2)%N].x,p1[(i+2)%N].y);

    }
    for(int i=0;i<N;i+=2)//畫內角
    {
        moveTo(p1[i].x,p1[i].y);
        lineTo(p2[(i+1)%N].x,p2[(i+1)%N].y);
        moveTo(p2[i+1].x,p2[i+1].y);
        lineTo(p1[(i+2)%N].x,p1[(i+2)%N].y);
    }
    //畫內圓
    glBegin(GL_POINTS);
    for(double i=0.0;i<=2*pi;i+=0.05)
        glVertex2d(r*cos(i)+screenWidth/2,r*sin(i)+screenHeight/2);
    glEnd();
    glFlush();
}
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);      //background color
    glColor3f(0.0f,0.2f,0.6f);          //point color
    glPointSize(3.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,500,0.0,500);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(500,500);
    glutCreateWindow("內外圓多邊形");
    glutDisplayFunc(photo);
    myInit();
    glutMainLoop();
    return 0;
}

練習3.4.1   

 3.4.2證實

 

 

 

 圖片3.30  某大學的標誌

給定一點

//3.4.3  校標

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const double screenWidth=500;
const double screenHeight=500;

int j=0;//聲明一個全局變量

class point
{
  public:
    GLdouble x;
    GLdouble y;
    void setp(GLdouble _x,GLdouble _y){x=_x;y=_y;};
};
void photo(void)
{
    point p[6]; //定義對象數組  而且初始化   
    p[0].x=0;
    p[0].y=20;
    p[1].x=-100;
    p[1].y=80;
    p[2].x=-100;
    p[2].y=200;
    p[3].x=0;
    p[3].y=140;
    p[4].x=100;
    p[4].y=200;
    p[5].x=100;
    p[5].y=80;
    int N=3;
    double pi=3.1415926;
    double theta=2*pi/N;
    //開始畫圖
    glClear(GL_COLOR_BUFFER_BIT);
    for(int j=0;j<3;j++)        //j定義爲全局變量    不然不能經過編譯
    {
        glBegin(GL_LINE_LOOP);
          for(int i=0;i<6;i++)
glVertex2d((cos(theta
*j)*p[i].x-sin(theta*j)*p[i].y)+screenWidth/2,(sin(theta*j)*p[i].x+cos(theta*j)*p[i].y)+screenHeight/2); glEnd(); } glFlush(); } void myInit(void) { glClearColor(1.0,1.0,1.0,0.0); //background color glColor3f(0.0f,0.2f,0.6f); //point color glPointSize(3.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,500,0.0,500); } int main(int argc,char ** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowPosition(0,0); glutInitWindowSize(500,500); glutCreateWindow("校標"); glutDisplayFunc(photo); myInit(); glutMainLoop(); return 0; }

 3.4.3 繪製圓與圓弧

 

 圓心:c

半徑:R

開始角度:a

展開角度:b   

  b爲負值  則順時針畫圖

  b爲正值  則逆時針畫圖

展開的角度是360度

 drawCirlce()   經過指定圓心和半徑來繪製,還有其餘的方法來描述圓,常見的方式是:

  1.已知圓心以及一個院上的點。    利用圓心以及一個圓上的點  計算兩點的距離即半徑

  2.給定圓必須通過的三個點。  三個不共線的點能夠惟一肯定一個圓

畫圓案例2  

//3.4.3  圓外切

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const double screenWidth=500;
const double screenHeight=500;

class point
{
  public:
    GLdouble x;
    GLdouble y;
    void setp(GLdouble _x,GLdouble _y){x=_x;y=_y;};
};
void photo(void)
{
    double r=100;
    double x;
    int w=150;
    int h=120;
    glClear(GL_COLOR_BUFFER_BIT);
        glBegin(GL_POINTS);
        for(x=-100;x<100;x+=0.05)
        {
         glVertex2d(x+w,sqrt(r*r-x*x)+h);
         glVertex2d(x+w,-sqrt(r*r-x*x)+h);
        }
        glVertex2d(w,h);
        glEnd();
    glFlush();
}
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);      //background color
    glColor3f(0.0f,0.2f,0.6f);          //point color
    glPointSize(3.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,500,0.0,500);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(500,500);
    glutCreateWindow("畫弧和圓");
    glutDisplayFunc(photo);
    myInit();
    glutMainLoop();
    return 0;
}

 畫圓案例3

 

//3.4.3  圓外切   給定一個兩個圓心  和兩個圓的交點    畫兩個圓和一條切線

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const double screenWidth=500;
const double screenHeight=500;
int w=80;//位移
int h=80;
class point
{
  public:
    GLdouble x;
    GLdouble y;
    void setp(GLdouble _x,GLdouble _y){x=_x;y=_y;};
};

double getr(point p1,point p2)//獲取半徑的平方
{
    double r=sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
    return r;
}
void line(point p1,point p2)//p1爲圓心,p2爲圓上點   直線過p2點
{
    double k,b;
    k=-(p2.x-p1.x)/(p2.y-p1.y);
    b=p2.y-k*p2.x;
    glBegin(GL_POINTS);
        for(double x=10;x<200;x++)
        glVertex2d(x+w,k*x+b+h);
    glEnd();
}
void photo(point p1,point p2)    //根據兩個點畫圓   p1爲圓心   p2爲圓上的點
{
    double r=getr(p1,p2);
    double x;

    glBegin(GL_POINTS);
        for(x=p1.x-r;x<=p1.x+r;x+=0.05)
        {
            glVertex2d(x+w,sqrt(r*r-(x-p1.x)*(x-p1.x))+p1.y+h);
            glVertex2d(x+w,-sqrt(r*r-(x-p1.x)*(x-p1.x))+p1.y+h);
        }
        glVertex2d(p1.x+w,p1.y+h);
    glEnd();
 }
 void mydisplay(void)
 {
    class point p1;//初始化 三個對象
    p1.x=50;
    p1.y=50;
    point p2;
    p2.x=120;
    p2.y=120;
    point p3;
    p3.x=180;
    p3.y=160;
    glClear(GL_COLOR_BUFFER_BIT);
        photo(p1,p2);
        photo(p3,p2);
        line(p1,p2);
    glFlush();
 }
void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);      //background color
    glColor3f(0.0f,0.2f,0.6f);          //point color
    glPointSize(3.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,500,0.0,500);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(500,500);
    glutCreateWindow("畫弧和圓");
    glutDisplayFunc(mydisplay);
    myInit();
    glutMainLoop();
    return 0;
}

執行結果:

 3.4.4曲線的逐次細化

  逐次細化一個簡單的曲線,能夠遞歸造成很是複雜的曲線。  例如koch曲線   逐漸逼近真實的曲線   

  

    將kn的每一條線段平均分爲3的段,而後將中間的那段用一個等邊三角形來提升代替,採用遞歸的方式,每一線段的長度變爲原來的4/3,因此總的曲線長度也是它上一代的4/3.所以kn的總長度爲(4/3)的n次冪。

 3.5曲線的參數形式

描述曲線的形狀主要有兩種方法:

隱式法和參數形式

 隱式法:使用函數f(x,y)來描述曲線    而且提供xy之間的關係       

  點在曲線上的條件:f(x,y)=0      

  一類曲線  曲線的內部和外部是有意義的,此種狀況下    f(x,y)也被叫作內部-外部函數   其意義是:

    f(x,y)=0    對應全部在曲線上的點 (x,y)

    f(x,y)>0    對全部在曲線外的點(x,y)

    f(x,y)<0    對全部在曲線內的點(x,y) 

     曲線對x是單值   那麼   g(x)對於每個x   僅有一個g(x)     能夠寫成f(x,y)=y-g(x)

  曲線對y是單值, 存在函數h()   使得曲線上的全部點知足x=h(y)

  還有對於x和y都不是單值的:f(x,y)=0  不能寫成y=g(x)   或者 x=h(y)的形式   能夠表示成:

    y=+-根號下(r^2-x^2)   這裏爲兩個函數    一個是正號,另外一個是負號

3.5.1曲線的參數形式

  當參數取不一樣值的時候,會產生出曲線上不一樣的點。推薦使用       以時間t的運動軌跡

  粒子沿着曲線運動的路徑由兩個函數x()和y()來肯定,若是是三維  則有三個函數  x()      y()     z()    他們肯定粒子在時刻t的位置。

  參數t一般被看做是時間,而曲線自己就是粒子隨着時間在某一個區間內的變化所通過的點。

  一般證實隱式形式和參數形式相同   將參數形式帶入隱式形式便可    即從參數形式求隱式形式

3.5.2  繪製參數形式

  根據p(t)=(x(t),y(t))      其中t從0變化到T    咱們只須要用很是緊湊的間隔採集p(t)的樣本   而後鏈接成折線   近似的逼近曲線

  時間數組 t[i]     i=0 1 2 3...  

glBegin(GL_LINES);
    for(int i=0;i<n;i++)
    glVertex2f(x(t[i]),y(t[i]));
glEnd();

  案例繪製橢圓  

glBegin(GL_LINES);
    for(double t=0;t<2*pi;t+=2*pi/n)//將2pi   n等分  越細分曲線越光滑
    glVertex2f(W*cos(t),H*sin(t));
glEnd();

 3.5.4  樣例曲線代碼

//3.4.3  圓外切   給定一個兩個圓心  和兩個圓的交點    畫兩個圓和一條切線

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const double screenWidth=500;
const double screenHeight=500;
int w=180;//位移
int h=80;
const double pi=3.141592;
const int n=360;


 void mydisplay(void)
 {
    glClear(GL_COLOR_BUFFER_BIT);
      glBegin(GL_LINE_LOOP);
      for(double t=0.0;t<2*pi;t+=2*pi/n)
        glVertex2d(w*cos(t)+screenWidth/2,h*sin(t)+screenHeight/2);
      glEnd();
    glFlush();
 }

void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);      //background color
    glColor3f(0.0f,0.2f,0.6f);          //point color
    glPointSize(3.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,500,0.0,500);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(500,500);
    glutCreateWindow("畫橢圓");
    glutDisplayFunc(mydisplay);
    myInit();
    glutMainLoop();
    return 0;
}

執行結果

 

 3.5.5   畫圖

//3.4.3  圓外切   給定一個兩個圓心  和兩個圓的交點    畫兩個圓和一條切線

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const double screenWidth=500;
const double screenHeight=500;
int w=180;//位移
int h=140;
const float f=h/w;
double d=0.5;
double t=d*f;


const double pi=3.141592;
const int n=360;
const float color1[3]={1.0,1.0,1.0};
const float color2[3]={0.0,0.0,0.0};
void drawEllipse(int w,int h,const float * clr)//畫圓並填充
{
    if(w!=h)
    {
        glBegin(GL_POINTS);
        for(;w>0&&h>0;w-=d,h-=t)
       {
            glColor3f(clr[0],clr[1],clr[2]);
            for(double t=0.0;t<2*pi;t+=2*pi/n)
            glVertex2d(w*cos(t)+screenWidth/2,h*sin(t)+screenHeight/2);
        }
        glEnd();
    }

    if(w==h)
    {
        glBegin(GL_POINTS);
        for(;w>0&&h>0;w-=d)
        {
            glColor3f(clr[0],clr[1],clr[2]);
            for(double t=0.0;t<2*pi;t+=2*pi/n)
            glVertex2d(w*cos(t)+screenWidth/2,w*sin(t)+screenHeight/2);
        }
        glEnd();
    }
}
 void mydisplay(void)
 {
    glClear(GL_COLOR_BUFFER_BIT);
        drawEllipse(w,h,color2);
        drawEllipse(h-5,h-5,color1);
        drawEllipse(h-10,h-50,color2);
        drawEllipse(h-55,h-55,color1);
    glFlush();
 }

void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);      //background color
    glPointSize(3.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,500,0.0,500);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(500,500);
    glutCreateWindow("畫橢圓");
    myInit();
    glutDisplayFunc(mydisplay);
    glutMainLoop();
    return 0;
}

執行結果

 3.5.3極座標形式

用來表示和繪製一些有趣曲線

 極座標畫圓

//3.4.3  圓外切   給定一個兩個圓心  和兩個圓的交點    畫兩個圓和一條切線

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <math.h>

using namespace std;

const double screenWidth=500;
const double screenHeight=500;
double pi=3.1415926;

void drawEllipse(double k)//極座標畫圓
{
   double theta=0;
     glBegin(GL_POINTS);
        for(;theta<=2*pi;theta+=0.01)
        {
           glVertex2d(k*cos(theta)+screenWidth/2,k*sin(theta)+screenHeight/2);
        }
    glEnd();
}
 void mydisplay(void)
 {
    glClear(GL_COLOR_BUFFER_BIT);
        drawEllipse(200);
    glFlush();
 }

void myInit(void)
{
    glClearColor(1.0,1.0,1.0,0.0);      //background color
    glPointSize(3.0);
    glColor3f(1.0,0.0,0.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,500,0.0,500);
}
int main(int argc,char ** argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(500,500);
    glutCreateWindow("極座標畫圓");
    glutDisplayFunc(mydisplay);
    myInit();
    glutMainLoop();
    return 0;
}

執行結果

 

 

極座標畫心形

替換上面的函數代碼段

void drawEllipse(double k)//極座標畫圓
{
   double theta=0;
     glBegin(GL_POINTS);
        for(;theta<=2*pi;theta+=0.01)
        {
            double f=k*(1+cos(theta));
            glVertex2d(f*cos(theta)+screenWidth/3,f*sin(theta)+screenHeight/2);
        }
    glEnd();
}

執行結果

 玫瑰曲線   圖3.45

代碼段替換

void drawEllipse(double k,int n)//極座標畫圓   n爲花瓣
{
   double theta=0;
     glBegin(GL_LINES);
        for(;theta<=2*pi;theta+=0.00001)
        {
            double f=k*cos(n*theta);
            glVertex2d(f*cos(theta)+screenWidth/2,f*sin(theta)+screenHeight/2);
            glVertex2d(f*cos(theta+0.00001)+screenWidth/2,f*sin(theta+0.01)+screenHeight/2);
        }
    glEnd();
}
 void mydisplay(void)
 {
    glClear(GL_COLOR_BUFFER_BIT);
        drawEllipse(200,8);
    glFlush();
 }

執行結果

 阿基米德螺旋線

替換代碼段

void drawEllipse(double k,int n)//極座標畫圓   n爲圈數
{
   double theta=0;
     glBegin(GL_POINTS);
        for(;theta<=n*pi;theta+=0.01)
        {
            double f=k*theta;
            glVertex2d(f*cos(theta)+screenWidth/2,f*sin(theta)+screenHeight/2);
        }
    glEnd();
}

 以上各種函數以下:

 

 

圓錐曲線代碼

void drawEllipse(double e)//極座標畫圓   n爲圈數
{
   double theta=0;
     glBegin(GL_POINTS);
        for(;theta<=2*pi;theta+=0.0001)
        {
            double f1=1/(1-e*cos(theta));
            //double f2=1/(1+e*cos(theta));
            glVertex2d(f1*cos(theta)+screenWidth/4,f1*sin(theta)+screenHeight/2);
            //glVertex2d(f2*cos(theta)+screenWidth/2,f2*sin(theta)+screenHeight/2);
        }
    glEnd();
}

對數螺旋線

void drawEllipse(double e)//極座標畫圓   n爲圈數    調用時  e的值須要大於1
{
   double theta=0;
   double k=0.8;
   double a=0.6;
     glBegin(GL_POINTS);
        for(;theta<=16*pi;theta+=0.01)
        {
            double f1=k*pow(e,a*theta);//e的a*theta次冪
            //double f2=1/(1+e*cos(theta));
            glVertex2d(f1*cos(theta)+screenWidth/2,f1*sin(theta)+screenHeight/2);
            //glVertex2d(f2*cos(theta)+screenWidth/2,f2*sin(theta)+screenHeight/2);
        }
    glEnd();
}

 

雙曲線

void drawEllipse(double e,double p)//極座標畫圓   n爲圈數                                   e大於1
{
   double theta=0;

     glBegin(GL_POINTS);
        for(;theta<=2*pi;theta+=0.001)
        {
            double f1=e*p/(1-e*cos(theta));//圓錐曲線通用方程  p爲焦點到準線的距離     f1表示數學中極座標的徑向距離
            glVertex2d(f1*cos(theta)+screenWidth/2,f1*sin(theta)+screenHeight/2);
        }
    glEnd();
    glBegin(GL_LINES);  //x軸
        glVertex2d(0,250);
        glVertex2d(500,250);
    glEnd();
    glBegin(GL_LINES);  //y軸
        glVertex2d(250,0);
        glVertex2d(250,500);
    glEnd();
}

 

 由上例可知  雙曲線的右焦點爲極座標系的極點   用到的公式以下

 同理可得橢圓的極座標畫圖代碼及圖像

void drawEllipse(double e,double p)//極座標畫圓   n爲圈數     e小於1
{
   double theta=0;

     glBegin(GL_POINTS);
        for(;theta<=2*pi;theta+=0.001)
        {
            double f1=e*p/(1-e*cos(theta));//圓錐曲線通用方程  p爲焦點到準線的距離     f1表示數學中極座標的徑向距離
            glVertex2d(f1*cos(theta)+screenWidth/2,f1*sin(theta)+screenHeight/2);
        }
    glEnd();
    glBegin(GL_LINES);  //x軸
        glVertex2d(0,250);
        glVertex2d(500,250);
    glEnd();
    glBegin(GL_LINES);  //y軸
        glVertex2d(250,0);
        glVertex2d(250,500);
    glEnd();
}

 能夠看出 橢圓的左焦點爲  極座標的極點  

同理上面代碼中e=1時   是拋物線    開口向右   極點爲焦點

相關文章
相關標籤/搜索