mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-30 01:24:07 +00:00
Organic Maps sources as of 02.04.2025 (fad26bbf22ac3da75e01e62aa01e5c8e11861005)
To expand with full Organic Maps and Maps.ME commits history run: git remote add om-historic [om-historic.git repo url] git fetch --tags om-historic git replace squashed-history historic-commits
This commit is contained in:
181
ge0/url_generator.cpp
Normal file
181
ge0/url_generator.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "ge0/url_generator.hpp"
|
||||
|
||||
#include "coding/url.hpp"
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
// Replaces ' ' with '_' and vice versa.
|
||||
std::string TransformName(std::string const & s)
|
||||
{
|
||||
std::string result = s;
|
||||
for (auto & c : result)
|
||||
{
|
||||
if (c == ' ')
|
||||
c = '_';
|
||||
else if (c == '_')
|
||||
c = ' ';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// URL-encodes string |s|.
|
||||
// URL restricted / unsafe / unwise characters are %-encoded.
|
||||
// See rfc3986, rfc1738, rfc2396.
|
||||
//
|
||||
// Not compatible with the url encode function from coding/.
|
||||
std::string UrlEncodeString(std::string const & s)
|
||||
{
|
||||
std::string result;
|
||||
result.reserve(s.size() * 3 + 1);
|
||||
for (size_t i = 0; i < s.size(); ++i)
|
||||
{
|
||||
auto const c = static_cast<unsigned char>(s[i]);
|
||||
switch (c)
|
||||
{
|
||||
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
|
||||
case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F:
|
||||
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
|
||||
case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F:
|
||||
case 0x7F:
|
||||
case ' ':
|
||||
case '<':
|
||||
case '>':
|
||||
case '#':
|
||||
case '%':
|
||||
case '"':
|
||||
case '!':
|
||||
case '*':
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case ';':
|
||||
case ':':
|
||||
case '@':
|
||||
case '&':
|
||||
case '=':
|
||||
case '+':
|
||||
case '$':
|
||||
case ',':
|
||||
case '/':
|
||||
case '?':
|
||||
case '[':
|
||||
case ']':
|
||||
case '{':
|
||||
case '}':
|
||||
case '|':
|
||||
case '^':
|
||||
case '`':
|
||||
result += '%';
|
||||
result += "0123456789ABCDEF"[c >> 4];
|
||||
result += "0123456789ABCDEF"[c & 15];
|
||||
break;
|
||||
default:
|
||||
result += s[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace ge0
|
||||
{
|
||||
std::string GenerateShortShowMapUrl(double lat, double lon, double zoom, std::string const & name)
|
||||
{
|
||||
size_t constexpr schemaLength = 5; // strlen("om://")
|
||||
std::string urlSample = "om://ZCoordba64";
|
||||
|
||||
int const zoomI = (zoom <= 4 ? 0 : (zoom >= 19.75 ? 63 : static_cast<int>((zoom - 4) * 4)));
|
||||
urlSample[schemaLength] = Base64Char(zoomI);
|
||||
|
||||
LatLonToString(lat, lon, urlSample.data() + schemaLength + 1, 9);
|
||||
|
||||
if (!name.empty())
|
||||
{
|
||||
urlSample += '/';
|
||||
urlSample += UrlEncodeString(TransformName(name));
|
||||
}
|
||||
|
||||
return urlSample;
|
||||
}
|
||||
|
||||
std::string GenerateGeoUri(double lat, double lon, double zoom, std::string const & name)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "geo:" << std::fixed << std::setprecision(7) << lat << ',' << lon << "?z=" << std::setprecision(1) << zoom;
|
||||
|
||||
if (!name.empty())
|
||||
oss << '(' << url::UrlEncode(name) << ')';
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
char Base64Char(int x)
|
||||
{
|
||||
CHECK_GREATER_OR_EQUAL(x, 0, ());
|
||||
CHECK_LESS(x, 64, ());
|
||||
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"[x];
|
||||
}
|
||||
|
||||
// Map latitude: [-90, 90] -> [0, maxValue]
|
||||
int LatToInt(double lat, int maxValue)
|
||||
{
|
||||
// M = maxValue, L = maxValue-1
|
||||
// lat: -90 90
|
||||
// x: 0 1 2 L M
|
||||
// |--+--|--+--|--...--|--+--|
|
||||
// 000111111222222...LLLLLMMMM
|
||||
|
||||
double const x = (lat + 90.0) / 180.0 * maxValue;
|
||||
return x < 0 ? 0 : (x > maxValue ? maxValue : static_cast<int>(x + 0.5));
|
||||
}
|
||||
|
||||
// Make lon in [-180, 180)
|
||||
double LonIn180180(double lon)
|
||||
{
|
||||
if (lon >= 0)
|
||||
return fmod(lon + 180.0, 360.0) - 180.0;
|
||||
|
||||
// Handle the case of l = -180
|
||||
double const l = fmod(lon - 180.0, 360.0) + 180.0;
|
||||
return l < 180.0 ? l : l - 360.0;
|
||||
}
|
||||
|
||||
// Map longitude: [-180, 180) -> [0, maxValue]
|
||||
int LonToInt(double lon, int maxValue)
|
||||
{
|
||||
double const x = (LonIn180180(lon) + 180.0) / 360.0 * (maxValue + 1.0) + 0.5;
|
||||
return (x <= 0 || x >= maxValue + 1) ? 0 : static_cast<int>(x);
|
||||
}
|
||||
|
||||
void LatLonToString(double lat, double lon, char * s, size_t nBytes)
|
||||
{
|
||||
if (nBytes > kMaxPointBytes)
|
||||
nBytes = kMaxPointBytes;
|
||||
|
||||
int const latI = LatToInt(lat, (1 << kMaxCoordBits) - 1);
|
||||
int const lonI = LonToInt(lon, (1 << kMaxCoordBits) - 1);
|
||||
|
||||
size_t i;
|
||||
int shift;
|
||||
for (i = 0, shift = kMaxCoordBits - 3; i < nBytes; ++i, shift -= 3)
|
||||
{
|
||||
int const latBits = latI >> shift & 7;
|
||||
int const lonBits = lonI >> shift & 7;
|
||||
|
||||
int const nextByte =
|
||||
(latBits >> 2 & 1) << 5 |
|
||||
(lonBits >> 2 & 1) << 4 |
|
||||
(latBits >> 1 & 1) << 3 |
|
||||
(lonBits >> 1 & 1) << 2 |
|
||||
(latBits & 1) << 1 |
|
||||
(lonBits & 1);
|
||||
|
||||
s[i] = Base64Char(nextByte);
|
||||
}
|
||||
}
|
||||
} // namespace ge0
|
||||
Reference in New Issue
Block a user