-
Notifications
You must be signed in to change notification settings - Fork 657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
contract over nodes connecting edges with differing names/speed #4608
Changes from 6 commits
ff1f877
764b743
2998344
5d1afba
c3a12f7
875b394
d427e65
6026a90
6d139de
26f0751
34a7054
50bbba7
88d8c19
bb42b4d
db7ea53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,6 +61,7 @@ CMakeLists.txt.user | |
.idea | ||
/.tidytmp | ||
vcpkg*/ | ||
*.log | ||
|
||
# python | ||
.venv | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,16 +77,6 @@ bool EdgesMatch(const graph_tile_ptr& tile, const DirectedEdge* edge1, const Dir | |
return false; | ||
} | ||
|
||
// Names must match | ||
// TODO - this allows matches in any order. Do we need to maintain order? | ||
// TODO - should allow near matches? | ||
std::vector<std::string> edge1names = tile->GetNames(edge1); | ||
std::vector<std::string> edge2names = tile->GetNames(edge2); | ||
std::sort(edge1names.begin(), edge1names.end()); | ||
std::sort(edge2names.begin(), edge2names.end()); | ||
if (edge1names != edge2names) | ||
return false; | ||
|
||
// if they have access restrictions those must match (for modes that use shortcuts) | ||
if (edge1->access_restriction()) { | ||
auto res1 = tile->GetAccessRestrictions(edge1 - tile->directededge(0), kVehicularAccess); | ||
|
@@ -231,11 +221,6 @@ bool CanContract(GraphReader& reader, | |
return false; | ||
} | ||
|
||
// Can not have different speeds in the same direction | ||
if ((oppdiredge1->speed() != edge2->speed()) || (oppdiredge2->speed() != edge1->speed())) { | ||
return false; | ||
} | ||
|
||
// ISO country codes at the end nodes must equal this node | ||
std::string iso = tile->admininfo(nodeinfo->admin_index()).country_iso(); | ||
std::string e1_iso = EndNodeIso(edge1, reader); | ||
|
@@ -337,18 +322,18 @@ bool IsEnteringEdgeOfContractedNode(GraphReader& reader, const GraphId& nodeid, | |
} | ||
|
||
// Add shortcut edges (if they should exist) from the specified node | ||
uint32_t AddShortcutEdges(GraphReader& reader, | ||
const graph_tile_ptr& tile, | ||
GraphTileBuilder& tilebuilder, | ||
const GraphId& start_node, | ||
const uint32_t edge_index, | ||
const uint32_t edge_count, | ||
std::unordered_map<uint32_t, uint32_t>& shortcuts) { | ||
std::pair<uint32_t, uint32_t> AddShortcutEdges(GraphReader& reader, | ||
const graph_tile_ptr& tile, | ||
GraphTileBuilder& tilebuilder, | ||
const GraphId& start_node, | ||
const uint32_t edge_index, | ||
const uint32_t edge_count, | ||
std::unordered_map<uint32_t, uint32_t>& shortcuts) { | ||
// Shortcut edges have to start at a node that is not contracted - return if | ||
// this node can be contracted. | ||
EdgePairs edgepairs; | ||
if (CanContract(reader, tile, start_node, edgepairs)) { | ||
return 0; | ||
return {uint32_t(0), uint32_t(0)}; | ||
} | ||
|
||
// Check if this is the last edge in a shortcut (if the endnode cannot be contracted). | ||
|
@@ -359,6 +344,7 @@ uint32_t AddShortcutEdges(GraphReader& reader, | |
// Iterate through directed edges of the base node | ||
uint32_t shortcut = 0; | ||
uint32_t shortcut_count = 0; | ||
uint32_t total_edge_count = 0; | ||
GraphId edge_id(start_node.tileid(), start_node.level(), edge_index); | ||
for (uint32_t i = 0; i < edge_count; i++, ++edge_id) { | ||
// Skip transit connection edges. | ||
|
@@ -376,6 +362,7 @@ uint32_t AddShortcutEdges(GraphReader& reader, | |
// edge of the contracted node. | ||
GraphId end_node = directededge->endnode(); | ||
if (IsEnteringEdgeOfContractedNode(reader, end_node, edge_id)) { | ||
total_edge_count++; | ||
// Form a shortcut edge. | ||
DirectedEdge newedge = *directededge; | ||
|
||
|
@@ -401,13 +388,6 @@ uint32_t AddShortcutEdges(GraphReader& reader, | |
std::reverse(shape.begin(), shape.end()); | ||
} | ||
|
||
// Get names - they apply over all edges of the shortcut | ||
auto names = edgeinfo.GetNames(); | ||
auto tagged_values = edgeinfo.GetTaggedValues(); | ||
auto linguistics = edgeinfo.GetLinguisticTaggedValues(); | ||
|
||
auto types = edgeinfo.GetTypes(); | ||
Comment on lines
-406
to
-411
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. those are not needed anymore either |
||
|
||
// Add any access restriction records. We don't contract if they differ, so if | ||
// there's any, they're the same for all involved edges | ||
if (newedge.access_restriction()) { | ||
|
@@ -453,11 +433,9 @@ uint32_t AddShortcutEdges(GraphReader& reader, | |
// off of shortcuts work properly | ||
ConnectEdges(reader, end_node, next_edge_id, shape, end_node, opp_local_idx, rst, | ||
average_density, total_duration, total_truck_duration); | ||
total_edge_count++; | ||
} | ||
|
||
// Names can be different in the forward and backward direction | ||
bool diff_names = tilebuilder.OpposingEdgeInfoDiffers(tile, directededge); | ||
|
||
// Get the length from the shape. This prevents roundoff issues when forming | ||
// elevation. | ||
uint32_t length = valhalla::midgard::length(shape); | ||
|
@@ -466,13 +444,13 @@ uint32_t AddShortcutEdges(GraphReader& reader, | |
// edge in case multiple shortcut edges exist between the 2 nodes. | ||
// Test whether this shape is forward or reverse (in case an existing | ||
// edge exists). Shortcuts use way Id = 0.Set mean elevation to 0 as a placeholder, | ||
// set it later if adding elevation to this dataset. | ||
// set it later if adding elevation to this dataset. No need for names etc, shortcuts | ||
// aren't used in guidance | ||
bool forward = true; | ||
uint32_t idx = ((length & 0xfffff) | ((shape.size() & 0xfff) << 20)); | ||
uint32_t edge_info_offset = | ||
tilebuilder.AddEdgeInfo(idx, start_node, end_node, 0, 0, edgeinfo.bike_network(), | ||
edgeinfo.speed_limit(), shape, names, tagged_values, linguistics, | ||
types, forward, diff_names); | ||
edgeinfo.speed_limit(), shape, {}, {}, {}, 0U, forward, false); | ||
|
||
newedge.set_edgeinfo_offset(edge_info_offset); | ||
|
||
|
@@ -554,16 +532,17 @@ uint32_t AddShortcutEdges(GraphReader& reader, | |
LOG_WARN("Exceeding max shortcut edges from a node at LL = " + std::to_string(ll.lat()) + "," + | ||
std::to_string(ll.lng())); | ||
} | ||
return shortcut_count; | ||
return {shortcut_count, total_edge_count}; | ||
} | ||
|
||
// Form shortcuts for tiles in this level. | ||
uint32_t FormShortcuts(GraphReader& reader, const TileLevel& level) { | ||
std::pair<uint32_t, uint32_t> FormShortcuts(GraphReader& reader, const TileLevel& level) { | ||
// Iterate through the tiles at this level (TODO - can we mark the tiles | ||
// the tiles that shortcuts end within?) | ||
reader.Clear(); | ||
bool added = false; | ||
uint32_t shortcut_count = 0; | ||
uint32_t total_edge_count = 0; | ||
uint32_t ntiles = level.tiles.TileCount(); | ||
uint32_t tile_level = (uint32_t)level.level; | ||
graph_tile_ptr tile; | ||
|
@@ -605,8 +584,10 @@ uint32_t FormShortcuts(GraphReader& reader, const TileLevel& level) { | |
|
||
// Add shortcut edges first. | ||
std::unordered_map<uint32_t, uint32_t> shortcuts; | ||
shortcut_count += AddShortcutEdges(reader, tile, tilebuilder, node_id, old_edge_index, | ||
old_edge_count, shortcuts); | ||
auto stats = AddShortcutEdges(reader, tile, tilebuilder, node_id, old_edge_index, | ||
old_edge_count, shortcuts); | ||
shortcut_count += stats.first; | ||
total_edge_count += stats.second; | ||
|
||
// Copy the rest of the directed edges from this node | ||
GraphId edgeid(tileid, tile_level, old_edge_index); | ||
|
@@ -711,7 +692,7 @@ uint32_t FormShortcuts(GraphReader& reader, const TileLevel& level) { | |
reader.Trim(); | ||
} | ||
} | ||
return shortcut_count; | ||
return {shortcut_count, total_edge_count}; | ||
} | ||
|
||
} // namespace | ||
|
@@ -736,8 +717,11 @@ void ShortcutBuilder::Build(const boost::property_tree::ptree& pt) { | |
for (; tile_level != TileHierarchy::levels().rend(); ++tile_level) { | ||
// Create shortcuts on this level | ||
LOG_INFO("Creating shortcuts on level " + std::to_string(tile_level->level)); | ||
[[maybe_unused]] uint32_t count = FormShortcuts(reader, *tile_level); | ||
LOG_INFO("Finished with " + std::to_string(count) + " shortcuts"); | ||
[[maybe_unused]] auto stats = FormShortcuts(reader, *tile_level); | ||
[[maybe_unused]] uint32_t avg = stats.first ? (stats.second / stats.first) : 0; | ||
LOG_INFO("Finished with " + std::to_string(stats.first) + " shortcuts superseding " + | ||
std::to_string(stats.second) + " edges, average ~" + std::to_string(avg) + | ||
" edges per shortcut"); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,38 +67,6 @@ TEST(Shortcuts, LoopWithoutShortcut) { | |
EXPECT_FALSE(shortcut.Is_Valid()) << "Shortcuts found. Check the map."; | ||
} | ||
|
||
// Here no shortcuts are created. There could be one from A to C with speed 80 but in the opposite | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is entirely redundant now |
||
// direction speeds differ which blocks CA creation. | ||
TEST(Shortcuts, CreateInvalid) { | ||
constexpr double gridsize = 50; | ||
|
||
const std::string ascii_map = R"( | ||
A--B--C | ||
)"; | ||
|
||
const gurka::ways ways = { | ||
{"AB", | ||
{{"highway", "primary"}, | ||
{"name", "Independence Avenue"}, | ||
{"maxspeed:forward", "80"}, | ||
{"maxspeed:backward", "80"}}}, | ||
{"BC", | ||
{{"highway", "primary"}, | ||
{"name", "Independence Avenue"}, | ||
{"maxspeed:forward", "80"}, | ||
{"maxspeed:backward", "90"}}}, | ||
}; | ||
|
||
const auto layout = gurka::detail::map_to_coordinates(ascii_map, gridsize); | ||
auto map = gurka::buildtiles(layout, ways, {}, {}, "test/data/gurka_openlrjoiner_shortcut_speed"); | ||
|
||
baldr::GraphReader graph_reader(map.config.get_child("mjolnir")); | ||
|
||
// check that there are no shortcut edges | ||
EXPECT_ANY_THROW(gurka::findEdgeByNodes(graph_reader, layout, "A", "C")); | ||
EXPECT_ANY_THROW(gurka::findEdgeByNodes(graph_reader, layout, "C", "A")); | ||
} | ||
|
||
TEST(Shortcuts, ShortcutSpeed) { | ||
// At C node turn duration is present. As a result the speed for AE shortcut is decreased | ||
// from 100 kph to 93 kph and for EA shortcut - from 100 kph to 98 kph in the test case below. | ||
|
@@ -363,13 +331,15 @@ TEST(Shortcuts, ShortcutsInBins) { | |
} | ||
|
||
TEST(Shortcuts, ShortcutRestrictions) { | ||
using node_pairs = std::vector<std::pair<std::string, std::string>>; | ||
|
||
// the first line should produce only one shortcut, the second two | ||
const std::string ascii_map = R"( | ||
A--B--C--D--E--F | ||
|
||
G--H--I--J--K--L | ||
)"; | ||
|
||
// the first line should produce only one shortcut, the second two | ||
gurka::ways ways = { | ||
{"AB", {{"highway", "motorway"}, {"name", "highway"}}}, | ||
{"BC", {{"highway", "motorway"}, {"name", "highway"}}}, | ||
|
@@ -389,13 +359,11 @@ TEST(Shortcuts, ShortcutRestrictions) { | |
baldr::GraphReader reader(map.config.get_child("mjolnir")); | ||
|
||
// test we got the right shortcuts edges, implicitly means they were broken properly | ||
for (const auto& end_node : {"C", "J", "L"}) { | ||
const auto shortcut = | ||
gurka::findEdge(reader, layout, "highway", end_node, baldr::GraphId{}, 0, true); | ||
for (const auto& pair : | ||
node_pairs{{"A", "C"}, {"C", "A"}, {"H", "J"}, {"J", "H"}, {"J", "L"}, {"L", "J"}}) { | ||
const auto shortcut = gurka::findEdgeByNodes(reader, layout, pair.first, pair.second); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the |
||
EXPECT_TRUE(std::get<1>(shortcut)->is_shortcut()); | ||
EXPECT_TRUE(std::get<3>(shortcut)->is_shortcut()); | ||
EXPECT_NEAR(std::get<1>(shortcut)->length(), 3000, 1); | ||
EXPECT_NEAR(std::get<3>(shortcut)->length(), 3000, 1); | ||
} | ||
|
||
// test the right edges are really superseded by a shortcut | ||
|
@@ -430,12 +398,9 @@ TEST(Shortcuts, ShortcutRestrictions) { | |
} | ||
|
||
// we did build the long shorcuts across all edges | ||
for (const auto& end_node : {"F", "L"}) { | ||
const auto shortcut = | ||
gurka::findEdge(reader2, layout, "highway", end_node, baldr::GraphId{}, 0, true); | ||
for (const auto& pair : node_pairs{{"A", "F"}, {"F", "A"}, {"G", "L"}, {"L", "G"}}) { | ||
const auto shortcut = gurka::findEdgeByNodes(reader2, layout, pair.first, pair.second); | ||
EXPECT_TRUE(std::get<1>(shortcut)->is_shortcut()); | ||
EXPECT_TRUE(std::get<3>(shortcut)->is_shortcut()); | ||
EXPECT_NEAR(std::get<1>(shortcut)->length(), 7500, 1); | ||
EXPECT_NEAR(std::get<3>(shortcut)->length(), 7500, 1); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doing some graph build experiments and logging to .log. happens frequently, might as well put it in .gitignore