Browse Source

[SL.Core] add matrix tests & fix GetHashCode

pull/1087/head
Scott Williams 9 years ago
parent
commit
f4626c1ceb
  1. 9
      src/Shared/AssemblyInfo.Common.cs
  2. 210
      src/SixLabors.Primitives/ApproximateFloatComparer.cs
  3. 11
      src/SixLabors.Primitives/Ellipse.cs
  4. 23
      src/SixLabors.Primitives/HashHelpers.cs
  5. 5
      src/SixLabors.Primitives/LongRational.cs
  6. 4
      src/SixLabors.Primitives/MathF.cs
  7. 51
      src/SixLabors.Primitives/Matrix.cs
  8. 25
      src/SixLabors.Primitives/Point.cs
  9. 65
      src/SixLabors.Primitives/PointF.cs
  10. 26
      src/SixLabors.Primitives/Rectangle.cs
  11. 26
      src/SixLabors.Primitives/RectangleF.cs
  12. 21
      src/SixLabors.Primitives/Size.cs
  13. 20
      src/SixLabors.Primitives/SizeF.cs
  14. 1
      tests/CodeCoverage/.gitignore
  15. 2
      tests/CodeCoverage/CodeCoverage.cmd
  16. 1015
      tests/SixLabors.Primitives.Tests/MatrixTests.cs
  17. 2
      tests/SixLabors.Primitives.Tests/PointFTests.cs
  18. 3
      tests/SixLabors.Primitives.Tests/SixLabors.Primitives.Tests.csproj

9
src/Shared/AssemblyInfo.Common.cs

@ -10,11 +10,11 @@ using System.Runtime.CompilerServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyDescription("A cross-platform library for processing of image files; written in C#")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Scott Williams")]
[assembly: AssemblyProduct("SixLabors.Shapes")]
[assembly: AssemblyCopyright("Copyright (c) Scott Williams and contributors.")]
[assembly: AssemblyProduct("SixLabors.Primitives")]
[assembly: AssemblyCopyright("Copyright (c) Six Labors and contributors.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
@ -34,5 +34,4 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyInformationalVersion("1.0.0.0")]
// Ensure the internals can be tested.
[assembly: InternalsVisibleTo("SixLabors.Shapes.Tests")]
[assembly: InternalsVisibleTo("SixLabors.Shapes.Benchmarks")]
[assembly: InternalsVisibleTo("SixLabors.Primitives.Tests")]

210
src/SixLabors.Primitives/ApproximateFloatComparer.cs

@ -0,0 +1,210 @@
// <copyright file="Ellipse.cs" company="Six Labors">
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System;
using System.Collections.Generic;
using System.Numerics;
namespace SixLabors.Primitives
{
internal struct ApproximateFloatComparer
: IEqualityComparer<float>,
IEqualityComparer<Vector4>,
IEqualityComparer<Vector2>,
IEqualityComparer<Vector3>,
IEqualityComparer<Matrix3x2>,
IEqualityComparer<Matrix4x4>,
IEqualityComparer<PointF>
{
private readonly float tolerance;
const float defaultTolerance = 1e-5f;
public ApproximateFloatComparer(float tolerance = defaultTolerance)
{
this.tolerance = tolerance;
}
public static bool Equal(float x, float y, float tolerance)
{
float d = x - y;
return d > -tolerance && d < tolerance;
}
public static bool Equal(float x, float y)
{
return Equal(x, y, defaultTolerance);
}
public bool Equals(float x, float y)
{
return Equal(x, y, this.tolerance);
}
public int GetHashCode(float obj)
{
var diff = obj % this.tolerance;// how different from tollerance are we?
return (obj - diff).GetHashCode();
}
public bool Equals(Vector4 a, Vector4 b)
{
return this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y) && this.Equals(a.Z, b.Z) && this.Equals(a.W, b.W);
}
public int GetHashCode(Vector4 obj)
{
int hash = GetHashCode(obj.X);
hash = HashHelpers.Combine(hash, GetHashCode(obj.Y));
hash = HashHelpers.Combine(hash, GetHashCode(obj.Z));
hash = HashHelpers.Combine(hash, GetHashCode(obj.W));
return hash;
}
public bool Equals(Vector2 a, Vector2 b)
{
return this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y);
}
public int GetHashCode(Vector2 obj)
{
int hash = GetHashCode(obj.X);
hash = HashHelpers.Combine(hash, GetHashCode(obj.Y));
return hash;
}
public bool Equals(Vector3 a, Vector3 b)
{
return this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y) && this.Equals(a.Z, b.Z);
}
public int GetHashCode(Vector3 obj)
{
int hash = GetHashCode(obj.X);
hash = HashHelpers.Combine(hash, GetHashCode(obj.Y));
hash = HashHelpers.Combine(hash, GetHashCode(obj.Z));
return hash;
}
public static bool Equal(Matrix3x2 a, Matrix3x2 b, float tolerance)
{
return Equal(a.M11, b.M11, tolerance) &&
Equal(a.M12, b.M12, tolerance) &&
Equal(a.M21, b.M21, tolerance) &&
Equal(a.M22, b.M22, tolerance) &&
Equal(a.M31, b.M31, tolerance) &&
Equal(a.M32, b.M32, tolerance);
}
public static bool Equal(Matrix3x2 a, Matrix3x2 b)
{
return Equal(a, b, defaultTolerance);
}
public bool Equals(Matrix3x2 a, Matrix3x2 b)
{
return Equal(a, b, this.tolerance);
}
public int GetHashCode(Matrix3x2 obj)
{
int hash = GetHashCode(obj.M11);
hash = HashHelpers.Combine(hash, GetHashCode(obj.M11));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M12));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M21));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M22));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M31));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M32));
return hash;
}
public static bool Equal(Matrix4x4 a, Matrix4x4 b, float tolerance)
{
return
Equal(a.M11, b.M11, tolerance) &&
Equal(a.M12, b.M12, tolerance) &&
Equal(a.M13, b.M13, tolerance) &&
Equal(a.M14, b.M14, tolerance) &&
Equal(a.M21, b.M21, tolerance) &&
Equal(a.M22, b.M22, tolerance) &&
Equal(a.M23, b.M23, tolerance) &&
Equal(a.M24, b.M24, tolerance) &&
Equal(a.M31, b.M31, tolerance) &&
Equal(a.M32, b.M32, tolerance) &&
Equal(a.M33, b.M33, tolerance) &&
Equal(a.M34, b.M34, tolerance) &&
Equal(a.M41, b.M41, tolerance) &&
Equal(a.M42, b.M42, tolerance) &&
Equal(a.M43, b.M43, tolerance) &&
Equal(a.M44, b.M44, tolerance);
}
public static bool Equal(Matrix4x4 a, Matrix4x4 b)
{
return Equal(a, b, defaultTolerance);
}
public bool Equals(Matrix4x4 a, Matrix4x4 b)
{
return Equal(a, b, this.tolerance);
}
public int GetHashCode(Matrix4x4 obj)
{
int hash = GetHashCode(obj.M11);
hash = HashHelpers.Combine(hash, GetHashCode(obj.M12));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M13));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M14));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M21));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M22));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M23));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M24));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M31));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M32));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M33));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M34));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M41));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M42));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M43));
hash = HashHelpers.Combine(hash, GetHashCode(obj.M44));
return hash;
}
public static bool Equal(PointF a, PointF b, float tolerance)
{
return
Equal(a.X, b.X, tolerance) &&
Equal(a.Y, b.Y, tolerance);
}
public static bool Equal(PointF a, PointF b)
{
return Equal(a, b, defaultTolerance);
}
public bool Equals(PointF a, PointF b)
{
return Equal(a, b, this.tolerance);
}
public int GetHashCode(PointF obj)
{
int hash = GetHashCode(obj.X);
hash = HashHelpers.Combine(hash, GetHashCode(obj.Y));
return hash;
}
}
}

11
src/SixLabors.Primitives/Ellipse.cs

@ -171,13 +171,10 @@ namespace SixLabors.Primitives
/// </returns>
private int GetHashCode(Ellipse ellipse)
{
unchecked
{
int hashCode = ellipse.center.GetHashCode();
hashCode = (hashCode * 397) ^ ellipse.RadiusX.GetHashCode();
hashCode = (hashCode * 397) ^ ellipse.RadiusY.GetHashCode();
return hashCode;
}
int hashCode = ellipse.center.GetHashCode();
hashCode = HashHelpers.Combine(hashCode, ellipse.RadiusX.GetHashCode());
hashCode = HashHelpers.Combine(hashCode, ellipse.RadiusY.GetHashCode());
return hashCode;
}
}
}

23
src/SixLabors.Primitives/HashHelpers.cs

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SixLabors.Primitives
{
// lifted from coreFX repo
internal static class HashHelpers
{
public static readonly int RandomSeed = Guid.NewGuid().GetHashCode();
public static int Combine(int h1, int h2)
{
unchecked
{
// RyuJIT optimizes this to use the ROL instruction
// Related GitHub pull request: dotnet/coreclr#1830
uint rol5 = ((uint)h1 << 5) | ((uint)h1 >> 27);
return ((int)rol5 + h1) ^ h2;
}
}
}
}

5
src/SixLabors.Primitives/LongRational.cs

@ -347,9 +347,6 @@ namespace SixLabors.Primitives
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private int GetHashCode(LongRational rational)
{
return ((rational.Numerator * 397) ^ rational.Denominator).GetHashCode();
}
private int GetHashCode(LongRational rational) => HashHelpers.Combine(rational.Numerator.GetHashCode(), rational.Denominator.GetHashCode());
}
}

4
src/SixLabors.Primitives/MathF.cs

@ -94,7 +94,7 @@ namespace SixLabors.Primitives
/// The <see cref="float"/> representing the degree as radians.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float DegreeToRadian(float degree)
public static float ToRadians(float degree)
{
return degree * (PI / 180F);
}
@ -181,7 +181,7 @@ namespace SixLabors.Primitives
/// The <see cref="float"/> representing the degree as radians.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float RadianToDegree(float radian)
public static float ToDegree(float radian)
{
return radian / (PI / 180F);
}

51
src/SixLabors.Primitives/Matrix.cs

@ -32,9 +32,43 @@ namespace SixLabors.Primitives
public bool IsIdentity => this.backingMatrix.IsIdentity;
/// <summary>
/// Gets or sets the translation component of this matrix.
/// Gets or Sets the translation component of this matrix.
/// </summary>
public Vector2 Translation => this.backingMatrix.Translation;
public PointF Translation
{
get => this.backingMatrix.Translation;
set => this.backingMatrix.Translation = value;
}
/// <summary>
/// The first element of the first row
/// </summary>
public float M11 { get => this.backingMatrix.M11; set => this.backingMatrix.M11 = value; }
/// <summary>
/// The second element of the first row
/// </summary>
public float M12 { get => this.backingMatrix.M12; set => this.backingMatrix.M12 = value; }
/// <summary>
/// The first element of the second row
/// </summary>
public float M21 { get => this.backingMatrix.M21; set => this.backingMatrix.M21 = value; }
/// <summary>
/// The second element of the second row
/// </summary>
public float M22 { get => this.backingMatrix.M22; set => this.backingMatrix.M22 = value; }
/// <summary>
/// The first element of the third row
/// </summary>
public float M31 { get => this.backingMatrix.M31; set => this.backingMatrix.M31 = value; }
/// <summary>
/// The second element of the third row
/// </summary>
public float M32 { get => this.backingMatrix.M32; set => this.backingMatrix.M32 = value; }
/// <summary>
/// Constructs a Matrix3x2 from the given components.
@ -122,7 +156,7 @@ namespace SixLabors.Primitives
/// <param name="degreesX">The X angle, in degrees.</param>
/// <param name="degreesY">The Y angle, in degrees.</param>
/// <returns>A skew matrix.</returns>
public static Matrix CreateSkewDegrees(float degreesX, float degreesY) => Matrix3x2.CreateSkew(MathF.DegreeToRadian(degreesX), MathF.DegreeToRadian(degreesY));
public static Matrix CreateSkewDegrees(float degreesX, float degreesY) => Matrix3x2.CreateSkew(MathF.ToRadians(degreesX), MathF.ToRadians(degreesY));
/// <summary>
/// Creates a skew matrix from the given angles in radians and a center point.
@ -140,7 +174,7 @@ namespace SixLabors.Primitives
/// <param name="degreesY">The Y angle, in degrees.</param>
/// <param name="centerPoint">The center point.</param>
/// <returns>A skew matrix.</returns>
public static Matrix CreateSkewDegrees(float degreesX, float degreesY, PointF centerPoint) => Matrix3x2.CreateSkew(MathF.DegreeToRadian(degreesX), MathF.DegreeToRadian(degreesY), centerPoint);
public static Matrix CreateSkewDegrees(float degreesX, float degreesY, PointF centerPoint) => Matrix3x2.CreateSkew(MathF.ToRadians(degreesX), MathF.ToRadians(degreesY), centerPoint);
/// <summary>
/// Creates a rotation matrix using the given rotation in radians.
@ -154,7 +188,7 @@ namespace SixLabors.Primitives
/// </summary>
/// <param name="degrees">The amount of rotation, in degrees.</param>
/// <returns>A rotation matrix.</returns>
public static Matrix CreateRotationDegrees(float degrees) => System.Numerics.Matrix3x2.CreateRotation(MathF.DegreeToRadian(degrees));
public static Matrix CreateRotationDegrees(float degrees) => System.Numerics.Matrix3x2.CreateRotation(MathF.ToRadians(degrees));
/// <summary>
/// Creates a rotation matrix using the given rotation in radians and a center point.
@ -170,7 +204,7 @@ namespace SixLabors.Primitives
/// <param name="degrees">The amount of rotation, in degrees.</param>
/// <param name="centerPoint">The center point.</param>
/// <returns>A rotation matrix.</returns>
public static Matrix CreateRotationDegrees(float degrees, PointF centerPoint) => Matrix3x2.CreateRotation(MathF.DegreeToRadian(degrees), centerPoint);
public static Matrix CreateRotationDegrees(float degrees, PointF centerPoint) => Matrix3x2.CreateRotation(MathF.ToRadians(degrees), centerPoint);
/// <summary>
/// Calculates the determinant for this matrix.
@ -356,5 +390,10 @@ namespace SixLabors.Primitives
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Matrix(Matrix3x2 matrix) => new Matrix { backingMatrix = matrix };
internal static Matrix CreateScale(Vector2 scale, object zero)
{
throw new NotImplementedException();
}
}
}

25
src/SixLabors.Primitives/Point.cs

@ -25,6 +25,11 @@ namespace SixLabors.Primitives
/// </summary>
public static readonly Point Empty = default(Point);
/// <summary>
/// Represents a <see cref="Point"/> that has X and Y values set to zero.
/// </summary>
public static readonly Point Zero = new Point(0, 0);
/// <summary>
/// Initializes a new instance of the <see cref="Point"/> struct.
/// </summary>
@ -95,6 +100,13 @@ namespace SixLabors.Primitives
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Size(Point point) => new Size(point.X, point.Y);
/// <summary>
/// Negates the given point by multiplying all values by -1.
/// </summary>
/// <param name="value">The source point.</param>
/// <returns>The negated point.</returns>
public static Point operator -(Point value) => new Point(-value.X, -value.Y);
/// <summary>
/// Translates a <see cref="Point"/> by a given <see cref="Size"/>.
/// </summary>
@ -252,6 +264,17 @@ namespace SixLabors.Primitives
private static short LowInt16(int n) => unchecked((short)(n & 0xffff));
private int GetHashCode(Point point) => point.X ^ point.Y;
private int GetHashCode(Point point) => HashHelpers.Combine(point.X.GetHashCode(), point.Y.GetHashCode());
/// <summary>
/// Transforms a point by the given matrix.
/// </summary>
/// <param name="position"> The source point</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns></returns>
public static PointF Transform(Point position, Matrix matrix)
{
return Vector2.Transform(position, matrix);
}
}
}

65
src/SixLabors.Primitives/PointF.cs

@ -25,6 +25,11 @@ namespace SixLabors.Primitives
/// </summary>
public static readonly PointF Empty = default(PointF);
/// <summary>
/// Represents a <see cref="PointF"/> that has X and Y values set to zero.
/// </summary>
public static readonly PointF Zero = new PointF(0, 0);
/// <summary>
/// Initializes a new instance of the <see cref="PointF"/> struct.
/// </summary>
@ -93,6 +98,13 @@ namespace SixLabors.Primitives
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator Point(PointF point) => Point.Truncate(point);
/// <summary>
/// Negates the given point by multiplying all values by -1.
/// </summary>
/// <param name="value">The source point.</param>
/// <returns>The negated point.</returns>
public static PointF operator -(PointF value) => new PointF(-value.X, -value.Y);
/// <summary>
/// Translates a <see cref="PointF"/> by a given <see cref="SizeF"/>.
/// </summary>
@ -104,6 +116,26 @@ namespace SixLabors.Primitives
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PointF operator +(PointF point, SizeF size) => Add(point, size);
/// <summary>
/// Translates a <see cref="PointF"/> by the negative of a given <see cref="SizeF"/>.
/// </summary>
/// <param name="point">The point on the left hand of the operand.</param>
/// <param name="size">The size on the right hand of the operand.</param>
/// <returns>The <see cref="PointF"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PointF operator -(PointF point, PointF size) => Subtract(point, size);
/// <summary>
/// Translates a <see cref="PointF"/> by a given <see cref="SizeF"/>.
/// </summary>
/// <param name="point">The point on the left hand of the operand.</param>
/// <param name="size">The size on the right hand of the operand.</param>
/// <returns>
/// The <see cref="PointF"/>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PointF operator +(PointF point, PointF size) => Add(point, size);
/// <summary>
/// Translates a <see cref="PointF"/> by the negative of a given <see cref="SizeF"/>.
/// </summary>
@ -144,7 +176,7 @@ namespace SixLabors.Primitives
public static bool operator !=(PointF left, PointF right) => !left.Equals(right);
/// <summary>
/// Translates a <see cref="PointF"/> by the negative of a given <see cref="SizeF"/>.
/// Translates a <see cref="PointF"/> by the given <see cref="SizeF"/>.
/// </summary>
/// <param name="point">The point on the left hand of the operand.</param>
/// <param name="size">The size on the right hand of the operand.</param>
@ -152,6 +184,15 @@ namespace SixLabors.Primitives
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PointF Add(PointF point, SizeF size) => new PointF(point.X + size.Width, point.Y + size.Height);
/// <summary>
/// Translates a <see cref="PointF"/> by the given <see cref="PointF"/>.
/// </summary>
/// <param name="point">The point on the left hand of the operand.</param>
/// <param name="pointb">The point on the right hand of the operand.</param>
/// <returns>The <see cref="PointF"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PointF Add(PointF point, PointF pointb) => new PointF(point.X + pointb.X, point.Y + pointb.Y);
/// <summary>
/// Translates a <see cref="PointF"/> by the negative of a given <see cref="SizeF"/>.
/// </summary>
@ -161,6 +202,15 @@ namespace SixLabors.Primitives
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PointF Subtract(PointF point, SizeF size) => new PointF(point.X - size.Width, point.Y - size.Height);
/// <summary>
/// Translates a <see cref="PointF"/> by the negative of a given <see cref="PointF"/>.
/// </summary>
/// <param name="point">The point on the left hand of the operand.</param>
/// <param name="pointb">The point on the right hand of the operand.</param>
/// <returns>The <see cref="PointF"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PointF Subtract(PointF point, PointF pointb) => new PointF(point.X - pointb.X, point.Y - pointb.Y);
/// <summary>
/// Rotates a point around the given rotation matrix.
/// </summary>
@ -228,6 +278,17 @@ namespace SixLabors.Primitives
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private int GetHashCode(PointF point) => point.X.GetHashCode() ^ point.Y.GetHashCode();
private int GetHashCode(PointF point) => HashHelpers.Combine(point.X.GetHashCode(), point.Y.GetHashCode());
/// <summary>
/// Transforms a point by the given matrix.
/// </summary>
/// <param name="position"> The source point</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns></returns>
public static PointF Transform(PointF position, Matrix matrix)
{
return Vector2.Transform(position, matrix);
}
}
}

26
src/SixLabors.Primitives/Rectangle.cs

@ -454,14 +454,24 @@ namespace SixLabors.Primitives
private int GetHashCode(Rectangle rectangle)
{
unchecked
{
int hashCode = rectangle.X;
hashCode = (hashCode * 397) ^ rectangle.Y;
hashCode = (hashCode * 397) ^ rectangle.Width;
hashCode = (hashCode * 397) ^ rectangle.Height;
return hashCode;
}
int hashCode = rectangle.X.GetHashCode();
hashCode = HashHelpers.Combine(hashCode, rectangle.Y.GetHashCode());
hashCode = HashHelpers.Combine(hashCode, rectangle.Width.GetHashCode());
hashCode = HashHelpers.Combine(hashCode, rectangle.Height.GetHashCode());
return hashCode;
}
/// <summary>
/// Transforms a rectangle by the given matrix.
/// </summary>
/// <param name="rectangle">The source rectangle</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns></returns>
public static RectangleF Transform(Rectangle rectangle, Matrix matrix)
{
PointF bottomRight = Point.Transform(new Point(rectangle.Right, rectangle.Bottom), matrix);
PointF topLeft = Point.Transform(rectangle.Location, matrix);
return new RectangleF(topLeft, new SizeF(bottomRight - topLeft));
}
}
}

26
src/SixLabors.Primitives/RectangleF.cs

@ -387,14 +387,24 @@ namespace SixLabors.Primitives
private int GetHashCode(RectangleF rectangle)
{
unchecked
{
int hashCode = rectangle.X.GetHashCode();
hashCode = (hashCode * 397) ^ rectangle.Y.GetHashCode();
hashCode = (hashCode * 397) ^ rectangle.Width.GetHashCode();
hashCode = (hashCode * 397) ^ rectangle.Height.GetHashCode();
return hashCode;
}
int hashCode = rectangle.X.GetHashCode();
hashCode = HashHelpers.Combine(hashCode, rectangle.Y.GetHashCode());
hashCode = HashHelpers.Combine(hashCode, rectangle.Width.GetHashCode());
hashCode = HashHelpers.Combine(hashCode, rectangle.Height.GetHashCode());
return hashCode;
}
/// <summary>
/// Transforms a rectangle by the given matrix.
/// </summary>
/// <param name="rectangle">The source rectangle</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns></returns>
public static RectangleF Transform(RectangleF rectangle, Matrix matrix)
{
PointF bottomRight = PointF.Transform(new PointF(rectangle.Right, rectangle.Bottom), matrix);
PointF topLeft = PointF.Transform(rectangle.Location, matrix);
return new RectangleF(topLeft, new SizeF(bottomRight - topLeft));
}
}
}

21
src/SixLabors.Primitives/Size.cs

@ -7,6 +7,7 @@ namespace SixLabors.Primitives
{
using System;
using System.ComponentModel;
using System.Numerics;
using System.Runtime.CompilerServices;
/// <summary>
@ -22,6 +23,11 @@ namespace SixLabors.Primitives
/// Represents a <see cref="Size"/> that has Width and Height values set to zero.
/// </summary>
public static readonly Size Empty = default(Size);
/// <summary>
/// Represents a <see cref="Size"/> that has Width and Height values set to zero.
/// </summary>
public static readonly Size Zero = new Size(0, 0);
/// <summary>
/// Initializes a new instance of the <see cref="Size"/> struct.
@ -220,6 +226,19 @@ namespace SixLabors.Primitives
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private int GetHashCode(Size size) => size.Width ^ size.Height;
private int GetHashCode(Size size) => HashHelpers.Combine(size.Width.GetHashCode(), size.Height.GetHashCode());
/// <summary>
/// Transforms a size by the given matrix.
/// </summary>
/// <param name="size">The source size</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns></returns>
public static SizeF Transform(Size size, Matrix matrix)
{
var v = Vector2.Transform(new Vector2(size.Width, size.Height), matrix);
return new SizeF(v.X, v.Y);
}
}
}

20
src/SixLabors.Primitives/SizeF.cs

@ -24,6 +24,11 @@ namespace SixLabors.Primitives
/// </summary>
public static readonly SizeF Empty = default(SizeF);
/// <summary>
/// Represents a <see cref="SizeF"/> that has Width and Height values set to zero.
/// </summary>
public static readonly SizeF Zero = new SizeF(0, 0);
/// <summary>
/// Initializes a new instance of the <see cref="SizeF"/> struct.
/// </summary>
@ -175,7 +180,7 @@ namespace SixLabors.Primitives
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(SizeF other) => this.Width.Equals(other.Width) && this.Height.Equals(other.Height);
private int GetHashCode(SizeF size) => size.Width.GetHashCode() ^ size.Height.GetHashCode();
private int GetHashCode(SizeF size) => HashHelpers.Combine(size.Width.GetHashCode(), size.Height.GetHashCode());
/// <summary>
/// Creates a <see cref="Vector2"/> with the coordinates of the specified <see cref="PointF"/>.
@ -186,5 +191,18 @@ namespace SixLabors.Primitives
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Vector2(SizeF point) => new Vector2(point.Width, point.Height);
/// <summary>
/// Transforms a size by the given matrix.
/// </summary>
/// <param name="size">The source size</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns></returns>
public static SizeF Transform(SizeF size, Matrix matrix)
{
var v = Vector2.Transform(new Vector2(size.Width, size.Height), matrix);
return new SizeF(v.X, v.Y);
}
}
}

1
tests/CodeCoverage/.gitignore

@ -0,0 +1 @@
/OpenCover.4.6.519

2
tests/CodeCoverage/CodeCoverage.cmd

@ -12,7 +12,7 @@ dotnet build SixLabors.Primitives.sln --no-incremental -c debug /p:codecov=true
rem The -threshold options prevents this taking ages...
rem tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\SixLabors.Shapes.Tests\SixLabors.Shapes.Tests.csproj --no-build -c Release /p:codecov=true" -threshold:10 -register:user -filter:"+[SixLabors.Shapes*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\SixLabors.Shapes.Coverage.xml
tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\SixLabors.Primitives.Tests\SixLabors.Primitives.Tests.csproj --no-build -c debug" -searchdirs:"tests\SixLabors.Shapes.Tests\bin\Release\netcoreapp1.1" -register:user -output:.\SixLabors.Shapes.Coverage.xml -hideskipped:All -returntargetcode -oldStyle -filter:"+[SixLabors.Primitives*]*"
tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\SixLabors.Primitives.Tests\SixLabors.Primitives.Tests.csproj --no-build -c debug" -searchdirs:"tests\SixLabors.Primitives.Tests\bin\Release\netcoreapp1.1" -register:user -output:.\SixLabors.Primitives.Coverage.xml -hideskipped:All -returntargetcode -oldStyle -filter:"+[SixLabors.Primitives*]*"
if %errorlevel% neq 0 exit /b %errorlevel%

1015
tests/SixLabors.Primitives.Tests/MatrixTests.cs

File diff suppressed because it is too large

2
tests/SixLabors.Primitives.Tests/PointFTests.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace SixLabors.Primitives.Tests.Numerics
namespace SixLabors.Primitives.Tests
{
using System;
using System.Globalization;

3
tests/SixLabors.Primitives.Tests/SixLabors.Primitives.Tests.csproj

@ -3,7 +3,7 @@
<PropertyGroup>
<VersionPrefix>0.0.0</VersionPrefix>
<TargetFrameworks>netcoreapp1.1</TargetFrameworks>
<AssemblyName>SixLabors.Shapes.Tests</AssemblyName>
<AssemblyName>SixLabors.Primitives.Tests</AssemblyName>
<PackageId>SixLabors.Shapes.Tests</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
@ -17,7 +17,6 @@
<ItemGroup>
<ProjectReference Include="..\..\src\SixLabors.Primitives\SixLabors.Primitives.csproj" />
<ProjectReference Include="..\..\src\SixLabors.Shapes\SixLabors.Shapes.csproj" />
</ItemGroup>
<ItemGroup>

Loading…
Cancel
Save