Bug 8386 - Bug in CGAffineTransform
Summary: Bug in CGAffineTransform
Alias: None
Product: iOS
Classification: Xamarin
Component: XI runtime ()
Version: 6.0.x
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
: 8389 ()
Depends on:
Reported: 2012-11-13 18:57 UTC by BB
Modified: 2014-04-29 09:01 UTC (History)
6 users (show)

Is this bug a regression?: ---
Last known good build:

Obj-C version of test (71.66 KB, application/zip)
2012-11-13 20:09 UTC, Pierce Boggan [MSFT]

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description BB 2012-11-13 18:57:32 UTC
In Apple iOS:

    CGAffineTransform transform=CGAffineTransformMakeTranslation(-8.66f,0.0f);

gives the CORRECT result:
[0.91, 0, 0, 1, -8.66, 0]

In Xamarin MonoTouch (v 6.0.6):
       CGAffineTransform transform=CGAffineTransform.MakeTranslation(-8.66f,0.0f);

gives an INCORRECT result:
xx:0.91 yx:0.0 xy:0.0 yy:1.0 x0:-7.9 y0:0.0

ie it's -7.9 instead of -8.66

It took me ages to find this bug and obviously may cause unpredictable results.
I have just paid $399 for Xamarin today and found this bug on the first day! This is VERY concerning about
whether we can use Xamarin in our company now. Please re-assure me you will fix this quickly.

Comment 1 Sebastien Pouliot 2012-11-13 19:55:17 UTC
*** Bug 8389 has been marked as a duplicate of this bug. ***
Comment 3 Sebastien Pouliot 2012-11-13 20:47:49 UTC
For historical reasons (that I'm still digging, it predates Xamarin) MonoTouch does not multiple the matrices in the same order as CoreGraphics. It's also a type that is entirely managed (it does not p/invoke CoreGraphics).

In that case it means the scale is applied to the translation [1].

The immediate workaround is to invert the operations, like below. That won't scale the translation and give you the same result as an ObjC app.

var transform = CGAffineTransform.MakeTranslation (-8.66f, 0.0f);
var scale = CGAffineTransform.MakeScale (0.91f, 1.0f);
var t2 = CGAffineTransform.Multiply (scale, transform);

xx:0.91 yx:0.0 xy:0.0 yy:1.0 x0:-8.66 y0:0.0

I'll update the bug once I have more information the original decision(s).

[1] other libraries, like Cairo use this model, GDI+ has a parameter [2] that allow you to prepend (default) or append the operation.
[2] http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.matrixorder.aspx
Comment 4 BB 2012-11-14 03:08:24 UTC
Thanks for the workaround, but this must be fixed or people are always at risk from inconsistent behaviour with native iPhone, and will be wasting hours of development time debugging it (as I did). 

This is the sort of bug that causes Space Shuttles to crash!
Comment 5 Rolf Bjarne Kvinge [MSFT] 2012-11-14 06:10:38 UTC
See also bug #7832.
Comment 6 Sebastien Pouliot 2012-11-14 14:58:26 UTC
This is a known issue. Fixing it, to match CoreGraphics, would cause issues to every existing applications, which are less likely to be fully tested (after a MonoTouch update) than newly developed applications.
Comment 7 Miguel de Icaza [MSFT] 2012-11-14 15:07:12 UTC
I want to add to this discussion that the MonoTouch API is currently designed to alter the caller.


foo.Scale (bar)

Affects "foo", and does so by performing:

this = this.Multiply (MakeScale ());

The Objective-C APIs on the other hand are given one source affine, parameters and return a new one.

So it is not an exact match to the API.   What we could provide is one where the semantics are more obvious as static methods:

static CGAffineTransform Scale (CGAffineTransform source, float sx, flaot sy)
Comment 8 BB 2012-11-14 18:55:36 UTC
OK, I  understand the problem of changing it now it's out there but providing an alternate API to match Core Graphics as suggested by Miguel de Icaza is a good suggestion.

You could mark the current API as "deprecated" so have a good chance of seeing issue when they start looking for the API.
Comment 9 Dan Fordham 2013-04-11 08:54:04 UTC
I've been having a similar issue with the CGAffineTransform Rotate method, it's causing a translation to occur which doesn't happen in the native iOS CoreGraphics.

transform.Translate (0, newSize.Height);
transform.Rotate (-3.14159f / 2.0f);

gives a different TX, TY result to:

transform = CGAffineTransformTranslate(transform, 0, newSize.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);

The only reason I worked it out was because I'm converting a project to Xamarin and I could debug from XCode to see the differences.

This has cost me about 6 hours of work! 

I can create a workaround but this has to be fixed or deprecated.
Comment 10 Rolf Bjarne Kvinge [MSFT] 2014-04-29 08:05:34 UTC
A new overload has been introduced that behaves like the native CGAffineTransformScale function.

See bug #19341 for more information.
Comment 11 Rolf Bjarne Kvinge [MSFT] 2014-04-29 09:01:54 UTC
@Dan: I've also introduced equivalent overloads for Rotate and Translate.