\brief Return |CarDirection::ExitHighwayToRight| or |CarDirection::ExitHighwayToLeft| or return |CarDirection::None| if no exit is detected. \note The function makes a decision about turn based on geometry of the route and turn candidates, so it works correctly for both left and right hand traffic.
| 210 | /// \note The function makes a decision about turn based on geometry of the route and turn |
| 211 | /// candidates, so it works correctly for both left and right hand traffic. |
| 212 | CarDirection TryToGetExitDirection(TurnCandidates const & possibleTurns, TurnInfo const & turnInfo, |
| 213 | Segment const & firstOutgoingSeg, CarDirection const intermediateDirection) |
| 214 | { |
| 215 | if (!possibleTurns.isCandidatesAngleValid) |
| 216 | return CarDirection::None; |
| 217 | |
| 218 | if (!IsHighway(turnInfo.m_ingoing->m_highwayClass, turnInfo.m_ingoing->m_isLink)) |
| 219 | return CarDirection::None; |
| 220 | |
| 221 | if (!turnInfo.m_outgoing->m_isLink && |
| 222 | !(IsSmallRoad(turnInfo.m_outgoing->m_highwayClass) && IsGoStraightOrSlightTurn(intermediateDirection))) |
| 223 | return CarDirection::None; |
| 224 | |
| 225 | // At this point it is known that the route goes form a highway to a link road or to a small road |
| 226 | // which has a slight angle with the highway. |
| 227 | |
| 228 | // Considering cases when the route goes from a highway to a link or a small road. |
| 229 | // Checking all turn candidates (sorted by their angles) and looking for the road which is a |
| 230 | // continuation of the ingoing segment. If the continuation is on the right hand of the route |
| 231 | // it's an exit to the left. If the continuation is on the left hand of the route |
| 232 | // it's an exit to the right. |
| 233 | // Note. The angle which is used for sorting turn candidates in |possibleTurns.candidates| |
| 234 | // is a counterclockwise angle between the ingoing route edge and corresponding candidate. |
| 235 | // For left turns the angle is less than zero and for right ones it is more than zero. |
| 236 | bool isCandidateBeforeOutgoing = true; |
| 237 | bool isHighwayCandidateBeforeOutgoing = true; |
| 238 | size_t highwayCandidateNumber = 0; |
| 239 | |
| 240 | for (auto const & c : possibleTurns.candidates) |
| 241 | { |
| 242 | if (c.m_segment == firstOutgoingSeg) |
| 243 | { |
| 244 | isCandidateBeforeOutgoing = false; |
| 245 | continue; |
| 246 | } |
| 247 | |
| 248 | if (IsHighway(c.m_highwayClass, c.m_isLink)) |
| 249 | { |
| 250 | ++highwayCandidateNumber; |
| 251 | if (highwayCandidateNumber >= 2) |
| 252 | return CarDirection::None; // There are two or more highway candidates from the junction. |
| 253 | isHighwayCandidateBeforeOutgoing = isCandidateBeforeOutgoing; |
| 254 | } |
| 255 | } |
| 256 | if (highwayCandidateNumber == 1) |
| 257 | return isHighwayCandidateBeforeOutgoing ? CarDirection::ExitHighwayToRight : CarDirection::ExitHighwayToLeft; |
| 258 | return CarDirection::None; |
| 259 | } |
| 260 | |
| 261 | // Min difference of route and alternative turn abs angles in degrees |
| 262 | // to ignore alternative turn (when route direction is GoStraight). |
no test coverage detected