Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Pimenov <m@maps.me>2016-10-28 20:14:18 +0300
committerMaxim Pimenov <m@maps.me>2016-11-08 16:42:21 +0300
commitc796ec6f5797d6fd95c95e8c9eb2d59df7434b2a (patch)
tree269c1a90b2f09b1e979fa5dd93a9624be248dbad /traffic
parent77269ecfb0650a3f51995831c4d5917b8d7cc244 (diff)
[tracking] A wasteful version of the traffic data receiver.
Diffstat (limited to 'traffic')
-rw-r--r--traffic/CMakeLists.txt13
-rw-r--r--traffic/speed_groups.cpp22
-rw-r--r--traffic/speed_groups.hpp41
-rw-r--r--traffic/traffic.pro15
-rw-r--r--traffic/traffic_info.cpp132
-rw-r--r--traffic/traffic_info.hpp70
-rw-r--r--traffic/traffic_tests/traffic_info_test.cpp52
-rw-r--r--traffic/traffic_tests/traffic_tests.pro29
8 files changed, 374 insertions, 0 deletions
diff --git a/traffic/CMakeLists.txt b/traffic/CMakeLists.txt
new file mode 100644
index 0000000000..40ac62dd71
--- /dev/null
+++ b/traffic/CMakeLists.txt
@@ -0,0 +1,13 @@
+project(traffic)
+
+set(
+ SRC
+ speed_groups.cpp
+ speed_groups.hpp
+ traffic_info.cpp
+ traffic_info.hpp
+)
+
+add_library(${PROJECT_NAME} ${SRC})
+
+add_subdirectory(traffic_tests)
diff --git a/traffic/speed_groups.cpp b/traffic/speed_groups.cpp
new file mode 100644
index 0000000000..dd1d22f964
--- /dev/null
+++ b/traffic/speed_groups.cpp
@@ -0,0 +1,22 @@
+#include "traffic/speed_groups.hpp"
+
+namespace traffic
+{
+uint32_t const kSpeedGroupThresholdPercentage[] = {8, 16, 33, 58, 83, 100, 100, 100};
+
+string DebugPrint(SpeedGroup const & group)
+{
+ switch (group)
+ {
+ case SpeedGroup::G0: return "G0";
+ case SpeedGroup::G1: return "G1";
+ case SpeedGroup::G2: return "G2";
+ case SpeedGroup::G3: return "G3";
+ case SpeedGroup::G4: return "G4";
+ case SpeedGroup::G5: return "G5";
+ case SpeedGroup::TempBlock: return "TempBlock";
+ case SpeedGroup::Unknown: return "Unknown";
+ case SpeedGroup::Count: return "Count";
+ }
+}
+} // namespace traffic
diff --git a/traffic/speed_groups.hpp b/traffic/speed_groups.hpp
new file mode 100644
index 0000000000..be18ea0634
--- /dev/null
+++ b/traffic/speed_groups.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "std/cstdint.hpp"
+#include "std/string.hpp"
+
+namespace traffic
+{
+enum class SpeedGroup : uint8_t
+{
+ G0 = 0,
+ G1,
+ G2,
+ G3,
+ G4,
+ G5,
+ TempBlock,
+ Unknown,
+ Count
+};
+
+static_assert(static_cast<uint8_t>(SpeedGroup::Count) <= 8, "");
+
+// Let M be the maximal speed that is possible on a free road
+// and let V be the maximal speed that is possible on this road when
+// taking the traffic data into account.
+// We group all possible ratios (V/M) into a small number of
+// buckets and only use the number of a bucket everywhere.
+// That is, we forget the specific values of V when transmitting and
+// displaying traffic information. The value M of a road is known at the
+// stage of building the mwm containing this road.
+//
+// kSpeedGroupThresholdPercentage[g] denotes the maximal value of (V/M)
+// that is possible for group |g|. Values falling on a border of two groups
+// may belong to either group.
+//
+// The threshold percentage is defined to be 100 for the
+// special groups where V is unknown or not defined.
+extern uint32_t const kSpeedGroupThresholdPercentage[static_cast<size_t>(SpeedGroup::Count)];
+
+string DebugPrint(SpeedGroup const & group);
+} // namespace traffic
diff --git a/traffic/traffic.pro b/traffic/traffic.pro
new file mode 100644
index 0000000000..ecacd5f855
--- /dev/null
+++ b/traffic/traffic.pro
@@ -0,0 +1,15 @@
+TARGET = traffic
+TEMPLATE = lib
+CONFIG += staticlib warn_on
+
+ROOT_DIR = ..
+
+include($$ROOT_DIR/common.pri)
+
+SOURCES += \
+ speed_groups.cpp \
+ traffic_info.cpp \
+
+HEADERS += \
+ speed_groups.hpp \
+ traffic_info.hpp \
diff --git a/traffic/traffic_info.cpp b/traffic/traffic_info.cpp
new file mode 100644
index 0000000000..ef233b6538
--- /dev/null
+++ b/traffic/traffic_info.cpp
@@ -0,0 +1,132 @@
+#include "traffic/traffic_info.hpp"
+
+#include "platform/http_client.hpp"
+
+#include "coding/bit_streams.hpp"
+#include "coding/reader.hpp"
+#include "coding/varint.hpp"
+#include "coding/write_to_sink.hpp"
+#include "coding/writer.hpp"
+
+#include "base/assert.hpp"
+#include "base/logging.hpp"
+
+#include "std/algorithm.hpp"
+#include "std/string.hpp"
+
+#include "private.h"
+
+namespace traffic
+{
+namespace
+{
+char const kTestFileName[] = "traffic_data";
+
+bool ReadRemoteFile(string const & url, vector<uint8_t> & result)
+{
+ platform::HttpClient request(url);
+ if (!request.RunHttpRequest() || request.ErrorCode() != 200)
+ return false;
+ string const & response = request.ServerResponse();
+ result.resize(response.size());
+ for (size_t i = 0; i < response.size(); ++i)
+ result[i] = static_cast<uint8_t>(response[i]);
+ return true;
+}
+} // namespace
+
+// TrafficInfo::RoadSegmentId -----------------------------------------------------------------
+TrafficInfo::RoadSegmentId::RoadSegmentId() : m_fid(0), m_idx(0), m_dir(0) {}
+
+TrafficInfo::RoadSegmentId::RoadSegmentId(uint32_t fid, uint16_t idx, uint8_t dir)
+ : m_fid(fid), m_idx(idx), m_dir(dir)
+{
+}
+
+// TrafficInfo --------------------------------------------------------------------------------
+TrafficInfo::TrafficInfo(MwmSet::MwmId const & mwmId) : m_mwmId(mwmId) {}
+
+bool TrafficInfo::ReceiveTrafficData()
+{
+ if (strlen(TRAFFIC_DATA_BASE_URL) == 0)
+ return false;
+
+ string const url = string(TRAFFIC_DATA_BASE_URL) + string(kTestFileName);
+ vector<uint8_t> contents;
+ if (!ReadRemoteFile(url, contents))
+ return false;
+
+ Coloring coloring;
+ try
+ {
+ DeserializeTrafficData(contents, coloring);
+ }
+ catch (Reader::Exception const & e)
+ {
+ LOG(LINFO, ("Could not read traffic data received from server."));
+ return false;
+ }
+ m_coloring.swap(coloring);
+ return true;
+}
+
+SpeedGroup TrafficInfo::GetSpeedGroup(RoadSegmentId const & id) const
+{
+ auto const it = m_coloring.find(id);
+ if (it == m_coloring.cend())
+ return SpeedGroup::Unknown;
+ return it->second;
+}
+
+// static
+void TrafficInfo::SerializeTrafficData(Coloring const & coloring, vector<uint8_t> & result)
+{
+ MemWriter<vector<uint8_t>> memWriter(result);
+ WriteToSink(memWriter, static_cast<uint32_t>(coloring.size()));
+ for (auto const & p : coloring)
+ {
+ WriteVarUint(memWriter, p.first.m_fid);
+ uint16_t const x = (p.first.m_idx << 1) | p.first.m_dir;
+ WriteVarUint(memWriter, x);
+ }
+ {
+ BitWriter<decltype(memWriter)> bitWriter(memWriter);
+ for (auto const & p : coloring)
+ {
+ // SpeedGroup's values fit into 3 bits.
+ bitWriter.Write(static_cast<uint8_t>(p.second), 3);
+ }
+ }
+}
+
+// static
+void TrafficInfo::DeserializeTrafficData(vector<uint8_t> const & data, Coloring & coloring)
+{
+ MemReader memReader(data.data(), data.size());
+ ReaderSource<decltype(memReader)> src(memReader);
+ auto const n = ReadPrimitiveFromSource<uint32_t>(src);
+
+ vector<RoadSegmentId> keys(n);
+ for (size_t i = 0; i < static_cast<size_t>(n); ++i)
+ {
+ keys[i].m_fid = ReadVarUint<uint32_t>(src);
+ auto const x = ReadVarUint<uint32_t>(src);
+ keys[i].m_idx = static_cast<uint16_t>(x >> 1);
+ keys[i].m_dir = static_cast<uint8_t>(x & 1);
+ }
+
+ vector<SpeedGroup> values(n);
+ BitReader<decltype(src)> bitReader(src);
+ for (size_t i = 0; i < static_cast<size_t>(n); ++i)
+ {
+ // SpeedGroup's values fit into 3 bits.
+ values[i] = static_cast<SpeedGroup>(bitReader.Read(3));
+ }
+
+ coloring.clear();
+ for (size_t i = 0; i < static_cast<size_t>(n); ++i)
+ coloring[keys[i]] = values[i];
+
+ ASSERT_EQUAL(src.Size(), 0, ());
+}
+} // namespace traffic
diff --git a/traffic/traffic_info.hpp b/traffic/traffic_info.hpp
new file mode 100644
index 0000000000..90bcdab50f
--- /dev/null
+++ b/traffic/traffic_info.hpp
@@ -0,0 +1,70 @@
+#pragma once
+
+#include "traffic/speed_groups.hpp"
+
+#include "indexer/mwm_set.hpp"
+
+#include "std/cstdint.hpp"
+#include "std/map.hpp"
+#include "std/vector.hpp"
+
+namespace traffic
+{
+// This class is responsible for providing the real-time
+// information about road traffic for one mwm file.
+class TrafficInfo
+{
+public:
+ struct RoadSegmentId
+ {
+ RoadSegmentId();
+
+ RoadSegmentId(uint32_t fid, uint16_t idx, uint8_t dir);
+
+ bool operator<(RoadSegmentId const & o) const
+ {
+ if (m_fid != o.m_fid)
+ return m_fid < o.m_fid;
+ if (m_idx != o.m_idx)
+ return m_idx < o.m_idx;
+ return m_dir < o.m_dir;
+ }
+
+ // The ordinal number of feature this segment belongs to.
+ uint32_t m_fid;
+
+ // The ordinal number of this segment in the list of
+ // its feature's segments.
+ uint16_t m_idx : 15;
+
+ // The direction of the segment.
+ // todo(@m) Write up what the values 0 and 1 mean specifically.
+ uint8_t m_dir : 1;
+ };
+
+ // todo(@m) unordered_map?
+ using Coloring = map<RoadSegmentId, SpeedGroup>;
+
+ TrafficInfo() = default;
+
+ TrafficInfo(MwmSet::MwmId const & mwmId);
+
+ // Fetches the latest traffic data from the server and updates the coloring.
+ // todo(@m, @syershov) Currently a hardcoded path is used.
+ // Construct the url by passing an MwmId.
+ // *NOTE* This method must not be called on the UI thread.
+ bool ReceiveTrafficData();
+
+ // Returns the latest known speed group by a feature segment's id.
+ SpeedGroup GetSpeedGroup(RoadSegmentId const & id) const;
+
+ static void SerializeTrafficData(Coloring const & coloring, vector<uint8_t> & result);
+
+ static void DeserializeTrafficData(vector<uint8_t> const & data, Coloring & coloring);
+
+private:
+ // The mapping from feature segments to speed groups (see speed_groups.hpp).
+ Coloring m_coloring;
+ MwmSet::MwmId m_mwmId;
+};
+} // namespace traffic
diff --git a/traffic/traffic_tests/traffic_info_test.cpp b/traffic/traffic_tests/traffic_info_test.cpp
new file mode 100644
index 0000000000..3efbcd7e35
--- /dev/null
+++ b/traffic/traffic_tests/traffic_info_test.cpp
@@ -0,0 +1,52 @@
+#include "testing/testing.hpp"
+
+#include "traffic/speed_groups.hpp"
+#include "traffic/traffic_info.hpp"
+
+#include "std/algorithm.hpp"
+
+namespace traffic
+{
+namespace
+{
+SpeedGroup GetSpeedGroup(TrafficInfo::Coloring const & coloring,
+ TrafficInfo::RoadSegmentId const & fid)
+{
+ auto const it = coloring.find(fid);
+ if (it == coloring.cend())
+ return SpeedGroup::Unknown;
+ return it->second;
+}
+} // namespace
+
+UNIT_TEST(TrafficInfo_RemoteFile)
+{
+ TrafficInfo r;
+ TEST(r.ReceiveTrafficData(), ());
+}
+
+UNIT_TEST(TrafficInfo_Serialization)
+{
+ TrafficInfo::Coloring coloring = {
+ {TrafficInfo::RoadSegmentId(0, 0, 0), SpeedGroup::G0},
+ {TrafficInfo::RoadSegmentId(1000, 1, 1), SpeedGroup::G1},
+ {TrafficInfo::RoadSegmentId(1000000, 0, 0), SpeedGroup::G5},
+ {TrafficInfo::RoadSegmentId(4294967295, 32767, 1), SpeedGroup::TempBlock},
+ };
+
+ vector<uint8_t> buf;
+ TrafficInfo::SerializeTrafficData(coloring, buf);
+
+ TrafficInfo::Coloring deserializedColoring;
+ TrafficInfo::DeserializeTrafficData(buf, deserializedColoring);
+
+ TEST_EQUAL(coloring.size(), deserializedColoring.size(), ());
+
+ for (auto const & p : coloring)
+ {
+ auto const g1 = p.second;
+ auto const g2 = GetSpeedGroup(deserializedColoring, p.first);
+ TEST_EQUAL(g1, g2, ());
+ }
+}
+} // namespace traffic
diff --git a/traffic/traffic_tests/traffic_tests.pro b/traffic/traffic_tests/traffic_tests.pro
new file mode 100644
index 0000000000..5a99696570
--- /dev/null
+++ b/traffic/traffic_tests/traffic_tests.pro
@@ -0,0 +1,29 @@
+TARGET = traffic_tests
+CONFIG += console warn_on
+CONFIG -= app_bundle
+TEMPLATE = app
+
+ROOT_DIR = ../..
+
+INCLUDEPATH *= $$ROOT_DIR/3party/jansson/src
+
+DEPENDENCIES = routing traffic indexer platform_tests_support platform coding geometry base stats_client tomcrypt
+
+include($$ROOT_DIR/common.pri)
+
+DEFINES *= OMIM_UNIT_TEST_WITH_QT_EVENT_LOOP
+
+QT *= core
+
+macx-* {
+ QT *= widgets # needed for QApplication with event loop, to test async events
+ LIBS *= "-framework IOKit" "-framework SystemConfiguration"
+}
+
+win*|linux* {
+ QT *= network
+}
+
+SOURCES += \
+ $$ROOT_DIR/testing/testingmain.cpp \
+ traffic_info_test.cpp \