3

2 つUIViewの があり、それぞれにオブジェクトの視覚的表現が含まれています。そのオブジェクトの同じ場所に対応する3 つの既知CGPointの があります。UIViewこれらのビューの 1 つに変換を適用して、これらの 3 つのポイントが他のビューの対応するポイントと完全に一致するようにする必要があります。

スケーリング、回転、平行移動、つまりアフィン変換を処理する必要があり、そのような平行移動のパラメーターを計算するための数学を知っています (この質問を参照してください)。私が理解していないのは、実際に Obj-C でこれらの計算を実行し、正しい数値を に差し込む方法CGAffineTrasnformMakeです。当然のことのように思えますが、何らかの理由で、ここで概念の一部が欠けているだけだと思います。

つまり、CGPointAに (X1a,Y1a), (X2a,Y2a), (X3a,Y3a) があり、 B にUIView(X1b,Y1b), (X2b,Y2b), (X3b,Y3b) がある場合、UIView私は自分自身を得るために私はBCGAffineTransformに適用することができますか?UIViewAとUIView並ぶ?

ちなみに、私の展開ターゲットは iOS 5 です。以前は何もサポートする必要はありません。

ありがとう!

4

1 に答える 1

1

iOSでもまったく同じことが必要です。これが最終的に思いついたものです...代数計算は知っていますが、LAPACKの使い方はわかりません。逆行列を計算するには、Accelerate フレームワークを追加する必要があります。元の UIView にポイント p1、p2、p3 があり、変換された UIView に q1、q2、q3 があるとします。

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... 

これが matrix_inverse の定義です。これは C 関数です。別のSO回答から変更されました:

#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;
}

これが github のソース コードです。後で CGPoints の NSArray を取る関数にリファクタリングするかもしれません。

点が 3 つ以上ある場合は、最小二乗法で解く必要があります。逆行列は を実行できますが、数値的に安定していません (結果が大きくずれることがあります)。後でこのソリューションを要点に追加することもできます。正しい方法は特異値分解を使用することですが、LAPACK の使用方法がわかりません。

于 2013-06-12T06:52:58.090 に答える