ANALOGMETER.CPP
上传用户:shgx688
上传日期:2009-12-27
资源大小:855k
文件大小:15k
源码类别:

SNMP编程

开发平台:

MultiPlatform

  1. // AnalogMeter.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include <math.h>
  5. #include "AnalogMeter.h"
  6. #ifdef _DEBUG
  7. #define new DEBUG_NEW
  8. #undef THIS_FILE
  9. static char THIS_FILE[] = __FILE__;
  10. #endif
  11. #define ROUND(x) (int)((x) + 0.5 - (double)((x) < 0))
  12. /////////////////////////////////////////////////////////////////////////////
  13. // CAnalogMeter
  14. IMPLEMENT_DYNCREATE(CAnalogMeter, CCmdTarget)
  15. CAnalogMeter::CAnalogMeter()
  16. {
  17. m_dPI = 4.0*atan(1.0) ;  // for trig calculations
  18. // initialized rectangle locations, will be modified on first drawing
  19. m_rectDraw = CRect(0, 0, 0, 0) ;
  20. m_nRectWidth = 0;
  21. m_nRectHeight = 0;
  22. // draw the whole thing the first time 
  23. m_boolForceRedraw = TRUE ;
  24. m_dRadiansPerValue = 0.0 ;  // will be modified on first drawing
  25. // FALSE if we are printing
  26. m_boolUseBitmaps = TRUE ;
  27. // default titles, scaling and needle position
  28. m_dMinScale = -10.0 ;       
  29. m_dMaxScale = 10.0 ; 
  30. m_dNeedlePos = 0.0 ;
  31. m_strTitle.Format("Volts") ;
  32. // for numerical values
  33. m_nRangeDecimals = 1 ;
  34. m_nValueDecimals = 3 ;
  35. // grid color
  36. m_colorGrid = RGB(128, 128, 128) ;
  37. // current numerical value color
  38. m_colorValue = RGB(0, 0, 0) ;
  39. // needle color
  40. m_colorNeedle = RGB(255, 0, 0) ;
  41. // background color brushes (for erasing)
  42. m_brushErase.CreateSolidBrush(RGB(255, 255, 255)) ;
  43. m_penErase.CreatePen(PS_SOLID, 0, RGB(255, 255, 255)) ;
  44. }
  45. CAnalogMeter::~CAnalogMeter()
  46. {
  47. if(m_dcGrid.m_hDC)
  48. {
  49. m_dcGrid.SelectObject(m_pbitmapOldGrid) ;
  50. m_dcGrid.DeleteDC() ;
  51. }
  52. if(m_dcNeedle.m_hDC)
  53. {
  54. m_dcNeedle.SelectObject(m_pbitmapOldNeedle) ;
  55. m_dcNeedle.DeleteDC() ;
  56. }
  57. if(m_bitmapGrid.m_hObject)
  58. m_bitmapGrid.DeleteObject() ;
  59. if(m_bitmapNeedle.m_hObject)
  60. m_bitmapNeedle.DeleteObject() ;
  61. }
  62. BEGIN_MESSAGE_MAP(CAnalogMeter, CCmdTarget)
  63. //{{AFX_MSG_MAP(CAnalogMeter)
  64. // NOTE - the ClassWizard will add and remove mapping macros here.
  65. //}}AFX_MSG_MAP
  66. END_MESSAGE_MAP()
  67. /////////////////////////////////////////////////////////////////////////////
  68. // CAnalogMeter message handlers
  69. void CAnalogMeter::ShowMeter(CDC * pDC, CRect rectBorder)
  70. {
  71. // check for a new meter or a resize of the old one.
  72. // (if the rectangles have changed, then redraw from scratch).
  73. // If we are printing, always draw from scratch without bitmaps.
  74. if (m_rectOwner != rectBorder) 
  75. m_boolForceRedraw = TRUE ;
  76. if (m_boolForceRedraw || (pDC->IsPrinting()))
  77. {
  78. m_boolForceRedraw = FALSE ;
  79. // first store the rectangle for the owner
  80. // and determine the rectangle to draw to
  81. m_rectOwner = rectBorder ;
  82. if (pDC->IsPrinting())  
  83. {
  84. m_boolUseBitmaps = FALSE ;
  85. m_rectDraw = m_rectOwner ;  // draw directly to the owner
  86. }
  87. else  
  88. {
  89. m_boolUseBitmaps = TRUE ;
  90. m_rectDraw.left = 0 ;       // draw to a bitmap rectangle
  91. m_rectDraw.top = 0 ;
  92. m_rectDraw.right = rectBorder.Width() ;
  93. m_rectDraw.bottom = rectBorder.Height() ;
  94. }
  95. m_nRectWidth = m_rectDraw.Width() ;
  96. m_nRectHeight = m_rectDraw.Height() ;
  97. // if we already have a memory dc, destroy it 
  98. // (this occurs for a re-size of the meter)
  99. if (m_dcGrid.GetSafeHdc())
  100. {
  101. m_dcGrid.SelectObject(m_pbitmapOldGrid) ;
  102. m_dcGrid.DeleteDC() ;
  103. m_dcNeedle.SelectObject(m_pbitmapOldNeedle) ;
  104. m_dcNeedle.DeleteDC() ;
  105. m_bitmapGrid.DeleteObject() ;
  106. m_bitmapNeedle.DeleteObject() ;
  107. }
  108. if (m_boolUseBitmaps)  
  109. {
  110. // create a memory based dc for drawing the grid
  111. m_dcGrid.CreateCompatibleDC(pDC) ;
  112. m_bitmapGrid.CreateCompatibleBitmap(pDC, m_nRectWidth, m_nRectHeight) ;
  113. m_pbitmapOldGrid = m_dcGrid.SelectObject(&m_bitmapGrid) ;
  114. // create a memory based dc for drawing the needle
  115. m_dcNeedle.CreateCompatibleDC(pDC) ;
  116. m_bitmapNeedle.CreateCompatibleBitmap(pDC, m_nRectWidth, m_nRectHeight) ;
  117. m_pbitmapOldNeedle = m_dcNeedle.SelectObject(&m_bitmapNeedle) ;
  118. }
  119. else  // no bitmaps, draw to the destination
  120. {
  121. // use the destination dc for the grid
  122. m_dcGrid.m_hDC = pDC->m_hDC ;
  123. m_dcGrid.m_hAttribDC = pDC->m_hAttribDC ;
  124. // use the destination dc for the grid
  125. m_dcNeedle.m_hDC = pDC->m_hDC ;
  126. m_dcNeedle.m_hAttribDC = pDC->m_hAttribDC ;
  127. }
  128. // draw the grid in the to the "grid dc"
  129. DrawGrid () ;           
  130. // draw the needle in the "needle dc" 
  131. DrawNeedle () ;    
  132. }
  133. // display the new image, combining the needle with the grid
  134. if (m_boolUseBitmaps)
  135. ShowMeterImage(pDC);
  136. } // end ShowMeter
  137. void CAnalogMeter::ShowMeterImage(CDC *pDC)
  138. {
  139. CDC memDC ;
  140. CBitmap memBitmap ;
  141. CBitmap* oldBitmap ; // bitmap originally found in CMemDC
  142. // this function is only used when the needle and grid
  143. // have been drawn to bitmaps and they need to be combined
  144. // and sent to the destination
  145. if (!m_boolUseBitmaps)  
  146. return ;
  147. // to avoid flicker, establish a memory dc, draw to it 
  148. // and then BitBlt it to the destination "pDC"
  149. memDC.CreateCompatibleDC(pDC) ;
  150. memBitmap.CreateCompatibleBitmap(pDC, m_nRectWidth, m_nRectHeight) ;
  151. oldBitmap = (CBitmap *)memDC.SelectObject(&memBitmap) ;
  152. // make sure we have the bitmaps
  153. if (!m_dcGrid.GetSafeHdc())
  154. return ;
  155. if (!m_dcNeedle.GetSafeHdc())
  156. return ;
  157. if (memDC.GetSafeHdc() != NULL)
  158. {
  159. // draw the inverted grid
  160. memDC.BitBlt(0, 0, m_nRectWidth, m_nRectHeight, &m_dcGrid, 0, 0, NOTSRCCOPY) ;
  161. // merge the needle image with the grid
  162. memDC.BitBlt(0, 0, m_nRectWidth, m_nRectHeight, &m_dcNeedle, 0, 0, SRCINVERT) ;
  163. // copy the resulting bitmap to the destination
  164. pDC->BitBlt(m_rectOwner.left, m_rectOwner.top, m_nRectWidth, m_nRectHeight, 
  165.     &memDC, 0, 0, SRCCOPY) ;
  166. }
  167. memDC.SelectObject(oldBitmap) ;
  168. } // end ShowMeterImage
  169. //////////////////////////////////////////////////////
  170. void CAnalogMeter::UpdateNeedle(CDC *pDC, double dPos)
  171. {
  172. // do not support updates if we are not working with 
  173. // bitmaps images
  174. if (!m_boolUseBitmaps)
  175. return ;
  176. // must have created the grid if we are going to 
  177. // update the needle (the needle locations are 
  178. // calculateed based on the grid)
  179. if (!m_dcGrid.GetSafeHdc())
  180. return ;
  181. // if the needle hasn't changed, don't bother updating
  182. if (m_dNeedlePos == dPos)
  183. return ;
  184. // store the position in the member variable 
  185. // for availability elsewhere
  186. m_dNeedlePos = dPos ;
  187. // draw the new needle image
  188. DrawNeedle () ;
  189. // combine the needle with the grid and display the result
  190. ShowMeterImage (pDC) ;
  191. } // end UpdateNeedle
  192. //////////////////////////////////////////
  193. void CAnalogMeter::DrawGrid () 
  194. {
  195. int nFontHeight ;
  196. int nLeftBoundX, nRightBoundX,
  197. nLeftBoundY, nRightBoundY ;
  198. double dLimitAngleDeg = 45.0 ;  // this specifies the width of the pie slice
  199. double dX, dY, dTemp ;
  200. CPen penSolid, *oldPen ;
  201. CBrush brushSolid, *oldBrush ;
  202. CFont *oldFont ;
  203. CString tempString ;
  204. // draw the boundary rectangle and 
  205. // fill the entire area with the background color
  206. penSolid.CreatePen(PS_SOLID, 0, RGB(0, 0, 0)) ;
  207. oldPen = m_dcGrid.SelectObject(&penSolid) ;
  208. oldBrush = m_dcGrid.SelectObject(&m_brushErase) ;
  209. m_dcGrid.Rectangle(m_rectDraw) ;
  210. m_dcGrid.SelectObject(oldBrush) ;
  211. m_dcGrid.SelectObject(oldPen) ;
  212. // determine the angular scaling
  213. m_dLimitAngleRad = dLimitAngleDeg*m_dPI/180.0 ;
  214. m_dRadiansPerValue = (2.0*m_dLimitAngleRad)/(m_dMaxScale-m_dMinScale) ;
  215. // determine the center point
  216. m_nCXPix = (m_rectDraw.left+m_rectDraw.right)/2 ;
  217. m_nCYPix = m_rectDraw.bottom - m_nRectHeight/5 ;
  218. // determine the size and location of the meter "pie"
  219. m_nRadiusPix = m_nRectWidth*60/100 ;
  220. m_nHalfBaseWidth = m_nRadiusPix/40 ;
  221. dTemp = m_nCXPix - m_nRadiusPix*sin(m_dLimitAngleRad) ;
  222. m_nLeftLimitXPix = ROUND(dTemp) ;
  223. dTemp = m_nCYPix - m_nRadiusPix*cos(m_dLimitAngleRad) ;
  224. m_nLeftLimitYPix = ROUND(dTemp) ;
  225. dTemp = m_nCXPix + m_nRadiusPix*sin(m_dLimitAngleRad) ;
  226. m_nRightLimitXPix = ROUND(dTemp) ;
  227. m_nRightLimitYPix = m_nLeftLimitYPix ;
  228. // determine the placement of the current value text
  229. m_rectValue.left = m_rectDraw.left+1 ;
  230. m_rectValue.top = m_rectDraw.top+1 ;
  231. m_rectValue.right = m_rectDraw.right-1 ;
  232. if (m_boolUseBitmaps)
  233. m_rectValue.bottom = m_rectDraw.top+m_nCYPix - m_nRadiusPix - 1 ;
  234. else
  235. m_rectValue.bottom = m_nCYPix - m_nRadiusPix - 1 ;
  236. // determine the placement of the minimum value
  237. m_rectMinValue.left = m_rectDraw.left+1 ;
  238. m_rectMinValue.top = m_nCYPix - m_nRectHeight*3/20 ;
  239. m_rectMinValue.right = m_nLeftLimitXPix + 3*(m_nCXPix-m_nLeftLimitXPix)/4 ;
  240. m_rectMinValue.bottom = m_nCYPix + m_nRectHeight/20 ;
  241. // determine the placement of the maximum value
  242. m_rectMaxValue.right = m_rectDraw.right-1 ;
  243. m_rectMaxValue.top = m_nCYPix - m_nRectHeight*3/20 ;
  244. m_rectMaxValue.left = m_nRightLimitXPix - 3*(m_nRightLimitXPix-m_nCXPix)/4 ;
  245. m_rectMaxValue.bottom = m_nCYPix + m_nRectHeight/20 ;
  246. // create a font based on these sizes
  247. nFontHeight = m_rectMaxValue.Height()*4/5 ;  // modify the fraction to adjust
  248. m_fontValue.DeleteObject() ;
  249. m_fontValue.CreateFont (nFontHeight, 0, 0, 0, 400,
  250. FALSE, FALSE, 0, ANSI_CHARSET,
  251. OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  252. DEFAULT_QUALITY, DEFAULT_PITCH|FF_SWISS, "Arial") ;
  253. // grab the font and set the text color
  254. oldFont = m_dcGrid.SelectObject(&m_fontValue) ;
  255. m_dcGrid.SetTextColor(m_colorGrid) ;
  256. m_nTextBaseSpacing = m_rectMinValue.Height()/4 ;
  257. // show the title
  258. m_dcGrid.SetTextAlign(TA_CENTER|TA_BOTTOM) ;
  259. m_dcGrid.TextOut ((m_rectDraw.left+m_rectDraw.right)/2,
  260.                  m_rectDraw.bottom-1, m_strTitle) ;
  261. // show the max and min (limit) values
  262. m_dcGrid.SetTextAlign(TA_CENTER|TA_BASELINE) ;
  263. tempString.Format("%.*f", m_nRangeDecimals, m_dMinScale) ;
  264. m_dcGrid.TextOut ((m_rectMinValue.left+m_rectMinValue.right)/2, 
  265.                  m_rectMinValue.bottom-m_nTextBaseSpacing, tempString) ;
  266. tempString.Format("%.*f", m_nRangeDecimals, m_dMaxScale) ;
  267. m_dcGrid.TextOut ((m_rectMaxValue.left+m_rectMaxValue.right)/2, 
  268.                  m_rectMaxValue.bottom-m_rectMaxValue.Height()/4, tempString) ;
  269. // restore the font
  270. m_dcGrid.SelectObject(oldFont) ;
  271. // create the pen and brush for drawing
  272. penSolid.DeleteObject() ;
  273. penSolid.CreatePen(PS_SOLID, 0, m_colorGrid) ;
  274. // grab the pen
  275. oldPen = m_dcGrid.SelectObject(&penSolid) ;
  276. // determine the bounding rectangle for the pie slice
  277. // and draw it
  278. nLeftBoundX = m_nCXPix - m_nRadiusPix ;
  279. nRightBoundX = m_nCXPix + m_nRadiusPix ;
  280. nLeftBoundY = m_nCYPix - m_nRadiusPix ;
  281. nRightBoundY = m_nCYPix + m_nRadiusPix ;
  282. m_dcGrid.Pie(nLeftBoundX, nLeftBoundY, nRightBoundX+1, nRightBoundY+1,
  283.    m_nRightLimitXPix, m_nRightLimitYPix, m_nLeftLimitXPix, m_nLeftLimitYPix) ;
  284. // center tick mark
  285. m_dcGrid.MoveTo (m_nCXPix, m_nCYPix-m_nRadiusPix) ;
  286. m_dcGrid.LineTo (m_nCXPix, m_nCYPix-46*m_nRadiusPix/50) ;
  287. // left tick mark
  288. dX = m_nCXPix - m_nRadiusPix*sin(m_dLimitAngleRad/2) ;
  289. dY = m_nCYPix - m_nRadiusPix*cos(m_dLimitAngleRad/2) ;
  290. m_dcGrid.MoveTo(ROUND(dX), ROUND(dY)) ;
  291. dX = m_nCXPix - 46*m_nRadiusPix*sin(m_dLimitAngleRad/2)/50 ;
  292. dY = m_nCYPix - 46*m_nRadiusPix*cos(m_dLimitAngleRad/2)/50 ;
  293. m_dcGrid.LineTo(ROUND(dX), ROUND(dY)) ;
  294. // right tick mark
  295. dX = m_nCXPix + m_nRadiusPix*sin(m_dLimitAngleRad/2) ;
  296. dY = m_nCYPix - m_nRadiusPix*cos(m_dLimitAngleRad/2) ;
  297. m_dcGrid.MoveTo(ROUND(dX), ROUND(dY)) ;
  298. dX = m_nCXPix + 46*m_nRadiusPix*sin(m_dLimitAngleRad/2)/50 ;
  299. dY = m_nCYPix - 46*m_nRadiusPix*cos(m_dLimitAngleRad/2)/50 ;
  300. m_dcGrid.LineTo(ROUND(dX), ROUND(dY)) ;
  301. // draw circle at the bottom
  302. brushSolid.CreateSolidBrush (m_colorGrid) ;
  303. oldBrush = m_dcGrid.SelectObject(&brushSolid) ;
  304. m_dcGrid.Ellipse (m_nCXPix-m_nHalfBaseWidth, m_nCYPix-m_nHalfBaseWidth,
  305.                 m_nCXPix+m_nHalfBaseWidth+1, m_nCYPix+m_nHalfBaseWidth+1) ;
  306. m_dcGrid.SelectObject(oldBrush) ;
  307. m_dcGrid.SelectObject(oldPen) ;
  308. } // end DrawGrid
  309. ///////////////////////////////////
  310. void CAnalogMeter::DrawNeedle()
  311. {
  312. CPoint pPoints[6] ;
  313. CString tempString ;
  314. CFont *oldFont ;
  315. CPen *oldPen, solidPen ;
  316. CBrush *oldBrush, solidBrush ;
  317. double dAngleRad, dX, dY ;
  318. double dCosAngle, dSinAngle ;
  319. if (!m_dcNeedle.GetSafeHdc())
  320. return ;
  321. if (m_boolUseBitmaps)
  322. {
  323. oldPen = m_dcNeedle.SelectObject(&m_penErase) ;
  324. oldBrush = m_dcNeedle.SelectObject(&m_brushErase) ;
  325. m_dcNeedle.Rectangle(m_rectDraw) ;
  326. m_dcNeedle.SelectObject(oldBrush) ;
  327. m_dcNeedle.SelectObject(oldPen) ;
  328. }
  329. oldFont = m_dcNeedle.SelectObject(&m_fontValue) ;
  330. m_dcNeedle.SetTextAlign(TA_CENTER|TA_BASELINE) ;
  331. m_dcNeedle.SetTextColor(m_colorValue) ;
  332. tempString.Format("%.*f", m_nValueDecimals, m_dNeedlePos) ;
  333. m_dcNeedle.TextOut ((m_rectValue.right+m_rectValue.left)/2, 
  334.                  m_rectValue.bottom-m_nTextBaseSpacing, tempString) ;
  335. m_dcNeedle.SelectObject(oldFont) ;
  336. dAngleRad = (m_dNeedlePos - m_dMinScale)*m_dRadiansPerValue 
  337.         - m_dLimitAngleRad ;
  338. dAngleRad = max(dAngleRad, -m_dLimitAngleRad) ;
  339. dAngleRad = min(dAngleRad, m_dLimitAngleRad) ;
  340. dCosAngle = cos(dAngleRad) ;
  341. dSinAngle = sin(dAngleRad) ;
  342. // tip
  343. dX = m_nCXPix + m_nRadiusPix*dSinAngle ;
  344. dY = m_nCYPix - m_nRadiusPix*dCosAngle ;
  345. pPoints[0].x = ROUND(dX) ;
  346. pPoints[0].y = ROUND(dY) ;
  347. // left base
  348. dX = m_nCXPix - m_nHalfBaseWidth*dCosAngle ;
  349. dY = m_nCYPix - m_nHalfBaseWidth*dSinAngle ;
  350. pPoints[1].x = ROUND(dX) ;
  351. pPoints[1].y = ROUND(dY) ;
  352. // right base
  353. pPoints[2].x = m_nCXPix + (m_nCXPix-pPoints[1].x) ;
  354. pPoints[2].y = m_nCYPix + (m_nCYPix-pPoints[1].y) ;
  355. // tip
  356. pPoints[3].x = pPoints[0].x ;
  357. pPoints[3].y = pPoints[0].y ;
  358. solidPen.CreatePen (PS_SOLID, 0, m_colorNeedle) ;
  359. solidBrush.CreateSolidBrush (m_colorNeedle) ;
  360. oldPen = m_dcNeedle.SelectObject(&solidPen) ;
  361. oldBrush = m_dcNeedle.SelectObject(&solidBrush) ;
  362. // draw the needle pointer
  363. m_dcNeedle.Polygon(pPoints, 4) ;
  364. m_dcNeedle.SelectObject(oldPen) ;
  365. m_dcNeedle.SelectObject(oldBrush) ;
  366. // draw the circle at the bottom of the needle
  367. m_dcNeedle.Ellipse (m_nCXPix-m_nHalfBaseWidth, m_nCYPix-m_nHalfBaseWidth,
  368.                   m_nCXPix+m_nHalfBaseWidth+1, m_nCYPix+m_nHalfBaseWidth+1) ;
  369. m_dcNeedle.SelectObject(oldPen) ;
  370. m_dcNeedle.SelectObject(oldBrush) ;
  371. } // end DrawNeedle
  372. //////////////////////////////////////////////////////
  373. void CAnalogMeter::SetRange(double dMin, double dMax)
  374. {
  375. // Note, this only changes the plotting range. 
  376. // It does NOT force the re-drawing of the meter.
  377. // The owner must explicitly call the ShowMeter function
  378. // to get the new range values to display.
  379. m_dMinScale = dMin ;
  380. m_dMaxScale = dMax ;
  381. m_boolForceRedraw = TRUE ;
  382. }
  383. //////////////////////////////////////////////////////
  384. void CAnalogMeter::SetRangeDecimals(int nRangeDecimals)
  385. {
  386. m_nRangeDecimals = nRangeDecimals;
  387. m_boolForceRedraw = TRUE ;
  388. }
  389. //////////////////////////////////////////////////////
  390. void CAnalogMeter::SetValueDecimals(int nValueDecimals)
  391. {
  392. m_nValueDecimals = nValueDecimals;
  393. m_boolForceRedraw = TRUE ;
  394. }
  395. //////////////////////////////////////////////////////
  396. void CAnalogMeter::SetTitle(CString strTitle)
  397. {
  398. m_strTitle = strTitle ;
  399. m_boolForceRedraw = TRUE ;
  400. }