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;
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 (!bearings.empty())
{
bearings.back() = bearing;
pass = true;
}
if (range && (*range < 0 || *range > 180)) return;
bearings.emplace_back(std::make_pair(bearing,range));
pass = true;
}
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']
else
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 = []
timestamps = []
if row['trace']
@ -19,24 +30,13 @@ When /^I match I should get$/ do |table|
if row['timestamps']
timestamps = row['timestamps'].split(" ").compact.map { |t| t.to_i}
end
got = {'trace' => row['trace'] }
got = got.merge({'trace' => row['trace'] })
response = request_matching trace, timestamps, params
else
raise "*** no trace"
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
json = JSON.parse response.body
end

View File

@ -8,6 +8,17 @@ When /^I route I should get$/ do |table|
response = request_url row['request']
else
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 = []
if row['from'] and row['to']
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
waypoints << node
got = {'from' => row['from'], 'to' => row['to'] }
got = got.merge({'from' => row['from'], 'to' => row['to'] })
response = request_route waypoints, params
elsif row['waypoints']
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
waypoints << node
end
got = {'waypoints' => row['waypoints'] }
got = got.merge({'waypoints' => row['waypoints'] })
response = request_route waypoints, params
else
raise "*** no waypoints"
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
json = JSON.parse response.body
end

View File

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

View File

@ -72,7 +72,7 @@ struct RouteParameters
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);
@ -102,7 +102,7 @@ struct RouteParameters
std::string language;
std::vector<std::string> hints;
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<FixedPointCoordinate> coordinates;
};

View File

@ -75,6 +75,13 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
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());
unsigned max_locations =
std::min(static_cast<unsigned>(max_locations_distance_table),
@ -94,8 +101,10 @@ template <class DataFacadeT> class DistanceTablePlugin final : public BasePlugin
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],
phantom_node_vector[i], 1);
phantom_node_vector[i], 1, bearing, range);
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,
const std::vector<int> &input_bearings,
const std::vector<std::pair<const int,const boost::optional<int>>> &input_bearings,
const double gps_precision,
std::vector<double> &sub_trace_lengths,
osrm::matching::CandidateLists &candidates_lists)
@ -130,8 +130,8 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
std::vector<std::pair<PhantomNode, double>> candidates;
// Use bearing values if supplied, otherwise fallback to 0,180 defaults
auto bearing = input_bearings.size() > 0 ? input_bearings[current_coordinate] : 0;
auto range = input_bearings.size() > 0 ? 10 : 180;
auto bearing = input_bearings.size() > 0 ? input_bearings[current_coordinate].first : 0;
auto range = input_bearings.size() > 0 ? (input_bearings[current_coordinate].second ? *input_bearings[current_coordinate].second : 10 ) : 180;
facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
input_coords[current_coordinate], candidates, query_radius,
bearing, range);

View File

@ -58,11 +58,21 @@ template <class DataFacadeT> class NearestPlugin final : public BasePlugin
{
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);
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(),
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())
{

View File

@ -76,6 +76,7 @@ template <class DataFacadeT> class RoundTripPlugin final : public BasePlugin
PhantomNodeArray &phantom_node_vector)
{
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
const auto &input_bearings = route_parameters.bearings;
// find phantom nodes for all input coords
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;
}
}
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],
phantom_node_vector[i], 1);
phantom_node_vector[i], 1, bearing, range);
if (phantom_node_vector[i].size() > 1)
{
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;
}
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
PhantomNodeArray phantom_node_vector(route_parameters.coordinates.size());
GetPhantomNodes(route_parameters, phantom_node_vector);

View File

@ -1,210 +1,210 @@
/*
Copyright (c) 2015, 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 VIA_ROUTE_HPP
#define VIA_ROUTE_HPP
#include "plugin_base.hpp"
#include "../algorithms/object_encoder.hpp"
#include "../data_structures/search_engine.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/gpx_descriptor.hpp"
#include "../descriptors/json_descriptor.hpp"
#include "../util/integer_range.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/simple_logger.hpp"
#include "../util/timing_util.hpp"
#include <osrm/json_container.hpp>
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
{
private:
DescriptorTable descriptor_table;
std::string descriptor_string;
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
DataFacadeT *facade;
public:
explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
{
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
descriptor_table.emplace("json", 0);
descriptor_table.emplace("gpx", 1);
// descriptor_table.emplace("geojson", 2);
}
virtual ~ViaRoutePlugin() {}
const std::string GetDescriptor() const override final { return descriptor_string; }
int HandleRequest(const RouteParameters &route_parameters,
osrm::json::Object &json_result) override final
{
if (!check_all_coordinates(route_parameters.coordinates))
{
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;
}
std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size());
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
{
if (checksum_OK && i < route_parameters.hints.size() &&
!route_parameters.hints[i].empty())
{
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i],
phantom_node_pair_list[i]);
if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
{
continue;
}
}
std::vector<PhantomNode> phantom_node_vector;
int bearing = input_bearings.size() > 0 ? input_bearings[i] : 0;
int range = input_bearings.size() > 0 ? 8 : 180;
if (facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
phantom_node_vector, 1, bearing, range))
{
BOOST_ASSERT(!phantom_node_vector.empty());
phantom_node_pair_list[i].first = phantom_node_vector.front();
if (phantom_node_vector.size() > 1)
{
phantom_node_pair_list[i].second = phantom_node_vector.back();
}
}
}
auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair)
{
return phantom_pair.first.is_in_tiny_component();
};
const bool every_phantom_is_in_tiny_cc =
std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
check_component_id_is_tiny);
// are all phantoms from a tiny cc?
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)
{
return component_id == phantom_pair.first.component_id;
};
const bool every_phantom_has_equal_id =
std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
check_component_id_is_equal);
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)
{
using namespace std;
swap(phantom_pair.first, phantom_pair.second);
}
};
// this case is true if we take phantoms from the big CC
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),
swap_phantom_from_big_cc_into_front);
}
InternalRouteResult raw_route;
auto build_phantom_pairs =
[&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair)
{
raw_route.segment_end_coordinates.emplace_back(
PhantomNodes{first_pair.first, second_pair.first});
};
osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);
if (1 == raw_route.segment_end_coordinates.size())
{
if (route_parameters.alternate_route)
{
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
raw_route);
}
else
{
search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route);
}
}
else
{
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route);
}
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
{
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
}
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
switch (descriptor_table.get_id(route_parameters.output_format))
{
case 1:
descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
break;
// case 2:
// descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
// break;
default:
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
break;
}
descriptor->SetConfig(route_parameters);
descriptor->Run(raw_route, json_result);
return 200;
}
};
#endif // VIA_ROUTE_HPP
/*
Copyright (c) 2015, 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 VIA_ROUTE_HPP
#define VIA_ROUTE_HPP
#include "plugin_base.hpp"
#include "../algorithms/object_encoder.hpp"
#include "../data_structures/search_engine.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/gpx_descriptor.hpp"
#include "../descriptors/json_descriptor.hpp"
#include "../util/integer_range.hpp"
#include "../util/json_renderer.hpp"
#include "../util/make_unique.hpp"
#include "../util/simple_logger.hpp"
#include "../util/timing_util.hpp"
#include <osrm/json_container.hpp>
#include <cstdlib>
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
template <class DataFacadeT> class ViaRoutePlugin final : public BasePlugin
{
private:
DescriptorTable descriptor_table;
std::string descriptor_string;
std::unique_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;
DataFacadeT *facade;
public:
explicit ViaRoutePlugin(DataFacadeT *facade) : descriptor_string("viaroute"), facade(facade)
{
search_engine_ptr = osrm::make_unique<SearchEngine<DataFacadeT>>(facade);
descriptor_table.emplace("json", 0);
descriptor_table.emplace("gpx", 1);
// descriptor_table.emplace("geojson", 2);
}
virtual ~ViaRoutePlugin() {}
const std::string GetDescriptor() const override final { return descriptor_string; }
int HandleRequest(const RouteParameters &route_parameters,
osrm::json::Object &json_result) override final
{
if (!check_all_coordinates(route_parameters.coordinates))
{
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;
}
std::vector<phantom_node_pair> phantom_node_pair_list(route_parameters.coordinates.size());
const bool checksum_OK = (route_parameters.check_sum == facade->GetCheckSum());
for (const auto i : osrm::irange<std::size_t>(0, route_parameters.coordinates.size()))
{
if (checksum_OK && i < route_parameters.hints.size() &&
!route_parameters.hints[i].empty())
{
ObjectEncoder::DecodeFromBase64(route_parameters.hints[i],
phantom_node_pair_list[i]);
if (phantom_node_pair_list[i].first.is_valid(facade->GetNumberOfNodes()))
{
continue;
}
}
std::vector<PhantomNode> phantom_node_vector;
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;
if (facade->IncrementalFindPhantomNodeForCoordinate(route_parameters.coordinates[i],
phantom_node_vector, 1, bearing, range))
{
BOOST_ASSERT(!phantom_node_vector.empty());
phantom_node_pair_list[i].first = phantom_node_vector.front();
if (phantom_node_vector.size() > 1)
{
phantom_node_pair_list[i].second = phantom_node_vector.back();
}
}
}
auto check_component_id_is_tiny = [](const phantom_node_pair &phantom_pair)
{
return phantom_pair.first.is_in_tiny_component();
};
const bool every_phantom_is_in_tiny_cc =
std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
check_component_id_is_tiny);
// are all phantoms from a tiny cc?
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)
{
return component_id == phantom_pair.first.component_id;
};
const bool every_phantom_has_equal_id =
std::all_of(std::begin(phantom_node_pair_list), std::end(phantom_node_pair_list),
check_component_id_is_equal);
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)
{
using namespace std;
swap(phantom_pair.first, phantom_pair.second);
}
};
// this case is true if we take phantoms from the big CC
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),
swap_phantom_from_big_cc_into_front);
}
InternalRouteResult raw_route;
auto build_phantom_pairs =
[&raw_route](const phantom_node_pair &first_pair, const phantom_node_pair &second_pair)
{
raw_route.segment_end_coordinates.emplace_back(
PhantomNodes{first_pair.first, second_pair.first});
};
osrm::for_each_pair(phantom_node_pair_list, build_phantom_pairs);
if (1 == raw_route.segment_end_coordinates.size())
{
if (route_parameters.alternate_route)
{
search_engine_ptr->alternative_path(raw_route.segment_end_coordinates.front(),
raw_route);
}
else
{
search_engine_ptr->direct_shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route);
}
}
else
{
search_engine_ptr->shortest_path(raw_route.segment_end_coordinates,
route_parameters.uturns, raw_route);
}
if (INVALID_EDGE_WEIGHT == raw_route.shortest_path_length)
{
SimpleLogger().Write(logDEBUG) << "Error occurred, single path not found";
}
std::unique_ptr<BaseDescriptor<DataFacadeT>> descriptor;
switch (descriptor_table.get_id(route_parameters.output_format))
{
case 1:
descriptor = osrm::make_unique<GPXDescriptor<DataFacadeT>>(facade);
break;
// case 2:
// descriptor = osrm::make_unique<GEOJSONDescriptor<DataFacadeT>>();
// break;
default:
descriptor = osrm::make_unique<JSONDescriptor<DataFacadeT>>(facade);
break;
}
descriptor->SetConfig(route_parameters);
descriptor->Run(raw_route, json_result);
return 200;
}
};
#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") >> '=' >>
qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
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") >> '=' >>
qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>