⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xgraph.cpp

📁 Displaying large amounts of technical data in a chart can be a frustrating task. You can find tons o
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// XGRAPH.cpp : Definiert den Einsprungpunkt f黵 die DLL-Anwendung.
//

#include "stdafx.h"
#include "XGRAPH.h"
#include "XGraphLabel.h"
#ifndef _WIN32_WCE
#include "AxisDlg.h"
#include "ChartPage.h"
#include "CurveDlg.h"
#include "ChartDlg.h"
#endif
#include <afxpriv.h>

#include "float.h"
#include "GfxUtils.h"
#include "math.h"
#include "MemDC.h"

#include "WinGDI.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// XGraph.cpp: Implementation
//

/////////////////////////////////////////////////////////////////////////////
// CXGraph

IMPLEMENT_SERIAL( CXGraph, CWnd, 1 )
  
#pragma warning (disable : 4244)
#pragma warning (disable : 4800)

CXGraph::NM_POINTMOVING CXGraph::m_nmCurrentPointMoving;
	
CXGraph::CXGraph()
{
	WNDCLASS wndcls;

	// setup drawing function pointers
	m_pDrawFn[0] = DrawRect;
	m_pDrawFn[1] = DrawCircle;
	m_pDrawFn[2] = DrawCross;
	m_pDrawFn[3] = DrawRhombus;
	m_pDrawFn[4] = DrawLeftTriangle;
	m_pDrawFn[5] = DrawUpTriangle;
	m_pDrawFn[6] = DrawRightTriangle;
	m_pDrawFn[7] = DrawDownTriangle;
	
    HINSTANCE hInst   = AfxGetInstanceHandle();
	m_crBackColor     = RGB(255,255,255);
	m_crGraphColor    = RGB(255,255,255);
	m_crInnerColor    = RGB(240,240,240);
	m_nLeftMargin     = 
	m_nTopMargin      = 
	m_nRightMargin    =
	m_nBottomMargin   = 5;
	m_LegendAlignment = right;
	m_bLButtonDown    = false;
	m_bRButtonDown    = false;
	m_bObjectSelected = false;
	m_bTmpDC		  = false;
	m_bDoubleBuffer   = true;
	m_bShowLegend     = true;
	m_bInteraction    = true;
	m_bDataPointMoving= false;
	m_nSelectedSerie  = -1;
	m_pTracker        = NULL;
	m_pCurrentObject  = NULL;
	m_pPrintDC        = NULL;
	m_pDrawDC         = NULL;
	m_nAxisSpace      = 5;
	m_nCursorFlags    = XGC_LEGEND | XGC_VERT | XGC_HORIZ;
	m_OldPoint        = CPoint(0,0);
	m_opOperation	  = opNone;
	m_bSnapCursor     = true;
	m_nSnapRange      = 10;
	m_cPrintHeader    = _T("");
	m_cPrintFooter    = _T("");
	m_pCurrentObject  = NULL;
	m_nForcedSnapCurve = -1;
	m_nSnappedCurve1   = 0;
	m_fCurrentEditValue = 0.0;
	
	m_OldCursorRect.SetRectEmpty();

	// Create one legend for the cursor
	m_CursorLabel.m_bVisible = false;
	m_CursorLabel.m_bCanEdit = false;
	m_CursorLabel.m_bBorder  = true;
	m_CursorLabel.m_clRect.SetRect(100,100,200,175);

	m_Objects.AddHead (&m_CursorLabel);

    // Register window class
    if (!(::GetClassInfo(hInst, _T("XGraph"), &wndcls)))
    {
        wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
        wndcls.lpfnWndProc      = ::DefWindowProc;
        wndcls.cbClsExtra       = 0;
		wndcls.cbWndExtra		= 0;
        wndcls.hInstance        = hInst;
        wndcls.hIcon            = NULL;
        wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
        wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);
        wndcls.lpszMenuName     = NULL;
        wndcls.lpszClassName    = _T("XGraph");

        if (!AfxRegisterClass(&wndcls))
        {
            AfxThrowResourceException();
            return ;
        }
    }
}

CXGraph::~CXGraph()
{
	ResetAll();
}



BEGIN_MESSAGE_MAP(CXGraph, CWnd)
	//{{AFX_MSG_MAP(CXGraph)
	ON_WM_PAINT()
	ON_WM_SIZE()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDOWN()
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_SETCURSOR()
#ifndef _WIN32_WCE
	ON_WM_RBUTTONUP()
	ON_WM_RBUTTONDOWN()
	ON_WM_MOUSEWHEEL()
#endif
	ON_WM_KEYUP()
	ON_COMMAND(IDM_ZOOM, Zoom )
	ON_COMMAND(IDM_PAN, Pan )
	ON_COMMAND(IDM_CURSOR, Cursor )
	ON_COMMAND(IDM_MEASURE, Measure)
	ON_COMMAND(IDM_SELECT, NoOp )
	ON_COMMAND(IDM_RESET, ResetZoom )
	ON_COMMAND(IDM_INSERTLABEL, InsertEmptyLabel)
	ON_COMMAND(IDM_PROPERTIES, OnProperties)
#ifndef _WIN32_WCE
	ON_COMMAND(IDM_PRINT, OnPrint)
#endif
	ON_COMMAND(IDM_LINEARTREND, LinearTrend)
	ON_COMMAND(IDM_CUBICTREND, CubicTrend)
	ON_COMMAND(IDM_PARENTCALLBACK, ParentCallback)
	ON_COMMAND(IDM_ZOOM_BACK, RestoreLastZoom)
	ON_COMMAND(IDM_EDITCURVE, Edit)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


bool CXGraph::DeleteXAxis(int nAxis)
{
	if (nAxis < 0 || nAxis >= static_cast<int>(m_XAxis.size()))
		return false;

	m_XAxis.erase (&m_XAxis[nAxis]);
	
	return true;
}

bool CXGraph::DeleteYAxis(int nAxis)
{
	if (nAxis < 0 || nAxis >= static_cast<int>(m_YAxis.size()))
		return false;

	m_YAxis.erase (&m_YAxis[nAxis]);
	
	return true;
}

bool CXGraph::DeleteCurve(int nCurve)
{
	if (nCurve < 0 || nCurve >= static_cast<int>(m_Data.size()))
		return false;
	
	m_Data.erase (&m_Data[nCurve]);

	return true;
}

CXGraphDataSerie& CXGraph::SetData(TDataPoint* pValues, long nCount, int nCurve, int nXAxis, int nYAxis, bool bAutoDelete)
{
	ASSERT (nCurve <= static_cast<int>(m_Data.size()));
	ASSERT (nXAxis <= static_cast<int>(m_XAxis.size()));
	ASSERT (nYAxis <= static_cast<int>(m_YAxis.size()));

			
	if (pValues == NULL || nCount == 0)
		return (CXGraphDataSerie&)*((CXGraphDataSerie*)NULL);


	if (nCurve == m_Data.size ())
	{
		// New data serie

		CXGraphDataSerie serie;
		
		serie.m_bAutoDelete = bAutoDelete;
		serie.m_nXAxis		= nXAxis;
		serie.m_nYAxis		= nYAxis;
		serie.m_nCount		= nCount;
		serie.m_nIndex      = nCurve;

		if (bAutoDelete)
		{
			serie.m_pData = (TDataPoint*) new TDataPoint[nCount];
			memcpy(serie.m_pData, pValues, sizeof(TDataPoint) * nCount);
		}
		else
			serie.m_pData = pValues;
		
		serie.m_crColor = BASECOLORTABLE[m_Data.size () % 12];

		m_Data.push_back (serie);
	}
	else
	{
		// existing data serie, just update

		m_Data[nCurve].m_nXAxis = nXAxis;
		m_Data[nCurve].m_nYAxis = nYAxis;
		m_Data[nCurve].m_pData  = pValues;
		m_Data[nCurve].m_nCount = nCount;
		m_Data[nCurve].m_bAutoDelete = bAutoDelete;
	}

	// Need additional X-Axis
	if (nXAxis == m_XAxis.size())
	{
		CXGraphAxis axis;
		axis.m_pGraph   = this;
		axis.m_AxisKind = CXGraphAxis::xAxis;
		m_XAxis.push_back (axis);
	}
	
	// Need additional Y-Axis
	if (nYAxis == m_YAxis.size())
	{
		CXGraphAxis axis;
		axis.m_pGraph   = this;
		axis.m_AxisKind = CXGraphAxis::yAxis;
		m_YAxis.push_back (axis);
	}

	m_Data[nCurve].m_pGraph = this;
	
	Autoscale(nXAxis, nYAxis, nCurve);
	
	Invalidate(TRUE);
		
	return m_Data[nCurve];
}


void CXGraph::Autoscale(int nXAxis, int nYAxis, int nCurve)
{
	// Get min/max for data serie
	double fxMin = m_XAxis[nXAxis].m_fMin;
	double fxMax = m_XAxis[nXAxis].m_fMax;
	double fyMin = m_YAxis[nYAxis].m_fMin;
	double fyMax = m_YAxis[nYAxis].m_fMax;

	GetMinMaxForData(m_Data[nCurve], fxMin, 
									 fxMax,
									 fyMin, 
									 fyMax);

	// Set axis ranges
	VERIFY(m_XAxis[nXAxis].SetRange(fxMin, fxMax));
	VERIFY(m_YAxis[nYAxis].SetRange(fyMin, fyMax));
	
}


CXGraphAxis& CXGraph::GetXAxis(int nAxis)
{
	ASSERT(nAxis >= 0 && nAxis < static_cast<int>(m_XAxis.size()));
	return m_XAxis[nAxis]; 
}

CXGraphAxis& CXGraph::GetYAxis(int nAxis)
{
	ASSERT(nAxis >= 0 && nAxis < static_cast<int>(m_YAxis.size()));
	return m_YAxis[nAxis]; 
}

CXGraphDataSerie& CXGraph::GetCurve(int nCurve)
{
	ASSERT(nCurve >= 0 && nCurve < static_cast<int>(m_Data.size()));
	return m_Data[nCurve];
}

TDataPoint CXGraph::GetCursorAbsolute(int nCurve)
{
	TDataPoint vPoint = { 0.0, 0.0};
	long     nIndex;

	vPoint.fXVal = m_XAxis[m_Data[nCurve].m_nXAxis].GetValueForPos (m_CurrentPoint.x);

	double fSnappedXVal = m_XAxis[m_Data[nCurve].m_nXAxis].GetValueForPos (m_CurrentPoint.x);
	// Find index for this value
	m_XAxis[m_Data[nCurve].m_nXAxis].GetIndexByXVal(nIndex, fSnappedXVal, nCurve);
	// get yval for index
	vPoint.fYVal = m_Data[nCurve].m_pData[nIndex].fYVal;

	return vPoint;
}

void CXGraph::SetCursorAbsolute(int nCurve, TDataPoint vPoint, bool bForceVisible )
{
	long nIndex;

	m_CurrentPoint = m_XAxis[m_Data[nCurve].m_nXAxis].GetPointForValue (&vPoint);

	m_XAxis[m_Data[nCurve].m_nXAxis].GetIndexByXVal(nIndex, vPoint.fXVal, nCurve);
	vPoint.fYVal = m_Data[nCurve].m_pData[nIndex].fYVal;


	if (m_nCursorFlags & XGC_ADJUSTSMOOTH && bForceVisible)
	{
		double fRange = m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMax - m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMin;
		m_XAxis[m_Data[nCurve].m_nXAxis].SetCurrentRange(vPoint.fXVal -  fRange / 2, vPoint.fXVal + fRange / 2);
	}
	else
	if ( (vPoint.fXVal < m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMin || 
		  vPoint.fXVal > m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMax ) &&
		  bForceVisible)
	{
		double fRange = m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMax - m_XAxis[m_Data[nCurve].m_nXAxis].m_fCurMin;
		m_XAxis[m_Data[nCurve].m_nXAxis].SetCurrentRange(vPoint.fXVal - (fRange / 2.0), vPoint.fXVal + (fRange / 2.0));
	}

	if (m_nCursorFlags & XGC_ADJUSTSMOOTH && bForceVisible)
	{
		double fRange = m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMax - m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMin;
		m_YAxis[m_Data[nCurve].m_nYAxis].SetCurrentRange(vPoint.fYVal - (fRange / 2.0), vPoint.fYVal + (fRange / 2.0));
	}
	else
	if ( (vPoint.fYVal < m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMin || 
		  vPoint.fYVal > m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMax ) &&
		  bForceVisible)
	{
		double fRange = m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMax - m_YAxis[m_Data[nCurve].m_nYAxis].m_fCurMin;
		m_YAxis[m_Data[nCurve].m_nYAxis].SetCurrentRange(vPoint.fYVal - (fRange / 2.0), vPoint.fYVal + (fRange / 2.0));
	}

	Invalidate();

}

void CXGraph::GetMinMaxForData (CXGraphDataSerie& serie, double& fXMin, double& fXMax, double& fYMin, double& fYMax)
{	
	// check mins and maxs
	for (long i = 0; i < serie.m_nCount; i++)
	{
		if (serie.m_pData[i].fXVal > fXMax)
			fXMax = serie.m_pData[i].fXVal;

		if (serie.m_pData[i].fXVal < fXMin)
			fXMin = serie.m_pData[i].fXVal;

		if (serie.m_pData[i].fYVal > fYMax)
			fYMax = serie.m_pData[i].fYVal;

		if (serie.m_pData[i].fYVal < fYMin)
			fYMin = serie.m_pData[i].fYVal;
	}
}

// Returns the index for the given axis
int CXGraph::GetAxisIndex(CXGraphAxis* pAxis)
{
	for (int x = 0; x < static_cast<int>(m_XAxis.size()); x++)
		if (pAxis == &m_XAxis[x])
			return x;
	
	for (int y = 0; y < static_cast<int>(m_YAxis.size()); y++)
		if (pAxis == &m_YAxis[y])
			return y;

	return -1;
}

// Returns the index for the given curve
int CXGraph::GetCurveIndex(CXGraphDataSerie* pSerie)
{
	for (int i = 0; i < static_cast<int>(m_Data.size()); i++)
		if (pSerie == &m_Data[i])
			return i;

	return -1;
}

void CXGraph::SetGraphMargins(int nLeft, int nTop, int nRight, int nBottom)
{
	m_nLeftMargin   = nLeft;
	m_nTopMargin    = nTop;
	m_nRightMargin  = nRight;
	m_nBottomMargin = nBottom;
}

void CXGraph::DrawMeasures (CDCEx* pDC)
{
	for (UINT i = 0; i < m_Measures.size(); i++)
	{
		CRect measureRect;
						
		measureRect.left = m_XAxis[m_Data[m_Measures[i].nCurve1].m_nXAxis].GetPointForValue(&m_Data[m_Measures[i].nCurve1].m_pData[m_Measures[i].nIndex1]).x;
		measureRect.right= m_XAxis[m_Data[m_Measures[i].nCurve2].m_nXAxis].GetPointForValue(&m_Data[m_Measures[i].nCurve2].m_pData[m_Measures[i].nIndex2]).x;
		
		measureRect.top = m_YAxis[m_Data[m_Measures[i].nCurve1].m_nYAxis].GetPointForValue(&m_Data[m_Measures[i].nCurve1].m_pData[m_Measures[i].nIndex1]).y;
		measureRect.bottom = m_YAxis[m_Data[m_Measures[i].nCurve2].m_nYAxis].GetPointForValue(&m_Data[m_Measures[i].nCurve2].m_pData[m_Measures[i].nIndex2]).y;
		
		DrawMeasure(pDC, measureRect);
	}
}

void CXGraph::DrawMeasure (CDCEx* pDC, CRect measureRect)
{
	COLORREF crColor = RGB(255,0,0);
	COLORREF crColorGray = RGB(200, 200, 200);
	int      nArrowSize = 6;
	CString  cMarker;
	long	 nIndex1, nIndex2;

	UINT nOldBkColor = pDC->SetBkColor(m_crInnerColor);
	
	CQuickFont font("Arial", -11, FW_BOLD);
	CFontSelector fs(&font, pDC, false);

	if (measureRect.IsRectEmpty () && m_opOperation == opMeasure)
	{
		measureRect.SetRect(m_MouseDownPoint.x, m_MouseDownPoint.y, m_CurrentPoint.x, m_CurrentPoint.y);
	
		measureRect.left = max(measureRect.left, m_clInnerRect.left);
		measureRect.top = max(measureRect.top, m_clInnerRect.top);
		measureRect.right = min(measureRect.right, m_clInnerRect.right);
		measureRect.bottom = min(measureRect.bottom, m_clInnerRect.bottom);

		m_clCurrentMeasure = measureRect;
	}


	{
		CPenSelector ps(crColorGray, 1, pDC, PS_DOT);

		pDC->MoveTo (m_clInnerRect.left, measureRect.top);
		pDC->LineTo (m_clInnerRect.right, measureRect.top);

		pDC->MoveTo (measureRect.right, m_clInnerRect.top);
		pDC->LineTo (measureRect.right, m_clInnerRect.bottom);

	}	
	{
		CPenSelector ps(crColor, 1, pDC, PS_DOT);

		pDC->MoveTo (measureRect.left, measureRect.top);
		pDC->LineTo (measureRect.right, measureRect.top);
		pDC->LineTo (measureRect.right, measureRect.bottom);

		if (abs(measureRect.Width()) > nArrowSize )
			DrawLeftTriangle(CPoint(measureRect.left, measureRect.top - (nArrowSize/2)), nArrowSize, crColor, false, pDC);
		else
			DrawUpTriangle(CPoint(measureRect.right - (nArrowSize/2), measureRect.top + (nArrowSize/2)), nArrowSize, crColor, false, pDC);
		

		if (abs(measureRect.Height()) > nArrowSize )
			DrawDownTriangle(CPoint(measureRect.right - (nArrowSize/2), measureRect.bottom - nArrowSize), nArrowSize, crColor, false, pDC);
		else
			DrawRightTriangle(CPoint(measureRect.right - nArrowSize, measureRect.bottom - nArrowSize), nArrowSize, crColor, false, pDC);

	}
	

	double fSnappedX1 = m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetValueForPos (measureRect.left);
	double fSnappedX2 = m_XAxis[m_Data[m_nSnappedCurve1].m_nXAxis].GetValueForPos (measureRect.right);
	
	double fX = fSnappedX2 - fSnappedX1;

	if (m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetDateTime())
#ifndef _WIN32_WCE
		cMarker = COleDateTime(fX).Format(m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetDisplayFmt());
#else
		cMarker = COleDateTime(fX).Format();
#endif
	else
		cMarker.Format(m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetDisplayFmt(), fX);

		
	pDC->SetBkMode(TRANSPARENT);

	if (abs(measureRect.Width()) > pDC->GetTextExtent(cMarker).cx)
		pDC->DrawText(cMarker, measureRect, DT_CENTER | DT_SINGLELINE | DT_TOP | DT_NOCLIP);
		
	m_XAxis[m_Data[m_nSnappedCurve].m_nXAxis].GetIndexByXVal(nIndex1, fSnappedX1, m_nSnappedCurve);
	m_XAxis[m_Data[m_nSnappedCurve1].m_nXAxis].GetIndexByXVal(nIndex2, fSnappedX2, m_nSnappedCurve1);
		
	double fSnappedY1 = m_Data[m_nSnappedCurve].m_pData[nIndex1].fYVal;
	double fSnappedY2 = m_Data[m_nSnappedCurve1].m_pData[nIndex2].fYVal;

	double fY = fabs(fSnappedY2 - fSnappedY1);

	cMarker.Format(m_YAxis[m_Data[m_nSnappedCurve].m_nYAxis].GetDisplayFmt(), fY);
	cMarker += (" " + m_YAxis[m_Data[m_nSnappedCurve].m_nYAxis].GetLabel());

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -