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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#include "generator/relation_tags.hpp"
#include "generator/osm_element.hpp"
namespace generator
{
RelationTagsBase::RelationTagsBase() : m_cache(14 /* logCacheSize */) {}
void RelationTagsBase::Reset(uint64_t fID, OsmElement * p)
{
m_featureID = fID;
m_current = p;
}
bool RelationTagsBase::IsSkipRelation(std::string const & type)
{
/// @todo Skip special relation types.
return type == "multipolygon" || type == "bridge";
}
bool RelationTagsBase::IsKeyTagExists(std::string const & key) const
{
auto const & tags = m_current->m_tags;
return std::any_of(std::begin(tags), std::end(tags), [&](OsmElement::Tag const & p) {
return p.m_key == key;
});
}
void RelationTagsBase::AddCustomTag(std::pair<std::string, std::string> const & p)
{
m_current->AddTag(p.first, p.second);
}
void RelationTagsNode::Process(RelationElement const & e)
{
std::string const & type = e.GetType();
if (Base::IsSkipRelation(type))
return;
bool const processAssociatedStreet = type == "associatedStreet" &&
Base::IsKeyTagExists("addr:housenumber") &&
!Base::IsKeyTagExists("addr:street");
for (auto const & p : e.tags)
{
// - used in railway station processing
// - used in routing information
// - used in building addresses matching
if (p.first == "network" || p.first == "operator" || p.first == "route" ||
p.first == "maxspeed" ||
strings::StartsWith(p.first, "addr:"))
{
if (!Base::IsKeyTagExists(p.first))
Base::AddCustomTag(p);
}
// Convert associatedStreet relation name to addr:street tag if we don't have one.
else if (p.first == "name" && processAssociatedStreet)
Base::AddCustomTag({"addr:street", p.second});
}
}
bool RelationTagsWay::IsAcceptBoundary(RelationElement const & e) const
{
std::string role;
CHECK(e.FindWay(Base::m_featureID, role), (Base::m_featureID));
// Do not accumulate boundary types (boundary=administrative) for inner polygons.
// Example: Minsk city border (admin_level=8) is inner for Minsk area border (admin_level=4).
return role != "inner";
}
void RelationTagsWay::Process(RelationElement const & e)
{
/// @todo Review route relations in future.
/// Actually, now they give a lot of dummy tags.
std::string const & type = e.GetType();
if (Base::IsSkipRelation(type))
return;
if (type == "route")
{
if (e.GetTagValue("route") == "road")
{
// Append "network/ref" to the feature ref tag.
std::string ref = e.GetTagValue("ref");
if (!ref.empty())
{
std::string const & network = e.GetTagValue("network");
// Not processing networks with more than 15 chars (see road_shields_parser.cpp).
if (!network.empty() && network.find('/') == std::string::npos && network.size() < 15)
ref = network + '/' + ref;
std::string const & refBase = m_current->GetTag("ref");
if (!refBase.empty())
ref = refBase + ';' + ref;
Base::AddCustomTag({"ref", std::move(ref)});
}
}
return;
}
if (type == "building")
{
// If this way has "outline" role, add [building=has_parts] type.
if (e.GetWayRole(m_current->m_id) == "outline")
Base::AddCustomTag({"building", "has_parts"});
return;
}
bool const isBoundary = (type == "boundary") && IsAcceptBoundary(e);
bool const processAssociatedStreet = type == "associatedStreet" &&
Base::IsKeyTagExists("addr:housenumber") &&
!Base::IsKeyTagExists("addr:street");
bool const isHighway = Base::IsKeyTagExists("highway");
for (auto const & p : e.tags)
{
/// @todo Skip common key tags.
if (p.first == "type" || p.first == "route" || p.first == "area")
continue;
// Convert associatedStreet relation name to addr:street tag if we don't have one.
if (p.first == "name" && processAssociatedStreet)
Base::AddCustomTag({"addr:street", p.second});
// All "name" tags should be skipped.
if (strings::StartsWith(p.first, "name") || p.first == "int_name")
continue;
if (!isBoundary && p.first == "boundary")
continue;
if (p.first == "place")
continue;
// Do not pass "ref" tags from boundaries and other, non-route relations to highways.
if (p.first == "ref" && isHighway)
continue;
Base::AddCustomTag(p);
}
}
} // namespace generator
|