Base class MapObject to store feature properties and query them in UI code.

This commit is contained in:
Alex Zolotarev 2016-03-01 13:02:03 +03:00 committed by Sergey Yershov
parent 2cf158a887
commit 9ec64c31e4
3 changed files with 321 additions and 0 deletions

View file

@ -41,6 +41,7 @@ SOURCES += \
geometry_serialization.cpp \
index.cpp \
index_builder.cpp \
map_object.cpp \
map_style.cpp \
map_style_reader.cpp \
mwm_set.cpp \
@ -92,6 +93,7 @@ HEADERS += \
interval_index.hpp \
interval_index_builder.hpp \
interval_index_iface.hpp \
map_object.hpp \
map_style.hpp \
map_style_reader.hpp \
mwm_set.hpp \

172
indexer/map_object.cpp Normal file
View file

@ -0,0 +1,172 @@
#include "map_object.hpp"
#include "indexer/categories_holder.hpp"
#include "indexer/cuisines.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_algo.hpp"
#include "platform/measurement_utils.hpp"
#include "platform/preferred_languages.hpp"
#include "base/logging.hpp"
#include "base/string_utils.hpp"
namespace osm
{
namespace
{
constexpr char const * kWlan = "wlan";
constexpr char const * kWired = "wired";
constexpr char const * kYes = "yes";
constexpr char const * kNo = "no";
}
string DebugPrint(osm::Internet internet)
{
switch (internet)
{
case Internet::No: return kNo;
case Internet::Yes: return kYes;
case Internet::Wlan: return kWlan;
case Internet::Wired: return kWired;
case Internet::Unknown: break;
}
return {};
}
string DebugPrint(Props props)
{
string k;
switch (props)
{
case osm::Props::Phone: k = "phone"; break;
case osm::Props::Fax: k = "fax"; break;
case osm::Props::Email: k = "email"; break;
case osm::Props::Website: k = "website"; break;
case osm::Props::Internet: k = "internet_access"; break;
case osm::Props::Cuisine: k = "cuisine"; break;
case osm::Props::OpeningHours: k = "opening_hours"; break;
case osm::Props::Stars: k = "stars"; break;
case osm::Props::Operator: k = "operator"; break;
case osm::Props::Elevation: k = "ele"; break;
case osm::Props::Wikipedia: k = "wikipedia"; break;
case osm::Props::Flats: k = "addr:flats"; break;
case osm::Props::BuildingLevels: k = "building:levels"; break;
}
return k;
}
void MapObject::SetFromFeatureType(FeatureType const & ft)
{
m_mercator = feature::GetCenter(ft);
m_name = ft.GetNames();
m_types = feature::TypesHolder(ft);
m_metadata = ft.GetMetadata();
m_featureID = ft.GetID();
ASSERT(m_featureID.IsValid(), ());
}
FeatureID const & MapObject::GetID() const { return m_featureID; }
ms::LatLon MapObject::GetLatLon() const { return MercatorBounds::ToLatLon(m_mercator); }
m2::PointD const & MapObject::GetMercator() const { return m_mercator; }
feature::TypesHolder const & MapObject::GetTypes() const { return m_types; }
string MapObject::GetDefaultName() const
{
string name;
UNUSED_VALUE(m_name.GetString(StringUtf8Multilang::kDefaultCode, name));
return name;
}
string MapObject::GetLocalizedType() const
{
ASSERT(!m_types.Empty(), ());
feature::TypesHolder copy(m_types);
copy.SortBySpec();
CategoriesHolder const & categories = GetDefaultCategories();
return categories.GetReadableFeatureType(
*copy.begin(), categories.MapLocaleToInteger(languages::GetCurrentOrig()));
}
vector<osm::Props> MapObject::AvailableProperties() const
{
return MetadataToProps(m_metadata.GetPresentTypes());
}
string MapObject::GetPhone() const { return m_metadata.Get(feature::Metadata::FMD_PHONE_NUMBER); }
string MapObject::GetFax() const { return m_metadata.Get(feature::Metadata::FMD_FAX_NUMBER); }
string MapObject::GetEmail() const { return m_metadata.Get(feature::Metadata::FMD_EMAIL); }
string MapObject::GetWebsite() const
{
string website = m_metadata.Get(feature::Metadata::FMD_WEBSITE);
if (website.empty())
website = m_metadata.Get(feature::Metadata::FMD_URL);
return website;
}
Internet MapObject::GetInternet() const
{
string inet = m_metadata.Get(feature::Metadata::FMD_INTERNET);
strings::AsciiToLower(inet);
// Most popular case.
if (inet.empty())
return Internet::Unknown;
if (inet.find(kWlan) != string::npos)
return Internet::Wlan;
if (inet.find(kWired) != string::npos)
return Internet::Wired;
if (inet == kYes)
return Internet::Yes;
if (inet == kNo)
return Internet::No;
return Internet::Unknown;
}
vector<string> MapObject::GetCuisines() const
{
vector<string> localized;
Cuisines::Instance().ParseAndLocalize(m_metadata.Get(feature::Metadata::FMD_CUISINE), localized);
return localized;
}
string MapObject::FormatCuisines() const { return strings::JoinStrings(GetCuisines(), ""); }
string MapObject::GetOpeningHours() const
{
return m_metadata.Get(feature::Metadata::FMD_OPEN_HOURS);
}
string MapObject::GetOperator() const { return m_metadata.Get(feature::Metadata::FMD_OPERATOR); }
int MapObject::GetStars() const
{
// Most popular case.
if (m_metadata.Has(feature::Metadata::FMD_STARS))
{
int count;
if (strings::to_int(m_metadata.Get(feature::Metadata::FMD_STARS), count))
return count;
}
return 0;
}
string MapObject::GetElevation() const
{
if (m_metadata.Has(feature::Metadata::FMD_ELE))
{
double value;
if (strings::to_double(m_metadata.Get(feature::Metadata::FMD_ELE), value))
return MeasurementUtils::FormatAltitude(value);
else
LOG(LWARNING,
("Invalid metadata for elevation:", m_metadata.Get(feature::Metadata::FMD_ELE)));
}
return {};
}
string MapObject::GetWikipediaLink() const { return m_metadata.GetWikiURL(); }
string MapObject::GetFlats() const { return m_metadata.Get(feature::Metadata::FMD_FLATS); }
string MapObject::GetBuildingLevels() const
{
return m_metadata.Get(feature::Metadata::FMD_BUILDING_LEVELS);
}
feature::Metadata const & MapObject::GetMetadata() const { return m_metadata; }
} // namespace osm

147
indexer/map_object.hpp Normal file
View file

@ -0,0 +1,147 @@
#pragma once
#include "indexer/feature_data.hpp"
#include "indexer/feature_decl.hpp"
#include "indexer/feature_meta.hpp"
#include "geometry/latlon.hpp"
#include "geometry/mercator.hpp"
#include "coding/multilang_utf8_string.hpp"
#include "base/stl_helpers.hpp"
#include "std/string.hpp"
#include "std/vector.hpp"
class FeatureType;
namespace osm
{
class EditableMapObject;
/// OSM internet_access tag values.
enum class Internet
{
Unknown, //!< Internet state is unknown (default).
Wlan, //!< Wireless Internet access is present.
Wired, //!< Wired Internet access is present.
Yes, //!< Unspecified Internet access is available.
No //!< There is definitely no any Internet access.
};
string DebugPrint(Internet internet);
/// Metadata fields in the sorted order, visible to users.
enum class Props
{
OpeningHours,
Phone,
Fax,
Website,
Email,
Cuisine,
Stars,
Operator,
Elevation,
Internet,
Wikipedia,
Flats,
BuildingLevels
};
string DebugPrint(Props props);
class MapObject
{
public:
void SetFromFeatureType(FeatureType const & ft);
FeatureID const & GetID() const;
ms::LatLon GetLatLon() const;
m2::PointD const & GetMercator() const;
/// @returns "the best" type to display in UI.
string GetLocalizedType() const;
feature::TypesHolder const & GetTypes() const;
string GetDefaultName() const;
/// @name Metadata fields.
//@{
vector<Props> AvailableProperties() const;
string GetPhone() const;
string GetFax() const;
string GetEmail() const;
string GetWebsite() const;
Internet GetInternet() const;
/// @returns translated cuisine(s).
vector<string> GetCuisines() const;
/// @returns translated and formatted cuisines.
string FormatCuisines() const;
string GetOpeningHours() const;
string GetOperator() const;
int GetStars() const;
/// @returns formatted elevation in feet or meters, or empty string.
string GetElevation() const;
/// @returns URL to Wikipedia or empty string.
string GetWikipediaLink() const;
string GetFlats() const;
string GetBuildingLevels() const;
//@}
// TODO(Vlad, yunikkk): Use Props enum + getters instead of direct metadata access.
// TODO: Remove this method.
feature::Metadata const & GetMetadata() const;
protected:
FeatureID m_featureID;
m2::PointD m_mercator;
StringUtf8Multilang m_name;
feature::TypesHolder m_types;
feature::Metadata m_metadata;
};
/// Helper to convert internal feature::Metadata::FMD_* enum into a users-visible one.
template <class T>
vector<Props> MetadataToProps(vector<T> const & metadata)
{
vector<Props> res;
using feature::Metadata;
for (auto const type : metadata)
{
switch (static_cast<Metadata::EType>(type))
{
case Metadata::FMD_CUISINE: res.push_back(Props::Cuisine); break;
case Metadata::FMD_OPEN_HOURS: res.push_back(Props::OpeningHours); break;
case Metadata::FMD_PHONE_NUMBER: res.push_back(Props::Phone); break;
case Metadata::FMD_FAX_NUMBER: res.push_back(Props::Fax); break;
case Metadata::FMD_STARS: res.push_back(Props::Stars); break;
case Metadata::FMD_OPERATOR:
res.push_back(Props::Operator);
break;
// Url is not used in UI and should be matched to Website.
case Metadata::FMD_URL:
case Metadata::FMD_WEBSITE: res.push_back(Props::Website); break;
case Metadata::FMD_INTERNET: res.push_back(Props::Internet); break;
case Metadata::FMD_ELE: res.push_back(Props::Elevation); break;
case Metadata::FMD_EMAIL: res.push_back(Props::Email); break;
case Metadata::FMD_WIKIPEDIA: res.push_back(Props::Wikipedia); break;
case Metadata::FMD_FLATS: res.push_back(Props::Flats); break;
case Metadata::FMD_BUILDING_LEVELS: res.push_back(Props::BuildingLevels); break;
case Metadata::FMD_TURN_LANES:
case Metadata::FMD_TURN_LANES_FORWARD:
case Metadata::FMD_TURN_LANES_BACKWARD:
// Postcode should be processed separately, in the address.
case Metadata::FMD_POSTCODE:
case Metadata::FMD_MAXSPEED:
case Metadata::FMD_HEIGHT:
case Metadata::FMD_MIN_HEIGHT:
case Metadata::FMD_DENOMINATION:
case Metadata::FMD_TEST_ID:
case Metadata::FMD_COUNT:
break;
// Please add new cases when compiler issues an "unhandled switch case" warning here.
}
}
my::SortUnique(res);
return res;
}
} // namespace osm