[mapguide-commits] r9185 - in sandbox/jng/utfgrid: Common/MapGuideCommon/Services Common/Renderers Server/src/Services/Rendering Server/src/UnitTesting

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Mon May 1 16:56:15 PDT 2017


Author: jng
Date: 2017-05-01 16:56:15 -0700 (Mon, 01 May 2017)
New Revision: 9185

Modified:
   sandbox/jng/utfgrid/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
   sandbox/jng/utfgrid/Common/MapGuideCommon/Services/ProxyRenderingService.h
   sandbox/jng/utfgrid/Common/MapGuideCommon/Services/RenderingDefs.h
   sandbox/jng/utfgrid/Common/MapGuideCommon/Services/RenderingService.h
   sandbox/jng/utfgrid/Common/Renderers/UTFGridContent.cpp
   sandbox/jng/utfgrid/Common/Renderers/UTFGridContent.h
   sandbox/jng/utfgrid/Common/Renderers/UTFGridRenderer.cpp
   sandbox/jng/utfgrid/Common/Renderers/UTFGridRenderer.h
   sandbox/jng/utfgrid/Common/Renderers/agg_utfgrid_context.h
   sandbox/jng/utfgrid/Server/src/Services/Rendering/RenderingOperationFactory.cpp
   sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.cpp
   sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.h
   sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.vcxproj
   sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.vcxproj.filters
   sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingServiceBuild.cpp
   sandbox/jng/utfgrid/Server/src/UnitTesting/TestRenderingService.cpp
   sandbox/jng/utfgrid/Server/src/UnitTesting/TestRenderingService.h
Log:
- Add RenderTileUTFGrid API to MgRenderingService
- Extract out XYZ tile extent computation to a common method in MgServerFeatureService
- Fix access violation in agg_utfgrid_context, we don't use the stride value as copypasta'd from agg_context!
- Use plain unsigned int instead of the typedef'd utfgrid_band_type in our various new headers to avoid AGG headers leaking out to ServerRenderingService project
- Add unit test for rendering out UTFGrid tiles, re-using XYZ tile test data and giving us a nice baseline visual comparsion.

Modified: sandbox/jng/utfgrid/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
===================================================================
--- sandbox/jng/utfgrid/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2017-05-01 23:56:15 UTC (rev 9185)
@@ -19,6 +19,7 @@
 #include "Command.h"
 
 #include "RenderingDefs.h"
+#include "ProxyRenderingService.h"
 
 static const int Rendering_Service = (int)MgPacketParser::msiRendering;
 
@@ -192,6 +193,28 @@
     return (MgByteReader*)cmd.GetReturnValue().val.m_obj;
 }
 
+MgByteReader * MgProxyRenderingService::RenderTileUTFGrid(MgMap * map, CREFSTRING baseMapLayerGroupName, INT32 x, INT32 y, INT32 z, INT32 dpi)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                      // Connection
+        MgCommand::knObject,                            // Return type expected
+        MgRenderingServiceOpId::RenderTileUTFGrid,      // Command Code
+        7,                                              // No of arguments
+        Rendering_Service,                              // Service Id
+        BUILD_VERSION(3, 3, 0),                         // Operation version
+        MgCommand::knObject, map,                       // Argument#1
+        MgCommand::knString, &baseMapLayerGroupName,    // Argument#2
+        MgCommand::knInt32, x,                          // Argument#3
+        MgCommand::knInt32, y,                          // Argument#4
+        MgCommand::knInt32, z,                          // Argument#5
+        MgCommand::knInt32, dpi,                        // Argument#6
+        MgCommand::knNone);                             // End of arguments
+
+    SetWarning(cmd.GetWarningObject());
+
+    return (MgByteReader*)cmd.GetReturnValue().val.m_obj;
+}
+
 /////////////////////////////////////////////////////////////////
 /// <summary>
 /// Renders all dynamic layers in the specified MgMap to a dynamic overlay image

Modified: sandbox/jng/utfgrid/Common/MapGuideCommon/Services/ProxyRenderingService.h
===================================================================
--- sandbox/jng/utfgrid/Common/MapGuideCommon/Services/ProxyRenderingService.h	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Common/MapGuideCommon/Services/ProxyRenderingService.h	2017-05-01 23:56:15 UTC (rev 9185)
@@ -179,6 +179,45 @@
 
     /////////////////////////////////////////////////////////////////
     /// \brief
+    /// Returns the specified UTFGrid 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.
+    ///
+    /// \return
+    /// A byte reader containing the rendered tile image.
+    ///
+    virtual MgByteReader* RenderTileUTFGrid(
+        MgMap* map,
+        CREFSTRING baseMapLayerGroupName,
+        INT32 x,
+        INT32 y,
+        INT32 z,
+        INT32 dpi);
+
+    /////////////////////////////////////////////////////////////////
+    /// \brief
     /// Renders all dynamic layers in the specified MgMap to a dynamic overlay image
     /// with a transparent background. The center, scale, size, and layers to be
     /// rendered are defined by the specified map instance.  The format parameter

Modified: sandbox/jng/utfgrid/Common/MapGuideCommon/Services/RenderingDefs.h
===================================================================
--- sandbox/jng/utfgrid/Common/MapGuideCommon/Services/RenderingDefs.h	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Common/MapGuideCommon/Services/RenderingDefs.h	2017-05-01 23:56:15 UTC (rev 9185)
@@ -45,6 +45,7 @@
     static const int RenderTileXYZ2             = 0x1111E911;
     static const int RenderMap6                 = 0x1111E912;
     static const int RenderMap7                 = 0x1111E913;
+    static const int RenderTileUTFGrid          = 0x1111E914;
 };
 /// \endcond
 

Modified: sandbox/jng/utfgrid/Common/MapGuideCommon/Services/RenderingService.h
===================================================================
--- sandbox/jng/utfgrid/Common/MapGuideCommon/Services/RenderingService.h	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Common/MapGuideCommon/Services/RenderingService.h	2017-05-01 23:56:15 UTC (rev 9185)
@@ -194,6 +194,45 @@
 
     /////////////////////////////////////////////////////////////////
     /// \brief
+    /// Returns the specified UTFGrid 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.
+    ///
+    /// \return
+    /// A byte reader containing the rendered tile image.
+    ///
+    virtual MgByteReader* RenderTileUTFGrid(
+        MgMap* map,
+        CREFSTRING baseMapLayerGroupName,
+        INT32 x,
+        INT32 y,
+        INT32 z,
+        INT32 dpi) = 0;
+
+    /////////////////////////////////////////////////////////////////
+    /// \brief
     /// Renders all dynamic layers in the specified MgMap to a dynamic overlay image
     /// with a transparent background. The center, scale, size, and layers to be
     /// rendered are defined by the specified map instance.  The format parameter

Modified: sandbox/jng/utfgrid/Common/Renderers/UTFGridContent.cpp
===================================================================
--- sandbox/jng/utfgrid/Common/Renderers/UTFGridContent.cpp	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Common/Renderers/UTFGridContent.cpp	2017-05-01 23:56:15 UTC (rev 9185)
@@ -1,4 +1,5 @@
 #include "UTFGridContent.h"
+#include "UnicodeString.h"
 #include "agg_utfgrid_context.h"
 
 UTFGridContent::UTFGridContent()
@@ -11,7 +12,10 @@
 
 std::string UTFGridContent::GetString()
 {
-    return m_content.str();
+    std::string mbContent;
+    std::wstring content = m_content.str();
+    UnicodeString::WideCharToMultiByte(content.c_str(), mbContent);
+    return mbContent;
 }
 
 void UTFGridContent::AddFeature(unsigned int color, RS_FeatureReader* feature)
@@ -24,7 +28,7 @@
 
 }
 
-void UTFGridContent::AppendRowPixel(utfgrid_band_type pixel)
+void UTFGridContent::AppendRowPixel(unsigned int pixel)
 {
     m_content.sputc(EncodeChar(pixel));
 }
@@ -34,12 +38,12 @@
     m_content.sputc('\n');
 }
 
-utfgrid_band_type UTFGridContent::EncodeChar(utfgrid_band_type toEncode)
+unsigned int UTFGridContent::EncodeChar(unsigned int toEncode)
 {
     // Encoding IDs: https://github.com/mapbox/utfgrid-spec/blob/master/1.3/utfgrid.md#encoding-ids
 
     // Add 32
-    utfgrid_band_type encoded = toEncode + 32;
+    unsigned int encoded = toEncode + 32;
     // If result is >= 34, add 1
     if (encoded >= 34)
     {
@@ -53,12 +57,12 @@
     return encoded;
 }
 
-utfgrid_band_type UTFGridContent::DecodeChar(utfgrid_band_type toDecode)
+unsigned int UTFGridContent::DecodeChar(unsigned int toDecode)
 {
     // Decoding IDs: https://github.com/mapbox/utfgrid-spec/blob/master/1.3/utfgrid.md#encoding-ids
 
     // If codepoint is >= 93, subtract 1
-    utfgrid_band_type decoded = toDecode;
+    unsigned int decoded = toDecode;
     if (decoded >= 93)
     {
         decoded -= 1;

Modified: sandbox/jng/utfgrid/Common/Renderers/UTFGridContent.h
===================================================================
--- sandbox/jng/utfgrid/Common/Renderers/UTFGridContent.h	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Common/Renderers/UTFGridContent.h	2017-05-01 23:56:15 UTC (rev 9185)
@@ -20,7 +20,6 @@
 
 #include "Renderers.h"
 #include "RS_FeatureReader.h"
-#include "agg_utfgrid_context.h"
 #include <sstream>
 
 typedef std::map<unsigned int, std::string> FeaturePixelMap;
@@ -36,14 +35,14 @@
     void AddFeature(unsigned int color, RS_FeatureReader* feature);
 
     void StartGridRow();
-    void AppendRowPixel(utfgrid_band_type pixel);
+    void AppendRowPixel(unsigned int pixel);
     void EndGridRow();
 
 private:
-    static utfgrid_band_type EncodeChar(utfgrid_band_type toEncode);
-    static utfgrid_band_type DecodeChar(utfgrid_band_type toDecode);
+    static unsigned int EncodeChar(unsigned int toEncode);
+    static unsigned int DecodeChar(unsigned int toDecode);
 
-    std::stringbuf m_content;
+    std::wstringbuf m_content;
     FeaturePixelMap m_features;
 };
 

Modified: sandbox/jng/utfgrid/Common/Renderers/UTFGridRenderer.cpp
===================================================================
--- sandbox/jng/utfgrid/Common/Renderers/UTFGridRenderer.cpp	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Common/Renderers/UTFGridRenderer.cpp	2017-05-01 23:56:15 UTC (rev 9185)
@@ -48,7 +48,14 @@
 
 UTFGridRenderer::UTFGridRenderer(UTFGridContent* utfGrid)
   : m_currentColor(0),
-    m_content(utfGrid)
+    m_content(utfGrid),
+    m_dpi(0),
+    m_drawingScale(0.0),
+    m_metersPerUnit(0.0),
+    m_mapScale(0.0),
+    m_mapInfo(NULL),
+    m_layerInfo(NULL),
+    m_fcInfo(NULL)
 {
     // allocate back buffer
     int len = UTF_GRID_WIDTH * UTF_GRID_HEIGHT;

Modified: sandbox/jng/utfgrid/Common/Renderers/UTFGridRenderer.h
===================================================================
--- sandbox/jng/utfgrid/Common/Renderers/UTFGridRenderer.h	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Common/Renderers/UTFGridRenderer.h	2017-05-01 23:56:15 UTC (rev 9185)
@@ -100,7 +100,7 @@
     agg_utfgrid_context* m_context;
 
     //screen buffer
-    utfgrid_band_type* m_rows;
+    unsigned int* m_rows;
 
     //Not used, just passed around to satisfy required func signatures
     SE_LineStroke m_lineStroke;

Modified: sandbox/jng/utfgrid/Common/Renderers/agg_utfgrid_context.h
===================================================================
--- sandbox/jng/utfgrid/Common/Renderers/agg_utfgrid_context.h	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Common/Renderers/agg_utfgrid_context.h	2017-05-01 23:56:15 UTC (rev 9185)
@@ -61,7 +61,7 @@
             m_rows = rows;
         }
 
-        int stride = width * sizeof(utfgrid_band_type);
+        int stride = width; // *sizeof(utfgrid_band_type);
         rendering_buffer.attach(m_rows, width, height, stride);
         pixel_format.attach(rendering_buffer);
         renderer_base.attach(pixel_format);

Modified: sandbox/jng/utfgrid/Server/src/Services/Rendering/RenderingOperationFactory.cpp
===================================================================
--- sandbox/jng/utfgrid/Server/src/Services/Rendering/RenderingOperationFactory.cpp	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Server/src/Services/Rendering/RenderingOperationFactory.cpp	2017-05-01 23:56:15 UTC (rev 9185)
@@ -108,6 +108,17 @@
                 L"MgRenderingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
         }
         break;
+    case MgRenderingServiceOpId::RenderTileUTFGrid:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(3, 3):
+            handler.reset(new MgOpRenderTileUTFGrid());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgRenderingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
 
     case MgRenderingServiceOpId::RenderDynamicOverlay:
         switch (VERSION_NO_PHASE(operationVersion))

Modified: sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.cpp
===================================================================
--- sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.cpp	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.cpp	2017-05-01 23:56:15 UTC (rev 9185)
@@ -20,6 +20,7 @@
 #include "DefaultStylizer.h"
 #include "GDRenderer.h"
 #include "AGGRenderer.h"
+#include "UTFGridRenderer.h"
 #include "RSMgSymbolManager.h"
 #include "RSMgFeatureReader.h"
 #include "FeatureInfoRenderer.h"
@@ -259,6 +260,48 @@
     return ret.Detach();
 }
 
+void MgServerRenderingService::ComputeXYZTileExtents(MgMap* map, INT32 x, INT32 y, INT32 z, RS_Bounds& extent)
+{
+    //XYZ to lat/lon math. From this we can convert to the bounds in the map's CS
+    //
+    //Source: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
+    double nMin = M_PI - 2.0 * M_PI * y / pow(2.0, (int)z);
+    double nMax = M_PI - 2.0 * M_PI * (y + 1) / pow(2.0, (int)z);
+    double lonMin = x / pow(2.0, (int)z) * 360.0 - 180;
+    double latMin = 180.0 / M_PI * atan(0.5 * (exp(nMin) - exp(-nMin)));
+    double lonMax = (x + 1) / pow(2.0, (int)z) * 360.0 - 180;
+    double latMax = 180.0 / M_PI * atan(0.5 * (exp(nMax) - exp(-nMax)));
+
+    double mcsMinX = std::min(lonMin, lonMax);
+    double mcsMinY = std::min(latMin, latMax);
+    double mcsMaxX = std::max(lonMin, lonMax);
+    double mcsMaxY = std::max(latMin, latMax);
+
+    STRING mapCsWkt = map->GetMapSRS();
+    Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
+    Ptr<MgCoordinateSystem> mapCs = csFactory->Create(mapCsWkt);
+    if (mapCs->GetCsCode() != L"LL84")
+    {
+        //Set up LL to map transform and transform the bounds into map space
+        Ptr<MgCoordinateSystem> llCs = csFactory->CreateFromCode(L"LL84");
+        Ptr<MgCoordinateSystemTransform> trans = csFactory->GetTransform(llCs, mapCs);
+
+        Ptr<MgCoordinate> ul = trans->Transform(lonMin, latMin);
+        Ptr<MgCoordinate> lr = trans->Transform(lonMax, latMax);
+
+        mcsMinX = std::min(lr->GetX(), ul->GetX());
+        mcsMinY = std::min(lr->GetY(), ul->GetY());
+        mcsMaxX = std::max(lr->GetX(), ul->GetX());
+        mcsMaxY = std::max(lr->GetY(), ul->GetY());
+    }
+
+    // get map extent that corresponds to tile extent
+    extent.minx = mcsMinX;
+    extent.miny = mcsMinY;
+    extent.maxx = mcsMaxX;
+    extent.maxy = mcsMaxY;
+}
+
 MgByteReader* MgServerRenderingService::RenderTileXYZ(MgMap* map,
                                                       CREFSTRING baseMapLayerGroupName,
                                                       INT32 x,
@@ -293,45 +336,11 @@
     int width = XYZ_TILE_WIDTH;
     int height = XYZ_TILE_HEIGHT;
 
-    //XYZ to lat/lon math. From this we can convert to the bounds in the map's CS
-    //
-    //Source: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
-    double nMin = M_PI - 2.0 * M_PI * y / pow(2.0, (int)z);
-    double nMax = M_PI - 2.0 * M_PI * (y + 1) / pow(2.0, (int)z);
-    double lonMin = x / pow(2.0, (int)z) * 360.0 - 180;
-    double latMin = 180.0 / M_PI * atan(0.5 * (exp(nMin) - exp(-nMin)));
-    double lonMax = (x + 1) / pow(2.0, (int)z) * 360.0 - 180;
-    double latMax = 180.0 / M_PI * atan(0.5 * (exp(nMax) - exp(-nMax)));
-
-    double mcsMinX = std::min(lonMin, lonMax);
-    double mcsMinY = std::min(latMin, latMax);
-    double mcsMaxX = std::max(lonMin, lonMax);
-    double mcsMaxY = std::max(latMin, latMax);
-
-    STRING mapCsWkt = map->GetMapSRS();
-    Ptr<MgCoordinateSystemFactory> csFactory = new MgCoordinateSystemFactory();
-    Ptr<MgCoordinateSystem> mapCs = csFactory->Create(mapCsWkt);
-    if (mapCs->GetCsCode() != L"LL84")
-    {
-        //Set up LL to map transform and transform the bounds into map space
-        Ptr<MgCoordinateSystem> llCs = csFactory->CreateFromCode(L"LL84");
-        Ptr<MgCoordinateSystemTransform> trans = csFactory->GetTransform(llCs, mapCs);
-
-        Ptr<MgCoordinate> ul = trans->Transform(lonMin, latMin);
-        Ptr<MgCoordinate> lr = trans->Transform(lonMax, latMax);
-
-        mcsMinX = std::min(lr->GetX(), ul->GetX());
-        mcsMinY = std::min(lr->GetY(), ul->GetY());
-        mcsMaxX = std::max(lr->GetX(), ul->GetX());
-        mcsMaxY = std::max(lr->GetY(), ul->GetY());
-    }
-
     // Inlining same logic from RenderTile() overload below as we want the same logic, but we want to pass scale
     // instead of scale index
+    RS_Bounds extent;
+    ComputeXYZTileExtents(map, x, y, z, extent);
 
-    // get map extent that corresponds to tile extent
-    RS_Bounds extent(mcsMinX, mcsMinY, mcsMaxX, mcsMaxY);
-
     // use the map's background color, but always make it fully transparent
     RS_Color bgColor;
     StylizationUtil::ParseColor(map->GetBackgroundColor(), bgColor);
@@ -425,6 +434,197 @@
     return ret.Detach();
 }
 
+MgByteReader* MgServerRenderingService::RenderTileUTFGrid(MgMap * map, 
+                                                          CREFSTRING baseMapLayerGroupName, 
+                                                          INT32 x,
+                                                          INT32 y, 
+                                                          INT32 z, 
+                                                          INT32 dpi)
+{
+    Ptr<MgByteReader> ret;
+
+    MG_TRY()
+
+    CHECKARGUMENTNULL(map, L"MgServerRenderingService.RenderTileUTFGrid");
+    CHECKARGUMENTEMPTYSTRING(baseMapLayerGroupName, L"MgServerRenderingService.RenderTileUTFGrid");
+
+    // get the layer group associated with the name
+    Ptr<MgLayerGroupCollection> layerGroups = map->GetLayerGroups();
+    Ptr<MgLayerGroup> baseGroup = layerGroups->GetItem(baseMapLayerGroupName);
+    if (baseGroup == NULL)
+    {
+        MgStringCollection arguments;
+        arguments.Add(L"2");
+        arguments.Add(baseMapLayerGroupName);
+
+        throw new MgInvalidArgumentException(L"MgServerRenderingService.RenderTileUTFGrid",
+            __LINE__, __WFILE__, &arguments, L"MgMapLayerGroupNameNotFound", NULL);
+    }
+
+    //Set the dpi
+    map->SetDisplayDpi(dpi);
+
+    int width = XYZ_TILE_WIDTH;
+    int height = XYZ_TILE_HEIGHT;
+
+    // Inlining same logic from RenderTile() overload below as we want the same logic, but we want to pass scale
+    // instead of scale index
+
+    // get map extent that corresponds to tile extent
+    RS_Bounds extent;
+    ComputeXYZTileExtents(map, x, y, z, extent);
+
+    // use the map's background color, but always make it fully transparent
+    RS_Color bgColor;
+    StylizationUtil::ParseColor(map->GetBackgroundColor(), bgColor);
+    bgColor.alpha() = 0;
+
+    // the label renderer needs to know the tile extent offset parameter
+    double tileExtentOffset = 0.0;
+    MgConfiguration* pConf = MgConfiguration::GetInstance();
+    pConf->GetDoubleValue(MgConfigProperties::RenderingServicePropertiesSection,
+        MgConfigProperties::RenderingServicePropertyTileExtentOffset,
+        tileExtentOffset,
+        MgConfigProperties::DefaultRenderingServicePropertyTileExtentOffset);
+    if (tileExtentOffset < 0.0)
+        tileExtentOffset = MgConfigProperties::DefaultRenderingServicePropertyTileExtentOffset;
+
+    // Image scaling logic ripped verbatim from RenderMap() overload that takes MgEnvelope
+    //
+    // If we need to scale the image (because of request for non-square
+    // pixels) we will need to draw at one image size and then save at
+    // another scaled size.  Here we will compute the correct map scale
+    // and render size for a requested extent and image size.
+    double screenAR = (double)width / (double)height;
+    double mapAR = extent.width() / extent.height();
+
+    int drawWidth = width;
+    int drawHeight = height;
+    double scale = 0.0;
+
+    if (mapAR >= screenAR)
+    {
+        scale = extent.width() * map->GetMetersPerUnit() / METERS_PER_INCH * (double)dpi / (double)width;
+
+        // we based map scale on the image width, so adjust rendering
+        // height to match the map aspect ratio
+        drawHeight = (int)(width / mapAR);
+
+        // ignore small perturbations in order to avoid rescaling the
+        // end image in cases where the rescaling of width is less than
+        // a pixel or so
+        if (abs(drawHeight - height) <= 1)
+            drawHeight = height;
+    }
+    else
+    {
+        scale = extent.height() * map->GetMetersPerUnit() / METERS_PER_INCH * (double)dpi / (double)height;
+
+        // we based map scale on the image height, so adjust rendering
+        // height to match the map aspect ratio
+        drawWidth = (int)(height * mapAR);
+
+        // ignore small perturbations, in order to avoid rescaling the
+        // end image in cases where the rescaling of width is less than
+        // a pixel or so
+        if (abs(drawWidth - width) <= 1)
+            drawWidth = width;
+    }
+
+    //printf("XYZ(%d, %d, %d) -> [%f, %f] [%f, %f] at %f -- (w: %d, h: %d, mpu: %f)\n", x, y, z, mcsMinX, mcsMinY, mcsMaxX, mcsMaxY, scale, width, height, map->GetMetersPerUnit());
+
+    // sanity check - number of image pixels cannot exceed MAX_PIXELS
+    if (drawWidth * drawHeight > MAX_PIXELS)
+        throw new MgOutOfRangeException(L"MgServerRenderingService.RenderMap", __LINE__, __WFILE__, NULL, L"MgInvalidImageSizeTooBig", NULL);
+
+    // create a temporary collection containing all the layers for the base group
+    Ptr<MgLayerCollection> layers = map->GetLayers();
+    Ptr<MgReadOnlyLayerCollection> roLayers = new MgReadOnlyLayerCollection();
+    for (int i = 0; i<layers->GetCount(); i++)
+    {
+        Ptr<MgLayerBase> layer = layers->GetItem(i);
+        Ptr<MgLayerGroup> parentGroup = layer->GetGroup();
+        if (parentGroup == baseGroup)
+            roLayers->Add(layer);
+    }
+
+    // of course the group has to also be visible
+    bool groupVisible = baseGroup->GetVisible();
+    baseGroup->SetVisible(true);
+
+    // We'd like to re-use RenderMapInternal, but its design is biased towards image-based SE_Renderers (that expect to
+    // save to some RS_ByteData that an MgByteReader is returned from.
+    //
+    // Our UTFGridRenderer is not such a renderer, so we have to inline the pertinent bits here
+    
+    // set the map scale to the requested scale
+    map->SetViewScale(scale);
+
+    // convert the map coordinate system from srs wkt to a mentor cs structure
+    STRING srs = map->GetMapSRS();
+    Ptr<MgCoordinateSystem> dstCs;
+    if (!srs.empty())
+    {
+        // let's not fail here if coord sys conversion fails for the map's
+        // coordinate system. Instead we will fail per layer at a later stage
+        try
+        {
+            dstCs = m_pCSFactory->Create(srs);
+        }
+        catch (MgInvalidCoordinateSystemException* e)
+        {
+            e->Release();
+        }
+    }
+
+    RS_String units = dstCs.p ? dstCs->GetUnits() : L"";
+
+    // get the session ID
+    STRING sessionId;
+    Ptr<MgUserInformation> userInfo = MgUserInformation::GetCurrentUserInfo();
+    if (userInfo != NULL)
+        sessionId = userInfo->GetMgSessionId();
+
+    UTFGridContent content;
+    std::auto_ptr<UTFGridRenderer> dr(new UTFGridRenderer(&content));
+
+    RSMgSymbolManager mgr(m_svcResource);
+    dr->SetSymbolManager(&mgr);
+
+    SEMgSymbolManager semgr(m_svcResource);
+    DefaultStylizer ds(&semgr);
+
+    RS_Color bgcolor(0, 0, 0, 255); //Not used by UTFGridRenderer
+
+    Ptr<MgPoint> ptCenter = map->GetViewCenter();
+    Ptr<MgCoordinate> coord = ptCenter->GetCoordinate();
+    RS_MapUIInfo mapInfo(sessionId, map->GetName(), map->GetObjectId(), srs, units, bgcolor, coord->GetX(), coord->GetY(), scale);
+
+    // begin map stylization
+    dr->StartMap(&mapInfo, extent, scale, map->GetDisplayDpi(), map->GetMetersPerUnit(), NULL);
+
+    // We can't use RenderMapInternal, but we can use RenderLayers, which is all we really need
+    RenderLayers(map, roLayers, &ds, dr.get(), dstCs, true, scale, L"UTFGRID", NULL);
+
+    dr->EndMap(); //This will trigger the UTFGrid tile encoding process
+
+    // restore the base group's visibility
+    baseGroup->SetVisible(groupVisible);
+
+    // Now extract the encoded utfgrid tile and pack it into a MgByteReader
+    std::string utfgrid = content.GetString();
+    Ptr<MgByteSource> bs = new MgByteSource((BYTE_ARRAY_IN)utfgrid.c_str(), (INT32)utfgrid.length());
+
+    // TODO: Convert to MgMimeType::Json when encoding is fully implemented
+    bs->SetMimeType(MgMimeType::Text);
+
+    ret = bs->GetReader();
+
+    MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderTileUTFGrid")
+
+    return ret.Detach();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 /// render a map using all layers from the baseGroup
 MgByteReader* MgServerRenderingService::RenderTile(MgMap* map,

Modified: sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.h
===================================================================
--- sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.h	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.h	2017-05-01 23:56:15 UTC (rev 9185)
@@ -70,6 +70,13 @@
                                         INT32 dpi,
                                         CREFSTRING tileImageFormat);
 
+    virtual MgByteReader* RenderTileUTFGrid(MgMap* map,
+                                            CREFSTRING baseMapLayerGroupName,
+                                            INT32 x,
+                                            INT32 y,
+                                            INT32 z,
+                                            INT32 dpi);
+
     virtual MgByteReader* RenderDynamicOverlay(MgMap* map,
                                                MgSelection* selection,
                                                CREFSTRING format);
@@ -226,6 +233,7 @@
                                         bool bIncludeFeatureBBOX);
 
 private:
+    static void ComputeXYZTileExtents(MgMap* map, INT32 x, INT32 y, INT32 z, RS_Bounds& extent);
     // used for tile generation
     MgByteReader* RenderTile(MgMap* map,
                              MgLayerGroup* baseGroup,

Modified: sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.vcxproj
===================================================================
--- sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.vcxproj	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.vcxproj	2017-05-01 23:56:15 UTC (rev 9185)
@@ -240,6 +240,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="OpRenderTileUTFGrid.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="RenderingOperation.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -292,6 +298,7 @@
     <ClInclude Include="OpRenderMapLegend.h" />
     <ClInclude Include="OpRenderTile.h" />
     <ClInclude Include="OpRenderTileXYZ.h" />
+    <ClInclude Include="OpRenderTileUTFGrid.h" />
     <ClInclude Include="RenderingOperation.h" />
     <ClInclude Include="RenderingOperationFactory.h" />
     <ClInclude Include="FeatureInfoRenderer.h" />

Modified: sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.vcxproj.filters
===================================================================
--- sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.vcxproj.filters	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingService.vcxproj.filters	2017-05-01 23:56:15 UTC (rev 9185)
@@ -39,6 +39,9 @@
     <ClCompile Include="OpRenderTileXYZ.cpp">
       <Filter>Ops</Filter>
     </ClCompile>
+    <ClCompile Include="OpRenderTileUTFGrid.cpp">
+      <Filter>Ops</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="OpQueryFeatureProperties.h">
@@ -74,6 +77,9 @@
     <ClInclude Include="OpRenderTileXYZ.h">
       <Filter>Ops</Filter>
     </ClInclude>
+    <ClInclude Include="OpRenderTileUTFGrid.h">
+      <Filter>Ops</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ServerRenderingService.rc" />

Modified: sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingServiceBuild.cpp
===================================================================
--- sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingServiceBuild.cpp	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Server/src/Services/Rendering/ServerRenderingServiceBuild.cpp	2017-05-01 23:56:15 UTC (rev 9185)
@@ -25,6 +25,7 @@
 #include "OpRenderMapLegend.cpp"
 #include "OpRenderTile.cpp"
 #include "OpRenderTileXYZ.cpp"
+#include "OpRenderTileUTFGrid.cpp"
 #include "OpQueryFeatures.cpp"
 #include "OpQueryFeatureProperties.cpp"
 #include "RenderingOperation.cpp"

Modified: sandbox/jng/utfgrid/Server/src/UnitTesting/TestRenderingService.cpp
===================================================================
--- sandbox/jng/utfgrid/Server/src/UnitTesting/TestRenderingService.cpp	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Server/src/UnitTesting/TestRenderingService.cpp	2017-05-01 23:56:15 UTC (rev 9185)
@@ -1761,6 +1761,29 @@
     }
 }
 
+void TestRenderingService::TestCase_RenderTileUTFGrid()
+{
+    try
+    {
+        Ptr<MgMap> map = CreateTestTiledMap();
+        Ptr<MgByteReader> tileTL = m_svcRendering->RenderTileUTFGrid(map, L"BaseLayers", 2099, 2985, 13, 96);
+        Ptr<MgByteReader> tileTR = m_svcRendering->RenderTileUTFGrid(map, L"BaseLayers", 2100, 2985, 13, 96);
+        Ptr<MgByteReader> tileBL = m_svcRendering->RenderTileUTFGrid(map, L"BaseLayers", 2099, 2986, 13, 96);
+        Ptr<MgByteReader> tileBR = m_svcRendering->RenderTileUTFGrid(map, L"BaseLayers", 2100, 2986, 13, 96);
+
+        tileTL->ToFile(L"../UnitTestFiles/RenderTileUTFGrid_TopLeft.utfgrid");
+        tileTR->ToFile(L"../UnitTestFiles/RenderTileUTFGrid_TopRight.utfgrid");
+        tileBL->ToFile(L"../UnitTestFiles/RenderTileUTFGrid_BottomLeft.utfgrid");
+        tileBR->ToFile(L"../UnitTestFiles/RenderTileUTFGrid_BottomRight.utfgrid");
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+}
+
 STRING TestRenderingService::GetPath(CREFSTRING basePath, CREFSTRING imageFormat, CREFSTRING extension)
 {
 	STRING ret;

Modified: sandbox/jng/utfgrid/Server/src/UnitTesting/TestRenderingService.h
===================================================================
--- sandbox/jng/utfgrid/Server/src/UnitTesting/TestRenderingService.h	2017-05-01 16:24:06 UTC (rev 9184)
+++ sandbox/jng/utfgrid/Server/src/UnitTesting/TestRenderingService.h	2017-05-01 23:56:15 UTC (rev 9185)
@@ -55,6 +55,7 @@
     CPPUNIT_TEST(TestCase_LayerWatermarkPNG);
     CPPUNIT_TEST(TestCase_RenderTilePNG);
     CPPUNIT_TEST(TestCase_RenderTileXYZ_PNG);
+    CPPUNIT_TEST(TestCase_RenderTileUTFGrid);
 
     CPPUNIT_TEST(TestCase_StylizationFunctionsPNG8);
 
@@ -219,6 +220,7 @@
     void TestCase_LayerWatermarkPNG() { TestCase_LayerWatermark(L"PNG", L"png"); }
     void TestCase_RenderTilePNG() { TestCase_RenderTile(L"PNG", L"png"); }
     void TestCase_RenderTileXYZ_PNG() { TestCase_RenderTileXYZ(L"PNG", L"png"); }
+    void TestCase_RenderTileUTFGrid();
 
     //PNG8 output tests
     void TestCase_RenderDynamicOverlayPNG8() { TestCase_RenderDynamicOverlay(L"PNG8", L"png"); }



More information about the mapguide-commits mailing list