1

Update: partially working implementation below.

I've asked a couple questions on this previously here and here.

The first works great to determine if the "image" rect is sufficiently contained inside the "crop" rect. The second works a little bit, but something's off in my implementation of it that it doesn't really work.

I'm now looking at the problem a little differently, and would like to change the behavior:

  1. When the user begins to rotate the image, I'll run the check method (below) to determine if it needs fixing or not.
  2. If it does need fixing, rather than waiting until the user has finished rotating it, I'd like to resize the image simultaneously to fit the bounds. Is there a simpler (or more reliable) way to implement this behavior?
  3. I'm going to block rotation greater than 35ยบ in either direction so that we don't have to worry about severe enlargements.

Assumptions/Constraints:

  1. I'm using AutoLayout
  2. Point of rotation will be the center of the crop rect, which may or may not be the center of the image rect.
  3. This demonstrates it working with a square crop, but the user can resize it to whatever, so I imagine it's going to bite me in the ass even more so when it's not square.

Code:

- (BOOL)rotatedView:(UIView*)rotatedView containsViewCompletely:(UIView*)cropView {
    // If this method returns YES, good! if NO, bad!

    CGPoint cropRotated[4];
    CGRect rotatedBounds = rotatedView.bounds;
    CGRect cropBounds = cropView.bounds;

    // Convert corner points of cropView to the coordinate system of rotatedView:
    cropRotated[0] = [cropView convertPoint:cropBounds.origin toView:rotatedView];
    cropRotated[1] = [cropView convertPoint:CGPointMake(cropBounds.origin.x + cropBounds.size.width, cropBounds.origin.y) toView:rotatedView];
    cropRotated[2] = [cropView convertPoint:CGPointMake(cropBounds.origin.x + cropBounds.size.width, cropBounds.origin.y + cropBounds.size.height) toView:rotatedView];
    cropRotated[3] = [cropView convertPoint:CGPointMake(cropBounds.origin.x, cropBounds.origin.y + cropBounds.size.height) toView:rotatedView];

    // Check if all converted points are within the bounds of rotatedView:
    return (CGRectContainsPoint(rotatedBounds, cropRotated[0]) &&
            CGRectContainsPoint(rotatedBounds, cropRotated[1]) &&
            CGRectContainsPoint(rotatedBounds, cropRotated[2]) &&
            CGRectContainsPoint(rotatedBounds, cropRotated[3]));
}

Taking even yet a different spin on this, I'm getting there. But as you can see in the .gif, eventually the calculations get out of whack because the rotation really isn't what I should be using to calculate the new size. How can I implement this with the correct geometry to ensure the image always resizes correctly? For time saving, I put this into an Xcode project so you don't have to fiddle around building your own: https://github.com/r3mus/RotationCGRectFix.git

- (IBAction)gestureRecognized:(UIRotationGestureRecognizer *)gesture {
    CGFloat maxRotation = 40;
    CGFloat rotation = gesture.rotation;
    CGFloat currentRotation = atan2f(_imageView.transform.b, _imageView.transform.a);;

    NSLog(@"%0.4f", RADIANS_TO_DEGREES(rotation));
    if ((currentRotation > DEGREES_TO_RADIANS(maxRotation) && rotation > 0) || (currentRotation < DEGREES_TO_RADIANS(-maxRotation) && rotation < 0)) {
        return;
    }

    CGAffineTransform rotationTransform = CGAffineTransformRotate(self.imageView.transform, rotation);
    gesture.rotation = 0.0f;

    if (gesture.state == UIGestureRecognizerStateChanged) {
        CGFloat scale = sqrt(_imageView.transform.a * _imageView.transform.a + _imageView.transform.c * _imageView.transform.c);

        if ((currentRotation > 0 && rotation > 0) || (currentRotation < 0 && rotation < 0))
            scale = 1 + fabs(rotation);
        else if (currentRotation == 0)
            scale = 1;
        else
            scale = 1 - fabs(rotation);

        CGAffineTransform sizeTransform = CGAffineTransformMakeScale(scale, scale);
        CGPoint center = _imageView.center;
        _imageView.transform = CGAffineTransformConcat(rotationTransform, sizeTransform);
        _imageView.center = center;
    }
}

Gif:

enter image description here

Community
  • 1
  • 1
brandonscript
  • 68,675
  • 32
  • 163
  • 220

0 Answers0