From 6280f7740faa7da9fc8553eb4b884a0725d5d490 Mon Sep 17 00:00:00 2001 From: Daria Volvenkova Date: Tue, 24 Mar 2020 14:36:28 +0300 Subject: [PATCH] [bookmarks] Select only tracks from the catalog containing valid altitudes. --- map/bookmark_manager.cpp | 8 +-- map/framework.cpp | 3 +- map/track.cpp | 102 ++++++++++++++++++++++++++++++--------- map/track.hpp | 22 +++++++-- 4 files changed, 103 insertions(+), 32 deletions(-) diff --git a/map/bookmark_manager.cpp b/map/bookmark_manager.cpp index 363ba184c5..88a398bd5c 100644 --- a/map/bookmark_manager.cpp +++ b/map/bookmark_manager.cpp @@ -705,7 +705,7 @@ void BookmarkManager::DeleteBookmark(kml::MarkId bmId) Track * BookmarkManager::CreateTrack(kml::TrackData && trackData) { CHECK_THREAD_CHECKER(m_threadChecker, ()); - return AddTrack(std::make_unique(std::move(trackData))); + return AddTrack(std::make_unique(std::move(trackData), false /* interactive */)); } Track const * BookmarkManager::GetTrack(kml::TrackId trackId) const @@ -1143,10 +1143,10 @@ BookmarkManager::TrackSelectionInfo BookmarkManager::FindNearestTrack( for (auto trackId : category.GetUserLines()) { auto const track = GetTrack(trackId); - if (tracksFilter && !tracksFilter(track)) + if (!track->IsInteractive() || (tracksFilter && !tracksFilter(track))) continue; - auto const & trackRect = track->GetLimitRect(); + auto const trackRect = track->GetLimitRect(); if (!trackRect.IsIntersect(touchRect)) continue; @@ -2733,7 +2733,7 @@ void BookmarkManager::CreateCategories(KMLDataCollection && dataCollection, bool } for (auto & trackData : fileData.m_tracksData) { - auto track = std::make_unique(std::move(trackData)); + auto track = std::make_unique(std::move(trackData), group->IsCategoryFromCatalog()); auto * t = AddTrack(std::move(track)); t->Attach(groupId); group->AttachTrack(t->GetId()); diff --git a/map/framework.cpp b/map/framework.cpp index 86e88b7496..180ac619f1 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1137,7 +1137,8 @@ void Framework::ShowTrack(kml::TrackId trackId) StopLocationFollow(); ShowRect(rect); - GetBookmarkManager().ShowDefaultTrackInfo(trackId); + if (track->IsInteractive()) + GetBookmarkManager().ShowDefaultTrackInfo(trackId); } void Framework::ShowBookmarkCategory(kml::MarkGroupId categoryId, bool animation) diff --git a/map/track.cpp b/map/track.cpp index c255fa4bb6..78b8d3d1ed 100644 --- a/map/track.cpp +++ b/map/track.cpp @@ -7,52 +7,99 @@ #include -Track::Track(kml::TrackData && data) +Track::Track(kml::TrackData && data, bool interactive) : Base(data.m_id == kml::kInvalidTrackId ? UserMarkIdStorage::Instance().GetNextTrackId() : data.m_id) , m_data(std::move(data)) { m_data.m_id = GetId(); CHECK_GREATER(m_data.m_pointsWithAltitudes.size(), 1, ()); - CacheLengthsAndLimitRect(); + if (interactive && HasAltitudes()) + CacheDataForInteraction(); } -void Track::CacheLengthsAndLimitRect() +void Track::CacheDataForInteraction() { - m_cachedLimitRect.MakeEmpty(); - m_cachedLimitRect.Add(m_data.m_pointsWithAltitudes.front().GetPoint()); - m_cachedLengths.resize(m_data.m_pointsWithAltitudes.size()); - double length = 0.0; - m_cachedLengths[0] = 0.0; + m_interactionData = InteractionData(); + GetLengthsImpl(m_interactionData->m_lengths); + m_interactionData->m_limitRect = GetLimitRectImpl(); +} + +void Track::GetLengthsImpl(std::vector & lengths) const +{ + lengths.resize(m_data.m_pointsWithAltitudes.size()); + lengths[0] = 0.0; for (size_t i = 1; i < m_data.m_pointsWithAltitudes.size(); ++i) { auto const & pt1 = m_data.m_pointsWithAltitudes[i - 1].GetPoint(); auto const & pt2 = m_data.m_pointsWithAltitudes[i].GetPoint(); auto const segmentLength = mercator::DistanceOnEarth(pt1, pt2); - length += segmentLength; - m_cachedLengths[i] = length; - m_cachedLimitRect.Add(pt2); + lengths[i] = lengths[i - 1] + segmentLength; } } +m2::RectD Track::GetLimitRectImpl() const +{ + m2::RectD limitRect; + for (auto const & pt : m_data.m_pointsWithAltitudes) + limitRect.Add(pt.GetPoint()); + return limitRect; +} + +bool Track::HasAltitudes() const +{ + bool hasNonDefaultAltitude = false; + for (auto const & pt : m_data.m_pointsWithAltitudes) + { + if (pt.GetAltitude() == geometry::kInvalidAltitude) + return false; + hasNonDefaultAltitude |= pt.GetAltitude() != geometry::kDefaultAltitudeMeters; + } + + return hasNonDefaultAltitude; +} + std::string Track::GetName() const { return GetPreferredBookmarkStr(m_data.m_name); } -m2::RectD const & Track::GetLimitRect() const +m2::RectD Track::GetLimitRect() const { - return m_cachedLimitRect; + if (m_interactionData) + return m_interactionData->m_limitRect; + return GetLimitRectImpl(); } double Track::GetLengthMeters() const { - return m_cachedLengths.back(); + if (m_interactionData) + return m_interactionData->m_lengths.back(); + + return GetLengthMeters(m_data.m_pointsWithAltitudes.size() - 1); } double Track::GetLengthMeters(size_t pointIndex) const { - CHECK_LESS(pointIndex, m_cachedLengths.size(), (pointIndex, m_cachedLengths.size())); - return m_cachedLengths[pointIndex]; + CHECK_LESS(pointIndex, m_data.m_pointsWithAltitudes.size(), + (pointIndex, m_data.m_pointsWithAltitudes.size())); + + if (m_interactionData) + return m_interactionData->m_lengths[pointIndex]; + + double length = 0.0; + for (size_t i = 1; i <= pointIndex; ++i) + { + auto const & pt1 = m_data.m_pointsWithAltitudes[i - 1].GetPoint(); + auto const & pt2 = m_data.m_pointsWithAltitudes[i].GetPoint(); + auto const segmentLength = mercator::DistanceOnEarth(pt1, pt2); + length += segmentLength; + } + return length; +} + +bool Track::IsInteractive() const +{ + return m_interactionData.has_value(); } df::DepthLayer Track::GetDepthLayer() const @@ -117,27 +164,38 @@ bool Track::GetPoint(double distanceInMeters, m2::PointD & pt) const { CHECK_GREATER_OR_EQUAL(distanceInMeters, 0.0, (distanceInMeters)); + if (m_interactionData) + return GetPointImpl(m_interactionData->m_lengths, distanceInMeters, pt); + + std::vector lengths; + GetLengthsImpl(lengths); + return GetPointImpl(lengths, distanceInMeters, pt); +} + +bool Track::GetPointImpl(std::vector const & lengths, double distanceInMeters, + m2::PointD & pt) const +{ double const kEpsMeters = 1e-2; - if (base::AlmostEqualAbs(distanceInMeters, m_cachedLengths.front(), kEpsMeters)) + if (base::AlmostEqualAbs(distanceInMeters, lengths.front(), kEpsMeters)) { pt = m_data.m_pointsWithAltitudes.front().GetPoint(); return true; } - if (base::AlmostEqualAbs(distanceInMeters, m_cachedLengths.back(), kEpsMeters)) + if (base::AlmostEqualAbs(distanceInMeters, lengths.back(), kEpsMeters)) { pt = m_data.m_pointsWithAltitudes.back().GetPoint(); return true; } - auto const it = std::lower_bound(m_cachedLengths.begin(), m_cachedLengths.end(), distanceInMeters); - if (it == m_cachedLengths.end()) + auto const it = std::lower_bound(lengths.begin(), lengths.end(), distanceInMeters); + if (it == lengths.end()) return false; - auto const pointIndex = std::distance(m_cachedLengths.begin(), it); + auto const pointIndex = std::distance(lengths.begin(), it); auto const length = *it; - auto const segmentLength = length - m_cachedLengths[pointIndex - 1]; + auto const segmentLength = length - lengths[pointIndex - 1]; auto const k = (segmentLength - (length - distanceInMeters)) / segmentLength; auto const & pt1 = m_data.m_pointsWithAltitudes[pointIndex - 1].GetPoint(); diff --git a/map/track.hpp b/map/track.hpp index dfd200da36..e8383d66d4 100644 --- a/map/track.hpp +++ b/map/track.hpp @@ -10,7 +10,7 @@ class Track : public df::UserLineMark { using Base = df::UserLineMark; public: - explicit Track(kml::TrackData && data); + Track(kml::TrackData && data, bool interactive); kml::MarkGroupId GetGroupId() const override { return m_groupID; } @@ -20,9 +20,10 @@ public: kml::TrackData const & GetData() const { return m_data; } std::string GetName() const; - m2::RectD const & GetLimitRect() const; + m2::RectD GetLimitRect() const; double GetLengthMeters() const; double GetLengthMeters(size_t pointIndex) const; + bool IsInteractive() const; int GetMinZoom() const override { return 1; } df::DepthLayer GetDepthLayer() const override; @@ -41,12 +42,23 @@ public: bool GetPoint(double distanceInMeters, m2::PointD & pt) const; private: - void CacheLengthsAndLimitRect(); + void CacheDataForInteraction(); + bool HasAltitudes() const; + void GetLengthsImpl(std::vector & lengths) const; + m2::RectD GetLimitRectImpl() const; + bool GetPointImpl(std::vector const & lengths, double distanceInMeters, + m2::PointD & pt) const; kml::TrackData m_data; kml::MarkGroupId m_groupID = kml::kInvalidMarkGroupId; kml::MarkId m_selectionMarkId = kml::kInvalidMarkId; - std::vector m_cachedLengths; - m2::RectD m_cachedLimitRect; + + struct InteractionData + { + std::vector m_lengths; + m2::RectD m_limitRect; + }; + std::optional m_interactionData; + mutable bool m_isDirty = true; };