www.pudn.com > SNMP·¶ÀýÔ´´úÂë.zip > ANALOGMETER.CPP


// AnalogMeter.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include  
#include "AnalogMeter.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
#define ROUND(x) (int)((x) + 0.5 - (double)((x) < 0)) 
 
///////////////////////////////////////////////////////////////////////////// 
// CAnalogMeter 
 
IMPLEMENT_DYNCREATE(CAnalogMeter, CCmdTarget) 
 
CAnalogMeter::CAnalogMeter() 
{ 
	m_dPI = 4.0*atan(1.0) ;  // for trig calculations 
	 
	// initialized rectangle locations, will be modified on first drawing 
	m_rectDraw = CRect(0, 0, 0, 0) ; 
	m_nRectWidth = 0; 
	m_nRectHeight = 0; 
 
	// draw the whole thing the first time  
	m_boolForceRedraw = TRUE ; 
 
	m_dRadiansPerValue = 0.0 ;  // will be modified on first drawing 
 
	// FALSE if we are printing 
	m_boolUseBitmaps = TRUE ; 
 
	// default titles, scaling and needle position 
	m_dMinScale = -10.0 ;        
	m_dMaxScale = 10.0 ;  
	m_dNeedlePos = 0.0 ; 
	m_strTitle.Format("Volts") ; 
 
	// for numerical values 
	m_nRangeDecimals = 1 ; 
	m_nValueDecimals = 3 ; 
 
	// grid color 
	m_colorGrid = RGB(128, 128, 128) ; 
	// current numerical value color 
	m_colorValue = RGB(0, 0, 0) ; 
	// needle color 
	m_colorNeedle = RGB(255, 0, 0) ; 
 
	// background color brushes (for erasing) 
	m_brushErase.CreateSolidBrush(RGB(255, 255, 255)) ; 
	m_penErase.CreatePen(PS_SOLID, 0, RGB(255, 255, 255)) ; 
 
} 
 
CAnalogMeter::~CAnalogMeter() 
{ 
	if(m_dcGrid.m_hDC) 
	{ 
		m_dcGrid.SelectObject(m_pbitmapOldGrid) ; 
		m_dcGrid.DeleteDC() ; 
	} 
	if(m_dcNeedle.m_hDC) 
	{ 
		m_dcNeedle.SelectObject(m_pbitmapOldNeedle) ; 
		m_dcNeedle.DeleteDC() ; 
	} 
	if(m_bitmapGrid.m_hObject) 
		m_bitmapGrid.DeleteObject() ; 
	if(m_bitmapNeedle.m_hObject) 
		m_bitmapNeedle.DeleteObject() ; 
 
} 
 
 
BEGIN_MESSAGE_MAP(CAnalogMeter, CCmdTarget) 
	//{{AFX_MSG_MAP(CAnalogMeter) 
		// NOTE - the ClassWizard will add and remove mapping macros here. 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CAnalogMeter message handlers 
 
void CAnalogMeter::ShowMeter(CDC * pDC, CRect rectBorder) 
{ 
	// check for a new meter or a resize of the old one. 
	// (if the rectangles have changed, then redraw from scratch). 
	// If we are printing, always draw from scratch without bitmaps. 
	if (m_rectOwner != rectBorder)  
		m_boolForceRedraw = TRUE ; 
 
	if (m_boolForceRedraw || (pDC->IsPrinting())) 
	{ 
		m_boolForceRedraw = FALSE ; 
		// first store the rectangle for the owner 
		// and determine the rectangle to draw to 
		m_rectOwner = rectBorder ; 
		if (pDC->IsPrinting())   
		{ 
			m_boolUseBitmaps = FALSE ; 
			m_rectDraw = m_rectOwner ;  // draw directly to the owner 
		} 
		else   
		{ 
			m_boolUseBitmaps = TRUE ; 
			m_rectDraw.left = 0 ;       // draw to a bitmap rectangle 
			m_rectDraw.top = 0 ; 
			m_rectDraw.right = rectBorder.Width() ; 
			m_rectDraw.bottom = rectBorder.Height() ; 
		} 
		m_nRectWidth = m_rectDraw.Width() ; 
		m_nRectHeight = m_rectDraw.Height() ; 
 
		// if we already have a memory dc, destroy it  
		// (this occurs for a re-size of the meter) 
		if (m_dcGrid.GetSafeHdc()) 
		{ 
			m_dcGrid.SelectObject(m_pbitmapOldGrid) ; 
			m_dcGrid.DeleteDC() ; 
 
			m_dcNeedle.SelectObject(m_pbitmapOldNeedle) ; 
			m_dcNeedle.DeleteDC() ; 
 
			m_bitmapGrid.DeleteObject() ; 
			m_bitmapNeedle.DeleteObject() ; 
		} 
 
		if (m_boolUseBitmaps)   
		{ 
			// create a memory based dc for drawing the grid 
			m_dcGrid.CreateCompatibleDC(pDC) ; 
			m_bitmapGrid.CreateCompatibleBitmap(pDC, m_nRectWidth, m_nRectHeight) ; 
			m_pbitmapOldGrid = m_dcGrid.SelectObject(&m_bitmapGrid) ; 
 
			// create a memory based dc for drawing the needle 
			m_dcNeedle.CreateCompatibleDC(pDC) ; 
			m_bitmapNeedle.CreateCompatibleBitmap(pDC, m_nRectWidth, m_nRectHeight) ; 
			m_pbitmapOldNeedle = m_dcNeedle.SelectObject(&m_bitmapNeedle) ; 
 
		} 
		else  // no bitmaps, draw to the destination 
		{ 
			// use the destination dc for the grid 
			m_dcGrid.m_hDC = pDC->m_hDC ; 
			m_dcGrid.m_hAttribDC = pDC->m_hAttribDC ; 
 
			// use the destination dc for the grid 
			m_dcNeedle.m_hDC = pDC->m_hDC ; 
			m_dcNeedle.m_hAttribDC = pDC->m_hAttribDC ; 
		} 
 
		// draw the grid in the to the "grid dc" 
		DrawGrid () ;            
		// draw the needle in the "needle dc"  
		DrawNeedle () ;     
	} 
 
	// display the new image, combining the needle with the grid 
	if (m_boolUseBitmaps) 
		ShowMeterImage(pDC); 
 
} // end ShowMeter 
 
 
void CAnalogMeter::ShowMeterImage(CDC *pDC) 
{ 
	CDC memDC ; 
	CBitmap memBitmap ; 
	CBitmap* oldBitmap ; // bitmap originally found in CMemDC 
 
	// this function is only used when the needle and grid 
	// have been drawn to bitmaps and they need to be combined 
	// and sent to the destination 
	if (!m_boolUseBitmaps)   
		return ; 
 
	// to avoid flicker, establish a memory dc, draw to it  
	// and then BitBlt it to the destination "pDC" 
	memDC.CreateCompatibleDC(pDC) ; 
	memBitmap.CreateCompatibleBitmap(pDC, m_nRectWidth, m_nRectHeight) ; 
	oldBitmap = (CBitmap *)memDC.SelectObject(&memBitmap) ; 
 
	// make sure we have the bitmaps 
	if (!m_dcGrid.GetSafeHdc()) 
		return ; 
	if (!m_dcNeedle.GetSafeHdc()) 
		return ; 
 
	if (memDC.GetSafeHdc() != NULL) 
	{ 
		// draw the inverted grid 
		memDC.BitBlt(0, 0, m_nRectWidth, m_nRectHeight, &m_dcGrid, 0, 0, NOTSRCCOPY) ; 
		// merge the needle image with the grid 
		memDC.BitBlt(0, 0, m_nRectWidth, m_nRectHeight, &m_dcNeedle, 0, 0, SRCINVERT) ; 
		// copy the resulting bitmap to the destination 
		pDC->BitBlt(m_rectOwner.left, m_rectOwner.top, m_nRectWidth, m_nRectHeight,  
						    &memDC, 0, 0, SRCCOPY) ; 
	} 
 
	memDC.SelectObject(oldBitmap) ; 
 
} // end ShowMeterImage 
 
 
////////////////////////////////////////////////////// 
void CAnalogMeter::UpdateNeedle(CDC *pDC, double dPos) 
{ 
	// do not support updates if we are not working with  
	// bitmaps images 
	if (!m_boolUseBitmaps) 
		return ; 
 
	// must have created the grid if we are going to  
	// update the needle (the needle locations are  
	// calculateed based on the grid) 
	if (!m_dcGrid.GetSafeHdc()) 
		return ; 
 
	// if the needle hasn't changed, don't bother updating 
	if (m_dNeedlePos == dPos) 
		return ; 
 
	// store the position in the member variable  
	// for availability elsewhere 
	m_dNeedlePos = dPos ; 
 
	// draw the new needle image 
	DrawNeedle () ; 
 
	// combine the needle with the grid and display the result 
	ShowMeterImage (pDC) ; 
 
} // end UpdateNeedle 
 
////////////////////////////////////////// 
void CAnalogMeter::DrawGrid ()  
{ 
	int nFontHeight ; 
	int nLeftBoundX, nRightBoundX, 
			nLeftBoundY, nRightBoundY ; 
	double dLimitAngleDeg = 45.0 ;  // this specifies the width of the pie slice 
	double dX, dY, dTemp ; 
	CPen penSolid, *oldPen ; 
	CBrush brushSolid, *oldBrush ; 
	CFont *oldFont ; 
	CString tempString ; 
 
	// draw the boundary rectangle and  
	// fill the entire area with the background color 
	penSolid.CreatePen(PS_SOLID, 0, RGB(0, 0, 0)) ; 
	oldPen = m_dcGrid.SelectObject(&penSolid) ; 
	oldBrush = m_dcGrid.SelectObject(&m_brushErase) ; 
	m_dcGrid.Rectangle(m_rectDraw) ; 
	m_dcGrid.SelectObject(oldBrush) ; 
	m_dcGrid.SelectObject(oldPen) ; 
 
	// determine the angular scaling 
	m_dLimitAngleRad = dLimitAngleDeg*m_dPI/180.0 ; 
	m_dRadiansPerValue = (2.0*m_dLimitAngleRad)/(m_dMaxScale-m_dMinScale) ; 
 
	// determine the center point 
	m_nCXPix = (m_rectDraw.left+m_rectDraw.right)/2 ; 
	m_nCYPix = m_rectDraw.bottom - m_nRectHeight/5 ; 
	 
	// determine the size and location of the meter "pie" 
	m_nRadiusPix = m_nRectWidth*60/100 ; 
	m_nHalfBaseWidth = m_nRadiusPix/40 ; 
	dTemp = m_nCXPix - m_nRadiusPix*sin(m_dLimitAngleRad) ; 
	m_nLeftLimitXPix = ROUND(dTemp) ; 
	dTemp = m_nCYPix - m_nRadiusPix*cos(m_dLimitAngleRad) ; 
	m_nLeftLimitYPix = ROUND(dTemp) ; 
 
	dTemp = m_nCXPix + m_nRadiusPix*sin(m_dLimitAngleRad) ; 
	m_nRightLimitXPix = ROUND(dTemp) ; 
	m_nRightLimitYPix = m_nLeftLimitYPix ; 
 
	// determine the placement of the current value text 
	m_rectValue.left = m_rectDraw.left+1 ; 
	m_rectValue.top = m_rectDraw.top+1 ; 
	m_rectValue.right = m_rectDraw.right-1 ; 
	if (m_boolUseBitmaps) 
		m_rectValue.bottom = m_rectDraw.top+m_nCYPix - m_nRadiusPix - 1 ; 
	else 
		m_rectValue.bottom = m_nCYPix - m_nRadiusPix - 1 ; 
 
	// determine the placement of the minimum value 
	m_rectMinValue.left = m_rectDraw.left+1 ; 
	m_rectMinValue.top = m_nCYPix - m_nRectHeight*3/20 ; 
	m_rectMinValue.right = m_nLeftLimitXPix + 3*(m_nCXPix-m_nLeftLimitXPix)/4 ; 
	m_rectMinValue.bottom = m_nCYPix + m_nRectHeight/20 ; 
 
	// determine the placement of the maximum value 
	m_rectMaxValue.right = m_rectDraw.right-1 ; 
	m_rectMaxValue.top = m_nCYPix - m_nRectHeight*3/20 ; 
	m_rectMaxValue.left = m_nRightLimitXPix - 3*(m_nRightLimitXPix-m_nCXPix)/4 ; 
	m_rectMaxValue.bottom = m_nCYPix + m_nRectHeight/20 ; 
 
	// create a font based on these sizes 
	nFontHeight = m_rectMaxValue.Height()*4/5 ;  // modify the fraction to adjust 
	m_fontValue.DeleteObject() ; 
	m_fontValue.CreateFont (nFontHeight, 0, 0, 0, 400, 
													FALSE, FALSE, 0, ANSI_CHARSET, 
													OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, 
													DEFAULT_QUALITY, DEFAULT_PITCH|FF_SWISS, "Arial") ; 
	 
	// grab the font and set the text color 
	oldFont = m_dcGrid.SelectObject(&m_fontValue) ; 
	m_dcGrid.SetTextColor(m_colorGrid) ; 
	m_nTextBaseSpacing = m_rectMinValue.Height()/4 ; 
 
	// show the title 
	m_dcGrid.SetTextAlign(TA_CENTER|TA_BOTTOM) ; 
	m_dcGrid.TextOut ((m_rectDraw.left+m_rectDraw.right)/2, 
		                 m_rectDraw.bottom-1, m_strTitle) ; 
 
	// show the max and min (limit) values 
	m_dcGrid.SetTextAlign(TA_CENTER|TA_BASELINE) ; 
	tempString.Format("%.*f", m_nRangeDecimals, m_dMinScale) ; 
	m_dcGrid.TextOut ((m_rectMinValue.left+m_rectMinValue.right)/2,  
		                 m_rectMinValue.bottom-m_nTextBaseSpacing, tempString) ; 
	tempString.Format("%.*f", m_nRangeDecimals, m_dMaxScale) ; 
	m_dcGrid.TextOut ((m_rectMaxValue.left+m_rectMaxValue.right)/2,  
		                 m_rectMaxValue.bottom-m_rectMaxValue.Height()/4, tempString) ; 
 
	// restore the font 
	m_dcGrid.SelectObject(oldFont) ; 
 
	// create the pen and brush for drawing 
	penSolid.DeleteObject() ; 
	penSolid.CreatePen(PS_SOLID, 0, m_colorGrid) ; 
	// grab the pen 
	oldPen = m_dcGrid.SelectObject(&penSolid) ; 
	 
	// determine the bounding rectangle for the pie slice 
	// and draw it 
	nLeftBoundX = m_nCXPix - m_nRadiusPix ; 
	nRightBoundX = m_nCXPix + m_nRadiusPix ; 
	nLeftBoundY = m_nCYPix - m_nRadiusPix ; 
	nRightBoundY = m_nCYPix + m_nRadiusPix ; 
	m_dcGrid.Pie(nLeftBoundX, nLeftBoundY, nRightBoundX+1, nRightBoundY+1, 
						   m_nRightLimitXPix, m_nRightLimitYPix, m_nLeftLimitXPix, m_nLeftLimitYPix) ; 
 
	// center tick mark 
	m_dcGrid.MoveTo (m_nCXPix, m_nCYPix-m_nRadiusPix) ; 
	m_dcGrid.LineTo (m_nCXPix, m_nCYPix-46*m_nRadiusPix/50) ; 
 
	// left tick mark 
	dX = m_nCXPix - m_nRadiusPix*sin(m_dLimitAngleRad/2) ; 
	dY = m_nCYPix - m_nRadiusPix*cos(m_dLimitAngleRad/2) ; 
	m_dcGrid.MoveTo(ROUND(dX), ROUND(dY)) ; 
	dX = m_nCXPix - 46*m_nRadiusPix*sin(m_dLimitAngleRad/2)/50 ; 
	dY = m_nCYPix - 46*m_nRadiusPix*cos(m_dLimitAngleRad/2)/50 ; 
	m_dcGrid.LineTo(ROUND(dX), ROUND(dY)) ; 
 
	// right tick mark 
	dX = m_nCXPix + m_nRadiusPix*sin(m_dLimitAngleRad/2) ; 
	dY = m_nCYPix - m_nRadiusPix*cos(m_dLimitAngleRad/2) ; 
	m_dcGrid.MoveTo(ROUND(dX), ROUND(dY)) ; 
	dX = m_nCXPix + 46*m_nRadiusPix*sin(m_dLimitAngleRad/2)/50 ; 
	dY = m_nCYPix - 46*m_nRadiusPix*cos(m_dLimitAngleRad/2)/50 ; 
	m_dcGrid.LineTo(ROUND(dX), ROUND(dY)) ; 
 
 
	// draw circle at the bottom 
	brushSolid.CreateSolidBrush (m_colorGrid) ; 
	oldBrush = m_dcGrid.SelectObject(&brushSolid) ; 
	m_dcGrid.Ellipse (m_nCXPix-m_nHalfBaseWidth, m_nCYPix-m_nHalfBaseWidth, 
		                m_nCXPix+m_nHalfBaseWidth+1, m_nCYPix+m_nHalfBaseWidth+1) ; 
 
 
	m_dcGrid.SelectObject(oldBrush) ; 
	m_dcGrid.SelectObject(oldPen) ; 
 
} // end DrawGrid 
 
///////////////////////////////////		 
void CAnalogMeter::DrawNeedle() 
{ 
	CPoint pPoints[6] ; 
	CString tempString ; 
	CFont *oldFont ; 
	CPen *oldPen, solidPen ; 
	CBrush *oldBrush, solidBrush ; 
	double dAngleRad, dX, dY ; 
	double dCosAngle, dSinAngle ; 
 
	if (!m_dcNeedle.GetSafeHdc()) 
		return ; 
 
	if (m_boolUseBitmaps) 
	{ 
		oldPen = m_dcNeedle.SelectObject(&m_penErase) ; 
		oldBrush = m_dcNeedle.SelectObject(&m_brushErase) ; 
		m_dcNeedle.Rectangle(m_rectDraw) ; 
		m_dcNeedle.SelectObject(oldBrush) ; 
		m_dcNeedle.SelectObject(oldPen) ; 
	} 
 
	oldFont = m_dcNeedle.SelectObject(&m_fontValue) ; 
 
	m_dcNeedle.SetTextAlign(TA_CENTER|TA_BASELINE) ; 
	m_dcNeedle.SetTextColor(m_colorValue) ; 
	tempString.Format("%.*f", m_nValueDecimals, m_dNeedlePos) ; 
	m_dcNeedle.TextOut ((m_rectValue.right+m_rectValue.left)/2,  
			                 m_rectValue.bottom-m_nTextBaseSpacing, tempString) ; 
	m_dcNeedle.SelectObject(oldFont) ; 
 
 
	dAngleRad = (m_dNeedlePos - m_dMinScale)*m_dRadiansPerValue  
			        - m_dLimitAngleRad ; 
	dAngleRad = max(dAngleRad, -m_dLimitAngleRad) ; 
	dAngleRad = min(dAngleRad, m_dLimitAngleRad) ; 
	dCosAngle = cos(dAngleRad) ; 
	dSinAngle = sin(dAngleRad) ; 
 
	// tip 
	dX = m_nCXPix + m_nRadiusPix*dSinAngle ; 
	dY = m_nCYPix - m_nRadiusPix*dCosAngle ; 
	pPoints[0].x = ROUND(dX) ; 
	pPoints[0].y = ROUND(dY) ; 
 
	// left base 
	dX = m_nCXPix - m_nHalfBaseWidth*dCosAngle ; 
	dY = m_nCYPix - m_nHalfBaseWidth*dSinAngle ; 
	pPoints[1].x = ROUND(dX) ; 
	pPoints[1].y = ROUND(dY) ; 
 
	// right base 
	pPoints[2].x = m_nCXPix + (m_nCXPix-pPoints[1].x) ; 
	pPoints[2].y = m_nCYPix + (m_nCYPix-pPoints[1].y) ; 
 
	// tip 
	pPoints[3].x = pPoints[0].x ; 
	pPoints[3].y = pPoints[0].y ; 
 
	solidPen.CreatePen (PS_SOLID, 0, m_colorNeedle) ; 
	solidBrush.CreateSolidBrush (m_colorNeedle) ; 
	oldPen = m_dcNeedle.SelectObject(&solidPen) ; 
	oldBrush = m_dcNeedle.SelectObject(&solidBrush) ; 
 
	// draw the needle pointer 
	m_dcNeedle.Polygon(pPoints, 4) ; 
 
	m_dcNeedle.SelectObject(oldPen) ; 
	m_dcNeedle.SelectObject(oldBrush) ; 
 
	// draw the circle at the bottom of the needle 
	m_dcNeedle.Ellipse (m_nCXPix-m_nHalfBaseWidth, m_nCYPix-m_nHalfBaseWidth, 
		                  m_nCXPix+m_nHalfBaseWidth+1, m_nCYPix+m_nHalfBaseWidth+1) ; 
 
	m_dcNeedle.SelectObject(oldPen) ; 
	m_dcNeedle.SelectObject(oldBrush) ; 
 
} // end DrawNeedle 
 
////////////////////////////////////////////////////// 
void CAnalogMeter::SetRange(double dMin, double dMax) 
{ 
	// Note, this only changes the plotting range.  
	// It does NOT force the re-drawing of the meter. 
	// The owner must explicitly call the ShowMeter function 
	// to get the new range values to display. 
	m_dMinScale = dMin ; 
	m_dMaxScale = dMax ; 
	m_boolForceRedraw = TRUE ; 
 
} 
 
////////////////////////////////////////////////////// 
void CAnalogMeter::SetRangeDecimals(int nRangeDecimals) 
{ 
	m_nRangeDecimals = nRangeDecimals; 
	m_boolForceRedraw = TRUE ; 
 
} 
 
////////////////////////////////////////////////////// 
void CAnalogMeter::SetValueDecimals(int nValueDecimals) 
{ 
	m_nValueDecimals = nValueDecimals; 
	m_boolForceRedraw = TRUE ; 
 
} 
 
////////////////////////////////////////////////////// 
void CAnalogMeter::SetTitle(CString strTitle) 
{ 
	m_strTitle = strTitle ; 
	m_boolForceRedraw = TRUE ; 
 
}