[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