diff --git a/generator/booking_dataset.cpp b/generator/booking_dataset.cpp index d9e0945ed1..d93b3bac31 100644 --- a/generator/booking_dataset.cpp +++ b/generator/booking_dataset.cpp @@ -166,14 +166,14 @@ vector BookingDataset::GetNearestHotels(double lat, double lon, size_t l return indexes; } -void BookingDataset::BuildFeature(FeatureBuilder1 const & /*fb*/, size_t const hotelIndex, +void BookingDataset::BuildFeature(size_t const hotelIndex, function const & fn) const { auto const & hotel = m_hotels[hotelIndex]; FeatureBuilder1 bookingFb; FeatureParams params; - // TODO(mgsergio): handle areas. + bookingFb.SetCenter(MercatorBounds::FromLatLon(hotel.lat, hotel.lon)); auto & metadata = params.GetMetadata(); @@ -333,9 +333,6 @@ bool BookingDataset::CanBeBooking(FeatureBuilder1 const & fb) const { // TODO(mgsergio): Remove me after refactoring is done and tested. // Or remove the entire filter func. - if (fb.GetGeomType() != feature::GEOM_POINT) - return false; - if (fb.GetName(StringUtf8Multilang::kDefaultCode).empty()) return false; diff --git a/generator/booking_dataset.hpp b/generator/booking_dataset.hpp index 9de339d500..0193d4f001 100644 --- a/generator/booking_dataset.hpp +++ b/generator/booking_dataset.hpp @@ -88,8 +88,7 @@ public: double maxDistance = 0.0) const; bool MatchByName(string const & osmName, vector const & bookingIndexes) const; - void BuildFeature(FeatureBuilder1 const & fb, size_t hotelIndex, - function const & fn) const; + void BuildFeature(size_t hotelIndex, function const & fn) const; protected: vector m_hotels; diff --git a/generator/booking_quality_check/booking_quality_check.cpp b/generator/booking_quality_check/booking_quality_check.cpp index 1df4239bdd..3257ffe5f4 100644 --- a/generator/booking_quality_check/booking_quality_check.cpp +++ b/generator/booking_quality_check/booking_quality_check.cpp @@ -51,6 +51,13 @@ string PrintBuilder(FeatureBuilder1 const & fb) auto const center = MercatorBounds::ToLatLon(fb.GetKeyPoint()); s << "lat: " << center.lat << " lon: " << center.lon << '\t'; + if (fb.GetGeomType() == feature::GEOM_POINT) + s << "GeomType: GEOM_POINT"; + else if (fb.GetGeomType() == feature::GEOM_AREA) + s << "GeomType: GEOM_AREA"; + else + CHECK(false, ()); + return s.str(); } diff --git a/generator/booking_scoring.cpp b/generator/booking_scoring.cpp index 3c5941b325..b93b8331c6 100644 --- a/generator/booking_scoring.cpp +++ b/generator/booking_scoring.cpp @@ -21,7 +21,7 @@ namespace booking_scoring namespace { // Calculated with tools/python/booking_hotels_quality.py. -double constexpr kOptimalThreshold = 0.321098; +double constexpr kOptimalThreshold = 0.304875; template struct decay_equiv : diff --git a/generator/feature_builder.cpp b/generator/feature_builder.cpp index 81d6130e45..5423274bbf 100644 --- a/generator/feature_builder.cpp +++ b/generator/feature_builder.cpp @@ -469,6 +469,25 @@ osm::Id FeatureBuilder1::GetLastOsmId() const return m_osmIds.back(); } +osm::Id FeatureBuilder1::GetMostGenericOsmId() const +{ + ASSERT(!m_osmIds.empty(), ()); + auto result = m_osmIds.front(); + for (auto const & id : m_osmIds) + { + if (id.IsRelation()) + { + result = id; + break; + } + else if (result.IsNode() && id.IsWay()) + { + result = id; + } + } + return result; +} + bool FeatureBuilder1::HasOsmId(osm::Id const & id) const { for (auto const & cid : m_osmIds) diff --git a/generator/feature_builder.hpp b/generator/feature_builder.hpp index a775a10d2f..ff27806cf0 100644 --- a/generator/feature_builder.hpp +++ b/generator/feature_builder.hpp @@ -161,12 +161,15 @@ public: inline FeatureParams const & GetParams() const { return m_params; } - /// @name For OSM debugging, store original OSM id + /// @name For OSM debugging and osm objects replacement, store original OSM id //@{ void AddOsmId(osm::Id id); void SetOsmId(osm::Id id); osm::Id GetFirstOsmId() const; osm::Id GetLastOsmId() const; + /// @returns an id of the most general element: node's one if there is no area or relation, + /// area's one if there is no relation, and relation id otherwise. + osm::Id GetMostGenericOsmId() const; bool HasOsmId(osm::Id const & id) const; string GetOsmIdsString() const; //@} diff --git a/generator/generator_tests/feature_builder_test.cpp b/generator/generator_tests/feature_builder_test.cpp index c663e5b0d3..6695677999 100644 --- a/generator/generator_tests/feature_builder_test.cpp +++ b/generator/generator_tests/feature_builder_test.cpp @@ -122,6 +122,23 @@ UNIT_TEST(FBuilder_Waterfall) TEST_EQUAL(fb2.GetTypesCount(), 1, ()); } +UNIT_TEST(FBbuilder_GetMostGeneralOsmId) +{ + FeatureBuilder1 fb; + + fb.AddOsmId(osm::Id::Node(1)); + TEST_EQUAL(fb.GetMostGenericOsmId(), osm::Id::Node(1), ()); + + fb.AddOsmId(osm::Id::Node(2)); + fb.AddOsmId(osm::Id::Way(1)); + TEST_EQUAL(fb.GetMostGenericOsmId(), osm::Id::Way(1), ()); + + fb.AddOsmId(osm::Id::Node(3)); + fb.AddOsmId(osm::Id::Way(2)); + fb.AddOsmId(osm::Id::Relation(1)); + TEST_EQUAL(fb.GetMostGenericOsmId(), osm::Id::Relation(1), ()); +} + UNIT_TEST(FVisibility_RemoveNoDrawableTypes) { classificator::Load(); diff --git a/generator/osm_id.cpp b/generator/osm_id.cpp index f01d9d5224..87191edc13 100644 --- a/generator/osm_id.cpp +++ b/generator/osm_id.cpp @@ -38,11 +38,21 @@ uint64_t Id::OsmId() const return m_encodedId & RESET; } +bool Id::IsNode() const +{ + return ((m_encodedId & NODE) == NODE); +} + bool Id::IsWay() const { return ((m_encodedId & WAY) == WAY); } +bool Id::IsRelation() const +{ + return ((m_encodedId & RELATION) == RELATION); +} + string Id::Type() const { if ((m_encodedId & RELATION) == RELATION) diff --git a/generator/osm_id.hpp b/generator/osm_id.hpp index 9ab0a63e09..58a390af16 100644 --- a/generator/osm_id.hpp +++ b/generator/osm_id.hpp @@ -21,7 +21,9 @@ public: static Id Relation(uint64_t osmId); uint64_t OsmId() const; + bool IsNode() const; bool IsWay() const; + bool IsRelation() const; /// For debug output string Type() const; diff --git a/generator/osm_source.cpp b/generator/osm_source.cpp index cf337c8eec..4c6a401ea6 100644 --- a/generator/osm_source.cpp +++ b/generator/osm_source.cpp @@ -185,7 +185,7 @@ public: } }; -// TODO(mgsergio): comment +/// Used to make a "good" node for a highway graph with OSRM for low zooms. class Place { FeatureBuilder1 m_ft; @@ -267,12 +267,16 @@ class MainFeaturesEmitter : public EmitterBase unique_ptr m_coasts; unique_ptr m_coastsHolder; + string const m_skippedElementsPath; + ostringstream m_skippedElements; + string m_srcCoastsFile; bool m_failOnCoasts; generator::BookingDataset m_bookingDataset; - // TODO(mgsergio): comment. + /// Used to prepare a list of cities to serve as a list of nodes + /// for building a highway graph with OSRM for low zooms. m4::Tree m_places; enum TypeIndex @@ -290,7 +294,8 @@ class MainFeaturesEmitter : public EmitterBase public: MainFeaturesEmitter(feature::GenerateInfo const & info) - : m_failOnCoasts(info.m_failOnCoasts) + : m_skippedElementsPath(info.GetIntermediateFileName("skipped_elements", ".lst")) + , m_failOnCoasts(info.m_failOnCoasts) , m_bookingDataset(info.m_bookingDatafileName, info.m_bookingReferenceDir) { Classificator const & c = classif(); @@ -345,7 +350,31 @@ public: else if ((hotelIndex = m_bookingDataset.GetMatchingHotelIndex(fb)) != numeric_limits::max()) { - m_bookingDataset.BuildFeature(fb, hotelIndex, [this](FeatureBuilder1 & fb) { Emit(fb); }); + m_skippedElements << DebugPrint(fb.GetMostGenericOsmId()) << endl; + + // Make a hotel a simple building. + if (fb.GetGeomType() == feature::GEOM_AREA) + { + // Remove all information about a hotel. + auto params = fb.GetParams(); + params.ClearName(); + auto & meta = params.GetMetadata(); + meta.Drop(feature::Metadata::EType::FMD_STARS); + meta.Drop(feature::Metadata::EType::FMD_WEBSITE); + meta.Drop(feature::Metadata::EType::FMD_PHONE_NUMBER); + + auto & types = params.m_Types; + types.erase(remove_if(begin(types), end(types), [](uint32_t type) + { + static auto const & c = classif(); + static auto tourism = c.GetTypeByPath({"tourism"}); + ftype::TruncValue(type, 1); + return type == tourism; + })); + fb.SetParams(params); + + Emit(fb); + } } else { @@ -356,6 +385,12 @@ public: /// @return false if coasts are not merged and FLAG_fail_on_coasts is set bool Finish() override { + DumpSkippedElements(); + + // Emit all booking objecs to the map. + for (size_t hotelIndex = 0; hotelIndex < m_bookingDataset.Size(); ++hotelIndex) + m_bookingDataset.BuildFeature(hotelIndex, [this](FeatureBuilder1 & fb) { Emit(fb); }); + m_places.ForEach([this](Place const & p) { // m_places are no longer used after this point. @@ -459,11 +494,34 @@ private: if (m_countries) (*m_countries)(fb); } + + void DumpSkippedElements() + { + auto const skippedElements = m_skippedElements.str(); + + if (skippedElements.empty()) + { + LOG(LINFO, ("No osm object was skipped.")); + return; + } + + ofstream file(m_skippedElementsPath, ios_base::app); + if (file.is_open()) + { + file << m_skippedElements.str(); + LOG(LINFO, ("Saving skipped elements to", m_skippedElementsPath, "done.")); + } + else + { + LOG(LERROR, ("Can't output into", m_skippedElementsPath)); + } + } }; } // anonymous namespace unique_ptr MakeMainFeatureEmitter(feature::GenerateInfo const & info) { + LOG(LINFO, ("Processing booking data from", info.m_bookingDatafileName, "done.")); return make_unique(info); } @@ -632,22 +690,13 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info, EmitterBase & emitter) TagReplacer tagReplacer(GetPlatform().ResourcesDir() + REPLACED_TAGS_FILE); OsmTagMixer osmTagMixer(GetPlatform().ResourcesDir() + MIXED_TAGS_FILE); - // TODO(mgsergio): Output skipped elemnts. - // stringstream skippedElements; - - // Here we can add new tags to element!!! + // Here we can add new tags to the elements! auto const fn = [&](OsmElement * e) { tagReplacer(e); tagAdmixer(e); osmTagMixer(e); - // if (bookingDataset.BookingFilter(*e)) - // { - // skippedElements << e->id << endl; - // return; - // } - parser.EmitElement(e); }; @@ -664,24 +713,6 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info, EmitterBase & emitter) LOG(LINFO, ("Processing", info.m_osmFileName, "done.")); - // TOFO(mgsergio): Build features in Emitter. - // if (!info.m_bookingDatafileName.empty()) - // { - // bookingDataset.BuildFeatures([&](OsmElement * e) { parser.EmitElement(e); }); - // LOG(LINFO, ("Processing booking data from", info.m_bookingDatafileName, "done.")); - // string skippedElementsPath = info.GetIntermediateFileName("skipped_elements", ".lst"); - // ofstream file(skippedElementsPath); - // if (file.is_open()) - // { - // file << skippedElements.str(); - // LOG(LINFO, ("Saving skipped elements to", skippedElementsPath, "done.")); - // } - // else - // { - // LOG(LERROR, ("Can't output into", skippedElementsPath)); - // } - // } - // Stop if coasts are not merged and FLAG_fail_on_coasts is set if (!emitter.Finish()) return false; diff --git a/indexer/feature_data.cpp b/indexer/feature_data.cpp index c40b42eb20..b0f0ad9cc5 100644 --- a/indexer/feature_data.cpp +++ b/indexer/feature_data.cpp @@ -239,6 +239,11 @@ bool IsDummyName(string const & s) // FeatureParams implementation ///////////////////////////////////////////////////////////////////////////////////////// +void FeatureParams::ClearName() +{ + name.Clear(); +} + bool FeatureParams::AddName(string const & lang, string const & s) { if (IsDummyName(s)) diff --git a/indexer/feature_data.hpp b/indexer/feature_data.hpp index 93521b212b..a813403f50 100644 --- a/indexer/feature_data.hpp +++ b/indexer/feature_data.hpp @@ -222,6 +222,8 @@ public: FeatureParams() : m_geomType(0xFF), m_reverseGeometry(false) {} + void ClearName(); + bool AddName(string const & lang, string const & s); bool AddHouseName(string const & s); bool AddHouseNumber(string houseNumber);