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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
#pragma once
#include "world_map_generator.hpp"
#include "../../base/base.hpp"
#include "../../coding/file_writer.hpp"
#include "../../geometry/rect2d.hpp"
#include "../../indexer/feature.hpp"
#include "../../std/string.hpp"
namespace feature
{
// Groups features in buckets according to their coordinates.
template <class FeatureOutT, class FeatureClipperT, class BoundsT, typename CellIdT>
class CellFeatureBucketer
{
typedef typename FeatureClipperT::feature_builder_t feature_builder_t;
void Init()
{
uint32_t const size = 1 << 2 * m_Level;
m_Buckets.resize(size);
for (uint32_t i = 0; i < m_Buckets.size(); ++i)
{
CellIdT cell = CellIdT::FromBitsAndLevel(i, m_Level);
double minX, minY, maxX, maxY;
CellIdConverter<BoundsT, CellIdT>::GetCellBounds(cell, minX, minY, maxX, maxY);
m_Buckets[i].m_Rect = m2::RectD(minX, minY, maxX, maxY);
}
}
public:
template <class TInfo>
explicit CellFeatureBucketer(TInfo & info)
: m_Level(info.cellBucketingLevel), m_FeatureOutInitData(info.datFilePrefix, info.datFileSuffix),
m_worldMap(info.maxScaleForWorldFeatures, info.mergeCoastlines, m_FeatureOutInitData)
{
Init();
}
/// @note this constructor doesn't support world file generation
CellFeatureBucketer(int level, typename FeatureOutT::InitDataType const & initData)
: m_Level(level), m_FeatureOutInitData(initData), m_worldMap(-1, false, initData)
{
Init();
}
void operator () (feature_builder_t & fb)
{
m_worldMap(fb);
FeatureClipperT clipper(fb);
// TODO: Is feature fully inside GetLimitRect()?
m2::RectD const limitRect = fb.GetLimitRect();
for (uint32_t i = 0; i < m_Buckets.size(); ++i)
{
// First quick and dirty limit rect intersection.
// Clipper may (or may not) do a better intersection.
if (m_Buckets[i].m_Rect.IsIntersect(limitRect))
{
feature_builder_t clippedFb;
if (clipper(m_Buckets[i].m_Rect, clippedFb))
{
if (!m_Buckets[i].m_pOut)
m_Buckets[i].m_pOut = new FeatureOutT(BucketName(i), m_FeatureOutInitData);
(*(m_Buckets[i].m_pOut))(clippedFb);
}
}
}
}
template <typename F> void GetBucketNames(F f) const
{
for (uint32_t i = 0; i < m_Buckets.size(); ++i)
if (m_Buckets[i].m_pOut)
f(BucketName(i));
}
private:
inline string BucketName(uint32_t i) const
{
return CellIdT::FromBitsAndLevel(i, m_Level).ToString();
}
struct Bucket
{
Bucket() : m_pOut(NULL) {}
~Bucket() { delete m_pOut; }
FeatureOutT * m_pOut;
m2::RectD m_Rect;
};
int m_Level;
typename FeatureOutT::InitDataType m_FeatureOutInitData;
vector<Bucket> m_Buckets;
WorldMapGenerator<FeatureOutT> m_worldMap;
};
class SimpleFeatureClipper
{
public:
typedef FeatureBuilder1 feature_builder_t;
private:
feature_builder_t const & m_Feature;
public:
explicit SimpleFeatureClipper(feature_builder_t const & f) : m_Feature(f)
{
}
bool operator () (m2::RectD const & /*rect*/, feature_builder_t & clippedF) const
{
clippedF = m_Feature;
return true;
}
};
}
|