From ace168d416393f3603dbbd20eab511d04e5b5fa2 Mon Sep 17 00:00:00 2001 From: Mandeep Sandhu Date: Wed, 27 Jan 2021 16:59:06 -0800 Subject: [PATCH 1/7] Add support for closure annotations Adds a new shape attribute filter for getting closure locations in the directions response. Similar to incidents, each closure annotation has a start & end geometry index, which indexes into the coordinates list. --- proto/trip.proto | 6 + src/thor/attributes_controller.cc | 1 + src/thor/triplegbuilder.cc | 58 ++++++- src/tyr/route_serializer_osrm.cc | 18 +++ test/gurka/test_closure_annotations.cc | 199 +++++++++++++++++++++++++ valhalla/thor/attributes_controller.h | 1 + 6 files changed, 277 insertions(+), 6 deletions(-) create mode 100644 test/gurka/test_closure_annotations.cc diff --git a/proto/trip.proto b/proto/trip.proto index 9678bb437d..5daf524a0f 100644 --- a/proto/trip.proto +++ b/proto/trip.proto @@ -319,6 +319,11 @@ message TripLeg { optional uint32 end_shape_index = 4; }; + message Closure { + optional uint32 begin_shape_index = 1; + optional uint32 end_shape_index = 2; + }; + optional uint64 osm_changeset = 1; optional uint64 trip_id = 2; optional uint32 leg_id = 3; @@ -331,6 +336,7 @@ message TripLeg { optional ShapeAttributes shape_attributes = 10; repeated Incident incidents = 11; repeated string algorithms = 12; + repeated Closure closures = 13; } message TripRoute { diff --git a/src/thor/attributes_controller.cc b/src/thor/attributes_controller.cc index c1f28b9c7d..a9bfbcb2fc 100644 --- a/src/thor/attributes_controller.cc +++ b/src/thor/attributes_controller.cc @@ -131,6 +131,7 @@ const std::unordered_map AttributesController::kDefaultAttrib {kShapeAttributesLength, false}, {kShapeAttributesSpeed, false}, {kShapeAttributesSpeedLimit, false}, + {kShapeAttributesClosure, false}, }; AttributesController::AttributesController() { diff --git a/src/thor/triplegbuilder.cc b/src/thor/triplegbuilder.cc index 459fc67c2b..293c74497e 100644 --- a/src/thor/triplegbuilder.cc +++ b/src/thor/triplegbuilder.cc @@ -125,6 +125,17 @@ void UpdateIncident(const std::shared_ptr& incide } } +valhalla::TripLeg_Closure* fetch_last_closure_annotation(TripLeg& leg) { + return leg.closures_size() ? leg.mutable_closures(leg.closures_size() - 1) : nullptr; +} + +valhalla::TripLeg_Closure* fetch_or_create_closure_annotation(TripLeg& leg) { + valhalla::TripLeg_Closure* closure = fetch_last_closure_annotation(leg); + // If last closure annotation has its end index populated, create a new + // closure annotation + return (!closure || closure->has_end_shape_index()) ? leg.add_closures() : closure; +} + /** * Chops up the shape for an edge so that we have shape points where speeds change along the edge * and where incidents occur along the edge. Also sets the various per shape point attributes @@ -172,6 +183,7 @@ void SetShapeAttributes(const AttributesController& controller, double speed; // meters per second uint8_t congestion; std::vector incidents; + bool closed; }; // A list of percent along the edge, corresponding speed (meters per second), incident id @@ -187,15 +199,20 @@ void SetShapeAttributes(const AttributesController& controller, cuts.emplace_back(cut_t{traffic_speed.breakpoint1 / 255.0, speed, static_cast(traffic_speed.congestion1), - {}}); + {}, + traffic_speed.closed(0)}); if (traffic_speed.breakpoint2 > 0) { cuts.emplace_back(cut_t{traffic_speed.breakpoint2 / 255.0, speed, static_cast(traffic_speed.congestion2), - {}}); + {}, + traffic_speed.closed(1)}); if (traffic_speed.speed3 != UNKNOWN_TRAFFIC_SPEED_RAW) { - cuts.emplace_back( - cut_t{1, speed, static_cast(traffic_speed.congestion3), {}}); + cuts.emplace_back(cut_t{1, + speed, + static_cast(traffic_speed.congestion3), + {}, + traffic_speed.closed(2)}); } } } @@ -203,7 +220,7 @@ void SetShapeAttributes(const AttributesController& controller, // Cap the end so that we always have something to use if (cuts.empty() || cuts.back().percent_along < tgt_pct) { - cuts.emplace_back(cut_t{tgt_pct, speed, UNKNOWN_CONGESTION_VAL, {}}); + cuts.emplace_back(cut_t{tgt_pct, speed, UNKNOWN_CONGESTION_VAL, {}, false}); } // sort the start and ends of the incidents along this edge @@ -241,7 +258,8 @@ void SetShapeAttributes(const AttributesController& controller, cuts.insert(itr, cut_t{offset, itr == cuts.end() ? speed : itr->speed, itr == cuts.end() ? UNKNOWN_CONGESTION_VAL : itr->congestion, - {&incident}}); + {&incident}, + itr == cuts.end() ? false : itr->closed}); } } } @@ -289,6 +307,25 @@ void SetShapeAttributes(const AttributesController& controller, distance *= coef; shift = 1; } + if (controller.attributes.at(kShapeAttributesClosure)) { + // Process closure annotations + if (cut_itr->closed) { + // Found a closure. Fetch a new annotation, or the last closure + // annotation if it does not have an end index set (meaning the shape + // is still within an existing closure) + ::valhalla::TripLeg_Closure* closure = fetch_or_create_closure_annotation(leg); + if (!closure->has_begin_shape_index()) { + closure->set_begin_shape_index(i - 1); + } + } else { + // Not a closure, check if we need to set the end of an existing + // closure annotation or not + ::valhalla::TripLeg_Closure* closure = fetch_last_closure_annotation(leg); + if (closure && !closure->has_end_shape_index()) { + closure->set_end_shape_index(i - 1); + } + } + } distance_total_pct = next_total; double time = distance / cut_itr->speed; // seconds @@ -1413,6 +1450,15 @@ void TripLegBuilder::Build( node->mutable_cost()->mutable_transition_cost()->set_cost(0); } + if (controller.attributes.at(kShapeAttributesClosure)) { + // Set the end shape index if we're ending on a closure as the last index is + // not processed in SetShapeAttributes above + valhalla::TripLeg_Closure* closure = fetch_last_closure_annotation(trip_path); + if (closure && !closure->has_end_shape_index()) { + closure->set_end_shape_index(trip_shape.size() - 1); + } + } + // Assign the admins AssignAdmins(controller, trip_path, admin_info_list); diff --git a/src/tyr/route_serializer_osrm.cc b/src/tyr/route_serializer_osrm.cc index 505b9a1aca..e59066b100 100644 --- a/src/tyr/route_serializer_osrm.cc +++ b/src/tyr/route_serializer_osrm.cc @@ -773,6 +773,21 @@ void serializeIncidents(const google::protobuf::RepeatedPtrFieldreserve(leg.closures_size()); + for (const valhalla::TripLeg_Closure& closure : leg.closures()) { + auto closure_obj = json::map({}); + closure_obj->emplace("geometry_index_start", static_cast(closure.begin_shape_index())); + closure_obj->emplace("geometry_index_end", static_cast(closure.end_shape_index())); + closures->emplace_back(std::move(closure_obj)); + } + doc.emplace("closures", closures); +} + // Compile and return the refs of the specified list // TODO we could enhance by limiting results by using consecutive count std::string get_sign_element_refs(const google::protobuf::RepeatedPtrField< @@ -1595,6 +1610,9 @@ json::ArrayPtr serialize_legs(const google::protobuf::RepeatedPtrFieldemplace_back(std::move(output_leg)); leg++; diff --git a/test/gurka/test_closure_annotations.cc b/test/gurka/test_closure_annotations.cc new file mode 100644 index 0000000000..1a48487b4f --- /dev/null +++ b/test/gurka/test_closure_annotations.cc @@ -0,0 +1,199 @@ +#include "gurka.h" +#include "test.h" + +#include +#include + +using namespace valhalla; +using LiveTrafficCustomize = test::LiveTrafficCustomize; + +namespace { + +inline void +SetSubsegmentLiveSpeed(baldr::TrafficSpeed* live_speed, uint64_t speed, uint8_t subsegment) { + live_speed->breakpoint1 = subsegment; + live_speed->overall_speed = speed >> 1; + live_speed->speed1 = speed >> 1; +} + +inline void SetLiveSpeed(baldr::TrafficSpeed* live_speed, uint64_t speed) { + SetSubsegmentLiveSpeed(live_speed, speed, 255); +} + +void close_partial_dir_edge(baldr::GraphReader& reader, + baldr::TrafficTile& tile, + uint32_t index, + double percent_along, + baldr::TrafficSpeed* current, + const std::string& edge_name, + const std::string& start_node, + const gurka::map& map) { + baldr::GraphId tile_id(tile.header->tile_id); + auto edge = std::get<0>(gurka::findEdge(reader, map.nodes, edge_name, start_node)); + if (edge.Tile_Base() == tile_id && edge.id() == index) { + SetSubsegmentLiveSpeed(current, 0, static_cast(255 * percent_along)); + } +} + +void close_dir_edge(baldr::GraphReader& reader, + baldr::TrafficTile& tile, + uint32_t index, + baldr::TrafficSpeed* current, + const std::string& edge_name, + const std::string& start_node, + const gurka::map& map) { + close_partial_dir_edge(reader, tile, index, 1., current, edge_name, start_node, map); +} + +void close_bidir_edge(baldr::GraphReader& reader, + baldr::TrafficTile& tile, + uint32_t index, + baldr::TrafficSpeed* current, + const std::string& edge_name, + const gurka::map& map) { + baldr::GraphId tile_id(tile.header->tile_id); + std::string start_node(1, edge_name.front()); + std::string end_node(1, edge_name.back()); + + close_dir_edge(reader, tile, index, current, edge_name, start_node, map); + close_dir_edge(reader, tile, index, current, edge_name, end_node, map); +} + +} // namespace + +class ClosureAnnotations : public ::testing::Test { +protected: + static gurka::map closure_map; + static int const default_speed; + static std::string const tile_dir; + static std::shared_ptr reader; + + static void SetUpTestSuite() { + const std::string ascii_map = R"( + + A-1----2-B + | + 3 + | + C + | + 4 + | + D-5----6-E + )"; + + const std::string speed_str = std::to_string(default_speed); + const gurka::ways ways = {{"AB", {{"highway", "primary"}, {"maxspeed", speed_str}}}, + {"BC", {{"highway", "primary"}, {"maxspeed", speed_str}}}, + {"CD", {{"highway", "primary"}, {"maxspeed", speed_str}}}, + {"DE", {{"highway", "primary"}, {"maxspeed", speed_str}}}}; + + const auto layout = gurka::detail::map_to_coordinates(ascii_map, 100, {.05f, .2f}); + closure_map = gurka::buildtiles(layout, ways, {}, {}, tile_dir); + + closure_map.config.put("mjolnir.traffic_extract", tile_dir + "/traffic.tar"); + test::build_live_traffic_data(closure_map.config); + + reader = test::make_clean_graphreader(closure_map.config.get_child("mjolnir")); + } + + void set_default_speed_on_all_edges() { + test::customize_live_traffic_data(closure_map.config, + [](baldr::GraphReader&, baldr::TrafficTile&, uint32_t, + baldr::TrafficSpeed* current) -> void { + SetLiveSpeed(current, default_speed); + }); + } + + virtual void SetUp() { + set_default_speed_on_all_edges(); + + // Partially(50%) close 12 + test::customize_live_traffic_data(closure_map.config, + [](baldr::GraphReader& reader, baldr::TrafficTile& tile, + uint32_t index, baldr::TrafficSpeed* current) -> void { + // close_partial_dir_edge(reader, tile, index, 0.5, current, + // "AB", "B", closure_map); + close_partial_dir_edge(reader, tile, index, 0.5, current, + "AB", "A", closure_map); + }); + +#if 0 + // Fully close BC + test::customize_live_traffic_data(closure_map.config, + [](baldr::GraphReader& reader, baldr::TrafficTile& tile, + uint32_t index, baldr::TrafficSpeed* current) -> void { + close_bidir_edge(reader, tile, index, current, "BC", closure_map); + }); + // Partially(50%) close DE + test::customize_live_traffic_data(closure_map.config, + [](baldr::GraphReader& reader, baldr::TrafficTile& tile, + uint32_t index, baldr::TrafficSpeed* current) -> void { + close_partial_dir_edge(reader, tile, index, 0.5, current, "DE", "D", closure_map); + }); +#endif + } + + virtual void TearDown() { + set_default_speed_on_all_edges(); + } +}; + +gurka::map ClosureAnnotations::closure_map = {}; +const int ClosureAnnotations::default_speed = 36; +const std::string ClosureAnnotations::tile_dir = "test/data/closure_annotations"; +std::shared_ptr ClosureAnnotations::reader; + +const std::string req_without_closure_annotations = R"({ + "locations": [ + {"lat": %s, "lon": %s}, + {"lat": %s, "lon": %s} + ], + "costing": "auto", + "costing_options": { + "auto": { + "speed_types": [ "freeflow", "constrained", "predicted", "current"], + "ignore_closures": true + } + }, + "date_time": { "type": 3, "value": "current" }, + "format": "osrm" +} +)"; + +const std::string req_with_closure_annotations = R"({ + "locations": [ + {"lat": %s, "lon": %s}, + {"lat": %s, "lon": %s} + ], + "costing": "auto", + "costing_options": { + "auto": { + "speed_types": [ "freeflow", "constrained", "predicted", "current"], + "ignore_closures": true + } + }, + "date_time": { "type": 3, "value": "current" }, + "format": "osrm", + "shape_format": "geojson", + "filters": { + "attributes": [ + "shape_attributes.closure" + ], + "action": "include" + } +} +)"; + +TEST_F(ClosureAnnotations, EndOnClosure) { + const std::string& req = + (boost::format(req_with_closure_annotations) % std::to_string(closure_map.nodes.at("1").lat()) % + std::to_string(closure_map.nodes.at("1").lng()) % + std::to_string(closure_map.nodes.at("2").lat()) % + std::to_string(closure_map.nodes.at("2").lng())) + .str(); + auto result = gurka::do_action(Options::route, closure_map, req, reader); + gurka::assert::raw::expect_path(result, {"AB"}); + + // rapidjson::Document response = gurka::convert_to_json(result, valhalla::Options_Format_osrm); +} diff --git a/valhalla/thor/attributes_controller.h b/valhalla/thor/attributes_controller.h index 77bb541482..f3ebd96d3f 100644 --- a/valhalla/thor/attributes_controller.h +++ b/valhalla/thor/attributes_controller.h @@ -136,6 +136,7 @@ const std::string kShapeAttributesTime = "shape_attributes.time"; const std::string kShapeAttributesLength = "shape_attributes.length"; const std::string kShapeAttributesSpeed = "shape_attributes.speed"; const std::string kShapeAttributesSpeedLimit = "shape_attributes.speed_limit"; +const std::string kShapeAttributesClosure = "shape_attributes.closure"; // Categories const std::string kNodeCategory = "node."; From faee2ff7754822f651781cbe2723f4ea7567a90f Mon Sep 17 00:00:00 2001 From: Mandeep Sandhu Date: Wed, 27 Jan 2021 17:34:20 -0800 Subject: [PATCH 2/7] set closure in fwd direction --- test/gurka/test_closure_annotations.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gurka/test_closure_annotations.cc b/test/gurka/test_closure_annotations.cc index 1a48487b4f..9255a57c5c 100644 --- a/test/gurka/test_closure_annotations.cc +++ b/test/gurka/test_closure_annotations.cc @@ -115,7 +115,7 @@ class ClosureAnnotations : public ::testing::Test { // close_partial_dir_edge(reader, tile, index, 0.5, current, // "AB", "B", closure_map); close_partial_dir_edge(reader, tile, index, 0.5, current, - "AB", "A", closure_map); + "AB", "B", closure_map); }); #if 0 From be0fafdbdc5faeb06574ec9c1e515c64fd0fb85d Mon Sep 17 00:00:00 2001 From: Mandeep Sandhu Date: Wed, 27 Jan 2021 23:57:30 -0800 Subject: [PATCH 3/7] Add tests for closure annotations --- test/gurka/test_closure_annotations.cc | 200 ++++++++++++++++++++----- 1 file changed, 164 insertions(+), 36 deletions(-) diff --git a/test/gurka/test_closure_annotations.cc b/test/gurka/test_closure_annotations.cc index 9255a57c5c..d2cfd422b5 100644 --- a/test/gurka/test_closure_annotations.cc +++ b/test/gurka/test_closure_annotations.cc @@ -9,29 +9,53 @@ using LiveTrafficCustomize = test::LiveTrafficCustomize; namespace { -inline void -SetSubsegmentLiveSpeed(baldr::TrafficSpeed* live_speed, uint64_t speed, uint8_t subsegment) { +inline void SetLiveSpeedFrom(baldr::TrafficSpeed* live_speed, uint64_t speed, uint8_t subsegment) { + live_speed->breakpoint1 = subsegment; + live_speed->breakpoint2 = 255; + live_speed->speed2 = speed >> 1; + live_speed->speed3 = UNKNOWN_TRAFFIC_SPEED_RAW; +} + +inline void SetLiveSpeedUpto(baldr::TrafficSpeed* live_speed, uint64_t speed, uint8_t subsegment) { live_speed->breakpoint1 = subsegment; - live_speed->overall_speed = speed >> 1; live_speed->speed1 = speed >> 1; } inline void SetLiveSpeed(baldr::TrafficSpeed* live_speed, uint64_t speed) { - SetSubsegmentLiveSpeed(live_speed, speed, 255); + live_speed->breakpoint1 = 255; + live_speed->overall_speed = speed >> 1; + live_speed->speed1 = speed >> 1; +} + +void close_partial_dir_edge_from(baldr::GraphReader& reader, + baldr::TrafficTile& tile, + uint32_t index, + double percent_along, + baldr::TrafficSpeed* current, + const std::string& edge_name, + const std::string& end_node, + const gurka::map& map) { + baldr::GraphId tile_id(tile.header->tile_id); + auto edge = std::get<0>(gurka::findEdge(reader, map.nodes, edge_name, end_node)); + if (edge.Tile_Base() == tile_id && edge.id() == index) { + uint8_t subsegment = static_cast(255 * percent_along); + SetLiveSpeedFrom(current, 0, subsegment); + } } -void close_partial_dir_edge(baldr::GraphReader& reader, - baldr::TrafficTile& tile, - uint32_t index, - double percent_along, - baldr::TrafficSpeed* current, - const std::string& edge_name, - const std::string& start_node, - const gurka::map& map) { +void close_partial_dir_edge_upto(baldr::GraphReader& reader, + baldr::TrafficTile& tile, + uint32_t index, + double percent_along, + baldr::TrafficSpeed* current, + const std::string& edge_name, + const std::string& end_node, + const gurka::map& map) { baldr::GraphId tile_id(tile.header->tile_id); - auto edge = std::get<0>(gurka::findEdge(reader, map.nodes, edge_name, start_node)); + auto edge = std::get<0>(gurka::findEdge(reader, map.nodes, edge_name, end_node)); if (edge.Tile_Base() == tile_id && edge.id() == index) { - SetSubsegmentLiveSpeed(current, 0, static_cast(255 * percent_along)); + uint8_t subsegment = static_cast(255 * percent_along); + SetLiveSpeedUpto(current, 0, subsegment); } } @@ -40,9 +64,13 @@ void close_dir_edge(baldr::GraphReader& reader, uint32_t index, baldr::TrafficSpeed* current, const std::string& edge_name, - const std::string& start_node, + const std::string& end_node, const gurka::map& map) { - close_partial_dir_edge(reader, tile, index, 1., current, edge_name, start_node, map); + baldr::GraphId tile_id(tile.header->tile_id); + auto edge = std::get<0>(gurka::findEdge(reader, map.nodes, edge_name, end_node)); + if (edge.Tile_Base() == tile_id && edge.id() == index) { + SetLiveSpeed(current, 0); + } } void close_bidir_edge(baldr::GraphReader& reader, @@ -71,15 +99,15 @@ class ClosureAnnotations : public ::testing::Test { static void SetUpTestSuite() { const std::string ascii_map = R"( - A-1----2-B - | - 3 - | - C - | - 4 - | - D-5----6-E + A-1----2-B + | + 3 + | + C + | + 4 + | + D-5---E )"; const std::string speed_str = std::to_string(default_speed); @@ -108,30 +136,28 @@ class ClosureAnnotations : public ::testing::Test { virtual void SetUp() { set_default_speed_on_all_edges(); - // Partially(50%) close 12 + // Partially close AB from 50% test::customize_live_traffic_data(closure_map.config, [](baldr::GraphReader& reader, baldr::TrafficTile& tile, uint32_t index, baldr::TrafficSpeed* current) -> void { - // close_partial_dir_edge(reader, tile, index, 0.5, current, - // "AB", "B", closure_map); - close_partial_dir_edge(reader, tile, index, 0.5, current, - "AB", "B", closure_map); + close_partial_dir_edge_from(reader, tile, index, 0.5, current, + "AB", "B", closure_map); }); -#if 0 // Fully close BC test::customize_live_traffic_data(closure_map.config, [](baldr::GraphReader& reader, baldr::TrafficTile& tile, uint32_t index, baldr::TrafficSpeed* current) -> void { - close_bidir_edge(reader, tile, index, current, "BC", closure_map); + close_bidir_edge(reader, tile, index, current, "BC", + closure_map); }); - // Partially(50%) close DE + // Partially close DE upto 50% test::customize_live_traffic_data(closure_map.config, [](baldr::GraphReader& reader, baldr::TrafficTile& tile, uint32_t index, baldr::TrafficSpeed* current) -> void { - close_partial_dir_edge(reader, tile, index, 0.5, current, "DE", "D", closure_map); + close_partial_dir_edge_upto(reader, tile, index, 0.5, current, + "DE", "E", closure_map); }); -#endif } virtual void TearDown() { @@ -185,6 +211,37 @@ const std::string req_with_closure_annotations = R"({ } )"; +#include "rapidjson/stringbuffer.h" +#include "rapidjson/writer.h" +#include + +void print_json(const rapidjson::Document& doc) { + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + doc.Accept(writer); + std::cout << buffer.GetString() << std::endl; +} + +void expect_closures(const rapidjson::Document& response, + const std::vector>& expected_closures, + int expected_coord_count) { + auto route = response["routes"][0].GetObject(); + auto leg = route["legs"][0].GetObject(); + size_t num_coordinates = route["geometry"]["coordinates"].Size(); + size_t num_closures = leg["closures"].Size(); + + ASSERT_EQ(num_coordinates, expected_coord_count); + ASSERT_EQ(num_closures, expected_closures.size()); + int idx = 0; + for (const auto& start_end_pair : expected_closures) { + EXPECT_EQ(leg["closures"][idx]["geometry_index_start"].GetInt(), start_end_pair.first); + EXPECT_EQ(leg["closures"][idx]["geometry_index_end"].GetInt(), start_end_pair.second); + idx++; + } + auto last_closure = leg["closures"][num_closures - 1].GetObject(); + ASSERT_LE(last_closure["geometry_index_end"].GetInt(), num_coordinates); +} + TEST_F(ClosureAnnotations, EndOnClosure) { const std::string& req = (boost::format(req_with_closure_annotations) % std::to_string(closure_map.nodes.at("1").lat()) % @@ -195,5 +252,76 @@ TEST_F(ClosureAnnotations, EndOnClosure) { auto result = gurka::do_action(Options::route, closure_map, req, reader); gurka::assert::raw::expect_path(result, {"AB"}); - // rapidjson::Document response = gurka::convert_to_json(result, valhalla::Options_Format_osrm); + rapidjson::Document response = gurka::convert_to_json(result, valhalla::Options_Format_osrm); + expect_closures(response, {{1, 2}}, 3); +} + +TEST_F(ClosureAnnotations, EndWithConsecutiveClosures) { + const std::string& req = + (boost::format(req_with_closure_annotations) % std::to_string(closure_map.nodes.at("1").lat()) % + std::to_string(closure_map.nodes.at("1").lng()) % + std::to_string(closure_map.nodes.at("3").lat()) % + std::to_string(closure_map.nodes.at("3").lng())) + .str(); + auto result = gurka::do_action(Options::route, closure_map, req, reader); + gurka::assert::raw::expect_path(result, {"AB", "BC"}); + + rapidjson::Document response = gurka::convert_to_json(result, valhalla::Options_Format_osrm); + expect_closures(response, {{1, 3}}, 4); +} + +TEST_F(ClosureAnnotations, IntermediateClosure) { + const std::string& req = + (boost::format(req_with_closure_annotations) % std::to_string(closure_map.nodes.at("1").lat()) % + std::to_string(closure_map.nodes.at("1").lng()) % + std::to_string(closure_map.nodes.at("4").lat()) % + std::to_string(closure_map.nodes.at("4").lng())) + .str(); + auto result = gurka::do_action(Options::route, closure_map, req, reader); + gurka::assert::raw::expect_path(result, {"AB", "BC", "CD"}); + + rapidjson::Document response = gurka::convert_to_json(result, valhalla::Options_Format_osrm); + expect_closures(response, {{1, 3}}, 5); +} + +TEST_F(ClosureAnnotations, BeginAtClosure) { + const std::string& req = + (boost::format(req_with_closure_annotations) % std::to_string(closure_map.nodes.at("2").lat()) % + std::to_string(closure_map.nodes.at("2").lng()) % + std::to_string(closure_map.nodes.at("4").lat()) % + std::to_string(closure_map.nodes.at("4").lng())) + .str(); + auto result = gurka::do_action(Options::route, closure_map, req, reader); + gurka::assert::raw::expect_path(result, {"AB", "BC", "CD"}); + + rapidjson::Document response = gurka::convert_to_json(result, valhalla::Options_Format_osrm); + expect_closures(response, {{0, 2}}, 4); +} + +TEST_F(ClosureAnnotations, AllWithinClosure) { + const std::string& req = + (boost::format(req_with_closure_annotations) % std::to_string(closure_map.nodes.at("2").lat()) % + std::to_string(closure_map.nodes.at("2").lng()) % + std::to_string(closure_map.nodes.at("3").lat()) % + std::to_string(closure_map.nodes.at("3").lng())) + .str(); + auto result = gurka::do_action(Options::route, closure_map, req, reader); + gurka::assert::raw::expect_path(result, {"AB", "BC"}); + + rapidjson::Document response = gurka::convert_to_json(result, valhalla::Options_Format_osrm); + expect_closures(response, {{0, 2}}, 3); +} + +TEST_F(ClosureAnnotations, DiscontinuousClosures) { + const std::string& req = + (boost::format(req_with_closure_annotations) % std::to_string(closure_map.nodes.at("A").lat()) % + std::to_string(closure_map.nodes.at("A").lng()) % + std::to_string(closure_map.nodes.at("E").lat()) % + std::to_string(closure_map.nodes.at("E").lng())) + .str(); + auto result = gurka::do_action(Options::route, closure_map, req, reader); + gurka::assert::raw::expect_path(result, {"AB", "BC", "CD", "DE"}); + + rapidjson::Document response = gurka::convert_to_json(result, valhalla::Options_Format_osrm); + expect_closures(response, {{1, 3}, {4, 5}}, 7); } From 3947bff76fc86f1fa38f06447cf81b61b7e0062b Mon Sep 17 00:00:00 2001 From: Mandeep Sandhu Date: Wed, 17 Feb 2021 17:47:02 -0800 Subject: [PATCH 4/7] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0741d3aaf4..bfa2537d76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ * CHANGED: Throw an exception if directory does not exist when building traffic extract [#2871](https://github.com/valhalla/valhalla/pull/2871) * CHANGED: Support for ignoring multiple consecutive closures at start/end locations [#2846](https://github.com/valhalla/valhalla/pull/2846) * ADDED: Ukrainian language translations [#2882](https://github.com/valhalla/valhalla/pull/2882) + * ADDED: Add support for closure annotations [#2816](https://github.com/valhalla/valhalla/pull/2816) ## Release Date: 2021-01-25 Valhalla 3.1.0 * **Removed** From e5c3f6d87aefb5b7a5cef94d6dee787ef22fa60c Mon Sep 17 00:00:00 2001 From: Mandeep Sandhu Date: Mon, 22 Feb 2021 14:39:13 -0800 Subject: [PATCH 5/7] Address review comments --- test/gurka/CMakeLists.txt | 1 + test/gurka/test_closure_annotations.cc | 18 +++++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/test/gurka/CMakeLists.txt b/test/gurka/CMakeLists.txt index bb5ef1da34..6c556a5692 100644 --- a/test/gurka/CMakeLists.txt +++ b/test/gurka/CMakeLists.txt @@ -12,6 +12,7 @@ if(ENABLE_DATA_TOOLS) set_source_files_properties( test_route_incidents.cc test_incident_loading.cc + test_closure_annotations.cc PROPERTIES COMPILE_FLAGS "-Werror") endif (UNIX) diff --git a/test/gurka/test_closure_annotations.cc b/test/gurka/test_closure_annotations.cc index d2cfd422b5..9421180f7b 100644 --- a/test/gurka/test_closure_annotations.cc +++ b/test/gurka/test_closure_annotations.cc @@ -9,19 +9,19 @@ using LiveTrafficCustomize = test::LiveTrafficCustomize; namespace { -inline void SetLiveSpeedFrom(baldr::TrafficSpeed* live_speed, uint64_t speed, uint8_t subsegment) { - live_speed->breakpoint1 = subsegment; + inline void SetLiveSpeedFrom(baldr::TrafficSpeed* live_speed, uint8_t speed, uint8_t breakpoint1) { + live_speed->breakpoint1 = breakpoint1; live_speed->breakpoint2 = 255; live_speed->speed2 = speed >> 1; live_speed->speed3 = UNKNOWN_TRAFFIC_SPEED_RAW; } -inline void SetLiveSpeedUpto(baldr::TrafficSpeed* live_speed, uint64_t speed, uint8_t subsegment) { - live_speed->breakpoint1 = subsegment; +inline void SetLiveSpeedUpto(baldr::TrafficSpeed* live_speed, uint8_t speed, uint8_t breakpoint1) { + live_speed->breakpoint1 = breakpoint1; live_speed->speed1 = speed >> 1; } -inline void SetLiveSpeed(baldr::TrafficSpeed* live_speed, uint64_t speed) { +inline void SetLiveSpeed(baldr::TrafficSpeed* live_speed, uint8_t speed) { live_speed->breakpoint1 = 255; live_speed->overall_speed = speed >> 1; live_speed->speed1 = speed >> 1; @@ -38,8 +38,8 @@ void close_partial_dir_edge_from(baldr::GraphReader& reader, baldr::GraphId tile_id(tile.header->tile_id); auto edge = std::get<0>(gurka::findEdge(reader, map.nodes, edge_name, end_node)); if (edge.Tile_Base() == tile_id && edge.id() == index) { - uint8_t subsegment = static_cast(255 * percent_along); - SetLiveSpeedFrom(current, 0, subsegment); + uint8_t breakpoint1 = static_cast(255 * percent_along); + SetLiveSpeedFrom(current, 0, breakpoint1); } } @@ -54,8 +54,8 @@ void close_partial_dir_edge_upto(baldr::GraphReader& reader, baldr::GraphId tile_id(tile.header->tile_id); auto edge = std::get<0>(gurka::findEdge(reader, map.nodes, edge_name, end_node)); if (edge.Tile_Base() == tile_id && edge.id() == index) { - uint8_t subsegment = static_cast(255 * percent_along); - SetLiveSpeedUpto(current, 0, subsegment); + uint8_t breakpoint1 = static_cast(255 * percent_along); + SetLiveSpeedUpto(current, 0, breakpoint1); } } From 64e88249c291fc146ed321865a7d3acc16545573 Mon Sep 17 00:00:00 2001 From: Mandeep Sandhu Date: Mon, 22 Feb 2021 14:58:24 -0800 Subject: [PATCH 6/7] lint fix --- test/gurka/test_closure_annotations.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gurka/test_closure_annotations.cc b/test/gurka/test_closure_annotations.cc index 9421180f7b..918505f22b 100644 --- a/test/gurka/test_closure_annotations.cc +++ b/test/gurka/test_closure_annotations.cc @@ -9,7 +9,7 @@ using LiveTrafficCustomize = test::LiveTrafficCustomize; namespace { - inline void SetLiveSpeedFrom(baldr::TrafficSpeed* live_speed, uint8_t speed, uint8_t breakpoint1) { +inline void SetLiveSpeedFrom(baldr::TrafficSpeed* live_speed, uint8_t speed, uint8_t breakpoint1) { live_speed->breakpoint1 = breakpoint1; live_speed->breakpoint2 = 255; live_speed->speed2 = speed >> 1; From 845223e3e25fdddf6cf37dcb32d00f526358f37a Mon Sep 17 00:00:00 2001 From: Mandeep Sandhu Date: Tue, 23 Feb 2021 13:11:55 -0800 Subject: [PATCH 7/7] remove debug function --- test/gurka/test_closure_annotations.cc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/gurka/test_closure_annotations.cc b/test/gurka/test_closure_annotations.cc index 918505f22b..5f487cdbf0 100644 --- a/test/gurka/test_closure_annotations.cc +++ b/test/gurka/test_closure_annotations.cc @@ -211,17 +211,6 @@ const std::string req_with_closure_annotations = R"({ } )"; -#include "rapidjson/stringbuffer.h" -#include "rapidjson/writer.h" -#include - -void print_json(const rapidjson::Document& doc) { - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - doc.Accept(writer); - std::cout << buffer.GetString() << std::endl; -} - void expect_closures(const rapidjson::Document& response, const std::vector>& expected_closures, int expected_coord_count) {