Shapes
GIS made easy, a lightweight header-only planar geometry library for Modern C++
polyline.hpp
1 #pragma once
2 
3 #include <ciso646>
4 #include <simo/exceptions.hpp>
5 
6 namespace simo
7 {
8 namespace shapes
9 {
10 namespace polyline
11 {
12 
14 constexpr static const int32_t CHUNK_SIZE = 5;
15 
17 constexpr static const int32_t CHUNK_MASK = 0x1f;
18 
20 constexpr static const int32_t CHUNK_THRESHOLD = 0x20;
21 
23 constexpr static const int32_t ASCII_OFFSET = 63;
24 
33 std::string encode(double coord, int32_t precision = 5)
34 {
35  assert(precision >= 0);
36  double pow10 = std::pow(10, precision);
37  auto value = static_cast<int32_t>(std::round(coord * pow10));
38  value <<= 1;
39  if (coord < 0)
40  {
41  value = ~value;
42  }
43  std::string res;
44  while (value >= CHUNK_THRESHOLD)
45  {
46  int32_t ch = ((value & CHUNK_MASK) | CHUNK_THRESHOLD) + ASCII_OFFSET;
47  res += static_cast<char>(ch);
48  value >>= CHUNK_SIZE;
49  }
50  res += static_cast<char>(value + ASCII_OFFSET);
51  return res;
52 }
53 
62 int32_t advance(const std::string& text, size_t& index)
63 {
64  int32_t res = 0;
65  int32_t shift = 0;
66  char ch = 0;
67  while (index < text.size())
68  {
69  ch = text[index++] - ASCII_OFFSET;
70  res |= (ch & CHUNK_MASK) << shift;
71  shift += CHUNK_SIZE;
72  if (ch < CHUNK_THRESHOLD)
73  {
74  break;
75  }
76  }
77  if (res & 1)
78  {
79  res = ~res;
80  }
81  res >>= 1;
82  return res;
83 }
84 
94 std::vector<double> decode(const std::string& text, int32_t precision = 5)
95 {
96  assert(precision >= 0);
97  double pow10 = std::pow(10, precision);
98  std::vector<double> res;
99  res.reserve(text.size() / 3);
100  size_t index = 0;
101  int32_t y = 0;
102  int32_t x = 0;
103  while (index < text.size())
104  {
105  y += advance(text, index);
106  x += advance(text, index);
107  res.push_back(x / pow10);
108  res.push_back(y / pow10);
109  }
110  return res;
111 }
112 
113 } // namespace polyline
114 } // namespace shapes
115 } // namespace simo