ViewBase.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. using PaintDotNet.Annotation.Enum;
  2. using PaintDotNet.Base.CommTool;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Drawing;
  6. using System.Drawing.Drawing2D;
  7. using System.Windows.Forms;
  8. /*
  9. * 视场,
  10. * 全部图形构成基于点阵(Points)拟合.
  11. * 图形变换,对外属性均依赖于点阵的换算.
  12. * 点阵集合继承DrawObject 的 pointArrayList 字段
  13. * 全部接口数值皆为原始数值并未进行缩放处理.
  14. */
  15. namespace PaintDotNet.Annotation.FieldView
  16. {
  17. public abstract class ViewBase : DrawObject
  18. {
  19. /// <summary>
  20. /// 鼠标形状
  21. /// </summary>
  22. public static Cursor m_rotateCursor = new Cursor(PdnResources.GetResourceStream("Cursors.AnnotationRotateHandle.cur"));
  23. public static Cursor m_resizeCursor = new Cursor(PdnResources.GetResourceStream("Cursors.AnnotationResizeHandle.cur"));
  24. public override double Width
  25. {
  26. get => Rectangle.Width;
  27. set
  28. {
  29. }
  30. }
  31. public override double Height
  32. {
  33. get => Rectangle.Height;
  34. set
  35. {
  36. }
  37. }
  38. #region Points
  39. public virtual List<PointF> Points
  40. {
  41. get
  42. {
  43. if (pointArrayList == null)
  44. pointArrayList = new List<PointF>();
  45. return pointArrayList;
  46. }
  47. set
  48. {
  49. pointArrayList = new List<PointF>();
  50. foreach (var p in value)
  51. {
  52. pointArrayList.Add(p);
  53. }
  54. }
  55. }
  56. public void AddPoint(int x, int y)
  57. {
  58. AddPoint(new PointF(x, y));
  59. }
  60. protected void AddPoint(PointF point)
  61. {
  62. Points.Add(point);
  63. }
  64. public override List<PointF> GetPoints()
  65. {
  66. return Points;
  67. }
  68. #endregion
  69. #region Bounding Rectangle
  70. public override RectangleF Rectangle
  71. {
  72. get
  73. {
  74. return GetBoundingBox();
  75. }
  76. }
  77. /// <summary>
  78. /// 外接矩形
  79. /// </summary>
  80. public override RectangleF GetBoundingBox()
  81. {
  82. float minx = 0, maxx = 0, miny = 0, maxy = 0;
  83. for (int i = 0; i < Points.Count; i++)
  84. {
  85. if (i == 0)
  86. {
  87. minx = maxx = Points[i].X;
  88. miny = maxy = Points[i].Y;
  89. }
  90. else
  91. {
  92. if (Points[i].X > maxx) maxx = Points[i].X;
  93. if (Points[i].X < minx) minx = Points[i].X;
  94. if (Points[i].Y > maxy) maxy = Points[i].Y;
  95. if (Points[i].Y < miny) miny = Points[i].Y;
  96. }
  97. }
  98. return new RectangleF(minx, miny, maxx - minx, maxy - miny);
  99. }
  100. #endregion
  101. #region Draw
  102. /// <summary>
  103. /// 指定如何组合不同的剪辑区域
  104. /// 用于存储是合并视场、还是剪切视场
  105. /// </summary>
  106. public CombineMode combineMode;
  107. /// <summary>
  108. /// Draw rectangle
  109. /// </summary>
  110. /// <param name="g"></param>
  111. public override void Draw(Graphics g)
  112. {
  113. Region reg = g.Clip;
  114. ViewBase view = null;
  115. for (int i = ISurfaceBox.GraphicsList.Count - 1; ;)
  116. {
  117. if (ISurfaceBox.GraphicsList[i].objectType == DrawClass.View)
  118. {
  119. view = (ViewBase)ISurfaceBox.GraphicsList[i];
  120. if (view.combineMode == CombineMode.Union)
  121. {
  122. break;
  123. }
  124. }
  125. i--;
  126. if (i < 0)
  127. {
  128. view.combineMode = CombineMode.Union;
  129. break;
  130. }
  131. }
  132. //获取所有合并的视场
  133. Region union = GetUnionOrDeleteView(CombineMode.Union);
  134. //获取所有删除的视场
  135. Region delete = GetUnionOrDeleteView(CombineMode.Complement);
  136. if (union != null)
  137. {
  138. reg.Xor(union);
  139. }
  140. if (delete != null)
  141. {
  142. reg.Union(delete);
  143. }
  144. SolidBrush sb = new SolidBrush(Color.FromArgb(180, 0, 0, 0));
  145. g.FillRegion(sb, reg);
  146. }
  147. /// <summary>
  148. /// 获取所有合并或删除的视场
  149. /// </summary>
  150. /// <returns></returns>
  151. private Region GetUnionOrDeleteView(CombineMode combineMode)
  152. {
  153. Region region = null;
  154. if (ISurfaceBox.GraphicsList != null && ISurfaceBox.GraphicsList.Count > 0)
  155. {
  156. for (int i = 0; i < ISurfaceBox.GraphicsList.Count; i++)
  157. {
  158. if (ISurfaceBox.GraphicsList[i].objectType == DrawClass.View)
  159. {
  160. ViewBase view = (ViewBase)ISurfaceBox.GraphicsList[i];
  161. GraphicsPath path = new GraphicsPath();
  162. switch (view.drawToolType)
  163. {
  164. case DrawToolType.ViewOval:
  165. path.AddClosedCurve(ISurfaceBox.GraphicsList[i].GetPoints().ToArray());
  166. break;
  167. case DrawToolType.ViewCircle:
  168. path.AddEllipse(ISurfaceBox.GraphicsList[i].Rectangle);
  169. break;
  170. case DrawToolType.ViewSquare:
  171. case DrawToolType.ViewRectangle:
  172. case DrawToolType.ViewTriangle:
  173. case DrawToolType.ViewPolygon:
  174. case DrawToolType.ViewTriangleEx:
  175. case DrawToolType.ViewRectangleEx:
  176. if ((ISurfaceBox.GraphicsList[i]).GetPoints().Count > 2)
  177. {
  178. path.AddPolygon((ISurfaceBox.GraphicsList[i]).GetPoints().ToArray());
  179. }
  180. break;
  181. }
  182. if (view.combineMode == combineMode)
  183. {
  184. if (region == null)
  185. region = new Region(path);
  186. else
  187. region.Union(path);
  188. }
  189. }
  190. }
  191. }
  192. return region;
  193. }
  194. public override void DrawTracker(Graphics g)
  195. {
  196. if (!Selected)
  197. return;
  198. SolidBrush brush = new SolidBrush(Color.FromArgb(184, Color.Black));
  199. var pen = new Pen(Color.FromArgb(0, 148, 255));
  200. switch (drawToolType)
  201. {
  202. case DrawToolType.ViewOval:
  203. g.DrawClosedCurve(pen, GetPoints().ToArray());
  204. break;
  205. case DrawToolType.ViewCircle:
  206. g.DrawEllipse(pen, Rectangle);
  207. break;
  208. case DrawToolType.ViewSquare:
  209. case DrawToolType.ViewRectangle:
  210. case DrawToolType.ViewTriangle:
  211. case DrawToolType.ViewPolygon:
  212. case DrawToolType.ViewTriangleEx:
  213. case DrawToolType.ViewRectangleEx:
  214. if (GetPoints().Count > 2)
  215. {
  216. g.DrawPolygon(pen, GetPoints().ToArray());
  217. }
  218. break;
  219. }
  220. if (Rotatable && Points.Count > 2)
  221. {
  222. for (int i = 1; i <= HandleCount - 1; i++)
  223. {
  224. g.FillRectangle(brush, GetHandleRectangle(i));
  225. g.DrawRectangle(pen, GetHandleRectangle(i));
  226. }
  227. brush = new SolidBrush(Color.Red);
  228. g.FillEllipse(brush, GetHandleRectangle(HandleCount));
  229. brush.Dispose();
  230. }
  231. else
  232. {
  233. for (int i = 1; i <= HandleCount; i++)
  234. {
  235. g.FillRectangle(brush, GetHandleRectangle(i));
  236. g.DrawRectangle(pen, GetHandleRectangle(i));
  237. }
  238. }
  239. }
  240. #endregion
  241. #region Rotate
  242. protected PointF _lastPoint;
  243. protected PointF _lastCenter;
  244. protected bool _isRotating;
  245. /// <summary>
  246. /// 设置可旋转性,用于显示旋转Handle
  247. /// </summary>
  248. public bool Rotatable = false;
  249. /// <summary>
  250. /// 图形斜率,用于旋转
  251. /// </summary>
  252. public double K
  253. {
  254. get;
  255. set;
  256. } = 0;
  257. public virtual void SetK() { }
  258. public virtual PointF Center
  259. {
  260. get
  261. {
  262. var centerX = Rectangle.X + Math.Abs(Rectangle.Width / 2);
  263. var centerY = Rectangle.Y + Math.Abs(Rectangle.Height / 2);
  264. return new PointF(centerX, centerY);
  265. }
  266. set { }
  267. }
  268. protected virtual void StartRotate()
  269. {
  270. _isRotating = true;
  271. _lastCenter = Center;
  272. }
  273. protected virtual void EndRotate()
  274. {
  275. _isRotating = false;
  276. SetK();
  277. }
  278. protected virtual void MoveRotate(PointF point)
  279. {
  280. if (!_isRotating)
  281. {
  282. StartRotate();
  283. _lastPoint = point;
  284. }
  285. double angle = BasicCalculationHelper.CalculateAngle(_lastCenter.X, _lastCenter.Y, _lastPoint.X, _lastPoint.Y, point.X, point.Y);
  286. _lastPoint = point;
  287. for (int i = 0; i < Points.Count; i++)
  288. {
  289. Points[i] = BasicCalculationHelper.GetAnglePoint(Points[i], _lastCenter, angle);
  290. }
  291. }
  292. /// <summary>
  293. /// 标准化外接矩形
  294. /// </summary>
  295. public override void Normalize()
  296. {
  297. Console.WriteLine("Normalize");
  298. if (_isRotating)
  299. EndRotate();
  300. }
  301. #endregion
  302. #region Select
  303. /// <summary>
  304. /// Hit test.
  305. /// Return value: -1 - no hit
  306. /// 0 - hit anywhere
  307. /// > 1 - handle number
  308. /// </summary>
  309. /// <param name="pointscroll"></param>
  310. /// <returns></returns>
  311. public override int HitTest(Point point)
  312. {
  313. if (Selected)
  314. {
  315. for (int i = 1; i <= HandleCount; i++)
  316. {
  317. if (GetHandleRectangle(i).Contains(point))
  318. return i;
  319. }
  320. }
  321. if (PointInObject(point))
  322. return 0;
  323. return -1;
  324. }
  325. protected override bool PointInObject(Point point)
  326. {
  327. int counter = 0;
  328. int i;
  329. double xinters;
  330. PointF p1, p2;
  331. int pointCount = Points.Count;
  332. p1 = Points[0];
  333. for (i = 1; i <= pointCount; i++)
  334. {
  335. p2 = Points[i % pointCount];
  336. if (point.Y > Math.Min(p1.Y, p2.Y)//校验点的Y大于线段端点的最小Y
  337. && point.Y <= Math.Max(p1.Y, p2.Y))//校验点的Y小于线段端点的最大Y
  338. {
  339. if (point.X <= Math.Max(p1.X, p2.X))//校验点的X小于等线段端点的最大X(使用校验点的左射线判断).
  340. {
  341. if (p1.Y != p2.Y)//线段不平行于X轴
  342. {
  343. xinters = (point.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y) + p1.X;
  344. if (p1.X == p2.X || point.X <= xinters)
  345. {
  346. counter++;
  347. }
  348. }
  349. }
  350. }
  351. p1 = p2;
  352. }
  353. return counter % 2 != 0;
  354. }
  355. public override bool IntersectsWith(Rectangle rectangle)
  356. {
  357. return Rectangle.IntersectsWith(rectangle);
  358. }
  359. #endregion
  360. public override void Move(int x, int y)
  361. {
  362. for (int i = 0; i < Points.Count; i++)
  363. {
  364. PointF p = Points[i];
  365. p.X += x;
  366. p.Y += y;
  367. Points[i] = p;
  368. }
  369. OnPropertyChanged();
  370. }
  371. /// <summary>
  372. /// 获取视场面积
  373. /// </summary>
  374. /// <returns></returns>
  375. public virtual double Getacreage()
  376. {
  377. var count = Points.Count;
  378. double area0 = 0;
  379. double area1 = 0;
  380. for (int i = 0; i < count; i++)
  381. {
  382. var x = Points[i].X;
  383. var y = i + 1 < count ? Points[i + 1].Y : Points[0].Y;
  384. area0 += x * y;
  385. x = Points[i].Y;
  386. y = i + 1 < count ? Points[i + 1].X : Points[0].X;
  387. area1 += x * y;
  388. }
  389. return Math.Abs(0.5 * (area0 - area1));
  390. }
  391. }
  392. }