| 530 | } |
| 531 | |
| 532 | size_t CheckUTurnOnRoute(IRoutingResult const & result, size_t const outgoingSegmentIndex, NumMwmIds const & numMwmIds, |
| 533 | RoutingSettings const & vehicleSettings, TurnItem & turn) |
| 534 | { |
| 535 | size_t constexpr kUTurnLookAhead = 3; |
| 536 | double constexpr kUTurnHeadingSensitivity = math::pi / 10.0; |
| 537 | auto const & segments = result.GetSegments(); |
| 538 | |
| 539 | // In this function we process the turn between the previous and the current |
| 540 | // segments. So we need a shift to get the previous segment. |
| 541 | ASSERT_GREATER(segments.size(), 1, ()); |
| 542 | ASSERT_GREATER(outgoingSegmentIndex, 0, ()); |
| 543 | ASSERT_GREATER(segments.size(), outgoingSegmentIndex, ()); |
| 544 | auto const & masterSegment = segments[outgoingSegmentIndex - 1]; |
| 545 | if (masterSegment.m_path.size() < 2) |
| 546 | return 0; |
| 547 | |
| 548 | // Roundabout is not the UTurn. |
| 549 | if (masterSegment.m_onRoundabout) |
| 550 | return 0; |
| 551 | for (size_t i = 0; i < kUTurnLookAhead && i + outgoingSegmentIndex < segments.size(); ++i) |
| 552 | { |
| 553 | auto const & checkedSegment = segments[outgoingSegmentIndex + i]; |
| 554 | if (checkedSegment.m_path.size() < 2) |
| 555 | return 0; |
| 556 | |
| 557 | if (checkedSegment.m_roadNameInfo.m_name == masterSegment.m_roadNameInfo.m_name && |
| 558 | checkedSegment.m_highwayClass == masterSegment.m_highwayClass && |
| 559 | checkedSegment.m_isLink == masterSegment.m_isLink && !checkedSegment.m_onRoundabout) |
| 560 | { |
| 561 | auto const & path = masterSegment.m_path; |
| 562 | auto const & pointBeforeTurn = path[path.size() - 2]; |
| 563 | auto const & turnPoint = path[path.size() - 1]; |
| 564 | auto const & pointAfterTurn = checkedSegment.m_path[1]; |
| 565 | // Same segment UTurn case. |
| 566 | if (i == 0) |
| 567 | { |
| 568 | // TODO Fix direction calculation. |
| 569 | // Warning! We can not determine UTurn direction in single edge case. So we use UTurnLeft. |
| 570 | // We decided to add driving rules (left-right sided driving) to mwm header. |
| 571 | if (pointBeforeTurn == pointAfterTurn && turnPoint != pointBeforeTurn) |
| 572 | { |
| 573 | turn.m_turn = CarDirection::UTurnLeft; |
| 574 | return 1; |
| 575 | } |
| 576 | // Wide UTurn must have link in it's middle. |
| 577 | return 0; |
| 578 | } |
| 579 | |
| 580 | // Avoid the UTurn on unnamed roads inside the rectangle based distinct. |
| 581 | if (checkedSegment.m_roadNameInfo.m_name.empty()) |
| 582 | return 0; |
| 583 | |
| 584 | // Avoid returning to the same edge after uturn somewere else. |
| 585 | if (pointBeforeTurn == pointAfterTurn) |
| 586 | return 0; |
| 587 | |
| 588 | m2::PointD const v1 = turnPoint.GetPoint() - pointBeforeTurn.GetPoint(); |
| 589 | m2::PointD const v2 = pointAfterTurn.GetPoint() - checkedSegment.m_path[0].GetPoint(); |