Friday, July 27, 2012

Network image tile paging

As soon as I had quad tree paging working for local image data sets, like MapBox Tiles, the next question was "What about over the network?"

It's actually a little harder than it seems.  If we're paging data locally and the read is fast enough, we can just fetch one tile at a time.  That's not going to work over the network.  Latency might be fairly severe and loading could be unacceptably slow.

The Demo

But enough of the problems, obviously we can solve them.  So let's see how it works.

The answer is, it works pretty well.  The whole quad display layer infrastructure and assorted data structures and sources is panning out nicely.


Here is where things get complicated and then, happily, simpler again.  Let's start with the complicated part.

The data layer that controls all of this is the WhirlyGlobeQuadDisplayLayer.  I discuss it in an earlier blog post, but I'll give it a quick review.  You tell the layer how big the data set you're paging is and provide a whole bunch of delegate methods to fill in the details.  As the user pans and zooms around, the layer is constantly evaluating tiles to load and reevaluating tiles to unload.  But it doesn't actually load anything, that's up to the delegates.

To make one of these things work, you need to provide a couple different delegates to implement the example in the video.  It goes like so.

  • Create a WhirlyGlobeNetworkTileQuadSource, giving it the base URL and image extension.  It'll fetch tiles in the usual base/level/col/row.ext form.  You can also give it a cache directory to check first.
  • Create a WhirlyGlobeQuadTileLoader and give it the data source.  This is the bit that manages the geometry underneath the images.
  • Create a WhirlyGlobeQuadDisplayLayer and add it to the layer thread.  Give this the tile loader and data source and off it goes.
That means setting up image set paging over the network involves three different objects created and initialized in the right order.  That can get complicated.

Implementation: WhirlyGlobe Component

So to make it a bit easier, I've added this functionality to the WhirlyGlobe Component.  All you have to do there is make a call to addQuadEarthLayerWithRemoteSource with the following.
  • The base URL for the image data set.
  • Extension for the image type (e.g. png)
  • An optional cache directory.
  • The min and max zoom levels.  Zero is standard for the min and max can go as deep as the data set provides.
You can tear that thing down just as easily without thinking about threads or ordering or what have you.

Onward to the Future

The WhirlyGlobe 2.0 release is close.  I only have a couple of serious bugs to fix and then a bit of documentation to do.  But first, I'm going to release WhirlyGlobeComponent.

I provide a stripped down, simplified view of WhirlyGlobe with the Component.  It's built on top of the toolkit, of course, but it's entirely an Objective C interface that exposes little of the complexity.  I'd say it has about 60% of the functionality at this point, but 90% of what most people want.  For example, no vectors in the first version, just labels, markers, and base image layers.

The WhirlyGlobe Component's launch is imminent, likely in the next week or two.  I've tested it on client projects and I like how it's working.

Saturday, July 21, 2012

Is WhirlyGlobe dead?

That's the question I always ask when a project's blog has gone dark.  Github and google code are populated with the dried out husks of open source dreams past.  WhirlyGlobe isn't one of them.  Or at least not yet.  I've just been busy.

If you check out the WhirlyGlobe 2.0 repository on github, you'll see a steady stream of updates.  2.0 isn't quite ready to ship, but it's getting close.  My list of things to do is below two digits at this point.  One of them deserves a bit more discussion.

WhirlyGlobe Component

The single biggest problem I have with WhirlyGlobe is that it's, apparently, a complete bitch and a half to understand.  I mean, hey, it's just a combination of Objective C/C++, OpenGL ES, a bunch of dependent open source libraries, and multi-threading.  Like that's hard?  What?

Okay, that's kind of hard.  Now I'm doing something about it.

For the high end user, your iPad melting kind of app that swaps gigabytes of data in and out on the fly... you're stuck.  Suck it up.  But for the low end, I'm making a nice self contained component.

On the compile side, it's one single package that contains all the weird stuff I pull in.  No more compiling Eigen or downloading Boost and Shape and Clipper.  It's all in the library.  The mistakes you can make compiling it are few and easy to fix.

On the development side, the component is... well it's just the one component.  You create a WhirlyGlobeViewController, add its view your view hierarchy and off you go.  It will manage the threading, selection, interaction, and tear down.  All stuff that confused the hell out of people.

Oh, and no more direct C++ exposure.  It's all Objective-C from the outside.

The Future

It's starting simple, of course, with a standard interaction model (think WhirlyGlobeTester) and just the basic markers, vectors, and labels.  For imagery I'll support the old texture groups and the new quad tree data sets (both local and network) so that'll be a bit more exciting.  Then we'll just see where it goes.

Supporting a more general purpose vector data set is going to be tricky.  I'll have to see what's possible and, frankly, who comes in with paying work.  On the plus side, most people are interested in a whole lot of images and just a few vectors.  The Component will work well for that.