CGAffineTransformMakeRotation with negative M_PI
As I stated in my first comment and as Segii already wrote: the animation will take the shortest distance between where it's value is at now and where it is trying to go. The best solution imho is to use CABasicAnimation
for forcing a counterclockwise rotation:
let anim = CABasicAnimation(keyPath: "transform.rotation")
anim.fromValue = M_PI
anim.toValue = 0
anim.additive = true
anim.duration = 2.0
myView.layer.addAnimation(anim, forKey: "rotate")
myView.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI))
This will rotate it by 180 counter clockwise in one go.
The angle you specify in the last line + the fromValue
is the starting angle -> 0. And then the rotation will go the distance (toValue - fromValue) = 0 - M_PI = - M_PI
-> counter clockwise 180 degree rotation.
CGAffineTransformRotate and M_PI inconsistencies (Objective-C, iOS)
The problem is you can't really control the rotation direction when using animateWithDuration. It will always take the shortest route. When rotating 180 degrees the behavior is undetermined because in theory there are 2 possibilities for the shortest route. This also explains why you can't rotate more than 180 degrees. If you want to have more control over the animation or do more complex animations use a CAKeyframeAnimation.
About CGAffineTransformMakeRotation rotation direction?
This is an error in documentation.
Here they describe matrix and provide equations which they use to do the transform:
If you do the math, you'll see that for positive angles, it gives rotation counterclockwise when Y axis direction is upwards as in OS X and clockwise when Y axis directed downwards as in iOS
For example you may try to transform point (5,0) with 90 degrees, you will get (0,5), which means clockwise for iOS and counterclockwise for OS X.
The same piece of documentation still have the (false) part you quoted:
In iOS, a positive value specifies counterclockwise
rotation and a negative value specifies clockwise rotation. In OS X, a
positive value specifies clockwise rotation and a negative value
specifies counterclockwise rotation.
Which is clearly wrong, because the equations (which are the part of the same document and are pretty standard rotation equations) say the opposite.
CGAffineTransformMakeRotation on AnnotationViews
As a matter of fact, for a reason I ignore, it was enough to assign the angle in the animation for the annotation view to appropriately rotate: this is the upadated code including a chunk for reversing the annotation if pointing towards the left:
BOOL oldVerticalInverted=NO;
#define degreesToRadians(x) (M_PI * x / 180.0)
#define radiandsToDegrees(x) (x * 180.0 / M_PI)
-(void)adjustAnnotationFor:(CLLocationCoordinate2D)start ToCoordinates:(CLLocationCoordinate2D)end completion:(void (^)(void))completion{
__block float newAngle=[Line angleFromCoordinate:start toCoordinate:end];
__block float angle2Rotate=self.angle;
__block BusAnnotation* blockSelf=self;
__block BOOL blockOldInverted=oldVerticalInverted;
NSLog(@"setto angle a %f cos=%f", self.angle, cos(self.angle));
if (view!=nil){
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:1 animations:^{
blockSelf.angle=newAngle;
BOOL verticallyInverted=cos(blockSelf.angle)<0;
int invertVertical=blockOldInverted==verticallyInverted?1:-1;
blockOldInverted=verticallyInverted;
CGAffineTransform affineInvert=CGAffineTransformMakeScale(1, invertVertical);
view.transform=CGAffineTransformConcat(CGAffineTransformIdentity, affineInvert);
}
completion :^(BOOL finished){
if (completion) completion();
}];
});
}
}
The only remaining issue is how to reverse a text I have burnt inside the annotationView and that would be reversed when pointing towards the left: that is how I make this latter part:
-(UIImage *)burnText:(NSString *)text ofBackColor:(UIColor*)color intoImage:(UIImage *)img inRect:(CGRect)aRect font:(UIFont*) font{
UIGraphicsBeginImageContextWithOptions(img.size,NO,0.0);
CGRect aRectangle = CGRectMake(0,0, img.size.width, img.size.height);
[img drawInRect:aRectangle];
NSMutableParagraphStyle *textStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
textStyle.lineBreakMode = NSLineBreakByTruncatingTail;
textStyle.alignment=NSTextAlignmentCenter;
NSDictionary *dictionary = @{ NSFontAttributeName: font,
NSParagraphStyleAttributeName: textStyle,
NSForegroundColorAttributeName: [UIColor blackColor],
NSBackgroundColorAttributeName: color};
[text drawInRect:aRect withAttributes:dictionary];
UIImage *theImage=UIGraphicsGetImageFromCurrentImageContext(); // extract the image
UIGraphicsEndImageContext(); // clean up the context.
theImage.accessibilityValue=text;
return theImage;
}
Rotate UIImageView with same center point using CGAffineTransformMakeRotation
Turns out the weird rotation issue was related to the new iOS 6 autolayout feature. Once I took some time to understand how the align constraints worked I was able to achieve the results I wanted.
If you run into weird rotation issues and are using iOS 6 with autolayout enabled chances are your constraints need adjusting.
The key is to vertically and horizontally center the image under rotation in it's parent view.
iOS: How to rotate UIImageView around center point?
From my above comment: You can simply reset the transformation with
hourHand.transform = CGAffineTransformMakeRotation(0);
// or:
hourHand.transform = CGAffineTransformIdentity;
and there is no need to remember rotationBackHour
. (Setting the transform
does not accumulate.)
Note also that you can simplify your code to
hourHand.transform = CGAffineTransformMakeRotation((hourHandLocation + 1)*M_PI/6.0);
hourCorrectAnswer = [NSString stringWithFormat:@"%d", hourHandLocation + 1];
make the many if-blocks obsolete.
The "appears sometimes in random positions" problem is caused by Autolayout or by the Autosizing options. Either switch them off or fix them such that the size and relative position of the hours/minute view to the clock does not change.
how To detect that cgaffinetransformrotate method is rotating the clockwise or anticlockwise?
YourView.transform = CGAffineTransformMakeRotation( positive value );will rotate the view clockwise, and
YourView.transform = CGAffineTransformMakeRotation( Negative value );will rotate the view Anti clockwise,
CGAffineTransform rotation goes the wrong way
Your confusion is quite understandable.
In truth, a positive angle represents a rotation from the positive X axis toward the positive Y axis. A negative angle represents a rotation from the positive X axis toward the negative Y axis.
The “native” Core Graphics coordinate system is modeled after the standard Cartesian coordinate system, in which the Y axis increases upward on the page. In this system, a positive angle represents a counter-clockwise rotation:
So if you create your own CGContext
(for example, by using CGBitmapContextCreate
or CGPDFContextCreate
), rotations will work as you expect.
However, computer systems have historically used a coordinate system in which the Y axis increases downward on the page. In a flipped coordinate system like this, a positive angle represents a clockwise rotation:
Notice that in both coordinate systems, a positive angle rotates from the positive X axis toward the positive Y axis.
It turns out that UIKit flips the coordinate system of the graphics contexts that it creates for you. This includes the graphics context it sets up before sending you drawRect:
and the graphics context it sets up in UIGraphicsBeginImageContext
. (The Quartz 2D Programming Guide explains this.) You can check this by looking at the current transform matrix (using CGContextGetCTM
). You will find that it has a -1
in its d
element, meaning that the Y axis is flipped.
A UIView
also uses a flipped coordinate system for laying out its subviews, which affects the meaning of the UIView
transform
property.
Related Topics
iOS - Setobject VS. Synchronize
Swift - How to Open Another Viewcontroller with Collectionviewcell Inside Uitableviewcell
Displaying Strings in iOS Randomly Without Repeating Them
Dyld: Library Not Loaded: @Rpath/Mydsk.Framework/Mydsk -> Swift iOS 8.0
Backgroundtimeremaining Returns (35791394 Mins)
iOS Pass Data Back from Viewcontroller2 to Viewcontroller 1 with Presentmodalsegue
Multiple Cells Selected on Scrolling [Reuse Cells Problem]
How to Make Async/Await in Swift
How to Indicate a View Which Has Created with Uikit from a Skscene
How to Convert Base64 into Nsdata in Swift
Swift: Terminating with Uncaught Exception of Type Nsexception
Draw Button on Top of Avplayer
Changing Constraint When Keyboard Appears - Swift
How to Get the Index (String.Index) Value from the Cursor Position of a Uitextview Element in Swift