Question

I'm trying to rotate an image around the center of a view using sliders, one for x, y and Z planes. I would like the image to rotate inside it's framed boundaries (700X700) but for some reason it rotates around the edges of the frame. I tried resetting the anchor point but that doesn't seem to do anything. here's the code to rotate it around the Y axis; you'll notice the anchor point section commented out - it wasn't having any affect at all. Any idea of what i'm doing wrong?

     float angleYDeg = self.ySlider.value;
     float angleYRad = (angleYDeg / 180.0) * M_PI;

    // Disable Animation
     [CATransaction begin];
     [CATransaction setValue:[NSNumber numberWithBool:YES]
                  forKey:kCATransactionDisableActions];

 // Get Layers
     CALayer *containerLayer = [[self.imageView.layer sublayers] objectAtIndex:0];
     CALayer *holder = [containerLayer valueForKey:@"__holderLayer"];

     //CGPoint anchor = holder.anchorPoint;
     //anchor.y = self.imageView.frame.size.height/2;
     //holder.anchorPoint = anchor;

     // Update xAngle Value
     [containerLayer setValue:[NSNumber numberWithFloat:angleYRad] forKey:@"__angleY"];

    // Apply rotations
     CGFloat angleX = [[containerLayer valueForKey:@"__angleX"]floatValue];
     CATransform3D holderTransform = CATransform3DMakeRotation( angleX, 1.0f, 0.0f,  0.0f);
     holderTransform = CATransform3DRotate(holderTransform, angleYRad, 0.0f, 1.0f, 0.0f);
     holder.transform = holderTransform;

     [CATransaction commit];

     // Update Label
     self.yValueLabel.text = [NSString stringWithFormat:@"%4.0fº", angleYDeg]; 
Was it helpful?

Solution

I'm not sure the exact answer to your question as I can't figure out where it's going wrong in the code. By default things should be rotating around the center. I wrote a demo app that shows how to change the rotation for all the axis using a UISlider. I've posted it on github here: https://github.com/perlmunger/AllAxis.git . Here is the gist of the code, though:

- (IBAction)sliderDidChange:(id)sender
{
  [self setTransforms];
}

- (void)setTransforms
{
  CGFloat x = [_xSlider value];
  CGFloat y = [_ySlider value];
  CGFloat z = [_zSlider value];

  CATransform3D transform = CATransform3DIdentity;
  transform.m34 = 1.0f/-800.0f; // perspective

  CGFloat rotationValue = x * kRotationMaxInDegrees;

  transform = CATransform3DRotate(transform, 
                  degreesToRadians(rotationValue), 1.0f, 0.0f, 0.0f);

  rotationValue = y * kRotationMaxInDegrees;

  transform = CATransform3DRotate(transform, 
                  degreesToRadians(rotationValue), 0.0f, 1.0f, 0.0f);

  rotationValue = z * kRotationMaxInDegrees;

  transform = CATransform3DRotate(transform, 
                  degreesToRadians(rotationValue), 0.0f, 0.0f, 1.0f);

  [[_rotationView layer] setTransform:transform];

}

This code builds up a collective transform that you apply to the view's layer on each change to any slider.

OTHER TIPS

Doing consecutive transforms can often go awry. When you transform the angleX, the AngleY transform will then be executed based on the new coordinate system. Basically all the transforms are done relative to the "model" or object.

Most people usually expect the transforms to be made relative to the camera system, or as we are looking at the view. Its likely that the results you want are going to be obtained by reversing the order of the transforms like this:

// Apply rotations
 CGFloat angleX = [[containerLayer valueForKey:@"__angleX"]floatValue];
 CATransform3D holderTransform = CATransform3DMakeRotation( angleYRad, 0.0f, 1.0f, 0.0f);
 holderTransform = CATransform3DRotate(holderTransform, angleX, 1.0f, 0.0f,  0.0f);
 holder.transform = holderTransform;

 [CATransaction commit];

It might help if you think of it as a lifo system (though its not!) if you are considering all moves based on camera coordinates instead of the model's coordinates.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top