= !MapGuide RFC 170 - Tile Service Enhancements (Part 2) = This page contains a change request (RFC) for the !MapGuide Open Source project. More !MapGuide RFCs can be found on the [wiki:MapGuideRfcs RFCs] page. == Status == ||RFC Template Version||(1.0)|| ||Submission Date||22 May 2019|| ||Last Modified||25 May 2019|| ||Author||Jackie Ng|| ||RFC Status||Ready for review|| ||Implementation Status||sandbox in progress|| ||Proposed Milestone||4.0|| ||Assigned PSC guide(s)||(when determined)|| ||'''Voting History'''||(vote date)|| ||+1||Jackie,Gordon,Crispin,Martin|| ||+0|||| ||-0|||| ||-1|||| ||no vote||Haris,Reno,Trevor|| == Overview == This RFC proposes to build on top of the Tile Service Enhancements introduced in MapGuide Open Source 3.0 with RFC 140 == Motivation == RFC 140 introduced the concept of a tile set as a resource (TileSetDefinition) and support for XYZ tile sets. While the RFC laid down a lot of groundwork, there are some feature gaps, loose ends and cases not considered in the initial implementation that did not make it in the 3.0 release cycle. This RFC will tie up such loose ends == Proposed Solution == This RFC will tie up the following loose ends: === Configurable TileExtentOffset === The (previously-global) {{{TileExtentOffset}}} server configuration property is now available as a tileset-specific parameter. === Meta-tiling === RFC90 introduced an implementation of meta-tiling. Meta-tiling is the process of rendering a bigger tile and slicing it down into sub-tiles of the original requested size, generally improving tile generation throughput as a result. However, this implementation has not yet been integrated back into trunk so as a result, it has not surfaced as a feature in any release of MapGuide since the RFC was implemented. For this RFC, we will take the RFC90 implementation of meta-tiling and retro-fit it into the new Tile Set Definition infrastructure. Firstly, we will add new {{{RenderTile}}} and {{{RenderTileXYZ}}} primitives that accept a meta-tiling factor: {{{ class MG_MAPGUIDE_API MgRenderingService : public MgService { ... EXTERNAL_API: ///////////////////////////////////////////////////////////////// /// \brief /// Returns the specified base map tile for the given map. /// /// \remarks /// This method only renders the given tile. No tile caching is performed /// by this method. To render and cache the tile, use the /// \link MgTileService::GetTile GetTile \endlink method instead. However, /// using that method will use default tile width/height/dpi/format specified /// in your MapGuide Server configuration /// /// \param map /// Input /// map object containing current state of map. /// \param baseMapLayerGroupName /// Input /// Specifies the name of the baseMapLayerGroup for which to render the tile. /// \param tileColumn /// Input /// Specifies the column index of the tile to return. /// \param tileRow /// Input /// Specifies the row index of the tile to return. /// \param tileWidth /// Input /// Specifies the width of the tile to return. /// \param tileHeight /// Input /// Specifies the height of the tile to return. /// \param tileDpi /// Input /// Specifies the dpi the tile to return. /// \param tileImageFormat /// Input /// Specifies the image format of the tile. See \link MgImageFormats \endlink /// \param tileExtentOffset /// Input /// Specifies the ratio by which the tile to be rendered should be "buffered out". The tile will be rendered at the specified width /// multiplied by the given ratio, which will be cropped back to the original requested size after rendering. This is to improve /// label placement on rendered tiles by giving extra "breathing space" to label placement algorithms. /// \param metaTilingFactor /// Input /// The meta-tiling factor. If less than or equal to 1, no meta-tiling is done and the returned meta-tile can be extracted /// as the orignally requested tile image. If greater than 1, a tile that is m times bigger than the requested tile is rendered /// (where m is the specified tiling factor) and the raw image frame buffer of this meta-tile is returned instead. /// /// \return /// A meta-tile with sufficient information for the consumer to properly sub-divide this back into sub-tiles of the /// originally requested size. /// /// \since 3.3 virtual MgMetatile* RenderMetatile( MgMap* map, CREFSTRING baseMapLayerGroupName, INT32 tileColumn, INT32 tileRow, INT32 tileWidth, INT32 tileHeight, INT32 tileDpi, CREFSTRING tileImageFormat, double tileExtentOffset, INT32 metaTilingFactor) = 0; ///////////////////////////////////////////////////////////////// /// \brief /// Returns the specified map tile for the given map. Tile structure is /// based on the XYZ tiling scheme used by Google Maps, OpenStreetMap, and /// others /// /// \param map /// Input /// map object containing current state of map. /// \param baseMapLayerGroupName /// Input /// Specifies the name of the baseMapLayerGroup for which to render the tile. /// \param x /// Input /// Specifies the row index of the tile to return. /// \param y /// Input /// Specifies the column index of the tile to return. /// \param z /// Input /// Specifies the zoom level of the tile to return. /// \param dpi /// Input /// Specifies the dpi of the tile to return. /// \param tileImageFormat /// Input /// Specifies the image format of the tile to return. /// \param tileExtentOffset /// Input /// Specifies the ratio by which the tile to be rendered should be "buffered out". The tile will be rendered at the specified width /// multiplied by the given ratio, which will be cropped back to the original requested size after rendering. This is to improve /// label placement on rendered tiles by giving extra "breathing space" to label placement algorithms. /// \param metaTilingFactor /// Input /// The meta-tiling factor. If less than or equal to 1, no meta-tiling is done and the returned meta-tile can be extracted /// as the orignally requested tile image. If greater than 1, a tile that is m times bigger than the requested tile is rendered /// (where m is the specified tiling factor) and the raw image frame buffer of this meta-tile is returned instead. /// /// \return /// A meta-tile with sufficient information for the consumer to properly sub-divide this back into sub-tiles of the /// originally requested size. /// /// \since 3.3 virtual MgMetatile* RenderMetatileXYZ( MgMap* map, CREFSTRING baseMapLayerGroupName, INT32 x, INT32 y, INT32 z, INT32 dpi, CREFSTRING tileImageFormat, double tileExtentOffset, INT32 metaTilingFactor) = 0; ///////////////////////////////////////////////////////////////// /// \brief /// Returns the requested sub-tile from the given metatile /// /// \param map /// Input /// map object containing current state of map. /// \param metaTile /// Input /// The meta-tile from which a subtile is being requested for /// \param rendererName /// Input /// The name of the renderer to create for sub-tile slicing /// \param subTileX /// Input /// The x sub-tile coordinate of the meta-tile to request /// \param subTileY /// Input /// The y sub-tile coordinate of the meta-tile to request /// /// \return /// The requested sub-tile /// /// \since 3.3 virtual MgByteReader* RenderTileFromMetaTile(MgMap* map, MgMetatile* metaTile, CREFSTRING rendererName, INT32 subTileX, INT32 subTileY) = 0; }; }}} These new overloads are designated {{{EXTERNAL_API}}} because meta-tiles are not intended to be consumed by regular MapGuide applications. They are raw image frame buffers that the rendering infrastructure will use to sub-divide back into tiles of the original requested size. But at the same time, these overloads have to be present in the {{{MgRenderingService}}} contract to allow a server-based tile service to still request meta-tiles through a proxy instance (should a server-based instance not be available). If applications do take advantage of these new overloads, it is expected they will always pass a {{{metaTilingFactor}}} of {{{0}}} when calling these new overloads or they know how to process and sub-divide the raw image frame buffer back into tile images of the original tile size. The new `MgMetatile` class is a semi-opaque handle from the perspective of MapGuide applications and its only purpose is really only to be fed to the {{{RenderTileFromMetaTile}}} method. The class is shown below for reference: {{{ ///////////////////////////////////////////////////////////////// /// \brief /// Defines a raw image frame buffer from the result of a meta-tile /// rendering operation /// /// \since 3.3 class MG_MAPGUIDE_API MgMetatile : public MgSerializable { MG_DECL_DYNCREATE() DECLARE_CLASSNAME(MgMetatile) EXTERNAL_API: /// \brief /// Gets the meta-tile content. If no meta-tiling is performed, this is the tile image. Otherwise, /// it is the raw image frame buffer (for sub-dividing into originally requested tile images) MgByteReader* GetImage(); /// \brief /// Gets the originally requested width of this tile INT32 GetRequestedWidth(); /// \brief /// Gets the originally requested height of this tile INT32 GetRequestedHeight(); /// \brief /// Gets the width of this metatile INT32 GetWidth(); /// \brief /// Gets the height of this metatile INT32 GetHeight(); /// \brief /// Gets the meta-tiling factor. INT32 GetMetaTilingFactor(); /// \brief /// Gets the originally requested tile image format STRING GetTileImageFormat(); ... }; }}} Meta-tiling support will be surfaced via new tile set definition parameters: * {{{MetaTileFactor}}} * {{{LockMethod}}} Meta-tiling has no effect for tile formats that are not image-based (eg. UTFGrid) An implementation of this RFC has been carried out in the [https://trac.osgeo.org/mapguide/browser/sandbox/jng/tiling_v2 tiling_v2 sandbox]. Upon adoption of this RFC, it will be merged into trunk. == Implications == Tiles generated through meta-tiling may have subtle differences in label placement due to being "cut" from a parent tile that is {{{x}}} times bigger (where {{{x}}} = meta-tiling factor), thus affording the tile renderer more "breathing space" in determining optimal label placement for applicable features that a regular tile would not have. == Test Plan == Add unit tests to render meta-tiles and also render baseline regular tiles for comparison. With the exception of subtle differences in label placement, verify that the tiles cut from meta-tiles are visually the same as regular tiles (esp. Line/Polygon features) == Funding / Resources == Community