Marble/GSoC2012
Accepted projects
- OpenStreetMap vector rendering with tiling support for Marble (Ander Pijoan)
OpenStreetMap vector rendering with tiling support for MarbleGSoC Proposal
- Natural Earth Vector Map in Marble (Cezar Mocan)
Natural Earth Vector Map in Marble GSoC Proposal
- An OpenGL Mode for Marble (Shentey)
An OpenGL Mode for Marble GSoC Proposal
OpenStreetMap vector rendering with tiling support for Marble Documentation
Vectortile tag in dgml format
For creating vector tile maps with the .dgml files a new tag <vectortile> has been added to the dgml parser (DgmlVectorTileTagHandler). In the beginning I thought of calling it vectorTile as happens with other composed-words tags like downloadUrl or storageLayout, the problem is that there are some .tolower() through the code (when checking the <backend> tag) that made it impossible. However there are some tags with camelcasing and others without which would me maybe necessary to check.
The new vectortile tag has also been added to DgmlElementDictionary (const char* dgmlTag_Vectortile = "vectortile";) and the auxiliary DgmlAuxillaryDictionary. This auxiliary dictionary is used for checking the <backend> tag of the .dgml file and before it turns the attribute to lowercase (that's why <vectortile> tag could not be camelcase).
For <texture> (image tile) layers, the dgml parser created a GeoSceneTexture which stored all the important information to manage and download the tiles from, like <downloadPolicy>, <sourceDir>, <tileSize>... This attributes are need also for vector tile layers so the best option was to create a new class GeoSceneTiled for storing all data in common and then two child classes, GeoSceneVectorTile and rename GeoSceneTexture to GeoSceneTextureTile. Currently booth GeoSceneVectorTile and GeoSceneTextureTile are empty but this will help future works and make the code more scalable.
So now when the dgml parser reads a <vectortile> it will go to DgmlVectorTileTagHandler and after checking if <backend> is also set to vectortile it will create a GeoSceneVectorTile. The backend checking is made in all layers but I don't know if it has sense to check if <backend> tag is the same as the tag we have already read. However <backend> tag is checked again in MarbleMap to distinguish between <vectortile> and <texture> as booth become a GeoSceneTiled class.
VectorTileLayer in MarbleMap
MarbleMap has a TextureLayer (m_textureLayer) for downloading and mapping the image tiles and depending on the selected map projection (Globe, Plane Map or Mercator), calls a different image mapper (EquirectScanlineTextureMapper, MercatorScanlineTextureMapper or SphericalScanlineTextureMapper) that will do different operations to generate the world's image.
For vector tiles, all vector data is going to be inserted into the maps TreeModel (class inside MarbleModel that renders vector data) and it already manages projection changes. In addition, logic for vector tile downloading and storing needs to be different (due to the amount of memory vector data needs compared to images). So in this case VectorTileLayer (m_vectorTileLayer) will be a completely new class independent from TextureLayer.
When creating or changing the map theme, MarbleMap will ask if the new map has any GeoSceneTiled layers (hasTextureLayers()). If it does it will iterate through them and by checking their <backend> tag it will distinguish between an image tile layer and vector tile layer and add them to m_textureLayer or m_vectorTileLayer.
Finally all the layers are added to the LayerManager (m_layerManager).
VectorTileLayer
VectorTileLayer has the logic for downloading, rendering and managing vector tiles. The main problem with this is the amount of memory and process it needs. The layer has a pointer to the maps TreeModel (the class that renders vector data) and a QCache< GeoDataLatLonAltBox, CacheDocument> (m_documents) that will store all the GeoDataDocuments (class that stores Geometries) that are being displayed in screen in each moment. Explained in another way, all the GeoDataDocuments inside the TreeModel (m_treeModel) will also be inside m_documents.
The key for m_documents is the tile's GeoDataLatLonAltBox so when the map is moved every tile that doesn't intersect with the screens GeoDataLatLonAltBox will be removed from m_documents and from m_treeModel, to avoid having to process geometries that are not inside the screen. This GeoDataDocument only can be removed, not deleted because it's StackedTile (which will be explained afterwards) still contains a pointer to it.
Everytime the map is moved or updated, render() function is called. The layer will calculate if the zoom level has changed and if it did change, all tile geometries will be removed from m_documents and m_treeModel because new tiles for the new zoom have to bee loaded. If the zoom didn't change, it will check the screen and tile's intersection to removed not displaying tiles as previously explained. Next, it will call VectorTileMapper (m_texmapper) for it to download needed tiles.
VectorTileLayer contains a SLOT (updateTile()) that receives vector tiles. When a new vector tile is received, it is inserted into m_documents and m_treeModel.
VectorTileMapper
Image tile layers use different mappers depending on the maps projection but for vector tiles, changes between different projection are already made by the TreeModel. VectorTileMapper saves the screen's tiles maximum and minimum X and Y (more info here: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Subtiles). When the layer calls, it will calculate the new screens X and Y and comparing them to the previous ones it will know in which direction the map has been moved and download the required tiles. There is a RenderJob QRunnable, that given a tile X and Y bounding box, asks the StackedTileLoader (loadTile())for those tiles. While tiles are received, if they have data they are sent through a SIGNAL/SLOT to VectorTileLayer.
StackedTileLoader
The StackedTileLoader stores tiles, manages them and launches their download if missing. In the beginning it only supported image tiles (TextureTile) that were stored inside a StackedTile. Now StackedTile supports two types of tiles TextureTile and VectorTile. Booth extend the Tile class, created to contain the common attributes from a tile such as format or TileId. Then TextureTile contains a Qimage and VectorTile a GeoDataDocument.
When a tile is missing, StackedTileLoader calls MergedLayerDecorator to download it, by looking at the GeoSceneTiled's nodetype() method it chooses between creating a TextureTile (if it is a GeoSceneTextureTile) or a VectorTile (if it is a GeoSceneVectorTile) and it wraps it inside a StackedTile.