Skip to content

Commit

Permalink
[coregraphics] Add 'MatrixOrder' overload for Scale, Rotate and Trans…
Browse files Browse the repository at this point in the history
…late (#5011)

- Fixes #4698: CGAffineTransform.Scale does not work like Swift's .scaledBy(x:y:)
  (#4698)
- 'Scale' monotouch-test now covers the new overload for the new multiplication order.
- Changed the Scale test's values so we have different values for 'x0' (it was always 0 before) and so it matches the test case from the bug report.

* Same fix for Rotate and Translate
  • Loading branch information
VincentDondain authored and spouliot committed Oct 22, 2018
1 parent c378d6b commit f87f3b8
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 20 deletions.
56 changes: 53 additions & 3 deletions src/CoreGraphics/CGAffineTransform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,30 @@ public void Multiply (CGAffineTransform b)
x0 = a.x0 * b.xx + a.y0 * b.xy + b.x0;
y0 = a.x0 * b.yx + a.y0 * b.yy + b.y0;
}

public enum MatrixOrder {
Prepend = 0,
Append = 1,
}

public void Scale (nfloat sx, nfloat sy, MatrixOrder order)
{
switch (order) {
case MatrixOrder.Prepend: // The new operation is applied before the old operation.
this = Multiply (MakeScale (sx, sy), this); // t' = [ sx 0 0 sy 0 0 ] * t – Swift equivalent
break;
case MatrixOrder.Append: // The new operation is applied after the old operation.
this = Multiply (this, MakeScale (sx, sy)); // t' = t * [ sx 0 0 sy 0 0 ]
break;
default:
throw new ArgumentOutOfRangeException (nameof (order));
}
}

[Advice ("By default, the new operation is applied after the old operation: t' = t * [ sx 0 0 sy 0 0 ].\nTo have the same behavior as the native Swift API, pass 'MatrixOrder.Prepend' to 'Scale (nfloat, nfloat, MatrixOrder)'.")]
public void Scale (nfloat sx, nfloat sy)
{
Multiply (MakeScale (sx, sy));
Scale (sx, sy, MatrixOrder.Append);
}

public static CGAffineTransform Scale (CGAffineTransform transform, nfloat sx, nfloat sy)
Expand All @@ -123,9 +143,24 @@ public static CGAffineTransform Scale (CGAffineTransform transform, nfloat sx, n
transform.y0);
}

public void Translate (nfloat tx, nfloat ty, MatrixOrder order)
{
switch (order) {
case MatrixOrder.Prepend: // The new operation is applied before the old operation.
this = Multiply (MakeTranslation (tx, ty), this); // t' = [ 1 0 0 1 tx ty ] * t – Swift equivalent
break;
case MatrixOrder.Append: // The new operation is applied after the old operation.
this = Multiply (this, MakeTranslation (tx, ty)); // t' = t * [ 1 0 0 1 tx ty ]
break;
default:
throw new ArgumentOutOfRangeException (nameof (order));
}
}

[Advice ("By default, the new operation is applied after the old operation: t' = t * [ 1 0 0 1 tx ty ].\nTo have the same behavior as the native Swift API, pass 'MatrixOrder.Prepend' to 'Translate (nfloat, nfloat, MatrixOrder)'.")]
public void Translate (nfloat tx, nfloat ty)
{
Multiply (MakeTranslation (tx, ty));
Translate (tx, ty, MatrixOrder.Append);
}

public static CGAffineTransform Translate (CGAffineTransform transform, nfloat tx, nfloat ty)
Expand All @@ -139,9 +174,24 @@ public static CGAffineTransform Translate (CGAffineTransform transform, nfloat t
tx * transform.yx + ty * transform.yy + transform.y0);
}

public void Rotate (nfloat angle, MatrixOrder order)
{
switch (order) {
case MatrixOrder.Prepend: // The new operation is applied before the old operation.
this = Multiply (MakeRotation (angle), this); // t' = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] * t – Swift equivalent
break;
case MatrixOrder.Append: // The new operation is applied after the old operation.
this = Multiply (this, MakeRotation (angle)); // t' = t * [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ]
break;
default:
throw new ArgumentOutOfRangeException (nameof (order));
}
}

[Advice ("By default, the new operation is applied after the old operation: t' = t * [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ].\nTo have the same behavior as the native Swift API, pass 'MatrixOrder.Prepend' to 'Rotate (nfloat, MatrixOrder)'.")]
public void Rotate (nfloat angle)
{
Multiply (MakeRotation (angle));
Rotate (angle, MatrixOrder.Append);
}

public static CGAffineTransform Rotate (CGAffineTransform transform, nfloat angle)
Expand Down
66 changes: 49 additions & 17 deletions tests/monotouch-test/CoreGraphics/AffineTransformTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,27 @@ public void StaticMultiply ()
[Test]
public void Scale ()
{
var transform = CGAffineTransform.MakeTranslation (0, 200);
transform.Scale (1, -1);

Assert.AreEqual ((nfloat) 1, transform.xx);
Assert.AreEqual ((nfloat) 0, transform.yx);
Assert.AreEqual ((nfloat) 0, transform.xy);
Assert.AreEqual ((nfloat) (-1), transform.yy);
Assert.AreEqual ((nfloat) 0, transform.x0);
Assert.AreEqual ((nfloat) (-200), transform.y0);
var transform1 = CGAffineTransform.MakeTranslation (1, 2);
// t' = t * [ sx 0 0 sy 0 0 ]
transform1.Scale (3, 4); // MatrixOrder.Append by default

Assert.AreEqual ((nfloat) 3, transform1.xx);
Assert.AreEqual ((nfloat) 0, transform1.yx);
Assert.AreEqual ((nfloat) 0, transform1.xy);
Assert.AreEqual ((nfloat) 4, transform1.yy);
Assert.AreEqual ((nfloat) 3, transform1.x0);
Assert.AreEqual ((nfloat) 8, transform1.y0);

var transform2 = CGAffineTransform.MakeTranslation (1, 2);
// t' = [ sx 0 0 sy 0 0 ] * t – Swift equivalent
transform2.Scale (3, 4, CGAffineTransform.MatrixOrder.Prepend);

Assert.AreEqual ((nfloat)3, transform2.xx);
Assert.AreEqual ((nfloat)0, transform2.yx);
Assert.AreEqual ((nfloat)0, transform2.xy);
Assert.AreEqual ((nfloat)4, transform2.yy);
Assert.AreEqual ((nfloat)1, transform2.x0);
Assert.AreEqual ((nfloat)2, transform2.y0);
}

[Test]
Expand All @@ -172,7 +184,7 @@ public void StaticScale ()
public void Translate ()
{
var transform = CGAffineTransform.MakeIdentity ();
transform.Translate (1, -1);
transform.Translate (1, -1); // MatrixOrder.Append by default

Assert.AreEqual ((nfloat) 1, transform.xx, "xx");
Assert.AreEqual ((nfloat) 0, transform.yx, "yx");
Expand All @@ -184,12 +196,22 @@ public void Translate ()
transform = new CGAffineTransform (1, 2, 3, 4, 5, 6);
transform.Translate (2, -3);

Assert.AreEqual ((nfloat) 1, transform.xx, "xx");
Assert.AreEqual ((nfloat) 2, transform.yx, "yx");
Assert.AreEqual ((nfloat) 3, transform.xy, "xy");
Assert.AreEqual ((nfloat) 4, transform.yy, "yy");
Assert.AreEqual ((nfloat) 7, transform.x0, "x0");
Assert.AreEqual ((nfloat) 3, transform.y0, "y0");
Assert.AreEqual ((nfloat)1, transform.xx, "xx");
Assert.AreEqual ((nfloat)2, transform.yx, "yx");
Assert.AreEqual ((nfloat)3, transform.xy, "xy");
Assert.AreEqual ((nfloat)4, transform.yy, "yy");
Assert.AreEqual ((nfloat)7, transform.x0, "x0");
Assert.AreEqual ((nfloat)3, transform.y0, "y0");

transform = new CGAffineTransform (1, 2, 3, 4, 5, 6);
transform.Translate (2, -3, CGAffineTransform.MatrixOrder.Prepend);

Assert.AreEqual ((nfloat)1, transform.xx, "xx");
Assert.AreEqual ((nfloat)2, transform.yx, "yx");
Assert.AreEqual ((nfloat)3, transform.xy, "xy");
Assert.AreEqual ((nfloat)4, transform.yy, "yy");
Assert.AreEqual ((nfloat)(-2), transform.x0, "x0");
Assert.AreEqual ((nfloat)(-2), transform.y0, "y0");
}

[Test]
Expand Down Expand Up @@ -227,14 +249,24 @@ public void StaticTranslate ()
public void Rotate ()
{
var transform = new CGAffineTransform (1, 2, 3, 4, 5, 6);
transform.Rotate ((nfloat) Math.PI);
transform.Rotate ((nfloat) Math.PI); // MatrixOrder.Append by default

Assert.That ((double) (-1), Is.EqualTo ((double) transform.xx).Within (0.000001), "xx");
Assert.That ((double) (-2), Is.EqualTo ((double) transform.yx).Within (0.000001), "yx");
Assert.That ((double) (-3), Is.EqualTo ((double) transform.xy).Within (0.000001), "xy");
Assert.That ((double) (-4), Is.EqualTo ((double) transform.yy).Within (0.000001), "yy");
Assert.That ((double) (-5), Is.EqualTo ((double) transform.x0).Within (0.000001), "x0");
Assert.That ((double) (-6), Is.EqualTo ((double) transform.y0).Within (0.000001), "y0");

transform = new CGAffineTransform (1, 2, 3, 4, 5, 6);
transform.Rotate ((nfloat)Math.PI, CGAffineTransform.MatrixOrder.Prepend);

Assert.That ((double)(-1), Is.EqualTo ((double)transform.xx).Within (0.000001), "xx");
Assert.That ((double)(-2), Is.EqualTo ((double)transform.yx).Within (0.000001), "yx");
Assert.That ((double)(-3), Is.EqualTo ((double)transform.xy).Within (0.000001), "xy");
Assert.That ((double)(-4), Is.EqualTo ((double)transform.yy).Within (0.000001), "yy");
Assert.That ((double)5, Is.EqualTo ((double)transform.x0).Within (0.000001), "x0");
Assert.That ((double)6, Is.EqualTo ((double)transform.y0).Within (0.000001), "y0");
}

[Test]
Expand Down

0 comments on commit f87f3b8

Please sign in to comment.