diff --git a/drape_frontend/backend_renderer.cpp b/drape_frontend/backend_renderer.cpp index 91631dcf1c..189d703f7b 100644 --- a/drape_frontend/backend_renderer.cpp +++ b/drape_frontend/backend_renderer.cpp @@ -22,6 +22,7 @@ namespace df , m_contextFactory(oglcontextfactory) { ///{ Temporary initialization + m_model.InitClassificator(); Platform::FilesList maps; Platform & pl = GetPlatform(); pl.GetFilesByExt(pl.WritableDir(), DATA_FILE_EXTENSION, maps); diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index 981ec51cae..3af86ea81b 100644 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -6,6 +6,7 @@ DEPENDENCIES = drape base ROOT_DIR = .. include($$ROOT_DIR/common.pri) +INCLUDEPATH *= $$ROOT_DIR/3party/protobuf/src DEFINES += DRAW_INFO SOURCES += \ @@ -24,6 +25,7 @@ SOURCES += \ read_manager.cpp \ tile_info.cpp \ coverage_update_descriptor.cpp \ + stylist.cpp \ line_shape.cpp HEADERS += \ @@ -44,4 +46,5 @@ HEADERS += \ area_shape.hpp \ read_manager.hpp \ coverage_update_descriptor.hpp \ + stylist.hpp \ line_shape.hpp diff --git a/drape_frontend/stylist.cpp b/drape_frontend/stylist.cpp new file mode 100644 index 0000000000..34153ef21f --- /dev/null +++ b/drape_frontend/stylist.cpp @@ -0,0 +1,346 @@ +#include "stylist.hpp" + +#include "../indexer/feature.hpp" +#include "../indexer/feature_visibility.hpp" +#include "../indexer/drawing_rules.hpp" +#include "../indexer/drules_include.hpp" +#include "../indexer/scales.hpp" + +namespace df +{ + namespace + { + enum Type + { + Line = 1, + Area = Line << 1, + Symbol = Area << 1, + Caption = Symbol << 1, + Circle = Caption << 1, + PathText = Circle << 1, + Waymarker = PathText << 1, + CountOfType = PathText + 1 + }; + + inline drule::rule_type_t Convert(Type t) + { + switch (t) + { + case Line : return drule::line; + case Area : return drule::area; + case Symbol : return drule::symbol; + case Caption : return drule::caption; + case Circle : return drule::circle; + case PathText : return drule::pathtext; + case Waymarker: return drule::waymarker; + default: + return drule::count_of_rules; + } + + } + + // ==================================== // + + inline bool IsTypeOf(drule::Key const & key, int flags) + { + int currentFlag = Line; + while (currentFlag < CountOfType) + { + Type type = Type(flags & currentFlag); + if (type != 0 && key.m_type == Convert(type)) + return true; + + currentFlag <<= 1; + } + + return false; + } + + bool IsMiddleTunnel(int const layer, double const depth) + { + return layer != feature::LAYER_EMPTY && depth < 19000; + } + + double CalcPopulationRank(FeatureType const & f) + { + uint32_t population = f.GetPopulation(); + if (population != 1) + { + double const maxPopulation = 3.0E6; + return min(maxPopulation, (double)population) / (maxPopulation * 4); + } + + return 0.0; + } + + class KeyFunctor + { + public: + KeyFunctor(FeatureType const & f, + feature::EGeomType type, + int const zoomLevel, + int const keyCount, + bool isNameExists) + : m_f(f) + , m_geomType(type) + , m_zoomLevel(zoomLevel) + , m_isNameExists(isNameExists) + { + m_rules.reserve(keyCount); + Init(); + } + + void operator() (drule::Key const & key) + { + double depth = key.m_priority; + if (IsMiddleTunnel(m_depthLayer, depth) && + IsTypeOf(key, Line | Area | Waymarker)) + { + double const layerPart = m_depthLayer * drule::layer_base_priority; + double const depthPart = fmod(depth, drule::layer_base_priority); + depth = layerPart + depthPart; + } + + if (IsTypeOf(key, Caption | Symbol | Circle | PathText)) + { + depth += m_priorityModifier; + if (m_geomType == feature::GEOM_POINT) ++depth; + } + else if (IsTypeOf(key, Area)) + depth -= m_priorityModifier; + + drule::BaseRule const * dRule = drule::rules().Find(key); + m_rules.push_back(make_pair(dRule, depth)); + + bool isNonEmptyCaption = IsTypeOf(key, Caption) && m_isNameExists; + m_pointStyleFinded |= (IsTypeOf(key, Symbol | Circle) || isNonEmptyCaption); + m_lineStyleFinded |= IsTypeOf(key, Line); + m_auxCaptionFinded |= (dRule->GetCaption(1) != 0); + } + + bool m_pointStyleFinded; + bool m_lineStyleFinded; + bool m_iconFinded; + bool m_captionWithoutOffsetFinded; + bool m_auxCaptionFinded; + buffer_vector m_rules; + + private: + void Init() + { + m_population = m_f.GetPopulation(); + m_depthLayer = m_f.GetLayer(); + if (m_depthLayer == feature::LAYER_TRANSPARENT_TUNNEL) + m_depthLayer = feature::LAYER_EMPTY; + + if (m_geomType == feature::GEOM_POINT) + m_priorityModifier = m_population / 7E9; + else + { + m2::RectD const r = m_f.GetLimitRect(m_zoomLevel); + m_priorityModifier = min(1.0, r.SizeX() * r.SizeY() * 10000.0); + } + } + + private: + FeatureType const & m_f; + feature::EGeomType m_geomType; + int const m_zoomLevel; + bool const m_isNameExists; + double m_priorityModifier; + int m_depthLayer; + uint32_t m_population; + }; + + const uint8_t CoastlineFlag = 1; + const uint8_t AreaStyleFlag = 1 << 1; + const uint8_t LineStyleFlag = 1 << 2; + const uint8_t PointStyleFlag = 1 << 3; + } + + // ==================================== // + + CaptionDescription::CaptionDescription() + : m_populationRank(0.0) {} + + void CaptionDescription::Init(const FeatureType & f, + const int zoomLevel) + { + f.GetPreferredNames(m_mainText, m_auxText); + + m_roadNumber = f.GetRoadNumber(); + m_houseNumber = f.GetHouseNumber(); + m_populationRank = CalcPopulationRank(f); + + SwapCaptions(zoomLevel); + DiscardLongCaption(zoomLevel); + } + + void CaptionDescription::FormatCaptions(const FeatureType & f, + feature::EGeomType type, + bool auxCaptionExists) + { + if (auxCaptionExists == false && + m_auxText.empty() == false && + type != feature::GEOM_LINE) + { + f.GetReadableName(m_mainText); + if (m_mainText == m_auxText) + m_auxText.clear(); + } + + if (m_houseNumber.empty() == false) + { + if (m_mainText.empty() == true || m_houseNumber.find(m_mainText) != string::npos) + m_houseNumber.swap(m_mainText); + else + m_mainText += ("(" + m_houseNumber + ")"); + } + } + + string const & CaptionDescription::GetMainText() const + { + return m_mainText; + } + + string const & CaptionDescription::GetAuxText() const + { + return m_auxText; + } + + string const & CaptionDescription::GetRoadNumber() const + { + return m_roadNumber; + } + + double CaptionDescription::GetPopulationRank() const + { + return m_populationRank; + } + + bool CaptionDescription::IsNameExists() const + { + return !m_mainText.empty() || !m_houseNumber.empty(); + } + + void CaptionDescription::SwapCaptions(const int zoomLevel) + { + if (zoomLevel <= scales::GetUpperWorldScale() && + m_auxText.empty() == false) + { + m_mainText.swap(m_auxText); + m_auxText.clear(); + } + } + + void CaptionDescription::DiscardLongCaption(const int zoomLevel) + { + if (zoomLevel < 5 && m_mainText.size() > 50) + m_mainText.clear(); + } + + // ==================================== // + + Stylist::Stylist() + : m_state(0) + { + } + + bool Stylist::IsCoastLine() const + { + return (m_state & CoastlineFlag) != 0; + } + + bool Stylist::AreaStyleExists() const + { + return (m_state & AreaStyleFlag) != 0; + } + + bool Stylist::LineStyleExists() const + { + return (m_state & LineStyleFlag) != 0; + } + + bool Stylist::PointStyleExists() const + { + return (m_state & PointStyleFlag) != 0; + } + + CaptionDescription const & Stylist::GetCaptionDescription() const + { + return m_captionDescriptor; + } + + void Stylist::ForEachRule(const Stylist::rule_callback_t & fn) + { + typedef rules_t::const_iterator const_iter; + for (const_iter it = m_rules.begin(); it != m_rules.end(); ++it) + fn(*it); + } + + void Stylist::RaiseCoastlineFlag() + { + m_state |= CoastlineFlag; + } + + void Stylist::RaiseAreaStyleFlag() + { + m_state |= AreaStyleFlag; + } + + void Stylist::RaiseLineStyleFlag() + { + m_state |= LineStyleFlag; + } + + void Stylist::RaisePointStyleFlag() + { + m_state |= PointStyleFlag; + } + + CaptionDescription & Stylist::GetCaptionDescriptionImpl() + { + return m_captionDescriptor; + } + + // ==================================== // + + bool InitStylist(FeatureType const & f, + int const zoomLevel, + Stylist & s) + { + drule::KeysT keys; + pair geomType = feature::GetDrawRule(f, zoomLevel, keys); + + if (keys.empty()) + return false; + + drule::MakeUnique(keys); + if (geomType.second) + s.RaiseCoastlineFlag(); + + feature::EGeomType mainGeomType = feature::EGeomType(geomType.first); + + switch (mainGeomType) { + case feature::GEOM_POINT: s.RaisePointStyleFlag(); + break; + case feature::GEOM_LINE : s.RaiseLineStyleFlag(); + break; + case feature::GEOM_AREA : s.RaiseAreaStyleFlag(); + break; + default: + ASSERT(false, ()); + return false; + } + + CaptionDescription & descr = s.GetCaptionDescriptionImpl(); + descr.Init(f, zoomLevel); + + KeyFunctor keyFunctor(f, mainGeomType, zoomLevel, keys.size(), descr.IsNameExists()); + for_each(keys.begin(), keys.end(), keyFunctor); + + s.m_rules.swap(keyFunctor.m_rules); + descr.FormatCaptions(f, mainGeomType, keyFunctor.m_auxCaptionFinded); + return true; + } +} diff --git a/drape_frontend/stylist.hpp b/drape_frontend/stylist.hpp new file mode 100644 index 0000000000..abb5943061 --- /dev/null +++ b/drape_frontend/stylist.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "../indexer/feature_data.hpp" + +#include "../base/buffer_vector.hpp" + +#include "../std/function.hpp" +#include "../std/string.hpp" + +class FeatureType; + +namespace drule { class BaseRule; } + +namespace df +{ + struct CaptionDescription + { + CaptionDescription(); + + void Init(FeatureType const & f, + int const zoomLevel); + + void FormatCaptions(FeatureType const & f, + feature::EGeomType type, + bool auxCaptionExists); + + const string & GetMainText() const; + const string & GetAuxText() const; + const string & GetRoadNumber() const; + double GetPopulationRank() const; + bool IsNameExists() const; + + private: + void SwapCaptions(int const zoomLevel); + void DiscardLongCaption(int const zoomLevel); + + private: + string m_mainText; + string m_auxText; + string m_roadNumber; + string m_houseNumber; + double m_populationRank; + }; + + class Stylist + { + public: + Stylist(); + + bool IsCoastLine() const; + bool AreaStyleExists() const; + bool LineStyleExists() const; + bool PointStyleExists() const; + + CaptionDescription const & GetCaptionDescription() const; + + typedef pair rule_wrapper_t; + typedef function rule_callback_t; + void ForEachRule(rule_callback_t const & fn); + + private: + friend bool InitStylist(FeatureType const &, + int const, + Stylist &); + + void RaiseCoastlineFlag(); + void RaiseAreaStyleFlag(); + void RaiseLineStyleFlag(); + void RaisePointStyleFlag(); + + CaptionDescription & GetCaptionDescriptionImpl(); + + private: + typedef buffer_vector rules_t; + rules_t m_rules; + + uint8_t m_state; + CaptionDescription m_captionDescriptor; + }; + + bool InitStylist(FeatureType const & f, + int const zoomLevel, + Stylist & s); +} diff --git a/drape_frontend/tile_info.cpp b/drape_frontend/tile_info.cpp index 2b7156a30b..54093d8641 100644 --- a/drape_frontend/tile_info.cpp +++ b/drape_frontend/tile_info.cpp @@ -1,5 +1,7 @@ #include "tile_info.hpp" +#include "stylist.hpp" + #include "../map/feature_vec_model.hpp" #include "../indexer/mercator.hpp" @@ -36,7 +38,7 @@ namespace } df::LineShape * CreateFakeLine1() - { +{ vector points; const float magn = 4; @@ -58,39 +60,39 @@ namespace points.push_back(m2::PointF(0,0)); return new df::LineShape(points, Extract(0xFF00FF00), .5f, 0.5f); } -} + } namespace df -{ + { TileInfo::TileInfo(TileKey const & key) - : m_key(key) -{} + : m_key(key) + {} -m2::RectD TileInfo::GetGlobalRect() const -{ - double const worldSizeDevisor = 1 << m_key.m_zoomLevel; - double const rectSizeX = (MercatorBounds::maxX - MercatorBounds::minX) / worldSizeDevisor; - double const rectSizeY = (MercatorBounds::maxY - MercatorBounds::minY) / worldSizeDevisor; + m2::RectD TileInfo::GetGlobalRect() const + { + double const worldSizeDevisor = 1 << m_key.m_zoomLevel; + double const rectSizeX = (MercatorBounds::maxX - MercatorBounds::minX) / worldSizeDevisor; + double const rectSizeY = (MercatorBounds::maxY - MercatorBounds::minY) / worldSizeDevisor; - m2::RectD tileRect(m_key.m_x * rectSizeX, - m_key.m_y * rectSizeY, - (m_key.m_x + 1) * rectSizeX, - (m_key.m_y + 1) * rectSizeY); + m2::RectD tileRect(m_key.m_x * rectSizeX, + m_key.m_y * rectSizeY, + (m_key.m_x + 1) * rectSizeX, + (m_key.m_y + 1) * rectSizeY); - return tileRect; -} + return tileRect; + } void TileInfo::ReadFeatureIndex(model::FeaturesFetcher const & model) -{ + { if (DoNeedReadIndex()) -{ - threads::MutexGuard guard(m_mutex); + { + threads::MutexGuard guard(m_mutex); CheckCanceled(); model.ForEachFeatureID(GetGlobalRect(), *this, m_key.m_zoomLevel); sort(m_featureInfo.begin(), m_featureInfo.end()); } -} + } namespace { @@ -99,26 +101,26 @@ m2::RectD TileInfo::GetGlobalRect() const IDsAccumulator(vector & ids, vector const & src) : m_ids(ids) , m_src(src) -{ -} + { + } void operator()(size_t index) -{ + { ASSERT_LESS(index, m_src.size(), ()); m_ids.push_back(m_src[index].m_id); -} + } vector & m_ids; vector const & m_src; }; -} + } void TileInfo::ReadFeatures(model::FeaturesFetcher const & model, MemoryFeatureIndex & memIndex, EngineContext & context) -{ - CheckCanceled(); - vector indexes; + { + CheckCanceled(); + vector indexes; RequestFeatures(memIndex, indexes); vector featuresToRead; @@ -136,14 +138,23 @@ m2::RectD TileInfo::GetGlobalRect() const bool TileInfo::operator ()(FeatureType const & f) { - return true; -} + Stylist s; + InitStylist(f, m_key.m_zoomLevel, s); -void TileInfo::operator ()(FeatureID const & id) -{ - m_featureInfo.push_back(id); - CheckCanceled(); -} + if (s.PointStyleExists()) + ASSERT(s.AreaStyleExists() == false && s.LineStyleExists() == false, ()); + + if (s.LineStyleExists()) + ASSERT(s.AreaStyleExists() == false && s.PointStyleExists() == false, ()); + + return true; + } + + void TileInfo::operator ()(FeatureID const & id) + { + m_featureInfo.push_back(id); + CheckCanceled(); + } //====================================================//