GeometryHelper.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.CompilerServices;
  4. using System.Windows;
  5. using System.Windows.Media;
  6. namespace HandyControl.Expression.Drawing;
  7. public static class GeometryHelper
  8. {
  9. internal static void ApplyTransform(this IList<Point> points, GeneralTransform transform)
  10. {
  11. for (var i = 0; i < points.Count; i++) points[i] = transform.Transform(points[i]);
  12. }
  13. internal static Rect Bounds(this Size size)
  14. {
  15. return new(0.0, 0.0, size.Width, size.Height);
  16. }
  17. internal static Point Center(this Rect rect)
  18. {
  19. return new(rect.X + rect.Width / 2.0, rect.Y + rect.Height / 2.0);
  20. }
  21. internal static Vector Subtract(this Point lhs, Point rhs)
  22. {
  23. return new(lhs.X - rhs.X, lhs.Y - rhs.Y);
  24. }
  25. internal static Thickness Subtract(this Rect lhs, Rect rhs)
  26. {
  27. return new(rhs.Left - lhs.Left,
  28. rhs.Top - lhs.Top, lhs.Right - rhs.Right,
  29. lhs.Bottom - rhs.Bottom);
  30. }
  31. internal static Point Lerp(Point pointA, Point pointB, double alpha)
  32. {
  33. return new(
  34. MathHelper.Lerp(pointA.X, pointB.X, alpha),
  35. MathHelper.Lerp(pointA.Y, pointB.Y, alpha));
  36. }
  37. internal static Vector Lerp(Vector vectorA, Vector vectorB, double alpha)
  38. {
  39. return new(MathHelper.Lerp(vectorA.X, vectorB.X, alpha),
  40. MathHelper.Lerp(vectorA.Y, vectorB.Y, alpha));
  41. }
  42. internal static double Distance(Point lhs, Point rhs)
  43. {
  44. var num = lhs.X - rhs.X;
  45. var num2 = lhs.Y - rhs.Y;
  46. return Math.Sqrt(num * num + num2 * num2);
  47. }
  48. internal static Rect Resize(this Rect rect, double ratio)
  49. {
  50. return rect.Resize(ratio, ratio);
  51. }
  52. internal static Rect Resize(this Rect rect, double ratioX, double ratioY)
  53. {
  54. var point = rect.Center();
  55. var width = rect.Width * ratioX;
  56. var height = rect.Height * ratioY;
  57. return new Rect(point.X - width / 2.0, point.Y - height / 2.0, width, height);
  58. }
  59. internal static Rect GetStretchBound(Rect logicalBound, Stretch stretch, Size aspectRatio)
  60. {
  61. if (stretch == Stretch.None) stretch = Stretch.Fill;
  62. if (stretch == Stretch.Fill || !aspectRatio.HasValidArea()) return logicalBound;
  63. var point = logicalBound.Center();
  64. if (stretch == Stretch.Uniform)
  65. {
  66. if (aspectRatio.Width * logicalBound.Height < logicalBound.Width * aspectRatio.Height)
  67. logicalBound.Width = logicalBound.Height * aspectRatio.Width / aspectRatio.Height;
  68. else
  69. logicalBound.Height = logicalBound.Width * aspectRatio.Height / aspectRatio.Width;
  70. }
  71. else if (stretch == Stretch.UniformToFill)
  72. {
  73. if (aspectRatio.Width * logicalBound.Height < logicalBound.Width * aspectRatio.Height)
  74. logicalBound.Height = logicalBound.Width * aspectRatio.Height / aspectRatio.Width;
  75. else
  76. logicalBound.Width = logicalBound.Height * aspectRatio.Width / aspectRatio.Height;
  77. }
  78. return new Rect(point.X - logicalBound.Width / 2.0, point.Y - logicalBound.Height / 2.0,
  79. logicalBound.Width, logicalBound.Height);
  80. }
  81. internal static Point GetArcPoint(double degree)
  82. {
  83. var a = degree * 3.1415926535897931 / 180.0;
  84. return new Point(0.5 + 0.5 * Math.Sin(a), 0.5 - 0.5 * Math.Cos(a));
  85. }
  86. [MethodImpl(MethodImplOptions.NoInlining)]
  87. internal static Point GetArcPoint(double degree, Rect bound)
  88. {
  89. var arcPoint = GetArcPoint(degree);
  90. return RelativeToAbsolutePoint(bound, arcPoint);
  91. }
  92. internal static Point RelativeToAbsolutePoint(Rect bound, Point relative)
  93. {
  94. return new(bound.X + relative.X * bound.Width, bound.Y + relative.Y * bound.Height);
  95. }
  96. internal static double SquaredDistance(Point lhs, Point rhs)
  97. {
  98. var num = lhs.X - rhs.X;
  99. var num2 = lhs.Y - rhs.Y;
  100. return num * num + num2 * num2;
  101. }
  102. internal static Point Midpoint(Point lhs, Point rhs)
  103. {
  104. return new((lhs.X + rhs.X) / 2.0, (lhs.Y + rhs.Y) / 2.0);
  105. }
  106. internal static bool HasValidArea(this Size size)
  107. {
  108. return size.Width > 0.0 && size.Height > 0.0 && !double.IsInfinity(size.Width) &&
  109. !double.IsInfinity(size.Height);
  110. }
  111. internal static Rect Inflate(Rect rect, double offset)
  112. {
  113. return Inflate(rect, new Thickness(offset));
  114. }
  115. internal static Rect Inflate(Rect rect, Thickness thickness)
  116. {
  117. var width = rect.Width + thickness.Left + thickness.Right;
  118. var height = rect.Height + thickness.Top + thickness.Bottom;
  119. var x = rect.X - thickness.Left;
  120. if (width < 0.0)
  121. {
  122. x += width / 2.0;
  123. width = 0.0;
  124. }
  125. var y = rect.Y - thickness.Top;
  126. if (height < 0.0)
  127. {
  128. y += height / 2.0;
  129. height = 0.0;
  130. }
  131. return new Rect(x, y, width, height);
  132. }
  133. internal static double Dot(Point lhs, Point rhs)
  134. {
  135. return lhs.X * rhs.X + lhs.Y * rhs.Y;
  136. }
  137. internal static double Dot(Vector lhs, Vector rhs)
  138. {
  139. return lhs.X * rhs.X + lhs.Y * rhs.Y;
  140. }
  141. internal static Point Plus(this Point lhs, Point rhs)
  142. {
  143. return new(lhs.X + rhs.X, lhs.Y + rhs.Y);
  144. }
  145. internal static Point Minus(this Point lhs, Point rhs)
  146. {
  147. return new(lhs.X - rhs.X, lhs.Y - rhs.Y);
  148. }
  149. internal static Vector Normal(Point lhs, Point rhs)
  150. {
  151. return new Vector(lhs.Y - rhs.Y, rhs.X - lhs.X).Normalized();
  152. }
  153. internal static Vector Normalized(this Vector vector)
  154. {
  155. var vector2 = new Vector(vector.X, vector.Y);
  156. var length = vector2.Length;
  157. if (MathHelper.IsVerySmall(length)) return new Vector(0.0, 1.0);
  158. return vector2 / length;
  159. }
  160. internal static double Determinant(Point lhs, Point rhs)
  161. {
  162. return lhs.X * rhs.Y - lhs.Y * rhs.X;
  163. }
  164. internal static bool EnsureSegmentType<T>(out T result, IList<PathSegment> list, int index,
  165. Func<T> factory) where T : PathSegment
  166. {
  167. result = list[index] as T;
  168. if (result == null)
  169. {
  170. list[index] = result = factory();
  171. return true;
  172. }
  173. return false;
  174. }
  175. internal static bool EnsureGeometryType<T>(out T result, ref Geometry value, Func<T> factory)
  176. where T : Geometry
  177. {
  178. result = value as T;
  179. if (result == null)
  180. {
  181. value = result = factory();
  182. return true;
  183. }
  184. return false;
  185. }
  186. }