ANALOGMETER.CPP
上传用户:lvjun8202
上传日期:2013-04-30
资源大小:797k
文件大小:15k
- // AnalogMeter.cpp : implementation file
- //
- #include "stdafx.h"
- #include <math.h>
- #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 ;
- }