DashedView.cpp
上传用户:whjcdz88
上传日期:2011-09-07
资源大小:121k
文件大小:12k
源码类别:

图形图象

开发平台:

WINDOWS

  1. // DashedView.cpp : implementation of the CDashedView class
  2. //
  3. #include "stdafx.h"
  4. #include "Dashed.h"
  5. #include "DashedDoc.h"
  6. #include "DashedView.h"
  7. #include "Line.h"
  8. #include "bezier.h"
  9. #include <MAPIDBG.h>
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15. // timing functions
  16. #ifdef _DEBUG
  17. #define LGStartTiming(LGTime)
  18. LGTime = GetTickCount();
  19. GdiFlush();
  20. #define LGNoteTime(description, LGTime)
  21. GdiFlush();
  22. LGTime = GetTickCount() -LGTime;
  23. {CString OutputStr;
  24. DebugTraceLine();
  25. OutputStr.Format("%s(%i) : %s %drn", __FILE__,__LINE__, description , LGTime);
  26. TRACE0((LPCTSTR)OutputStr);}
  27. #else
  28. #define LGStartTiming(LGTime)
  29. #define LGNoteTime(description, LGTime)
  30. #endif
  31. /////////////////////////////////////////////////////////////////////////////
  32. // CDashedView
  33. IMPLEMENT_DYNCREATE(CDashedView, CView)
  34. BEGIN_MESSAGE_MAP(CDashedView, CView)
  35. //{{AFX_MSG_MAP(CDashedView)
  36. ON_WM_TIMER()
  37. ON_WM_KEYDOWN()
  38. ON_WM_ERASEBKGND()
  39. ON_WM_DESTROY()
  40. ON_WM_CREATE()
  41. ON_COMMAND(ID_INCREASEWIDTH, OnIncreasewidth)
  42. ON_COMMAND(ID_DECREASEWIDTH, OnDecreasewidth)
  43. ON_COMMAND(ID_ROTATE, OnRotate)
  44. ON_UPDATE_COMMAND_UI(ID_ROTATE, OnUpdateRotate)
  45. ON_COMMAND(ID_ROUND, OnRound)
  46. ON_UPDATE_COMMAND_UI(ID_ROUND, OnUpdateRound)
  47. //}}AFX_MSG_MAP
  48. END_MESSAGE_MAP()
  49. /////////////////////////////////////////////////////////////////////////////
  50. // CDashedView construction/destruction
  51. CDashedView::CDashedView()
  52. {
  53. m_PenSize = 5;
  54. m_Radians = 0.5;
  55. m_Rotate = true;
  56. m_Round = false;
  57. }
  58. CDashedView::~CDashedView()
  59. {
  60. }
  61. BOOL CDashedView::PreCreateWindow(CREATESTRUCT& cs)
  62. {
  63. return CView::PreCreateWindow(cs);
  64. }
  65. /////////////////////////////////////////////////////////////////////////////
  66. // CDashedView drawing
  67. void CDashedView::DrawPathOutline(const COLORREF& c, CDC& dc)
  68. {
  69. // make pen and stroke path
  70. LOGBRUSH lbrush;
  71. lbrush.lbStyle = BS_SOLID;
  72. lbrush.lbColor = c;
  73. CPen Pen(PS_GEOMETRIC | PS_SOLID | 
  74. (m_Round ? 
  75. (PS_JOIN_ROUND | PS_ENDCAP_ROUND):
  76. (PS_JOIN_MITER | PS_ENDCAP_FLAT) ) , m_PenSize, &lbrush);
  77. CPen *pOldPen = dc.SelectObject(&Pen);
  78. dc.StrokePath();
  79. dc.SelectObject(pOldPen);
  80. }
  81. void CDashedView::OnDraw(CDC* pClientDC)
  82. {
  83. #ifdef _DEBUG
  84. DWORD time;
  85. #endif
  86. CRect rect; GetClientRect(&rect);
  87. // Prepare memory DC to avoid flicker
  88. CDC memDC;
  89. CDC* pDC = &memDC;
  90. pDC->CreateCompatibleDC(pClientDC);
  91. CBitmap bmp;
  92. CRect clientRect(rect);
  93. bmp.CreateCompatibleBitmap(pClientDC, rect.Width(), rect.Height());
  94. CBitmap* pOldBmp = pDC->SelectObject(&bmp);
  95. pDC->FillSolidRect(&rect, PALETTERGB(255,255,255));
  96. // various line patterns
  97. unsigned Type1[8];
  98. unsigned Type2[8];
  99. unsigned Type3[8];
  100. unsigned Type4[8];
  101. int c1 = CDashLine::GetPattern(Type1, m_Round, m_PenSize, CDashLine::DL_DASHDOTDOT);
  102. int c2 = CDashLine::GetPattern(Type2, m_Round, m_PenSize, CDashLine::DL_DASHDOT);
  103. int c3 = CDashLine::GetPattern(Type3, m_Round, m_PenSize, CDashLine::DL_DASH);
  104. int c4 = CDashLine::GetPattern(Type4, m_Round, m_PenSize, CDashLine::DL_DOT);
  105. // save the current pen before using DashLine
  106. CPen *pOldPen = pDC->GetCurrentPen();
  107. LOGBRUSH lbrush;
  108. lbrush.lbStyle = BS_SOLID;
  109. CDashLine Line(*pDC, Type1, c1);
  110. RecreateEllipse();
  111. UpdateEllipseRgn(pDC);
  112. // Draw gradient ellipse interior
  113. {
  114. pDC->SelectClipRgn(&m_EllipseFillRgn);
  115. VerticalGradientFill(m_EllipseRect, *pDC);
  116. pDC->SelectClipRgn(0);
  117. }
  118. // Draw dotted ellipse border
  119. Line.SetPattern(Type1, c1);
  120. {
  121. LGStartTiming(time);
  122. // do drawing inside path for win95/8 compatibility
  123. pDC->BeginPath();
  124. Line.MoveTo(m_EllipsePts[0]);
  125. for (int i = 1; i < 12; i+=3)
  126. Line.BezierTo(m_EllipsePts+i);
  127. pDC->EndPath();
  128. LGNoteTime("Ellipse border calculate", time);
  129. // make pen and stroke path
  130. LGStartTiming(time);
  131. DrawPathOutline(PALETTERGB(128,255,128), *pDC);
  132. LGNoteTime("Ellipse border draw", time);
  133. }
  134. // Setup Dash dot dot line
  135. Line.SetPattern(Type1, c1);
  136. {
  137. // do drawing inside path for win95/8 compatibility
  138. pDC->BeginPath();
  139. Line.MoveTo(rect.TopLeft());
  140. Line.LineTo(rect.BottomRight());
  141. pDC->EndPath();
  142. // make pen and stroke path
  143. DrawPathOutline(PALETTERGB(0,0,255), *pDC);
  144. }
  145. //Setup Dash dot line
  146. Line.SetPattern(Type2, c2);
  147. {
  148. // do drawing inside path for win95/8 compatibility
  149. pDC->BeginPath();
  150. Line.MoveTo(rect.left, rect.bottom);
  151. Line.LineTo(rect.right, rect.top);
  152. pDC->EndPath();
  153. // make pen and stroke path
  154. DrawPathOutline(PALETTERGB(255,0,255), *pDC);
  155. }
  156. //Setup Dash line
  157. Line.SetPattern(Type3, c3);
  158. {
  159. // do drawing inside path for win95/8 compatibility
  160. pDC->BeginPath();
  161. Line.MoveTo(rect.left,  rect.Height() / 2);
  162. Line.LineTo(rect.right, rect.Height() / 2);
  163. pDC->EndPath();
  164. // make pen and stroke path
  165. DrawPathOutline(PALETTERGB(0,0,0), *pDC);
  166. }
  167. rect.DeflateRect(m_PenSize, m_PenSize);
  168. // Draw background to rectangle to simulate SetBkMode(OPAQUE) SetBkColor(xxx)
  169. {
  170. // do drawing inside path for win95/8 compatibility
  171. pDC->BeginPath();
  172. pDC->MoveTo(rect.left,  rect.bottom);
  173. pDC->LineTo(rect.BottomRight());
  174. pDC->LineTo(rect.right, rect.top);
  175. pDC->LineTo(rect.TopLeft());
  176. pDC->LineTo(rect.left,  rect.bottom);
  177. pDC->EndPath();
  178. // make pen and stroke path
  179. DrawPathOutline(PALETTERGB(0,255,255), *pDC);
  180. }
  181. //Setup dot line and draw rectangle
  182. Line.SetPattern(Type4, c4);
  183. {
  184. // do drawing inside path for win95/8 compatibility
  185. pDC->BeginPath();
  186. Line.MoveTo(rect.left,  rect.bottom);
  187. Line.LineTo(rect.BottomRight());
  188. Line.LineTo(rect.right, rect.top);
  189. Line.LineTo(rect.TopLeft());
  190. Line.LineTo(rect.left,  rect.bottom);
  191. pDC->EndPath();
  192. // make pen and stroke path
  193. DrawPathOutline(PALETTERGB(255,0,0), *pDC);
  194. }
  195. // bit from memdc to paintdc
  196. pClientDC->BitBlt(clientRect.left, clientRect.top, clientRect.Width(), clientRect.Height(), pDC, 0, 0, SRCCOPY);
  197. pDC->SelectObject(pOldBmp);
  198. }
  199. /////////////////////////////////////////////////////////////////////////////
  200. // CDashedView diagnostics
  201. #ifdef _DEBUG
  202. void CDashedView::AssertValid() const
  203. {
  204. CView::AssertValid();
  205. }
  206. void CDashedView::Dump(CDumpContext& dc) const
  207. {
  208. CView::Dump(dc);
  209. }
  210. CDashedDoc* CDashedView::GetDocument() // non-debug version is inline
  211. {
  212. ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDashedDoc)));
  213. return (CDashedDoc*)m_pDocument;
  214. }
  215. #endif //_DEBUG
  216. /////////////////////////////////////////////////////////////////////////////
  217. // CDashedView message handlers
  218. void CDashedView::OnTimer(UINT nIDEvent) 
  219. {
  220. CView::OnTimer(nIDEvent);
  221. if (nIDEvent == 1)
  222. RotateEllipse();
  223. }
  224. void CDashedView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  225. {
  226. CView::OnKeyDown(nChar, nRepCnt, nFlags);
  227. if (nChar == VK_DOWN)
  228. OnDecreasewidth();
  229. else if (nChar == VK_UP)
  230. OnIncreasewidth();
  231. else if (nChar == 'R')
  232. OnRound();
  233. else if (nChar == 'S')
  234. OnRotate();
  235. else if (nChar == VK_ADD)
  236. RotateEllipse();
  237. }
  238. BOOL CDashedView::OnEraseBkgnd(CDC* pDC) 
  239. {
  240. return 1;
  241. }
  242. void CDashedView::OnDestroy() 
  243. {
  244. CView::OnDestroy();
  245. KillTimer(1);
  246. }
  247. int CDashedView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  248. {
  249. if (CView::OnCreate(lpCreateStruct) == -1)
  250. return -1;
  251. // Add timer to rotate ellipse
  252. if (m_Rotate)
  253. SetTimer(1,500, 0);
  254. return 0;
  255. }
  256. void CDashedView::OnIncreasewidth() 
  257. {
  258. ++m_PenSize;
  259. Invalidate();
  260. }
  261. void CDashedView::OnDecreasewidth() 
  262. {
  263. if (m_PenSize >1)
  264. {
  265. --m_PenSize;
  266. Invalidate();
  267. }
  268. }
  269. void CDashedView::OnRotate()
  270. {
  271. m_Rotate = !m_Rotate;
  272. if (!m_Rotate)
  273. KillTimer(1);
  274. else
  275. SetTimer(1,500, 0);
  276. }
  277. void CDashedView::OnUpdateRotate(CCmdUI* pCmdUI) 
  278. {
  279. pCmdUI->SetCheck(m_Rotate);
  280. pCmdUI->Enable(true);
  281. }
  282. void CDashedView::OnRound() 
  283. {
  284. m_Round = !m_Round;
  285. Invalidate();
  286. }
  287. void CDashedView::OnUpdateRound(CCmdUI* pCmdUI) 
  288. {
  289. pCmdUI->SetCheck(m_Round);
  290. pCmdUI->Enable(true);
  291. }
  292. //***************************************************
  293. // RotateEllipse()
  294. //
  295. //***************************************************
  296. void CDashedView::RotateEllipse()
  297. {
  298. CDC* pDC = GetWindowDC( );
  299. InvalidateRgn(&m_EllipseRgn);
  300. m_Radians += 0.1;
  301. RecreateEllipse();
  302. UpdateEllipseRgn(pDC);
  303. InvalidateRgn(&m_EllipseRgn);
  304. ReleaseDC(pDC);
  305. }
  306. //***************************************************
  307. // UpdateEllipseRgn()
  308. //
  309. //***************************************************
  310. void CDashedView::UpdateEllipseRgn(CDC* pDC)
  311. {
  312. // Get fill area of ellipse
  313. pDC->BeginPath();
  314. pDC->PolyBezier(m_EllipsePts, 13);
  315. pDC->EndPath();
  316. m_EllipseFillRgn.DeleteObject();
  317. m_EllipseFillRgn.CreateFromPath(pDC);
  318. // Add border width area of ellipse
  319. pDC->BeginPath();
  320. pDC->PolyBezier(m_EllipsePts, 13);
  321. // if you do not close the figure, 
  322. // there will be a hole at the begin/end join
  323. pDC->CloseFigure();
  324. pDC->EndPath();
  325. LOGBRUSH lbrush;
  326. lbrush.lbStyle = BS_SOLID;
  327. CPen Pen(PS_GEOMETRIC, m_PenSize+4, &lbrush);
  328. CPen* pOldPen = pDC->SelectObject(&Pen);
  329. pDC->WidenPath();
  330. m_EllipseRgn.DeleteObject();
  331. m_EllipseRgn.CreateFromPath(pDC);
  332. pDC->SelectObject(pOldPen);
  333. m_EllipseRgn.CombineRgn(&m_EllipseRgn, &m_EllipseFillRgn, RGN_OR);
  334. }
  335. //***************************************************
  336. // RecreateEllipse()
  337. // Rotates Cnt number of points radians around c
  338. //
  339. //***************************************************
  340. void CDashedView::RecreateEllipse()
  341. {
  342. CRect rect; 
  343. GetClientRect(&rect);
  344. CPoint midPoint((rect.left +rect.right)/2, (rect.top + rect.bottom)/2);
  345. int size = min(rect.Height(), rect.Width()) * 3 / 8;
  346. CRect ellipseR(midPoint.x-size, midPoint.y-(size/2), midPoint.x+size, midPoint.y+(size/2));
  347. // Create an axis aligned ellipse dimensions  = ellipseR
  348. EllipseToBezier(ellipseR, m_EllipsePts);
  349. // Rotate ellipse points
  350. RotatePoints(m_Radians, midPoint, m_EllipsePts, 13);
  351. // Get bounding rect of ellipse
  352. // Note this does NOT include the pen width
  353. CPoint tl = m_EllipsePts[0];
  354. CPoint br = tl;
  355. for (int i = 1; i < 13; ++i)
  356. {
  357. if(m_EllipsePts[i].x < tl.x)
  358. tl.x = m_EllipsePts[i].x;
  359. else if (m_EllipsePts[i].x > br.x)
  360. br.x = m_EllipsePts[i].x;
  361. if(m_EllipsePts[i].y < tl.y)
  362. tl.y = m_EllipsePts[i].y;
  363. else if (m_EllipsePts[i].y > br.y)
  364. br.y = m_EllipsePts[i].y;
  365. }
  366. m_EllipseRect = CRect(tl, br);
  367. }
  368. /////////////////////////////////////////////////////////////////////////////
  369. // helper functions
  370. //
  371. //
  372. //***************************************************
  373. // Rotate
  374. // Rotates Cnt number of points radians around c
  375. //
  376. //***************************************************
  377. void RotatePoints(double radians, const CPoint& c, CPoint* vCtlPt, unsigned Cnt)
  378. {
  379. double sinAng = sin(radians);
  380. double cosAng = cos(radians);
  381. LDPoint constTerm( c.x - c.x * cosAng - c.y * sinAng,
  382. c.y + c.x * sinAng - c.y * cosAng);
  383. for (int i = Cnt-1; i>=0; --i)
  384. {
  385. vCtlPt[i] = (LDPoint( vCtlPt[i].x * cosAng + vCtlPt[i].y * sinAng,
  386.    -vCtlPt[i].x * sinAng + vCtlPt[i].y * cosAng) + constTerm).GetCPoint();
  387. }
  388. }
  389. //***************************************************
  390. // VerticalGradientFill
  391. // From Blue to red if dc is not paletted
  392. // Ad hoc slow code
  393. //***************************************************
  394. void VerticalGradientFill(const CRect& r, CDC& dc)
  395. {
  396. //don't draw gradient if paletted: really ugly
  397. if (dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
  398. {
  399. CBrush brush(HS_BDIAGONAL, RGB(255,0,0));
  400. dc.FillRect(&r, &brush);
  401. return;
  402. }
  403. // rect is a horizontal strip
  404. CRect rect = r;
  405. rect.bottom = rect.top+1;
  406. int nHeight = r.Height();
  407. for(int i = 0; i < nHeight; ++i) // Fill in strips
  408. {
  409. dc.FillSolidRect(&rect, PALETTERGB(MulDiv(i, 200, nHeight), 0, 255 -MulDiv(i, 200, nHeight)));
  410. rect.OffsetRect(0,1);
  411. }
  412. }