iPhone Learning Application
Monday, September 21st, 2009I’ve been working on an application for the iPhone but it’ll never be on the app store. Cou
rses and reading are all good, but if you’re going to know how to build something you ultimately have to learn by building. So when I learn a new system I always make sample projects. This one comes from the Stanford iPhone applications course (via iTunesU) that I’m doing.
This application makes polygons with user-variable number of sides. A slider or buttons control the number of slides, other buttons control a dashed or solid line around the polygon. There are various other features for drawing and updating text, etc. (A screen capture of the app is to the right. )
An interesting extra item in this exercise was to allow the user to drag a finger on the polygon and rotate it. This is my thinking behind the software development for this one feature.
It took me a bit of reading and experimentation to figure out that the rotate operation (CGContextRotateCTM) always rotates around the origin of the UIView. In the iPhone the origin is the top left of the coordinate space. But I wanted to rotate the polygon around it’s center, not the orgin. I ended up doing this:
CGContextTranslateCTM(context, self.bounds.size.width/2, self.bounds.size.height/2);
CGContextRotateCTM(context, rotateAngle);
CGContextTranslateCTM(context, -self.bounds.size.width/2, -self.bounds.size.height/2);
This translates the center of the polygon to the coordinate space origin, rotates that space, then translates the polygon back to its starting location, but rotated now. There are other ways to do this transform and I’ll have to learn them at some point, but this seemed the best for now.
Figuring the angle to rotate was interesting too. First, I had to refresh my trig knowledge as I don’t use it much. I have several points: the center of the polygon, and the position that the user has their finger on. When I touch my finger to the polygon I get the “touchesBegan” event. Then when I drag my finger on the polygon, the app gets a series of new finger positions as “touchesMoved” events. When I lift my finger, the app gets the “touchesEnded” event. All the events have their location as a parameter.
Given these positions I needed to calculate the starting angle of the finger drag from the center of the polygon, and the successive angles as new events came in. The new angle of rotation (rotateAngle above) is the difference of those two calculated angles.
I used the right triangles as shown here in the square polygon to find the angles. The center of the square has the blue dot, the first event (”touchesBegan” event) locations is red, and the second is green (”touchesMoved” event). I used the formula of opposite side length/hypotenuse side length to find the sine, then used arcsine to find the actual angle.
Due the way I was calculating the angle, I had to adjust the sign of the angle value and it’s magnitude depending on the relative location of the center and the touch points. My calculation gave angles 0-90 degrees only. The triangle would be upright or upside down in the example here. Or it would be reversed if the touch point was to the left of the center. (All angle calculations were in radians though.)
In my code I’d be saving the cumulating angle of rotation, I initialized this to zero. The new angle of rotation was this old saved angle plus the difference of the two angles I’d calculated above. Then, I redrew the UIView to show the polygon rotated. When the “touchesEnded” event happens, then the old saved angle plus the current angle difference is saved as the new cumulative angle of rotation.
So now the polygon turns under my finger as if I were moving a real physical object mounted on a turntable.
