// ■ランダムな地形と陰線消去 // @左クリックでランダムな地形を再生成します。 // A右クリックで陰線消去の手法が変わります。 // #include "myWin.h" #include "math.h" #include "stdlib.h" #include "time.h" #define frand() ((double)rand()/(RAND_MAX+1)) #define numX 51 #define numY 51 static HDC hBuff; static HBITMAP hBM; double PI=3.14159265358979; // π double dlx, dx, dy; // 表示刻み幅、XY軸方向の単位メッシュ幅 double alpha,beta; // X(α)Y(β)軸との水平軸との角度 double Z[52][52]; // 高さデータ double *Ymax, *Ymin;// 上下浮動水平線 double Xlen, Ylen; // 表示上のXY方向長さ double curX, curY; // 現在ペン位置 double dxCosA; // dx*cos(α) double dyCosB; // dy*cos(β) double dxSinA; // dx*sin(α) double dySinB; // dy*sin(β) double dlxTanA; // dlx*tan(α) double dlxTanB; // dlx*tan(β) int NR; // 浮動水平線用配列の大きさ int cnt=100; // 形状変更用 int method=1; // 手法変更用 static double (*fun[10])(double A, double B); void drawLine(double X1, double Y1, double X2, double Y2, int width, int color){ HPEN hpen=CreatePen(PS_SOLID,width, color); SelectObject(hBuff, hpen); MoveToEx(hBuff,20+(int) (X1*2), 400 - (int)(Y1*2), NULL); LineTo (hBuff,20+(int) (X2*2), 400 - (int)(Y2*2)); DeleteObject(hpen); } int hiddenDraw(double px, double py,int p, int Visible, int Update){ int R=false; if((py>=Ymax[p]) ||(py<=Ymin[p])){ if(Update && (py>=Ymax[p])) Ymax[p]=py; if(Update && (py<=Ymin[p])) Ymin[p]=py; if(Visible) drawLine(curX, curY, px, py, 1, 0xFF0000); R = true; } curX=px; curY=py;return R; } double GroundX(int j, int k){// X0=Y0=0のときのX座標 return ((double)j * dxCosA-(double)k * dyCosB); } double GroundY(int j, int k){// X0=Y0=0のときのX座標 return ((double)j * dxSinA+(double)k * dySinB); } int DrawPos(int j, int k){// 表示位置 return (int)(0.5+(Ylen+GroundX(j,k)/dlx)); } double setPx(int j, int k,double X0, double PH){ return PH* dlx + GroundX(j,k)+X0; } double setPy(int j, int k,double Y0, double PH, double fp){ return PH* dlxTanA + GroundY(j,k) + fp + Y0; } double setPy2(int j, int k,double Y0, double PH, double fp){ return -PH* dlxTanA + GroundY(j,k) + fp + Y0; } void setMap(int L, int U, int W, double dH){ if(W<2)return; int WW =(int)((double) W / 2); Z[L+WW][U ] = (Z[L+W ][U ]+Z[L][U ])*0.5+dH*(frand()-0.5); Z[L+WW][U+W ] = (Z[L+W ][U+W]+Z[L][U+W])*0.5+dH*(frand()-0.5); Z[L ][U+WW] = (Z[L ][U ]+Z[L][U+W])*0.5+dH*(frand()-0.5); Z[L+W ][U+WW] = (Z[L+W ][U+W]+Z[L+W][U])*0.5+dH*(frand()-0.5); Z[L+WW][U+WW] = (Z[L+WW][U]+Z[L+WW][U+W]+Z[L][U+WW]+Z[L+W][U+WW])*0.25 +dH*(frand()-0.5)*0.5; setMap(L ,U ,WW,dH*0.8); setMap(L+WW,U ,WW,dH*0.8); setMap(L ,U+WW,WW,dH*0.8); setMap(L+WW,U+WW,WW,dH*0.8); } void setData(){//データを設定 for(int j=0;j<=numX; j++)for(int k=0;k<=numY;k++) Z[j][k]=0; setMap(0,0, numX-1,1); for(int i=1;i<5;i++) { for(int k=1;k=-999) return Z[j][k]; double R=1000, N=0; for(int jj = j - 1; jj <= j + 1; jj += 2) for(int kk = k - 1; kk <= k + 1; kk += 2){ if(Z[jj][kk]>-999 && Z[jj][kk]>8) & 0xFF) #define BLUE(C) ((C>>16) & 0xFF) int mixColor(int CX, double CC){ double DC=1-CC; return RGB((int)(DC*RED(CX)),(int)(DC*GREEN(CX)),(int)(DC*BLUE(CX))); } int setColor(double Z[], int N, double CC){// もっと良い色設定があるかもしれない。 double W=127; double SZ=0; for(int i=0; i=512) return RGB(255 , (int)(CC*W), (int)(CC*W)); //if(R>=384) return RGB(255 , 511- R * 2 , (int)(CC*W)); //if(R>=256) return RGB((R-256)*2 , 255 , (int)(CC*W)); //if(R>=128) return RGB((int)(CC*W), R , (int)(CC*W)); //if(R<0) return RGB( 0 , 0 , 127 ); // return RGB((int)(CC*R), R , 255-R*2 ); int CX; if (R>=512) CX=RGB( 255 , 0 , 0); else if(R>=384) CX=RGB( 255 , 511- R * 2, 0); else if(R>=256) CX=RGB((R-256)*2 , 255 , 0); else if(R>=128) CX=RGB( 0 , R , 0); else if(R<0) CX=RGB( 0 , 0 , 64 ); else CX=RGB( 0 , R , 177-R ); return mixColor(CX,CC); } int setColor(double Z[], int N){ double SZ=0; for(int i=0; i=512) return RGB(255 , 0 , 0 ); if(R>=384) return RGB(255 , 511- R * 2, 0 ); if(R>=256) return RGB((R-256)*2, 255 , 0 ); if(R>=128) return RGB( 0 , R , 0 ); if(R<0) return RGB( 0 , 0 , 64); return RGB( 0 , R , 177-R); } double cmpArea(double AX[],double AY[], int N){ //面積計算 double A=0, X=(double)AX[0], Y=(double)AY[0]; for(int i=1;i0; k--) for(int j = numX-1; j >0; j--) if(Z[j][k]>-999 || Z[j-1][k]>-999 || Z[j][k-1]>-999 || Z[j-1][k-1]>-999){ setSquareXYZ(X0, Y0, j, k, AX, AY, AZ); //-------------------------------------------------------- // 四角形で表示する方法 //drawPoly(AX,AY,4, setColor(AZ, 4)); //-------------------------------------------------------- // 三角形に分ける方法(その1) //double TX[3], TY[3], TZ[3]; //TX[0]=AX[0]; TY[0]=AY[0]; TZ[0]=AZ[0]; //TX[1]=AX[2]; TY[1]=AY[2]; TZ[1]=AZ[2]; //TX[2]=AX[1]; TY[2]=AY[1]; TZ[2]=AZ[1]; //drawPoly(TX,TY,3, setColor(TZ, 3)); //TX[2]=AX[3]; TY[2]=AY[3]; TZ[2]=AZ[3]; //drawPoly(TX,TY,3, setColor(TZ, 3, CC)); //-------------------------------------------------------- // 三角形に分ける方法(その2) double TX[3], TY[3], TZ[3]; double CX = 0, CY = 0, CZ=0; for(int i=0;i<4; i++) { CX+=AX[i]; CY+=AY[i]; CZ+=AZ[i];} CX /= 4; CY /= 4; CZ /=4; TX[0]=CX; TY[0]=CY; TZ[0]=CZ; int IB=3; SelectObject(hBuff,GetStockObject(NULL_PEN)); for(int i=0; i<4;i++) { TX[1]=AX[IB]; TX[2]= AX[i]; TY[1]=AY[IB]; TY[2]= AY[i]; TZ[1]=AZ[IB]; TZ[2]= AZ[i]; drawPoly(TX,TY,3, setColor(TZ, 3)); IB=i; } SelectObject(hBuff,pen);SetROP2(hBuff,R2_MASKPEN);// 画面とAndで線を描く drawPoly(AX,AY,4, 0xFFFFFF);SetROP2(hBuff,R2_COPYPEN); } DeleteObject(pen); } void hiddenLine3(){//線を描かないようにしたら… SelectObject(hBuff,GetStockObject(NULL_PEN)); double X0 = 80, Y0=100, CC, AX[4], AY[4], AZ[4];//maxS;; // 奥方向から四角形を描く for(int k = numY-1; k >0; k--) for(int j = numX-1; j >0; j--) if(Z[j][k]>-999 || Z[j-1][k]>-999 || Z[j][k-1]>-999 || Z[j-1][k-1]>-999){ setSquareXYZ(X0, Y0, j, k, AX, AY, AZ); double DZX = Z[j][k]-Z[j-1][k], DZY=Z[j][k]-Z[j][k-1], DXY=DZX-DZY; CC=sqrt(DZX*DZX+DZY*DZY+DXY*DXY)/30;if(CC>1)CC=1; //CC= cmpArea(AX,AY,4)/maxS;if(CC>1)CC=1; //-------------------------------------------------------- // 四角形で表示する方法 //drawPoly(AX,AY,4, setColor(AZ,4, CC)); //-------------------------------------------------------- // 三角形に分ける方法(その1) //double TX[3], TY[3], TZ[3]; //drawPoly(AX,AY,4, setColor(AZ,4, CC)); //TX[0]=AX[0]; TY[0]=AY[0]; TZ[0]=AZ[0]; //TX[1]=AX[2]; TY[1]=AY[2]; TZ[1]=AZ[2]; //TX[2]=AX[1]; TY[2]=AY[1]; TZ[2]=AZ[1]; //drawPoly(TX,TY,3, setColor(TZ, 3)); //TX[2]=AX[3]; TY[2]=AY[3]; TZ[2]=AZ[3]; //drawPoly(TX,TY,3, setColor(TZ,3,CC)); //-------------------------------------------------------- // 三角形に分ける方法(その2) double TX[3], TY[3], TZ[3]; double CX = 0, CY = 0, CZ=0; for(int i=0;i<4; i++) { CX+=AX[i]; CY+=AY[i]; CZ+=AZ[i];} CX /= 4; CY /= 4; CZ /=4; TX[0]=CX; TY[0]=CY; TZ[0]=CZ; int IB=3; for(int i=0; i<4;i++) { TX[1]=AX[IB]; TX[2]= AX[i]; TY[1]=AY[IB]; TY[2]= AY[i]; TZ[1]=AZ[IB]; TZ[2]= AZ[i]; drawPoly(TX,TY,3, setColor(TZ,3,CC)); IB=i; } } } void hiddenLine(){ for(int j=0; j-999 || Z[j+1][k]>-999){ double Z1=getZ(j,k), Z2=getZ(j+1,k); p1 = screenX(j,k); p2=screenX(j+1,k); H = Z1; DH = (Z2 - Z1) * dlx/ dxCosA; for(int p = p1; p <= p2; p++){ PH=(double)(p - p1); fp = H + DH * PH; px = setPx(j, k, X0, PH); py = setPy(j, k, Y0, PH, fp); if((j < numX - 2 && p < p2) || (j == numX-2)) Vflag=hiddenDraw(px,py,p,Vflag, true); } } if(k < numY - 1) for (int j = 0; j < numX ; j++) // Y軸方向描画 if(Z[j][k]>-999 || Z[j][k+1]>-999){ double Z1=getZ(j,k), Z2=getZ(j,k+1); Vflag = false;p1=screenX(j,k);p2=screenX(j,k+1); for (int p = p1; p >= p2; p--){ // 補間 PH = (double)(p - p1); fp = Z1 - (Z2 - Z1) * PH * dlx / dyCosB; px = setPx(j, k, X0, PH); py = setPy2(j, k, Y0, PH, fp); Vflag= hiddenDraw(px, py, p, Vflag, p != p2); } } } } void procPaint(HWND hw, WPARAM wp,LPARAM lp){ PAINTSTRUCT ps; HDC hdc=BeginPaint(hw, &ps); BitBlt(hdc, 0,0,500,500,hBuff,0,0,SRCCOPY); EndPaint(hw,&ps); } void crearBitmap(int width, int height){ SelectObject(hBuff,GetStockObject(NULL_PEN)); PatBlt(hBuff,0, 0,width, height, WHITENESS); } void procDrawHiddenLine(HWND hw){ if (method==0){SetWindowText(hw,TEXT("ランダムな地形と陰線消去 (その1)"));hiddenLine(); } else if(method==1){ SetWindowText(hw,TEXT("ランダムな地形と陰線消去 (その2)")); hiddenLine2();} else { SetWindowText(hw,TEXT("ランダムな地形と陰線消去 (その3)線を描かなければ…")); hiddenLine3();} InvalidateRect(hw,NULL,FALSE); } void procLButtonDown(HWND hw, WPARAM wp,LPARAM lp){ crearBitmap(500,500); cnt++;if(cnt>4)cnt=0; setData();procDrawHiddenLine(hw); } void procRButtonDown(HWND hw, WPARAM wp,LPARAM lp){ crearBitmap(500,500); method++;if(method>2) method=0; procDrawHiddenLine(hw); } void genBitmap(HWND hw, int width,int height){ HDC hdc=GetDC(hw); hBM=CreateCompatibleBitmap(hdc,500,400); hBuff=CreateCompatibleDC(hdc); SelectObject(hBuff,hBM); crearBitmap(500,500); ReleaseDC(hw,hdc); } void setWindowSize(HWND hw, int width,int height){ RECT r; GetWindowRect(hw, &r); MoveWindow(hw,r.left,r.top, width,height,TRUE); } void procCreate(HWND hw, WPARAM wp,LPARAM lp){ setWindowSize(hw,452,400); genBitmap(hw, 500,500); initialize(); procLButtonDown(hw, wp,lp); } 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_PAINT : procPaint(hw,wp,lp) ; return 0; case WM_LBUTTONDOWN : procLButtonDown(hw,wp,lp) ; break; case WM_RBUTTONDOWN : procRButtonDown(hw,wp,lp) ; break; } return DefWindowProc(hw,msg,wp,lp); }