using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Media; namespace HandyControl.Expression.Drawing { public static class GeometryHelper { internal static void ApplyTransform(this IList points, GeneralTransform transform) { for (var i = 0; i < points.Count; i++) points[i] = transform.Transform(points[i]); } internal static Rect Bounds(this Size size) { return new(0.0, 0.0, size.Width, size.Height); } internal static Point Center(this Rect rect) { return new(rect.X + rect.Width / 2.0, rect.Y + rect.Height / 2.0); } internal static Vector Subtract(this Point lhs, Point rhs) { return new(lhs.X - rhs.X, lhs.Y - rhs.Y); } internal static Thickness Subtract(this Rect lhs, Rect rhs) { return new(rhs.Left - lhs.Left, rhs.Top - lhs.Top, lhs.Right - rhs.Right, lhs.Bottom - rhs.Bottom); } internal static Point Lerp(Point pointA, Point pointB, double alpha) { return new( MathHelper.Lerp(pointA.X, pointB.X, alpha), MathHelper.Lerp(pointA.Y, pointB.Y, alpha)); } internal static Vector Lerp(Vector vectorA, Vector vectorB, double alpha) { return new(MathHelper.Lerp(vectorA.X, vectorB.X, alpha), MathHelper.Lerp(vectorA.Y, vectorB.Y, alpha)); } internal static double Distance(Point lhs, Point rhs) { var num = lhs.X - rhs.X; var num2 = lhs.Y - rhs.Y; return Math.Sqrt(num * num + num2 * num2); } internal static Rect Resize(this Rect rect, double ratio) { return rect.Resize(ratio, ratio); } internal static Rect Resize(this Rect rect, double ratioX, double ratioY) { var point = rect.Center(); var width = rect.Width * ratioX; var height = rect.Height * ratioY; return new Rect(point.X - width / 2.0, point.Y - height / 2.0, width, height); } internal static Rect GetStretchBound(Rect logicalBound, Stretch stretch, Size aspectRatio) { if (stretch == Stretch.None) stretch = Stretch.Fill; if (stretch == Stretch.Fill || !aspectRatio.HasValidArea()) return logicalBound; var point = logicalBound.Center(); if (stretch == Stretch.Uniform) { if (aspectRatio.Width * logicalBound.Height < logicalBound.Width * aspectRatio.Height) logicalBound.Width = logicalBound.Height * aspectRatio.Width / aspectRatio.Height; else logicalBound.Height = logicalBound.Width * aspectRatio.Height / aspectRatio.Width; } else if (stretch == Stretch.UniformToFill) { if (aspectRatio.Width * logicalBound.Height < logicalBound.Width * aspectRatio.Height) logicalBound.Height = logicalBound.Width * aspectRatio.Height / aspectRatio.Width; else logicalBound.Width = logicalBound.Height * aspectRatio.Width / aspectRatio.Height; } return new Rect(point.X - logicalBound.Width / 2.0, point.Y - logicalBound.Height / 2.0, logicalBound.Width, logicalBound.Height); } internal static Point GetArcPoint(double degree) { var a = degree * 3.1415926535897931 / 180.0; return new Point(0.5 + 0.5 * Math.Sin(a), 0.5 - 0.5 * Math.Cos(a)); } [MethodImpl(MethodImplOptions.NoInlining)] internal static Point GetArcPoint(double degree, Rect bound) { var arcPoint = GetArcPoint(degree); return RelativeToAbsolutePoint(bound, arcPoint); } internal static Point RelativeToAbsolutePoint(Rect bound, Point relative) { return new(bound.X + relative.X * bound.Width, bound.Y + relative.Y * bound.Height); } internal static double SquaredDistance(Point lhs, Point rhs) { var num = lhs.X - rhs.X; var num2 = lhs.Y - rhs.Y; return num * num + num2 * num2; } internal static Point Midpoint(Point lhs, Point rhs) { return new((lhs.X + rhs.X) / 2.0, (lhs.Y + rhs.Y) / 2.0); } internal static bool HasValidArea(this Size size) { return size.Width > 0.0 && size.Height > 0.0 && !double.IsInfinity(size.Width) && !double.IsInfinity(size.Height); } internal static Rect Inflate(Rect rect, double offset) { return Inflate(rect, new Thickness(offset)); } internal static Rect Inflate(Rect rect, Thickness thickness) { var width = rect.Width + thickness.Left + thickness.Right; var height = rect.Height + thickness.Top + thickness.Bottom; var x = rect.X - thickness.Left; if (width < 0.0) { x += width / 2.0; width = 0.0; } var y = rect.Y - thickness.Top; if (height < 0.0) { y += height / 2.0; height = 0.0; } return new Rect(x, y, width, height); } internal static double Dot(Point lhs, Point rhs) { return lhs.X * rhs.X + lhs.Y * rhs.Y; } internal static double Dot(Vector lhs, Vector rhs) { return lhs.X * rhs.X + lhs.Y * rhs.Y; } internal static Point Plus(this Point lhs, Point rhs) { return new(lhs.X + rhs.X, lhs.Y + rhs.Y); } internal static Point Minus(this Point lhs, Point rhs) { return new(lhs.X - rhs.X, lhs.Y - rhs.Y); } internal static Vector Normal(Point lhs, Point rhs) { return new Vector(lhs.Y - rhs.Y, rhs.X - lhs.X).Normalized(); } internal static Vector Normalized(this Vector vector) { var vector2 = new Vector(vector.X, vector.Y); var length = vector2.Length; if (MathHelper.IsVerySmall(length)) return new Vector(0.0, 1.0); return vector2 / length; } internal static double Determinant(Point lhs, Point rhs) { return lhs.X * rhs.Y - lhs.Y * rhs.X; } internal static bool EnsureSegmentType(out T result, IList list, int index, Func factory) where T : PathSegment { result = list[index] as T; if (result == null) { list[index] = result = factory(); return true; } return false; } internal static bool EnsureGeometryType(out T result, ref Geometry value, Func factory) where T : Geometry { result = value as T; if (result == null) { value = result = factory(); return true; } return false; } } }