Adds turn instructions to the turns layer in debug tiles. (#4460)

Add turn types and modifiers to turn points in debug tiles.  Also refactor some of the tile code to reduce some repetition.
This commit is contained in:
Daniel Patterson 2017-09-01 15:08:22 -07:00 committed by GitHub
parent 89cf6d9e74
commit 0fc1aa2711
9 changed files with 270 additions and 150 deletions

View File

@ -17,6 +17,8 @@
updating ETAs returned, without changing route selection (for example, in a distance-based profile with traffic data loaded).
- Infrastructure:
- New file `.osrm.cell_metrics` created by `osrm-customize`.
- Debug tiles:
- Added new properties `type` and `modifier` to `turns` layer, useful for viewing guidance calculated turn types on the map
# 5.11.0
- Changes from 5.10:

View File

@ -437,6 +437,8 @@ Vector tiles contain two layers:
| `turn_angle` | `integer` | the angle of the turn, relative to the `bearing_in`. -180 to +180, 0 = straight ahead, 90 = 90-degrees to the right |
| `cost` | `float` | the time we think it takes to make that turn, in seconds. May be negative, depending on how the data model is constructed (some turns get a "bonus"). |
| `weight` | `float` | the weight we think it takes to make that turn. May be negative, depending on how the data model is constructed (some turns get a "bonus"). ACTUAL ROUTING USES THIS VALUE |
| `type` | `string` | the type of this turn - values like `turn`, `continue`, etc. See the `StepManeuver` for a partial list, this field also exposes internal turn types that are never returned with an API response |
| `modifier` | `string` | the direction modifier of the turn (`left`, `sharp left`, etc) |
## Result objects

View File

@ -36,6 +36,15 @@ namespace detail
std::string instructionTypeToString(extractor::guidance::TurnType::Enum type);
std::string instructionModifierToString(extractor::guidance::DirectionModifier::Enum modifier);
/**
* Returns a string representing all instruction types (including internal types that
* are normally not exposed in route responses)
*
* @param type the TurnType value to convert into a string
* @return a string representing the turn type (e.g. `turn` or `continue`)
*/
std::string internalInstructionTypeToString(extractor::guidance::TurnType::Enum type);
util::json::Array coordinateToLonLat(const util::Coordinate coordinate);
std::string modeToString(const extractor::TravelMode mode);

View File

@ -24,6 +24,7 @@ struct TurnData final
const int turn_angle;
const EdgeWeight weight;
const EdgeWeight duration;
const extractor::guidance::TurnInstruction turn_instruction;
};
using RTreeLeaf = datafacade::BaseDataFacade::RTreeLeaf;

View File

@ -41,15 +41,47 @@ const constexpr char *modifier_names[] = {"uturn",
"left",
"sharp left"};
// translations of TurnTypes. Not all types are exposed to the outside world.
// invalid types should never be returned as part of the API
const constexpr char *turn_type_names[] = {
"invalid", "new name", "continue", "turn", "merge",
"on ramp", "off ramp", "fork", "end of road", "notification",
"roundabout", "roundabout", "rotary", "rotary", "roundabout turn",
"roundabout turn", "use lane", "invalid", "invalid", "invalid",
"invalid", "invalid", "invalid", "invalid", "invalid",
"invalid", "invalid"};
/**
* Human readable values for TurnType enum values
*/
struct TurnTypeName
{
// String value we return with our API
const char *external_name;
// Internal only string name for the turn type - useful for debugging
// and used by debug tiles for visualizing hidden turn types
const char *internal_name;
};
// Indexes in this list correspond to the Enum values of osrm::extractor::guidance::TurnType
const constexpr TurnTypeName turn_type_names[] = {
{"invalid", "(not set)"},
{"new name", "new name"},
{"continue", "continue"},
{"turn", "turn"},
{"merge", "merge"},
{"on ramp", "on ramp"},
{"off ramp", "off ramp"},
{"fork", "fork"},
{"end of road", "end of road"},
{"notification", "notification"},
{"roundabout", "enter roundabout"},
{"roundabout", "enter and exit roundabout"},
{"rotary", "enter rotary"},
{"rotary", "enter and exit rotary"},
{"roundabout turn", "enter roundabout turn"},
{"roundabout turn", "enter and exit roundabout turn"},
{"use lane", "use lane"},
{"invalid", "(noturn)"},
{"invalid", "(suppressed)"},
{"invalid", "(enter roundabout at exit)"},
{"invalid", "(exit roundabout)"},
{"invalid", "(enter rotary at exit)"},
{"invalid", "(exit rotary)"},
{"invalid", "(enter roundabout intersection at exit)"},
{"invalid", "(exit roundabout intersection)"},
{"invalid", "(stay on roundabout)"},
{"invalid", "(sliproad)"}};
const constexpr char *waypoint_type_names[] = {"invalid", "arrive", "depart"};
@ -69,7 +101,14 @@ std::string instructionTypeToString(const TurnType::Enum type)
{
static_assert(sizeof(turn_type_names) / sizeof(turn_type_names[0]) >= TurnType::MaxTurnType,
"Some turn types has not string representation.");
return turn_type_names[static_cast<std::size_t>(type)];
return turn_type_names[static_cast<std::size_t>(type)].external_name;
}
std::string internalInstructionTypeToString(const TurnType::Enum type)
{
static_assert(sizeof(turn_type_names) / sizeof(turn_type_names[0]) >= TurnType::MaxTurnType,
"Some turn types has not string representation.");
return turn_type_names[static_cast<std::size_t>(type)].internal_name;
}
util::json::Array lanesFromIntersection(const guidance::IntermediateIntersection &intersection)

View File

@ -6,6 +6,8 @@
#include "util/vector_tile.hpp"
#include "util/web_mercator.hpp"
#include "engine/api/json_factory.hpp"
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
@ -37,6 +39,41 @@ constexpr const static int MIN_ZOOM_FOR_TURNS = 15;
namespace
{
// Creates an indexed lookup table for values - used to encoded the vector tile
// which uses a lookup table and index pointers for encoding
template <typename T> struct ValueIndexer
{
private:
std::vector<T> used_values;
std::unordered_map<T, std::size_t> value_offsets;
public:
std::size_t add(const T &value)
{
const auto found = value_offsets.find(value);
std::size_t offset;
if (found == value_offsets.end())
{
used_values.push_back(value);
offset = used_values.size() - 1;
value_offsets[value] = offset;
}
else
{
offset = found->second;
}
return offset;
}
std::size_t indexOf(const T &value) { return value_offsets[value]; };
const std::vector<T> &values() { return used_values; }
std::size_t size() const { return used_values.size(); }
};
using RTreeLeaf = datafacade::BaseDataFacade::RTreeLeaf;
// TODO: Port all this encoding logic to https://github.com/mapbox/vector-tile, which wasn't
// available when this code was originally written.
@ -281,87 +318,17 @@ void encodeVectorTile(const DataFacadeBase &facade,
std::string &pbf_buffer)
{
// Vector tiles encode properties as references to a common lookup table.
// When we add a property to a "feature", we actually attach the index of the value
// rather than the value itself. Thus, we need to keep a list of the unique
// values we need, and we add this list to the tile as a lookup table. This
// vector holds all the actual used values, the feature refernce offsets in
// this vector.
// for integer values
std::vector<int> used_line_ints;
// While constructing the tile, we keep track of which integers we have in our table
// and their offsets, so multiple features can re-use the same values
std::unordered_map<int, std::size_t> line_int_offsets;
// Same idea for street names - one lookup table for names for all features
std::vector<util::StringView> names;
std::unordered_map<util::StringView, std::size_t> name_offsets;
// And again for integer values used by points.
std::vector<int> used_point_ints;
std::unordered_map<int, std::size_t> point_int_offsets;
// And again for float values used by points
std::vector<float> used_point_floats;
std::unordered_map<float, std::size_t> point_float_offsets;
std::uint8_t max_datasource_id = 0;
// This is where we accumulate information on turns
// Helper function for adding a new value to the line_ints lookup table. Returns
// the index of the value in the table, adding the value if it doesn't already
// exist
const auto use_line_value = [&used_line_ints, &line_int_offsets](const int value) {
const auto found = line_int_offsets.find(value);
if (found == line_int_offsets.end())
{
used_line_ints.push_back(value);
line_int_offsets[value] = used_line_ints.size() - 1;
}
return;
};
// Same again
const auto use_point_int_value = [&used_point_ints, &point_int_offsets](const int value) {
const auto found = point_int_offsets.find(value);
std::size_t offset;
if (found == point_int_offsets.end())
{
used_point_ints.push_back(value);
offset = used_point_ints.size() - 1;
point_int_offsets[value] = offset;
}
else
{
offset = found->second;
}
return offset;
};
// And a third time, should probably template this....
const auto use_point_float_value = [&used_point_floats,
&point_float_offsets](const float value) {
const auto found = point_float_offsets.find(value);
std::size_t offset;
if (found == point_float_offsets.end())
{
used_point_floats.push_back(value);
offset = used_point_floats.size() - 1;
point_float_offsets[value] = offset;
}
else
{
offset = found->second;
}
return offset;
};
// Vector tiles encode properties on features as indexes into a layer-specific
// lookup table. These ValueIndexer's act as memoizers for values as we discover
// them during edge explioration, and are then used to generate the lookup
// tables for each tile layer.
ValueIndexer<int> line_int_index;
ValueIndexer<util::StringView> line_string_index;
ValueIndexer<int> point_int_index;
ValueIndexer<float> point_float_index;
ValueIndexer<std::string> point_string_index;
const auto get_geometry_id = [&facade](auto edge) {
return facade.GetGeometryIndex(edge.forward_segment_id.id).id;
@ -439,16 +406,16 @@ void encodeVectorTile(const DataFacadeBase &facade,
const auto forward_weight = forward_weight_vector[edge.fwd_segment_position];
const auto reverse_weight = reverse_weight_vector[reverse_weight_vector.size() -
edge.fwd_segment_position - 1];
use_line_value(forward_weight);
use_line_value(reverse_weight);
line_int_index.add(forward_weight);
line_int_index.add(reverse_weight);
std::uint32_t forward_rate =
static_cast<std::uint32_t>(round(length / forward_weight * 10.));
std::uint32_t reverse_rate =
static_cast<std::uint32_t>(round(length / reverse_weight * 10.));
use_line_value(forward_rate);
use_line_value(reverse_rate);
line_int_index.add(forward_rate);
line_int_index.add(reverse_rate);
// Duration values
const auto forward_duration_vector =
@ -459,8 +426,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
const auto reverse_duration =
reverse_duration_vector[reverse_duration_vector.size() -
edge.fwd_segment_position - 1];
use_line_value(forward_duration);
use_line_value(reverse_duration);
line_int_index.add(forward_duration);
line_int_index.add(reverse_duration);
}
// Begin the layer features block
@ -510,24 +477,14 @@ void encodeVectorTile(const DataFacadeBase &facade,
const auto name_id = facade.GetNameIndex(edge.forward_segment_id.id);
auto name = facade.GetNameForID(name_id);
const auto name_offset = [&name, &names, &name_offsets]() {
auto iter = name_offsets.find(name);
if (iter == name_offsets.end())
{
auto offset = names.size();
name_offsets[name] = offset;
names.push_back(name);
return offset;
}
return iter->second;
}();
line_string_index.add(name);
const auto encode_tile_line = [&line_layer_writer,
&edge,
&component_id,
&id,
&max_datasource_id,
&used_line_ints](
&line_int_index](
const FixedLine &tile_line,
const std::uint32_t speed_kmh_idx,
const std::uint32_t rate_idx,
@ -575,12 +532,11 @@ void encodeVectorTile(const DataFacadeBase &facade,
duration_idx); // duration value offset
field.add_element(5); // "name" tag key offset
field.add_element(130 + max_datasource_id + 1 + used_line_ints.size() +
name_idx); // name value offset
field.add_element(130 + max_datasource_id + 1 +
line_int_index.values().size() + name_idx);
field.add_element(6); // rate tag key offset
field.add_element(130 + max_datasource_id + 1 +
rate_idx); // rate goes in used_line_ints
field.add_element(130 + max_datasource_id + 1 + rate_idx);
}
{
@ -614,11 +570,11 @@ void encodeVectorTile(const DataFacadeBase &facade,
{
encode_tile_line(tile_line,
speed_kmh_idx,
line_int_offsets[forward_rate],
line_int_offsets[forward_weight],
line_int_offsets[forward_duration],
line_int_index.indexOf(forward_rate),
line_int_index.indexOf(forward_weight),
line_int_index.indexOf(forward_duration),
forward_datasource_idx,
name_offset,
line_string_index.indexOf(name),
start_x,
start_y);
}
@ -648,11 +604,11 @@ void encodeVectorTile(const DataFacadeBase &facade,
{
encode_tile_line(tile_line,
speed_kmh_idx,
line_int_offsets[reverse_rate],
line_int_offsets[reverse_weight],
line_int_offsets[reverse_duration],
line_int_index.indexOf(reverse_rate),
line_int_index.indexOf(reverse_weight),
line_int_index.indexOf(reverse_duration),
reverse_datasource_idx,
name_offset,
line_string_index.indexOf(name),
start_x,
start_y);
}
@ -703,7 +659,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING,
facade.GetDatasourceName(i).to_string());
}
for (auto value : used_line_ints)
for (auto value : line_int_index.values())
{
// Writing field type 4 == variant type
protozero::pbf_writer values_writer(line_layer_writer,
@ -714,7 +670,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
values_writer.add_double(util::vector_tile::VARIANT_TYPE_DOUBLE, value / 10.);
}
for (const auto &name : names)
for (const auto &name : line_string_index.values())
{
// Writing field type 4 == variant type
protozero::pbf_writer values_writer(line_layer_writer,
@ -729,23 +685,46 @@ void encodeVectorTile(const DataFacadeBase &facade,
// for tiles of z<16, and tiles that don't show any intersections)
if (!all_turn_data.empty())
{
struct EncodedTurnData
{
util::Coordinate coordinate;
std::size_t angle_index;
std::size_t turn_index;
std::size_t duration_index;
std::size_t weight_index;
std::size_t turntype_index;
std::size_t turnmodifier_index;
};
// we need to pre-encode all values here because we need the full offsets later
// for encoding the actual features.
std::vector<std::tuple<util::Coordinate, unsigned, unsigned, unsigned, unsigned>>
encoded_turn_data(all_turn_data.size());
std::transform(all_turn_data.begin(),
all_turn_data.end(),
encoded_turn_data.begin(),
[&](const routing_algorithms::TurnData &t) {
auto angle_idx = use_point_int_value(t.in_angle);
auto turn_idx = use_point_int_value(t.turn_angle);
auto duration_idx = use_point_float_value(
t.duration / 10.0); // Note conversion to float here
auto weight_idx = use_point_float_value(
t.weight / 10.0); // Note conversion to float here
return std::make_tuple(
t.coordinate, angle_idx, turn_idx, duration_idx, weight_idx);
});
std::vector<EncodedTurnData> encoded_turn_data(all_turn_data.size());
std::transform(
all_turn_data.begin(),
all_turn_data.end(),
encoded_turn_data.begin(),
[&](const routing_algorithms::TurnData &t) {
auto angle_idx = point_int_index.add(t.in_angle);
auto turn_idx = point_int_index.add(t.turn_angle);
auto duration_idx =
point_float_index.add(t.duration / 10.0); // Note conversion to float here
auto weight_idx =
point_float_index.add(t.weight / 10.0); // Note conversion to float here
auto turntype_idx =
point_string_index.add(api::json::detail::internalInstructionTypeToString(
t.turn_instruction.type));
auto turnmodifier_idx =
point_string_index.add(api::json::detail::instructionModifierToString(
t.turn_instruction.direction_modifier));
return EncodedTurnData{t.coordinate,
angle_idx,
turn_idx,
duration_idx,
weight_idx,
turntype_idx,
turnmodifier_idx};
});
// Now write the points layer for turn penalty data:
// Add a layer object to the PBF stream. 3=='layer' from the vector tile spec
@ -778,13 +757,19 @@ void encodeVectorTile(const DataFacadeBase &facade,
protozero::packed_field_uint32 field(
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
field.add_element(0); // "bearing_in" tag key offset
field.add_element(std::get<1>(point_turn_data));
field.add_element(point_turn_data.angle_index);
field.add_element(1); // "turn_angle" tag key offset
field.add_element(std::get<2>(point_turn_data));
field.add_element(point_turn_data.turn_index);
field.add_element(2); // "cost" tag key offset
field.add_element(used_point_ints.size() + std::get<3>(point_turn_data));
field.add_element(point_int_index.size() + point_turn_data.duration_index);
field.add_element(3); // "weight" tag key offset
field.add_element(used_point_ints.size() + std::get<4>(point_turn_data));
field.add_element(point_int_index.size() + point_turn_data.weight_index);
field.add_element(4); // "type" tag key offset
field.add_element(point_int_index.size() + point_float_index.size() +
point_turn_data.turntype_index);
field.add_element(5); // "modifier" tag key offset
field.add_element(point_int_index.size() + point_float_index.size() +
point_turn_data.turnmodifier_index);
}
{
// Add the geometry as the last field in this feature
@ -797,8 +782,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
// Loop over all the turns we found and add them as features to the layer
for (const auto &turndata : encoded_turn_data)
{
const auto tile_point =
coordinatesToTilePoint(std::get<0>(turndata), tile_bbox);
const auto tile_point = coordinatesToTilePoint(turndata.coordinate, tile_bbox);
if (!boost::geometry::within(point_t(tile_point.x, tile_point.y), clip_box))
{
continue;
@ -813,20 +797,28 @@ void encodeVectorTile(const DataFacadeBase &facade,
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "turn_angle");
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "cost");
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "weight");
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "type");
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "modifier");
// Now, save the lists of integers and floats that our features refer to.
for (const auto &value : used_point_ints)
for (const auto &value : point_int_index.values())
{
protozero::pbf_writer values_writer(point_layer_writer,
util::vector_tile::VARIANT_TAG);
values_writer.add_sint64(util::vector_tile::VARIANT_TYPE_SINT64, value);
}
for (const auto &value : used_point_floats)
for (const auto &value : point_float_index.values())
{
protozero::pbf_writer values_writer(point_layer_writer,
util::vector_tile::VARIANT_TAG);
values_writer.add_float(util::vector_tile::VARIANT_TYPE_FLOAT, value);
}
for (const auto &value : point_string_index.values())
{
protozero::pbf_writer values_writer(point_layer_writer,
util::vector_tile::VARIANT_TAG);
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING, value);
}
}
// OSM Node tile layer

View File

@ -183,6 +183,7 @@ std::vector<TurnData> generateTurns(const datafacade &facade,
// treat the whole lot as the "turn cost" that we'll stick on the map.
const auto turn_weight = data.weight - sum_node_weight;
const auto turn_duration = data.duration - sum_node_duration;
const auto turn_instruction = facade.GetTurnInstructionForEdgeID(data.turn_id);
// Find the three nodes that make up the turn movement)
const auto node_from = startnode;
@ -214,8 +215,12 @@ std::vector<TurnData> generateTurns(const datafacade &facade,
// Save everything we need to later add all the points to the tile.
// We need the coordinate of the intersection, the angle in, the turn
// angle and the turn cost.
all_turn_data.push_back(
TurnData{coord_via, angle_in, turn_angle, turn_weight, turn_duration});
all_turn_data.push_back(TurnData{coord_via,
angle_in,
turn_angle,
turn_weight,
turn_duration,
turn_instruction});
}
}
}

View File

@ -10,7 +10,7 @@ exports.three_test_coordinates = [[7.41337, 43.72956],
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2)
exports.test_tile = {'at': [17059, 11948, 15], 'size': 162429};
exports.test_tile = {'at': [17059, 11948, 15], 'size': 167178};
// Test files generated by the routing engine; check test/data

View File

@ -151,7 +151,7 @@ void validate_turn_layer(protozero::pbf_reader &layer_message)
BOOST_CHECK_EQUAL(feature_message.tag(), util::vector_tile::FEATURE_ATTRIBUTES_TAG);
// properties
auto feature_iter_pair = feature_message.get_packed_uint32();
BOOST_CHECK_EQUAL(std::distance(feature_iter_pair.begin(), feature_iter_pair.end()), 8);
BOOST_CHECK_EQUAL(std::distance(feature_iter_pair.begin(), feature_iter_pair.end()), 12);
auto iter = feature_iter_pair.begin();
BOOST_CHECK_EQUAL(*iter++, 0); // bearing_in key
*iter++;
@ -161,6 +161,10 @@ void validate_turn_layer(protozero::pbf_reader &layer_message)
*iter++; // skip value check, can be valud uint32
BOOST_CHECK_EQUAL(*iter++, 3); // turn weight key
*iter++; // skip value check, can be valud uint32
BOOST_CHECK_EQUAL(*iter++, 4); // turn type key
*iter++; // skip value check, can be valud uint32
BOOST_CHECK_EQUAL(*iter++, 5); // turn modifier
*iter++; // skip value check, can be valud uint32
BOOST_CHECK(iter == feature_iter_pair.end());
// geometry
feature_message.next();
@ -201,7 +205,7 @@ void validate_turn_layer(protozero::pbf_reader &layer_message)
}
}
BOOST_CHECK_EQUAL(number_of_turn_keys, 4);
BOOST_CHECK_EQUAL(number_of_turn_keys, 6);
BOOST_CHECK(number_of_turns_found > 700);
}
@ -337,6 +341,8 @@ void test_tile_turns(const osrm::OSRM &osrm)
std::vector<int> found_turn_angles_indexes;
std::vector<int> found_time_penalties_indexes;
std::vector<int> found_weight_penalties_indexes;
std::vector<int> found_turn_type_indexes;
std::vector<int> found_turn_modifier_indexes;
const auto check_turn_feature = [&](protozero::pbf_reader feature_message) {
feature_message.next(); // advance parser to first entry
@ -351,7 +357,7 @@ void test_tile_turns(const osrm::OSRM &osrm)
BOOST_CHECK_EQUAL(feature_message.tag(), util::vector_tile::FEATURE_ATTRIBUTES_TAG);
// properties
auto feature_iter_pair = feature_message.get_packed_uint32();
BOOST_CHECK_EQUAL(std::distance(feature_iter_pair.begin(), feature_iter_pair.end()), 8);
BOOST_CHECK_EQUAL(std::distance(feature_iter_pair.begin(), feature_iter_pair.end()), 12);
auto iter = feature_iter_pair.begin();
BOOST_CHECK_EQUAL(*iter++, 0); // bearing_in key
found_bearing_in_indexes.push_back(*iter++);
@ -361,6 +367,10 @@ void test_tile_turns(const osrm::OSRM &osrm)
found_time_penalties_indexes.push_back(*iter++); // skip value check, can be valud uint32
BOOST_CHECK_EQUAL(*iter++, 3); // "weight" key
found_weight_penalties_indexes.push_back(*iter++); // skip value check, can be valud uint32
BOOST_CHECK_EQUAL(*iter++, 4); // "weight" key
found_turn_type_indexes.push_back(*iter++); // skip value check, can be valud uint32
BOOST_CHECK_EQUAL(*iter++, 5); // "weight" key
found_turn_modifier_indexes.push_back(*iter++); // skip value check, can be valud uint32
BOOST_CHECK(iter == feature_iter_pair.end());
// geometry
feature_message.next();
@ -370,6 +380,7 @@ void test_tile_turns(const osrm::OSRM &osrm)
std::unordered_map<int, float> float_vals;
std::unordered_map<int, std::int64_t> sint64_vals;
std::unordered_map<int, std::string> string_vals;
int kv_index = 0;
@ -384,6 +395,9 @@ void test_tile_turns(const osrm::OSRM &osrm)
case util::vector_tile::VARIANT_TYPE_SINT64:
sint64_vals[kv_index] = value.get_sint64();
break;
case util::vector_tile::VARIANT_TYPE_STRING:
string_vals[kv_index] = value.get_string();
break;
default:
BOOST_CHECK(false);
}
@ -448,6 +462,62 @@ void test_tile_turns(const osrm::OSRM &osrm)
0, 0, 0, 0, 0, 0, .1f, .1f, .3f, .4f, 1.2f, 1.9f, 5.3f, 5.5f, 5.8f, 7.1f, 7.2f, 7.2f};
CHECK_EQUAL_RANGE(actual_weight_turn_penalties, expected_weight_turn_penalties);
// Verify that we got the expected turn types
std::vector<std::string> actual_turn_types;
for (const auto &i : found_turn_type_indexes)
{
BOOST_CHECK(string_vals.count(i) == 1);
actual_turn_types.push_back(string_vals[i]);
}
std::sort(actual_turn_types.begin(), actual_turn_types.end());
const std::vector<std::string> expected_turn_types = {"(noturn)",
"(noturn)",
"(noturn)",
"(noturn)",
"(suppressed)",
"(suppressed)",
"end of road",
"end of road",
"fork",
"fork",
"turn",
"turn",
"turn",
"turn",
"turn",
"turn",
"turn",
"turn"};
CHECK_EQUAL_RANGE(actual_turn_types, expected_turn_types);
// Verify that we got the expected turn modifiers
std::vector<std::string> actual_turn_modifiers;
for (const auto &i : found_turn_modifier_indexes)
{
BOOST_CHECK(string_vals.count(i) == 1);
actual_turn_modifiers.push_back(string_vals[i]);
}
std::sort(actual_turn_modifiers.begin(), actual_turn_modifiers.end());
const std::vector<std::string> expected_turn_modifiers = {"left",
"left",
"left",
"left",
"right",
"right",
"right",
"right",
"sharp left",
"sharp right",
"slight left",
"slight left",
"slight right",
"slight right",
"straight",
"straight",
"straight",
"straight"};
CHECK_EQUAL_RANGE(actual_turn_modifiers, expected_turn_modifiers);
// Verify the expected turn angles
std::vector<std::int64_t> actual_turn_angles;
for (const auto &i : found_turn_angles_indexes)