Implementing touch-based rotation in cocoa touch
        Posted  
        
            by ewoo
        on Stack Overflow
        
        See other posts from Stack Overflow
        
            or by ewoo
        
        
        
        Published on 2010-05-06T11:04:13Z
        Indexed on 
            2010/05/06
            11:08 UTC
        
        
        Read the original article
        Hit count: 758
        
I am wondering what is the best way to implement rotation-based dragging movements in my iPhone application.
I have a UIView that I wish to rotate around its centre, when the users finger is touch the view and they move it. Think of it like a dial that needs to be adjusted with the finger.
The basic question comes down to:
1) Should I remember the initial angle and transform when touchesBegan is called, and then every time touchesMoved is called apply a new transform to the view based on the current position of the finger, e.g., something like:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
  UITouch *touch = [touches anyObject];
  CGPoint currentPoint = [touch locationInView:self]; //current position of touch   
 if (([touch view] == self) 
    &&  [Utility getDistance:currentPoint toPoint:self.middle] <= ROTATE_RADIUS //middle is centre of view
    && [Utility getDistance:currentPoint toPoint:self.middle] >= MOVE_RADIUS) { //will be rotation gesture
  //remember state of view at beginning of touch
  CGPoint top = CGPointMake(self.middle.x, 0);
  self.initialTouch = currentPoint;
  self.initialAngle = angleBetweenLines(self.middle, top, self.middle, currentPoint);   
  self.initialTransform = self.transform;
 }
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
  UITouch *touch = [touches anyObject];
  CGPoint currentPoint = [touch locationInView:self]; //current position of touch
  if (([touch view] == self) 
  &&  [Utility getDistance:currentPoint toPoint:self.middle] <= ROTATE_RADIUS
  && [Utility getDistance:currentPoint toPoint:self.middle] >= MOVE_RADIUS) { //a rotation gesture
  //rotate tile
  float newAngle = angleBetweenLines(self.middle, CGPointMake(self.middle.x, 0), self.middle, currentPoint); //touch angle
  float angleDif = newAngle - self.initialAngle; //work out dif between angle at beginning of touch and now.
  CGAffineTransform newTransform = CGAffineTransformRotate(self.initialTransform, angleDif); //create new transform
  self.transform = newTransform;  //apply transform.
}
OR
2) Should I simply remember the last known position/angle, and rotate the view based on the difference in angle between that and now, e.g.,:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
      UITouch *touch = [touches anyObject];
      CGPoint currentPoint = [touch locationInView:self]; //current position of touch   
     if (([touch view] == self) 
        &&  [Utility getDistance:currentPoint toPoint:self.middle] <= ROTATE_RADIUS
        && [Utility getDistance:currentPoint toPoint:self.middle] >= MOVE_RADIUS) { //will be rotation gesture
      //remember state of view at beginning of touch
      CGPoint top = CGPointMake(self.middle.x, 0);
      self.lastTouch = currentPoint;
      self.lastAngle = angleBetweenLines(self.middle, top, self.middle, currentPoint);  
     }
    }
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
      UITouch *touch = [touches anyObject];
      CGPoint currentPoint = [touch locationInView:self]; //current position of touch
      if (([touch view] == self) 
      &&  [Utility getDistance:currentPoint toPoint:middle] <= ROTATE_RADIUS
      && [Utility getDistance:currentPoint toPoint:middle] >= MOVE_RADIUS) { //a rotation gesture
      //rotate tile
      float newAngle = angleBetweenLines(self.middle, CGPointMake(self.middle.x, 0), self.middle, currentPoint); //touch angle
      float angleDif = newAngle - self.lastAngle; //work out dif between angle at beginning of touch and now.
      CGAffineTransform newTransform = CGAffineTransformRotate(self.transform, angleDif); //create new transform
      self.transform = newTransform;  //apply transform.
      self.lastTouch = currentPoint;
      self.lastAngle = newAngle;
    }
The second option makes more sense to me, but it is not giving very pleasing results (jaggy updates and non-smooth rotations). Which way is best (if any), in terms of performance?
Cheers!
© Stack Overflow or respective owner