DrawRect.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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. /// <summary>
  72. /// 鼠标按下时的坐标
  73. /// </summary>
  74. public Point MouseDownPoint { get; set; }
  75. /// <summary>
  76. /// 移动偏移量
  77. /// </summary>
  78. private Point MoveOffset { get; set; } = new Point(0, 0);
  79. public DrawRect()
  80. {
  81. FillBrush = new SolidColorBrush(Color.FromArgb(0x01, 0x00, 0x00, 0x00));
  82. PointPen = new Pen(new SolidColorBrush(Color.FromRgb(0xC0, 0x4C, 0xF8)), 4);
  83. LinePen = new Pen(Brushes.White, 2);
  84. LinePen.DashStyle = DashStyles.Dash;
  85. }
  86. public void SetMaxRect(Rect rect)
  87. {
  88. MaxRect = rect;
  89. }
  90. /// <summary>
  91. /// 开始绘制
  92. /// </summary>
  93. public void OpenDraw()
  94. {
  95. if (DrawDC == null)
  96. {
  97. DrawDC = RenderOpen();
  98. }
  99. }
  100. /// <summary>
  101. /// 关闭绘制
  102. /// </summary>
  103. private void CloseDraw()
  104. {
  105. DrawDC?.Close();
  106. DrawDC = null;
  107. }
  108. /// <summary>
  109. /// 清除绘制内容
  110. /// </summary>
  111. public void ClearDraw()
  112. {
  113. OpenDraw();
  114. CloseDraw();
  115. }
  116. /// <summary>
  117. /// 绘制所需的内容
  118. /// </summary>
  119. public void Draw()
  120. {
  121. Dispatcher.Invoke(() =>
  122. {
  123. CalcControlPoint();
  124. OpenDraw();
  125. DrawDC?.DrawRectangle(FillBrush, LinePen, ClientRect);
  126. DrawClipMode();
  127. CloseDraw();
  128. });
  129. }
  130. /// <summary>
  131. /// 鼠标按下时调用,存储鼠标状态
  132. /// </summary>
  133. public bool MouseLeftButtonDown(Point clickPoint, CustomPanel custom)
  134. {
  135. HitControlType = PointControlType.None;
  136. HitTestResult hitResult = VisualTreeHelper.HitTest(custom, clickPoint);
  137. if (hitResult != null)
  138. {
  139. MouseDownPoint = clickPoint;
  140. MoveOffset = new Point(0, 0);
  141. HitControlType = GetHitControlIndex(clickPoint);
  142. if (HitControlType == PointControlType.None)
  143. {
  144. return false;
  145. }
  146. SnapClientRect = ClientRect;
  147. return true;
  148. }
  149. return false;
  150. }
  151. /// <summary>
  152. /// 鼠标松开时调用,存储鼠标状态
  153. /// </summary>
  154. public bool MouseLeftButtonUp(Point clickPoint)
  155. {
  156. if (HitControlType != PointControlType.None)
  157. {
  158. Draw();
  159. MoveOffset = new Point(0, 0);
  160. return true;
  161. }
  162. MoveOffset = new Point(0, 0);
  163. return false;
  164. }
  165. /// <summary>
  166. /// 鼠标移动时调用,根据按下时的状态,更新内部矩形
  167. /// </summary>
  168. public bool MouseMove(Point clickPoint)
  169. {
  170. if (HitControlType != PointControlType.None)
  171. {
  172. if (CalcHitPointMove(clickPoint))
  173. {
  174. Draw();
  175. return true;
  176. }
  177. }
  178. return false;
  179. }
  180. /// <summary>
  181. /// 设置矩形用于绘制
  182. /// </summary>
  183. public void SetRect(Rect newRect)
  184. {
  185. ClientRect = newRect;
  186. }
  187. /// <summary>
  188. /// 获取当前命中状态
  189. /// </summary>
  190. private PointControlType GetHitControlIndex(Point clickPoint)
  191. {
  192. for (int i = 0; i < ControlPoints.Count; i++)
  193. {
  194. Point checkPoint = ControlPoints[i];
  195. Rect checkRect = new Rect(checkPoint.X - PointSize, checkPoint.Y - PointSize, PointSize * 2, PointSize * 2);
  196. if (checkRect.Contains(clickPoint))
  197. {
  198. return (PointControlType)i;
  199. }
  200. }
  201. if (ClientRect.Contains(clickPoint))
  202. {
  203. return PointControlType.Body;
  204. }
  205. return PointControlType.None;
  206. }
  207. /// <summary>
  208. /// 绘制框上的可选点
  209. /// </summary>
  210. private void DrawClipMode()
  211. {
  212. GeometryGroup geometryGroup = new GeometryGroup();
  213. //四个角的可选点样式绘制
  214. for (int i = 0; i <= 6; i += 2)
  215. {
  216. PathGeometry pathGeometry = GetCornerGeometry(ControlPoints[i], (PointControlType)i);
  217. if (pathGeometry != null)
  218. {
  219. geometryGroup.Children.Add(pathGeometry);
  220. }
  221. }
  222. //四条边的可选点样式绘制
  223. for (int i = 1; i <= 7; i += 2)
  224. {
  225. LineGeometry lineGeometry = GetMiddleGeometry(ControlPoints[i], (PointControlType)i);
  226. if (lineGeometry != null)
  227. {
  228. geometryGroup.Children.Add(lineGeometry);
  229. }
  230. }
  231. if (geometryGroup.Children.Count > 0)
  232. {
  233. DrawDC?.DrawGeometry(null, PointPen, geometryGroup);
  234. }
  235. }
  236. /// <summary>
  237. /// 计算所有点的坐标
  238. /// </summary>
  239. private void CalcControlPoint()
  240. {
  241. ControlPoints.Clear();
  242. int centerX = (int)(ClientRect.Left + ClientRect.Right) / 2;
  243. int centerY = (int)(ClientRect.Top + ClientRect.Bottom) / 2;
  244. ControlPoints.Add(new Point(ClientRect.Left, ClientRect.Top));
  245. ControlPoints.Add(new Point(ClientRect.Left, centerY));
  246. ControlPoints.Add(new Point(ClientRect.Left, ClientRect.Bottom));
  247. ControlPoints.Add(new Point(centerX, ClientRect.Bottom));
  248. ControlPoints.Add(new Point(ClientRect.Right, ClientRect.Bottom));
  249. ControlPoints.Add(new Point(ClientRect.Right, centerY));
  250. ControlPoints.Add(new Point(ClientRect.Right, ClientRect.Top));
  251. ControlPoints.Add(new Point(centerX, ClientRect.Top));
  252. }
  253. /// <summary>
  254. /// 根据类型生成对应四个角的Path路径
  255. /// </summary>
  256. private PathGeometry GetCornerGeometry(Point cornerPoint, PointControlType pointType)
  257. {
  258. PathGeometry pathGeometry = new PathGeometry();
  259. PathFigure figure = new PathFigure();
  260. PolyLineSegment polyLine = new PolyLineSegment();
  261. figure.Segments.Add(polyLine);
  262. pathGeometry.Figures.Add(figure);
  263. Point startPoint = new Point(0, 0), middlePoint = new Point(0, 0), endPoint = new Point(0, 0);
  264. int MinLine = (int)Math.Min(Math.Min(ClipLine, ClientRect.Width), ClientRect.Height);
  265. switch (pointType)
  266. {
  267. case PointControlType.LeftTop:
  268. {
  269. startPoint = new Point(cornerPoint.X, cornerPoint.Y + MinLine);
  270. middlePoint = cornerPoint;
  271. endPoint = new Point(cornerPoint.X + MinLine, cornerPoint.Y);
  272. }
  273. break;
  274. case PointControlType.LeftBottom:
  275. {
  276. startPoint = new Point(cornerPoint.X, cornerPoint.Y - MinLine);
  277. middlePoint = cornerPoint;
  278. endPoint = new Point(cornerPoint.X + MinLine, cornerPoint.Y);
  279. }
  280. break;
  281. case PointControlType.RightBottom:
  282. {
  283. startPoint = new Point(cornerPoint.X - MinLine, cornerPoint.Y);
  284. middlePoint = cornerPoint;
  285. endPoint = new Point(cornerPoint.X, cornerPoint.Y - MinLine);
  286. }
  287. break;
  288. case PointControlType.RightTop:
  289. {
  290. startPoint = new Point(cornerPoint.X - MinLine, cornerPoint.Y);
  291. middlePoint = cornerPoint;
  292. endPoint = new Point(cornerPoint.X, cornerPoint.Y + MinLine);
  293. }
  294. break;
  295. default:
  296. return null;
  297. }
  298. figure.StartPoint = startPoint;
  299. polyLine.Points.Add(middlePoint);
  300. polyLine.Points.Add(endPoint);
  301. return pathGeometry;
  302. }
  303. /// <summary>
  304. /// 根据类型生成对应四条边的Path路径
  305. /// </summary>
  306. private LineGeometry GetMiddleGeometry(Point middlePoint, PointControlType pointType)
  307. {
  308. LineGeometry lineGeometry = new LineGeometry();
  309. Point startPoint = new Point(0, 0), endPoint = new Point(0, 0);
  310. int MinLine = (int)Math.Min(Math.Min(ClipLine * 2, ClientRect.Width), ClientRect.Height) / 2;
  311. switch (pointType)
  312. {
  313. case PointControlType.LeftMiddle:
  314. case PointControlType.RightMiddle:
  315. {
  316. startPoint.X = middlePoint.X;
  317. startPoint.Y = middlePoint.Y - MinLine;
  318. endPoint.X = middlePoint.X;
  319. endPoint.Y = middlePoint.Y + MinLine;
  320. }
  321. break;
  322. case PointControlType.MiddleTop:
  323. case PointControlType.MiddlBottom:
  324. {
  325. startPoint.X = middlePoint.X - MinLine;
  326. startPoint.Y = middlePoint.Y;
  327. endPoint.X = middlePoint.X + MinLine;
  328. endPoint.Y = middlePoint.Y;
  329. }
  330. break;
  331. default:
  332. return null;
  333. }
  334. lineGeometry.StartPoint = startPoint;
  335. lineGeometry.EndPoint = endPoint;
  336. return lineGeometry;
  337. }
  338. /// <summary>
  339. /// 计算当前命中点是否需要绘制。为True则更新内部矩形
  340. /// </summary>
  341. private bool CalcHitPointMove(Point mousePoint)
  342. {
  343. if (HitControlType == PointControlType.None)
  344. {
  345. return false;
  346. }
  347. Point centerPoint = new Point((SnapClientRect.Right + SnapClientRect.Left) / 2, (SnapClientRect.Bottom + SnapClientRect.Top) / 2);
  348. Vector moveVector = mousePoint - centerPoint;
  349. int xMove = (int)Math.Abs(moveVector.X);
  350. int yMove = xMove;
  351. switch (HitControlType)
  352. {
  353. case PointControlType.LeftTop:
  354. {
  355. ClientRect = new Rect(new Point(centerPoint.X - xMove, centerPoint.Y - yMove), new Size(xMove * 2, yMove * 2));
  356. }
  357. break;
  358. case PointControlType.LeftMiddle:
  359. {
  360. ClientRect = new Rect(new Point(centerPoint.X - xMove, SnapClientRect.Top), new Size(xMove * 2, SnapClientRect.Height));
  361. }
  362. break;
  363. case PointControlType.LeftBottom:
  364. {
  365. ClientRect = new Rect(new Point(centerPoint.X - xMove, centerPoint.Y - yMove), new Size(xMove * 2, yMove * 2));
  366. }
  367. break;
  368. case PointControlType.MiddlBottom:
  369. {
  370. yMove = (int)Math.Abs(moveVector.Y);
  371. ClientRect = new Rect(SnapClientRect.Left, centerPoint.Y - yMove, SnapClientRect.Width, yMove * 2);
  372. }
  373. break;
  374. case PointControlType.RightBottom:
  375. {
  376. ClientRect = new Rect(new Point(centerPoint.X - xMove, centerPoint.Y - yMove), new Size(xMove * 2, yMove * 2));
  377. }
  378. break;
  379. case PointControlType.RightMiddle:
  380. {
  381. ClientRect = new Rect(new Point(centerPoint.X - xMove, SnapClientRect.Top), new Size(xMove * 2, SnapClientRect.Height));
  382. }
  383. break;
  384. case PointControlType.RightTop:
  385. {
  386. ClientRect = new Rect(new Point(centerPoint.X - xMove, centerPoint.Y - yMove), new Size(xMove * 2, yMove * 2));
  387. }
  388. break;
  389. case PointControlType.MiddleTop:
  390. {
  391. yMove = (int)Math.Abs(moveVector.Y);
  392. ClientRect = new Rect(SnapClientRect.Left, centerPoint.Y - yMove, SnapClientRect.Width, yMove * 2);
  393. }
  394. break;
  395. case PointControlType.Rotate:
  396. break;
  397. case PointControlType.Body:
  398. {
  399. moveVector = mousePoint - MouseDownPoint;
  400. ClientRect = new Rect(SnapClientRect.Left + moveVector.X, SnapClientRect.Y + moveVector.Y, SnapClientRect.Width, SnapClientRect.Height);
  401. }
  402. break;
  403. default:
  404. return false;
  405. }
  406. //if (ClientRect.X < MaxRect.X)
  407. //{
  408. // ClientRect = new Rect
  409. // (MaxRect.X,
  410. // ClientRect.Y,
  411. // (ClientRect.Width - ClientRect.X) + MaxRect.X,
  412. // ClientRect.Height);
  413. //}
  414. //if (ClientRect.Y < MaxRect.Y)
  415. //{
  416. // ClientRect = new Rect
  417. // (ClientRect.X,
  418. // MaxRect.Y,
  419. // ClientRect.Width,
  420. // (ClientRect.Height - ClientRect.Y) + MaxRect.Y);
  421. //}
  422. //if (ClientRect.Width> MaxRect.Width)
  423. //{
  424. // ClientRect = new Rect
  425. // (MaxRect.Width - (ClientRect.Width - ClientRect.X),
  426. // ClientRect.Y,
  427. // MaxRect.Width,
  428. // ClientRect.Height);
  429. //}
  430. //if (ClientRect.Height>MaxRect.Height)
  431. //{
  432. // ClientRect = new Rect
  433. // (ClientRect.X,
  434. // MaxRect.Height-(ClientRect.Height- ClientRect.Y),
  435. // ClientRect.Width,
  436. // MaxRect.Height);
  437. //}
  438. MoveOffset = new Point(ClientRect.X - SnapClientRect.X, ClientRect.Y - SnapClientRect.Y);
  439. return true;
  440. }
  441. }
  442. }