This is the current code I'm using to do your typical iPhone rotate/scale with two fingers on a view. I did it using your fairly typical pythagorean theorem and trig combination.

What I'm wondering is if there's a better/cleaner/more efficient mathematically way to do it?

This is an example of how it could be used in program:

Code:

view.transform = CGAffineTransformWithTouches(view.transform, firstTouch, secondTouch);
[UIView commitAnimations];

The code:

Code:

CGFloat distanceBetweenPoints(CGPoint firstPoint, CGPoint secondPoint) {
CGFloat distance;
//Square difference in x
CGFloat xDifferenceSquared = pow(firstPoint.x - secondPoint.x, 2);
// NSLog(@"xDifferenceSquared: %f", xDifferenceSquared);
// Square difference in y
CGFloat yDifferenceSquared = pow(firstPoint.y - secondPoint.y, 2);
// NSLog(@"yDifferenceSquared: %f", yDifferenceSquared);
// Add and take Square root
distance = sqrt(xDifferenceSquared + yDifferenceSquared);
// NSLog(@"Distance: %f", distance);
return distance;
}
CGPoint vectorBetweenPoints(CGPoint firstPoint, CGPoint secondPoint) {
// NSLog(@"Point One: %f, %f", firstPoint.x, firstPoint.y);
// NSLog(@"Point Two: %f, %f", secondPoint.x, secondPoint.y);
CGFloat xDifference = firstPoint.x - secondPoint.x;
CGFloat yDifference = firstPoint.y - secondPoint.y;
CGPoint result = CGPointMake(xDifference, yDifference);
return result;
}
CGAffineTransform CGAffineTransformWithTouches(CGAffineTransform oldTransform,
UITouch *firstTouch,
UITouch *secondTouch) {
CGPoint firstTouchLocation = [firstTouch locationInView:nil];
CGPoint firstTouchPreviousLocaion = [firstTouch previousLocationInView:nil];
CGPoint secondTouchLocation = [secondTouch locationInView:nil];
CGPoint secondTouchPreviousLocaion = [secondTouch previousLocationInView:nil];
CGAffineTransform newTransform;
// Calculate new scale and rotation
// Get distance between points
CGFloat currentDistance = distanceBetweenPoints(firstTouchLocation,
secondTouchLocation);
CGFloat previousDistance = distanceBetweenPoints(firstTouchPreviousLocaion,
secondTouchPreviousLocaion);
// Figure new scale
CGFloat distanceRatio = currentDistance / previousDistance;
// NSLog(@"DifferenceRatio: %f, %f", distanceRatio.x, distanceRatio.y);
// Combine with current transform
newTransform = CGAffineTransformScale(oldTransform, distanceRatio, distanceRatio);
// Now figure new rotation
// Get previous angle
CGPoint previousDifference = vectorBetweenPoints(firstTouchPreviousLocaion, secondTouchPreviousLocaion);
CGFloat xDifferencePrevious = previousDifference.x;
// Use acos to get angle to avoid issue with the denominator being 0
CGFloat previousRotation = acos(xDifferencePrevious / previousDistance); // adjacent over hypotenuse
if (previousDifference.y < 0) {
// account for acos of angles in quadrants III and IV
previousRotation *= -1;
}
// NSLog(@"previousRotation: %f", previousRotation);
// Get current angle
CGPoint currentDifference = vectorBetweenPoints(firstTouchLocation, secondTouchLocation);
CGFloat xDifferenceCurrent = currentDifference.x;
// Use acos to get angle to avoid issue with the denominator being 0
CGFloat currentRotation = acos(xDifferenceCurrent / currentDistance); // adjacent over hypotenuse
if (currentDifference.y < 0) {
// account for acos of angles in quadrants III and IV
currentRotation *= -1;
}
// NSLog(@"currentRotation: %f", currentRotation);
CGFloat newAngle = currentRotation - previousRotation;
// Combine with current transform
newTransform = CGAffineTransformRotate(newTransform, newAngle);
// Return result
return newTransform;
}