Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
335
libs/map/gps_track.cpp
Normal file
335
libs/map/gps_track.cpp
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
#include "map/gps_track.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
namespace gps_track
|
||||
{
|
||||
|
||||
inline pair<size_t, size_t> UnionRanges(pair<size_t, size_t> const & a, pair<size_t, size_t> const & b)
|
||||
{
|
||||
if (a.first == GpsTrack::kInvalidId)
|
||||
{
|
||||
ASSERT_EQUAL(a.second, GpsTrack::kInvalidId, ());
|
||||
return b;
|
||||
}
|
||||
if (b.first == GpsTrack::kInvalidId)
|
||||
{
|
||||
ASSERT_EQUAL(b.second, GpsTrack::kInvalidId, ());
|
||||
return a;
|
||||
}
|
||||
ASSERT_LESS_OR_EQUAL(a.first, a.second, ());
|
||||
ASSERT_LESS_OR_EQUAL(b.first, b.second, ());
|
||||
return make_pair(min(a.first, b.first), max(a.second, b.second));
|
||||
}
|
||||
|
||||
size_t constexpr kItemBlockSize = 1000;
|
||||
|
||||
} // namespace gps_track
|
||||
|
||||
size_t const GpsTrack::kInvalidId = GpsTrackCollection::kInvalidId;
|
||||
|
||||
GpsTrack::GpsTrack(string const & filePath, unique_ptr<IGpsTrackFilter> && filter)
|
||||
: m_filePath(filePath)
|
||||
, m_needClear(false)
|
||||
, m_needSendSnapshop(false)
|
||||
, m_filter(std::move(filter))
|
||||
, m_threadExit(false)
|
||||
, m_threadWakeup(false)
|
||||
{
|
||||
if (!m_filter)
|
||||
m_filter = make_unique<GpsTrackNullFilter>();
|
||||
|
||||
ASSERT(!m_filePath.empty(), ());
|
||||
}
|
||||
|
||||
GpsTrack::~GpsTrack()
|
||||
{
|
||||
if (m_thread.joinable())
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lg(m_threadGuard);
|
||||
m_threadExit = true;
|
||||
m_cv.notify_one();
|
||||
}
|
||||
m_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void GpsTrack::AddPoint(location::GpsInfo const & point)
|
||||
{
|
||||
{
|
||||
std::lock_guard lg(m_dataGuard);
|
||||
m_points.emplace_back(point);
|
||||
}
|
||||
ScheduleTask();
|
||||
}
|
||||
|
||||
void GpsTrack::AddPoints(vector<location::GpsInfo> const & points)
|
||||
{
|
||||
{
|
||||
std::lock_guard lg(m_dataGuard);
|
||||
m_points.insert(m_points.end(), points.begin(), points.end());
|
||||
}
|
||||
ScheduleTask();
|
||||
}
|
||||
|
||||
TrackStatistics GpsTrack::GetTrackStatistics() const
|
||||
{
|
||||
return m_collection ? m_collection->GetTrackStatistics() : TrackStatistics();
|
||||
}
|
||||
|
||||
ElevationInfo const & GpsTrack::GetElevationInfo() const
|
||||
{
|
||||
return m_collection->UpdateAndGetElevationInfo();
|
||||
}
|
||||
|
||||
void GpsTrack::Clear()
|
||||
{
|
||||
{
|
||||
std::lock_guard lg(m_dataGuard);
|
||||
m_points.clear();
|
||||
m_needClear = true;
|
||||
}
|
||||
ScheduleTask();
|
||||
}
|
||||
|
||||
size_t GpsTrack::GetSize() const
|
||||
{
|
||||
CHECK(m_collection != nullptr, ());
|
||||
return m_collection->GetSize();
|
||||
}
|
||||
|
||||
bool GpsTrack::IsEmpty() const
|
||||
{
|
||||
if (!m_collection)
|
||||
return true;
|
||||
return m_collection->IsEmpty();
|
||||
}
|
||||
|
||||
void GpsTrack::SetCallback(TGpsTrackDiffCallback callback)
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lg(m_callbackGuard);
|
||||
m_callback = callback;
|
||||
m_needSendSnapshop = true;
|
||||
}
|
||||
ScheduleTask();
|
||||
}
|
||||
|
||||
void GpsTrack::ScheduleTask()
|
||||
{
|
||||
lock_guard<mutex> lg(m_threadGuard);
|
||||
|
||||
if (m_thread.get_id() == std::thread::id())
|
||||
{
|
||||
m_thread = threads::SimpleThread([this]()
|
||||
{
|
||||
unique_lock<mutex> ul(m_threadGuard);
|
||||
while (true)
|
||||
{
|
||||
m_cv.wait(ul, [this]() -> bool { return m_threadExit || m_threadWakeup; });
|
||||
if (m_threadExit)
|
||||
break;
|
||||
m_threadWakeup = false;
|
||||
ProcessPoints();
|
||||
}
|
||||
|
||||
m_storage.reset();
|
||||
});
|
||||
}
|
||||
|
||||
m_threadWakeup = true;
|
||||
m_cv.notify_one();
|
||||
}
|
||||
|
||||
void GpsTrack::InitStorageIfNeed()
|
||||
{
|
||||
if (m_storage)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
m_storage = make_unique<GpsTrackStorage>(m_filePath);
|
||||
}
|
||||
catch (RootException const & e)
|
||||
{
|
||||
LOG(LWARNING, ("Track storage creation error:", e.Msg()));
|
||||
}
|
||||
}
|
||||
|
||||
void GpsTrack::InitCollection()
|
||||
{
|
||||
ASSERT(m_collection == nullptr, ());
|
||||
|
||||
m_collection = make_unique<GpsTrackCollection>();
|
||||
|
||||
InitStorageIfNeed();
|
||||
if (!m_storage)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// All origin points have been written in the storage,
|
||||
// and filtered points are inserted in the runtime collection.
|
||||
|
||||
vector<location::GpsInfo> originPoints;
|
||||
originPoints.reserve(gps_track::kItemBlockSize);
|
||||
|
||||
m_storage->ForEach([this, &originPoints](location::GpsInfo const & originPoint) -> bool
|
||||
{
|
||||
originPoints.emplace_back(originPoint);
|
||||
if (originPoints.size() == originPoints.capacity())
|
||||
{
|
||||
vector<location::GpsInfo> points;
|
||||
m_filter->Process(originPoints, points);
|
||||
|
||||
m_collection->Add(points);
|
||||
|
||||
originPoints.clear();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!originPoints.empty())
|
||||
{
|
||||
vector<location::GpsInfo> points;
|
||||
m_filter->Process(originPoints, points);
|
||||
|
||||
m_collection->Add(points);
|
||||
}
|
||||
}
|
||||
catch (RootException const & e)
|
||||
{
|
||||
LOG(LWARNING, ("Track storage exception:", e.Msg()));
|
||||
m_collection->Clear();
|
||||
m_storage.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void GpsTrack::ProcessPoints()
|
||||
{
|
||||
vector<location::GpsInfo> originPoints;
|
||||
bool needClear;
|
||||
// Steal data for processing
|
||||
{
|
||||
std::lock_guard lg(m_dataGuard);
|
||||
originPoints.swap(m_points);
|
||||
needClear = m_needClear;
|
||||
m_needClear = false;
|
||||
}
|
||||
|
||||
// Create collection only if callback appears
|
||||
if (!m_collection && HasCallback())
|
||||
InitCollection();
|
||||
|
||||
// All origin points are written in the storage,
|
||||
// and filtered points are inserted in the runtime collection.
|
||||
|
||||
UpdateStorage(needClear, originPoints);
|
||||
|
||||
if (!m_collection)
|
||||
return;
|
||||
|
||||
vector<location::GpsInfo> points;
|
||||
m_filter->Process(originPoints, points);
|
||||
|
||||
pair<size_t, size_t> addedIds;
|
||||
pair<size_t, size_t> evictedIds;
|
||||
UpdateCollection(needClear, points, addedIds, evictedIds);
|
||||
|
||||
NotifyCallback(addedIds, evictedIds);
|
||||
}
|
||||
|
||||
bool GpsTrack::HasCallback()
|
||||
{
|
||||
lock_guard<mutex> lg(m_callbackGuard);
|
||||
return m_callback != nullptr;
|
||||
}
|
||||
|
||||
void GpsTrack::UpdateStorage(bool needClear, vector<location::GpsInfo> const & points)
|
||||
{
|
||||
InitStorageIfNeed();
|
||||
if (!m_storage)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
if (needClear)
|
||||
m_storage->Clear();
|
||||
|
||||
m_storage->Append(points);
|
||||
}
|
||||
catch (RootException const & e)
|
||||
{
|
||||
LOG(LWARNING, ("Track storage exception:", e.Msg()));
|
||||
m_storage.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void GpsTrack::UpdateCollection(bool needClear, vector<location::GpsInfo> const & points,
|
||||
pair<size_t, size_t> & addedIds, pair<size_t, size_t> & evictedIds)
|
||||
{
|
||||
// Apply Clear and Add points
|
||||
// Clear points from collection, if need.
|
||||
evictedIds = needClear ? m_collection->Clear(false /* resetIds */) : make_pair(kInvalidId, kInvalidId);
|
||||
;
|
||||
|
||||
// Add points to the collection, if need
|
||||
if (!points.empty())
|
||||
addedIds = m_collection->Add(points);
|
||||
else
|
||||
addedIds = make_pair(kInvalidId, kInvalidId);
|
||||
}
|
||||
|
||||
void GpsTrack::NotifyCallback(pair<size_t, size_t> const & addedIds, pair<size_t, size_t> const & evictedIds)
|
||||
{
|
||||
lock_guard<mutex> lg(m_callbackGuard);
|
||||
|
||||
if (!m_callback)
|
||||
return;
|
||||
|
||||
if (m_needSendSnapshop)
|
||||
{
|
||||
m_needSendSnapshop = false;
|
||||
|
||||
vector<pair<size_t, location::GpsInfo>> toAdd;
|
||||
toAdd.reserve(m_collection->GetSize());
|
||||
m_collection->ForEach([&toAdd](location::GpsInfo const & point, size_t id) -> bool
|
||||
{
|
||||
toAdd.emplace_back(id, point);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (toAdd.empty())
|
||||
return; // nothing to send
|
||||
|
||||
m_callback(std::move(toAdd), make_pair(kInvalidId, kInvalidId), m_collection->GetTrackStatistics());
|
||||
}
|
||||
else
|
||||
{
|
||||
vector<pair<size_t, location::GpsInfo>> toAdd;
|
||||
if (addedIds.first != kInvalidId)
|
||||
{
|
||||
size_t const addedCount = addedIds.second - addedIds.first + 1;
|
||||
ASSERT_GREATER_OR_EQUAL(m_collection->GetSize(), addedCount, ());
|
||||
toAdd.reserve(addedCount);
|
||||
m_collection->ForEach([&toAdd](location::GpsInfo const & point, size_t id) -> bool
|
||||
{
|
||||
toAdd.emplace_back(id, point);
|
||||
return true;
|
||||
}, m_collection->GetSize() - addedCount);
|
||||
ASSERT_EQUAL(toAdd.size(), addedCount, ());
|
||||
}
|
||||
|
||||
if (toAdd.empty() && evictedIds.first == kInvalidId)
|
||||
return; // nothing to send
|
||||
|
||||
m_callback(std::move(toAdd), evictedIds, m_collection->GetTrackStatistics());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue