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
|
#include "towns_dumper.hpp"
#include "geometry/distance_on_sphere.hpp"
#include "geometry/tree4d.hpp"
#include "base/logging.hpp"
#include <fstream>
#include <limits>
#include <string>
#include <vector>
namespace
{
uint64_t constexpr kTownsEqualityMeters = 500000;
} // namespace
TownsDumper::TownsDumper() {}
void TownsDumper::FilterTowns()
{
LOG(LINFO, ("Preprocessing started. Have", m_records.size(), "towns."));
m4::Tree<Town> resultTree;
std::vector<Town> towns;
towns.reserve(m_records.size());
for (auto const & town : m_records)
{
if (town.capital)
resultTree.Add(town);
else
towns.push_back(town);
}
sort(towns.begin(), towns.end());
LOG(LINFO, ("Tree of capitals has size", resultTree.GetSize(), "towns has size:", towns.size()));
m_records.clear();
while (!towns.empty())
{
auto const & top = towns.back();
bool isUniq = true;
resultTree.ForEachInRect(
MercatorBounds::RectByCenterXYAndSizeInMeters(MercatorBounds::FromLatLon(top.point),
kTownsEqualityMeters),
[&top, &isUniq](Town const & candidate)
{
if (ms::DistanceOnEarth(top.point, candidate.point) < kTownsEqualityMeters)
isUniq = false;
});
if (isUniq)
resultTree.Add(top);
towns.pop_back();
}
resultTree.ForEach([this](Town const & town)
{
m_records.push_back(town);
});
LOG(LINFO, ("Preprocessing finished. Have", m_records.size(), "towns."));
}
void TownsDumper::CheckElement(OsmElement const & em)
{
if (em.m_type != OsmElement::EntityType::Node)
return;
uint64_t population = 1;
bool town = false;
bool capital = false;
int admin_level = std::numeric_limits<int>::max();
for (auto const & tag : em.Tags())
{
auto const & key = tag.m_key;
auto const & value = tag.m_value;
if (key == "population")
{
if (!strings::to_uint64(value, population))
continue;
}
else if (key == "admin_level")
{
if (!strings::to_int(value, admin_level))
continue;
}
else if (key == "capital" && value == "yes")
{
capital = true;
}
else if (key == "place" && (value == "city" || value == "town"))
{
town = true;
}
}
// Ignore regional capitals.
if (capital && admin_level > 2)
capital = false;
if (town || capital)
m_records.emplace_back(em.m_lat, em.m_lon, em.m_id, capital, population);
}
void TownsDumper::Dump(std::string const & filePath)
{
FilterTowns();
ASSERT(!filePath.empty(), ());
std::ofstream stream(filePath);
stream.precision(9);
for (auto const & record : m_records)
{
std::string const isCapital = record.capital ? "t" : "f";
stream << record.point.m_lat << ";" << record.point.m_lon << ";" << record.id << ";" << isCapital << std::endl;
}
}
|