diff --git a/build.cmd b/build.cmd index eaa54e8..e55aad0 100644 --- a/build.cmd +++ b/build.cmd @@ -14,7 +14,7 @@ if not "%GitVersion_NuGetVersion%" == "" ( ) if not "%errorlevel%"=="0" goto failure -dotnet test ./tests/SixLabors.Core.Tests/SixLabors.Primitives.Tests.csproj +dotnet test ./tests/SixLabors.Core.Tests/SixLabors.Core.Tests.csproj if not "%GitVersion_NuGetVersion%" == "" ( diff --git a/src/SixLabors.Core/MathF.cs b/src/SixLabors.Core/MathF.cs index a4ad9ed..3079c91 100644 --- a/src/SixLabors.Core/MathF.cs +++ b/src/SixLabors.Core/MathF.cs @@ -1,14 +1,17 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Runtime.CompilerServices; -namespace SixLabors +#if NETCOREAPP2_0 +[assembly: TypeForwardedTo(typeof(System.MathF))] +#else +namespace System { /// /// Provides single-precision floating point constants and static methods for trigonometric, logarithmic, and other common mathematical functions. /// + /// MathF emulation on platforms that don't support it natively. // ReSharper disable InconsistentNaming internal static class MathF { @@ -84,19 +87,6 @@ public static float Cos(float f) return (float)Math.Cos(f); } - /// - /// Converts a degree (360-periodic) angle to a radian (2*Pi-periodic) angle. - /// - /// The angle in degrees. - /// - /// The representing the degree as radians. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float ToRadians(float degree) - { - return degree * (PI / 180F); - } - /// /// Returns e raised to the specified power. /// @@ -171,19 +161,6 @@ public static float Pow(float x, float y) return (float)Math.Pow(x, y); } - /// - /// Converts a radian (2*Pi-periodic) angle to a degree (360-periodic) angle. - /// - /// The angle in radians. - /// - /// The representing the degree as radians. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float ToDegree(float radian) - { - return radian / (PI / 180F); - } - /// /// Rounds a single-precision floating-point value to the nearest integral value. /// @@ -233,26 +210,6 @@ public static float Sin(float f) return (float)Math.Sin(f); } - /// - /// Returns the result of a normalized sine cardinal function for the given value. - /// SinC(x) = sin(pi*x)/(pi*x). - /// - /// A single-precision floating-point number to calculate the result for. - /// - /// The sine cardinal of . - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float SinC(float f) - { - if (Abs(f) > Constants.Epsilon) - { - f *= PI; - return Clean(Sin(f) / f); - } - - return 1F; - } - /// /// Returns the square root of a specified number. /// @@ -269,23 +226,6 @@ public static float Sqrt(float f) { return (float)Math.Sqrt(f); } - - /// - /// Ensures that any passed float is correctly rounded to zero - /// - /// The value to clean. - /// - /// The - /// . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static float Clean(float x) - { - if (Abs(x) < Constants.Epsilon) - { - return 0F; - } - - return x; - } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/SixLabors.Core/MathFExtensions.cs b/src/SixLabors.Core/MathFExtensions.cs new file mode 100644 index 0000000..27d18d4 --- /dev/null +++ b/src/SixLabors.Core/MathFExtensions.cs @@ -0,0 +1,40 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors +{ + /// + /// Provides common mathematical methods. + /// + internal static class MathFExtensions + { + /// + /// Converts a degree (360-periodic) angle to a radian (2*Pi-periodic) angle. + /// + /// The angle in degrees. + /// + /// The representing the degree as radians. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float DegreeToRadian(float degree) + { + return degree * (MathF.PI / 180F); + } + + /// + /// Converts a radian (2*Pi-periodic) angle to a degree (360-periodic) angle. + /// + /// The angle in radians. + /// + /// The representing the degree as radians. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float RadianToDegree(float radian) + { + return radian / (MathF.PI / 180F); + } + } +} \ No newline at end of file diff --git a/src/SixLabors.Core/Primitives/Matrix3x2Extensions.cs b/src/SixLabors.Core/Primitives/Matrix3x2Extensions.cs index 80c4f46..55d75b8 100644 --- a/src/SixLabors.Core/Primitives/Matrix3x2Extensions.cs +++ b/src/SixLabors.Core/Primitives/Matrix3x2Extensions.cs @@ -50,12 +50,12 @@ public static class Matrix3x2Extensions public static Matrix3x2 CreateScale(float scale, PointF centerPoint) => Matrix3x2.CreateScale(scale, centerPoint); /// - /// Creates a skew matrix from the given angles in radians. + /// Creates a skew matrix from the given angles in degrees. /// /// The X angle, in degrees. /// The Y angle, in degrees. /// A skew matrix. - public static Matrix3x2 CreateSkewDegrees(float degreesX, float degreesY) => Matrix3x2.CreateSkew(MathF.ToRadians(degreesX), MathF.ToRadians(degreesY)); + public static Matrix3x2 CreateSkewDegrees(float degreesX, float degreesY) => Matrix3x2.CreateSkew(MathFExtensions.DegreeToRadian(degreesX), MathFExtensions.DegreeToRadian(degreesY)); /// /// Creates a skew matrix from the given angles in radians and a center point. @@ -67,20 +67,20 @@ public static class Matrix3x2Extensions public static Matrix3x2 CreateSkew(float radiansX, float radiansY, PointF centerPoint) => Matrix3x2.CreateSkew(radiansX, radiansY, centerPoint); /// - /// Creates a skew matrix from the given angles in radians and a center point. + /// Creates a skew matrix from the given angles in degrees and a center point. /// /// The X angle, in degrees. /// The Y angle, in degrees. /// The center point. /// A skew matrix. - public static Matrix3x2 CreateSkewDegrees(float degreesX, float degreesY, PointF centerPoint) => Matrix3x2.CreateSkew(MathF.ToRadians(degreesX), MathF.ToRadians(degreesY), centerPoint); + public static Matrix3x2 CreateSkewDegrees(float degreesX, float degreesY, PointF centerPoint) => Matrix3x2.CreateSkew(MathFExtensions.DegreeToRadian(degreesX), MathFExtensions.DegreeToRadian(degreesY), centerPoint); /// - /// Creates a rotation matrix using the given rotation in radians. + /// Creates a rotation matrix using the given rotation in degrees. /// /// The amount of rotation, in degrees. /// A rotation matrix. - public static Matrix3x2 CreateRotationDegrees(float degrees) => Matrix3x2.CreateRotation(MathF.ToRadians(degrees)); + public static Matrix3x2 CreateRotationDegrees(float degrees) => Matrix3x2.CreateRotation(MathFExtensions.DegreeToRadian(degrees)); /// /// Creates a rotation matrix using the given rotation in radians and a center point. @@ -91,11 +91,11 @@ public static class Matrix3x2Extensions public static Matrix3x2 CreateRotation(float radians, PointF centerPoint) => Matrix3x2.CreateRotation(radians, centerPoint); /// - /// Creates a rotation matrix using the given rotation in radians and a center point. + /// Creates a rotation matrix using the given rotation in degrees and a center point. /// /// The amount of rotation, in degrees. /// The center point. /// A rotation matrix. - public static Matrix3x2 CreateRotationDegrees(float degrees, PointF centerPoint) => Matrix3x2.CreateRotation(MathF.ToRadians(degrees), centerPoint); + public static Matrix3x2 CreateRotationDegrees(float degrees, PointF centerPoint) => Matrix3x2.CreateRotation(MathFExtensions.DegreeToRadian(degrees), centerPoint); } -} +} \ No newline at end of file diff --git a/src/SixLabors.Core/SixLabors.Core.csproj b/src/SixLabors.Core/SixLabors.Core.csproj index e38298f..dee1f1a 100644 --- a/src/SixLabors.Core/SixLabors.Core.csproj +++ b/src/SixLabors.Core/SixLabors.Core.csproj @@ -1,48 +1,49 @@  - - Low level primitives for use across Six Labors projects.. - $(packageversion) - 0.1.0-alpha2 - Six Labors - netstandard1.1 - true - true - SixLabors.Core - SixLabors.Core - rectangle;point;size,primitives - https://raw.githubusercontent.com/SixLabors/Home/master/logo.png - https://github.com/SixLabors/Core - http://www.apache.org/licenses/LICENSE-2.0 - git - https://github.com/SixLabors/Core - false - false - false - false - false - false - false - false - false - false - full - SixLabors - + + Low level primitives for use across Six Labors projects.. + $(packageversion) + 0.1.0-alpha2 + Six Labors + netstandard1.1;netcoreapp2.0; + true + true + SixLabors.Core + SixLabors.Core + rectangle;point;size,primitives + https://raw.githubusercontent.com/SixLabors/Home/master/logo.png + https://github.com/SixLabors/Core + http://www.apache.org/licenses/LICENSE-2.0 + git + https://github.com/SixLabors/Core + false + false + false + false + false + false + false + false + false + false + full + SixLabors + - - ..\SixLabors.ruleset - + + ..\SixLabors.ruleset + - - - - - - - All - - - + + + + + + All + + + + + \ No newline at end of file diff --git a/tests/SixLabors.Core.Tests/Helpers/FloatRoundingComparer.cs b/tests/SixLabors.Core.Tests/Helpers/FloatRoundingComparer.cs new file mode 100644 index 0000000..e3ef6a0 --- /dev/null +++ b/tests/SixLabors.Core.Tests/Helpers/FloatRoundingComparer.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace SixLabors.Tests.Helpers +{ + /// + /// Allows the comparison of single-precision floating point values by precision. + /// + public struct FloatRoundingComparer : IEqualityComparer, IEqualityComparer + { + /// + /// Initializes a new instance of the struct. + /// + /// The number of decimal places (valid values: 0-7) + public FloatRoundingComparer(int precision) + { + Guard.MustBeBetweenOrEqualTo(precision, 0, 7, nameof(precision)); + this.Precision = precision; + } + + /// + /// Gets the number of decimal places (valid values: 0-7) + /// + public int Precision { get; } + + /// + public bool Equals(float x, float y) + { + float xp = (float)Math.Round(x, this.Precision, MidpointRounding.AwayFromZero); + float yp = (float)Math.Round(y, this.Precision, MidpointRounding.AwayFromZero); + + return Comparer.Default.Compare(xp, yp) == 0; + } + + /// + public bool Equals(Vector4 x, Vector4 y) + { + return this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z) && this.Equals(x.W, y.W); + } + + /// + public int GetHashCode(float obj) + { + unchecked + { + int hashCode = obj.GetHashCode(); + hashCode = (hashCode * 397) ^ this.Precision.GetHashCode(); + return hashCode; + } + } + + /// + public int GetHashCode(Vector4 obj) => HashHelpers.Combine(obj.GetHashCode(), this.Precision.GetHashCode()); + } +} \ No newline at end of file diff --git a/tests/SixLabors.Core.Tests/Helpers/MathFTests.cs b/tests/SixLabors.Core.Tests/Helpers/MathFTests.cs new file mode 100644 index 0000000..4772599 --- /dev/null +++ b/tests/SixLabors.Core.Tests/Helpers/MathFTests.cs @@ -0,0 +1,107 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using Xunit; + +namespace SixLabors.Tests.Helpers +{ + public class MathFTests + { + [Fact] + public void MathF_PI_Is_Equal() + { + Assert.Equal(MathF.PI, (float)Math.PI); + } + + [Fact] + public void MathF_Ceililng_Is_Equal() + { + Assert.Equal(MathF.Ceiling(0.3333F), (float)Math.Ceiling(0.3333F)); + } + + [Fact] + public void MathF_Cos_Is_Equal() + { + Assert.Equal(MathF.Cos(0.3333F), (float)Math.Cos(0.3333F)); + } + + [Fact] + public void MathF_Abs_Is_Equal() + { + Assert.Equal(MathF.Abs(-0.3333F), (float)Math.Abs(-0.3333F)); + } + + [Fact] + public void MathF_Atan2_Is_Equal() + { + Assert.Equal(MathF.Atan2(1.2345F, 1.2345F), (float)Math.Atan2(1.2345F, 1.2345F)); + } + + [Fact] + public void MathF_Exp_Is_Equal() + { + Assert.Equal(MathF.Exp(1.2345F), (float)Math.Exp(1.2345F)); + } + + [Fact] + public void MathF_Floor_Is_Equal() + { + Assert.Equal(MathF.Floor(1.2345F), (float)Math.Floor(1.2345F)); + } + + [Fact] + public void MathF_Min_Is_Equal() + { + Assert.Equal(MathF.Min(1.2345F, 5.4321F), (float)Math.Min(1.2345F, 5.4321F)); + } + + [Fact] + public void MathF_Max_Is_Equal() + { + Assert.Equal(MathF.Max(1.2345F, 5.4321F), (float)Math.Max(1.2345F, 5.4321F)); + } + + [Fact] + public void MathF_Pow_Is_Equal() + { + Assert.Equal(MathF.Pow(1.2345F, 5.4321F), (float)Math.Pow(1.2345F, 5.4321F)); + } + + [Fact] + public void MathF_Round_Is_Equal() + { + Assert.Equal(MathF.Round(1.2345F), (float)Math.Round(1.2345F)); + } + + [Fact] + public void MathF_Round_With_Midpoint_Is_Equal() + { + Assert.Equal(MathF.Round(1.2345F, MidpointRounding.AwayFromZero), (float)Math.Round(1.2345F, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void MathF_Sin_Is_Equal() + { + Assert.Equal(MathF.Sin(1.2345F), (float)Math.Sin(1.2345F)); + } + + [Fact] + public void MathF_Sqrt_Is_Equal() + { + Assert.Equal(MathF.Sqrt(2F), (float)Math.Sqrt(2F)); + } + + [Fact] + public void Convert_Degree_To_Radian() + { + Assert.Equal((float)(Math.PI / 2D), MathFExtensions.DegreeToRadian(90F), new FloatRoundingComparer(6)); + } + + [Fact] + public void Convert_Radian_To_Degree() + { + Assert.Equal(60F, MathFExtensions.RadianToDegree((float)(Math.PI / 3D)), new FloatRoundingComparer(5)); + } + } +} \ No newline at end of file diff --git a/tests/SixLabors.Core.Tests/Primitives/PointTests.cs b/tests/SixLabors.Core.Tests/Primitives/PointTests.cs index a1880d0..79fd0bd 100644 --- a/tests/SixLabors.Core.Tests/Primitives/PointTests.cs +++ b/tests/SixLabors.Core.Tests/Primitives/PointTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Globalization; using System.Numerics; using Xunit; diff --git a/tests/SixLabors.Core.Tests/SixLabors.Core.Tests.csproj b/tests/SixLabors.Core.Tests/SixLabors.Core.Tests.csproj index a80bf5a..6869491 100644 --- a/tests/SixLabors.Core.Tests/SixLabors.Core.Tests.csproj +++ b/tests/SixLabors.Core.Tests/SixLabors.Core.Tests.csproj @@ -2,7 +2,7 @@ 0.0.0 - netcoreapp1.1 + netcoreapp1.1;netcoreapp2.0; SixLabors.Core.Tests SixLabors.Shapes.Tests true