Skip to content

Commit

Permalink
add improved penalty function
Browse files Browse the repository at this point in the history
  • Loading branch information
Moritz Kobitzsch committed Sep 20, 2016
1 parent b988317 commit d0d470a
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 48 deletions.
10 changes: 0 additions & 10 deletions include/extractor/profile_properties.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,8 @@ struct ProfileProperties
traffic_signal_penalty = boost::numeric_cast<int>(traffic_signal_penalty_ * 10.);
}

double GetCrossingTrafficPenalty() const { return crossing_through_traffic_penalty / 10.; }

void SetCrossingTrafficPenalty(const double crossing_through_traffic_penalty_)
{
crossing_through_traffic_penalty = boost::numeric_cast<int>(crossing_through_traffic_penalty_ * 10.);
}

//! penalty to cross a traffic light in deci-seconds
int traffic_signal_penalty;
// if a turn crosses through traffic, this additional penalty (in deci-seconds) describes the
// expected average delay. At some point this should be integrated into the turn function
int crossing_through_traffic_penalty;
//! penalty to do a uturn in deci-seconds
int u_turn_penalty;
bool continue_straight_at_waypoint;
Expand Down
9 changes: 8 additions & 1 deletion include/extractor/scripting_environment.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
#include "extractor/internal_extractor_edge.hpp"
#include "extractor/profile_properties.hpp"
#include "extractor/restriction.hpp"
#include "extractor/turn_penalty.hpp"

#include <osmium/memory/buffer.hpp>

#include <boost/optional/optional.hpp>

#include <tbb/concurrent_vector.h>

#include <cstdint>
#include <string>
#include <vector>

Expand Down Expand Up @@ -53,7 +55,12 @@ class ScriptingEnvironment
virtual std::vector<std::string> GetNameSuffixList() = 0;
virtual std::vector<std::string> GetExceptions() = 0;
virtual void SetupSources() = 0;
virtual int32_t GetTurnPenalty(double angle) = 0;
virtual std::int32_t GetTurnPenalty(double angle) = 0;
virtual std::int32_t
GetDetailedTurnPenalty(const TurnProperties &turn_properties,
const IntersectionProperties &intersection_properties,
const TurnSegment &approach_segment,
const TurnSegment &exit_segment) = 0;
virtual void ProcessSegment(const osrm::util::Coordinate &source,
const osrm::util::Coordinate &target,
double distance,
Expand Down
9 changes: 8 additions & 1 deletion include/extractor/scripting_environment_lua.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
#define SCRIPTING_ENVIRONMENT_LUA_HPP

#include "extractor/scripting_environment.hpp"
#include "extractor/turn_penalty.hpp"

#include "extractor/raster_source.hpp"

#include "util/lua_util.hpp"

#include <tbb/enumerable_thread_specific.h>

#include <cstdint>
#include <memory>
#include <mutex>
#include <string>
Expand All @@ -30,6 +32,7 @@ struct LuaScriptingContext final
util::LuaState state;

bool has_turn_penalty_function;
bool has_detailed_penalty_function;
bool has_node_function;
bool has_way_function;
bool has_segment_function;
Expand All @@ -55,7 +58,11 @@ class LuaScriptingEnvironment final : public ScriptingEnvironment
std::vector<std::string> GetNameSuffixList() override;
std::vector<std::string> GetExceptions() override;
void SetupSources() override;
int32_t GetTurnPenalty(double angle) override;
std::int32_t GetTurnPenalty(double angle) override;
std::int32_t GetDetailedTurnPenalty(const TurnProperties &turn_properties,
const IntersectionProperties &intersection_properties,
const TurnSegment &approach_segment,
const TurnSegment &exit_segment) override;
void ProcessSegment(const osrm::util::Coordinate &source,
const osrm::util::Coordinate &target,
double distance,
Expand Down
46 changes: 46 additions & 0 deletions include/extractor/turn_penalty.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#ifndef OSRM_TURN_PENALTY_HPP_
#define OSRM_TURN_PENALTY_HPP_

/* The turn functions offered by osrm come in two variations. One uses a basic angle. The other one
* offers a list of additional entries to improve the turn penalty */

namespace osrm
{
namespace extractor
{

// properties describing the turn
struct TurnProperties
{
// the turn angle between the ingoing/outgoing segments
double angle;
// the radius of the turn at the curve (approximated)
double radius;
// the turn is crossing through opposing traffic
bool crossing_through_traffic;
// indicate if the turn needs to be announced or if it is a turn following the obvious road
bool requires_announcement;
};

// properties describing intersection related penalties
struct IntersectionProperties
{
// is the turn at a traffic light
bool traffic_light;
// is the turn at a stop-light
bool stop_sign;
// is the turn following a right-of-way situation
bool right_of_way;
};

// information about the segments coming in/out of the intersection
struct TurnSegment
{
double length_in_meters;
double speed_in_meters_per_second;
};

} // namespace extractor
} // namespace osrm

#endif // OSRM_TURN_PENALTY_HPP_
36 changes: 30 additions & 6 deletions profiles/car.lua
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,15 @@ maxspeed_table = {
properties.u_turn_penalty = 20
properties.traffic_signal_penalty = 2
-- if we are crossing through traffic on a turn, we add this penalty
properties.crossing_traffic_penalty = 5
properties.use_turn_restrictions = true
properties.continue_straight_at_waypoint = true
properties.left_hand_driving = false

local side_road_speed_multiplier = 0.8

local turn_penalty = 7.5
local crossing_through_traffic_penalty = 5
local turn_announcement_penalty = 3
-- Note: this biases right-side driving. Should be
-- inverted for left-driving countries.
local turn_bias = properties.left_hand_driving and 1/1.075 or 1.075
Expand Down Expand Up @@ -541,14 +542,37 @@ function way_function (way, result)
result.is_startpoint = result.forward_mode == mode.driving or result.backward_mode == mode.driving
end

-- a detailed turn function as an alternative to turn function, offering more properties to decide on a good penalty
-- returns penalty in seconds
function detailed_turn_function(turn_properties, intersection_properties, approach_segment, exit_segment)
local penalty = 0;
if turn_properties.angle>=0 then
penalty = turn_penalty / (1 + 2.718 ^ - ((13 / turn_bias) * angle/180 - 6.5*turn_bias))
else
penalty = turn_penalty / (1 + 2.718 ^ - ((13 * turn_bias) * - angle/180 - 6.5/turn_bias))
end

-- we make announced turns more expensive while, at the same time, we reduce the cost of suppressed turns
if turn_properties.requires_announcement then
penalty = penalty + turn_announcement_penalty
else
-- unanounced turns are cheaper than normal turns
penalty = penalty * 0.8;
end

-- crossing through traffic is expensive
if turn_properties.crossing_through_traffic then
penalty = penalty + crossing_through_traffic_penalty
end

return penalty;
end


function turn_function (angle)
-- Use a sigmoid function to return a penalty that maxes out at turn_penalty
-- over the space of 0-180 degrees. Values here were chosen by fitting
-- the function to some turn penalty samples from real driving.
-- multiplying by 10 converts to deci-seconds see issue #1318
if angle>=0 then
return 10 * turn_penalty / (1 + 2.718 ^ - ((13 / turn_bias) * angle/180 - 6.5*turn_bias))
else
return 10 * turn_penalty / (1 + 2.718 ^ - ((13 * turn_bias) * - angle/180 - 6.5/turn_bias))
end
return 0;
end
71 changes: 44 additions & 27 deletions src/extractor/edge_based_graph_factory.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "extractor/edge_based_edge.hpp"
#include "extractor/edge_based_graph_factory.hpp"
#include "extractor/turn_penalty.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/exception.hpp"
Expand Down Expand Up @@ -415,40 +416,35 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
}(turn_classification.second);
bearing_class_by_node_based_node[node_v] = bearing_class_id;

bool crosses_through_traffic = false;
const bool crosses_traffic_light =
m_traffic_lights.find(node_v) != m_traffic_lights.end();

bool crosses_through_traffic = false;
const EdgeData &edge_data_from_u = m_node_based_graph->GetEdgeData(edge_from_u);
const TurnSegment approach_segment = {static_cast<double>(edge_data_from_u.distance),
static_cast<double>(edge_data_from_u.distance)};
const IntersectionProperties intersection_properties = {
crosses_traffic_light, false, false};
for (const auto turn : possible_turns)
{
// only add an edge if turn is not prohibited
const EdgeData &edge_data1 = m_node_based_graph->GetEdgeData(edge_from_u);

const EdgeData &edge_data2 = m_node_based_graph->GetEdgeData(turn.eid);

BOOST_ASSERT(edge_data1.edge_id != edge_data2.edge_id);
BOOST_ASSERT(!edge_data1.reversed);
BOOST_ASSERT(edge_data_from_u.edge_id != edge_data2.edge_id);
BOOST_ASSERT(!edge_data_from_u.reversed);
BOOST_ASSERT(!edge_data2.reversed);

// the following is the core of the loop.
unsigned distance = edge_data1.distance;
if (m_traffic_lights.find(node_v) != m_traffic_lights.end())
{
distance += profile_properties.traffic_signal_penalty;
}

const int32_t turn_penalty =
scripting_environment.GetTurnPenalty(180. - turn.angle);
const auto turn_instruction = turn.instruction;
unsigned distance = edge_data_from_u.distance;

if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn)
if (crosses_traffic_light)
{
distance += profile_properties.u_turn_penalty;
distance += profile_properties.traffic_signal_penalty;
}

distance += turn_penalty;

if (crosses_through_traffic)
distance += profile_properties.crossing_through_traffic_penalty;

// a through street is an obvious turn on which we can expect traffic coming onto our direction
// a through street is an obvious turn on which we can expect traffic coming onto
// our direction
const auto isThrough = [&](const guidance::TurnOperation &turn) {
if (!((turn.instruction.type == guidance::TurnType::Suppressed) ||
(turn.instruction.type == guidance::TurnType::NewName) ||
Expand All @@ -461,6 +457,27 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
return !m_node_based_graph->GetEdgeData(eid).reversed;
};

const bool requires_announcement = isThrough(turn);

const TurnProperties turn_properties = {
180. - turn.angle, turn.angle, crosses_through_traffic, requires_announcement};

const TurnSegment exit_segment = {static_cast<double>(edge_data2.distance),
static_cast<double>(edge_data2.distance)};

const int32_t turn_penalty =
scripting_environment.GetTurnPenalty(180. - turn.angle) +
scripting_environment.GetDetailedTurnPenalty(
turn_properties, intersection_properties, approach_segment, exit_segment);
const auto turn_instruction = turn.instruction;

if (turn_instruction.direction_modifier == guidance::DirectionModifier::UTurn)
{
distance += profile_properties.u_turn_penalty;
}

distance += turn_penalty;

// if a turn is a through turn, all following turns are crossing through the
// opposite traffic
if (isThrough(turn))
Expand All @@ -469,11 +486,11 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
BOOST_ASSERT(m_compressed_edge_container.HasEntryForID(edge_from_u));
original_edge_data_vector.emplace_back(
m_compressed_edge_container.GetPositionForID(edge_from_u),
edge_data1.name_id,
edge_data_from_u.name_id,
turn.lane_data_id,
turn_instruction,
entry_class_id,
edge_data1.travel_mode);
edge_data_from_u.travel_mode);

++original_edges_counter;

Expand All @@ -482,12 +499,12 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
FlushVectorToStream(edge_data_file, original_edge_data_vector);
}

BOOST_ASSERT(SPECIAL_NODEID != edge_data1.edge_id);
BOOST_ASSERT(SPECIAL_NODEID != edge_data_from_u.edge_id);
BOOST_ASSERT(SPECIAL_NODEID != edge_data2.edge_id);

// NOTE: potential overflow here if we hit 2^32 routable edges
BOOST_ASSERT(m_edge_based_edge_list.size() <= std::numeric_limits<NodeID>::max());
m_edge_based_edge_list.emplace_back(edge_data1.edge_id,
m_edge_based_edge_list.emplace_back(edge_data_from_u.edge_id,
edge_data2.edge_id,
m_edge_based_edge_list.size(),
distance,
Expand All @@ -498,7 +515,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// the node-based edges that are originally used to calculate the `distance`
// for the edge-expanded edges. About 40 lines back, there is:
//
// unsigned distance = edge_data1.distance;
// unsigned distance = edge_data_from_u.distance;
//
// This tells us that the weight for an edge-expanded-edge is based on the weight
// of the *source* node-based edge. Therefore, we will look up the individual
Expand Down Expand Up @@ -558,7 +575,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
m_node_info_list[m_compressed_edge_container.GetFirstEdgeTargetID(
turn.eid)];

const unsigned fixed_penalty = distance - edge_data1.distance;
const unsigned fixed_penalty = distance - edge_data_from_u.distance;
lookup::PenaltyBlock penaltyblock = {
fixed_penalty, from_node.node_id, via_node.node_id, to_node.node_id};
edge_penalty_file.write(reinterpret_cast<const char *>(&penaltyblock),
Expand Down
Loading

0 comments on commit d0d470a

Please sign in to comment.