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

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Thu Apr 25 03:09:05 PDT 2019


Author: jng
Date: 2019-04-25 03:09:05 -0700 (Thu, 25 Apr 2019)
New Revision: 9496

Added:
   sandbox/jng/tiling_v2/Server/src/Services/Rendering/OpRenderMetatileXYZ.cpp
   sandbox/jng/tiling_v2/Server/src/Services/Rendering/OpRenderMetatileXYZ.h
Modified:
   sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
   sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/ProxyRenderingService.h
   sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/RenderingService.h
   sandbox/jng/tiling_v2/Common/Renderers/AGGRenderer.cpp
   sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.cpp
   sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.h
   sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.vcxproj
   sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.vcxproj.filters
   sandbox/jng/tiling_v2/Server/src/UnitTesting/TestRenderingService.cpp
   sandbox/jng/tiling_v2/Server/src/UnitTesting/TestRenderingService.h
Log:
Implement the XYZ metatile rendering primitive with unit tests.

Modified: sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
===================================================================
--- sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2019-04-25 10:09:05 UTC (rev 9496)
@@ -1368,4 +1368,38 @@
     SetWarning(cmd.GetWarningObject());
 
     return (MgMetatile*)cmd.GetReturnValue().val.m_obj;
+}
+
+MgMetatile* MgProxyRenderingService::RenderMetatileXYZ(
+    MgMap* map,
+    CREFSTRING baseMapLayerGroupName,
+    INT32 x,
+    INT32 y,
+    INT32 z,
+    INT32 dpi,
+    CREFSTRING tileImageFormat,
+    double tileExtentOffset,
+    INT32 metaTilingFactor)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                      // Connection
+        MgCommand::knObject,                            // Return type expected
+        MgRenderingServiceOpId::RenderTileXYZ2,         // Command Code
+        9,                                              // 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::knString, &tileImageFormat,          // Argument#7
+        MgCommand::knDouble, tileExtentOffset,          // Argument#8
+        MgCommand::knInt32, metaTilingFactor,           // Argument#9
+        MgCommand::knNone);                             // End of arguments
+
+    SetWarning(cmd.GetWarningObject());
+
+    return (MgMetatile*)cmd.GetReturnValue().val.m_obj;
 }
\ No newline at end of file

Modified: sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/ProxyRenderingService.h
===================================================================
--- sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/ProxyRenderingService.h	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/ProxyRenderingService.h	2019-04-25 10:09:05 UTC (rev 9496)
@@ -1140,13 +1140,21 @@
     /// 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 ration, which will be cropped back to the original requested size after rendering. This is to improve
+    /// 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 byte reader containing the rendered tile image.
+    /// 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,
@@ -1159,6 +1167,60 @@
         double tileExtentOffset,
         INT32 metaTilingFactor);
 
+    /////////////////////////////////////////////////////////////////
+    /// \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);
+
 protected:
 
     //////////////////////////////////////////////////////////////////

Modified: sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/RenderingService.h
===================================================================
--- sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/RenderingService.h	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Common/MapGuideCommon/Services/RenderingService.h	2019-04-25 10:09:05 UTC (rev 9496)
@@ -1153,12 +1153,19 @@
     /// 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 ration, which will be cropped back to the original requested size after rendering. This is to improve
+    /// 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 byte reader containing the rendered tile image.
+    /// 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(
@@ -1171,8 +1178,62 @@
         INT32 tileDpi,
         CREFSTRING tileImageFormat,
         double tileExtentOffset,
-        INT32 metaTileFactor) = 0;
+        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;
+
 protected:
 
     /////////////////////////////////////////////////////////////////

Modified: sandbox/jng/tiling_v2/Common/Renderers/AGGRenderer.cpp
===================================================================
--- sandbox/jng/tiling_v2/Common/Renderers/AGGRenderer.cpp	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Common/Renderers/AGGRenderer.cpp	2019-04-25 10:09:05 UTC (rev 9496)
@@ -268,6 +268,11 @@
     {
         //        if (imagebuffer == NULL)  // this musnt happen
         //            return NULL;
+
+        // TODO: For extent-based tiles like XYZ, it means our framebuffer represents a non-square
+        // tile, which technically means we're wasting allocated memory on pixels that aren't being 
+        // stored for such cases, but this being the first cut implementation, we're being extremely
+        // conservative here. If there is indeed wasted space. So be it.
         int imagebufferByteSize = width * height * 4; // multiply 32 bit pixel by 4 bytes
         return new RS_ByteData((unsigned char*)m_rows, imagebufferByteSize);
     }

Added: sandbox/jng/tiling_v2/Server/src/Services/Rendering/OpRenderMetatileXYZ.cpp
===================================================================
--- sandbox/jng/tiling_v2/Server/src/Services/Rendering/OpRenderMetatileXYZ.cpp	                        (rev 0)
+++ sandbox/jng/tiling_v2/Server/src/Services/Rendering/OpRenderMetatileXYZ.cpp	2019-04-25 10:09:05 UTC (rev 9496)
@@ -0,0 +1,126 @@
+//
+//  Copyright (C) 2004-2019 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "OpRenderMetatileXYZ.h"
+#include "LogManager.h"
+
+MgOpRenderMetatileXYZ::MgOpRenderMetatileXYZ()
+{
+}
+
+MgOpRenderMetatileXYZ::~MgOpRenderMetatileXYZ()
+{
+}
+
+void MgOpRenderMetatileXYZ::Execute()
+{
+    ACE_DEBUG((LM_DEBUG, ACE_TEXT("  (%t) MgOpRenderMetatileXYZ::Execute()\n")));
+
+    MG_LOG_OPERATION_MESSAGE(L"MgOpRenderMetatileXYZ");
+
+    MG_TRY()
+
+    MG_LOG_OPERATION_MESSAGE_INIT(m_packet.m_OperationVersion, m_packet.m_NumArguments);
+
+    ACE_ASSERT(m_stream != NULL);
+
+    if (8 == m_packet.m_NumArguments)
+    {
+        Ptr<MgMap> map = (MgMap*)m_stream->GetObject();
+        Ptr<MgResourceIdentifier> resource = map->GetResourceId();
+        map->SetDelayedLoadResourceService(m_resourceService);
+
+        STRING baseMapLayerGroupName;
+        m_stream->GetString(baseMapLayerGroupName);
+
+        INT32 x = 0;
+        m_stream->GetInt32(x);
+
+        INT32 y = 0;
+        m_stream->GetInt32(y);
+
+        INT32 z = 0;
+        m_stream->GetInt32(z);
+
+        INT32 tileDpi = 0;
+        m_stream->GetInt32(tileDpi);
+
+        STRING tileImageFormat;
+        m_stream->GetString(tileImageFormat);
+
+        double tileExtentOffset = 0.0;
+        m_stream->GetDouble(tileExtentOffset);
+
+        INT32 metaTilingFactor = 0;
+        m_stream->GetInt32(metaTilingFactor);
+
+        BeginExecution();
+
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING((NULL == resource) ? L"MgResourceIdentifier" : resource->ToString().c_str());
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(baseMapLayerGroupName.c_str());
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_INT32(x);
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_INT32(y);
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_INT32(z);
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_INT32(tileDpi);
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(tileImageFormat.c_str());
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_DOUBLE(tileExtentOffset);
+        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+        MG_LOG_OPERATION_MESSAGE_ADD_INT32(metaTilingFactor);
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+        Validate();
+
+        Ptr<MgMetatile> metaTile = m_service->RenderMetatileXYZ(map, baseMapLayerGroupName, x, y, z, tileDpi, tileImageFormat, tileExtentOffset, metaTilingFactor);
+
+        EndExecution(metaTile);
+    }
+    else
+    {
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+        MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+    }
+
+    if (!m_argsRead)
+    {
+        throw new MgOperationProcessingException(L"MgOpRenderMetatileXYZ.Execute",
+            __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    // Successful operation
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Success.c_str());
+
+    MG_CATCH(L"MgOpRenderMetatileXYZ.Execute")
+
+    if (mgException != NULL)
+    {
+        // Failed operation
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Failure.c_str());
+    }
+
+    // Add access log entry for operation
+    MG_LOG_OPERATION_MESSAGE_ACCESS_ENTRY();
+
+    MG_THROW()
+}

Added: sandbox/jng/tiling_v2/Server/src/Services/Rendering/OpRenderMetatileXYZ.h
===================================================================
--- sandbox/jng/tiling_v2/Server/src/Services/Rendering/OpRenderMetatileXYZ.h	                        (rev 0)
+++ sandbox/jng/tiling_v2/Server/src/Services/Rendering/OpRenderMetatileXYZ.h	2019-04-25 10:09:05 UTC (rev 9496)
@@ -0,0 +1,32 @@
+//
+//  Copyright (C) 2004-2019 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+#ifndef MG_OP_RENDER_METATILE_XYZ_H
+#define MG_OP_RENDER_METATILE_XYZ_H
+
+#include "RenderingOperation.h"
+
+class MgOpRenderMetatileXYZ : public MgRenderingOperation
+{
+public:
+    MgOpRenderMetatileXYZ();
+    virtual ~MgOpRenderMetatileXYZ();
+
+public:
+    virtual void Execute();
+};
+
+#endif
\ No newline at end of file

Modified: sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.cpp
===================================================================
--- sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.cpp	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.cpp	2019-04-25 10:09:05 UTC (rev 9496)
@@ -513,18 +513,37 @@
     ByteSourceMemoryImpl* source = dynamic_cast<ByteSourceMemoryImpl*>(bs->GetSourceImpl());
     assert(source);
     assert(bs->GetMimeType() == MgMimeType::Meta);
-    int size = (int)source->GetLength();
+    INT32 size = (INT32)source->GetLength();
 
     // some checking: the complete meta tile of 32b pixels should be in the framebuffer handed over
-    int expectedSize = 4 * (metaTileFactor * origTileWidth)
+    INT32 expectedSize = 4 * (metaTileFactor * origTileWidth)
                          * (metaTileFactor * origTileHeight);
     assert(size == expectedSize);
 
+    INT32 scaledTileWidth = origTileWidth;
+    INT32 scaledTileHeight = origTileHeight;
+
+    // For extent-driven tile rendering like XYZ, the raw image frame buffer of the tile may not actually 
+    // be square which means the meta-tile itself would not be square, so when we sub-divide we must make 
+    // sure to not sub-divide by the original width/height, but by its *proportially scaled* width/height, 
+    // which we then pass it down to AGGRenderer::Save() to write the buffer back up to the originally 
+    // requested size, scaling as appropriate.
+    if (metaTileFactor > 1)
+    {
+        scaledTileWidth = (INT32)(metaTile->GetWidth() / metaTileFactor);
+        scaledTileHeight = (INT32)(metaTile->GetHeight() / metaTileFactor);
+
+        // This may be the same or may be less, but it can't be more!
+        _ASSERT(scaledTileWidth <= origTileWidth);
+        _ASSERT(scaledTileHeight <= origTileHeight);
+    }
+
     // use the map's background color, but always make it fully transparent
     RS_Color bgColor;
     StylizationUtil::ParseColor(map->GetBackgroundColor(), bgColor);
     bgColor.alpha() = 0;
-    auto_ptr<SE_Renderer> dr(CreateRenderer(origTileWidth, origTileHeight, bgColor, true));
+    // Must create renderer under the scaled width/height and not original
+    auto_ptr<SE_Renderer> dr(CreateRenderer(scaledTileWidth, scaledTileHeight, bgColor, true));
     RS_ColorVector tileColorPalette;
     if (m_rendererName == L"AGG" && hasColorMap(origTileFormat))
     {
@@ -542,18 +561,18 @@
 
     // allocate subtile buffer to copy new framebuf with changed dimensions
     // place buffer in allocated MgByte auto_ptr object for destruction at end of scope
-    auto_ptr<MgByte> subTileBytes(new MgByte((unsigned char*)new unsigned int[origTileWidth * origTileHeight],
-        origTileWidth * origTileHeight * sizeof(int), MgByte::New));
+    auto_ptr<MgByte> subTileBytes(new MgByte((unsigned char*)new unsigned int[scaledTileWidth * scaledTileHeight],
+        scaledTileWidth * scaledTileHeight * sizeof(int), MgByte::New));
     // get the pointer to the internal target buffer
     unsigned int* subTileBuf = (unsigned int*)subTileBytes->Bytes();
-    for (int y = 0; y < origTileHeight; y++)    // rows
-        for (int x = 0; x < origTileWidth; x++)    // columns innerloop
+    for (int y = 0; y < scaledTileHeight; y++)    // rows
+        for (int x = 0; x < scaledTileWidth; x++)    // columns innerloop
         {  // this copies the 32bit pixels from the meta tile framebuffer to the subtile framebuffer
             *(subTileBuf + x
-                + y * origTileWidth)                 // target address in subtile
-                = *(framebuf + (x + (subTileX * origTileWidth))   // X address in meta tile
-                    + (y + (subTileY * origTileHeight))  // Y address in meta tile
-                    * origTileWidth * metaTileFactor);  // use width of metaTile here
+                + y * scaledTileWidth)                 // target address in subtile
+                = *(framebuf + (x + (subTileX * scaledTileWidth))   // X address in meta tile
+                    + (y + (subTileY * scaledTileHeight))  // Y address in meta tile
+                    * scaledTileWidth * metaTileFactor);  // use width of metaTile here
         }
     // then call the image renderer to convert the framebuffer bitmap into the desired image format
     return CreateImage(map, dr.get(), origTileWidth, origTileHeight, origTileFormat, NULL, subTileBuf);
@@ -2436,74 +2455,15 @@
 
     MG_TRY()
 
-    CHECKARGUMENTNULL(map, L"MgServerRenderingService.RenderTileXYZ");
-    CHECKARGUMENTEMPTYSTRING(baseMapLayerGroupName, L"MgServerRenderingService.RenderTileXYZ");
-    
-    // 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);
+    INT32 metaTilingFactor = 0;
+    Ptr<MgMetatile> metaTile = RenderMetatileXYZ(map, baseMapLayerGroupName, x, y, z, dpi, tileImageFormat, tileExtentOffset, metaTilingFactor);
 
-        throw new MgInvalidArgumentException(L"MgServerRenderingService.RenderTileXYZ",
-            __LINE__, __WFILE__, &arguments, L"MgMapLayerGroupNameNotFound", NULL);
-    }
+    _ASSERT(metaTile->GetRequestedWidth() == XYZ_TILE_WIDTH);
+    _ASSERT(metaTile->GetRequestedHeight() == XYZ_TILE_HEIGHT);
+    _ASSERT(metaTile->GetMetaTilingFactor() <= 1);
 
-    //Set the dpi
-    map->SetDisplayDpi(dpi);
+    ret = metaTile->GetImage();
 
-    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
-    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;
-    
-    INT32 drawWidth = width;
-    INT32 drawHeight = height;
-    double scale = 0.0;
-    ComputeScaledDimensions(extent, width, height, dpi, map->GetMetersPerUnit(), drawWidth, drawHeight, scale);
-
-    //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);
-
-    // initialize the renderer (set clipping to false so that we label
-    // the unclipped geometry)
-    auto_ptr<SE_Renderer> dr(CreateRenderer(drawWidth, drawHeight, bgColor, false, true, tileExtentOffset));
-
-    // 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);
-
-    // call the internal helper API to do all the stylization overhead work
-    ret = RenderMapInternal(map, NULL, roLayers, dr.get(), drawWidth, drawHeight, width, height, tileImageFormat, scale, extent, true, true, false, NULL);
-
-    // restore the base group's visibility
-    baseGroup->SetVisible(groupVisible);
-
     MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderTileXYZ")
 
     return ret.Detach();
@@ -2621,4 +2581,105 @@
     MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderMetatile")
 
     return ret.Detach();
+}
+
+MgMetatile* MgServerRenderingService::RenderMetatileXYZ(MgMap* map,
+                                                        CREFSTRING baseMapLayerGroupName,
+                                                        INT32 x,
+                                                        INT32 y,
+                                                        INT32 z,
+                                                        INT32 dpi,
+                                                        CREFSTRING tileImageFormat,
+                                                        double tileExtentOffset,
+                                                        INT32 metaTilingFactor)
+{
+    Ptr<MgMetatile> ret;
+
+    MG_TRY()
+
+    CHECKARGUMENTNULL(map, L"MgServerRenderingService.RenderMetatileXYZ");
+    CHECKARGUMENTEMPTYSTRING(baseMapLayerGroupName, L"MgServerRenderingService.RenderMetatileXYZ");
+    
+    // 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.RenderMetatileXYZ",
+            __LINE__, __WFILE__, &arguments, L"MgMapLayerGroupNameNotFound", NULL);
+    }
+
+    //Set the dpi
+    map->SetDisplayDpi(dpi);
+
+    // 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);
+
+    // If meta-tiling, request bounds for:
+    //   (x, y, z) -> (x + (tm - 1), y + (tm - 1), z)
+    // And combine the resulting bounds
+    if (metaTilingFactor > 1)
+    {
+        RS_Bounds extent2;
+        INT32 endX = x + (metaTilingFactor - 1);
+        INT32 endY = y + (metaTilingFactor - 1);
+        ComputeXYZTileExtents(map, endX, endY, z, extent2);
+
+        extent.add_bounds(extent2);
+    }
+
+    // use the map's background color, but always make it fully transparent
+    RS_Color bgColor;
+    StylizationUtil::ParseColor(map->GetBackgroundColor(), bgColor);
+    bgColor.alpha() = 0;
+    
+    INT32 width = XYZ_TILE_WIDTH * std::max(metaTilingFactor, 1);
+    INT32 height = XYZ_TILE_HEIGHT * std::max(metaTilingFactor, 1);
+    INT32 drawWidth = width;
+    INT32 drawHeight = height;
+    double scale = 0.0;
+    ComputeScaledDimensions(extent, width, height, dpi, map->GetMetersPerUnit(), drawWidth, drawHeight, scale);
+
+    //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.RenderMetatileXYZ", __LINE__, __WFILE__, NULL, L"MgInvalidImageSizeTooBig", NULL);
+
+    // initialize the renderer (set clipping to false so that we label
+    // the unclipped geometry)
+    auto_ptr<SE_Renderer> dr(CreateRenderer(drawWidth, drawHeight, bgColor, false, true, tileExtentOffset));
+
+    // 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);
+
+    // call the internal helper API to do all the stylization overhead work
+    STRING format = (metaTilingFactor > 1) ? MgImageFormats::Meta : tileImageFormat;
+    Ptr<MgByteReader> tile = RenderMapInternal(map, NULL, roLayers, dr.get(), drawWidth, drawHeight, width, height, format, scale, extent, true, true, false, NULL);
+    ret = new MgMetatile(tile, drawWidth, drawHeight, XYZ_TILE_WIDTH, XYZ_TILE_HEIGHT, tileImageFormat, metaTilingFactor);
+
+    // restore the base group's visibility
+    baseGroup->SetVisible(groupVisible);
+
+    MG_CATCH_AND_THROW(L"MgServerRenderingService.RenderMetatileXYZ")
+
+    return ret.Detach();
 }
\ No newline at end of file

Modified: sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.h
===================================================================
--- sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.h	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.h	2019-04-25 10:09:05 UTC (rev 9496)
@@ -273,6 +273,16 @@
                                        double tileExtentOffset,
                                        INT32 metaTilingFactor);
 
+    virtual MgMetatile* RenderMetatileXYZ(MgMap* map,
+                                          CREFSTRING baseMapLayerGroupName,
+                                          INT32 x,
+                                          INT32 y,
+                                          INT32 z,
+                                          INT32 dpi,
+                                          CREFSTRING tileImageFormat,
+                                          double tileExtentOffset,
+                                          INT32 metaTilingFactor);
+
     MgByteReader* RenderTileFromMetaTile(MgMap* map, MgMetatile* metaTile, INT32 subTileX, INT32 subTileY);
 
 private:

Modified: sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.vcxproj
===================================================================
--- sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.vcxproj	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.vcxproj	2019-04-25 10:09:05 UTC (rev 9496)
@@ -234,6 +234,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="OpRenderMetatileXYZ.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="OpRenderTile.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -303,6 +309,7 @@
     <ClInclude Include="OpRenderMap.h" />
     <ClInclude Include="OpRenderMapLegend.h" />
     <ClInclude Include="OpRenderMetatile.h" />
+    <ClInclude Include="OpRenderMetatileXYZ.h" />
     <ClInclude Include="OpRenderTile.h" />
     <ClInclude Include="OpRenderTileXYZ.h" />
     <ClInclude Include="OpRenderTileUTFGrid.h" />

Modified: sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.vcxproj.filters
===================================================================
--- sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.vcxproj.filters	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Server/src/Services/Rendering/ServerRenderingService.vcxproj.filters	2019-04-25 10:09:05 UTC (rev 9496)
@@ -45,6 +45,9 @@
     <ClCompile Include="OpRenderMetatile.cpp">
       <Filter>Ops</Filter>
     </ClCompile>
+    <ClCompile Include="OpRenderMetatileXYZ.cpp">
+      <Filter>Ops</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="OpQueryFeatureProperties.h">
@@ -86,6 +89,9 @@
     <ClInclude Include="OpRenderMetatile.h">
       <Filter>Ops</Filter>
     </ClInclude>
+    <ClInclude Include="OpRenderMetatileXYZ.h">
+      <Filter>Ops</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ServerRenderingService.rc" />

Modified: sandbox/jng/tiling_v2/Server/src/UnitTesting/TestRenderingService.cpp
===================================================================
--- sandbox/jng/tiling_v2/Server/src/UnitTesting/TestRenderingService.cpp	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Server/src/UnitTesting/TestRenderingService.cpp	2019-04-25 10:09:05 UTC (rev 9496)
@@ -1762,6 +1762,51 @@
     }
 }
 
+void TestRenderingService::TestCase_RenderXYZMetatile(CREFSTRING imageFormat, CREFSTRING extension)
+{
+    try
+    {
+        Ptr<MgMap> map = CreateTestTiledMap();
+        map->SetViewScale(12500.0);
+        Ptr<MgByteReader> tile_16798_23891_baseline = m_svcRendering->RenderTileXYZ(map, L"BaseLayers", 16798, 23891, 16, MgTileParameters::tileDPI, imageFormat);
+        Ptr<MgByteReader> tile_16799_23891_baseline = m_svcRendering->RenderTileXYZ(map, L"BaseLayers", 16799, 23891, 16, MgTileParameters::tileDPI, imageFormat);
+        Ptr<MgByteReader> tile_16798_23892_baseline = m_svcRendering->RenderTileXYZ(map, L"BaseLayers", 16798, 23892, 16, MgTileParameters::tileDPI, imageFormat);
+        Ptr<MgByteReader> tile_16799_23892_baseline = m_svcRendering->RenderTileXYZ(map, L"BaseLayers", 16799, 23892, 16, MgTileParameters::tileDPI, imageFormat);
+
+        tile_16798_23891_baseline->ToFile(GetPath(L"../UnitTestFiles/RenderTileXYZ_16798_23891_16_Baseline", imageFormat, extension));
+        tile_16799_23891_baseline->ToFile(GetPath(L"../UnitTestFiles/RenderTileXYZ_16799_23891_16_Baseline", imageFormat, extension));
+        tile_16798_23892_baseline->ToFile(GetPath(L"../UnitTestFiles/RenderTileXYZ_16798_23892_16_Baseline", imageFormat, extension));
+        tile_16799_23892_baseline->ToFile(GetPath(L"../UnitTestFiles/RenderTileXYZ_16799_23892_16_Baseline", imageFormat, extension));
+
+        //This should be a server impl
+        MgServerRenderingService* renderSvc = dynamic_cast<MgServerRenderingService*>(m_svcRendering.p);
+        CPPUNIT_ASSERT(NULL != renderSvc);
+
+        // Render a 2x2 metatile which should cover the same tiles as the baseline test.
+        INT32 metaTileFactor = 2;
+        Ptr<MgMetatile> metaTile = renderSvc->RenderMetatileXYZ(map, L"BaseLayers", 16798, 23891, 16, MgTileParameters::tileDPI, imageFormat, MgConfigProperties::DefaultRenderingServicePropertyTileExtentOffset, metaTileFactor);
+        //metaTile->ToFile(L"../UnitTestFiles/RenderTileXYZ_Metatile at 16798_23891_16.png");
+        //CPPUNIT_ASSERT(metaTile->IsRewindable());
+        //metaTile->Rewind();
+
+        Ptr<MgByteReader> tile_16798_23891 = renderSvc->RenderTileFromMetaTile(map, metaTile, 0, 0);
+        Ptr<MgByteReader> tile_16799_23891 = renderSvc->RenderTileFromMetaTile(map, metaTile, 1, 0);
+        Ptr<MgByteReader> tile_16798_23892 = renderSvc->RenderTileFromMetaTile(map, metaTile, 0, 1);
+        Ptr<MgByteReader> tile_16799_23892 = renderSvc->RenderTileFromMetaTile(map, metaTile, 1, 1);
+
+        tile_16798_23891->ToFile(GetPath(L"../UnitTestFiles/RenderTileXYZ_16798_23891_16_Metatiled", imageFormat, extension));
+        tile_16799_23891->ToFile(GetPath(L"../UnitTestFiles/RenderTileXYZ_16799_23891_16_Metatiled", imageFormat, extension));
+        tile_16798_23892->ToFile(GetPath(L"../UnitTestFiles/RenderTileXYZ_16798_23892_16_Metatiled", imageFormat, extension));
+        tile_16799_23892->ToFile(GetPath(L"../UnitTestFiles/RenderTileXYZ_16799_23892_16_Metatiled", imageFormat, extension));
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+}
+
 void TestRenderingService::TestCase_RenderTile(CREFSTRING imageFormat, CREFSTRING extension)
 {
     try

Modified: sandbox/jng/tiling_v2/Server/src/UnitTesting/TestRenderingService.h
===================================================================
--- sandbox/jng/tiling_v2/Server/src/UnitTesting/TestRenderingService.h	2019-04-25 07:15:43 UTC (rev 9495)
+++ sandbox/jng/tiling_v2/Server/src/UnitTesting/TestRenderingService.h	2019-04-25 10:09:05 UTC (rev 9496)
@@ -25,6 +25,11 @@
     CPPUNIT_TEST_SUITE(TestRenderingService);
     CPPUNIT_TEST(TestStart); // This must be the very first unit test
 
+    CPPUNIT_TEST(TestCase_RenderXYZMetatilePNG);
+    CPPUNIT_TEST(TestCase_RenderXYZMetatilePNG8);
+    CPPUNIT_TEST(TestCase_RenderXYZMetatileJPG);
+    CPPUNIT_TEST(TestCase_RenderXYZMetatileGIF);
+    
     CPPUNIT_TEST(TestCase_RenderMetatilePNG);
     CPPUNIT_TEST(TestCase_RenderMetatilePNG8);
     CPPUNIT_TEST(TestCase_RenderMetatileJPG);
@@ -164,6 +169,7 @@
 
     void TestCase_QueryFeatures();
     void TestCase_RenderMetatile(CREFSTRING imageFormat, CREFSTRING extension);
+    void TestCase_RenderXYZMetatile(CREFSTRING imageFormat, CREFSTRING extension);
     void TestCase_RenderTile(CREFSTRING imageFormat, CREFSTRING extension);
     void TestCase_RenderTileXYZ(CREFSTRING imageFormat, CREFSTRING extension);
 
@@ -312,6 +318,11 @@
     void TestCase_RenderMetatileJPG() { TestCase_RenderMetatile(L"JPG", L"jpg"); }
     void TestCase_RenderMetatileGIF() { TestCase_RenderMetatile(L"GIF", L"gif"); }
 
+    void TestCase_RenderXYZMetatilePNG() { TestCase_RenderXYZMetatile(L"PNG", L"png"); }
+    void TestCase_RenderXYZMetatilePNG8() { TestCase_RenderXYZMetatile(L"PNG8", L"png"); }
+    void TestCase_RenderXYZMetatileJPG() { TestCase_RenderXYZMetatile(L"JPG", L"jpg"); }
+    void TestCase_RenderXYZMetatileGIF() { TestCase_RenderXYZMetatile(L"GIF", L"gif"); }
+
 private:
     MgMap* CreateTestMap();
     MgMap* CreateTestTiledMap();



More information about the mapguide-commits mailing list