/***************************************************************************** * * Copyright (c) 1999, KL GROUP INC. All Rights Reserved. * http://www.klgroup.com * * This file is provided for demonstration and educational uses only. * Permission to use, copy, modify and distribute this file for * any purpose and without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies, and that the name of KL Group not be used in advertising * or publicity pertaining to this material without the specific, * prior written permission of an authorized representative of * KL Group. * * KL GROUP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. KL GROUP SHALL NOT BE LIABLE FOR ANY * DAMAGES SUFFERED BY USERS AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ // mathView.cpp : implementation of the CMathView class // #include "stdafx.h" #include #include "math.h" #include "mathDoc.h" #include "mathView.h" // Olectra Chart includes #include "Axis.h" #include "AxisCollection.h" #include "Ceiling.h" #include "Chart3DData.h" #include "ChartArea.h" #include "ChartGroup.h" #include "ChartGroupCollection.h" #include "Contour.h" #include "ContourLevels.h" #include "Elevation.h" #include "Floor.h" #include "Gridlines.h" #include "Label.h" #include "Legend.h" #include "PlotCube.h" #include "Projection.h" #include "Surface.h" #include "Title.h" #include "View3d.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CMathView IMPLEMENT_DYNCREATE(CMathView, CFormView) BEGIN_MESSAGE_MAP(CMathView, CFormView) //{{AFX_MSG_MAP(CMathView) ON_BN_CLICKED(IDC_EXIT_BUTTON, OnExitButton) ON_BN_CLICKED(IDC_APPLY_BUTTON, OnApplyButton) ON_CBN_SELENDOK(IDC_FUNCTION_COMBOBOX, OnSelendokFunctionCombobox) ON_BN_CLICKED(IDC_MESH_CHECK, OnMeshCheck) ON_NOTIFY(UDN_DELTAPOS, IDC_NUMLINES_X_SPIN, OnDeltaposNumlinesXSpin) ON_NOTIFY(UDN_DELTAPOS, IDC_NUMLINES_Y_SPIN, OnDeltaposNumlinesYSpin) ON_NOTIFY(UDN_DELTAPOS, IDC_CONTOURS_SPIN, OnDeltaposContoursSpin) ON_EN_CHANGE(IDC_NUMLINES_X_EDIT, OnChangeNumlinesXEdit) ON_EN_CHANGE(IDC_NUMLINES_Y_EDIT, OnChangeNumlinesYEdit) ON_EN_CHANGE(IDC_MAX_X_EDIT, OnChangeMaxXEdit) ON_EN_CHANGE(IDC_MAX_Y_EDIT, OnChangeMaxYEdit) ON_EN_CHANGE(IDC_MIN_X_EDIT, OnChangeMinXEdit) ON_EN_CHANGE(IDC_MIN_Y_EDIT, OnChangeMinYEdit) ON_EN_KILLFOCUS(IDC_CONTOURS_EDIT, OnKillfocusContoursEdit) ON_EN_KILLFOCUS(IDC_ANGLE_X_EDIT, OnKillfocusAngleXEdit) ON_EN_KILLFOCUS(IDC_ANGLE_Y_EDIT, OnKillfocusAngleYEdit) ON_EN_KILLFOCUS(IDC_ANGLE_Z_EDIT, OnKillfocusAngleZEdit) ON_EN_KILLFOCUS(IDC_MAX_X_EDIT, OnKillfocusMaxXEdit) ON_EN_KILLFOCUS(IDC_MAX_Y_EDIT, OnKillfocusMaxYEdit) ON_EN_KILLFOCUS(IDC_MIN_X_EDIT, OnKillfocusMinXEdit) ON_EN_KILLFOCUS(IDC_MIN_Y_EDIT, OnKillfocusMinYEdit) ON_EN_KILLFOCUS(IDC_PERSPECTIVE_EDIT, OnKillfocusPerspectiveEdit) ON_EN_KILLFOCUS(IDC_NUMLINES_X_EDIT, OnKillfocusNumlinesXEdit) ON_EN_KILLFOCUS(IDC_NUMLINES_Y_EDIT, OnKillfocusNumlinesYEdit) ON_WM_TIMER() ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() // helper funtion prototypes void LoadCombo(CComboBox *cmb); double Log10(double Num); double Frac(double x, double y); // Represents the HoleValue double HugeVal; ///////////////////////////////////////////////////////////////////////////// // CMathView construction/destruction CMathView::CMathView() : CFormView(CMathView::IDD) { //{{AFX_DATA_INIT(CMathView) //}}AFX_DATA_INIT // TODO: add construction code here } CMathView::~CMathView() { // destroy the output window m_OutWnd.DestroyWindow(); } void CMathView::DoDataExchange(CDataExchange* pDX) { CFormView::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMathView) DDX_Control(pDX, IDC_ZONES_CHECK, m_ZonesChk); DDX_Control(pDX, IDC_ZONEDFLOOR_CHECK, m_ZonedFloorChk); DDX_Control(pDX, IDC_ZONEDCEILING_CHECK, m_ZonedCeilingChk); DDX_Control(pDX, IDC_YMESH_CHECK, m_YMeshChk); DDX_Control(pDX, IDC_XMESH_CHECK, m_XMeshChk); DDX_Control(pDX, IDC_SOLID_CHECK, m_SolidChk); DDX_Control(pDX, IDC_SHADED_CHECK, m_ShadedChk); DDX_Control(pDX, IDC_SCALE_Y_EDIT, m_ScaleYEdit); DDX_Control(pDX, IDC_PERSPECTIVE_EDIT, m_PerspectiveEdit); DDX_Control(pDX, IDC_SCALE_X_EDIT, m_ScaleXEdit); DDX_Control(pDX, IDC_NUMLINES_Y_SPIN, m_NumlinesYSpin); DDX_Control(pDX, IDC_NUMLINES_X_SPIN, m_NumlinesXSpin); DDX_Control(pDX, IDC_MIN_Y_EDIT, m_MinYEdit); DDX_Control(pDX, IDC_MIN_X_EDIT, m_MinXEdit); DDX_Control(pDX, IDC_MESH_CHECK, m_MeshChk); DDX_Control(pDX, IDC_MAX_Y_EDIT, m_MaxYEdit); DDX_Control(pDX, IDC_MAX_X_EDIT, m_MaxXEdit); DDX_Control(pDX, IDC_LEGEND_CHECK, m_LegendChk); DDX_Control(pDX, IDC_HIDDENLINES_CHECK, m_HiddenlinesChk); DDX_Control(pDX, IDC_GRIDLINES_Z_YZ_CHECK, m_GridlinesZYZChk); DDX_Control(pDX, IDC_GRIDLINES_Z_XZ_CHECK, m_GridlinesZXZChk); DDX_Control(pDX, IDC_GRIDLINES_Y_YZ_CHECK, m_GridlinesYYZChk); DDX_Control(pDX, IDC_GRIDLINES_Y_XY_CHECK, m_GridlinesYXYChk); DDX_Control(pDX, IDC_GRIDLINES_X_XZ_CHECK, m_GridlinesXXZChk); DDX_Control(pDX, IDC_GRIDLINES_X_XY_CHECK, m_GridlinesXXYChk); DDX_Control(pDX, IDC_DOUBLEBUFFER_CHECK, m_DoubleBufferChk); DDX_Control(pDX, IDC_CONTOURS_SPIN, m_ContoursSpin); DDX_Control(pDX, IDC_CONTOURS_EDIT, m_ContoursEdit); DDX_Control(pDX, IDC_CONTOUREDCEILING_CHECK, m_ContourCeilingChk); DDX_Control(pDX, IDC_CONTOUREDFLOOR_CHECK, m_ContourFloorChk); DDX_Control(pDX, IDC_CONTOUR_CHECK, m_ContourChk); DDX_Control(pDX, IDC_ANGLE_Z_EDIT, m_AngleZEdit); DDX_Control(pDX, IDC_ANGLE_Z_CHECK, m_AngleZChk); DDX_Control(pDX, IDC_ANGLE_Y_EDIT, m_AngleYEdit); DDX_Control(pDX, IDC_ANGLE_Y_CHECK, m_AngleYChk); DDX_Control(pDX, IDC_ANGLE_X_CHECK, m_AngleXChk); DDX_Control(pDX, IDC_ANGLE_X_EDIT, m_AngleXEdit); DDX_Control(pDX, IDC_NUMLINES_Y_EDIT, m_NumlinesYEdit); DDX_Control(pDX, IDC_NUMLINES_X_EDIT, m_NumlinesXEdit); DDX_Control(pDX, IDC_FUNCTION_COMBOBOX, m_FunctionCmb); //}}AFX_DATA_MAP } BOOL CMathView::PreCreateWindow(CREATESTRUCT& cs) { bool temp; temp = (CFormView::PreCreateWindow(cs) == 1); // this (and it's buddy in mainframe.cpp) kill the sunken window effect cs.dwExStyle ^= WS_EX_CLIENTEDGE; return temp; } void CMathView::OnInitialUpdate() { // This is where is it all begins! RECT my_Rect; LPCTSTR szWndClass; CFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); // setup position and size of output window my_Rect.top = 3; my_Rect.left = 3; my_Rect.bottom = 384; my_Rect.right = 471; // create the Output Window szWndClass = AfxRegisterWndClass(0); // give the output window a pointer to this view m_OutWnd.SetInWindow(this); // Do the Create if( !m_OutWnd.CreateEx(NULL, szWndClass, "Olectra Chart 3D - Math Functions Demo", WS_BORDER | WS_POPUP | WS_CAPTION | WS_THICKFRAME, my_Rect, NULL, 0)) { ASSERT(FALSE); } // display the window m_OutWnd.ShowWindow(1); // Setup Default Form Info InitialFormSetup(); // Prevent the user from making changes to the graph at run-time m_OutWnd.GetChart()->SetAllowUserChanges(false); // Set the Spin flags m_XSpin = m_YSpin = m_ZSpin = false; // Setup a Timer to send a message every second. this->SetTimer(1, 1, NULL); // Change the cursor to an Hourglass so the user knows we are doing something BeginWaitCursor(); // Sets up the Hole Value HugeVal = m_OutWnd.GetChart()->GetChartGroups().GetItem(COleVariant(1L)).GetElevationData().GetHoleValue(); //Calls the sub to load the formula list into the combo box LoadCombo(&m_FunctionCmb); // Since we are starting up, don't need to repaint the graph as it is already set // to the default formula and visual defaults m_DataChange = false; // Set the mouse cursor back to what is was before EndWaitCursor(); // Apply the starting values to the chart OnApplyButton(); } // helper function to load a combo box void LoadCombo(CComboBox *cmb) { // Used to load the combo box with the pre-selected formulas. cmb->AddString("COS(SIN(X*Y)) + SIN(COS(X/Y))"); cmb->AddString("FRAC(X, Y)"); cmb->AddString("SIN(X*X + Y*Y)/(X*X + Y*Y)"); cmb->AddString("3*X*Y - X*X*X - Y*Y*Y"); cmb->AddString("((Y*Y <=1) + (X*X >1)) * SIN(X-Y)"); cmb->AddString("COS(4*(SIN(X) + COS(Y)))"); cmb->AddString("Y * (Y-1) * (Y-1.1) - 10*X*X*(X*X-1)"); cmb->AddString("ACOS(X*Y)"); cmb->AddString("POW(POW(X, -LOG(Y)), POW(Y, -LOG(X)))"); cmb->AddString("ATAN(POW(X, Y))"); cmb->AddString("SIN(X*Y)"); cmb->AddString("COS(X*Y)"); cmb->AddString("TAN(X*Y)"); // Set the current selection to the first item in the list cmb->SetCurSel(0); } ///////////////////////////////////////////////////////////////////////////// // CMathView diagnostics #ifdef _DEBUG void CMathView::AssertValid() const { CFormView::AssertValid(); } void CMathView::Dump(CDumpContext& dc) const { CFormView::Dump(dc); } CMathDoc* CMathView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMathDoc))); return (CMathDoc*)m_pDocument; } #endif //_DEBUG // Setup look/data of Form on initial startup // must also change some Chart data ... maybe void CMathView::InitialFormSetup(void) { // Set the max amount of Text that can fit into the text boxes m_NumlinesXEdit.SetLimitText(4); m_NumlinesYEdit.SetLimitText(4); m_ScaleXEdit.SetLimitText(3); m_ScaleYEdit.SetLimitText(3); m_PerspectiveEdit.SetLimitText(5); m_ContoursEdit.SetLimitText(3); m_MaxXEdit.SetLimitText(10); m_MaxYEdit.SetLimitText(10); m_MinXEdit.SetLimitText(10); m_MinYEdit.SetLimitText(10); m_AngleXEdit.SetLimitText(10); m_AngleYEdit.SetLimitText(10); m_AngleZEdit.SetLimitText(10); // Set the number of lines per axis m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); // check some checkboxes m_MeshChk.SetCheck(1); m_XMeshChk.SetCheck(1); m_YMeshChk.SetCheck(1); m_ShadedChk.SetCheck(1); m_ZonesChk.SetCheck(1); m_DoubleBufferChk.SetCheck(1); // Set the Scale m_ScaleXEdit.SetWindowText("100"); m_ScaleYEdit.SetWindowText("100"); // Set the View Angle m_AngleXEdit.SetWindowText("45"); m_AngleYEdit.SetWindowText("0"); m_AngleZEdit.SetWindowText("45"); // Set the number of Contours m_ContoursEdit.SetWindowText("10"); // Set the Perspective m_PerspectiveEdit.SetWindowText("2.5"); // output the max/min for the initial data. m_MaxXEdit.SetWindowText("1.571"); m_MaxYEdit.SetWindowText("1.571"); m_MinXEdit.SetWindowText("3.142"); m_MinYEdit.SetWindowText("3.142"); // make the spin boxes "buddies" with the appropriate text edit windows m_NumlinesXSpin.SetBuddy(&m_NumlinesXEdit); m_NumlinesYSpin.SetBuddy(&m_NumlinesYEdit); m_ContoursSpin.SetBuddy(&m_ContoursEdit); // Set the spinbox maximums and minimums m_NumlinesXSpin.SetRange(1, 200); m_NumlinesYSpin.SetRange(1, 200); m_ContoursSpin.SetRange(1, 1000); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); m_ContoursSpin.SetPos(10); } // For Convienience double Log10(double Num) { // Derived math function. return log(Num) / log(10.0); } // Perform the Frac math function double Frac(double x, double y) { // An interesting function when graphed. int i = 0; int Maxi = 256; double a1 = 0.0; double b1 = 0.0; double a2 = 0.0; double b2 = 0.0; do { b1 = 2 * a1 * b1 + y; a1 = a2 - b2 + x; a2 = a1 * a1; b2 = b1 * b1; i++; } while ((i < Maxi) && (a2 + b2 < 100000.0)) ; i++; if (i > Maxi) { return HugeVal; } else { return ( (-0.6 * Log10(a2 + b2)) / pow(2.0, (double)i) ); } } // member function to get access to the output window CMathOutWnd* CMathView::GetOutWnd(void) { if (::IsWindow((HWND)m_OutWnd.m_hWnd)) { // return a pointer to the output window return &m_OutWnd; } else { // NULL otherwise return NULL; } } // used by CMathOutWnd to set text field that can be manipulated by // rotating the chart with the mouse. void CMathView::SetXYZAngleEdit(char* XRot, char* YRot, char* ZRot) { // set the appropriate text windows m_AngleXEdit.SetWindowText(XRot); m_AngleYEdit.SetWindowText(YRot); m_AngleZEdit.SetWindowText(ZRot); } ///////////////////////////////////////////////////////////////////////////// // CMathView message handlers void CMathView::OnExitButton() { // exit the proggy ASSERT(AfxGetMainWnd() != NULL); AfxGetMainWnd()->SendMessage(WM_CLOSE); } void CMathView::OnApplyButton() { // Update the Graph with the changes the user has selected. // Temp Variables CChart3D *chart; CString tempStr, maxStr, numlinesStr; CChartGroup chGroup; CChartArea chArea; CChart3DData elevData; double h; double x, y; // Change the cursor to an hourglass to show we are busy doing something BeginWaitCursor(); // get some commonly used objects chart = m_OutWnd.GetChart(); chArea = chart->GetChartArea(); chGroup = chart->GetChartGroups().GetItem(COleVariant(1L)); elevData = m_OutWnd.GetChart()->GetChartGroups().GetItem(COleVariant(1L)).GetElevationData(); // Batch all the updates to the output Chart so all the changes occur at once chart->SetIsBatched(true); // Setup the Chart header m_FunctionCmb.GetLBText(m_FunctionCmb.GetCurSel(), tempStr); chart->GetHeader().GetText().SetText("F(x, y)=" + tempStr); //Set the Maximum number of Rows to Plot m_NumlinesXEdit.GetWindowText(tempStr); chGroup.GetElevationData().SetRowCount( atoi(tempStr) ); // Change the SpinBox Value m_NumlinesXSpin.SetPos( atoi(tempStr) ); //Set the Maximum number of Columns to Plot m_NumlinesYEdit.GetWindowText(tempStr); chGroup.GetElevationData().SetColumnCount( atoi(tempStr) ); // Change the SpinBox Value m_NumlinesYSpin.SetPos( atoi(tempStr) ); // Apply the various display options chGroup.GetElevation().SetIsMeshed( m_MeshChk.GetCheck() ); chGroup.GetElevation().SetIsShaded( m_ShadedChk.GetCheck() ); chGroup.GetContour().SetIsContoured( m_ContourChk.GetCheck() ); chGroup.GetContour().SetIsZoned( m_ZonesChk.GetCheck() ); chArea.GetSurface().SetIsSolid( m_SolidChk.GetCheck() ); chGroup.GetElevation().SetIsTransparent( m_HiddenlinesChk.GetCheck() ); chArea.GetSurface().SetIsRowMeshShowing( m_XMeshChk.GetCheck() ); chArea.GetSurface().SetIsColumnMeshShowing( m_YMeshChk.GetCheck() ); chart->GetLegend().SetIsShowing( m_LegendChk.GetCheck() ); chart->SetIsDoubleBuffered( m_DoubleBufferChk.GetCheck() ); chArea.GetPlotCube().GetFloor().GetProjection().SetIsContoured( m_ContourFloorChk.GetCheck() ); chArea.GetPlotCube().GetFloor().GetProjection().SetIsZoned( m_ZonedFloorChk.GetCheck() ); chArea.GetPlotCube().GetCeiling().GetProjection().SetIsContoured( m_ContourCeilingChk.GetCheck() ); chArea.GetPlotCube().GetCeiling().GetProjection().SetIsZoned( m_ZonedCeilingChk.GetCheck() ); // Set the scale for the X-Axis and Y-Axis m_ScaleXEdit.GetWindowText(tempStr); chArea.GetPlotCube().SetXScale( atoi(tempStr) ); m_ScaleYEdit.GetWindowText(tempStr); chArea.GetPlotCube().SetYScale( atoi(tempStr) ); // Set the viewing angles for the 3 Axes m_AngleXEdit.GetWindowText(tempStr); chArea.GetView3D().SetXRotation( atoi(tempStr)); m_AngleYEdit.GetWindowText(tempStr); chArea.GetView3D().SetYRotation( atoi(tempStr)); m_AngleZEdit.GetWindowText(tempStr); chArea.GetView3D().SetZRotation( atoi(tempStr)); // Apply the grid lines in the various directions chArea.GetAxes().GetItem(COleVariant(1L)).GetMajorGrid().SetIsOnXYPlane( m_GridlinesXXYChk.GetCheck() ); chArea.GetAxes().GetItem(COleVariant(1L)).GetMajorGrid().SetIsOnXZPlane( m_GridlinesXXZChk.GetCheck() ); chArea.GetAxes().GetItem(COleVariant(2L)).GetMajorGrid().SetIsOnXYPlane( m_GridlinesYXYChk.GetCheck() ); chArea.GetAxes().GetItem(COleVariant(2L)).GetMajorGrid().SetIsOnYZPlane( m_GridlinesYYZChk.GetCheck() ); chArea.GetAxes().GetItem(COleVariant(3L)).GetMajorGrid().SetIsOnXZPlane( m_GridlinesZXZChk.GetCheck() ); chArea.GetAxes().GetItem(COleVariant(3L)).GetMajorGrid().SetIsOnYZPlane( m_GridlinesZYZChk.GetCheck() ); // Set the number of Contour Levels m_ContoursEdit.GetWindowText(tempStr); chGroup.GetContour().GetLevels().SetNumLevels( atoi(tempStr) ); // Change the SpinBox Value m_ContoursSpin.SetPos( atoi(tempStr) ); // Set the Perspective of how the graph looks m_PerspectiveEdit.GetWindowText(tempStr); chArea.GetView3D().SetPerspective( atof(tempStr) ); // If there has been a major change to the graph, then recalculate the graph // otherwise, skip the recalc as it is not necessary if (m_DataChange) { // Batch everything for better performance (at the data level) elevData.SetIsBatched(true); // Set the X Origin m_MinXEdit.GetWindowText(tempStr); elevData.SetRowOrigin( atof(tempStr) ); // Calculate the space between the Rows m_MaxXEdit.GetWindowText(maxStr); m_NumlinesXEdit.GetWindowText(numlinesStr); elevData.SetRowDelta(1, fabs(atof(maxStr) - atof(tempStr)) / (atoi(numlinesStr) - 1) ); // Set the Y Origin m_MinYEdit.GetWindowText(tempStr); elevData.SetColumnOrigin( atof(tempStr) ); // Calculate the space between the Columns m_MaxYEdit.GetWindowText(maxStr); m_NumlinesYEdit.GetWindowText(numlinesStr); elevData.SetColumnDelta(1, fabs(atof(maxStr) - atof(tempStr)) / (atoi(numlinesStr) - 1) ); // Check if a formula was selected from the combo box long numXLines, numYLines; m_NumlinesXEdit.GetWindowText(numlinesStr); numXLines = atoi(numlinesStr); m_NumlinesYEdit.GetWindowText(numlinesStr); numYLines = atoi(numlinesStr); switch ( m_FunctionCmb.GetCurSel() ) { long i; //"COS(SIN(X*Y)) + SIN(COS(X/Y))" case 0: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, cos(sin(x * y)) + sin(cos(x / y)) ); } } break; // "FRAC(X, Y)" case 1: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, Frac(x, y) ); } } break; // "SIN(X*X + Y*Y)/(X*X + Y*Y)" case 2: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, sin(x * x + y * y) / (x * x + y * y) ); } } break; // "3*X*Y - X*X*X - Y*Y*Y" case 3: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, 3 * x * y - x * x * x - y * y * y); } } break; // '"((Y*Y <=1) + (X*X >1)) * SIN(X-Y)" case 4: h = 2; for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); if ( y*y > 1 ){ h--; } if ( x*x <= 1) { h--; } elevData.SetValue(i, j, h * sin(x - y) ); h = 2; } } break; // "COS(4*(SIN(X) + COS(Y)))" case 5: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, cos(4 * (sin(x) + cos(y))) ); } } break; // "Y * (Y-1) * (Y-1.1) - 10*X*X*(X*X-1)" case 6: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, y * (y - 1) * (y - 1.1) - 10 * x * x * (x * x - 1) ); } } break; // "ACOS(X*Y)" case 7: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); /* * The domain of the ArcCosine Function is -1 <= x <= 1 ForAll Real x. * Thus we must check for valid input, otherwise an error is returned * from the 'double acos(double)' C Function. */ if (x * y <= 1 && x*y >= -1) { elevData.SetValue(i, j, acos(x * y) ); } else { elevData.SetValue(i, j, HugeVal); } } } break; // "POW(POW(X, -LOG(Y)), POW(Y, -LOG(X)))" case 8: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, pow(pow(x, -log(y)) , pow(y, -log(x))) ); } } break; // "ATAN(POW(X, Y))" case 9: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, atan(pow(x, y)) ); } } break; // "SIN(X*Y)" case 10: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, sin(x * y) ); } } break; // "COS(X*Y)" case 11: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, cos(x * y) ); } } break; // "TAN(X*Y)" case 12: for (i=1; i<=numXLines; i++) { x = elevData.GetRowOrigin() + (i * elevData.GetRowDelta(1)); for (long j=1; j<=numYLines; j++) { y = elevData.GetColumnOrigin() + (j * elevData.GetColumnDelta(1)); elevData.SetValue(i, j, tan(x * y) ); } } default: TRACE("ERROR: Illegal Combo Box Selection!"); } // end switch // Resume normal updating of the data object elevData.SetIsBatched(false); } // Resume regular updating of the output Chart chart->SetIsBatched(false); // Reset the flag m_DataChange = false; // Set the spin flag m_XSpin = (m_AngleXChk.GetCheck() == 1); m_YSpin = (m_AngleYChk.GetCheck() == 1); m_ZSpin = (m_AngleZChk.GetCheck() == 1); //Set the cursor back to what is was before EndWaitCursor(); } void CMathView::OnSelendokFunctionCombobox() { // Update some fields as the user has changed the selected formula. // Indicate that a major change has occured for use in the Apply button m_DataChange = true; switch ( m_FunctionCmb.GetCurSel() ) { // COS(SIN(X*Y)) + SIN(COS(X/Y)) case 0: m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); m_MinXEdit.SetWindowText("1.571"); m_MinYEdit.SetWindowText("1.571"); m_MaxXEdit.SetWindowText("3.142"); m_MaxYEdit.SetWindowText("3.142"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); break; // FRAC(X, Y) case 1: m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); m_MinXEdit.SetWindowText("-2.0"); m_MinYEdit.SetWindowText("-2.0"); m_MaxXEdit.SetWindowText("2.0"); m_MaxYEdit.SetWindowText("2.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); break; // SIN(X*X + Y*Y)/(X*X + Y*Y) case 2: m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); m_MinXEdit.SetWindowText("-2.5"); m_MinYEdit.SetWindowText("-2.5"); m_MaxXEdit.SetWindowText("5.0"); m_MaxYEdit.SetWindowText("5.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); break; // 3*X*Y - X*X*X - Y*Y*Y case 3: m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); m_MinXEdit.SetWindowText("-2.5"); m_MinYEdit.SetWindowText("-2.5"); m_MaxXEdit.SetWindowText("5.0"); m_MaxYEdit.SetWindowText("5.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); break; // ((Y*Y <=1) + (X*X >1)) * SIN(X-Y) case 4: m_NumlinesXEdit.SetWindowText("30"); m_NumlinesYEdit.SetWindowText("30"); m_MinXEdit.SetWindowText("-3.0"); m_MinYEdit.SetWindowText("-3.0"); m_MaxXEdit.SetWindowText("3.0"); m_MaxYEdit.SetWindowText("3.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(30); m_NumlinesYSpin.SetPos(30); break; // COS(4*(SIN(X) + COS(Y))) case 5: m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); m_MinXEdit.SetWindowText("-2.0"); m_MinYEdit.SetWindowText("-2.0"); m_MaxXEdit.SetWindowText("2.5"); m_MaxYEdit.SetWindowText("2.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); break; // Y * (Y-1) * (Y-1.1) - 10*X*X*(X*X-1) case 6: m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); m_MinXEdit.SetWindowText("-1.0"); m_MinYEdit.SetWindowText("-1.0"); m_MaxXEdit.SetWindowText("1.0"); m_MaxYEdit.SetWindowText("4.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); break; // ACOS(X*Y) case 7: m_NumlinesXEdit.SetWindowText("21"); m_NumlinesYEdit.SetWindowText("21"); m_MinXEdit.SetWindowText("-2.0"); m_MinYEdit.SetWindowText("-2.0"); m_MaxXEdit.SetWindowText("2.0"); m_MaxYEdit.SetWindowText("2.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(21); m_NumlinesYSpin.SetPos(21); break; // POW(POW(X, -LOG(Y)), POW(Y, -LOG(X))) case 8: m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); m_MinXEdit.SetWindowText("0.0"); m_MinYEdit.SetWindowText("0.0"); m_MaxXEdit.SetWindowText("1.0"); m_MaxYEdit.SetWindowText("1.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); break; // ATAN(POW(X, Y)) case 9: m_NumlinesXEdit.SetWindowText("21"); m_NumlinesYEdit.SetWindowText("21"); m_MinXEdit.SetWindowText("0.0"); m_MinYEdit.SetWindowText("0.0"); m_MaxXEdit.SetWindowText("1.0"); m_MaxYEdit.SetWindowText("1.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(21); m_NumlinesYSpin.SetPos(21); break; // SIN(X*Y) case 10: m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); m_MinXEdit.SetWindowText("-2.0"); m_MinYEdit.SetWindowText("-2.0"); m_MaxXEdit.SetWindowText("2.0"); m_MaxYEdit.SetWindowText("2.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); break; // COS(X*Y) case 11: m_NumlinesXEdit.SetWindowText("20"); m_NumlinesYEdit.SetWindowText("20"); m_MinXEdit.SetWindowText("-4.0"); m_MinYEdit.SetWindowText("-4.0"); m_MaxXEdit.SetWindowText("3.0"); m_MaxYEdit.SetWindowText("3.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(20); m_NumlinesYSpin.SetPos(20); break; // TAN(X*Y) case 12: m_NumlinesXEdit.SetWindowText("25"); m_NumlinesYEdit.SetWindowText("25"); m_MinXEdit.SetWindowText("-1.0"); m_MinYEdit.SetWindowText("-2.0"); m_MaxXEdit.SetWindowText("3.5"); m_MaxYEdit.SetWindowText("4.0"); // Set the current position of the spin boxes m_NumlinesXSpin.SetPos(25); m_NumlinesYSpin.SetPos(25); break; } // end of switch } void CMathView::OnMeshCheck() { // Disabled the X and Y Mesh options if Meshing is disabled. if (m_MeshChk.GetCheck()) { // Enable the Checks m_XMeshChk.EnableWindow(true); m_YMeshChk.EnableWindow(true); } else { // disable the checks m_XMeshChk.EnableWindow(false); m_YMeshChk.EnableWindow(false); } } void CMathView::OnDeltaposNumlinesXSpin(NMHDR* pNMHDR, LRESULT* pResult) { NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR; char tempStr[MAX_STRING_LEN]; int newVal; // iPos is the old value before pressing a button on the spin box. // iDelta is the change in value due to pressing a button on the spin box newVal = pNMUpDown->iPos + pNMUpDown->iDelta; if (newVal > 1) { itoa(newVal, tempStr, 10); // change the window text. m_NumlinesXEdit.SetWindowText( tempStr ); } else { m_NumlinesXSpin.SetPos(2); } *pResult = 0; } void CMathView::OnDeltaposNumlinesYSpin(NMHDR* pNMHDR, LRESULT* pResult) { NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR; // TODO: Add your control notification handler code here char tempStr[MAX_STRING_LEN]; int newVal; // iPos is the old value before pressing a button on the spin box. // iDelta is the change in value due to pressing a button on the spin box newVal = pNMUpDown->iPos + pNMUpDown->iDelta; if (newVal > 0) { itoa(newVal, tempStr, 10); // change the window text. m_NumlinesYEdit.SetWindowText( tempStr ); } *pResult = 0; } void CMathView::OnDeltaposContoursSpin(NMHDR* pNMHDR, LRESULT* pResult) { NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR; // TODO: Add your control notification handler code here char tempStr[MAX_STRING_LEN]; int newVal; // iPos is the old value before pressing a button on the spin box. // iDelta is the change in value due to pressing a button on the spin box newVal = pNMUpDown->iPos + pNMUpDown->iDelta; if (newVal >= 0 && newVal <= 100) { itoa(newVal, tempStr, 10); // change the window text. m_ContoursEdit.SetWindowText(tempStr); } *pResult = 0; } void CMathView::OnChangeNumlinesXEdit() { // Need to re-calculate data, so set m_DataChange flag to true m_DataChange = true; } void CMathView::OnChangeNumlinesYEdit() { // Need to re-calculate data, so set m_DataChange flag to true m_DataChange = true; } void CMathView::OnChangeMaxXEdit() { // Need to re-calculate data, so set m_DataChange flag to true m_DataChange = true; } void CMathView::OnChangeMaxYEdit() { // Need to re-calculate data, so set m_DataChange flag to true m_DataChange = true; } void CMathView::OnChangeMinXEdit() { // Need to re-calculate data, so set m_DataChange flag to true m_DataChange = true; } void CMathView::OnChangeMinYEdit() { // Need to re-calculate data, so set m_DataChange flag to true m_DataChange = true; } void CMathView::OnKillfocusContoursEdit() { // convert whatever was entered into an integer. CString tempStr; char charArr[MAX_STRING_LEN]; int tempInt; m_ContoursEdit.GetWindowText(tempStr); tempInt = atoi(tempStr.GetBuffer(0)); // keep the integer within the allowable range if (tempInt < 0) { tempInt = 0; } else if (tempInt > 100) { tempInt = 100; } // change the text itoa(tempInt, charArr, 10); m_ContoursEdit.SetWindowText(charArr); // set the spinbox position to match m_ContoursSpin.SetPos(atoi(charArr)); } void CMathView::OnKillfocusAngleXEdit() { // convert whatever was entered into an integer. CString tempStr; char charArr[MAX_STRING_LEN]; int tempInt; m_AngleXEdit.GetWindowText(tempStr); tempInt = atoi(tempStr.GetBuffer(0)); // keep the integer within the allowable range if (tempInt < 0) { tempInt = 0; } else if (tempInt > 360) { tempInt = 360; } // change the text itoa(tempInt, charArr, 10); m_AngleXEdit.SetWindowText(charArr); } void CMathView::OnKillfocusAngleYEdit() { // convert whatever was entered into an integer. CString tempStr; char charArr[MAX_STRING_LEN]; int tempInt; m_AngleYEdit.GetWindowText(tempStr); tempInt = atoi(tempStr.GetBuffer(0)); // keep the integer within the allowable range if (tempInt < 0) { tempInt = 0; } else if (tempInt > 360) { tempInt = 360; } // change the text itoa(tempInt, charArr, 10); m_AngleYEdit.SetWindowText(charArr); } void CMathView::OnKillfocusAngleZEdit() { // convert whatever was entered into an integer. CString tempStr; char charArr[MAX_STRING_LEN]; int tempInt; m_AngleZEdit.GetWindowText(tempStr); tempInt = atoi(tempStr.GetBuffer(0)); // keep the integer within the allowable range if (tempInt < 0) { tempInt = 0; } else if (tempInt > 360) { tempInt = 360; } // change the text itoa(tempInt, charArr, 10); m_AngleZEdit.SetWindowText(charArr); } void CMathView::OnKillfocusMaxXEdit() { // convert whatever was entered into a float CString tempStr; char charArr[MAX_STRING_LEN]; double tempFloat; m_MaxXEdit.GetWindowText(tempStr); tempFloat = atof(tempStr.GetBuffer(0)); // change the text sprintf(charArr, "%g", tempFloat); m_MaxXEdit.SetWindowText(charArr); } void CMathView::OnKillfocusMaxYEdit() { // convert whatever was entered into a float CString tempStr; char charArr[MAX_STRING_LEN]; double tempFloat; m_MaxYEdit.GetWindowText(tempStr); tempFloat = atof(tempStr.GetBuffer(0)); // change the text sprintf(charArr, "%g", tempFloat); m_MaxYEdit.SetWindowText(charArr); } void CMathView::OnKillfocusMinXEdit() { // convert whatever was entered into a float CString tempStr; char charArr[MAX_STRING_LEN]; double tempFloat; m_MinXEdit.GetWindowText(tempStr); tempFloat = atof(tempStr.GetBuffer(0)); // change the text sprintf(charArr, "%g", tempFloat); m_MinXEdit.SetWindowText(charArr); } void CMathView::OnKillfocusMinYEdit() { // convert whatever was entered into a float CString tempStr; char charArr[MAX_STRING_LEN]; double tempFloat; m_MinYEdit.GetWindowText(tempStr); tempFloat = atof(tempStr.GetBuffer(0)); // change the text sprintf(charArr, "%g", tempFloat); m_MinYEdit.SetWindowText(charArr); } void CMathView::OnKillfocusPerspectiveEdit() { // convert whatever was entered into a float CString tempStr; char charArr[MAX_STRING_LEN]; double tempFloat; m_PerspectiveEdit.GetWindowText(tempStr); tempFloat = atof(tempStr.GetBuffer(0)); // make sure we stay within an allowable range if (tempFloat > 100) { tempFloat = 100.0; } else if (tempFloat < 1) { tempFloat = 1.0; } // change the text sprintf(charArr, "%g", tempFloat); m_PerspectiveEdit.SetWindowText(charArr); } void CMathView::OnKillfocusNumlinesXEdit() { // convert whatever was entered into an integer. CString tempStr; char charArr[MAX_STRING_LEN]; int tempInt; m_NumlinesXEdit.GetWindowText(tempStr); tempInt = atoi(tempStr.GetBuffer(0)); // keep the integer within the allowable range if (tempInt < 0) { tempInt = 0; } else if (tempInt > 200) { tempInt = 200; } // change the text itoa(tempInt, charArr, 10); m_NumlinesXEdit.SetWindowText(charArr); // set the spinbox position to match m_NumlinesXSpin.SetPos(atoi(charArr)); } void CMathView::OnKillfocusNumlinesYEdit() { // convert whatever was entered into an integer. CString tempStr; char charArr[MAX_STRING_LEN]; int tempInt; m_NumlinesYEdit.GetWindowText(tempStr); tempInt = atoi(tempStr.GetBuffer(0)); // keep the integer within the allowable range if (tempInt < 0) { tempInt = 0; } else if (tempInt > 200) { tempInt = 200; } // change the text itoa(tempInt, charArr, 10); m_NumlinesYEdit.SetWindowText(charArr); // set the spinbox position to match m_NumlinesYSpin.SetPos(atoi(charArr)); } void CMathView::OnTimer(UINT nIDEvent) { CFormView::OnTimer(nIDEvent); // Rotate the graph in various directions automatically 1 degree at a time. CView3D view; CString tempStr; char charArr[MAX_STRING_LEN]; int tempInt; // Get the view for convenience view = m_OutWnd.GetChart()->GetChartArea().GetView3D(); // spinning on X-Axis if (m_XSpin) { m_AngleXEdit.GetWindowText(tempStr); tempInt = atoi(tempStr.GetBuffer(0)); if (tempInt + 1 < 360) { // incrament the textbox/chart-rotation by 1 itoa(tempInt+1, charArr, 10); m_AngleXEdit.SetWindowText(charArr); view.SetXRotation(tempInt+1); } else { // reset to 0 m_AngleXEdit.SetWindowText("0"); view.SetXRotation(0.0); } } // spinning on Y-Axis if (m_YSpin) { m_AngleYEdit.GetWindowText(tempStr); tempInt = atoi(tempStr.GetBuffer(0)); if (tempInt + 1 < 360) { // incrament the textbox/chart-rotation by 1 itoa(tempInt+1, charArr, 10); m_AngleYEdit.SetWindowText(charArr); view.SetYRotation(tempInt+1); } else { // reset to 0 m_AngleYEdit.SetWindowText("0"); view.SetYRotation(0.0); } } // spinning on Z-Axis if (m_ZSpin) { m_AngleZEdit.GetWindowText(tempStr); tempInt = atoi(tempStr.GetBuffer(0)); if (tempInt + 1 < 360) { // incrament the textbox/chart-rotation by 1 itoa(tempInt+1, charArr, 10); m_AngleZEdit.SetWindowText(charArr); view.SetZRotation(tempInt+1); } else { // reset to 0 m_AngleZEdit.SetWindowText("0"); view.SetZRotation(0.0); } } } void CMathView::OnDestroy() { CFormView::OnDestroy(); // kill the timer this->KillTimer(1); }