How to determine whether value for angle of rotation of UIView is perpendicular to Y-axis or to restrict the angle of rotation to only quarter of the circle instead of whole 360 rotation.
I have a UIView with the below applied CATransformation,.
t = CATransform3DIdentity;
//Add the perspective!!!
t.m34 = 1.0/ 300;
t = CATransform3DRotate(t, 45.0f * M_PI / 180.0f, 0, 1, 0);
self.containerView.layer.sublayerTransform = t;
like in this link1
and changing the rotation angles based on UIPanGesture in the space outside of the rotated UIView with below code
- (void)handleRevealGestureStateChangedWithRecognizer:(UIPanGestureRecognizer *)recognizer{
//Calculating percent of translation.
CGPoint translation = [recognizer translationInView:recognizer.view.superview];
CGFloat rotationpercent = translation.x / recognizer.view.frame.size.width;
[self rotate:rotationpercent]; //calling method to transform based on translation value
}
- (void)rotate:(CGFloat)rotateDegress{
CGFloat angle = M_PI * rotateDegress;
t = CATransform3DRotate(t, angle, 0, 1, 0);
self.containerView.layer.sublayerTransform = t;
}
this rotates the view and for certain angles the view is either perpendicular to Y-axis on further it goes beyond window to rotate in full 360 degrees like shown in this link2.
Hence is it possible to determine if the angle is exceeding 90 degree so that rotation is disabled.
Thanks
Your code is using angles in degrees, which is fine (since you convert to radians before applying a rotation.)
Just put code in your gesture recognizer that limits the angles to a range of 0 to ~85 degrees. (Experiment with the upper limit to see how close to 90% you can get before the page is too thin to maintain the illusion of depth.) Problem solved.
Related
Hi I used UISlider and rotate an image/subview based on slider value. Slider minimum value is zero and maximum value is 360. I had multiple views. With slider I am rotating the Image perfectly.
UIView *subView = [self.view viewWithTag:100];
subView.transform = CGAffineTransformMakeRotation(slider.value * 2*M_PI / slider.maximumValue);
I selected another subview and next again selected the first view. So based on view angle I need to set slider value. But I am getting wrong.
CGAffineTransform transform = subView.transform;
CGFloat angle = atan2f(transform.b, transform.a);
[slider setValue:(angle / ((2*M_PI)/ 360)) animated:true];
What I did Wrong?
Thanks in Advance.
After some struggle I got the answer. I am getting negative angle after 90. So if I got negative angle I calculated the differences between required angle and the current angle.
CGFloat angle = [(NSNumber *)[subView valueForKeyPath:#"layer.transform.rotation.z"] floatValue];
if (angle < 0) {
angle = 6.28 + angle;
}
[slider setValue:(angle*360 / (2*M_PI)) animated:true];
i have already rotate success from center point.
But its not rotate from one side.
for ex,
When i have select point A & rotate then its rotate from Only A side,not from Point B side.
When i have select point B & rotate then its rotate from Only B side,not from Point A side.
I have already set anchor point but its not work.
Code Like that:
CGFloat angle = [self pointPairToBearingDegrees:frspnt secondPoint:lastpnt];
CGAffineTransform newtrans = CGAffineTransformMakeRotation( ( angle * M_PI ) / 180 );
[sender.superview layer].anchorPoint = CGPointMake(1.0, 1.1);
sender.superview.transform = CGAffineTransformConcat(sender.superview.transform, newtrans);
I have a UIView in my view. Right now I have a button moving the UIView on it's y axis. Here is my code
CGRect frame2 = self.test22.frame;
frame2.origin.y -= 1.f/[UIScreen mainScreen].scale; //however many pixels to the right..
self.test22.frame = frame2;
But how can I rotate it? Except using the x or y axis. I want to be able to move the UIView by rotation by 1.f.
To Rotate the UIView create the object of UIView (*view) and make transform on it
Lets to rotate the view 90 degree use below code
CGAffineTransform r_transform = CGAffineTransformIdentity;
r_transform = CGAffineTransformRotate(r_transform,DegreeYoRadians(90));
view.transform = r_transform;
Welcome to SO. You want to look at the UIView method animateWithDuration, and the view's transform property. You'd apply a rotation transform to the view in your animation block. Note that if you change a view's transform, you should not read or write the frame property. Instead use the center property to change the position and the bounds.size property if you need to change the size.
Your code might look like this:
[UIView animateWithDuration: .25
animations: ^
{
self.test22.transform = CGAffineTransformMakeRotation(M_PI/2);
CGPoint center = self.test22.center;
center.y -= 1;
self.test22.center = center;
}
];
EDIT:
I have no idea what you mean when you say "I want to be able to move the UIView by rotation by 1.f." Rotating a view is not moving it, it's rotating it. And rotation is expressed as an angle, not a value like "1". Furthermore, the angle is in radians, where π is 180 degrees, π/2 is 90 degrees, and 2π is a full-circle rotation (or no change, since it puts the rotation back at it's original value.) You have to think in terms of fractions of 2π when you do rotations. Or you can use degrees and convert to radians, where:
degrees = radians * 180/π
Also, your code that moves the view will only change the view's position by half a point on retina displays which doesn't make much sense.
I have two image views. The first is the blueish arrow, and the second is the white circle, with a black dot drawn to represent the center of the circle.
I'm trying to rotate the arrow so it's anchor point is the black dot in the picture like this
Right now I'm setting the anchor point of the arrow's layer to a point calculated like this
CGFloat y = _userImageViewContainer.center.y - CGRectGetMinY(_directionArrowView.frame);
CGFloat x = _userImageViewContainer.center.x - CGRectGetMinX(_directionArrowView.frame);
CGFloat yOff = y / CGRectGetHeight(_directionArrowView.frame);
CGFloat xOff = x / CGRectGetWidth(_directionArrowView.frame);
_directionArrowView.center = _userImageViewContainer.center;
CGPoint anchor = CGPointMake(xOff, yOff);
NSLog(#"anchor: %#", NSStringFromCGPoint(anchor));
_directionArrowView.layer.anchorPoint = anchor;
Since the anchor point is set as a percentage of the view, i.e. the coords for the center are (.5, .5), I'm calculating the percentage of the height in arrow's frame where the black dot falls. But my math, even after working out by hand, keeps resulting in .5, which isn't right because it's further than half way down when the arrow is in the original position (vertical, with the point up).
I'm rotating based on the user's compass heading
CLHeading *heading = [notif object];
// update direction of arrow
CGFloat degrees = [self p_calculateAngleBetween:[PULAccount currentUser].location.coordinate
and:_user.location.coordinate];
_directionArrowView.transform = CGAffineTransformMakeRotation((degrees - heading.trueHeading) * M_PI / 180);
The rotation is correct, it's just the anchor point that's not working right. Any ideas of how to accomplish this?
I've always found the anchor point stuff flaky, especially with rotation. I'd try something like this.
CGPoint convertedCenter = [_directionArrowView convertPoint:_userImageViewContainer.center fromView:_userImageViewContainer ];
CGSize offset = CGSizeMake(_directionArrowView.center.x - convertedCenter.x, _directionArrowView.center.y - convertedCenter.y);
// I may have that backwards, try the one below if it offsets the rotation in the wrong direction..
// CGSize offset = CGSizeMake(convertedCenter.x -_directionArrowView.center.x , convertedCenter.y - _directionArrowView.center.y);
CGFloat rotation = 0; //get your angle (radians)
CGAffineTransform tr = CGAffineTransformMakeTranslation(-offset.width, -offset.height);
tr = CGAffineTransformConcat(tr, CGAffineTransformMakeRotation(rotation) );
tr = CGAffineTransformConcat(tr, CGAffineTransformMakeTranslation(offset.width, offset.height) );
[_directionArrowView setTransform:tr];
NB. the transform property on UIView is animatable, so you could put that last line there in an animation block if desired..
Maybe better use much easier solution - make arrow image size bigger, and square. So the black point will be in center of image.
Please compare attached images and you understand what I'm talking about
New image with black dot in center
Old image with shifted dot
Now you can easy use standard anchor point (0.5, 0.5) to rotate edited image
I've been working on a maps replacement for quite a while now. The whole thing works with a UIScrollView backed by a CATiledLayer.
To rotate my map, i rotate the layer itself. (Using CATransform3DMakeRotation) Works pretty well so far =)
But if I ever call setZoomScale method the CATransform3D that is going to be submitted to my layer is resetting the rotation to 0.
My question is, is there any way to set the zoomscale of my scrollView without loosing the applied rotation?
The same problem exists for the pinch gestures.
//Additional Infos
To rotate around the current Position, i have to edit the anchor point. Maybe this is a problem for the scaling, too.
- (void)correctLayerPosition {
CGPoint position = rootView.layer.position;
CGPoint anchorPoint = rootView.layer.anchorPoint;
CGRect bounds = rootView.bounds;
// 0.5, 0.5 is the default anchorPoint; calculate the difference
// and multiply by the bounds of the view
position.x = (0.5 * bounds.size.width) + (anchorPoint.x - 0.5) * bounds.size.width;
position.y = (0.5 * bounds.size.height) + (anchorPoint.y - 0.5) * bounds.size.height;
rootView.layer.position = position;
}
- (void)onFinishedUpdateLocation:(CLLocation *)newLocation {
if (stayOnCurrentLocation) {
[self scrollToCurrentPosition];
}
if (rotationEnabled) {
CGPoint anchorPoint = [currentConfig layerPointForLocation:newLocation];
anchorPoint.x = anchorPoint.x / rootView.bounds.size.width;
anchorPoint.y = anchorPoint.y / rootView.bounds.size.height;
rootView.layer.anchorPoint = anchorPoint;
[self correctLayerPosition];
}
}
You can implement scrollViewDidZoom: delegate method and concatenate the two transforms to achieve desired effect:
- (void) scrollViewDidZoom:(UIScrollView *) scrollView
{
CATransform3D scale = contentView.layer.transform;
CATransform3D rotation = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
contentView.layer.transform = CATransform3DConcat(rotation, scale);
}
EDIT
I've got simpler idea! How about adding another view to the hierarchy with the rotation transform attached? Here's the proposed hierarchy:
ScrollView
ContentView - the one returned by viewForZoomingInScrollView:
RotationView - the one with rotation transform
MapView - the one with all the tiles
I don't think that performance should be any concern here and it's worth trying.