Problem moving UIView with touches

Discussion in 'iPhone/iPad Programming' started by blueeye, Nov 12, 2009.

  1. macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #1
    Hi all,

    I'm trying to build an object which lets you "grab" a corner with your finger and move it around as if it were a real object (it would rotate and translate depending on where you grabbed it and moved to).

    For some reason, though the rotation works fine and in theory the translation seems to work fine as well, the object does not move as much as it should (so the touch slowly gains distance between itself and the object) and the object seems to jump between two positions as it moves making it almost seem as if there are two (because it flickers with surprising frequency).

    I'll post the relevant methods here:

    Code:
    - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    	NSLog(@"Touches began on Physical Object");
    	if([touches count] == 1) {
    		UITouch * touch = [[touches allObjects] objectAtIndex:0];
    		self.throwStartLocation = [touch locationInView:[self superview]];
    		NSLog(@"Touch location: (%f, %f)", self.throwStartLocation.x, self.throwStartLocation.y);
    		self.throwStartTime = [touch timestamp];
    		
    		self.touchBearingFromCentre = [self calculateBearingFromCentre:self.throwStartLocation];
    	}
    }
    
    - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    	if([touches count] == 1) {
    		UITouch * touch = [[touches allObjects] objectAtIndex:0];
    		CGPoint touchLocation = [touch locationInView:[self superview]];
    		
    		//Get new bearings
    		Bearing2D bearing = [self calculateBearingFromCentre:touchLocation];
    		
    		//Calculate required translation
    		float trans = bearing.distance - self.touchBearingFromCentre.distance;
    		float tx = trans * sinf(bearing.angle);
    		float ty = - (trans * cosf(bearing.angle));
    	
    		self.center = CGPointMake(self.center.x+tx, self.center.y+ty);
    		
    		//Calculate required rotation
    		self.transform = CGAffineTransformRotate(self.transform, bearing.angle - self.touchBearingFromCentre.angle);
    		
    		//Set saved positions to current touch positions
    		self.throwStartLocation = touchLocation;
    		self.throwStartTime = [touch timestamp];
    		self.touchBearingFromCentre = bearing;
    	}
    }
    
    - (Bearing2D) calculateBearingFromCentre: (CGPoint) touchLocation {
    	CGPoint centre = self.center;
    
    	Bearing2D bearing;
    	bearing.distance = distanceBetweenTwoPoints2D(centre, touchLocation);
    	float angle = asinf(ABS(touchLocation.x - centre.x)/bearing.distance);
    	
    	BOOL TOP = (touchLocation.y <= centre.y);
    	BOOL LEFT = (touchLocation.x <= centre.x);
    	
    	if(TOP && !LEFT) {
    		//Top Right Quadrant
    		bearing.angle = angle;
    	} else if (!TOP && !LEFT) {
    		//Bottom Right Quadrant
    		bearing.angle = (M_PI- angle);
    	} else if (!TOP && LEFT) {
    		//Bottom Left Quadrant
    		bearing.angle = M_PI + angle;
    	} else if(TOP && LEFT) {
    		//Top Left Quadrant
    		bearing.angle = 2*M_PI - angle;
    	}
    	
    	NSLog(@"Touch is at a bearing of %f and a distance of %f from centre at (%f, %f)", bearing.angle, bearing.distance, centre.x, centre.y);
    	return bearing;
    }
    
    Bearing2D is just a struct containing distance and angle data (floats). Bearings are taken from "North" (the top direction of the screen) as is the convention. All angles are in radians.

    Any help would be much appreciated.
     
  2. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #2
    I don't know if this helps but I logged the centre of the UIView and also tx and ty as follows (in the touchesMoved method):

    Code:
    float trans = bearing.distance - self.touchBearingFromCentre.distance;
    float tx = trans * sinf(bearing.angle);
    float ty = -(trans * cosf(bearing.angle));
    
    NSLog(@"%f %f %f %f", self.center.x, self.center.y, tx, ty);
    
    The output shows two pairs of translations being calculated very quickly together. The translation values are almost negatives of each other which might explain the flickering. The output looks as follows (sample):

    Code:
    2009-11-12 14:58:19.294 DocThrow[7604:207] 175.810349 210.684875 3.826098 6.233794
    2009-11-12 14:58:19.303 DocThrow[7604:207] 179.636444 216.918671 -0.223187 -0.384551
    2009-11-12 14:58:19.314 DocThrow[7604:207] 179.413254 216.534119 4.245363 7.671549
    2009-11-12 14:58:19.323 DocThrow[7604:207] 183.658615 224.205673 -0.175163 -0.331645
    2009-11-12 14:58:19.343 DocThrow[7604:207] 183.483444 223.874023 3.362693 6.688859
    2009-11-12 14:58:19.355 DocThrow[7604:207] 186.846130 230.562881 -0.131342 -0.274367
    2009-11-12 14:58:19.369 DocThrow[7604:207] 186.714783 230.288513 3.138061 6.867931
    2009-11-12 14:58:19.382 DocThrow[7604:207] 189.852844 237.156448 -0.098292 -0.225313
    2009-11-12 14:58:19.397 DocThrow[7604:207] 189.754547 236.931137 3.269465 7.875489
    2009-11-12 14:58:19.413 DocThrow[7604:207] 193.024017 244.806625 -1.107775 -2.758256
    2009-11-12 14:58:19.429 DocThrow[7604:207] 191.916245 242.048370 2.776053 7.096982
    2009-11-12 14:58:19.445 DocThrow[7604:207] 194.692291 249.145355 -1.390990 -3.633013
    2009-11-12 14:58:19.461 DocThrow[7604:207] 193.301300 245.512344 2.679798 7.144592
    2009-11-12 14:58:19.478 DocThrow[7604:207] 195.981094 252.656937 -2.003174 -5.397062
    2009-11-12 14:58:19.495 DocThrow[7604:207] 193.977921 247.259872 2.319129 6.280084
    2009-11-12 14:58:19.511 DocThrow[7604:207] 196.297043 253.539963 -1.888470 -5.068898
    2009-11-12 14:58:19.527 DocThrow[7604:207] 194.408569 248.471069 2.672719 7.149411
    2009-11-12 14:58:19.543 DocThrow[7604:207] 197.081284 255.620483 -2.238668 -5.936920
    2009-11-12 14:58:19.557 DocThrow[7604:207] 194.842621 249.683563 2.712987 7.135958
    
    This is weird because the translation values seem to occur in pairs of negative and positive ones.
     
  3. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #3
    I've narrowed it down to what I think is the cause of the problem. The trans value, which calculates the difference between the distances of the touches from the centre of the UIView rapidly flickers between positive and negative. This could be due to an inaccuracy in using one's finger? I'm sure that what I'm trying to do has been done before, however, so I'm wondering how I would programme around this.

    Any ideas?

    (for reference, trans is set as follows)

    Code:
    float trans = bearing.distance - self.touchBearingFromCentre.distance;
    
    self.touchBearingFromCentre is set from the previous touch.
     
  4. thread starter macrumors member

    blueeye

    Joined:
    Oct 27, 2007
    #4
    I solved the problem. I used [touch previousLocationInView:[self superview]] and now it works, beautifully.
     

Share This Page