diff --git a/generator/generator_tests/metadata_parser_test.cpp b/generator/generator_tests/metadata_parser_test.cpp index fbe11bfe07..8603f192fd 100644 --- a/generator/generator_tests/metadata_parser_test.cpp +++ b/generator/generator_tests/metadata_parser_test.cpp @@ -138,49 +138,6 @@ UNIT_TEST(Metadata_ValidateAndFormat_height) TEST_EQUAL(md.Get(Metadata::FMD_HEIGHT), "6", ()); } -UNIT_TEST(Metadata_ValidateAndFormat_building_levels) -{ - FeatureParams params; - MetadataTagProcessor p(params); - Metadata & md = params.GetMetadata(); - - p("building:levels", "0"); - TEST(md.Empty(), ()); - - p("building:levels", "0,0000"); - TEST(md.Empty(), ()); - - p("building:levels", "0.0"); - TEST(md.Empty(), ()); - - p("building:levels", "1"); - TEST_EQUAL(md.Get(Metadata::FMD_BUILDING_LEVELS), "1", ()); - md.Drop(Metadata::FMD_BUILDING_LEVELS); - - p("building:levels", "3.2"); - TEST_EQUAL(md.Get(Metadata::FMD_BUILDING_LEVELS), "3.2", ()); - md.Drop(Metadata::FMD_BUILDING_LEVELS); - - p("building:levels", "1.0"); - TEST_EQUAL(md.Get(Metadata::FMD_BUILDING_LEVELS), "1", ()); - md.Drop(Metadata::FMD_BUILDING_LEVELS); - - - p("building:levels", "1.0"); - p("height", "4.0"); - TEST_EQUAL(md.Get(Metadata::FMD_BUILDING_LEVELS), "1", ()); - md.Drop(Metadata::FMD_BUILDING_LEVELS); - - p("height", "4.0"); - p("building:levels", "1"); - TEST_EQUAL(md.Get(Metadata::FMD_BUILDING_LEVELS), "1", ()); - md.Drop(Metadata::FMD_BUILDING_LEVELS); - md.Drop(Metadata::FMD_HEIGHT); - - p("building:levels", "Level 1"); - TEST(md.Empty(), ()); -} - UNIT_TEST(Metadata_ValidateAndFormat_wikipedia) { char const * kWikiKey = "wikipedia"; diff --git a/generator/generator_tests/osm2meta_test.cpp b/generator/generator_tests/osm2meta_test.cpp index 57706624de..af4a7c6a56 100644 --- a/generator/generator_tests/osm2meta_test.cpp +++ b/generator/generator_tests/osm2meta_test.cpp @@ -40,3 +40,18 @@ UNIT_TEST(ValidateAndFormat_ele) TEST_EQUAL(tagProc.ValidateAndFormat_ele("11'"), "3.35", ()); TEST_EQUAL(tagProc.ValidateAndFormat_ele("11'4\""), "3.45", ()); } + +UNIT_TEST(ValidateAndFormat_building_levels) +{ + FeatureParams params; + MetadataTagProcessorImpl tp(params); + TEST_EQUAL(tp.ValidateAndFormat_building_levels("4"), "4", ()); + TEST_EQUAL(tp.ValidateAndFormat_building_levels("4floors"), "4", ()); + TEST_EQUAL(tp.ValidateAndFormat_building_levels("between 1 and 4"), "", ()); + TEST_EQUAL(tp.ValidateAndFormat_building_levels("0"), "0", ("OSM has many zero-level buildings.")); + TEST_EQUAL(tp.ValidateAndFormat_building_levels("0.0"), "0", ()); + TEST_EQUAL(tp.ValidateAndFormat_building_levels(""), "", ()); + TEST_EQUAL(tp.ValidateAndFormat_building_levels("Level 1"), "", ()); + TEST_EQUAL(tp.ValidateAndFormat_building_levels("2.51"), "2.5", ()); + TEST_EQUAL(tp.ValidateAndFormat_building_levels("250"), "", ("Too many levels.")); +} diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index 0f4a0ea73d..7455729b58 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -9,6 +9,8 @@ #include "std/algorithm.hpp" #include "std/cctype.hpp" +#include "std/cmath.hpp" +#include "std/cstdlib.hpp" #include "std/unordered_set.hpp" namespace @@ -158,12 +160,19 @@ string MetadataTagProcessorImpl::ValidateAndFormat_height(string const & v) cons return MeasurementUtils::OSMDistanceToMetersString(v, false /*supportZeroAndNegativeValues*/, 1); } -string MetadataTagProcessorImpl::ValidateAndFormat_building_levels(string const & v) const +string MetadataTagProcessorImpl::ValidateAndFormat_building_levels(string v) const { - double d; - if (!strings::to_double(v, d) || d == 0) - return {}; - return strings::to_string_dac(d, 1); + // 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; + char const * s = v.c_str(); + double const levels = strtod(s, &stop); + if (s != stop && isfinite(levels) && levels >= 0 && levels <= kMaxBuildingLevelsInTheWorld) + return strings::to_string_dac(levels, 1); + + return {}; } string MetadataTagProcessorImpl::ValidateAndFormat_denomination(string const & v) const diff --git a/generator/osm2meta.hpp b/generator/osm2meta.hpp index 2e9f0969e7..2a334fe6e0 100644 --- a/generator/osm2meta.hpp +++ b/generator/osm2meta.hpp @@ -29,7 +29,7 @@ struct MetadataTagProcessorImpl string ValidateAndFormat_flats(string const & v) const; string ValidateAndFormat_internet(string v) const; string ValidateAndFormat_height(string const & v) const; - string ValidateAndFormat_building_levels(string const & v) const; + string ValidateAndFormat_building_levels(string v) const; string ValidateAndFormat_denomination(string const & v) const; string ValidateAndFormat_wikipedia(string v) const;