Browse Source

Translation, Scale -> ProjectiveTransformBuilder

af/merge-core
Anton Firszov 7 years ago
parent
commit
1f330306db
  1. 26
      src/ImageSharp/Processing/AffineTransformBuilder.cs
  2. 113
      src/ImageSharp/Processing/ProjectiveTransformBuilder.cs
  3. 54
      tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs

26
src/ImageSharp/Processing/AffineTransformBuilder.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing
public class AffineTransformBuilder
{
private readonly List<Matrix3x2> matrices = new List<Matrix3x2>();
private readonly Rectangle rectangle;
private readonly Rectangle sourceRectangle;
/// <summary>
/// Initializes a new instance of the <see cref="AffineTransformBuilder"/> class.
@ -34,13 +34,13 @@ namespace SixLabors.ImageSharp.Processing
Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle));
Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle));
this.rectangle = sourceRectangle;
this.sourceRectangle = sourceRectangle;
}
/// <summary>
/// Gets the source image size.
/// </summary>
internal Size Size => this.rectangle.Size;
internal Size Size => this.sourceRectangle.Size;
/// <summary>
/// Prepends a centered rotation matrix using the given rotation in degrees.
@ -145,32 +145,32 @@ namespace SixLabors.ImageSharp.Processing
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder PrependTranslation(PointF position)
=> this.PrependTranslation((Vector2)position);
public AffineTransformBuilder PrependTranslation(Vector2 position)
=> this.PrependMatrix(Matrix3x2.CreateTranslation(position));
/// <summary>
/// Appends a translation matrix from the given vector.
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder AppendTranslation(PointF position)
=> this.AppendTranslation((Vector2)position);
public AffineTransformBuilder AppendTranslation(Vector2 position)
=> this.AppendMatrix(Matrix3x2.CreateTranslation(position));
/// <summary>
/// Prepends a translation matrix from the given vector.
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder PrependTranslation(Vector2 position)
=> this.PrependMatrix(Matrix3x2.CreateTranslation(position));
public AffineTransformBuilder PrependTranslation(PointF position)
=> this.PrependTranslation((Vector2)position);
/// <summary>
/// Appends a translation matrix from the given vector.
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder AppendTranslation(Vector2 position)
=> this.AppendMatrix(Matrix3x2.CreateTranslation(position));
public AffineTransformBuilder AppendTranslation(PointF position)
=> this.AppendTranslation((Vector2)position);
/// <summary>
/// Prepends a raw matrix.
@ -203,9 +203,9 @@ namespace SixLabors.ImageSharp.Processing
Matrix3x2 matrix = Matrix3x2.Identity;
// Translate the origin matrix to cater for source rectangle offsets.
if (!this.rectangle.Equals(default))
if (!this.sourceRectangle.Equals(default))
{
matrix *= Matrix3x2.CreateTranslation(-this.rectangle.Location);
matrix *= Matrix3x2.CreateTranslation(-this.sourceRectangle.Location);
}
foreach (Matrix3x2 m in this.matrices)

113
src/ImageSharp/Processing/ProjectiveTransformBuilder.cs

@ -14,18 +14,15 @@ namespace SixLabors.ImageSharp.Processing
public class ProjectiveTransformBuilder
{
private readonly List<Matrix4x4> matrices = new List<Matrix4x4>();
private Rectangle rectangle;
private Rectangle sourceRectangle;
/// <summary>
/// Initializes a new instance of the <see cref="ProjectiveTransformBuilder"/> class.
/// </summary>
/// <param name="sourceSize">The source image size.</param>
public ProjectiveTransformBuilder(Size sourceSize)
: this(new Rectangle(Point.Empty, sourceSize))
{
Guard.MustBeGreaterThan(sourceSize.Width, 0, nameof(sourceSize));
Guard.MustBeGreaterThan(sourceSize.Height, 0, nameof(sourceSize));
this.Size = sourceSize;
}
/// <summary>
@ -33,13 +30,18 @@ namespace SixLabors.ImageSharp.Processing
/// </summary>
/// <param name="sourceRectangle">The source rectangle.</param>
public ProjectiveTransformBuilder(Rectangle sourceRectangle)
: this(sourceRectangle.Size)
=> this.rectangle = sourceRectangle;
{
Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle));
Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle));
this.sourceRectangle = sourceRectangle;
}
/// <summary>
/// Gets the source image size.
/// </summary>
internal Size Size { get; }
internal Size Size => this.sourceRectangle.Size;
/// <summary>
/// Prepends a matrix that performs a tapering projective transform.
@ -61,6 +63,96 @@ namespace SixLabors.ImageSharp.Processing
public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction)
=> this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction));
public void AppendRotationRadians(float radians)
{
throw new System.NotImplementedException();
}
public void PrependRotationRadians(float radians)
{
throw new System.NotImplementedException();
}
/// <summary>
/// Prepends a scale matrix from the given uniform scale.
/// </summary>
/// <param name="scale">The uniform scale.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder PrependScale(float scale)
=> this.PrependMatrix(Matrix4x4.CreateScale(scale));
/// <summary>
/// Appends a scale matrix from the given uniform scale.
/// </summary>
/// <param name="scale">The uniform scale.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder AppendScale(float scale)
=> this.AppendMatrix(Matrix4x4.CreateScale(scale));
/// <summary>
/// Prepends a scale matrix from the given vector scale.
/// </summary>
/// <param name="scales">The horizontal and vertical scale.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder PrependScale(Vector2 scales)
=> this.PrependMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f)));
/// <summary>
/// Appends a scale matrix from the given vector scale.
/// </summary>
/// <param name="scales">The horizontal and vertical scale.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder AppendScale(Vector2 scales)
=> this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f)));
/// <summary>
/// Prepends a scale matrix from the given vector scale.
/// </summary>
/// <param name="scale">The horizontal and vertical scale.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder PrependScale(SizeF scale)
=> this.PrependScale((Vector2)scale);
/// <summary>
/// Appends a scale matrix from the given vector scale.
/// </summary>
/// <param name="scales">The horizontal and vertical scale.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder AppendScale(SizeF scales)
=> this.AppendScale((Vector2)scales);
/// <summary>
/// Prepends a translation matrix from the given vector.
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder PrependTranslation(Vector2 position)
=> this.PrependMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0)));
/// <summary>
/// Appends a translation matrix from the given vector.
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder AppendTranslation(Vector2 position)
=> this.AppendMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0)));
/// <summary>
/// Prepends a translation matrix from the given vector.
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder PrependTranslation(PointF position)
=> this.PrependTranslation((Vector2)position);
/// <summary>
/// Appends a translation matrix from the given vector.
/// </summary>
/// <param name="position">The translation position.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder AppendTranslation(PointF position)
=> this.AppendTranslation((Vector2)position);
/// <summary>
/// Prepends a raw matrix.
/// </summary>
@ -92,9 +184,9 @@ namespace SixLabors.ImageSharp.Processing
Matrix4x4 matrix = Matrix4x4.Identity;
// Translate the origin matrix to cater for source rectangle offsets.
if (!this.rectangle.Equals(default))
if (!this.sourceRectangle.Equals(default))
{
matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.rectangle.Location, 0));
matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.sourceRectangle.Location, 0));
}
foreach (Matrix4x4 m in this.matrices)
@ -109,5 +201,6 @@ namespace SixLabors.ImageSharp.Processing
/// Removes all matrices from the builder.
/// </summary>
public void Clear() => this.matrices.Clear();
}
}

54
tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs

@ -9,7 +9,7 @@ using Xunit;
namespace SixLabors.ImageSharp.Tests.Processing.Transforms
{
public class ProjectiveTransformBuilderTests
public class ProjectiveTransformBuilderTests : TransformBuilderTestBase<ProjectiveTransformBuilder>
{
[Fact]
public void ConstructorAssignsProperties()
@ -34,45 +34,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s));
});
}
[Fact]
public void AppendPrependOpposite()
{
var rectangle = new Rectangle(-1, -1, 3, 3);
var b1 = new ProjectiveTransformBuilder(rectangle);
var b2 = new ProjectiveTransformBuilder(rectangle);
const float pi = (float)Math.PI;
Matrix4x4 m4 = Matrix4x4.Identity;
m4.M31 = pi;
// Forwards
b1.AppendMatrix(m4)
.AppendTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi);
// Backwards
b2.PrependTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi)
.PrependMatrix(m4);
Assert.Equal(b1.BuildMatrix(), b2.BuildMatrix());
}
[Fact]
public void BuilderCanClear()
protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate);
protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale);
protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians);
protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate);
protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale);
protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians);
protected override Vector2 Execute(
ProjectiveTransformBuilder builder,
Rectangle rectangle,
Vector2 sourcePoint)
{
var rectangle = new Rectangle(0, 0, 3, 3);
var builder = new ProjectiveTransformBuilder(rectangle);
Matrix4x4 matrix = Matrix4x4.Identity;
matrix.M31 = (float)Math.PI;
Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix());
builder.AppendMatrix(matrix);
Assert.NotEqual(Matrix4x4.Identity, builder.BuildMatrix());
builder.Clear();
Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix());
Matrix4x4 matrix = builder.BuildMatrix();
return Vector2.Transform(sourcePoint, matrix);
}
}
}

Loading…
Cancel
Save