I need the exact same thing in iOS. Here is what I finally came up with... I know the algebra calculation, but I don't know how to use LAPACK. You need to add Accelerate framework to calculate matrix inverse. Assume you have points p1, p2, p3 in the original UIView, and q1, q2, q3 in the transformed UIView:
CGPoint p1, p2, p3, q1, q2, q3;
// TODO: initialize points
double A[36];
A[ 0] = p1.x; A[ 1] = p1.y; A[ 2] = 0; A[ 3] = 0; A[ 4] = 1; A[ 5] = 0;
A[ 6] = 0; A[ 7] = 0; A[ 8] = p1.x; A[ 9] = p1.y; A[10] = 0; A[11] = 1;
A[12] = p2.x; A[13] = p2.y; A[14] = 0; A[15] = 0; A[16] = 1; A[17] = 0;
A[18] = 0; A[19] = 0; A[20] = p2.x; A[21] = p2.y; A[22] = 0; A[23] = 1;
A[24] = p3.x; A[25] = p3.y; A[26] = 0; A[27] = 0; A[28] = 1; A[29] = 0;
A[30] = 0; A[31] = 0; A[32] = p3.x; A[33] = p3.y; A[34] = 0; A[35] = 1;
int err = matrix_invert(6, A);
assert(err == 0);
double B[6];
B[0] = q1.x; B[1] = q1.y; B[2] = q2.x; B[3] = q2.y; B[4] = q3.x; B[5] = q3.y;
double M[6];
M[0] = A[ 0] * B[0] + A[ 1] * B[1] + A[ 2] * B[2] + A[ 3] * B[3] + A[ 4] * B[4] + A[ 5] * B[5];
M[1] = A[ 6] * B[0] + A[ 7] * B[1] + A[ 8] * B[2] + A[ 9] * B[3] + A[10] * B[4] + A[11] * B[5];
M[2] = A[12] * B[0] + A[13] * B[1] + A[14] * B[2] + A[15] * B[3] + A[16] * B[4] + A[17] * B[5];
M[3] = A[18] * B[0] + A[19] * B[1] + A[20] * B[2] + A[21] * B[3] + A[22] * B[4] + A[23] * B[5];
M[4] = A[24] * B[0] + A[25] * B[1] + A[26] * B[2] + A[27] * B[3] + A[28] * B[4] + A[29] * B[5];
M[5] = A[30] * B[0] + A[31] * B[1] + A[32] * B[2] + A[33] * B[3] + A[34] * B[4] + A[35] * B[5];
NSLog(@"%f, %f, %f, %f, %f, %f", M[0], M[1], M[2], M[3], M[4], M[5]);
CGAffineTransform transform = CGAffineTransformMake(M[0], M[2], M[1], M[3], M[4], M[5]); // Order is correct...
Here is the definition of matrix_inverse, it's a C function. It's modified from another SO answer:
#import <Accelerate/Accelerate.h>
#include <stdlib.h>
int matrix_invert(long N, double *matrix) {
long error=0;
long *pivot = malloc(N*N*sizeof(long));
double *workspace = malloc(N*sizeof(double));
dgetrf_(&N, &N, matrix, &N, pivot, &error);
if (error != 0) {
// NSLog(@"Error 1");
return error;
}
dgetri_(&N, matrix, &N, pivot, workspace, &N, &error);
if (error != 0) {
// NSLog(@"Error 2");
return error;
}
free(pivot);
free(workspace);
return error;
}
Here is the source code on github, I might refactor it into a function taking NSArray of CGPoints later.
If you have more than 3 points, you need to solve by least square fit. Matrix inverse can do , but is not numerical stable (results can be off a lot), I might also add this solution into the gist later. The correct way is using Singular Value Decomposition, which I don't know how to do with LAPACK.