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();