// ■陰線消去 // @左クリックで図形が変わります。 // A右クリックで陰線消去の手法が変わります。 // #include "myWin.h" #include "math.h" #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; } double xyExpM(double X, double Y){//高さの値を決める関数 (x-y)*Exp(-(x*x+y*y)) X /= 4; Y /= -4; return (X-Y)*exp(-(X*X+Y*Y))*1.5; } double hSphere(double X, double Y){//高さの値を決める関数 球 double R=sqrt(X*X+Y*Y); if(R<=2) { R /=2; return sqrt(1-R*R)*0.3+0.7;} else if(R>2 && R<4) return 0.7; else if(R>=4 && R<=6){ R=(R-4)/2;return -sqrt(1-R*R)*1.5+0.7;} else if(R<6.5) return 0.7; else return -1000; } double mntFuji(double X, double Y){//高さの値を決める関数 富士山モデル double R=sqrt(X*X+Y*Y); if(R<=1) return 1; R--;return exp(-R/3); } double sinByR(double X, double Y) { //高さの値を決める関数 sin(R)/R double R = sqrt(X * X + Y * Y); if(R==0.0) return 1; else return sin(R)/R; } double cone(double X,double Y){ // 高さの値を決める関数 円錐モデル double R = sqrt(X * X + Y * Y); if(R<5) return 1-R*2/5; else return -1; } void setData(double (*fun)(double A, double B)){//データを設定 double DNX2=(double) numX / 2.0, DNY2=(double) numY / 2.0, X; for(int j=0;j=-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]=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 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, maxS=0, AX[4], AY[4], AZ[4], CC; // 表示面積の最大値を求める 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); CC= cmpArea(AX,AY,4);if(maxS0; 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); 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 procLButtonDown(HWND hw, WPARAM wp,LPARAM lp){ crearBitmap(500,500); cnt++;if(cnt>4)cnt=0; setData(fun[cnt]); 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 procRButtonDown(HWND hw, WPARAM wp,LPARAM lp){ method++;if(method>2) method=0; cnt--; procLButtonDown(hw, wp,lp); } 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); }