From 2174fd1800da931b31a676966be70f692c3d6dad Mon Sep 17 00:00:00 2001 From: Arsentiy Milchakov Date: Thu, 15 Jun 2017 18:01:10 +0300 Subject: [PATCH] [generator] viator --- base/newtype.hpp | 19 +- generator/CMakeLists.txt | 5 + generator/booking_dataset.cpp | 22 +- generator/generate_info.hpp | 2 + generator/generator.pro | 5 + generator/generator_tool/generator_tool.cpp | 4 + generator/opentable_dataset.cpp | 13 +- generator/osm_source.cpp | 14 +- generator/sponsored_dataset.hpp | 51 +---- generator/sponsored_dataset_inl.hpp | 196 ++++++------------ generator/sponsored_storage.hpp | 165 +++++++++++++++ generator/utils.cpp | 29 +++ generator/utils.hpp | 8 + generator/viator_dataset.cpp | 111 ++++++++++ generator/viator_dataset.hpp | 54 +++++ indexer/ftypes_matcher.cpp | 11 + indexer/ftypes_matcher.hpp | 8 + map/framework.cpp | 4 +- map/framework.hpp | 4 +- map/map.pro | 1 - search/CMakeLists.txt | 1 + {map => search}/city_finder.hpp | 3 + search/search.pro | 1 + tools/python/viator_cities.py | 72 +++++++ tools/unix/generate_planet.sh | 22 ++ .../generator.xcodeproj/project.pbxproj | 20 ++ xcode/search/search.xcodeproj/project.pbxproj | 4 + 27 files changed, 641 insertions(+), 208 deletions(-) create mode 100644 generator/sponsored_storage.hpp create mode 100644 generator/utils.cpp create mode 100644 generator/utils.hpp create mode 100644 generator/viator_dataset.cpp create mode 100644 generator/viator_dataset.hpp rename {map => search}/city_finder.hpp (93%) create mode 100644 tools/python/viator_cities.py diff --git a/base/newtype.hpp b/base/newtype.hpp index f17194e779..a51e35b65f 100644 --- a/base/newtype.hpp +++ b/base/newtype.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace my @@ -144,7 +145,7 @@ private: namespace newtype_default_output { template -string SimpleDebugPrint(NewType const & nt) +std::string SimpleDebugPrint(NewType const & nt) { return ::DebugPrint(nt.Get()); } @@ -155,12 +156,12 @@ string SimpleDebugPrint(NewType const & nt) struct NAME ## _tag; \ using NAME = my::NewType -#define NEWTYPE_SIMPLE_OUTPUT(NAME) \ - inline string DebugPrint(NAME const & nt) \ - { \ - return my::newtype_default_output::SimpleDebugPrint(nt); \ - } \ - inline ostream & operator<<(ostream & ost, NAME const & nt) \ - { \ - return ost << my::newtype_default_output::SimpleDebugPrint(nt); \ +#define NEWTYPE_SIMPLE_OUTPUT(NAME) \ + inline std::string DebugPrint(NAME const & nt) \ + { \ + return my::newtype_default_output::SimpleDebugPrint(nt); \ + } \ + inline ostream & operator<<(ostream & ost, NAME const & nt) \ + { \ + return ost << my::newtype_default_output::SimpleDebugPrint(nt); \ } diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index f833bd2695..8a314b726a 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -77,6 +77,7 @@ set(SRC sponsored_dataset_inl.hpp sponsored_scoring.cpp sponsored_scoring.hpp + sponsored_storage.hpp srtm_parser.cpp srtm_parser.hpp statistics.cpp @@ -90,6 +91,10 @@ set(SRC traffic_generator.hpp unpack_mwm.cpp unpack_mwm.hpp + utils.cpp + utils.hpp + viator_dataset.cpp + viator_dataset.hpp ways_merger.hpp world_map_generator.hpp ) diff --git a/generator/booking_dataset.cpp b/generator/booking_dataset.cpp index ced38363da..a590776e78 100644 --- a/generator/booking_dataset.cpp +++ b/generator/booking_dataset.cpp @@ -22,22 +22,22 @@ BookingHotel::BookingHotel(std::string const & src) CHECK_EQUAL(rec.size(), FieldsCount(), ("Error parsing hotels.tsv line:", boost::replace_all_copy(src, "\t", "\\t"))); - strings::to_uint(rec[FieldIndex(Fields::Id)], m_id.Get()); + CHECK(strings::to_uint(rec[FieldIndex(Fields::Id)], m_id.Get()), ()); // TODO(mgsergio): Use ms::LatLon. - strings::to_double(rec[FieldIndex(Fields::Latitude)], m_latLon.lat); - strings::to_double(rec[FieldIndex(Fields::Longtitude)], m_latLon.lon); + CHECK(strings::to_double(rec[FieldIndex(Fields::Latitude)], m_latLon.lat), ()); + CHECK(strings::to_double(rec[FieldIndex(Fields::Longtitude)], m_latLon.lon), ()); m_name = rec[FieldIndex(Fields::Name)]; m_address = rec[FieldIndex(Fields::Address)]; - strings::to_uint(rec[FieldIndex(Fields::Stars)], m_stars); - strings::to_uint(rec[FieldIndex(Fields::PriceCategory)], m_priceCategory); - strings::to_double(rec[FieldIndex(Fields::RatingBooking)], m_ratingBooking); - strings::to_double(rec[FieldIndex(Fields::RatingUsers)], m_ratingUser); + CHECK(strings::to_uint(rec[FieldIndex(Fields::Stars)], m_stars), ()); + CHECK(strings::to_uint(rec[FieldIndex(Fields::PriceCategory)], m_priceCategory), ()); + CHECK(strings::to_double(rec[FieldIndex(Fields::RatingBooking)], m_ratingBooking), ()); + CHECK(strings::to_double(rec[FieldIndex(Fields::RatingUsers)], m_ratingUser), ()); m_descUrl = rec[FieldIndex(Fields::DescUrl)]; - strings::to_uint(rec[FieldIndex(Fields::Type)], m_type); + CHECK(strings::to_uint(rec[FieldIndex(Fields::Type)], m_type), ()); m_translations = rec[FieldIndex(Fields::Translations)]; } @@ -195,12 +195,12 @@ BookingDataset::ObjectId BookingDataset::FindMatchingObjectIdImpl(FeatureBuilder return Object::InvalidObjectId(); // Find |kMaxSelectedElements| nearest values to a point. - auto const bookingIndexes = GetNearestObjects(MercatorBounds::ToLatLon(fb.GetKeyPoint()), - kMaxSelectedElements, kDistanceLimitInMeters); + auto const bookingIndexes = + GetStorage().GetNearestObjects(MercatorBounds::ToLatLon(fb.GetKeyPoint())); for (auto const j : bookingIndexes) { - if (sponsored_scoring::Match(GetObjectById(j), fb).IsMatched()) + if (sponsored_scoring::Match(GetStorage().GetObjectById(j), fb).IsMatched()) return j; } diff --git a/generator/generate_info.hpp b/generator/generate_info.hpp index e6983b81ef..4724cb7c65 100644 --- a/generator/generate_info.hpp +++ b/generator/generate_info.hpp @@ -44,6 +44,8 @@ struct GenerateInfo std::string m_bookingReferenceDir; std::string m_opentableDatafileName; std::string m_opentableReferenceDir; + std::string m_viatorDatafileName; + std::string m_viatorReferenceDir; uint32_t m_versionDate = 0; diff --git a/generator/generator.pro b/generator/generator.pro index 7131cd6fbd..dc1e62f9d7 100644 --- a/generator/generator.pro +++ b/generator/generator.pro @@ -52,6 +52,8 @@ SOURCES += \ towns_dumper.cpp \ traffic_generator.cpp \ unpack_mwm.cpp \ + utils.cpp \ + viator_dataset.cpp \ HEADERS += \ altitude_generator.hpp \ @@ -93,6 +95,7 @@ HEADERS += \ sponsored_dataset.hpp \ sponsored_dataset_inl.hpp \ sponsored_scoring.hpp \ + sponsored_storage.hpp \ srtm_parser.hpp \ statistics.hpp \ tag_admixer.hpp \ @@ -100,5 +103,7 @@ HEADERS += \ towns_dumper.hpp \ traffic_generator.hpp \ unpack_mwm.hpp \ + utils.hpp \ + viator_dataset.hpp \ ways_merger.hpp \ world_map_generator.hpp \ diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index b18a2e3c6c..a5329a6f0c 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -86,6 +86,8 @@ DEFINE_string(booking_data, "", "Path to booking data in .tsv format."); DEFINE_string(booking_reference_path, "", "Path to mwm dataset for booking addresses matching."); DEFINE_string(opentable_data, "", "Path to opentable data in .tsv format."); DEFINE_string(opentable_reference_path, "", "Path to mwm dataset for opentable addresses matching."); +DEFINE_string(viator_data, "", "Path to viator data in .tsv format."); +DEFINE_string(viator_reference_path, "", "Path to mwm dataset for viator cities matching."); // Printing stuff. DEFINE_bool(calc_statistics, false, "Calculate feature statistics for specified mwm bucket files."); @@ -141,6 +143,8 @@ int main(int argc, char ** argv) genInfo.m_bookingReferenceDir = FLAGS_booking_reference_path; genInfo.m_opentableDatafileName = FLAGS_opentable_data; genInfo.m_opentableReferenceDir = FLAGS_opentable_reference_path; + genInfo.m_viatorDatafileName = FLAGS_viator_data; + genInfo.m_viatorReferenceDir = FLAGS_viator_reference_path; genInfo.m_versionDate = static_cast(FLAGS_planet_version); diff --git a/generator/opentable_dataset.cpp b/generator/opentable_dataset.cpp index 816284a08e..d880d29c7a 100644 --- a/generator/opentable_dataset.cpp +++ b/generator/opentable_dataset.cpp @@ -22,9 +22,9 @@ OpentableRestaurant::OpentableRestaurant(std::string const & src) CHECK_EQUAL(rec.size(), FieldsCount(), ("Error parsing restaurants.tsv line:", boost::replace_all_copy(src, "\t", "\\t"))); - strings::to_uint(rec[FieldIndex(Fields::Id)], m_id.Get()); - strings::to_double(rec[FieldIndex(Fields::Latitude)], m_latLon.lat); - strings::to_double(rec[FieldIndex(Fields::Longtitude)], m_latLon.lon); + CHECK(strings::to_uint(rec[FieldIndex(Fields::Id)], m_id.Get()), ()); + CHECK(strings::to_double(rec[FieldIndex(Fields::Latitude)], m_latLon.lat), ()); + CHECK(strings::to_double(rec[FieldIndex(Fields::Longtitude)], m_latLon.lon), ()); m_name = rec[FieldIndex(Fields::Name)]; m_address = rec[FieldIndex(Fields::Address)]; @@ -54,7 +54,7 @@ void OpentableDataset::PreprocessMatchedOsmObject(ObjectId const matchedObjId, F { FeatureParams params = fb.GetParams(); - auto restaurant = GetObjectById(matchedObjId); + auto restaurant = GetStorage().GetObjectById(matchedObjId); auto & metadata = params.GetMetadata(); metadata.Set(feature::Metadata::FMD_SPONSORED_ID, strings::to_string(restaurant.m_id.Get())); @@ -81,12 +81,11 @@ OpentableDataset::ObjectId OpentableDataset::FindMatchingObjectIdImpl(FeatureBui return Object::InvalidObjectId(); // Find |kMaxSelectedElements| nearest values to a point. - auto const nearbyIds = GetNearestObjects(MercatorBounds::ToLatLon(fb.GetKeyPoint()), - kMaxSelectedElements, kDistanceLimitInMeters); + auto const nearbyIds = GetStorage().GetNearestObjects(MercatorBounds::ToLatLon(fb.GetKeyPoint())); for (auto const objId : nearbyIds) { - if (sponsored_scoring::Match(GetObjectById(objId), fb).IsMatched()) + if (sponsored_scoring::Match(GetStorage().GetObjectById(objId), fb).IsMatched()) return objId; } diff --git a/generator/osm_source.cpp b/generator/osm_source.cpp index 53106fb27e..e569ae50b8 100644 --- a/generator/osm_source.cpp +++ b/generator/osm_source.cpp @@ -14,6 +14,7 @@ #include "generator/booking_dataset.hpp" #include "generator/opentable_dataset.hpp" +#include "generator/viator_dataset.hpp" #include "indexer/classificator.hpp" @@ -262,7 +263,6 @@ private: m2::PointD m_pt; uint32_t m_type; double m_thresholdM; - }; class MainFeaturesEmitter : public EmitterBase @@ -284,6 +284,7 @@ class MainFeaturesEmitter : public EmitterBase generator::BookingDataset m_bookingDataset; generator::OpentableDataset m_opentableDataset; + generator::ViatorDataset m_viatorDataset; /// Used to prepare a list of cities to serve as a list of nodes /// for building a highway graph with OSRM for low zooms. @@ -308,6 +309,7 @@ public: , m_failOnCoasts(info.m_failOnCoasts) , m_bookingDataset(info.m_bookingDatafileName, info.m_bookingReferenceDir) , m_opentableDataset(info.m_opentableDatafileName, info.m_opentableReferenceDir) + , m_viatorDataset(info.m_viatorDatafileName, info.m_viatorReferenceDir) { Classificator const & c = classif(); @@ -354,6 +356,16 @@ public: // The first object which perform action terminates the cahin. if (type != ftype::GetEmptyValue() && !fb.GetName().empty()) { + auto const viatorObjId = m_viatorDataset.FindMatchingObjectId(fb); + if (viatorObjId != generator::ViatorCity::InvalidObjectId()) + { + m_viatorDataset.PreprocessMatchedOsmObject(viatorObjId, fb, [this, viatorObjId](FeatureBuilder1 & fb) + { + m_skippedElements << "VIATOR\t" << DebugPrint(fb.GetMostGenericOsmId()) + << '\t' << viatorObjId.Get() << endl; + }); + } + m_places.ReplaceEqualInRect( Place(fb, type), [](Place const & p1, Place const & p2) { return p1.IsEqual(p2); }, diff --git a/generator/sponsored_dataset.hpp b/generator/sponsored_dataset.hpp index 9bd0f1daf0..edd7dc772c 100644 --- a/generator/sponsored_dataset.hpp +++ b/generator/sponsored_dataset.hpp @@ -1,24 +1,13 @@ #pragma once -#include "indexer/index.hpp" - -#include "search/reverse_geocoder.hpp" - -#include "platform/local_country_file.hpp" -#include "platform/local_country_file_utils.hpp" -#include "platform/platform.hpp" +#include "generator/sponsored_storage.hpp" #include "base/newtype.hpp" #include -#include +#include #include -#include "boost/geometry.hpp" -#include "boost/geometry/geometries/point.hpp" -#include "boost/geometry/geometries/box.hpp" -#include "boost/geometry/index/rtree.hpp" - class FeatureBuilder1; namespace generator @@ -38,13 +27,6 @@ public: explicit SponsoredDataset(std::istream & dataSource, std::string const & addressReferencePath = std::string()); - size_t Size() const { return m_objects.size(); } - - Object const & GetObjectById(ObjectId id) const; - Object & GetObjectById(ObjectId id); - std::vector GetNearestObjects(ms::LatLon const & latLon, size_t limit, - double maxDistance = 0.0) const; - /// @return true if |fb| satisfies some necessary conditions to match one or serveral /// objects from dataset. bool NecessaryMatchingConditionHolds(FeatureBuilder1 const & fb) const; @@ -57,37 +39,18 @@ public: // Creates objects and adds them to the map (MWM) via |fn|. void BuildOsmObjects(std::function const & fn) const; -protected: - class AddressMatcher - { - public: - AddressMatcher(); - void operator()(Object & object); - - private: - Index m_index; - std::unique_ptr m_coder; - }; - - // TODO(mgsergio): Get rid of Box since boost::rtree supports point as value type. - // TODO(mgsergio): Use mercator instead of latlon or boost::geometry::cs::spherical_equatorial - // instead of boost::geometry::cs::cartesian. - using Point = boost::geometry::model::point; - using Box = boost::geometry::model::box; - using Value = std::pair; - - // Create the rtree using default constructor. - boost::geometry::index::rtree> m_rtree; +private: + void InitStorage(); + SponsoredStorage const & GetStorage() const; + SponsoredStorage & GetStorage(); void BuildObject(Object const & object, std::function const & fn) const; - void LoadData(std::istream & src, std::string const & addressReferencePath); - /// @return an id of a matched object or kInvalidObjectId on failure. ObjectId FindMatchingObjectIdImpl(FeatureBuilder1 const & fb) const; - std::map m_objects; + SponsoredStorage m_storage; }; } // namespace generator diff --git a/generator/sponsored_dataset_inl.hpp b/generator/sponsored_dataset_inl.hpp index b437a4041c..c9a8dd612e 100644 --- a/generator/sponsored_dataset_inl.hpp +++ b/generator/sponsored_dataset_inl.hpp @@ -1,96 +1,104 @@ #include "generator/sponsored_dataset.hpp" -#include "geometry/distance_on_sphere.hpp" +#include "generator/utils.hpp" + +#include "search/reverse_geocoder.hpp" + +#include "geometry/latlon.hpp" +#include "geometry/mercator.hpp" #include "base/logging.hpp" +#include "base/stl_add.hpp" #include "base/string_utils.hpp" -#include #include namespace generator { -// AddressMatcher ---------------------------------------------------------------------------------- -template -SponsoredDataset::AddressMatcher::AddressMatcher() +class AddressMatcher { - vector localFiles; - - Platform & platform = GetPlatform(); - platform::FindAllLocalMapsInDirectoryAndCleanup(platform.WritableDir(), 0 /* version */, - -1 /* latestVersion */, localFiles); - - for (platform::LocalCountryFile const & localFile : localFiles) +public: + AddressMatcher() { - LOG(LINFO, ("Found mwm:", localFile)); - try - { - m_index.RegisterMap(localFile); - } - catch (RootException const & ex) - { - CHECK(false, (ex.Msg(), "Bad mwm file:", localFile)); - } + LoadIndex(m_index); + m_coder = make_unique(m_index); } - m_coder = make_unique(m_index); -} - -template -void SponsoredDataset::AddressMatcher::operator()(Object & object) -{ - search::ReverseGeocoder::Address addr; - m_coder->GetNearbyAddress(MercatorBounds::FromLatLon(object.m_latLon), addr); - object.m_street = addr.GetStreetName(); - object.m_houseNumber = addr.GetHouseNumber(); -} + template + void operator()(SponsoredObject & object) + { + search::ReverseGeocoder::Address addr; + m_coder->GetNearbyAddress(MercatorBounds::FromLatLon(object.m_latLon), addr); + object.m_street = addr.GetStreetName(); + object.m_houseNumber = addr.GetHouseNumber(); + } +private: + Index m_index; + std::unique_ptr m_coder; +}; // SponsoredDataset -------------------------------------------------------------------------------- template -SponsoredDataset::SponsoredDataset(std::string const & dataPath, std::string const & addressReferencePath) +SponsoredDataset::SponsoredDataset(std::string const & dataPath, + std::string const & addressReferencePath) + : m_storage(kDistanceLimitInMeters, kMaxSelectedElements) { - if (dataPath.empty()) - return; - - std::ifstream dataSource(dataPath); - if (!dataSource.is_open()) - { - LOG(LERROR, ("Error while opening", dataPath, ":", strerror(errno))); - return; - } - - LoadData(dataSource, addressReferencePath); + InitStorage(); + GetStorage().LoadData(dataPath, addressReferencePath); } template -SponsoredDataset::SponsoredDataset(std::istream & dataSource, std::string const & addressReferencePath) +SponsoredDataset::SponsoredDataset(std::istream & dataSource, + std::string const & addressReferencePath) + : m_storage(kDistanceLimitInMeters, kMaxSelectedElements) { - LoadData(dataSource, addressReferencePath); + InitStorage(); + GetStorage().LoadData(dataSource, addressReferencePath); } template -typename SponsoredDataset::Object const & -SponsoredDataset::GetObjectById(ObjectId id) const +void SponsoredDataset::InitStorage() { - auto const it = m_objects.find(id); - CHECK(it != end(m_objects), ("Got wrong object id:", id)); - return it->second; + using Container = typename SponsoredStorage::ObjectsContainer; + + m_storage.SetFillObject([](Container & objects) { + AddressMatcher addressMatcher; + + size_t matchedCount = 0; + size_t emptyCount = 0; + for (auto & item : objects) + { + auto & object = item.second; + addressMatcher(object); + + if (object.m_address.empty()) + ++emptyCount; + if (object.HasAddresParts()) + ++matchedCount; + } + + LOG(LINFO, ("Num of objects:", objects.size(), "matched:", matchedCount, "empty addresses:", + emptyCount)); + }); } template -typename SponsoredDataset::Object & -SponsoredDataset::GetObjectById(ObjectId id) +SponsoredStorage const & SponsoredDataset::GetStorage() const { - auto const it = m_objects.find(id); - CHECK(it != end(m_objects), ("Got wrong object id:", id)); - return it->second; + return m_storage; +} + +template +SponsoredStorage & SponsoredDataset::GetStorage() +{ + return m_storage; } template void SponsoredDataset::BuildOsmObjects(function const & fn) const { - for (auto const & item : m_objects) + for (auto const & item : GetStorage().GetObjects()) BuildObject(item.second, fn); } @@ -102,78 +110,4 @@ SponsoredDataset::FindMatchingObjectId(FeatureBuilder1 const & return FindMatchingObjectIdImpl(fb); return Object::InvalidObjectId(); } - -template -vector::ObjectId> -SponsoredDataset::GetNearestObjects(ms::LatLon const & latLon, size_t const limit, - double const maxDistanceMeters /* = 0.0 */) const -{ - namespace bgi = boost::geometry::index; - - vector indexes; - for_each(bgi::qbegin(m_rtree, bgi::nearest(Point(latLon.lat, latLon.lon), static_cast(limit))), - bgi::qend(m_rtree), [this, &latLon, &indexes, maxDistanceMeters](Value const & v) - { - auto const & object = GetObjectById(v.second); - double const dist = ms::DistanceOnEarth(latLon, object.m_latLon); - if (maxDistanceMeters != 0.0 && dist > maxDistanceMeters /* max distance in meters */) - return; - - indexes.emplace_back(v.second); - }); - - return indexes; -} - -template -void SponsoredDataset::LoadData(std::istream & src, std::string const & addressReferencePath) -{ - m_objects.clear(); - m_rtree.clear(); - - for (std::string line; std::getline(src, line);) - { - Object hotel(line); - m_objects.emplace(hotel.m_id, hotel); - } - - // Try to get object address from existing MWMs. - if (!addressReferencePath.empty()) - { - LOG(LINFO, ("Reference addresses for sponsored objects", addressReferencePath)); - Platform & platform = GetPlatform(); - std::string const backupPath = platform.WritableDir(); - - // MWMs can be loaded only from a writebledir or from a resourcedir, - // changig resourcedir can lead to probles with classificator, so - // we change writebledir. - platform.SetWritableDirForTests(addressReferencePath); - - AddressMatcher addressMatcher; - - size_t matchedCount = 0; - size_t emptyCount = 0; - for (auto & item : m_objects) - { - auto & object = item.second; - addressMatcher(object); - - if (object.m_address.empty()) - ++emptyCount; - if (object.HasAddresParts()) - ++matchedCount; - } - LOG(LINFO, - ("Num of hotels:", m_objects.size(), "matched:", matchedCount, "empty addresses:", emptyCount)); - platform.SetWritableDirForTests(backupPath); - } - - for (auto const & item : m_objects) - { - auto const & object = item.second; - Box b(Point(object.m_latLon.lat, object.m_latLon.lon), - Point(object.m_latLon.lat, object.m_latLon.lon)); - m_rtree.insert(make_pair(b, object.m_id)); - } -} } // namespace generator diff --git a/generator/sponsored_storage.hpp b/generator/sponsored_storage.hpp new file mode 100644 index 0000000000..ad51174ff1 --- /dev/null +++ b/generator/sponsored_storage.hpp @@ -0,0 +1,165 @@ +#pragma once + +#include "platform/platform.hpp" + +#include "geometry/distance_on_sphere.hpp" +#include "geometry/latlon.hpp" + +#include "base/logging.hpp" + +#include +#include +#include +#include +#include + +#include "boost/geometry.hpp" +#include "boost/geometry/geometries/box.hpp" +#include "boost/geometry/geometries/point.hpp" +#include "boost/geometry/index/rtree.hpp" + +namespace generator +{ +template +class SponsoredStorage +{ +public: + using ObjectId = typename Object::ObjectId; + using ObjectsContainer = std::map; + using FillObject = std::function; + + SponsoredStorage(double distanceLimitMeters, size_t maxSelectedElements, + FillObject const & fn = {}) + : m_distanceLimitMeters(distanceLimitMeters) + , m_maxSelectedElements(maxSelectedElements) + , m_fillObject(fn) + { + } + + double GetDistanceLimitInMeters() const + { + return m_distanceLimitMeters; + } + + size_t GetMaxSelectedElements() const + { + return m_maxSelectedElements; + } + + ObjectsContainer const & GetObjects() const + { + return m_objects; + } + + size_t Size() const + { + return m_objects.size(); + } + + void SetFillObject(FillObject const & fn) + { + m_fillObject = fn; + } + + void LoadData(std::string const & dataPath, std::string const & addressReferencePath) + { + if (dataPath.empty()) + return; + + std::ifstream dataSource(dataPath); + if (!dataSource.is_open()) + { + LOG(LERROR, ("Error while opening", dataPath, ":", strerror(errno))); + return; + } + + LoadData(dataSource, addressReferencePath); + } + + void LoadData(std::istream & src, std::string const & addressReferencePath) + { + m_objects.clear(); + m_rtree.clear(); + + for (std::string line; std::getline(src, line);) + { + Object object(line); + m_objects.emplace(object.m_id, object); + } + + // Try to get object address from existing MWMs. + if (!addressReferencePath.empty()) + { + LOG(LINFO, ("Reference addresses for sponsored objects", addressReferencePath)); + Platform & platform = GetPlatform(); + std::string const backupPath = platform.WritableDir(); + + // MWMs can be loaded only from a writebledir or from a resourcedir, + // changig resourcedir can lead to probles with classificator, so + // we change writebledir. + platform.SetWritableDirForTests(addressReferencePath); + + m_fillObject(m_objects); + + platform.SetWritableDirForTests(backupPath); + } + + for (auto const & item : m_objects) + { + auto const & object = item.second; + Box b(Point(object.m_latLon.lat, object.m_latLon.lon), + Point(object.m_latLon.lat, object.m_latLon.lon)); + m_rtree.insert(make_pair(b, object.m_id)); + } + } + + Object const & GetObjectById(ObjectId id) const + { + auto const it = m_objects.find(id); + CHECK(it != end(m_objects), ("Got wrong object id:", id)); + return it->second; + } + + Object & GetObjectById(ObjectId id) + { + auto const it = m_objects.find(id); + CHECK(it != end(m_objects), ("Got wrong object id:", id)); + return it->second; + } + + std::vector GetNearestObjects(ms::LatLon const & latLon) const + { + namespace bgi = boost::geometry::index; + + std::vector indexes; + for_each(bgi::qbegin(m_rtree, bgi::nearest(Point(latLon.lat, latLon.lon), + static_cast(m_maxSelectedElements))), + bgi::qend(m_rtree), [this, &latLon, &indexes](Value const & v) { + auto const & object = GetObjectById(v.second); + double const dist = ms::DistanceOnEarth(latLon, object.m_latLon); + if (m_distanceLimitMeters != 0.0 && dist > m_distanceLimitMeters) + return; + + indexes.emplace_back(v.second); + }); + + return indexes; + } + +private: + // TODO(mgsergio): Get rid of Box since boost::rtree supports point as value type. + // TODO(mgsergio): Use mercator instead of latlon or boost::geometry::cs::spherical_equatorial + // instead of boost::geometry::cs::cartesian. + using Point = boost::geometry::model::point; + using Box = boost::geometry::model::box; + using Value = std::pair; + + // Create the rtree using default constructor. + boost::geometry::index::rtree> m_rtree; + ObjectsContainer m_objects; + + double const m_distanceLimitMeters; + size_t const m_maxSelectedElements; + FillObject m_fillObject; +}; +} // namespace generator diff --git a/generator/utils.cpp b/generator/utils.cpp new file mode 100644 index 0000000000..9981ad8b10 --- /dev/null +++ b/generator/utils.cpp @@ -0,0 +1,29 @@ +#include "generator/utils.hpp" + +#include "platform/local_country_file.hpp" +#include "platform/local_country_file_utils.hpp" +#include "platform/platform.hpp" + +namespace generator +{ +void LoadIndex(Index & index) +{ + vector localFiles; + + Platform & platform = GetPlatform(); + platform::FindAllLocalMapsInDirectoryAndCleanup(platform.WritableDir(), 0 /* version */, + -1 /* latestVersion */, localFiles); + for (platform::LocalCountryFile const & localFile : localFiles) + { + LOG(LINFO, ("Found mwm:", localFile)); + try + { + index.RegisterMap(localFile); + } + catch (RootException const & ex) + { + CHECK(false, (ex.Msg(), "Bad mwm file:", localFile)); + } + } +} +} // namespace generator diff --git a/generator/utils.hpp b/generator/utils.hpp new file mode 100644 index 0000000000..f00dba6e5c --- /dev/null +++ b/generator/utils.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "indexer/index.hpp" + +namespace generator +{ +void LoadIndex(Index & index); +} // namespace generator diff --git a/generator/viator_dataset.cpp b/generator/viator_dataset.cpp new file mode 100644 index 0000000000..64264fd874 --- /dev/null +++ b/generator/viator_dataset.cpp @@ -0,0 +1,111 @@ +#include "generator/viator_dataset.hpp" + +#include "generator/feature_builder.hpp" +#include "generator/utils.hpp" + +#include "indexer/classificator.hpp" +#include "indexer/ftypes_matcher.hpp" + +#include "coding/multilang_utf8_string.hpp" + +#include "geometry/mercator.hpp" + +#include "boost/algorithm/string/replace.hpp" + +namespace +{ +enum class TsvFields +{ + Id = 0, + Name, + Latitude, + Longtitude, + + FieldsCount +}; + +static constexpr size_t FieldIndex(TsvFields field) { return static_cast(field); } +static constexpr size_t FieldsCount() { return static_cast(TsvFields::FieldsCount); } +} // namespace + +namespace generator +{ +// ViatorCity ------------------------------------------------------------------------------------- +ViatorCity::ViatorCity(std::string const & src) +{ + vector rec; + strings::ParseCSVRow(src, '\t', rec); + CHECK_EQUAL(rec.size(), FieldsCount(), + ("Error parsing viator cities line:", boost::replace_all_copy(src, "\t", "\\t"))); + + CHECK(strings::to_uint(rec[FieldIndex(TsvFields::Id)], m_id.Get()), ()); + CHECK(strings::to_double(rec[FieldIndex(TsvFields::Latitude)], m_latLon.lat), ()); + CHECK(strings::to_double(rec[FieldIndex(TsvFields::Longtitude)], m_latLon.lon), ()); + + m_name = rec[FieldIndex(TsvFields::Name)]; +} + +ostream & operator<<(ostream & s, ViatorCity const & h) +{ + s << std::fixed << std::setprecision(7); + return s << "Id: " << h.m_id << "\t Name: " << h.m_name << "\t lat: " << h.m_latLon.lat + << " lon: " << h.m_latLon.lon; +} + +// ViatorDataset ---------------------------------------------------------------------------------- +ViatorDataset::ViatorDataset(std::string const & dataPath, std::string const & addressReferencePath) + : m_storage(3000.0 /* distanceLimitMeters */, 3 /* maxSelectedElements */) +{ + LoadIndex(m_index); + m_cityFinder = make_unique(m_index); + + m_storage.LoadData(dataPath, addressReferencePath); +} + +ViatorCity::ObjectId ViatorDataset::FindMatchingObjectId(FeatureBuilder1 const & fb) const +{ + if (!ftypes::IsCityChecker::Instance()(fb.GetTypes())) + return ViatorCity::InvalidObjectId(); + + auto const name = m_cityFinder->GetCityName(fb.GetKeyPoint(), StringUtf8Multilang::kEnglishCode); + + auto const nearbyIds = m_storage.GetNearestObjects(MercatorBounds::ToLatLon(fb.GetKeyPoint())); + + for (auto const objId : nearbyIds) + { + auto const city = m_storage.GetObjectById(objId); + if (name == city.m_name) + return objId; + + auto const viatorName = m_cityFinder->GetCityName(MercatorBounds::FromLatLon(city.m_latLon), + StringUtf8Multilang::kEnglishCode); + if (name == viatorName) + return objId; + } + + if (!nearbyIds.empty()) + LOG(LWARNING, ("Viator city matching failed! " + "OSM city:", name, "OSM point:", fb.GetKeyPoint(), + "Viator cities:", nearbyIds)); + + return ViatorCity::InvalidObjectId(); +} + +void ViatorDataset::PreprocessMatchedOsmObject(ViatorCity::ObjectId const matchedObjId, + FeatureBuilder1 & fb, + function const fn) const +{ + FeatureParams params = fb.GetParams(); + + auto city = m_storage.GetObjectById(matchedObjId); + auto & metadata = params.GetMetadata(); + metadata.Set(feature::Metadata::FMD_SPONSORED_ID, strings::to_string(city.m_id.Get())); + + auto const & clf = classif(); + params.AddType(clf.GetTypeByPath({"sponsored", "viator"})); + + fb.SetParams(params); + + fn(fb); +} +} // namespace generator diff --git a/generator/viator_dataset.hpp b/generator/viator_dataset.hpp new file mode 100644 index 0000000000..d5af5980d8 --- /dev/null +++ b/generator/viator_dataset.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include "generator/sponsored_storage.hpp" + +#include "search/city_finder.hpp" + +#include "indexer/index.hpp" + +#include "geometry/latlon.hpp" + +#include "base/newtype.hpp" + +#include +#include +#include + +namespace generator +{ +struct ViatorCity +{ + explicit ViatorCity(std::string const & src); + + NEWTYPE(uint32_t, ObjectId); + + static constexpr ObjectId InvalidObjectId() + { + return ObjectId(std::numeric_limits::max()); + } + + ObjectId m_id{InvalidObjectId()}; + ms::LatLon m_latLon = ms::LatLon::Zero(); + std::string m_name; +}; + +ostream & operator<<(ostream & s, ViatorCity const & r); + +NEWTYPE_SIMPLE_OUTPUT(ViatorCity::ObjectId); + +class ViatorDataset +{ +public: + ViatorDataset(std::string const & dataPath, std::string const & addressReferencePath); + + ViatorCity::ObjectId FindMatchingObjectId(FeatureBuilder1 const & fb) const; + + void PreprocessMatchedOsmObject(ViatorCity::ObjectId const matchedObjId, FeatureBuilder1 & fb, + function const fn) const; + +private: + SponsoredStorage m_storage; + Index m_index; + std::unique_ptr m_cityFinder; +}; +} // namespace generator diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index ba103554a7..c8abde6d8f 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -500,6 +500,17 @@ IsInvisibleIndexedChecker const & IsInvisibleIndexedChecker::Instance() return instance; } +IsCityChecker::IsCityChecker() +{ + m_types.push_back(classif().GetTypeByPath({"place", "city"})); +} + +IsCityChecker const & IsCityChecker::Instance() +{ + static IsCityChecker const inst; + return inst; +} + IsViatorChecker::IsViatorChecker() { m_types.push_back(classif().GetTypeByPath({"sponsored", "viator"})); diff --git a/indexer/ftypes_matcher.hpp b/indexer/ftypes_matcher.hpp index b092ecf51a..eba5abbe22 100644 --- a/indexer/ftypes_matcher.hpp +++ b/indexer/ftypes_matcher.hpp @@ -225,6 +225,14 @@ public: static IsInvisibleIndexedChecker const & Instance(); }; +class IsCityChecker : public BaseChecker +{ + IsCityChecker(); + +public: + static IsCityChecker const & Instance(); +}; + class IsViatorChecker : public BaseChecker { IsViatorChecker(); diff --git a/map/framework.cpp b/map/framework.cpp index c4a924ebc6..2ef27fa5c7 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -180,7 +180,7 @@ void CancelQuery(weak_ptr & handle) handle.reset(); } -string MakeSearchBookingUrl(booking::Api const & bookingApi, CityFinder & cityFinder, +string MakeSearchBookingUrl(booking::Api const & bookingApi, search::CityFinder & cityFinder, FeatureType const & ft) { string name; @@ -469,7 +469,7 @@ Framework::Framework(FrameworkParams const & params) m_trafficManager.SetCurrentDataVersion(m_storage.GetCurrentDataVersion()); - m_cityFinder = make_unique(m_model.GetIndex()); + m_cityFinder = make_unique(m_model.GetIndex()); m_adsEngine = make_unique(); diff --git a/map/framework.hpp b/map/framework.hpp index cf341c277b..60c3f9bfc4 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -3,7 +3,6 @@ #include "map/api_mark_point.hpp" #include "map/bookmark.hpp" #include "map/bookmark_manager.hpp" -#include "map/city_finder.hpp" #include "map/displacement_mode_manager.hpp" #include "map/feature_vec_model.hpp" #include "map/local_ads_manager.hpp" @@ -29,6 +28,7 @@ #include "editor/user_stats.hpp" +#include "search/city_finder.hpp" #include "search/displayed_categories.hpp" #include "search/downloader_search_callback.hpp" #include "search/engine.hpp" @@ -834,6 +834,6 @@ public: storage::TCountriesVec GetTopmostCountries(ms::LatLon const & latlon) const; private: - std::unique_ptr m_cityFinder; + std::unique_ptr m_cityFinder; unique_ptr m_adsEngine; }; diff --git a/map/map.pro b/map/map.pro index 548d644b59..9c6d62d46d 100644 --- a/map/map.pro +++ b/map/map.pro @@ -16,7 +16,6 @@ HEADERS += \ bookmark.hpp \ bookmark_manager.hpp \ chart_generator.hpp \ - city_finder.hpp \ displacement_mode_manager.hpp \ feature_vec_model.hpp \ framework.hpp \ diff --git a/search/CMakeLists.txt b/search/CMakeLists.txt index e4d5108b4c..e817fa3e22 100644 --- a/search/CMakeLists.txt +++ b/search/CMakeLists.txt @@ -11,6 +11,7 @@ set( categories_set.hpp cbv.cpp cbv.hpp + city_finder.hpp common.hpp displayed_categories.cpp displayed_categories.hpp diff --git a/map/city_finder.hpp b/search/city_finder.hpp similarity index 93% rename from map/city_finder.hpp rename to search/city_finder.hpp index 0854435a84..9f1b0c0500 100644 --- a/map/city_finder.hpp +++ b/search/city_finder.hpp @@ -9,6 +9,8 @@ #include +namespace search +{ class CityFinder { public: @@ -30,3 +32,4 @@ private: search::VillagesCache m_unusedCache; search::LocalityFinder m_finder; }; +} // namespace search diff --git a/search/search.pro b/search/search.pro index 58f50edf58..119a31026c 100644 --- a/search/search.pro +++ b/search/search.pro @@ -15,6 +15,7 @@ HEADERS += \ categories_cache.hpp \ categories_set.hpp \ cbv.hpp \ + city_finder.hpp \ common.hpp \ displayed_categories.hpp \ downloader_search_callback.hpp \ diff --git a/tools/python/viator_cities.py b/tools/python/viator_cities.py new file mode 100644 index 0000000000..36c4423b11 --- /dev/null +++ b/tools/python/viator_cities.py @@ -0,0 +1,72 @@ +from __future__ import print_function + +import argparse +import json +import logging +import os +import urllib2 + +logging.basicConfig(level=logging.DEBUG, format='[%(asctime)s] %(levelname)s: %(message)s') + + +class ViatorApi(object): + def __init__(self, apikey): + self.apikey = apikey + + def get_locations(self): + url = 'http://viatorapi.viator.com/service/taxonomy/locations?apiKey=' + self.apikey + request = urllib2.Request(url) + stream = urllib2.urlopen(request) + payload = stream.read() + locations = json.loads(payload) + return locations + + +def check_errors(locations): + if not locations['success']: + raise Exception('Viator error, error codes:{} error text:{}' + .format(locations['errorCodes'], locations['errorMessageText'])) + + +def save_cities(locations, output_file_name): + with open(output_file_name, 'w') as output_file: + for l in locations['data']: + if l['destinationType'] == 'CITY' and l['destinationId'] and \ + l['destinationName'] and l['latitude'] and l['longitude']: + city = '\t'.join([ + str(l['destinationId']), + l['destinationName'], + str(l['latitude']), + str(l['longitude']) + ]) + print(city.encode('utf-8'), file=output_file) + + +def run(options): + try: + api = ViatorApi(options.apikey) + locations = api.get_locations() + check_errors(locations) + save_cities(locations, options.output) + except Exception as e: + logging.exception(e) + + +def process_options(): + parser = argparse.ArgumentParser(description='Download and process viator cities.') + + parser.add_argument('--apikey', dest='apikey', help='Viator apikey', required=True) + parser.add_argument('--output', dest='output', help='Destination file', required=True) + + options = parser.parse_args() + + return options + + +def main(): + options = process_options() + run(options) + + +if __name__ == '__main__': + main() diff --git a/tools/unix/generate_planet.sh b/tools/unix/generate_planet.sh index 4d0211b95a..debdb2e4c0 100755 --- a/tools/unix/generate_planet.sh +++ b/tools/unix/generate_planet.sh @@ -181,6 +181,8 @@ BOOKING_SCRIPT="$PYTHON_SCRIPTS_PATH/booking_hotels.py" BOOKING_FILE="${BOOKING_FILE:-$INTDIR/hotels.csv}" OPENTABLE_SCRIPT="$PYTHON_SCRIPTS_PATH/opentable_restaurants.py" OPENTABLE_FILE="${OPENTABLE_FILE:-$INTDIR/restaurants.csv}" +VIATOR_SCRIPT="$PYTHON_SCRIPTS_PATH/viator_cities.py" +VIATOR_FILE="${VIATOR_FILE:-$INTDIR/viator.csv}" TESTING_SCRIPT="$SCRIPTS_PATH/test_planet.sh" PYTHON="$(which python2.7)" MWM_VERSION_FORMAT="%s" @@ -295,6 +297,25 @@ if [ ! -f "$OPENTABLE_FILE" -a -n "${OPENTABLE_USER-}" -a -n "${OPENTABLE_PASS-} ) & fi +# Download viator.com cities. This takes around 3 seconds. +if [ ! -f "$VIATOR_FILE" -a -n "${VIATOR_KEY-}" ]; then + log "STATUS" "Step S3: Starting background viator cities downloading" + ( + $PYTHON $VIATOR_SCRIPT --apikey $VIATOR_KEY --output "$VIATOR_FILE" 2>"$LOG_PATH"/viator.log || true + if [ -f "$VIATOR_FILE" -a "$(wc -l < "$VIATOR_FILE" || echo 0)" -gt 100 ]; then + echo "Viator cities have been downloaded. Please ensure this line is before Step 4." >> "$PLANET_LOG" + else + if [ -n "${OLD_INTDIR-}" -a -f "${OLD_INTDIR-}/$(basename "$VIATOR_FILE")" ]; then + cp "$OLD_INTDIR/$(basename "$VIATOR_FILE")" "$INTDIR" + warn "Failed to download viator cities! Using older viator cities list." + else + warn "Failed to download viator cities!" + fi + [ -n "${MAIL-}" ] && tail "$LOG_PATH/viator.log" | mailx -s "Failed to download viator cities at $(hostname), please hurry to fix" "$MAIL" + fi + ) & +fi + if [ "$MODE" == "coast" ]; then putmode @@ -419,6 +440,7 @@ if [ "$MODE" == "features" ]; then [ -n "$OPT_WORLD" -a "$NODE_STORAGE" == "map" ] && warn "generating world files with NODE_STORAGE=map may lead to an out of memory error. Try NODE_STORAGE=mem if it fails." [ -f "$BOOKING_FILE" ] && PARAMS_SPLIT="$PARAMS_SPLIT --booking_data=$BOOKING_FILE" [ -f "$OPENTABLE_FILE" ] && PARAMS_SPLIT="$PARAMS_SPLIT --opentable_data=$OPENTABLE_FILE" + [ -f "$VIATOR_FILE" ] && PARAMS_SPLIT="$PARAMS_SPLIT --viator_data=$VIATOR_FILE" "$GENERATOR_TOOL" --intermediate_data_path="$INTDIR/" --node_storage=$NODE_STORAGE --osm_file_type=o5m --osm_file_name="$PLANET" \ --data_path="$TARGET" --user_resource_path="$DATA_PATH/" $PARAMS_SPLIT 2>> "$PLANET_LOG" MODE=mwm diff --git a/xcode/generator/generator.xcodeproj/project.pbxproj b/xcode/generator/generator.xcodeproj/project.pbxproj index 5683681950..e0e6023dd6 100644 --- a/xcode/generator/generator.xcodeproj/project.pbxproj +++ b/xcode/generator/generator.xcodeproj/project.pbxproj @@ -28,6 +28,11 @@ 3D51BC571D5E512500F1FA8D /* region_meta.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D51BC4F1D5E512500F1FA8D /* region_meta.hpp */; }; 3D51BC581D5E512500F1FA8D /* srtm_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D51BC501D5E512500F1FA8D /* srtm_parser.cpp */; }; 3D51BC591D5E512500F1FA8D /* srtm_parser.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D51BC511D5E512500F1FA8D /* srtm_parser.hpp */; }; + 3DFEBF7C1EF2D58900317D5C /* sponsored_storage.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DFEBF771EF2D58900317D5C /* sponsored_storage.hpp */; }; + 3DFEBF7D1EF2D58900317D5C /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEBF781EF2D58900317D5C /* utils.cpp */; }; + 3DFEBF7E1EF2D58900317D5C /* utils.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DFEBF791EF2D58900317D5C /* utils.hpp */; }; + 3DFEBF7F1EF2D58900317D5C /* viator_dataset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEBF7A1EF2D58900317D5C /* viator_dataset.cpp */; }; + 3DFEBF801EF2D58900317D5C /* viator_dataset.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DFEBF7B1EF2D58900317D5C /* viator_dataset.hpp */; }; 670B84BC1A8CDB0000CE4492 /* osm_source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670B84BA1A8CDB0000CE4492 /* osm_source.cpp */; }; 670B84BD1A8CDB0000CE4492 /* osm_source.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 670B84BB1A8CDB0000CE4492 /* osm_source.hpp */; }; 6726C1D51A4AFEF4005EEA39 /* osm2meta.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6726C1D31A4AFEF4005EEA39 /* osm2meta.cpp */; }; @@ -119,6 +124,11 @@ 3D51BC4F1D5E512500F1FA8D /* region_meta.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = region_meta.hpp; sourceTree = ""; }; 3D51BC501D5E512500F1FA8D /* srtm_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = srtm_parser.cpp; sourceTree = ""; }; 3D51BC511D5E512500F1FA8D /* srtm_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = srtm_parser.hpp; sourceTree = ""; }; + 3DFEBF771EF2D58900317D5C /* sponsored_storage.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = sponsored_storage.hpp; sourceTree = ""; }; + 3DFEBF781EF2D58900317D5C /* utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utils.cpp; sourceTree = ""; }; + 3DFEBF791EF2D58900317D5C /* utils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = utils.hpp; sourceTree = ""; }; + 3DFEBF7A1EF2D58900317D5C /* viator_dataset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = viator_dataset.cpp; sourceTree = ""; }; + 3DFEBF7B1EF2D58900317D5C /* viator_dataset.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = viator_dataset.hpp; sourceTree = ""; }; 670B84BA1A8CDB0000CE4492 /* osm_source.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = osm_source.cpp; sourceTree = ""; }; 670B84BB1A8CDB0000CE4492 /* osm_source.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = osm_source.hpp; sourceTree = ""; }; 6726C1D31A4AFEF4005EEA39 /* osm2meta.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = osm2meta.cpp; sourceTree = ""; }; @@ -231,6 +241,11 @@ 6753401D1A3F2A1B00A0A8C3 /* generator */ = { isa = PBXGroup; children = ( + 3DFEBF771EF2D58900317D5C /* sponsored_storage.hpp */, + 3DFEBF781EF2D58900317D5C /* utils.cpp */, + 3DFEBF791EF2D58900317D5C /* utils.hpp */, + 3DFEBF7A1EF2D58900317D5C /* viator_dataset.cpp */, + 3DFEBF7B1EF2D58900317D5C /* viator_dataset.hpp */, 67C79BA71E2CEEAB00C40034 /* restriction_collector.cpp */, 67C79BA81E2CEEAB00C40034 /* restriction_collector.hpp */, 67C79BA91E2CEEAB00C40034 /* restriction_generator.cpp */, @@ -349,6 +364,7 @@ 675340631A3F2A7400A0A8C3 /* coastlines_generator.hpp in Headers */, 675340641A3F2A7400A0A8C3 /* intermediate_data.hpp in Headers */, 675340781A3F2A7400A0A8C3 /* intermediate_elements.hpp in Headers */, + 3DFEBF7E1EF2D58900317D5C /* utils.hpp in Headers */, 6753406B1A3F2A7400A0A8C3 /* feature_emitter_iface.hpp in Headers */, 6753408C1A3F2A7400A0A8C3 /* world_map_generator.hpp in Headers */, 67C79BB41E2CEEAB00C40034 /* restriction_writer.hpp in Headers */, @@ -363,8 +379,10 @@ 34F5588B1DBF4C9600A4FC11 /* sponsored_dataset.hpp in Headers */, 6753405F1A3F2A7400A0A8C3 /* borders_loader.hpp in Headers */, 675340801A3F2A7400A0A8C3 /* polygonizer.hpp in Headers */, + 3DFEBF7C1EF2D58900317D5C /* sponsored_storage.hpp in Headers */, 0C5FEC711DDE19E50017688C /* routing_index_generator.hpp in Headers */, 67C79BB01E2CEEAB00C40034 /* restriction_collector.hpp in Headers */, + 3DFEBF801EF2D58900317D5C /* viator_dataset.hpp in Headers */, 675340941C5231BA002CF0D9 /* search_index_builder.hpp in Headers */, 3D51BC591D5E512500F1FA8D /* srtm_parser.hpp in Headers */, 677E2A181CAACC5F001DC42A /* towns_dumper.hpp in Headers */, @@ -485,11 +503,13 @@ 675340701A3F2A7400A0A8C3 /* feature_sorter.cpp in Sources */, 675340621A3F2A7400A0A8C3 /* coastlines_generator.cpp in Sources */, 675340811A3F2A7400A0A8C3 /* routing_generator.cpp in Sources */, + 3DFEBF7F1EF2D58900317D5C /* viator_dataset.cpp in Sources */, 675340931C5231BA002CF0D9 /* search_index_builder.cpp in Sources */, 6753406E1A3F2A7400A0A8C3 /* feature_merger.cpp in Sources */, 34F5587B1DBF4C8300A4FC11 /* feature_segments_checker.cpp in Sources */, 67C79BB31E2CEEAB00C40034 /* restriction_writer.cpp in Sources */, 67A0FEBE1CEB467F008F2A61 /* booking_dataset.cpp in Sources */, + 3DFEBF7D1EF2D58900317D5C /* utils.cpp in Sources */, 6753408D1A3F2A7400A0A8C3 /* osm_element.cpp in Sources */, 6726C1D51A4AFEF4005EEA39 /* osm2meta.cpp in Sources */, 34F5588C1DBF4C9600A4FC11 /* sponsored_scoring.cpp in Sources */, diff --git a/xcode/search/search.xcodeproj/project.pbxproj b/xcode/search/search.xcodeproj/project.pbxproj index bfe237a0c1..ba7337cf95 100644 --- a/xcode/search/search.xcodeproj/project.pbxproj +++ b/xcode/search/search.xcodeproj/project.pbxproj @@ -75,6 +75,7 @@ 397AFE071D6C9AC700F583E7 /* downloader_search_callback.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 397AFE051D6C9AC700F583E7 /* downloader_search_callback.hpp */; }; 3DF37FAA1EA11B380012CB31 /* everywhere_search_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF37FA81EA11B380012CB31 /* everywhere_search_callback.cpp */; }; 3DF37FAB1EA11B380012CB31 /* everywhere_search_callback.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DF37FA91EA11B380012CB31 /* everywhere_search_callback.hpp */; }; + 3DFEBF761EF2D55800317D5C /* city_finder.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DFEBF751EF2D55800317D5C /* city_finder.hpp */; }; 56D5456E1C74A48C00E3719C /* mode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56D5456C1C74A48C00E3719C /* mode.cpp */; }; 56D5456F1C74A48C00E3719C /* mode.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56D5456D1C74A48C00E3719C /* mode.hpp */; }; 670F88741CE4C032003F68BA /* types_skipper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670F88721CE4C032003F68BA /* types_skipper.cpp */; }; @@ -258,6 +259,7 @@ 397AFE051D6C9AC700F583E7 /* downloader_search_callback.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = downloader_search_callback.hpp; sourceTree = ""; }; 3DF37FA81EA11B380012CB31 /* everywhere_search_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = everywhere_search_callback.cpp; sourceTree = ""; }; 3DF37FA91EA11B380012CB31 /* everywhere_search_callback.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = everywhere_search_callback.hpp; sourceTree = ""; }; + 3DFEBF751EF2D55800317D5C /* city_finder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = city_finder.hpp; sourceTree = ""; }; 56D5456C1C74A48C00E3719C /* mode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mode.cpp; sourceTree = ""; }; 56D5456D1C74A48C00E3719C /* mode.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = mode.hpp; sourceTree = ""; }; 670F88721CE4C032003F68BA /* types_skipper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types_skipper.cpp; sourceTree = ""; }; @@ -488,6 +490,7 @@ 675346B21A4055CF00A0A8C3 /* search */ = { isa = PBXGroup; children = ( + 3DFEBF751EF2D55800317D5C /* city_finder.hpp */, 3DF37FA81EA11B380012CB31 /* everywhere_search_callback.cpp */, 3DF37FA91EA11B380012CB31 /* everywhere_search_callback.hpp */, 675346BE1A40560D00A0A8C3 /* algos.hpp */, @@ -707,6 +710,7 @@ 3441CE531CFC1D7000CF30D4 /* query_params.hpp in Headers */, 3DF37FAB1EA11B380012CB31 /* everywhere_search_callback.hpp in Headers */, 3453BD591DAF91C100380ECB /* emitter.hpp in Headers */, + 3DFEBF761EF2D55800317D5C /* city_finder.hpp in Headers */, F6E2B0001D9E794800793C36 /* categories_cache.hpp in Headers */, 679624961D10137D00AE4E3C /* test_results_matching.hpp in Headers */, 675346DC1A40560D00A0A8C3 /* algos.hpp in Headers */,