プロシージャルな樹木生成

学生時代に作ったプログラム.
がんばってリファクタリングしたけど,限界まで飽きたのでアップ.
VC++とWinAPI使用.

D

DrawTree.cpp

/*******************************************************************
*
*    DESCRIPTION:   樹木曲線
*
*    AUTHOR:        shom
*
*    HISTORY:       
*
*    DATE:          2009/12/17
*
*******************************************************************/

/** include files **/

#include "DrawTree.h"

#include "windows.h"
#include <math.h>  /* sin(), cos() */
#include <stdlib.h> /* srand(), rand() */
#include <assert.h>
#include <algorithm> /* min(), max() */

/** local definitions **/

#define FACT_RIGHT	(0.700)
#define FACT_LEFT	(0.700)
#define FACT_UP		(0.800)
#define DELTA_ANGLE_LEFT	(0.4)
#define DELTA_ANGLE_RIGHT	(0.4)
#define START_HIGH	(4.0f/5.0f)
#define START_LOW	(3.0f/5.0f)


/**
 * 関数:木の描画を行う再帰関数
 * 
 * @param energy 伸ばす枝の数の参考値
 * @param length 幹の長さ
 * @param angle  幹の角度
 * @param x      枝の始点のx座標値
 * @param y      枝の始点のy座標値
 * @param nest   ネストの深さを保持
 * @param hdc
 * @param flow
 */
void DrawTree( int energy, double length, double angle, double x, double y, double nest, HDC hdc )
{
	/*	<幹の描画> */
	// ペン生成
	HPEN pen;
	if( nest < 3 )
	{
		//* 幹
		//色
		BYTE r = min( 150 + static_cast<int>( ( nest / 3.0f ) * 50 ), 255 );
		BYTE g = min( static_cast<int>( ( nest / 3.0f ) * 100 ), 255 );
		BYTE b = min( static_cast<int>( 0 ), 255 );
		COLORREF pen_color = RGB( r, g, b );

		//太さ
		int pen_width = 15 - static_cast<int>( nest * 5 );

		//ペン生成
		pen = CreatePen( PS_SOLID, pen_width, pen_color );
	}
	else if( ( nest < 4.9 ) && ( nest > 4.7 ) )
	{
		static int flow = 0;
		flow++;

		if ( flow % 5 != 2 )
		{
			//* 葉
			//色
			BYTE r = 0;
			BYTE g = min( static_cast<int>( ( nest / 6.0f ) * 255 ), 255 );
			BYTE b = 0;
			COLORREF pen_color = RGB( r, g, b );
	
			//太さ
			int pen_width = 2 + static_cast<int>( nest );
	
			//ペン生成
			pen = CreatePen( PS_SOLID, pen_width, pen_color ); 
		}
		else
		{
			//* 花
			//色
			BYTE r = 230;
			BYTE g = 153;
			BYTE b = 153;
			COLORREF pen_color = RGB( r, g, b );
	
			//太さ
			int pen_width = 5;
	
			//ペン生成
			pen = CreatePen( PS_DASH, pen_width, pen_color );
		}
	}
	else
	{
		//* 葉
		//色
		BYTE r = 0;
		BYTE g = min( static_cast<int>( ( nest / 6.0f ) * 255 ), 255 );
		BYTE b = 0;
		COLORREF pen_color = RGB( r, g, b );

		//太さ
		int pen_width = 2 + static_cast<int>( nest );

		//ペン生成
		pen = CreatePen( PS_SOLID, pen_width, pen_color ); 
	}

	//デバイスハンドルにセット
	HGDIOBJ pen_post = SelectObject( hdc, pen );
	//処分
	DeleteObject( pen_post );

	// ペンで枝を描く
	double delta_x = length * sin(angle); 
	double delta_y = length * cos(angle);

	int start_x = static_cast<int>( x );
	int start_y = static_cast<int>( y );
	int end_x	= static_cast<int>( x - delta_x );
	int end_y	= static_cast<int>( y - delta_y );

	MoveToEx( hdc, start_x, start_y, NULL );
	LineTo( hdc, end_x, end_y );

	///*
	///<枝の描画>
	///・DrawTreeを再帰に呼び出す.
	///・枝は左, 右, 上の3方向に伸びる.
	///・再帰の度にenergyを一定値減らす.
	///*
	if( energy > 0 )
	{
		// 左と右に枝を伸ばす
		{
			//length
			double lb_length = length * FACT_LEFT;
			double rb_length = length * FACT_RIGHT;
	
			//angle
			// "lb" is "Left Branch", "rb" is "Right Branch".
			double lb_angle	= angle + ( static_cast<double>(rand() % 4) / 10 ) + DELTA_ANGLE_LEFT;
			double rb_angle	= angle - ( static_cast<double>(rand() % 4) / 10 ) - DELTA_ANGLE_RIGHT;
	
			//start_x, start_y
			//左右どちらの枝を高くするかは、ランダムに決定する
			double lb_start_x, lb_start_y, rb_start_x, rb_start_y;
			if( rand() % 2 == 1 )
			{
				lb_start_x	= x - (delta_x * START_HIGH); 
				lb_start_y	= y - (delta_y * START_HIGH); 
				rb_start_x	= x - (delta_x * START_LOW);
				rb_start_y	= y - (delta_y * START_LOW);
			}
			else
			{
				lb_start_x	= x - (delta_x * START_LOW);
				lb_start_y	= y - (delta_y * START_LOW);
				rb_start_x	= x - (delta_x * START_HIGH); 
				rb_start_y	= y - (delta_y * START_HIGH); 
			}
	
			//再帰
			DrawTree( (energy-2), lb_length, lb_angle, lb_start_x, lb_start_y, (nest+1), hdc );
			DrawTree( (energy-2), rb_length, rb_angle, rb_start_x, rb_start_y, (nest+1), hdc );
		}

		// 上に枝を伸ばす
		{
			//length
			double ub_length = length * FACT_UP;
			//angle
			double ub_angle = angle;
			//start_x, start_y
			double ub_start_x = x - delta_x;
			double ub_start_y = y - delta_y;

			//再帰
			DrawTree( (energy-1), ub_length, ub_angle, ub_start_x, ub_start_y, (nest+0.7), hdc );
		}
	}
}

DrawTree.h

#ifndef __DRAW_TREE__H__
#define __DRAW_TREE__H__

#include <windows.h>

extern void DrawTree(int energy, double length, double angle, double x, double y, double nest, HDC hdc );

#endif //__DRAW_TREE__H__

WinMain.cpp

#include <windows.h>
#include <math.h>  /* sin(), cos() */
#include <stdlib.h> /* srand(), rand() */

#include "DrawTree.h"

#define TM (1000.0f/10.0f) //タイマー

PAINTSTRUCT ps;
HDC hdc, hdc2;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg , WPARAM wp , LPARAM lp) 
{
	static unsigned i=0;

	switch (msg)
	{
		case WM_CREATE:
			{
				SetTimer(hwnd, 1, static_cast<UINT>(TM), NULL);
				return 0;
			}
			//break;

		case WM_DESTROY:
			{
				KillTimer(hwnd,1);
				ReleaseDC(hwnd, hdc2);
				PostQuitMessage(0);
				return 0;
			}
			//break;

		case WM_PAINT:
			{
				/*
				// 描画処理
				{
					treeingProcedural.DrawTree();
				}

				return;
				*/		

				/*
				//<描画処理>
				//・5つの木を、200ピクセル間隔で描画する。
				//・1単位時間毎に、各木を25ピクセル右に動かす。
				//・8単位時間毎に、
				// (1)各木の位置を、元に戻す。
				// (2)各木の乱数の種を、それぞれの右の木にずらす。		
				*/
				hdc = BeginPaint(hwnd, &ps);
				{
					srand(i/40 + 4);
					DrawTree( 8, 50.0f, 0, -100 + i%40 * 5, 300, 0, hdc );
					srand(i/40 + 3);
					DrawTree( 8, 50.0f, 0, 100 + i%40 * 5, 300, 0, hdc );
					srand(i/40 + 2);
					DrawTree( 8, 50.0f, 0, 300 + i%40 * 5, 300, 0, hdc );
					srand(i/40 + 1);
					DrawTree( 8, 50.0f, 0, 500 + i%40 * 5, 300, 0, hdc ); 
					srand(i/40);
					DrawTree( 8, 50.0f, 0, 700 + i%40 * 5, 300, 0, hdc );
				}
				EndPaint(hwnd , &ps);
				return 0;
			}
			//break;

		case WM_TIMER:
			{
				// カウント
				i+=1;

				// WM_PAINT呼び出し
				InvalidateRect( hwnd, NULL, TRUE );	//表示を無効に

				return 0;
			}
			//break;
	}
	return DefWindowProc( hwnd, msg, wp, lp );
}

int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance,
 PSTR lpCmdLine, int nCmdShow)
{
	MSG msg;
	WNDCLASS winc;
	HWND hwnd;

	winc.style		   = CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc   = WndProc;
	winc.cbClsExtra	   = 0;
	winc.cbWndExtra	   = 0;
	winc.hInstance	   = hInstance;
	winc.hIcon		   = LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor	   = LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName  = NULL;
	winc.lpszClassName = TEXT("CLASS");

	if (!RegisterClass(&winc)) return -1;

	hwnd = CreateWindow(
			TEXT("CLASS") , TEXT("ProceduralTree") ,
			WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
			CW_USEDEFAULT , CW_USEDEFAULT ,
			800, 500,
			NULL , NULL , hInstance , NULL
	);

	if (hwnd == NULL) return -1;

	while( GetMessage(&msg , NULL , 0 , 0) ) { DispatchMessage(&msg); }
	return msg.wParam;
}