DrawRect.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Media;
  8. namespace PDF_Office.CustomControl.ScanViewControl
  9. {
  10. public class DrawRect : DrawingVisual
  11. {
  12. private DrawingContext DrawDC { get; set; }
  13. /// <summary>
  14. /// 当前点的类型
  15. /// </summary>
  16. public enum PointControlType
  17. {
  18. None = -1,
  19. LeftTop,
  20. LeftMiddle,
  21. LeftBottom,
  22. MiddlBottom,
  23. RightBottom,
  24. RightMiddle,
  25. RightTop,
  26. MiddleTop,
  27. Rotate,
  28. Body
  29. }
  30. /// <summary>
  31. /// 当前点击命中的控制点
  32. /// </summary>
  33. public PointControlType HitControlType { get; private set; }
  34. /// <summary>
  35. /// 矩形框周围可拖拽点的坐标集合
  36. /// </summary>
  37. private List<Point> ControlPoints { get; set; } = new List<Point>();
  38. /// <summary>
  39. /// 当前内部缓存的矩形
  40. /// </summary>
  41. private Rect ClientRect { get; set; } = new Rect(0, 0, 0, 0);
  42. private Rect MaxRect { get; set; } = new Rect(0, 0, 0, 0);
  43. /// <summary>
  44. /// 按下时缓存的矩形
  45. /// </summary>
  46. private Rect SnapClientRect { get; set; }
  47. /// <summary>
  48. /// 覆盖填充色
  49. /// </summary>
  50. public SolidColorBrush FillBrush { get; set; }
  51. /// <summary>
  52. /// 边框线画刷
  53. /// </summary>
  54. public SolidColorBrush BorderBrush { get; set; }
  55. /// <summary>
  56. /// 边框线画笔
  57. /// </summary>
  58. public Pen LinePen { get; set; }
  59. /// <summary>
  60. /// 控制点画笔
  61. /// </summary>
  62. public Pen PointPen { get; set; }
  63. /// <summary>
  64. /// 控制点大小
  65. /// </summary>
  66. public int PointSize { get; set; } = 6;
  67. /// <summary>
  68. /// 绘制线段长度(点)
  69. /// </summary>
  70. public int ClipLine { get; set; } = 8;
  71. private double RatioRate { get; set; } = 1;
  72. /// <summary>
  73. /// 鼠标按下时的坐标
  74. /// </summary>
  75. public Point MouseDownPoint { get; set; }
  76. /// <summary>
  77. /// 移动偏移量
  78. /// </summary>
  79. private Point MoveOffset { get; set; } = new Point(0, 0);
  80. public DrawRect()
  81. {
  82. FillBrush = new SolidColorBrush(Color.FromArgb(0x01, 0x00, 0x00, 0x00));
  83. PointPen = new Pen(new SolidColorBrush(Color.FromRgb(0xC0, 0x4C, 0xF8)), 4);
  84. LinePen = new Pen(Brushes.White, 2);
  85. LinePen.DashStyle = DashStyles.Dash;
  86. }
  87. public void SetMaxRect(Rect rect)
  88. {
  89. MaxRect = rect;
  90. }
  91. /// <summary>
  92. /// 开始绘制
  93. /// </summary>
  94. public void OpenDraw()
  95. {
  96. if (DrawDC == null)
  97. {
  98. DrawDC = RenderOpen();
  99. }
  100. }
  101. /// <summary>
  102. /// 关闭绘制
  103. /// </summary>
  104. private void CloseDraw()
  105. {
  106. DrawDC?.Close();
  107. DrawDC = null;
  108. }
  109. /// <summary>
  110. /// 清除绘制内容
  111. /// </summary>
  112. public void ClearDraw()
  113. {
  114. OpenDraw();
  115. CloseDraw();
  116. }
  117. /// <summary>
  118. /// 绘制所需的内容
  119. /// </summary>
  120. public void Draw()
  121. {
  122. Dispatcher.Invoke(() =>
  123. {
  124. CalcControlPoint();
  125. OpenDraw();
  126. DrawDC?.DrawRectangle(FillBrush, LinePen, ClientRect);
  127. DrawClipMode();
  128. CloseDraw();
  129. });
  130. }
  131. /// <summary>
  132. /// 鼠标按下时调用,存储鼠标状态
  133. /// </summary>
  134. public bool MouseLeftButtonDown(Point clickPoint, CustomPanel custom)
  135. {
  136. HitControlType = PointControlType.None;
  137. HitTestResult hitResult = VisualTreeHelper.HitTest(custom, clickPoint);
  138. if (hitResult != null)
  139. {
  140. MouseDownPoint = clickPoint;
  141. MoveOffset = new Point(0, 0);
  142. HitControlType = GetHitControlIndex(clickPoint);
  143. if (HitControlType == PointControlType.None)
  144. {
  145. return false;
  146. }
  147. SnapClientRect = ClientRect;
  148. RatioRate = ClientRect.Width > 0 ? ClientRect.Height / ClientRect.Width : 1;
  149. return true;
  150. }
  151. return false;
  152. }
  153. /// <summary>
  154. /// 鼠标松开时调用,存储鼠标状态
  155. /// </summary>
  156. public bool MouseLeftButtonUp(Point clickPoint)
  157. {
  158. if (HitControlType != PointControlType.None)
  159. {
  160. Draw();
  161. MoveOffset = new Point(0, 0);
  162. return true;
  163. }
  164. MoveOffset = new Point(0, 0);
  165. return false;
  166. }
  167. /// <summary>
  168. /// 鼠标移动时调用,根据按下时的状态,更新内部矩形
  169. /// </summary>
  170. public bool MouseMove(Point clickPoint)
  171. {
  172. if (HitControlType != PointControlType.None)
  173. {
  174. if (CalcHitPointMove(clickPoint))
  175. {
  176. Draw();
  177. return true;
  178. }
  179. }
  180. return false;
  181. }
  182. /// <summary>
  183. /// 设置矩形用于绘制
  184. /// </summary>
  185. public void SetRect(Rect newRect)
  186. {
  187. ClientRect = newRect;
  188. }
  189. /// <summary>
  190. /// 获取当前命中状态
  191. /// </summary>
  192. private PointControlType GetHitControlIndex(Point clickPoint)
  193. {
  194. for (int i = 0; i < ControlPoints.Count; i++)
  195. {
  196. Point checkPoint = ControlPoints[i];
  197. Rect checkRect = new Rect(checkPoint.X - PointSize, checkPoint.Y - PointSize, PointSize * 2, PointSize * 2);
  198. if (checkRect.Contains(clickPoint))
  199. {
  200. return (PointControlType)i;
  201. }
  202. }
  203. if (ClientRect.Contains(clickPoint))
  204. {
  205. return PointControlType.Body;
  206. }
  207. return PointControlType.None;
  208. }
  209. /// <summary>
  210. /// 绘制框上的可选点
  211. /// </summary>
  212. private void DrawClipMode()
  213. {
  214. GeometryGroup geometryGroup = new GeometryGroup();
  215. //四个角的可选点样式绘制
  216. for (int i = 0; i <= 6; i += 2)
  217. {
  218. PathGeometry pathGeometry = GetCornerGeometry(ControlPoints[i], (PointControlType)i);
  219. if (pathGeometry != null)
  220. {
  221. geometryGroup.Children.Add(pathGeometry);
  222. }
  223. }
  224. //四条边的可选点样式绘制
  225. for (int i = 1; i <= 7; i += 2)
  226. {
  227. LineGeometry lineGeometry = GetMiddleGeometry(ControlPoints[i], (PointControlType)i);
  228. if (lineGeometry != null)
  229. {
  230. geometryGroup.Children.Add(lineGeometry);
  231. }
  232. }
  233. if (geometryGroup.Children.Count > 0)
  234. {
  235. DrawDC?.DrawGeometry(null, PointPen, geometryGroup);
  236. }
  237. }
  238. /// <summary>
  239. /// 计算所有点的坐标
  240. /// </summary>
  241. private void CalcControlPoint()
  242. {
  243. ControlPoints.Clear();
  244. int centerX = (int)(ClientRect.Left + ClientRect.Right) / 2;
  245. int centerY = (int)(ClientRect.Top + ClientRect.Bottom) / 2;
  246. ControlPoints.Add(new Point(ClientRect.Left, ClientRect.Top));
  247. ControlPoints.Add(new Point(ClientRect.Left, centerY));
  248. ControlPoints.Add(new Point(ClientRect.Left, ClientRect.Bottom));
  249. ControlPoints.Add(new Point(centerX, ClientRect.Bottom));
  250. ControlPoints.Add(new Point(ClientRect.Right, ClientRect.Bottom));
  251. ControlPoints.Add(new Point(ClientRect.Right, centerY));
  252. ControlPoints.Add(new Point(ClientRect.Right, ClientRect.Top));
  253. ControlPoints.Add(new Point(centerX, ClientRect.Top));
  254. }
  255. /// <summary>
  256. /// 根据类型生成对应四个角的Path路径
  257. /// </summary>
  258. private PathGeometry GetCornerGeometry(Point cornerPoint, PointControlType pointType)
  259. {
  260. PathGeometry pathGeometry = new PathGeometry();
  261. PathFigure figure = new PathFigure();
  262. PolyLineSegment polyLine = new PolyLineSegment();
  263. figure.Segments.Add(polyLine);
  264. pathGeometry.Figures.Add(figure);
  265. Point startPoint = new Point(0, 0), middlePoint = new Point(0, 0), endPoint = new Point(0, 0);
  266. int MinLine = (int)Math.Min(Math.Min(ClipLine, ClientRect.Width), ClientRect.Height);
  267. switch (pointType)
  268. {
  269. case PointControlType.LeftTop:
  270. {
  271. startPoint = new Point(cornerPoint.X, cornerPoint.Y + MinLine);
  272. middlePoint = cornerPoint;
  273. endPoint = new Point(cornerPoint.X + MinLine, cornerPoint.Y);
  274. }
  275. break;
  276. case PointControlType.LeftBottom:
  277. {
  278. startPoint = new Point(cornerPoint.X, cornerPoint.Y - MinLine);
  279. middlePoint = cornerPoint;
  280. endPoint = new Point(cornerPoint.X + MinLine, cornerPoint.Y);
  281. }
  282. break;
  283. case PointControlType.RightBottom:
  284. {
  285. startPoint = new Point(cornerPoint.X - MinLine, cornerPoint.Y);
  286. middlePoint = cornerPoint;
  287. endPoint = new Point(cornerPoint.X, cornerPoint.Y - MinLine);
  288. }
  289. break;
  290. case PointControlType.RightTop:
  291. {
  292. startPoint = new Point(cornerPoint.X - MinLine, cornerPoint.Y);
  293. middlePoint = cornerPoint;
  294. endPoint = new Point(cornerPoint.X, cornerPoint.Y + MinLine);
  295. }
  296. break;
  297. default:
  298. return null;
  299. }
  300. figure.StartPoint = startPoint;
  301. polyLine.Points.Add(middlePoint);
  302. polyLine.Points.Add(endPoint);
  303. return pathGeometry;
  304. }
  305. /// <summary>
  306. /// 根据类型生成对应四条边的Path路径
  307. /// </summary>
  308. private LineGeometry GetMiddleGeometry(Point middlePoint, PointControlType pointType)
  309. {
  310. LineGeometry lineGeometry = new LineGeometry();
  311. Point startPoint = new Point(0, 0), endPoint = new Point(0, 0);
  312. int MinLine = (int)Math.Min(Math.Min(ClipLine * 2, ClientRect.Width), ClientRect.Height) / 2;
  313. switch (pointType)
  314. {
  315. case PointControlType.LeftMiddle:
  316. case PointControlType.RightMiddle:
  317. {
  318. startPoint.X = middlePoint.X;
  319. startPoint.Y = middlePoint.Y - MinLine;
  320. endPoint.X = middlePoint.X;
  321. endPoint.Y = middlePoint.Y + MinLine;
  322. }
  323. break;
  324. case PointControlType.MiddleTop:
  325. case PointControlType.MiddlBottom:
  326. {
  327. startPoint.X = middlePoint.X - MinLine;
  328. startPoint.Y = middlePoint.Y;
  329. endPoint.X = middlePoint.X + MinLine;
  330. endPoint.Y = middlePoint.Y;
  331. }
  332. break;
  333. default:
  334. return null;
  335. }
  336. lineGeometry.StartPoint = startPoint;
  337. lineGeometry.EndPoint = endPoint;
  338. return lineGeometry;
  339. }
  340. /// <summary>
  341. /// 计算当前命中点是否需要绘制。为True则更新内部矩形
  342. /// </summary>
  343. private bool CalcHitPointMove(Point mousePoint)
  344. {
  345. if (HitControlType == PointControlType.None)
  346. {
  347. return false;
  348. }
  349. Point centerPoint = new Point((SnapClientRect.Right + SnapClientRect.Left) / 2, (SnapClientRect.Bottom + SnapClientRect.Top) / 2);
  350. Vector moveVector = mousePoint - centerPoint;
  351. int xMove = -(int)moveVector.X;
  352. int yMove = -(int)moveVector.Y;
  353. switch (HitControlType)
  354. {
  355. case PointControlType.LeftTop:
  356. {
  357. double X = centerPoint.X - xMove;
  358. double Width =SnapClientRect.Width + SnapClientRect.X - centerPoint.X + xMove;
  359. if (Width < 10)
  360. {
  361. Width = 10;
  362. X = SnapClientRect.X + SnapClientRect.Width- 10;
  363. }
  364. double Y = centerPoint.Y - yMove;
  365. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y + yMove;
  366. if (Height < 10)
  367. {
  368. Height = 10;
  369. Y = SnapClientRect.Y + SnapClientRect.Height - 10;
  370. }
  371. ClientRect = new Rect(new Point(X, Y),
  372. new Size(Width, Height));
  373. }
  374. break;
  375. case PointControlType.LeftMiddle:
  376. {
  377. double X = centerPoint.X - xMove;
  378. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X + xMove;
  379. if (Width < 10)
  380. {
  381. Width = 10;
  382. X = SnapClientRect.X + SnapClientRect.Width - 10;
  383. }
  384. double Y = SnapClientRect.Top;
  385. double Height = SnapClientRect.Height;
  386. ClientRect = new Rect(new Point(X, Y),
  387. new Size(Width, Height));
  388. }
  389. break;
  390. case PointControlType.LeftBottom:
  391. {
  392. double X = centerPoint.X - xMove;
  393. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X + xMove;
  394. if (Width < 10)
  395. {
  396. Width = 10;
  397. X = SnapClientRect.X + SnapClientRect.Width - 10;
  398. }
  399. double Y = SnapClientRect.Y;
  400. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y - yMove;
  401. if (Height < 10)
  402. {
  403. Height = 10;
  404. Y = SnapClientRect.Y ;
  405. }
  406. ClientRect = new Rect(new Point(X, Y),
  407. new Size(Width, Height));
  408. }
  409. break;
  410. case PointControlType.MiddlBottom:
  411. {
  412. double X = SnapClientRect.Left;
  413. double Width = SnapClientRect.Width;
  414. double Y = SnapClientRect.Y;
  415. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y - yMove;
  416. if (Height < 10)
  417. {
  418. Height = 10;
  419. Y = SnapClientRect.Y;
  420. }
  421. ClientRect = new Rect(new Point(X, Y),
  422. new Size(Width, Height));
  423. }
  424. break;
  425. case PointControlType.RightBottom:
  426. {
  427. double X = SnapClientRect.Left;
  428. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X -xMove;
  429. if (Width < 10)
  430. {
  431. Width = 10;
  432. }
  433. double Y = SnapClientRect.Y;
  434. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y - yMove;
  435. if (Height < 10)
  436. {
  437. Height = 10;
  438. }
  439. ClientRect = new Rect(new Point(X, Y),
  440. new Size(Width, Height));
  441. }
  442. break;
  443. case PointControlType.RightMiddle:
  444. {
  445. double X = SnapClientRect.Left;
  446. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X - xMove;
  447. if (Width < 10)
  448. {
  449. Width = 10;
  450. }
  451. double Y = SnapClientRect.Top;
  452. double Height = SnapClientRect.Height;
  453. ClientRect = new Rect(new Point(X, Y),
  454. new Size(Width, Height));
  455. }
  456. break;
  457. case PointControlType.RightTop:
  458. {
  459. double X = SnapClientRect.X;
  460. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X - xMove;
  461. if (Width < 10)
  462. {
  463. Width = 10;
  464. X = SnapClientRect.X;
  465. }
  466. double Y = centerPoint.Y - yMove;
  467. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y + yMove;
  468. if (Height < 10)
  469. {
  470. Height = 10;
  471. Y = SnapClientRect.Y + SnapClientRect.Height - 10;
  472. }
  473. ClientRect = new Rect(new Point(X, Y),
  474. new Size(Width, Height));
  475. }
  476. break;
  477. case PointControlType.MiddleTop:
  478. {
  479. double X = SnapClientRect.X;
  480. double Width = SnapClientRect.Width;
  481. double Y = centerPoint.Y - yMove;
  482. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y + yMove;
  483. if (Height < 10)
  484. {
  485. Height = 10;
  486. Y = SnapClientRect.Y + SnapClientRect.Height - 10;
  487. }
  488. ClientRect = new Rect(new Point(X, Y),
  489. new Size(Width, Height));
  490. }
  491. break;
  492. case PointControlType.Rotate:
  493. break;
  494. case PointControlType.Body:
  495. {
  496. moveVector = mousePoint - MouseDownPoint;
  497. ClientRect = new Rect(SnapClientRect.Left - xMove, SnapClientRect.Top -yMove, SnapClientRect.Width , SnapClientRect.Height);
  498. }
  499. break;
  500. default:
  501. return false;
  502. }
  503. if (ClientRect.X < MaxRect.X)
  504. {
  505. ClientRect = new Rect
  506. (MaxRect.X,
  507. ClientRect.Y,
  508. ClientRect.Width + MaxRect.X - ClientRect.X,
  509. ClientRect.Height);
  510. }
  511. if (ClientRect.Y < MaxRect.Y)
  512. {
  513. ClientRect = new Rect
  514. (ClientRect.X,
  515. MaxRect.Y,
  516. ClientRect.Width,
  517. ClientRect.Height - ClientRect.Y + MaxRect.Y);
  518. }
  519. if (ClientRect.Right > MaxRect.Right)
  520. {
  521. ClientRect = new Rect
  522. (ClientRect.X,
  523. ClientRect.Y,
  524. MaxRect.Right - ClientRect.X,
  525. ClientRect.Height);
  526. }
  527. if (ClientRect.Bottom > MaxRect.Bottom)
  528. {
  529. ClientRect = new Rect
  530. (ClientRect.X,
  531. ClientRect.Y,
  532. ClientRect.Width,
  533. MaxRect.Bottom - ClientRect.Y);
  534. }
  535. Console.WriteLine(ClientRect.ToString());
  536. MoveOffset = new Point(ClientRect.X - SnapClientRect.X, ClientRect.Y - SnapClientRect.Y);
  537. return true;
  538. }
  539. }
  540. }