New "sides" setting in base parameters for phantom nodes.

- Adding sides parameter into base parameters, it can take the values SIDE, OPPOSITE or DEFAULT.
 - Adding url parser for "sides" parameter, url values are "s" for SIDE, "o" for OPPOSITE and "d" for DEFAULT, example : "sides=s;s".
 - Checking parameters, if "sides" parameter is used, the number of parameter is the same as number of location.
 - Create a phantom to start at side driving or Opposite side driving.

Signed-off-by: FILLAU Jean-Maxime <jean-maxime.fillau@mapotempo.com>
This commit is contained in:
FILLAU Jean-Maxime 2017-05-18 17:05:11 +02:00 committed by Patrick Niklaus
parent 579a1ed42e
commit 8e70c87e64
10 changed files with 141 additions and 12 deletions

View File

@ -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)

View File

@ -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 <boost/optional.hpp>
@ -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<boost::optional<Hint>> hints;
std::vector<boost::optional<double>> radiuses;
std::vector<boost::optional<Bearing>> bearings;
std::vector<boost::optional<Side>> 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<boost::optional<Hint>> hints_ = {},
std::vector<boost::optional<double>> radiuses_ = {},
std::vector<boost::optional<Bearing>> bearings_ = {},
std::vector<boost::optional<Side>> 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> bearing_and_range) {

View File

@ -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<PhantomNode, PhantomNode> 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<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(

View File

@ -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<PhantomNode, PhantomNode> NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate input_coordinate) const = 0;
virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const engine::SideValue side_value) const = 0;
virtual std::pair<PhantomNode, PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
const double max_distance) const = 0;

View File

@ -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 <memory>
#include <vector>
#include <util/log.hpp>
namespace osrm
{
namespace engine
@ -208,16 +211,45 @@ template <typename RTreeT, typename DataFacadeT> 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<PhantomNode, PhantomNode>
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);

View File

@ -16,6 +16,8 @@
#include <string>
#include <vector>
#include <util/log.hpp>
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<std::size_t>(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);
}
}

62
include/engine/side.hpp Normal file
View File

@ -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 <string>
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

View File

@ -99,6 +99,16 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
base_parameters.bearings.push_back(std::move(bearing));
};
const auto add_side = [](engine::api::BaseParameters &base_parameters,
const boost::optional<std::string> &side_string) {
boost::optional<engine::Side> 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<double>::infinity()];
@ -149,10 +159,13 @@ struct BaseParametersGrammar : boost::spirit::qi::grammar<Iterator, Signature>
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<Iterator, Signature>
qi::rule<Iterator, Signature> bearings_rule;
qi::rule<Iterator, Signature> radiuses_rule;
qi::rule<Iterator, Signature> hints_rule;
qi::rule<Iterator, Signature> sides_rule;
qi::rule<Iterator, Signature> generate_hints_rule;

View File

@ -26,7 +26,9 @@ std::string getWrongOptionHelp(const engine::api::RouteParameters &parameters)
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)
{

View File

@ -147,7 +147,8 @@ class MockBaseDataFacade : public engine::datafacade::BaseDataFacade
std::pair<engine::PhantomNode, engine::PhantomNode>
NearestPhantomNodeWithAlternativeFromBigComponent(
const util::Coordinate /*input_coordinate*/) const override
const util::Coordinate /*input_coordinate*/,
const engine::SideValue /*side_value*/) const override
{
return {};
}