From 67eeacccc55594257c620e04a5c5299016ac6213 Mon Sep 17 00:00:00 2001 From: Ilya Zverev Date: Mon, 23 May 2016 16:59:16 +0300 Subject: [PATCH] [bicycle] Add surface types and tests --- data/mapcss-mapping.csv | 4 + .../generator_tests/feature_builder_test.cpp | 3 +- generator/generator_tests/osm_type_test.cpp | 56 ++++++++++++-- generator/osm2type.cpp | 76 ++++++++++++++++++- indexer/feature_data.cpp | 1 + indexer/feature_visibility.cpp | 15 ++-- 6 files changed, 139 insertions(+), 16 deletions(-) diff --git a/data/mapcss-mapping.csv b/data/mapcss-mapping.csv index 221386578f..33af72c205 100644 --- a/data/mapcss-mapping.csv +++ b/data/mapcss-mapping.csv @@ -1113,3 +1113,7 @@ sponsored;[sponsored];;name;int_name;1112; sponsored|booking;1113; hwtag|nobicycle;1114; hwtag|yesbicycle;1115; +psurface|paved_good;1116; +psurface|paved_bad;1117; +psurface|unpaved_good;1118; +psurface|unpaved_bad;1119; diff --git a/generator/generator_tests/feature_builder_test.cpp b/generator/generator_tests/feature_builder_test.cpp index ee7e4a029e..c663e5b0d3 100644 --- a/generator/generator_tests/feature_builder_test.cpp +++ b/generator/generator_tests/feature_builder_test.cpp @@ -66,6 +66,7 @@ UNIT_TEST(FBuilder_LineTypes) { "railway", "rail" }, { "highway", "motorway" }, { "hwtag", "oneway" }, + { "psurface", "paved_good" }, { "junction", "roundabout" }, }; @@ -89,7 +90,7 @@ UNIT_TEST(FBuilder_LineTypes) TEST(fb2.CheckValid(), ()); TEST_EQUAL(fb1, fb2, ()); - TEST_EQUAL(fb2.GetTypesCount(), 4, ()); + TEST_EQUAL(fb2.GetTypesCount(), 5, ()); } UNIT_TEST(FBuilder_Waterfall) diff --git a/generator/generator_tests/osm_type_test.cpp b/generator/generator_tests/osm_type_test.cpp index 4980eb3667..efef83dc3d 100644 --- a/generator/generator_tests/osm_type_test.cpp +++ b/generator/generator_tests/osm_type_test.cpp @@ -60,6 +60,29 @@ namespace DumpTypes(params.m_Types); } + + void TestSurfaceTypes(string const & surface, string const & smoothness, string const & grade, char const * value) + { + OsmElement e; + e.AddTag("highway", "unclassified"); + e.AddTag("surface", surface); + e.AddTag("smoothness", smoothness); + e.AddTag("surface:grade", grade); + + FeatureParams params; + ftype::GetNameAndType(&e, params); + + TEST_EQUAL(params.m_Types.size(), 2, (params)); + TEST(params.IsTypeExist(GetType({"highway", "unclassified"})), ()); + string psurface; + for (auto type : params.m_Types) + { + string const rtype = classif().GetReadableObjectName(type); + if (rtype.substr(0, 9) == "psurface-") + psurface = rtype.substr(9); + } + TEST(params.IsTypeExist(GetType({"psurface", value})), ("Surface:", surface, "Smoothness:", smoothness, "Grade:", grade, "Expected:", value, "Got:", psurface)); + } } UNIT_TEST(OsmType_Check) @@ -483,7 +506,7 @@ UNIT_TEST(OsmType_Amenity) UNIT_TEST(OsmType_Hwtag) { char const * tags[][2] = { - {"hwtag", "oneway"}, {"hwtag", "private"}, {"hwtag", "lit"}, {"hwtag", "nofoot"}, {"hwtag", "yesfoot"}, + {"hwtag", "oneway"}, {"hwtag", "private"}, {"hwtag", "lit"}, {"hwtag", "nofoot"}, {"hwtag", "yesfoot"}, {"hwtag", "yesbicycle"} }; { @@ -510,6 +533,7 @@ UNIT_TEST(OsmType_Hwtag) {"access", "private"}, {"lit", "no"}, {"foot", "no"}, + {"bicycle", "yes"}, }; OsmElement e; @@ -518,16 +542,17 @@ UNIT_TEST(OsmType_Hwtag) FeatureParams params; ftype::GetNameAndType(&e, params); - TEST_EQUAL(params.m_Types.size(), 4, (params)); + TEST_EQUAL(params.m_Types.size(), 5, (params)); TEST(params.IsTypeExist(GetType(arr[1])), ()); TEST(params.IsTypeExist(GetType(tags[0])), ()); TEST(params.IsTypeExist(GetType(tags[1])), ()); TEST(params.IsTypeExist(GetType(tags[3])), ()); + TEST(params.IsTypeExist(GetType(tags[5])), ()); } { char const * arr[][2] = { - {"foot", "yes"}, {"highway", "primary"}, + {"foot", "yes"}, {"cycleway", "lane"}, {"highway", "primary"}, }; OsmElement e; @@ -536,12 +561,33 @@ UNIT_TEST(OsmType_Hwtag) FeatureParams params; ftype::GetNameAndType(&e, params); - TEST_EQUAL(params.m_Types.size(), 2, (params)); - TEST(params.IsTypeExist(GetType(arr[1])), ()); + TEST_EQUAL(params.m_Types.size(), 3, (params)); + TEST(params.IsTypeExist(GetType(arr[2])), ()); TEST(params.IsTypeExist(GetType(tags[4])), ()); + TEST(params.IsTypeExist(GetType(tags[5])), ()); } } +UNIT_TEST(OsmType_Surface) +{ + TestSurfaceTypes("asphalt", "", "", "paved_good"); + TestSurfaceTypes("asphalt", "bad", "", "paved_bad"); + TestSurfaceTypes("asphalt", "", "0", "paved_bad"); + TestSurfaceTypes("paved", "", "2", "paved_good"); + TestSurfaceTypes("", "excellent", "", "paved_good"); + TestSurfaceTypes("wood", "", "", "paved_bad"); + TestSurfaceTypes("wood", "good", "", "paved_good"); + TestSurfaceTypes("wood", "", "3", "paved_good"); + TestSurfaceTypes("unpaved", "", "", "unpaved_good"); + TestSurfaceTypes("mud", "", "", "unpaved_bad"); + TestSurfaceTypes("", "bad", "", "unpaved_good"); + TestSurfaceTypes("", "horrible", "", "unpaved_bad"); + TestSurfaceTypes("ground", "", "1", "unpaved_bad"); + TestSurfaceTypes("mud", "", "3", "unpaved_good"); + TestSurfaceTypes("unknown", "", "", "unpaved_good"); + TestSurfaceTypes("", "unknown", "", "unpaved_good"); +} + UNIT_TEST(OsmType_Ferry) { routing::CarModel const & carModel = routing::CarModel::Instance(); diff --git a/generator/osm2type.cpp b/generator/osm2type.cpp index c4d5fce627..c8dfbd4e18 100644 --- a/generator/osm2type.cpp +++ b/generator/osm2type.cpp @@ -168,7 +168,7 @@ namespace ftype static bool IsNegative(string const & value) { - for (char const * s : { "no", "none", "false", "0" }) + for (char const * s : { "no", "none", "false" }) if (value == s) return true; return false; @@ -214,7 +214,8 @@ namespace ftype public: enum EType { ENTRANCE, HIGHWAY, ADDRESS, ONEWAY, PRIVATE, LIT, NOFOOT, YESFOOT, - NOBICYCLE, YESBICYCLE, RW_STATION, RW_STATION_SUBWAY }; + NOBICYCLE, YESBICYCLE, SURFPGOOD, SURFPBAD, SURFUGOOD, SURFUBAD, + RW_STATION, RW_STATION_SUBWAY }; CachedTypes() { @@ -227,7 +228,9 @@ namespace ftype { {"building", "address"}, {"hwtag", "oneway"}, {"hwtag", "private"}, {"hwtag", "lit"}, {"hwtag", "nofoot"}, {"hwtag", "yesfoot"}, - {"hwtag", "nobicycle"}, {"hwtag", "yesbicycle"} + {"hwtag", "nobicycle"}, {"hwtag", "yesbicycle"}, + {"psurface", "paved_good"}, {"psurface", "paved_bad"}, + {"psurface", "unpaved_good"}, {"psurface", "unpaved_bad"}, }; for (auto const & e : arr) m_types.push_back(c.GetTypeByPath(e)); @@ -383,6 +386,71 @@ namespace ftype return string(); } + string DetermineSurface(OsmElement * p) + { + string surface; + string smoothness; + string surface_grade; + bool isHighway = false; + + for (auto & tag : p->m_tags) + { + if (tag.key == "surface") + surface = tag.value; + else if (tag.key == "smoothness") + smoothness = tag.value; + else if (tag.key == "surface:grade") + surface_grade = tag.value; + else if (tag.key == "highway") + isHighway = true; + } + + if (!isHighway || (surface.empty() && smoothness.empty())) + return string(); + + static StringIL pavedSurfaces = {"paved", "asphalt", "cobblestone", "cobblestone:flattened", + "sett", "concrete", "concrete:lanes", "concrete:plates", + "paving_stones", "metal", "wood"}; + static StringIL badSurfaces = {"cobblestone", "sett", "metal", "wood", "grass", "gravel", + "mud", "sand", "snow", "woodchips"}; + static StringIL badSmoothness = {"bad", "very_bad", "horrible", "very_horrible", "impassable", + "robust_wheels", "high_clearance", "off_road_wheels", "rough"}; + + bool isPaved = false; + bool isGood = true; + + if (!surface.empty()) + { + for (auto const & value : pavedSurfaces) + if (surface == value) + isPaved = true; + } + else + isPaved = smoothness == "excellent" || smoothness == "good"; + + if (!smoothness.empty()) + { + for (auto const & value : badSmoothness) + if (smoothness == value) + isGood = false; + if (smoothness == "bad" && !isPaved) + isGood = true; + } + else if (surface_grade == "0" || surface_grade == "1") + isGood = false; + else + { + if (surface_grade != "3" ) + for (auto const & value : badSurfaces) + if (surface == value) + isGood = false; + } + + string psurface = isPaved ? "paved_" : "unpaved_"; + psurface += isGood ? "good" : "bad"; + return psurface; + } + void PreprocessElement(OsmElement * p) { bool hasLayer = false; @@ -413,6 +481,8 @@ namespace ftype if (!city.empty()) p->AddTag("city", city); } + + p->AddTag("psurface", DetermineSurface(p)); } void PostprocessElement(OsmElement * p, FeatureParams & params) diff --git a/indexer/feature_data.cpp b/indexer/feature_data.cpp index 0280e0883b..3347ae7dcb 100644 --- a/indexer/feature_data.cpp +++ b/indexer/feature_data.cpp @@ -86,6 +86,7 @@ public: { "building" }, { "building:part" }, { "hwtag" }, + { "psurface" }, { "internet_access" }, }; diff --git a/indexer/feature_visibility.cpp b/indexer/feature_visibility.cpp index 53db917f68..921b9131d6 100644 --- a/indexer/feature_visibility.cpp +++ b/indexer/feature_visibility.cpp @@ -208,21 +208,22 @@ namespace /// Add here all exception classificator types: needed for algorithms, /// but don't have drawing rules. - bool TypeAlwaysExists(uint32_t t, EGeomType g = GEOM_UNDEFINED) + bool TypeAlwaysExists(uint32_t type, EGeomType g = GEOM_UNDEFINED) { - static const uint32_t s1 = classif().GetTypeByPath({ "junction", "roundabout" }); - static const uint32_t s2 = classif().GetTypeByPath({ "hwtag" }); + static const uint32_t roundabout = classif().GetTypeByPath({ "junction", "roundabout" }); + static const uint32_t hwtag = classif().GetTypeByPath({ "hwtag" }); + static const uint32_t psurface = classif().GetTypeByPath({ "psurface" }); if (g == GEOM_LINE || g == GEOM_UNDEFINED) { - if (s1 == t) + if (roundabout == type) return true; - if (HasRoutingExceptionType(t)) + if (HasRoutingExceptionType(type)) return true; - ftype::TruncValue(t, 1); - if (s2 == t) + ftype::TruncValue(type, 1); + if (hwtag == type || psurface == type) return true; }