CGAffineTransform matrix in readable format

How to interpret CoreGraphics CGAffineTransform in a human-readable format?

I want to take something like:

NSLog(@"naturalSize %@, appliedSize %@, transformationMatrix %@",
      NSStringFromCGSize(clipVideoTrack.naturalSize),
      NSStringFromCGSize(CGSizeApplyAffineTransform(clipVideoTrack.naturalSize, clipVideoTrack.preferredTransform)),
      NSStringFromCGAffineTransform(clipVideoTrack.preferredTransform));

naturalSize {1920, 1080}, applySize {-1080, 1920}, transformMatrix [0, 1, -1, 0, 1080, 0]

The end result of the aforementioned matrix transformation takes this Landscape Right Video and is converted to this Portrait video

I would be glad to have the opportunity to break it down into human readable steps so that you can understand and understand what the transformation actually does.

Something like (not sure what I understood correctly):

 0. Will use upper left corner for video export of width 1080, height 1920.
 1. Will move the video -1080(left) on the x axis 
 2. Will move the video 1920(down) on the y axis
 3. Will rotate 90deg clockwise from bottom right corner 

, , , . , AVFoundation.

+4
2

, , . 3D- : (

, , , . , .


, , .

, if (fabs(foo - bar) < FLT_EPSILON), if (foo == bar), . , (im).

, . asin(b), , . b a arctan .

, , , .

NSString *affineTransformDescription(CGAffineTransform transform)
{
    // check if it simply the identity matrix
    if (CGAffineTransformIsIdentity(transform)) {
        return @"Is the identity transform";
    }
    // the above does't catch things like a 720° rotation so also check it manually
    if (fabs(transform.a  - 1.0) < FLT_EPSILON &&
        fabs(transform.b  - 0.0) < FLT_EPSILON &&
        fabs(transform.c  - 0.0) < FLT_EPSILON &&
        fabs(transform.d  - 1.0) < FLT_EPSILON &&
        fabs(transform.tx - 0.0) < FLT_EPSILON &&
        fabs(transform.ty - 0.0) < FLT_EPSILON) {
        return @"Is the identity transform";
    }

    // The affine transforms is built up like this:

    // a b tx
    // c d ty
    // 0 0 1

    // An array to hold all the different descirptions, charasteristics of the transform.
    NSMutableArray *descriptions = [NSMutableArray array];

    // Checking for a translation
    if (fabs(transform.tx) > FLT_EPSILON) { // translation along X
        [descriptions addObject:[NSString stringWithFormat:@"Will move %.2f along the X axis",
                                 transform.tx]];
    }
    if (fabs(transform.ty) > FLT_EPSILON) { // translation along Y
        [descriptions addObject:[NSString stringWithFormat:@"Will move %.2f along the Y axis",
                                 transform.ty]];
    }


    // Checking for a rotation
    CGFloat angle = atan2(transform.b, transform.a); // get the angle of the rotation. Note this assumes no shearing!
    if (fabs(angle) < FLT_EPSILON || fabs(angle - M_PI) < FLT_EPSILON) {
        // there is a change that there is a 180° rotation, in that case, A and D will and be negative.
        BOOL bothAreNegative  = transform.a < 0.0 && transform.d < 0.0;

        if (bothAreNegative) {
            angle = M_PI;
        } else {
            angle = 0.0; // this is not considered a rotation, but a negative scale along one axis.
        }
    }

    // add the rotation description if there was an angle
    if (fabs(angle) > FLT_EPSILON) {
        [descriptions addObject:[NSString stringWithFormat:@"Will rotate %.1f° degrees",
                                 angle*180.0/M_PI]];
    }


    // Checking for a scale (and account for the possible rotation as well)
    CGFloat scaleX = transform.a/cos(angle);
    CGFloat scaleY = transform.d/cos(angle);


    if (fabs(scaleX - scaleY) < FLT_EPSILON && fabs(scaleX - 1.0) > FLT_EPSILON) {
        // if both are the same then we can format things a little bit nicer
        [descriptions addObject:[NSString stringWithFormat:@"Will scale by %.2f along both X and Y",
                                 scaleX]];
    } else {
        // otherwise we look at X and Y scale separately
        if (fabs(scaleX - 1.0) > FLT_EPSILON) { // scale along X
            [descriptions addObject:[NSString stringWithFormat:@"Will scale by %.2f along the X axis",
                                     scaleX]];
        }

        if (fabs(scaleY - 1.0) > FLT_EPSILON) { // scale along Y
            [descriptions addObject:[NSString stringWithFormat:@"Will scale by %.2f along the Y axis",
                                     scaleY]];
        }
    }

    // Return something else when there is nothing to say about the transform matrix
    if (descriptions.count == 0) {
        return @"Can't easilly be described.";
    }

    // join all the descriptions on their own line
    return [descriptions componentsJoinedByString:@",\n"];
}

, . , :

// identity
CGAffineTransform t = CGAffineTransformIdentity;
NSLog(@"identity: \n%@", affineTransformDescription(t));


// translation
t = CGAffineTransformMakeTranslation(10, 0);
NSLog(@"translate(10, 0): \n%@", affineTransformDescription(t));

t = CGAffineTransformMakeTranslation(0, 20);
NSLog(@"translate(0, 20): \n%@", affineTransformDescription(t));

t = CGAffineTransformMakeTranslation(2, -3);
NSLog(@"translate(2, -3): \n%@", affineTransformDescription(t));


// scale
t = CGAffineTransformMakeScale(2, 2);
NSLog(@"scale(2, 2): \n%@", affineTransformDescription(t));


t = CGAffineTransformMakeScale(-1, 3);
NSLog(@"scale(-1, 3): \n%@", affineTransformDescription(t));



// rotation
t = CGAffineTransformMakeRotation(M_PI/3.0);
NSLog(@"rotate(60 deg): \n%@", affineTransformDescription(t));

t = CGAffineTransformMakeRotation(M_PI);
NSLog(@"rotate(180 deg): \n%@", affineTransformDescription(t));

t = CGAffineTransformMakeRotation(4.0*M_PI);
NSLog(@"rotate(720 deg): \n%@", affineTransformDescription(t));

t = CGAffineTransformMakeRotation(3.0*M_PI);
NSLog(@"rotate(540 deg): \n%@", affineTransformDescription(t));



// concatenated transforms
// rotate & translate
t = CGAffineTransformMakeRotation(M_PI/3.0);
t = CGAffineTransformTranslate(t, 10, 20);
NSLog(@"rotate(60 deg), translate(10, 20): \n%@", affineTransformDescription(t));

t = CGAffineTransformMakeTranslation(10, 20);
t = CGAffineTransformRotate(t, M_PI/3.0);
NSLog(@"translate(10, 20), rotate(60 deg): \n%@", affineTransformDescription(t));

// rotate & scale
t = CGAffineTransformMakeRotation(M_PI/3.0);
t = CGAffineTransformScale(t, 2, 2);
NSLog(@"rotate(60 deg), scale(2, 2): \n%@", affineTransformDescription(t));

t = CGAffineTransformMakeScale(2, 2);
t = CGAffineTransformRotate(t, M_PI/3.0);
NSLog(@"scale(2, 2), rotate(60 deg): \n%@", affineTransformDescription(t));

// translate & scale
t = CGAffineTransformMakeTranslation(10, 20);
t = CGAffineTransformScale(t, 2, 2);
NSLog(@"translate(10, 20), scale(2, 2): \n%@", affineTransformDescription(t));

t = CGAffineTransformMakeScale(2, 2);
t = CGAffineTransformTranslate(t, 10, 20);
NSLog(@"scale(2, 2), translate(10, 20): \n%@", affineTransformDescription(t));

:

identity: 
  Is the identity transform
translate(10, 0): 
  Will move 10.00 along the X axis
translate(0, 20): 
  Will move 20.00 along the Y axis
translate(2, -3): 
  Will move 2.00 along the X axis,
  Will move -3.00 along the Y axis
scale(2, 2): 
  Will scale by 2.00 along both X and Y
scale(-1, 3): 
  Will scale by -1.00 along the X axis,
  Will scale by 3.00 along the Y axis
rotate(60 deg): 
  Will rotate 60.0° degrees
rotate(180 deg): 
  Will rotate 180.0° degrees
rotate(720 deg): 
  Is the identity transform
rotate(540 deg): 
  Will rotate 180.0° degrees
rotate(60 deg), translate(10, 20): 
  Will move -12.32 along the X axis,
  Will move 18.66 along the Y axis,
  Will rotate 60.0° degrees
translate(10, 20), rotate(60 deg): 
  Will move 10.00 along the X axis,
  Will move 20.00 along the Y axis,
  Will rotate 60.0° degrees
rotate(60 deg), scale(2, 2): 
  Will rotate 60.0° degrees,
  Will scale by 2.00 along both X and Y
scale(2, 2), rotate(60 deg): 
  Will rotate 60.0° degrees,
  Will scale by 2.00 along both X and Y
translate(10, 20), scale(2, 2): 
  Will move 10.00 along the X axis,
  Will move 20.00 along the Y axis,
  Will scale by 2.00 along both X and Y
scale(2, 2), translate(10, 20): 
  Will move 20.00 along the X axis,
  Will move 40.00 along the Y axis,
  Will scale by 2.00 along both X and Y
+15

, , .

, , . GitHub, , . 3D-, .

+2

Source: https://habr.com/ru/post/1537856/


All Articles