Hi all you smart people out there! I want to create a touch interface to an iOS app, that allows the user to drag an object on the screen around. However, this object should be restricted to move along the perimeter of a circle, so that if the user is trying to drag the object outside that path, it would stick to the nearest point of that circle. I have done some iPhone programming, but my math is poor. Please help!
All you have to do is set the frame of the view to follow the equation of a circle (of the form: (x-a)^2 + (y-b)^2 = r^2
). Once you detect the touch point, you can restrict the view's frame according to the x or the y coordinate of the touch point (both ways are the same).
#define circleRadius 60.0 // r in the above eqtn
#define circlesCenter_X 160.0 // a in the above eqtn
#define circlesCenter_Y 200.0 // b in the above eqtn
#define circleCenter_y(x) sqrtf(circleRadius*circleRadius - (x-circlesCenter_X)*(x-circlesCenter_X))
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event touchesForView:firstPieceView] anyObject];
CGPoint previousLocation = [touch previousLocationInView:self.view];
CGPoint location = [touch locationInView:self.view];
CGFloat delta_x = previousLocation.x - location.x; // constrained by x in this eg.
CGFloat newX = firstPieceView.center.x-delta_x;
// do limit the view's x-coordinate for possible solutions
if(newX<circlesCenter_X - circleRadius)
newX = circlesCenter_X - circleRadius;
if(newX>circlesCenter_X + circleRadius)
newX = circlesCenter_X + circleRadius;
firstPieceView.center = CGPointMake(newX, circleCenter_y(newX)*(location.y>=circlesCenter_Y?1:-1) + circlesCenter_Y);
}
EDIT- Better solution:
#define circleRadius 60.0 // r in the above eqtn
#define circlesCenter_X 160.0 // a in the above eqtn
#define circlesCenter_Y 200.0 // b in the above eqtn
#define slope(x,y) (y-circlesCenter_Y)/(x-circlesCenter_X)
#define pointOnCircle_X(m) circleRadius/(sqrtf(m*m + 1))
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event touchesForView:self.view] anyObject];
CGPoint location = [touch locationInView:self.view];
CGFloat slope;
CGPoint pointOnCircle;
if(location.x==circlesCenter_X){// case for infinite slope
pointOnCircle.x = circlesCenter_X;
if(location.x<circlesCenter_X){
pointOnCircle.y = circlesCenter_Y - circleRadius;
}else{
pointOnCircle.y = circlesCenter_Y + circleRadius;
}
}else{
slope = slope(location.x,location.y);
if(location.x<circlesCenter_X){
pointOnCircle.x = circlesCenter_X - pointOnCircle_X(slope);
}else{
pointOnCircle.x = circlesCenter_X + pointOnCircle_X(slope);
}
pointOnCircle.y = slope * (pointOnCircle.x - circlesCenter_X) + circlesCenter_Y;
}
firstPieceView.center = pointOnCircle;
}
This can be applied similarly for Android
, Blackberry
, etc too!