diff --git a/editor/xml_feature.cpp b/editor/xml_feature.cpp index 92211197d2..92857b1781 100644 --- a/editor/xml_feature.cpp +++ b/editor/xml_feature.cpp @@ -23,6 +23,7 @@ constexpr char const * kUploadTimestamp = "upload_timestamp"; constexpr char const * kUploadStatus = "upload_status"; constexpr char const * kUploadError = "upload_error"; constexpr char const * kHouseNumber = "addr:housenumber"; +constexpr char const * kGeomType = "mapswithme:geom_type"; pugi::xml_node FindTag(pugi::xml_document const & document, string const & key) { @@ -88,6 +89,16 @@ XMLFeature::XMLFeature(pugi::xml_node const & xml) ValidateNode(GetRootNode()); } +string XMLFeature::GetGeomType() const +{ + return GetTagValue(kGeomType); +} + +void XMLFeature::SetGeomType(string const & type) +{ + SetTagValue(kGeomType, type); +} + void XMLFeature::Save(ostream & ost) const { m_document.save(ost, " ", pugi::format_indent_attributes); diff --git a/editor/xml_feature.hpp b/editor/xml_feature.hpp index 1643b2bf47..787d38d113 100644 --- a/editor/xml_feature.hpp +++ b/editor/xml_feature.hpp @@ -33,12 +33,12 @@ public: XMLFeature(XMLFeature const & feature) : XMLFeature(feature.m_document) {} void Save(ostream & ost) const; + string GetGeomType() const; + void SetGeomType(string const & type); + m2::PointD GetCenter() const; void SetCenter(m2::PointD const & mercatorCenter); - string GetType() const; - void SetType(string const & type); - string GetName(string const & lang) const; string GetName(uint8_t const langCode = StringUtf8Multilang::DEFAULT_CODE) const; diff --git a/indexer/feature.cpp b/indexer/feature.cpp index 000cabb778..8a5f69e4f3 100644 --- a/indexer/feature.cpp +++ b/indexer/feature.cpp @@ -42,53 +42,66 @@ FeatureType FeatureType::FromXML(string const & xml) FeatureType FeatureType::FromXML(editor::XMLFeature const & xml) { FeatureType feature; + // Should be set to true. Or later call to ParseGeometry will lead to crash. feature.m_bTrianglesParsed = feature.m_bPointsParsed = true; - feature.m_center = xml.GetCenter(); - xml.ForEachName([&feature](string const & lang, string const & name) + // Preset type for header calculation later in ApplyPatch. + feature.m_header = HEADER_GEOM_POINT; + + feature.ApplyPatch(xml); + + return feature; +} + +void FeatureType::ApplyPatch(editor::XMLFeature const & xml) +{ + xml.ForEachName([this](string const & lang, string const & name) { - feature.m_params.name.AddString(lang, name); + m_params.name.AddString(lang, name); }); + string const house = xml.GetHouse(); if (!house.empty()) - feature.m_params.house.Set(house); + m_params.house.Set(house); // TODO(mgsergio): - // feature.m_params.ref = - // feature.m_params.layer = - // feature.m_params.rank = - feature.m_bCommonParsed = true; - - // EGeomType + // m_params.ref = + // m_params.layer = + // m_params.rank = + m_bCommonParsed = true; auto const & types = osm::Editor::Instance().GetTypesOfFeature(xml); - copy(begin(types), end(types), begin(feature.m_types)); - feature.m_bTypesParsed = true; + copy(begin(types), end(types), begin(m_types)); + m_bTypesParsed = true; for (auto const i : my::Range(1u, static_cast(feature::Metadata::FMD_COUNT))) { auto const type = static_cast(i); auto const attributeName = DebugPrint(type); if (xml.HasTag(attributeName)) - feature.m_metadata.Set(type, xml.GetTagValue(attributeName)); + m_metadata.Set(type, xml.GetTagValue(attributeName)); } - feature.m_bMetadataParsed = true; + m_bMetadataParsed = true; - // TODO(mgsergio): Get types count and GeomType from xml. - // Only feature::GEOM_POINT is now supported. + // TODO(mgsergio): Get types count from xml. auto constexpr kOnlyOneTypeCount = 1; - feature.m_header = CalculateHeader(kOnlyOneTypeCount, feature::GEOM_POINT, feature.m_params); - feature.m_bHeader2Parsed = true; - - return feature; + m_header = CalculateHeader(kOnlyOneTypeCount, Header() & HEADER_GEOTYPE_MASK, m_params); + m_bHeader2Parsed = true; } editor::XMLFeature FeatureType::ToXML() const { editor::XMLFeature feature; - feature.SetCenter(GetCenter()); + // Save geom type to choose what to do later: + // deserialize or patch. + feature.SetGeomType(DebugPrint(GetFeatureType())); + + // Only Poins are completely serialized and deserialized. + // Other types could only be patched. + if (GetFeatureType() == feature::GEOM_POINT) + feature.SetCenter(GetCenter()); ForEachNameRef([&feature](uint8_t const & lang, string const & name) { diff --git a/indexer/feature.hpp b/indexer/feature.hpp index f475b752da..3598ea1701 100644 --- a/indexer/feature.hpp +++ b/indexer/feature.hpp @@ -157,6 +157,9 @@ public: static FeatureType FromXML(string const & xml); static FeatureType FromXML(editor::XMLFeature const & xml); + /// Rewrites all but geometry. + void ApplyPatch(editor::XMLFeature const & xml); + editor::XMLFeature ToXML() const; inline void SetID(FeatureID const & id) { m_id = id; } diff --git a/indexer/feature_data.cpp b/indexer/feature_data.cpp index bf9b144978..fe4b8a9679 100644 --- a/indexer/feature_data.cpp +++ b/indexer/feature_data.cpp @@ -102,7 +102,7 @@ public: namespace feature { -uint8_t CalculateHeader(uint32_t const typesCount, uint8_t const geomType, +uint8_t CalculateHeader(uint32_t const typesCount, uint8_t const headerGeomType, FeatureParamsBase const & params) { ASSERT(typesCount != 0, ("Feature should have at least one type.")); @@ -114,10 +114,10 @@ uint8_t CalculateHeader(uint32_t const typesCount, uint8_t const geomType, if (params.layer != 0) header |= HEADER_HAS_LAYER; - header |= geomType; + header |= headerGeomType; // Geometry type for additional info is only one. - switch (geomType) + switch (headerGeomType) { case HEADER_GEOM_POINT: if (params.rank != 0) diff --git a/indexer/feature_data.hpp b/indexer/feature_data.hpp index 17e27a9afc..3f2588b9ae 100644 --- a/indexer/feature_data.hpp +++ b/indexer/feature_data.hpp @@ -114,7 +114,7 @@ namespace feature { return t.DebugPrint(); } - uint8_t CalculateHeader(uint32_t const typesCount, uint8_t const geomType, + uint8_t CalculateHeader(uint32_t const typesCount, uint8_t const headerGeomType, FeatureParamsBase const & params); } diff --git a/indexer/feature_decl.cpp b/indexer/feature_decl.cpp index c697f6948c..d0475aa429 100644 --- a/indexer/feature_decl.cpp +++ b/indexer/feature_decl.cpp @@ -2,6 +2,19 @@ #include "std/sstream.hpp" +namespace feature +{ +string DebugPrint(feature::EGeomType type) +{ + switch (type) + { + case feature::GEOM_UNDEFINED: return "GEOM_UNDEFINED"; + case feature::GEOM_POINT: return "GEOM_POINT"; + case feature::GEOM_LINE: return "GEOM_LINE"; + case feature::GEOM_AREA: return "GEOM_AREA"; + } +} +} // namespace feature string DebugPrint(FeatureID const & id) { diff --git a/indexer/feature_decl.hpp b/indexer/feature_decl.hpp index 6c89648b5f..fcac8c5bc2 100644 --- a/indexer/feature_decl.hpp +++ b/indexer/feature_decl.hpp @@ -15,6 +15,8 @@ enum EGeomType GEOM_LINE = 1, GEOM_AREA = 2 }; + +string DebugPrint(EGeomType type); } struct FeatureID diff --git a/indexer/index.cpp b/indexer/index.cpp index 3eaefc7971..79f7f63398 100644 --- a/indexer/index.cpp +++ b/indexer/index.cpp @@ -118,19 +118,13 @@ bool Index::FeaturesLoaderGuard::IsWorld() const } void Index::FeaturesLoaderGuard::GetFeatureByIndex(uint32_t index, FeatureType & ft) const -{ - MwmId const & id = m_handle.GetId(); - if (m_editor.GetFeatureStatus(id, index) == osm::Editor::FeatureStatus::Untouched) - GetFeatureByIndexIgnoringEditor(index, ft); - else - m_editor.GetEditedFeature(m_handle.GetId(), index, ft); -} - -void Index::FeaturesLoaderGuard::GetFeatureByIndexIgnoringEditor(uint32_t index, FeatureType & ft) const { MwmId const & id = m_handle.GetId(); ASSERT_NOT_EQUAL(osm::Editor::FeatureStatus::Deleted, m_editor.GetFeatureStatus(id, index), ("Deleted feature was cached. Please review your code.")); - m_vector.GetByIndex(index, ft); - ft.SetID(FeatureID(id, index)); + if (!m_editor.Instance().GetEditedFeature(id, index, ft)) + { + m_vector.GetByIndex(index, ft); + ft.SetID(FeatureID(id, index)); + } } diff --git a/indexer/index.hpp b/indexer/index.hpp index fd3cc43558..f22681382d 100644 --- a/indexer/index.hpp +++ b/indexer/index.hpp @@ -282,7 +282,6 @@ public: bool IsWorld() const; void GetFeatureByIndex(uint32_t index, FeatureType & ft) const; inline FeaturesVector const & GetFeaturesVector() const { return m_vector; } - void GetFeatureByIndexIgnoringEditor(uint32_t index, FeatureType & ft) const; private: MwmHandle m_handle; diff --git a/indexer/indexer_tests/feature_xml_test.cpp b/indexer/indexer_tests/feature_xml_test.cpp index c2ccbc1c27..38d12c9e4a 100644 --- a/indexer/indexer_tests/feature_xml_test.cpp +++ b/indexer/indexer_tests/feature_xml_test.cpp @@ -73,6 +73,9 @@ UNIT_TEST(FeatureType_FromXMLAndBackToXML) + )"; diff --git a/indexer/osm_editor.cpp b/indexer/osm_editor.cpp index 997017a76c..7734538c45 100644 --- a/indexer/osm_editor.cpp +++ b/indexer/osm_editor.cpp @@ -38,8 +38,8 @@ namespace osm namespace { -// TODO(mgsergio): Replace hard-coded value with reading from file. string GetEditorFilePath() { return GetPlatform().WritablePathForFile(kEditorXMLFileName); } +// TODO(mgsergio): Replace hard-coded value with reading from file. static unordered_set> const gConvertibleTypepairs = { {"aeroway", "aerodrome"}, {"aeroway", "airport"}, @@ -238,9 +238,19 @@ void Editor::LoadMapEdits() { XMLFeature const xml(node); FeatureID const fid(id, xml.GetOffset()); - auto & fti = m_features[id][fid.m_index]; + FeatureTypeInfo fti; + + if (xml.GetGeomType() != DebugPrint(feature::GEOM_POINT)) + { + // TODO(mgsergio): Check if feature can be read. + fti.m_feature = m_featureLoaderFn(fid); + fti.m_feature.ApplyPatch(xml); + } + else + { + fti.m_feature = FeatureType::FromXML(xml); + } - fti.m_feature = FeatureType::FromXML(xml); fti.m_feature.SetID(fid); fti.m_modificationTimestamp = xml.GetModificationTime(); @@ -249,6 +259,12 @@ void Editor::LoadMapEdits() fti.m_uploadStatus = xml.GetUploadStatus(); fti.m_uploadError = xml.GetUploadError(); fti.m_status = section.first; + + /// Install edited feature back to editor. + /// This instruction should be after calling m_featureLoaderFn cause + /// it'll try to return feature from editor first and if + /// it can't read it from disk. + m_features[id][fid.m_index] = fti; } catch (editor::XMLFeatureError const & ex) { @@ -432,7 +448,7 @@ vector Editor::EditableMetadataForType(FeatureType const & feat TTypes types; feature.ForEachType([&types](uint32_t type) { types.push_back(type); }); // TODO(mgsergio): Only one-typed features are now supported. - if (types.size() != 1 || feature.GetFeatureType() != feature::GEOM_POINT) + if (types.size() != 1) return {}; // Enable opening hours for the first release. diff --git a/indexer/osm_editor.hpp b/indexer/osm_editor.hpp index 681945da5c..82f1b58387 100644 --- a/indexer/osm_editor.hpp +++ b/indexer/osm_editor.hpp @@ -104,6 +104,7 @@ private: TMwmIdByMapNameFn m_mwmIdByMapNameFn; /// Invalidate map viewport after edits. TInvalidateFn m_invalidateFn; + /// Get FeatureType from mwm. TFeatureLoaderFn m_featureLoaderFn; }; // class Editor @@ -117,5 +118,4 @@ inline string DebugPrint(Editor::FeatureStatus fs) case Editor::FeatureStatus::Created: return "Created"; }; } - } // namespace osm