diff --git a/data/editor.config b/data/editor.config index 2abb93a945..ff911e233f 100644 --- a/data/editor.config +++ b/data/editor.config @@ -312,6 +312,11 @@ + + + + + diff --git a/editor/editor_tests/xml_feature_test.cpp b/editor/editor_tests/xml_feature_test.cpp index bf5894132e..1ae1360a37 100644 --- a/editor/editor_tests/xml_feature_test.cpp +++ b/editor/editor_tests/xml_feature_test.cpp @@ -387,3 +387,80 @@ UNIT_TEST(XMLFeature_FromXMLAndBackToXML) fromFtWithoutType.SetAttribute("timestamp", kTimestamp); TEST_EQUAL(fromFtWithoutType, xmlNoType, ()); } + +UNIT_TEST(XMLFeature_AmenityRecyclingFromAndToXml) +{ + classificator::Load(); + { + std::string const recyclingCentreStr = R"( + + + + + )"; + + char const kTimestamp[] = "2018-07-11T13:24:41Z"; + + editor::XMLFeature xmlFeature(recyclingCentreStr); + + osm::EditableMapObject emo; + editor::FromXML(xmlFeature, emo); + + auto const th = emo.GetTypes(); + TEST_EQUAL(th.Size(), 1, ()); + TEST_EQUAL(*th.begin(), classif().GetTypeByPath({"amenity", "recycling"}), ()); + + auto convertedFt = editor::ToXML(emo, true); + convertedFt.SetAttribute("timestamp", kTimestamp); + TEST_EQUAL(xmlFeature, convertedFt, ()); + } + { + std::string const recyclingContainerStr = R"( + + + + + )"; + + char const kTimestamp[] = "2018-07-11T13:24:41Z"; + + editor::XMLFeature xmlFeature(recyclingContainerStr); + + osm::EditableMapObject emo; + editor::FromXML(xmlFeature, emo); + + auto const th = emo.GetTypes(); + TEST_EQUAL(th.Size(), 1, ()); + TEST_EQUAL(*th.begin(), classif().GetTypeByPath({"amenity", "recycling_container"}), ()); + + auto convertedFt = editor::ToXML(emo, true); + convertedFt.SetAttribute("timestamp", kTimestamp); + TEST_EQUAL(xmlFeature, convertedFt, ()); + } + { + std::string const recyclingStr = R"( + + + + )"; + + editor::XMLFeature xmlFeature(recyclingStr); + + osm::EditableMapObject emo; + editor::FromXML(xmlFeature, emo); + + auto const th = emo.GetTypes(); + TEST_EQUAL(th.Size(), 1, ()); + // We construct recycling container by default if no recycling type is specified. + TEST_EQUAL(*th.begin(), classif().GetTypeByPath({"amenity", "recycling_container"}), ()); + + auto convertedFt = editor::ToXML(emo, true); + + // We save recycling container with "recycling_type"="container" tag. + TEST(convertedFt.HasTag("recycling_type"), ()); + TEST_EQUAL(convertedFt.GetTagValue("recycling_type"), "container", ()); + + TEST(convertedFt.HasTag("amenity"), ()); + TEST_EQUAL(convertedFt.GetTagValue("amenity"), "recycling", ()); + } +} diff --git a/editor/xml_feature.cpp b/editor/xml_feature.cpp index 9ef0b67a13..50398b502b 100644 --- a/editor/xml_feature.cpp +++ b/editor/xml_feature.cpp @@ -487,6 +487,22 @@ XMLFeature ToXML(osm::EditableMapObject const & object, bool serializeType) if (ftypes::IsCuisineChecker::Instance()(type)) continue; + if (ftypes::IsRecyclingTypeChecker::Instance()(type)) + continue; + + if (ftypes::IsRecyclingCentreChecker::Instance()(type)) + { + toFeature.SetTagValue("amenity", "recycling"); + toFeature.SetTagValue("recycling_type", "centre"); + continue; + } + if (ftypes::IsRecyclingContainerChecker::Instance()(type)) + { + toFeature.SetTagValue("amenity", "recycling"); + toFeature.SetTagValue("recycling_type", "container"); + continue; + } + string const strType = classif().GetReadableObjectName(type); strings::SimpleTokenizer iter(strType, "-"); string const k = *iter; @@ -543,18 +559,31 @@ bool FromXML(XMLFeature const & xml, osm::EditableMapObject & object) } feature::TypesHolder types = object.GetTypes(); - xml.ForEachTag([&object, &types](string const & k, string const & v) { + + Classificator const & cl = classif(); + xml.ForEachTag([&](string const & k, string const & v) { if (object.UpdateMetadataValue(k, v)) return; if (k == "cuisine") return; - // Simple heuristics. It works if all our supported types for - // new features at data/editor.config - // are of one or two levels nesting (currently it's true). - Classificator & cl = classif(); - uint32_t type = cl.GetTypeByPathSafe({k, v}); + if (k == "recycling" || k == "recycling_type") + return; + + uint32_t type = 0; + if (k == "amenity" && v == "recycling") + { + if (xml.HasTag("recycling_type") && xml.GetTagValue("recycling_type") == "centre") + type = ftypes::IsRecyclingCentreChecker::Instance().GetType(); + else + type = ftypes::IsRecyclingContainerChecker::Instance().GetType(); + } + + // Simple heuristics. It works for types converted from osm with short mapcss rules + // where k=v from osm is converted to our k-v type (amenity=restaurant, shop=convenience etc.). + if (type == 0) + type = cl.GetTypeByPathSafe({k, v}); if (type == 0) type = cl.GetTypeByPathSafe({k}); // building etc. if (type == 0) diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index 6a2e2755f7..697a4867d3 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -208,6 +208,22 @@ IsFuelStationChecker::IsFuelStationChecker() m_types.push_back(c.GetTypeByPath({"amenity", "fuel"})); } +IsRecyclingCentreChecker::IsRecyclingCentreChecker() +{ + Classificator const & c = classif(); + m_types.push_back(c.GetTypeByPath({"amenity", "recycling"})); +} + +uint32_t IsRecyclingCentreChecker::GetType() const { return m_types[0]; } + +IsRecyclingContainerChecker::IsRecyclingContainerChecker() +{ + Classificator const & c = classif(); + m_types.push_back(c.GetTypeByPath({"amenity", "recycling_container"})); +} + +uint32_t IsRecyclingContainerChecker::GetType() const { return m_types[0]; } + IsRailwayStationChecker::IsRailwayStationChecker() { Classificator const & c = classif(); diff --git a/indexer/ftypes_matcher.hpp b/indexer/ftypes_matcher.hpp index f2a4d31845..946f16e5d7 100644 --- a/indexer/ftypes_matcher.hpp +++ b/indexer/ftypes_matcher.hpp @@ -84,6 +84,26 @@ public: DECLARE_CHECKER_INSTANCE(IsFuelStationChecker); }; +class IsRecyclingCentreChecker : public BaseChecker +{ + IsRecyclingCentreChecker(); + +public: + DECLARE_CHECKER_INSTANCE(IsRecyclingCentreChecker); + + uint32_t GetType() const; +}; + +class IsRecyclingContainerChecker : public BaseChecker +{ + IsRecyclingContainerChecker(); + +public: + DECLARE_CHECKER_INSTANCE(IsRecyclingContainerChecker); + + uint32_t GetType() const; +}; + class IsRailwayStationChecker : public BaseChecker { IsRailwayStationChecker();