Skip to content

Commit 708f5d9

Browse files
authored
Merge pull request #6989 from MarchingCube/fix-transform-operations-interpolation
Fix transform problems caused by missing transform data or invalid order of operations
2 parents 32fe95a + 7a44407 commit 708f5d9

File tree

4 files changed

+101
-8
lines changed

4 files changed

+101
-8
lines changed

src/Avalonia.Visuals/Matrix.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,28 @@ public static double ToRadians(double angle)
215215
return angle * 0.0174532925;
216216
}
217217

218+
/// <summary>
219+
/// Appends another matrix as post-multiplication operation.
220+
/// Equivalent to this * value;
221+
/// </summary>
222+
/// <param name="value">A matrix.</param>
223+
/// <returns>Post-multiplied matrix.</returns>
224+
public Matrix Append(Matrix value)
225+
{
226+
return this * value;
227+
}
228+
229+
/// <summary>
230+
/// Prpends another matrix as pre-multiplication operation.
231+
/// Equivalent to value * this;
232+
/// </summary>
233+
/// <param name="value">A matrix.</param>
234+
/// <returns>Pre-multiplied matrix.</returns>
235+
public Matrix Prepend(Matrix value)
236+
{
237+
return value * this;
238+
}
239+
218240
/// <summary>
219241
/// Calculates the determinant for this matrix.
220242
/// </summary>

src/Avalonia.Visuals/Media/Transformation/InterpolationUtilities.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ public static Vector InterpolateVectors(Vector from, Vector to, double progress)
1818
public static Matrix ComposeTransform(Matrix.Decomposed decomposed)
1919
{
2020
// According to https://www.w3.org/TR/css-transforms-1/#recomposing-to-a-2d-matrix
21-
22-
return Matrix.CreateTranslation(decomposed.Translate) *
23-
Matrix.CreateRotation(decomposed.Angle) *
24-
Matrix.CreateSkew(decomposed.Skew.X, decomposed.Skew.Y) *
25-
Matrix.CreateScale(decomposed.Scale);
21+
return Matrix.Identity
22+
.Prepend(Matrix.CreateTranslation(decomposed.Translate))
23+
.Prepend(Matrix.CreateRotation(decomposed.Angle))
24+
.Prepend(Matrix.CreateSkew(decomposed.Skew.X, decomposed.Skew.Y))
25+
.Prepend(Matrix.CreateScale(decomposed.Scale));
2626
}
2727

2828
public static Matrix.Decomposed InterpolateDecomposedTransforms(ref Matrix.Decomposed from, ref Matrix.Decomposed to, double progress)

src/Avalonia.Visuals/Media/Transformation/TransformOperation.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ public static bool TryInterpolate(TransformOperation? from, TransformOperation?
8686

8787
if (fromIdentity && toIdentity)
8888
{
89+
result.Matrix = Matrix.Identity;
90+
8991
return true;
9092
}
9193

@@ -179,7 +181,8 @@ public static bool TryInterpolate(TransformOperation? from, TransformOperation?
179181
}
180182
case OperationType.Identity:
181183
{
182-
// Do nothing.
184+
result.Matrix = Matrix.Identity;
185+
183186
break;
184187
}
185188
}

tests/Avalonia.Visuals.UnitTests/Media/TransformOperationsTests.cs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public void Can_Parse_Matrix_Operation()
129129

130130
Assert.Single(operations);
131131
Assert.Equal(TransformOperation.OperationType.Matrix, operations[0].Type);
132-
132+
133133
var expectedMatrix = new Matrix(1, 2, 3, 4, 5, 6);
134134

135135
Assert.Equal(expectedMatrix, operations[0].Matrix);
@@ -195,7 +195,7 @@ public void Can_Interpolate_Skew(double progress, double x, double y)
195195
[Theory]
196196
[InlineData(0d, 10d)]
197197
[InlineData(0.5d, 15d)]
198-
[InlineData(1d,20d)]
198+
[InlineData(1d, 20d)]
199199
public void Can_Interpolate_Rotation(double progress, double angle)
200200
{
201201
var from = TransformOperations.Parse("rotate(10deg)");
@@ -225,5 +225,73 @@ public void Interpolation_Fallback_To_Matrix()
225225
Assert.Single(operations);
226226
Assert.Equal(TransformOperation.OperationType.Matrix, operations[0].Type);
227227
}
228+
229+
[Fact]
230+
public void Order_Of_Operations_Is_Preserved_No_Prefix()
231+
{
232+
var from = TransformOperations.Parse("scale(1)");
233+
var to = TransformOperations.Parse("translate(50px,50px) scale(0.5,0.5)");
234+
235+
var interpolated_0 = TransformOperations.Interpolate(from, to, 0);
236+
237+
Assert.True(interpolated_0.IsIdentity);
238+
239+
var interpolated_50 = TransformOperations.Interpolate(from, to, 0.5);
240+
241+
AssertMatrix(interpolated_50.Value, scaleX: 0.75, scaleY: 0.75, translateX: 12.5, translateY: 12.5);
242+
243+
var interpolated_100 = TransformOperations.Interpolate(from, to, 1);
244+
245+
AssertMatrix(interpolated_100.Value, scaleX: 0.5, scaleY: 0.5, translateX: 25, translateY: 25);
246+
}
247+
248+
[Fact]
249+
public void Order_Of_Operations_Is_Preserved_One_Prefix()
250+
{
251+
var from = TransformOperations.Parse("scale(1)");
252+
var to = TransformOperations.Parse("scale(0.5,0.5) translate(50px,50px)");
253+
254+
var interpolated_0 = TransformOperations.Interpolate(from, to, 0);
255+
256+
Assert.True(interpolated_0.IsIdentity);
257+
258+
var interpolated_50 = TransformOperations.Interpolate(from, to, 0.5);
259+
260+
AssertMatrix(interpolated_50.Value, scaleX: 0.75, scaleY: 0.75, translateX: 25.0, translateY: 25);
261+
262+
var interpolated_100 = TransformOperations.Interpolate(from, to, 1);
263+
264+
AssertMatrix(interpolated_100.Value, scaleX: 0.5, scaleY: 0.5, translateX: 50, translateY: 50);
265+
}
266+
267+
private static void AssertMatrix(Matrix matrix, double? angle = null, double? scaleX = null, double? scaleY = null, double? translateX = null, double? translateY = null)
268+
{
269+
Assert.True(Matrix.TryDecomposeTransform(matrix, out var composed));
270+
271+
if (angle.HasValue)
272+
{
273+
Assert.Equal(angle.Value, composed.Angle);
274+
}
275+
276+
if (scaleX.HasValue)
277+
{
278+
Assert.Equal(scaleX.Value, composed.Scale.X);
279+
}
280+
281+
if (scaleY.HasValue)
282+
{
283+
Assert.Equal(scaleY.Value, composed.Scale.Y);
284+
}
285+
286+
if (translateX.HasValue)
287+
{
288+
Assert.Equal(translateX.Value, composed.Translate.X);
289+
}
290+
291+
if (translateY.HasValue)
292+
{
293+
Assert.Equal(translateY.Value, composed.Translate.Y);
294+
}
295+
}
228296
}
229297
}

0 commit comments

Comments
 (0)