From 2f0356070a4d8e682892eb5916b50897d937773c Mon Sep 17 00:00:00 2001 From: Konstantin Pastbin Date: Sun, 19 Feb 2023 09:27:27 +0000 Subject: [PATCH] [drape] Render areas in reverse size order Signed-off-by: Konstantin Pastbin --- drape_frontend/stylist.cpp | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/drape_frontend/stylist.cpp b/drape_frontend/stylist.cpp index a31e4118fa..3da5ad815d 100644 --- a/drape_frontend/stylist.cpp +++ b/drape_frontend/stylist.cpp @@ -1,4 +1,5 @@ #include "drape_frontend/stylist.hpp" +#include "drape/utils/projection.hpp" #include "indexer/classificator.hpp" #include "indexer/feature.hpp" @@ -15,6 +16,11 @@ namespace df { namespace { +// Minimum possible log2() value for the float (== -126). +double const kMinLog2 = std::log2(std::numeric_limits::min()); +// Minimum priority/depth value for lines and foreground areas. Should be same as in kothic. +static double constexpr kMinLinesDepth = 999.0f; + enum Type { Line = 1 << 0, @@ -73,6 +79,7 @@ public: , m_f(f) , m_geomType(type) , m_zoomLevel(zoomLevel) + , m_areaDepth(0) { m_rules.reserve(keyCount); Init(); @@ -104,8 +111,17 @@ private: void ProcessKey(drule::Key const & key) { double depth = key.m_priority; + + // Prioritize background areas by their sizes instead of style-set priorities. + // Foreground areas continue to use priorities to be orderable inbetween lines. + if (depth <= kMinLinesDepth && IsTypeOf(key, Area)) + depth = m_areaDepth; + if (m_featureLayer != feature::LAYER_EMPTY) { + // @todo layers are applicable relative to intersecting features only + // (atm layer correction changes feature's priority against ALL other features); + // and the current implementation is dependent on a stable priorities range. if (IsTypeOf(key, Line)) { double const layerPart = m_featureLayer * drule::layer_base_priority; @@ -114,7 +130,7 @@ private: } else if (IsTypeOf(key, Area)) { - // Area styles have big negative priorities (like -15000), so just add layer correction. + // Background areas have big negative priorities (-13000, -8000), so just add layer correction. depth += m_featureLayer * drule::layer_base_priority; } else @@ -144,21 +160,28 @@ private: void Init() { m_featureLayer = m_f.GetLayer(); - // @todo m_priorityModifier is not used, try to apply to areas to render in size order. - if (m_geomType == feature::GeomType::Point) - m_priorityModifier = (double)m_f.GetPopulation() / 7E9; - else + if (m_geomType == feature::GeomType::Area) { + // Calculate depth based on areas' sizes instead of style-set priorities. m2::RectD const r = m_f.GetLimitRect(m_zoomLevel); - m_priorityModifier = std::min(1.0, r.SizeX() * r.SizeY() * 10000.0); + // Raw areas' size range of about (1e-10, 3000) is too big, have to shrink it. + double const areaSize = r.SizeX() * r.SizeY(); + // log2() of numbers <1.0 is negative, adjust it to be positive. + double const areaSizeCompact = std::log2(areaSize) - kMinLog2; + // Should be well below lines and foreground areas for the layering logic to work correctly, + // produces a depth range of about (-13000, -8000). + m_areaDepth = kMinLinesDepth - areaSizeCompact * 100.0f; + + // There are depth limits out of which areas won't render. + ASSERT(dp::kMinDepth < m_areaDepth && m_areaDepth < dp::kMaxDepth, (m_areaDepth)); } } FeatureType & m_f; feature::GeomType m_geomType; int const m_zoomLevel; - double m_priorityModifier; int m_featureLayer; + double m_areaDepth; }; } // namespace