Ruler.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. using Resources;
  2. using SmartCoalApplication.Base;
  3. using SmartCoalApplication.Base.Enum;
  4. using SmartCoalApplication.SystemLayer;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.ComponentModel;
  8. using System.Drawing;
  9. using System.Drawing.Drawing2D;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using System.Windows.Forms;
  14. namespace SmartCoalApplication.Core
  15. {
  16. /// <summary>
  17. /// 顶部和左侧的标尺控件
  18. /// </summary>
  19. public sealed class Ruler : UserControl
  20. {
  21. /// <summary>
  22. /// 默认单位,英寸
  23. /// </summary>
  24. private MeasurementUnit measurementUnit = MeasurementUnit.Inch;
  25. public MeasurementUnit MeasurementUnit
  26. {
  27. get
  28. {
  29. return measurementUnit;
  30. }
  31. set
  32. {
  33. if (value != measurementUnit)
  34. {
  35. measurementUnit = value;
  36. Invalidate();
  37. }
  38. }
  39. }
  40. /// <summary>
  41. /// 默认方向 水平
  42. /// </summary>
  43. private Orientation orientation = Orientation.Horizontal;
  44. [DefaultValue(Orientation.Horizontal)]
  45. public Orientation Orientation
  46. {
  47. get
  48. {
  49. return orientation;
  50. }
  51. set
  52. {
  53. if (orientation != value)
  54. {
  55. orientation = value;
  56. Invalidate();
  57. }
  58. }
  59. }
  60. /// <summary>
  61. /// 每英寸长度内的像素点数
  62. /// 默认写死的dpi,96没有实际意义
  63. /// 需要从标尺读取
  64. /// </summary>
  65. private double dpu = 96;
  66. [DefaultValue(96.0)]
  67. public double Dpu
  68. {
  69. get
  70. {
  71. return dpu;
  72. }
  73. set
  74. {
  75. if (value != dpu)
  76. {
  77. dpu = value;
  78. Invalidate();
  79. }
  80. }
  81. }
  82. /// <summary>
  83. /// 封装了缩放功能的结构体
  84. /// </summary>
  85. private ScaleFactor scaleFactor = ScaleFactor.OneToOne;
  86. [Browsable(false)]
  87. public ScaleFactor ScaleFactor
  88. {
  89. get
  90. {
  91. return scaleFactor;
  92. }
  93. set
  94. {
  95. if (scaleFactor != value)
  96. {
  97. scaleFactor = value;
  98. Invalidate();
  99. }
  100. }
  101. }
  102. private float offset = 0;
  103. [DefaultValue(0)]
  104. public float Offset
  105. {
  106. get
  107. {
  108. return offset;
  109. }
  110. set
  111. {
  112. if (offset != value)
  113. {
  114. offset = value;
  115. Invalidate();
  116. }
  117. }
  118. }
  119. private float rulerValue = 0.0f;
  120. [DefaultValue(0)]
  121. public float Value
  122. {
  123. get
  124. {
  125. return rulerValue;
  126. }
  127. set
  128. {
  129. if (this.rulerValue != value)
  130. {
  131. float oldStart = this.scaleFactor.ScaleScalar(this.rulerValue - offset) - 1;
  132. float oldEnd = this.scaleFactor.ScaleScalar(this.rulerValue + 1 - offset) + 1;
  133. RectangleF oldRect;
  134. if (this.orientation == Orientation.Horizontal)
  135. {
  136. oldRect = new RectangleF(oldStart, this.ClientRectangle.Top, oldEnd - oldStart, this.ClientRectangle.Height);
  137. }
  138. else // if (this.orientation == Orientation.Vertical)
  139. {
  140. oldRect = new RectangleF(this.ClientRectangle.Left, oldStart, this.ClientRectangle.Width, oldEnd - oldStart);
  141. }
  142. float newStart = this.scaleFactor.ScaleScalar(value - offset);
  143. float newEnd = this.scaleFactor.ScaleScalar(value + 1 - offset);
  144. RectangleF newRect;
  145. if (this.orientation == Orientation.Horizontal)
  146. {
  147. newRect = new RectangleF(newStart, this.ClientRectangle.Top, newEnd - newStart, this.ClientRectangle.Height);
  148. }
  149. else // if (this.orientation == Orientation.Vertical)
  150. {
  151. newRect = new RectangleF(this.ClientRectangle.Left, newStart, this.ClientRectangle.Width, newEnd - newStart);
  152. }
  153. this.rulerValue = value;
  154. Invalidate(Utility.RoundRectangle(oldRect));
  155. Invalidate(Utility.RoundRectangle(newRect));
  156. }
  157. }
  158. }
  159. private float highlightStart = 0.0f;
  160. public float HighlightStart
  161. {
  162. get
  163. {
  164. return this.highlightStart;
  165. }
  166. set
  167. {
  168. if (this.highlightStart != value)
  169. {
  170. this.highlightStart = value;
  171. Invalidate();
  172. }
  173. }
  174. }
  175. private float highlightLength = 0.0f;
  176. public float HighlightLength
  177. {
  178. get
  179. {
  180. return this.highlightLength;
  181. }
  182. set
  183. {
  184. if (this.highlightLength != value)
  185. {
  186. this.highlightLength = value;
  187. Invalidate();
  188. }
  189. }
  190. }
  191. private bool highlightEnabled = false;
  192. public bool HighlightEnabled
  193. {
  194. get
  195. {
  196. return this.highlightEnabled;
  197. }
  198. set
  199. {
  200. if (this.highlightEnabled != value)
  201. {
  202. this.highlightEnabled = value;
  203. Invalidate();
  204. }
  205. }
  206. }
  207. /// <summary>
  208. /// 构造方法
  209. /// </summary>
  210. public Ruler()
  211. {
  212. SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
  213. }
  214. protected override void OnPaint(PaintEventArgs e)
  215. {
  216. float valueStart = this.scaleFactor.ScaleScalar(this.rulerValue - offset);
  217. float valueEnd = this.scaleFactor.ScaleScalar(this.rulerValue + 1.0f - offset);
  218. float highlightStartPx = this.scaleFactor.ScaleScalar(this.highlightStart - offset);
  219. float highlightEndPx = this.scaleFactor.ScaleScalar(this.highlightStart + this.highlightLength - offset);
  220. RectangleF highlightRect;
  221. RectangleF valueRect;
  222. if (this.orientation == Orientation.Horizontal)
  223. {
  224. valueRect = new RectangleF(valueStart, this.ClientRectangle.Top, valueEnd - valueStart, this.ClientRectangle.Height);
  225. highlightRect = new RectangleF(highlightStartPx, this.ClientRectangle.Top, highlightEndPx - highlightStartPx, this.ClientRectangle.Height);
  226. }
  227. else // if (this.orientation == Orientation.Vertical)
  228. {
  229. valueRect = new RectangleF(this.ClientRectangle.Left, valueStart, this.ClientRectangle.Width, valueEnd - valueStart);
  230. highlightRect = new RectangleF(this.ClientRectangle.Left, highlightStartPx, this.ClientRectangle.Width, highlightEndPx - highlightStartPx);
  231. }
  232. if (!this.highlightEnabled)
  233. {
  234. highlightRect = RectangleF.Empty;
  235. }
  236. if (this.orientation == Orientation.Horizontal)
  237. {
  238. e.Graphics.DrawLine(
  239. SystemPens.WindowText,
  240. UI.ScaleWidth(15),
  241. ClientRectangle.Top,
  242. UI.ScaleWidth(15),
  243. ClientRectangle.Bottom);
  244. string abbStringName = "MeasurementUnit." + this.MeasurementUnit.ToString() + ".Abbreviation";
  245. string abbString = PdnResources.GetString(abbStringName);
  246. //e.Graphics.DrawString(abbString, Font, SystemBrushes.WindowText, UI.ScaleWidth(-2), 0);
  247. }
  248. Region clipRegion = new Region(highlightRect);
  249. clipRegion.Xor(valueRect);
  250. if (this.orientation == Orientation.Horizontal)
  251. {
  252. clipRegion.Exclude(new Rectangle(0, 0, UI.ScaleWidth(16), ClientRectangle.Height));
  253. }
  254. e.Graphics.SetClip(clipRegion, CombineMode.Replace);
  255. DrawRuler(e, true);
  256. clipRegion.Xor(this.ClientRectangle);
  257. if (this.orientation == Orientation.Horizontal)
  258. {
  259. clipRegion.Exclude(new Rectangle(0, 0, UI.ScaleWidth(16), ClientRectangle.Height - 1));
  260. }
  261. e.Graphics.SetClip(clipRegion, CombineMode.Replace);
  262. DrawRuler(e, false);
  263. clipRegion.Dispose();
  264. }
  265. private static readonly float[] majorDivisors =
  266. new float[]
  267. {
  268. 10.0f,
  269. 10.0f,
  270. 10.0f
  271. };
  272. private int[] GetSubdivs(MeasurementUnit unit)
  273. {
  274. switch (unit)
  275. {
  276. case MeasurementUnit.Inch:
  277. {
  278. return new int[] { 2 };
  279. }
  280. case MeasurementUnit.Centimeter:
  281. {
  282. return new int[] { 2 };
  283. }
  284. case MeasurementUnit.Millimeter:
  285. {
  286. return new int[] { 2 };
  287. }
  288. case MeasurementUnit.Micron:
  289. {
  290. return new int[] { 2 };
  291. }
  292. case MeasurementUnit.Nano:
  293. {
  294. return new int[] { 2 };
  295. }
  296. default:
  297. {
  298. return null;
  299. }
  300. }
  301. }
  302. /// <summary>
  303. /// 分割x轴
  304. /// </summary>
  305. /// <param name="g"></param>
  306. /// <param name="pen"></param>
  307. /// <param name="x"></param>
  308. /// <param name="delta"></param>
  309. /// <param name="index"></param>
  310. /// <param name="y"></param>
  311. /// <param name="height"></param>
  312. /// <param name="subdivs"></param>
  313. private void SubdivideX(
  314. Graphics g,
  315. Pen pen,
  316. float x,
  317. float delta,
  318. int index,
  319. float y,
  320. float height,
  321. int[] subdivs)
  322. {
  323. g.DrawLine(pen, x, y, x, y + height);
  324. if (index > 10)
  325. {
  326. return;
  327. }
  328. float div;
  329. if (subdivs != null && index >= 0)
  330. {
  331. div = subdivs[index % subdivs.Length];
  332. }
  333. else if (index < 0)
  334. {
  335. div = majorDivisors[(-index - 1) % majorDivisors.Length];
  336. }
  337. else
  338. {
  339. return;
  340. }
  341. for (int i = 0; i < div; i++)
  342. {
  343. if ((delta / div) > 3.5)
  344. {
  345. SubdivideX(g, pen, x + delta * i / div, delta / div, index + 1, y, height / div + 0.5f, subdivs);
  346. }
  347. }
  348. }
  349. /// <summary>
  350. /// 分割y轴
  351. /// </summary>
  352. /// <param name="g"></param>
  353. /// <param name="pen"></param>
  354. /// <param name="y"></param>
  355. /// <param name="delta"></param>
  356. /// <param name="index"></param>
  357. /// <param name="x"></param>
  358. /// <param name="width"></param>
  359. /// <param name="subdivs"></param>
  360. private void SubdivideY(
  361. Graphics g,
  362. Pen pen,
  363. float y,
  364. float delta,
  365. int index,
  366. float x,
  367. float width,
  368. int[] subdivs)
  369. {
  370. g.DrawLine(pen, x, y, x + width, y);
  371. if (index > 10)
  372. {
  373. return;
  374. }
  375. float div;
  376. if (subdivs != null && index >= 0)
  377. {
  378. div = subdivs[index % subdivs.Length];
  379. }
  380. else if (index < 0)
  381. {
  382. div = majorDivisors[(-index - 1) % majorDivisors.Length];
  383. }
  384. else
  385. {
  386. return;
  387. }
  388. for (int i = 0; i < div; i++)
  389. {
  390. if ((delta / div) > 3.5)
  391. {
  392. SubdivideY(g, pen, y + delta * i / div, delta / div, index + 1, x, width / div + 0.5f, subdivs);
  393. }
  394. }
  395. }
  396. /// <summary>
  397. /// 绘制标尺
  398. /// </summary>
  399. /// <param name="e"></param>
  400. /// <param name="highlighted"></param>
  401. private void DrawRuler(PaintEventArgs e, bool highlighted)
  402. {
  403. Pen pen;
  404. Brush cursorBrush;
  405. Brush textBrush;
  406. StringFormat textFormat = new StringFormat();
  407. int maxPixel;
  408. Color cursorColor;
  409. /**
  410. if (highlighted)
  411. {
  412. e.Graphics.Clear(SystemColors.Highlight);
  413. pen = SystemPens.HighlightText;
  414. textBrush = SystemBrushes.HighlightText;
  415. cursorColor = SystemColors.Window;
  416. }
  417. else
  418. {
  419. e.Graphics.Clear(SystemColors.Window);
  420. pen = SystemPens.WindowText;
  421. textBrush = SystemBrushes.WindowText;
  422. cursorColor = SystemColors.Highlight;
  423. }**/
  424. pen = SystemPens.WindowText;
  425. textBrush = SystemBrushes.WindowText;
  426. cursorColor = SystemColors.Highlight;
  427. cursorColor = Color.FromArgb(128, cursorColor);
  428. cursorBrush = new SolidBrush(cursorColor);
  429. if (orientation == Orientation.Horizontal)
  430. {
  431. maxPixel = ScaleFactor.UnscaleScalar(ClientRectangle.Width);
  432. textFormat.Alignment = StringAlignment.Near;
  433. textFormat.LineAlignment = StringAlignment.Far;
  434. }
  435. else // if (orientation == Orientation.Vertical)
  436. {
  437. maxPixel = ScaleFactor.UnscaleScalar(ClientRectangle.Height);
  438. textFormat.Alignment = StringAlignment.Near;
  439. textFormat.LineAlignment = StringAlignment.Near;
  440. textFormat.FormatFlags |= StringFormatFlags.DirectionVertical;
  441. }
  442. float majorSkip = 1f;
  443. int majorSkipPower = 0;
  444. float majorDivisionLength = (float)dpu;
  445. float majorDivisionPixels = (float)ScaleFactor.ScaleScalar(majorDivisionLength);
  446. int[] subdivs = GetSubdivs(measurementUnit);
  447. float offsetPixels = ScaleFactor.ScaleScalar((float)offset);
  448. int startMajor = (int)(offset / majorDivisionLength) - 1;
  449. int endMajor = (int)((offset + maxPixel) / majorDivisionLength) + 1;
  450. if (orientation == Orientation.Horizontal)
  451. {
  452. // draw Value
  453. if (!highlighted)
  454. {
  455. PointF pt = scaleFactor.ScalePointJustX(new PointF(ClientRectangle.Left + Value - Offset, ClientRectangle.Top));
  456. SizeF size = new SizeF(Math.Max(1, scaleFactor.ScaleScalar(1.0f)), ClientRectangle.Height);
  457. pt.X -= 0.5f;
  458. CompositingMode oldCM = e.Graphics.CompositingMode;
  459. e.Graphics.CompositingMode = CompositingMode.SourceOver;
  460. e.Graphics.FillRectangle(cursorBrush, new RectangleF(pt, size));
  461. e.Graphics.CompositingMode = oldCM;
  462. }
  463. // draw border
  464. e.Graphics.DrawLine(SystemPens.WindowText, new Point(ClientRectangle.Left, ClientRectangle.Bottom - 1),
  465. new Point(ClientRectangle.Right - 1, ClientRectangle.Bottom - 1));
  466. }
  467. else if (orientation == Orientation.Vertical)
  468. {
  469. // draw Value
  470. if (!highlighted)
  471. {
  472. PointF pt = scaleFactor.ScalePointJustY(new PointF(ClientRectangle.Left, ClientRectangle.Top + Value - Offset));
  473. SizeF size = new SizeF(ClientRectangle.Width, Math.Max(1, scaleFactor.ScaleScalar(1.0f)));
  474. pt.Y -= 0.5f;
  475. CompositingMode oldCM = e.Graphics.CompositingMode;
  476. e.Graphics.CompositingMode = CompositingMode.SourceOver;
  477. e.Graphics.FillRectangle(cursorBrush, new RectangleF(pt, size));
  478. e.Graphics.CompositingMode = oldCM;
  479. }
  480. // draw border
  481. e.Graphics.DrawLine(SystemPens.WindowText, new Point(ClientRectangle.Right - 1, ClientRectangle.Top),
  482. new Point(ClientRectangle.Right - 1, ClientRectangle.Bottom - 1));
  483. }
  484. while (majorDivisionPixels * majorSkip < 60)
  485. {
  486. majorSkip *= majorDivisors[majorSkipPower % majorDivisors.Length];
  487. ++majorSkipPower;
  488. }
  489. startMajor = (int)Math.Round((majorSkip * Math.Floor(startMajor / (double)majorSkip)));
  490. //decimal skip = Math.Round(Convert.ToDecimal(majorSkip), 1, MidpointRounding.AwayFromZero);
  491. //if(skip == 0)
  492. //{
  493. // skip = Math.Round(Convert.ToDecimal(majorSkip), 4, MidpointRounding.AwayFromZero);
  494. //}
  495. for (float major = startMajor; major <= endMajor; major += majorSkip)//skip
  496. {
  497. float majorMarkPos = ((float)major * majorDivisionPixels) - offsetPixels;
  498. //string majorText = major.ToString();//(Math.Round(Convert.ToDecimal(major), 4, MidpointRounding.AwayFromZero)).ToString();
  499. if (orientation == Orientation.Horizontal)
  500. {
  501. SubdivideX(e.Graphics, pen, ClientRectangle.Left + majorMarkPos, majorDivisionPixels * majorSkip, -majorSkipPower, ClientRectangle.Top, ClientRectangle.Height, subdivs);
  502. //e.Graphics.DrawString(majorText, Font, textBrush, new PointF(ClientRectangle.Left + majorMarkPos, ClientRectangle.Bottom), textFormat);
  503. }
  504. else // if (orientation == Orientation.Vertical)
  505. {
  506. SubdivideY(e.Graphics, pen, ClientRectangle.Top + majorMarkPos, majorDivisionPixels * majorSkip, -majorSkipPower, ClientRectangle.Left, ClientRectangle.Width, subdivs);
  507. // e.Graphics.DrawString(majorText, Font, textBrush, new PointF(ClientRectangle.Left, ClientRectangle.Top + majorMarkPos), textFormat);
  508. }
  509. }
  510. //
  511. // 以下是绘制文字
  512. //
  513. decimal skip = this.SkipNumberCalc(measurementUnit);
  514. int k = 0;
  515. int f = this.SkipInterval(measurementUnit);
  516. for (decimal major = startMajor; major <= endMajor; major += skip)//majorSkip
  517. {
  518. float majorMarkPos = ((float)major * majorDivisionPixels) - offsetPixels;
  519. string majorText = major.ToString();//(Math.Round(Convert.ToDecimal(major), 4, MidpointRounding.AwayFromZero)).ToString();
  520. if (orientation == Orientation.Horizontal)
  521. {
  522. if (k % f == 0)
  523. {
  524. e.Graphics.DrawString(majorText, Font, textBrush, new PointF(ClientRectangle.Left + majorMarkPos, ClientRectangle.Bottom), textFormat);
  525. }
  526. }
  527. else // if (orientation == Orientation.Vertical)
  528. {
  529. if (k % f == 0)
  530. {
  531. e.Graphics.DrawString(majorText, Font, textBrush, new PointF(ClientRectangle.Left, ClientRectangle.Top + majorMarkPos), textFormat);
  532. }
  533. }
  534. k++;
  535. }
  536. textFormat.Dispose();
  537. }
  538. /// <summary>
  539. /// 根据不同单位返回不同的间隔长度
  540. /// </summary>
  541. /// <param name="unit"></param>
  542. /// <returns></returns>
  543. private decimal SkipNumberCalc(MeasurementUnit unit)
  544. {
  545. decimal skip = 100M;
  546. if (unit == MeasurementUnit.Inch)
  547. {
  548. skip = 0.001M;
  549. }
  550. else if (unit == MeasurementUnit.Centimeter)
  551. {
  552. skip = 0.01M;
  553. }
  554. else if (unit == MeasurementUnit.Millimeter)
  555. {
  556. skip = 0.1M;
  557. }
  558. else if (unit == MeasurementUnit.Micron)
  559. {
  560. skip = 10M;
  561. }
  562. else if (unit == MeasurementUnit.Nano)
  563. {
  564. skip = 10000M;
  565. }
  566. return skip;
  567. }
  568. /// <summary>
  569. /// 不同的缩放比列下,间隔多少单元格绘制文字
  570. /// </summary>
  571. /// <param name="unit"></param>
  572. /// <returns></returns>
  573. private int SkipInterval(MeasurementUnit unit)
  574. {
  575. int f = 1;
  576. if (scaleFactor.Ratio <= 0.05f)
  577. {
  578. switch (unit)
  579. {
  580. case MeasurementUnit.Pixel:
  581. case MeasurementUnit.Centimeter:
  582. case MeasurementUnit.Millimeter:
  583. f = 100;
  584. break;
  585. case MeasurementUnit.Inch:
  586. case MeasurementUnit.Micron:
  587. case MeasurementUnit.Nano:
  588. f = 1000;
  589. break;
  590. }
  591. }
  592. else if (scaleFactor.Ratio <= 0.1f)
  593. {
  594. switch (unit)
  595. {
  596. case MeasurementUnit.Pixel:
  597. case MeasurementUnit.Centimeter:
  598. case MeasurementUnit.Millimeter:
  599. f = 10;
  600. break;
  601. case MeasurementUnit.Inch:
  602. case MeasurementUnit.Micron:
  603. case MeasurementUnit.Nano:
  604. f = 100;
  605. break;
  606. }
  607. }
  608. else if (scaleFactor.Ratio <= 0.5f)
  609. {
  610. switch (unit)
  611. {
  612. case MeasurementUnit.Pixel:
  613. case MeasurementUnit.Centimeter:
  614. case MeasurementUnit.Millimeter:
  615. f = 5;
  616. break;
  617. case MeasurementUnit.Inch:
  618. case MeasurementUnit.Micron:
  619. case MeasurementUnit.Nano:
  620. f = 50;
  621. break;
  622. }
  623. }
  624. else
  625. {
  626. switch (unit)
  627. {
  628. case MeasurementUnit.Pixel:
  629. case MeasurementUnit.Centimeter:
  630. case MeasurementUnit.Millimeter:
  631. f = 1;
  632. break;
  633. case MeasurementUnit.Inch:
  634. case MeasurementUnit.Micron:
  635. case MeasurementUnit.Nano:
  636. f = 10;
  637. break;
  638. }
  639. }
  640. return f;
  641. }
  642. }
  643. }