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
106
107
108
109
110
111
112
|
#pragma once
#include "coding/point_to_integer.hpp"
#include "geometry/mercator.hpp"
#include "base/assert.hpp"
using RectId = m2::CellId<19>;
// 24 is enough to have cell size < 2.5m * 2.5m for world.
using LocalityCellId = m2::CellId<24>;
template <int MinX, int MinY, int MaxX, int MaxY>
struct Bounds
{
enum
{
minX = MinX,
maxX = MaxX,
minY = MinY,
maxY = MaxY
};
};
//typedef Bounds<-180, -90, 180, 90> OrthoBounds;
template <typename BoundsT, typename CellIdT>
class CellIdConverter
{
public:
static double XToCellIdX(double x)
{
return (x - BoundsT::minX) / StepX();
}
static double YToCellIdY(double y)
{
return (y - BoundsT::minY) / StepY();
}
static double CellIdXToX(double x)
{
return (x*StepX() + BoundsT::minX);
}
static double CellIdYToY(double y)
{
return (y*StepY() + BoundsT::minY);
}
static CellIdT 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));
CellIdT id = CellIdT::FromXY(ix, iy, CellIdT::DEPTH_LEVELS - 1);
#if 0 // DEBUG
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 CellIdT Cover2PointsWithCell(double x1, double y1, double x2, double y2)
{
CellIdT id1 = ToCellId(x1, y1);
CellIdT 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(CellIdT id)
{
pair<uint32_t, uint32_t> const xy = id.XY();
return m2::PointD(CellIdXToX(xy.first), CellIdYToY(xy.second));
}
static void GetCellBounds(CellIdT id,
double & minX, double & minY, double & maxX, double & maxY)
{
pair<uint32_t, uint32_t> const xy = id.XY();
uint32_t const r = id.Radius();
minX = (xy.first - r) * StepX() + BoundsT::minX;
maxX = (xy.first + r) * StepX() + BoundsT::minX;
minY = (xy.second - r) * StepY() + BoundsT::minY;
maxY = (xy.second + r) * StepY() + BoundsT::minY;
}
private:
inline static double StepX()
{
return double(BoundsT::maxX - BoundsT::minX) / CellIdT::MAX_COORD;
}
inline static double StepY()
{
return double(BoundsT::maxY - BoundsT::minY) / CellIdT::MAX_COORD;
}
};
|