Spiral path animation using CGMutablePathRef - ios

I'm trying to animate a view from the center of the screen to the upper left corner in a spiral-type motion. Here's what I'm doing:
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGPathMoveToPoint(curvedPath, NULL, viewOrigin.x, viewOrigin.y);
controlX1 = viewOrigin.x + halfScreenWidth*0.3;
controlY1 = viewOrigin.y + halfScreenHeight*0.1;
controlX2 = viewOrigin.x - halfScreenWidth*0.05;
controlY2 = viewOrigin.y + halfScreenHeight*0.5;
controlX3 = viewOrigin.x - halfScreenWidth*0.4;
controlY3 = viewOrigin.y;
rndX1 = viewOrigin.x + halfScreenWidth*.1;
rndX2 = viewOrigin.x - halfScreenWidth*.40;
rndY1 = viewOrigin.y + halfScreenHeight*.10;
rndY2 = viewOrigin.y + halfScreenHeight*.35;
}
CGPathAddQuadCurveToPoint(curvedPath, NULL, controlX1, controlY1, rndX1, rndY1);
CGPathAddQuadCurveToPoint(curvedPath, NULL, controlX2, controlY2, rndX2, rndY2);
CGPathAddQuadCurveToPoint(curvedPath, NULL, controlX3, controlY3, endPoint.x, endPoint.y);
pathAnimation.path = curvedPath;
CGPathRelease(curvedPath);
CAAnimationGroup *group = [CAAnimationGroup animation];
group.fillMode = kCAFillModeForwards;
[group setAnimations:[NSArray arrayWithObjects: pathAnimation, nil]];
group.duration = 3.0f;
group.delegate = self;
[group setValue:self.theView forKey:#"imageViewBeingAnimated"];
The view moves to each point on the curve, but it's not smooth, and not very curvy either. It just moves in pretty much a straight line to each point. Why isn't the path curved? I'm using this as a reference.

If you want a more smooth spiral, you could use the following function. It' s possible to adjust the code to have an opening spiral also.
-(void)addEnteringSpiralOnPath: (CGMutablePathRef) path
size: (CGSize)size
turns: (int)turns
{
CGPathMoveToPoint(path, NULL, size.width/2, 0); //To begining: Right
for (int turn = turns; turn >= 1; turn--) {
CGSize largeSize = CGSizeMake(size.width * turn/turns, size.height * turn/turns);
CGSize smallSize = CGSizeMake(size.width * (turn-1) / turns, size.height * (turn-1) / turns);
NSLog(#"Large: %#; Small: %#", NSStringFromCGSize(largeSize), NSStringFromCGSize(smallSize));
CGFloat wStep = (largeSize.width/2 - smallSize.width/2 ) / 360;
CGFloat hStep = (largeSize.height/2 - smallSize.height/2 ) / 360;
for (CGFloat i = 0; i<=360; i = i + 10) {
CGFloat iRad = i * M_PI / 180.0f;
CGPoint p = CGPointMake(cosf(iRad) * (largeSize.width/2 - wStep * i),
sinf(iRad) * (largeSize.height/2 - hStep * i));
CGPathAddLineToPoint(path, nil, p.x, p.y);
}
}
}
-(void)addOpenningSpiralOnPath: (CGMutablePathRef) path
size: (CGSize)size
turns: (int)turns
{
CGPathMoveToPoint(path, NULL, 0, 0); //To begining: Center
for (int turn = 1; turn <= turns; turn++) {
CGSize largeSize = CGSizeMake(size.width * turn/turns, size.height * turn/turns);
CGSize smallSize = CGSizeMake(size.width * (turn-1) / turns, size.height * (turn-1) / turns);
NSLog(#"Large: %#; Small: %#", NSStringFromCGSize(largeSize), NSStringFromCGSize(smallSize));
CGFloat wStep = (largeSize.width/2 - smallSize.width/2 ) / 360;
CGFloat hStep = (largeSize.height/2 - smallSize.height/2 ) / 360;
for (CGFloat i = 0; i<=360; i = i + 10) {
CGFloat iRad = i * M_PI / 180.0f;
CGPoint p = CGPointMake(cosf(iRad) * (smallSize.width/2 + wStep * i),
sinf(iRad) * (smallSize.height/2 + hStep * i));
CGPathAddLineToPoint(path, nil, p.x, p.y);
}
}
}
Then, you will just need a simple code like that to make the path:
CGMutablePathRef pathToDraw = CGPathCreateMutable();
[self addEnteringSpiralOnPath:pathToDraw size:CGSizeMake(400, 400) turns:3];

Related

How to redraw on erased image iOS? e.g. I have one erased image, would like to get redraw erased image when move on context

To Erase I'm using kCGBlendModeClear.
e.g. I have one erased image, would like to get redraw on erased image when move on CGContext.
Image : https://www.dropbox.com/s/hsltjqa3ue2dpx8/Simulator%20Screen%20Shot%20-%20iPhone%208%20-%202020-05-09%20at%2019.56.15.png?dl=0
My erase code :
-(void)initialize {
self.userInteractionEnabled = YES;
_tilesFilled = 0;
dragVw = [[UIView alloc] init];
dragVw.backgroundColor = [UIColor redColor];
[dragVw removeFromSuperview];
[self addSubview:dragVw];
if (nil == self.image) {
_tilesX = _tilesY = 0;
self.maskedMatrix = nil;
if (NULL != _imageContext) {
CGContextRelease(_imageContext);
_imageContext = NULL;
}
if (NULL != _colorSpace) {
CGColorSpaceRelease(_colorSpace);
_colorSpace = NULL;
}
} else {
self.touchPoints = [NSMutableArray array];
// CGSize size = self.image.size;
// CGSize fromImage = [self aspectScaledImageSizeForImageView:self image:self.image];
CGSize size = /*CGSizeMake(fromImage.width * pinchScale, fromImage.height * pinchScale);*/ CGSizeMake(self.image.size.width * self.image.scale, self.image.size.height * self.image.scale);
// initalize bitmap context
if (NULL == _colorSpace) {
_colorSpace = CGColorSpaceCreateDeviceRGB();
}
if (NULL != _imageContext) {
CGContextRelease(_imageContext);
}
_imageContext = CGBitmapContextCreate(0, size.width, size.height, 8, size.width * 4 , _colorSpace, kCGImageAlphaPremultipliedLast);
CGContextDrawImage(_imageContext, CGRectMake(0, 0, size.width, size.height), self.image.CGImage);
int blendMode = kCGBlendModeClear;
CGContextSetBlendMode(_imageContext, (CGBlendMode) blendMode);
_tilesX = size.width / (2 * __radius);
_tilesY = size.height / (2 * __radius);
offset = 0;
}
-(void)moveTouches:(NSSet*)touches {
// CGSize fromImage = [self aspectScaledImageSizeForImageView:self image:self.image];
CGSize size = /*CGSizeMake(fromImage.width, fromImage.height);*/ CGSizeMake(self.image.size.width * self.image.scale, self.image.size.height * self.image.scale);
CGContextRef ctx = _imageContext;
CGContextSetFillColorWithColor(ctx,[UIColor clearColor].CGColor);
CGContextSetStrokeColorWithColor(ctx,[UIColor colorWithRed:0 green:0 blue:0 alpha:0].CGColor);
// int tempFilled = _tilesFilled;
// process touches
for (UITouch *touch in touches) {
CGContextBeginPath(ctx);
CGPoint touchPoint = CGPointMake([touch locationInView:self].x , [touch locationInView:self].y);
touchPoint = fromUItoQuartz(touchPoint, self.bounds.size);
touchPoint = scalePoint(touchPoint, self.bounds.size, size);
CGPoint dragPoint = [touch locationInView:self];
CGFloat fineRadius = __radius;
NSLog(#"__radius : %zu",__radius);
dispatch_async(dispatch_get_main_queue(), ^{
self->dragVw.frame = CGRectMake(dragPoint.x - fineRadius/2 , dragPoint.y - fineRadius/2, fineRadius, fineRadius);
self->dragVw.layer.cornerRadius = self->dragVw.frame.size.height / 2;
self->dragVw.alpha = 0;
// NSLog(#"DragVw frame : %#",NSStringFromCGRect(self->dragVw.frame));
});
if(UITouchPhaseBegan == touch.phase){
[self.touchPoints removeAllObjects];
[self.touchPoints addObject:[NSValue valueWithCGPoint:touchPoint]];
[self.touchPoints addObject:[NSValue valueWithCGPoint:touchPoint]];
// on begin, we just draw ellipse
CGRect rect = CGRectMake(touchPoint.x - __radius, touchPoint.y - __radius, __radius*2, __radius*2);
CGContextAddEllipseInRect(ctx, rect);
CGContextFillPath(ctx);
static const FillTileWithPointFunc fillTileFunc = (FillTileWithPointFunc) [self methodForSelector:#selector(fillTileWithPoint:)];
(*fillTileFunc)(self,#selector(fillTileWithPoint:),rect.origin);
} else if (UITouchPhaseMoved == touch.phase) {
[self.touchPoints addObject:[NSValue valueWithCGPoint:touchPoint]];
// then touch moved, we draw superior-width line
CGContextSetStrokeColor(ctx, CGColorGetComponents([UIColor clearColor].CGColor));
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, 2 * __radius);
while(self.touchPoints.count > 3){
CGPoint bezier[4];
bezier[0] = ((NSValue*)self.touchPoints[1]).CGPointValue;
bezier[3] = ((NSValue*)self.touchPoints[2]).CGPointValue;
CGFloat k = 0.3;
CGFloat len = sqrt(pow(bezier[3].x - bezier[0].x, 2) + pow(bezier[3].y - bezier[0].y, 2));
bezier[1] = ((NSValue*)self.touchPoints[0]).CGPointValue;
bezier[1] = [self normalizeVector:CGPointMake(bezier[0].x - bezier[1].x - (bezier[0].x - bezier[3].x), bezier[0].y - bezier[1].y - (bezier[0].y - bezier[3].y) )];
bezier[1].x *= len * k;
bezier[1].y *= len * k;
bezier[1].x += bezier[0].x;
bezier[1].y += bezier[0].y;
bezier[2] = ((NSValue*)self.touchPoints[3]).CGPointValue;
bezier[2] = [self normalizeVector:CGPointMake( (bezier[3].x - bezier[2].x) - (bezier[3].x - bezier[0].x), (bezier[3].y - bezier[2].y) - (bezier[3].y - bezier[0].y) )];
bezier[2].x *= len * k;
bezier[2].y *= len * k;
bezier[2].x += bezier[3].x;
bezier[2].y += bezier[3].y;
CGContextMoveToPoint(ctx, bezier[0].x , bezier[0].y + offset );
CGContextAddCurveToPoint(ctx, bezier[1].x , bezier[1].y + offset, bezier[2].x , bezier[2].y + offset, bezier[3].x , bezier[3].y + offset);
[self.touchPoints removeObjectAtIndex:0];
}
CGContextStrokePath(ctx);
CGPoint prevPoint = [touch previousLocationInView:self];
prevPoint = fromUItoQuartz(prevPoint, self.bounds.size);
prevPoint = scalePoint(prevPoint, self.bounds.size, size);
static const FillTileWithTwoPointsFunc fillTileFunc = (FillTileWithTwoPointsFunc) [self methodForSelector:#selector(fillTileWithTwoPoints:end:)];
(*fillTileFunc)(self,#selector(fillTileWithTwoPoints:end:),touchPoint, prevPoint);
}
}
}

How to create clockwise angle text in xcode

I'm trying to create clockwise text in Xcode. My current coding is just displaying like that.
But I want to change outer text to as follow
By using this library : https://github.com/javenisme/CurvaView
CoreTextArcView * cityLabel = [[[CoreTextArcView alloc] initWithFrame:rect1
font:font1
text:#"Hello this is radious arc with text"
radius:85
arcSize:110
color:color1] autorelease];
Remove arc for one file like as follows (set -fno-objc-arc to that library's .m file from build phases of your project target) :
Output like this
This is my code to do this, it draw attributed strings.
I can't post images but the result it's just right.
Text is also automatically reversed if the angle is between 100° and 260°
#define degreesToRadians(degrees) (( degrees ) / 180.0 * M_PI )
#define radiansToDegrees(radians) (( radians ) * ( 180.0 / M_PI ) )
+ (void)drawCurvedStringOnLayer:(CALayer *)layer
withAttributedText:(NSAttributedString *)text
atAngle:(float)angle
withRadius:(float)radius {
// angle in radians
CGSize textSize = CGRectIntegral([text boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
context:nil]).size;
float perimeter = 2 * M_PI * radius;
float textAngle = (textSize.width / perimeter * 2 * M_PI); // text curved width
float textRotation;
float textDirection;
if (angle > degreesToRadians(10) && angle < degreesToRadians(170))
{
//down
textRotation = 0.5 * M_PI ;
textDirection = - 2 * M_PI;
angle += textAngle / 2 + degreesToRadians(6);
}
else
{
//up
textRotation = 1.5 * M_PI ;
textDirection = 2 * M_PI;
angle -= textAngle / 2; // + degreesToRadians(6);
}
for (int c = 0; c < text.length; c++)
{
NSRange range = {c, 1};
NSAttributedString* letter = [text attributedSubstringFromRange:range];
CGSize charSize = CGRectIntegral([letter boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
context:nil]).size;
float letterAngle = ( (charSize.width / perimeter) * textDirection );
float x = radius * cos(angle + (letterAngle/2));
float y = radius * sin(angle + (letterAngle/2));
//NSLog(#"Char %# with size: %f x %f", letter, charSize.width, charSize.height);
//NSLog(#"Char %# with angle: %f x: %f y: %f", letter, angle, x, y);
CATextLayer *text = [layers drawTextOnLayer:layer
withText:letter
frame:CGRectMake(layer.frame.size.width/2 - charSize.width/2 + x,
layer.frame.size.height/2 - charSize.height/2 + y,
charSize.width, charSize.height)
bgColor:nil
opacity:1];
text.transform = CATransform3DMakeAffineTransform( CGAffineTransformMakeRotation(angle - textRotation) );
angle += letterAngle;
}
}
+ (CATextLayer *)drawTextOnLayer:(CALayer *)layer
withText:(NSAttributedString *)text
frame:(CGRect)frame
bgColor:(UIColor *)bgColor
opacity:(float)opacity {
CATextLayer *textLayer = [[CATextLayer alloc] init];
textLayer.needsDisplayOnBoundsChange = true;
//[textLayer setFont:(__bridge CFTypeRef)(font)];
//[textLayer setFontSize:fontSize];
[textLayer setFrame:frame];
[textLayer setString:text];
[textLayer setAlignmentMode:kCAAlignmentCenter];
// [textLayer setForegroundColor:color.CGColor];
[textLayer setBackgroundColor:bgColor.CGColor];
[textLayer setContentsScale:[UIScreen mainScreen].scale];
[textLayer setOpacity:opacity];
[layer addSublayer:textLayer];
}

How does CALayer convert point from and to its sublayers?

Lets assume we have a 2D space (to simplify situation), and layer S and layer C, where C is sublayer of S.
The conversion process must affect bounds, position of C, transform of C, sublayersTransform of S, anchorPoint of C. My guess was the next:
CGAffineTransform transformToChild(CALayer *S, CALayer *C) {
CGFloat txa = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x;
CGFloat tya = - C.bounds.origin.y - C.bounds.size.height * C.anchorPoint.y;
CGFloat txb = C.position.x;
CGFloat tyb = C.position.y;
CGAffineTransform sublayerTransform = CATransform3DGetAffineTransform(S.sublayerTransform);
CGAffineTransform fromS = CGAffineTransformTranslate(sublayerTransform, txb, tyb);
fromS = CGAffineTransformConcat(fromS, C.affineTransform);
fromS = CGAffineTransformTranslate(fromS, txa, tya);
return fromS;
}
But this is not working when transform of the child layer is not identity (e.g. in case of rotation to M_PI_2 angle).
Whole code with layers:
CALayer *l1 = [CALayer new];
l1.frame = CGRectMake(-40, -40, 80, 80);
l1.bounds = CGRectMake(40, 40, 80, 80);
CALayer *l2 = [CALayer new];
l2.frame = CGRectMake(50, 40, 20, 20);
l2.bounds = CGRectMake(40, 40, 20, 20);
CGAffineTransform t2 = CGAffineTransformMakeRotation(M_PI / 2);
l2.affineTransform = t2;
[l1 addSublayer:l2];
CGAffineTransform toL2 = transformToChild(l1, l2);
CGPoint p = CGPointApplyAffineTransform(CGPointMake(70, 50), toL2);
NSLog(#"Custom Point %#", [NSValue valueWithCGPoint:p]);
p = [l1 convertPoint:CGPointMake(70, 50) toLayer:l2];
NSLog(#"CoreAnimation Point %#", [NSValue valueWithCGPoint:p]);
Comparison to system results:
Custom Point NSPoint: {-50, 80}
CoreAnimation Point NSPoint: {50, 40}
There's an old mailing list thread with some details about this here:
http://lists.apple.com/archives/quartz-dev/2008/Mar/msg00086.html
http://lists.apple.com/archives/quartz-dev/2008/Mar/msg00087.html
those messages are quite old, so e.g. they don't include the effects of the geometryFlipped property, which was added more recently, but that would just add another term onto the merged matrix.
So, I found this way of point conversion to and from sublayer's coordinate space, which works correctly with sublayer's non-identity transformation. sublayersTransform of the super layer is not covered here, but I think it would be not hard to extend these functions to support it.
CGPoint pointToChild(CALayer *C, CGPoint p) {
CGFloat txa = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x;
CGFloat tya = - C.bounds.origin.y - C.bounds.size.height * C.anchorPoint.y;
CGFloat txb = C.position.x;
CGFloat tyb = C.position.y;
p.x -= txb;
p.y -= tyb;
p = CGPointApplyAffineTransform(p, CGAffineTransformInvert(C.affineTransform));
if (C.isGeometryFlipped) {
CGAffineTransform flip = CGAffineTransformMakeScale(1.0f, -1.0f);
flip = CGAffineTransformTranslate(flip, 0, C.bounds.size.height * (2.0f * C.anchorPoint.y - 1.0f));
p = CGPointApplyAffineTransform(p, CGAffineTransformInvert(flip));
}
p.x -= txa;
p.y -= tya;
return p;
}
CGPoint pointFromChild(CALayer *C, CGPoint p) {
CGFloat txb = - C.bounds.origin.x - C.bounds.size.width * C.anchorPoint.x;
CGFloat tyb = - C.bounds.origin.y - C.bounds.size.height * C.anchorPoint.y;
CGFloat txa = C.position.x;
CGFloat tya = C.position.y;
p.x += txb;
p.y += tyb;
if (C.isGeometryFlipped) {
CGAffineTransform flip = CGAffineTransformMakeScale(1.0f, -1.0f);
flip = CGAffineTransformTranslate(flip, 0, C.bounds.size.height * (2.0f * C.anchorPoint.y - 1.0f));
p = CGPointApplyAffineTransform(p, flip);
}
p = CGPointApplyAffineTransform(p, C.affineTransform);
p.x += txa;
p.y += tya;
return p;
}

iphone: Core Animation: Reversing animation after hitting view boundary

I am trying hands at Core Animation on iphone.
Details of what I have done so far:
I am using layers and CAKeyFrameAnimation using path.
I have created a layer with Contents set to a bitmap file of a fly which I want to animate on a spiral path. The centre point of the spiral path is at CGPoint (150,150). The end point of the spiral path is a radius of 100.0f.
What I want to achieve:
I further want to increase the radius to a value so that the spiral can go beyond the bounds of the view frame, but when it reaches the bound, I desire the fly to trace back the path.
EDIT: (adding code):
-(IBAction) clickToAnimate:(id) sender
{
//create a path to animate the fly
CGFloat minRadius = 5.0f;
CGFloat maxRadius = 100.0f;
CGFloat radiusOffset = 5.0f;
float i;
int count =1;
int remainder;
curvePath = CGPathCreateMutable();
//this looping mimics the "spiral path"
for (i = minRadius; i <= maxRadius; i = i + 5.0f)
{
remainder = count % 2;
if (remainder == 0)
{
CGPathAddArc(curvePath, NULL, currentPoint.x, currentPoint.y, i, M_PI / 2, 1.5 * M_PI, NO);
}
else
{
CGPathAddArc(curvePath, NULL, currentPoint.x, currentPoint.y + radiusOffset, i, 1.5 * M_PI , M_PI / 2, NO);
}
count = count +1;
}
//add timer
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(checkCoordinatesOnTimer) userInfo:self repeats:YES];
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
animation.calculationMode = kCAAnimationPaced;
animation.path = curvePath;
animation.duration = 25.0f;
animation.autoreverses = YES;
animation.fillMode = kCAFillModeFrozen;
CGPathRelease(curvePath);
[animationLayer addAnimation:animation forKey:#"position"];
}
Approach taken:
I set up a timer, which would check the co-ordinates of the animation layer every half second. The co-ordinates would be checked against the bounding x and y co-ordinates. If the co-ordinates are found to cross the boundary, we will disable the timer and start with the reverse animation process.
The reverse animation process would first check the angle from horizontal at which the animation is when it crosses the boundary. Using this angle and radius from center point, create a path for reverse animation. Details can be found in code below.
- (void) checkCoordinatesOnTimer
{
if (!presentLayer)
{
presentLayer =[[CALayer alloc] init];
}
presentLayer = [animationLayer presentationLayer];
CGPoint curPt;
curPt.x = presentLayer.position.x;
curPt.y = presentLayer.position.y;
currRadius = sqrt(pow(fabsf(curPt.x - centerPoint.x), 2) + pow(fabsf(curPt.y - centerPoint.y), 2));
if ((curPt.x >= CGRectGetMaxX(self.view.frame)) || (curPt.y >= CGRectGetMaxY(self.view.frame)))
{
[timer invalidate];
[self reverseAnimation:curPt];
}
}
-(void) reverseAnimation:(CGPoint)curPoint
{
CGFloat angle = (CGFloat)[self calculateAngleInRadians:curPoint];
maxRadius = currRadius;
float i;
int count =1;
int remainder;
BOOL firstLap = YES;
CGPathRelease(curvePath);
curvePath = CGPathCreateMutable();
for (i = maxRadius; i >= minRadius; i = i - 5.0f)
{
remainder = count % 2 ;
if (firstLap)
{
if ((angle >= (M_PI/2)) && (angle <= 1.5 *M_PI))
//2nd and third quard,
//angle to change from final angle to 90
{
CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y, i, angle, 1.5 * M_PI, FALSE);
}
else
{
CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y, i, angle, M_PI / 2 , FALSE);
}
firstLap = NO;
continue;
}
else
{
if (remainder == 0)
{
CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y, i, 1.5* M_PI, M_PI / 2, FALSE);
}
else
{
CGPathAddArc(curvePath, NULL, centerPoint.x, centerPoint.y + radiusOffset, i, M_PI / 2 ,1.5* M_PI, FALSE);
}
}
count = count +1;
}
animation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
animation.calculationMode =kCAAnimationPaced; // for even pacing of animation in segments.
animation.path = curvePath;
animation.duration = 40.0f;
animation.fillMode = kCAFillModeForwards;
CGPathRelease(curvePath);
[animationLayer addAnimation:animation forKey:#"position"];
}
-(CGFloat) calculateAngleInRadians:(CGPoint) pt
{
CGFloat xLen = fabsf(centerPoint.x - pt.x);
CGFloat yLen = fabsf(centerPoint.y - pt.y);
double value = yLen/xLen;
double angle = atan(value);
double angleInDeg = ( 180 * angle/ M_PI);
double finalAngle;
if ((pt.x > centerPoint.x) || (pt.y > centerPoint.y)) {
finalAngle = angle;
}
else if ((centerPoint.x > pt.x) || (pt.y > centerPoint.y))
{
finalAngle = M_PI/2 + angle;
}
else if ((centerPoint.x > pt.x) || (centerPoint.y > pt.y))
{
finalAngle = M_PI + angle;
}
else {
finalAngle = (1.5 * M_PI) + angle;
}
return finalAngle;
}

Moving the 3d object in iOS application?

I am working on rotating the 3d object in my application by using the application downloaded from here.I succeed on stopping the rotating object as below, but I can't rotate the object again from the stopped position.Below is the piece of code I've worked from the downloaded project
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
{
    if (aRotate) {
        [self startOrStopAutorotation:nil];
    }
    if ([[event touchesForView:self.view] count] > 1) // Pinch gesture, possibly two-finger movement
{
//CGPoint directionOfPanning = CGPointZero;
}
    else{
        CGPoint currentMovementPosition = [[touches anyObject] locationInView:glView_];
        [self renderByRotatingAroundX:(lastMovementPosition.x - currentMovementPosition.x) rotatingAroundY: (lastMovementPosition.y - currentMovementPosition.y) scaling:1.0f translationInX:0.0f translationInY:0.0f];
        lastMovementPosition = currentMovementPosition;
    }
}
}
- (void)renderByRotatingAroundX:(float)xRotation rotatingAroundY:(float)yRotation scaling:(float)scaleF translationInX:(float)xTranslation translationInY:(float)yTranslation{
    
    glView_ = [[REGLView alloc] initWithFrame:CGRectMake(0, 0, 320, 320) colorFormat:kEAGLColorFormatRGBA8 multisampling:YES];
    [self.view addSubview:glView_];
    
    
    camera_ = [[RECamera alloc] initWithProjection:kRECameraProjectionOrthographic];
    camera_.position = CC3VectorMake(0, 0, 320);
    camera_.upDirection = CC3VectorMake(0, 1, 0);
    camera_.lookDirection = CC3VectorMake(0, 0, -1);
    camera_.frustumNear = 10;
    camera_.frustumFar = 640;
    camera_.frustumLeft = -glView_.frame.size.width / 2.0;
    camera_.frustumRight = glView_.frame.size.width / 2.0;
    camera_.frustumBottom = -glView_.frame.size.height / 2.0;
    camera_.frustumTop = glView_.frame.size.height / 2.0;
    
    scene_ = [[REScene alloc] init];
    scene_.camera = camera_;
    
    world_ = [[REWorld alloc] init];
    [scene_ addChild:world_];
    
    director_ = [[REDirector alloc] init];
    director_.view = glView_;
    director_.scene = scene_;
    
//    currentCalculatedMatrix = CATransform3DIdentity;
    GLfloat currentModelViewMatrix[16]  = {0.402560,0.094840,0.910469,0.000000, 0.913984,-0.096835,-0.394028,0.000000, 0.050796,0.990772,-0.125664,0.000000, 0.000000,0.000000,0.000000,1.000000};
    currentCalculatedMatrix = CATransform3DScale(currentCalculatedMatrix, 0.5, 0.5 * (320.0/480.0), 0.5);
    
////    if ((xRotation != 0.0) || (yRotation != 0.0))
//{
GLfloat totalRotation = sqrt(xRotation*xRotation + yRotation*yRotation);
CATransform3D temporaryMatrix = CATransform3DRotate(currentCalculatedMatrix, totalRotation * M_PI / 180.0,
((xRotation/totalRotation) * currentCalculatedMatrix.m12 + (yRotation/totalRotation) * currentCalculatedMatrix.m11),
((xRotation/totalRotation) * currentCalculatedMatrix.m22 + (yRotation/totalRotation) * currentCalculatedMatrix.m21),
((xRotation/totalRotation) * currentCalculatedMatrix.m32 + (yRotation/totalRotation) * currentCalculatedMatrix.m31));
if ((temporaryMatrix.m11 >= -100.0) && (temporaryMatrix.m11 <= 100.0))
currentCalculatedMatrix = temporaryMatrix;
    float currentScaleFactor = sqrt(pow(currentCalculatedMatrix.m11, 2.0f) + pow(currentCalculatedMatrix.m12, 2.0f) + pow(currentCalculatedMatrix.m13, 2.0f));
xTranslation = xTranslation / (currentScaleFactor * currentScaleFactor);
yTranslation = yTranslation / (currentScaleFactor * currentScaleFactor);
// Use the (0,4,8) components to figure the eye's X axis in the model coordinate system, translate along that
temporaryMatrix = CATransform3DTranslate(currentCalculatedMatrix, xTranslation * currentCalculatedMatrix.m11, xTranslation * currentCalculatedMatrix.m21, xTranslation * currentCalculatedMatrix.m31);
// Use the (1,5,9) components to figure the eye's Y axis in the model coordinate system, translate along that
temporaryMatrix = CATransform3DTranslate(temporaryMatrix, yTranslation * currentCalculatedMatrix.m12, yTranslation * currentCalculatedMatrix.m22, yTranslation * currentCalculatedMatrix.m32);
if ((temporaryMatrix.m11 >= -100.0) && (temporaryMatrix.m11 <= 100.0))
currentCalculatedMatrix = temporaryMatrix;
[self convert3DTransform:&currentCalculatedMatrix toMatrix:currentModelViewMatrix];    
   
// Black background, with depth buffer enabled
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
And below is the code I've worked for stopping and stopping
- (void)startOrStopAutorotation:(id)sender;
{
    id dLink=nil;
    if (aRotate){
        dLink=[[REDisplayLink sharedDisplayLink] observers];
        [[REDisplayLink sharedDisplayLink] removeObserver:[dLink objectAtIndex:0]];
    }
    else{
        CADisplayLink *aDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(handleAutorotationTimer)];
[aDisplayLink setFrameInterval:2];
[aDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        //          [[REDisplayLink sharedDisplayLink] addObserver:[[REDirector alloc]init]];
    }
    aRotate = !aRotate;
}

Resources