Loose Leaf is more aboutĀ photos and imports than it is about drawing or sketching, and I wanted to make sure it was easy not only to cut and create new scraps, but also to manipulate and duplicate existing scraps. To make a copy of a photo or scrap, I thought through numerous gesture options, menus, long press popups, buttons, and more, and in the end I settled on a simple pull-it-apart-gesture.
So howād it turn out? Hereās what it looks like to duplicate any photo scrap in Loose Leaf, just pull it apart into two identical pieces.
Itās a simple gesture to pull a photo into two copies. The stretch animation as you pull makes it obvious whatās happening, and then ā snap!Ā ā Itās two copies!
The difficult piece of this gesture isnāt the copy itself, itās the stretch animation as you pull the image apart. For a number of reasons, I needed to do this without additional OpenGL rendering, I needed to keep the code solidly in the normal UIKit stuff.Ā To make itĀ work, IĀ borrowed some technology thatās fairly common in Augmented Reality apps: itās called homography.
The short description is that any convex quadrilateral can appear to be any other convex quadrilateral by just rotating and translating it- It basically lets me turn any four sided shape into any other four sided shape. Perfect! scraps, even non-rectangleĀ oneās cut by scissors, are still modeled as simple rectangle UIViews. As I stretch, IĀ can transform that rectangle into a parallelogram for that stretched effect.
Hereās the simple test application I used to fine-tune the animation with the above strategy:
The algorithm visible above goes through the following steps:
- create a 4 sided quadrilateral from the four touch points on the scrap
- as the fingers move, create a 2nd quadrilateral from the new locations of those same touches
- compute the homography between those two quadrilaterals to find the transform between them
- apply that transform to the scrap itself
Note that Iām not trying toĀ calculate the transform from the UIViewās bounds to its new parallelogram ā instead iām transforming the quad of finger positions to thew new quad of finger positions, then usingĀ that transform on the view.
The red lines in the above image is the quadrilateral between the touch points. The green line is an āaverageā quadrilateral, whichĀ averages the red quad into a parallelogram. You can see the stretch is very dramatic, and it causes a problem if the touch points formĀ ever form a concave instead of convex polygon. You can see an example of what goes wrong below:
But if I use the average quad instead, and treat those points as transforms between parallelograms, then the same gesture gives smoother results:
My last experiment for the stretch gesture was how to keep the orientation of the image as it stretched. I thought about trying to maintain the āupāness of the image regardless of the stretch vs. having the gesture also rotate the image during the stretch. You can see what I mean with the two videos below.
In the end, I decided to rotate the image during the gesture, and not try to maintain āupā orientation. It gave a cool effect, especially when stretching, but felt just a bit off since it also caused the fingers to slide more over the image.
To try it for yourself, download Loose Leaf on the app store.
You can also findĀ all of the code on GitHubĀ for each one of the versions talked about here, and be sure to check out the rest of Loose Leafās open source contributions as well.