3DStatic






4.81/5 (21 votes)
Jun 7, 2005
3 min read

92818

2521
An article to draw a 3D math function on a static control.
Introduction
I wanted to draw a 3D math function on a static control like "MatLab" does. Finally, I found a solution.
Consider that you want to plot a 3D Pixel Q (a,b,c) on a plane with X and Y directions. In (figure 1), I illustrate this. At first, you must move in X direction from O to P1. It is important to know |P1 O| = b. Then you must move in Y direction from P1 to P2 and |P2 P1| = c. Now you must move in 't' direction from P2 to Q. And |Q P2 | = a. In 3D space, 't' direction is X-axis, X direction is Y-axis, and Y direction is Z-axis.
Figure 1 – Plot a 3D Point on a 2D page.
We want to obtain Q(x,y), so …
Eq. 1
Using the code
First of all, add 3DStatic.h and 3DStatic.cpp files to your project. Select Resource tab from Workspace window, and select your dialog that you want to add a display static. Select Static Control from Control toolbox and draw it on the dialog (Figure 2). Change its ID from IDC_STATIC
to IDC_MyStatic
.
Figure 2 - Add Static and Button Control to your dialog.
Now it's time to add a member variable to your dialog class. Call Class Wizard to do it for you. Figure 3 shows you how to do it. In this case, we add a member variable m_MyStatic
with type CStatic
.
Figure 3 - Add member variable to your dialog class.
OK, open your dialog class header file, add this line on top of your class definition:
// 3DFunctionDlg.h : header file // #if !defined(AFX_2DFUNCTIONDLG_H__D5D048D5_079A_ 40BD_86A0_32A26253D2E5__INCLUDED_) #define AFX_2DFUNCTIONDLG_H__D5D048D5_079A_40BD_ 86A0_32A26253D2E5__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include "3DStatic.h" /////////////////////////////////////////////////////////// // C2DFunctionDlg dialog class CMy3DPageDlg : public CDialog { // Construction public: CMy3DPageDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data //{{AFX_DATA(CMy3DPageDlg) enum { IDD = IDD_MY3DPage_DIALOG }; C3DStatic m_MyStatic; //We change it from CStatic m_MyStatic; //to C3DStatic m_MyStatic; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMy3DPageDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: HICON m_hIcon; // Generated message map functions //{{AFX_MSG(C2DFunctionDlg) afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations // immediately before the previous line. #endif // !defined(AFX_My3DPageDLG_H__D5D048D5_079A_40BD_ //86A0_32A26253D2E5__INCLUDED_)
How does it work?
One of the important functions is Set3DPixel
.This function changes a point in 3D space to a 2D point. It is a polymorphism function and in its second form, it plots the obtained point on static. It uses equation 1.
CPoint C3DStatic::Set3DPixel(C3DStatic::C3DPoint pPixel) { // x=lenght ; in t Direction |P2 Q| // y=b ; in X Direction |OP1| // z=c ; in Y Direction |P1 P2| // newX=b-+lcos(isteep) // newY=newX*tan(isteep)+c-b*tan(isteep) // so... CPoint newP; float newX,newY; CString aa; newX=pPixel.y-pPixel.x*cos(iSteep); newY=newX*tan(iSteep)+(pPixel.z-pPixel.y*tan(iSteep)); crColor=Set3DColor(pPixel.z); if ((newX<=pPixel.y && pPixel.x>=0) || (newX>=pPixel.y && pPixel.x<0)) { newP=GetNewPixel(newX,newY); return newP; } else { newX=pPixel.y+pPixel.x*cos(iSteep); newY=newX*tan(iSteep)+(pPixel.z-pPixel.y*tan(iSteep)); if ((newX<=pPixel.y && pPixel.x>=0) || (newX>=pPixel.y && pPixel.x<0)) { newP=GetNewPixel(newX,newY); return newP; } }
C3DStatic::Set3DPixel(CDC* pDC,C3DStatic::C3DPoint pPixel,COLORREF crColor) { // x=l // y=A // z=B // newX=A-+lcos(isteep) // newY=newX*tan(isteep)+B-A*tan(isteep) // so... CPoint newP,oldP; float newX,newY; CString aa; CPen pen (PS_SOLID, 1, crColor); pDC->SelectObject (&pen); newX=pPixel.y-pPixel.x*cos(iSteep); newY=newX*tan(iSteep)+(pPixel.z-pPixel.y*tan(iSteep)); if ((newX<=pPixel.y && pPixel.x>=0) || (newX>=pPixel.y && pPixel.x<0)) { newP=GetNewPixel(newX,newY); if ((newP.x>=0 && newP.y<=0) && (newP.x<=stcWidth && newP.y>=-stcHeight) ) pDC->SetPixel(newP,crColor); } else { newX=pPixel.y+pPixel.x*cos(iSteep); newY=newX*tan(iSteep)+(pPixel.z-pPixel.y*tan(iSteep)); if ((newX<=pPixel.y && pPixel.x>=0) || (newX>=pPixel.y && pPixel.x<0)) { newP=GetNewPixel(newX,newY); if ((newP.x>=0 && newP.y<=0) && (newP.x<=stcWidth && newP.y>=-stcHeight)) pDC->SetPixel(newP,crColor); } } }
C3DPoint
is a structure with three member variables x
, y
, z
to get a point in three dimensions.
struct C3DPoint { float x; float y; float z; };
The next function is SetXSteep
: this function sets a steep for X axis in 3D space. iSteep
must be set before using the function Set3DPixel
. The next function is GetNewPixel
:
CPoint C3DStatic::GetNewPixel(float Oldx,float Oldy) { CPoint NewPoint; NewPoint.x=int((stcWidth/(x_Max-x_Min))*Oldx-((stcWidth*x_Min)/(x_Max- x_Min))); NewPoint.y=int(stcHeight/(y_Max-y_Min)*Oldy-(stcHeight*y_Max)/(y_Max- y_Min)); return NewPoint; }
This function gets a CPoint
variable in the Static scale. The static maximum and minimum value can be obtained by using this code:
CRect rect; GetClientRect (&rect); stcWidth=rect.Width(); stcHeight=rect.Height();
In the constructor function, we can set a virtual scale for static width by defining x_Max
and x_Min
, and for static height by defining y_Max
and y_Min
. Note that variable Oldx
must be between x_Min
and y_Min
and similarly for Oldy
.
The most important part of the code is below:
for (j=y_Min;j<=y_Max;j+=(x_Max-x_Min)/500) for (i=x_Min;i<=x_Max;i+=(x_Max-x_Min)/500) { _3DPixel.z=MathFunc(j,i); if (_3DPixel.z>=MAXp) MAXp=_3DPixel.z; if (_3DPixel.z<=MINp) MINp=_3DPixel.z; } SetHighLowColor(MAX,MIN); for (j=y_Min+.5;j<=y_Max;j+=(y_Max-y_Min)/2000) for (i=x_Min+.5;i<=x_Max;i+=(x_Max-x_Min)/2000) { _3DPixel.y=i; _3DPixel.x=j; _3DPixel.z=MathFunc(j,i); crColor=Set3DColor(_3DPixel.z); Set3DPixel(&dc,_3DPixel,crColor); }
Function MathFunc
is a math function. In this example, we have:
float C3DStatic::MathFunc(float x,float y) { return 2*sin(x*y/3); }
The two next functions are SetHighLowColor
and Set3DColor
. The first attributes maximum value of MyFunc (MAXp)
to pure red color and minimum value of MyFunc (MINp)
to pure blue color. The second one sets a color for a given value of Mathfunc
. Finally using Set3DPixel
, we plot a pixel on the static.
Have fun.