OpenGL学习进程(13)第十课:基本图形的底层实现及算法原理

Posted MenAngel

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenGL学习进程(13)第十课:基本图形的底层实现及算法原理相关的知识,希望对你有一定的参考价值。

    本节介绍OpenGL中绘制直线、圆、椭圆,多边形的算法原理。

    (1)绘制任意方向(任意斜率)的直线:

      1)中点画线法:

      中点画线法的算法原理不做介绍,但这里用到最基本的画0<=k<=1的中点画线法实现任意斜率k直线的绘制。

1)当A点x坐标值大于B点坐标值时,即A点在B点的右侧时,交换A、B点的坐标。保证A点在B的左侧。
2)考虑特殊情况,当直线AB的斜率不存在时,做近似处理,设置斜率为-(y0-y1)*100,即近似无穷大。
3)当斜率m满足0<=m<=1时,按书本上的中点画线算法进行处理。
4)当m>1时和m<0时,以y为步进选择对象,计算x基于y的斜率,再重复中点画线的过程。

      代码如下:

 1 #include<GL/glut.h>
 2 #pragma comment(linker,"/subsystem:\\"windows\\" /entry:\\"mainCRTStartup\\"")
 3 
 4 void myInit(){
 5     glMatrixMode(GL_MODELVIEW);
 6     glLoadIdentity();
 7     gluOrtho2D(0.0, 480, 0.0, 480);
 8 }
 9 void Drawpixel(int x, int y){
10     glPointSize(1.0);
11     glColor3f(1.0f, 0.0f, 0.0f);//设置颜色为红色
12     glVertex2i((int)(x), (int)(y));
13 }
14 void MidpointLine(int x0, int y0, int x1, int y1)
15 {
16     int a, b, d1, d2, d, x, y; float m;
17     if (x1<x0){
18         d = x0, x0 = x1, x1 = d;
19         d = y0, y0 = y1, y1 = d;
20     }
21     a = y0 - y1, b = x1 - x0;
22     if (b == 0)
23         m = -1 * a * 100;
24     else
25         m = (float)a / (x0 - x1); x = x0, y = y0;
26     Drawpixel(x, y);
27     if (m >= 0 && m <= 1){
28         d = 2 * a + b; d1 = 2 * a, d2 = 2 * (a + b);
29         while (x<x1){
30             if (d <= 0){
31                 x++, y++, d += d2;
32             }
33             else{
34                 x++, d += d1;
35             }
36             Drawpixel(x, y);
37         }
38     }
39     else if (m <= 0 && m >= -1){
40         d = 2 * a - b; d1 = 2 * a - 2 * b, d2 = 2 * a;
41         while (x<x1){
42             if (d>0){ x++, y--, d += d1; }
43             else{
44                 x++, d += d2;
45             }
46             Drawpixel(x, y);
47         }
48     }
49     else if (m>1){
50         d = a + 2 * b; d1 = 2 * (a + b), d2 = 2 * b;
51         while (y<y1){
52             if (d>0){
53                 x++, y++, d += d1;
54             }
55             else{
56                 y++, d += d2;
57             }
58             Drawpixel(x, y);
59         }
60     }
61     else{
62         d = a - 2 * b; d1 = -2 * b, d2 = 2 * (a - b);
63         while (y>y1){
64             if (d <= 0){
65                 x++, y--, d += d2;
66             }
67             else{
68                 y--, d += d1;
69             }
70             Drawpixel(x, y);
71         }
72     }
73 }
74 void myDisplay(){
75     glClearColor(0, 0, 0, 0);
76     glClear(GL_COLOR_BUFFER_BIT);
77     glBegin(GL_POINTS);
78     MidpointLine(100, 100, 400, 400);
79     MidpointLine(400, 100, 100, 400);
80     glEnd();
81     glFlush();
82 }
83 int main(int argc, char **argv)
84 {
85     glutInit(&argc, argv);
86     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
87     glutInitWindowSize(480, 480);
88     glutInitWindowPosition(200, 200);
89     glutCreateWindow("中点画线法");
90     myInit();
91     glutDisplayFunc(myDisplay);
92     glutMainLoop();
93     return 0;
94 }

 

    2)Breseham算法:

      在这里依然不介绍Breseham的算法原理,但依然以它为基础。Breseham算法与中点算法一样也面临着只能处理0<k<1的情况,要扩展到任意斜率需要进行下述操作:

1)类似中点画线法,保证A(x0,y0)点在B(x1,y1)的左侧。
2)斜率为无穷大时单独画线;
3)其余情况分为4种情况:
一、斜率大于0小于1,按书本上的算法进行画线;
二、斜率大于1则交换横纵坐标;
三、斜率大于-1小于1的情况可先以y=y0作B点的对称点B\',将AB’(此时斜率转化到情况二)画出之后,转化增量到相反的方向,画出直线AB;
四、当斜率小于-1时,先交换横纵坐标值转化为情况三,再利用情况三的算法转化为情况二进行画线。
总结:由于用的是转化法,无论斜率属于那种情况,计算增量的方式都转化到情况一上计算,因此我在这里将情况一抽象为一个函数,仅仅在画点时仅对不同情况做相应的坐标变换。

      代码如下:

 1 #include<GL/glut.h>
 2 #pragma comment(linker,"/subsystem:\\"windows\\" /entry:\\"mainCRTStartup\\"")
 3 
 4 void myInit(){
 5     glMatrixMode(GL_MODELVIEW);
 6     glLoadIdentity();
 7     gluOrtho2D(0.0, 480, 0.0, 480);
 8 }
 9 void Drawpixel(int x, int y){
10     glPointSize(1.0);
11     glColor3f(1.0f, 0.0f, 0.0f);//设置颜色为红色
12     glVertex2i((int)(x), (int)(y));
13 }
14 void drawOrdinayLine(int x0, int y0, int x1, int y1, int flag){
15     int i;
16     int x, y, dx, dy, e;
17     dx = x1 - x0;
18     dy = y1 - y0;
19     e = -dx;
20     x = x0; y = y0;
21     for (i = 0; i <= dx; i++){
22         switch (flag){
23         case 0:        Drawpixel(x, y);  break;
24         case 1:        Drawpixel(x, 2 * y0 - y); break;//增量为(y-y0)则,实际增量应取相反方向为y0-(y-y0)=2y0-y
25         case 2:        Drawpixel(y, x); break;//这里也要交换
26         case 3:        Drawpixel(2 * y0 - y, x); break;
27         }
28         x++;
29         e = e + 2 * dy;
30         if (e >= 0){
31             y++;
32             e = e - 2 * dx;
33         }
34     }
35 }
36 void BresenhamLine(int x0, int y0, int x1, int y1){
37     int d;
38     int i;
39     if (x0>x1){
40         d = x0, x0 = x1, x1 = d;
41         d = y0, y0 = y1, y1 = d;
42     }
43     if (x0 == x1){
44         if (y0>y1){//保证y0<y1;
45             d = y0, y0 = y1, y1 = d;
46         }
47         for (i = y0; i< y1; i++){
48             Drawpixel(x0, i);
49         }
50         return;
51     }
52     float k = (1.0*(y1 - y0)) / (x1 - x0);
53     if (0 <= k&&k <= 1){  //直接画
54         drawOrdinayLine(x0, y0, x1, y1, 0);
55     }
56     else if (-1 <= k&&k<0){//以y=y0作B点的对称点
57         drawOrdinayLine(x0, y0, x1, y1 + 2 * (y0 - y1), 1);
58     }
59     else if (k>1){//交换x,y的坐标值。
60         drawOrdinayLine(y0, x0, y1, x1, 2);
61     }
62     else if (k<-1){
63         //交换x0和y0,x1和y1;
64         d = x0; x0 = y0; y0 = d;
65         d = x1; x1 = y1; y1 = d;
66         //交换两个点
67         d = x0, x0 = x1, x1 = d;
68         d = y0, y0 = y1, y1 = d;
69         drawOrdinayLine(x0, y0, x1, y1 + 2 * (y0 - y1), 3);
70     }
71 }
72 void myDisplay(){
73     glClearColor(0, 0, 0, 0);
74     glClear(GL_COLOR_BUFFER_BIT);
75     glBegin(GL_POINTS);
76     int i;
77     BresenhamLine(200, 100, 300, 150);
78     BresenhamLine(200, 100, 300, 450);
79     BresenhamLine(125, 125, 400, 400);
80     BresenhamLine(125, 125, 75, 175);
81     glEnd();
82     glFlush();
83 }
84 int main(int argc, char **argv)
85 {
86     glutInit(&argc, argv);
87     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
88     glutInitWindowSize(480, 480);
89     glutInitWindowPosition(200, 200);
90     glutCreateWindow("中点画线法");
91     myInit();
92     glutDisplayFunc(myDisplay);
93     glutMainLoop();
94     return 0;
95 }

  

 

    (2)绘制圆和椭圆:

    中点画线法利用直线方程,画圆和椭圆利用的是椭圆和圆的方程。

    1)中点画圆法:

    标准中点画圆算法只能实现八分之一的圆弧,这里利用椭圆的点的对称性,每画一个点就对称的画出其他七段圆弧上的点。最后每个点均加上一个平移量,即圆的中点坐标,实现任意指定圆心坐标。

    2)中点画椭圆法:

1)先画椭圆上顶点,然后以上顶点为基础运用椭圆的坐标方程式和中点画线法计算步进值。
2)从上顶点开始,每两个像素点组成一组画一条直线,一个像素点可同时当开始点和结束点。
3)利用椭圆的轴对称性对称的画出其它三条线。任意坐标的指定利用像素点的平移操作来进行。

    代码如下:(圆和椭圆)

  1 #include <GL/glut.h>   
  2 #include <math.h>
  3 #pragma comment(linker,"/subsystem:\\"windows\\" /entry:\\"mainCRTStartup\\"")
  4 
  5 void Init()
  6 {
  7     glClearColor(0,0,0,0);
  8     glMatrixMode(GL_MODELVIEW);
  9     glLoadIdentity();
 10     gluOrtho2D(-400,400,-400,400);
 11 }
 12 void CirclePoint(int x0,int y0,int x,int y){
 13     //每画一个点对称的画出八个点,并按照中点坐标平移相同单位
 14     glVertex2d(x + x0, y + y0);
 15     glVertex2d(x + x0, -y + y0);
 16     glVertex2d(-x + x0, -y + y0);
 17     glVertex2d(-x + x0, y + y0);
 18     glVertex2d(y + x0, x + y0);
 19     glVertex2d(-y + x0, x + y0);
 20     glVertex2d(y + x0, -x + y0);
 21     glVertex2d(-y + x0, -x + y0);
 22 }
 23 void MidPointCircle(int x0,int y0,int r){//圆点和半径
 24     //画右上方1/8的圆
 25     int x, y;
 26     float d;
 27     x = 0; y = r;
 28     d = 1.25;
 29     CirclePoint(x0, y0,x,y);
 30     while (x <= y){
 31         if (d < 0)
 32             d += 2 * x + 3;
 33         else{
 34             d += 2 * (x - y) + 5;
 35             y--;
 36         }
 37         x++;
 38         CirclePoint(x0, y0, x, y);
 39     }
 40 }
 41 
 42 void Drawpixel(int x, int y){
 43     glPointSize(1.0);
 44     glColor3f(1.0f, 0.0f, 0.0f);//设置颜色为红色
 45     glVertex2i((int)(x), (int)(y));
 46 }
 47 void drawLine(int x0,int y0,int x1,int y1){
 48     int a, b, d1, d2, d, x, y; float m;
 49     if (x1<x0){
 50         d = x0, x0 = x1, x1 = d;
 51         d = y0, y0 = y1, y1 = d;
 52     }
 53     a = y0 - y1, b = x1 - x0;
 54     if (b == 0)
 55         m = -1 * a * 100;
 56     else
 57         m = (float)a / (x0 - x1); x = x0, y = y0;
 58     Drawpixel(x, y);
 59     if (m >= 0 && m <= 1){
 60         d = 2 * a + b; d1 = 2 * a, d2 = 2 * (a + b);
 61         while (x<x1){
 62             if (d <= 0){
 63                 x++, y++, d += d2;
 64             }
 65             else{
 66                 x++, d += d1;
 67             }
 68             Drawpixel(x, y);
 69         }
 70     }
 71     else if (m <= 0 && m >= -1){
 72         d = 2 * a - b; d1 = 2 * a - 2 * b, d2 = 2 * a;
 73         while (x<x1){
 74             if (d>0){ x++, y--, d += d1; }
 75             else{
 76                 x++, d += d2;
 77             }
 78             Drawpixel(x, y);
 79         }
 80     }
 81     else if (m>1){
 82         d = a + 2 * b; d1 = 2 * (a + b), d2 = 2 * b;
 83         while (y<y1){
 84             if (d>0){
 85                 x++, y++, d += d1;
 86             }
 87             else{
 88                 y++, d += d2;
 89             }
 90             Drawpixel(x, y);
 91         }
 92     }
 93     else{
 94         d = a - 2 * b; d1 = -2 * b, d2 = 2 * (a - b);
 95         while (y>y1){
 96             if (d <= 0){
 97                 x++, y--, d += d2;
 98             }
 99             else{
100                 y--, d += d1;
101             }
102             Drawpixel(x, y);
103         }
104     }
105 }
106 void drawOval(int x0,int y0,int a, int b){
107     int x, y;
108     int xx, yy;
109     double d1, d2;
110     x = 0; y = b;
111     d1 = b*b + a*a*(-b + 0.25);
112     drawLine(x0 + x, y0 + y, x0+ x, y0 + y);
113     drawLine(x0 - x, y0-y, x0 - x, y0-y);
114     drawLine(x0 + x, y0-y, x0 + x, y0-y);
115     drawLine(x0 - x, y0+y, x0 - x, y0+y);
116     xx = x; yy = y;
117     while (b*b*(x + 1)<a*a*(y - 0.5))
118     {
119         if (d1<0)
120         {
121             d1 += b*b*(2 * x + 3);
122             x++;
123         }
124         else
125         {
126             d1 += (b*b*(2 * x + 3) + a*a*(-2 * y + 2));
127             x++; y--;
128         }
129         drawLine(x0 + xx, y0+yy, x0 + x, y0+y);
130         drawLine(x0 - xx, y0-yy, x0 - x, y0-y);
131         drawLine(x0 + xx, y0-yy, x0 + x, y0-y);
132         drawLine(x0 - xx, y0+yy, x0 - x, y0+y);
133         xx = x; yy = y;
134     }
135     d2 = sqrt(b*(x + 0.5)) + sqrt(a*(y - 1)) - sqrt(a*b);
136     while (y>0)
137     {
138         if (d2<0)
139         {
140             d2 += b*b*(2 * x + 2) + a*a*(-2 * y + 3);
141             x++; y--;
142         }
143         else
144         {
145             d2 += a*a*(-2 * y + 3);
146             y--;
147         }
148         drawLine(x0 + xx, y0+yy, x0 + x, y0+y);
149         drawLine(x0 - xx, y0-yy, x0 - x, y0-y);
150         drawLine(x0 + xx, y0-yy, x0 + x, y0-y);
151         drawLine(x0 - xx, y0+yy, x0 - x, y0+y);
152         xx = x; yy = y;
153     }
154 }
155 void display(){
156     glClear(GL_COLOR_BUFFER_BIT);
157     glColor3f(1.0,1.0,0);
158     glBegin(GL_POINTS);
159     MidPointCircle(0, 50, 100);
160     MidPointCircle(0, -50, 100);
161     MidPointCircle(50, 0, 100);
162     MidPointCircle(-50, 0, 100);
163     //drawOval(100,0,200,100);
164     Es学习第十课,ElasticSearch集群搭建

openGL学习进程OpenGL的简介

Django 第十课 4.ORM查询操作

7.10-第十课:线程同步

电脑小白学习第十课---excel文件设置访问密码

Jsp第十课 Jsp标准标签库(JSTL)的学习和使用