Midpoint Circle 算法 是计算机图形学中画圆的一种重要的算法,用这种算法我们可以很轻易的绘制出一个圆形的图案,在这里我将使用OpenGL来绘制一个八卦图,也主要就是使用Midpoint Circle 算法进行圆以及半圆等的绘制然后填充。
主要的思路如下:
首先我们使用Midpoint Circle 算法来绘制一个圆形,然后对于圆形的上半部分使用黑色进行填充,然后再黑色调冲部分的左半圆部分使用大圆半径的一半大小来绘制一个白色填充部分,然后在下半圆的右半部分使用同样的方法来填充一块黑色的部分,然后再对两个部分进行白色填充黑色的实心圆,黑色部分填充白色的实心圆,这样一个八卦图就基本成形了。当然这里只是我个人的一点愚见,大家有什么更好的画法希望能够进行讨论,我之所以贴出来也就是为了和大家一起讨论学习。。哈哈
Midpoint Circle 算法概述:
设圆之半径为r。先考虑圆心在(0,0),并从x=0, y=r开始的顺时针方向的1/8圆周的生成过程。在这种情况下,x每步增加1,从x=0开始,到x=y结束。即有:xi+1 =xi+1 相应的yi+1 则在两种可能中选择:yi+1 =yi ,或者yi+1 =yi -1选择的原则是考察精确值y靠近yi还是靠近yi-1
因此定义Pk如下:
由此先画
1/8
个圆
,
再画其余对称的
7
个
1/8
个圆
(
坐标变换得来
)
画圆的OpenGL代码如下:
/**/
/* 工程名称: 八卦图 *版权信息: CopyRight By Fonhal *作者信息: :fonhal *工程描述: 使用OpenGL绘制一个八卦图 */
//
八卦图.cpp : 定义控制台应用程序的入口点。
//
#include
"
stdafx.h
"
#include
<
glglut.h
>
void
init(
void
)
...
{ glClearColor( 1.0 , 1.0 , 1.0 , 0.0 ); // 设置窗口背景色 glMatrixMode(GL_PROJECTION); gluOrtho2D( 0.0 , 400.0 , 0.0 , 400.0 ); // 窗口坐标左下角(0,0), 右上角(400,400) }
//
功能说明: 画一个圆的边缘,用GL_LINES去填充外面的线
void
DrawCircle(
int
PX,
int
PY,
int
Radius)
...
{ int px = 0 , py = 0 ; int pX = 0 , pY = Radius; int pkNow = 5 / 4 - Radius, pkNext = 0 ; glColor3f( 0.0 , 0.0 , 0.0 ); while (px <= py) ... { px = pX;py = pY; if (pkNow < 0 ) ... { pkNext = pkNow + 2 * px + 3 ; pkNow = pkNext; pX = px + 1 ; } else ... { pkNext = pkNow + 2 * px - 2 * py + 5 ; pkNow = pkNext; pX = px + 1 ; pY = py - 1 ; } glBegin(GL_LINES); // 第一象限 glVertex2i(PX + px,PY + py); glVertex2i(PX + pX,PY + pY); glVertex2i(PX + py,PY + px); glVertex2i(PX + pY,PY + pX); // 第二象限 glVertex2i(PX - px,PY + py); glVertex2i(PX - pX,PY + pY); glVertex2i(PX - py,PY + px); glVertex2i(PX - pY,PY + pX); // 第三象限 glVertex2i(PX - py,PY - px); glVertex2i(PX - pY,PY - pX); glVertex2i(PX - px,PY - py); glVertex2i(PX - pX,PY - pY); // 第四象限 glVertex2i(PX + py,PY - px); glVertex2i(PX + pY,PY - pX); glVertex2i(PX + px,PY - py); glVertex2i(PX + pX,PY - pY); glEnd(); } glFlush(); }
//
功能说明: 画一个实心圆,可以自定义填充颜色,并且可以通过选择Pozition来选择位置,如果Pozition=1则画一个完整的实心圆,Pozition=2画一个上半圆,Pozition=3画一个下半圆
void
DrawCircle(
int
PX,
int
PY,
int
Radius,
int
red,
int
green,
int
blue,
int
pozition)
...
{ int px = 0 , py = 0 ; int pX = 0 , pY = Radius; int pkNow = 5 / 4 - Radius, pkNext = 0 ; glColor3f(red,green,blue); while (px <= py) ... { px = pX;py = pY; if (pkNext < 0 ) ... { pkNext = pkNow + 2 * px + 3 ; pkNow = pkNext; pX = px + 1 ; } else ... { pkNext = pkNow + 2 * px - 2 * py + 5 ; pkNow = pkNext; pX = px + 1 ; pY = py - 1 ; } if ( 1 == pozition) // 当pozition=1的时候绘制一个完整的实心圆,使用凸三角形进行填充 ... { // 第一象限 glBegin(GL_POLYGON); glVertex2i(PX + px,PY + py); glVertex2i(PX + pX,PY + pY); glVertex2i(PX,PY); glEnd(); glBegin(GL_POLYGON); glVertex2i(PX + py,PY + px); glVertex2i(PX + pY,PY + pX); glVertex2i(PX,PY); glEnd(); // 第二象限 glBegin(GL_POLYGON); glVertex2i(PX - px,PY + py); glVertex2i(PX - pX,PY + pY); glVertex2i(PX,PY); glEnd(); glBegin(GL_POLYGON); glVertex2i(PX - py,PY + px); glVertex2i(PX - pY,PY + pX); glVertex2i(PX,PY); glEnd(); // 第三象限 glBegin(GL_POLYGON); glVertex2i(PX - py,PY - px); glVertex2i(PX - pY,PY - pX); glVertex2i(PX,PY); glEnd(); glBegin(GL_POLYGON); glVertex2i(PX - px,PY - py); glVertex2i(PX - pX,PY - pY); glVertex2i(PX,PY); glEnd(); // 第四象限 glBegin(GL_POLYGON); glVertex2i(PX + py,PY - px); glVertex2i(PX + pY,PY - pX); glVertex2i(PX,PY); glEnd(); glBegin(GL_POLYGON); glVertex2i(PX + px,PY - py); glVertex2i(PX + pX,PY - pY); glVertex2i(PX,PY); glEnd(); } else if ( 2 == pozition) // 当pozition=2的时候绘制上半圆,使用凸三角形进行填充 ... { // 第一象限 glBegin(GL_POLYGON); glVertex2i(PX + px,PY + py); glVertex2i(PX + pX,PY + pY); glVertex2i(PX,PY); glEnd(); glBegin(GL_POLYGON); glVertex2i(PX + py,PY + px); glVertex2i(PX + pY,PY + pX); glVertex2i(PX,PY); glEnd(); // 第二象限 glBegin(GL_POLYGON); glVertex2i(PX - px,PY + py); glVertex2i(PX - pX,PY + pY); glVertex2i(PX,PY); glEnd(); glBegin(GL_POLYGON); glVertex2i(PX - py,PY + px); glVertex2i(PX - pY,PY + pX); glVertex2i(PX,PY); glEnd(); } else if ( 3 == pozition) // 当pozition=3的时候绘制下半圆,使用凸三角形进行填充 ... { // 第三象限 glBegin(GL_POLYGON); glVertex2i(PX - py,PY - px); glVertex2i(PX - pY,PY - pX); glVertex2i(PX,PY); glEnd(); glBegin(GL_POLYGON); glVertex2i(PX - px,PY - py); glVertex2i(PX - pX,PY - pY); glVertex2i(PX,PY); glEnd(); // 第四象限 glBegin(GL_POLYGON); glVertex2i(PX + py,PY - px); glVertex2i(PX + pY,PY - pX); glVertex2i(PX,PY); glEnd(); glBegin(GL_POLYGON); glVertex2i(PX + px,PY - py); glVertex2i(PX + pX,PY - pY); glVertex2i(PX,PY); glEnd(); } } glFlush(); }
//
功能说明: 调用上面的函数来画一个八卦图形
void
DisplayFunc()
...
{ glClear(GL_COLOR_BUFFER_BIT); DrawCircle( 200 , 200 , 144 ); // 画一个圆心在(200,200)半径为144的圆 DrawCircle( 200 , 200 , 144 , 0 , 0 , 0 , 2 ); // 画一个圆心在(200,200)半径为144填充颜色为白色的上半圆 DrawCircle( 129 , 200 , 72 , 1 , 1 , 1 , 2 ); // 画一个圆心在(129,200)半径为72填充颜色为白色的上半圆 DrawCircle( 272 , 200 , 72 , 0 , 0 , 0 , 3 ); // 画一个圆心在(272,200)半径为72填充颜色为黑色的下半圆 DrawCircle( 129 , 200 , 7 ); // 画一个圆心在(129,200)半径为7黑色圆 DrawCircle( 129 , 200 , 8 , 0 , 0 , 0 , 1 ); // 画一个圆心在(129,200)半径为8填充颜色为黑色的实心圆 DrawCircle( 272 , 200 , 7 ); // 画一个圆心在(272,200)半径为7黑色圆 DrawCircle( 272 , 200 , 8 , 1 , 1 , 1 , 1 ); // 画一个圆心在(272,200)半径为8填充颜色为白色的实心圆 }
void
main(
int
argc,
char
**
argv)
...
{ glutInit( & argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // 单缓存+RGB方式 glutInitWindowPosition( 50 , 100 ); // 窗口位置 glutInitWindowSize( 400 , 400 ); // 窗口大小 glutCreateWindow( " 八卦 " ); // 建立窗口 init(); glutDisplayFunc(DisplayFunc); // 显示图形 glutMainLoop(); // 等待 }
绘制结果如下: