Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
CGAffineTransformFromRectToRect (not working)
CGAffineTransform CGAffineTransformFromRectToRect(CGRect fromRect, CGRect toRect)
{
CGSize scale = CGSizeMake(toRect.size.width / fromRect.size.width, toRect.size.height / fromRect.size.height);
CGRect scaledFromRect = CGRectMake(fromRect.origin.x * scale.width, fromRect.origin.y * scale.height,
fromRect.size.width * scale.width, fromRect.size.height * scale.height);
CGSize translation = CGSizeMake(fromRect.origin.x - scaledFromRect.origin.x, fromRect.origin.y - scaledFromRect.origin.y);
return CGAffineTransformMake(scale.width, 0.0, 0.0, scale.height, translation.width, translation.height);
}
CGRect fromRect = CGRectMake(3, -1, 1, 1);
CGRect toRect = CGRectMake(1, 3, 3, 2);
CGAffineTransform trans = OLVAffineTransformFromRectToRect(fromRect, toRect); // [3, 0, 0, 2, -6, 1]
CGRect calculatedFromRect = CGRectApplyAffineTransform(fromRect, trans); // {{3, -1}, {3, 2}}
@neilgall
Copy link

Not very optimised, but this works:

CGAffineTransform CGAffineTransformFromRectToRect(CGRect fromRect, CGRect toRect)
{
    CGAffineTransform trans1 = CGAffineTransformMakeTranslation(-fromRect.origin.x, -fromRect.origin.y);
    CGAffineTransform scale = CGAffineTransformMakeScale(toRect.size.width/fromRect.size.width, toRect.size.height/fromRect.size.height);
    CGAffineTransform trans2 = CGAffineTransformMakeTranslation(toRect.origin.x, toRect.origin.y);
    return CGAffineTransformConcat(CGAffineTransformConcat(trans1, scale), trans2);
}

@hatfinch
Copy link
Author

Thank you Neil!

@mindbrix
Copy link

mindbrix commented Nov 5, 2011

Thank you. This was so useful. Here is a supplementary method which preserves the aspect ratio.

CGAffineTransform CGAffineTransformFromRectToRectKeepAspectRatio( CGRect fromRect, CGRect toRect )
{
    float aspectRatio = fromRect.size.width / fromRect.size.height;

    if( aspectRatio > ( toRect.size.width / toRect.size.height ))
    {
        toRect = CGRectInset( toRect, 0, ( toRect.size.height - toRect.size.width / aspectRatio ) / 2.0f );
    }
    else
    {
        toRect = CGRectInset( toRect, ( toRect.size.width - toRect.size.height * aspectRatio ) / 2.0f, 0 );
    }

    return CGAffineTransformFromRectToRect( fromRect, toRect );
}

@MattFoley
Copy link

I tried to use this for some CI work and noticed that it was just slightly off. I think you guys may have been missing a small bit to offset for the size change:

 CGAffineTransform CGAffineTransformFromRectToRect(CGRect fromRect, CGRect toRect)
 {
     CGAffineTransform trans1 = CGAffineTransformMakeTranslation(-fromRect.origin.x, -fromRect.origin.y);
     CGAffineTransform scale = CGAffineTransformMakeScale(toRect.size.width/fromRect.size.width, toRect.size.height/fromRect.size.height);

     CGFloat heightDiff = fromRect.size.height - toRect.size.height;
     CGFloat widthDiff = fromRect.size.width - toRect.size.width;

     CGAffineTransform trans2 = CGAffineTransformMakeTranslation(toRect.origin.x - (widthDiff / 2), toRect.origin.y - (heightDiff / 2));
     return CGAffineTransformConcat(CGAffineTransformConcat(trans1, scale), trans2);
 }

What do you think?

@vovasty
Copy link

vovasty commented Jan 22, 2016

improved @MattFoley variant (fix for non-zero initial coordinates)

func CGAffineTransformFromRectToRect(fromRect: CGRect, toRect: CGRect) -> CGAffineTransform {
    let sx  = toRect.size.width/fromRect.size.width
    let sy  = toRect.size.height/fromRect.size.height

    let scale = CGAffineTransformMakeScale(sx, sy)

    let heightDiff = fromRect.size.height - toRect.size.height
    let widthDiff = fromRect.size.width - toRect.size.width

    let dx = toRect.origin.x - widthDiff / 2 - fromRect.origin.x
    let dy = toRect.origin.y - heightDiff / 2 - fromRect.origin.y

    let trans = CGAffineTransformMakeTranslation(dx, dy)
    return CGAffineTransformConcat(scale, trans)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment