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

cell_id.hpp « indexer - github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 81c64c03497373406d386c76e471618cb725ad2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#pragma once

#include "geometry/cellid.hpp"
#include "geometry/mercator.hpp"
#include "geometry/rect2d.hpp"

#include "base/assert.hpp"

#include <cstdint>
#include <utility>

using RectId = m2::CellId<19>;

// 24 is enough to have cell size < 2.5m * 2.5m for world.
constexpr int kGeoObjectsDepthLevels = 24;

// Cell size < 40m * 40m for world is good for regions.
constexpr int kRegionsDepthLevels = 20;

template <typename Bounds, typename CellId>
class CellIdConverter
{
public:
  static double XToCellIdX(double x)
  {
    return (x - Bounds::minX) / StepX();
  }
  static double YToCellIdY(double y)
  {
    return (y - Bounds::minY) / StepY();
  }

  static double CellIdXToX(double  x)
  {
    return (x*StepX() + Bounds::minX);
  }
  static double CellIdYToY(double y)
  {
    return (y*StepY() + Bounds::minY);
  }

  static CellId ToCellId(double x, double y)
  {
    uint32_t const ix = static_cast<uint32_t>(XToCellIdX(x));
    uint32_t const iy = static_cast<uint32_t>(YToCellIdY(y));
    CellId id = CellId::FromXY(ix, iy, CellId::DEPTH_LEVELS - 1);
#if 0 // DEBUG
    std::pair<uint32_t, uint32_t> ixy = id.XY();
    ASSERT(Abs(ixy.first  - ix) <= 1, (x, y, id, ixy));
    ASSERT(Abs(ixy.second - iy) <= 1, (x, y, id, ixy));
    CoordT minX, minY, maxX, maxY;
    GetCellBounds(id, minX, minY, maxX, maxY);
    ASSERT(minX <= x && x <= maxX, (x, y, id, minX, minY, maxX, maxY));
    ASSERT(minY <= y && y <= maxY, (x, y, id, minX, minY, maxX, maxY));
#endif
    return id;
  }

  static CellId Cover2PointsWithCell(double x1, double y1, double x2, double y2)
  {
    CellId id1 = ToCellId(x1, y1);
    CellId id2 = ToCellId(x2, y2);
    while (id1 != id2)
    {
      id1 = id1.Parent();
      id2 = id2.Parent();
    }
#if 0 // DEBUG
    double minX, minY, maxX, maxY;
    GetCellBounds(id1, minX, minY, maxX, maxY);
    ASSERT(my::between_s(minX, maxX, x1), (x1, minX, maxX));
    ASSERT(my::between_s(minX, maxX, x2), (x2, minX, maxX));
    ASSERT(my::between_s(minY, maxY, y1), (y1, minY, maxY));
    ASSERT(my::between_s(minY, maxY, y2), (y2, minY, maxY));
#endif
    return id1;
  }

  static m2::PointD FromCellId(CellId id)
  {
    std::pair<uint32_t, uint32_t> const xy = id.XY();
    return m2::PointD(CellIdXToX(xy.first), CellIdYToY(xy.second));
  }

  static void GetCellBounds(CellId id,
                            double & minX, double & minY, double & maxX, double & maxY)
  {
    std::pair<uint32_t, uint32_t> const xy = id.XY();
    uint32_t const r = id.Radius();
    minX = (xy.first - r) * StepX() + Bounds::minX;
    maxX = (xy.first + r) * StepX() + Bounds::minX;
    minY = (xy.second - r) * StepY() + Bounds::minY;
    maxY = (xy.second + r) * StepY() + Bounds::minY;
  }

private:
  inline static double StepX()
  {
    return double(Bounds::maxX - Bounds::minX) / CellId::MAX_COORD;
  }
  inline static double StepY()
  {
    return double(Bounds::maxY - Bounds::minY) / CellId::MAX_COORD;
  }
};