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

📄 graph.cpp

📁 EZ-USB 开发板完整资料
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		
		int nTickXLocation((int)(m_ptOrigin.x + ii * nSeriesSpace));

		ASSERT(m_nXAxisScale >= 10);

		if(ii%jj == 0) {
			pDc->MoveTo(nTickXLocation, m_ptOrigin.y - TICK_PIXELS);
			VERIFY(pDc->LineTo(nTickXLocation, m_ptOrigin.y + TICK_PIXELS));

			if(ii%kk == 0) {
				// Draw x-axis tick label.
				CString sTickLabel;
				CFileTime logFT = m_nXAxisStartFT.UTCToLocal();
				BYTE Minute = (BYTE)(((logFT.GetTime() + ii * CFileTime::Second) % CFileTime::Hour)/CFileTime::Minute);
				BYTE Second = (BYTE)(((logFT.GetTime() + ii * CFileTime::Second) % CFileTime::Minute)/CFileTime::Second);


				sTickLabel.Format("%.2d:%.2d", Minute, Second);

				CSize sizTickLabel(pDc->GetTextExtent(sTickLabel));

				VERIFY(pDc->TextOut(nTickXLocation - (sizTickLabel.cx / 2),
					m_ptOrigin.y + sizTickLabel.cy, sTickLabel));
			}
		}

	}

	

	VERIFY(pDc->SelectObject(pFontOld));
}

//
void CGraph::DrawSeriesBar(CDC* pDc)
{
	VALIDATE;
	ASSERT_VALID(pDc);

	// How much space does each series get (includes interseries space)?
	// We ignore series whose members are all zero.
	int nSeriesSpace(0);

	if (m_paLegend.GetSize()) {

		nSeriesSpace = (m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)) /
			GetNonZeroSeriesCount();
	}
	else {
		nSeriesSpace = m_nXAxisWidth / GetNonZeroSeriesCount();
	}

	// Determine width of bars.  Data points with a value of zero are assumed 
	// to be empty.  This is a bad assumption.
	int nBarWidth(nSeriesSpace / GetMaxNonZeroSeriesSize());

	if (1 < GetNonZeroSeriesCount()) {
		nBarWidth = (int) ((double) nBarWidth * INTERSERIES_PERCENT_USED);
	}

	// This is the width of the largest series (no interseries space).
	int nMaxSeriesPlotSize(GetMaxNonZeroSeriesSize() * nBarWidth);

	// Iterate the series.
	POSITION pos(m_olCGraphSeries.GetHeadPosition());
	int nSeries(0);

	while (pos) {
		
		CGraphSeries* pSeries = (CGraphSeries*)m_olCGraphSeries.GetNext(pos);
		ASSERT_VALID(pSeries);

		// Ignore unpopulated series.
		if (0 < pSeries->GetNonZeroElementCount()) {

			// Draw each bar; empty bars are not drawn.
			int nRunningLeft(m_ptOrigin.x + ((nSeries + 1) * nSeriesSpace) - 
				nMaxSeriesPlotSize);

			for (int nGroup = 0; nGroup < GetMaxSeriesSize(); ++nGroup) {

				if (pSeries->GetData(nGroup) > 0) {

					CRect rcBar;
					rcBar.left = nRunningLeft; 
					rcBar.top = m_ptOrigin.y - (m_nYAxisHeight *
						pSeries->GetData(nGroup)) / (GetMaxDataValue()-m_nYAxisShift);
					rcBar.right = rcBar.left + nBarWidth;
					rcBar.bottom = m_ptOrigin.y;

					//COLORREF crBar(m_dwaColors.GetAt(nGroup));
					COLORREF crBar(((PGRAPHICLEGEND)(m_paLegend.GetAt(nGroup)))->dwColor);
					CBrush br(crBar);
					CBrush* pBrushOld = pDc->SelectObject(&br);
					ASSERT_VALID(pBrushOld);

					VERIFY(pDc->Rectangle(rcBar));
					pDc->SelectObject(&pBrushOld);

					nRunningLeft += nBarWidth;
				}
			}

			++nSeries;
		}
	}
}

//
void CGraph::DrawSeriesLine(CDC* pDc) 
{
	VALIDATE;
	ASSERT_VALID(pDc);

	// Iterate the groups.
	for (int nGroup = 0; nGroup < GetMaxSeriesSize(); nGroup++) {

		// How much space does each series get (includes interseries space)?
		float nSeriesSpace(0);


		nSeriesSpace = (float)((float)(m_nXAxisWidth - m_rcLegend.Width() - (GAP_PIXELS * 2)) / (float)(m_nXAxisScale+1));

		int nBarWidth((int)nSeriesSpace / GetMaxSeriesSize());

		if (1 < m_olCGraphSeries.GetCount()) {
			nBarWidth = (int) ((double) nBarWidth * INTERSERIES_PERCENT_USED);
		}

		// This is the width of the largest series (no interseries space).
		int nMaxSeriesPlotSize(GetMaxSeriesSize() * nBarWidth);

		// Iterate the series.
		POSITION pos(m_olCGraphSeries.GetHeadPosition());
		bool firstSeries = true;	
		CPoint ptLastLoc(0,0);

		for (int nSeries = 0; nSeries < m_olCGraphSeries.GetCount(); ++nSeries) {

			CGraphSeries* pSeries = (CGraphSeries*)m_olCGraphSeries.GetNext(pos);
			ASSERT_VALID(pSeries);
			
			// Get x and y location of center of ellipse.
			CPoint ptLoc(0,0);
			
			CFileTime logFT = m_nXAxisStartFT.UTCToLocal();
			ptLoc.x = m_ptOrigin.x + 
				      (LONG)((_atoi64(pSeries->m_sLabel.Right(20)) - logFT.GetTime())*nSeriesSpace/CFileTime::Second);
			

			if (((int)pSeries->m_dwaValues.GetUpperBound() >= nGroup) && 
				(pSeries->m_dwaValues[nGroup]) && 
				(pSeries->GetData(nGroup) >= m_nYAxisShift))
			{
				double dLineHeight = 0;

				int nMaxValue;
				if (m_nMaxDataValueAllowed == INVALID_MAX_VALUE) {// no Max data value
					nMaxValue = (GetMaxDataValue()-m_nYAxisShift);
				} 
				else {
					nMaxValue = (m_nMaxDataValueAllowed-m_nYAxisShift);	
				}


				if (nMaxValue != 0)
					dLineHeight = ((pSeries->GetData(nGroup)-m_nYAxisShift) * (float)m_nYAxisHeight)/(float)nMaxValue;

				ptLoc.y = (int) ((double) m_ptOrigin.y - dLineHeight);
				
				// Build objects.
				_ASSERTE(nGroup <= m_paLegend.GetUpperBound());
				COLORREF crLine(((PGRAPHICLEGEND)(m_paLegend.GetAt(nGroup)))->dwColor);
				CBrush br(crLine);
				CBrush* pBrushOld = pDc->SelectObject(&br);
				ASSERT_VALID(pBrushOld);

				// Draw line back to last data member.
				if (!firstSeries) {
					CPen penLine(PS_SOLID, 1, crLine);
					CPen* pPenOld = pDc->SelectObject(&penLine);
					ASSERT_VALID(pPenOld);

					pDc->MoveTo(ptLastLoc.x + 2, ptLastLoc.y - 1);
					VERIFY(pDc->LineTo(ptLoc.x - 3, ptLoc.y - 1));
					VERIFY(pDc->SelectObject(pPenOld));
				}
				else firstSeries = false;

				// Now draw ellipse.
				CRect rcEllipse(ptLoc.x - 3, ptLoc.y - 3, ptLoc.x + 3, ptLoc.y + 3);
				VERIFY(pDc->Ellipse(rcEllipse));

				pDc->SelectObject(&pBrushOld);
				ptLastLoc = ptLoc;
			}
		}
	}
}

//
void CGraph::DrawSeriesPie(CDC* pDc) 
{
	VALIDATE;
	ASSERT_VALID(pDc);
	_ASSERTE(0 < GetNonZeroSeriesCount()  &&  "Div by zero");

	// Determine width of pie display area (pie and space).
	int nSeriesSpace(0);

	if (m_paLegend.GetSize()) {
		
		int nPieAndSpaceWidth((m_nXAxisWidth - m_rcLegend.Width() - 
			(GAP_PIXELS * 2)) / GetNonZeroSeriesCount());

		// Height is limiting factor.
		if (nPieAndSpaceWidth > m_nYAxisHeight - (GAP_PIXELS * 2)) {
			nSeriesSpace = (m_nYAxisHeight - (GAP_PIXELS * 2)) /
				GetNonZeroSeriesCount();
		}
		else {
			// Width is limiting factor.
			nSeriesSpace = nPieAndSpaceWidth;
		}
	}
	else {
		// No legend box.

		// Height is limiting factor.
		if (m_nXAxisWidth > m_nYAxisHeight) {
			nSeriesSpace = m_nYAxisHeight / GetNonZeroSeriesCount();
		}
		else {
			// Width is limiting factor.
			nSeriesSpace = m_nXAxisWidth / GetNonZeroSeriesCount();
		}
	}

	// Draw each pie.
	int nPie(0);
	int nRadius((int) (nSeriesSpace * INTERSERIES_PERCENT_USED / 2.0));
	POSITION pos(m_olCGraphSeries.GetHeadPosition());

	while (pos) {

		CGraphSeries* pSeries = (CGraphSeries*)m_olCGraphSeries.GetNext(pos);
		ASSERT_VALID(pSeries);

		// Don't leave a space for empty pies.
		if (0 < pSeries->GetNonZeroElementCount()) {

			// Locate this pie.
			CRect rcPie;
			rcPie.left = m_ptOrigin.x + GAP_PIXELS + (nSeriesSpace * nPie);
			rcPie.right = rcPie.left + (2 * nRadius);
			rcPie.top = (m_nYAxisHeight / 2) - nRadius;
			rcPie.bottom = (m_nYAxisHeight / 2) + nRadius;

			CPoint ptCenter((rcPie.left + rcPie.right) / 2,
				(rcPie.top + rcPie.bottom) / 2);

			// Draw series label.
			CSize sizPieLabel(pDc->GetTextExtent(pSeries->GetLabel()));
			
			VERIFY(pDc->TextOut((rcPie.left + nRadius) - (sizPieLabel.cx / 2),
			  ptCenter.y + nRadius + GAP_PIXELS, pSeries->GetLabel()));
			
			// How much do the wedges total to?
			double dPieTotal(pSeries->GetDataTotal());

			// Draw each wedge in this pie.
			CPoint ptStart(rcPie.left, ptCenter.y);
			double dRunningWedgeTotal(0.0);
			
			for (int nGroup = 0; nGroup < m_paLegend.GetSize(); ++nGroup) {

				// Ignore empty wedges.
				if (0 < pSeries->GetData(nGroup)) {

					// Get the degrees of this wedge.
					dRunningWedgeTotal += pSeries->GetData(nGroup);
					double dPercent(dRunningWedgeTotal * 100.0 / dPieTotal);
					int nDegrees((int) (360.0 * dPercent / 100.0));

					// Find the location of the wedge's endpoint.
					CPoint ptEnd(WedgeEndFromDegrees(nDegrees, &ptCenter, nRadius));

					// Special case: a wedge that takes up the whole pie would
					// otherwise be confused with an empty wedge.
					if (1 == pSeries->GetNonZeroElementCount()) {
						_ASSERTE(360 == nDegrees  &&  ptStart == ptEnd  &&  "This is the problem we're correcting");
						--ptEnd.y;
					}

					// If the wedge is of zero size, don't paint it!
					if (ptStart != ptEnd) {

						// Draw wedge.
						//COLORREF crWedge(m_dwaColors.GetAt(nGroup));
						COLORREF crWedge(((PGRAPHICLEGEND)(m_paLegend.GetAt(nGroup)))->dwColor);
						CBrush br(crWedge);
						CBrush* pBrushOld = pDc->SelectObject(&br);
						ASSERT_VALID(pBrushOld);
						VERIFY(pDc->Pie(rcPie, ptStart, ptEnd));

						// Create a region from the path we create.
						VERIFY(pDc->BeginPath());
						VERIFY(pDc->Pie(rcPie, ptStart, ptEnd));
						VERIFY(pDc->EndPath());
						CRgn* prgnWedge = new CRgn;
						VERIFY(prgnWedge->CreateFromPath(pDc));

						// Cleanup.
						pDc->SelectObject(pBrushOld);
						ptStart = ptEnd;
					}
				}
			}

			++nPie;
		}
	}
}

// Convert degrees to x and y coords.
CPoint CGraph::WedgeEndFromDegrees(int nDegrees, CPoint* ptCenter,
												int nRadius) 
{
	VALIDATE;

	CPoint pt;

	pt.x = (int) ((double) nRadius * cos((double) nDegrees / 360.0 * PI * 2.0));
	pt.x = ptCenter->x - pt.x;

	pt.y = (int) ((double) nRadius * sin((double) nDegrees / 360.0 * PI * 2.0));
	pt.y = ptCenter->y + pt.y;

	return pt;
}

// Spin The Message Loop: C++ version.  See "Advanced Windows Programming", 
// M. Heller, p. 153, and the MS TechNet CD, PSS ID Number: Q99999.
/* static */ UINT CGraph::SpinTheMessageLoop(bool bNoDrawing /* = false */ ,
															 bool bOnlyDrawing /* = false */ ,
															 UINT uiMsgAllowed /* = WM_NULL */ )
{
	MSG msg;
	::ZeroMemory(&msg, sizeof(msg));

	while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

		// Do painting only.
		if (bOnlyDrawing  &&  WM_PAINT == msg.message)  {
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);

			// Update user interface.
			AfxGetApp()->OnIdle(0);
		}
		// Do everything *but* painting.
		else if (bNoDrawing  &&  WM_PAINT == msg.message)  {
			break;
		}
		// Special handling for this message.
		else if (WM_QUIT == msg.message) {
			::PostQuitMessage((int)msg.wParam);
			break;
		}
		// Allow one message (like WM_LBUTTONDOWN).
		else if (uiMsgAllowed == msg.message
		  &&  ! AfxGetApp()->PreTranslateMessage(&msg)) {
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
			break;
		}
		// This is the general case.
		else if (! bOnlyDrawing  &&  ! AfxGetApp()->PreTranslateMessage(&msg)) {
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);

			// Update user interface, then free temporary objects.
			AfxGetApp()->OnIdle(0);
			AfxGetApp()->OnIdle(1);
		}
	}

	return msg.message;
}


/////////////////////////////////////////////////////////////////////////////
// Conversion routines: RGB to HLS (Red-Green-Blue to Hue-Luminosity-Saturation).
// See Microsoft KnowledgeBase article Q29240.

#define  HLSMAX   240		// H,L, and S vary over 0-HLSMAX
#define  RGBMAX   255		// R,G, and B vary over 0-RGBMAX
									// HLSMAX BEST IF DIVISIBLE BY 6
									// RGBMAX, HLSMAX must each fit in a byte (255).

#define  UNDEFINED  (HLSMAX * 2 / 3)		// Hue is undefined if Saturation is 0 
														// (grey-scale).  This value determines 
														// where the Hue scrollbar is initially 
														// set for achromatic colors.


// Convert HLS to RGB.
/* static */ COLORREF CGraph::HLStoRGB(WORD wH, WORD wL, WORD wS)
{
	_ASSERTE(0 <= wH  &&  240 >= wH  &&  "Illegal hue value");
	_ASSERTE(0 <= wL  &&  240 >= wL  &&  "Illegal lum value");
	_ASSERTE(0 <= wS  &&  240 >= wS  &&  "Illegal sat value");

	WORD wR(0);
	WORD wG(0);
	WORD wB(0);
	
	// Achromatic case.
	if (0 == wS) {
		wR = wG = wB = (wL * RGBMAX) / HLSMAX;

		if (UNDEFINED != wH) {
			_ASSERTE(! "ERROR");
		}
	}
	else {
		// Chromatic case.
		WORD Magic1(0);
		WORD Magic2(0);

		// Set up magic numbers.
		if (wL <= HLSMAX / 2) {
			Magic2 = (wL * (HLSMAX + wS) + (HLSMAX / 2)) / HLSMAX;
		}
		else {
			Magic2 = wL + wS - ((wL * wS) + (HLSMAX / 2)) / HLSMAX;
		}

		Magic1 = 2 * wL - Magic2;
		
		// Get RGB, change units from HLSMAX to RGBMAX.
		wR = (HueToRGB(Magic1, Magic2, wH + (HLSMAX / 3)) * RGBMAX + (HLSMAX / 2)) / HLSMAX;
		wG = (HueToRGB(Magic1, Magic2, wH)                * RGBMAX + (HLSMAX / 2)) / HLSMAX;
		wB = (HueToRGB(Magic1, Magic2, wH - (HLSMAX / 3)) * RGBMAX + (HLSMAX / 2)) / HLSMAX;
	}
	
	return RGB(wR,wG,wB);
}

// Utility routine for HLStoRGB.
/* static */ WORD CGraph::HueToRGB(WORD w1, WORD w2, WORD wH)
{
	// Range check: note values passed add/subtract thirds of range.
	if (wH < 0) {
		wH += HLSMAX;
	}

	if (wH > HLSMAX) {
		wH -= HLSMAX;
	}

	// Return r, g, or b value from this tridrant.
	if (wH < HLSMAX / 6) {
		return w1 + (((w2 - w1) * wH + (HLSMAX / 12)) / (HLSMAX / 6));
	}

	if (wH < HLSMAX / 2) {
		return w2;
	}

	if (wH < (HLSMAX * 2) / 3) {
		return w1 + (((w2 - w1) * (((HLSMAX * 2) / 3) - wH) + (HLSMAX / 12)) / (HLSMAX / 6));
	}
	else {
		return w1;
	}
}



⌨️ 快捷键说明

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