您的位置:首页 > 运维架构

基于OpenGL的LS分形演示程序

2011-11-27 16:59 302 查看
实现了一个基于LS(L系统)的二维分形演示程序。

实现这个演示程序的第一步当然是理解LS文法。咋看之下似乎有点难度,其实一点也不难。

举个例子就明白了:

LS文法先定义了绘图规则:

F:以当前方向前进一步,并画线;

f:以当前方向前进一步,不画线;

+:逆时针旋转角;

-:顺时针旋转角;

[:将海龟当前信息压栈;

]:将“[”时刻的海龟信息出栈。

Koch曲线的LS文法如下:

w:F(初始字母)

a :60(旋转角度)

P:F → F + F - - F + F(F的替代文法)

根据这一文法生成Koch曲线的步骤(假设迭代两次):

第一步: 得到迭代两次的文法。

第一次迭代结果:

F + F - - F + F

第二次迭代结果:(第一次迭代得到的结果的每一个F用规则P替换)

F + F - - F + F + F + F - - F + F - - F + F - - F + F + F + F - - F + F

第二步:按照迭代得到的文法绘图。

界面使用GLUI实现,写得比较简单。可以自己根据规则DIY文法,得到各种图形。全部演示程序代码如下:

#include <GL/glui.h>
#include<iostream>
#include<cmath>
#include<string>
#include<stack>
#define PI 3.1415926
#define lsSize 14

using namespace std;
/** These are the live variables passed into GLUI ***/
int   wireframe = 0;

int   main_window;

int curr_string = 0;
int obj_type = 0;
GLfloat startX = 0.0f;
GLfloat startY = 0.0f;
GLUI_Panel  *obj_panel;
GLUI_Panel  *data_panel;
GLUI_Panel  *basic_data_panel;
GLUI_Panel  *tree_panel;
GLUI_RadioGroup  *radio;

GLUI_EditText *textF;
GLUI_EditText *textX;
GLUI_EditText *textY;
GLUI_EditText *textS;

string diyS;
string diyF;
string diyX;
string diyY;
GLfloat diyAngle;

GLfloat  angle = 30.0; //步进角度
GLfloat len = 0.05f; //线段长度
GLint  depth = 4; //递归深度

struct L_Sys{
string name;
string startStr;
string replaceF;
string replaceX;
string replaceY;
GLfloat angle;
L_Sys(string nname,string nstartStr,string nreplaceF,string nreplaceX,string nreplaceY,GLfloat nangle){
name = nname;
startStr = nstartStr;
replaceF = nreplaceF;
replaceX = nreplaceX;
replaceY = nreplaceY;
angle = nangle;
}
};

struct L_Sys ls[] = {
L_Sys("Koch curve","F","F-F++F-F","","",60.0),
L_Sys("Quadratic Koch IsLand","F+F+F+F","F+F-F-FF+F+F-F","","",90.0f),
L_Sys("Dragon Curve","X","F","X+YF+","-FX-Y",90.0f),
L_Sys("Gosper hexagonal curve","XF","F","X+YF++YF-FX--FXFX-YF+","-FX+YFYF++YF+FX--FX-Y",60.0),
L_Sys("Sierpinski gasket","FXF--FF--FF","FF","--FXF++FXF++FXF--","",60.0f),
L_Sys("SIerpinski arrowhead","YF","F","YF+XF+Y","XF-YF-X",60.0f),
L_Sys("Hilbert curve","X","F","-YF+XFX+FY-","+XF-YFY-FX+",90.0f),
L_Sys("F[+F]F[-F]F","F","F[+F]F[-F]F","","",30.0f),
L_Sys("F[+F]F[-F][F]","F","F[+F]F[-F][F]","","",20.0f),
L_Sys("FF-[-F+F+F]+[+F-F-F]","F","FF-[-F+F+F]+[+F-F-F]","","",22.5f),
L_Sys("F[+X]F[-X]+X","X","FF","F[+X]F[-X]+X","",20.0f),
L_Sys("F[+X][-X]FX","X","FF","F[+X][-X]FX","",25.7f),
L_Sys("F-[[X]+X]+F[+FX]-X","X","FF","F-[[X]+X]+F[+FX]-X","",22.5f),
L_Sys("","","","","",0.0)
};

/***************************************** myGlutIdle() ***********/

void myGlutIdle( void )
{
if ( glutGetWindow() != main_window )
glutSetWindow(main_window);

glutPostRedisplay();
}

void control_cb( int control )
{
if(control == 5){
ls[lsSize-1].angle = diyAngle;
ls[lsSize-1].startStr = diyS;
ls[lsSize-1].replaceF = diyF;
ls[lsSize-1].replaceX = diyX;
ls[lsSize-1].replaceY = diyY;
curr_string = lsSize-1;
}
}

/**************************************** myGlutReshape() *************/

void drawLine(GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2){
glBegin(GL_LINES);
glVertex2f(x1,y1);
glVertex2f(x2,y2);
glEnd();
}

void changeSize(int w, int h) {
if(h == 0)
h = 1;
float ratio = 1.0* w / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(45,ratio,1,1000);
gluLookAt(0.0,0.0,5.0,
0.0,0.0,-1.0,
0.0f,1.0f,0.0f);
glMatrixMode(GL_MODELVIEW);
}

/***************************************** myGlutDisplay() *****************/
struct tpoint{
GLfloat x;
GLfloat y;
GLfloat delta;
};

void fractal(){
string resultStr=ls[curr_string].startStr;
GLfloat Delta= PI*(ls[curr_string].angle)/180;//生成角度
//第一步 得到推进文法
for(int i=0; i<depth;++i){
string tmpStr;
for(int j=0;j<resultStr.size();++j){
if(resultStr[j]=='F'){
tmpStr=tmpStr+ls[curr_string].replaceF;
}else if(resultStr[j]=='X'){
tmpStr=tmpStr+ls[curr_string].replaceX;
}else if(resultStr[j]=='Y'){
tmpStr=tmpStr+ls[curr_string].replaceY;
}else{
tmpStr=tmpStr+resultStr[j];
}
}
resultStr = tmpStr;
}
//解析文法,绘制
int k=0;
tpoint bef={startX,startY,-PI/2},aft;//前一节点 和 后一节点
stack<tpoint> s;
while(k<resultStr.size()){
switch(resultStr[k]) {
case 'F':
aft.x=bef.x+len*cos(bef.delta);
aft.y=bef.y-len*sin(bef.delta);
aft.delta = bef.delta;
drawLine(bef.x,bef.y,aft.x,aft.y);
bef=aft;
break;
case 'X':
aft.x=bef.x+len*cos(bef.delta);
aft.y=bef.y-len*sin(bef.delta);
aft.delta = bef.delta;
drawLine(bef.x,bef.y,aft.x,aft.y);
bef=aft;
break;
case 'Y':
aft.x=bef.x+len*cos(bef.delta);
aft.y=bef.y-len*sin(bef.delta);
aft.delta = bef.delta;
drawLine(bef.x,bef.y,aft.x,aft.y);
bef=aft;
break;
case '+':
bef.delta += Delta;
break;
case '-':
bef.delta -= Delta;
break;
case '[':
s.push(bef);
break;
case ']':
bef = s.top();
s.pop();
break;
default:
break;
}
++k;
}
}

void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(0.0f,1.0f,0.0f);
fractal();
glutSwapBuffers();
}

/**************************************** main() ********************/

int main(int argc, char* argv[])
{
/****************************************/
/*   Initialize GLUT and create window  */
/****************************************/
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowPosition( 100, 100 );
glutInitWindowSize( 500, 500 );
main_window = glutCreateWindow( "OpenGL Fractal " );
glutDisplayFunc( renderScene);
glutReshapeFunc( changeSize );
glEnable(GL_DEPTH_TEST);
GLUI *glui = GLUI_Master.create_glui( "Fractal" );
new GLUI_StaticText( glui, "OpenGL Fractal Control Board" );
basic_data_panel = new GLUI_Panel(glui,"basic data");
GLUI_Spinner *spinnerX =
new GLUI_Spinner( basic_data_panel, "startX:", &startX);
spinnerX->set_float_limits(-2.0, 2.0);
spinnerX->set_alignment( GLUI_ALIGN_LEFT );
GLUI_Spinner *spinnerY =
new GLUI_Spinner( basic_data_panel, "startY:", &startY);
spinnerY->set_float_limits(-3.0, 3.0);
spinnerY->set_alignment( GLUI_ALIGN_LEFT );
GLUI_Spinner *spinnerLen =
new GLUI_Spinner( basic_data_panel, "lenth:", &len);
spinnerLen->set_float_limits(0.0, 3.0);
spinnerLen->set_alignment( GLUI_ALIGN_LEFT );
GLUI_Spinner *spinnerDepth =
new GLUI_Spinner( basic_data_panel, "depth:", &depth);
spinnerDepth->set_int_limits(1, 10);
spinnerDepth->set_alignment( GLUI_ALIGN_LEFT );
data_panel = new GLUI_Panel(glui,"common curve");
GLUI_Listbox *list = new GLUI_Listbox( data_panel, "", &curr_string );
for(int i=0; i<7; ++i)
list->add_item( i, ls[i].name.c_str());
tree_panel = new GLUI_Panel(glui,"2D fractal tree");
GLUI_Listbox *treeList = new GLUI_Listbox( tree_panel, "", &curr_string );
for(int j=7; j<lsSize; ++j)
treeList->add_item( j, ls[j].name.c_str());
GLUI_Rollout *roll_diy = new GLUI_Rollout(glui, "DIY", false);
GLUI_Panel *DIY_panel = new GLUI_Panel( roll_diy, "LS DIY" );
textS = new GLUI_EditText( DIY_panel, "start", diyS, 1, control_cb );
textF = new GLUI_EditText( DIY_panel, "F->", diyF, 2, control_cb );
textX = new GLUI_EditText( DIY_panel, "X->", diyX, 3, control_cb );
textY = new GLUI_EditText( DIY_panel, "Y->", diyY, 4, control_cb );
textS->set_w(50);
textF->set_w(50);
textX->set_w(50);
textY->set_w(50);
textS->set_alignment( GLUI_ALIGN_LEFT);
GLUI_Spinner *spinnerAngle =
new GLUI_Spinner( DIY_panel, "angle:", &diyAngle);
spinnerAngle->set_float_limits(0.0, 90.0);
spinnerAngle->set_alignment( GLUI_ALIGN_LEFT );
GLUI_Button *ok = new GLUI_Button(DIY_panel,"OK!!",5,control_cb);
glui->set_main_gfx_window( main_window );
GLUI_Master.set_glutIdleFunc( myGlutIdle );
new GLUI_Button( glui, "iQuit", 0,(GLUI_Update_CB)exit );
glutMainLoop();
return EXIT_SUCCESS;
}

部分截图:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: