Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
203
libs/ge0/url_generator.cpp
Normal file
203
libs/ge0/url_generator.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
#include "ge0/url_generator.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/math.hpp"
|
||||
#include "coding/url.hpp"
|
||||
|
||||
#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("cm://")
|
||||
std::string urlSample = "cm://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;
|
||||
// For Google Maps compatibility, otherwise it doesn't select the point on the map, only shows the area.
|
||||
oss << "&q=" << std::setprecision(7) << lat << ',' << lon;
|
||||
|
||||
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 : math::iround(x));
|
||||
}
|
||||
|
||||
// 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue