//■グモウスキーとミラの写像
#include "myWin.h"
#include "stdio.h"
#include "stdlib.h"
#include "locale.h"
// ラベル
#define LB_1 1001 // μ
#define LB_2 1002 // a
#define LB_3 1003 // b
#define LB_4 1004 // dμ
// エディットボックス
#define ED_1 2001 // μ 
#define ED_2 2002 // a
#define ED_3 2003 // b
#define ED_4 2004 // dμ
// ボタン
#define BT_1 3001 // 開始
#define BT_2 3002 // 停止
#define BT_3 3003 // 単一表示

float mu=-1, a=0.008F, b=0.05F,dm= 0.0005F;//写像用変数
static HWND editMu, editA, editB, editDm, btStart, btStop, btDsp;//コントロール用
static HDC hbuf; static HBITMAP hBM;//ビットマップ描画用

void createLabel(HWND hw, LPARAM lp, HMENU hm, int X, int Y,TCHAR *str){//ラベル生成
	CreateWindow(TEXT("STATIC"),str,
		WS_CHILD|WS_VISIBLE|SS_RIGHT, X,Y,50,20,hw,hm,
		((LPCREATESTRUCT)(lp))->hInstance, NULL);
}
HWND createEdit(HWND hw, LPARAM lp,HMENU hm, int X, int Y, TCHAR *str){//エディットボックス生成
	return CreateWindow(TEXT("EDIT"),str, 
		WS_CHILD|WS_VISIBLE|WS_BORDER|ES_RIGHT, 
		X,Y,70,20,hw,hm,((LPCREATESTRUCT)(lp))->hInstance, NULL);
}
HWND createButton(HWND hw, LPARAM lp,HMENU hm, int X, int Y, TCHAR str[]){//ボタン生成
	return CreateWindow(TEXT("BUTTON"),str,
		WS_CHILD|WS_VISIBLE|WS_BORDER|BS_PUSHBUTTON, 
		X,Y,70,30,hw,hm,((LPCREATESTRUCT)(lp))->hInstance, NULL);
}
void initBitMap(HWND hw){// ビットマップ作成とメモリデバイスコンテキスト作成
	HDC hdc=GetDC(hw); hBM=CreateCompatibleBitmap(hdc,2000,1000);
	hbuf=CreateCompatibleDC(hdc);SelectObject(hbuf,hBM);
	SelectObject(hbuf,GetStockObject(NULL_PEN));
	PatBlt(hbuf,0,0,2000,1000,WHITENESS);
	ReleaseDC(hw, hdc);
}
void procCreate(HWND hw, WPARAM wp, LPARAM lp){
	initBitMap(hw);
	SetWindowText(hw,TEXT("グモウスキーとミラの写像"));
	createLabel(hw,lp,(HMENU) LB_1, 0,10,TEXT("μ"));//ラベル生成
	createLabel(hw,lp,(HMENU) LB_2,100,10,TEXT("a"));
	createLabel(hw,lp,(HMENU) LB_3,200,10,TEXT("b"));
	createLabel(hw,lp,(HMENU) LB_4,300,10,TEXT("dμ"));
	editMu=createEdit(hw,lp,(HMENU) ED_1,50,10,TEXT("-1.0"));//エディットボックス生成
	editA=createEdit(hw,lp,(HMENU) ED_2,150,10,TEXT("0.008"));
	editB=createEdit(hw,lp,(HMENU) ED_3,250,10,TEXT("0.05"));
	editDm=createEdit(hw,lp,(HMENU) ED_4,350,10,TEXT("0.0005"));
	btStart=createButton(hw,lp,(HMENU) BT_1,450,5,TEXT("開始"));//ボタン生成
	btStop=createButton(hw,lp,(HMENU) BT_2,550,5,TEXT("停止"));
	btDsp=createButton(hw,lp,(HMENU) BT_3,650,5,TEXT("単一表示"));
	setlocale(LC_ALL,"jpn");//日本語設定
}
void dspMu(float mu){//μの値表示
	char s[64]; TCHAR str[128];//書式変換とワイド文字への変換
	sprintf(s,"μ = %10.5f",mu);wsprintf(str,TEXT("%S"),s);
	TextOut(hbuf,750,10,str,lstrlen(str));
}
void displayG(HWND hw){//グモウスキーとミラの写像をビットマップに描画
	float X, Y, G, XN; int i,XP,YP;
	SelectObject(hbuf,GetStockObject(NULL_PEN));//ビットマップクリア
	PatBlt(hbuf,0,0,2000,1000,WHITENESS); dspMu(mu);
	X=0.1F;Y=0.0F;//写像をビットマップ描画
	G = mu * X + 2.F * (1.F - mu) * X * X / (1.F + X * X);
	for(i=0;i<10000;i++){
		XP = (int)(500.F - X * 10.F); YP=(int)(200.F - Y * 10.F);
		SetPixel(hbuf,XP,YP,0x007700);//点を描く
		XN = X; X = Y + a * (1 - b * Y * Y) * Y + G;
		G = mu * X + 2.F * (1.F - mu) * X * X / (1.F + X * X);
		Y = -XN + G;
	}
	InvalidateRect(hw, NULL, TRUE);
}
float getValue(HWND editBox){//エディットボックスの値を取り出す。
	TCHAR str[128];char ansi[256];double X;
	GetWindowText(editBox,str,127);//文字列を取り出し
	WideCharToMultiByte(CP_ACP, 0, str,-1,ansi,255,NULL,NULL);//char配列に変換
	sscanf(ansi,"%lf",&X); //浮動小数点変換
	return (float)X;
}
void procDisp(HWND hw){//描画処理
	mu= getValue(editMu); a= getValue(editA);//各変数値を取り出す
	b= getValue(editB)  ; dm= getValue(editDm);
	displayG(hw);
}
void procTimer(HWND hw, WPARAM wp, LPARAM lp){//タイマー処理
	mu +=dm; if(mu>1.0) mu=-1;
	displayG(hw);
}
void procPaint(HWND hw, WPARAM wp, LPARAM lp){//ビットマップを画面に表示
	PAINTSTRUCT ps; HDC hdc=BeginPaint(hw, &ps);
	BitBlt(hdc,0,0,2000,1000,hbuf,0,0,SRCCOPY);
	EndPaint(hw,&ps);
}

void procStart(HWND hw){//開始ボタンクリック時の処理
	mu= getValue(editMu); a= getValue(editA);//各変数値を取り出す
	b= getValue(editB)  ; dm= getValue(editDm);
	SetTimer(hw, 1,200, NULL);//タイマー開始
}
void procStop(HWND hw){//停止ボタンクリック時の処理
	KillTimer(hw,1);//タイマー停止
}
void procCommand(HWND hw, WPARAM wp, LPARAM lp){
	switch(LOWORD(wp)){
	case BT_1: procStart(hw);return;//開始ボタンクリック
	case BT_2: procStop(hw) ;return;//停止ボタンクリック
	case BT_3: procDisp(hw) ;return;//単一表示ボタンクリック
	}
}
LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp){
	switch(msg){
	case WM_DESTROY : PostQuitMessage(0)    ; return 0;
	case WM_CREATE  : procCreate (hw, wp, lp); return 0;
	case WM_TIMER   : procTimer  (hw, wp, lp); return 0;
	case WM_PAINT   : procPaint  (hw, wp, lp); return 0;
	case WM_COMMAND : procCommand(hw, wp, lp);
	}
	return DefWindowProc(hw, msg, wp, lp);
}