Skip to content
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

Making the turn function more flexible #4789

Merged
merged 37 commits into from
Jan 24, 2018
Merged

Conversation

chaupow
Copy link
Member

@chaupow chaupow commented Jan 11, 2018

Issue

Targeting issue #4775
In short: The goal is to make the turn function in lua profiles more flexible and powerful by exposing more information to it.

Tasklist

Requirements / Relations

maybe none

@chaupow chaupow self-assigned this Jan 11, 2018
@chaupow chaupow force-pushed the feature/flexible_turn_func branch from 6b7dcf3 to a09d6ad Compare January 15, 2018 09:49
bool is_link, int number_of_lanes, int highway_turn_classification, int access_turn_classification, int speed)
bool is_link, int number_of_lanes,
int highway_turn_classification,
int access_turn_classification, int speed, bool is_incoming,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you also need incoming/outgoing status for other modes. e.g for bicycle routing you also need information about car traffic

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'll target that in another issue. I'd prefer getting the changes ready and see how these changes make a difference in better ETA & route planning & extraction memory usage peak. But your comment is well noted and will not be forgotten! :)

@chaupow chaupow force-pushed the feature/flexible_turn_func branch from 48e71da to 8778c86 Compare January 17, 2018 15:17
@chaupow chaupow requested a review from oxidase January 17, 2018 16:36
Copy link
Contributor

@oxidase oxidase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, but some changes are needed as PR adds information about connected roads into ExtractionTurn and this will cause a merge conflict with splitting of EBGF and guidance code.

docs/profiles.md Outdated
target_mode | Read | Enum | Travel mode after the turn. Defined in `include/extractor/travel_mode.hpp`
Attribute | Read/write? | Type | Notes
--------------------- | ------------- | --------- | ------------------------------------------------------
angle | Read | Float | Angle of turn in degrees (`0-360`: `0`=u-turn, `180`=straight on)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Angle in ExtractionTurn is initialized with 180. - angle: 0 is straight on, positive values for right turns, negative values for left turns, 180 is a U-turn

Feature: Turn Function Information

Scenario: Turns should have correct information of source and target
Given the profile file
Copy link
Contributor

@oxidase oxidase Jan 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test profile with printing can be moved to a background section and removed from scenarios. Profile customization also can be placed directly in the feature file as: ``` Background: Given the profile file """ functions = require('car')

function test_setup()
profile = functions.setup()
profile.highway_turn_classification = {
['motorway'] = 4,
['motorway_link'] = 4,
['trunk'] = 4,
['trunk_link'] = 4,
['primary'] = 4,
['primary_link'] = 4,
['secondary'] = 3,
['secondary_link'] = 3,
['tertiary'] = 2,
['tertiary_link'] = 2,
['residential'] = 1,
['living_street'] = 1,
}

profile.access_turn_classification = {
['discouraged'] = 1;
['permissive'] = 1;
['private'] = 1;
['customers'] = 1;
['dismount'] = 1;
}
return profile
end

function turn_leg_string (leg)
return 'speed: ' .. tostring(leg.speed)
.. ', is_incoming: ' .. tostring(leg.is_incoming)
.. ', is_outgoing: ' .. tostring(leg.is_outgoing)
.. ', highway_turn_classification: ' .. tostring(leg.highway_turn_classification)
.. ', access_turn_classification: ' .. tostring(leg.access_turn_classification)
end

function print_turn (profile, turn)
print ('source_restricted ' .. string.format("%s", tostring(turn.source_restricted)))
print ('source_is_motorway ' .. string.format("%s", tostring(turn.source_is_motorway)))
print ('source_is_link ' .. string.format("%s", tostring(turn.source_is_link)))
print ('source_number_of_lanes ' .. string.format("%s", tostring(turn.source_number_of_lanes)))
print ('source_highway_turn_classification ' .. string.format("%s", tostring(turn.source_highway_turn_classification)))
print ('source_access_turn_classification ' .. string.format("%s", tostring(turn.source_access_turn_classification)))
print ('source_speed ' .. string.format("%s", tostring(turn.source_speed)))

print ('target_restricted ' .. string.format("%s", tostring(turn.target_restricted)))
print ('target_is_motorway ' .. string.format("%s", tostring(turn.target_is_motorway)))
print ('target_is_link ' .. string.format("%s", tostring(turn.target_is_link)))
print ('target_number_of_lanes ' .. string.format("%s", tostring(turn.target_number_of_lanes)))
print ('target_highway_turn_classification ' .. string.format("%s", tostring(turn.target_highway_turn_classification)))
print ('target_access_turn_classification ' .. string.format("%s", tostring(turn.target_access_turn_classification)))
print ('target_speed ' .. string.format("%s", tostring(turn.target_speed)))

print ('number_of_roads ' .. string.format("%s", tostring(turn.number_of_roads)))
if not turn.is_u_turn then
for roadCount, road in ipairs(turn.roads_on_the_right) do
print('roads_on_the_right [' .. tostring(roadCount) .. '] ' .. turn_leg_string(road))
end

for roadCount, road in ipairs(turn.roads_on_the_left) do
  print('roads_on_the_left [' .. tostring(roadCount) .. '] ' .. turn_leg_string(road))
end

end
end

return {
setup = test_setup,
process_way = functions.process_way,
process_node = functions.process_node,
process_turn = print_turn
}
"""


</details>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks 👍

@@ -0,0 +1,483 @@
-- Adjusted car profile with print output for testing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file can be easily out of sync with the original car profile. I would suggest to load car profile functions and set testing functions directly in the feature file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

@@ -27,6 +27,9 @@ struct NodeBasedEdgeClassification
std::uint8_t startpoint : 1; // 1
std::uint8_t restricted : 1; // 1
guidance::RoadClassification road_classification; // 16 2
std::uint8_t highway_turn_classification : 4; // 4
std::uint8_t access_turn_classification : 4; // 4
std::uint8_t speed; // 8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

speed can be moved to NodeBasedEdge and grouped with weight and duration

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried calculating speed by edge length and duration. Many calculated speeds are within 10% of the actual speed. Some are not. Here is an extract of the differences running on Berlin:


calculated speed 50.000792 real speed 56
calculated speed 41.707704 real speed 48
calculated speed 41.707704 real speed 48
calculated speed 41.707704 real speed 48
calculated speed 30.748476 real speed 40
calculated speed 30.748476 real speed 40
calculated speed 32.505609 real speed 40
calculated speed 32.505609 real speed 40
calculated speed 30.754826 real speed 48
calculated speed 30.754826 real speed 48
calculated speed 30.754826 real speed 48
calculated speed 31.699496 real speed 40
calculated speed 31.699496 real speed 40
calculated speed 19.930782 real speed 25
calculated speed 19.930782 real speed 25
calculated speed 26.538870 real speed 55
calculated speed 26.538870 real speed 55
calculated speed 26.538870 real speed 55
calculated speed 19.930782 real speed 25

in favour of using less memory, @oxidase do you think this is preferable?

Copy link
Contributor

@oxidase oxidase Jan 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chaupow both speeds values have different meaning. For example, an NBG edge from https://www.openstreetmap.org/node/5339762636 to https://www.openstreetmap.org/node/1736058469 consists of two segments:

The speed value of the NBG edge is 40 kmh as the value of the first smaller segment.

The computed speed value is an average that also includes traffic light penalties.
In the example, the average speed is 26.44 kmh without traffic light penalty and 19.39 kmh with 2 seconds traffic light penalty.

I think average values are preferable over speed values of single segments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think average values are preferable over speed values of single segments.

Agreed! Done thanks 👍

@@ -405,6 +405,9 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti
forward_classes,
parsed_way.forward_travel_mode,
parsed_way.is_left_hand_driving});

std::uint8_t speed = parsed_way.forward_speed > 255 ? 255 : parsed_way.forward_speed;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here can be speed = std::min(parsed_way.forward_speed, 255)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

return road.eid == turn.eid;
});

// if the turn is a u turn, store all information in road_legs_on_the_right
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here can be an edge case for U-turns in left-driving countries.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think I should change this in left-driving countries?

I wonder whether it is important whether roads are on the left or right when you do a u turn and want to assign turn weights for u turns. Maybe it doesn't really matter here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, it should not matter, but would good to mention u-turns in the description of ExtractionTurn:roads_on_the_right property

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -562,7 +562,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto node_based_edge_to,
const auto incoming_bearing,
const auto &turn,
const auto entry_class_id) {
const auto entry_class_id,
const auto &intersection) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change conflicts with #4674 which removes guidance intersections analysis code from the edge-based-graph factory. To resolve the conflict a convertToIntersectionView call must be included back in #4674 and intersection_view must be used instead of intersection.

I would suggest to move initialization of road_legs_on_the_right and road_legs_on_the_left vectors out of the lambda and split intersection into two arrays after lines

const auto turn =
std::find_if(intersection.begin(),
intersection.end(),
[edge = outgoing_edge.edge](const auto &road) {
return road.eid == edge;
});

Copy link
Member Author

@chaupow chaupow Jan 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To resolve the conflict a convertToIntersectionView call must be included back in #4674

How should we approach this. Are you going to change it in #4674 or should I make the changes?

local access = way:get_value_by_key("access")

if profile.highway_turn_classification[highway] then
assert(profile.highway_turn_classification[highway] < 16, "highway_turn_classification must be smaller than 16")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asserts can can be directly checked before assignments below.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

@@ -50,6 +50,9 @@ module.exports = function () {
.defer(mkdirp, logDir)
.defer(rimraf, this.scenarioLogFile)
.awaitAll(callback);
// Question @review is this line nice to have here (commented, but ready to use and uncomment if needed?)
// i think this is super useful and would love to have it here
// console.log(" Writing logging output to " + this.scenarioLogFile)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

And stdout should contain "source_number_of_lanes 3"
And stdout should contain "target_is_motorway false"
And stdout should contain "target_is_link true"
# Question @review: should number_of_lanes when untagged be 0 or 1?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for using 0 number of lanes when untagged, otherwise number_of_lanes=1 would mean both untagged lanes and one lane cases.

@chaupow
Copy link
Member Author

chaupow commented Jan 22, 2018

I compared RAM peak usage during osrm-extract of this PR and current master when extracting california:

  • master uses 4.59GB
  • this PR uses 4.57GB

@chaupow chaupow force-pushed the feature/flexible_turn_func branch 2 times, most recently from d0354d4 to d239814 Compare January 24, 2018 16:11
@chaupow chaupow force-pushed the feature/flexible_turn_func branch from 49efaeb to 5550f76 Compare January 24, 2018 18:57
Copy link
Contributor

@oxidase oxidase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@chaupow chaupow merged commit 61e06fc into master Jan 24, 2018
@chaupow chaupow deleted the feature/flexible_turn_func branch January 24, 2018 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants