Browse Source

Rotation around custom center point. Rename PrependCenteredRotationRadians back to PrependRotationRadians

pull/775/head
Anton Firszov 7 years ago
parent
commit
bbfb2a0ef9
  1. 40
      src/ImageSharp/Processing/AffineTransformBuilder.cs
  2. 35
      src/ImageSharp/Processing/ProjectiveTransformBuilder.cs
  3. 2
      tests/ImageSharp.Tests/Drawing/DrawImageTest.cs
  4. 8
      tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs
  5. 8
      tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs
  6. 8
      tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs
  7. 46
      tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs

40
src/ImageSharp/Processing/AffineTransformBuilder.cs

@ -20,33 +20,55 @@ namespace SixLabors.ImageSharp.Processing
/// Prepends a centered rotation matrix using the given rotation in radians.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <param name="centerPoint">The rotation center point</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder PrependCenteredRotationRadians(float radians)
=> this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size));
public AffineTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint)
=> this.PrependMatrix(Matrix3x2.CreateRotation(radians, centerPoint));
/// <summary>
/// Appends a centered rotation matrix using the given rotation in radians.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <param name="centerPoint">The rotation center point</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint)
=> this.AppendMatrix(Matrix3x2.CreateRotation(radians, centerPoint));
/// <summary>
/// Prepends a rotation matrix using the given rotation angle in radians
/// and the image center point as rotation center.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder PrependRotationRadians(float radians)
=> this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size));
/// <summary>
/// Appends a rotation matrix using the given rotation angle in radians
/// and the image center point as rotation center.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder AppendCenteredRotationRadians(float radians)
public AffineTransformBuilder AppendRotationRadians(float radians)
=> this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size));
/// <summary>
/// Prepends a centered rotation matrix using the given rotation in degrees.
/// Prepends a rotation matrix using the given rotation angle in degrees
/// and the image center point as rotation center.
/// </summary>
/// <param name="degrees">The amount of rotation, in degrees.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder PrependCenteredRotationDegrees(float degrees)
=> this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees));
public AffineTransformBuilder PrependRotationDegrees(float degrees)
=> this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees));
/// <summary>
/// Appends a centered rotation matrix using the given rotation in degrees.
/// Appends a rotation matrix using the given rotation angle in degrees
/// and the image center point as rotation center.
/// </summary>
/// <param name="degrees">The amount of rotation, in degrees.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public AffineTransformBuilder AppendCenteredRotationDegrees(float degrees)
=> this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees));
public AffineTransformBuilder AppendRotationDegrees(float degrees)
=> this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees));
/// <summary>
/// Prepends a scale matrix from the given uniform scale.

35
src/ImageSharp/Processing/ProjectiveTransformBuilder.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.Numerics;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
@ -67,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <returns>The <see cref="ProjectiveTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder PrependCenteredRotationRadians(float radians)
public ProjectiveTransformBuilder PrependRotationRadians(float radians)
{
var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size));
return this.PrependMatrix(m);
@ -78,27 +79,51 @@ namespace SixLabors.ImageSharp.Processing
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <returns>The <see cref="ProjectiveTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder AppendCenteredRotationRadians(float radians)
public ProjectiveTransformBuilder AppendRotationRadians(float radians)
{
var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size));
return this.AppendMatrix(m);
}
/// <summary>
/// Appends a centered rotation matrix using the given rotation in radians.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <param name="centerPoint">The rotation center.</param>
/// <returns>The <see cref="ProjectiveTransformBuilder"/>.</returns>
internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint)
{
var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0));
return this.PrependMatrix(m);
}
/// <summary>
/// Appends a centered rotation matrix using the given rotation in radians.
/// </summary>
/// <param name="radians">The amount of rotation, in radians.</param>
/// <param name="centerPoint">The rotation center.</param>
/// <returns>The <see cref="ProjectiveTransformBuilder"/>.</returns>
internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint)
{
var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0));
return this.AppendMatrix(m);
}
/// <summary>
/// Prepends a centered rotation matrix using the given rotation in degrees.
/// </summary>
/// <param name="degrees">The amount of rotation, in degrees.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees)
=> this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees));
=> this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees));
/// <summary>
/// Appends a centered rotation matrix using the given rotation in degrees.
/// </summary>
/// <param name="degrees">The amount of rotation, in degrees.</param>
/// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
public ProjectiveTransformBuilder AppendCenteredRotationDegrees(float degrees)
=> this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees));
public ProjectiveTransformBuilder AppendRotationDegrees(float degrees)
=> this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees));
/// <summary>
/// Prepends a scale matrix from the given uniform scale.

2
tests/ImageSharp.Tests/Drawing/DrawImageTest.cs

@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests
using (var blend = Image.Load<TPixel>(TestFile.Create(TestImages.Bmp.Car).Bytes))
{
AffineTransformBuilder builder = new AffineTransformBuilder()
.AppendCenteredRotationDegrees(45F)
.AppendRotationDegrees(45F)
.AppendScale(new SizeF(.25F, .25F))
.AppendTranslation(new PointF(10, 10));

8
tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs

@ -14,11 +14,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
{
protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate);
protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale);
protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians);
protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians);
protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) =>
builder.AppendRotationRadians(radians, center);
protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate);
protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale);
protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians);
protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians);
protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) =>
builder.PrependRotationRadians(radians, center);
protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder();

8
tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs

@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
using (Image<TPixel> image = provider.GetImage())
{
AffineTransformBuilder builder = new AffineTransformBuilder()
.AppendCenteredRotationDegrees(30);
.AppendRotationDegrees(30);
image.Mutate(c => c.Transform(builder, resampler));
image.DebugSave(provider, resamplerName);
@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
{
image.DebugSave(provider, $"_original");
AffineTransformBuilder builder = new AffineTransformBuilder()
.AppendCenteredRotationDegrees(angleDeg)
.AppendRotationDegrees(angleDeg)
.AppendScale(new SizeF(sx, sy))
.AppendTranslation(new PointF(tx, ty));
@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
using (Image<TPixel> image = provider.GetImage())
{
AffineTransformBuilder builder = new AffineTransformBuilder()
.AppendCenteredRotationDegrees(angleDeg)
.AppendRotationDegrees(angleDeg)
.AppendScale(new SizeF(s, s));
image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic));
@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
using (Image<TPixel> image = provider.GetImage())
{
AffineTransformBuilder builder = new AffineTransformBuilder()
.AppendCenteredRotationDegrees(50)
.AppendRotationDegrees(50)
.AppendScale(new SizeF(.6F, .6F));
image.Mutate(i => i.Transform(builder, sampler));

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

@ -39,11 +39,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
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.AppendCenteredRotationRadians(radians);
protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians);
protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) =>
builder.AppendRotationRadians(radians, center);
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.PrependCenteredRotationRadians(radians);
protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians);
protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) =>
builder.PrependRotationRadians(radians, center);
protected override Vector2 Execute(
ProjectiveTransformBuilder builder,

46
tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs

@ -87,7 +87,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
[InlineData(200, 100, 10, 42, 84)]
[InlineData(200, 100, 100, 42, 84)]
[InlineData(100, 200, -10, 42, 84)]
public void RotateDegrees_ShouldCreateCenteredMatrix(int width, int height, float deg, float x, float y)
public void AppendRotationDegrees_WithoutSpecificRotationCenter_RotationIsCenteredAroundImageCenter(
int width,
int height,
float deg,
float x,
float y)
{
var size = new Size(width, height);
TBuilder builder = this.CreateBuilder(size);
@ -97,13 +102,41 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
// TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness
Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(deg, size);
var position = new Vector2(x, y);
var position = new Vector2(x, y);
var expected = Vector2.Transform(position, matrix);
Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position);
Assert.Equal(actual, expected, Comparer);
}
[Theory]
[InlineData(200, 100, 10, 30, 61, 42, 84)]
[InlineData(200, 100, 100, 30, 10, 20, 84)]
[InlineData(100, 200, -10, 30, 20, 11, 84)]
public void AppendRotationDegrees_WithRotationCenter(
int width,
int height,
float deg,
float cx,
float cy,
float x,
float y)
{
var size = new Size(width, height);
TBuilder builder = this.CreateBuilder(size);
var centerPoint = new Vector2(cx, cy);
this.AppendRotationDegrees(builder, deg, centerPoint);
var matrix = Matrix3x2.CreateRotation(ImageMaths.DegreesToRadians(deg), centerPoint);
var position = new Vector2(x, y);
var expected = Vector2.Transform(position, matrix);
Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position);
Assert.Equal(actual, expected, Comparer);
}
[Fact]
public void AppendPrependOpposite()
{
@ -116,10 +149,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
// Forwards
this.AppendRotationRadians(b1, pi);
this.AppendScale(b1, new SizeF(2, 0.5f));
this.AppendRotationRadians(b1, pi / 2, new Vector2(-0.5f, -0.1f));
this.AppendTranslation(b1, new PointF(123, 321));
// Backwards
this.PrependTranslation(b2, new PointF(123, 321));
this.PrependRotationRadians(b2, pi / 2, new Vector2(-0.5f, -0.1f));
this.PrependScale(b2, new SizeF(2, 0.5f));
this.PrependRotationRadians(b2, pi);
@ -152,14 +187,19 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
protected abstract void AppendTranslation(TBuilder builder, PointF translate);
protected abstract void AppendScale(TBuilder builder, SizeF scale);
protected abstract void AppendRotationRadians(TBuilder builder, float radians);
protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 center);
protected abstract void PrependTranslation(TBuilder builder, PointF translate);
protected abstract void PrependScale(TBuilder builder, SizeF scale);
protected abstract void PrependRotationRadians(TBuilder builder, float radians);
protected abstract void PrependRotationRadians(TBuilder b1, float v, Vector2 vector2);
protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) =>
this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees));
protected virtual void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 center) =>
this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees), center);
protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint);
private static float Sqrt(float a) => (float)Math.Sqrt(a);

Loading…
Cancel
Save