diff --git a/transit/world_feed/feed_helpers.cpp b/transit/world_feed/feed_helpers.cpp index 1eabc94365..82e34582ca 100644 --- a/transit/world_feed/feed_helpers.cpp +++ b/transit/world_feed/feed_helpers.cpp @@ -370,7 +370,7 @@ std::optional GetIntersection(size_t start1, size_t finish1, size_t if (intersectionLen == 0) return std::nullopt; - return LineSegment(maxStart, maxStart + intersectionLen); + return LineSegment(maxStart, static_cast(maxStart + intersectionLen)); } int CalcSegmentOrder(size_t segIndex, size_t totalSegCount) @@ -383,4 +383,143 @@ int CalcSegmentOrder(size_t segIndex, size_t totalSegCount) return curSegOffset; } + +bool StopIndexIsSet(size_t stopIndex) +{ + return stopIndex != std::numeric_limits::max(); +} + +std::pair GetStopsRange(IdList const & lineStopIds, IdSet const & stopIdsInRegion) +{ + size_t first = std::numeric_limits::max(); + size_t last = std::numeric_limits::max(); + + for (size_t i = 0; i < lineStopIds.size(); ++i) + { + auto const & stopId = lineStopIds[i]; + if (stopIdsInRegion.count(stopId) != 0) + { + if (!StopIndexIsSet(first)) + { + first = i; + } + last = i; + } + } + + if (StopIndexIsSet(first)) + { + if (first > 0) + --first; + + if (last < lineStopIds.size() - 1) + ++last; + } + + CHECK_GREATER_OR_EQUAL(last, first, ()); + return {first, last}; +} + +// Returns indexes of nearest to the |point| elements in |shape|. +std::vector GetMinDistIndexes(std::vector const & shape, + m2::PointD const & point) +{ + double minDist = std::numeric_limits::max(); + + std::vector indexes; + + for (size_t i = 0; i < shape.size(); ++i) + { + double dist = mercator::DistanceOnEarth(shape[i], point); + + if (base::AlmostEqualAbs(dist, minDist, kEps)) + { + indexes.push_back(i); + continue; + } + + if (dist < minDist) + { + minDist = dist; + indexes.clear(); + indexes.push_back(i); + } + } + + CHECK(std::is_sorted(indexes.begin(), indexes.end()), ()); + return indexes; +} + +// Returns minimal distance between |val| and element in |vals| and the nearest element value. +std::pair FindMinDist(size_t val, std::vector const & vals) +{ + size_t minDist = std::numeric_limits::max(); + size_t minVal; + + CHECK(!vals.empty(), ()); + + for (size_t curVal : vals) + { + auto const & [min, max] = std::minmax(val, curVal); + size_t const dist = max - min; + + if (dist < minDist) + { + minVal = curVal; + minDist = dist; + } + } + + return {minDist, minVal}; +} + +std::pair FindSegmentOnShape(std::vector const & shape, + std::vector const & segment) +{ + auto const & intersectionsShape = FindIntersections(shape, segment).first; + + if (intersectionsShape.empty()) + return {0, 0}; + + auto const & firstIntersection = intersectionsShape.front(); + return {firstIntersection.m_startIdx, firstIntersection.m_endIdx}; +} + +std::pair FindPointsOnShape(std::vector const & shape, + m2::PointD const & p1, m2::PointD const & p2) +{ + // We find indexes of nearest points in |shape| to |p1| and |p2| correspondingly. + std::vector const & indexes1 = GetMinDistIndexes(shape, p1); + std::vector const & indexes2 = GetMinDistIndexes(shape, p2); + + // We fill mapping of distance (between p1 and p2 on the shape) to pairs of indexes of p1 and p2. + std::map> distToIndexes; + + for (size_t i1 : indexes1) + { + auto [minDist, i2] = FindMinDist(i1, indexes2); + distToIndexes.emplace(minDist, std::make_pair(i1, i2)); + } + + CHECK(!distToIndexes.empty(), ()); + + // If index of |p1| equals index of |p2| on the |shape| we return the next pair of the nearest + // indexes. It is possible in case if |p1| and |p2| are ends of the edge which represents the loop + // on the route. + auto const & [first, last] = distToIndexes.begin()->second; + if (first == last) + { + LOG(LINFO, + ("Edge with equal indexes of first and last points on the shape. Index on the shape:", + first)); + CHECK_GREATER(distToIndexes.size(), 1, ()); + + auto const & nextPair = std::next(distToIndexes.begin()); + CHECK_NOT_EQUAL(nextPair->second.first, nextPair->second.second, ()); + + return nextPair->second; + } + + return distToIndexes.begin()->second; +} } // namespace transit diff --git a/transit/world_feed/feed_helpers.hpp b/transit/world_feed/feed_helpers.hpp index 0c39aef67f..339bad6610 100644 --- a/transit/world_feed/feed_helpers.hpp +++ b/transit/world_feed/feed_helpers.hpp @@ -97,7 +97,7 @@ LineParts::iterator FindLinePart(LineParts & lineParts, LineSegment const & segm struct LineSchemeData { TransitId m_lineId = 0; - TransitId m_routeId = 0; + std::string m_color; ShapeLink m_shapeLink; LineParts m_lineParts; @@ -122,4 +122,29 @@ std::optional GetIntersection(size_t start1, size_t finish1, size_t // total parallel lines count. Line order must be symmetrical with respect to the сentral axis of // the polyline. int CalcSegmentOrder(size_t segIndex, size_t totalSegCount); + +// Returns true if |stopIndex| doesn't equal size_t maximum value. +bool StopIndexIsSet(size_t stopIndex); + +// Gets interval of stop indexes on the line with |lineStopIds| which belong to the region and +// its vicinity. |stopIdsInRegion| is set of all stop ids in the region. +std::pair GetStopsRange(IdList const & lineStopIds, IdSet const & stopIdsInRegion); + +// Returns indexes of points |p1| and |p2| on the |shape| polyline. If there are more then 1 +// occurrences of |p1| or |p2| in |shape|, indexes with minimum distance are returned. +std::pair FindPointsOnShape(std::vector const & shape, + m2::PointD const & p1, m2::PointD const & p2); + +// Returns indexes of first and last points of |segment| in the |shape| polyline. If |edgeShape| +// is not found returns pair of zeroes. +std::pair FindSegmentOnShape(std::vector const & shape, + std::vector const & segment); + +// Returns reversed vector. +template +std::vector GetReversed(std::vector vec) +{ + std::reverse(vec.begin(), vec.end()); + return vec; +} } // namespace transit