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集群搭建