Search code examples
iosobjective-cframecgaffinetransformbounds

Update frame's origin after applying CGAffineTransformRotate


I have the x and y coordinates, and the rotation of a UIImageView that I need to place on its original position. The coordinates correspond to the ones of the view once it had been rotated.

The problem that I have found is that if I initialize the view with the given x and y, and perform the rotation afterwards, the final position is not correct, because the order in which the transformations were applied was not correct:

float x, y, w, h; // These values are given 

UIImageView *imageView = [[UIImageView alloc] init];

// Apply transformations
imageView.frame = CGRectMake(x, y, w, h);
imageView.transform = CGAffineTransformRotate(imageView.transform, a.rotation);

If I try to use the x and y to translate the view once it has been rotated, then the final x and y are completely wrong:

float x, y, w, h; // These values are given 

UIImageView *imageView = [[UIImageView alloc] init];
imageView.frame = CGRectMake(0, 0, w, h);

// Apply transformations
imageView.transform = CGAffineTransformTranslate(imageView.transform, x, y);
imageView.transform = CGAffineTransformRotate(imageView.transform, a.rotation);

I have tried updating the center of the view after applying the rotation with incorrect results too.

I am looking for some advice or tips on how to deal with this in order to achieve the result that I need.

Thanks in advanced!


Solution

  • I was able to fix this by calculating the offset in the Y axis between the original Y position where the frame should be, and the origin of the transformed view.

    The functions provided in this answer for a similar question provide a way to calculate the new origin of the frame by creating a point with the minimum X and Y among all the new corners:

    -(CGPoint)frameOriginAfterTransform 
    {
        CGPoint newTopLeft = [self newTopLeft];
        CGPoint newTopRight = [self newTopRight];
        CGPoint newBottomLeft = [self newBottomLeft];
        CGPoint newBottomRight = [self newBottomRight];
    
        CGFloat minX = fminf(newTopLeft.x, fminf(newTopRight.x, fminf(newBottomLeft.x, newBottomRight.x)));
        CGFloat minY = fminf(newTopLeft.y, fminf(newTopRight.y, fminf(newBottomLeft.y, newBottomRight.y)));
    
        return CGPointMake(minX, minY);
    }
    

    Afterwards I calculated the offset in the Y axis and applied it to the center of the transformed view:

    // Adjust Y after rotating to compensate offset
    CGPoint center = imageView.center;
    CGPoint newOrigin = [imageView frameOriginAfterTransform]; // Frame origin calculated after transform
    CGPoint newCenter = CGPointZero;
    newCenter.x = center.x;
    newCenter.y = center.y + (y - newOrigin.y);
    imageView.center = newCenter;
    

    For some reason the offset is only affecting the Y axis, although at first I thought it was going to affect both X and Y.

    Hope this helps!