File indexing completed on 2024-05-12 04:42:47

0001 /*
0002     SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #ifndef KPUBLICTRANSPORT_POLYLINEDECODER_P_H
0008 #define KPUBLICTRANSPORT_POLYLINEDECODER_P_H
0009 
0010 #include "kpublictransport_export.h"
0011 
0012 #include <QPolygonF>
0013 
0014 #include <array>
0015 #include <cstdint>
0016 #include <cstring>
0017 #include <limits>
0018 
0019 namespace KPublicTransport {
0020 
0021 ///@cond internal
0022 class PolylineDecoderBase {
0023 protected:
0024     explicit inline PolylineDecoderBase(const char *const begin, const char *const end)
0025         : m_it(begin)
0026         , m_end(end)
0027     {}
0028 
0029     inline bool canReadMore() const
0030     {
0031         return m_it != m_end && *m_it;
0032     }
0033 
0034     KPUBLICTRANSPORT_EXPORT int32_t readNextIntNonDifferential();
0035 
0036     const char *m_it = nullptr;
0037     const char *m_end = nullptr;
0038 };
0039 ///@endcond
0040 
0041 /**
0042  * Decoder for Google's Polyline format.
0043  * @see https://developers.google.com/maps/documentation/utilities/polylinealgorithm
0044  */
0045 template <int Dim = 2, bool Differential = true>
0046 class PolylineDecoder : PolylineDecoderBase
0047 {
0048 public:
0049     explicit inline PolylineDecoder(const char *const begin, const char *const end)
0050         : PolylineDecoderBase(begin, end)
0051     {
0052         m_accu.fill(0);
0053     }
0054 
0055     template <std::size_t N>
0056     explicit inline PolylineDecoder(const char (&data)[N])
0057         : PolylineDecoder(std::begin(data), std::end(data)) {}
0058 
0059     explicit inline PolylineDecoder(const char *data)
0060         : PolylineDecoder(data, data + std::strlen(data)) {}
0061 
0062     ~PolylineDecoder() = default;
0063 
0064     constexpr inline int dimensions() const { return Dim; }
0065 
0066     using PolylineDecoderBase::canReadMore;
0067 
0068     inline int32_t readNextInt()
0069     {
0070         auto n = readNextIntNonDifferential();
0071         if constexpr(Differential) {
0072             n += m_accu[m_nextDim];
0073             m_accu[m_nextDim++] = n;
0074             m_nextDim %= Dim;
0075         }
0076         return n;
0077     }
0078 
0079     inline double readNextDouble()
0080     {
0081         return readNextInt() / 100000.0;
0082     }
0083 
0084     inline void readPolygon(QPolygonF &polygon, int maxEntries = -1)
0085     {
0086         static_assert(Dim == 2, "Polygons require a two-dimensional polyline");
0087         if (maxEntries > 0) {
0088             polygon.reserve(polygon.size() + maxEntries);
0089         }
0090         while (canReadMore() && maxEntries != 0) {
0091             const auto lat = readNextDouble();
0092             const auto lon = readNextDouble();
0093             polygon.push_back({lon, lat});
0094             --maxEntries;
0095         }
0096     }
0097 
0098 private:
0099     int m_nextDim = 0;
0100     std::array<int32_t, Dim> m_accu;
0101 };
0102 
0103 }
0104 
0105 #endif // KPUBLICTRANSPORT_POLYLINEDECODER_P_H