mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-23 14:43:43 +00:00
[traffic] Penalize turns near endpoints
This improves decoding quality on urban multi-carriageway roads. Signed-off-by: mvglasow <michael -at- vonglasow.com>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<!--
|
||||
From DE-realworld5.
|
||||
Test case for turn penalty (eastern end).
|
||||
-->
|
||||
<feed>
|
||||
<message expiration_time="2025-10-09T21:37:08+03:00" id="tmc:d.1.15:d.1.29829.n.1" receive_time="2025-10-09T21:17:08+03:00" update_time="2025-10-09T21:17:08+03:00">
|
||||
<location directionality="ONE_DIRECTION" fuzziness="LOW_RES" road_name="Mittlerer Ring" road_ref="B2R">
|
||||
<from junction_name="Lerchenauer Straße">+48.176102 +11.558100</from>
|
||||
<to junction_name="Petueltunnel">+48.178001 +11.572800</to>
|
||||
</location>
|
||||
<events>
|
||||
<event class="CONGESTION" type="CONGESTION_QUEUE">
|
||||
</event>
|
||||
</events>
|
||||
</message>
|
||||
</feed>
|
||||
@@ -3,6 +3,7 @@
|
||||
A combination of reference points on the opposite carriageway, high offroad cost,
|
||||
allowing any road to be used and a low penalty results in a completely incorrect
|
||||
location (through a residential area rather than along the opposite carriageway).
|
||||
Test case for turn penalty (eastern end) if the above is resolved.
|
||||
-->
|
||||
<feed>
|
||||
<message expiration_time="2025-10-09T21:37:08+03:00" id="tmc:d.1.15:d.1.22689.p.1" receive_time="2025-10-09T21:17:08+03:00" update_time="2025-10-09T21:17:08+03:00">
|
||||
|
||||
22
data/test_data/traff/DE-GM4-UrbanDualCarriagewayEndpoint.xml
Normal file
22
data/test_data/traff/DE-GM4-UrbanDualCarriagewayEndpoint.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<!--
|
||||
Subset of realworld5.
|
||||
Test case for turn penalty (both ends).
|
||||
Junction names are the names of the crossing roads.
|
||||
No segments of the crossing roads should be among the matched segments.
|
||||
-->
|
||||
<feed>
|
||||
<message expiration_time="2025-10-09T21:37:08+03:00" id="tmc:d.1.15:d.1.46572.p.1,14" receive_time="2025-10-09T21:17:08+03:00" update_time="2025-10-09T21:17:08+03:00">
|
||||
<location directionality="ONE_DIRECTION" fuzziness="LOW_RES" road_name="Leopoldstraße" road_ref="GM4">
|
||||
<from junction_name="Potsdamer Straße">+48.167301 +11.586200</from>
|
||||
<to junction_name="Ungererstraße">+48.164200 +11.586500</to>
|
||||
</location>
|
||||
<events>
|
||||
<event class="INCIDENT" type="INCIDENT_ACCIDENT">
|
||||
</event>
|
||||
<event class="CONGESTION" type="CONGESTION_STATIONARY_TRAFFIC">
|
||||
</event>
|
||||
<event class="HAZARD" type="HAZARD_PASSABLE_WITH_CARE_BELOW_ELEVATION">
|
||||
</event>
|
||||
</events>
|
||||
</message>
|
||||
</feed>
|
||||
@@ -91,6 +91,21 @@ auto constexpr kAttributePenalty = 4;
|
||||
*/
|
||||
auto constexpr kReducedAttributePenalty = 2;
|
||||
|
||||
/*
|
||||
* Maximum distance in meters from location endpoint at which a turn penalty is applied
|
||||
*/
|
||||
auto constexpr kTurnPenaltyMaxDist = 100.0;
|
||||
|
||||
/*
|
||||
* Minimum angle in degrees at which turn penalty is applied
|
||||
*/
|
||||
auto constexpr kTurnPenaltyMinAngle = 65.0;
|
||||
|
||||
/*
|
||||
* Minimum angle in degrees at which the full turn penalty is applied
|
||||
*/
|
||||
auto constexpr kTurnPenaltyFullAngle = 90.0;
|
||||
|
||||
/*
|
||||
* Invalid feature ID.
|
||||
* Borrowed from indexer/feature_decl.hpp.
|
||||
@@ -563,15 +578,67 @@ double RoutingTraffDecoder::TraffEstimator::GetUTurnPenalty(Purpose /* purpose *
|
||||
return 2 * 60; // seconds
|
||||
}
|
||||
|
||||
double RoutingTraffDecoder::TraffEstimator::GetTurnPenalty(Purpose /* purpose */, double /* angle */,
|
||||
routing::RoadGeometry const & /* from_road */,
|
||||
routing::RoadGeometry const & /* to_road */,
|
||||
bool /* is_left_hand_traffic */) const
|
||||
double RoutingTraffDecoder::TraffEstimator::GetTurnPenalty(Purpose /* purpose */, double angle,
|
||||
routing::RoadGeometry const & from_road,
|
||||
routing::RoadGeometry const & to_road,
|
||||
bool is_left_hand_traffic) const
|
||||
{
|
||||
/*
|
||||
* TODO determine if turn penalties make sense for the traffic decoder, else leave them out.
|
||||
* `angle` seems to be in degrees, right is negative
|
||||
* Turn is at the first or last point of the roads involved, compare points to find out.
|
||||
*/
|
||||
// Flip sign for left-hand traffic, so a positive angle always means a turn across traffic
|
||||
if (is_left_hand_traffic)
|
||||
angle *= -1;
|
||||
|
||||
// We only penalize sharp turns (above kTurnPenaltyMinAngle) across traffic
|
||||
if (angle < kTurnPenaltyMinAngle)
|
||||
return 0.0;
|
||||
|
||||
/*
|
||||
* Identify coordinates of location endpoints and of the turn, and establish distance between the
|
||||
* turn and the nearest endpoint.
|
||||
*/
|
||||
ms::LatLon from = m_decoder.m_message.value().m_location.value().m_from
|
||||
? m_decoder.m_message.value().m_location.value().m_from.value().m_coordinates
|
||||
: m_decoder.m_message.value().m_location.value().m_at.value().m_coordinates;
|
||||
ms::LatLon to = m_decoder.m_message.value().m_location.value().m_to
|
||||
? m_decoder.m_message.value().m_location.value().m_to.value().m_coordinates
|
||||
: m_decoder.m_message.value().m_location.value().m_at.value().m_coordinates;
|
||||
|
||||
// Upper boundary for distance (approximately earth circumference)
|
||||
double dist = 4.0e+7;
|
||||
|
||||
for (auto & fromPoint : { from_road.GetPoint(0), from_road.GetPoint(from_road.GetPointsCount() - 1) })
|
||||
for (auto & toPoint : { to_road.GetPoint(0), to_road.GetPoint(to_road.GetPointsCount() - 1) })
|
||||
if (fromPoint == toPoint)
|
||||
for (auto & endpoint : { from, to })
|
||||
{
|
||||
auto newdist = ms::DistanceOnEarth(fromPoint, endpoint);
|
||||
if (newdist < dist)
|
||||
dist = newdist;
|
||||
}
|
||||
|
||||
// We only penalize turns close to an endpoint
|
||||
if (dist > kTurnPenaltyMaxDist)
|
||||
return 0.0;
|
||||
|
||||
/*
|
||||
* The penalty depends on the distance between the turn point and the nearest endpoint: the
|
||||
* shorter the distance, the greater the penalty. This is obtained by subtracting the distance
|
||||
* from `kTurnPenaltyMaxDist`.
|
||||
*
|
||||
* Above `kTurnPenaltyFullAngle`, the full turn penalty applies, i.e. the distance-based value is
|
||||
* multiplied with `kAttributePenalty`.
|
||||
*
|
||||
* Between `kTurnPenaltyMinAngle` and `kTurnPenaltyFullAngle`, the penalty proportionally
|
||||
* increases from 0 to the full value.
|
||||
*/
|
||||
double result = (kTurnPenaltyMaxDist - dist) * kAttributePenalty;
|
||||
if (angle < kTurnPenaltyFullAngle)
|
||||
result *= (angle - kTurnPenaltyMinAngle) / (kTurnPenaltyFullAngle - kTurnPenaltyMinAngle);
|
||||
return result;
|
||||
}
|
||||
|
||||
double RoutingTraffDecoder::TraffEstimator::GetFerryLandingPenalty(Purpose /* purpose */) const
|
||||
|
||||
Reference in New Issue
Block a user