//----------------------------------------------------------------------------- // Fraktaly v pocitacove grafice // Demonstracni priklad 53.2 // Autor: Pavel Tisnovsky // // Vykresleni snehove vlocky Helge von Kocha (Koch Snowflake) pomoci L-systemu. // Po prekladu a spusteni programu se nejprve provede nekolikere rozepsani // gramatiky. Vysledny retezec je posleze pouzit pro vykresleni L-systemu // za pomoci zelvi grafiky (turtle graphics). // Zmena velikosti fraktalu se provadi stiskem klaves [PageUp] a [PageDown], // posun fraktalu je mozne provest kurzorovymi klavesami (sipkami). // Zmena poctu prepisu symbolu 'F' se provadi pomoci klaves [1]-[5]. // Ukonceni aplikace se provede klavesou [Esc] nebo klavesou [Q]. //----------------------------------------------------------------------------- #ifdef __BORLANDC__ #include <windows.h> #endif #include <GL/glut.h> // hlavickovy soubor funkci GLUTu a OpenGL #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #define WINDOW_TITLE "Fraktaly 53.2" // titulek okna #define WINDOW_WIDTH 400 // pocatecni velikost okna #define WINDOW_HEIGHT 470 #define MAX_LENGTH 16384 // maximalni delka retezce #define START_SYMBOL "F++F++F" // startovaci symbol double xpos=0.0; // pozice fraktalu v okne double ypos=0.87*WINDOW_WIDTH/3; char ret[MAX_LENGTH]=START_SYMBOL; // pocatecni symbol const char prepstr[]="F-F++F-F"; // prepisovaci pravidlo int rulesCount=1; // pocet aplikaci prepisovaciho pravidla double step=WINDOW_WIDTH/3; // krok zelvy double x, y, alpha; // souradnice a natoceni zelvy double delta=3.1415927/3.0; //----------------------------------------------------------------------------- // Aplikace prepisovaciho pravidla na retezec //----------------------------------------------------------------------------- void applyRule(void) { int i, j, k; // pocitadla smycek a indexy znaku char src[MAX_LENGTH]; // zdrojovy retezec char dest[MAX_LENGTH]; // cilovy retezec int fcount=0; // pocet prepisu strcpy(src, ret); puts(src); // kontrolni vypis pred prepisem for (i=0, j=0; src[i]; i++) { // projit celym retezcem if (src[i]=='F') { // tento symbol se ma prepsat for (k=0; prepstr[k]; k++) // provest prepis dest[j++]=prepstr[k]; } else { // ostatni symboly kopirovat dest[j]=src[i]; j++; } } dest[j]=0; for (j=0; dest[j]; j++) if (dest[j]=='F') fcount++; puts(dest); // kontrolni vypis po prepisu printf("fcount=%d\n", fcount); strcpy(ret, dest); } //----------------------------------------------------------------------------- // Inicializace L-systemu //----------------------------------------------------------------------------- void initLSystem(void) { int i; // pocatecni symbol strcpy(ret, START_SYMBOL); // aplikace prepisovaciho pravidla for (i=0; i<rulesCount; i++) applyRule(); } //----------------------------------------------------------------------------- // Nastaveni zelvy do pocatecni (domaci) pozice //----------------------------------------------------------------------------- void logo_home(double xpos, double ypos) { x=xpos; y=ypos; alpha=0.0; } //----------------------------------------------------------------------------- // Posun zelvy dopredu s kreslenim //----------------------------------------------------------------------------- void logo_forward(void) { glBegin(GL_LINES); glVertex2d(x,y); x+=step*cos(alpha); // posun v zadanem smeru y+=step*sin(alpha); glVertex2d(x,y); glEnd(); } //----------------------------------------------------------------------------- // Posun zelvy dozadu s kreslenim //----------------------------------------------------------------------------- void logo_backward(void) { glBegin(GL_LINES); glVertex2d(x,y); x+=step*cos(alpha); // posun v zadanem smeru y+=step*sin(alpha); glVertex2d(x,y); glEnd(); } //----------------------------------------------------------------------------- // Posun zelvy dopredu bez kresleni //----------------------------------------------------------------------------- void logo_move(void) { x+=step*cos(alpha); // posun v zadanem smeru y+=step*sin(alpha); } //----------------------------------------------------------------------------- // Otoceni zelvy doleva //----------------------------------------------------------------------------- void logo_left(void) { alpha+=delta; // zmena uhlu } //----------------------------------------------------------------------------- // Otoceni zelvy doprava //----------------------------------------------------------------------------- void logo_right(void) { alpha-=delta; // zmena uhlu } //----------------------------------------------------------------------------- // Prekresleni L-systemu //----------------------------------------------------------------------------- void recalcLsys(const char *ret, // ridici retezec double xpos, // posun obrazce double ypos) { int i; logo_home(xpos, ypos); // inicializace zelvy for (i=0; ret[i]; i++) { // projit celym retezcem switch (ret[i]) { // a reagovat na prikazy case 'F': // posun v zadanem smeru logo_forward(); break; case 'B': // zpetny posun v zadanem smeru logo_backward(); break; case 'G': // posun v zadanem smeru bez kresleni logo_move(); break; case '+': // zmena uhlu logo_left(); break; case '-': // zmena uhlu logo_right(); break; default: break; } } } //----------------------------------------------------------------------------- // Funkce volana pro inicializaci vykreslovani //----------------------------------------------------------------------------- void onInit(void) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // barva pozadi glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // mod ulozeni pixelu initLSystem(); } //----------------------------------------------------------------------------- // Nastaveni souradneho systemu v zavislosti na velikosti okna //----------------------------------------------------------------------------- void onResize(int w, int h) // argumenty w a h reprezentuji novou velikost okna { glViewport(0, 0, w, h); // viditelna oblast pres cele okno glMatrixMode(GL_PROJECTION); // zacatek modifikace projekcni matice glLoadIdentity(); // vymazani projekcni matice (=identita) glOrtho(0, w, 0, h, -1, 1); // mapovani abstraktnich souradnic do souradnic okna } //----------------------------------------------------------------------------- // Tato callback funkce je zavolana pri kazdem prekresleni okna //----------------------------------------------------------------------------- void onDisplay(void) { glClear(GL_COLOR_BUFFER_BIT); // vymazani vsech bitovych rovin barvoveho bufferu glDrawBuffer(GL_BACK); // pixmapa se bude kreslit do zadniho barvoveho bufferu recalcLsys(ret, xpos, ypos); // prekresleni L-systemu glFlush(); // provedeni a vykresleni vsech zmen glutSwapBuffers(); } //----------------------------------------------------------------------------- // Tato callback funkce je zavolana pri stlaceni ASCII klavesy //----------------------------------------------------------------------------- #ifdef __BORLANDC__ #pragma option -w-par #endif void onKeyboard(unsigned char key, int x, int y) { key=(key>='A' && key<='Z') ? key-'A'+'a': key; // zmena poctu prepsani retezce if (key>='1' && key<='5') { rulesCount=key-'1'+1; // zmena kroku v zavislosti na poctu prepisu step=WINDOW_WIDTH/(pow(3, rulesCount)); initLSystem(); glutPostRedisplay(); return; } switch (key) { case 27: // pokud byla stlacena klavesa ESC, konec programu case 'q': exit(0); break; // totez co klavesa ESC default: break; } } #ifdef __BORLANDC__ #pragma option -w+par #endif //----------------------------------------------------------------------------- // Tato callback funkce je zavolana pri stlaceni non-ASCII klavesy //----------------------------------------------------------------------------- #ifdef __BORLANDC__ #pragma option -w-par #endif void onSpecial(int key, int x, int y) { // posun fraktalu a zmena meritka switch (key) { case GLUT_KEY_LEFT: xpos-=5; glutPostRedisplay(); break; case GLUT_KEY_RIGHT: xpos+=5; glutPostRedisplay(); break; case GLUT_KEY_UP: ypos+=5; glutPostRedisplay(); break; case GLUT_KEY_DOWN: ypos-=5; glutPostRedisplay(); break; case GLUT_KEY_PAGE_UP: step+=0.1; glutPostRedisplay(); break; case GLUT_KEY_PAGE_DOWN: step-=0.1; glutPostRedisplay(); break; default: break; } } #ifdef __BORLANDC__ #pragma option -w+par #endif //----------------------------------------------------------------------------- // Hlavni funkce konzolove aplikace //----------------------------------------------------------------------------- int main(int argc, char **argv) { glutInit(&argc, argv); // inicializace knihovny GLUT glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutCreateWindow(WINDOW_TITLE); // vytvoreni okna pro kresleni glutReshapeWindow(WINDOW_WIDTH, WINDOW_HEIGHT);// zmena velikosti okna glutPositionWindow(100, 100); // pozice leveho horniho rohu okna glutDisplayFunc(onDisplay); // registrace funkce volane pri prekreslovani okna glutReshapeFunc(onResize); // registrace funkce volane pri zmene velikosti okna glutKeyboardFunc(onKeyboard); // registrace funkce volane pri stlaceni klavesy glutSpecialFunc(onSpecial); // registrace funkce volane pri stlaceni specialni klavesy onInit(); // inicializace vykreslovani glutMainLoop(); // nekonecna smycka, kde se volaji zaregistrovane funkce return 0; // navratova hodnota vracena operacnimu systemu } //----------------------------------------------------------------------------- // finito //-----------------------------------------------------------------------------