From b0f81fac2d84274da18862a2ab8f41ce596ae3b4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 10 Mar 2026 12:04:21 +1000 Subject: [PATCH] Add Clear method to matrix builders. --- .../Processing/AffineTransformBuilder.cs | 10 +++++ .../Processing/ProjectiveTransformBuilder.cs | 10 +++++ .../Transforms/AffineTransformBuilderTests.cs | 3 ++ .../ProjectiveTransformBuilderTests.cs | 3 ++ .../Transforms/TransformBuilderTestBase.cs | 44 +++++++++++++++++++ 5 files changed, 70 insertions(+) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index c1e11a1d42..84d0d2ea1d 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -349,6 +349,16 @@ public class AffineTransformBuilder internal static SizeF GetTransformedSize(Rectangle sourceRectangle, Matrix3x2 matrix) => TransformUtilities.GetRawTransformedSize(matrix, sourceRectangle.Size); + /// + /// Clears all accumulated transform matrices, resetting the builder to its initial state. + /// + /// The . + public AffineTransformBuilder Clear() + { + this.transformMatrixFactories.Clear(); + return this; + } + private static void CheckDegenerate(Matrix3x2 matrix) { if (TransformUtilities.IsDegenerate(matrix)) diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index e40a307a3d..74da440401 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -397,6 +397,16 @@ public class ProjectiveTransformBuilder internal static SizeF GetTransformedSize(Rectangle sourceRectangle, Matrix4x4 matrix) => TransformUtilities.GetRawTransformedSize(matrix, sourceRectangle.Size); + /// + /// Clears all accumulated transform matrices, resetting the builder to its initial state. + /// + /// The . + public ProjectiveTransformBuilder Clear() + { + this.transformMatrixFactories.Clear(); + return this; + } + private static void CheckDegenerate(Matrix4x4 matrix) { if (TransformUtilities.IsDegenerate(matrix)) diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 232571d4d0..d0e4cf5663 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -58,6 +58,9 @@ public class AffineTransformBuilderTests : TransformBuilderTestBase builder.PrependTranslation(translate); + protected override void ClearBuilder(AffineTransformBuilder builder) + => builder.Clear(); + protected override Vector2 Execute( AffineTransformBuilder builder, Rectangle rectangle, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index a0380033fd..dcc6533163 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -55,6 +55,9 @@ public class ProjectiveTransformBuilderTests : TransformBuilderTestBase builder.PrependRotationRadians(radians, origin); + protected override void ClearBuilder(ProjectiveTransformBuilder builder) + => builder.Clear(); + protected override Vector2 Execute( ProjectiveTransformBuilder builder, Rectangle rectangle, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 73215b1c6f..12f8326fc7 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -248,6 +248,48 @@ public abstract class TransformBuilderTestBase }); } + [Fact] + public void Clear_ResetsBuilderToIdentity() + { + Size size = new(100, 100); + Rectangle rectangle = new(Point.Empty, size); + Vector2 source = new(10, 20); + + TBuilder builder = this.CreateBuilder(); + + // Apply a transform that changes the point. + this.AppendScale(builder, new SizeF(2, 3)); + this.AppendTranslation(builder, new PointF(50, 50)); + Vector2 transformed = this.Execute(builder, rectangle, source); + Assert.NotEqual(source, transformed, Comparer); + + // Clear and verify the builder produces identity behavior. + this.ClearBuilder(builder); + Vector2 afterClear = this.Execute(builder, rectangle, source); + Assert.Equal(source, afterClear, Comparer); + } + + [Fact] + public void Clear_AllowsReuse() + { + Size size = new(100, 100); + Rectangle rectangle = new(Point.Empty, size); + Vector2 source = new(10, 20); + + TBuilder builder = this.CreateBuilder(); + + // First transform: scale by 2. + this.AppendScale(builder, new SizeF(2, 2)); + Vector2 scaled = this.Execute(builder, rectangle, source); + Assert.Equal(new Vector2(20, 40), scaled, Comparer); + + // Clear and apply a different transform: translate. + this.ClearBuilder(builder); + this.AppendTranslation(builder, new PointF(5, 10)); + Vector2 translated = this.Execute(builder, rectangle, source); + Assert.Equal(new Vector2(15, 30), translated, Comparer); + } + protected abstract TBuilder CreateBuilder(); protected abstract void AppendRotationDegrees(TBuilder builder, float degrees); @@ -282,5 +324,7 @@ public abstract class TransformBuilderTestBase protected abstract void PrependTranslation(TBuilder builder, PointF translate); + protected abstract void ClearBuilder(TBuilder builder); + protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); }