Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / MFC
Article

3DStatic

Rate me:
Please Sign up or sign in to vote.
4.81/5 (23 votes)
6 Jun 20053 min read 91.2K   2.5K   47   17
An article to draw a 3D math function on a static control.

Image 1

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.

Image 2

Figure 1 – Plot a 3D Point on a 2D page.

Image 3

We want to obtain Q(x,y), so …

Image 4

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.

Image 5

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.

Image 6

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Iran (Islamic Republic of) Iran (Islamic Republic of)
I live in Iran . I started hardware programming when I was young. I designed and built some ISA cards for attaching to PC.like ocsiloscope and signal generator. Now I am working for a engineering company and Manager of some project.

Comments and Discussions

 
QuestionMy 5 Pin
Amir Mahfoozi19-Dec-11 1:13
Amir Mahfoozi19-Dec-11 1:13 
GeneralAgain ... Pin
Mehdi Bonvari9-Jun-05 3:48
Mehdi Bonvari9-Jun-05 3:48 
GeneralRe: Again ... Pin
asef10-Jun-05 17:41
asef10-Jun-05 17:41 
GeneralThe working is exemplary, ... Pin
WREY8-Jun-05 6:30
WREY8-Jun-05 6:30 
GeneralRe: The working is exemplary, ... Pin
Anonymous8-Jun-05 19:53
Anonymous8-Jun-05 19:53 
GeneralSuper Pin
Georgi Petrov7-Jun-05 7:38
Georgi Petrov7-Jun-05 7:38 
GeneralRe: Super Pin
asef7-Jun-05 17:48
asef7-Jun-05 17:48 
GeneralRe: Super Pin
Anonymous7-Jun-05 20:28
Anonymous7-Jun-05 20:28 
GeneralRe: Super Pin
asef7-Jun-05 23:38
asef7-Jun-05 23:38 
Yes it is.I myself wanted to do like this.I think processing for detemining the visible point is a time cosumption.But I'll work on it.

You can rotate the view point by using SetXSteep.

Have Fun
Smile | :)

MOSTAFA
GeneralRe: Super Pin
Rick York25-Jun-05 10:04
mveRick York25-Jun-05 10:04 
GeneralRe: Super Pin
Georgi Petrov19-Jul-05 10:33
Georgi Petrov19-Jul-05 10:33 
GeneralRe: Super Pin
asef22-Jul-05 19:37
asef22-Jul-05 19:37 
GeneralRe: Super Pin
Georgi Petrov29-Jul-05 0:33
Georgi Petrov29-Jul-05 0:33 
GeneralExcellent! Pin
Abbas_Riazi6-Jun-05 21:03
professionalAbbas_Riazi6-Jun-05 21:03 
GeneralRe: Excellent! Pin
asef6-Jun-05 21:07
asef6-Jun-05 21:07 
GeneralRe: Excellent! Pin
Majid Shahabfar7-Jun-05 3:04
Majid Shahabfar7-Jun-05 3:04 
GeneralRe: Excellent! Pin
asef7-Jun-05 17:42
asef7-Jun-05 17:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.