diff --git a/data/editor.config b/data/editor.config
index 99793c48d1..9c5d1daea3 100644
--- a/data/editor.config
+++ b/data/editor.config
@@ -50,6 +50,10 @@
+
+
+
+
@@ -112,6 +116,7 @@
+
@@ -121,6 +126,7 @@
+
diff --git a/editor/editor_config.cpp b/editor/editor_config.cpp
index 54d112b0d5..39898031c2 100644
--- a/editor/editor_config.cpp
+++ b/editor/editor_config.cpp
@@ -11,30 +11,31 @@ namespace
using EType = feature::Metadata::EType;
// TODO(mgsergio): It would be nice to have this map generated from editor.config.
-static unordered_map const kNamesToFMD= {
- {"cuisine", feature::Metadata::FMD_CUISINE},
- {"opening_hours", feature::Metadata::FMD_OPEN_HOURS},
- {"phone", feature::Metadata::FMD_PHONE_NUMBER},
- {"fax", feature::Metadata::FMD_FAX_NUMBER},
- {"stars", feature::Metadata::FMD_STARS},
- {"operator", feature::Metadata::FMD_OPERATOR},
- // {"", feature::Metadata::FMD_URL},
- {"website", feature::Metadata::FMD_WEBSITE},
- {"internet", feature::Metadata::FMD_INTERNET},
- {"ele", feature::Metadata::FMD_ELE},
- // {"", feature::Metadata::FMD_TURN_LANES},
- // {"", feature::Metadata::FMD_TURN_LANES_FORWARD},
- // {"", feature::Metadata::FMD_TURN_LANES_BACKWARD},
- {"email", feature::Metadata::FMD_EMAIL},
- {"postcode", feature::Metadata::FMD_POSTCODE},
- {"wikipedia", feature::Metadata::FMD_WIKIPEDIA},
- // {"", feature::Metadata::FMD_MAXSPEED},
- {"flats", feature::Metadata::FMD_FLATS},
- {"height", feature::Metadata::FMD_HEIGHT},
- // {"", feature::Metadata::FMD_MIN_HEIGHT},
- {"denomination", feature::Metadata::FMD_DENOMINATION},
- {"building:levels", feature::Metadata::FMD_BUILDING_LEVELS}
- // description
+static unordered_map const kNamesToFMD = {
+ {"cuisine", feature::Metadata::FMD_CUISINE},
+ {"opening_hours", feature::Metadata::FMD_OPEN_HOURS},
+ {"phone", feature::Metadata::FMD_PHONE_NUMBER},
+ {"fax", feature::Metadata::FMD_FAX_NUMBER},
+ {"stars", feature::Metadata::FMD_STARS},
+ {"operator", feature::Metadata::FMD_OPERATOR},
+ // {"", feature::Metadata::FMD_URL},
+ {"website", feature::Metadata::FMD_WEBSITE},
+ {"internet", feature::Metadata::FMD_INTERNET},
+ {"ele", feature::Metadata::FMD_ELE},
+ // {"", feature::Metadata::FMD_TURN_LANES},
+ // {"", feature::Metadata::FMD_TURN_LANES_FORWARD},
+ // {"", feature::Metadata::FMD_TURN_LANES_BACKWARD},
+ {"email", feature::Metadata::FMD_EMAIL},
+ {"postcode", feature::Metadata::FMD_POSTCODE},
+ {"wikipedia", feature::Metadata::FMD_WIKIPEDIA},
+ // {"", feature::Metadata::FMD_MAXSPEED},
+ {"flats", feature::Metadata::FMD_FLATS},
+ {"height", feature::Metadata::FMD_HEIGHT},
+ // {"", feature::Metadata::FMD_MIN_HEIGHT},
+ {"denomination", feature::Metadata::FMD_DENOMINATION},
+ {"building:levels", feature::Metadata::FMD_BUILDING_LEVELS},
+ {"level", feature::Metadata::FMD_LEVEL}
+ // description
};
unordered_map const kPriorityWeights = {{"high", 0}, {"", 1}, {"low", 2}};
diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp
index 9b76032a84..85dd448007 100644
--- a/generator/osm2meta.cpp
+++ b/generator/osm2meta.cpp
@@ -20,6 +20,10 @@ namespace
constexpr char const * kOSMMultivalueDelimiter = ";";
+// https://en.wikipedia.org/wiki/List_of_tallest_buildings_in_the_world
+auto constexpr kMaxBuildingLevelsInTheWorld = 167;
+auto constexpr kMinBuildingLevel = -6;
+
template
void RemoveDuplicatesAndKeepOrder(vector & vec)
{
@@ -179,8 +183,6 @@ string MetadataTagProcessorImpl::ValidateAndFormat_height(string const & v) cons
string MetadataTagProcessorImpl::ValidateAndFormat_building_levels(string v) const
{
- // https://en.wikipedia.org/wiki/List_of_tallest_buildings_in_the_world
- auto constexpr kMaxBuildingLevelsInTheWorld = 167;
// Some mappers use full width unicode digits. We can handle that.
strings::NormalizeDigits(v);
char * stop;
@@ -192,6 +194,22 @@ string MetadataTagProcessorImpl::ValidateAndFormat_building_levels(string v) con
return {};
}
+string MetadataTagProcessorImpl::ValidateAndFormat_level(string v) const
+{
+ // Some mappers use full width unicode digits. We can handle that.
+ strings::NormalizeDigits(v);
+ char * stop;
+ char const * s = v.c_str();
+ double const levels = strtod(s, &stop);
+ if (s != stop && isfinite(levels) && levels >= kMinBuildingLevel &&
+ levels <= kMaxBuildingLevelsInTheWorld)
+ {
+ return strings::to_string(levels);
+ }
+
+ return {};
+}
+
string MetadataTagProcessorImpl::ValidateAndFormat_sponsored_id(string const & v) const
{
uint64_t id;
diff --git a/generator/osm2meta.hpp b/generator/osm2meta.hpp
index 1d14aa0e7e..9b8f6d82ac 100644
--- a/generator/osm2meta.hpp
+++ b/generator/osm2meta.hpp
@@ -30,6 +30,7 @@ struct MetadataTagProcessorImpl
std::string ValidateAndFormat_internet(std::string v) const;
std::string ValidateAndFormat_height(std::string const & v) const;
std::string ValidateAndFormat_building_levels(std::string v) const;
+ std::string ValidateAndFormat_level(std::string v) const;
std::string ValidateAndFormat_denomination(std::string const & v) const;
std::string ValidateAndFormat_wikipedia(std::string v) const;
std::string ValidateAndFormat_price_rate(std::string const & v) const;
@@ -98,6 +99,7 @@ public:
case Metadata::FMD_PRICE_RATE: valid = ValidateAndFormat_price_rate(v); break;
case Metadata::FMD_RATING: valid = ValidateAndFormat_rating(v); break;
case Metadata::FMD_BANNER_URL: valid = ValidateAndFormat_url(v); break;
+ case Metadata::FMD_LEVEL: valid = ValidateAndFormat_level(v); break;
case Metadata::FMD_TEST_ID:
case Metadata::FMD_COUNT: CHECK(false, ("FMD_COUNT can not be used as a type."));
diff --git a/indexer/editable_map_object.cpp b/indexer/editable_map_object.cpp
index 0f03d30793..30982a103b 100644
--- a/indexer/editable_map_object.cpp
+++ b/indexer/editable_map_object.cpp
@@ -513,6 +513,11 @@ void EditableMapObject::SetBuildingLevels(string const & buildingLevels)
m_metadata.Set(feature::Metadata::FMD_BUILDING_LEVELS, buildingLevels);
}
+void EditableMapObject::SetLevel(string const & level)
+{
+ m_metadata.Set(feature::Metadata::FMD_LEVEL, level);
+}
+
LocalizedStreet const & EditableMapObject::GetStreet() const { return m_street; }
void EditableMapObject::SetCuisines(vector const & cuisine)
@@ -708,4 +713,27 @@ bool EditableMapObject::ValidateEmail(string const & email)
return true;
}
+
+// static
+bool EditableMapObject::ValidateLevel(string const & level)
+{
+ if (level.empty())
+ return true;
+
+ if (level.size() > 4 /* 10.5, for example */)
+ return false;
+
+ // Allowing only half-levels.
+ if (level.find('.') != string::npos && !strings::EndsWith(level, ".5"))
+ return false;
+
+ // Forbid "04" and "0.".
+ if ('0' == level.front() && level.size() == 2)
+ return false;
+
+ auto constexpr kMinBuildingLevel = -9;
+ double result;
+ return strings::to_double(level, result) && result > kMinBuildingLevel &&
+ result <= kMaximumLevelsEditableByUsers;
+}
} // namespace osm
diff --git a/indexer/editable_map_object.hpp b/indexer/editable_map_object.hpp
index b27caf08ad..b75bc78a1d 100644
--- a/indexer/editable_map_object.hpp
+++ b/indexer/editable_map_object.hpp
@@ -142,6 +142,7 @@ public:
void SetFlats(string const & flats);
void SetBuildingLevels(string const & buildingLevels);
+ void SetLevel(string const & level);
/// @param[in] cuisine is a vector of osm cuisine ids.
void SetCuisines(vector const & cuisine);
void SetOpeningHours(string const & openingHours);
@@ -163,6 +164,7 @@ public:
static bool ValidatePhone(string const & phone);
static bool ValidateWebsite(string const & site);
static bool ValidateEmail(string const & email);
+ static bool ValidateLevel(string const & level);
/// Check whether langCode can be used as default name.
static bool CanUseAsDefaultName(int8_t const langCode, vector const & nativeMwmLanguages);
diff --git a/indexer/feature_meta.cpp b/indexer/feature_meta.cpp
index e1362f671b..6b521895ac 100644
--- a/indexer/feature_meta.cpp
+++ b/indexer/feature_meta.cpp
@@ -96,6 +96,8 @@ bool Metadata::TypeFromString(string const & k, Metadata::EType & outType)
outType = Metadata::FMD_RATING;
else if (k == "banner_url")
outType = Metadata::FMD_BANNER_URL;
+ else if (k == "level")
+ outType = Metadata::FMD_LEVEL;
else
return false;
@@ -194,6 +196,7 @@ string DebugPrint(feature::Metadata::EType type)
case Metadata::FMD_PRICE_RATE: return "price_rate";
case Metadata::FMD_RATING: return "rating:sponsored";
case Metadata::FMD_BANNER_URL: return "banner_url";
+ case Metadata::FMD_LEVEL: return "level";
case Metadata::FMD_TEST_ID: return "test_id";
case Metadata::FMD_COUNT: CHECK(false, ("FMD_COUNT can not be used as a type."));
};
diff --git a/indexer/feature_meta.hpp b/indexer/feature_meta.hpp
index c66334f0f2..443a0f4704 100644
--- a/indexer/feature_meta.hpp
+++ b/indexer/feature_meta.hpp
@@ -127,6 +127,7 @@ public:
FMD_PRICE_RATE = 25,
FMD_RATING = 26,
FMD_BANNER_URL = 27,
+ FMD_LEVEL = 28,
FMD_COUNT
};
diff --git a/indexer/map_object.cpp b/indexer/map_object.cpp
index 34dac74c6b..8a77c09973 100644
--- a/indexer/map_object.cpp
+++ b/indexer/map_object.cpp
@@ -61,6 +61,7 @@ string DebugPrint(Props props)
case osm::Props::Wikipedia: k = "wikipedia"; break;
case osm::Props::Flats: k = "addr:flats"; break;
case osm::Props::BuildingLevels: k = "building:levels"; break;
+ case osm::Props::Level: k = "level"; break;
}
return k;
}
@@ -193,6 +194,8 @@ string MapObject::GetWikipediaLink() const { return m_metadata.GetWikiURL(); }
string MapObject::GetFlats() const { return m_metadata.Get(feature::Metadata::FMD_FLATS); }
+string MapObject::GetLevel() const { return m_metadata.Get(feature::Metadata::FMD_LEVEL); }
+
string MapObject::GetBuildingLevels() const
{
return m_metadata.Get(feature::Metadata::FMD_BUILDING_LEVELS);
diff --git a/indexer/map_object.hpp b/indexer/map_object.hpp
index b3b969c38c..5aedca14fa 100644
--- a/indexer/map_object.hpp
+++ b/indexer/map_object.hpp
@@ -46,7 +46,8 @@ enum class Props
Internet,
Wikipedia,
Flats,
- BuildingLevels
+ BuildingLevels,
+ Level
};
string DebugPrint(Props props);
@@ -89,6 +90,7 @@ public:
string GetWikipediaLink() const;
string GetFlats() const;
string GetBuildingLevels() const;
+ string GetLevel() const;
ftraits::WheelchairAvailability GetWheelchairType() const;
// TODO(Vlad, yunikkk): Use Props enum + getters instead of direct metadata access.
@@ -136,6 +138,7 @@ vector MetadataToProps(vector const & metadata)
case Metadata::FMD_WIKIPEDIA: res.push_back(Props::Wikipedia); break;
case Metadata::FMD_FLATS: res.push_back(Props::Flats); break;
case Metadata::FMD_BUILDING_LEVELS: res.push_back(Props::BuildingLevels); break;
+ case Metadata::FMD_LEVEL: res.push_back(Props::Level); break;
case Metadata::FMD_TURN_LANES:
case Metadata::FMD_TURN_LANES_FORWARD:
case Metadata::FMD_TURN_LANES_BACKWARD: