[bookmarks] Select only tracks from the catalog containing valid altitudes.

This commit is contained in:
Daria Volvenkova 2020-03-24 14:36:28 +03:00 committed by Vladimir Byko-Ianko
parent 0b5b73dc31
commit 6280f7740f
4 changed files with 103 additions and 32 deletions

View file

@ -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<Track>(std::move(trackData)));
return AddTrack(std::make_unique<Track>(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<Track>(std::move(trackData));
auto track = std::make_unique<Track>(std::move(trackData), group->IsCategoryFromCatalog());
auto * t = AddTrack(std::move(track));
t->Attach(groupId);
group->AttachTrack(t->GetId());

View file

@ -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)

View file

@ -7,52 +7,99 @@
#include <utility>
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<double> & 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<double> lengths;
GetLengthsImpl(lengths);
return GetPointImpl(lengths, distanceInMeters, pt);
}
bool Track::GetPointImpl(std::vector<double> 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();

View file

@ -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<double> & lengths) const;
m2::RectD GetLimitRectImpl() const;
bool GetPointImpl(std::vector<double> 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<double> m_cachedLengths;
m2::RectD m_cachedLimitRect;
struct InteractionData
{
std::vector<double> m_lengths;
m2::RectD m_limitRect;
};
std::optional<InteractionData> m_interactionData;
mutable bool m_isDirty = true;
};