Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Magidovich <mgsergio@mapswithme.com>2016-07-30 16:35:14 +0300
committerSergey Magidovich <mgsergio@mapswithme.com>2016-08-02 17:04:05 +0300
commit177a515c8581e7b9e51206449efce5d8d6853cff (patch)
tree42b7d849e76a41ea6576593aeb62c30039e63ea3 /generator
parent9d821509fe11748aa6f2045dd78f2d7feb27d415 (diff)
Use FeatureBuilder insted of OsmelElement to handle geometry.
Handle booking in Emitter.
Diffstat (limited to 'generator')
-rw-r--r--generator/booking_dataset.cpp181
-rw-r--r--generator/booking_dataset.hpp18
-rw-r--r--generator/booking_quality_check/booking_quality_check.cpp212
-rw-r--r--generator/booking_scoring.cpp11
-rw-r--r--generator/booking_scoring.hpp4
-rw-r--r--generator/osm_source.cpp61
6 files changed, 278 insertions, 209 deletions
diff --git a/generator/booking_dataset.cpp b/generator/booking_dataset.cpp
index 60745a6364..d9e0945ed1 100644
--- a/generator/booking_dataset.cpp
+++ b/generator/booking_dataset.cpp
@@ -1,10 +1,12 @@
#include "generator/booking_dataset.hpp"
#include "generator/booking_scoring.hpp"
+#include "generator/feature_builder.hpp"
#include "platform/local_country_file_utils.hpp"
#include "platform/platform.hpp"
+#include "indexer/classificator.hpp"
#include "indexer/ftypes_matcher.hpp"
#include "geometry/distance_on_sphere.hpp"
@@ -14,18 +16,13 @@
#include "std/fstream.hpp"
#include "std/iostream.hpp"
+#include "std/limits.hpp"
#include "std/sstream.hpp"
namespace generator
{
namespace
{
-bool CheckForValues(string const & value)
-{
- auto const & tags = ftypes::IsHotelChecker::GetHotelTags();
- return find(tags.begin(), tags.end(), value) != tags.end();
-}
-
string EscapeTabs(string const & str)
{
stringstream ss;
@@ -124,20 +121,17 @@ BookingDataset::BookingDataset(istream & dataSource, string const & addressRefer
LoadHotels(dataSource, addressReferencePath);
}
-bool BookingDataset::BookingFilter(OsmElement const & e) const
+size_t BookingDataset::GetMatchingHotelIndex(FeatureBuilder1 const & fb) const
{
- return Filter(e, [&](OsmElement const & e)
- {
- return MatchWithBooking(e);
- });
+ if (CanBeBooking(fb))
+ return MatchWithBooking(fb);
+ return numeric_limits<size_t>::max();
}
-bool BookingDataset::TourismFilter(OsmElement const & e) const
+// TODO(mgsergio): rename to ... or delete.
+bool BookingDataset::TourismFilter(FeatureBuilder1 const & fb) const
{
- return Filter(e, [&](OsmElement const & e)
- {
- return true;
- });
+ return CanBeBooking(fb);
}
BookingDataset::Hotel const & BookingDataset::GetHotel(size_t index) const
@@ -161,64 +155,71 @@ vector<size_t> BookingDataset::GetNearestHotels(double lat, double lon, size_t l
for_each(bgi::qbegin(m_rtree, bgi::nearest(TPoint(lat, lon), limit)), bgi::qend(m_rtree),
[&](TValue const & v)
{
- auto const & hotel = m_hotels[v.second];
+ auto const & hotel = GetHotel(v.second);
double const dist = ms::DistanceOnEarth(lat, lon, hotel.lat, hotel.lon);
if (maxDistance != 0.0 && dist > maxDistance /* max distance in meters */)
return;
indexes.emplace_back(v.second);
});
+
return indexes;
}
-void BookingDataset::BuildFeatures(function<void(OsmElement *)> const & fn) const
+void BookingDataset::BuildFeature(FeatureBuilder1 const & /*fb*/, size_t const hotelIndex,
+ function<void(FeatureBuilder1 &)> const & fn) const
{
- for (auto const & hotel : m_hotels)
- {
- OsmElement e;
- e.type = OsmElement::EntityType::Node;
- e.id = 1;
-
- e.lat = hotel.lat;
- e.lon = hotel.lon;
-
- e.AddTag("sponsored", "booking");
- e.AddTag("name", hotel.name);
- e.AddTag("ref:sponsored", strings::to_string(hotel.id));
- e.AddTag("website", hotel.descUrl);
- e.AddTag("rating:sponsored", strings::to_string(hotel.ratingUser));
- e.AddTag("stars", strings::to_string(hotel.stars));
- e.AddTag("price_rate", strings::to_string(hotel.priceCategory));
- e.AddTag("addr:full", hotel.address);
-
- if (!hotel.translations.empty())
- {
- vector<string> parts;
- strings::ParseCSVRow(hotel.translations, '|', parts);
- CHECK(parts.size() % 3 == 0, ());
- for (auto i = 0; i < parts.size(); i += 3)
- {
- e.AddTag("name:" + parts[i], parts[i + 1]);
- e.AddTag("addr:full:" + parts[i], parts[i + 2]);
- }
- }
+ auto const & hotel = m_hotels[hotelIndex];
- if (!hotel.street.empty())
- e.AddTag("addr:street", hotel.street);
+ FeatureBuilder1 bookingFb;
+ FeatureParams params;
+ // TODO(mgsergio): handle areas.
+ bookingFb.SetCenter(MercatorBounds::FromLatLon(hotel.lat, hotel.lon));
- if (!hotel.houseNumber.empty())
- e.AddTag("addr:housenumber", hotel.houseNumber);
+ auto & metadata = params.GetMetadata();
+ metadata.Set(feature::Metadata::FMD_SPONSORED_ID, strings::to_string(hotel.id));
+ metadata.Set(feature::Metadata::FMD_WEBSITE, hotel.descUrl);
+ metadata.Set(feature::Metadata::FMD_RATING, strings::to_string(hotel.ratingUser));
+ metadata.Set(feature::Metadata::FMD_STARS, strings::to_string(hotel.stars));
+ metadata.Set(feature::Metadata::FMD_PRICE_RATE, strings::to_string(hotel.priceCategory));
- // Matching booking.com hotel types to OpenStreetMap values.
- // Booking types are listed in the closed API docs.
- switch (hotel.type)
+ // params.AddAddress(hotel.address);
+ // TODO(mgsergio): addr:full ???
+
+ if (!hotel.street.empty())
+ bookingFb.AddStreet(hotel.street);
+
+ if (!hotel.houseNumber.empty())
+ bookingFb.AddHouseNumber(hotel.houseNumber);
+
+ params.AddName(StringUtf8Multilang::GetLangByCode(StringUtf8Multilang::kDefaultCode),
+ hotel.name);
+ if (!hotel.translations.empty())
+ {
+ // TODO(mgsergio): Move parsing to the hotel costruction stage.
+ vector<string> parts;
+ strings::ParseCSVRow(hotel.translations, '|', parts);
+ CHECK(parts.size() % 3 == 0, ());
+ for (auto i = 0; i < parts.size(); i += 3)
{
+ auto const langCode = StringUtf8Multilang::GetLangIndex(parts[i]);
+ params.AddName(StringUtf8Multilang::GetLangByCode(langCode), parts[i + 1]);
+ // TODO(mgsergio): e.AddTag("addr:full:" + parts[i], parts[i + 2]);
+ }
+ }
+
+ auto const & clf = classif();
+ params.AddType(clf.GetTypeByPath({"sponsored", "booking"}));
+ // Matching booking.com hotel types to OpenStreetMap values.
+ // Booking types are listed in the closed API docs.
+ switch (hotel.type)
+ {
case 19:
- case 205: e.AddTag("tourism", "motel"); break;
+ case 205: params.AddType(clf.GetTypeByPath({"tourism", "motel"})); break;
case 21:
case 206:
- case 212: e.AddTag("tourism", "resort"); break;
+ case 212: params.AddType(clf.GetTypeByPath({"tourism", "resort"})); break;
case 3:
case 23:
@@ -231,7 +232,7 @@ void BookingDataset::BuildFeatures(function<void(OsmElement *)> const & fn) cons
case 210:
case 216:
case 220:
- case 223: e.AddTag("tourism", "guest_house"); break;
+ case 223: params.AddType(clf.GetTypeByPath({"tourism", "guest_house"})); break;
case 14:
case 204:
@@ -239,29 +240,30 @@ void BookingDataset::BuildFeatures(function<void(OsmElement *)> const & fn) cons
case 218:
case 219:
case 226:
- case 222: e.AddTag("tourism", "hotel"); break;
+ case 222: params.AddType(clf.GetTypeByPath({"tourism", "hotel"})); break;
case 211:
case 224:
- case 228: e.AddTag("tourism", "chalet"); break;
+ case 228: params.AddType(clf.GetTypeByPath({"tourism", "chalet"})); break;
case 13:
case 225:
- case 203: e.AddTag("tourism", "hostel"); break;
+ case 203: params.AddType(clf.GetTypeByPath({"tourism", "hostel"})); break;
case 215:
case 221:
case 227:
case 2:
- case 201: e.AddTag("tourism", "apartment"); break;
+ case 201: params.AddType(clf.GetTypeByPath({"tourism", "apartment"})); break;
- case 214: e.AddTag("tourism", "camp_site"); break;
+ case 214: params.AddType(clf.GetTypeByPath({"tourism", "camp_site"})); break;
- default: e.AddTag("tourism", "hotel"); break;
- }
-
- fn(&e);
+ default: params.AddType(clf.GetTypeByPath({"tourism", "hotel"})); break;
}
+
+ bookingFb.SetParams(params);
+
+ fn(bookingFb);
}
void BookingDataset::LoadHotels(istream & src, string const & addressReferencePath)
@@ -306,58 +308,37 @@ void BookingDataset::LoadHotels(istream & src, string const & addressReferencePa
}
}
-bool BookingDataset::MatchWithBooking(OsmElement const & e) const
+size_t BookingDataset::MatchWithBooking(FeatureBuilder1 const & fb) const
{
- string name;
- for (auto const & tag : e.Tags())
- {
- if (tag.key == "name")
- {
- name = tag.value;
- break;
- }
- }
+ auto const name = fb.GetName(StringUtf8Multilang::kDefaultCode);
if (name.empty())
return false;
+ auto const center = MercatorBounds::ToLatLon(fb.GetKeyPoint());
// Find |kMaxSelectedElements| nearest values to a point.
auto const bookingIndexes =
- GetNearestHotels(e.lat, e.lon, kMaxSelectedElements, kDistanceLimitInMeters);
-
- bool matched = false;
+ GetNearestHotels(center.lat, center.lon, kMaxSelectedElements, kDistanceLimitInMeters);
for (size_t const j : bookingIndexes)
{
- if (booking_scoring::Match(GetHotel(j), e).IsMatched())
- break;
+ if (booking_scoring::Match(GetHotel(j), fb).IsMatched())
+ return j;
}
- return matched;
+ return numeric_limits<size_t>::max();
}
-bool BookingDataset::Filter(OsmElement const & e,
- function<bool(OsmElement const &)> const & fn) const
+bool BookingDataset::CanBeBooking(FeatureBuilder1 const & fb) const
{
- if (e.type != OsmElement::EntityType::Node)
+ // 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 (e.Tags().empty())
+ if (fb.GetName(StringUtf8Multilang::kDefaultCode).empty())
return false;
- bool matched = false;
- for (auto const & tag : e.Tags())
- {
- if (tag.key == "tourism" && CheckForValues(tag.value))
- {
- matched = fn(e);
- break;
- }
- }
-
- // TODO: Need to write file with dropped osm features.
-
- return matched;
+ return ftypes::IsHotelChecker::Instance()(fb.GetTypes());
}
-
} // namespace generator
diff --git a/generator/booking_dataset.hpp b/generator/booking_dataset.hpp
index c37859cca6..9de339d500 100644
--- a/generator/booking_dataset.hpp
+++ b/generator/booking_dataset.hpp
@@ -1,7 +1,5 @@
#pragma once
-#include "generator/osm_element.hpp"
-
#include "indexer/index.hpp"
#include "search/reverse_geocoder.hpp"
@@ -14,6 +12,8 @@
#include "std/function.hpp"
#include "std/string.hpp"
+class FeatureBuilder1;
+
namespace generator
{
class BookingDataset
@@ -77,8 +77,9 @@ public:
explicit BookingDataset(string const & dataPath, string const & addressReferencePath = string());
explicit BookingDataset(istream & dataSource, string const & addressReferencePath = string());
- bool BookingFilter(OsmElement const & e) const;
- bool TourismFilter(OsmElement const & e) const;
+ /// @returns an index of a matched hotel or numeric_limits<size_t>::max on failure.
+ size_t GetMatchingHotelIndex(FeatureBuilder1 const & e) const;
+ bool TourismFilter(FeatureBuilder1 const & e) const;
inline size_t Size() const { return m_hotels.size(); }
Hotel const & GetHotel(size_t index) const;
@@ -87,7 +88,8 @@ public:
double maxDistance = 0.0) const;
bool MatchByName(string const & osmName, vector<size_t> const & bookingIndexes) const;
- void BuildFeatures(function<void(OsmElement *)> const & fn) const;
+ void BuildFeature(FeatureBuilder1 const & fb, size_t hotelIndex,
+ function<void(FeatureBuilder1 &)> const & fn) const;
protected:
vector<Hotel> m_hotels;
@@ -100,10 +102,10 @@ protected:
boost::geometry::index::rtree<TValue, boost::geometry::index::quadratic<16>> m_rtree;
void LoadHotels(istream & path, string const & addressReferencePath);
- bool MatchWithBooking(OsmElement const & e) const;
- bool Filter(OsmElement const & e, function<bool(OsmElement const &)> const & fn) const;
+ /// @returns an index of a matched hotel or numeric_limits<size_t>::max() on failure.
+ size_t MatchWithBooking(FeatureBuilder1 const & e) const;
+ bool CanBeBooking(FeatureBuilder1 const & e) const;
};
ostream & operator<<(ostream & s, BookingDataset::Hotel const & h);
-
} // namespace generator
diff --git a/generator/booking_quality_check/booking_quality_check.cpp b/generator/booking_quality_check/booking_quality_check.cpp
index b4e817fc18..1df4239bdd 100644
--- a/generator/booking_quality_check/booking_quality_check.cpp
+++ b/generator/booking_quality_check/booking_quality_check.cpp
@@ -1,17 +1,21 @@
#include "generator/booking_dataset.hpp"
#include "generator/booking_scoring.hpp"
+#include "generator/feature_builder.hpp"
#include "generator/osm_source.hpp"
+#include "indexer/classificator_loader.hpp"
+
#include "geometry/distance_on_sphere.hpp"
#include "std/fstream.hpp"
#include "std/iostream.hpp"
#include "std/numeric.hpp"
#include "std/random.hpp"
+#include "std/unique_ptr.hpp"
#include "3party/gflags/src/gflags/gflags.h"
-DEFINE_bool(generate_classif, false, "Generate classificator.");
+// TODO(mgsergio):Unused: DEFINE_bool(generate_classif, false, "Generate classificator.");
DEFINE_string(osm_file_name, "", "Input .o5m file");
DEFINE_string(booking_data, "", "Path to booking data in .tsv format");
@@ -21,93 +25,163 @@ DEFINE_uint64(seed, minstd_rand::default_seed, "Seed for random shuffle");
using namespace generator;
-ostream & operator<<(ostream & s, OsmElement const & e)
+namespace
{
- for (auto const & tag : e.Tags())
- {
- auto t = tag;
- replace(t.key.begin(), t.key.end(), '\n', ' ');
- replace(t.value.begin(), t.value.end(), '\n', ' ');
- s << t.key << "=" << t.value << "\t";
- }
- return s;
-}
-
-int main(int argc, char * argv[])
+string PrintBuilder(FeatureBuilder1 const & fb)
{
- google::SetUsageMessage(
- "Takes OSM XML data from stdin and creates"
- " data and index files in several passes.");
- google::ParseCommandLineFlags(&argc, &argv, true);
+ ostringstream s;
- LOG_SHORT(LINFO, ("Booking data:", FLAGS_booking_data));
+ s << "Name: " << fb.GetName(StringUtf8Multilang::kDefaultCode) << '\t';
- BookingDataset bookingDataset(FLAGS_booking_data);
+ auto const params = fb.GetParams();
+ auto const street = params.GetStreet();
+ auto const house = params.house.Get();
- vector<OsmElement> elements;
- LOG_SHORT(LINFO, ("OSM data:", FLAGS_osm_file_name));
+ string address = street;
+ if (!house.empty())
{
- SourceReader reader =
- FLAGS_osm_file_name.empty() ? SourceReader() : SourceReader(FLAGS_osm_file_name);
- ProcessOsmElementsFromO5M(reader, [&](OsmElement * e)
- {
- if (bookingDataset.TourismFilter(*e))
- elements.emplace_back(*e);
- });
+ if (!street.empty())
+ address += ", ";
+ address += house;
}
- LOG_SHORT(LINFO, ("Num of tourism elements:", elements.size()));
- vector<size_t> elementIndexes(elements.size());
- iota(elementIndexes.begin(), elementIndexes.end(), 0);
+ if (!address.empty())
+ s << "Address: " << address << '\t';
- shuffle(elementIndexes.begin(), elementIndexes.end(), minstd_rand(FLAGS_seed));
- if (FLAGS_selection_size < elementIndexes.size())
- elementIndexes.resize(FLAGS_selection_size);
+ auto const center = MercatorBounds::ToLatLon(fb.GetKeyPoint());
+ s << "lat: " << center.lat << " lon: " << center.lon << '\t';
- stringstream outStream;
+ return s.str();
+}
- for (size_t i : elementIndexes)
+struct Emitter : public EmitterBase
+{
+ Emitter(feature::GenerateInfo const & info)
+ : m_bookingDataset(info.m_bookingDatafileName)
{
- OsmElement const & e = elements[i];
- auto const bookingIndexes = bookingDataset.GetNearestHotels(
- e.lat, e.lon, BookingDataset::kMaxSelectedElements, BookingDataset::kDistanceLimitInMeters);
- for (size_t const j : bookingIndexes)
- {
- auto const & hotel = bookingDataset.GetHotel(j);
- auto const score = booking_scoring::Match(hotel, e);
-
- double const distanceMeters = ms::DistanceOnEarth(e.lat, e.lon, hotel.lat, hotel.lon);
- bool matched = score.IsMatched();
-
- outStream << "# ------------------------------------------" << fixed << setprecision(6)
- << endl;
- outStream << (matched ? 'y' : 'n') << " \t" << i << "\t " << j
- << "\tdistance: " << distanceMeters
- << "\tdistance score: " << score.m_linearNormDistanceScore
- << "\tname score: " << score.m_nameSimilarityScore
- << "\tresult score: " << score.GetMatchingScore()
- << endl;
- outStream << "# " << e << endl;
- outStream << "# " << hotel << endl;
- outStream << "# URL: https://www.openstreetmap.org/?mlat=" << hotel.lat
- << "&mlon=" << hotel.lon << "#map=18/" << hotel.lat << "/" << hotel.lon << endl;
- }
- if (!bookingIndexes.empty())
- outStream << endl << endl;
+ LOG_SHORT(LINFO, (m_bookingDataset.Size(), "hotels are loaded from Booking."));
+ LOG_SHORT(LINFO, ("OSM data:", FLAGS_osm_file_name));
}
- if (FLAGS_sample_data.empty())
+ void operator()(FeatureBuilder1 & fb) override
{
- cout << outStream.str();
+ if (m_bookingDataset.TourismFilter(fb))
+ m_features.emplace_back(fb);
}
- else
+
+ void GetNames(vector<string> & names) const override
+ {
+ names.clear();
+ }
+
+ bool Finish() override
{
- ofstream file(FLAGS_sample_data);
- if (file.is_open())
- file << outStream.str();
+ LOG_SHORT(LINFO, ("Num of tourism elements:", m_features.size()));
+ vector<size_t> elementIndexes(m_features.size());
+ iota(elementIndexes.begin(), elementIndexes.end(), 0);
+
+ shuffle(elementIndexes.begin(), elementIndexes.end(), minstd_rand(FLAGS_seed));
+ if (FLAGS_selection_size < elementIndexes.size())
+ elementIndexes.resize(FLAGS_selection_size);
+
+ stringstream outStream;
+
+ for (size_t i : elementIndexes)
+ {
+ auto const & fb = m_features[i];
+ auto const center = MercatorBounds::ToLatLon(fb.GetKeyPoint());
+ auto const bookingIndexes = m_bookingDataset.GetNearestHotels(
+ center.lat, center.lon,
+ BookingDataset::kMaxSelectedElements,
+ BookingDataset::kDistanceLimitInMeters);
+
+ for (size_t const j : bookingIndexes)
+ {
+ auto const & hotel = m_bookingDataset.GetHotel(j);
+ auto const score = booking_scoring::Match(hotel, fb);
+
+ double const distanceMeters = ms::DistanceOnEarth(center.lat, center.lon,
+ hotel.lat, hotel.lon);
+ auto const matched = score.IsMatched();
+
+ outStream << "# ------------------------------------------" << fixed << setprecision(6)
+ << endl;
+ outStream << (matched ? 'y' : 'n') << " \t" << i << "\t " << j
+ << "\tdistance: " << distanceMeters
+ << "\tdistance score: " << score.m_linearNormDistanceScore
+ << "\tname score: " << score.m_nameSimilarityScore
+ << "\tresult score: " << score.GetMatchingScore()
+ << endl;
+ outStream << "# " << PrintBuilder(fb) << endl;
+ outStream << "# " << hotel << endl;
+ outStream << "# URL: https://www.openstreetmap.org/?mlat=" << hotel.lat
+ << "&mlon=" << hotel.lon << "#map=18/" << hotel.lat << "/" << hotel.lon << endl;
+ }
+ if (!bookingIndexes.empty())
+ outStream << endl << endl;
+ }
+
+ if (FLAGS_sample_data.empty())
+ {
+ cout << outStream.str();
+ }
else
- LOG(LERROR, ("Can't output into", FLAGS_sample_data));
+ {
+ ofstream file(FLAGS_sample_data);
+ if (file.is_open())
+ {
+ file << outStream.str();
+ }
+ else
+ {
+ LOG(LERROR, ("Can't output into", FLAGS_sample_data));
+ return false;
+ }
+ }
+
+ return true;
}
+ BookingDataset m_bookingDataset;
+ vector<FeatureBuilder1> m_features;
+};
+
+unique_ptr<Emitter> GetEmitter(feature::GenerateInfo const & info)
+{
+ LOG_SHORT(LINFO, ("Booking data:", FLAGS_booking_data));
+ return make_unique<Emitter>(info);
+}
+
+feature::GenerateInfo GetGenerateInfo()
+{
+ feature::GenerateInfo info;
+ info.m_bookingDatafileName = FLAGS_booking_data;
+ info.m_osmFileName = FLAGS_osm_file_name;
+ info.SetNodeStorageType("map");
+ info.SetOsmFileType("o5m");
+
+ auto const lastSlash = FLAGS_sample_data.rfind("/");
+ if (lastSlash == string::npos)
+ info.m_intermediateDir = ".";
+ else
+ info.m_intermediateDir = FLAGS_sample_data.substr(0, lastSlash);
+ // ...
+ return info;
+}
+} // namespace
+
+int main(int argc, char * argv[])
+{
+ google::SetUsageMessage(
+ "Takes OSM XML data from stdin and creates"
+ " data and index files in several passes.");
+ google::ParseCommandLineFlags(&argc, &argv, true);
+
+ classificator::Load();
+
+ auto info = GetGenerateInfo();
+ GenerateIntermediateData(info);
+ GenerateFeatures(info, GetEmitter);
+
return 0;
}
diff --git a/generator/booking_scoring.cpp b/generator/booking_scoring.cpp
index 2ddd071f6f..3c5941b325 100644
--- a/generator/booking_scoring.cpp
+++ b/generator/booking_scoring.cpp
@@ -1,6 +1,7 @@
#include "generator/booking_scoring.hpp"
#include "generator/booking_dataset.hpp"
+#include "generator/feature_builder.hpp"
#include "indexer/search_delimiters.hpp"
#include "indexer/search_string_utils.hpp"
@@ -20,7 +21,7 @@ namespace booking_scoring
namespace
{
// Calculated with tools/python/booking_hotels_quality.py.
-double constexpr kOptimalThreshold = 0.317324;
+double constexpr kOptimalThreshold = 0.321098;
template <typename T, typename U>
struct decay_equiv :
@@ -125,15 +126,17 @@ bool BookingMatchScore::IsMatched() const
return GetMatchingScore() > kOptimalThreshold;
}
-BookingMatchScore Match(BookingDataset::Hotel const & h, OsmElement const & e)
+BookingMatchScore Match(BookingDataset::Hotel const & h, FeatureBuilder1 const & fb)
{
BookingMatchScore score;
- auto const distance = ms::DistanceOnEarth(e.lat, e.lon, h.lat, h.lon);
+ auto const fbCenter = MercatorBounds::ToLatLon(fb.GetKeyPoint());
+ auto const distance = ms::DistanceOnEarth(fbCenter.lat, fbCenter.lon, h.lat, h.lon);
score.m_linearNormDistanceScore = GetLinearNormDistanceScore(distance);
// TODO(mgsergio): Check all translations and use the best one.
- score.m_nameSimilarityScore = GetNameSimilarityScore(h.name, e.GetTag("name"));
+ score.m_nameSimilarityScore =
+ GetNameSimilarityScore(h.name, fb.GetName(StringUtf8Multilang::kDefaultCode));
return score;
}
diff --git a/generator/booking_scoring.hpp b/generator/booking_scoring.hpp
index e5516a4470..225fe4822b 100644
--- a/generator/booking_scoring.hpp
+++ b/generator/booking_scoring.hpp
@@ -2,7 +2,7 @@
#include "generator/booking_dataset.hpp"
-struct OsmElement;
+class FeatureBuilder1;
namespace generator
{
@@ -17,6 +17,6 @@ struct BookingMatchScore
double m_nameSimilarityScore{};
};
-BookingMatchScore Match(BookingDataset::Hotel const & h, OsmElement const & e);
+BookingMatchScore Match(BookingDataset::Hotel const & h, FeatureBuilder1 const & fb);
} // namespace booking_scoring
} // namespace generator
diff --git a/generator/osm_source.cpp b/generator/osm_source.cpp
index d9e43bec2f..cf337c8eec 100644
--- a/generator/osm_source.cpp
+++ b/generator/osm_source.cpp
@@ -23,6 +23,7 @@
#include "coding/parse_xml.hpp"
#include "std/fstream.hpp"
+#include "std/limits.hpp"
#include "defines.hpp"
@@ -269,6 +270,8 @@ class MainFeaturesEmitter : public EmitterBase
string m_srcCoastsFile;
bool m_failOnCoasts;
+ generator::BookingDataset m_bookingDataset;
+
// TODO(mgsergio): comment.
m4::Tree<Place> m_places;
@@ -288,6 +291,7 @@ class MainFeaturesEmitter : public EmitterBase
public:
MainFeaturesEmitter(feature::GenerateInfo const & info)
: m_failOnCoasts(info.m_failOnCoasts)
+ , m_bookingDataset(info.m_bookingDatafileName, info.m_bookingReferenceDir)
{
Classificator const & c = classif();
@@ -329,6 +333,8 @@ public:
static uint32_t const placeType = classif().GetTypeByPath({"place"});
uint32_t const type = fb.GetParams().FindType(placeType, 1);
+ auto hotelIndex = numeric_limits<size_t>::max();
+
if (type != ftype::GetEmptyValue() && !fb.GetName().empty())
{
m_places.ReplaceEqualInRect(
@@ -336,6 +342,11 @@ public:
[](Place const & p1, Place const & p2) { return p1.IsEqual(p2); },
[](Place const & p1, Place const & p2) { return p1.IsBetterThan(p2); });
}
+ else if ((hotelIndex = m_bookingDataset.GetMatchingHotelIndex(fb)) !=
+ numeric_limits<size_t>::max())
+ {
+ m_bookingDataset.BuildFeature(fb, hotelIndex, [this](FeatureBuilder1 & fb) { Emit(fb); });
+ }
else
{
Emit(fb);
@@ -621,11 +632,8 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info, EmitterBase & emitter)
TagReplacer tagReplacer(GetPlatform().ResourcesDir() + REPLACED_TAGS_FILE);
OsmTagMixer osmTagMixer(GetPlatform().ResourcesDir() + MIXED_TAGS_FILE);
- // If info.m_bookingDatafileName is empty then no data will be loaded.
- generator::BookingDataset bookingDataset(info.m_bookingDatafileName,
- info.m_bookingReferenceDir);
-
- stringstream skippedElements;
+ // TODO(mgsergio): Output skipped elemnts.
+ // stringstream skippedElements;
// Here we can add new tags to element!!!
auto const fn = [&](OsmElement * e)
@@ -634,11 +642,11 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info, EmitterBase & emitter)
tagAdmixer(e);
osmTagMixer(e);
- if (bookingDataset.BookingFilter(*e))
- {
- skippedElements << e->id << endl;
- return;
- }
+ // if (bookingDataset.BookingFilter(*e))
+ // {
+ // skippedElements << e->id << endl;
+ // return;
+ // }
parser.EmitElement(e);
};
@@ -656,22 +664,23 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info, EmitterBase & emitter)
LOG(LINFO, ("Processing", info.m_osmFileName, "done."));
- 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));
- }
- }
+ // 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())