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:
parent
89cf6d9e74
commit
0fc1aa2711
@ -17,6 +17,8 @@
|
|||||||
updating ETAs returned, without changing route selection (for example, in a distance-based profile with traffic data loaded).
|
updating ETAs returned, without changing route selection (for example, in a distance-based profile with traffic data loaded).
|
||||||
- Infrastructure:
|
- Infrastructure:
|
||||||
- New file `.osrm.cell_metrics` created by `osrm-customize`.
|
- 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
|
# 5.11.0
|
||||||
- Changes from 5.10:
|
- Changes from 5.10:
|
||||||
|
@ -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 |
|
| `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"). |
|
| `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 |
|
| `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
|
## Result objects
|
||||||
|
@ -36,6 +36,15 @@ namespace detail
|
|||||||
std::string instructionTypeToString(extractor::guidance::TurnType::Enum type);
|
std::string instructionTypeToString(extractor::guidance::TurnType::Enum type);
|
||||||
std::string instructionModifierToString(extractor::guidance::DirectionModifier::Enum modifier);
|
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);
|
util::json::Array coordinateToLonLat(const util::Coordinate coordinate);
|
||||||
|
|
||||||
std::string modeToString(const extractor::TravelMode mode);
|
std::string modeToString(const extractor::TravelMode mode);
|
||||||
|
@ -24,6 +24,7 @@ struct TurnData final
|
|||||||
const int turn_angle;
|
const int turn_angle;
|
||||||
const EdgeWeight weight;
|
const EdgeWeight weight;
|
||||||
const EdgeWeight duration;
|
const EdgeWeight duration;
|
||||||
|
const extractor::guidance::TurnInstruction turn_instruction;
|
||||||
};
|
};
|
||||||
|
|
||||||
using RTreeLeaf = datafacade::BaseDataFacade::RTreeLeaf;
|
using RTreeLeaf = datafacade::BaseDataFacade::RTreeLeaf;
|
||||||
|
@ -41,15 +41,47 @@ const constexpr char *modifier_names[] = {"uturn",
|
|||||||
"left",
|
"left",
|
||||||
"sharp 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
|
* Human readable values for TurnType enum values
|
||||||
const constexpr char *turn_type_names[] = {
|
*/
|
||||||
"invalid", "new name", "continue", "turn", "merge",
|
struct TurnTypeName
|
||||||
"on ramp", "off ramp", "fork", "end of road", "notification",
|
{
|
||||||
"roundabout", "roundabout", "rotary", "rotary", "roundabout turn",
|
// String value we return with our API
|
||||||
"roundabout turn", "use lane", "invalid", "invalid", "invalid",
|
const char *external_name;
|
||||||
"invalid", "invalid", "invalid", "invalid", "invalid",
|
// Internal only string name for the turn type - useful for debugging
|
||||||
"invalid", "invalid"};
|
// 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"};
|
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,
|
static_assert(sizeof(turn_type_names) / sizeof(turn_type_names[0]) >= TurnType::MaxTurnType,
|
||||||
"Some turn types has not string representation.");
|
"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)
|
util::json::Array lanesFromIntersection(const guidance::IntermediateIntersection &intersection)
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include "util/vector_tile.hpp"
|
#include "util/vector_tile.hpp"
|
||||||
#include "util/web_mercator.hpp"
|
#include "util/web_mercator.hpp"
|
||||||
|
|
||||||
|
#include "engine/api/json_factory.hpp"
|
||||||
|
|
||||||
#include <boost/geometry.hpp>
|
#include <boost/geometry.hpp>
|
||||||
#include <boost/geometry/geometries/geometries.hpp>
|
#include <boost/geometry/geometries/geometries.hpp>
|
||||||
#include <boost/geometry/geometries/point_xy.hpp>
|
#include <boost/geometry/geometries/point_xy.hpp>
|
||||||
@ -37,6 +39,41 @@ constexpr const static int MIN_ZOOM_FOR_TURNS = 15;
|
|||||||
namespace
|
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;
|
using RTreeLeaf = datafacade::BaseDataFacade::RTreeLeaf;
|
||||||
// TODO: Port all this encoding logic to https://github.com/mapbox/vector-tile, which wasn't
|
// TODO: Port all this encoding logic to https://github.com/mapbox/vector-tile, which wasn't
|
||||||
// available when this code was originally written.
|
// available when this code was originally written.
|
||||||
@ -281,87 +318,17 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
std::string &pbf_buffer)
|
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;
|
std::uint8_t max_datasource_id = 0;
|
||||||
|
|
||||||
// This is where we accumulate information on turns
|
// 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
|
||||||
// Helper function for adding a new value to the line_ints lookup table. Returns
|
// them during edge explioration, and are then used to generate the lookup
|
||||||
// the index of the value in the table, adding the value if it doesn't already
|
// tables for each tile layer.
|
||||||
// exist
|
ValueIndexer<int> line_int_index;
|
||||||
const auto use_line_value = [&used_line_ints, &line_int_offsets](const int value) {
|
ValueIndexer<util::StringView> line_string_index;
|
||||||
const auto found = line_int_offsets.find(value);
|
ValueIndexer<int> point_int_index;
|
||||||
|
ValueIndexer<float> point_float_index;
|
||||||
if (found == line_int_offsets.end())
|
ValueIndexer<std::string> point_string_index;
|
||||||
{
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto get_geometry_id = [&facade](auto edge) {
|
const auto get_geometry_id = [&facade](auto edge) {
|
||||||
return facade.GetGeometryIndex(edge.forward_segment_id.id).id;
|
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 forward_weight = forward_weight_vector[edge.fwd_segment_position];
|
||||||
const auto reverse_weight = reverse_weight_vector[reverse_weight_vector.size() -
|
const auto reverse_weight = reverse_weight_vector[reverse_weight_vector.size() -
|
||||||
edge.fwd_segment_position - 1];
|
edge.fwd_segment_position - 1];
|
||||||
use_line_value(forward_weight);
|
line_int_index.add(forward_weight);
|
||||||
use_line_value(reverse_weight);
|
line_int_index.add(reverse_weight);
|
||||||
|
|
||||||
std::uint32_t forward_rate =
|
std::uint32_t forward_rate =
|
||||||
static_cast<std::uint32_t>(round(length / forward_weight * 10.));
|
static_cast<std::uint32_t>(round(length / forward_weight * 10.));
|
||||||
std::uint32_t reverse_rate =
|
std::uint32_t reverse_rate =
|
||||||
static_cast<std::uint32_t>(round(length / reverse_weight * 10.));
|
static_cast<std::uint32_t>(round(length / reverse_weight * 10.));
|
||||||
|
|
||||||
use_line_value(forward_rate);
|
line_int_index.add(forward_rate);
|
||||||
use_line_value(reverse_rate);
|
line_int_index.add(reverse_rate);
|
||||||
|
|
||||||
// Duration values
|
// Duration values
|
||||||
const auto forward_duration_vector =
|
const auto forward_duration_vector =
|
||||||
@ -459,8 +426,8 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
const auto reverse_duration =
|
const auto reverse_duration =
|
||||||
reverse_duration_vector[reverse_duration_vector.size() -
|
reverse_duration_vector[reverse_duration_vector.size() -
|
||||||
edge.fwd_segment_position - 1];
|
edge.fwd_segment_position - 1];
|
||||||
use_line_value(forward_duration);
|
line_int_index.add(forward_duration);
|
||||||
use_line_value(reverse_duration);
|
line_int_index.add(reverse_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin the layer features block
|
// 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);
|
const auto name_id = facade.GetNameIndex(edge.forward_segment_id.id);
|
||||||
auto name = facade.GetNameForID(name_id);
|
auto name = facade.GetNameForID(name_id);
|
||||||
|
|
||||||
const auto name_offset = [&name, &names, &name_offsets]() {
|
line_string_index.add(name);
|
||||||
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;
|
|
||||||
}();
|
|
||||||
|
|
||||||
const auto encode_tile_line = [&line_layer_writer,
|
const auto encode_tile_line = [&line_layer_writer,
|
||||||
&edge,
|
&edge,
|
||||||
&component_id,
|
&component_id,
|
||||||
&id,
|
&id,
|
||||||
&max_datasource_id,
|
&max_datasource_id,
|
||||||
&used_line_ints](
|
&line_int_index](
|
||||||
const FixedLine &tile_line,
|
const FixedLine &tile_line,
|
||||||
const std::uint32_t speed_kmh_idx,
|
const std::uint32_t speed_kmh_idx,
|
||||||
const std::uint32_t rate_idx,
|
const std::uint32_t rate_idx,
|
||||||
@ -575,12 +532,11 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
duration_idx); // duration value offset
|
duration_idx); // duration value offset
|
||||||
field.add_element(5); // "name" tag key offset
|
field.add_element(5); // "name" tag key offset
|
||||||
|
|
||||||
field.add_element(130 + max_datasource_id + 1 + used_line_ints.size() +
|
field.add_element(130 + max_datasource_id + 1 +
|
||||||
name_idx); // name value offset
|
line_int_index.values().size() + name_idx);
|
||||||
|
|
||||||
field.add_element(6); // rate tag key offset
|
field.add_element(6); // rate tag key offset
|
||||||
field.add_element(130 + max_datasource_id + 1 +
|
field.add_element(130 + max_datasource_id + 1 + rate_idx);
|
||||||
rate_idx); // rate goes in used_line_ints
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -614,11 +570,11 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
{
|
{
|
||||||
encode_tile_line(tile_line,
|
encode_tile_line(tile_line,
|
||||||
speed_kmh_idx,
|
speed_kmh_idx,
|
||||||
line_int_offsets[forward_rate],
|
line_int_index.indexOf(forward_rate),
|
||||||
line_int_offsets[forward_weight],
|
line_int_index.indexOf(forward_weight),
|
||||||
line_int_offsets[forward_duration],
|
line_int_index.indexOf(forward_duration),
|
||||||
forward_datasource_idx,
|
forward_datasource_idx,
|
||||||
name_offset,
|
line_string_index.indexOf(name),
|
||||||
start_x,
|
start_x,
|
||||||
start_y);
|
start_y);
|
||||||
}
|
}
|
||||||
@ -648,11 +604,11 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
{
|
{
|
||||||
encode_tile_line(tile_line,
|
encode_tile_line(tile_line,
|
||||||
speed_kmh_idx,
|
speed_kmh_idx,
|
||||||
line_int_offsets[reverse_rate],
|
line_int_index.indexOf(reverse_rate),
|
||||||
line_int_offsets[reverse_weight],
|
line_int_index.indexOf(reverse_weight),
|
||||||
line_int_offsets[reverse_duration],
|
line_int_index.indexOf(reverse_duration),
|
||||||
reverse_datasource_idx,
|
reverse_datasource_idx,
|
||||||
name_offset,
|
line_string_index.indexOf(name),
|
||||||
start_x,
|
start_x,
|
||||||
start_y);
|
start_y);
|
||||||
}
|
}
|
||||||
@ -703,7 +659,7 @@ void encodeVectorTile(const DataFacadeBase &facade,
|
|||||||
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING,
|
values_writer.add_string(util::vector_tile::VARIANT_TYPE_STRING,
|
||||||
facade.GetDatasourceName(i).to_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
|
// Writing field type 4 == variant type
|
||||||
protozero::pbf_writer values_writer(line_layer_writer,
|
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.);
|
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
|
// Writing field type 4 == variant type
|
||||||
protozero::pbf_writer values_writer(line_layer_writer,
|
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)
|
// for tiles of z<16, and tiles that don't show any intersections)
|
||||||
if (!all_turn_data.empty())
|
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
|
// we need to pre-encode all values here because we need the full offsets later
|
||||||
// for encoding the actual features.
|
// for encoding the actual features.
|
||||||
std::vector<std::tuple<util::Coordinate, unsigned, unsigned, unsigned, unsigned>>
|
std::vector<EncodedTurnData> encoded_turn_data(all_turn_data.size());
|
||||||
encoded_turn_data(all_turn_data.size());
|
std::transform(
|
||||||
std::transform(all_turn_data.begin(),
|
all_turn_data.begin(),
|
||||||
all_turn_data.end(),
|
all_turn_data.end(),
|
||||||
encoded_turn_data.begin(),
|
encoded_turn_data.begin(),
|
||||||
[&](const routing_algorithms::TurnData &t) {
|
[&](const routing_algorithms::TurnData &t) {
|
||||||
auto angle_idx = use_point_int_value(t.in_angle);
|
auto angle_idx = point_int_index.add(t.in_angle);
|
||||||
auto turn_idx = use_point_int_value(t.turn_angle);
|
auto turn_idx = point_int_index.add(t.turn_angle);
|
||||||
auto duration_idx = use_point_float_value(
|
auto duration_idx =
|
||||||
t.duration / 10.0); // Note conversion to float here
|
point_float_index.add(t.duration / 10.0); // Note conversion to float here
|
||||||
auto weight_idx = use_point_float_value(
|
auto weight_idx =
|
||||||
t.weight / 10.0); // Note conversion to float here
|
point_float_index.add(t.weight / 10.0); // Note conversion to float here
|
||||||
return std::make_tuple(
|
|
||||||
t.coordinate, angle_idx, turn_idx, duration_idx, weight_idx);
|
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:
|
// Now write the points layer for turn penalty data:
|
||||||
// Add a layer object to the PBF stream. 3=='layer' from the vector tile spec
|
// 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(
|
protozero::packed_field_uint32 field(
|
||||||
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
||||||
field.add_element(0); // "bearing_in" tag key offset
|
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(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(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(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
|
// 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
|
// Loop over all the turns we found and add them as features to the layer
|
||||||
for (const auto &turndata : encoded_turn_data)
|
for (const auto &turndata : encoded_turn_data)
|
||||||
{
|
{
|
||||||
const auto tile_point =
|
const auto tile_point = coordinatesToTilePoint(turndata.coordinate, tile_bbox);
|
||||||
coordinatesToTilePoint(std::get<0>(turndata), tile_bbox);
|
|
||||||
if (!boost::geometry::within(point_t(tile_point.x, tile_point.y), clip_box))
|
if (!boost::geometry::within(point_t(tile_point.x, tile_point.y), clip_box))
|
||||||
{
|
{
|
||||||
continue;
|
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, "turn_angle");
|
||||||
point_layer_writer.add_string(util::vector_tile::KEY_TAG, "cost");
|
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, "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.
|
// 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,
|
protozero::pbf_writer values_writer(point_layer_writer,
|
||||||
util::vector_tile::VARIANT_TAG);
|
util::vector_tile::VARIANT_TAG);
|
||||||
values_writer.add_sint64(util::vector_tile::VARIANT_TYPE_SINT64, value);
|
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,
|
protozero::pbf_writer values_writer(point_layer_writer,
|
||||||
util::vector_tile::VARIANT_TAG);
|
util::vector_tile::VARIANT_TAG);
|
||||||
values_writer.add_float(util::vector_tile::VARIANT_TYPE_FLOAT, value);
|
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
|
// OSM Node tile layer
|
||||||
|
@ -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.
|
// 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_weight = data.weight - sum_node_weight;
|
||||||
const auto turn_duration = data.duration - sum_node_duration;
|
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)
|
// Find the three nodes that make up the turn movement)
|
||||||
const auto node_from = startnode;
|
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.
|
// 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
|
// We need the coordinate of the intersection, the angle in, the turn
|
||||||
// angle and the turn cost.
|
// angle and the turn cost.
|
||||||
all_turn_data.push_back(
|
all_turn_data.push_back(TurnData{coord_via,
|
||||||
TurnData{coord_via, angle_in, turn_angle, turn_weight, turn_duration});
|
angle_in,
|
||||||
|
turn_angle,
|
||||||
|
turn_weight,
|
||||||
|
turn_duration,
|
||||||
|
turn_instruction});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ exports.three_test_coordinates = [[7.41337, 43.72956],
|
|||||||
|
|
||||||
exports.two_test_coordinates = exports.three_test_coordinates.slice(0, 2)
|
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
|
// Test files generated by the routing engine; check test/data
|
||||||
|
@ -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);
|
BOOST_CHECK_EQUAL(feature_message.tag(), util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
||||||
// properties
|
// properties
|
||||||
auto feature_iter_pair = feature_message.get_packed_uint32();
|
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();
|
auto iter = feature_iter_pair.begin();
|
||||||
BOOST_CHECK_EQUAL(*iter++, 0); // bearing_in key
|
BOOST_CHECK_EQUAL(*iter++, 0); // bearing_in key
|
||||||
*iter++;
|
*iter++;
|
||||||
@ -161,6 +161,10 @@ void validate_turn_layer(protozero::pbf_reader &layer_message)
|
|||||||
*iter++; // skip value check, can be valud uint32
|
*iter++; // skip value check, can be valud uint32
|
||||||
BOOST_CHECK_EQUAL(*iter++, 3); // turn weight key
|
BOOST_CHECK_EQUAL(*iter++, 3); // turn weight key
|
||||||
*iter++; // skip value check, can be valud uint32
|
*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());
|
BOOST_CHECK(iter == feature_iter_pair.end());
|
||||||
// geometry
|
// geometry
|
||||||
feature_message.next();
|
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);
|
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_turn_angles_indexes;
|
||||||
std::vector<int> found_time_penalties_indexes;
|
std::vector<int> found_time_penalties_indexes;
|
||||||
std::vector<int> found_weight_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) {
|
const auto check_turn_feature = [&](protozero::pbf_reader feature_message) {
|
||||||
feature_message.next(); // advance parser to first entry
|
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);
|
BOOST_CHECK_EQUAL(feature_message.tag(), util::vector_tile::FEATURE_ATTRIBUTES_TAG);
|
||||||
// properties
|
// properties
|
||||||
auto feature_iter_pair = feature_message.get_packed_uint32();
|
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();
|
auto iter = feature_iter_pair.begin();
|
||||||
BOOST_CHECK_EQUAL(*iter++, 0); // bearing_in key
|
BOOST_CHECK_EQUAL(*iter++, 0); // bearing_in key
|
||||||
found_bearing_in_indexes.push_back(*iter++);
|
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
|
found_time_penalties_indexes.push_back(*iter++); // skip value check, can be valud uint32
|
||||||
BOOST_CHECK_EQUAL(*iter++, 3); // "weight" key
|
BOOST_CHECK_EQUAL(*iter++, 3); // "weight" key
|
||||||
found_weight_penalties_indexes.push_back(*iter++); // skip value check, can be valud uint32
|
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());
|
BOOST_CHECK(iter == feature_iter_pair.end());
|
||||||
// geometry
|
// geometry
|
||||||
feature_message.next();
|
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, float> float_vals;
|
||||||
std::unordered_map<int, std::int64_t> sint64_vals;
|
std::unordered_map<int, std::int64_t> sint64_vals;
|
||||||
|
std::unordered_map<int, std::string> string_vals;
|
||||||
|
|
||||||
int kv_index = 0;
|
int kv_index = 0;
|
||||||
|
|
||||||
@ -384,6 +395,9 @@ void test_tile_turns(const osrm::OSRM &osrm)
|
|||||||
case util::vector_tile::VARIANT_TYPE_SINT64:
|
case util::vector_tile::VARIANT_TYPE_SINT64:
|
||||||
sint64_vals[kv_index] = value.get_sint64();
|
sint64_vals[kv_index] = value.get_sint64();
|
||||||
break;
|
break;
|
||||||
|
case util::vector_tile::VARIANT_TYPE_STRING:
|
||||||
|
string_vals[kv_index] = value.get_string();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_CHECK(false);
|
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};
|
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);
|
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
|
// Verify the expected turn angles
|
||||||
std::vector<std::int64_t> actual_turn_angles;
|
std::vector<std::int64_t> actual_turn_angles;
|
||||||
for (const auto &i : found_turn_angles_indexes)
|
for (const auto &i : found_turn_angles_indexes)
|
||||||
|
Loading…
Reference in New Issue
Block a user