Helper.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Drawing.Drawing2D;
  5. using System.Linq;
  6. using System.Text;
  7. namespace FurnaceUI.Controls
  8. {
  9. /// <summary>
  10. /// 整个组件的代码辅助工具,提供了一个基础的类库方法
  11. /// </summary>
  12. public class Helper
  13. {
  14. /// <summary>
  15. /// 从一个矩形的图形中获取菱形的坐标数组
  16. /// </summary>
  17. /// <param name="rect">矩形</param>
  18. /// <returns>数组结果</returns>
  19. public static Point[] GetRhombusFromRectangle(Rectangle rect)
  20. {
  21. return new Point[]
  22. {
  23. new Point(rect.X, rect.Y + rect.Height / 2),
  24. new Point(rect.X + rect.Width / 2, rect.Y + rect.Height - 1),
  25. new Point(rect.X + rect.Width - 1, rect.Y + rect.Height / 2),
  26. new Point(rect.X + rect.Width / 2, rect.Y),
  27. new Point(rect.X, rect.Y + rect.Height / 2),
  28. };
  29. }
  30. /// <summary>
  31. /// 计算绘图时的相对偏移值
  32. /// </summary>
  33. /// <param name="max">0-100分的最大值,就是指准备绘制的最大值</param>
  34. /// <param name="min">0-100分的最小值,就是指准备绘制的最小值</param>
  35. /// <param name="height">实际绘图区域的高度</param>
  36. /// <param name="value">需要绘制数据的当前值</param>
  37. /// <returns>相对于0的位置,还需要增加上面的偏值</returns>
  38. public static float ComputePaintLocationY(int max, int min, int height, int value)
  39. {
  40. if ((max - min) == 0f)
  41. {
  42. return height;
  43. }
  44. else
  45. {
  46. return height - (value - min) * 1.0f / (max - min) * height;
  47. }
  48. }
  49. /// <summary>
  50. /// 计算绘图时的相对偏移值
  51. /// </summary>
  52. /// <param name="max">0-100分的最大值,就是指准备绘制的最大值</param>
  53. /// <param name="min">0-100分的最小值,就是指准备绘制的最小值</param>
  54. /// <param name="height">实际绘图区域的高度</param>
  55. /// <param name="value">需要绘制数据的当前值</param>
  56. /// <returns>相对于0的位置,还需要增加上面的偏值</returns>
  57. public static float ComputePaintLocationY(float max, float min, float height, float value)
  58. {
  59. if ((max - min) == 0f)
  60. {
  61. return height;
  62. }
  63. else
  64. {
  65. return height - (value - min) / (max - min) * height;
  66. }
  67. }
  68. /// <summary>
  69. /// 绘制坐标系中的刻度线
  70. /// </summary>
  71. /// <param name="g">绘图对象</param>
  72. /// <param name="penLine">画坐标轴的画笔</param>
  73. /// <param name="penDash"></param>
  74. /// <param name="font"></param>
  75. /// <param name="brush"></param>
  76. /// <param name="sf"></param>
  77. /// <param name="degree"></param>
  78. /// <param name="max"></param>
  79. /// <param name="min"></param>
  80. /// <param name="width"></param>
  81. /// <param name="height"></param>
  82. /// <param name="left"></param>
  83. /// <param name="right"></param>
  84. /// <param name="up"></param>
  85. /// <param name="down"></param>
  86. public static void PaintCoordinateDivide(
  87. Graphics g,
  88. Pen penLine,
  89. Pen penDash,
  90. Font font,
  91. Brush brush,
  92. StringFormat sf,
  93. int degree,
  94. int max,
  95. int min,
  96. int width,
  97. int height,
  98. int left = 60,
  99. int right = 8,
  100. int up = 8,
  101. int down = 8
  102. )
  103. {
  104. for (int i = 0; i <= degree; i++)
  105. {
  106. int value = (max - min) * i / degree + min;
  107. int location = (int)ComputePaintLocationY(max, min, (height - up - down), value) + up + 1;
  108. g.DrawLine(penLine, left - 1, location, left - 4, location);
  109. if (i != 0)
  110. {
  111. g.DrawLine(penDash, left, location, width - right, location);
  112. }
  113. g.DrawString(value.ToString(), font, brush, new Rectangle(-5, location - font.Height / 2, left, font.Height), sf);
  114. }
  115. }
  116. /// <summary>
  117. /// 根据指定的方向绘制一个箭头
  118. /// </summary>
  119. /// <param name="g"></param>
  120. /// <param name="brush"></param>
  121. /// <param name="point"></param>
  122. /// <param name="size"></param>
  123. /// <param name="direction"></param>
  124. public static void PaintTriangle(Graphics g, Brush brush, Point point, int size, GraphDirection direction)
  125. {
  126. Point[] points = new Point[4];
  127. if (direction == GraphDirection.Leftward)
  128. {
  129. points[0] = new Point(point.X, point.Y - size);
  130. points[1] = new Point(point.X, point.Y + size);
  131. points[2] = new Point(point.X - 2 * size, point.Y);
  132. }
  133. else if (direction == GraphDirection.Rightward)
  134. {
  135. points[0] = new Point(point.X, point.Y - size);
  136. points[1] = new Point(point.X, point.Y + size);
  137. points[2] = new Point(point.X + 2 * size, point.Y);
  138. }
  139. else if (direction == GraphDirection.Upward)
  140. {
  141. points[0] = new Point(point.X - size, point.Y);
  142. points[1] = new Point(point.X + size, point.Y);
  143. points[2] = new Point(point.X, point.Y - 2 * size);
  144. }
  145. else
  146. {
  147. points[0] = new Point(point.X - size, point.Y);
  148. points[1] = new Point(point.X + size, point.Y);
  149. points[2] = new Point(point.X, point.Y + 2 * size);
  150. }
  151. points[3] = points[0];
  152. g.FillPolygon(brush, points);
  153. }
  154. /// <summary>
  155. /// 根据指定的方向绘制一个箭头
  156. /// </summary>
  157. /// <param name="g"></param>
  158. /// <param name="brush"></param>
  159. /// <param name="point"></param>
  160. /// <param name="size"></param>
  161. /// <param name="direction"></param>
  162. public static void PaintTriangle(Graphics g, Brush brush, PointF point, int size, GraphDirection direction)
  163. {
  164. PointF[] points = new PointF[4];
  165. if (direction == GraphDirection.Leftward)
  166. {
  167. points[0] = new PointF(point.X, point.Y - size);
  168. points[1] = new PointF(point.X, point.Y + size);
  169. points[2] = new PointF(point.X - 2 * size, point.Y);
  170. }
  171. else if (direction == GraphDirection.Rightward)
  172. {
  173. points[0] = new PointF(point.X, point.Y - size);
  174. points[1] = new PointF(point.X, point.Y + size);
  175. points[2] = new PointF(point.X + 2 * size, point.Y);
  176. }
  177. else if (direction == GraphDirection.Upward)
  178. {
  179. points[0] = new PointF(point.X - size, point.Y);
  180. points[1] = new PointF(point.X + size, point.Y);
  181. points[2] = new PointF(point.X, point.Y - 2 * size);
  182. }
  183. else
  184. {
  185. points[0] = new PointF(point.X - size, point.Y);
  186. points[1] = new PointF(point.X + size, point.Y);
  187. points[2] = new PointF(point.X, point.Y + 2 * size);
  188. }
  189. points[3] = points[0];
  190. g.FillPolygon(brush, points);
  191. }
  192. /// <summary>
  193. /// 一个通用的数组新增个数方法,会自动判断越界情况,越界的情况下,会自动的截断或是填充 ->
  194. /// A common array of new methods, will automatically determine the cross-border situation, in the case of cross-border, will be automatically truncated or filled
  195. /// </summary>
  196. /// <typeparam name="T">数据类型</typeparam>
  197. /// <param name="array">原数据</param>
  198. /// <param name="data">等待新增的数据</param>
  199. /// <param name="max">原数据的最大值</param>
  200. public static void AddArrayData<T>(ref T[] array, T[] data, int max)
  201. {
  202. if (data == null) return; // 数据为空
  203. if (data.Length == 0) return; // 数据长度为空
  204. if (array.Length == max)
  205. {
  206. Array.Copy(array, data.Length, array, 0, array.Length - data.Length);
  207. Array.Copy(data, 0, array, array.Length - data.Length, data.Length);
  208. }
  209. else
  210. {
  211. if ((array.Length + data.Length) > max)
  212. {
  213. T[] tmp = new T[max];
  214. for (int i = 0; i < (max - data.Length); i++)
  215. {
  216. tmp[i] = array[i + (array.Length - max + data.Length)];
  217. }
  218. for (int i = 0; i < data.Length; i++)
  219. {
  220. tmp[tmp.Length - data.Length + i] = data[i];
  221. }
  222. // 更新数据
  223. array = tmp;
  224. }
  225. else
  226. {
  227. T[] tmp = new T[array.Length + data.Length];
  228. for (int i = 0; i < array.Length; i++)
  229. {
  230. tmp[i] = array[i];
  231. }
  232. for (int i = 0; i < data.Length; i++)
  233. {
  234. tmp[tmp.Length - data.Length + i] = data[i];
  235. }
  236. array = tmp;
  237. }
  238. }
  239. }
  240. /// <summary>
  241. /// 尺寸转换,计算旋转后的尺寸。
  242. /// </summary>
  243. /// <param name="size"></param>
  244. /// <param name="angle"></param>
  245. /// <returns></returns>
  246. public static SizeF ConvertSize(SizeF size, float angle)
  247. {
  248. Matrix matrix = new Matrix();
  249. matrix.Rotate(angle);
  250. // 旋转矩形四个顶点
  251. PointF[] pts = new PointF[4];
  252. pts[0].X = -size.Width / 2f;
  253. pts[0].Y = -size.Height / 2f;
  254. pts[1].X = -size.Width / 2f;
  255. pts[1].Y = size.Height / 2f;
  256. pts[2].X = size.Width / 2f;
  257. pts[2].Y = size.Height / 2f;
  258. pts[3].X = size.Width / 2f;
  259. pts[3].Y = -size.Height / 2f;
  260. matrix.TransformPoints(pts);
  261. // 求取四个顶点的包围盒
  262. float left = float.MaxValue;
  263. float right = float.MinValue;
  264. float top = float.MaxValue;
  265. float bottom = float.MinValue;
  266. foreach (PointF pt in pts)
  267. {
  268. // 求取并集
  269. if (pt.X < left)
  270. left = pt.X;
  271. if (pt.X > right)
  272. right = pt.X;
  273. if (pt.Y < top)
  274. top = pt.Y;
  275. if (pt.Y > bottom)
  276. bottom = pt.Y;
  277. }
  278. SizeF result = new SizeF(right - left, bottom - top);
  279. return result;
  280. }
  281. /// <summary>
  282. /// 绘制旋转文本
  283. /// </summary>
  284. /// <param name="g"></param>
  285. /// <param name="s"></param>
  286. /// <param name="font"></param>
  287. /// <param name="brush"></param>
  288. /// <param name="point"></param>
  289. /// <param name="format"></param>
  290. /// <param name="angle"></param>
  291. public static void DrawString(Graphics g, string s, Font font, Brush brush, PointF point, StringFormat format, float angle)
  292. {
  293. // Save the matrix
  294. Matrix mtxSave = g.Transform;
  295. Matrix mtxRotate = g.Transform;
  296. mtxRotate.RotateAt(angle, point);
  297. g.Transform = mtxRotate;
  298. g.DrawString(s, font, brush, point, format);
  299. // Reset the matrix
  300. g.Transform = mtxSave;
  301. }
  302. private static int GetPow(int digit)
  303. {
  304. int result = 1;
  305. for (int i = 0; i < digit; i++)
  306. {
  307. result *= 10;
  308. }
  309. return result;
  310. }
  311. /// <summary>
  312. /// 获得数据的上限值,这个上限值是自动计算的。
  313. /// </summary>
  314. /// <param name="values">数据值</param>
  315. /// <returns>数据值</returns>
  316. public static int CalculateMaxSectionFrom(int[] values)
  317. {
  318. int max = values.Max();
  319. if (max <= 5) return 5;
  320. if (max <= 10) return 10;
  321. int digit = max.ToString().Length - 2;
  322. int head = int.Parse(max.ToString().Substring(0, 2));
  323. if (head < 12) return 12 * GetPow(digit);
  324. if (head < 14) return 14 * GetPow(digit);
  325. if (head < 16) return 16 * GetPow(digit);
  326. if (head < 18) return 18 * GetPow(digit);
  327. if (head < 20) return 20 * GetPow(digit);
  328. if (head < 22) return 22 * GetPow(digit);
  329. if (head < 24) return 24 * GetPow(digit);
  330. if (head < 26) return 26 * GetPow(digit);
  331. if (head < 28) return 28 * GetPow(digit);
  332. if (head < 30) return 30 * GetPow(digit);
  333. if (head < 40) return 40 * GetPow(digit);
  334. if (head < 50) return 50 * GetPow(digit);
  335. if (head < 60) return 60 * GetPow(digit);
  336. if (head < 80) return 80 * GetPow(digit);
  337. return 100 * GetPow(digit);
  338. }
  339. /// <summary>
  340. /// 获取当前颜色更淡的颜色信息
  341. /// </summary>
  342. /// <param name="color">颜色信息</param>
  343. /// <returns>颜色</returns>
  344. public static Color GetColorLight(Color color)
  345. {
  346. return Color.FromArgb(color.R + (255 - color.R) * 40 / 100, color.G + (255 - color.G) * 40 / 100, color.B + (255 - color.B) * 40 / 100);
  347. }
  348. /// <summary>
  349. /// 获取当前颜色更淡的颜色信息
  350. /// </summary>
  351. /// <param name="color">颜色信息</param>
  352. /// <returns>颜色</returns>
  353. public static Color GetColorLightFive(Color color)
  354. {
  355. return Color.FromArgb(color.R + (255 - color.R) * 50 / 100, color.G + (255 - color.G) * 50 / 100, color.B + (255 - color.B) * 50 / 100);
  356. }
  357. #if NET45
  358. /// <summary>
  359. /// 获取当前颜色更淡的颜色信息
  360. /// </summary>
  361. /// <param name="color">颜色信息</param>
  362. /// <returns>颜色</returns>
  363. public static System.Windows.Media.Color GetColorLight( System.Windows.Media.Color color )
  364. {
  365. return System.Windows.Media.Color.FromRgb( (byte)(color.R + (255 - color.R) * 40 / 100), (byte)(color.G + (255 - color.G) * 40 / 100), (byte)(color.B + (255 - color.B) * 40 / 100) );
  366. }
  367. /// <summary>
  368. /// 获取当前颜色更淡的颜色信息
  369. /// </summary>
  370. /// <param name="color">颜色信息</param>
  371. /// <returns>颜色</returns>
  372. public static System.Windows.Media.Color GetColorLightFive( System.Windows.Media.Color color )
  373. {
  374. return System.Windows.Media.Color.FromRgb( (byte)(color.R + (255 - color.R) * 50 / 100), (byte)(color.G + (255 - color.G) * 50 / 100), (byte)(color.B + (255 - color.B) * 50 / 100) );
  375. }
  376. #endif
  377. /// <summary>
  378. /// 从字符串表示的点位信息里解析出真正的点位信息
  379. /// </summary>
  380. /// <param name="points">字符串的点位</param>
  381. /// <param name="soureWidth">原来的长度信息</param>
  382. /// <param name="sourceHeight">原来的高度信息</param>
  383. /// <param name="width">实际的宽度信息</param>
  384. /// <param name="height">实际的高度信息</param>
  385. /// <param name="dx">x偏移量信息</param>
  386. /// <param name="dy">y偏移量信息</param>
  387. /// <returns></returns>
  388. public static PointF[] GetPointsFrom(string points, float soureWidth, float sourceHeight, float width, float height, float dx = 0, float dy = 0)
  389. {
  390. string[] itemPoint = points.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  391. PointF[] ret = new PointF[itemPoint.Length];
  392. for (int i = 0; i < itemPoint.Length; i++)
  393. {
  394. int index = itemPoint[i].IndexOf(',');
  395. float x = Convert.ToSingle(itemPoint[i].Substring(0, index));
  396. float y = Convert.ToSingle(itemPoint[i].Substring(index + 1));
  397. ret[i] = new PointF(width * (x + dx) / soureWidth, height * (y + dy) / sourceHeight);
  398. }
  399. return ret;
  400. }
  401. }
  402. /// <summary>
  403. /// 图形的方向
  404. /// </summary>
  405. public enum GraphDirection
  406. {
  407. /// <summary>
  408. /// 向上
  409. /// </summary>
  410. Upward = 1,
  411. /// <summary>
  412. /// 向下
  413. /// </summary>
  414. Downward = 2,
  415. /// <summary>
  416. /// 向左
  417. /// </summary>
  418. Leftward = 3,
  419. /// <summary>
  420. /// 向右
  421. /// </summary>
  422. Rightward = 4,
  423. }
  424. /// <summary>
  425. /// 指示控件的样子
  426. /// </summary>
  427. public enum HslDirectionStyle
  428. {
  429. /// <summary>
  430. /// 控件是横向摆放的
  431. /// </summary>
  432. Horizontal = 1,
  433. /// <summary>
  434. /// 控件是纵向摆放的
  435. /// </summary>
  436. Vertical = 2
  437. }
  438. /// <summary>
  439. /// 系统的主题样式,将会改变一些控件的外观
  440. /// </summary>
  441. public enum HslThemeStyle
  442. {
  443. /// <summary>
  444. /// 浅色的主题
  445. /// </summary>
  446. Light = 1,
  447. /// <summary>
  448. /// 深色的主题
  449. /// </summary>
  450. Dark = 2,
  451. }
  452. /// <summary>
  453. /// 某些特殊图形的表现形式
  454. /// </summary>
  455. public enum HslRenderStyle
  456. {
  457. /// <summary>
  458. /// 椭圆
  459. /// </summary>
  460. Ellipse = 1,
  461. /// <summary>
  462. /// 矩形
  463. /// </summary>
  464. Rectangle = 2,
  465. /// <summary>
  466. /// 菱形
  467. /// </summary>
  468. Rhombus = 3
  469. }
  470. /// <summary>
  471. /// 包含整型和字符串描述的数据类型
  472. /// </summary>
  473. public struct Paintdata
  474. {
  475. /// <summary>
  476. /// 数量
  477. /// </summary>
  478. public int Count { get; set; }
  479. /// <summary>
  480. /// 描述
  481. /// </summary>
  482. public string Description { get; set; }
  483. }
  484. /// <summary>
  485. /// 计算的基础数据
  486. /// </summary>
  487. public class CenterPoint
  488. {
  489. /// <summary>
  490. /// 中心点的位置
  491. /// </summary>
  492. public Point Point { get; set; }
  493. /// <summary>
  494. /// 半径
  495. /// </summary>
  496. public int Radius { get; set; }
  497. /// <summary>
  498. /// 角度
  499. /// </summary>
  500. public double Angle { get; set; }
  501. }
  502. }