PathFigureHelper.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Media;
  6. namespace HandyControl.Expression.Drawing;
  7. internal static class PathFigureHelper
  8. {
  9. public static IEnumerable<PathSegmentData> AllSegments(this PathFigure figure)
  10. {
  11. if (figure != null && figure.Segments.Count > 0)
  12. {
  13. var startPoint = figure.StartPoint;
  14. // ReSharper disable once GenericEnumeratorNotDisposed
  15. var enumerator = figure.Segments.GetEnumerator();
  16. while (enumerator.MoveNext())
  17. {
  18. var current = enumerator.Current;
  19. var lastPoint = current.GetLastPoint();
  20. yield return new PathSegmentData(startPoint, current);
  21. startPoint = lastPoint;
  22. }
  23. }
  24. }
  25. internal static void ApplyTransform(this PathFigure figure, GeneralTransform transform)
  26. {
  27. figure.StartPoint = transform.Transform(figure.StartPoint);
  28. for (var i = 0; i < figure.Segments.Count; i++)
  29. {
  30. var segment =
  31. PathSegmentHelper.ApplyTransform(figure.Segments[i], figure.StartPoint, transform);
  32. if (!Equals(figure.Segments[i], segment)) figure.Segments[i] = segment;
  33. }
  34. }
  35. internal static void FlattenFigure(PathFigure figure, IList<Point> points, double tolerance,
  36. bool removeRepeat)
  37. {
  38. if (figure == null) throw new ArgumentNullException(nameof(figure));
  39. if (points == null) throw new ArgumentNullException(nameof(points));
  40. if (tolerance < 0.0) throw new ArgumentOutOfRangeException(nameof(tolerance));
  41. var list = removeRepeat ? new List<Point>() : points;
  42. list.Add(figure.StartPoint);
  43. foreach (var data in figure.AllSegments())
  44. data.PathSegment.FlattenSegment(list, data.StartPoint, tolerance);
  45. if (figure.IsClosed) list.Add(figure.StartPoint);
  46. if (removeRepeat && list.Count > 0)
  47. {
  48. points.Add(list[0]);
  49. for (var i = 1; i < list.Count; i++)
  50. if (!MathHelper.IsVerySmall(GeometryHelper.SquaredDistance(points.Last(), list[i])))
  51. points.Add(list[i]);
  52. }
  53. }
  54. internal static bool SyncEllipseFigure(PathFigure figure, Rect bounds, SweepDirection sweepDirection,
  55. bool isFilled = true)
  56. {
  57. var flag = false;
  58. var pointArray = new Point[2];
  59. var size = new Size(bounds.Width / 2.0, bounds.Height / 2.0);
  60. var point = bounds.Center();
  61. if (size.Width > size.Height)
  62. {
  63. pointArray[0] = new Point(bounds.Left, point.Y);
  64. pointArray[1] = new Point(bounds.Right, point.Y);
  65. }
  66. else
  67. {
  68. pointArray[0] = new Point(point.X, bounds.Top);
  69. pointArray[1] = new Point(point.X, bounds.Bottom);
  70. }
  71. flag |= figure.SetIfDifferent(PathFigure.IsClosedProperty, true);
  72. flag |= figure.SetIfDifferent(PathFigure.IsFilledProperty, isFilled);
  73. flag |= figure.SetIfDifferent(PathFigure.StartPointProperty, pointArray[0]);
  74. flag |= figure.Segments.EnsureListCount(2, () => new ArcSegment());
  75. flag |= GeometryHelper.EnsureSegmentType(out var segment, figure.Segments, 0, () => new ArcSegment());
  76. flag |= segment.SetIfDifferent(ArcSegment.PointProperty, pointArray[1]);
  77. flag |= segment.SetIfDifferent(ArcSegment.SizeProperty, size);
  78. flag |= segment.SetIfDifferent(ArcSegment.IsLargeArcProperty, false);
  79. flag |= segment.SetIfDifferent(ArcSegment.SweepDirectionProperty, sweepDirection);
  80. flag |= GeometryHelper.EnsureSegmentType(out segment, figure.Segments, 1, () => new ArcSegment());
  81. flag |= segment.SetIfDifferent(ArcSegment.PointProperty, pointArray[0]);
  82. flag |= segment.SetIfDifferent(ArcSegment.SizeProperty, size);
  83. flag |= segment.SetIfDifferent(ArcSegment.IsLargeArcProperty, false);
  84. return flag | segment.SetIfDifferent(ArcSegment.SweepDirectionProperty, sweepDirection);
  85. }
  86. internal static bool SyncPolylineFigure(PathFigure figure, IList<Point> points, bool isClosed,
  87. bool isFilled = true)
  88. {
  89. if (figure == null) throw new ArgumentNullException(nameof(figure));
  90. var flag = false;
  91. if (points == null || points.Count == 0)
  92. {
  93. flag |= figure.ClearIfSet(PathFigure.StartPointProperty);
  94. flag |= figure.Segments.EnsureListCount(0);
  95. }
  96. else
  97. {
  98. flag |= figure.SetIfDifferent(PathFigure.StartPointProperty, points[0]);
  99. flag |= figure.Segments.EnsureListCount(1, () => new PolyLineSegment());
  100. flag |= PathSegmentHelper.SyncPolylineSegment(figure.Segments, 0, points, 1,
  101. points.Count - 1);
  102. }
  103. flag |= figure.SetIfDifferent(PathFigure.IsClosedProperty, isClosed);
  104. return flag | figure.SetIfDifferent(PathFigure.IsFilledProperty, isFilled);
  105. }
  106. }