From e3276324b961b53a2334ecb16226dd5723d07715 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Thu, 15 Jun 2017 17:50:57 +0200 Subject: [PATCH] Include 'rate' property (reciprocal of weight) on debug tile edges. (#4162) Include 'rate' property (reciprocal of weight) on debug tile edges and add turn weight data to debug tiles. --- CHANGELOG.md | 2 + docs/http.md | 5 +- src/engine/plugins/tile.cpp | 124 ++++++++++++++++++++++++------------ unit_tests/library/tile.cpp | 58 ++++++++++++----- 4 files changed, 131 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd5750af2..6b1239f04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ - #4075 Changed counting of exits on service roundabouts - Debug Tiles - added support for visualising turn penalties to the MLD plugin + - added support for showing the rate (reciprocal of weight) on each edge when used + - added support for turn weights in addition to turn durations in debug tiles - Bugfixes - Fixed a copy/paste issue assigning wrong directions in similar turns (left over right) - #4074: fixed a bug that would announce entering highway ramps as u-turns diff --git a/docs/http.md b/docs/http.md index 28601ba1b..24c00d59b 100644 --- a/docs/http.md +++ b/docs/http.md @@ -419,8 +419,10 @@ Vector tiles contain two layers: | `speed` | `integer` | the speed on that road segment, in km/h | | `is_small` | `boolean` | whether this segment belongs to a small (< 1000 node) [strongly connected component](https://en.wikipedia.org/wiki/Strongly_connected_component) | | `datasource` | `string` | the source for the speed value (normally `lua profile` unless you're using the [traffic update feature](https://github.com/Project-OSRM/osrm-backend/wiki/Traffic), in which case it contains the stem of the filename that supplied the speed value for this segment | -| `duration` | `float` | how long this segment takes to traverse, in seconds | +| `duration` | `float` | how long this segment takes to traverse, in seconds. This value is to calculate the total route ETA. | +| `weight ` | `integer` | how long this segment takes to traverse, in units (may differ from `duration` when artificial biasing is applied in the Lua profiles). ACTUAL ROUTING USES THIS VALUE. | | `name` | `string` | the name of the road this segment belongs to | +| `rate` | `float` | the value of `length/weight` - analagous to `speed`, but using the `weight` value rather than `duration`, rounded to the nearest integer | `turns` layer: @@ -429,6 +431,7 @@ Vector tiles contain two layers: | `bearing_in` | `integer` | the absolute bearing that approaches the intersection. -180 to +180, 0 = North, 90 = East | | `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 | ## Result objects diff --git a/src/engine/plugins/tile.cpp b/src/engine/plugins/tile.cpp index bf0476756..74f5b100e 100644 --- a/src/engine/plugins/tile.cpp +++ b/src/engine/plugins/tile.cpp @@ -428,6 +428,12 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & const auto &edge = edges[edge_index]; const auto geometry_id = get_geometry_id(edge); + // Get coordinates for start/end nodes of segment (NodeIDs u and v) + const auto a = facade.GetCoordinateOfNode(edge.u); + const auto b = facade.GetCoordinateOfNode(edge.v); + // Calculate the length in meters + const double length = osrm::util::coordinate_calculation::haversineDistance(a, b); + // Weight values const auto forward_weight_vector = facade.GetUncompressedForwardWeights(geometry_id); @@ -439,6 +445,14 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & use_line_value(forward_weight); use_line_value(reverse_weight); + std::uint32_t forward_rate = + static_cast(round(length / forward_weight * 10.)); + std::uint32_t reverse_rate = + static_cast(round(length / reverse_weight * 10.)); + + use_line_value(forward_rate); + use_line_value(reverse_rate); + // Duration values const auto forward_duration_vector = facade.GetUncompressedForwardDurations(geometry_id); @@ -489,9 +503,9 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & const auto reverse_duration = reverse_duration_vector[reverse_duration_vector.size() - edge.fwd_segment_position - 1]; - const auto forward_datasource = + const auto forward_datasource_idx = forward_datasource_vector[edge.fwd_segment_position]; - const auto reverse_datasource = + const auto reverse_datasource_idx = reverse_datasource_vector[reverse_datasource_vector.size() - edge.fwd_segment_position - 1]; @@ -516,14 +530,16 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & &component_id, &id, &max_datasource_id, - &used_line_ints](const FixedLine &tile_line, - const std::uint32_t speed_kmh, - const std::size_t weight, - const std::size_t duration, - const DatasourceID datasource, - const std::size_t name_idx, - std::int32_t &start_x, - std::int32_t &start_y) { + &used_line_ints]( + const FixedLine &tile_line, + const std::uint32_t speed_kmh_idx, + const std::uint32_t rate_idx, + const std::size_t weight_idx, + const std::size_t duration_idx, + const DatasourceID datasource_idx, + const std::size_t name_idx, + std::int32_t &start_x, + std::int32_t &start_y) { // Here, we save the two attributes for our feature: the speed and // the is_small boolean. We only serve up speeds from 0-139, so all we // do is save the first @@ -547,23 +563,27 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & feature_writer, util::vector_tile::FEATURE_ATTRIBUTES_TAG); field.add_element(0); // "speed" tag key offset + field.add_element(std::min( + speed_kmh_idx, 127u)); // save the speed value, capped at 127 + field.add_element(1); // "is_small" tag key offset field.add_element( - std::min(speed_kmh, 127u)); // save the speed value, capped at 127 - field.add_element(1); // "is_small" tag key offset - field.add_element(128 + - (component_id.is_tiny ? 0 : 1)); // is_small feature - field.add_element(2); // "datasource" tag key offset - field.add_element(130 + datasource); // datasource value offset - field.add_element(3); // "weight" tag key offset + 128 + (component_id.is_tiny ? 0 : 1)); // is_small feature offset + field.add_element(2); // "datasource" tag key offset + field.add_element(130 + datasource_idx); // datasource value offset + field.add_element(3); // "weight" tag key offset field.add_element(130 + max_datasource_id + 1 + - weight); // weight value offset - field.add_element(4); // "duration" tag key offset + weight_idx); // weight value offset + field.add_element(4); // "duration" tag key offset field.add_element(130 + max_datasource_id + 1 + - duration); // duration value offset - field.add_element(5); // "name" tag key offset + 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(6); // rate tag key offset + field.add_element(130 + max_datasource_id + 1 + + rate_idx); // rate goes in used_line_ints } { @@ -581,17 +601,26 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & std::int32_t start_y = 0; // Calculate the speed for this line - std::uint32_t speed_kmh = + // Speeds are looked up in a simple 1:1 table, so the speed value == lookup + // table index + std::uint32_t speed_kmh_idx = static_cast(round(length / forward_duration * 10 * 3.6)); + // Rate values are in meters per weight-unit - and similar to speeds, we + // present 1 decimal place of precision (these values are added as + // double/10) lower down + std::uint32_t forward_rate = + static_cast(round(length / forward_weight * 10.)); + auto tile_line = coordinatesToTileLine(a, b, tile_bbox); if (!tile_line.empty()) { encode_tile_line(tile_line, - speed_kmh, + speed_kmh_idx, + line_int_offsets[forward_rate], line_int_offsets[forward_weight], line_int_offsets[forward_duration], - forward_datasource, + forward_datasource_idx, name_offset, start_x, start_y); @@ -606,17 +635,26 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & std::int32_t start_y = 0; // Calculate the speed for this line - std::uint32_t speed_kmh = + // Speeds are looked up in a simple 1:1 table, so the speed value == lookup + // table index + std::uint32_t speed_kmh_idx = static_cast(round(length / reverse_duration * 10 * 3.6)); + // Rate values are in meters per weight-unit - and similar to speeds, we + // present 1 decimal place of precision (these values are added as + // double/10) lower down + std::uint32_t reverse_rate = + static_cast(round(length / reverse_weight * 10.)); + auto tile_line = coordinatesToTileLine(b, a, tile_bbox); if (!tile_line.empty()) { encode_tile_line(tile_line, - speed_kmh, + speed_kmh_idx, + line_int_offsets[reverse_rate], line_int_offsets[reverse_weight], line_int_offsets[reverse_duration], - reverse_datasource, + reverse_datasource_idx, name_offset, start_x, start_y); @@ -634,6 +672,7 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & line_layer_writer.add_string(util::vector_tile::KEY_TAG, "weight"); line_layer_writer.add_string(util::vector_tile::KEY_TAG, "duration"); line_layer_writer.add_string(util::vector_tile::KEY_TAG, "name"); + line_layer_writer.add_string(util::vector_tile::KEY_TAG, "rate"); // Now, we write out the possible speed value arrays and possible is_tiny // values. Field type 4 is the "values" field. It's a variable type field, @@ -695,19 +734,21 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & { // we need to pre-encode all values here because we need the full offsets later // for encoding the actual features. - std::vector> + std::vector> 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 - return std::make_tuple(t.coordinate, angle_idx, turn_idx, duration_idx); - }); + 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); + }); // Now write the points layer for turn penalty data: // Add a layer object to the PBF stream. 3=='layer' from the vector tile spec @@ -734,7 +775,7 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & util::vector_tile::GEOMETRY_TYPE_POINT); // geometry type feature_writer.add_uint64(util::vector_tile::ID_TAG, id++); // id { - // Write out the 3 properties we want on the feature. These + // Write out the 4 properties we want on the feature. These // refer to indexes in the properties lookup table, which we // add to the tile after we add all features. protozero::packed_field_uint32 field( @@ -745,6 +786,8 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & field.add_element(std::get<2>(point_turn_data)); field.add_element(2); // "cost" tag key offset field.add_element(used_point_ints.size() + std::get<3>(point_turn_data)); + field.add_element(3); // "weight" tag key offset + field.add_element(used_point_ints.size() + std::get<4>(point_turn_data)); } { // Add the geometry as the last field in this feature @@ -772,6 +815,7 @@ void encodeVectorTile(const datafacade::ContiguousInternalMemoryDataFacadeBase & point_layer_writer.add_string(util::vector_tile::KEY_TAG, "bearing_in"); 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"); // Now, save the lists of integers and floats that our features refer to. for (const auto &value : used_point_ints) diff --git a/unit_tests/library/tile.cpp b/unit_tests/library/tile.cpp index 2cde495cf..85af1ca30 100644 --- a/unit_tests/library/tile.cpp +++ b/unit_tests/library/tile.cpp @@ -53,7 +53,7 @@ template void test_tile(algorithm &osrm) auto property_iter_pair = feature_message.get_packed_uint32(); auto value_begin = property_iter_pair.begin(); auto value_end = property_iter_pair.end(); - BOOST_CHECK_EQUAL(std::distance(value_begin, value_end), 12); + BOOST_CHECK_EQUAL(std::distance(value_begin, value_end), 14); auto iter = value_begin; BOOST_CHECK_EQUAL(*iter++, 0); // speed key BOOST_CHECK_LT(*iter++, 128); // speed value @@ -71,6 +71,9 @@ template void test_tile(algorithm &osrm) // name BOOST_CHECK_EQUAL(*iter++, 5); BOOST_CHECK_GT(*iter++, 130); + // rate + BOOST_CHECK_EQUAL(*iter++, 6); + BOOST_CHECK_GT(*iter++, 130); BOOST_CHECK(iter == value_end); // geometry feature_message.next(); @@ -138,7 +141,7 @@ template void test_tile(algorithm &osrm) } } - BOOST_CHECK_EQUAL(number_of_speed_keys, 6); + BOOST_CHECK_EQUAL(number_of_speed_keys, 7); BOOST_CHECK_GT(number_of_speed_values, 128); // speed value resolution tile_message.next(); @@ -157,13 +160,15 @@ template void test_tile(algorithm &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()), 6); + BOOST_CHECK_EQUAL(std::distance(feature_iter_pair.begin(), feature_iter_pair.end()), 8); auto iter = feature_iter_pair.begin(); BOOST_CHECK_EQUAL(*iter++, 0); // bearing_in key *iter++; BOOST_CHECK_EQUAL(*iter++, 1); // turn_angle key *iter++; - BOOST_CHECK_EQUAL(*iter++, 2); // cost key + BOOST_CHECK_EQUAL(*iter++, 2); // turn cost (duration) key + *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(iter == feature_iter_pair.end()); // geometry @@ -205,7 +210,7 @@ template void test_tile(algorithm &osrm) } } - BOOST_CHECK_EQUAL(number_of_turn_keys, 3); + BOOST_CHECK_EQUAL(number_of_turn_keys, 4); BOOST_CHECK(number_of_turns_found > 700); } @@ -255,7 +260,8 @@ template void test_tile_turns(algorithm &osrm) std::vector found_bearing_in_indexes; std::vector found_turn_angles_indexes; - std::vector found_penalties_indexes; + std::vector found_time_penalties_indexes; + std::vector found_weight_penalties_indexes; const auto check_turn_feature = [&](protozero::pbf_reader feature_message) { feature_message.next(); // advance parser to first entry @@ -270,14 +276,16 @@ template void test_tile_turns(algorithm &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()), 6); + BOOST_CHECK_EQUAL(std::distance(feature_iter_pair.begin(), feature_iter_pair.end()), 8); auto iter = feature_iter_pair.begin(); BOOST_CHECK_EQUAL(*iter++, 0); // bearing_in key found_bearing_in_indexes.push_back(*iter++); BOOST_CHECK_EQUAL(*iter++, 1); // turn_angle key found_turn_angles_indexes.push_back(*iter++); - BOOST_CHECK_EQUAL(*iter++, 2); // cost key - found_penalties_indexes.push_back(*iter++); // skip value check, can be valud uint32 + BOOST_CHECK_EQUAL(*iter++, 2); // "cost" key (actually duration) + 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(iter == feature_iter_pair.end()); // geometry feature_message.next(); @@ -342,16 +350,28 @@ template void test_tile_turns(algorithm &osrm) } // Verify that we got the expected turn penalties - std::vector actual_turn_penalties; - for (const auto &i : found_penalties_indexes) + std::vector actual_time_turn_penalties; + for (const auto &i : found_time_penalties_indexes) { BOOST_CHECK(float_vals.count(i) == 1); - actual_turn_penalties.push_back(float_vals[i]); + actual_time_turn_penalties.push_back(float_vals[i]); } - std::sort(actual_turn_penalties.begin(), actual_turn_penalties.end()); - const std::vector expected_turn_penalties = { + std::sort(actual_time_turn_penalties.begin(), actual_time_turn_penalties.end()); + const std::vector expected_time_turn_penalties = { 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_turn_penalties, expected_turn_penalties); + CHECK_EQUAL_RANGE(actual_time_turn_penalties, expected_time_turn_penalties); + + // Verify that we got the expected turn penalties + std::vector actual_weight_turn_penalties; + for (const auto &i : found_weight_penalties_indexes) + { + BOOST_CHECK(float_vals.count(i) == 1); + actual_weight_turn_penalties.push_back(float_vals[i]); + } + std::sort(actual_weight_turn_penalties.begin(), actual_weight_turn_penalties.end()); + const std::vector expected_weight_turn_penalties = { + 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 the expected turn angles std::vector actual_turn_angles; @@ -425,8 +445,10 @@ template void test_tile_speeds(algorithm &osrm) std::vector found_speed_indexes; std::vector found_component_indexes; std::vector found_datasource_indexes; + std::vector found_weight_indexes; std::vector found_duration_indexes; std::vector found_name_indexes; + std::vector found_rate_indexes; const auto check_feature = [&](protozero::pbf_reader feature_message) { feature_message.next(); // advance parser to first entry @@ -443,7 +465,7 @@ template void test_tile_speeds(algorithm &osrm) auto property_iter_pair = feature_message.get_packed_uint32(); auto value_begin = property_iter_pair.begin(); auto value_end = property_iter_pair.end(); - BOOST_CHECK_EQUAL(std::distance(value_begin, value_end), 12); + BOOST_CHECK_EQUAL(std::distance(value_begin, value_end), 14); auto iter = value_begin; BOOST_CHECK_EQUAL(*iter++, 0); // speed key found_speed_indexes.push_back(*iter++); @@ -453,12 +475,14 @@ template void test_tile_speeds(algorithm &osrm) BOOST_CHECK_EQUAL(*iter++, 2); // data source key found_datasource_indexes.push_back(*iter++); BOOST_CHECK_EQUAL(*iter++, 3); // weight key - found_duration_indexes.push_back(*iter++); + found_weight_indexes.push_back(*iter++); BOOST_CHECK_EQUAL(*iter++, 4); // duration key found_duration_indexes.push_back(*iter++); // name BOOST_CHECK_EQUAL(*iter++, 5); found_name_indexes.push_back(*iter++); + BOOST_CHECK_EQUAL(*iter++, 6); + found_rate_indexes.push_back(*iter++); BOOST_CHECK(iter == value_end); // geometry feature_message.next();