[mapguide-commits] r9605 - in sandbox/jng/mvt_alt/Common/Renderers: . mvt
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Sat Sep 21 10:25:41 PDT 2019
Author: jng
Date: 2019-09-21 10:25:40 -0700 (Sat, 21 Sep 2019)
New Revision: 9605
Added:
sandbox/jng/mvt_alt/Common/Renderers/mvt/
sandbox/jng/mvt_alt/Common/Renderers/mvt/gpb.h
sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile.cpp
sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile.h
sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile_test.cpp
sandbox/jng/mvt_alt/Common/Renderers/mvt/mvtutils.cpp
sandbox/jng/mvt_alt/Common/Renderers/mvt/mvtutils.h
Log:
Add OGR sources for writing MVT tiles. We'll kitbash this code into shape so it can work in our renderer infrastructure
Added: sandbox/jng/mvt_alt/Common/Renderers/mvt/gpb.h
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/mvt/gpb.h (rev 0)
+++ sandbox/jng/mvt_alt/Common/Renderers/mvt/gpb.h 2019-09-21 17:25:40 UTC (rev 9605)
@@ -0,0 +1,540 @@
+/******************************************************************************
+ * $Id: gpb.h 1758774fff760a0e28521d01de2d9ae74ca66701 2018-02-14 22:17:51Z Kurt Schwehr $
+ *
+ * Project: OpenGIS Simple Features Reference Implementation
+ * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
+ * Purpose: Google Protocol Buffer generic handling functions
+ *
+ ******************************************************************************
+ * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#ifndef GPB_H_INCLUDED
+#define GPB_H_INCLUDED
+
+#include "cpl_port.h"
+#include "cpl_error.h"
+#include "cpl_string.h"
+
+#include <string>
+#include <exception>
+
+#ifndef CHECK_OOB
+#define CHECK_OOB 1
+#endif
+
+class GPBException: public std::exception
+{
+ std::string m_osMessage;
+ public:
+ explicit GPBException(int nLine): m_osMessage(
+ CPLSPrintf("Parsing error occurred at line %d", nLine)) {}
+
+ const char* what() const noexcept override
+ { return m_osMessage.c_str(); }
+};
+
+#define THROW_GPB_EXCEPTION throw GPBException(__LINE__)
+
+/************************************************************************/
+/* Google Protocol Buffer definitions */
+/************************************************************************/
+
+// TODO(schwehr): This should be an enum.
+constexpr int WT_VARINT = 0;
+constexpr int WT_64BIT = 1;
+constexpr int WT_DATA = 2;
+// constexpr WT_STARTGROUP = 3; // unused
+// constexpr WT_ENDGROUP = 4; // unused
+constexpr int WT_32BIT = 5;
+
+#define MAKE_KEY(nFieldNumber, nWireType) ((nFieldNumber << 3) | nWireType)
+#define GET_WIRETYPE(nKey) (nKey & 0x7)
+#define GET_FIELDNUMBER(nKey) (nKey >> 3)
+
+/************************************************************************/
+/* ReadVarUInt32() */
+/************************************************************************/
+
+inline int ReadVarUInt32(const GByte** ppabyData)
+{
+ unsigned int nVal = 0;
+ int nShift = 0;
+ const GByte* pabyData = *ppabyData;
+
+ while(true)
+ {
+ int nByte = *pabyData;
+ if (!(nByte & 0x80))
+ {
+ *ppabyData = pabyData + 1;
+ return nVal | ((unsigned)nByte << nShift);
+ }
+ nVal |= (nByte & 0x7f) << nShift;
+ pabyData ++;
+ nShift += 7;
+ if( nShift == 28 )
+ {
+ nByte = *pabyData;
+ if (!(nByte & 0x80))
+ {
+ *ppabyData = pabyData + 1;
+ return nVal | (((unsigned)nByte & 0xf) << nShift);
+ }
+ *ppabyData = pabyData;
+ return nVal;
+ }
+ }
+}
+
+#define READ_VARUINT32(pabyData, pabyDataLimit, nVal) \
+ { \
+ nVal = ReadVarUInt32(&pabyData); \
+ if (CHECK_OOB && pabyData > pabyDataLimit) THROW_GPB_EXCEPTION; \
+ }
+
+#define READ_SIZE(pabyData, pabyDataLimit, nSize) \
+ { \
+ READ_VARUINT32(pabyData, pabyDataLimit, nSize); \
+ if (CHECK_OOB && nSize > (unsigned int)(pabyDataLimit - pabyData)) THROW_GPB_EXCEPTION; \
+ }
+
+/************************************************************************/
+/* ReadVarUInt64() */
+/************************************************************************/
+
+inline GUIntBig ReadVarUInt64(const GByte** ppabyData)
+{
+ GUIntBig nVal = 0;
+ int nShift = 0;
+ const GByte* pabyData = *ppabyData;
+
+ while(true)
+ {
+ int nByte = *pabyData;
+ if (!(nByte & 0x80))
+ {
+ *ppabyData = pabyData + 1;
+ return nVal | ((GUIntBig)nByte << nShift);
+ }
+ nVal |= ((GUIntBig)(nByte & 0x7f)) << nShift;
+ pabyData ++;
+ nShift += 7;
+ if( nShift == 63 )
+ {
+ nByte = *pabyData;
+ if (!(nByte & 0x80))
+ {
+ *ppabyData = pabyData + 1;
+ return nVal | (((GUIntBig)nByte & 1) << nShift);
+ }
+ *ppabyData = pabyData;
+ return nVal;
+ }
+ }
+}
+
+#define READ_VARUINT64(pabyData, pabyDataLimit, nVal) \
+ { \
+ nVal = ReadVarUInt64(&pabyData); \
+ if (CHECK_OOB && pabyData > pabyDataLimit) THROW_GPB_EXCEPTION; \
+ }
+
+#define READ_SIZE64(pabyData, pabyDataLimit, nSize) \
+ { \
+ READ_VARUINT64(pabyData, pabyDataLimit, nSize); \
+ if (CHECK_OOB && nSize > (unsigned int)(pabyDataLimit - pabyData)) THROW_GPB_EXCEPTION; \
+ }
+
+/************************************************************************/
+/* ReadVarInt64() */
+/************************************************************************/
+
+inline GIntBig ReadVarInt64(const GByte** ppabyData)
+{
+ return static_cast<GIntBig>(ReadVarUInt64(ppabyData));
+}
+
+#define READ_VARINT64(pabyData, pabyDataLimit, nVal) \
+ { \
+ nVal = ReadVarInt64(&pabyData); \
+ if (CHECK_OOB && pabyData > pabyDataLimit) THROW_GPB_EXCEPTION; \
+ }
+
+/************************************************************************/
+/* DecodeSInt() */
+/************************************************************************/
+
+inline GIntBig DecodeSInt(GUIntBig nVal)
+{
+ return ((nVal & 1) == 0) ?
+ static_cast<GIntBig>(nVal >> 1) : -static_cast<GIntBig>(nVal >> 1)-1;
+}
+
+inline GInt32 DecodeSInt(GUInt32 nVal)
+{
+ return ((nVal & 1) == 0) ?
+ static_cast<GInt32>(nVal >> 1) : -static_cast<GInt32>(nVal >> 1)-1;
+}
+
+/************************************************************************/
+/* ReadVarSInt64() */
+/************************************************************************/
+
+inline GIntBig ReadVarSInt64(const GByte** ppabyPtr)
+{
+ return DecodeSInt(ReadVarUInt64(ppabyPtr));
+}
+
+#define READ_VARSINT64(pabyData, pabyDataLimit, nVal) \
+ { \
+ nVal = ReadVarSInt64(&pabyData); \
+ if (CHECK_OOB && pabyData > pabyDataLimit) THROW_GPB_EXCEPTION; \
+ }
+
+#define READ_VARSINT64_NOCHECK(pabyData, pabyDataLimit, nVal) \
+ { \
+ nVal = ReadVarSInt64(&pabyData); \
+ }
+
+/************************************************************************/
+/* ReadVarInt32() */
+/************************************************************************/
+
+inline int ReadVarInt32(const GByte** ppabyData)
+{
+ /* If you use int32 or int64 as the type for a negative number, */
+ /* the resulting varint is always ten bytes long */
+ GIntBig nVal = static_cast<GIntBig>(ReadVarUInt64(ppabyData));
+ return static_cast<int>(nVal);
+}
+
+#define READ_VARINT32(pabyData, pabyDataLimit, nVal) \
+ { \
+ nVal = ReadVarInt32(&pabyData); \
+ if (CHECK_OOB && pabyData > pabyDataLimit) THROW_GPB_EXCEPTION; \
+ }
+
+#define READ_VARSINT32(pabyData, pabyDataLimit, nVal) \
+ { \
+ nVal = DecodeSInt(static_cast<GUInt32>(ReadVarUInt64(&pabyData))); \
+ if (CHECK_OOB && pabyData > pabyDataLimit) THROW_GPB_EXCEPTION; \
+ }
+
+/************************************************************************/
+/* ReadFloat32() */
+/************************************************************************/
+
+inline float ReadFloat32(const GByte** ppabyData, const GByte* pabyDataLimit)
+{
+ if( *ppabyData + sizeof(float) > pabyDataLimit )
+ THROW_GPB_EXCEPTION;
+ float fValue;
+ memcpy(&fValue, *ppabyData, sizeof(float));
+ CPL_LSBPTR32(&fValue);
+ *ppabyData += sizeof(float);
+ return fValue;
+}
+
+/************************************************************************/
+/* ReadFloat64() */
+/************************************************************************/
+
+inline double ReadFloat64(const GByte** ppabyData, const GByte* pabyDataLimit)
+{
+ if( *ppabyData + sizeof(double) > pabyDataLimit )
+ THROW_GPB_EXCEPTION;
+ double dfValue;
+ memcpy(&dfValue, *ppabyData, sizeof(double));
+ CPL_LSBPTR64(&dfValue);
+ *ppabyData += sizeof(double);
+ return dfValue;
+}
+
+/************************************************************************/
+/* SkipVarInt() */
+/************************************************************************/
+
+inline void SkipVarInt(const GByte** ppabyData)
+{
+ const GByte* pabyData = *ppabyData;
+ while(true)
+ {
+ int nByte = *pabyData;
+ if (!(nByte & 0x80))
+ {
+ *ppabyData = pabyData + 1;
+ return;
+ }
+ pabyData ++;
+ }
+}
+
+#define SKIP_VARINT(pabyData, pabyDataLimit) \
+ { \
+ SkipVarInt(&pabyData); \
+ if (CHECK_OOB && pabyData > pabyDataLimit) THROW_GPB_EXCEPTION; \
+ }
+
+#define READ_FIELD_KEY(nKey) READ_VARINT32(pabyData, pabyDataLimit, nKey)
+
+#define READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength) do { \
+ READ_SIZE(pabyData, pabyDataLimit, l_nDataLength); \
+ pszTxt = (char*)VSI_MALLOC_VERBOSE(l_nDataLength + 1); \
+ if( pszTxt == nullptr ) THROW_GPB_EXCEPTION; \
+ memcpy(pszTxt, pabyData, l_nDataLength); \
+ pszTxt[l_nDataLength] = 0; \
+ pabyData += l_nDataLength; } while(0)
+
+#define READ_TEXT(pabyData, pabyDataLimit, pszTxt) do { \
+ unsigned int l_nDataLength; \
+ READ_TEXT_WITH_SIZE(pabyData, pabyDataLimit, pszTxt, l_nDataLength); } while(0)
+
+/************************************************************************/
+/* SkipUnknownField() */
+/************************************************************************/
+
+#define SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose) \
+ int nWireType = GET_WIRETYPE(nKey); \
+ if (verbose) \
+ { \
+ int nFieldNumber = GET_FIELDNUMBER(nKey); \
+ CPLDebug("PBF", "Unhandled case: nFieldNumber = %d, nWireType = %d", nFieldNumber, nWireType); \
+ } \
+ switch (nWireType) \
+ { \
+ case WT_VARINT: \
+ { \
+ SKIP_VARINT(pabyData, pabyDataLimit); \
+ break; \
+ } \
+ case WT_64BIT: \
+ { \
+ if (CHECK_OOB && pabyDataLimit - pabyData < 8) THROW_GPB_EXCEPTION; \
+ pabyData += 8; \
+ break; \
+ } \
+ case WT_DATA: \
+ { \
+ unsigned int nDataLength; \
+ READ_SIZE(pabyData, pabyDataLimit, nDataLength); \
+ pabyData += nDataLength; \
+ break; \
+ } \
+ case WT_32BIT: \
+ { \
+ if (CHECK_OOB && pabyDataLimit - pabyData < 4) THROW_GPB_EXCEPTION; \
+ pabyData += 4; \
+ break; \
+ } \
+ default: \
+ THROW_GPB_EXCEPTION; \
+ }
+
+inline int SkipUnknownField(int nKey, const GByte* pabyData, const GByte* pabyDataLimit, int verbose)
+{
+ const GByte* pabyDataBefore = pabyData;
+ try
+ {
+ SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose);
+ return static_cast<int>(pabyData - pabyDataBefore);
+ }
+ catch( const GPBException& e )
+ {
+ if( verbose )
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
+ }
+ return -1;
+ }
+}
+
+#define SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, verbose) \
+ { \
+ int _nOffset = SkipUnknownField(nKey, pabyData, pabyDataLimit, verbose); \
+ if (_nOffset < 0) \
+ THROW_GPB_EXCEPTION; \
+ pabyData += _nOffset; \
+ }
+
+
+/************************************************************************/
+/* GetVarUIntSize() */
+/************************************************************************/
+
+inline int GetVarUIntSize(GUIntBig nVal)
+{
+ int nBytes = 1;
+ while( nVal > 127 )
+ {
+ nBytes ++;
+ nVal >>= 7;
+ }
+ return nBytes;
+}
+
+/************************************************************************/
+/* EncodeSInt() */
+/************************************************************************/
+
+inline GUIntBig EncodeSInt(GIntBig nVal)
+{
+ if( nVal < 0 )
+ return (static_cast<GUIntBig>(-(nVal + 1)) << 1) | 1;
+ else
+ return static_cast<GUIntBig>(nVal) << 1;
+}
+
+inline GUInt32 EncodeSInt(GInt32 nVal)
+{
+ if( nVal < 0 )
+ return (static_cast<GUInt32>(-(nVal + 1)) << 1) | 1;
+ else
+ return static_cast<GUInt32>(nVal) << 1;
+}
+
+/************************************************************************/
+/* GetVarIntSize() */
+/************************************************************************/
+
+inline int GetVarIntSize(GIntBig nVal)
+{
+ return GetVarUIntSize(static_cast<GUIntBig>(nVal));
+}
+
+/************************************************************************/
+/* GetVarSIntSize() */
+/************************************************************************/
+
+inline int GetVarSIntSize(GIntBig nVal)
+{
+ return GetVarUIntSize(EncodeSInt(nVal));
+}
+
+/************************************************************************/
+/* WriteVarUInt() */
+/************************************************************************/
+
+inline void WriteVarUInt(GByte** ppabyData, GUIntBig nVal)
+{
+ GByte* pabyData = *ppabyData;
+ while( nVal > 127 )
+ {
+ *pabyData = static_cast<GByte>((nVal & 0x7f) | 0x80);
+ pabyData ++;
+ nVal >>= 7;
+ }
+ *pabyData = static_cast<GByte>(nVal);
+ pabyData ++;
+ *ppabyData = pabyData;
+}
+
+/************************************************************************/
+/* WriteVarUIntSingleByte() */
+/************************************************************************/
+
+inline void WriteVarUIntSingleByte(GByte** ppabyData, GUIntBig nVal)
+{
+ GByte* pabyData = *ppabyData;
+ CPLAssert( nVal < 128 );
+ *pabyData = static_cast<GByte>(nVal);
+ pabyData ++;
+ *ppabyData = pabyData;
+}
+
+/************************************************************************/
+/* WriteVarInt() */
+/************************************************************************/
+
+inline void WriteVarInt(GByte** ppabyData, GIntBig nVal)
+{
+ WriteVarUInt(ppabyData, static_cast<GUIntBig>(nVal));
+}
+
+/************************************************************************/
+/* WriteVarSInt() */
+/************************************************************************/
+
+inline void WriteVarSInt(GByte** ppabyData, GIntBig nVal)
+{
+ WriteVarUInt(ppabyData, EncodeSInt(nVal) );
+}
+
+/************************************************************************/
+/* WriteFloat32() */
+/************************************************************************/
+
+inline void WriteFloat32(GByte** ppabyData, float fVal)
+{
+ CPL_LSBPTR32(&fVal);
+ memcpy(*ppabyData, &fVal, sizeof(float));
+ *ppabyData += sizeof(float);
+}
+
+/************************************************************************/
+/* WriteFloat64() */
+/************************************************************************/
+
+inline void WriteFloat64(GByte** ppabyData, double dfVal)
+{
+ CPL_LSBPTR64(&dfVal);
+ memcpy(*ppabyData, &dfVal, sizeof(double));
+ *ppabyData += sizeof(double);
+}
+
+/************************************************************************/
+/* GetTextSize() */
+/************************************************************************/
+
+inline int GetTextSize(const char* pszText)
+{
+ size_t nTextSize = strlen(pszText);
+ return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
+}
+
+inline int GetTextSize(const std::string& osText)
+{
+ size_t nTextSize = osText.size();
+ return GetVarUIntSize(nTextSize) + static_cast<int>(nTextSize);
+}
+
+/************************************************************************/
+/* WriteText() */
+/************************************************************************/
+
+inline void WriteText(GByte** ppabyData, const char* pszText)
+{
+ size_t nTextSize = strlen(pszText);
+ WriteVarUInt(ppabyData, nTextSize);
+ memcpy(*ppabyData, pszText, nTextSize);
+ *ppabyData += nTextSize;
+}
+
+inline void WriteText(GByte** ppabyData, const std::string& osText)
+{
+ size_t nTextSize = osText.size();
+ WriteVarUInt(ppabyData, nTextSize);
+ memcpy(*ppabyData, osText.c_str(), nTextSize);
+ *ppabyData += nTextSize;
+}
+
+
+#endif /* GPB_H_INCLUDED */
Added: sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile.cpp
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile.cpp (rev 0)
+++ sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile.cpp 2019-09-21 17:25:40 UTC (rev 9605)
@@ -0,0 +1,928 @@
+/******************************************************************************
+ *
+ * Project: MVT Translator
+ * Purpose: Mapbox Vector Tile decoder and encoder
+ * Author: Even Rouault, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "gpb.h"
+
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include "mvt_tile.h"
+
+constexpr int knSIZE_KEY = 1;
+
+/************************************************************************/
+/* MVTTileLayerValue() */
+/************************************************************************/
+
+MVTTileLayerValue::MVTTileLayerValue(): m_nUIntValue(0)
+{
+}
+
+MVTTileLayerValue::MVTTileLayerValue(const MVTTileLayerValue& oOther)
+{
+ operator=(oOther);
+}
+
+/************************************************************************/
+/* ~MVTTileLayerValue() */
+/************************************************************************/
+
+MVTTileLayerValue::~MVTTileLayerValue()
+{
+ unset();
+}
+
+/************************************************************************/
+/* operator= */
+/************************************************************************/
+
+MVTTileLayerValue& MVTTileLayerValue::operator=(
+ const MVTTileLayerValue& oOther)
+
+{
+ if( this != &oOther )
+ {
+ unset();
+ m_eType = oOther.m_eType;
+ if( m_eType == ValueType::STRING )
+ {
+ const size_t nSize = strlen(oOther.m_pszValue);
+ m_pszValue = static_cast<char*>(CPLMalloc(1 + nSize));
+ memcpy(m_pszValue, oOther.m_pszValue, nSize);
+ m_pszValue[nSize] = 0;
+ }
+ else
+ {
+ m_nUIntValue = oOther.m_nUIntValue;
+ }
+ }
+ return *this;
+}
+
+/************************************************************************/
+/* operator< */
+/************************************************************************/
+
+bool MVTTileLayerValue::operator <(const MVTTileLayerValue& rhs) const
+{
+ if( m_eType < rhs.m_eType )
+ return false;
+ if( m_eType > rhs.m_eType )
+ return true;
+ if( m_eType == ValueType::NONE )
+ return false;
+ if( m_eType == ValueType::STRING )
+ return strcmp( m_pszValue, rhs.m_pszValue ) < 0;
+ if( m_eType == ValueType::FLOAT )
+ return m_fValue < rhs.m_fValue;
+ if( m_eType == ValueType::DOUBLE )
+ return m_dfValue < rhs.m_dfValue;
+ if( m_eType == ValueType::INT )
+ return m_nIntValue < rhs.m_nIntValue;
+ if( m_eType == ValueType::UINT )
+ return m_nUIntValue < rhs.m_nUIntValue;
+ if( m_eType == ValueType::SINT )
+ return m_nIntValue < rhs.m_nIntValue;
+ if( m_eType == ValueType::BOOL )
+ return m_bBoolValue < rhs.m_bBoolValue;
+ if( m_eType == ValueType::STRING_MAX_8 )
+ return strncmp( m_achValue, rhs.m_achValue, 8 ) < 0;
+ CPLAssert(false);
+ return false;
+}
+
+/************************************************************************/
+/* unset() */
+/************************************************************************/
+
+void MVTTileLayerValue::unset()
+{
+ if( m_eType == ValueType::STRING )
+ CPLFree(m_pszValue);
+ m_eType = ValueType::NONE;
+ m_nUIntValue = 0;
+}
+
+/************************************************************************/
+/* GetSizeMax8() */
+/************************************************************************/
+
+static size_t GetSizeMax8(const char achValue[8])
+{
+ size_t nSize = 0;
+ while( nSize < 8 && achValue[nSize] != 0 )
+ nSize ++;
+ return nSize;
+}
+
+/************************************************************************/
+/* setStringValue() */
+/************************************************************************/
+
+void MVTTileLayerValue::setStringValue(const std::string& osValue)
+{
+ unset();
+ const size_t nSize = osValue.size();
+ if( nSize <= 8 )
+ {
+ m_eType = ValueType::STRING_MAX_8;
+ if( nSize )
+ memcpy( m_achValue, osValue.c_str(), nSize );
+ if( nSize < 8 )
+ m_achValue[nSize] = 0;
+ }
+ else
+ {
+ m_eType = ValueType::STRING;
+ m_pszValue = static_cast<char*>(CPLMalloc(1 + nSize));
+ memcpy(m_pszValue, osValue.c_str(), nSize);
+ m_pszValue[nSize] = 0;
+ }
+}
+
+/************************************************************************/
+/* setValue() */
+/************************************************************************/
+
+void MVTTileLayerValue::setValue(double dfVal)
+{
+ if( dfVal >= 0 &&
+ dfVal <= static_cast<double>(std::numeric_limits<GUInt64>::max()) &&
+ dfVal == static_cast<double>(static_cast<GUInt64>(dfVal)) )
+ {
+ setUIntValue(static_cast<GUInt64>(dfVal));
+ }
+ else if( dfVal >= static_cast<double>(
+ std::numeric_limits<GInt64>::min()) &&
+ dfVal < 0 &&
+ dfVal == static_cast<double>(static_cast<GInt64>(dfVal)) )
+ {
+ setSIntValue(static_cast<GInt64>(dfVal));
+ }
+ else if( !CPLIsFinite(dfVal) ||
+ (dfVal >= -std::numeric_limits<float>::max() &&
+ dfVal <= std::numeric_limits<float>::max() &&
+ dfVal == static_cast<float>(dfVal)) )
+ {
+ setFloatValue( static_cast<float>(dfVal) );
+ }
+ else
+ {
+ setDoubleValue( dfVal );
+ }
+}
+
+/************************************************************************/
+/* getSize() */
+/************************************************************************/
+
+size_t MVTTileLayerValue::getSize() const
+{
+ switch( m_eType )
+ {
+ case ValueType::NONE: return 0;
+ case ValueType::STRING:
+ {
+ const size_t nSize = strlen(m_pszValue);
+ return knSIZE_KEY + GetVarUIntSize(nSize) + nSize;
+ }
+ case ValueType::STRING_MAX_8:
+ {
+ const size_t nSize = GetSizeMax8(m_achValue);
+ return knSIZE_KEY + GetVarUIntSize(nSize) + nSize;
+ }
+ case ValueType::FLOAT: return knSIZE_KEY + sizeof(float);
+ case ValueType::DOUBLE: return knSIZE_KEY + sizeof(double);
+ case ValueType::INT: return knSIZE_KEY + GetVarIntSize(m_nIntValue);
+ case ValueType::UINT: return knSIZE_KEY + GetVarUIntSize(m_nUIntValue);
+ case ValueType::SINT: return knSIZE_KEY + GetVarSIntSize(m_nIntValue);
+ case ValueType::BOOL: return knSIZE_KEY + 1;
+ default: return 0;
+ }
+}
+
+/************************************************************************/
+/* write() */
+/************************************************************************/
+
+void MVTTileLayerValue::write(GByte** ppabyData) const
+{
+ GByte* pabyData = *ppabyData;
+
+ switch( m_eType )
+ {
+ case ValueType::STRING:
+ {
+ const size_t nSize = strlen(m_pszValue);
+ WriteVarUIntSingleByte(&pabyData,
+ MAKE_KEY(knVALUE_STRING, WT_DATA));
+ WriteVarUInt(&pabyData, nSize);
+ memcpy(pabyData, m_pszValue, nSize);
+ pabyData += nSize;
+ break;
+ }
+
+ case ValueType::STRING_MAX_8:
+ {
+ const size_t nSize = GetSizeMax8(m_achValue);
+ WriteVarUIntSingleByte(&pabyData,
+ MAKE_KEY(knVALUE_STRING, WT_DATA));
+ WriteVarUInt(&pabyData, nSize);
+ if( nSize )
+ memcpy(pabyData, m_achValue, nSize);
+ pabyData += nSize;
+ break;
+ }
+
+ case ValueType::FLOAT:
+ WriteVarUIntSingleByte(&pabyData,
+ MAKE_KEY(knVALUE_FLOAT, WT_32BIT));
+ WriteFloat32(&pabyData, m_fValue);
+ break;
+
+ case ValueType::DOUBLE:
+ WriteVarUIntSingleByte(&pabyData,
+ MAKE_KEY(knVALUE_DOUBLE, WT_64BIT));
+ WriteFloat64(&pabyData, m_dfValue);
+ break;
+
+ case ValueType::INT:
+ WriteVarUIntSingleByte(&pabyData,
+ MAKE_KEY(knVALUE_INT, WT_VARINT));
+ WriteVarInt(&pabyData, m_nIntValue);
+ break;
+
+ case ValueType::UINT:
+ WriteVarUIntSingleByte(&pabyData,
+ MAKE_KEY(knVALUE_UINT, WT_VARINT));
+ WriteVarUInt(&pabyData, m_nUIntValue);
+ break;
+
+ case ValueType::SINT:
+ WriteVarUIntSingleByte(&pabyData,
+ MAKE_KEY(knVALUE_SINT, WT_VARINT));
+ WriteVarSInt(&pabyData, m_nIntValue);
+ break;
+
+ case ValueType::BOOL:
+ WriteVarUIntSingleByte(&pabyData,
+ MAKE_KEY(knVALUE_BOOL, WT_VARINT));
+ WriteVarUIntSingleByte(&pabyData, m_bBoolValue ? 1 : 0);
+ break;
+
+ default:
+ break;
+ }
+
+ CPLAssert(pabyData == *ppabyData + getSize());
+ *ppabyData = pabyData;
+}
+
+/************************************************************************/
+/* read() */
+/************************************************************************/
+
+bool MVTTileLayerValue::read(const GByte** ppabyData, const GByte* pabyDataLimit)
+{
+ const GByte* pabyData = *ppabyData;
+
+ try
+ {
+ unsigned int nKey = 0;
+ if( pabyData < pabyDataLimit )
+ {
+ READ_FIELD_KEY(nKey);
+
+ if( nKey == MAKE_KEY(knVALUE_STRING, WT_DATA) )
+ {
+ char* pszValue = nullptr;
+ READ_TEXT(pabyData, pabyDataLimit, pszValue);
+ // cppcheck-suppress nullPointer
+ setStringValue(pszValue);
+ CPLFree(pszValue);
+ }
+ else if( nKey == MAKE_KEY(knVALUE_FLOAT, WT_32BIT) )
+ {
+ setFloatValue(ReadFloat32(&pabyData, pabyDataLimit));
+ }
+ else if( nKey == MAKE_KEY(knVALUE_DOUBLE, WT_64BIT) )
+ {
+ setDoubleValue(ReadFloat64(&pabyData, pabyDataLimit));
+ }
+ else if( nKey == MAKE_KEY(knVALUE_INT, WT_VARINT) )
+ {
+ GIntBig nVal = 0;
+ READ_VARINT64(pabyData, pabyDataLimit, nVal);
+ setIntValue(nVal);
+ }
+ else if( nKey == MAKE_KEY(knVALUE_UINT, WT_VARINT) )
+ {
+ GUIntBig nVal = 0;
+ READ_VARUINT64(pabyData, pabyDataLimit, nVal);
+ setUIntValue(nVal);
+ }
+ else if( nKey == MAKE_KEY(knVALUE_SINT, WT_VARINT) )
+ {
+ GIntBig nVal = 0;
+ READ_VARSINT64(pabyData, pabyDataLimit, nVal);
+ setSIntValue(nVal);
+ }
+ else if( nKey == MAKE_KEY(knVALUE_BOOL, WT_VARINT) )
+ {
+ unsigned nVal = 0;
+ READ_VARUINT32(pabyData, pabyDataLimit, nVal);
+ setBoolValue(nVal != 0);
+ }
+ }
+ *ppabyData = pabyData;
+ return true;
+ }
+ catch( const GPBException& )
+ {
+ return false;
+ }
+}
+
+/************************************************************************/
+/* MVTTileLayer() */
+/************************************************************************/
+
+MVTTileLayerFeature::MVTTileLayerFeature()
+{
+}
+
+/************************************************************************/
+/* setOwner() */
+/************************************************************************/
+
+void MVTTileLayerFeature::setOwner(MVTTileLayer* poOwner)
+{
+ CPLAssert( !m_poOwner );
+ m_poOwner = poOwner;
+ m_poOwner->invalidateCachedSize();
+}
+
+/************************************************************************/
+/* invalidateCachedSize() */
+/************************************************************************/
+
+void MVTTileLayerFeature::invalidateCachedSize()
+{
+ m_bCachedSize = false;
+ m_nCachedSize = 0;
+ if( m_poOwner )
+ m_poOwner->invalidateCachedSize();
+}
+
+/************************************************************************/
+/* GetPackedArraySize() */
+/************************************************************************/
+
+static size_t GetPackedArraySize(const std::vector<GUInt32>& anVals)
+{
+ size_t nPackedSize = 0;
+ for( const auto& nVal: anVals )
+ {
+ nPackedSize += GetVarUIntSize(nVal);
+ }
+ return nPackedSize;
+}
+
+/************************************************************************/
+/* getSize() */
+/************************************************************************/
+
+size_t MVTTileLayerFeature::getSize() const
+{
+ if( m_bCachedSize )
+ return m_nCachedSize;
+ m_bCachedSize = true;
+ m_nCachedSize = 0;
+ if( m_bHasId )
+ m_nCachedSize += knSIZE_KEY + GetVarUIntSize(m_nId);
+ if( !m_anTags.empty() )
+ {
+ size_t nPackedSize = GetPackedArraySize(m_anTags);
+ m_nCachedSize += knSIZE_KEY;
+ m_nCachedSize += GetVarUIntSize(nPackedSize);
+ m_nCachedSize += nPackedSize;
+ }
+ if( m_bHasType )
+ m_nCachedSize += knSIZE_KEY + 1; // fixed size for m_eType
+ if( !m_anGeometry.empty() )
+ {
+ size_t nPackedSize = GetPackedArraySize(m_anGeometry);
+ m_nCachedSize += knSIZE_KEY;
+ m_nCachedSize += GetVarUIntSize(nPackedSize);
+ m_nCachedSize += nPackedSize;
+ }
+ return m_nCachedSize;
+}
+
+/************************************************************************/
+/* WriteUIntPackedArray() */
+/************************************************************************/
+
+static void WriteUIntPackedArray(GByte** ppabyData, int nKey,
+ const std::vector<GUInt32>& anVals)
+{
+ GByte* pabyData = *ppabyData;
+ const size_t nPackedSize = GetPackedArraySize(anVals);
+ WriteVarUIntSingleByte(&pabyData, nKey);
+ WriteVarUInt(&pabyData, nPackedSize);
+ for( const auto& nVal: anVals )
+ {
+ WriteVarUInt(&pabyData, nVal);
+ }
+ *ppabyData = pabyData;
+}
+
+/************************************************************************/
+/* write() */
+/************************************************************************/
+
+void MVTTileLayerFeature::write(GByte** ppabyData) const
+{
+ GByte* pabyData = *ppabyData;
+
+ if( m_bHasId )
+ {
+ WriteVarUIntSingleByte(&pabyData, MAKE_KEY(knFEATURE_ID, WT_VARINT));
+ WriteVarUInt(&pabyData, m_nId);
+ }
+ if( !m_anTags.empty() )
+ {
+ WriteUIntPackedArray(&pabyData, MAKE_KEY(knFEATURE_TAGS, WT_DATA),
+ m_anTags);
+ }
+ if( m_bHasType )
+ {
+ WriteVarUIntSingleByte(&pabyData, MAKE_KEY(knFEATURE_TYPE, WT_VARINT));
+ WriteVarUIntSingleByte(&pabyData, static_cast<GUIntBig>(m_eType));
+ }
+ if( !m_anGeometry.empty() )
+ {
+ WriteUIntPackedArray(&pabyData, MAKE_KEY(knFEATURE_GEOMETRY, WT_DATA),
+ m_anGeometry);
+ }
+
+ CPLAssert(pabyData == *ppabyData + getSize());
+ *ppabyData = pabyData;
+}
+
+/************************************************************************/
+/* read() */
+/************************************************************************/
+
+bool MVTTileLayerFeature::read(const GByte** ppabyData,
+ const GByte* pabyDataLimit)
+{
+ const GByte* pabyData = *ppabyData;
+
+ try
+ {
+ unsigned int nKey = 0;
+ while( pabyData < pabyDataLimit )
+ {
+ READ_FIELD_KEY(nKey);
+ if( nKey == MAKE_KEY(knFEATURE_ID, WT_VARINT) )
+ {
+ GUIntBig nID = 0;
+ READ_VARUINT64(pabyData, pabyDataLimit, nID);
+ setId(nID);
+ }
+ else if( nKey == MAKE_KEY(knFEATURE_TAGS, WT_DATA) )
+ {
+ unsigned int nTagsSize = 0;
+ READ_SIZE(pabyData, pabyDataLimit, nTagsSize);
+ const GByte* pabyDataTagsEnd = pabyData + nTagsSize;
+ while( pabyData < pabyDataTagsEnd )
+ {
+ unsigned int nTag = 0;
+ READ_VARUINT32(pabyData, pabyDataTagsEnd, nTag);
+ addTag(nTag);
+ }
+ pabyData = pabyDataTagsEnd;
+ }
+ else if( nKey == MAKE_KEY(knFEATURE_TYPE, WT_VARINT) )
+ {
+ unsigned int nType = 0;
+ READ_VARUINT32(pabyData, pabyDataLimit, nType);
+ if( nType <= knGEOM_TYPE_POLYGON )
+ setType(static_cast<GeomType>(nType));
+ }
+ else if( nKey == MAKE_KEY(knFEATURE_GEOMETRY, WT_DATA) )
+ {
+ unsigned int nGeometrySize = 0;
+ READ_SIZE(pabyData, pabyDataLimit, nGeometrySize);
+ const GByte* pabyDataGeometryEnd = pabyData + nGeometrySize;
+ while( pabyData < pabyDataGeometryEnd )
+ {
+ unsigned int nGeometry = 0;
+ READ_VARUINT32(pabyData, pabyDataGeometryEnd, nGeometry);
+ addGeometry(nGeometry);
+ }
+ pabyData = pabyDataGeometryEnd;
+ }
+ else
+ {
+ SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, FALSE);
+ }
+ }
+ *ppabyData = pabyData;
+ return true;
+ }
+ catch( const GPBException& )
+ {
+ return false;
+ }
+}
+
+/************************************************************************/
+/* MVTTileLayer() */
+/************************************************************************/
+
+MVTTileLayer::MVTTileLayer()
+{
+}
+
+/************************************************************************/
+/* setOwner() */
+/************************************************************************/
+
+void MVTTileLayer::setOwner(MVTTile* poOwner)
+{
+ CPLAssert( !m_poOwner );
+ m_poOwner = poOwner;
+ m_poOwner->invalidateCachedSize();
+}
+
+/************************************************************************/
+/* invalidateCachedSize() */
+/************************************************************************/
+
+void MVTTileLayer::invalidateCachedSize()
+{
+ m_bCachedSize = false;
+ m_nCachedSize = 0;
+ if( m_poOwner )
+ m_poOwner->invalidateCachedSize();
+}
+
+/************************************************************************/
+/* addFeature() */
+/************************************************************************/
+
+size_t MVTTileLayer::addFeature(std::shared_ptr<MVTTileLayerFeature> poFeature)
+{
+ poFeature->setOwner(this);
+ m_apoFeatures.push_back(poFeature);
+ invalidateCachedSize();
+ return m_apoFeatures.size() - 1;
+}
+
+/************************************************************************/
+/* getSize() */
+/************************************************************************/
+
+size_t MVTTileLayer::getSize() const
+{
+ if( m_bCachedSize )
+ return m_nCachedSize;
+ m_nCachedSize = knSIZE_KEY + GetTextSize(m_osName);
+ for( const auto& poFeature: m_apoFeatures )
+ {
+ const size_t nFeatureSize = poFeature->getSize();
+ m_nCachedSize += knSIZE_KEY +
+ GetVarUIntSize(nFeatureSize) + nFeatureSize;
+ }
+ for( const auto& osKey: m_aosKeys )
+ {
+ m_nCachedSize += knSIZE_KEY + GetTextSize(osKey);
+ }
+ for( const auto& oValue: m_aoValues )
+ {
+ const size_t nValueSize = oValue.getSize();
+ m_nCachedSize += knSIZE_KEY + GetVarUIntSize(nValueSize) + nValueSize;
+ }
+ if( m_bHasExtent )
+ {
+ m_nCachedSize += knSIZE_KEY + GetVarUIntSize(m_nExtent);
+ }
+ m_nCachedSize += knSIZE_KEY + GetVarUIntSize(m_nVersion);
+ m_bCachedSize = true;
+ return m_nCachedSize;
+}
+
+/************************************************************************/
+/* write() */
+/************************************************************************/
+
+void MVTTileLayer::write(GByte** ppabyData) const
+{
+ GByte* pabyData = *ppabyData;
+
+ WriteVarUIntSingleByte(&pabyData, MAKE_KEY(knLAYER_NAME, WT_DATA));
+ WriteText(&pabyData, m_osName);
+
+ for( const auto& poFeature: m_apoFeatures )
+ {
+ WriteVarUIntSingleByte(&pabyData, MAKE_KEY(knLAYER_FEATURES, WT_DATA));
+ WriteVarUInt(&pabyData, poFeature->getSize());
+ poFeature->write(&pabyData);
+ }
+
+ for( const auto& osKey: m_aosKeys )
+ {
+ WriteVarUIntSingleByte(&pabyData, MAKE_KEY(knLAYER_KEYS, WT_DATA));
+ WriteText(&pabyData, osKey);
+ }
+
+ for( const auto& oValue: m_aoValues )
+ {
+ WriteVarUIntSingleByte(&pabyData, MAKE_KEY(knLAYER_VALUES, WT_DATA));
+ WriteVarUInt(&pabyData, oValue.getSize());
+ oValue.write(&pabyData);
+ }
+
+ if( m_bHasExtent )
+ {
+ WriteVarUIntSingleByte(&pabyData, MAKE_KEY(knLAYER_EXTENT, WT_VARINT));
+ WriteVarUInt(&pabyData, m_nExtent);
+ }
+
+ WriteVarUIntSingleByte(&pabyData, MAKE_KEY(knLAYER_VERSION, WT_VARINT));
+ WriteVarUInt(&pabyData, m_nVersion);
+
+ CPLAssert(pabyData == *ppabyData + getSize());
+ *ppabyData = pabyData;
+}
+
+/************************************************************************/
+/* write() */
+/************************************************************************/
+
+void MVTTileLayer::write(GByte* pabyData) const
+{
+ write(&pabyData);
+}
+
+/************************************************************************/
+/* write() */
+/************************************************************************/
+
+std::string MVTTileLayer::write() const
+{
+ std::string buffer;
+ size_t nSize = getSize();
+ buffer.resize(nSize);
+ write( reinterpret_cast<GByte*>(&buffer[0]) );
+ return buffer;
+}
+
+/************************************************************************/
+/* read() */
+/************************************************************************/
+
+bool MVTTileLayer::read(const GByte** ppabyData, const GByte* pabyDataLimit)
+{
+ const GByte* pabyData = *ppabyData;
+
+ try
+ {
+ unsigned int nKey = 0;
+ while( pabyData < pabyDataLimit )
+ {
+ READ_FIELD_KEY(nKey);
+ if( nKey == MAKE_KEY(knLAYER_NAME, WT_DATA) )
+ {
+ char* pszLayerName = nullptr;
+ READ_TEXT(pabyData, pabyDataLimit, pszLayerName);
+ // cppcheck-suppress nullPointer
+ setName(pszLayerName);
+ CPLFree(pszLayerName);
+ }
+ else if( nKey == MAKE_KEY(knLAYER_FEATURES, WT_DATA) )
+ {
+ unsigned int nFeatureLength = 0;
+ READ_SIZE(pabyData, pabyDataLimit, nFeatureLength);
+ const GByte* pabyDataFeatureEnd = pabyData + nFeatureLength;
+ std::shared_ptr<MVTTileLayerFeature> poFeature(
+ new MVTTileLayerFeature());
+ addFeature(poFeature);
+ if( !poFeature->read(&pabyData, pabyDataFeatureEnd) )
+ return false;
+ pabyData = pabyDataFeatureEnd;
+ }
+ else if( nKey == MAKE_KEY(knLAYER_KEYS, WT_DATA) )
+ {
+ char* pszKey = nullptr;
+ READ_TEXT(pabyData, pabyDataLimit, pszKey);
+ // cppcheck-suppress nullPointer
+ addKey(pszKey);
+ CPLFree(pszKey);
+ }
+ else if( nKey == MAKE_KEY(knLAYER_VALUES, WT_DATA) )
+ {
+ unsigned int nValueLength = 0;
+ READ_SIZE(pabyData, pabyDataLimit, nValueLength);
+ const GByte* pabyDataValueEnd = pabyData + nValueLength;
+ MVTTileLayerValue oValue;
+ if( !oValue.read(&pabyData, pabyDataValueEnd) )
+ return false;
+ addValue(oValue);
+ pabyData = pabyDataValueEnd;
+ }
+ else if( nKey == MAKE_KEY(knLAYER_EXTENT, WT_VARINT) )
+ {
+ unsigned int nExtent = 0;
+ READ_VARUINT32(pabyData, pabyDataLimit, nExtent);
+ setExtent(nExtent);
+ }
+ else if( nKey == MAKE_KEY(knLAYER_VERSION, WT_VARINT) )
+ {
+ unsigned int nVersion = 0;
+ READ_VARUINT32(pabyData, pabyDataLimit, nVersion);
+ setVersion(nVersion);
+ }
+ else
+ {
+ SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, FALSE);
+ }
+ }
+ *ppabyData = pabyData;
+ return true;
+ }
+ catch( const GPBException& )
+ {
+ return false;
+ }
+}
+
+/************************************************************************/
+/* read() */
+/************************************************************************/
+
+bool MVTTileLayer::read(const GByte* pabyData, const GByte* pabyEnd)
+{
+ return read(&pabyData, pabyEnd);
+}
+
+/************************************************************************/
+/* MVTTile() */
+/************************************************************************/
+
+MVTTile::MVTTile()
+{
+}
+
+/************************************************************************/
+/* addLayer() */
+/************************************************************************/
+
+void MVTTile::addLayer(std::shared_ptr<MVTTileLayer> poLayer)
+{
+ poLayer->setOwner(this);
+ invalidateCachedSize();
+ m_apoLayers.push_back(poLayer);
+}
+
+/************************************************************************/
+/* getSize() */
+/************************************************************************/
+
+size_t MVTTile::getSize() const
+{
+ if( m_bCachedSize )
+ return m_nCachedSize;
+ m_nCachedSize = 0;
+ for( const auto& poLayer: m_apoLayers )
+ {
+ const size_t nLayerSize = poLayer->getSize();
+ m_nCachedSize += knSIZE_KEY + GetVarUIntSize(nLayerSize) + nLayerSize;
+ }
+ m_bCachedSize = true;
+ return m_nCachedSize;
+}
+
+/************************************************************************/
+/* write() */
+/************************************************************************/
+
+void MVTTile::write(GByte** ppabyData) const
+{
+ GByte* pabyData = *ppabyData;
+
+ for( const auto& poLayer: m_apoLayers )
+ {
+ WriteVarUIntSingleByte(&pabyData, MAKE_KEY(knLAYER, WT_DATA));
+ WriteVarUInt(&pabyData, poLayer->getSize());
+ poLayer->write(&pabyData);
+ }
+
+ CPLAssert(pabyData == *ppabyData + getSize());
+ *ppabyData = pabyData;
+}
+
+/************************************************************************/
+/* write() */
+/************************************************************************/
+
+void MVTTile::write(GByte* pabyData) const
+{
+ write(&pabyData);
+}
+
+/************************************************************************/
+/* write() */
+/************************************************************************/
+
+std::string MVTTile::write() const
+{
+ std::string buffer;
+ size_t nSize = getSize();
+ if( nSize )
+ {
+ buffer.resize(nSize);
+ write( reinterpret_cast<GByte*>(&buffer[0]) );
+ }
+ return buffer;
+}
+
+#ifdef ADD_MVT_TILE_READ
+
+/************************************************************************/
+/* read() */
+/************************************************************************/
+
+bool MVTTile::read(const GByte** ppabyData, const GByte* pabyDataLimit)
+{
+ const GByte* pabyData = *ppabyData;
+
+ try
+ {
+ unsigned int nKey = 0;
+ while( pabyData < pabyDataLimit )
+ {
+ READ_FIELD_KEY(nKey);
+ if( nKey == MAKE_KEY(knLAYER, WT_DATA) )
+ {
+ unsigned int nLayerSize = 0;
+ READ_SIZE(pabyData, pabyDataLimit, nLayerSize);
+ const GByte* pabyDataLimitLayer = pabyData + nLayerSize;
+ std::shared_ptr<MVTTileLayer> poLayer(new MVTTileLayer());
+ addLayer(poLayer);
+ if( !poLayer->read(&pabyData, pabyDataLimitLayer) )
+ return false;
+ pabyData = pabyDataLimitLayer;
+ }
+ else
+ {
+ SKIP_UNKNOWN_FIELD(pabyData, pabyDataLimit, FALSE);
+ }
+ }
+ *ppabyData = pabyData;
+ return true;
+ }
+ catch( const GPBException& )
+ {
+ return false;
+ }
+}
+
+/************************************************************************/
+/* read() */
+/************************************************************************/
+
+bool MVTTile::read(const GByte* pabyData, const GByte* pabyEnd)
+{
+ return read(&pabyData, pabyEnd);
+}
+
+#endif
Added: sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile.h
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile.h (rev 0)
+++ sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile.h 2019-09-21 17:25:40 UTC (rev 9605)
@@ -0,0 +1,355 @@
+/******************************************************************************
+ *
+ * Project: MVT Translator
+ * Purpose: Mapbox Vector Tile decoder and encoder
+ * Author: Even Rouault, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#ifndef MVT_TILE_H
+#define MVT_TILE_H
+
+#include "cpl_port.h"
+
+#include <memory>
+#include <vector>
+
+/* See https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto */
+constexpr int knLAYER = 3;
+
+constexpr int knLAYER_NAME = 1;
+constexpr int knLAYER_FEATURES = 2;
+constexpr int knLAYER_KEYS = 3;
+constexpr int knLAYER_VALUES = 4;
+constexpr int knLAYER_EXTENT = 5;
+constexpr int knLAYER_VERSION = 15;
+
+constexpr int knVALUE_STRING = 1;
+constexpr int knVALUE_FLOAT = 2;
+constexpr int knVALUE_DOUBLE = 3;
+constexpr int knVALUE_INT = 4;
+constexpr int knVALUE_UINT = 5;
+constexpr int knVALUE_SINT = 6;
+constexpr int knVALUE_BOOL = 7;
+
+constexpr int knFEATURE_ID = 1;
+constexpr int knFEATURE_TAGS = 2;
+constexpr int knFEATURE_TYPE = 3;
+constexpr int knFEATURE_GEOMETRY = 4;
+
+constexpr int knGEOM_TYPE_UNKNOWN = 0;
+constexpr int knGEOM_TYPE_POINT = 1;
+constexpr int knGEOM_TYPE_LINESTRING = 2;
+constexpr int knGEOM_TYPE_POLYGON = 3;
+
+constexpr int knCMD_MOVETO = 1;
+constexpr int knCMD_LINETO = 2;
+constexpr int knCMD_CLOSEPATH = 7;
+
+constexpr unsigned knDEFAULT_EXTENT = 4096;
+
+/************************************************************************/
+/* MVTTileLayerValue */
+/************************************************************************/
+
+class MVTTileLayerValue
+{
+ public:
+ enum class ValueType
+ {
+ NONE,
+ STRING,
+ FLOAT,
+ DOUBLE,
+ INT,
+ UINT,
+ SINT,
+ BOOL,
+ STRING_MAX_8, // optimization for short strings.
+ };
+
+ private:
+ // Layout optimized for small memory footprint
+ union
+ {
+ float m_fValue;
+ double m_dfValue;
+ GInt64 m_nIntValue;
+ GUInt64 m_nUIntValue;
+ bool m_bBoolValue;
+ char* m_pszValue;
+ char m_achValue[8]; // optimization for short strings
+ };
+ ValueType m_eType = ValueType::NONE;
+
+ void unset();
+
+ public:
+ MVTTileLayerValue();
+ ~MVTTileLayerValue();
+ MVTTileLayerValue(const MVTTileLayerValue& oOther);
+ MVTTileLayerValue& operator=(const MVTTileLayerValue& oOther);
+
+ bool operator <(const MVTTileLayerValue& rhs) const;
+
+ ValueType getType() const { return m_eType; }
+ bool isNumeric() const { return m_eType == ValueType::FLOAT ||
+ m_eType == ValueType::DOUBLE ||
+ m_eType == ValueType::INT ||
+ m_eType == ValueType::UINT ||
+ m_eType == ValueType::SINT; }
+ bool isString() const { return m_eType == ValueType::STRING ||
+ m_eType == ValueType::STRING_MAX_8; }
+
+ float getFloatValue() const { return m_fValue; }
+ double getDoubleValue() const { return m_dfValue; }
+ GInt64 getIntValue() const { return m_nIntValue; }
+ GUInt64 getUIntValue() const { return m_nUIntValue; }
+ bool getBoolValue() const { return m_bBoolValue; }
+
+ double getNumericValue() const
+ { if( m_eType == ValueType::FLOAT )
+ return m_fValue;
+ if( m_eType == ValueType::DOUBLE )
+ return m_dfValue;
+ if( m_eType == ValueType::INT || m_eType == ValueType::SINT )
+ return static_cast<double>(m_nIntValue);
+ if( m_eType == ValueType::UINT )
+ return static_cast<double>(m_nUIntValue);
+ return 0.0;
+ }
+
+ std::string getStringValue() const
+ { if( m_eType == ValueType::STRING )
+ return m_pszValue;
+ else if( m_eType == ValueType::STRING_MAX_8 )
+ {
+ char szBuf[8+1];
+ memcpy(szBuf, m_achValue, 8);
+ szBuf[8] = 0;
+ return szBuf;
+ }
+ return std::string();
+ }
+
+ void setStringValue(const std::string& osValue);
+ void setFloatValue(float fValue)
+ { unset(); m_eType = ValueType::FLOAT; m_fValue = fValue; }
+ void setDoubleValue(double dfValue)
+ { unset(); m_eType = ValueType::DOUBLE; m_dfValue = dfValue; }
+ void setIntValue(GInt64 nVal)
+ { unset(); m_eType = ValueType::INT; m_nIntValue = nVal; }
+ void setUIntValue(GUInt64 nVal)
+ { unset(); m_eType = ValueType::UINT; m_nUIntValue = nVal; }
+ void setSIntValue(GInt64 nVal)
+ { unset(); m_eType = ValueType::SINT; m_nIntValue = nVal; }
+ void setBoolValue(bool bVal)
+ { unset(); m_eType = ValueType::BOOL; m_bBoolValue = bVal; }
+
+ void setValue(double dfVal);
+ void setValue(int nVal) { setValue(static_cast<GInt64>(nVal)); }
+ void setValue(GInt64 nVal)
+ { if (nVal < 0)
+ setSIntValue(nVal);
+ else
+ setUIntValue(nVal);
+ }
+
+ size_t getSize() const;
+ void write(GByte** ppabyData) const;
+ bool read(const GByte** ppabyData, const GByte* pabyEnd);
+};
+
+/************************************************************************/
+/* MVTTileLayerFeature */
+/************************************************************************/
+
+class MVTTileLayer;
+
+class MVTTileLayerFeature
+{
+ public:
+ enum class GeomType: char
+ {
+ UNKNOWN = 0,
+ POINT = 1,
+ LINESTRING = 2,
+ POLYGON = 3
+ };
+
+ private:
+ mutable size_t m_nCachedSize = 0;
+ GUInt64 m_nId = 0;
+ std::vector<GUInt32> m_anTags;
+ std::vector<GUInt32> m_anGeometry;
+ GeomType m_eType = GeomType::UNKNOWN;
+ mutable bool m_bCachedSize = false;
+ bool m_bHasId = false;
+ bool m_bHasType = false;
+ MVTTileLayer* m_poOwner = nullptr;
+
+ public:
+ MVTTileLayerFeature();
+ void setOwner(MVTTileLayer* poOwner);
+
+ bool hasId() const { return m_bHasId; }
+ GUInt64 getId() const { return m_nId; }
+ const std::vector<GUInt32>& getTags() const { return m_anTags; }
+ bool hasType() const { return m_bHasType; }
+ GeomType getType() const { return m_eType; }
+ GUInt32 getGeometryCount() const
+ { return static_cast<GUInt32>(m_anGeometry.size()); }
+ const std::vector<GUInt32>& getGeometry() const { return m_anGeometry; }
+
+ void setId(GUInt64 nId)
+ { m_bHasId = true;
+ m_nId = nId;
+ invalidateCachedSize(); }
+ void addTag(GUInt32 nTag)
+ { m_anTags.push_back(nTag);
+ invalidateCachedSize(); }
+ void setType(GeomType eType)
+ { m_bHasType = true;
+ m_eType = eType;
+ invalidateCachedSize(); }
+ void resizeGeometryArray(GUInt32 nNewSize)
+ { m_anGeometry.resize(nNewSize);
+ invalidateCachedSize(); }
+ void addGeometry(GUInt32 nGeometry)
+ { m_anGeometry.push_back(nGeometry);
+ invalidateCachedSize(); }
+ void setGeometry(GUInt32 nIdx, GUInt32 nVal)
+ { m_anGeometry[nIdx] = nVal;
+ invalidateCachedSize(); }
+ void setGeometry(const std::vector<GUInt32>& anGeometry )
+ { m_anGeometry = anGeometry;
+ invalidateCachedSize(); }
+
+ size_t getSize() const;
+ void write(GByte** ppabyData) const;
+ bool read(const GByte** ppabyData, const GByte* pabyEnd);
+
+ void invalidateCachedSize();
+};
+
+/************************************************************************/
+/* MVTTileLayer */
+/************************************************************************/
+
+class MVTTile;
+
+class MVTTileLayer
+{
+ mutable bool m_bCachedSize = false;
+ mutable size_t m_nCachedSize = 0;
+ GUInt32 m_nVersion = 1;
+ std::string m_osName;
+ std::vector<std::shared_ptr<MVTTileLayerFeature>> m_apoFeatures;
+ std::vector<std::string> m_aosKeys;
+ std::vector<MVTTileLayerValue> m_aoValues;
+ bool m_bHasExtent = false;
+ GUInt32 m_nExtent = 4096;
+ MVTTile* m_poOwner = nullptr;
+
+ public:
+ MVTTileLayer();
+ void setOwner(MVTTile* poOwner);
+
+ GUInt32 getVersion() const { return m_nVersion; }
+ const std::string& getName() const { return m_osName; }
+ const std::vector<std::shared_ptr<MVTTileLayerFeature>>& getFeatures()
+ const
+ { return m_apoFeatures; }
+ const std::vector<std::string>& getKeys() const { return m_aosKeys; }
+ const std::vector<MVTTileLayerValue>& getValues() const
+ { return m_aoValues; }
+ GUInt32 getExtent() const { return m_nExtent; }
+
+ void setVersion(GUInt32 nVersion)
+ { m_nVersion = nVersion;
+ invalidateCachedSize(); }
+ void setName(const std::string& osName)
+ { m_osName = osName;
+ invalidateCachedSize(); }
+ size_t addFeature(std::shared_ptr<MVTTileLayerFeature> poFeature);
+ GUInt32 addKey(const std::string& osKey)
+ {
+ m_aosKeys.push_back(osKey);
+ invalidateCachedSize();
+ return static_cast<GUInt32>(m_aosKeys.size()) - 1;
+ }
+
+ GUInt32 addValue(const MVTTileLayerValue& oValue)
+ {
+ m_aoValues.push_back(oValue);
+ invalidateCachedSize();
+ return static_cast<GUInt32>(m_aoValues.size()) - 1;
+ }
+
+ void setExtent(GUInt32 nExtent)
+ {
+ m_nExtent = nExtent;
+ m_bHasExtent = true;
+ invalidateCachedSize();
+ }
+
+ size_t getSize() const;
+ void write(GByte** ppabyData) const;
+ void write(GByte* pabyData) const;
+ std::string write() const;
+ bool read(const GByte** ppabyData, const GByte* pabyEnd);
+ bool read(const GByte* pabyData, const GByte* pabyEnd);
+
+ void invalidateCachedSize();
+};
+
+/************************************************************************/
+/* MVTTile */
+/************************************************************************/
+
+class MVTTile
+{
+ std::vector<std::shared_ptr<MVTTileLayer>> m_apoLayers;
+ mutable size_t m_nCachedSize = 0;
+ mutable bool m_bCachedSize = false;
+
+ public:
+ MVTTile();
+
+ const std::vector<std::shared_ptr<MVTTileLayer>>& getLayers() const
+ { return m_apoLayers; }
+
+ void clear() { m_apoLayers.clear(); invalidateCachedSize(); }
+ void addLayer(std::shared_ptr<MVTTileLayer> poLayer);
+ size_t getSize() const;
+ void write(GByte** ppabyData) const;
+ void write(GByte* pabyData) const;
+ std::string write() const;
+#ifdef ADD_MVT_TILE_READ
+ bool read(const GByte** ppabyData, const GByte* pabyEnd);
+ bool read(const GByte* pabyData, const GByte* pabyEnd);
+#endif
+ void invalidateCachedSize() { m_bCachedSize = false; m_nCachedSize = 0; }
+};
+
+#endif // MVT_TILE_H
Added: sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile_test.cpp
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile_test.cpp (rev 0)
+++ sandbox/jng/mvt_alt/Common/Renderers/mvt/mvt_tile_test.cpp 2019-09-21 17:25:40 UTC (rev 9605)
@@ -0,0 +1,203 @@
+/******************************************************************************
+ *
+ * Project: MVT Translator
+ * Purpose: Test Mapbox Vector Tile encoder
+ * Author: Even Rouault, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#define ADD_MVT_TILE_READ
+#include "mvt_tile.h"
+#include "mvt_tile.cpp"
+
+#include "cpl_conv.h"
+#include "cpl_error.h"
+#include "cpl_vsi.h"
+
+#include <limits>
+#include <memory>
+
+int main()
+{
+ {
+ MVTTile oEmptyTile;
+ CPLAssert( oEmptyTile.getSize() == 0 );
+ }
+
+ {
+ MVTTile oTile;
+ MVTTileLayer* poLayer = new MVTTileLayer();
+ oTile.addLayer( std::shared_ptr<MVTTileLayer>(poLayer) );
+ CPLAssert( oTile.getSize() ==
+ 1 /* layer key */ +
+ 1 /* layer size*/ +
+ 1 /* name key */ +
+ 1 /* version size */ +
+ 1 /* version key */ +
+ 1 /* version */
+ );
+ }
+
+ {
+ MVTTile oTile;
+ MVTTileLayer* poLayer = new MVTTileLayer();
+ oTile.addLayer( std::shared_ptr<MVTTileLayer>(poLayer) );
+ MVTTileLayerFeature* poFeature = new MVTTileLayerFeature();
+ poLayer->setVersion(2);
+ poLayer->setName(std::string("my_layer"));
+ poLayer->setExtent(4096);
+ poLayer->addFeature( std::shared_ptr<MVTTileLayerFeature>(poFeature) );
+ poLayer->addKey(std::string("key0"));
+ {
+ MVTTileLayerValue oValue;
+ oValue.setStringValue(std::string(""));
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setStringValue(std::string("x"));
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setStringValue(std::string("1234567"));
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setStringValue(std::string("12345678"));
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setStringValue(std::string("123456789"));
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setIntValue(-1);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setUIntValue(1);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setSIntValue(-1);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setFloatValue(1.25f);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setDoubleValue(1.25);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setBoolValue(true);
+ poLayer->addValue(oValue);
+ }
+
+ {
+ MVTTileLayerValue oValue;
+ oValue.setValue(123456);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setValue(-123456);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setValue(123456.0);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setValue(-123456.0);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setValue(1.25);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setValue(1.256789);
+ poLayer->addValue(oValue);
+ }
+ {
+ MVTTileLayerValue oValue;
+ oValue.setValue(std::numeric_limits<double>::infinity());
+ poLayer->addValue(oValue);
+ }
+
+ poFeature->setId(1);
+ poFeature->addTag(0);
+ poFeature->addTag(0);
+ poFeature->setType(MVTTileLayerFeature::GeomType::POINT);
+ poFeature->addGeometry(9);
+ poFeature->addGeometry(0);
+ poFeature->addGeometry(0);
+
+ poLayer->addFeature(
+ std::shared_ptr<MVTTileLayerFeature>(new MVTTileLayerFeature()) );
+
+ oTile.addLayer( std::shared_ptr<MVTTileLayer>(new MVTTileLayer()) );
+
+ poLayer = new MVTTileLayer();
+ oTile.addLayer( std::shared_ptr<MVTTileLayer>(poLayer) );
+ poLayer->addValue(MVTTileLayerValue());
+
+ size_t nSize = oTile.getSize();
+ GByte* pabyBuffer = static_cast<GByte*>(CPLMalloc(nSize));
+ oTile.write(pabyBuffer);
+ VSILFILE* fp = VSIFOpenL("out.gpb", "wb");
+ if( fp )
+ {
+ VSIFWriteL(pabyBuffer, 1, nSize, fp);
+ VSIFCloseL(fp);
+ }
+
+ MVTTile oTileDeserialized;
+ bool bRet = oTileDeserialized.read(pabyBuffer, pabyBuffer + nSize);
+ CPLAssert(bRet);
+ size_t nSize2 = oTileDeserialized.getSize();
+ CPLAssert(nSize == nSize2);
+ GByte* pabyBuffer2 = static_cast<GByte*>(CPLMalloc(nSize2));
+ oTileDeserialized.write(pabyBuffer2);
+ CPLAssert(memcmp(pabyBuffer, pabyBuffer2, nSize) == 0);
+ CPLFree(pabyBuffer);
+ CPLFree(pabyBuffer2);
+ }
+
+ return 0;
+}
Added: sandbox/jng/mvt_alt/Common/Renderers/mvt/mvtutils.cpp
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/mvt/mvtutils.cpp (rev 0)
+++ sandbox/jng/mvt_alt/Common/Renderers/mvt/mvtutils.cpp 2019-09-21 17:25:40 UTC (rev 9605)
@@ -0,0 +1,218 @@
+/******************************************************************************
+ *
+ * Project: MVT Translator
+ * Purpose: Mapbox Vector Tile decoder
+ * Author: Even Rouault, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "mvtutils.h"
+#include "ogr_api.h"
+
+/************************************************************************/
+/* OGRMVTInitFields() */
+/************************************************************************/
+
+void OGRMVTInitFields(OGRFeatureDefn* poFeatureDefn,
+ const CPLJSONObject& oFields)
+{
+ {
+ OGRFieldDefn oFieldDefnId("mvt_id", OFTInteger64);
+ poFeatureDefn->AddFieldDefn(&oFieldDefnId);
+ }
+
+ if( oFields.IsValid() )
+ {
+ for( const auto& oField: oFields.GetChildren() )
+ {
+ if( oField.GetType() == CPLJSONObject::String )
+ {
+ if( oField.ToString() == "Number" )
+ {
+ OGRFieldDefn oFieldDefn(
+ oField.GetName().c_str(), OFTReal );
+ poFeatureDefn->AddFieldDefn(&oFieldDefn);
+ }
+ else if( oField.ToString() == "Integer" ) // GDAL extension
+ {
+ OGRFieldDefn oFieldDefn(
+ oField.GetName().c_str(), OFTInteger );
+ poFeatureDefn->AddFieldDefn(&oFieldDefn);
+ }
+ else if( oField.ToString() == "Boolean" )
+ {
+ OGRFieldDefn oFieldDefn(
+ oField.GetName().c_str(), OFTInteger );
+ oFieldDefn.SetSubType(OFSTBoolean);
+ poFeatureDefn->AddFieldDefn(&oFieldDefn);
+ }
+ else
+ {
+ OGRFieldDefn oFieldDefn(
+ oField.GetName().c_str(), OFTString );
+ poFeatureDefn->AddFieldDefn(&oFieldDefn);
+ }
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* OGRMVTFindGeomTypeFromTileStat() */
+/************************************************************************/
+
+OGRwkbGeometryType OGRMVTFindGeomTypeFromTileStat(
+ const CPLJSONArray& oTileStatLayers,
+ const char* pszLayerName)
+{
+ OGRwkbGeometryType eGeomType = wkbUnknown;
+ for( int i = 0; i < oTileStatLayers.Size(); i++ )
+ {
+ CPLJSONObject oId =
+ oTileStatLayers[i].GetObj("layer");
+ if( oId.IsValid() && oId.GetType() ==
+ CPLJSONObject::String )
+ {
+ if( oId.ToString() == pszLayerName )
+ {
+ CPLJSONObject oGeom =
+ oTileStatLayers[i].GetObj("geometry");
+ if( oGeom.IsValid() && oGeom.GetType() ==
+ CPLJSONObject::String )
+ {
+ const std::string oGeomType(
+ oGeom.ToString());
+ // Note: this information is not
+ // reliable in case
+ // of mix of geometry types
+ if( oGeomType == "Point" )
+ {
+ eGeomType = wkbMultiPoint;
+ }
+ else if( oGeomType == "LineString" )
+ {
+ eGeomType = wkbMultiLineString;
+ }
+ else if( oGeomType == "Polygon" )
+ {
+ eGeomType = wkbMultiPolygon;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return eGeomType;
+}
+
+
+/************************************************************************/
+/* OGRMVTCreateFeatureFrom() */
+/************************************************************************/
+
+OGRFeature* OGRMVTCreateFeatureFrom(OGRFeature* poSrcFeature,
+ OGRFeatureDefn* poTargetFeatureDefn,
+ bool bJsonField,
+ OGRSpatialReference* poSRS)
+{
+ OGRFeature* poFeature = new OGRFeature(poTargetFeatureDefn);
+ if( bJsonField )
+ {
+ CPLJSONObject oProperties;
+ bool bEmpty = true;
+ for( int i = 1; i < poSrcFeature->GetFieldCount(); i++ )
+ {
+ if( poSrcFeature->IsFieldSet(i) )
+ {
+ bEmpty = false;
+ OGRFieldDefn* poFDefn = poSrcFeature->GetFieldDefnRef(i);
+ if( poSrcFeature->IsFieldNull(i) )
+ {
+ oProperties.AddNull(poFDefn->GetNameRef());
+ }
+ else if( poFDefn->GetType() == OFTInteger ||
+ poFDefn->GetType() == OFTInteger64 )
+ {
+ if( poFDefn->GetSubType() == OFSTBoolean )
+ {
+ oProperties.Add(poFDefn->GetNameRef(),
+ poSrcFeature->GetFieldAsInteger(i) == 1);
+ }
+ else
+ {
+ oProperties.Add(poFDefn->GetNameRef(),
+ poSrcFeature->GetFieldAsInteger64(i));
+ }
+ }
+ else if( poFDefn->GetType() == OFTReal )
+ {
+ oProperties.Add(poFDefn->GetNameRef(),
+ poSrcFeature->GetFieldAsDouble(i));
+ }
+ else
+ {
+ oProperties.Add(poFDefn->GetNameRef(),
+ poSrcFeature->GetFieldAsString(i));
+ }
+ }
+ }
+ if( !bEmpty )
+ {
+ poFeature->SetField("json",
+ oProperties.Format(CPLJSONObject::Pretty).c_str());
+ }
+
+ OGRGeometry* poSrcGeom = poSrcFeature->GetGeometryRef();
+ if( poSrcGeom )
+ {
+ poFeature->SetGeometry( poSrcGeom );
+ }
+#ifdef nodef
+ CPLJSONObject oObj;
+ oObj.Add("type", "Feature");
+ if( poSrcFeature->IsFieldSet(0) )
+ oObj.Add("id", poSrcFeature->GetFieldAsInteger64("mvt_id"));
+ oObj.Add("properties", oProperties);
+ if( poSrcGeom )
+ {
+ char* pszGeomJson = OGR_G_ExportToJson(
+ reinterpret_cast<OGRGeometryH>(poSrcGeom) );
+ CPLJSONDocument oJSonDoc;
+ oJSonDoc.LoadMemory(reinterpret_cast<const GByte*>(pszGeomJson));
+ CPLFree(pszGeomJson);
+ oObj.Add( "geometry", oJSonDoc.GetRoot() );
+ }
+ poFeature->SetNativeData(
+ oObj.Format(CPLJSONObject::Pretty).c_str());
+ poFeature->SetNativeMediaType("application/vnd.geo+json");
+#endif
+ }
+ else
+ {
+ poFeature->SetFrom( poSrcFeature );
+ }
+ OGRGeometry* poGeom = poFeature->GetGeometryRef();
+ if( poGeom )
+ poGeom->assignSpatialReference(poSRS);
+ return poFeature;
+}
Added: sandbox/jng/mvt_alt/Common/Renderers/mvt/mvtutils.h
===================================================================
--- sandbox/jng/mvt_alt/Common/Renderers/mvt/mvtutils.h (rev 0)
+++ sandbox/jng/mvt_alt/Common/Renderers/mvt/mvtutils.h 2019-09-21 17:25:40 UTC (rev 9605)
@@ -0,0 +1,91 @@
+/******************************************************************************
+ *
+ * Project: MVT Translator
+ * Purpose: Mapbox Vector Tile decoder
+ * Author: Even Rouault, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#ifndef MVTUTILS_H
+#define MVTUTILS_H
+
+#include "cpl_json.h"
+#include "ogrsf_frmts.h"
+
+#define MVT_LCO \
+"<LayerCreationOptionList>" \
+" <Option name='MINZOOM' type='int' min='0' max='22' " \
+ "description='Minimum zoom level'/>" \
+" <Option name='MAXZOOM' type='int' min='0' max='22' " \
+ "description='Maximum zoom level'/>" \
+" <Option name='NAME' type='string' description='Target layer name'/>" \
+" <Option name='DESCRIPTION' type='string' " \
+ "description='A description of the layer'/>" \
+"</LayerCreationOptionList>"
+
+#define MVT_MBTILES_COMMON_DSCO \
+" <Option name='MINZOOM' scope='vector' type='int' min='0' max='22' " \
+ "description='Minimum zoom level' default='0'/>" \
+" <Option name='MAXZOOM' scope='vector' type='int' min='0' max='22' " \
+ "description='Maximum zoom level' default='5'/>" \
+" <Option name='CONF' scope='vector' type='string' " \
+ "description='Layer configuration as a JSon serialized string, or a filename pointing to a JSon file'/>" \
+" <Option name='SIMPLIFICATION' scope='vector' type='float' " \
+ "description='Simplification factor'/>" \
+" <Option name='SIMPLIFICATION_MAX_ZOOM' scope='vector' type='float' " \
+ "description='Simplification factor at max zoom'/>" \
+" <Option name='EXTENT' scope='vector' type='unsigned int' default='4096' " \
+ "description='Number of units in a tile'/>" \
+" <Option name='BUFFER' scope='vector' type='unsigned int' default='80' " \
+ "description='Number of units for geometry buffering'/>" \
+" <Option name='COMPRESS' scope='vector' type='boolean' description=" \
+ "'Whether to deflate-compress tiles' default='YES'/>" \
+" <Option name='TEMPORARY_DB' scope='vector' type='string' description='" \
+ "Filename with path for the temporary database'/>" \
+" <Option name='MAX_SIZE' scope='vector' type='unsigned int' min='100' default='500000' " \
+ "description='Maximum size of a tile in bytes'/>" \
+" <Option name='MAX_FEATURES' scope='vector' type='unsigned int' min='1' default='200000' " \
+ "description='Maximum number of features per tile'/>"
+
+void OGRMVTInitFields(OGRFeatureDefn* poFeatureDefn,
+ const CPLJSONObject& oFields);
+
+OGRwkbGeometryType OGRMVTFindGeomTypeFromTileStat(
+ const CPLJSONArray& oTileStatLayers,
+ const char* pszLayerName);
+
+OGRFeature* OGRMVTCreateFeatureFrom(OGRFeature* poSrcFeature,
+ OGRFeatureDefn* poTargetFeatureDefn,
+ bool bJsonField,
+ OGRSpatialReference* poSRS);
+
+#ifdef HAVE_MVT_WRITE_SUPPORT
+GDALDataset* OGRMVTWriterDatasetCreate( const char * pszFilename,
+ int nXSize,
+ int nYSize,
+ int nBandsIn,
+ GDALDataType eDT,
+ char ** papszOptions );
+#endif
+
+#endif // MVTUTILS_H
More information about the mapguide-commits
mailing list