diff --git a/editor/editor_tests/xml_feature_test.cpp b/editor/editor_tests/xml_feature_test.cpp index 592de5b514..6f76e4e2f7 100644 --- a/editor/editor_tests/xml_feature_test.cpp +++ b/editor/editor_tests/xml_feature_test.cpp @@ -59,6 +59,8 @@ UNIT_TEST(XMLFeature_Setters) feature.SetHouse("10"); feature.SetTagValue("opening_hours", "Mo-Fr 08:15-17:30"); + feature.SetType("amenity|atm"); + stringstream sstr; feature.Save(sstr); @@ -82,6 +84,9 @@ UNIT_TEST(XMLFeature_Setters) + )"; @@ -110,6 +115,9 @@ UNIT_TEST(XMLFeatureFromXml) + )"; @@ -134,4 +142,6 @@ UNIT_TEST(XMLFeatureFromXml) TEST_EQUAL(feature.GetTagValue("opening_hours"), "Mo-Fr 08:15-17:30", ()); TEST_EQUAL(my::TimestampToString(feature.GetModificationTime()), "2015-11-27T21:13:32Z", ()); + + TEST_EQUAL(feature.GetType(), "amenity|atm", ()); } diff --git a/editor/xml_feature.cpp b/editor/xml_feature.cpp index 46ffc9037a..24b5f714d2 100644 --- a/editor/xml_feature.cpp +++ b/editor/xml_feature.cpp @@ -1,11 +1,17 @@ #include "editor/xml_feature.hpp" +#include "base/assert.hpp" #include "base/string_utils.hpp" #include "base/timer.hpp" #include "geometry/mercator.hpp" -#include "std/cstring.hpp" +#include "std/set.hpp" +#include "std/unordered_set.hpp" + +#include +#include +#include #include "3party/pugixml/src/pugixml.hpp" @@ -47,6 +53,153 @@ void ValidateNode(pugi::xml_node const & node) if (!node.attribute("timestamp")) MYTHROW(editor::XMLFeatureNoTimestampError, ("Node has no timestamp attribute")); } + +bool IsConvertable(string const & k, string const & v) +{ + static unordered_set, boost::hash>> const + convertableTypePairs = + { + { "aeroway", "aerodrome" }, + { "aeroway", "airport" }, + { "amenity", "atm" }, + { "amenity", "bank" }, + { "amenity", "bar" }, + { "amenity", "bbq" }, + { "amenity", "bench" }, + { "amenity", "bicycle_rental" }, + { "amenity", "bureau_de_change" }, + { "amenity", "bus_station" }, + { "amenity", "cafe" }, + { "amenity", "car_rental" }, + { "amenity", "car_sharing" }, + { "amenity", "casino" }, + { "amenity", "cinema" }, + { "amenity", "college" }, + { "amenity", "doctors" }, + { "amenity", "drinking_water" }, + { "amenity", "embassy" }, + { "amenity", "fast_food" }, + { "amenity", "ferry_terminal" }, + { "amenity", "fire_station" }, + { "amenity", "fountain" }, + { "amenity", "fuel" }, + { "amenity", "grave_yard" }, + { "amenity", "hospital" }, + { "amenity", "hunting_stand" }, + { "amenity", "kindergarten" }, + { "amenity", "library" }, + { "amenity", "marketplace" }, + { "amenity", "nightclub" }, + { "amenity", "parking" }, + { "amenity", "pharmacy" }, + { "amenity", "place_of_worship" }, + { "amenity", "police" }, + { "amenity", "post_box" }, + { "amenity", "post_office" }, + { "amenity", "pub" }, + { "amenity", "recycling" }, + { "amenity", "restaurant" }, + { "amenity", "school" }, + { "amenity", "shelter" }, + { "amenity", "taxi" }, + { "amenity", "telephone" }, + { "amenity", "theatre" }, + { "amenity", "toilets" }, + { "amenity", "townhall" }, + { "amenity", "university" }, + { "amenity", "waste_disposal" }, + { "highway", "bus_stop" }, + { "highway", "speed_camera" }, + { "historic", "archaeological_site" }, + { "historic", "castle" }, + { "historic", "memorial" }, + { "historic", "monument" }, + { "historic", "ruins" }, + { "internet", "access" }, + { "internet", "access|wlan" }, + { "landuse", "cemetery" }, + { "leisure", "garden" }, + { "leisure", "pitch" }, + { "leisure", "playground" }, + { "leisure", "sports_centre" }, + { "leisure", "stadium" }, + { "leisure", "swimming_pool" }, + { "natural", "peak" }, + { "natural", "spring" }, + { "natural", "waterfall" }, + { "office", "company" }, + { "office", "estate_agent" }, + { "office", "government" }, + { "office", "lawyer" }, + { "office", "telecommunication" }, + { "place", "farm" }, + { "place", "hamlet" }, + { "place", "village" }, + { "railway", "halt" }, + { "railway", "station" }, + { "railway", "subway_entrance" }, + { "railway", "tram_stop" }, + { "shop", "alcohol" }, + { "shop", "bakery" }, + { "shop", "beauty" }, + { "shop", "beverages" }, + { "shop", "bicycle" }, + { "shop", "books" }, + { "shop", "butcher" }, + { "shop", "car" }, + { "shop", "car_repair" }, + { "shop", "chemist" }, + { "shop", "clothes" }, + { "shop", "computer" }, + { "shop", "confectionery" }, + { "shop", "convenience" }, + { "shop", "department_store" }, + { "shop", "doityourself" }, + { "shop", "electronics" }, + { "shop", "florist" }, + { "shop", "furniture" }, + { "shop", "garden_centre" }, + { "shop", "gift" }, + { "shop", "greengrocer" }, + { "shop", "hairdresser" }, + { "shop", "hardware" }, + { "shop", "jewelry" }, + { "shop", "kiosk" }, + { "shop", "laundry" }, + { "shop", "mall" }, + { "shop", "mobile_phone" }, + { "shop", "optician" }, + { "shop", "shoes" }, + { "shop", "sports" }, + { "shop", "supermarket" }, + { "shop", "toys" }, + { "tourism", "alpine_hut" }, + { "tourism", "artwork" }, + { "tourism", "attraction" }, + { "tourism", "camp_site" }, + { "tourism", "caravan_site" }, + { "tourism", "guest_house" }, + { "tourism", "hostel" }, + { "tourism", "hotel" }, + { "tourism", "information" }, + { "tourism", "motel" }, + { "tourism", "museum" }, + { "tourism", "picnic_site" }, + { "tourism", "viewpoint" }, + { "waterway", "waterfall" } + }; + + return convertableTypePairs.find(make_pair(k, v)) != end(convertableTypePairs); +} + +pair SplitMapsmeType(string const & type) +{ + vector parts; + boost::split(parts, type, boost::is_any_of("|")); + // Current implementations supports only types with one pipe + ASSERT(parts.size() == 2, ("Too many parts in type: " + type)); + return make_pair(parts[0], parts[1]); +} } // namespace namespace editor @@ -80,6 +233,27 @@ void XMLFeature::Save(ostream & ost) const m_document.save(ost, " ", pugi::format_indent_attributes); } +string XMLFeature::GetType() const +{ + for (auto const tag : GetRootNode().select_nodes("tag")) + { + string const key = tag.node().attribute("k").value(); + string const val = tag.node().attribute("v").value(); + // Handle only the first appropriate tag in first version + if (IsConvertable(key, val)) + return key + '|' + val; + } + + return ""; +} + +void XMLFeature::SetType(string const & type) +{ + auto const p = SplitMapsmeType(type); + if (IsConvertable(p.first, p.second)) + SetTagValue(p.first, p.second); +} + m2::PointD XMLFeature::GetCenter() const { return PointFromLatLon(GetRootNode()); @@ -191,7 +365,12 @@ void XMLFeature::SetAttribute(string const & key, string const & value) node = value.data(); } -pugi::xml_node XMLFeature::GetRootNode() const +pugi::xml_node const XMLFeature::GetRootNode() const +{ + return m_document.child("node"); +} + +pugi::xml_node XMLFeature::GetRootNode() { return m_document.child("node"); } diff --git a/editor/xml_feature.hpp b/editor/xml_feature.hpp index ab13b96801..58fc76ef6e 100644 --- a/editor/xml_feature.hpp +++ b/editor/xml_feature.hpp @@ -5,7 +5,6 @@ #include "std/ctime.hpp" #include "std/iostream.hpp" #include "std/map.hpp" -#include "std/unique_ptr.hpp" #include "coding/multilang_utf8_string.hpp" @@ -60,7 +59,8 @@ public: void SetAttribute(string const & key, string const & value); private: - pugi::xml_node GetRootNode() const; + pugi::xml_node const GetRootNode() const; + pugi::xml_node GetRootNode(); pugi::xml_document m_document; };