Add bearing filter support to viaroute, trip, nearest, and distance

table plugins.
Make bearing range configurable by adding a comma-separated second part
to the bearing paramenter, like so:

    b=<bearing:0-359>(,<range:0-180>)

If no range is supplied, it defaults to +/- 10 degrees.
This commit is contained in:
Daniel Patterson 2015-11-10 18:54:11 -05:00
parent 16b6c26d6e
commit 1536d1c044
11 changed files with 326 additions and 282 deletions

View File

@ -118,16 +118,17 @@ void RouteParameters::addTimestamp(const unsigned timestamp)
} }
} }
void RouteParameters::addBearing(const int bearing, boost::spirit::qi::unused_type unused, bool& pass) void RouteParameters::addBearing(
const boost::fusion::vector<int, boost::optional<int>> &received_bearing,
boost::spirit::qi::unused_type /* unused */, bool& pass)
{ {
bearings.resize(coordinates.size());
pass = false; pass = false;
const int bearing = boost::fusion::at_c<0>(received_bearing);
const boost::optional<int> range = boost::fusion::at_c<1>(received_bearing);
if (bearing < 0 || bearing > 359) return; if (bearing < 0 || bearing > 359) return;
if (!bearings.empty()) if (range && (*range < 0 || *range > 180)) return;
{ bearings.emplace_back(std::make_pair(bearing,range));
bearings.back() = bearing; pass = true;
pass = true;
}
} }
void RouteParameters::setLanguage(const std::string &language_string) void RouteParameters::setLanguage(const std::string &language_string)

View File

@ -8,6 +8,17 @@ When /^I match I should get$/ do |table|
response = request_url row['request'] response = request_url row['request']
else else
params = @query_params params = @query_params
got = {}
row.each_pair do |k,v|
if k =~ /param:(.*)/
if v=='(nil)'
params[$1]=nil
elsif v!=nil
params[$1]=v
end
got[k]=v
end
end
trace = [] trace = []
timestamps = [] timestamps = []
if row['trace'] if row['trace']
@ -19,24 +30,13 @@ When /^I match I should get$/ do |table|
if row['timestamps'] if row['timestamps']
timestamps = row['timestamps'].split(" ").compact.map { |t| t.to_i} timestamps = row['timestamps'].split(" ").compact.map { |t| t.to_i}
end end
got = {'trace' => row['trace'] } got = got.merge({'trace' => row['trace'] })
response = request_matching trace, timestamps, params response = request_matching trace, timestamps, params
else else
raise "*** no trace" raise "*** no trace"
end end
end end
row.each_pair do |k,v|
if k =~ /param:(.*)/
if v=='(nil)'
params[$1]=nil
elsif v!=nil
params[$1]=v
end
got[k]=v
end
end
if response.body.empty? == false if response.body.empty? == false
json = JSON.parse response.body json = JSON.parse response.body
end end

View File

@ -8,6 +8,17 @@ When /^I route I should get$/ do |table|
response = request_url row['request'] response = request_url row['request']
else else
params = @query_params params = @query_params
got = {}
row.each_pair do |k,v|
if k =~ /param:(.*)/
if v=='(nil)'
params[$1]=nil
elsif v!=nil
params[$1]=v
end
got[k]=v
end
end
waypoints = [] waypoints = []
if row['from'] and row['to'] if row['from'] and row['to']
node = find_node_by_name(row['from']) node = find_node_by_name(row['from'])
@ -18,7 +29,7 @@ When /^I route I should get$/ do |table|
raise "*** unknown to-node '#{row['to']}" unless node raise "*** unknown to-node '#{row['to']}" unless node
waypoints << node waypoints << node
got = {'from' => row['from'], 'to' => row['to'] } got = got.merge({'from' => row['from'], 'to' => row['to'] })
response = request_route waypoints, params response = request_route waypoints, params
elsif row['waypoints'] elsif row['waypoints']
row['waypoints'].split(',').each do |n| row['waypoints'].split(',').each do |n|
@ -26,24 +37,13 @@ When /^I route I should get$/ do |table|
raise "*** unknown waypoint node '#{n.strip}" unless node raise "*** unknown waypoint node '#{n.strip}" unless node
waypoints << node waypoints << node
end end
got = {'waypoints' => row['waypoints'] } got = got.merge({'waypoints' => row['waypoints'] })
response = request_route waypoints, params response = request_route waypoints, params
else else
raise "*** no waypoints" raise "*** no waypoints"
end end
end end
row.each_pair do |k,v|
if k =~ /param:(.*)/
if v=='(nil)'
params[$1]=nil
elsif v!=nil
params[$1]=v
end
got[k]=v
end
end
if response.body.empty? == false if response.body.empty? == false
json = JSON.parse response.body json = JSON.parse response.body
end end

View File

@ -1,10 +1,26 @@
@routing @bearing_param @todo @testbot @routing @bearing_param @testbot
Feature: Bearing parameter Feature: Bearing parameter
Background: Background:
Given the profile "testbot" Given the profile "testbot"
And a grid size of 10 meters And a grid size of 10 meters
Scenario: Testbot - Intial bearing in simple case
Given the node map
| a | b | c | d |
And the ways
| nodes |
| ad |
When I route I should get
| from | to | param:b | route | bearing |
| b | c | 90&b=90 | ad | 90 |
| b | c | 180&b=90 | | |
| b | c | 80&b=100 | ad | 90 |
| b | c | 79&b=100 | | |
| b | c | 79,11&b=100 | ad | 90 |
Scenario: Testbot - Intial bearing in simple case Scenario: Testbot - Intial bearing in simple case
Given the node map Given the node map
| a | | | a | |
@ -17,13 +33,13 @@ Feature: Bearing parameter
| bc | | bc |
When I route I should get When I route I should get
| from | to | param:bearing | route | bearing | | from | to | param:b | route | bearing |
| 0 | c | 0 | bc | 45 | | 0 | c | 0&b=0 | | |
| 0 | c | 45 | bc | 45 | | 0 | c | 45&b=45 | bc | 45 ~3% |
| 0 | c | 85 | bc | 45 | | 0 | c | 85&b=85 | | |
| 0 | c | 95 | ac | 135 | | 0 | c | 95&b=95 | | |
| 0 | c | 135 | ac | 135 | | 0 | c | 135&b=135 | ac | 135 ~1% |
| 0 | c | 180 | ac | 135 | | 0 | c | 180&b=180 | | |
Scenario: Testbot - Initial bearing on split way Scenario: Testbot - Initial bearing on split way
Given the node map Given the node map
@ -38,23 +54,21 @@ Feature: Bearing parameter
| da | yes | | da | yes |
When I route I should get When I route I should get
| from | to | param:bearing | route | bearing | | from | to | param:b | route | bearing |
| 0 | b | 10 | ab | 90 | | 0 | b | 10&b=10 | | |
| 0 | b | 90 | ab | 90 | | 0 | b | 90&b=90 | ab | 90 |
| 0 | b | 170 | ab | 90 | | 0 | b | 170&b=170 | | |
| 0 | b | 190 | cd,da,ab | 270 | | 0 | b | 190&b=190 | | |
| 0 | b | 270 | cd,da,ab | 270 | | 0 | 1 | 90&b=270 | ab,bc,cd | 90,0,270 |
| 0 | b | 350 | cd,da,ab | 270 | | 1 | d | 10&b=10 | | |
| 1 | d | 10 | cd | 90 | | 1 | d | 90&b=90 | | |
| 1 | d | 90 | cd | 90 | | 1 | 0 | 190&b=190 | | |
| 1 | d | 170 | cd | 90 | | 1 | d | 270&b=270 | cd | 270 |
| 1 | d | 190 | ab,bc,cd | 270 | | 1 | d | 350&b=350 | | |
| 1 | d | 270 | ab,bc,cd | 270 |
| 1 | d | 350 | ab,bc,cd | 270 |
Scenario: Testbot - Initial bearing in all direction Scenario: Testbot - Initial bearing in all direction
Given the node map Given the node map
| h | | | a | | | b | | h | | q | a | | | b |
| | | | | | | | | | | | | | | |
| | | p | i | j | | | | | | p | i | j | | |
| g | | o | 0 | k | | c | | g | | o | 0 | k | | c |
@ -82,12 +96,12 @@ Feature: Bearing parameter
| ha | yes | | ha | yes |
When I route I should get When I route I should get
| from | to | param:bearing | route | bearing | | from | to | param:b | route | bearing |
| 0 | a | 0 | ia | 0 | | i | q | 0&b=90 | ia,ab,bc,cd,de,ef,fg,gh,ha | 0,90,180,180,270,270,0,0,90 |
| 0 | a | 45 | jb,bc,cd,de,ef,fg,gh,ha | 45 | | 0 | a | 45&b=90 | jb,bc,cd,de,ef,fg,gh,ha | 45,180,180,270,270,0,0,90 |
| 0 | a | 90 | kc,cd,de,ef,fg,gh,ha | 90 | | j | q | 90&b=90 | kc,cd,de,ef,fg,gh,ha | 90,180,270,270,0,0,90 |
| 0 | a | 135 | ld,de,ef,fg,gh,ha | 135 | | k | a | 135&b=90 | ld,de,ef,fg,gh,ha | 135,270,270,0,0,90 |
| 0 | a | 180 | me,de,ef,fg,gh,ha | 180 | | 0 | a | 180&b=90 | me,ef,fg,gh,ha | 180,270,0,0,90 |
| 0 | a | 225 | nf,ef,fg,gh,ha | 225 | | m | a | 225&b=90 | nf,fg,gh,ha | 225,0,0,90 |
| 0 | a | 270 | og,gh,ha | 270 | | 0 | a | 270&b=90 | og,gh,ha | 270,0,90 |
| 0 | a | 315 | pn,ha | 315 | | 0 | a | 315&b=90 | ph,ha | 315,90 |

View File

@ -72,7 +72,7 @@ struct RouteParameters
void addTimestamp(const unsigned timestamp); void addTimestamp(const unsigned timestamp);
void addBearing(const int timestamp, boost::spirit::qi::unused_type unused, bool& pass); void addBearing(const boost::fusion::vector<int, boost::optional<int>> &received_bearing, boost::spirit::qi::unused_type unused, bool& pass);
void setLanguage(const std::string &language); void setLanguage(const std::string &language);
@ -102,7 +102,7 @@ struct RouteParameters
std::string language; std::string language;
std::vector<std::string> hints; std::vector<std::string> hints;
std::vector<unsigned> timestamps; std::vector<unsigned> timestamps;
std::vector<int> bearings; std::vector<std::pair<const int,const boost::optional<int>>> bearings;
std::vector<bool> uturns; std::vector<bool> uturns;
std::vector<FixedPointCoordinate> coordinates; std::vector<FixedPointCoordinate> coordinates;
}; };

View File

@ -75,6 +75,13 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
return 400; return 400;
} }
const auto &input_bearings = route_parameters.bearings;
if (input_bearings.size() > 0 && route_parameters.coordinates.size() != input_bearings.size())
{
json_result.values["status"] = "Number of bearings does not match number of coordinates .";
return 400;
}
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
unsigned max_locations = unsigned max_locations =
std::min(static_cast<unsigned>(max_locations_distance_table), std::min(static_cast<unsigned>(max_locations_distance_table),
@ -94,8 +101,10 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
continue; continue;
} }
} }
const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
const int range = input_bearings.size() > 0 ? (input_bearings[i].second?*input_bearings[i].second:10) : 180;
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
phantom_node_vector[i], 1); phantom_node_vector[i], 1, bearing, range);
BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes())); BOOST_ASSERT(phantom_node_vector[i].front().is_valid(facade->GetNumberOfNodes()));
} }

View File

@ -94,7 +94,7 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
} }
bool getCandidates(const std::vector<FixedPointCoordinate> &input_coords, bool getCandidates(const std::vector<FixedPointCoordinate> &input_coords,
const std::vector<int> &input_bearings, const std::vector<std::pair<const int,const boost::optional<int>>> &input_bearings,
const double gps_precision, const double gps_precision,
std::vector<double> &sub_trace_lengths, std::vector<double> &sub_trace_lengths,
osrm::matching::CandidateLists &candidates_lists) osrm::matching::CandidateLists &candidates_lists)
@ -130,8 +130,8 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
std::vector<std::pair<PhantomNode, double>> candidates; std::vector<std::pair<PhantomNode, double>> candidates;
// Use bearing values if supplied, otherwise fallback to 0,180 defaults // Use bearing values if supplied, otherwise fallback to 0,180 defaults
auto bearing = input_bearings.size() > 0 ? input_bearings[current_coordinate] : 0; auto bearing = input_bearings.size() > 0 ? input_bearings[current_coordinate].first : 0;
auto range = input_bearings.size() > 0 ? 10 : 180; auto range = input_bearings.size() > 0 ? (input_bearings[current_coordinate].second ? *input_bearings[current_coordinate].second : 10 ) : 180;
facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance( facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
input_coords[current_coordinate], candidates, query_radius, input_coords[current_coordinate], candidates, query_radius,
bearing, range); bearing, range);

View File

@ -58,11 +58,21 @@ template <class DataFacadeT> class NearestPlugin final : public BasePlugin
{ {
return 400; return 400;
} }
const auto &input_bearings = route_parameters.bearings;
if (input_bearings.size() > 0 && route_parameters.coordinates.size() != input_bearings.size())
{
json_result.values["status"] = "Number of bearings does not match number of coordinates .";
return 400;
}
auto number_of_results = static_cast<std::size_t>(route_parameters.num_results); auto number_of_results = static_cast<std::size_t>(route_parameters.num_results);
std::vector<PhantomNode> phantom_node_vector; std::vector<PhantomNode> phantom_node_vector;
const int bearing = input_bearings.size() > 0 ? input_bearings.front().first : 0;
const int range = input_bearings.size() > 0 ? (input_bearings.front().second?*input_bearings.front().second:10) : 180;
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates.front(), facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates.front(),
phantom_node_vector, phantom_node_vector,
static_cast<int>(number_of_results)); static_cast<int>(number_of_results), bearing, range);
if (phantom_node_vector.empty() || !phantom_node_vector.front().is_valid()) if (phantom_node_vector.empty() || !phantom_node_vector.front().is_valid())
{ {

View File

@ -76,6 +76,7 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
PhantomNodeArray &phantom_node_vector) PhantomNodeArray &phantom_node_vector)
{ {
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
const auto &input_bearings = route_parameters.bearings;
// find phantom nodes for all input coords // find phantom nodes for all input coords
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size())) for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
@ -92,8 +93,10 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
continue; continue;
} }
} }
const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
const int range = input_bearings.size() > 0 ? (input_bearings[i].second?*input_bearings[i].second:10) : 180;
facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
phantom_node_vector[i], 1); phantom_node_vector[i], 1, bearing, range);
if (phantom_node_vector[i].size() > 1) if (phantom_node_vector[i].size() > 1)
{ {
phantom_node_vector[i].erase(std::begin(phantom_node_vector[i])); phantom_node_vector[i].erase(std::begin(phantom_node_vector[i]));
@ -239,6 +242,13 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
return 400; return 400;
} }
const auto &input_bearings = route_parameters.bearings;
if (input_bearings.size() > 0 && route_parameters.coordinates.size() != input_bearings.size())
{
json_result.values["status"] = "Number of bearings does not match number of coordinates .";
return 400;
}
// get phantom nodes // get phantom nodes
PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size()); PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size());
GetPhantomNodes(route_parameters, phantom_node_vector); GetPhantomNodes(route_parameters, phantom_node_vector);

View File

@ -1,210 +1,210 @@
/* /*
Copyright (c) 2015, Project OSRM contributors Copyright (c) 2015, Project OSRM contributors
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer. of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution. other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 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 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef VIA_ROUTE_HPP #ifndef VIA_ROUTE_HPP
#define VIA_ROUTE_HPP #define VIA_ROUTE_HPP
#include "plugin_base.hpp" #include "plugin_base.hpp"
#include "../algorithms/object_encoder.hpp" #include "../algorithms/object_encoder.hpp"
#include "../data_structures/search_engine.hpp" #include "../data_structures/search_engine.hpp"
#include "../descriptors/descriptor_base.hpp" #include "../descriptors/descriptor_base.hpp"
#include "../descriptors/gpx_descriptor.hpp" #include "../descriptors/gpx_descriptor.hpp"
#include "../descriptors/json_descriptor.hpp" #include "../descriptors/json_descriptor.hpp"
#include "../util/integer_range.hpp" #include "../util/integer_range.hpp"
#include "../util/json_renderer.hpp" #include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp" #include "../util/make_unique.hpp"
#include "../util/simple_logger.hpp" #include "../util/simple_logger.hpp"
#include "../util/timing_util.hpp" #include "../util/timing_util.hpp"
#include <osrm/json_container.hpp> #include <osrm/json_container.hpp>
#include <cstdlib> #include <cstdlib>
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
{ {
private: private:
DescriptorTable descriptor_table; DescriptorTable descriptor_table;
std::string descriptor_string; std::string descriptor_string;
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr; std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
DataFacadeT *facade; DataFacadeT *facade;
public: public:
explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade) explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
{ {
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade); search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
descriptor_table.emplace("json", 0); descriptor_table.emplace("json", 0);
descriptor_table.emplace("gpx", 1); descriptor_table.emplace("gpx", 1);
// descriptor_table.emplace("geojson", 2); // descriptor_table.emplace("geojson", 2);
} }
virtual ~ViaRoutePlugin() {} virtual ~ViaRoutePlugin() {}
const std::string GetDescriptor() const override final { return descriptor_string; } const std::string GetDescriptor() const override final { return descriptor_string; }
int HandleRequest(const RouteParameters &route_parameters, int HandleRequest(const RouteParameters &route_parameters,
osrm::json::Object &json_result) override final osrm::json::Object &json_result) override final
{ {
if (!check_all_coordinates(route_parameters.coordinates)) if (!check_all_coordinates(route_parameters.coordinates))
{ {
return 400; return 400;
} }
const auto &input_bearings = route_parameters.bearings; const auto &input_bearings = route_parameters.bearings;
if (input_bearings.size() > 0 && route_parameters.coordinates.size() != input_bearings.size()) if (input_bearings.size() > 0 && route_parameters.coordinates.size() != input_bearings.size())
{ {
json_result.values["status"] = "Number of bearings does not match number of coordinates ."; json_result.values["status"] = "Number of bearings does not match number of coordinates .";
return 400; return 400;
} }
std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size()); std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size());
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum()); const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size())) for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
{ {
if (checksum_OK && i < route_parameters.hints.size() && if (checksum_OK && i < route_parameters.hints.size() &&
!route_parameters.hints[i].empty()) !route_parameters.hints[i].empty())
{ {
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i], ObjectEncoder::DecodeFromBase64(route_parameters.hints[i],
phantom_node_pair_list[i]); phantom_node_pair_list[i]);
if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes())) if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
{ {
continue; continue;
} }
} }
std::vector<PhantomNode> phantom_node_vector; std::vector<PhantomNode> phantom_node_vector;
int bearing = input_bearings.size() > 0 ? input_bearings[i] : 0; const int bearing = input_bearings.size() > 0 ? input_bearings[i].first : 0;
int range = input_bearings.size() > 0 ? 8 : 180; const int range = input_bearings.size() > 0 ? (input_bearings[i].second?*input_bearings[i].second:10) : 180;
if (facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i], if (facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
phantom_node_vector, 1, bearing, range)) phantom_node_vector, 1, bearing, range))
{ {
BOOST_ASSERT(!phantom_node_vector.empty()); BOOST_ASSERT(!phantom_node_vector.empty());
phantom_node_pair_list[i].first = phantom_node_vector.front(); phantom_node_pair_list[i].first = phantom_node_vector.front();
if (phantom_node_vector.size() > 1) if (phantom_node_vector.size() > 1)
{ {
phantom_node_pair_list[i].second = phantom_node_vector.back(); phantom_node_pair_list[i].second = phantom_node_vector.back();
} }
} }
} }
auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair) auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair)
{ {
return phantom_pair.first.is_in_tiny_component(); return phantom_pair.first.is_in_tiny_component();
}; };
const bool every_phantom_is_in_tiny_cc = const bool every_phantom_is_in_tiny_cc =
std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list), std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
check_component_id_is_tiny); check_component_id_is_tiny);
// are all phantoms from a tiny cc? // are all phantoms from a tiny cc?
const auto component_id = phantom_node_pair_list.front().first.component_id; const auto component_id = phantom_node_pair_list.front().first.component_id;
auto check_component_id_is_equal = [component_id](const phantom_node_pair &phantom_pair) auto check_component_id_is_equal = [component_id](const phantom_node_pair &phantom_pair)
{ {
return component_id == phantom_pair.first.component_id; return component_id == phantom_pair.first.component_id;
}; };
const bool every_phantom_has_equal_id = const bool every_phantom_has_equal_id =
std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list), std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
check_component_id_is_equal); check_component_id_is_equal);
auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair &phantom_pair) auto swap_phantom_from_big_cc_into_front = [](phantom_node_pair &phantom_pair)
{ {
if (0 != phantom_pair.first.component_id && 0 == phantom_pair.second.component_id) if (0 != phantom_pair.first.component_id && 0 == phantom_pair.second.component_id)
{ {
using namespace std; using namespace std;
swap(phantom_pair.first, phantom_pair.second); swap(phantom_pair.first, phantom_pair.second);
} }
}; };
// this case is true if we take phantoms from the big CC // this case is true if we take phantoms from the big CC
if (!every_phantom_is_in_tiny_cc || !every_phantom_has_equal_id) if (!every_phantom_is_in_tiny_cc || !every_phantom_has_equal_id)
{ {
std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list), std::for_each(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
swap_phantom_from_big_cc_into_front); swap_phantom_from_big_cc_into_front);
} }
InternalRouteResult raw_route; InternalRouteResult raw_route;
auto build_phantom_pairs = auto build_phantom_pairs =
[&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair) [&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair)
{ {
raw_route.segment_end_coordinates.emplace_back( raw_route.segment_end_coordinates.emplace_back(
PhantomNodes{first_pair.first, second_pair.first}); PhantomNodes{first_pair.first, second_pair.first});
}; };
osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs); osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);
if (1 == raw_route.segment_end_coordinates.size()) if (1 == raw_route.segment_end_coordinates.size())
{ {
if (route_parameters.alternate_route) if (route_parameters.alternate_route)
{ {
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(), search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
raw_route); raw_route);
} }
else else
{ {
search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates, search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route); route_parameters.uturns, raw_route);
} }
} }
else else
{ {
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates, search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route); route_parameters.uturns, raw_route);
} }
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length) if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
{ {
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found"; SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
} }
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor; std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
switch (descriptor_table.get_id(route_parameters.output_format)) switch (descriptor_table.get_id(route_parameters.output_format))
{ {
case 1: case 1:
descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade); descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
break; break;
// case 2: // case 2:
// descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>(); // descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
// break; // break;
default: default:
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade); descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
break; break;
} }
descriptor->SetConfig(route_parameters); descriptor->SetConfig(route_parameters);
descriptor->Run(raw_route, json_result); descriptor->Run(raw_route, json_result);
return 200; return 200;
} }
}; };
#endif // VIA_ROUTE_HPP #endif // VIA_ROUTE_HPP

View File

@ -66,7 +66,7 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >> timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)]; qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
bearing = (-qi::lit('&')) >> qi::lit("b") >> '=' >> bearing = (-qi::lit('&')) >> qi::lit("b") >> '=' >>
qi::int_[boost::bind(&HandlerT::addBearing, handler, ::_1, ::_2, ::_3)]; (qi::int_ >> -(qi::lit(',') >> qi::int_ | qi::attr(10)))[boost::bind(&HandlerT::addBearing, handler, ::_1, ::_2, ::_3)];
u = (-qi::lit('&')) >> qi::lit("u") >> '=' >> u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)]; qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >> uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>