#include "myWin.h"
#include "stdio.h"
#include "math.h"
#define swap(type, X,Y) do{type T; T=X;X=Y; Y=T;}while(0)
static HDC hBuff; static HBITMAP hBM;
static int X, Y ;static int XDT[5], YDT[5];
int IMS=0;double MAT[5][6];
void clearBitmap(){//ビットマップのクリア
	SelectObject(hBuff,GetStockObject(NULL_PEN));
	PatBlt(hBuff,0,0,1000,600,WHITENESS);
}
int matSolve(){//行列式を解いて多項式の係数を求める
	int N=5, N2=N+1;
	for(int k=0;k<N;k++){
		if(fabs(MAT[k][k])<0.00001) return true;
		double S=1/MAT[k][k];
		for(int j=k+1;j<N2;j++) MAT[k][j]*=S;
		for(int i=0;i<N;i++)
			if(i!=k){
				S=MAT[i][k];
				for(int j=k+1;j<N2;j++)MAT[i][j] -= S*MAT[k][j];
			}
	}
	return false;
}
void dblToStr(double d, TCHAR str[]){//doubleを文字列に
	char tmp[256]; sprintf(tmp," %15.4E", d);int i;
	for(i=0; tmp[i];i++) str[i]=tmp[i];
	str[i]=0;
}
void setData(){
	for(int i=0;i<4;i++)for(int j=4;j>i;j--)//X座標の小さい順にソート
		if(XDT[j-1]>XDT[j]){
			swap(int, XDT[j-1],XDT[j]);swap(int, YDT[j-1],YDT[j]);
		}
	for(int i=0; i<5;i++) for(int j=0; j<5;j++){//左辺行列
		MAT[i][j]=0;
		for(int k=0; k<5; k++) MAT[i][j]+=pow(XDT[k],(double)(i+j));
	}
    for(int i=0; i<5;i++){//右辺ベクトル
		MAT[i][5]=0;
		for(int k=0; k<5; k++) MAT[i][5]+=pow(XDT[k],(double)i)*YDT[k];
	}
	matSolve();//上記行列式を解いて係数を設定する。
}
void initData(){//初期値設定
	for(int i=0; i<5;i++){ XDT[i] = YDT[i] = 64*i;}
	setData(); matSolve();
}
int setValue(double X){//カラートーン値を求める関数
	double A=0;
	for(int i=4;i>=0;i--)A = A*X+MAT[i][5];
	if(A<0)A=0; if(A>255)A=255;
	return (int)A;
}
void drawFig(HWND hw){
	clearBitmap();
	HPEN pen = CreatePen(PS_SOLID,1,0);SelectObject(hBuff,pen);
	Rectangle(hBuff,10,10,266,266);
	MoveToEx(hBuff,10,265,NULL);
	for(int k=1;k<256; k++)	LineTo(hBuff,k+10,265-(int)setValue((double)k));
	for(int j=1;j<=3;j++){
		int k=XDT[j], A=setValue(XDT[j]);
		Rectangle(hBuff,k+7,262-(int)A, k+13,268-(int)A);
	}
	// トーンカーブの係数を表示する処理(アプリに組み込むときはいらない)
	HFONT hF=CreateFont(16,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,SHIFTJIS_CHARSET,
		OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
		FIXED_PITCH|FF_MODERN,NULL);
	SelectObject(hBuff,hF);
	TCHAR str[1024]; lstrcpy(str,TEXT("多項式の係数"));
	                         TextOut(hBuff,10,270,str,lstrlen(str));
	dblToStr(MAT[0][5],str); TextOut(hBuff,120,270,str,lstrlen(str));
	dblToStr(MAT[1][5],str); TextOut(hBuff,120,290,str,lstrlen(str));
	dblToStr(MAT[2][5],str); TextOut(hBuff,120,310,str,lstrlen(str));
	dblToStr(MAT[3][5],str); TextOut(hBuff,120,330,str,lstrlen(str));
	dblToStr(MAT[4][5],str); TextOut(hBuff,120,350,str,lstrlen(str));
	DeleteObject(hF);
	// トーンカーブの係数を表示する処理 ここまで
	DeleteObject(pen);
	InvalidateRect(hw,NULL,TRUE);
}
void viewChange(HWND hw, int X, int Y){//座標値の変更
	if(Y>255 || Y<0 || X>255 || X<0) {IMS = 0;return;}
	int MinDT = 9999999, ID=0; 
	for(int i=1;i<=3; i++){
		int DX = X-XDT[i],DY=Y-YDT[i], RR=DX*DX+DY*DY;
		if(RR<MinDT){ MinDT=RR; ID=i;}
	}
	if(MinDT<16){
		IMS=ID;	XDT[IMS]=X; YDT[IMS]=Y;setData(); drawFig(hw);
	}
}
void procCreate(HWND hw, WPARAM wp,LPARAM lp){
	initData();MoveWindow(hw,0,0,300,420,TRUE);
	SetWindowText(hw,TEXT("トーンカーブ用係数計算"));
	HDC hdc=GetDC(hw); hBM=CreateCompatibleBitmap(hdc,1000,600);
	hBuff=CreateCompatibleDC(hdc); SelectObject(hBuff,hBM);
	viewChange(hw,127,127);	drawFig(hw);
	ReleaseDC(hw,hdc);
}
void procLButtonDown(HWND hw, WPARAM wp,LPARAM lp){
	X=LOWORD(lp)-10; Y=265-HIWORD(lp); viewChange(hw,X,Y);
}
void procLButtonUp(HWND hw, WPARAM wp,LPARAM lp){ IMS=0;}
void procMouseMove(HWND hw, WPARAM wp,LPARAM lp){
	if(GetKeyState(VK_LBUTTON)<0 && IMS!=0){
		X=LOWORD(lp)-10; Y=265-HIWORD(lp); viewChange(hw,X, Y);
	}
}
void procPaint(HWND hw,WPARAM wp,LPARAM lp){
	PAINTSTRUCT ps;	HDC hdc=BeginPaint(hw,&ps);
	BitBlt(hdc,0,0,1000,600,hBuff,0,0,SRCCOPY);
	EndPaint(hw,&ps);
}
LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp,LPARAM lp){
	switch(msg){
 	case WM_DESTROY    : DeleteDC(hBuff);DeleteObject(hBM); 
						 PostQuitMessage(0)     ; return 0;
	case WM_CREATE     : procCreate     (hw,wp,lp); return 0;
	case WM_LBUTTONDOWN: procLButtonDown(hw,wp,lp); return 0;	
	case WM_LBUTTONUP  : procLButtonUp  (hw,wp,lp); return 0;	
	case WM_MOUSEMOVE  : procMouseMove  (hw,wp,lp); return 0;	
	case WM_PAINT      : procPaint      (hw,wp,lp); return 0;
	}
	return DefWindowProc(hw,msg,wp,lp);
}