UCRadarChart.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. // ***********************************************************************
  2. // Assembly : HZH_Controls
  3. // Created : 2019-09-25
  4. //
  5. // ***********************************************************************
  6. // <copyright file="UCRadarChart.cs">
  7. // Copyright by Huang Zhenghui(黄正辉) All, QQ group:568015492 QQ:623128629 Email:623128629@qq.com
  8. // </copyright>
  9. //
  10. // Blog: https://www.cnblogs.com/bfyx
  11. // GitHub:https://github.com/kwwwvagaa/NetWinformControl
  12. // gitee:https://gitee.com/kwwwvagaa/net_winform_custom_control.git
  13. //
  14. // If you use this code, please keep this note.
  15. // ***********************************************************************
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Linq;
  19. using System.Text;
  20. using System.Windows.Forms;
  21. using System.Drawing;
  22. using System.Drawing.Drawing2D;
  23. using System.ComponentModel;
  24. namespace HZH_Controls.Controls
  25. {
  26. /// <summary>
  27. /// Class UCRadarChart.
  28. /// Implements the <see cref="System.Windows.Forms.UserControl" />
  29. /// </summary>
  30. /// <seealso cref="System.Windows.Forms.UserControl" />
  31. public class UCRadarChart : UserControl
  32. {
  33. /// <summary>
  34. /// The split count
  35. /// </summary>
  36. private int splitCount = 5;
  37. /// <summary>
  38. /// Gets or sets the split count.
  39. /// </summary>
  40. /// <value>The split count.</value>
  41. [Browsable(true)]
  42. [Category("自定义")]
  43. [Description("获取或设置分隔份数")]
  44. public int SplitCount
  45. {
  46. get { return splitCount; }
  47. set
  48. {
  49. splitCount = value;
  50. Invalidate();
  51. }
  52. }
  53. [Browsable(true)]
  54. [Category("自定义")]
  55. [Description("获取或设置是否使用圆代替连线进行分隔")]
  56. public bool UseRoundSplit { get; set; }
  57. /// <summary>
  58. /// The split odd color
  59. /// </summary>
  60. private Color splitOddColor = Color.White;
  61. /// <summary>
  62. /// 分隔奇数栏背景色
  63. /// </summary>
  64. /// <value>The color of the split odd.</value>
  65. [Browsable(true)]
  66. [Category("自定义")]
  67. [Description("获取或设置分隔奇数栏背景色")]
  68. public Color SplitOddColor
  69. {
  70. get { return splitOddColor; }
  71. set
  72. {
  73. splitOddColor = value;
  74. Invalidate();
  75. }
  76. }
  77. /// <summary>
  78. /// The split even color
  79. /// </summary>
  80. private Color splitEvenColor = Color.FromArgb(232, 232, 232);
  81. /// <summary>
  82. /// 分隔偶数栏背景色
  83. /// </summary>
  84. /// <value>The color of the split even.</value>
  85. [Browsable(true)]
  86. [Category("自定义")]
  87. [Description("获取或设置分隔偶数栏背景色")]
  88. public Color SplitEvenColor
  89. {
  90. get { return splitEvenColor; }
  91. set
  92. {
  93. splitEvenColor = value;
  94. Invalidate();
  95. }
  96. }
  97. /// <summary>
  98. /// The line color
  99. /// </summary>
  100. private Color lineColor = Color.FromArgb(153, 153, 153);
  101. /// <summary>
  102. /// Gets or sets the color of the line.
  103. /// </summary>
  104. /// <value>The color of the line.</value>
  105. [Browsable(true)]
  106. [Category("自定义")]
  107. [Description("获取或设置线条色")]
  108. public Color LineColor
  109. {
  110. get { return lineColor; }
  111. set
  112. {
  113. lineColor = value;
  114. Invalidate();
  115. }
  116. }
  117. /// <summary>
  118. /// The radar positions
  119. /// </summary>
  120. private RadarPosition[] radarPositions;
  121. /// <summary>
  122. /// 节点列表,至少需要3个
  123. /// </summary>
  124. /// <value>The radar positions.</value>
  125. [Browsable(true)]
  126. [Category("自定义")]
  127. [Description("获取或设置节点,至少需要3个")]
  128. public RadarPosition[] RadarPositions
  129. {
  130. get { return radarPositions; }
  131. set
  132. {
  133. radarPositions = value;
  134. Invalidate();
  135. }
  136. }
  137. /// <summary>
  138. /// The title
  139. /// </summary>
  140. private string title;
  141. /// <summary>
  142. /// 标题
  143. /// </summary>
  144. /// <value>The title.</value>
  145. [Browsable(true)]
  146. [Category("自定义")]
  147. [Description("获取或设置标题")]
  148. public string Title
  149. {
  150. get { return title; }
  151. set
  152. {
  153. title = value;
  154. ResetTitleSize();
  155. Invalidate();
  156. }
  157. }
  158. /// <summary>
  159. /// The title font
  160. /// </summary>
  161. private Font titleFont = new Font("微软雅黑", 12);
  162. /// <summary>
  163. /// Gets or sets the title font.
  164. /// </summary>
  165. /// <value>The title font.</value>
  166. [Browsable(true)]
  167. [Category("自定义")]
  168. [Description("获取或设置标题字体")]
  169. public Font TitleFont
  170. {
  171. get { return titleFont; }
  172. set
  173. {
  174. titleFont = value;
  175. ResetTitleSize();
  176. Invalidate();
  177. }
  178. }
  179. /// <summary>
  180. /// The title color
  181. /// </summary>
  182. private Color titleColor = Color.Black;
  183. /// <summary>
  184. /// Gets or sets the color of the title.
  185. /// </summary>
  186. /// <value>The color of the title.</value>
  187. [Browsable(true)]
  188. [Category("自定义")]
  189. [Description("获取或设置标题文本颜色")]
  190. public Color TitleColor
  191. {
  192. get { return titleColor; }
  193. set
  194. {
  195. titleColor = value;
  196. Invalidate();
  197. }
  198. }
  199. /// <summary>
  200. /// The lines
  201. /// </summary>
  202. private RadarLine[] lines;
  203. /// <summary>
  204. /// Gets or sets the lines.
  205. /// </summary>
  206. /// <value>The lines.</value>
  207. [Browsable(true)]
  208. [Category("自定义")]
  209. [Description("获取或设置值线条,Values长度必须与RadarPositions长度一致,否则无法显示")]
  210. public RadarLine[] Lines
  211. {
  212. get { return lines; }
  213. set
  214. {
  215. lines = value;
  216. Invalidate();
  217. }
  218. }
  219. /// <summary>
  220. /// The title size
  221. /// </summary>
  222. SizeF titleSize = SizeF.Empty;
  223. /// <summary>
  224. /// The m rect working
  225. /// </summary>
  226. private RectangleF m_rectWorking = Rectangle.Empty;
  227. /// <summary>
  228. /// The line value type size
  229. /// </summary>
  230. SizeF lineValueTypeSize = SizeF.Empty;
  231. /// <summary>
  232. /// The int line value COM count
  233. /// </summary>
  234. int intLineValueComCount = 0;
  235. /// <summary>
  236. /// The int line value row count
  237. /// </summary>
  238. int intLineValueRowCount = 0;
  239. /// <summary>
  240. /// Initializes a new instance of the <see cref="UCRadarChart"/> class.
  241. /// </summary>
  242. public UCRadarChart()
  243. {
  244. this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
  245. this.SetStyle(ControlStyles.DoubleBuffer, true);
  246. this.SetStyle(ControlStyles.ResizeRedraw, true);
  247. this.SetStyle(ControlStyles.Selectable, true);
  248. this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
  249. this.SetStyle(ControlStyles.UserPaint, true);
  250. this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
  251. this.SizeChanged += UCRadarChart_SizeChanged;
  252. Size = new System.Drawing.Size(150, 150);
  253. radarPositions = new RadarPosition[0];
  254. if (ControlHelper.IsDesignMode())
  255. {
  256. radarPositions = new RadarPosition[6];
  257. for (int i = 0; i < 6; i++)
  258. {
  259. radarPositions[i] = new RadarPosition
  260. {
  261. Text = "Item" + (i + 1),
  262. MaxValue = 100
  263. };
  264. }
  265. }
  266. lines = new RadarLine[0];
  267. if (ControlHelper.IsDesignMode())
  268. {
  269. Random r = new Random();
  270. lines = new RadarLine[2];
  271. for (int i = 0; i < 2; i++)
  272. {
  273. lines[i] = new RadarLine()
  274. {
  275. Name = "line" + i
  276. };
  277. lines[i].Values = new double[radarPositions.Length];
  278. for (int j = 0; j < radarPositions.Length; j++)
  279. {
  280. lines[i].Values[j] = r.Next(20, (int)radarPositions[j].MaxValue);
  281. }
  282. }
  283. }
  284. }
  285. /// <summary>
  286. /// Handles the SizeChanged event of the UCRadarChart control.
  287. /// </summary>
  288. /// <param name="sender">The source of the event.</param>
  289. /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
  290. void UCRadarChart_SizeChanged(object sender, EventArgs e)
  291. {
  292. ResetWorkingRect();
  293. }
  294. /// <summary>
  295. /// Resets the working rect.
  296. /// </summary>
  297. private void ResetWorkingRect()
  298. {
  299. if (lines != null && lines.Length > 0)
  300. {
  301. using (Graphics g = this.CreateGraphics())
  302. {
  303. foreach (var item in lines)
  304. {
  305. var s = g.MeasureString(item.Name, Font);
  306. if (s.Width > lineValueTypeSize.Width)
  307. lineValueTypeSize = s;
  308. }
  309. }
  310. }
  311. var lineTypePanelHeight = 0f;
  312. if (lineValueTypeSize != SizeF.Empty)
  313. {
  314. intLineValueComCount = (int)(this.Width / (lineValueTypeSize.Width + 25));
  315. intLineValueRowCount = lines.Length / intLineValueComCount;
  316. if (lines.Length % intLineValueComCount != 0)
  317. {
  318. intLineValueRowCount++;
  319. }
  320. lineTypePanelHeight = (lineValueTypeSize.Height + 10) * intLineValueRowCount;
  321. }
  322. var min = Math.Min(this.Width, this.Height - titleSize.Height - lineTypePanelHeight);
  323. var rectWorking = new RectangleF((this.Width - min) / 2 + 10, titleSize.Height + lineTypePanelHeight + 10, min - 10, min - 10);
  324. //处理文字
  325. float fltSplitAngle = 360F / radarPositions.Length;
  326. float fltRadiusWidth = rectWorking.Width / 2;
  327. float minX = rectWorking.Left;
  328. float maxX = rectWorking.Right;
  329. float minY = rectWorking.Top;
  330. float maxY = rectWorking.Bottom;
  331. using (Graphics g = this.CreateGraphics())
  332. {
  333. PointF centrePoint = new PointF(rectWorking.Left + rectWorking.Width / 2, rectWorking.Top + rectWorking.Height / 2);
  334. for (int i = 0; i < radarPositions.Length; i++)
  335. {
  336. float fltAngle = 270 + fltSplitAngle * i;
  337. fltAngle = fltAngle % 360;
  338. PointF _point = GetPointByAngle(centrePoint, fltAngle, fltRadiusWidth);
  339. var _txtSize = g.MeasureString(radarPositions[i].Text, Font);
  340. if (_point.X < centrePoint.X)//左
  341. {
  342. if (_point.X - _txtSize.Width < minX)
  343. {
  344. minX = rectWorking.Left + _txtSize.Width;
  345. }
  346. }
  347. else//右
  348. {
  349. if (_point.X + _txtSize.Width > maxX)
  350. {
  351. maxX = rectWorking.Right - _txtSize.Width;
  352. }
  353. }
  354. if (_point.Y < centrePoint.Y)//上
  355. {
  356. if (_point.Y - _txtSize.Height < minY)
  357. {
  358. minY = rectWorking.Top + _txtSize.Height;
  359. }
  360. }
  361. else//下
  362. {
  363. if (_point.Y + _txtSize.Height > maxY)
  364. {
  365. maxY = rectWorking.Bottom - _txtSize.Height;
  366. }
  367. }
  368. }
  369. }
  370. min = Math.Min(maxX - minX, maxY - minY);
  371. m_rectWorking = new RectangleF(minX, minY, min, min);
  372. }
  373. /// <summary>
  374. /// 引发 <see cref="E:System.Windows.Forms.Control.Paint" /> 事件。
  375. /// </summary>
  376. /// <param name="e">包含事件数据的 <see cref="T:System.Windows.Forms.PaintEventArgs" />。</param>
  377. protected override void OnPaint(PaintEventArgs e)
  378. {
  379. base.OnPaint(e);
  380. var g = e.Graphics;
  381. g.SetGDIHigh();
  382. if (!string.IsNullOrEmpty(title))
  383. {
  384. g.DrawString(title, titleFont, new SolidBrush(titleColor), new RectangleF(m_rectWorking.Left + (m_rectWorking.Width - titleSize.Width) / 2, m_rectWorking.Top - titleSize.Height - 10 - (intLineValueRowCount * (10 + lineValueTypeSize.Height)), titleSize.Width, titleSize.Height));
  385. }
  386. if (radarPositions.Length <= 2)
  387. {
  388. g.DrawString("至少需要3个顶点", Font, new SolidBrush(Color.Black), m_rectWorking, new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
  389. return;
  390. }
  391. var y = m_rectWorking.Top - 20 - (intLineValueRowCount * (10 + lineValueTypeSize.Height));
  392. for (int i = 0; i < intLineValueRowCount; i++)
  393. {
  394. var x = 0f;
  395. int intCount = intLineValueComCount;
  396. if (i == intLineValueRowCount - 1)
  397. {
  398. intCount = lines.Length % intLineValueComCount;
  399. }
  400. x = m_rectWorking.Left + (m_rectWorking.Width - intCount * (lineValueTypeSize.Width + 25)) / 2;
  401. for (int j = 0; j < intCount; j++)
  402. {
  403. g.FillRectangle(new SolidBrush(lines[i * intLineValueComCount + j].LineColor.Value), new RectangleF(x + (lineValueTypeSize.Width + 25) * j, y + lineValueTypeSize.Height * i, 15, lineValueTypeSize.Height));
  404. g.DrawString(lines[i * intLineValueComCount + j].Name, Font, new SolidBrush(lines[i * intLineValueComCount + j].LineColor.Value), new PointF(x + (lineValueTypeSize.Width + 25) * j + 20, y + lineValueTypeSize.Height * i));
  405. }
  406. }
  407. float fltSplitAngle = 360F / radarPositions.Length;
  408. float fltRadiusWidth = m_rectWorking.Width / 2;
  409. float fltSplitRadiusWidth = fltRadiusWidth / splitCount;
  410. PointF centrePoint = new PointF(m_rectWorking.Left + m_rectWorking.Width / 2, m_rectWorking.Top + m_rectWorking.Height / 2);
  411. List<List<PointF>> lstRingPoints = new List<List<PointF>>(splitCount);
  412. //分割点
  413. for (int i = 0; i < radarPositions.Length; i++)
  414. {
  415. float fltAngle = 270 + fltSplitAngle * i;
  416. fltAngle = fltAngle % 360;
  417. for (int j = 0; j < splitCount; j++)
  418. {
  419. if (i == 0)
  420. {
  421. lstRingPoints.Add(new List<PointF>());
  422. }
  423. PointF _point = GetPointByAngle(centrePoint, fltAngle, fltSplitRadiusWidth * (splitCount - j));
  424. lstRingPoints[j].Add(_point);
  425. }
  426. }
  427. if (UseRoundSplit)
  428. {
  429. for (int i = 0; i < splitCount; i++)
  430. {
  431. RectangleF rect = new RectangleF(centrePoint.X - fltSplitRadiusWidth * (splitCount - i), centrePoint.Y - fltSplitRadiusWidth * (splitCount - i), fltSplitRadiusWidth * (splitCount - i) * 2, fltSplitRadiusWidth * (splitCount - i) * 2);
  432. if (i % 2 == 0)
  433. {
  434. g.FillEllipse(new SolidBrush(splitOddColor), rect);
  435. }
  436. else
  437. {
  438. g.FillEllipse(new SolidBrush(splitEvenColor), rect);
  439. }
  440. g.DrawEllipse(new Pen(new SolidBrush(lineColor)), rect);
  441. }
  442. }
  443. else
  444. {
  445. //间隔颜色
  446. for (int i = 0; i < lstRingPoints.Count; i++)
  447. {
  448. var ring = lstRingPoints[i];
  449. GraphicsPath path = new GraphicsPath();
  450. path.AddLines(ring.ToArray());
  451. if ((lstRingPoints.Count - i) % 2 == 0)
  452. {
  453. g.FillPath(new SolidBrush(splitEvenColor), path);
  454. }
  455. else
  456. {
  457. g.FillPath(new SolidBrush(splitOddColor), path);
  458. }
  459. }
  460. //画环
  461. foreach (var ring in lstRingPoints)
  462. {
  463. ring.Add(ring[0]);
  464. g.DrawLines(new Pen(new SolidBrush(lineColor)), ring.ToArray());
  465. }
  466. }
  467. //分割线
  468. foreach (var item in lstRingPoints[0])
  469. {
  470. g.DrawLine(new Pen(new SolidBrush(lineColor)), centrePoint, item);
  471. }
  472. //值
  473. for (int i = 0; i < lines.Length; i++)
  474. {
  475. var line = lines[i];
  476. if (line.Values.Length != radarPositions.Length)//如果数据长度和节点长度不一致则不绘制
  477. continue;
  478. if (line.LineColor == null || line.LineColor == Color.Empty || line.LineColor == Color.Transparent)
  479. line.LineColor = ControlHelper.Colors[i + 13];
  480. List<PointF> ps = new List<PointF>();
  481. for (int j = 0; j < radarPositions.Length; j++)
  482. {
  483. float fltAngle = 270 + fltSplitAngle * j;
  484. fltAngle = fltAngle % 360;
  485. PointF _point = GetPointByAngle(centrePoint, fltAngle, fltRadiusWidth * (float)(line.Values[j] / radarPositions[i].MaxValue));
  486. ps.Add(_point);
  487. }
  488. ps.Add(ps[0]);
  489. if (line.FillColor != null && line.FillColor != Color.Empty && line.FillColor != Color.Transparent)
  490. {
  491. GraphicsPath path = new GraphicsPath();
  492. path.AddLines(ps.ToArray());
  493. g.FillPath(new SolidBrush(line.FillColor.Value), path);
  494. }
  495. g.DrawLines(new Pen(new SolidBrush(line.LineColor.Value), 2), ps.ToArray());
  496. for (int j = 0; j < radarPositions.Length; j++)
  497. {
  498. var item = ps[j];
  499. g.FillEllipse(new SolidBrush(Color.White), new RectangleF(item.X - 3, item.Y - 3, 6, 6));
  500. g.DrawEllipse(new Pen(new SolidBrush(line.LineColor.Value)), new RectangleF(item.X - 3, item.Y - 3, 6, 6));
  501. if (line.ShowValueText)
  502. {
  503. var valueSize = g.MeasureString(line.Values[j].ToString("0.##"), Font);
  504. g.DrawString(line.Values[j].ToString("0.##"), Font, new SolidBrush(line.LineColor.Value), new PointF(item.X - valueSize.Width / 2, item.Y - valueSize.Height - 5));
  505. }
  506. }
  507. }
  508. //文本
  509. for (int i = 0; i < radarPositions.Length; i++)
  510. {
  511. PointF point = lstRingPoints[0][i];
  512. var txtSize = g.MeasureString(radarPositions[i].Text, Font);
  513. if (point.X == centrePoint.X)
  514. {
  515. if (point.Y > centrePoint.Y)
  516. {
  517. g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - txtSize.Width / 2, point.Y + 10));
  518. }
  519. else
  520. {
  521. g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - txtSize.Width / 2, point.Y - 10 - txtSize.Height));
  522. }
  523. }
  524. else if (point.Y == centrePoint.Y)
  525. {
  526. if (point.X < centrePoint.X)
  527. g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - 10 - txtSize.Width, point.Y - txtSize.Height / 2));
  528. else
  529. g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X + 10, point.Y - txtSize.Height / 2));
  530. }
  531. else if (point.X < centrePoint.X)//左
  532. {
  533. if (point.Y < centrePoint.Y)//左上
  534. {
  535. g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - 10 - txtSize.Width, point.Y - 10 + txtSize.Height / 2));
  536. }
  537. else//左下
  538. {
  539. g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X - 10 - txtSize.Width, point.Y + 10 - txtSize.Height / 2));
  540. }
  541. }
  542. else
  543. {
  544. if (point.Y < centrePoint.Y)//右上
  545. {
  546. g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X + 10, point.Y - 10 + txtSize.Height / 2));
  547. }
  548. else//右下
  549. {
  550. g.DrawString(radarPositions[i].Text, Font, new SolidBrush(ForeColor), new PointF(point.X + 10, point.Y + 10 - txtSize.Height / 2));
  551. }
  552. }
  553. }
  554. }
  555. #region 根据中心点、角度、半径计算圆边坐标点 English:Calculating the coordinate points of circular edge according to the center point, angle and radius
  556. /// <summary>
  557. /// 功能描述:根据中心点、角度、半径计算圆边坐标点 English:Calculating the coordinate points of circular edge according to the center point, angle and radius
  558. /// 作  者:HZH
  559. /// 创建日期:2019-09-25 09:46:32
  560. /// 任务编号:POS
  561. /// </summary>
  562. /// <param name="centrePoint">centrePoint</param>
  563. /// <param name="fltAngle">fltAngle</param>
  564. /// <param name="fltRadiusWidth">fltRadiusWidth</param>
  565. /// <returns>返回值</returns>
  566. private PointF GetPointByAngle(PointF centrePoint, float fltAngle, float fltRadiusWidth)
  567. {
  568. PointF p = centrePoint;
  569. if (fltAngle == 0)
  570. {
  571. p.X += fltRadiusWidth;
  572. }
  573. else if (fltAngle == 90)
  574. {
  575. p.Y += fltRadiusWidth;
  576. }
  577. else if (fltAngle == 180)
  578. {
  579. p.X -= fltRadiusWidth;
  580. }
  581. else if (fltAngle == 270)
  582. {
  583. p.Y -= fltRadiusWidth;
  584. }
  585. else if (fltAngle > 0 && fltAngle < 90)
  586. {
  587. p.Y += (float)Math.Sin(Math.PI * (fltAngle / 180.00F)) * fltRadiusWidth;
  588. p.X += (float)Math.Cos(Math.PI * (fltAngle / 180.00F)) * fltRadiusWidth;
  589. }
  590. else if (fltAngle > 90 && fltAngle < 180)
  591. {
  592. p.Y += (float)Math.Sin(Math.PI * ((180 - fltAngle) / 180.00F)) * fltRadiusWidth;
  593. p.X -= (float)Math.Cos(Math.PI * ((180 - fltAngle) / 180.00F)) * fltRadiusWidth;
  594. }
  595. else if (fltAngle > 180 && fltAngle < 270)
  596. {
  597. p.Y -= (float)Math.Sin(Math.PI * ((fltAngle - 180) / 180.00F)) * fltRadiusWidth;
  598. p.X -= (float)Math.Cos(Math.PI * ((fltAngle - 180) / 180.00F)) * fltRadiusWidth;
  599. }
  600. else if (fltAngle > 270 && fltAngle < 360)
  601. {
  602. p.Y -= (float)Math.Sin(Math.PI * ((360 - fltAngle) / 180.00F)) * fltRadiusWidth;
  603. p.X += (float)Math.Cos(Math.PI * ((360 - fltAngle) / 180.00F)) * fltRadiusWidth;
  604. }
  605. return p;
  606. }
  607. #endregion
  608. /// <summary>
  609. /// Resets the size of the title.
  610. /// </summary>
  611. private void ResetTitleSize()
  612. {
  613. if (!string.IsNullOrEmpty(title))
  614. {
  615. using (Graphics g = this.CreateGraphics())
  616. {
  617. titleSize = g.MeasureString(title, titleFont);
  618. }
  619. }
  620. else
  621. {
  622. titleSize = SizeF.Empty;
  623. }
  624. titleSize.Height += 20;
  625. ResetWorkingRect();
  626. }
  627. }
  628. }