void EmitFeatureBase(FeatureBuilder1 & ft, FeatureParams const & params) { ft.SetParams(params); if (ft.PreSerialize()) { string addr; if (m_addrWriter && ftypes::IsBuildingChecker::Instance()(params.m_Types) && ft.FormatFullAddress(addr)) m_addrWriter->Write(addr.c_str(), addr.size()); static uint32_t const placeType = classif().GetTypeByPath({"place"}); uint32_t const type = params.FindType(placeType, 1); if (type != ftype::GetEmptyValue() && !ft.GetName().empty()) { m_places.ReplaceEqualInRect(Place(ft, type), [](Place const & p1, Place const & p2) { return p1.IsEqual(p2); }, [](Place const & p1, Place const & p2) { return p1.IsBetterThan(p2); }); } else m_emitter(ft); } }
void BookingDataset::BuildHotel(Hotel const & hotel, function<void(FeatureBuilder1 &)> const & fn) const { FeatureBuilder1 fb; FeatureParams params; fb.SetCenter(MercatorBounds::FromLatLon(hotel.lat, hotel.lon)); 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)); // params.AddAddress(hotel.address); // TODO(mgsergio): addr:full ??? if (!hotel.street.empty()) fb.AddStreet(hotel.street); if (!hotel.houseNumber.empty()) fb.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_EQUAL(parts.size() % 3, 0, ("Invalid translation string:", hotel.translations)); 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: params.AddType(clf.GetTypeByPath({"tourism", "motel"})); break; case 21: case 206: case 212: params.AddType(clf.GetTypeByPath({"tourism", "resort"})); break; case 3: case 23: case 24: case 25: case 202: case 207: case 208: case 209: case 210: case 216: case 220: case 223: params.AddType(clf.GetTypeByPath({"tourism", "guest_house"})); break; case 14: case 204: case 213: case 218: case 219: case 226: case 222: params.AddType(clf.GetTypeByPath({"tourism", "hotel"})); break; case 211: case 224: case 228: params.AddType(clf.GetTypeByPath({"tourism", "chalet"})); break; case 13: case 225: case 203: params.AddType(clf.GetTypeByPath({"tourism", "hostel"})); break; case 215: case 221: case 227: case 2: case 201: params.AddType(clf.GetTypeByPath({"tourism", "apartment"})); break; case 214: params.AddType(clf.GetTypeByPath({"tourism", "camp_site"})); break; default: params.AddType(clf.GetTypeByPath({"tourism", "hotel"})); break; } fb.SetParams(params); fn(fb); }
/// The main entry point for parsing process. void EmitElement(OsmElement * p) { enum class FeatureState {Unknown, Ok, EmptyTags, HasNoTypes, BrokenRef, ShortGeom, InvalidType}; FeatureParams params; FeatureState state = FeatureState::Unknown; switch(p->type) { case OsmElement::EntityType::Node: { if (p->m_tags.empty()) { state = FeatureState::EmptyTags; break; } if (!ParseType(p, params)) { state = FeatureState::HasNoTypes; break; } m2::PointD const pt = MercatorBounds::FromLatLon(p->lat, p->lon); EmitPoint(pt, params, osm::Id::Node(p->id)); state = FeatureState::Ok; break; } case OsmElement::EntityType::Way: { FeatureBuilder1 ft; // Parse geometry. for (uint64_t ref : p->Nodes()) { m2::PointD pt; if (!m_holder.GetNode(ref, pt.y, pt.x)) { state = FeatureState::BrokenRef; break; } ft.AddPoint(pt); } if (state == FeatureState::BrokenRef) break; if (ft.GetPointsCount() < 2) { state = FeatureState::ShortGeom; break; } if (!ParseType(p, params)) { state = FeatureState::HasNoTypes; break; } ft.SetOsmId(osm::Id::Way(p->id)); bool isCoastLine = (m_coastType != 0 && params.IsTypeExist(m_coastType)); EmitArea(ft, params, [&] (FeatureBuilder1 & ft) { isCoastLine = false; // emit coastline feature only once HolesProcessor processor(p->id, this); m_holder.ForEachRelationByWay(p->id, processor); ft.SetAreaAddHoles(processor.GetHoles()); }); EmitLine(ft, params, isCoastLine); state = FeatureState::Ok; break; } case OsmElement::EntityType::Relation: { { // 1. Check, if this is our processable relation. Here we process only polygon relations. size_t i = 0; size_t const count = p->m_tags.size(); for (; i < count; ++i) { if (p->m_tags[i].key == "type" && p->m_tags[i].value == "multipolygon") break; } if (i == count) { state = FeatureState::InvalidType; break; } } if (!ParseType(p, params)) { state = FeatureState::HasNoTypes; break; } HolesAccumulator holes(this); AreaWayMerger<TCache> outer(m_holder); // 3. Iterate ways to get 'outer' and 'inner' geometries for (auto const & e : p->Members()) { if (e.type != OsmElement::EntityType::Way) continue; if (e.role == "outer") outer.AddWay(e.ref); else if (e.role == "inner") holes(e.ref); } auto const & holesGeometry = holes.GetHoles(); outer.ForEachArea(true, [&] (FeatureBuilder1::TPointSeq const & pts, vector<uint64_t> const & ids) { FeatureBuilder1 ft; for (uint64_t id : ids) ft.AddOsmId(osm::Id::Way(id)); for (auto const & pt : pts) ft.AddPoint(pt); ft.AddOsmId(osm::Id::Relation(p->id)); EmitArea(ft, params, [&holesGeometry] (FeatureBuilder1 & ft) {ft.SetAreaAddHoles(holesGeometry);}); }); state = FeatureState::Ok; break; } default: state = FeatureState::Unknown; break; } // if (state == FeatureState::Ok) // { // Classificator const & c = classif(); // static char const * const stateText[] = {"U", "Ok", "ET", "HNT", "BR", "SG", "IT"}; // stringstream ss; // ss << p->id << " [" << stateText[static_cast<typename underlying_type<FeatureState>::type>(state)] << "]"; // for (auto const & p : params.m_Types) // ss << " " << c.GetReadableObjectName(p); // ss << endl; // std::ofstream file("feature_types_new2.txt", ios::app); // file.write(ss.str().data(), ss.str().size()); // } }