osrm-backend/include/server/api/base_parameters_grammar.hpp
Michael Bell d74e7b66bd
Support snapping to multiple ways at an input location ()
This PR improves routing results by adding support for snapping to
multiple ways at input locations.

This means all edges at the snapped location can act as source/target
candidates for routing search, ensuring we always find the best route,
and not the one dependent on the edge selected.
2022-08-27 11:36:20 +01:00

243 lines
9.3 KiB
C++

#ifndef SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP
#define SERVER_API_BASE_PARAMETERS_GRAMMAR_HPP
#include "engine/api/base_parameters.hpp"
#include "engine/bearing.hpp"
#include "engine/hint.hpp"
#include "engine/polyline_compressor.hpp"
#include <boost/optional.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <limits>
#include <string>
namespace osrm
{
namespace server
{
namespace api
{
namespace
{
namespace ph = boost::phoenix;
namespace qi = boost::spirit::qi;
} // namespace
template <typename T, char... Fmt> struct no_trailing_dot_policy : qi::real_policies<T>
{
template <typename Iterator> static bool parse_dot(Iterator &first, Iterator const &last)
{
auto diff = std::distance(first, last);
if (diff <= 0 || *first != '.')
return false;
static const constexpr char fmt[sizeof...(Fmt)] = {Fmt...};
if (sizeof(fmt) < static_cast<size_t>(diff) &&
std::equal(fmt, fmt + sizeof(fmt), first + 1u))
return false;
++first;
return true;
}
template <typename Iterator> static bool parse_exp(Iterator &, const Iterator &)
{
return false;
}
template <typename Iterator, typename Attribute>
static bool parse_exp_n(Iterator &, const Iterator &, Attribute &)
{
return false;
}
template <typename Iterator, typename Attribute>
static bool parse_nan(Iterator &, const Iterator &, Attribute &)
{
return false;
}
template <typename Iterator, typename Attribute>
static bool parse_inf(Iterator &, const Iterator &, Attribute &)
{
return false;
}
};
template <typename Iterator, typename Signature>
struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
{
using json_policy = no_trailing_dot_policy<double, 'j', 's', 'o', 'n'>;
BaseParametersGrammar(qi::rule<Iterator, Signature> &root_rule)
: BaseParametersGrammar::base_type(root_rule)
{
const auto add_hint = [](engine::api::BaseParameters &base_parameters,
const std::vector<std::string> &hint_strings) {
if (!hint_strings.empty())
{
std::vector<engine::SegmentHint> location_hints(hint_strings.size());
std::transform(hint_strings.begin(),
hint_strings.end(),
location_hints.begin(),
[](const auto &hint_string) {
return engine::SegmentHint::FromBase64(hint_string);
});
base_parameters.hints.push_back(engine::Hint{std::move(location_hints)});
}
else
{
base_parameters.hints.emplace_back(boost::none);
}
};
const auto add_bearing =
[](engine::api::BaseParameters &base_parameters,
boost::optional<boost::fusion::vector2<short, short>> bearing_range) {
boost::optional<engine::Bearing> bearing;
if (bearing_range)
{
bearing = engine::Bearing{boost::fusion::at_c<0>(*bearing_range),
boost::fusion::at_c<1>(*bearing_range)};
}
base_parameters.bearings.push_back(std::move(bearing));
};
polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
base64_char = qi::char_("a-zA-Z0-9--_=");
unlimited_rule = qi::lit("unlimited")[qi::_val = std::numeric_limits<double>::infinity()];
bearing_rule =
(qi::short_ > ',' > qi::short_)[qi::_val = ph::bind(
[](short bearing, short range) {
return osrm::engine::Bearing{bearing, range};
},
qi::_1,
qi::_2)];
location_rule = (double_ > qi::lit(',') >
double_)[qi::_val = ph::bind(
[](double lon, double lat) {
return util::Coordinate(
util::toFixed(util::UnsafeFloatLongitude{lon}),
util::toFixed(util::UnsafeFloatLatitude{lat}));
},
qi::_1,
qi::_2)];
polyline_rule = qi::as_string[qi::lit("polyline(") > +polyline_chars > ')']
[qi::_val = ph::bind(
[](const std::string &polyline) {
return engine::decodePolyline(polyline);
},
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 |
polyline6_rule)[ph::bind(&engine::api::BaseParameters::coordinates, qi::_r1) = qi::_1];
radiuses_rule = qi::lit("radiuses=") >
(-(qi::double_ | unlimited_rule) %
';')[ph::bind(&engine::api::BaseParameters::radiuses, qi::_r1) = qi::_1];
hints_rule =
qi::lit("hints=") >
(*qi::as_string[qi::repeat(engine::ENCODED_SEGMENT_HINT_SIZE)[base64_char]])[ph::bind(
add_hint, qi::_r1, qi::_1)] %
';';
generate_hints_rule =
qi::lit("generate_hints=") >
qi::bool_[ph::bind(&engine::api::BaseParameters::generate_hints, qi::_r1) = qi::_1];
skip_waypoints_rule =
qi::lit("skip_waypoints=") >
qi::bool_[ph::bind(&engine::api::BaseParameters::skip_waypoints, qi::_r1) = qi::_1];
bearings_rule =
qi::lit("bearings=") >
(-(qi::short_ > ',' > qi::short_))[ph::bind(add_bearing, qi::_r1, qi::_1)] % ';';
approach_type.add("unrestricted", engine::Approach::UNRESTRICTED)("curb",
engine::Approach::CURB);
approach_rule = qi::lit("approaches=") >
(-approach_type %
';')[ph::bind(&engine::api::BaseParameters::approaches, qi::_r1) = qi::_1];
snapping_type.add("default", engine::api::BaseParameters::SnappingType::Default)(
"any", engine::api::BaseParameters::SnappingType::Any);
snapping_rule =
qi::lit("snapping=") >
snapping_type[ph::bind(&engine::api::BaseParameters::snapping, qi::_r1) = qi::_1];
format_type.add(".json", engine::api::BaseParameters::OutputFormatType::JSON)(
".flatbuffers", engine::api::BaseParameters::OutputFormatType::FLATBUFFERS);
format_rule =
-format_type[ph::bind(&engine::api::BaseParameters::format, qi::_r1) = qi::_1];
exclude_rule = qi::lit("exclude=") >
(qi::as_string[+qi::char_("a-zA-Z0-9")] %
',')[ph::bind(&engine::api::BaseParameters::exclude, qi::_r1) = qi::_1];
base_rule = radiuses_rule(qi::_r1) //
| hints_rule(qi::_r1) //
| bearings_rule(qi::_r1) //
| generate_hints_rule(qi::_r1) //
| skip_waypoints_rule(qi::_r1) //
| approach_rule(qi::_r1) //
| exclude_rule(qi::_r1) //
| snapping_rule(qi::_r1);
}
protected:
qi::rule<Iterator, Signature> base_rule;
qi::rule<Iterator, Signature> query_rule;
qi::rule<Iterator, Signature> format_rule;
qi::symbols<char, engine::api::BaseParameters::OutputFormatType> format_type;
qi::real_parser<double, json_policy> double_;
private:
qi::rule<Iterator, Signature> bearings_rule;
qi::rule<Iterator, Signature> radiuses_rule;
qi::rule<Iterator, Signature> hints_rule;
qi::rule<Iterator, Signature> generate_hints_rule;
qi::rule<Iterator, Signature> skip_waypoints_rule;
qi::rule<Iterator, Signature> approach_rule;
qi::rule<Iterator, Signature> exclude_rule;
qi::rule<Iterator, osrm::engine::Bearing()> bearing_rule;
qi::rule<Iterator, osrm::util::Coordinate()> location_rule;
qi::rule<Iterator, std::vector<osrm::util::Coordinate>()> polyline_rule;
qi::rule<Iterator, std::vector<osrm::util::Coordinate>()> polyline6_rule;
qi::rule<Iterator, unsigned char()> base64_char;
qi::rule<Iterator, std::string()> polyline_chars;
qi::rule<Iterator, double()> unlimited_rule;
qi::rule<Iterator, Signature> snapping_rule;
qi::symbols<char, engine::Approach> approach_type;
qi::symbols<char, engine::api::BaseParameters::SnappingType> snapping_type;
};
} // namespace api
} // namespace server
} // namespace osrm
#endif