forked from organicmaps/organicmaps
Review fixes.
This commit is contained in:
parent
d0a304286f
commit
cf2ee50beb
5 changed files with 76 additions and 62 deletions
|
@ -64,10 +64,12 @@ location::GpsInfo LinearExtrapolation(location::GpsInfo const & gpsInfo1,
|
|||
result.m_altitude = e.Extrapolate(gpsInfo1.m_altitude, gpsInfo2.m_altitude);
|
||||
|
||||
if (gpsInfo1.HasVerticalAccuracy() && gpsInfo2.HasVerticalAccuracy())
|
||||
{
|
||||
result.m_verticalAccuracy =
|
||||
e.Extrapolate(gpsInfo1.m_verticalAccuracy, gpsInfo2.m_verticalAccuracy);
|
||||
}
|
||||
|
||||
// @TODO(bykoianko) Now |result.m_bearing == gpsInfo2.m_bearing|.
|
||||
// @TODO(bykoianko) Now |result.m_bearing| == |gpsInfo2.m_bearing|.
|
||||
// In case of |gpsInfo1.HasBearing() && gpsInfo2.HasBearing() == true|
|
||||
// consider finding an average value between |gpsInfo1.m_bearing| and |gpsInfo2.m_bearing|
|
||||
// taking into account that they are periodic. It's important to implement it
|
||||
|
@ -80,51 +82,50 @@ location::GpsInfo LinearExtrapolation(location::GpsInfo const & gpsInfo1,
|
|||
return result;
|
||||
}
|
||||
|
||||
bool AreCoordsGoodForExtrapolation(location::GpsInfo const & beforeLastGpsInfo,
|
||||
location::GpsInfo const & lastGpsInfo)
|
||||
bool AreCoordsGoodForExtrapolation(location::GpsInfo const & info1, location::GpsInfo const & info2)
|
||||
{
|
||||
if (!beforeLastGpsInfo.IsValid() || !lastGpsInfo.IsValid())
|
||||
if (!info1.IsValid() || !info2.IsValid())
|
||||
return false;
|
||||
|
||||
double const distM =
|
||||
ms::DistanceOnEarth(beforeLastGpsInfo.m_latitude, beforeLastGpsInfo.m_longitude,
|
||||
lastGpsInfo.m_latitude, lastGpsInfo.m_longitude);
|
||||
ms::DistanceOnEarth(info1.m_latitude, info1.m_longitude,
|
||||
info2.m_latitude, info2.m_longitude);
|
||||
|
||||
double const timeS = lastGpsInfo.m_timestamp - beforeLastGpsInfo.m_timestamp;
|
||||
double const timeS = info2.m_timestamp - info1.m_timestamp;
|
||||
if (timeS <= 0.0)
|
||||
return false;
|
||||
|
||||
// |maxDistAfterExtrapolationM| is maximum possible distance from |lastGpsInfo| to
|
||||
// |maxDistAfterExtrapolationM| is maximum possible distance from |info2| to
|
||||
// the furthest extrapolated point.
|
||||
double const maxDistAfterExtrapolationM =
|
||||
distM * (Extrapolator::kMaxExtrapolationTimeMs / 1000.0) / timeS;
|
||||
// |maxDistForAllExtrapolationsM| is maximum possible distance from |lastGpsInfo| to
|
||||
// |maxDistForAllExtrapolationsM| is maximum possible distance from |info2| to
|
||||
// all extrapolated points in any cases.
|
||||
double const maxDistForAllExtrapolationsM =
|
||||
kMaxExtrapolationSpeedMPS / kMaxExtrapolationTimeSeconds;
|
||||
double const distLastToMeridian180 = ms::DistanceOnEarth(
|
||||
lastGpsInfo.m_latitude, lastGpsInfo.m_longitude, lastGpsInfo.m_latitude, 180.0 /* lon2Deg */);
|
||||
// Switching off extrapolation if |lastGpsInfo| are so close to meridian 180 that extrapolated
|
||||
// points may cross meridian 180 or if |beforeLastGpsInfo| and |lastGpsInfo| are located on
|
||||
double const distLastGpsInfoToMeridian180 = ms::DistanceOnEarth(
|
||||
info2.m_latitude, info2.m_longitude, info2.m_latitude, 180.0 /* lon2Deg */);
|
||||
// Switching off extrapolation if |info2| are so close to meridian 180 that extrapolated
|
||||
// points may cross meridian 180 or if |info1| and |info2| are located on
|
||||
// different sides of meridian 180.
|
||||
if (distLastToMeridian180 < maxDistAfterExtrapolationM ||
|
||||
(distLastToMeridian180 < maxDistForAllExtrapolationsM &&
|
||||
lastGpsInfo.m_longitude * beforeLastGpsInfo.m_longitude < 0.0) ||
|
||||
ms::DistanceOnEarth(lastGpsInfo.m_latitude, lastGpsInfo.m_longitude, 90.0 /* lat2Deg */,
|
||||
lastGpsInfo.m_longitude) < maxDistAfterExtrapolationM ||
|
||||
ms::DistanceOnEarth(lastGpsInfo.m_latitude, lastGpsInfo.m_longitude, -90.0 /* lat2Deg */,
|
||||
lastGpsInfo.m_longitude) < maxDistAfterExtrapolationM)
|
||||
if (distLastGpsInfoToMeridian180 < maxDistAfterExtrapolationM ||
|
||||
(distLastGpsInfoToMeridian180 < maxDistForAllExtrapolationsM &&
|
||||
info2.m_longitude * info1.m_longitude < 0.0) ||
|
||||
ms::DistanceOnEarth(info2.m_latitude, info2.m_longitude, 90.0 /* lat2Deg */,
|
||||
info2.m_longitude) < maxDistAfterExtrapolationM ||
|
||||
ms::DistanceOnEarth(info2.m_latitude, info2.m_longitude, -90.0 /* lat2Deg */,
|
||||
info2.m_longitude) < maxDistAfterExtrapolationM)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note. |timeS| may be less than zero. (beforeLastGpsInfo.m_timestampS >=
|
||||
// lastGpsInfo.m_timestampS) It may happen in rare cases because GpsInfo::m_timestampS is not
|
||||
// Note. |timeS| may be less than zero. (info1.m_timestampS >=
|
||||
// info2.m_timestampS) It may happen in rare cases because GpsInfo::m_timestampS is not
|
||||
// monotonic generally. Please see comment in declaration of class GpsInfo for details.
|
||||
|
||||
// @TODO(bykoianko) Switching off extrapolation based on acceleration should be implemented.
|
||||
// Switching off extrapolation based on speed, distance and time.
|
||||
return timeS > 0 && distM / timeS <= kMaxExtrapolationSpeedMPS &&
|
||||
return distM / timeS <= kMaxExtrapolationSpeedMPS &&
|
||||
distM <= kMaxExtrapolationDistMeters && timeS <= kMaxExtrapolationTimeSeconds;
|
||||
}
|
||||
|
||||
|
@ -141,9 +142,10 @@ void Extrapolator::OnLocationUpdate(location::GpsInfo const & gpsInfo)
|
|||
lock_guard<mutex> guard(m_mutex);
|
||||
m_beforeLastGpsInfo = m_lastGpsInfo;
|
||||
m_lastGpsInfo = gpsInfo;
|
||||
m_extrapolationCounter = 0;
|
||||
m_consecutiveRuns = 0;
|
||||
// Canceling all background tasks which are put to the queue before the task run in this method.
|
||||
m_extrapolatedUpdateMinValid = m_extrapolatedUpdateCounter + 1;
|
||||
++m_locationUpdateCounter;
|
||||
m_locationUpdateMinValid = m_locationUpdateCounter;
|
||||
}
|
||||
RunTaskOnBackgroundThread(false /* delayed */);
|
||||
}
|
||||
|
@ -154,16 +156,16 @@ void Extrapolator::Enable(bool enabled)
|
|||
m_isEnabled = enabled;
|
||||
}
|
||||
|
||||
void Extrapolator::ExtrapolatedLocationUpdate(uint64_t extrapolatedUpdateCounter)
|
||||
void Extrapolator::ExtrapolatedLocationUpdate(uint64_t locationUpdateCounter)
|
||||
{
|
||||
location::GpsInfo gpsInfo;
|
||||
{
|
||||
lock_guard<mutex> guard(m_mutex);
|
||||
// Canceling all calls of the method which were activated before |m_extrapolatedUpdateMinValid|.
|
||||
if (extrapolatedUpdateCounter < m_extrapolatedUpdateMinValid)
|
||||
// Canceling all calls of the method which were activated before |m_locationUpdateMinValid|.
|
||||
if (locationUpdateCounter < m_locationUpdateMinValid)
|
||||
return;
|
||||
|
||||
uint64_t const extrapolationTimeMs = kExtrapolationPeriodMs * m_extrapolationCounter;
|
||||
uint64_t const extrapolationTimeMs = kExtrapolationPeriodMs * m_consecutiveRuns;
|
||||
if (extrapolationTimeMs < kMaxExtrapolationTimeMs && m_lastGpsInfo.IsValid())
|
||||
{
|
||||
if (DoesExtrapolationWork())
|
||||
|
@ -185,8 +187,8 @@ void Extrapolator::ExtrapolatedLocationUpdate(uint64_t extrapolatedUpdateCounter
|
|||
|
||||
{
|
||||
lock_guard<mutex> guard(m_mutex);
|
||||
if (m_extrapolationCounter != kExtrapolationCounterUndefined)
|
||||
++m_extrapolationCounter;
|
||||
if (m_consecutiveRuns != kExtrapolationCounterUndefined)
|
||||
++m_consecutiveRuns;
|
||||
}
|
||||
|
||||
// Calling ExtrapolatedLocationUpdate() in |kExtrapolationPeriodMs| milliseconds.
|
||||
|
@ -195,31 +197,30 @@ void Extrapolator::ExtrapolatedLocationUpdate(uint64_t extrapolatedUpdateCounter
|
|||
|
||||
void Extrapolator::RunTaskOnBackgroundThread(bool delayed)
|
||||
{
|
||||
uint64_t extrapolatedUpdateCounter = 0;
|
||||
uint64_t locationUpdateCounter = 0;
|
||||
{
|
||||
lock_guard<mutex> guard(m_mutex);
|
||||
++m_extrapolatedUpdateCounter;
|
||||
extrapolatedUpdateCounter = m_extrapolatedUpdateCounter;
|
||||
locationUpdateCounter = m_locationUpdateCounter;
|
||||
}
|
||||
|
||||
if (delayed)
|
||||
{
|
||||
auto constexpr kExtrapolationPeriod = std::chrono::milliseconds(kExtrapolationPeriodMs);
|
||||
GetPlatform().RunDelayedTask(Platform::Thread::Background, kExtrapolationPeriod,
|
||||
[this, extrapolatedUpdateCounter] {
|
||||
ExtrapolatedLocationUpdate(extrapolatedUpdateCounter);
|
||||
[this, locationUpdateCounter] {
|
||||
ExtrapolatedLocationUpdate(locationUpdateCounter);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlatform().RunTask(Platform::Thread::Background, [this, extrapolatedUpdateCounter] {
|
||||
ExtrapolatedLocationUpdate(extrapolatedUpdateCounter);
|
||||
GetPlatform().RunTask(Platform::Thread::Background, [this, locationUpdateCounter] {
|
||||
ExtrapolatedLocationUpdate(locationUpdateCounter);
|
||||
});
|
||||
}
|
||||
|
||||
bool Extrapolator::DoesExtrapolationWork() const
|
||||
{
|
||||
if (!m_isEnabled || m_extrapolationCounter == kExtrapolationCounterUndefined)
|
||||
if (!m_isEnabled || m_consecutiveRuns == kExtrapolationCounterUndefined)
|
||||
return false;
|
||||
|
||||
return AreCoordsGoodForExtrapolation(m_beforeLastGpsInfo, m_lastGpsInfo);
|
||||
|
|
|
@ -10,14 +10,25 @@
|
|||
namespace extrapolation
|
||||
{
|
||||
/// \brief Returns extrapolated position after |point2| in |timeAfterPoint2Ms|.
|
||||
/// \note |timeAfterPoint2Ms| should be relevantly small (several seconds maximum).
|
||||
/// \note |timeAfterPoint2Ms| should be reasonably small (several seconds maximum).
|
||||
location::GpsInfo LinearExtrapolation(location::GpsInfo const & gpsInfo1,
|
||||
location::GpsInfo const & gpsInfo2,
|
||||
uint64_t timeAfterPoint2Ms);
|
||||
|
||||
bool AreCoordsGoodForExtrapolation(location::GpsInfo const & beforeLastGpsInfo,
|
||||
location::GpsInfo const & lastGpsInfo);
|
||||
/// \returns true if linear extrapolation based on |info1| and |info2| should be done.
|
||||
/// \param info1 location information about point gotten before last one.
|
||||
/// \param info2 the latest location information.
|
||||
bool AreCoordsGoodForExtrapolation(location::GpsInfo const & info1,
|
||||
location::GpsInfo const & info2);
|
||||
|
||||
/// \brief This class implements linear extrapolation based on methods LinearExtrapolation()
|
||||
/// and AreCoordsGoodForExtrapolation(). The idea implemented in this class is
|
||||
/// - OnLocationUpdate() should be called from gui thread when new data from gps is available.
|
||||
/// - When OnLocationUpdate() was called twice so that AreCoordsGoodForExtrapolation()
|
||||
/// returns true, extrapolation for this two location will be launched.
|
||||
/// - That means all obsolete extrapolation calls in background thread will be canceled by
|
||||
/// incrementing |m_locationUpdateMinValid|.
|
||||
/// - Several new extrapolations based on two previous locations will be generated.
|
||||
class Extrapolator
|
||||
{
|
||||
static uint64_t constexpr kExtrapolationCounterUndefined = std::numeric_limits<uint64_t>::max();
|
||||
|
@ -48,7 +59,7 @@ private:
|
|||
/// \returns true if there's enough information for extrapolation and extrapolation is enabled.
|
||||
/// \note This method should be called only when |m_mutex| is locked.
|
||||
bool DoesExtrapolationWork() const;
|
||||
void ExtrapolatedLocationUpdate(uint64_t extrapolatedUpdateCounter);
|
||||
void ExtrapolatedLocationUpdate(uint64_t locationUpdateCounter);
|
||||
void RunTaskOnBackgroundThread(bool delayed);
|
||||
|
||||
bool m_isEnabled;
|
||||
|
@ -57,12 +68,14 @@ private:
|
|||
ExtrapolatedLocationUpdateFn m_extrapolatedLocationUpdate;
|
||||
location::GpsInfo m_lastGpsInfo;
|
||||
location::GpsInfo m_beforeLastGpsInfo;
|
||||
uint64_t m_extrapolationCounter = kExtrapolationCounterUndefined;
|
||||
// Number of calls Extrapolator::RunTaskOnBackgroundThread() method.
|
||||
uint64_t m_extrapolatedUpdateCounter = 0;
|
||||
// If |m_extrapolatedUpdateCounter| < |m_extrapolatedUpdateMinValid| when
|
||||
uint64_t m_consecutiveRuns = kExtrapolationCounterUndefined;
|
||||
// Number of calls Extrapolator::OnLocationUpdate() method. This way |m_locationUpdateCounter|
|
||||
// reflects generation of extrapolations. That mean the next gps location is
|
||||
// the next generation.
|
||||
uint64_t m_locationUpdateCounter = 0;
|
||||
// If |m_locationUpdateCounter| < |m_locationUpdateMinValid| when
|
||||
// ExtrapolatedLocationUpdate() is called (on background thread)
|
||||
// ExtrapolatedLocationUpdate() cancels its execution.
|
||||
uint64_t m_extrapolatedUpdateMinValid = 0;
|
||||
uint64_t m_locationUpdateMinValid = 0;
|
||||
};
|
||||
} // namespace extrapolation
|
||||
|
|
|
@ -181,7 +181,8 @@ int main(int argc, char * argv[])
|
|||
{
|
||||
google::SetUsageMessage(
|
||||
"Location extrapolation benchmark. Cumulative moving average, variance and standard "
|
||||
"deviation for all extrapolation deviations from tracks passed in csv with with csv_path.");
|
||||
"deviation for all extrapolation deviations from tracks passed in comma separated csv with "
|
||||
"csv_path.");
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (FLAGS_csv_path.empty())
|
||||
|
@ -224,12 +225,12 @@ int main(int argc, char * argv[])
|
|||
// For all points of each track in |tracks| some extrapolations will be calculated.
|
||||
// The number of extrapolations depends on |Extrapolator::kExtrapolationPeriodMs|
|
||||
// and |Extrapolator::kMaxExtrapolationTimeMs| and equal for all points.
|
||||
// Then cumulative moving average and variance each extrapolation will be printed.
|
||||
// Then cumulative moving average and variance of each extrapolation will be printed.
|
||||
auto const extrapolationNumber = static_cast<size_t>(Extrapolator::kMaxExtrapolationTimeMs /
|
||||
Extrapolator::kExtrapolationPeriodMs);
|
||||
MovingAverageVec mes(extrapolationNumber);
|
||||
MovingAverageVec squareMes(extrapolationNumber);
|
||||
// Number of extrapolations which projections are calculated successfully for.
|
||||
// Number of extrapolations for which projections are calculated successfully.
|
||||
size_t projectionCounter = 0;
|
||||
for (auto const & t : tracks)
|
||||
{
|
||||
|
@ -256,7 +257,7 @@ int main(int argc, char * argv[])
|
|||
|
||||
vector<double> onePointDeviations;
|
||||
vector<double> onePointDeviationsSquared;
|
||||
bool canFindClosestProjection = true;
|
||||
bool projFound = true;
|
||||
for (size_t timeMs = Extrapolator::kExtrapolationPeriodMs;
|
||||
timeMs <= Extrapolator::kMaxExtrapolationTimeMs;
|
||||
timeMs += Extrapolator::kExtrapolationPeriodMs)
|
||||
|
@ -270,10 +271,8 @@ int main(int argc, char * argv[])
|
|||
// which is used calculation of projection in production code.
|
||||
m2::RectD const posSquare = MercatorBounds::MetresToXY(
|
||||
extrapolated.m_longitude, extrapolated.m_latitude, 100.0 /* half square in meters */);
|
||||
// Note 1. One is deducted from polyline size because in GetClosestProjectionInInterval()
|
||||
// One is deducted from polyline size because in GetClosestProjectionInInterval()
|
||||
// is used segment indices but not point indices.
|
||||
// Note 2. Calculating projection of the center of |posRect| to polyline segments which
|
||||
// are inside of |posRect|.
|
||||
auto const & iter = followedPoly.GetClosestProjectionInInterval(
|
||||
posSquare,
|
||||
[&extrapolatedMerc](FollowedPolyline::Iter const & it) {
|
||||
|
@ -290,7 +289,7 @@ int main(int argc, char * argv[])
|
|||
// This situation is possible if |posRect| param of GetClosestProjectionInInterval()
|
||||
// method is too small and there is no segment in |followedPoly|
|
||||
// which is covered by this rect. It's a rare situation.
|
||||
canFindClosestProjection = false;
|
||||
projFound = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -299,7 +298,7 @@ int main(int argc, char * argv[])
|
|||
onePointDeviationsSquared.push_back(distFromPoly * distFromPoly);
|
||||
}
|
||||
|
||||
if (canFindClosestProjection)
|
||||
if (projFound)
|
||||
{
|
||||
CHECK_EQUAL(onePointDeviations.size(), extrapolationNumber, ());
|
||||
mes.Add(onePointDeviations);
|
||||
|
@ -321,7 +320,7 @@ int main(int argc, char * argv[])
|
|||
LOG(LINFO,
|
||||
("Extrapolation", i + 1, ",", Extrapolator::kExtrapolationPeriodMs * (i + 1),
|
||||
"seconds after point two. Cumulative moving average =", mes.Get()[i].Get(), "meters.",
|
||||
"Variance =", max(0.0, variance), ". Standard deviation =", sqrt(variance)));
|
||||
"Variance =", max(0.0, variance), ". Standard deviation =", sqrt(max(0.0, variance))));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -24,14 +24,15 @@ void CmdUnmatchedTracks(string const & logFile, string const & trackFileCsv)
|
|||
MwmToTracks mwmToTracks;
|
||||
ParseTracks(logFile, numMwmIds, storage, mwmToTracks);
|
||||
|
||||
string const sep = ",";
|
||||
ofstream ofs(trackFileCsv, std::ofstream::out);
|
||||
for (auto const & kv : mwmToTracks)
|
||||
{
|
||||
for (auto const & idTrack : kv.second)
|
||||
{
|
||||
ofs << numMwmIds->GetFile(kv.first).GetName() << ", " << idTrack.first;
|
||||
ofs << numMwmIds->GetFile(kv.first).GetName() << sep << idTrack.first;
|
||||
for (auto const & pnt : idTrack.second)
|
||||
ofs << ", " << pnt.m_timestamp << ", " << pnt.m_latLon.lat << ", " << pnt.m_latLon.lon;
|
||||
ofs << sep << pnt.m_timestamp << sep << pnt.m_latLon.lat << sep << pnt.m_latLon.lon;
|
||||
ofs << "\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ namespace
|
|||
DEFINE_string_ext(cmd, "",
|
||||
"command:\n"
|
||||
"match - based on raw logs gathers points to tracks and matches them to "
|
||||
"features. To use the tool raw logs should be taken from \"trafin\" project "
|
||||
"production in gz files and extracted.\n"
|
||||
"features. To use the tool raw logs should be taken from \"trafin\" production "
|
||||
"project in gz files and extracted.\n"
|
||||
"unmatched_tracks - based on raw logs gathers points to tracks\n"
|
||||
"and save tracks to csv. Track points save as lat, log, timestamp in seconds\n"
|
||||
"tracks - prints track statistics\n"
|
||||
|
|
Loading…
Add table
Reference in a new issue