views:

177

answers:

3

Edited to better explain my problem

I am trying to perform a zoom operation using my custom view (not UIView). The view has translation, scale, rotate values. I use these as follows, between calls to glPushMatrix() and glPopMatrix().

- (void)transform
{
    glTranslatef(translation.x + anchor.x, translation.y + anchor.y, 0.0f);
    //glRotatef(-rotation * 57.2957795f, 0.0f, 0.0f, 1.0f);
    glScalef(scale.x, scale.y, 1.0f);
    glTranslatef(-anchor.x, -anchor.y, 0.0f);
}

I am trying to figure out how I should modify the anchor and/or translation values so that the zoom operation is relative to what appears on screen. At 1:1 scale I can simply use the raw screen coordinates as the anchor and perform the above transform. But when the view is already at some arbitrary scale/position, the anchor and/or translation needs to account for that.

So far this is what I've figured out:

1) Get the displacement from the center of scale to the view origin, in screen coordinates.

2) Scale this value so it's in the view's local coordinate system.

3) Now I have the new anchor for scaling. I set the view's anchor to this value.

This alone is not enough it seems. I think I am missing a translation component, or another variable that goes into the new anchor point. What am I missing?

A: 

Some of the CGAffine animations make assumptions about the components of the matrix that you wouldn't expect.

For example,i found that CGAffineTransformMakeTranslation also effected the rotation of the View. For this reason i would recommend not using the 'Make' transforms if your concating many instances of CGAffineTransform

Also, in your above example i can see that you assume that your matrix understands that your two translates should occur at different times. A transform matrix is is a set of physical attributes about the object at any 1 point in time.

  • You want an object to move to -anchor and scale

  • You want an object to move to back to anchor

These should be considered as two different animations

You should do this with 'Key Frame Animation', here is an example: http://stackoverflow.com/questions/1175942/cgpath-animation

Alternatively, you could chain two CGAffineTransform methods together.

 -(void)Anim1
    {
    [UIView beginAnimations:@"Anim1_Done" context:NULL];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationDelegate:self];
    UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)];
    //DO STUFF HERE


    [UIView commitAnimations];
    }


- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void *)context
{


    if ([animationID isEqualToString:@"Anim1_Done"])
    {
    [self Anim2];
    }
}


 -(void)Anim2
    {
    [UIView beginAnimations:@"Anim2_Done" context:NULL];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationDelegate:self];
    UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)];
    //DO STUFF HERE
    [UIView commitAnimations];
    }
Luke Mcneice
Unfortunately I can't use the simpler UIView animation methods because I need to pass the affine transform to OpenGL to push on the matrix stack. Is there any way the anchor scale and translation can be combined in a single affine transform?
hyn
yes, you can concat animations like in your example, but just bear in mind that a transform is for 1 instance of movements so if you are moving and object to point B and then back again that would be two distinct transforms
Luke Mcneice
reading your edit, if you want a translate. scale. translate then this is three separate transforms
Luke Mcneice
A: 

Your transform intent still isn't exactly clear.

The CGAffineTransformMakeTranslation transform will create the translation matrix needed to get to a desired point, but as i mentioned in my other answer some of the make transforms make assumptions about other things like rotation, if your object hasn't been rotated and therefore cant be reset then this isn't a problem, other wise you can use the translation components of the matrix:

Transform.tx;
Transform.ty;

Edit: 3 separate animations should be done with 3 separate matrices:

baseMatrix = CGAffineTransformIdentity;

affineMatrix1 = CGAffineTransformTranslate(baseMatrix, -anchor.x, -anchor.y);

affineMatrix2 = CGAffineTransformScale(baseMatrix, scale.x, scale.y);

affineMatrix3 = CGAffineTransformTranslate(baseMatrix, anchor.x, anchor.y);
Luke Mcneice
I think I understand now that I need to perform the transforms separately. This is what I do now but I still can't figure out how to perform the zoom correctly. I edited my question to reflect this.
hyn
A: 

I found a solution. I used a separate transform specifically for the zoom operation, in addition to the transform that defines the original view. I simply concat the two to get the result I wanted -- which was to ensure that the zoom is relative to the original view.

hyn