diff --git a/CMakeLists.txt b/CMakeLists.txt index dae2a1c0e..2f23fb28a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -728,7 +728,7 @@ set_property(TARGET osrm-routed PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) file(GLOB VariantGlob third_party/variant/include/mapbox/*.hpp) file(GLOB LibraryGlob include/osrm/*.hpp) file(GLOB ParametersGlob include/engine/api/*_parameters.hpp) -set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/phantom_node.hpp) +set(EngineHeader include/engine/status.hpp include/engine/engine_config.hpp include/engine/hint.hpp include/engine/bearing.hpp include/engine/side.hpp include/engine/phantom_node.hpp) set(UtilHeader include/util/coordinate.hpp include/util/json_container.hpp include/util/typedefs.hpp include/util/alias.hpp include/util/exception.hpp) set(ExtractorHeader include/extractor/extractor.hpp include/extractor/extractor_config.hpp include/extractor/travel_mode.hpp) set(PartitionerHeader include/partition/partitioner.hpp include/partition/partition_config.hpp) diff --git a/include/engine/api/base_parameters.hpp b/include/engine/api/base_parameters.hpp index 21bdfd32a..a0ab986d2 100644 --- a/include/engine/api/base_parameters.hpp +++ b/include/engine/api/base_parameters.hpp @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "engine/bearing.hpp" #include "engine/hint.hpp" +#include "engine/side.hpp" #include "util/coordinate.hpp" #include @@ -55,6 +56,7 @@ namespace api * optional per coordinate * - bearings: limits the search for segments in the road network to given bearing(s) in degree * towards true north in clockwise direction, optional per coordinate + * - sides: force the phantom node to start towards the node with the road country side. * * \see OSRM, Coordinate, Hint, Bearing, RouteParame, RouteParameters, TableParameters, * NearestParameters, TripParameters, MatchParameters and TileParameters @@ -65,6 +67,7 @@ struct BaseParameters std::vector> hints; std::vector> radiuses; std::vector> bearings; + std::vector> sides; // Adds hints to response which can be included in subsequent requests, see `hints` above. bool generate_hints = true; @@ -73,9 +76,10 @@ struct BaseParameters const std::vector> hints_ = {}, std::vector> radiuses_ = {}, std::vector> bearings_ = {}, + std::vector> sides_ = {}, bool generate_hints_ = true) : coordinates(coordinates_), hints(hints_), radiuses(radiuses_), bearings(bearings_), - generate_hints(generate_hints_) + sides(sides_), generate_hints(generate_hints_) { } @@ -85,6 +89,7 @@ struct BaseParameters return (hints.empty() || hints.size() == coordinates.size()) && (bearings.empty() || bearings.size() == coordinates.size()) && (radiuses.empty() || radiuses.size() == coordinates.size()) && + (sides.empty() || sides.size() == coordinates.size()) && std::all_of(bearings.begin(), bearings.end(), [](const boost::optional bearing_and_range) { diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 8acb39b3b..03bee1b05 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -7,6 +7,7 @@ #include "engine/algorithm.hpp" #include "engine/geospatial_query.hpp" +#include "engine/side.hpp" #include "customizer/edge_based_graph.hpp" @@ -714,12 +715,13 @@ class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade } std::pair NearestPhantomNodeWithAlternativeFromBigComponent( - const util::Coordinate input_coordinate) const override final + const util::Coordinate input_coordinate, + const engine::SideValue side_value) const override final { BOOST_ASSERT(m_geospatial_query.get()); return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent( - input_coordinate); + input_coordinate, side_value); } std::pair NearestPhantomNodeWithAlternativeFromBigComponent( diff --git a/include/engine/datafacade/datafacade_base.hpp b/include/engine/datafacade/datafacade_base.hpp index d94bfefe1..48f9bbe9c 100644 --- a/include/engine/datafacade/datafacade_base.hpp +++ b/include/engine/datafacade/datafacade_base.hpp @@ -10,6 +10,7 @@ #include "extractor/guidance/turn_lane_types.hpp" #include "extractor/original_edge_data.hpp" #include "engine/phantom_node.hpp" +#include "engine/side.hpp" #include "util/exception.hpp" #include "util/guidance/bearing_class.hpp" #include "util/guidance/entry_class.hpp" @@ -117,8 +118,9 @@ class BaseDataFacade const unsigned max_results, const double max_distance) const = 0; - virtual std::pair NearestPhantomNodeWithAlternativeFromBigComponent( - const util::Coordinate input_coordinate) const = 0; + virtual std::pair + NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, + const engine::SideValue side_value) const = 0; virtual std::pair NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, const double max_distance) const = 0; diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp index ae984d969..e9e612f37 100644 --- a/include/engine/geospatial_query.hpp +++ b/include/engine/geospatial_query.hpp @@ -2,6 +2,7 @@ #define GEOSPATIAL_QUERY_HPP #include "engine/phantom_node.hpp" +#include "engine/side.hpp" #include "util/bearing.hpp" #include "util/coordinate_calculation.hpp" #include "util/rectangle.hpp" @@ -15,6 +16,8 @@ #include #include +#include + namespace osrm { namespace engine @@ -208,16 +211,45 @@ template class GeospatialQuery // Returns the nearest phantom node. If this phantom node is not from a big component // a second phantom node is return that is the nearest coordinate in a big component. std::pair - NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate) const + NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate, + const engine::SideValue side_value) const { bool has_small_component = false; bool has_big_component = false; auto results = rtree.Nearest( input_coordinate, - [this, &has_big_component, &has_small_component](const CandidateSegment &segment) { + [this, &side_value, &input_coordinate, &has_big_component, &has_small_component](const CandidateSegment &segment) { auto use_segment = (!has_small_component || (!has_big_component && !IsTinyComponent(segment))); auto use_directions = std::make_pair(use_segment, use_segment); + bool isOnewaySegment = !(segment.data.forward_segment_id.enabled && + segment.data.reverse_segment_id.enabled); + if (!isOnewaySegment && side_value != BOTH) + { + // Check the counter clockwise + // + // input_coordinate + // | + // | + // segment.data.u ---------------- segment.data.v + + bool input_coordinate_is_at_right = !util::coordinate_calculation::isCCW( + coordinates[segment.data.u], coordinates[segment.data.v], input_coordinate); + + // TODO Check the country side, for the moment right is the default country + // side. + // if drive left + // input_coordinate_is_at_right = !input_coordinate_is_at_right + + // We reverse goCountrySide if side_value is OPPOSITE + if (side_value == OPPOSITE) + input_coordinate_is_at_right = !input_coordinate_is_at_right; + + // Apply the side. + use_directions.first = use_directions.first && input_coordinate_is_at_right; + use_directions.second = use_directions.second && !input_coordinate_is_at_right; + } + if (!use_directions.first && !use_directions.second) return use_directions; const auto valid_edges = HasValidEdge(segment); diff --git a/include/engine/plugins/plugin_base.hpp b/include/engine/plugins/plugin_base.hpp index d98dc31f3..969bd1a28 100644 --- a/include/engine/plugins/plugin_base.hpp +++ b/include/engine/plugins/plugin_base.hpp @@ -16,6 +16,8 @@ #include #include +#include + namespace osrm { namespace engine @@ -224,10 +226,17 @@ class BasePlugin const bool use_hints = !parameters.hints.empty(); const bool use_bearings = !parameters.bearings.empty(); const bool use_radiuses = !parameters.radiuses.empty(); + const bool use_sides = !parameters.sides.empty(); BOOST_ASSERT(parameters.IsValid()); for (const auto i : util::irange(0UL, parameters.coordinates.size())) { + SideValue sideValue = engine::SideValue::BOTH; + // TODO init at SIDE for test + // SideValue sideValue = engine::SideValue::DEFAULT; + if (use_sides && parameters.sides[i]) + sideValue = parameters.sides[i]->side; + if (use_hints && parameters.hints[i] && parameters.hints[i]->IsValid(parameters.coordinates[i], facade)) { @@ -268,7 +277,7 @@ class BasePlugin { phantom_node_pairs[i] = facade.NearestPhantomNodeWithAlternativeFromBigComponent( - parameters.coordinates[i]); + parameters.coordinates[i], sideValue); } } diff --git a/include/engine/side.hpp b/include/engine/side.hpp new file mode 100644 index 000000000..44e814809 --- /dev/null +++ b/include/engine/side.hpp @@ -0,0 +1,62 @@ +/* + +Copyright (c) 2016, Project OSRM contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef OSRM_ENGINE_SIDE_HPP +#define OSRM_ENGINE_SIDE_HPP + +#include + +namespace osrm +{ +namespace engine +{ + +enum SideValue +{ + DEFAULT, + OPPOSITE, + BOTH + +}; + +struct Side +{ + SideValue side; + static SideValue fromString(const std::string &str) + { + if (str == "d") + return DEFAULT; + else if (str == "o") + return OPPOSITE; + else + return BOTH; + } +}; +} +} + +#endif diff --git a/include/server/api/base_parameters_grammar.hpp b/include/server/api/base_parameters_grammar.hpp index 21b2f6b3a..75686e85d 100644 --- a/include/server/api/base_parameters_grammar.hpp +++ b/include/server/api/base_parameters_grammar.hpp @@ -99,6 +99,16 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar base_parameters.bearings.push_back(std::move(bearing)); }; + const auto add_side = [](engine::api::BaseParameters &base_parameters, + const boost::optional &side_string) { + boost::optional side; + if (side_string) + { + side = engine::Side{engine::Side::fromString(side_string.get())}; + } + base_parameters.sides.push_back(std::move(side)); + }; + 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::infinity()]; @@ -149,10 +159,13 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar qi::lit("bearings=") > (-(qi::short_ > ',' > qi::short_))[ph::bind(add_bearing, qi::_r1, qi::_1)] % ';'; + sides_rule = qi::lit("sides=") > + (-qi::as_string[qi::char_("a-zA")])[ph::bind(add_side, qi::_r1, qi::_1)] % ';'; + base_rule = radiuses_rule(qi::_r1) // | hints_rule(qi::_r1) // | bearings_rule(qi::_r1) // - | generate_hints_rule(qi::_r1); + | generate_hints_rule(qi::_r1) | sides_rule(qi::_r1); } protected: @@ -163,6 +176,7 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar qi::rule bearings_rule; qi::rule radiuses_rule; qi::rule hints_rule; + qi::rule sides_rule; qi::rule generate_hints_rule; diff --git a/src/server/service/route_service.cpp b/src/server/service/route_service.cpp index cbf4fa0f5..466e8e4d3 100644 --- a/src/server/service/route_service.cpp +++ b/src/server/service/route_service.cpp @@ -26,7 +26,9 @@ std::string getWrongOptionHelp(const engine::api::RouteParameters ¶meters) constrainParamSize( PARAMETER_SIZE_MISMATCH_MSG, "bearings", parameters.bearings, coord_size, help) || constrainParamSize( - PARAMETER_SIZE_MISMATCH_MSG, "radiuses", parameters.radiuses, coord_size, help); + PARAMETER_SIZE_MISMATCH_MSG, "radiuses", parameters.radiuses, coord_size, help) || + constrainParamSize( + PARAMETER_SIZE_MISMATCH_MSG, "sides", parameters.sides, coord_size, help); if (!param_size_mismatch && parameters.coordinates.size() < 2) { diff --git a/unit_tests/mocks/mock_datafacade.hpp b/unit_tests/mocks/mock_datafacade.hpp index 57b48f3ef..9b695ffe6 100644 --- a/unit_tests/mocks/mock_datafacade.hpp +++ b/unit_tests/mocks/mock_datafacade.hpp @@ -147,7 +147,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade std::pair NearestPhantomNodeWithAlternativeFromBigComponent( - const util::Coordinate /*input_coordinate*/) const override + const util::Coordinate /*input_coordinate*/, + const engine::SideValue /*side_value*/) const override { return {}; }