Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

blueeye

macrumors member
Original poster
Oct 27, 2007
80
0
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.
 

blueeye

macrumors member
Original poster
Oct 27, 2007
80
0
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.
 

blueeye

macrumors member
Original poster
Oct 27, 2007
80
0
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.
 

blueeye

macrumors member
Original poster
Oct 27, 2007
80
0
I solved the problem. I used [touch previousLocationInView:[self superview]] and now it works, beautifully.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.