DrawRect.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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. public void test(double x)
  154. {
  155. ClientRect = new Rect(ClientRect.X , ClientRect.Y , ClientRect.Width * x, ClientRect.Height * x);
  156. }
  157. /// <summary>
  158. /// 鼠标松开时调用,存储鼠标状态
  159. /// </summary>
  160. public bool MouseLeftButtonUp(Point clickPoint)
  161. {
  162. if (HitControlType != PointControlType.None)
  163. {
  164. Draw();
  165. MoveOffset = new Point(0, 0);
  166. return true;
  167. }
  168. MoveOffset = new Point(0, 0);
  169. return false;
  170. }
  171. /// <summary>
  172. /// 鼠标移动时调用,根据按下时的状态,更新内部矩形
  173. /// </summary>
  174. public bool MouseMove(Point clickPoint)
  175. {
  176. if (HitControlType != PointControlType.None)
  177. {
  178. if (CalcHitPointMove(clickPoint))
  179. {
  180. Draw();
  181. return true;
  182. }
  183. }
  184. return false;
  185. }
  186. /// <summary>
  187. /// 设置矩形用于绘制
  188. /// </summary>
  189. public void SetRect(Rect newRect)
  190. {
  191. ClientRect = newRect;
  192. }
  193. public Rect GetClientRect()
  194. {
  195. return ClientRect;
  196. }
  197. /// <summary>
  198. /// 获取当前命中状态
  199. /// </summary>
  200. private PointControlType GetHitControlIndex(Point clickPoint)
  201. {
  202. for (int i = 0; i < ControlPoints.Count; i++)
  203. {
  204. Point checkPoint = ControlPoints[i];
  205. Rect checkRect = new Rect(checkPoint.X - PointSize, checkPoint.Y - PointSize, PointSize * 2, PointSize * 2);
  206. if (checkRect.Contains(clickPoint))
  207. {
  208. return (PointControlType)i;
  209. }
  210. }
  211. if (ClientRect.Contains(clickPoint))
  212. {
  213. return PointControlType.Body;
  214. }
  215. return PointControlType.None;
  216. }
  217. /// <summary>
  218. /// 绘制框上的可选点
  219. /// </summary>
  220. private void DrawClipMode()
  221. {
  222. GeometryGroup geometryGroup = new GeometryGroup();
  223. //四个角的可选点样式绘制
  224. for (int i = 0; i <= 6; i += 2)
  225. {
  226. PathGeometry pathGeometry = GetCornerGeometry(ControlPoints[i], (PointControlType)i);
  227. if (pathGeometry != null)
  228. {
  229. geometryGroup.Children.Add(pathGeometry);
  230. }
  231. }
  232. //四条边的可选点样式绘制
  233. for (int i = 1; i <= 7; i += 2)
  234. {
  235. LineGeometry lineGeometry = GetMiddleGeometry(ControlPoints[i], (PointControlType)i);
  236. if (lineGeometry != null)
  237. {
  238. geometryGroup.Children.Add(lineGeometry);
  239. }
  240. }
  241. if (geometryGroup.Children.Count > 0)
  242. {
  243. DrawDC?.DrawGeometry(null, PointPen, geometryGroup);
  244. }
  245. }
  246. /// <summary>
  247. /// 计算所有点的坐标
  248. /// </summary>
  249. private void CalcControlPoint()
  250. {
  251. ControlPoints.Clear();
  252. int centerX = (int)(ClientRect.Left + ClientRect.Right) / 2;
  253. int centerY = (int)(ClientRect.Top + ClientRect.Bottom) / 2;
  254. ControlPoints.Add(new Point(ClientRect.Left, ClientRect.Top));
  255. ControlPoints.Add(new Point(ClientRect.Left, centerY));
  256. ControlPoints.Add(new Point(ClientRect.Left, ClientRect.Bottom));
  257. ControlPoints.Add(new Point(centerX, ClientRect.Bottom));
  258. ControlPoints.Add(new Point(ClientRect.Right, ClientRect.Bottom));
  259. ControlPoints.Add(new Point(ClientRect.Right, centerY));
  260. ControlPoints.Add(new Point(ClientRect.Right, ClientRect.Top));
  261. ControlPoints.Add(new Point(centerX, ClientRect.Top));
  262. }
  263. /// <summary>
  264. /// 根据类型生成对应四个角的Path路径
  265. /// </summary>
  266. private PathGeometry GetCornerGeometry(Point cornerPoint, PointControlType pointType)
  267. {
  268. PathGeometry pathGeometry = new PathGeometry();
  269. PathFigure figure = new PathFigure();
  270. PolyLineSegment polyLine = new PolyLineSegment();
  271. figure.Segments.Add(polyLine);
  272. pathGeometry.Figures.Add(figure);
  273. Point startPoint = new Point(0, 0), middlePoint = new Point(0, 0), endPoint = new Point(0, 0);
  274. int MinLine = (int)Math.Min(Math.Min(ClipLine, ClientRect.Width), ClientRect.Height);
  275. switch (pointType)
  276. {
  277. case PointControlType.LeftTop:
  278. {
  279. startPoint = new Point(cornerPoint.X, cornerPoint.Y + MinLine);
  280. middlePoint = cornerPoint;
  281. endPoint = new Point(cornerPoint.X + MinLine, cornerPoint.Y);
  282. }
  283. break;
  284. case PointControlType.LeftBottom:
  285. {
  286. startPoint = new Point(cornerPoint.X, cornerPoint.Y - MinLine);
  287. middlePoint = cornerPoint;
  288. endPoint = new Point(cornerPoint.X + MinLine, cornerPoint.Y);
  289. }
  290. break;
  291. case PointControlType.RightBottom:
  292. {
  293. startPoint = new Point(cornerPoint.X - MinLine, cornerPoint.Y);
  294. middlePoint = cornerPoint;
  295. endPoint = new Point(cornerPoint.X, cornerPoint.Y - MinLine);
  296. }
  297. break;
  298. case PointControlType.RightTop:
  299. {
  300. startPoint = new Point(cornerPoint.X - MinLine, cornerPoint.Y);
  301. middlePoint = cornerPoint;
  302. endPoint = new Point(cornerPoint.X, cornerPoint.Y + MinLine);
  303. }
  304. break;
  305. default:
  306. return null;
  307. }
  308. figure.StartPoint = startPoint;
  309. polyLine.Points.Add(middlePoint);
  310. polyLine.Points.Add(endPoint);
  311. return pathGeometry;
  312. }
  313. /// <summary>
  314. /// 根据类型生成对应四条边的Path路径
  315. /// </summary>
  316. private LineGeometry GetMiddleGeometry(Point middlePoint, PointControlType pointType)
  317. {
  318. LineGeometry lineGeometry = new LineGeometry();
  319. Point startPoint = new Point(0, 0), endPoint = new Point(0, 0);
  320. int MinLine = (int)Math.Min(Math.Min(ClipLine * 2, ClientRect.Width), ClientRect.Height) / 2;
  321. switch (pointType)
  322. {
  323. case PointControlType.LeftMiddle:
  324. case PointControlType.RightMiddle:
  325. {
  326. startPoint.X = middlePoint.X;
  327. startPoint.Y = middlePoint.Y - MinLine;
  328. endPoint.X = middlePoint.X;
  329. endPoint.Y = middlePoint.Y + MinLine;
  330. }
  331. break;
  332. case PointControlType.MiddleTop:
  333. case PointControlType.MiddlBottom:
  334. {
  335. startPoint.X = middlePoint.X - MinLine;
  336. startPoint.Y = middlePoint.Y;
  337. endPoint.X = middlePoint.X + MinLine;
  338. endPoint.Y = middlePoint.Y;
  339. }
  340. break;
  341. default:
  342. return null;
  343. }
  344. lineGeometry.StartPoint = startPoint;
  345. lineGeometry.EndPoint = endPoint;
  346. return lineGeometry;
  347. }
  348. /// <summary>
  349. /// 计算当前命中点是否需要绘制。为True则更新内部矩形
  350. /// </summary>
  351. private bool CalcHitPointMove(Point mousePoint)
  352. {
  353. if (HitControlType == PointControlType.None)
  354. {
  355. return false;
  356. }
  357. Point centerPoint = new Point((SnapClientRect.Right + SnapClientRect.Left) / 2, (SnapClientRect.Bottom + SnapClientRect.Top) / 2);
  358. Vector moveVector = mousePoint - centerPoint;
  359. int xMove = -(int)moveVector.X;
  360. int yMove = -(int)moveVector.Y;
  361. switch (HitControlType)
  362. {
  363. case PointControlType.LeftTop:
  364. {
  365. double X = centerPoint.X - xMove;
  366. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X + xMove;
  367. if (Width < 10)
  368. {
  369. Width = 10;
  370. X = SnapClientRect.X + SnapClientRect.Width - 10;
  371. }
  372. double Y = centerPoint.Y - yMove;
  373. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y + yMove;
  374. if (Height < 10)
  375. {
  376. Height = 10;
  377. Y = SnapClientRect.Y + SnapClientRect.Height - 10;
  378. }
  379. ClientRect = new Rect(new Point(X, Y),
  380. new Size(Width, Height));
  381. }
  382. break;
  383. case PointControlType.LeftMiddle:
  384. {
  385. double X = centerPoint.X - xMove;
  386. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X + xMove;
  387. if (Width < 10)
  388. {
  389. Width = 10;
  390. X = SnapClientRect.X + SnapClientRect.Width - 10;
  391. }
  392. double Y = SnapClientRect.Top;
  393. double Height = SnapClientRect.Height;
  394. ClientRect = new Rect(new Point(X, Y),
  395. new Size(Width, Height));
  396. }
  397. break;
  398. case PointControlType.LeftBottom:
  399. {
  400. double X = centerPoint.X - xMove;
  401. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X + xMove;
  402. if (Width < 10)
  403. {
  404. Width = 10;
  405. X = SnapClientRect.X + SnapClientRect.Width - 10;
  406. }
  407. double Y = SnapClientRect.Y;
  408. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y - yMove;
  409. if (Height < 10)
  410. {
  411. Height = 10;
  412. Y = SnapClientRect.Y;
  413. }
  414. ClientRect = new Rect(new Point(X, Y),
  415. new Size(Width, Height));
  416. }
  417. break;
  418. case PointControlType.MiddlBottom:
  419. {
  420. double X = SnapClientRect.Left;
  421. double Width = SnapClientRect.Width;
  422. double Y = SnapClientRect.Y;
  423. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y - yMove;
  424. if (Height < 10)
  425. {
  426. Height = 10;
  427. Y = SnapClientRect.Y;
  428. }
  429. ClientRect = new Rect(new Point(X, Y),
  430. new Size(Width, Height));
  431. }
  432. break;
  433. case PointControlType.RightBottom:
  434. {
  435. double X = SnapClientRect.Left;
  436. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X - xMove;
  437. if (Width < 10)
  438. {
  439. Width = 10;
  440. }
  441. double Y = SnapClientRect.Y;
  442. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y - yMove;
  443. if (Height < 10)
  444. {
  445. Height = 10;
  446. }
  447. ClientRect = new Rect(new Point(X, Y),
  448. new Size(Width, Height));
  449. }
  450. break;
  451. case PointControlType.RightMiddle:
  452. {
  453. double X = SnapClientRect.Left;
  454. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X - xMove;
  455. if (Width < 10)
  456. {
  457. Width = 10;
  458. }
  459. double Y = SnapClientRect.Top;
  460. double Height = SnapClientRect.Height;
  461. ClientRect = new Rect(new Point(X, Y),
  462. new Size(Width, Height));
  463. }
  464. break;
  465. case PointControlType.RightTop:
  466. {
  467. double X = SnapClientRect.X;
  468. double Width = SnapClientRect.Width + SnapClientRect.X - centerPoint.X - xMove;
  469. if (Width < 10)
  470. {
  471. Width = 10;
  472. X = SnapClientRect.X;
  473. }
  474. double Y = centerPoint.Y - yMove;
  475. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y + yMove;
  476. if (Height < 10)
  477. {
  478. Height = 10;
  479. Y = SnapClientRect.Y + SnapClientRect.Height - 10;
  480. }
  481. ClientRect = new Rect(new Point(X, Y),
  482. new Size(Width, Height));
  483. }
  484. break;
  485. case PointControlType.MiddleTop:
  486. {
  487. double X = SnapClientRect.X;
  488. double Width = SnapClientRect.Width;
  489. double Y = centerPoint.Y - yMove;
  490. double Height = SnapClientRect.Height + SnapClientRect.Y - centerPoint.Y + yMove;
  491. if (Height < 10)
  492. {
  493. Height = 10;
  494. Y = SnapClientRect.Y + SnapClientRect.Height - 10;
  495. }
  496. ClientRect = new Rect(new Point(X, Y),
  497. new Size(Width, Height));
  498. }
  499. break;
  500. case PointControlType.Rotate:
  501. break;
  502. case PointControlType.Body:
  503. {
  504. moveVector = mousePoint - MouseDownPoint;
  505. ClientRect = new Rect(SnapClientRect.Left - xMove, SnapClientRect.Top - yMove, SnapClientRect.Width, SnapClientRect.Height);
  506. }
  507. break;
  508. default:
  509. return false;
  510. }
  511. if (ClientRect.X < MaxRect.X)
  512. {
  513. ClientRect = new Rect
  514. (MaxRect.X,
  515. ClientRect.Y,
  516. ClientRect.Width,
  517. ClientRect.Height);
  518. }
  519. if (ClientRect.Y < MaxRect.Y)
  520. {
  521. ClientRect = new Rect
  522. (ClientRect.X,
  523. MaxRect.Y,
  524. ClientRect.Width,
  525. ClientRect.Height);
  526. }
  527. if (ClientRect.Right > MaxRect.Right)
  528. {
  529. ClientRect = new Rect
  530. (MaxRect.Right - ClientRect.Width,
  531. ClientRect.Y,
  532. ClientRect.Width,
  533. ClientRect.Height);
  534. }
  535. if (ClientRect.Bottom > MaxRect.Bottom)
  536. {
  537. ClientRect = new Rect
  538. (ClientRect.X,
  539. MaxRect.Bottom - ClientRect.Height,
  540. ClientRect.Width,
  541. ClientRect.Height);
  542. }
  543. Console.WriteLine(ClientRect.ToString());
  544. MoveOffset = new Point(ClientRect.X - SnapClientRect.X, ClientRect.Y - SnapClientRect.Y);
  545. return true;
  546. }
  547. }
  548. }