Merge pull request #5740 from Zverik/intermediate_relations

[shields] Process road networks on relations
This commit is contained in:
Roman Kuznetsov 2017-04-05 15:18:34 +03:00 committed by GitHub
commit 9467c82b48
6 changed files with 301 additions and 77 deletions

View file

@ -267,6 +267,7 @@ bool IsColoredRoadShield(ftypes::RoadShield const & shield)
{
return shield.m_type == ftypes::RoadShieldType::Default ||
shield.m_type == ftypes::RoadShieldType::UK_Highway ||
shield.m_type == ftypes::RoadShieldType::Generic_White ||
shield.m_type == ftypes::RoadShieldType::Generic_Blue ||
shield.m_type == ftypes::RoadShieldType::Generic_Green ||
shield.m_type == ftypes::RoadShieldType::Generic_Red ||
@ -931,7 +932,7 @@ void ApplyLineFeature::GetRoadShieldsViewParams(ftypes::RoadShield const & shiel
}
}
void ApplyLineFeature::Finish(std::vector<ftypes::RoadShield> && roadShields)
void ApplyLineFeature::Finish(std::set<ftypes::RoadShield> && roadShields)
{
#ifdef CALC_FILTERED_POINTS
LinesStat::Get().InsertLine(m_id, m_currentScaleGtoP, m_readedCount, m_spline->GetSize());
@ -944,9 +945,9 @@ void ApplyLineFeature::Finish(std::vector<ftypes::RoadShield> && roadShields)
double const mainScale = df::VisualParams::Instance().GetVisualScale();
m2::PointD shieldOffset(0.0, 0.0);
for (size_t shieldIndex = 0; shieldIndex < roadShields.size(); shieldIndex++)
uint32_t shieldIndex = 0;
for (ftypes::RoadShield const & shield : roadShields)
{
ftypes::RoadShield const & shield = roadShields[shieldIndex];
TextViewParams textParams;
ColoredSymbolViewParams symbolParams;
PoiSymbolViewParams poiParams(m_id);
@ -957,7 +958,7 @@ void ApplyLineFeature::Finish(std::vector<ftypes::RoadShield> && roadShields)
if (minDistanceInPixels == 0)
minDistanceInPixels = static_cast<uint32_t>(mainScale * kDefaultMinDistance);
uint32_t textIndex = kShieldBaseTextIndex * (static_cast<uint32_t>(shieldIndex) + 1);
uint32_t textIndex = kShieldBaseTextIndex * (++shieldIndex);
for (auto const & spline : m_clippedSplines)
{
double const pathPixelLength = spline->GetLength() * m_currentScaleGtoP;

View file

@ -147,7 +147,7 @@ public:
void operator() (m2::PointD const & point);
bool HasGeometry() const;
void ProcessRule(Stylist::TRuleWrapper const & rule);
void Finish(std::vector<ftypes::RoadShield> && roadShields);
void Finish(std::set<ftypes::RoadShield> && roadShields);
m2::PolylineD GetPolyline() const;

View file

@ -96,12 +96,13 @@ public:
bool IsValid() const { return !(nodes.empty() && ways.empty()); }
string GetType() const
string GetTagValue(string const & key) const
{
auto it = tags.find("type");
auto it = tags.find(key);
return ((it != tags.end()) ? it->second : string());
}
string GetType() const { return GetTagValue("type"); }
bool FindWay(uint64_t id, string & role) const { return FindRoleImpl(ways, id, role); }
bool FindNode(uint64_t id, string & role) const { return FindRoleImpl(nodes, id, role); }

View file

@ -155,9 +155,29 @@ protected:
/// @todo Review route relations in future.
/// Actually, now they give a lot of dummy tags.
string const & type = e.GetType();
if (TBase::IsSkipRelation(type) || type == "route")
if (TBase::IsSkipRelation(type))
return;
if (type == "route")
{
if (e.GetTagValue("route") == "road")
{
// Append "network/ref" to the feature ref tag.
string ref = e.GetTagValue("ref");
if (!ref.empty())
{
string const & network = e.GetTagValue("network");
if (!network.empty() && network.find('/') == string::npos)
ref = network + '/' + ref;
string const & refBase = m_current->GetTag("ref");
if (!refBase.empty())
ref = refBase + ';' + ref;
TBase::AddCustomTag({"ref", std::move(ref)});
}
}
return;
}
if (type == "restriction")
{
m_routingTagsProcessor.m_restrictionWriter.Write(e);

View file

@ -16,9 +16,7 @@ using ftypes::RoadShieldType;
uint32_t constexpr kMaxRoadShieldBytesSize = 8;
std::array<std::string, 3> const kFederalCode = {{
"US", "SR", "FSR"
}};
std::array<std::string, 3> const kFederalCode = {{"US", "SR", "FSR"}};
std::array<std::string, 60> const kStatesCode = {{
"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL", "IN",
@ -27,29 +25,92 @@ std::array<std::string, 60> const kStatesCode = {{
"VT", "VA", "WA", "WV", "WI", "WY", "AS", "GU", "MP", "PR", "VI", "UM", "FM", "MH", "PW",
}};
std::array<std::string, 13> const kModifiers = {{
"alt", "alternate", "bus", "business", "bypass", "historic", "connector",
"loop", "scenic", "spur", "temporary", "toll", "truck"
}};
std::array<std::string, 13> const kModifiers = {{"alt", "alternate", "bus", "business", "bypass",
"historic", "connector", "loop", "scenic", "spur",
"temporary", "toll", "truck"}};
// Shields based on a network tag in a route=road relation.
std::unordered_map<std::string, RoadShieldType> const kRoadNetworkShields = {
// International road networks.
{"e-road", RoadShieldType::Generic_Green}, // E 105
{"asianhighway", RoadShieldType::Hidden}, // AH8. Blue, but usually not posted.
// National and regional networks for some countries.
{"ru:national", RoadShieldType::Generic_Blue},
{"ru:regional", RoadShieldType::Generic_Blue},
{"bg:national", RoadShieldType::Generic_Green},
{"bg:regional", RoadShieldType::Generic_Blue},
{"by:national", RoadShieldType::Generic_Red},
{"by:regional", RoadShieldType::Generic_Red},
{"co:national", RoadShieldType::Generic_White},
{"cz:national", RoadShieldType::Generic_Red},
{"cz:regional", RoadShieldType::Generic_Blue},
{"ee:national", RoadShieldType::Generic_Red},
{"ee:regional", RoadShieldType::Generic_White},
{"fr:a-road", RoadShieldType::Generic_Red},
{"jp:national", RoadShieldType::Generic_Blue},
{"jp:regional", RoadShieldType::Generic_Blue},
{"jp:prefectural", RoadShieldType::Generic_Blue},
{"lt:national", RoadShieldType::Generic_Red},
{"lt:regional", RoadShieldType::Generic_Blue},
{"lv:national", RoadShieldType::Generic_Red},
{"lv:regional", RoadShieldType::Generic_Blue},
{"pl:national", RoadShieldType::Generic_Red},
{"pl:regional", RoadShieldType::Generic_Orange},
{"pl:local", RoadShieldType::Generic_White},
{"ua:national", RoadShieldType::Generic_Blue},
{"ua:regional", RoadShieldType::Generic_Blue},
{"ua:territorial", RoadShieldType::Generic_White},
{"ua:local", RoadShieldType::Generic_White},
{"za:national", RoadShieldType::Generic_White},
{"za:regional", RoadShieldType::Generic_White},
// United States road networks.
{"us:i", RoadShieldType::US_Interstate},
{"us:us", RoadShieldType::US_Highway},
{"us:sr", RoadShieldType::US_Highway},
{"us:fsr", RoadShieldType::US_Highway},
};
class RoadShieldParser
{
public:
RoadShieldParser(std::string const & baseRoadNumber)
: m_baseRoadNumber(baseRoadNumber)
{}
virtual ~RoadShieldParser(){}
virtual RoadShield ParseRoadShield(std::string const & rawText) = 0;
explicit RoadShieldParser(std::string const & baseRoadNumber) : m_baseRoadNumber(baseRoadNumber) {}
virtual ~RoadShieldParser() {}
virtual RoadShield ParseRoadShield(std::string const & rawText) const = 0;
std::vector<RoadShield> GetRoadShields()
RoadShieldType FindNetworkShield(std::string network) const
{
std::vector<RoadShield> result;
// Minimum length for the network tag is 4 (US:I).
if (network.size() > 4)
{
strings::AsciiToLower(network);
// Cut off suffixes after a semicolon repeatedly, until we find a relevant shield.
auto semicolonPos = network.size();
while (semicolonPos != std::string::npos)
{
network.resize(semicolonPos); // cut off the ":xxx" suffix
auto const it = kRoadNetworkShields.find(network);
if (it != kRoadNetworkShields.cend())
return it->second;
semicolonPos = network.rfind(':');
}
}
return RoadShieldType::Default;
}
std::set<RoadShield> GetRoadShields() const
{
std::set<RoadShield> result;
std::vector<std::string> shieldsRawTests = strings::Tokenize(m_baseRoadNumber, ";");
for (std::string const & rawText : shieldsRawTests)
{
RoadShield shield = ParseRoadShield(rawText);
if (!shield.m_name.empty())
result.push_back(std::move(shield));
auto slashPos = rawText.find('/');
RoadShield shield = slashPos == std::string::npos
? ParseRoadShield(rawText)
: RoadShield{FindNetworkShield(rawText.substr(0, slashPos)),
rawText.substr(slashPos + 1)};
if (!shield.m_name.empty() && shield.m_type != RoadShieldType::Hidden)
result.insert(std::move(shield));
}
return result;
}
@ -61,11 +122,8 @@ protected:
class USRoadShieldParser : public RoadShieldParser
{
public:
USRoadShieldParser(std::string const & baseRoadNumber)
: RoadShieldParser(baseRoadNumber)
{}
RoadShield ParseRoadShield(std::string const & rawText) override
USRoadShieldParser(std::string const & baseRoadNumber) : RoadShieldParser(baseRoadNumber) {}
RoadShield ParseRoadShield(std::string const & rawText) const override
{
std::string shieldText = rawText;
@ -94,7 +152,8 @@ public:
if (shieldParts.size() <= 1)
return RoadShield(RoadShieldType::Default, rawText);
std::string const & roadType = shieldParts[0]; // 'I' for interstates and kFederalCode/kStatesCode for highways.
std::string const & roadType =
shieldParts[0]; // 'I' for interstates and kFederalCode/kStatesCode for highways.
std::string roadNumber = shieldParts[1];
std::string additionalInfo;
if (shieldParts.size() >= 3)
@ -115,23 +174,44 @@ public:
return RoadShield(RoadShieldType::US_Highway, roadNumber, additionalInfo);
if (std::find(kStatesCode.begin(), kStatesCode.end(), shieldParts[0]) != kStatesCode.end())
return RoadShield(RoadShieldType::Default, roadNumber, additionalInfo);
return RoadShield(RoadShieldType::Generic_White, roadNumber, additionalInfo);
return RoadShield(RoadShieldType::Default, rawText);
}
};
class DefaultTypeRoadShieldParser : public RoadShieldParser
{
public:
DefaultTypeRoadShieldParser(std::string const & baseRoadNumber,
RoadShieldType const & defaultType)
: RoadShieldParser(baseRoadNumber), m_type(defaultType)
{
}
RoadShield ParseRoadShield(std::string const & rawText) const override
{
if (rawText.size() > kMaxRoadShieldBytesSize)
return RoadShield();
return RoadShield(m_type, rawText);
}
private:
RoadShieldType const m_type;
};
class SimpleRoadShieldParser : public RoadShieldParser
{
public:
using ShieldTypes = std::unordered_map<char, RoadShieldType>;
SimpleRoadShieldParser(std::string const & baseRoadNumber, ShieldTypes const & types)
: RoadShieldParser(baseRoadNumber)
, m_types(types)
{}
: RoadShieldParser(baseRoadNumber), m_types(types)
{
}
RoadShield ParseRoadShield(std::string const & rawText) override
RoadShield ParseRoadShield(std::string const & rawText) const override
{
if (rawText.size() > kMaxRoadShieldBytesSize)
return RoadShield();
@ -149,32 +229,38 @@ private:
ShieldTypes const m_types;
};
class UKRoadShieldParser : public SimpleRoadShieldParser
class NumericRoadShieldParser : public RoadShieldParser
{
public:
UKRoadShieldParser(std::string const & baseRoadNumber)
: SimpleRoadShieldParser(baseRoadNumber, {{'M', RoadShieldType::Generic_Blue}, {'A', RoadShieldType::UK_Highway}})
{}
};
// A map of {lower_bound, higher_bound} -> RoadShieldType.
using ShieldTypes =
std::vector<std::pair<std::pair<std::uint16_t, std::uint16_t>, RoadShieldType>>;
class RussiaRoadShieldParser : public RoadShieldParser
{
public:
RussiaRoadShieldParser(std::string const & baseRoadNumber)
: RoadShieldParser(baseRoadNumber)
{}
NumericRoadShieldParser(std::string const & baseRoadNumber, ShieldTypes const & types)
: RoadShieldParser(baseRoadNumber), m_types(types)
{
}
RoadShield ParseRoadShield(std::string const & rawText) override
RoadShield ParseRoadShield(std::string const & rawText) const override
{
if (rawText.size() > kMaxRoadShieldBytesSize)
return RoadShield();
strings::UniString s = strings::MakeUniString(rawText);
if (s[0] == 'E' || s[0] == strings::UniChar(1045)) // Latin and cyrillic.
return RoadShield(RoadShieldType::Generic_Green, rawText);
std::uint64_t ref;
if (strings::to_uint64(rawText, ref))
{
for (auto const & p : m_types)
{
if (p.first.first <= ref && ref <= p.first.second)
return RoadShield(p.second, rawText);
}
}
return RoadShield(RoadShieldType::Generic_Blue, rawText);
return RoadShield(RoadShieldType::Default, rawText);
}
private:
ShieldTypes const m_types;
};
class SimpleUnicodeRoadShieldParser : public RoadShieldParser
@ -183,7 +269,7 @@ public:
struct Name
{
Name(std::string const & simpleName, string const & unicodeName)
: m_simpleName(simpleName), m_unicodeName(strings::MakeUniString(unicodeName))
: m_simpleName(simpleName), m_unicodeName(strings::MakeUniString(unicodeName))
{
}
@ -194,11 +280,11 @@ public:
using ShieldTypes = std::vector<std::pair<Name, RoadShieldType>>;
SimpleUnicodeRoadShieldParser(std::string const & baseRoadNumber, ShieldTypes const & types)
: RoadShieldParser(baseRoadNumber), m_types(types)
: RoadShieldParser(baseRoadNumber), m_types(types)
{
}
RoadShield ParseRoadShield(std::string const & rawText) override
RoadShield ParseRoadShield(std::string const & rawText) const override
{
uint32_t constexpr kMaxRoadShieldSymbolsSize = 4 * kMaxRoadShieldBytesSize;
@ -215,7 +301,8 @@ public:
auto const rawUnicode = strings::MakeUniString(rawText);
auto const & unicodeName = name.m_unicodeName;
auto const it = std::search(rawUnicode.begin(), rawUnicode.end(), unicodeName.begin(), unicodeName.end());
auto const it =
std::search(rawUnicode.begin(), rawUnicode.end(), unicodeName.begin(), unicodeName.end());
if (it != rawUnicode.end())
return RoadShield(type, rawText);
}
@ -227,14 +314,56 @@ private:
ShieldTypes const m_types;
};
// Implementations of "ref" parses for some countries.
class RussiaRoadShieldParser : public DefaultTypeRoadShieldParser
{
public:
RussiaRoadShieldParser(std::string const & baseRoadNumber)
: DefaultTypeRoadShieldParser(baseRoadNumber, RoadShieldType::Generic_Blue)
{
}
};
class SpainRoadShieldParser : public DefaultTypeRoadShieldParser
{
public:
SpainRoadShieldParser(std::string const & baseRoadNumber)
: DefaultTypeRoadShieldParser(baseRoadNumber, RoadShieldType::Generic_Blue)
{
}
};
class UKRoadShieldParser : public SimpleRoadShieldParser
{
public:
UKRoadShieldParser(std::string const & baseRoadNumber)
: SimpleRoadShieldParser(
baseRoadNumber, {{'M', RoadShieldType::Generic_Blue}, {'A', RoadShieldType::UK_Highway}})
{
}
};
class FranceRoadShieldParser : public SimpleRoadShieldParser
{
public:
FranceRoadShieldParser(std::string const & baseRoadNumber)
: SimpleRoadShieldParser(baseRoadNumber, {{'A', RoadShieldType::Generic_Red},
{'N', RoadShieldType::Generic_Red},
{'E', RoadShieldType::Generic_Green},
{'D', RoadShieldType::Generic_Orange}})
: SimpleRoadShieldParser(baseRoadNumber, {{'A', RoadShieldType::Generic_Red},
{'N', RoadShieldType::Generic_Red},
{'E', RoadShieldType::Generic_Green},
{'D', RoadShieldType::Generic_Orange}})
{
}
};
class GermanyRoadShieldParser : public SimpleRoadShieldParser
{
public:
GermanyRoadShieldParser(std::string const & baseRoadNumber)
: SimpleRoadShieldParser(baseRoadNumber, {{'A', RoadShieldType::Generic_Blue},
{'B', RoadShieldType::Generic_Orange},
{'L', RoadShieldType::Generic_White},
{'K', RoadShieldType::Generic_White}})
{
}
};
@ -244,10 +373,11 @@ class UkraineRoadShieldParser : public SimpleUnicodeRoadShieldParser
public:
// The second parameter in the constructor is a cyrillic symbol.
UkraineRoadShieldParser(std::string const & baseRoadNumber)
: SimpleUnicodeRoadShieldParser(baseRoadNumber, {{Name("M", "М"), RoadShieldType::Generic_Blue},
{Name("H", "Н"), RoadShieldType::Generic_Blue},
{Name("P", "Р"), RoadShieldType::Generic_Blue},
{Name("E", "Е"), RoadShieldType::Generic_Green}})
: SimpleUnicodeRoadShieldParser(baseRoadNumber,
{{Name("M", "М"), RoadShieldType::Generic_Blue},
{Name("H", "Н"), RoadShieldType::Generic_Blue},
{Name("P", "Р"), RoadShieldType::Generic_Blue},
{Name("E", "Е"), RoadShieldType::Generic_Green}})
{
}
};
@ -257,9 +387,10 @@ class BelarusRoadShieldParser : public SimpleUnicodeRoadShieldParser
public:
// The second parameter in the constructor is a cyrillic symbol.
BelarusRoadShieldParser(std::string const & baseRoadNumber)
: SimpleUnicodeRoadShieldParser(baseRoadNumber, {{Name("M", "М"), RoadShieldType::Generic_Red},
{Name("P", "Р"), RoadShieldType::Generic_Red},
{Name("E", "Е"), RoadShieldType::Generic_Green}})
: SimpleUnicodeRoadShieldParser(baseRoadNumber,
{{Name("M", "М"), RoadShieldType::Generic_Red},
{Name("P", "Р"), RoadShieldType::Generic_Red},
{Name("E", "Е"), RoadShieldType::Generic_Green}})
{
}
};
@ -268,9 +399,9 @@ class LatviaRoadShieldParser : public SimpleRoadShieldParser
{
public:
LatviaRoadShieldParser(std::string const & baseRoadNumber)
: SimpleRoadShieldParser(baseRoadNumber, {{'A', RoadShieldType::Generic_Red},
{'E', RoadShieldType::Generic_Green},
{'P', RoadShieldType::Generic_Blue}})
: SimpleRoadShieldParser(baseRoadNumber, {{'A', RoadShieldType::Generic_Red},
{'E', RoadShieldType::Generic_Green},
{'P', RoadShieldType::Generic_Blue}})
{
}
};
@ -279,20 +410,48 @@ class NetherlandsRoadShieldParser : public SimpleRoadShieldParser
{
public:
NetherlandsRoadShieldParser(std::string const & baseRoadNumber)
: SimpleRoadShieldParser(baseRoadNumber, {{'A', RoadShieldType::Generic_Red},
{'E', RoadShieldType::Generic_Green},
{'N', RoadShieldType::Generic_Orange}})
{}
: SimpleRoadShieldParser(baseRoadNumber, {{'A', RoadShieldType::Generic_Red},
{'E', RoadShieldType::Generic_Green},
{'N', RoadShieldType::Generic_Orange}})
{
}
};
class FinlandRoadShieldParser : public NumericRoadShieldParser
{
public:
FinlandRoadShieldParser(std::string const & baseRoadNumber)
: NumericRoadShieldParser(baseRoadNumber, {{{1, 30}, RoadShieldType::Generic_Red},
{{40, 99}, RoadShieldType::Generic_Orange},
{{100, 999}, RoadShieldType::Generic_White},
{{1000, 9999}, RoadShieldType::Generic_Blue},
{{10000, 60000}, RoadShieldType::Hidden}})
{
}
};
class EstoniaRoadShieldParser : public NumericRoadShieldParser
{
public:
EstoniaRoadShieldParser(std::string const & baseRoadNumber)
: NumericRoadShieldParser(baseRoadNumber, {{{1, 11}, RoadShieldType::Generic_Red},
{{12, 91}, RoadShieldType::Generic_Orange},
{{92, 92}, RoadShieldType::Generic_Red},
{{93, 95}, RoadShieldType::Generic_Orange},
{{96, 999}, RoadShieldType::Generic_White},
{{1000, 60000}, RoadShieldType::Hidden}})
{
}
};
} // namespace
namespace ftypes
{
std::vector<RoadShield> GetRoadShields(FeatureType const & f)
std::set<RoadShield> GetRoadShields(FeatureType const & f)
{
std::string const roadNumber = f.GetRoadNumber();
if (roadNumber.empty())
return std::vector<RoadShield>();
return std::set<RoadShield>();
// Find out country name.
std::string mwmName = f.GetID().GetMwmName();
@ -309,6 +468,10 @@ std::vector<RoadShield> GetRoadShields(FeatureType const & f)
return RussiaRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "France")
return FranceRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Germany")
return GermanyRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Spain")
return SpainRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Ukraine")
return UkraineRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Belarus")
@ -317,7 +480,37 @@ std::vector<RoadShield> GetRoadShields(FeatureType const & f)
return LatviaRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Netherlands")
return NetherlandsRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Finland")
return FinlandRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Estonia")
return EstoniaRoadShieldParser(roadNumber).GetRoadShields();
return SimpleRoadShieldParser(roadNumber, SimpleRoadShieldParser::ShieldTypes()).GetRoadShields();
}
std::string DebugPrint(RoadShieldType shieldType)
{
using ftypes::RoadShieldType;
switch (shieldType)
{
case RoadShieldType::Default: return "default";
case RoadShieldType::Generic_White: return "white";
case RoadShieldType::Generic_Blue: return "blue";
case RoadShieldType::Generic_Green: return "green";
case RoadShieldType::Generic_Orange: return "orange";
case RoadShieldType::Generic_Red: return "red";
case RoadShieldType::US_Interstate: return "US interstate";
case RoadShieldType::US_Highway: return "US highway";
case RoadShieldType::UK_Highway: return "UK highway";
case RoadShieldType::Hidden: return "hidden";
case RoadShieldType::Count: CHECK(false, ("RoadShieldType::Count is not to be used as a type"));
}
return string();
}
std::string DebugPrint(RoadShield const & shield)
{
return DebugPrint(shield.m_type) + "/" + shield.m_name +
(shield.m_additionalText.empty() ? "" : " (" + shield.m_additionalText + ")");
}
} // namespace ftypes

View file

@ -10,6 +10,7 @@ namespace ftypes
enum class RoadShieldType
{
Default = 0,
Generic_White, // The same as default, for semantics
Generic_Green,
Generic_Blue,
Generic_Red,
@ -17,6 +18,7 @@ enum class RoadShieldType
US_Interstate,
US_Highway,
UK_Highway,
Hidden,
Count
};
@ -33,7 +35,14 @@ struct RoadShield
RoadShield(RoadShieldType const & type, std::string const & name, std::string const & additionalText)
: m_type(type), m_name(name), m_additionalText(additionalText)
{}
inline bool operator<(RoadShield const & other) const
{
return m_type < other.m_type || m_name < other.m_name || m_additionalText < other.m_additionalText;
}
};
std::vector<RoadShield> GetRoadShields(FeatureType const & f);
std::set<RoadShield> GetRoadShields(FeatureType const & f);
std::string DebugPrint(RoadShieldType shieldType);
std::string DebugPrint(RoadShield const & shield);
} // namespace ftypes