diff --git a/routing/CMakeLists.txt b/routing/CMakeLists.txt index a80df847d0..fe13ca4bfd 100644 --- a/routing/CMakeLists.txt +++ b/routing/CMakeLists.txt @@ -51,6 +51,10 @@ set( following_info.hpp geometry.cpp geometry.hpp + guides_connections.cpp + guides_connections.hpp + guides_graph.cpp + guides_graph.hpp index_graph.cpp index_graph.hpp index_graph_loader.cpp diff --git a/routing/guides_connections.cpp b/routing/guides_connections.cpp new file mode 100644 index 0000000000..b059084018 --- /dev/null +++ b/routing/guides_connections.cpp @@ -0,0 +1,303 @@ +#include "routing/guides_connections.hpp" + +#include "routing/fake_feature_ids.hpp" + +namespace +{ +// We consider only really close points to be attached to the track. +double constexpr kMaxDistToTrackPointM = 50.0; + +// For points further from track then |kEqDistToTrackPointM| we try to attach them to the OSM +// graph. +double constexpr kEqDistToTrackPointM = 20.0; + +// It the checkpoint is further from the guides track than |kMaxDistToTrackForSkippingM|, we skip +// this track completely. For time optimization purposes only. +double constexpr kMaxDistToTrackForSkippingM = 100'000.0; +} // namespace + +namespace routing +{ +CheckpointTrackProj::CheckpointTrackProj(kml::MarkGroupId guideId, size_t trackIdx, + size_t trackPointIdx, + geometry::PointWithAltitude const & projectedPoint, + double distToProjectedPointM) + : m_guideId(guideId) + , m_trackIdx(trackIdx) + , m_trackPointIdx(trackPointIdx) + , m_projectedPoint(projectedPoint) + , m_distToProjectedPointM(distToProjectedPointM) +{ +} + +std::pair GetProjectionAndDistOnSegment( + m2::PointD const & point, geometry::PointWithAltitude const & startPath, + geometry::PointWithAltitude const & endPath) +{ + m2::PointD const projection = + m2::ParametrizedSegment(startPath.GetPoint(), endPath.GetPoint()) + .ClosestPointTo(point); + double const distM = mercator::DistanceOnEarth(projection, point); + return std::make_pair(geometry::PointWithAltitude(projection, 0 /* altitude */), distM); +} + +bool GuidesConnections::IsActive() const { return !m_allTracks.empty(); } + +std::vector GuidesConnections::GetOsmConnections(size_t checkpointIdx) const +{ + auto it = m_connectionsToOsm.find(checkpointIdx); + if (it == m_connectionsToOsm.end()) + return {}; + return it->second; +} + +void GuidesConnections::UpdateOsmConnections(size_t checkpointIdx, + std::vector const & links) +{ + auto const it = m_connectionsToOsm.find(checkpointIdx); + CHECK(it != m_connectionsToOsm.cend(), (checkpointIdx)); + it->second = links; +} + +GuidesConnections::GuidesConnections(GuidesTracks const & guides) : m_allTracks(guides) {} + +void GuidesConnections::PullCheckpointsToTracks(std::vector const & checkpoints) +{ + for (size_t checkpointIdx = 0; checkpointIdx < checkpoints.size(); ++checkpointIdx) + { + for (auto const & [guideId, tracks] : m_allTracks) + { + for (size_t trackIdx = 0; trackIdx < tracks.size(); ++trackIdx) + { + CHECK(!tracks[trackIdx].empty(), (trackIdx)); + for (size_t pointIdx = 0; pointIdx < tracks[trackIdx].size() - 1; ++pointIdx) + { + auto const [checkpointProj, distM] = + GetProjectionAndDistOnSegment(checkpoints[checkpointIdx], tracks[trackIdx][pointIdx], + tracks[trackIdx][pointIdx + 1]); + + // Skip too far track. + if (distM > kMaxDistToTrackForSkippingM) + break; + + // We consider only really close points to be attached to the track. + if (distM > kMaxDistToTrackPointM) + continue; + + CheckpointTrackProj const curProj(guideId, trackIdx, pointIdx, checkpointProj, distM); + auto const [it, inserted] = m_checkpointsOnTracks.emplace(checkpointIdx, curProj); + + if (!inserted && it->second.m_distToProjectedPointM > distM) + it->second = curProj; + } + } + } + } +} + +void GuidesConnections::AddTerminalGuidePoint(size_t checkpointIdx, size_t neighbourIdx, + m2::PointD const & curPoint) +{ + auto const it = m_checkpointsOnTracks.find(neighbourIdx); + CHECK(it != m_checkpointsOnTracks.cend(), (neighbourIdx)); + + auto const & neighbour = it->second; + auto const guideId = neighbour.m_guideId; + auto const trackIdx = neighbour.m_trackIdx; + auto const & track = m_allTracks[guideId][trackIdx]; + + CHECK_GREATER( + track.size(), 1, + ("checkpointIdx:", checkpointIdx, "neighbourIdx:", neighbourIdx, "trackIdx:", trackIdx)); + + // Connect start checkpoint to the starting point of the track. + if (checkpointIdx == 0) + { + double const distToStartM = mercator::DistanceOnEarth(curPoint, track.front().GetPoint()); + m_checkpointsOnTracks[checkpointIdx] = CheckpointTrackProj( + guideId, trackIdx, 0 /* trackPointIdx */, track.front() /* proj */, distToStartM); + + return; + } + + // Connect finish checkpoint to the finish point of the track. + double const distToSFinishM = mercator::DistanceOnEarth(curPoint, track.back().GetPoint()); + m_checkpointsOnTracks[checkpointIdx] = + CheckpointTrackProj(guideId, trackIdx, track.size() - 2 /* trackPointIdx */, + track.back() /* proj */, distToSFinishM); +} + +bool GuidesConnections::IsCheckpointAttached(size_t checkpointIdx) const +{ + return m_checkpointsOnTracks.find(checkpointIdx) != m_checkpointsOnTracks.end(); +} + +std::vector GetNeighbourIntermediatePoints(size_t checkpointIdx, size_t checkpointsCount) +{ + CHECK_GREATER(checkpointsCount, 2, (checkpointsCount)); + std::vector neighbours; + // We add left intermediate point: + if (checkpointIdx > 1) + neighbours.push_back(checkpointIdx - 1); + // We add right intermediate point: + if (checkpointIdx < checkpointsCount - 2) + neighbours.push_back(checkpointIdx + 1); + return neighbours; +} + +bool GuidesConnections::FitsForDirectLinkToGuide(size_t checkpointIdx, + size_t checkpointsCount) const +{ + auto it = m_checkpointsOnTracks.find(checkpointIdx); + CHECK(it != m_checkpointsOnTracks.end(), (checkpointIdx)); + bool const checkpointIsFar = it->second.m_distToProjectedPointM > kEqDistToTrackPointM; + if (checkpointIsFar) + return false; + + // If checkpoint lies on the track but its neighbour intermediate checkpoint does not, we should + // connect this checkpoint to the OSM graph. + if (checkpointsCount <= 2) + return true; + + for (auto const neighbourIdx : GetNeighbourIntermediatePoints(checkpointIdx, checkpointsCount)) + { + if (m_checkpointsOnTracks.find(neighbourIdx) == m_checkpointsOnTracks.end()) + return false; + } + + return true; +} + +void GuidesConnections::PullAdditionalCheckpointsToTracks( + std::vector const & checkpoints) +{ + for (size_t i : {size_t(0), checkpoints.size() - 1}) + { + // Skip already connected to the tracks checkpoints. + if (IsCheckpointAttached(i)) + continue; + + // Neighbour point of this terminal point should be on the track. + size_t neighbourIdx = i == 0 ? i + 1 : i - 1; + + if (!IsCheckpointAttached(neighbourIdx)) + continue; + + AddTerminalGuidePoint(i, neighbourIdx, checkpoints[i]); + } +} + +bool GuidesConnections::IsAttached() const { return !m_checkpointsFakeEndings.empty(); } + +FakeEnding GuidesConnections::GetFakeEnding(size_t checkpointIdx) const +{ + if (IsAttached()) + { + auto it = m_checkpointsFakeEndings.find(checkpointIdx); + if (it != m_checkpointsFakeEndings.end()) + return it->second; + } + return FakeEnding(); +} + +GuidesGraph const & GuidesConnections::GetGuidesGraph() const { return m_graph; } + +void GuidesConnections::OverwriteFakeEnding(size_t checkpointIdx, FakeEnding const & newFakeEnding) +{ + m_checkpointsFakeEndings[checkpointIdx] = newFakeEnding; +} + +// static +void GuidesConnections::ExtendFakeEndingProjections(FakeEnding const & srcFakeEnding, + FakeEnding & dstFakeEnding) +{ + dstFakeEnding.m_originJunction = srcFakeEnding.m_originJunction; + + for (auto const & proj : srcFakeEnding.m_projections) + { + if (std::find(dstFakeEnding.m_projections.begin(), dstFakeEnding.m_projections.end(), proj) == + dstFakeEnding.m_projections.end()) + { + dstFakeEnding.m_projections.push_back(proj); + } + } +} + +NumMwmId GuidesConnections::GetMwmId() const { return m_graph.GetMwmId(); } + +void GuidesConnections::SetGuidesGraphParams(NumMwmId mwmId, double maxSpeed) +{ + m_graph = GuidesGraph(maxSpeed, mwmId); +} + +void GuidesConnections::ConnectToGuidesGraph(std::vector const & checkpoints) +{ + PullCheckpointsToTracks(checkpoints); + + PullAdditionalCheckpointsToTracks(checkpoints); + + std::map, Segment> addedTracks; + + for (auto const & [checkpointIdx, proj] : m_checkpointsOnTracks) + { + auto const & checkpoint = checkpoints[checkpointIdx]; + auto const & checkpointProj = proj.m_projectedPoint; + + Segment segmentOnTrack; + auto const [it, insertedSegment] = + addedTracks.emplace(std::make_pair(proj.m_guideId, proj.m_trackIdx), segmentOnTrack); + if (insertedSegment) + { + CHECK(!m_allTracks[proj.m_guideId][proj.m_trackIdx].empty(), + ("checkpointIdx:", checkpointIdx, "guideId:", proj.m_guideId, + "trackIdx:", proj.m_trackIdx)); + + segmentOnTrack = + m_graph.AddTrack(m_allTracks[proj.m_guideId][proj.m_trackIdx], proj.m_trackPointIdx); + it->second = segmentOnTrack; + } + else + { + segmentOnTrack = m_graph.FindSegment(it->second, proj.m_trackPointIdx); + } + FakeEnding const newEnding = m_graph.MakeFakeEnding(segmentOnTrack, checkpoint, checkpointProj); + auto const [itEnding, inserted] = m_checkpointsFakeEndings.emplace(checkpointIdx, newEnding); + + CHECK(inserted, (checkpointIdx)); + bool const fitsForOsmLink = !FitsForDirectLinkToGuide(checkpointIdx, checkpoints.size()); + + if (fitsForOsmLink) + AddConnectionToOsm(checkpointIdx, segmentOnTrack, checkpointProj); + + // Connect to OSM start and finish points of the track. + auto const & firstPointOnTrack = m_allTracks[proj.m_guideId][proj.m_trackIdx][0]; + if (!(fitsForOsmLink && firstPointOnTrack == checkpointProj)) + { + auto const & firstSegmentOnTrack = m_graph.FindSegment(segmentOnTrack, 0); + AddConnectionToOsm(checkpointIdx, firstSegmentOnTrack, firstPointOnTrack); + } + + auto const & lastPointIdx = m_allTracks[proj.m_guideId][proj.m_trackIdx].size() - 1; + auto const & lastPointOnTrack = m_allTracks[proj.m_guideId][proj.m_trackIdx][lastPointIdx]; + if (!(fitsForOsmLink && lastPointOnTrack == checkpointProj)) + { + auto const & lastSegmentOnTrack = m_graph.FindSegment(segmentOnTrack, lastPointIdx - 1); + AddConnectionToOsm(checkpointIdx, lastSegmentOnTrack, lastPointOnTrack); + } + } +} + +void GuidesConnections::AddConnectionToOsm(size_t checkpointIdx, Segment const & real, + geometry::PointWithAltitude const & loop) +{ + LatLonWithAltitude const loopPoint(mercator::ToLatLon(loop.GetPoint()), loop.GetAltitude()); + + ConnectionToOsm link; + link.m_loopVertex = FakeVertex(kFakeNumMwmId, loopPoint, loopPoint, FakeVertex::Type::PureFake); + link.m_realSegment = real; + link.m_projectedPoint = loop; + std::tie(link.m_realFrom, link.m_realTo) = m_graph.GetFromTo(real); + + m_connectionsToOsm[checkpointIdx].push_back(link); +} +} // namespace routing diff --git a/routing/guides_connections.hpp b/routing/guides_connections.hpp new file mode 100644 index 0000000000..1a053ce07a --- /dev/null +++ b/routing/guides_connections.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include "routing/edge_estimator.hpp" +#include "routing/fake_ending.hpp" +#include "routing/fake_vertex.hpp" +#include "routing/guides_graph.hpp" +#include "routing/router.hpp" +#include "routing/segment.hpp" + +#include "kml/type_utils.hpp" + +#include "geometry/point2d.hpp" +#include "geometry/point_with_altitude.hpp" + +#include +#include +#include +#include + +namespace routing +{ +// Information needed to attach guide track to the OSM segments via fake edges. +struct ConnectionToOsm +{ + // Fake ending connecting |m_projectedPoint| on the tracks segment |m_realSegment| to OSM. + FakeEnding m_fakeEnding; + // Loop vertex for |m_projectedPoint|. + FakeVertex m_loopVertex; + // Segment on the track to which the |m_loopVertex| should be attached via |m_partsOfReal|. + Segment m_realSegment; + // Terminal points of |m_realSegment|. + LatLonWithAltitude m_realFrom; + LatLonWithAltitude m_realTo; + // Vertexes and corresponding PartOfReal segments connecting |m_loopVertex| and |m_realSegment|. + std::vector> m_partsOfReal; + // Projection of the checkpoint to the track. + geometry::PointWithAltitude m_projectedPoint; +}; + +// Information about checkpoint projection to the nearest guides track. +struct CheckpointTrackProj +{ + CheckpointTrackProj() = default; + CheckpointTrackProj(kml::MarkGroupId guideId, size_t trackIdx, size_t trackPointIdx, + geometry::PointWithAltitude const & projectedPoint, + double distToProjectedPointM); + // Guide id. + kml::MarkGroupId m_guideId = 0; + // Index of the track belonging to |m_guideId|. + size_t m_trackIdx = 0; + // Index of the nearest segment 'from' or 'to' point on the track to the checkpoint. + size_t m_trackPointIdx = 0; + // Projection of the checkpoint to the track. + geometry::PointWithAltitude m_projectedPoint; + // Distance between the checkpoint and |m_projectedPoint| + double m_distToProjectedPointM = 0; +}; + +using Projections = std::map; +using IterProjections = Projections::iterator; + +// Prepares guides tracks for attaching to the roads graph. +class GuidesConnections +{ +public: + GuidesConnections() = default; + GuidesConnections(GuidesTracks const & guides); + + // Sets mwm id and speed values for guides graph. + void SetGuidesGraphParams(NumMwmId mwmId, double maxSpeed); + + // Finds closest guides tracks for checkpoints, fills guides graph. + void ConnectToGuidesGraph(std::vector const & checkpoints); + + // Overwrites osm connections for checkpoint by its index |checkpointIdx|. + void UpdateOsmConnections(size_t checkpointIdx, std::vector const & links); + + // Set |newFakeEnding| for checkpoint. + void OverwriteFakeEnding(size_t checkpointIdx, FakeEnding const & newFakeEnding); + + // Merge existing |srcFakeEnding| with |dstFakeEnding|. + static void ExtendFakeEndingProjections(FakeEnding const & srcFakeEnding, + FakeEnding & dstFakeEnding); + + // Returns guides graph |m_graph| for index graph starter. + GuidesGraph const & GetGuidesGraph() const; + + // Returns all connections to the OSM graph relevant to checkpoint with |checkpointIdx| index. + std::vector GetOsmConnections(size_t checkpointIdx) const; + + // Checks if checkpoint is close enough to some track. + bool FitsForDirectLinkToGuide(size_t checkpointIdx, size_t checkpointsCount) const; + + // Checks if checkpoint is considered to be attached to some track. + bool IsCheckpointAttached(size_t checkpointIdx) const; + + // Checks if GuidesConnections instance is active. + bool IsActive() const; + + // Checks if some guides tracks in GuidesConnections instance are attached to the checkpoints. + bool IsAttached() const; + + // Returns mwm id linked to all tracks in the guides graph. + NumMwmId GetMwmId() const; + + // Returns fake ending associated with checkpoint by its index |checkpointIdx|. + FakeEnding GetFakeEnding(size_t checkpointIdx) const; + +private: + // Fills |ConnectionToOsm| for checkpoints for its further attachment to the roads graph. + void AddConnectionToOsm(size_t checkpointIdx, Segment const & real, + geometry::PointWithAltitude const & loop); + + // Attaches checkpoints to the nearest guides tracks if possible. + void PullCheckpointsToTracks(std::vector const & checkpoints); + + // Attaches terminal point on the track to the terminal checkpoint: start to start; + // finish - to finish. + void AddTerminalGuidePoint(size_t checkpointIdx, size_t neighbourIdx, + m2::PointD const & curPoint); + + // Attaches neighbour terminal checkpoints for those which are already attached. + void PullAdditionalCheckpointsToTracks(std::vector const & checkpoints); + + GuidesTracks m_allTracks; + Projections m_checkpointsOnTracks; + + // Maps with checkpoint indexes as keys. + std::map m_checkpointsFakeEndings; + std::map> m_connectionsToOsm; + + GuidesGraph m_graph; +}; +} // namespace routing diff --git a/routing/guides_graph.cpp b/routing/guides_graph.cpp new file mode 100644 index 0000000000..327c0906fd --- /dev/null +++ b/routing/guides_graph.cpp @@ -0,0 +1,158 @@ +#include "routing/guides_graph.hpp" + +#include "routing/fake_feature_ids.hpp" + +#include "geometry/distance_on_sphere.hpp" +#include "geometry/mercator.hpp" + +#include +#include +#include + +namespace +{ +double constexpr kZeroAltitude = 0.0; +} // namespace + +namespace routing +{ +bool GuideSegmentCompare::operator()(Segment const & lhs, Segment const & rhs) const +{ + if (lhs.GetFeatureId() != rhs.GetFeatureId()) + return lhs.GetFeatureId() < rhs.GetFeatureId(); + + return lhs.GetSegmentIdx() < rhs.GetSegmentIdx(); +} + +GuidesGraph::GuidesGraph(double maxSpeedMpS, NumMwmId mwmId) + : m_maxSpeedMpS(maxSpeedMpS) + , m_mwmId(mwmId) + , m_curGuidesFeatrueId(FakeFeatureIds::kGuidesGraphFeaturesStart) +{ + CHECK_NOT_EQUAL(m_maxSpeedMpS, 0.0, ()); +} + +double GuidesGraph::CalcSegmentTimeS(LatLonWithAltitude const & point1, + LatLonWithAltitude const & point2) const +{ + double const distM = ms::DistanceOnEarth(point1.GetLatLon(), point2.GetLatLon()); + double const weight = distM / m_maxSpeedMpS; + return weight; +} + +void GuidesGraph::GetEdgeList(Segment const & segment, bool isOutgoing, + std::vector & edges, + RouteWeight const & prevWeight) const +{ + auto const it = m_segments.find(segment); + CHECK(it != m_segments.end(), (segment)); + auto const & segmentOnTrack = it->first; + + IterOnTrack itOnTrack; + + if (segment.IsForward() == isOutgoing) + { + Segment nextSegment(segmentOnTrack.GetMwmId(), segmentOnTrack.GetFeatureId(), + segmentOnTrack.GetSegmentIdx() + 1, segmentOnTrack.IsForward()); + itOnTrack = m_segments.find(nextSegment); + if (itOnTrack == m_segments.end()) + return; + } + else + { + if (it->first.GetSegmentIdx() == 0) + return; + + Segment prevSegment(segmentOnTrack.GetMwmId(), segmentOnTrack.GetFeatureId(), + segmentOnTrack.GetSegmentIdx() - 1, segmentOnTrack.IsForward()); + itOnTrack = m_segments.find(prevSegment); + CHECK(itOnTrack != m_segments.end(), (segment)); + } + auto const & neighbour = itOnTrack->first; + Segment const resSegment(neighbour.GetMwmId(), neighbour.GetFeatureId(), + neighbour.GetSegmentIdx(), segment.IsForward()); + + auto const weight = isOutgoing ? RouteWeight(itOnTrack->second.m_weight) : prevWeight; + edges.emplace_back(resSegment, weight); +} + +LatLonWithAltitude const & GuidesGraph::GetJunction(Segment const & segment, bool front) const +{ + auto const it = m_segments.find(segment); + CHECK(it != m_segments.end(), (segment)); + return segment.IsForward() == front ? it->second.m_pointLast : it->second.m_pointFirst; +} + +NumMwmId GuidesGraph::GetMwmId() const { return m_mwmId; } + +Segment GuidesGraph::AddTrack(std::vector const & guideTrack, + size_t requiredSegmentIdx) +{ + uint32_t segmentIdx = 0; + Segment segment; + + for (size_t i = 0; i < guideTrack.size() - 1; ++i) + { + GuideSegmentData data; + Segment curSegment(m_mwmId, m_curGuidesFeatrueId, segmentIdx++, true /* forward */); + if (i == requiredSegmentIdx) + segment = curSegment; + + data.m_pointFirst = LatLonWithAltitude(mercator::ToLatLon(guideTrack[i].GetPoint()), + guideTrack[i].GetAltitude()); + data.m_pointLast = LatLonWithAltitude(mercator::ToLatLon(guideTrack[i + 1].GetPoint()), + guideTrack[i + 1].GetAltitude()); + + data.m_weight = CalcSegmentTimeS(data.m_pointFirst, data.m_pointLast); + + auto const [it, inserted] = m_segments.emplace(curSegment, data); + CHECK(inserted, (curSegment)); + } + ++m_curGuidesFeatrueId; + return segment; +} + +Segment GuidesGraph::FindSegment(Segment const & segment, size_t segmentIdx) const +{ + auto const it = m_segments.find(segment); + CHECK(it != m_segments.end(), (segment, segmentIdx)); + Segment segmentOnTrack(it->first.GetMwmId(), it->first.GetFeatureId(), + static_cast(segmentIdx), it->first.IsForward()); + + auto const itByIndex = m_segments.find(segmentOnTrack); + CHECK(itByIndex != m_segments.end(), (segment, segmentIdx)); + return itByIndex->first; +} + +RouteWeight GuidesGraph::CalcSegmentWeight(Segment const & segment) const +{ + auto const it = m_segments.find(segment); + CHECK(it != m_segments.end(), (segment)); + + return RouteWeight(it->second.m_weight); +} + +FakeEnding GuidesGraph::MakeFakeEnding(Segment const & segment, m2::PointD const & point, + geometry::PointWithAltitude const & projection) const +{ + auto const & frontJunction = GetJunction(segment, true /* front */); + auto const & backJunction = GetJunction(segment, false /* front */); + + FakeEnding ending; + ending.m_projections.emplace_back(segment, false /* isOneWay */, frontJunction, backJunction, + LatLonWithAltitude(mercator::ToLatLon(projection.GetPoint()), + projection.GetAltitude()) /* junction */); + + ending.m_originJunction = + LatLonWithAltitude(mercator::ToLatLon(point), static_cast(kZeroAltitude)); + return ending; +} + +std::pair GuidesGraph::GetFromTo( + Segment const & segment) const +{ + auto const & from = GetJunction(segment, false /* front */); + auto const & to = GetJunction(segment, true /* front */); + return std::make_pair(from, to); +} +} // namespace routing diff --git a/routing/guides_graph.hpp b/routing/guides_graph.hpp new file mode 100644 index 0000000000..2bc6b0f44b --- /dev/null +++ b/routing/guides_graph.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include "routing/fake_ending.hpp" +#include "routing/latlon_with_altitude.hpp" +#include "routing/segment.hpp" + +#include "routing_common/num_mwm_id.hpp" + +#include "geometry/point2d.hpp" + +#include +#include +#include +#include + +namespace routing +{ +// Segment of the track in the guides graph. +struct GuideSegmentData +{ + LatLonWithAltitude m_pointFirst; + LatLonWithAltitude m_pointLast; + double m_weight = 0.0; +}; + +// Custom comparison optimized for Guides segments: they all have the same |m_mwmId| and +// |m_forward| is always true. +struct GuideSegmentCompare +{ + bool operator()(Segment const & lhs, Segment const & rhs) const; +}; + +using GuideSegments = std::map; +using IterOnTrack = GuideSegments::const_iterator; + +// Graph used in IndexGraphStarter for building routes through the guides tracks. +class GuidesGraph +{ +public: + GuidesGraph() = default; + explicit GuidesGraph(double maxSpeedMpS, NumMwmId mwmId); + + Segment AddTrack(std::vector const & guideTrack, + size_t requiredSegmentIdx); + + FakeEnding MakeFakeEnding(Segment const & segment, m2::PointD const & point, + geometry::PointWithAltitude const & projection) const; + + void GetEdgeList(Segment const & segment, bool isOutgoing, std::vector & edges, + RouteWeight const & prevWeight) const; + routing::LatLonWithAltitude const & GetJunction(Segment const & segment, bool front) const; + RouteWeight CalcSegmentWeight(Segment const & segment) const; + Segment FindSegment(Segment const & segment, size_t segmentIdx) const; + + // Returns back and front points of the segment. Segment belongs to one of the guides tracks. + std::pair GetFromTo(Segment const & segment) const; + + NumMwmId GetMwmId() const; + +private: + double CalcSegmentTimeS(LatLonWithAltitude const & point1, + LatLonWithAltitude const & point2) const; + + GuideSegments m_segments; + double m_maxSpeedMpS = 0.0; + NumMwmId m_mwmId = 0; + uint32_t m_curGuidesFeatrueId = 0; +}; +} // namespace routing