[indexer] Support for road shield parsing by highway class

Signed-off-by: Yannik Bloscheck <git@yannikbloscheck.com>
This commit is contained in:
Yannik Bloscheck
2025-10-28 21:25:13 +01:00
parent 7f4ff8b606
commit e0f8e043bb
8 changed files with 125 additions and 40 deletions

View File

@@ -353,7 +353,7 @@ void RuleDrawer::ProcessLineStyle(FeatureType & f, Stylist const & s, TInsertSha
df::RoadClass m_roadClass; df::RoadClass m_roadClass;
}; };
static Checker const checkers[] = { static Checker const checkers[] = {
{{HighwayClass::Trunk, HighwayClass::Primary}, kRoadClass0ZoomLevel, df::RoadClass::Class0}, {{HighwayClass::Motorway, HighwayClass::Trunk, HighwayClass::Primary}, kRoadClass0ZoomLevel, df::RoadClass::Class0},
{{HighwayClass::Secondary, HighwayClass::Tertiary}, kRoadClass1ZoomLevel, df::RoadClass::Class1}, {{HighwayClass::Secondary, HighwayClass::Tertiary}, kRoadClass1ZoomLevel, df::RoadClass::Class1},
{{HighwayClass::LivingStreet, HighwayClass::Service, HighwayClass::ServiceMinor}, {{HighwayClass::LivingStreet, HighwayClass::Service, HighwayClass::ServiceMinor},
kRoadClass2ZoomLevel, kRoadClass2ZoomLevel,

View File

@@ -30,8 +30,8 @@ public:
m_map[c.GetTypeByPath({"route", "ferry"})] = HighwayClass::Transported; m_map[c.GetTypeByPath({"route", "ferry"})] = HighwayClass::Transported;
m_map[c.GetTypeByPath({"route", "shuttle_train"})] = HighwayClass::Transported; m_map[c.GetTypeByPath({"route", "shuttle_train"})] = HighwayClass::Transported;
m_map[c.GetTypeByPath({"highway", "motorway"})] = HighwayClass::Trunk; m_map[c.GetTypeByPath({"highway", "motorway"})] = HighwayClass::Motorway;
m_map[c.GetTypeByPath({"highway", "motorway_link"})] = HighwayClass::Trunk; m_map[c.GetTypeByPath({"highway", "motorway_link"})] = HighwayClass::Motorway;
m_map[c.GetTypeByPath({"highway", "trunk"})] = HighwayClass::Trunk; m_map[c.GetTypeByPath({"highway", "trunk"})] = HighwayClass::Trunk;
m_map[c.GetTypeByPath({"highway", "trunk_link"})] = HighwayClass::Trunk; m_map[c.GetTypeByPath({"highway", "trunk_link"})] = HighwayClass::Trunk;
@@ -83,6 +83,7 @@ char const * HighwayClassToString(HighwayClass const cls)
{ {
case HighwayClass::Undefined: return "Undefined"; case HighwayClass::Undefined: return "Undefined";
case HighwayClass::Transported: return "Transported"; case HighwayClass::Transported: return "Transported";
case HighwayClass::Motorway: return "Motorway";
case HighwayClass::Trunk: return "Trunk"; case HighwayClass::Trunk: return "Trunk";
case HighwayClass::Primary: return "Primary"; case HighwayClass::Primary: return "Primary";
case HighwayClass::Secondary: return "Secondary"; case HighwayClass::Secondary: return "Secondary";

View File

@@ -674,6 +674,7 @@ uint64_t GetPopulationByRadius(double r);
enum class HighwayClass enum class HighwayClass
{ {
Undefined = 0, // There has not been any attempt of calculating HighwayClass. Undefined = 0, // There has not been any attempt of calculating HighwayClass.
Motorway,
Trunk, Trunk,
Primary, Primary,
Secondary, Secondary,

View File

@@ -107,7 +107,7 @@ UNIT_TEST(GetHighwayClassTest)
feature::TypesHolder types2; feature::TypesHolder types2;
types2.Add(c.GetTypeByPath({"highway", "motorway_link", "tunnel"})); types2.Add(c.GetTypeByPath({"highway", "motorway_link", "tunnel"}));
TEST_EQUAL(ftypes::GetHighwayClass(types2), ftypes::HighwayClass::Trunk, ()); TEST_EQUAL(ftypes::GetHighwayClass(types2), ftypes::HighwayClass::Motorway, ());
feature::TypesHolder types3; feature::TypesHolder types3;
types3.Add(c.GetTypeByPath({"highway", "unclassified"})); types3.Add(c.GetTypeByPath({"highway", "unclassified"}));

View File

@@ -94,7 +94,7 @@ class RoadShieldParser
public: public:
explicit RoadShieldParser(std::string const & baseRoadNumber) : m_baseRoadNumber(baseRoadNumber) {} explicit RoadShieldParser(std::string const & baseRoadNumber) : m_baseRoadNumber(baseRoadNumber) {}
virtual ~RoadShieldParser() = default; virtual ~RoadShieldParser() = default;
virtual RoadShield ParseRoadShield(std::string_view rawText) const = 0; virtual RoadShield ParseRoadShield(std::string_view rawText, uint8_t index) const = 0;
RoadShieldType FindNetworkShield(std::string network) const RoadShieldType FindNetworkShield(std::string network) const
{ {
@@ -128,17 +128,19 @@ public:
{ {
RoadShieldsSetT result, defaultShields; RoadShieldsSetT result, defaultShields;
uint8_t index = 0;
strings::Tokenize(m_baseRoadNumber, ";", [&](std::string_view rawText) strings::Tokenize(m_baseRoadNumber, ";", [&](std::string_view rawText)
{ {
++index;
RoadShield shield; RoadShield shield;
auto slashPos = rawText.find('/'); auto slashPos = rawText.find('/');
if (slashPos == std::string::npos) if (slashPos == std::string::npos)
{ {
shield = ParseRoadShield(rawText); shield = ParseRoadShield(rawText, index);
} }
else else
{ {
shield = ParseRoadShield(rawText.substr(slashPos + 1)); shield = ParseRoadShield(rawText.substr(slashPos + 1), index);
// TODO: use a network-based shield type override only if a parser couldn't make it // TODO: use a network-based shield type override only if a parser couldn't make it
// more specific than country's default shield type. // more specific than country's default shield type.
// E.g. "94" is set to Generic_Orange by Estonia parser, but then // E.g. "94" is set to Generic_Orange by Estonia parser, but then
@@ -176,7 +178,7 @@ class USRoadShieldParser : public RoadShieldParser
{ {
public: public:
explicit USRoadShieldParser(std::string const & baseRoadNumber) : RoadShieldParser(baseRoadNumber) {} explicit USRoadShieldParser(std::string const & baseRoadNumber) : RoadShieldParser(baseRoadNumber) {}
RoadShield ParseRoadShield(std::string_view rawText) const override RoadShield ParseRoadShield(std::string_view rawText, uint8_t index) const override
{ {
std::string shieldText(rawText); std::string shieldText(rawText);
@@ -236,7 +238,7 @@ class IndiaRoadShieldParser : public RoadShieldParser
{ {
public: public:
explicit IndiaRoadShieldParser(std::string const & baseRoadNumber) : RoadShieldParser(baseRoadNumber) {} explicit IndiaRoadShieldParser(std::string const & baseRoadNumber) : RoadShieldParser(baseRoadNumber) {}
RoadShield ParseRoadShield(std::string_view rawText) const override RoadShield ParseRoadShield(std::string_view rawText, uint8_t index) const override
{ {
std::string shieldText(rawText); std::string shieldText(rawText);
@@ -269,7 +271,7 @@ public:
, m_type(defaultType) , m_type(defaultType)
{} {}
RoadShield ParseRoadShield(std::string_view rawText) const override RoadShield ParseRoadShield(std::string_view rawText, uint8_t index) const override
{ {
if (rawText.size() > kMaxRoadShieldBytesSize) if (rawText.size() > kMaxRoadShieldBytesSize)
return RoadShield(); return RoadShield();
@@ -304,7 +306,7 @@ public:
, m_defaultType(defaultType) , m_defaultType(defaultType)
{} {}
RoadShield ParseRoadShield(std::string_view rawText) const override RoadShield ParseRoadShield(std::string_view rawText, uint8_t index) const override
{ {
if (rawText.size() > kMaxRoadShieldBytesSize) if (rawText.size() > kMaxRoadShieldBytesSize)
return RoadShield(); return RoadShield();
@@ -329,6 +331,72 @@ private:
RoadShieldType const m_defaultType; RoadShieldType const m_defaultType;
}; };
// Matches by a list of given highway classes for the first shield.
// Falls back to matching by a list of given substrings (identical to SimpleRoadShieldParser) for all other shields.
class HighwayClassRoadShieldParser : public RoadShieldParser
{
public:
struct Entry
{
Entry() = default;
Entry(std::string_view name, HighwayClass highwayClass, RoadShieldType type, bool isRedundant = false) : m_name(name), m_highwayClass(highwayClass), m_type(type), m_isRedundant(isRedundant) {}
std::string_view m_name;
HighwayClass m_highwayClass = HighwayClass::Undefined;
RoadShieldType m_type = RoadShieldType::Default;
/* Hides a specific secondary etc. sign, if there is a primary one */
bool m_isRedundant = false;
};
using ShieldTypes = buffer_vector<Entry, 8>;
HighwayClassRoadShieldParser(std::string const & baseRoadNumber, HighwayClass highwayClass, ShieldTypes && types, RoadShieldType defaultType = RoadShieldType::Default)
: RoadShieldParser(baseRoadNumber)
, m_highwayClass(highwayClass)
, m_types(std::move(types))
, m_defaultType(defaultType)
{}
RoadShield ParseRoadShield(std::string_view rawText, uint8_t index) const override
{
if (rawText.size() > kMaxRoadShieldBytesSize)
return RoadShield();
RoadShieldType type = m_defaultType;
if (index == 1) {
for (auto const & p : m_types)
{
if (p.m_highwayClass == m_highwayClass)
{
return RoadShield(p.m_type, rawText);
}
}
} else {
size_t idx = std::numeric_limits<size_t>::max();
for (auto const & p : m_types)
{
auto const i = rawText.find(p.m_name);
if (i != std::string::npos && i < idx)
{
if (p.m_isRedundant) {
type = RoadShieldType::Hidden;
} else {
type = p.m_type;
}
idx = i;
}
}
}
return {type, rawText};
}
private:
HighwayClass const m_highwayClass;
ShieldTypes const m_types;
RoadShieldType const m_defaultType;
};
uint16_t constexpr kAnyHigherRoadNumber = std::numeric_limits<uint16_t>::max(); uint16_t constexpr kAnyHigherRoadNumber = std::numeric_limits<uint16_t>::max();
// Matches by a list of numeric ranges (a first matching range is used). // Matches by a list of numeric ranges (a first matching range is used).
@@ -354,7 +422,7 @@ public:
, m_types(std::move(types)) , m_types(std::move(types))
{} {}
RoadShield ParseRoadShield(std::string_view rawText) const override RoadShield ParseRoadShield(std::string_view rawText, uint8_t index) const override
{ {
if (rawText.size() > kMaxRoadShieldBytesSize) if (rawText.size() > kMaxRoadShieldBytesSize)
return RoadShield(); return RoadShield();
@@ -403,7 +471,7 @@ public:
, m_defaultType(defaultType) , m_defaultType(defaultType)
{} {}
RoadShield ParseRoadShield(std::string_view rawText) const override RoadShield ParseRoadShield(std::string_view rawText, uint8_t index) const override
{ {
uint32_t constexpr kMaxRoadShieldSymbolsSize = 4 * kMaxRoadShieldBytesSize; uint32_t constexpr kMaxRoadShieldSymbolsSize = 4 * kMaxRoadShieldBytesSize;
@@ -429,14 +497,15 @@ private:
// Implementations of "ref" parses for some countries. // Implementations of "ref" parses for some countries.
class AustriaRoadShieldParser : public SimpleRoadShieldParser class AustriaRoadShieldParser : public HighwayClassRoadShieldParser
{ {
public: public:
explicit AustriaRoadShieldParser(std::string const & baseRoadNumber) explicit AustriaRoadShieldParser(std::string const & baseRoadNumber, HighwayClass const & highwayClass)
: SimpleRoadShieldParser(baseRoadNumber, {{"A", RoadShieldType::Generic_Blue_Bordered}, : HighwayClassRoadShieldParser(baseRoadNumber, highwayClass,
{"S", RoadShieldType::Generic_Blue_Bordered}, {{"A", HighwayClass::Motorway, RoadShieldType::Generic_Blue_Bordered},
{"B", RoadShieldType::Generic_Blue}, {"S", HighwayClass::Trunk, RoadShieldType::Generic_Blue_Bordered},
{"L", RoadShieldType::Generic_Pill_White_Bordered}}) {"B", HighwayClass::Primary, RoadShieldType::Generic_Blue},
{"L", HighwayClass::Secondary, RoadShieldType::Generic_Pill_White_Bordered}})
{} {}
}; };
@@ -585,11 +654,16 @@ public:
{} {}
}; };
class UKRoadShieldParser : public SimpleRoadShieldParser class UKRoadShieldParser : public HighwayClassRoadShieldParser
{ {
public: public:
explicit UKRoadShieldParser(std::string const & baseRoadNumber) explicit UKRoadShieldParser(std::string const & baseRoadNumber, HighwayClass const & highwayClass)
: SimpleRoadShieldParser(baseRoadNumber, {{"M", RoadShieldType::Generic_Blue}, {"A", RoadShieldType::UK_Highway}}) : HighwayClassRoadShieldParser(baseRoadNumber, highwayClass,
{{"M", HighwayClass::Motorway, RoadShieldType::Generic_Blue, true},
{"E", HighwayClass::Motorway, RoadShieldType::Hidden},
{"A", HighwayClass::Trunk, RoadShieldType::UK_Highway, true},
{"A", HighwayClass::Primary, RoadShieldType::Generic_White_Bordered},
{"B", HighwayClass::Secondary, RoadShieldType::Generic_White_Bordered}})
{} {}
}; };
@@ -605,14 +679,17 @@ public:
{} {}
}; };
class GermanyRoadShieldParser : public SimpleRoadShieldParser class GermanyRoadShieldParser : public HighwayClassRoadShieldParser
{ {
public: public:
explicit GermanyRoadShieldParser(std::string const & baseRoadNumber) explicit GermanyRoadShieldParser(std::string const & baseRoadNumber, HighwayClass const & highwayClass)
: SimpleRoadShieldParser(baseRoadNumber, {{"A", RoadShieldType::Highway_Hexagon_Blue}, : HighwayClassRoadShieldParser(baseRoadNumber, highwayClass,
{"B", RoadShieldType::Generic_Orange_Bordered}, {{"A", HighwayClass::Motorway, RoadShieldType::Highway_Hexagon_Blue},
{"L", RoadShieldType::Generic_White_Bordered}, {"D", HighwayClass::Motorway, RoadShieldType::Hidden},
{"K", RoadShieldType::Generic_White_Bordered}}) {"B", HighwayClass::Trunk, RoadShieldType::Generic_Orange_Bordered},
{"B", HighwayClass::Primary, RoadShieldType::Generic_Orange_Bordered},
{"L", HighwayClass::Secondary, RoadShieldType::Generic_White_Bordered},
{"K", HighwayClass::Secondary, RoadShieldType::Generic_White_Bordered}})
{} {}
}; };
@@ -719,7 +796,7 @@ class MexicoRoadShieldParser : public RoadShieldParser
public: public:
explicit MexicoRoadShieldParser(std::string const & baseRoadNumber) : RoadShieldParser(baseRoadNumber) {} explicit MexicoRoadShieldParser(std::string const & baseRoadNumber) : RoadShieldParser(baseRoadNumber) {}
RoadShield ParseRoadShield(std::string_view rawText) const override RoadShield ParseRoadShield(std::string_view rawText, uint8_t index) const override
{ {
std::string shieldText(rawText); std::string shieldText(rawText);
@@ -762,6 +839,10 @@ RoadShieldsSetT GetRoadShields(FeatureType & f)
if (ref.empty()) if (ref.empty())
return {}; return {};
auto const & highwayClass = ftypes::GetHighwayClass(feature::TypesHolder(f));
if (highwayClass == HighwayClass::Undefined)
return {};
// Find out country name. // Find out country name.
std::string mwmName = f.GetID().GetMwmName(); std::string mwmName = f.GetID().GetMwmName();
ASSERT(!mwmName.empty(), (f.GetID())); ASSERT(!mwmName.empty(), (f.GetID()));
@@ -770,19 +851,19 @@ RoadShieldsSetT GetRoadShields(FeatureType & f)
if (underlinePos != std::string::npos) if (underlinePos != std::string::npos)
mwmName = mwmName.substr(0, underlinePos); mwmName = mwmName.substr(0, underlinePos);
return GetRoadShields(mwmName, ref); return GetRoadShields(mwmName, ref, highwayClass);
} }
RoadShieldsSetT GetRoadShields(std::string const & mwmName, std::string const & roadNumber) RoadShieldsSetT GetRoadShields(std::string const & mwmName, std::string const & roadNumber, HighwayClass const & highwayClass)
{ {
if (mwmName == "US") if (mwmName == "US")
return USRoadShieldParser(roadNumber).GetRoadShields(); return USRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "UK") if (mwmName == "UK")
return UKRoadShieldParser(roadNumber).GetRoadShields(); return UKRoadShieldParser(roadNumber, highwayClass).GetRoadShields();
if (mwmName == "India") if (mwmName == "India")
return IndiaRoadShieldParser(roadNumber).GetRoadShields(); return IndiaRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Austria") if (mwmName == "Austria")
return AustriaRoadShieldParser(roadNumber).GetRoadShields(); return AustriaRoadShieldParser(roadNumber, highwayClass).GetRoadShields();
if (mwmName == "Belgium") if (mwmName == "Belgium")
return BelgiumRoadShieldParser(roadNumber).GetRoadShields(); return BelgiumRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Greece") if (mwmName == "Greece")
@@ -816,7 +897,7 @@ RoadShieldsSetT GetRoadShields(std::string const & mwmName, std::string const &
if (mwmName == "France") if (mwmName == "France")
return FranceRoadShieldParser(roadNumber).GetRoadShields(); return FranceRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Germany") if (mwmName == "Germany")
return GermanyRoadShieldParser(roadNumber).GetRoadShields(); return GermanyRoadShieldParser(roadNumber, highwayClass).GetRoadShields();
if (mwmName == "Spain") if (mwmName == "Spain")
return SpainRoadShieldParser(roadNumber).GetRoadShields(); return SpainRoadShieldParser(roadNumber).GetRoadShields();
if (mwmName == "Ukraine") if (mwmName == "Ukraine")

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "indexer/feature.hpp" #include "indexer/feature.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "geometry/rect2d.hpp" #include "geometry/rect2d.hpp"
@@ -79,7 +80,7 @@ struct RoadShield
// Use specific country road shield styles based on mwm feature belongs to. // Use specific country road shield styles based on mwm feature belongs to.
using RoadShieldsSetT = buffer_vector<RoadShield, 2>; using RoadShieldsSetT = buffer_vector<RoadShield, 2>;
RoadShieldsSetT GetRoadShields(FeatureType & f); RoadShieldsSetT GetRoadShields(FeatureType & f);
RoadShieldsSetT GetRoadShields(std::string const & mwmName, std::string const & roadNumber); RoadShieldsSetT GetRoadShields(std::string const & mwmName, std::string const & roadNumber, HighwayClass const & highwayClass);
// Simple parsing without specific country styles. // Simple parsing without specific country styles.
RoadShieldsSetT GetRoadShields(std::string const & rawRoadNumber); RoadShieldsSetT GetRoadShields(std::string const & rawRoadNumber);

View File

@@ -14,7 +14,7 @@ using namespace ftypes;
bool IsHighway(HighwayClass hwClass, bool isLink) bool IsHighway(HighwayClass hwClass, bool isLink)
{ {
return (hwClass == HighwayClass::Trunk || hwClass == HighwayClass::Primary) && !isLink; return (hwClass == HighwayClass::Motorway || hwClass == HighwayClass::Trunk || hwClass == HighwayClass::Primary) && !isLink;
} }
bool IsSmallRoad(HighwayClass hwClass) bool IsSmallRoad(HighwayClass hwClass)
@@ -102,6 +102,7 @@ double CalcEstimatedTimeToPass(double const distanceMeters, HighwayClass const h
double speedKmph = 0; double speedKmph = 0;
switch (highwayClass) switch (highwayClass)
{ {
case HighwayClass::Motorway: speedKmph = 100.0; break;
case HighwayClass::Trunk: speedKmph = 100.0; break; case HighwayClass::Trunk: speedKmph = 100.0; break;
case HighwayClass::Primary: speedKmph = 70.0; break; case HighwayClass::Primary: speedKmph = 70.0; break;
case HighwayClass::Secondary: speedKmph = 70.0; break; case HighwayClass::Secondary: speedKmph = 70.0; break;

View File

@@ -21,6 +21,7 @@ openlr::FunctionalRoadClass HighwayClassToFunctionalRoadClass(ftypes::HighwayCla
{ {
switch (hwClass) switch (hwClass)
{ {
case ftypes::HighwayClass::Motorway: return openlr::FunctionalRoadClass::FRC0;
case ftypes::HighwayClass::Trunk: return openlr::FunctionalRoadClass::FRC0; case ftypes::HighwayClass::Trunk: return openlr::FunctionalRoadClass::FRC0;
case ftypes::HighwayClass::Primary: return openlr::FunctionalRoadClass::FRC1; case ftypes::HighwayClass::Primary: return openlr::FunctionalRoadClass::FRC1;
case ftypes::HighwayClass::Secondary: return openlr::FunctionalRoadClass::FRC2; case ftypes::HighwayClass::Secondary: return openlr::FunctionalRoadClass::FRC2;
@@ -48,11 +49,10 @@ optional<Score> GetFrcScore(Graph::Edge const & e, FunctionalRoadClass functiona
switch (functionalRoadClass) switch (functionalRoadClass)
{ {
case FunctionalRoadClass::FRC0: case FunctionalRoadClass::FRC0:
// Note. HighwayClass::Trunk means motorway, motorway_link, trunk or trunk_link. return hwClass == HighwayClass::Motorway || hwClass == HighwayClass::Trunk ? optional<Score>(kMaxScoreForFrc) : nullopt;
return hwClass == HighwayClass::Trunk ? optional<Score>(kMaxScoreForFrc) : nullopt;
case FunctionalRoadClass::FRC1: case FunctionalRoadClass::FRC1:
return (hwClass == HighwayClass::Trunk || hwClass == HighwayClass::Primary) ? optional<Score>(kMaxScoreForFrc) return (HighwayClass::Motorway || hwClass == HighwayClass::Trunk || hwClass == HighwayClass::Primary) ? optional<Score>(kMaxScoreForFrc)
: nullopt; : nullopt;
case FunctionalRoadClass::FRC2: case FunctionalRoadClass::FRC2: