diff options
author | r.kuznetsov <r.kuznetsov@corp.mail.ru> | 2017-04-11 14:54:27 +0300 |
---|---|---|
committer | r.kuznetsov <r.kuznetsov@corp.mail.ru> | 2017-04-11 15:55:41 +0300 |
commit | 6fa3e50e060259d40a8d7427687d1d3ce759d453 (patch) | |
tree | bca5a2d4487994b242b765266f31e11900685ab9 /coding | |
parent | 1a9b2ef125a1d4dbbf5e96d8990becebb9d2234c (diff) |
Moved point-to-integer to coding
Diffstat (limited to 'coding')
-rw-r--r-- | coding/CMakeLists.txt | 2 | ||||
-rw-r--r-- | coding/coding.pro | 2 | ||||
-rw-r--r-- | coding/coding_tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | coding/coding_tests/coding_tests.pro | 1 | ||||
-rw-r--r-- | coding/coding_tests/point_to_integer_test.cpp | 112 | ||||
-rw-r--r-- | coding/point_to_integer.cpp | 83 | ||||
-rw-r--r-- | coding/point_to_integer.hpp | 33 | ||||
-rw-r--r-- | coding/traffic.cpp | 13 | ||||
-rw-r--r-- | coding/traffic.hpp | 57 |
9 files changed, 263 insertions, 41 deletions
diff --git a/coding/CMakeLists.txt b/coding/CMakeLists.txt index 908c2d0fb6..f8d9cd9f6f 100644 --- a/coding/CMakeLists.txt +++ b/coding/CMakeLists.txt @@ -53,6 +53,8 @@ set( multilang_utf8_string.cpp multilang_utf8_string.hpp parse_xml.hpp + point_to_integer.cpp + point_to_integer.hpp polymorph_reader.hpp read_write_utils.hpp reader.cpp diff --git a/coding/coding.pro b/coding/coding.pro index 94ead8140d..a6f03f95c4 100644 --- a/coding/coding.pro +++ b/coding/coding.pro @@ -22,6 +22,7 @@ SOURCES += \ internal/file_data.cpp \ mmap_reader.cpp \ multilang_utf8_string.cpp \ + point_to_integer.cpp \ reader.cpp \ reader_streambuf.cpp \ reader_writer_ops.cpp \ @@ -67,6 +68,7 @@ HEADERS += \ mmap_reader.hpp \ multilang_utf8_string.hpp \ parse_xml.hpp \ + point_to_integer.hpp \ polymorph_reader.hpp \ read_write_utils.hpp \ reader.hpp \ diff --git a/coding/coding_tests/CMakeLists.txt b/coding/coding_tests/CMakeLists.txt index c4a2d1eb81..944730f8c7 100644 --- a/coding/coding_tests/CMakeLists.txt +++ b/coding/coding_tests/CMakeLists.txt @@ -24,6 +24,7 @@ set( mem_file_writer_test.cpp multilang_utf8_string_test.cpp png_decoder_test.cpp + point_to_integer_test.cpp reader_cache_test.cpp reader_test.cpp reader_test.hpp diff --git a/coding/coding_tests/coding_tests.pro b/coding/coding_tests/coding_tests.pro index 232d5eac79..20bf404214 100644 --- a/coding/coding_tests/coding_tests.pro +++ b/coding/coding_tests/coding_tests.pro @@ -32,6 +32,7 @@ SOURCES += ../../testing/testingmain.cpp \ mem_file_writer_test.cpp \ multilang_utf8_string_test.cpp \ png_decoder_test.cpp \ + point_to_integer_test.cpp \ reader_cache_test.cpp \ reader_test.cpp \ reader_writer_ops_test.cpp \ diff --git a/coding/coding_tests/point_to_integer_test.cpp b/coding/coding_tests/point_to_integer_test.cpp new file mode 100644 index 0000000000..6b871818b4 --- /dev/null +++ b/coding/coding_tests/point_to_integer_test.cpp @@ -0,0 +1,112 @@ +#include "testing/testing.hpp" + +#include "coding/point_to_integer.hpp" + +#include "geometry/mercator.hpp" + +#include "base/logging.hpp" + +#include "std/cmath.hpp" +#include "std/utility.hpp" + +namespace +{ +double const g_eps = MercatorBounds::GetCellID2PointAbsEpsilon(); +uint32_t const g_coordBits = POINT_COORD_BITS; + +void CheckEqualPoints(m2::PointD const & p1, m2::PointD const & p2) +{ + TEST(p1.EqualDxDy(p2, g_eps), (p1, p2)); + + TEST_GREATER_OR_EQUAL(p1.x, -180.0, ()); + TEST_GREATER_OR_EQUAL(p1.y, -180.0, ()); + TEST_LESS_OR_EQUAL(p1.x, 180.0, ()); + TEST_LESS_OR_EQUAL(p1.y, 180.0, ()); + + TEST_GREATER_OR_EQUAL(p2.x, -180.0, ()); + TEST_GREATER_OR_EQUAL(p2.y, -180.0, ()); + TEST_LESS_OR_EQUAL(p2.x, 180.0, ()); + TEST_LESS_OR_EQUAL(p2.y, 180.0, ()); +} +} + +UNIT_TEST(PointToInt64_Smoke) +{ + m2::PointD const arr[] = {{1.25, 1.3}, {180, 90}, {-180, -90}, {0, 0}}; + + for (size_t i = 0; i < ARRAY_SIZE(arr); ++i) + CheckEqualPoints(arr[i], Int64ToPoint(PointToInt64(arr[i], g_coordBits), g_coordBits)); +} + +UNIT_TEST(PointToInt64_Grid) +{ + int const delta = 5; + for (int ix = -180; ix <= 180; ix += delta) + for (int iy = -180; iy <= 180; iy += delta) + { + m2::PointD const pt(ix, iy); + int64_t const id = PointToInt64(pt, g_coordBits); + m2::PointD const pt1 = Int64ToPoint(id, g_coordBits); + + CheckEqualPoints(pt, pt1); + + int64_t const id1 = PointToInt64(pt1, g_coordBits); + TEST_EQUAL(id, id1, (pt, pt1)); + } +} + +UNIT_TEST(PointToInt64_Bounds) +{ + double const arrEps[] = {-1.0E-2, -1.0E-3, -1.0E-4, 0, 1.0E-4, 1.0E-3, 1.0E-2}; + + m2::PointD const arrPt[] = {{0, 0}, {-180, -180}, {-180, 180}, {180, 180}, {180, -180}, + {-90, -90}, {-90, 90}, {90, 90}, {90, -90}}; + + for (size_t iP = 0; iP < ARRAY_SIZE(arrPt); ++iP) + for (size_t iX = 0; iX < ARRAY_SIZE(arrEps); ++iX) + for (size_t iY = 0; iY < ARRAY_SIZE(arrEps); ++iY) + { + m2::PointD const pt(arrPt[iP].x + arrEps[iX], arrPt[iP].y + arrEps[iY]); + m2::PointD const pt1 = Int64ToPoint(PointToInt64(pt, g_coordBits), g_coordBits); + + TEST(fabs(pt.x - pt1.x) <= (fabs(arrEps[iX]) + g_eps) && + fabs(pt.y - pt1.y) <= (fabs(arrEps[iY]) + g_eps), + (pt, pt1)); + } +} + +UNIT_TEST(PointD2PointU_Epsilons) +{ + m2::PointD const arrPt[] = {{-180, -180}, {-180, 180}, {180, 180}, {180, -180}}; + m2::PointD const arrD[] = {{1, 1}, {1, -1}, {-1, -1}, {-1, 1}}; + size_t const count = ARRAY_SIZE(arrPt); + + /* + double eps = 1.0; + for (; true; eps = eps / 10.0) + { + size_t i = 0; + for (; i < count; ++i) + { + m2::PointU p = PointD2PointU(arrPt[i].x, arrPt[i].y, g_coordBits); + m2::PointU p1 = PointD2PointU(arrPt[i].x + arrD[i].x * eps, + arrPt[i].y + arrD[i].y * eps, + g_coordBits); + + if (p != p1) break; + } + if (i == count) break; + } + + LOG(LINFO, ("Epsilon = ", eps)); + */ + + for (size_t i = 0; i < count; ++i) + { + m2::PointU const p1 = PointD2PointU(arrPt[i].x, arrPt[i].y, g_coordBits); + m2::PointU const p2(p1.x + arrD[i].x, p1.y + arrD[i].y); + m2::PointD const p3 = PointU2PointD(p2, g_coordBits); + + LOG(LINFO, ("Dx = ", p3.x - arrPt[i].x, "Dy = ", p3.y - arrPt[i].y)); + } +} diff --git a/coding/point_to_integer.cpp b/coding/point_to_integer.cpp new file mode 100644 index 0000000000..f1a9044134 --- /dev/null +++ b/coding/point_to_integer.cpp @@ -0,0 +1,83 @@ +#include "coding/point_to_integer.hpp" + +#include "geometry/mercator.hpp" +#include "geometry/pointu_to_uint64.hpp" + +#include "base/bits.hpp" + +#include <algorithm> + +namespace +{ +inline double CoordSize(uint32_t coordBits) { return (1 << coordBits) - 1; } +} + +m2::PointU PointD2PointU(double x, double y, uint32_t coordBits) +{ + x = my::clamp(x, MercatorBounds::minX, MercatorBounds::maxX); + y = my::clamp(y, MercatorBounds::minY, MercatorBounds::maxY); + + uint32_t const ix = static_cast<uint32_t>(0.5 + + (x - MercatorBounds::minX) / + (MercatorBounds::maxX - MercatorBounds::minX) * + CoordSize(coordBits)); + uint32_t const iy = static_cast<uint32_t>(0.5 + + (y - MercatorBounds::minY) / + (MercatorBounds::maxY - MercatorBounds::minY) * + CoordSize(coordBits)); + + ASSERT_LESS_OR_EQUAL(ix, CoordSize(coordBits), ()); + ASSERT_LESS_OR_EQUAL(iy, CoordSize(coordBits), ()); + + return m2::PointU(ix, iy); +} + +int64_t PointToInt64(double x, double y, uint32_t coordBits) +{ + int64_t const res = static_cast<int64_t>(m2::PointUToUint64(PointD2PointU(x, y, coordBits))); + + ASSERT_LESS_OR_EQUAL(res, 3ULL << 2 * POINT_COORD_BITS, ()); + ASSERT_GREATER_OR_EQUAL(res, 0, ("Highest bits of (ix, iy) are not used, so res should be > 0.")); + return res; +} + +m2::PointD PointU2PointD(m2::PointU const & pt, uint32_t coordBits) +{ + return m2::PointD(static_cast<double>(pt.x) * (MercatorBounds::maxX - MercatorBounds::minX) / + CoordSize(coordBits) + + MercatorBounds::minX, + static_cast<double>(pt.y) * (MercatorBounds::maxY - MercatorBounds::minY) / + CoordSize(coordBits) + + MercatorBounds::minY); +} + +m2::PointD Int64ToPoint(int64_t v, uint32_t coordBits) +{ + ASSERT_LESS_OR_EQUAL(v, 3ULL << 2 * POINT_COORD_BITS, ()); + return PointU2PointD(m2::Uint64ToPointU(static_cast<uint64_t>(v)), coordBits); +} + +std::pair<int64_t, int64_t> RectToInt64(m2::RectD const & r, uint32_t coordBits) +{ + int64_t const p1 = PointToInt64(r.minX(), r.minY(), coordBits); + int64_t const p2 = PointToInt64(r.maxX(), r.maxY(), coordBits); + return std::make_pair(p1, p2); +} + +m2::RectD Int64ToRect(std::pair<int64_t, int64_t> const & p, uint32_t coordBits) +{ + m2::PointD const pt1 = Int64ToPoint(p.first, coordBits); + m2::PointD const pt2 = Int64ToPoint(p.second, coordBits); + return m2::RectD(pt1, pt2); +} + +uint32_t DoubleToUint32(double x, double min, double max, uint32_t coordBits) +{ + x = my::clamp(x, min, max); + return static_cast<uint32_t>(0.5 + (x - min) / (max - min) * ((1 << coordBits) - 1)); +} + +double Uint32ToDouble(uint32_t x, double min, double max, uint32_t coordBits) +{ + return min + static_cast<double>(x) * (max - min) / ((1 << coordBits) - 1); +} diff --git a/coding/point_to_integer.hpp b/coding/point_to_integer.hpp new file mode 100644 index 0000000000..068dd65193 --- /dev/null +++ b/coding/point_to_integer.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "geometry/cellid.hpp" +#include "geometry/rect2d.hpp" + +#include <utility> + +#define POINT_COORD_BITS 30 + +typedef m2::CellId<19> RectId; + +m2::PointU PointD2PointU(double x, double y, uint32_t coordBits); +inline m2::PointU PointD2PointU(m2::PointD const & pt, uint32_t coordBits) +{ + return PointD2PointU(pt.x, pt.y, coordBits); +} + +m2::PointD PointU2PointD(m2::PointU const & p, uint32_t coordBits); + +int64_t PointToInt64(double x, double y, uint32_t coordBits); +inline int64_t PointToInt64(m2::PointD const & pt, uint32_t coordBits) +{ + return PointToInt64(pt.x, pt.y, coordBits); +} + +m2::PointD Int64ToPoint(int64_t v, uint32_t coordBits); + +std::pair<int64_t, int64_t> RectToInt64(m2::RectD const & r, uint32_t coordBits); +m2::RectD Int64ToRect(std::pair<int64_t, int64_t> const & p, uint32_t coordBits); + +uint32_t DoubleToUint32(double x, double min, double max, uint32_t coordBits); + +double Uint32ToDouble(uint32_t x, double min, double max, uint32_t coordBits); diff --git a/coding/traffic.cpp b/coding/traffic.cpp index aa34a40711..4894bcbf6a 100644 --- a/coding/traffic.cpp +++ b/coding/traffic.cpp @@ -11,17 +11,4 @@ double const TrafficGPSEncoder::kMinDeltaLat = ms::LatLon::kMinLat - ms::LatLon: double const TrafficGPSEncoder::kMaxDeltaLat = ms::LatLon::kMaxLat - ms::LatLon::kMinLat; double const TrafficGPSEncoder::kMinDeltaLon = ms::LatLon::kMinLon - ms::LatLon::kMaxLon; double const TrafficGPSEncoder::kMaxDeltaLon = ms::LatLon::kMaxLon - ms::LatLon::kMinLon; - -// static -uint32_t TrafficGPSEncoder::DoubleToUint32(double x, double min, double max) -{ - x = my::clamp(x, min, max); - return static_cast<uint32_t>(0.5 + (x - min) / (max - min) * ((1 << kCoordBits) - 1)); -} - -// static -double TrafficGPSEncoder::Uint32ToDouble(uint32_t x, double min, double max) -{ - return min + static_cast<double>(x) * (max - min) / ((1 << kCoordBits) - 1); -} } // namespace coding diff --git a/coding/traffic.hpp b/coding/traffic.hpp index 0df9ee0a64..216590b4da 100644 --- a/coding/traffic.hpp +++ b/coding/traffic.hpp @@ -1,5 +1,6 @@ #pragma once +#include "coding/point_to_integer.hpp" #include "coding/reader.hpp" #include "coding/varint.hpp" #include "coding/writer.hpp" @@ -79,10 +80,6 @@ public: } private: - static uint32_t DoubleToUint32(double x, double min, double max); - - static double Uint32ToDouble(uint32_t x, double min, double max); - template <typename Writer, typename Collection> static size_t SerializeDataPointsV0(Writer & writer, Collection const & points) { @@ -91,10 +88,10 @@ private: if (!points.empty()) { uint64_t const firstTimestamp = points[0].m_timestamp; - uint32_t const firstLat = - DoubleToUint32(points[0].m_latLon.lat, ms::LatLon::kMinLat, ms::LatLon::kMaxLat); - uint32_t const firstLon = - DoubleToUint32(points[0].m_latLon.lon, ms::LatLon::kMinLon, ms::LatLon::kMaxLon); + uint32_t const firstLat = DoubleToUint32(points[0].m_latLon.lat, ms::LatLon::kMinLat, + ms::LatLon::kMaxLat, kCoordBits); + uint32_t const firstLon = DoubleToUint32(points[0].m_latLon.lon, ms::LatLon::kMinLon, + ms::LatLon::kMaxLon, kCoordBits); WriteVarUint(writer, firstTimestamp); WriteVarUint(writer, firstLat); WriteVarUint(writer, firstLon); @@ -106,9 +103,9 @@ private: uint64_t const deltaTimestamp = points[i].m_timestamp - points[i - 1].m_timestamp; uint32_t deltaLat = DoubleToUint32(points[i].m_latLon.lat - points[i - 1].m_latLon.lat, - kMinDeltaLat, kMaxDeltaLat); + kMinDeltaLat, kMaxDeltaLat, kCoordBits); uint32_t deltaLon = DoubleToUint32(points[i].m_latLon.lon - points[i - 1].m_latLon.lon, - kMinDeltaLon, kMaxDeltaLon); + kMinDeltaLon, kMaxDeltaLon, kCoordBits); WriteVarUint(writer, deltaTimestamp); WriteVarUint(writer, deltaLat); @@ -128,10 +125,10 @@ private: if (!points.empty()) { uint64_t const firstTimestamp = points[0].m_timestamp; - uint32_t const firstLat = - DoubleToUint32(points[0].m_latLon.lat, ms::LatLon::kMinLat, ms::LatLon::kMaxLat); - uint32_t const firstLon = - DoubleToUint32(points[0].m_latLon.lon, ms::LatLon::kMinLon, ms::LatLon::kMaxLon); + uint32_t const firstLat = DoubleToUint32(points[0].m_latLon.lat, ms::LatLon::kMinLat, + ms::LatLon::kMaxLat, kCoordBits); + uint32_t const firstLon = DoubleToUint32(points[0].m_latLon.lon, ms::LatLon::kMinLon, + ms::LatLon::kMaxLon, kCoordBits); uint32_t const traffic = points[0].m_traffic; WriteVarUint(writer, firstTimestamp); WriteVarUint(writer, firstLat); @@ -145,9 +142,9 @@ private: uint64_t const deltaTimestamp = points[i].m_timestamp - points[i - 1].m_timestamp; uint32_t deltaLat = DoubleToUint32(points[i].m_latLon.lat - points[i - 1].m_latLon.lat, - kMinDeltaLat, kMaxDeltaLat); + kMinDeltaLat, kMaxDeltaLat, kCoordBits); uint32_t deltaLon = DoubleToUint32(points[i].m_latLon.lon - points[i - 1].m_latLon.lon, - kMinDeltaLon, kMaxDeltaLon); + kMinDeltaLon, kMaxDeltaLon, kCoordBits); uint32_t const traffic = points[i - 1].m_traffic; WriteVarUint(writer, deltaTimestamp); @@ -175,18 +172,20 @@ private: if (first) { lastTimestamp = ReadVarUint<uint64_t>(src); - lastLat = - Uint32ToDouble(ReadVarUint<uint32_t>(src), ms::LatLon::kMinLat, ms::LatLon::kMaxLat); - lastLon = - Uint32ToDouble(ReadVarUint<uint32_t>(src), ms::LatLon::kMinLon, ms::LatLon::kMaxLon); + lastLat = Uint32ToDouble(ReadVarUint<uint32_t>(src), ms::LatLon::kMinLat, + ms::LatLon::kMaxLat, kCoordBits); + lastLon = Uint32ToDouble(ReadVarUint<uint32_t>(src), ms::LatLon::kMinLon, + ms::LatLon::kMaxLon, kCoordBits); result.emplace_back(lastTimestamp, ms::LatLon(lastLat, lastLon), traffic); first = false; } else { lastTimestamp += ReadVarUint<uint64_t>(src); - lastLat += Uint32ToDouble(ReadVarUint<uint32_t>(src), kMinDeltaLat, kMaxDeltaLat); - lastLon += Uint32ToDouble(ReadVarUint<uint32_t>(src), kMinDeltaLon, kMaxDeltaLon); + lastLat += + Uint32ToDouble(ReadVarUint<uint32_t>(src), kMinDeltaLat, kMaxDeltaLat, kCoordBits); + lastLon += + Uint32ToDouble(ReadVarUint<uint32_t>(src), kMinDeltaLon, kMaxDeltaLon, kCoordBits); result.emplace_back(lastTimestamp, ms::LatLon(lastLat, lastLon), traffic); } } @@ -206,10 +205,10 @@ private: if (first) { lastTimestamp = ReadVarUint<uint64_t>(src); - lastLat = - Uint32ToDouble(ReadVarUint<uint32_t>(src), ms::LatLon::kMinLat, ms::LatLon::kMaxLat); - lastLon = - Uint32ToDouble(ReadVarUint<uint32_t>(src), ms::LatLon::kMinLon, ms::LatLon::kMaxLon); + lastLat = Uint32ToDouble(ReadVarUint<uint32_t>(src), ms::LatLon::kMinLat, + ms::LatLon::kMaxLat, kCoordBits); + lastLon = Uint32ToDouble(ReadVarUint<uint32_t>(src), ms::LatLon::kMinLon, + ms::LatLon::kMaxLon, kCoordBits); traffic = base::asserted_cast<uint8_t>(ReadVarUint<uint32_t>(src)); result.emplace_back(lastTimestamp, ms::LatLon(lastLat, lastLon), traffic); first = false; @@ -217,8 +216,10 @@ private: else { lastTimestamp += ReadVarUint<uint64_t>(src); - lastLat += Uint32ToDouble(ReadVarUint<uint32_t>(src), kMinDeltaLat, kMaxDeltaLat); - lastLon += Uint32ToDouble(ReadVarUint<uint32_t>(src), kMinDeltaLon, kMaxDeltaLon); + lastLat += + Uint32ToDouble(ReadVarUint<uint32_t>(src), kMinDeltaLat, kMaxDeltaLat, kCoordBits); + lastLon += + Uint32ToDouble(ReadVarUint<uint32_t>(src), kMinDeltaLon, kMaxDeltaLon, kCoordBits); traffic = base::asserted_cast<uint8_t>(ReadVarUint<uint32_t>(src)); result.emplace_back(lastTimestamp, ms::LatLon(lastLat, lastLon), traffic); } |