Victory is Mine! (Sorta)


That challenge was a toughie for me. I tried following the hint in the book, as well as Joe’s suggestion in the thread entitled, “wow” but I just couldn’t get the darn thing to work properly.

The problem was thst I would store prior key NSValue *key = [NSValue valueWithPointer:t] information, then iterate through an array (or dictionary, depending on which attempt I was on) comparing the current key to keys I had already stored. For whatever reason, it couldn’t ever find two keys equal to each other. I still don’t know why, (I posted the code over in “Wow” but, for whatever reason, there was no reply.)

But, as I said, victory is now mine (sorta).

I think what the authors had in mind when they put the challenge into the book was if one finger touches the screen and moves, draw a line, but if a second finger joins the screen, turn that line into a circle with each finger representing the corners of a bounding box.

My implementation is somewhat different - because when I began with the challenge, I didn’t fully realize that was the approach. It was only after Joe posted in “wow” that I began to realize what they really meant, and by that point, I as well past the point of no return in my own implementation, and even in that case, I reasoned I could still implement Joe’s suggestion.

But, try as I might, I found myself going in circles (pun intended.)

Until this morning when I started a brand new implementation almost from scatch.

Here’s the implementation as I did it. I’m not going to post code, but I’ll outline it.

On startup, the progam defaults to drawing lines.
If the user double-taps the screen, the linesInProcess dictionary is cleared and the program switches to drawing circles.
If the user triple-taps the screen, everything is cleared, but the drawing method (lines or circles) remains the same.

Lines are drawn as per the book.

Circles, however, are a little more complex:

We track the number of fingers touching the screen.
When a finger touches the screen, if the number of fingers is odd, we know it’s the first of two fingers to be drawing a circle, so we get its location and store it, along with a (currently nill) pointer value (NSValue) which will, in the future, contain the value of the other finger touching the screen for this circle. The CGPoint value of this finger’s location and the NSValue pointer are placed into an object (call it circlePoint for the sake of discussion.) and then that object is placed into linesInProcess in the same way a Line gets stored when drawing lines. The key of this touch is also stored in an iVar called oldKey.

If, on the other hand, the number of finger is even, we know it’s the second of two fingers to touch. So this time, referencing oldKey (see above), we pull the old point out of linesInProcess, and set its otherPoint value to key. We then create a new circlePoint object, set the current location, and store oldKey in the otherPoint value. We then stuff this object into linesInProcess.

I know the hint in the book said this challenge is much easier if you don’t use linesInProcess, but I think that is based on the assumption that there are incomplete lines and circles all at the same time. In this implemenation, that can’t possibly happen.

When drawing an incomplete circle, the program iterates through linesInProcess, grabs the first point, and then, using the otherPoint value stored along with it, grabs the other point. Those two points are used to create a bounding box, and a circle is drawn.

If a finger moves, we simply update the point stored by changing its value.

If a finger leaves the screen, we first check otherPoint - if it’s nil, we only ever placed one finger on the screen, so we just remove the point from linesInProcess and continue on our merry way. On the other hand, if we have a value for otherPoint, we pull that value out as well (and remember to remove both from linesInProcess) and use them to create a Line object, and is added to an array of completed circles (called completeCircles) Why a Line object? I’m glad you asked! Since we use two two points to create a bounding box, and since once a circle is completed, we no longer care about the touches associated with it, we can simply store the two points as the begin and end values of a Line and use them to build a bounding box.

When drawing complete circles, we just iterate through the completedCircles array, use the begin and end values to create the bounding box, and draw it.

I say “sorta” when referring to this because (a) my program does not yet save circles. This should be fairly easy to implement; (b) because I track the number of fingers on the screen, and finalize a circle when one of them leaves the screen, if the user leaves the first finger on the screen and then adds a second, the program now thinks there is an even number of fingers, and the program messes up; © if the user double or triple taps while having fingers on the screen, I am not yet 100% sure if stable operation.

Since this is a practise program, I’m not overly concerned about the known issues in my program; I’m just very happy that I have finally managed to get the thing drawing circles.