| 129 | } |
| 130 | |
| 131 | std::pair<size_t, bool> PrepareNearestPointOnTrack(m2::PointD const & point, |
| 132 | std::optional<m2::PointD> const & prevPoint, size_t prevIndex, |
| 133 | Direction direction, std::vector<m2::PointD> & polyline) |
| 134 | { |
| 135 | // We skip 70% of the distance in a straight line between two stops for preventing incorrect |
| 136 | // projection of the |point| to the polyline of complex shape. |
| 137 | double const distStopsM = prevPoint ? mercator::DistanceOnEarth(point, *prevPoint) * 0.7 : 0.0; |
| 138 | |
| 139 | std::vector<ProjectionData> projections; |
| 140 | // Reserve space for points on polyline which are relatively close to the shape. |
| 141 | // Approximately 1/4 of all points on shape. |
| 142 | auto const size = direction == Direction::Forward ? polyline.size() - prevIndex : prevIndex; |
| 143 | projections.reserve(size / 4); |
| 144 | |
| 145 | auto const startIndex = direction == Direction::Forward ? prevIndex : 0; |
| 146 | auto const endIndex = direction == Direction::Forward ? polyline.size() - 1 : prevIndex; |
| 147 | FillProjections(polyline, startIndex, endIndex, point, distStopsM, direction, projections); |
| 148 | |
| 149 | if (projections.empty()) |
| 150 | return {polyline.size() + 1, false}; |
| 151 | |
| 152 | // We find the most fitting projection of the stop to the polyline. For two different projections |
| 153 | // with approximately equal distances to the stop the most preferable is the one that is closer |
| 154 | // to the beginning of the polyline segment. |
| 155 | auto const cmp = [](ProjectionData const & p1, ProjectionData const & p2) |
| 156 | { |
| 157 | if (CloserToEndingAndOnSimilarDistToLine(p1, p2)) |
| 158 | return true; |
| 159 | |
| 160 | if (CloserToEndingAndOnSimilarDistToLine(p2, p1)) |
| 161 | return false; |
| 162 | |
| 163 | if (p1.m_distFromPoint == p2.m_distFromPoint) |
| 164 | return p1.m_distFromEnding < p2.m_distFromEnding; |
| 165 | |
| 166 | return p1.m_distFromPoint < p2.m_distFromPoint; |
| 167 | }; |
| 168 | |
| 169 | auto proj = std::min_element(projections.begin(), projections.end(), cmp); |
| 170 | |
| 171 | // This case is possible not only for the first stop on the shape. We try to resolve situation |
| 172 | // when two stops are projected to the same point on the shape. |
| 173 | if (proj->m_indexOnShape == prevIndex) |
| 174 | { |
| 175 | proj = std::min_element(projections.begin(), projections.end(), |
| 176 | [](ProjectionData const & p1, ProjectionData const & p2) |
| 177 | { return p1.m_distFromPoint < p2.m_distFromPoint; }); |
| 178 | } |
| 179 | |
| 180 | if (proj->m_needsInsertion) |
| 181 | polyline.insert(polyline.begin() + proj->m_indexOnShape, proj->m_proj); |
| 182 | |
| 183 | return {proj->m_indexOnShape, proj->m_needsInsertion}; |
| 184 | } |
| 185 | |
| 186 | bool IsRelevantType(gtfs::RouteType const & routeType) |
| 187 | { |