재귀적 프랙탈

프랙탈의 기본 속성은 자기유사성(Self-Similarity)과 순환성(Recursiveness)으로, 프랙탈의 순환성을 구현하는 가장 원시적인 방법은 함수의 재귀호출을 이용하는 방법이다. 이에 의한 프랙탈은 있는 그대로 따져 만들어진다.

함수의 재귀호출

함수 실행 중 자기자신을 다시 호출하는 것을 재귀호출(Recursive Call)이라 한다. 재귀호출을 순환호출이라고도 한다. 다으에 재귀호출 함수를 사용한 프로그램예를 표시하였다. 이 프로그램에서 RecursiveFunc() 함수는 재귀호출 방식으로 실행된다. 즉 RecursiveFunc() 내부에서 다시 RecursiveFunc() 를 실행시키고 있다.

void RecursiveFunc(int n)
{
    if( n != 3 )
        RecursiveFunc(n+1);

    printf("%-3d", n);
}

int main(void)
{
    RecursivFunc(0);
    return 0;
}

재귀 호출의 자세한 내용은 참고 문헌을 참고하거나 기타 알고리즘 서적을 참고하길 바란다.

예제 프랙탈

다음 코드는 맛보기 프로그램을 표시한 것이다. RecursiveCircle() 함수, 코드는 불과 5 줄이다. 그런데 만들어내는 결과는 무시무시하다. 재귀호출 함수 인자의 '마법의 피리'에 의한 연출이다.

#include "lib\egl.h"
#include <math.h>

using namespace egl;

#define TORAD (0.01745f)

void DrawCircle(GLfloat x, GLfloat y, GLfloat r)
{
    glBegin(GL_POINTS);
        for(int i=0; i<360; ++i)
        {
            glVertex2f(x+(r*cos(i*TORAD)), y+(r*sin(i*TORAD)));
        }
    glEnd();
}

void RecursiveCircle(GLfloat x, GLfloat y, GLfloat r)
{
    if(r>1.0f)
    {
        DrawCircle(x, y, r);
        RecursiveCircle(x-r/2, y, r/2); /* x:r/2 감소, r:1/2감소 */
        RecursiveCircle(x+r/2, y, r/2); /* x:r/2 증가, r:1/2감수 */
    }
}

class RenderWindow : public Window
{
public:
    virtual void RenderGLScene(void);
};

void RenderWindow::RenderGLScene(void)
{
    Window::RenderGLScene();

    glTranslatef(0.0f, 0.0f, -100.0f);
    glColor3f(1.0f, 0.0f, 0.0f);
    RecursiveCircle(0.0f, 0.0f, 30.0f);
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    RenderWindow app;
    if(!app.Create(FALSE))
        return EXIT_FAILURE;
    return app.Run();
}

RecursiveCircle() 함수가 어떻게 위의 그림을 그려내는지 가물가물하다면 참고 문헌을 참고한다. 아주 자세한 설명이 적혀 있다. ;] RecursiveCircle() 의 함수 내용을 조금씩 바꿔 보면서 결과를 보자.

void RecursiveCircle(GLfloat x, GLfloat y, GLfloat r)
{
    if(r>1.0f)
    {
        DrawCircle(x, y, r);

        RecursiveCircle(x-r/2, y, r/2);
        RecursiveCircle(x+r/2, y, r/2);
        RecursiveCircle(x, y-r/2, r/2);
        RecursiveCircle(x, y+r/2, r/2);
    }
}
void RecursiveCircle(GLfloat x, GLfloat y, GLfloat r)
{
    if(r>8.0f)
    {
        DrawCircle(x, y, r/2);

        RecursiveCircle(x-r/2, y, r/2);
        RecursiveCircle(x+r/2, y, r/2);
        RecursiveCircle(x, y-r/2, r/2);
        RecursiveCircle(x, y+r/2, r/2);
    }
}
void RecursiveCircle(GLfloat x, GLfloat y, GLfloat r)
{
    if(r>1.0f)
    {
        if(r<=10.0f)
        {
            glColor3f(0.0f, 0.5f, 0.0f);
        }
        else if(r<=30.0f)
        {
            glColor3f(1.0f, 1.0f, 0.0f);
        }
        else if(r<=50.0f)
        {
            glColor3f(1.0f, 0.0f, 1.0f);
        }
        DrawCircle(x, y, r);
        RecursiveCircle(x-r/2, y, r*0.4);
        RecursiveCircle(x+r/2, y, r*0.4);
        RecursiveCircle(x, y-r/2, r*0.4);
        RecursiveCircle(x, y+r/2, r*0.4);
    }
}

Last updated