Monday 30 December 2013

A FireMonkey client for the DWS Terapixel Mandelbrot data set

You may have seen Eric Grange's precomputed Mandelbrot set data - read the Christmas announcement and the followup. He has generated and is hosting the fractal as a multi-level tiled data set: that is, as a structure of varying levels of detail, where each level of detail is twice as large as the one before. His tiles are not images, but rather a table of the number of iterations required for each point.  These values can then be mapped to colour as the client application decides.

Quick overview of tiled level-of-detail data

You can picture this as a pyramid, or as an infinitely divided square. The first level, level 0, has one tile. Level 1 subdivides level 0's tile into two on each axis, so four total.  Level 2 subdivides each of these tiles, as so forth.  Since each tile has the same dimensions in pixels, but represents a smaller area of the data, you get higher and higher resolution data in each tile.
This is a common method of storing similar data - I've previously used it for geographic maps, for example. Often tiles will be images, but in this case they are data that can be converted to images.
As of Dec 27, there are fourteen levels (0-13.)  At level 13, there are 213 tiles in each dimension making a Mandelbrot set 8192 x 8192 tiles on a side.  At 256 pixels square, this is 2097152 pixels a side, or 4398046511104 pixels in total.  That's quite a lot.  Add in the other smaller levels and you have an enormous of data, many gigabytes.  For comparison, zooming in from the whole earth to a few meters is only a few more orders of magnitude; at 1 pixel/meter, zoomed in to the maximum zoom on this set makes the whole Mandelbrot set, in pixel space on your screen, the size of a large country.

I thought it would be a fun project to write a small viewer app for this dataset, so here it is: a cross-platform (Windows and OS X) tiled data viewer written in Delphi and FireMonkey.

Why write it?

  • To find out first-hand what it's like writing a non-trival (although admittedly small) app using FireMonkey.  Some people rave, some people complain: who's right?  There's only one good way to find out. I will write about this in a followup post.
  • To provide an example of using a tile API.  If you end up having to implement one of the common tile APIs out there and you've never had to deal with tiles, navigation, zooming and pixel-perfect dragging/scrolling at different zoom levels, this code is simple and worth reading. It's also open-source (MPL.) You're welcome to use it.
  • Because everyone like knowing people are using code they've written, and I hope Eric finds it interesting someone's written an app to use his server fractal API & data.
  • For fun!

Features:

  • Smooth scaling: the zoom level does not have to match a tile level. High-res tiles are loaded and scaled down.
  • Smooth UI: grab and drag to scroll, animated scaling as you zoom in or out
  • Asynchronous loading: tiles are downloaded and converted to image data in another thread.
  • Cross-platform, from the one project and source code (only one $ifdef required for low-level pixel color handling)

Random notes:

  • Despite reviewing FireMonkey when it was released with XE2, this is actually my first non-trivial FireMonkey app.  It was written with Delphi XE2, and I will upgrade it to XE4.  My aim here is to see what the experience is truly like using both the first FMX and upgrading to a new FMX version.  I will write an article about my impressions soon.
  • In addition, unlike my other open-source projects (which are hopefully useful libraries, not apps) I've hosted this one on a Mercurial server. I had read about but hadn't used a distributed version control system before, so starting a new project was a good opportunity to try one out.  It's an interesting paradigm, although for a sole developer not much different to a standard system like Subversion.

Future:

  • While the DWS Mandelbrot set is cool, there's lots of other tiled data out there too.  With some refactoring, it would be easy to change this app to support a wide variety of tiled data sources and turn it into a generic tiled data viewer.  One immediate candidate is Bing Maps's tile API.  Nokia / HERE maps also has a tile API, and Google can have one with a bit of hacking / hope - its map APIs are not as extensive for non-web platforms.  I would be interested to hear of any data sources you are interested in, and if I expand the product to support each API as a plugin then anyone could implement support for a specific type of data.
Meanwhile, it's been a fun way to spend a day or two!

Download:

12 comments:

  1. I've tried your example on 64bit Windows 7 machine and none of the binaries work. What I see is the blank screen. I can zoom in / zoom out, I see information that tiles are loading but still a blank screen appears.

    ReplyDelete
  2. Same here, blank (white) screen, the loading indicator progresses along with size estimates. Windows resource explorer shows there is data getting actually downloaded, but nothing is displayed.

    ReplyDelete
  3. Hmm. Interesting!

    I saw something similar with the XE4 build running on OSX (not released yet) which I haven't yet solved. But the XE2 build, that you have, works perfectly for me on all platforms. One possibility is that it's to do with the canvas - on my dev machine it uses the GDI+ canvas, not the Direct2D one.

    I guess I am discovering real-world problems using FireMonkey :) That was after all one of the goals...

    It's new year's, and I'll be traveling over the next week. I'm afraid I may not have time to make a fix for a while. But I will look into it when I can!

    ReplyDelete
  4. I made an updated build that /may/ fix the issue, available here: https://code.google.com/p/dws-terapixel-explorer/

    (There is a download link on that page.)

    Could you let me know if that fixes the issue, please?

    ReplyDelete
    Replies
    1. And issue tracker: https://code.google.com/p/dws-terapixel-explorer/issues/detail?id=1

      Delete
    2. It works, however it's very slow, even in the small default window there is noticeable lag and CPU usage is at 100% whenever scrolling or zooming. I suppose it's not hardware accelerated at all and uses GDI+?
      (the web-based explorer is smooth in Chrome on the same machine)

      Delete
    3. Yes - the "fix" is to force it to use the GDI+ canvas. I need to investigate why it's not working with Direct2D, but - now I know to look! - on my Windows 7 / Fusion development machine it always uses GDI+, never D2D, and so I first have to figure out how to get it to choose that canvas in order to reproduce the issue.

      It's a shame. I will figure it out though - just not on NYE :) I did want to see what issues I ran into while developing a FMX app, and I suppose I am...

      Delete
  5. I can confirm that new version works but extremally slow. In my opinion it should not run smoothly even if it is using GDI+. I've also noticed that there is one pixel frame around each tile, I do not know if it is by design or not.

    Good luck with fixing your issues.

    ReplyDelete
    Replies
    1. You're quite right, it should. It does on my computer ;)

      I need to investigate (a) why it is using the GDI+ canvas only on my dev machine; (b) why the tiles are not visible with the Direct2D canvas, (c) the half-pixel antialiased line when zoom and scroll coordinates don't line up perfectly, and (d) performance with the GDI+ canvas. It will take some time, and since it's been new year's recently and I have a flight and some holiday travel in a few hours it might be a while :/ Sorry about that. I will look into it.

      Delete
  6. I've meant "it should run smoothly even if it is using GDI+" :)

    ReplyDelete
  7. I updated the code for Delphi XE5. It is available from http://www.overbyte.be/arch/dump/DWSMandelbrotExplorerXE5.zip

    ReplyDelete
  8. About performance: In my updated code, I optimized the access to the bitmap data by using Map/Unmap to get a pointer to the data bytes. This is much faster.
    See my code at http://www.overbyte.be/arch/dump/DWSMandelbrotExplorerXE5.zip

    ReplyDelete