// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageProcessor { using System; /// /// Provides common mathematical methods. /// internal static class ImageMaths { /// /// Represents PI, the ratio of a circle's circumference to its diameter. /// // ReSharper disable once InconsistentNaming public const float PI = 3.1415926535897931f; /// /// Implementation of 1D Gaussian G(x) function /// /// The x provided to G(x). /// The spread of the blur. /// The Gaussian G(x) public static float Gaussian(float x, float sigma) { const float Numerator = 1.0f; float denominator = (float)(Math.Sqrt(2 * PI) * sigma); float exponentNumerator = -x * x; float exponentDenominator = (float)(2 * Math.Pow(sigma, 2)); float left = Numerator / denominator; float right = (float)Math.Exp(exponentNumerator / exponentDenominator); return left * right; } /// /// Returns the result of a B-C filter against the given value. /// /// /// The value to process. /// The B-Spline curve variable. /// The Cardinal curve variable. /// /// The . /// public static float GetBcValue(float x, float b, float c) { float temp; if (x < 0) { x = -x; } temp = x * x; if (x < 1) { x = ((12 - (9 * b) - (6 * c)) * (x * temp)) + ((-18 + (12 * b) + (6 * c)) * temp) + (6 - (2 * b)); return x / 6; } if (x < 2) { x = ((-b - (6 * c)) * (x * temp)) + (((6 * b) + (30 * c)) * temp) + (((-12 * b) - (48 * c)) * x) + ((8 * b) + (24 * c)); return x / 6; } return 0; } /// /// Gets the result of a sine cardinal function for the given value. /// /// /// The value to calculate the result for. /// /// /// The . /// public static float SinC(float x) { const float Epsilon = .00001f; if (Math.Abs(x) > Epsilon) { x *= PI; return Clean((float)Math.Sin(x) / x); } return 1.0f; } /// /// Returns the given degrees converted to radians. /// /// /// The angle in degrees. /// /// /// The representing the degree as radians. /// public static double DegreesToRadians(double angleInDegrees) { return angleInDegrees * (PI / 180); } /// /// Rotates one point around another /// /// /// The point to rotate. /// The rotation angle in degrees. /// The centre point of rotation. If not set the point will equal /// /// /// Rotated point public static Point RotatePoint(Point pointToRotate, double angleInDegrees, Point? centerPoint = null) { Point center = centerPoint ?? Point.Empty; double angleInRadians = DegreesToRadians(angleInDegrees); double cosTheta = Math.Cos(angleInRadians); double sinTheta = Math.Sin(angleInRadians); return new Point { X = (int)((cosTheta * (pointToRotate.X - center.X)) - (sinTheta * (pointToRotate.Y - center.Y)) + center.X), Y = (int)((sinTheta * (pointToRotate.X - center.X)) + (cosTheta * (pointToRotate.Y - center.Y)) + center.Y) }; } /// /// Calculates the new size after rotation. /// /// The width of the image. /// The height of the image. /// The angle of rotation. /// The new size of the image public static Rectangle GetBoundingRotatedRectangle(int width, int height, float angleInDegrees) { // Check first clockwise. double radians = DegreesToRadians(angleInDegrees); double radiansSin = Math.Sin(radians); double radiansCos = Math.Cos(radians); double width1 = (height * radiansSin) + (width * radiansCos); double height1 = (width * radiansSin) + (height * radiansCos); // Find dimensions in the other direction radiansSin = Math.Sin(-radians); radiansCos = Math.Cos(-radians); double width2 = (height * radiansSin) + (width * radiansCos); double height2 = (width * radiansSin) + (height * radiansCos); // Get the external vertex for the rotation Rectangle result = new Rectangle( 0, 0, Convert.ToInt32(Math.Max(Math.Abs(width1), Math.Abs(width2))), Convert.ToInt32(Math.Max(Math.Abs(height1), Math.Abs(height2)))); return result; } /// /// Ensures that any passed double is correctly rounded to zero /// /// The value to clean. /// /// The /// . private static float Clean(float x) { const float Epsilon = .00001f; if (Math.Abs(x) < Epsilon) { return 0f; } return x; } } }