[mapguide-commits] r9607 - sandbox/jng/mvt_alt/Common/Renderers

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Sat Sep 21 12:45:09 PDT 2019


Author: jng
Date: 2019-09-21 12:45:09 -0700 (Sat, 21 Sep 2019)
New Revision: 9607

Added:
   sandbox/jng/mvt_alt/Common/Renderers/MVTRenderer.cpp
   sandbox/jng/mvt_alt/Common/Renderers/MVTRenderer.h
Modified:
   sandbox/jng/mvt_alt/Common/Renderers/Renderers.vcxproj
   sandbox/jng/mvt_alt/Common/Renderers/Renderers.vcxproj.filters
Log:
Add MVTRenderer from original mvt sandbox. Modify it to use the MVTTile and friends instead of vtzero.

Added: sandbox/jng/mvt_alt/Common/Renderers/MVTRenderer.cpp
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/MVTRenderer.cpp	                        (rev 0)
+++ sandbox/jng/mvt_alt/Common/Renderers/MVTRenderer.cpp	2019-09-21 19:45:09 UTC (rev 9607)
@@ -0,0 +1,836 @@
+//
+//  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 "MVTRenderer.h"
+#include "RS_FeatureReader.h"
+#include "UnicodeString.h"
+#include "mvt/gpb.h"
+#include "mvt/mvt_tile.h"
+
+// =========================== MVTRenderer overview =============================== //
+//
+// MVTRenderer is really just an adapter to connect our Stylizer to MVTTile
+//
+// So the responsibility of MVTRenderer is simply to:
+//
+//  - Create a new MVTTileLayer instance on every StartLayer(). Push any 
+//    current instance to the internal list for cleanup
+//  - Stash the RS_FeatureReader pointer on every StartFeature() call (we need this for writing properties)
+//  - For every ProcessXXX() call
+//    - Create a MVTTileLayerFeature instance
+//    - Write the line buffer coordinates to this builder
+//    - Write the active property map
+//    - Commit the builder
+//
+// ================================================================================ //
+
+static unsigned GetCmdCountCombined(unsigned int nCmdId,
+    unsigned int nCmdCount)
+{
+    return (nCmdId | (nCmdCount << 3));
+}
+
+
+struct MVTRenderer::MVTImpl {
+    MVTImpl(MVTRenderer* parent, int x, int y, int z)
+        : m_activeLayer(nullptr)
+        , m_nExtent(knDEFAULT_EXTENT)
+        , m_tileX(x)
+        , m_tileY(y)
+        , m_tileZ(z)
+        , m_dfTopX(0.0)
+        , m_dfTopY(0.0)
+        , m_dfTileDim0(0.0)
+        , m_parent(parent)
+    { }
+
+    ~MVTImpl()
+    {
+
+    }
+
+    void SetActiveLayerBuilder(const std::string& name)
+    {
+        m_activeLayer = new MVTTileLayer();
+        m_activeLayer->setName(name);
+    }
+
+    void ClearActiveLayerBuilder()
+    {
+        m_prevLayers.push_back(m_activeLayer);
+        m_activeLayer = nullptr;
+    }
+
+    void ConvertToTileCoords(double dfX,
+        double dfY,
+        int& nX,
+        int& nY,
+        double dfTopX,
+        double dfTopY,
+        double dfTileDim) const
+    {
+        nX = static_cast<int>(std::round((dfX - dfTopX) * m_nExtent / dfTileDim));
+        nY = static_cast<int>(std::round((dfTopY - dfY) * m_nExtent / dfTileDim));
+    }
+
+    static void AddActiveFeatureProperties(RS_FeatureReader* activeFeature, MVTTileLayer* layer, MVTTileLayerFeature* feature)
+    {
+        TrySetFeatureId(feature, activeFeature);
+
+        int count;
+        auto propNames = activeFeature->GetPropNames(count);
+        for (int i = 0; i < count; i++)
+        {
+            auto name = propNames[i];
+            if (activeFeature->IsNull(name))
+            {
+                continue;
+            }
+
+            MVTTileLayerValue tv;
+
+            std::string mbName;
+            UnicodeString::WideCharToMultiByte(name, mbName);
+            auto propType = activeFeature->GetPropertyType(name);
+            switch (propType)
+            {
+            case FdoDataType_Boolean:
+                tv.setBoolValue(activeFeature->GetBoolean(name));
+                break;
+            case FdoDataType_Byte:
+                tv.setIntValue(activeFeature->GetByte(name));
+                break;
+            case FdoDataType_DateTime:
+            {
+                auto dt = activeFeature->GetAsString(name);
+                std::string sDt;
+                UnicodeString::WideCharToMultiByte(dt, sDt);
+                tv.setStringValue(sDt);
+                break;
+            }
+            case FdoDataType_Decimal:
+            case FdoDataType_Double:
+                tv.setDoubleValue(activeFeature->GetDouble(name));
+                break;
+            case FdoDataType_Int16:
+                tv.setIntValue(activeFeature->GetInt16(name));
+                break;
+            case FdoDataType_Int32:
+                tv.setIntValue(activeFeature->GetInt32(name));
+                break;
+            case FdoDataType_Int64:
+                tv.setIntValue(activeFeature->GetInt64(name));
+                break;
+            case FdoDataType_Single:
+                tv.setFloatValue(activeFeature->GetSingle(name));
+                break;
+            case FdoDataType_String:
+            {
+                auto s = activeFeature->GetString(name);
+                std::string sVal;
+                UnicodeString::WideCharToMultiByte(s, sVal);
+                tv.setStringValue(sVal);
+                break;
+            }
+            case FdoDataType_BLOB: //Not handled
+            case FdoDataType_CLOB:
+                break;
+            }
+
+            auto nKey = layer->addKey(mbName);
+            auto nVal = layer->addValue(tv);
+            feature->addTag(nKey);
+            feature->addTag(nVal);
+        }
+    }
+
+    static void TrySetFeatureId(MVTTileLayerFeature* feature, RS_FeatureReader* activeFeature)
+    {
+        int count = 0;
+        auto idPropNames = activeFeature->GetIdentPropNames(count);
+        if (count == 1)
+        {
+            auto idName = idPropNames[0];
+            auto ptype = activeFeature->GetPropertyType(idName);
+            switch (ptype)
+            {
+            case FdoDataType_Byte:
+                feature->setId(activeFeature->GetByte(idName));
+                break;
+            case FdoDataType_Int16:
+                feature->setId(activeFeature->GetInt16(idName));
+                break;
+            case FdoDataType_Int32:
+                feature->setId(activeFeature->GetInt32(idName));
+                break;
+            case FdoDataType_Int64:
+                feature->setId(activeFeature->GetInt64(idName));
+                break;
+            }
+        }
+    }
+
+    bool EncodePolygonGeometry(MVTTileLayerFeature* poGPBFeature,
+                               LineBuffer* lb,
+                               int polyIdx,
+                               double dfTopX,
+                               double dfTopY,
+                               double dfTileDim,
+                               bool bCanRecurse,
+                               int& nLastX,
+                               int& nLastY) const
+    {
+        return false;
+    }
+
+    bool EncodePolygon(MVTTileLayerFeature* feature, LineBuffer* lb)
+    {
+        double dfTileDim = m_dfTileDim0 / (1 << m_tileZ);
+        double dfTopX = m_dfTopX + m_tileX * dfTileDim;
+        double dfTopY = m_dfTopY - m_tileY * dfTileDim;
+        int nLastX = 0;
+        int nLastY = 0;
+        bool bGeomOK = false;
+
+        //TODO: Can probably fold everything into the MultiPolygon code path here
+        if (lb->cntr_count() == 1)
+        {
+            bGeomOK = EncodePolygonGeometry(feature, lb, 0,
+                dfTopX, dfTopY, dfTileDim,
+                true,
+                nLastX, nLastY);
+        }
+        else //MultiPolygon
+        {
+            for (int i = 0; i < lb->cntr_count(); i++)
+            {
+                bGeomOK |= EncodePolygonGeometry(feature, lb, i,
+                    dfTopX, dfTopY, dfTileDim,
+                    true,
+                    nLastX, nLastY);
+            }
+        }
+
+        return bGeomOK;
+    }
+
+    void ProcessPolygon(RS_FeatureReader* activeFeature, LineBuffer * lb)
+    {
+        auto feature = std::make_shared<MVTTileLayerFeature>();
+        feature->setType(MVTTileLayerFeature::GeomType::POLYGON);
+        AddActiveFeatureProperties(activeFeature, m_activeLayer, feature.get());
+        EncodePolygon(feature.get(), lb);
+        m_activeLayer->addFeature(feature);
+    }
+
+    bool EncodeLineStringGeometry(MVTTileLayerFeature* poGPBFeature,
+                                  LineBuffer* lb,
+                                  int lineStrIdx,
+                                  bool bWriteLastPoint,
+                                  bool bReverseOrder,
+                                  GUInt32 nMinLineTo,
+                                  double dfTopX,
+                                  double dfTopY,
+                                  double dfTileDim,
+                                  int& nLastX,
+                                  int& nLastY) const
+    {
+        const GUInt32 nInitialSize = poGPBFeature->getGeometryCount();
+        const int nLastXOri = nLastX;
+        const int nLastYOri = nLastY;
+        GUInt32 nLineToCount = 0;
+        const int nPoints = lb->cntr_size(lineStrIdx) - (bWriteLastPoint ? 0 : 1);
+        int nFirstX = 0;
+        int nFirstY = 0;
+        int nLastXValid = nLastX;
+        int nLastYValid = nLastY;
+        auto pointOffset = lb->contour_start_point(lineStrIdx);
+        for (int i = 0; i < nPoints; i++)
+        {
+            int nX, nY;
+            int nSrcIdx = bReverseOrder ? lb->cntr_size(lineStrIdx) - 1 - i : i;
+            double dfX = lb->x_coord(nSrcIdx + pointOffset);
+            double dfY = lb->y_coord(nSrcIdx + pointOffset);
+
+            ConvertToTileCoords(dfX, dfY, nX, nY,
+                dfTopX, dfTopY, dfTileDim);
+            int nDiffX = nX - nLastX;
+            int nDiffY = nY - nLastY;
+            if (i == 0 || nDiffX != 0 || nDiffY != 0)
+            {
+                if (i > 0)
+                {
+                    nLineToCount++;
+                    if (nLineToCount == 1)
+                    {
+                        poGPBFeature->addGeometry(
+                            GetCmdCountCombined(knCMD_MOVETO, 1));
+                        const int nLastDiffX = nLastX - nLastXOri;
+                        const int nLastDiffY = nLastY - nLastYOri;
+                        poGPBFeature->addGeometry(EncodeSInt(nLastDiffX));
+                        poGPBFeature->addGeometry(EncodeSInt(nLastDiffY));
+                        
+                        // To be modified later
+                        poGPBFeature->addGeometry(
+                            GetCmdCountCombined(knCMD_LINETO, 0));
+                    }
+
+                    poGPBFeature->addGeometry(EncodeSInt(nDiffX));
+                    poGPBFeature->addGeometry(EncodeSInt(nDiffY));
+                }
+                else
+                {
+                    nFirstX = nX;
+                    nFirstY = nY;
+                }
+                nLastXValid = nLastX;
+                nLastYValid = nLastY;
+                nLastX = nX;
+                nLastY = nY;
+            }
+        }
+
+        // If last point of ring is identical to first one, discard it
+        if (nMinLineTo == 2 && nLineToCount > 0 &&
+            nFirstX == nLastX && nFirstY == nLastY)
+        {
+            poGPBFeature->resizeGeometryArray(
+                poGPBFeature->getGeometryCount() - 2);
+            nLineToCount--;
+            nLastX = nLastXValid;
+            nLastY = nLastYValid;
+        }
+
+        if (nLineToCount >= nMinLineTo)
+        {
+            // Patch actual number of points in LINETO command
+            poGPBFeature->setGeometry(nInitialSize + 3,
+                GetCmdCountCombined(knCMD_LINETO, nLineToCount));
+            return true;
+        }
+        else
+        {
+            poGPBFeature->resizeGeometryArray(nInitialSize);
+            nLastX = nLastXOri;
+            nLastY = nLastYOri;
+            return false;
+        }
+    }
+
+    bool EncodePolyine(MVTTileLayerFeature* feature, LineBuffer* lb)
+    {
+        double dfTileDim = m_dfTileDim0 / (1 << m_tileZ);
+        double dfTopX = m_dfTopX + m_tileX * dfTileDim;
+        double dfTopY = m_dfTopY - m_tileY * dfTileDim;
+        bool bGeomOK = false;
+        const bool bWriteLastPoint = true;
+        const bool bReverseOrder = false;
+        const GUInt32 nMinLineTo = 1;
+        int nLastX = 0;
+        int nLastY = 0;
+        //TODO: Can probably fold everything into the MultiLineString code path here
+        if (lb->cntr_count() == 1)
+        {
+            bGeomOK = EncodeLineStringGeometry(feature, lb, 0,
+                bWriteLastPoint, bReverseOrder,
+                nMinLineTo,
+                dfTopX, dfTopY, dfTileDim,
+                nLastX, nLastY);
+        }
+        else //MultiLineString
+        {
+            for (auto i = 0; i < lb->cntr_count(); i++)
+            {
+                bool bSubGeomOK = EncodeLineStringGeometry(
+                    feature, lb, i,
+                    bWriteLastPoint, bReverseOrder,
+                    nMinLineTo,
+                    dfTopX, dfTopY, dfTileDim,
+                    nLastX, nLastY);
+                bGeomOK |= bSubGeomOK;
+            }
+        }
+        return bGeomOK;
+    }
+
+    void ProcessPolyline(RS_FeatureReader* activeFeature, LineBuffer * lb)
+    {
+        auto feature = std::make_shared<MVTTileLayerFeature>();
+        feature->setType(MVTTileLayerFeature::GeomType::LINESTRING);
+        AddActiveFeatureProperties(activeFeature, m_activeLayer, feature.get());
+        EncodePolyine(feature.get(), lb);
+        m_activeLayer->addFeature(feature);
+    }
+
+    bool EncodePoint(MVTTileLayerFeature* feature, LineBuffer* lb)
+    {
+        double dfTileDim = m_dfTileDim0 / (1 << m_tileZ);
+        double dfTopX = m_dfTopX + m_tileX * dfTileDim;
+        double dfTopY = m_dfTopY - m_tileY * dfTileDim;
+
+        bool bGeomOK = false;
+        if (lb->point_count() == 1)
+        {
+            int nX, nY;
+            auto dfX = lb->x_coord(0);
+            auto dfY = lb->y_coord(0);
+            bGeomOK = true;
+            ConvertToTileCoords(dfX, dfY, nX, nY, dfTopX, dfTopY, dfTileDim);
+
+            feature->addGeometry(GetCmdCountCombined(knCMD_MOVETO, 1));
+            feature->addGeometry(EncodeSInt(nX));
+            feature->addGeometry(EncodeSInt(nY));
+        }
+        else //MultiPoint
+        {
+            std::set<std::pair<int, int>> oSetUniqueCoords;
+            feature->addGeometry(GetCmdCountCombined(knCMD_MOVETO, 0)); // To be modified later
+            int nLastX = 0;
+            int nLastY = 0;
+            for (auto i = 0; i < lb->point_count(); i++)
+            {
+                int nX, nY;
+                auto dfX = lb->x_coord(i);
+                auto dfY = lb->y_coord(i);
+                ConvertToTileCoords(dfX, dfY, nX, nY, dfTopX, dfTopY, dfTileDim);
+                if (oSetUniqueCoords.find(std::pair<int, int>(nX, nY)) ==
+                    oSetUniqueCoords.end())
+                {
+                    oSetUniqueCoords.insert(std::pair<int, int>(nX, nY));
+
+                    int nDiffX = nX - nLastX;
+                    int nDiffY = nY - nLastY;
+                    feature->addGeometry(EncodeSInt(nDiffX));
+                    feature->addGeometry(EncodeSInt(nDiffY));
+                    nLastX = nX;
+                    nLastY = nY;
+                }
+            }
+            GUInt32 nPoints = static_cast<GUInt32>(oSetUniqueCoords.size());
+            bGeomOK = nPoints > 0;
+            feature->setGeometry(0, GetCmdCountCombined(knCMD_MOVETO, nPoints));
+        }
+        return bGeomOK;
+    }
+
+    void ProcessMarker(RS_FeatureReader* activeFeature, LineBuffer * lb)
+    {
+        auto feature = std::make_shared<MVTTileLayerFeature>();
+        feature->setType(MVTTileLayerFeature::GeomType::POINT);
+        AddActiveFeatureProperties(activeFeature, m_activeLayer, feature.get());
+        EncodePoint(feature.get(), lb);
+        m_activeLayer->addFeature(feature);
+    }
+
+    unsigned char* GetMVTContent()
+    {
+        auto size = m_tile.getSize();
+        GByte* pabyBuffer = new GByte[size];
+        m_tile.write(pabyBuffer);
+        return pabyBuffer;
+    }
+
+    void ReleaseMVTContent(unsigned char* buf)
+    {
+        delete[] buf;
+    }
+
+    void SetTileCoords(const int x, const int y, const int z)
+    {
+        m_tileX = x;
+        m_tileY = y;
+        m_tileZ = z;
+    }
+
+private:
+    MVTTile m_tile;
+    MVTTileLayer* m_activeLayer;
+    std::vector<MVTTileLayer*> m_prevLayers;
+    MVTRenderer* m_parent;
+
+    int m_tileX;
+    int m_tileY;
+    int m_tileZ;
+
+    double m_dfTopX;
+    double m_dfTopY;
+    double m_dfTileDim0;
+
+    unsigned int m_nExtent;
+};
+
+MVTRenderer::MVTRenderer(int x, int y, int z)
+    : m_impl(new MVTRenderer::MVTImpl(this, x, y, z)) //MVTImpl only stashes this pointer in its ctor, nothing is called on it yet
+    , m_mapInfo(nullptr)
+    , m_layerInfo(nullptr)
+    , m_fcInfo(nullptr)
+{
+
+}
+
+MVTRenderer::~MVTRenderer()
+{ }
+
+//Called by the stylizer when rendering is about to begin on the map
+void MVTRenderer::StartMap(RS_MapUIInfo * /*mapInfo*/, RS_Bounds & extents, double mapScale, double dpi, double metersPerUnit, CSysTransformer * /*xformToLL*/)
+{
+    m_mapScale = mapScale;
+    m_dpi = dpi;
+    m_metersPerUnit = metersPerUnit;
+    m_extents = extents;
+
+    // find scale used to convert to pixel coordinates
+    // need to take aspect ratios into account
+    /*
+    double arDisplay = (double)m_width / (double)m_height;
+    double arMap = m_extents.width() / m_extents.height();
+
+    double scale;
+    if (arDisplay > arMap)
+        scale = (double)m_height / m_extents.height();
+    else
+    */    
+    double wScale = (double)m_width / m_extents.width();
+    double hScale = (double)m_height / m_extents.height();
+
+    m_xform.x0 = wScale;
+    m_xform.x1 = 0.0;
+    m_xform.x2 = -wScale * m_extents.minx;
+    m_xform.y0 = 0.0;
+    m_xform.y1 = hScale;
+    m_xform.y2 = -hScale * m_extents.miny;
+
+    m_ixform.x0 = 1.0 / wScale;
+    m_ixform.x1 = 0.0;
+    m_ixform.x2 = m_extents.minx;
+    m_ixform.y0 = 0.0;
+    m_ixform.y1 = m_ixform.x0;
+    m_ixform.y2 = m_extents.miny;
+
+    double metersPerPixel = METERS_PER_INCH / m_dpi;
+
+    // compute drawing scale
+    // drawing scale is map scale converted to [mapping units] / [pixels]
+    m_drawingScale = m_mapScale * metersPerPixel / m_metersPerUnit;
+}
+
+//Called by the stylizer when rendering is about to begin on the map
+void MVTRenderer::EndMap()
+{
+    // clear the map info
+    m_mapInfo = nullptr;
+}
+
+//Called by the stylizer when rendering is about to begin on the map for the given layer
+void MVTRenderer::StartLayer(RS_LayerUIInfo * layerInfo, RS_FeatureClassInfo * classInfo)
+{
+    m_layerInfo = layerInfo;
+    m_fcInfo = classInfo;
+
+    std::string name;
+    UnicodeString::WideCharToMultiByte(m_layerInfo->name().c_str(), name);
+
+    m_impl->SetActiveLayerBuilder(name);
+}
+
+//Called by the stylizer when rendering is about to begin on the map for the layer indicated by StartLayer()
+void MVTRenderer::EndLayer()
+{
+    // clear the layer/feature info
+    m_layerInfo = nullptr;
+    m_fcInfo = nullptr;
+
+    m_impl->ClearActiveLayerBuilder();
+}
+
+//Called by the stylizer when rendering is about to begin on the map for the given feature
+void MVTRenderer::StartFeature(RS_FeatureReader * feature, bool /*initialPass*/, const RS_String * /*tooltip*/, const RS_String * /*url*/, const RS_String * /*theme*/, double /*zOffset*/, double /*zExtrusion*/, RS_ElevationType /*zOffsetType*/)
+{
+    m_activeFeature = feature;
+}
+
+//Entry point for polygon rendering. Perform any pre-rendering operations.
+void MVTRenderer::ProcessPolygon(LineBuffer * lb, RS_FillStyle & /*fill*/)
+{
+    //Optimize LB before sending to MVT tile writer
+    auto workbuffer = lb->Optimize(m_drawingScale, m_pPool);
+    std::unique_ptr<LineBuffer> spLB(workbuffer);
+
+    //Also clip the geometry to the extents if required as we do not want to encode
+    //"out of tile" coordinates
+    auto clipped = workbuffer->Clip(m_extents, LineBuffer::ctArea, m_pPool);
+    if (workbuffer != clipped)
+    {
+        if (spLB.get())
+        {
+            LineBufferPool::FreeLineBuffer(m_pPool, spLB.release());
+        }
+
+        workbuffer = clipped;
+        spLB.reset(workbuffer);
+    }
+
+    if (workbuffer)
+        m_impl->ProcessPolygon(m_activeFeature, workbuffer);
+
+    if (spLB.get())
+        LineBufferPool::FreeLineBuffer(m_pPool, spLB.release());
+}
+
+//Entry point for polyline rendering. Perform any pre-rendering operations.
+void MVTRenderer::ProcessPolyline(LineBuffer * lb, RS_LineStroke & /*lsym*/)
+{
+    //Optimize LB before sending to MVT tile writer
+    auto workbuffer = lb->Optimize(m_drawingScale, m_pPool);
+    std::unique_ptr<LineBuffer> spLB(workbuffer);
+
+    //Also clip the geometry to the extents if required as we do not want to encode
+    //"out of tile" coordinates
+    auto clipped = workbuffer->Clip(m_extents, LineBuffer::ctLine, m_pPool);
+    if (workbuffer != clipped)
+    {
+        if (spLB.get())
+        {
+            LineBufferPool::FreeLineBuffer(m_pPool, spLB.release());
+        }
+
+        workbuffer = clipped;
+        spLB.reset(workbuffer);
+    }
+
+    if (workbuffer)
+        m_impl->ProcessPolyline(m_activeFeature, workbuffer);
+
+    if (spLB.get())
+        LineBufferPool::FreeLineBuffer(m_pPool, spLB.release());
+}
+
+//Entry point for raster/image rendering. Perform any pre-rendering operations.
+void MVTRenderer::ProcessRaster(unsigned char * /*data*/, int /*length*/, RS_ImageFormat /*format*/, int /*width*/, int /*height*/, RS_Bounds & /*extents*/, TransformMesh * /*xformMesh*/)
+{
+    //This will generally result in a call to DrawScreenRaster() after processing.
+    //
+    //If your renderer only concerns vector data, this method can be left blank
+}
+
+//Entry point for marker rendering. Perform any pre-rendering operations.
+void MVTRenderer::ProcessMarker(LineBuffer * lb, RS_MarkerDef & /*mdef*/, bool /*allowOverpost*/, RS_Bounds * /*bounds*/)
+{
+    //vtzero is very finicky about redundant coordinates, so feed vtzero an optimized LineBuffer
+    //that should weed such coordinates out
+    auto workbuffer = lb->Optimize(m_drawingScale, m_pPool);
+    std::unique_ptr<LineBuffer> spLB(workbuffer);
+
+    //Also clip the geometry to the extents if required as we do not want to encode
+    //"out of tile" coordinates
+    auto clipped = workbuffer->Clip(m_extents, LineBuffer::ctPoint, m_pPool);
+    if (workbuffer != clipped)
+    {
+        if (spLB.get())
+        {
+            LineBufferPool::FreeLineBuffer(m_pPool, spLB.release());
+        }
+
+        workbuffer = clipped;
+        spLB.reset(workbuffer);
+    }
+
+    if (workbuffer)
+        m_impl->ProcessMarker(m_activeFeature, workbuffer);
+
+    if (spLB.get())
+        LineBufferPool::FreeLineBuffer(m_pPool, spLB.release());
+}
+
+//Entry point for label group rendering.
+void MVTRenderer::ProcessLabelGroup(RS_LabelInfo * /*labels*/, int /*nlabels*/, const RS_String & /*text*/, RS_OverpostType /*type*/, bool /*exclude*/, LineBuffer * /*path*/, double /*scaleLimit*/)
+{
+    //Most implementations will carry a LabelRenderer member and forward this method call
+    //to it.
+    //
+    //If your renderer does not render labels, this method can be left blank
+}
+
+// Inserts the contents of a given DWF input stream into the current
+// output W2D.  The given coord sys transformation is applied and geometry
+// will be clipped to the RS_Bounds context of the DWFRenderer.
+void MVTRenderer::AddDWFContent(RS_InputStream * /*in*/, CSysTransformer * /*xformer*/, const RS_String & /*section*/, const RS_String & /*passwd*/, const RS_String & /*w2dfilter*/)
+{
+    // This is data from a DWF drawing layer. If your renderer is not intended to support DWF
+    // drawing layers/sources, this method can be left blank.
+}
+
+//Sets the legacy symbol manager which will be used when fetching (DWF) symbol data
+void MVTRenderer::SetSymbolManager(RS_SymbolManager * /*manager*/)
+{
+    //If your renderer does not render DWF-based image symbols, this method can be left blank
+}
+
+RS_MapUIInfo * MVTRenderer::GetMapInfo()
+{
+    return m_mapInfo;
+}
+
+RS_LayerUIInfo * MVTRenderer::GetLayerInfo()
+{
+    return m_layerInfo;
+}
+
+RS_FeatureClassInfo * MVTRenderer::GetFeatureClassInfo()
+{
+    return m_fcInfo;
+}
+
+double MVTRenderer::GetMapScale()
+{
+    return m_mapScale;
+}
+
+double MVTRenderer::GetDrawingScale()
+{
+    return m_drawingScale;
+}
+
+double MVTRenderer::GetMetersPerUnit()
+{
+    return m_metersPerUnit;
+}
+
+double MVTRenderer::GetDpi()
+{
+    return m_dpi;
+}
+
+RS_Bounds & MVTRenderer::GetBounds()
+{
+    return m_extents;
+}
+
+bool MVTRenderer::RequiresClipping()
+{
+    return false;
+}
+
+bool MVTRenderer::RequiresLabelClipping()
+{
+    return false;
+}
+
+//Return true if this renderer can handle 3D geometries
+bool MVTRenderer::SupportsZ()
+{
+    return false;
+}
+
+//Render out the given polyline using the provided fill style
+void MVTRenderer::DrawScreenPolyline(LineBuffer * /*polyline*/, const SE_Matrix * /*xform*/, const SE_LineStroke & /*lineStroke*/)
+{
+
+}
+
+//Render out the given polygon using the provided fill style
+void MVTRenderer::DrawScreenPolygon(LineBuffer * /*polygon*/, const SE_Matrix * /*xform*/, unsigned int /*fill*/)
+{
+
+}
+
+//Render out the given raster data.
+void MVTRenderer::DrawScreenRaster(unsigned char * /*data*/, int /*length*/, RS_ImageFormat /*format*/, int /*native_width*/, int /*native_height*/, double /*x*/, double /*y*/, double /*w*/, double /*h*/, double /*angleDeg*/)
+{
+    //If your renderer only concerns vector data, this method can be left blank
+}
+
+//Render out the given raster data.
+void MVTRenderer::DrawScreenRaster(unsigned char * /*data*/, int /*length*/, RS_ImageFormat /*format*/, int /*native_width*/, int /*native_height*/, double /*x*/, double /*y*/, double /*w*/, double /*h*/, double /*angleDeg*/, double /*alpha*/)
+{
+    //If your renderer only concerns vector data, this method can be left blank
+}
+
+//Render out the given text.
+void MVTRenderer::DrawScreenText(const RS_TextMetrics & /*tm*/, RS_TextDef & /*tdef*/, double /*insx*/, double /*insy*/, RS_F_Point * /*path*/, int /*npts*/, double /*param_position*/)
+{
+    //If your renderer does not render labels, this method can be left blank
+}
+
+bool MVTRenderer::YPointsUp()
+{
+    return false;
+}
+
+void MVTRenderer::GetWorldToScreenTransform(SE_Matrix & xform)
+{
+    xform = m_xform;
+}
+
+void MVTRenderer::WorldToScreenPoint(double & inx, double & iny, double & ox, double & oy)
+{
+    m_xform.transform(inx, iny, ox, oy);
+}
+
+void MVTRenderer::ScreenToWorldPoint(double & inx, double & iny, double & ox, double & oy)
+{
+    m_ixform.transform(inx, iny, ox, oy);
+}
+
+double MVTRenderer::GetScreenUnitsPerMillimeterDevice()
+{
+    return m_dpi / MILLIMETERS_PER_INCH;
+}
+
+double MVTRenderer::GetScreenUnitsPerMillimeterWorld()
+{
+    return m_dpi / MILLIMETERS_PER_INCH / m_mapScale;
+}
+
+double MVTRenderer::GetScreenUnitsPerPixel()
+{
+    return 1.0;
+}
+
+RS_FontEngine * MVTRenderer::GetRSFontEngine()
+{
+    return NULL;
+}
+
+//Entry point for label rendering.
+void MVTRenderer::ProcessSELabelGroup(SE_LabelInfo * /*labels*/, int /*nlabels*/, RS_OverpostType /*type*/, bool /*exclude*/, LineBuffer * /*path*/)
+{
+    //Most implementations will carry a LabelRenderer member and forward this method call
+    //to it.
+    //
+    //If this render does not render labels, this method can be left blank.
+}
+
+//If this renderer can render labels, add and track the given exclusion region.
+//An exclusion region is a region that should not factor into desired label/symbol placement.
+void MVTRenderer::AddExclusionRegion(RS_F_Point * /*fpts*/, int /*npts*/)
+{
+    //Most implementations will carry a LabelRenderer member and forward this method call
+    //to it.
+    //
+    //If this renderer does not render labels. This method can be left blank.
+}
+
+unsigned char* MVTRenderer::GetMVTContent()
+{
+    return m_impl->GetMVTContent();
+}
+
+void MVTRenderer::ReleaseMVTContent(unsigned char* buf)
+{
+    m_impl->ReleaseMVTContent(buf);
+}
\ No newline at end of file

Added: sandbox/jng/mvt_alt/Common/Renderers/MVTRenderer.h
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/MVTRenderer.h	                        (rev 0)
+++ sandbox/jng/mvt_alt/Common/Renderers/MVTRenderer.h	2019-09-21 19:45:09 UTC (rev 9607)
@@ -0,0 +1,102 @@
+//
+//  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 _MVTRENDERER_H_
+#define _MVTRENDERER_H_
+
+#include "Renderers.h"
+#include "SE_Renderer.h"
+#include <vector>
+
+// A renderer that produces Mapbox Vector Tiles (MVT). This renderer exclusively works
+// against an XYZ tile access scheme so it can only be used for rendering XYZ tiles and
+// no other type of rendering
+class MVTRenderer : public SE_Renderer
+{
+public:
+    RENDERERS_API MVTRenderer(int x, int y, int z);
+    RENDERERS_API virtual ~MVTRenderer();
+
+    // Inherited via SE_Renderer
+    RENDERERS_API virtual void StartMap(RS_MapUIInfo * mapInfo, RS_Bounds & extents, double mapScale, double dpi, double metersPerUnit, CSysTransformer * xformToLL);
+    RENDERERS_API virtual void EndMap();
+    RENDERERS_API virtual void StartLayer(RS_LayerUIInfo * layerInfo, RS_FeatureClassInfo * classInfo);
+    RENDERERS_API virtual void EndLayer();
+    RENDERERS_API virtual void StartFeature(RS_FeatureReader * feature, bool initialPass, const RS_String * tooltip = NULL, const RS_String * url = NULL, const RS_String * theme = NULL, double zOffset = 0.0, double zExtrusion = 0.0, RS_ElevationType zOffsetType = RS_ElevationType_RelativeToGround);
+    RENDERERS_API virtual void ProcessPolygon(LineBuffer * lb, RS_FillStyle & fill);
+    RENDERERS_API virtual void ProcessPolyline(LineBuffer * lb, RS_LineStroke & lsym);
+    RENDERERS_API virtual void ProcessRaster(unsigned char * data, int length, RS_ImageFormat format, int width, int height, RS_Bounds & extents, TransformMesh * xformMesh = NULL);
+    RENDERERS_API virtual void ProcessMarker(LineBuffer * lb, RS_MarkerDef & mdef, bool allowOverpost, RS_Bounds * bounds = NULL);
+    RENDERERS_API virtual void ProcessLabelGroup(RS_LabelInfo * labels, int nlabels, const RS_String & text, RS_OverpostType type, bool exclude, LineBuffer * path, double scaleLimit);
+    RENDERERS_API virtual void AddDWFContent(RS_InputStream * in, CSysTransformer * xformer, const RS_String & section, const RS_String & passwd, const RS_String & w2dfilter);
+    RENDERERS_API virtual void SetSymbolManager(RS_SymbolManager * manager);
+    RENDERERS_API virtual RS_MapUIInfo * GetMapInfo();
+    RENDERERS_API virtual RS_LayerUIInfo * GetLayerInfo();
+    RENDERERS_API virtual RS_FeatureClassInfo * GetFeatureClassInfo();
+    RENDERERS_API virtual double GetMapScale();
+    RENDERERS_API virtual double GetDrawingScale();
+    RENDERERS_API virtual double GetMetersPerUnit();
+    RENDERERS_API virtual double GetDpi();
+    RENDERERS_API virtual RS_Bounds & GetBounds();
+    RENDERERS_API virtual bool RequiresClipping();
+    RENDERERS_API virtual bool RequiresLabelClipping();
+    RENDERERS_API virtual bool SupportsZ();
+    RENDERERS_API virtual void DrawScreenPolyline(LineBuffer * polyline, const SE_Matrix * xform, const SE_LineStroke & lineStroke);
+    RENDERERS_API virtual void DrawScreenPolygon(LineBuffer * polygon, const SE_Matrix * xform, unsigned int fill);
+    RENDERERS_API virtual void DrawScreenRaster(unsigned char * data, int length, RS_ImageFormat format, int native_width, int native_height, double x, double y, double w, double h, double angleDeg);
+    RENDERERS_API virtual void DrawScreenRaster(unsigned char * data, int length, RS_ImageFormat format, int native_width, int native_height, double x, double y, double w, double h, double angleDeg, double alpha);
+    RENDERERS_API virtual void DrawScreenText(const RS_TextMetrics & tm, RS_TextDef & tdef, double insx, double insy, RS_F_Point * path, int npts, double param_position);
+    RENDERERS_API virtual bool YPointsUp();
+    RENDERERS_API virtual void GetWorldToScreenTransform(SE_Matrix & xform);
+    RENDERERS_API virtual void WorldToScreenPoint(double & inx, double & iny, double & ox, double & oy);
+    RENDERERS_API virtual void ScreenToWorldPoint(double & inx, double & iny, double & ox, double & oy);
+    RENDERERS_API virtual double GetScreenUnitsPerMillimeterDevice();
+    RENDERERS_API virtual double GetScreenUnitsPerMillimeterWorld();
+    RENDERERS_API virtual double GetScreenUnitsPerPixel();
+    RENDERERS_API virtual RS_FontEngine * GetRSFontEngine();
+    RENDERERS_API virtual void ProcessSELabelGroup(SE_LabelInfo * labels, int nlabels, RS_OverpostType type, bool exclude, LineBuffer * path = NULL);
+    RENDERERS_API virtual void AddExclusionRegion(RS_F_Point * fpts, int npts);
+
+    //MVT-specific. Caller responsible for calling ReleaseMVTContent() on the returned
+    //pointer once done
+    RENDERERS_API unsigned char* GetMVTContent();
+    RENDERERS_API void ReleaseMVTContent(unsigned char* buf);
+
+private:
+    struct MVTImpl;
+    std::unique_ptr<MVTImpl> m_impl;
+
+    RS_FeatureReader* m_activeFeature;
+
+    // map/layer/feature info
+    RS_MapUIInfo* m_mapInfo;
+    RS_LayerUIInfo* m_layerInfo;
+    RS_FeatureClassInfo* m_fcInfo;
+
+    SE_Matrix m_xform;
+    SE_Matrix m_ixform;
+    int m_width;
+    int m_height;
+
+    RS_Bounds m_extents;
+    double m_drawingScale;
+    double m_metersPerUnit;
+    double m_dpi;
+    double m_mapScale;
+};
+
+#endif
\ No newline at end of file

Modified: sandbox/jng/mvt_alt/Common/Renderers/Renderers.vcxproj
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/Renderers.vcxproj	2019-09-21 18:04:23 UTC (rev 9606)
+++ sandbox/jng/mvt_alt/Common/Renderers/Renderers.vcxproj	2019-09-21 19:45:09 UTC (rev 9607)
@@ -215,6 +215,7 @@
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="MapQuantization.cpp" />
+    <ClCompile Include="MVTRenderer.cpp" />
     <ClCompile Include="mvt\mvt_tile.cpp" />
     <ClCompile Include="SymbolTrans.cpp" />
     <ClCompile Include="DWFRenderer.cpp" />
@@ -260,6 +261,7 @@
     <ClInclude Include="agg_utfgrid_context.h" />
     <ClInclude Include="MapQuantization.h" />
     <ClInclude Include="MapUTFGrid.h" />
+    <ClInclude Include="MVTRenderer.h" />
     <ClInclude Include="mvt\gpb.h" />
     <ClInclude Include="mvt\mvt_port.h" />
     <ClInclude Include="mvt\mvt_tile.h" />

Modified: sandbox/jng/mvt_alt/Common/Renderers/Renderers.vcxproj.filters
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/Renderers.vcxproj.filters	2019-09-21 18:04:23 UTC (rev 9606)
+++ sandbox/jng/mvt_alt/Common/Renderers/Renderers.vcxproj.filters	2019-09-21 19:45:09 UTC (rev 9607)
@@ -117,6 +117,9 @@
     <ClCompile Include="mvt\mvt_tile.cpp">
       <Filter>MVTRenderer</Filter>
     </ClCompile>
+    <ClCompile Include="MVTRenderer.cpp">
+      <Filter>MVTRenderer</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="SymbolTrans.h">
@@ -217,6 +220,9 @@
     <ClInclude Include="mvt\mvt_port.h">
       <Filter>MVTRenderer</Filter>
     </ClInclude>
+    <ClInclude Include="MVTRenderer.h">
+      <Filter>MVTRenderer</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Renderers.rc" />



More information about the mapguide-commits mailing list