How Load-on-Demand Works
With the load-on-demand mechanism, a manager layer is divided into a set of rectangles of the same size, called tiles. The graphic objects that a tile contains are loaded into the application only when that tile becomes visible inside one of the manager views. When a tile is no longer visible in any manager view, it gets unloaded.
A tile is made visible or invisible according to the user’s actions such as moving a map, zooming in or out, activating or deactivating a scale filter, and resizing a window.
To be divided into tiles, a layer must be of the type
IlvTiledLayer, a subtype of
IlvManagerLayer. Tiles are managed by a tile controller (
IlvTileController) that is associated with a tile loader (
IlvTileLoader) and a tile cache (
IlvTileCache).
Figure 4.1 illustrates the classes involved in load-on-demand and how they are related:
The Load-on-Demand Classes
Each time that a tile becomes visible in one of the manager views, the tile controller is notified and the tile lock counter is incremented. If the tile has not been displayed yet, the tile loader is invoked and the data in the tile is loaded into memory. Each time that a tile gets hidden in one of the manager views, its tile lock counter is decremented. When the counter goes to zero, the tile controller places the tile in its associated cache. Each time the tile controller needs to load new tiles, it notifies the cache of this operation and one or more tiles in the cache are unloaded to free memory. A cache can handle tiles that are distributed over several layers belonging to different managers.
To activate the load-on-demand mechanism, the tiled layer must be added to a manager and its start method must be called.
The
IlvTiledLayer class has been extended to support load-on-demand for cartographic formats for which
Views Maps supplies predefined readers, namely CADRG, DTED, and Oracle Spatial. The classes
IlvCADRGLayer,
IlvDTEDLayer, and
IlvSDOLayer are described in
Predefined Readers.
Another useful class for load-on-demand is
IlvMapTileLoader. This class allows you to integrate a map reader (
IlvMapFeatureIterator) in a predefined tile loader. The most important method of this class is the
IlvMapTileLoader::load() method:
IlvMapsError IlvMapTileLoader::load(IlvTile* tile) { // Get the feature iterator. IlvMapFeatureIterator* iterator = getFeatureIterator(tile); ... // Check if the iterator implements IlvLookAheadFeatureIterator. ... // Parameters for rendering. ... IlvFeatureRenderer* renderer = getFeatureRenderer(tile->getDisplay()); ... do { // Case of look ahead feature iterator. // Check if the next feature ID corresponds to an object // already in the manager (skip the next feature in this // case and continue). ... // Process the feature itself. ... feature = iterator->getNextFeature(); ... // Ask the renderer to make the IlvGraphic. ... // Attach the attributes to the graphic if necessary // and add the graphic to the tile. } while (feature); ... } |
In this code sample you can see that the
IlvMapFeatureIterator class has some optimizations regarding the
IlvLookAheadFeatureIterator class. Feature iterators subclassing this class can fetch the ID of the next feature that will be returned by the
getNextFeature method and skip the next feature. For example, this is useful if a feature has a unique ID and belongs to a group of tiles (case of a large geometry). The first time one of these tiles becomes visible, the feature is read, then rendered, and the corresponding
IlvGraphic is added to the
IlvTile thanks to the
IlvTile::addObject(IlvGraphic*, IlvMapFeatureId* ) method. Then, when another tile of this group becomes visible, the
load method of the
IlvMapTileLoader checks through the
IlvLookAheadFeatureIterator::getNextFeatureId() method if the returned ID corresponds to an existing
IlvGraphic so that the feature belonging to multiple tiles is loaded, rendered, and added to the tile just once.
In order to define your own tile loader, you can subclass
IlvMapTileLoader and override its
getFeatureIterator() method so that it returns your map reader tuned for the specified
IlvTile.
The following code sample shows an implementation of
IlvMapTileLoader. The class
MyTileLoader allows you to load a mosaic of the same image in an
IlvManager when it is associated with an
IlvTiledLayer.
class MyTileLoader:public IlvMapTileLoader { IlvDisplay* _display; const char* _filename; // The filename that corresponds to the image // its format should be known by Views. IlvProjection* _projection; IlvMapInfo* _info; IlvDim _imageWidth; IlvDim _imageHeight; public: MyTileLoader(IlvDisplay* display, const char* filename) _display(display), _filename(IlvMapDataPathManager::ResolvePath(filename)), _projection(new IlvGeographicProjection()), _info(0), _imageWidth(0), _imageHeight(0) { //Creation of the IlvBitmap corresponding to the given filename. IlvBitmap* bitmap = display->readBitmap(IlvMapDataPathManager::ResolvePath(filename)); if(bitmap) { _imageWidth = bitmap->width(); _imageHeight = bitmap->height(); } } ~MyTileLoader() { if(_info) delete _info; } IlBoolean isPersistent() const { return IlFalse; } IlvMapFeatureIterator* getFeatureIterator(IlvTile* tile) { IlvRect rect; tile->boundingBox(rect); IlvMapInfo* info = getMapInfo(); IlvCoordinate ul; IlvCoordinate lr; IlvPoint p1(rect.x(), rect.y()); IlvPoint p2(rect.x() + rect.w(), rect.y() - rect.h()); ul = info->getAdapter()->fromViews(p1); lr = info->getAdapter()->fromViews(p2); return new IlvImageReader(_display, _filename, ul, lr); } |
IlvFeatureRenderer* getDefaultFeatureRenderer(IlvDisplay* display) { return new IlvDefaultFeatureRenderer(display); } IlvMapInfo* getMapInfo() { if (!_info) _info = new IlvMapInfo(_projection); return _info; } IlvRect getTileOrigin() { return IlvRect(0, 0, _imageWidth, _imageHeight); } }; |
In this code sample, note the following line: IlvMapDataPathManager::ResolvePath(filename)
The data path management feature allows you to resolve a relative path name.
For example, an .ilv file may contain tile loaders that reference files (such as Shapefile, GeoTIFF file, and so on). If these references are relative path names, they can be easily resolved thanks to a default resolver. For example, if the files needed by the tile loaders are located in “c:\data”, then all you have to do is call:
IlvDefaultDataPathResolver* resolver = new IlvDefaultDataPathResolver(“c:\\data”); IlvMapDataPathManager::AddDataPathResolver(resolver); |
This is a static function that can be called whenever before the .ilv file is read. Of course, it only works if the tile loader saved in the .ilv file uses IlvMapDataPathManager::ResolvePath(const char* filename) in order to resolve path names (see the sample code above).
Published date: 05/24/2022
Last modified date: 02/24/2022