From 6b8f3c7fefaf83e782f4cc5da1ce6d5ceaecc9b4 Mon Sep 17 00:00:00 2001 From: Lev Dragunov Date: Tue, 6 Jun 2017 19:51:00 +0300 Subject: [PATCH] Polyline6 support in the REST input --- include/engine/polyline_compressor.hpp | 29 ++++++++-- .../server/api/base_parameters_grammar.hpp | 10 +++- src/engine/polyline_compressor.cpp | 57 +++++-------------- 3 files changed, 49 insertions(+), 47 deletions(-) diff --git a/include/engine/polyline_compressor.hpp b/include/engine/polyline_compressor.hpp index 96d735930..81eedec6c 100644 --- a/include/engine/polyline_compressor.hpp +++ b/include/engine/polyline_compressor.hpp @@ -14,10 +14,8 @@ namespace engine { namespace detail { -constexpr double POLYLINE_DECODING_PRECISION = 1e5; -constexpr double POLYLINE_TO_COORDINATE = COORDINATE_PRECISION / POLYLINE_DECODING_PRECISION; - std::string encode(std::vector &numbers); +std::int32_t decode_polyline_integer(std::string::const_iterator &first, std::string::const_iterator last); } using CoordVectorForwardIter = std::vector::const_iterator; // Encodes geometry into polyline format. @@ -57,7 +55,30 @@ std::string encodePolyline(CoordVectorForwardIter begin, CoordVectorForwardIter // Decodes geometry from polyline format // See: https://developers.google.com/maps/documentation/utilities/polylinealgorithm -std::vector decodePolyline(const std::string &polyline); + +template +std::vector decodePolyline(const std::string &polyline) +{ + double polyline_to_coordinate = COORDINATE_PRECISION / POLYLINE_PRECISION ; + std::vector coordinates; + std::int32_t latitude = 0, longitude = 0; + + std::string::const_iterator first = polyline.begin(); + const std::string::const_iterator last = polyline.end(); + while (first != last) + { + const auto dlat = detail::decode_polyline_integer(first, last); + const auto dlon = detail::decode_polyline_integer(first, last); + + latitude += dlat; + longitude += dlon; + + coordinates.emplace_back( + util::Coordinate{util::FixedLongitude{static_cast(longitude*polyline_to_coordinate)}, + util::FixedLatitude{static_cast(latitude*polyline_to_coordinate)}}); + } + return coordinates; +} } } diff --git a/include/server/api/base_parameters_grammar.hpp b/include/server/api/base_parameters_grammar.hpp index 8d3c5af7c..f176e0acd 100644 --- a/include/server/api/base_parameters_grammar.hpp +++ b/include/server/api/base_parameters_grammar.hpp @@ -128,9 +128,16 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar }, qi::_1)]; + polyline6_rule = qi::as_string[qi::lit("polyline6(") > +polyline_chars > ')'] + [qi::_val = ph::bind( + [](const std::string &polyline) { + return engine::decodePolyline<1000000>(polyline); + }, + qi::_1)]; + query_rule = ((location_rule % ';') | - polyline_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1]; + polyline_rule | polyline6_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1]; radiuses_rule = qi::lit("radiuses=") > (-(qi::double_ | unlimited_rule) % @@ -176,6 +183,7 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar qi::rule bearing_rule; qi::rule location_rule; qi::rule()> polyline_rule; + qi::rule()> polyline6_rule; qi::rule base64_char; qi::rule polyline_chars; diff --git a/src/engine/polyline_compressor.cpp b/src/engine/polyline_compressor.cpp index 24c64f823..ff1bc9c9f 100644 --- a/src/engine/polyline_compressor.cpp +++ b/src/engine/polyline_compressor.cpp @@ -52,54 +52,27 @@ std::string encode(std::vector &numbers) } return output; } -} -std::vector decodePolyline(const std::string &geometry_string) -{ // https://developers.google.com/maps/documentation/utilities/polylinealgorithm - auto decode_polyline_integer = [](auto &first, auto last) { - // varint coding parameters - const std::uint32_t bits_in_chunk = 5; - const std::uint32_t continuation_bit = 1 << bits_in_chunk; - const std::uint32_t chunk_mask = (1 << bits_in_chunk) - 1; +std::int32_t decode_polyline_integer(std::string::const_iterator &first, std::string::const_iterator last) { + // varint coding parameters + const std::uint32_t bits_in_chunk = 5; + const std::uint32_t continuation_bit = 1 << bits_in_chunk; + const std::uint32_t chunk_mask = (1 << bits_in_chunk) - 1; - std::uint32_t result = 0; - for (std::uint32_t value = continuation_bit, shift = 0; - (value & continuation_bit) && (shift < CHAR_BIT * sizeof(result) - 1) && first != last; - ++first, shift += bits_in_chunk) - { - value = *first - 63; // convert ASCII coding [?..~] to an integer [0..63] - result |= (value & chunk_mask) << shift; - } - - // change "zig-zag" sign coding to two's complement - result = ((result & 1) == 1) ? ~(result >> 1) : (result >> 1); - return static_cast(result); - }; - - auto polyline_to_coordinate = [](auto value) { - return static_cast(value * detail::POLYLINE_TO_COORDINATE); - }; - - std::vector coordinates; - std::int32_t latitude = 0, longitude = 0; - - std::string::const_iterator first = geometry_string.begin(); - const std::string::const_iterator last = geometry_string.end(); - while (first != last) + std::uint32_t result = 0; + for (std::uint32_t value = continuation_bit, shift = 0; + (value & continuation_bit) && (shift < CHAR_BIT * sizeof(result) - 1) && first != last; + ++first, shift += bits_in_chunk) { - const auto dlat = decode_polyline_integer(first, last); - const auto dlon = decode_polyline_integer(first, last); - - latitude += dlat; - longitude += dlon; - - coordinates.emplace_back( - util::Coordinate{util::FixedLongitude{polyline_to_coordinate(longitude)}, - util::FixedLatitude{polyline_to_coordinate(latitude)}}); + value = *first - 63; // convert ASCII coding [?..~] to an integer [0..63] + result |= (value & chunk_mask) << shift; } - return coordinates; + // change "zig-zag" sign coding to two's complement + result = ((result & 1) == 1) ? ~(result >> 1) : (result >> 1); + return static_cast(result); +} } } }