タイトル 再帰によるフラクタル図形の描画
概要
「再帰」というプログラムを使い、不思議な不思議な図形、フラクタル図形を描いてみる、
関数自体にその関数が定義されているものを再帰と言います。
例えば、こんな関数↓
int func(int n){
if(n==0 || n==1) return 1;
else return n*func(n-1);
}
この関数は階乗を求める関数です。一見すると無限ループしそうですが引数nの値がループするうちにどんどん小さくなり、最終的にnが1になったとき、
この関数は終了し、戻り値を返します。
その図形の一部分と全体が相似な関係(自己相似性)をもっている図形をフラクタル図形といいます。
フラクタル図形は複雑そうですが再帰プログラムを用いることで比較的容易に描くことができます。
結果
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (h1.jpg)
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (h2.jpg)
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (h3.jpg)
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (h4.jpg)
imageプラグインエラー : ご指定のファイルが見つかりません。ファイル名を確認して、再度指定してください。 (h5.jpg)
考察
図形は三次元上に描き、近づいたり離れたりすることで拡大縮小を行っているため、近づく速度が一定だと、図形の拡大速度は
変化してしまうので、図形の拡大速度を一定にするようにしたい。
感想
次回はマンデルブロ集合やジュリア集合等のフラクタル図形を描くプログラムを作ってみたい(気)
参考文献
「c フラクタル」でgoogle先生に聞く
ソースコード
//DxLibのソースだよ!
#include "DxLib.h"
#include "math.h"
#include "Fractal.h"
#define magni 200 //表示の縮尺
#define magni2 0.01
#define Pi 3.14159 //π
double dosu = 30.0; //コッホ島度数
double rad = dosu*(Pi/180.0); //コッホ島ラジアン
double kl, kix, kiy; //コッホ島パラメーター
double s = sin(Pi/3.0);
double c = cos(Pi/3.0);
char Key[256]; //キー取得
int pros[10], prosn; //処理制限...
int Blue, Red, White, Purple; //各種色
int SelectNum = 0; // 現在の選択番号
int mode = 0;
// メニュー項目の表示に必要な構造体を用意する
typedef struct{
int x, y; // 座標格納用変数
char name[128]; // 項目名格納用変数
} MenuElement_t ;
//自作関数
int gpUpdateKey(); //キー入力更新(コピペ)
void Back(int pict); //背景表示
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //初期化処理
SetDrawScreen( DX_SCREEN_BACK ); //裏画面に設定
int i,n;
double x1,y1,x2,y2,x3,y3; //はじめの三角形
double kx1,ky1,kx2,ky2;
double bx1,by1,bx2,by2;
VECTOR CameraPos ;
// カメラの座標を初期化
CameraPos.x = 0.0f;
CameraPos.y = 0.0f;
CameraPos.z = 5000.0f;
// メニュー項目要素を5つ作る
MenuElement_t MenuElement[5]={
{ 100, 10, "1.シェルピンスキーのガスケット" },
{ 100, 10, "2.コッホ曲線" },
{ 100, 10, "3.Cカーブ" },
{ 100, 10, "4.ドラゴン曲線" },
{ 100, 10, "5.二分木" },
};
MenuElement_t ModeElement[2]={
{ 100, 50, "図形選択モード" },
{ 100, 50, "観察モード" },
};
n = 0;
x1 = 0.0;
y1 = -1.0;
x2 = 1.0;
y2 = 1.0;
x3 = -1.0;
y3 = 1.0;
kx1=-1.5;
ky1=1.0;
kx2=1.5;
ky2=1.0;
bx1=-0.0;
by1=2.0;
bx2=0.0;
by2=0.0;
White = GetColor( 255 , 255 , 255 ) ; // 白色の値を取得
Red = GetColor( 255 , 0 , 0 ) ; // 赤色の値を取得
while(!ProcessMessage() && !ClearDrawScreen() && gpUpdateKey()==0 && !Key[KEY_INPUT_ESCAPE]){
//↑メッセージ処理 ↑画面をクリア ↑キーボード入力状態取得 ↑ESCが押されていない
// 計算フェーズ
//モード選択
if( Key[ KEY_INPUT_SPACE ] == 1 ) mode = (mode+1) % 2;
//モード:0
//フラクタル図形選択
if( Key[ KEY_INPUT_RIGHT ] == 1 && mode==0 ) SelectNum = ( SelectNum + 1 ) % 5;
if( Key[ KEY_INPUT_LEFT ] == 1 && mode==0 ) SelectNum = ( SelectNum + 4 ) % 5;
//再帰回数の増減
if( Key[ KEY_INPUT_UP ] == 1 && mode==0 ) n+=1;
if( Key[ KEY_INPUT_DOWN ] == 1 && mode==0 && n>0 ) n-=1;
//モード1
//方向キーでカメラの座標を移動
if( CheckHitKey( KEY_INPUT_UP ) == 1 && mode==1 ) CameraPos.y += 5.0f;
if( CheckHitKey( KEY_INPUT_DOWN ) == 1 && mode==1 ) CameraPos.y -= 5.0f;
if( CheckHitKey( KEY_INPUT_LEFT ) == 1 && mode==1 ) CameraPos.x += 5.0f;
if( CheckHitKey( KEY_INPUT_RIGHT ) == 1 && mode==1 ) CameraPos.x -= 5.0f;
if( CheckHitKey( KEY_INPUT_Z ) == 1 && mode==1 && CameraPos.z>10.0f ){
if(SelectNum==0){
y1 += 1.0*magni2;
x2 -= sqrt(2)*magni2;
y2 -= sqrt(2)*magni2;
x3 += sqrt(2)*magni2;
y3 -= sqrt(2)*magni2;
}
else CameraPos.z -= 5.0f;
}
if( CheckHitKey( KEY_INPUT_X ) == 1 && mode==1 ){
if(SelectNum==0){
y1 -= 1.0*magni2;
x2 += sqrt(2)*magni2;
y2 += sqrt(2)*magni2;
x3 -= sqrt(2)*magni2;
y3 += sqrt(2)*magni2;
}
CameraPos.z += 5.0f;
}
//カメラの位置と注視点をセット
SetCameraPositionAndTarget_UpVecY(CameraPos, VGet(0.0f+CameraPos.x, 0.0f+CameraPos.y, 0.0f));
kl = kx2-kx1;
kix = kx1+kl*sin(rad);
kiy = ky1+kl*cos(rad);
// 描画フェーズ
if(SelectNum==0)Fractal_Sierpinski(x1, y1, x2, y2, x3, y3, n, White);
if(SelectNum==1){
Fractal_KochCurve(kx1, ky1, kx2, ky2, n, White);
Fractal_KochCurve(kix, kiy, kx1, ky1, n, White);
Fractal_KochCurve(kx2, ky2, kix, kiy, n, White);
}
if(SelectNum==2)Fractal_CCurve(kx1, ky1, kx2, ky2, n, White);
if(SelectNum==3)Fractal_DragonCurve(kx1, ky1, kx2, ky2, n, White);
if(SelectNum==4)Fractal_BinaryTree(bx1, by1, bx2, by2, n, White);
DrawFormatString( MenuElement[SelectNum].x, MenuElement[SelectNum].y, White, MenuElement[SelectNum].name );
DrawFormatString( 100, 30, White, "再帰回数:%d",n );
DrawFormatString( ModeElement[mode].x, ModeElement[mode].y, White, ModeElement[mode].name );
DrawFormatString( 100, 70, White, "距離:%f",CameraPos.z );
ScreenFlip();//裏画面を表画面に反映
}
DxLib_End();
return 0;
}
int gpUpdateKey(){
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
for( int i=0; i<256; i++ ){
if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
} else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
void Back(int pict)
{
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 100 ); //ブレンドモードをαに設定
DrawGraph( 0, 0,pict , TRUE );
SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0 ); //ブレンドモードをオフ
}
- Fractal.h(Fractal.cpp内の関数のプロトタイプ宣言)
#ifndef DEF_Fractal_H //二重インクルード防止
#define DEF_Fractal_H
//シェルピンスキーのガスケット関数
void Fractal_Sierpinski(double x1, double y1, double x2, double y2, double x3, double y3, int n, int Color);
//コッホ曲線関数
void Fractal_KochCurve(double x1, double y1, double x2, double y2, int n, int Color);
//Cカーブ関数
void Fractal_CCurve(double x1, double y1, double x2, double y2, int n, int Color);
//ドラゴン曲線関数
void Fractal_DragonCurve(double x1, double y1, double x2, double y2, int n, int Color);
//二分木関数
void Fractal_BinaryTree(double x1, double y1, double x2, double y2, int n, int Color);
//以下未使用
//ジュリア集合
void Fractal_JuliaPixel(int x, int y, int Color);
void Fractal_Julia(int Color);
//角度変化関数
void rad_meta();
#endif
- Fractal.cpp(図形描画関数をここにまとめてみた)
//フラクタル図形描画関数集
#include "DxLib.h"
#include "math.h"
static double Pi = 3.14159;
static int magni = 1000;
static int dosu = 60;
static double s = sin(Pi/3);
static double c = cos(Pi/3);
static double ox = 10.0;
static double oy = 10.0;
static double cx = 1.0;
static double cy = 1.0;
static int wx =100;
static int wy =100;
static int Color_num = 1;
static int fColor[3];
static int Stamp_num = 0;
//シェルピンスキーのガスケット関数
void Fractal_Sierpinski(double x1, double y1, double x2, double y2, double x3, double y3, int n, int Color)
{
double x4, y4, x5, y5, x6, y6;
if(n==0) return;
DrawLine3D( VGet(0.0f+x1*magni, 0.0f-y1*magni, 0.0f), VGet(0.0f+x2*magni, 0.0f-y2*magni, 0.0f), Color);
DrawLine3D( VGet(0.0f+x2*magni, 0.0f-y2*magni, 0.0f), VGet(0.0f+x3*magni, 0.0f-y3*magni, 0.0f), Color);
DrawLine3D( VGet(0.0f+x3*magni, 0.0f-y3*magni, 0.0f), VGet(0.0f+x1*magni, 0.0f-y1*magni, 0.0f), Color);
x4 = (x1 + x2)/2.0;
y4 = (y1 + y2)/2.0;
x5 = (x2 + x3)/2.0;
y5 = (y2 + y3)/2.0;
x6 = (x3 + x1)/2.0;
y6 = (y3 + y1)/2.0;
Fractal_Sierpinski(x1, y1, x4, y4, x6, y6, n-1, Color);
Fractal_Sierpinski(x4, y4, x2, y2, x5, y5, n-1, Color);
Fractal_Sierpinski(x6, y6, x5, y5, x3, y3, n-1, Color);
}
//コッホ曲線関数
void Fractal_KochCurve(double x1, double y1, double x2, double y2, int n, int Color)
{
double x3, y3, x4, y4, x5, y5;
if(n <= 0){
DrawLine3D( VGet(0.0f+x1*magni, 0.0f-y1*magni, 0.0f), VGet(0.0f+x2*magni, 0.0f-y2*magni, 0.0f), Color);
return;
}
x3 = (2*x1 + x2)/3.0;
y3 = (2*y1 + y2)/3.0;
x5 = ( x1 + 2*x2)/3.0;
y5 = ( y1 + 2*y2)/3.0;
x4 = x3 + (x5-x3)*c + (y5-y3)*s;
y4 = y3 - (x5-x3)*s + (y5-y3)*c;
Fractal_KochCurve(x1, y1, x3, y3, n-1, Color);
Fractal_KochCurve(x3, y3, x4, y4, n-1, Color);
Fractal_KochCurve(x4, y4, x5, y5, n-1, Color);
Fractal_KochCurve(x5, y5, x2, y2, n-1, Color);
}
//Cカーブ関数
void Fractal_CCurve(double x1, double y1, double x2, double y2, int n, int Color)
{
double x3, y3;
if( n <= 0 ){
DrawLine3D( VGet(0.0f+x1*magni, 0.0f-y1*magni, 0.0f), VGet(0.0f+x2*magni, 0.0f-y2*magni, 0.0f), Color);
return;
}
x3 = 0.5 * ( x1 + x2 - y1 + y2 );
y3 = 0.5 * ( x1 - x2 + y1 + y2 );
Fractal_CCurve( x1, y1, x3, y3, n-1, Color );
Fractal_CCurve( x3, y3, x2, y2, n-1, Color );
}
//ドラゴン曲線関数
void Fractal_DragonCurve(double x1, double y1, double x2, double y2, int n, int Color)
{
double x3, y3, x4, y4, x5, y5;
if( n <= 0 ){
DrawLine3D( VGet(0.0f+x1*magni, 0.0f-y1*magni, 0.0f), VGet(0.0f+x2*magni, 0.0f-y2*magni, 0.0f), Color);
return;
}
x3 = 0.5 * ( x1 + x2 );
y3 = 0.5 * ( y1 + y2 );
x4 = 0.5 * ( x1 + x3 - y1 + y3 );
y4 = 0.5 * ( x1 - x3 + y1 + y3 );
x5 = 0.5 * ( x2 + x3 - y2 + y3 );
y5 = 0.5 * ( x2 - x3 + y2 + y3 );
Fractal_DragonCurve( x1, y1, x4, y4, n-1, Color );
Fractal_DragonCurve( x4, y4, x3, y3, n-1, Color );
Fractal_DragonCurve( x3, y3, x5, y5, n-1, Color );
Fractal_DragonCurve( x5, y5, x2, y2, n-1, Color );
}
//二分木関数
void Fractal_BinaryTree(double x1, double y1, double x2, double y2, int n, int Color)
{
double dx, dy, x3, y3, x4, y4;
DrawLine3D( VGet(0.0f+x1*magni, 0.0f-y1*magni, 0.0f), VGet(0.0f+x2*magni, 0.0f-y2*magni, 0.0f), Color);
if( n == 0 ) return;
//s = sin(angle); c = cos(angle);
dx = 0.5*(x2-x1);
dy = 0.5*(y2-y1);
x3 = x2 + dx*c - dy*s;
y3 = y2 + dx*s + dy*c;
x4 = x2 + dx*c + dy*s;
y4 = y2 - dx*s + dy*c;
Fractal_BinaryTree( x2, y2, x3, y3, n-1, Color );
Fractal_BinaryTree( x2, y2, x4, y4, n-1, Color );
}
//以下未使用
//ジュリア集合
void Fractal_JuliaPixel(int x, int y, int Color){
double sx, sy, zx, zy;
register int i;
zx = (x-ox)*magni;
zy = (y-oy)*magni;
for(i=0;i<=Color_num;i++){
sx = zx*zx;
sy = zy*zy;
if((sx+sy)>=4){
DrawPixel(x, y, Color);
//break;
}
zy = 2*zx*zy+cy;
zx = sx-sy+cx;
}
}
void Fractal_Julia(int Color){
register int i,j;
for(i=0;i<=wx;i++){
for(j=0;j<=wy;j++){
Fractal_JuliaPixel(i,j,Color);
}
}
}
//角度変化関数
void rad_meta(){
if( CheckHitKey( KEY_INPUT_C ) == 1 ){
Stamp_num += 1;
dosu = (Stamp_num%3+1)*60;
}
}
最終更新:2012年09月28日 00:46