Search code examples
objective-ciosimagemathscale

iOS - Math help - base image zooms with pinch gesture need overlaid images adjust X/Y coords relative


I have an iPad application that has a base image UIImageView (in this case a large building or site plan or diagram) and then multiple 'pins' can be added on top of the plan (visually similar to Google Maps). These pins are also UIImageViews and are added to the main view on tap gestures. The base image is also added to the main view on viewDidLoad.

I have the base image working with the pinch gesture for zooming but obviously when you zoom the base image all the pins stay in the same x and y coordinates of the main view and loose there relative positioning on the base image (whose x,y and width,height coordinates have changed).

So far i have this...

- (IBAction)planZoom:(UIPinchGestureRecognizer *) recognizer;
{
    recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
    recognizer.scale = 1;

    for (ZonePin *pin in planContainer.subviews) {
        if ([pin isKindOfClass:[ZonePin class]]){
            CGRect pinFrame = pin.frame;

            // ****************************************
            // code to reposition the pins goes here...
            // ****************************************

            pin.frame = pinFrame;
        }
    }
}

I need help to calculate the math to reposition the pins x/y coordinates to retain there relative position on the zoomed in or out plan/diagram. The pins obviously do not want to be scaled/zoomed at all in terms of their width or height - they just need new x and y coordinates that are relative to there initial positions on the plan.

I have tried to work out the math myself but have struggled to work it through and unfortunately am not yet acquainted with the SDK enough to know if there is provision available built in to help or not.

Help with this math related problem would be really appreciated! :)

Many thanks, Michael. InNeedOfMathTuition.com


Solution

  • First, you might try embedding your UIImageView in a UIScrollView so zooming is largely accomplished for you. You can then set the max and min scale easily, and you can scroll around the zoomed image as desired (especially if your pins are subviews of the UIImageView or something else inside the UIScrollView).

    As for scaling the locations of the pins, I think it would work to store the original x and y coordinates of each pin (i.e. when the view first loads, when they are first positioned, at scale 1.0). Then when the view is zoomed, set x = (originalX * zoomScale) and y = (originalY * zoomScale).

    I had the same problem in an iOS app a couple of years ago, and if I recall correctly, that's how I accomplished it.

    EDIT: Below is more detail about how I accomplished this (I'm looking my old code now).

    I had a UIScrollView as a subview of my main view, and my UIImageView as a subview of that. My buttons were added to the scroll view, and I kept their original locations (at zoom 1.0) stored for reference.

    In -(void)scrollViewDidScroll:(UIScrollView *)scrollView method:

    for (id element in myButtons)
    {
       UIButton *theButton = (UIButton *)element;
       CGPoint originalPoint = //get original location however you want
       [theButton setFrame:CGRectMake(
           (originalPoint.x - theButton.frame.size.width / 2) * scrollView.zoomScale,
           (originalPoint.y - theButton.frame.size.height / 2) * scrollView.zoomScale,
           theButton.frame.size.width, theButton.frame.size.height)];
    }
    

    For the -(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView method, I returned my UIImageView. My buttons scaled in size, but I didn't include that in the code above. If you're finding that the pins are scaling in size automatically, you might have to store their original sizes as well as original coordinates and use that in the setFrame call.