| 108 | } |
| 109 | |
| 110 | void ExtractTrafficGeometry(FeatureType const & f, df::RoadClass const & roadClass, m2::PolylineD const & polyline, |
| 111 | bool oneWay, int zoomLevel, double pixelToGlobalScale, |
| 112 | df::TrafficSegmentsGeometry & geometry) |
| 113 | { |
| 114 | if (polyline.GetSize() < 2) |
| 115 | return; |
| 116 | |
| 117 | auto const & regionData = f.GetID().m_mwmId.GetInfo()->GetRegionData(); |
| 118 | bool const isLeftHandTraffic = regionData.Get(feature::RegionData::RD_DRIVING) == "l"; |
| 119 | |
| 120 | // Calculate offset between road lines in mercator for two-way roads. |
| 121 | double twoWayOffset = 0.0; |
| 122 | if (!oneWay) |
| 123 | twoWayOffset = pixelToGlobalScale * df::TrafficRenderer::GetTwoWayOffset(roadClass, zoomLevel); |
| 124 | |
| 125 | static std::array<uint8_t, 2> const directions = {traffic::TrafficInfo::RoadSegmentId::kForwardDirection, |
| 126 | traffic::TrafficInfo::RoadSegmentId::kReverseDirection}; |
| 127 | auto & segments = geometry[f.GetID().m_mwmId]; |
| 128 | |
| 129 | int const index = zoomLevel - kFirstZoomInAverageSegments; |
| 130 | ASSERT_GREATER_OR_EQUAL(index, 0, ()); |
| 131 | ASSERT_LESS(index, static_cast<int>(kAverageSegmentsCount.size()), ()); |
| 132 | segments.reserve(kAverageSegmentsCount[index]); |
| 133 | |
| 134 | for (uint16_t segIndex = 0; segIndex + 1 < static_cast<uint16_t>(polyline.GetSize()); ++segIndex) |
| 135 | { |
| 136 | for (size_t dirIndex = 0; dirIndex < directions.size(); ++dirIndex) |
| 137 | { |
| 138 | if (oneWay && dirIndex > 0) |
| 139 | break; |
| 140 | |
| 141 | auto const sid = traffic::TrafficInfo::RoadSegmentId(f.GetID().m_index, segIndex, directions[dirIndex]); |
| 142 | bool isReversed = (directions[dirIndex] == traffic::TrafficInfo::RoadSegmentId::kReverseDirection); |
| 143 | |
| 144 | auto const segment = polyline.ExtractSegment(segIndex, isReversed); |
| 145 | ASSERT_EQUAL(segment.size(), 2, ()); |
| 146 | |
| 147 | // Skip zero-length segments. |
| 148 | double constexpr kEps = 1e-5; |
| 149 | if (segment[0].EqualDxDy(segment[1], kEps)) |
| 150 | break; |
| 151 | |
| 152 | if (!oneWay) |
| 153 | { |
| 154 | m2::PointD const tangent = (segment[1] - segment[0]).Normalize(); |
| 155 | m2::PointD const normal = |
| 156 | isLeftHandTraffic ? m2::PointD(-tangent.y, tangent.x) : m2::PointD(tangent.y, -tangent.x); |
| 157 | m2::PolylineD segmentPolyline( |
| 158 | std::vector<m2::PointD>{segment[0] + normal * twoWayOffset, segment[1] + normal * twoWayOffset}); |
| 159 | segments.emplace_back(sid, df::TrafficSegmentGeometry(std::move(segmentPolyline), roadClass)); |
| 160 | } |
| 161 | else |
| 162 | { |
| 163 | m2::PolylineD segmentPolyline(std::vector<m2::PointD>{segment[0], segment[1]}); |
| 164 | segments.emplace_back(sid, df::TrafficSegmentGeometry(std::move(segmentPolyline), roadClass)); |
| 165 | } |
| 166 | } |
| 167 | } |
no test coverage detected