My blog has been moved to

Saturday, March 20, 2010

morphing clock

As I promised before, here is a fresh X2 example. Those who attended Bossa Conference 10 and followed my talk are lucky to have seen it for the first time there. In fact, this example is ridiculously simple that I am not surprised at all if somebody has done this ages ago.

Let's start with a screen capture, or two:

Basically the above shows an analog and digital clock running on my Nokia N900, hardly a shock. However, the fun part is when you switch the clock from analog to digital and vice versa. Check out this video, or watch directly on YouTube, courtesy of Signor Portale from Nokia/Qt, showing the morphing on Nokia 5800:

The trick is simple. Actually it's not even generic enough, meaning that you can't morph from an arbitrary path to another arbitrary path. However, for this clock use-case, the gross approximation is good enough. First, we need to convert the path into a polygon, which is done easily via QPainterPath::toFillPolygon() function. Then any line segment in the polygon longer than a certain tolerance is further split into smaller segments. As I claimed above, the result is not perfect, i.e. it does not approximate the original path into line segments with equal length. But hey, it is good enough for this animation purpose (unless your user has ueberhuman eyes).

The target path needs to be sliced into segments as well. Since we have only two types, circle (for the analog clock frame) and solid block (for the hour and minute hands), it is easier to special-case both. The secret is to have the same number of segments as the source path. The following figure shows the digit '7' and a circle, each splitted to 28 line segments. Small dots indicate the start and end points of those segments. The animation is now a matter of doing tweening, or linear interpolation, between each segment.

The flaw of this trick is when the source path contains holes inside it, e.g. for digits like 0, 4, 6, 8, and 9. Again, we are cheating here for the sake of keeping the code simple, so I leave the code as it is. Doing a more advanced, better handling for those cases is left as a motivational exercise for the perfectionist readers. Another bonus puzzle: find out why 503 ms is the morphing time (hint: find the same number in Qt source tree).

The code is in the X2 repository, check the sub-directory widget/morphingclock. You need Qt 4.5 or later. It is not long at all (surprise!), sloccount reports 191 lines of code. A morphing-clock plasmoid is also underway, just be patient.

For the sake of completeness, let me mentioned Dali Clock (even in Canvas and JavaScript version) from the famous Jamie Zawinski (jwz). It is similar, however Dali Clock just morphs the digits of the digital clock.

Also, if you just prefer a normal (but old-fashioned!) digital clock with the flipping effect, check the digiflip example I did back then. You already have it if you install Qt 4.6 for Symbian.

Last but not least, I'd like to mention my "special thanks to Delta Airlines for such a long (but safe) flight to Brazil so I had the chance to write this example while I was bored", but then I was told by the Trolls that this kind of intro line can't be funny anymore.


Kromain said...

Wow, I'm surprised how fluid the animation is on the 5800, given that it's all raster-based painter paths manipulations, which aren't hardware accelerated AFAIK.
Anyway, cool one - as usual ;)

Andreas K said...

Looks nice! thanks :-)

aviral said...

looks very smooth!