diff --git a/map/draw_processor.cpp b/map/draw_processor.cpp index 2502725cb3..b5e5cecccc 100644 --- a/map/draw_processor.cpp +++ b/map/draw_processor.cpp @@ -14,13 +14,13 @@ using namespace di; m2::PointD base::g2p(m2::PointD const & pt) const { - return m_convertor.GtoP(pt); + return m_convertor->GtoP(pt); } -base_screen::base_screen(ScreenBase const & convertor, m2::RectD const & rect) -: base(convertor) +base_screen::base_screen(params const & p) +: base(p) { - m_convertor.GtoP(rect, m_rect); + m_convertor->GtoP(*p.m_rect, m_rect); } void one_point::operator() (CoordPointT const & p) @@ -29,7 +29,7 @@ void one_point::operator() (CoordPointT const & p) m2::PointD pt(make_point(p)); - if (m_rect.IsPointInside(pt)) + if (m_rect->IsPointInside(pt)) { m_exist = true; m_point = convert_point(pt); @@ -55,7 +55,7 @@ void path_points::EndPL() void path_points::simple_filtration(m2::PointD const & pt) { - if (m_prevPt) + if (m_hasPrevPt) { if (!m2::RectD(m_prev, pt).IsIntersect(m_rect)) m_newPL = true; @@ -71,7 +71,7 @@ void path_points::simple_filtration(m2::PointD const & pt) } else { - m_prevPt = true; + m_hasPrevPt = true; m_length = 0.0; } @@ -80,32 +80,54 @@ void path_points::simple_filtration(m2::PointD const & pt) void path_points::best_filtration(m2::PointD const & pt) { - if (m_prevPt) + if (m_hasPrevPt) { m2::PointD prev = m_prev; m2::PointD curr = pt; - if (!m2::Intersect(m_rect, prev, curr)) - m_newPL = true; - else - { - if (!equal_glb_pts(prev, m_prev)) - m_newPL = true; + double segLen = curr.Length(prev); + if ((m_startLength != 0) && (m_endLength != 0)) + { + if ((m_startLength >= m_length) && (m_startLength < m_length + segLen)) + m_startLength = m_length; + + if ((m_endLength >= m_length) && (m_endLength < m_length + segLen)) + m_endLength = m_length + curr.Length(prev); + } + + if ((m_length >= m_startLength) && (m_endLength >= m_length + segLen)) + { + /// we're in the dead zone. add without clipping if (m_newPL) StartPL(prev); push_point(curr); - - if (!equal_glb_pts(curr, pt)) + } + else + { + if (!m2::Intersect(m_rect, prev, curr)) m_newPL = true; + else + { + if (!equal_glb_pts(prev, m_prev)) + m_newPL = true; + + if (m_newPL) + StartPL(prev); + + push_point(curr); + + if (!equal_glb_pts(curr, pt)) + m_newPL = true; + } } m_length += m_prev.Length(pt); } else { - m_prevPt = true; + m_hasPrevPt = true; m_length = 0.0; } diff --git a/map/draw_processor.hpp b/map/draw_processor.hpp index dfc6e36d1e..0195ad6e46 100644 --- a/map/draw_processor.hpp +++ b/map/draw_processor.hpp @@ -9,6 +9,8 @@ #include "../std/list.hpp" #include "../std/limits.hpp" +#include "../yg/glyph_cache.hpp" + class ScreenBase; namespace get_pts @@ -23,7 +25,7 @@ namespace get_pts class base { protected: - ScreenBase const & m_convertor; + ScreenBase const * m_convertor; static m2::PointD make_point(CoordPointT const & p) { @@ -31,7 +33,14 @@ namespace get_pts } m2::PointD g2p(m2::PointD const & pt) const; - base(ScreenBase const & convertor) : m_convertor(convertor) + struct params + { + ScreenBase const * m_convertor; + params() : m_convertor() + {} + }; + + base(params const & p) : m_convertor(p.m_convertor) { } }; @@ -40,15 +49,21 @@ namespace get_pts class base_global : public base { protected: - m2::RectD const & m_rect; + m2::RectD const * m_rect; m2::PointD convert_point(m2::PointD const & pt) const { return g2p(pt); } - base_global(ScreenBase const & convertor, m2::RectD const & rect) - : base(convertor), m_rect(rect) + struct params : base::params + { + m2::RectD const * m_rect; + params() : m_rect(0){} + }; + + base_global(params const & p) + : base(p), m_rect(p.m_rect) { } }; @@ -57,6 +72,7 @@ namespace get_pts class base_screen : public base { protected: + m2::RectD m_rect; m2::PointD convert_point(m2::PointD const & pt) const @@ -64,10 +80,45 @@ namespace get_pts return pt; } - base_screen(ScreenBase const & convertor, m2::RectD const & rect); + struct params : base::params + { + m2::RectD const * m_rect; + params() : m_rect(0) + {} + }; + + base_screen(params const & p); }; + //@} + template + class calc_length : public TBase + { + bool m_exist; + m2::PointD m_prevPt; + public: + double m_length; + + typedef typename TBase::params params; + + calc_length(params const & p) : + TBase(p), m_exist(false), m_length(0) + {} + + void operator() (CoordPointT const & p) + { + m2::PointD pt(this->convert_point(this->make_point(p))); + if (m_exist) + m_length += pt.Length(m_prevPt); + + m_exist = true; + m_prevPt = pt; + } + + bool IsExist() const {return m_exist;} + }; + class one_point : public base_global { bool m_exist; @@ -75,8 +126,10 @@ namespace get_pts public: m2::PointD m_point; - one_point(ScreenBase const & convertor, m2::RectD const & rect) - : base_global(convertor, rect), m_exist(false) + typedef base_global::params params; + + one_point(params const & p) + : base_global(p), m_exist(false) { } @@ -90,8 +143,10 @@ namespace get_pts public: list m_points; - geometry_base(ScreenBase const & convertor, m2::RectD const & rect) - : TBase(convertor, rect) + typedef typename TBase::params params; + + geometry_base(params const & p) + : TBase(p) { } @@ -110,10 +165,14 @@ namespace get_pts { typedef geometry_base base_type; - bool m_newPL, m_prevPt; + bool m_newPL, m_hasPrevPt; m2::PointD m_prev; double m_length; + double m_startLength; + double m_endLength; + + double m_fontSize; void StartPL(m2::PointD const & pt); void EndPL(); @@ -127,8 +186,22 @@ namespace get_pts void best_filtration(m2::PointD const & p); public: - path_points(ScreenBase const & convertor, m2::RectD const & rect) - : base_type(convertor, rect), m_newPL(true), m_prevPt(false), m_length(0.0) + + struct params : base_type::params + { + double m_startLength; + double m_endLength; + params() : m_startLength(0), m_endLength(0) + {} + }; + + path_points(params const & p) + : base_type(p), + m_newPL(true), + m_hasPrevPt(false), + m_length(0.0), + m_startLength(p.m_startLength), + m_endLength(p.m_endLength) { } @@ -144,8 +217,11 @@ namespace get_pts typedef geometry_base base_type; public: - area_base(ScreenBase const & convertor, m2::RectD const & rect) - : base_type(convertor, rect) + + typedef base_type::params params; + + area_base(params const & p) + : base_type(p) { } }; @@ -154,8 +230,10 @@ namespace get_pts class area_tess_points : public area_base { public: - area_tess_points(ScreenBase const & convertor, m2::RectD const & rect) - : area_base(convertor, rect) + typedef area_base::params params; + + area_tess_points(params const & p) + : area_base(p) { } @@ -184,8 +262,11 @@ namespace get_pts } public: - filter_screenpts_adapter(ScreenBase const & convertor, m2::RectD const & rect) - : TBase(convertor, rect), m_count(0), + + typedef typename TBase::params params; + + filter_screenpts_adapter(params const & p) + : TBase(p), m_count(0), m_prev(numeric_limits::min(), numeric_limits::min()), m_center(0, 0) { } diff --git a/map/drawer_yg.hpp b/map/drawer_yg.hpp index ad65b789db..9114f47d2f 100644 --- a/map/drawer_yg.hpp +++ b/map/drawer_yg.hpp @@ -65,10 +65,6 @@ class DrawerYG static void ClearSkinPage(uint8_t pageID); - uint8_t get_text_font_size(rule_ptr_t pRule) const; - uint8_t get_pathtext_font_size(rule_ptr_t pRule) const; - bool filter_text_size(rule_ptr_t pRule) const; - typedef map > org_map_t; org_map_t m_pathsOrg; @@ -113,4 +109,8 @@ public: void SetScale(int level); void Draw(di::DrawInfo const * pInfo, di::DrawRule const * rules, size_t count); + + uint8_t get_text_font_size(rule_ptr_t pRule) const; + uint8_t get_pathtext_font_size(rule_ptr_t pRule) const; + bool filter_text_size(rule_ptr_t pRule) const; }; diff --git a/map/framework.cpp b/map/framework.cpp index 40dd044a6d..c8143fb3ba 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -49,12 +49,14 @@ namespace fwork ScreenBase const & convertor, shared_ptr const & paintEvent, int scaleLevel, - shared_ptr const & renderState) + shared_ptr const & renderState, + yg::GlyphCache * glyphCache) : m_rect(r), m_convertor(convertor), m_paintEvent(paintEvent), m_zoom(scaleLevel), - m_renderState(renderState) + m_renderState(renderState), + m_glyphCache(glyphCache) #ifdef PROFILER_DRAWING , m_drawCount(0) #endif @@ -107,9 +109,8 @@ namespace fwork m_keys.erase(unique(m_keys.begin(), m_keys.end(), equal_key()), m_keys.end()); } -#define GET_POINTS(f, for_each_fun, functor_t, assign_fun) \ +#define GET_POINTS(f, for_each_fun, fun, assign_fun) \ { \ - functor_t fun(m_convertor, m_rect); \ f.for_each_fun(fun, m_zoom); \ if (fun.IsExist()) \ { \ @@ -136,50 +137,14 @@ namespace fwork return true; } - m_renderState->m_isEmptyModelCurrent = false; - - shared_ptr ptr(new di::DrawInfo(f.GetPreferredDrawableName())); - - using namespace get_pts; - - bool isExist = false; - switch (type) - { - case GEOM_POINT: - GET_POINTS(f, ForEachPointRef, get_pts::one_point, assign_point) - break; - - case GEOM_AREA: - GET_POINTS(f, ForEachTriangleExRef, filter_screenpts_adapter, assign_area) - { - // if area feature has any line-drawing-rules, than draw it like line - for (size_t i = 0; i < m_keys.size(); ++i) - if (m_keys[i].m_type == drule::line) - goto draw_line; - break; - } - - draw_line: - case GEOM_LINE: - GET_POINTS(f, ForEachPointRef, filter_screenpts_adapter, assign_path) - break; - } - - // nothing to draw - if (!isExist) return true; - - int const layer = f.GetLayer(); - DrawerYG * pDrawer = GetDrawer(); - - // remove duplicating identical drawing keys - PreProcessKeys(); - // get drawing rules for the m_keys array size_t const count = m_keys.size(); buffer_vector rules; rules.resize(count); + int const layer = f.GetLayer(); + for (size_t i = 0; i < count; ++i) { int depth = m_keys[i].m_priority; @@ -191,6 +156,97 @@ namespace fwork sort(rules.begin(), rules.end(), less_depth()); + m_renderState->m_isEmptyModelCurrent = false; + + shared_ptr ptr(new di::DrawInfo(f.GetPreferredDrawableName())); + + DrawerYG * pDrawer = GetDrawer(); + + using namespace get_pts; + + bool isExist = false; + switch (type) + { + case GEOM_POINT: + { + typedef get_pts::one_point functor_t; + + functor_t::params p; + p.m_convertor = &m_convertor; + p.m_rect = &m_rect; + + functor_t fun(p); + GET_POINTS(f, ForEachPointRef, fun, assign_point) + break; + } + + case GEOM_AREA: + { + typedef filter_screenpts_adapter functor_t; + + functor_t::params p; + p.m_convertor = &m_convertor; + p.m_rect = &m_rect; + + functor_t fun(p); + GET_POINTS(f, ForEachTriangleExRef, fun, assign_area) + { + // if area feature has any line-drawing-rules, than draw it like line + for (size_t i = 0; i < m_keys.size(); ++i) + if (m_keys[i].m_type == drule::line) + goto draw_line; + break; + } + } + draw_line: + case GEOM_LINE: + { + typedef filter_screenpts_adapter functor_t; + functor_t::params p; + p.m_convertor = &m_convertor; + p.m_rect = &m_rect; + + if (!ptr->m_name.empty()) + { + double fontSize = 0; + for (size_t i = 0; i < count; ++i) + { + if (pDrawer->filter_text_size(rules[i].m_rule)) + fontSize = pDrawer->get_pathtext_font_size(rules[i].m_rule); + } + + if (fontSize != 0) + { + double textLength = m_glyphCache->getTextLength(fontSize, ptr->m_name); + typedef calc_length functor_t; + functor_t::params p1; + p1.m_convertor = &m_convertor; + p1.m_rect = &m_rect; + functor_t fun(p1); + + f.ForEachPointRef(fun, m_zoom); + if ((fun.IsExist()) && (fun.m_length > textLength)) + { + textLength += 200; + p.m_startLength = (fun.m_length - textLength) / 2; + p.m_endLength = p.m_startLength + textLength; + } + } + } + + functor_t fun(p); + + GET_POINTS(f, ForEachPointRef, fun, assign_path) + break; + } + } + + // nothing to draw + if (!isExist) return true; + + // remove duplicating identical drawing keys + PreProcessKeys(); + #ifdef PROFILER_DRAWING m_drawCount += m_keys.size(); #endif @@ -632,7 +688,7 @@ void FrameWork::AddRedrawCommandSure() int scaleLevel ) { - fwork::DrawProcessor doDraw(selectRect, screen, e, scaleLevel, m_renderQueue.renderStatePtr()); + fwork::DrawProcessor doDraw(selectRect, screen, e, scaleLevel, m_renderQueue.renderStatePtr(), m_resourceManager->getGlyphCache()); m_renderQueue.renderStatePtr()->m_isEmptyModelCurrent = true; try diff --git a/map/framework.hpp b/map/framework.hpp index 6872c4af2f..9265d1783b 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -64,6 +64,7 @@ namespace fwork int m_zoom; shared_ptr m_renderState; + yg::GlyphCache * m_glyphCache; #ifdef PROFILER_DRAWING size_t m_drawCount; @@ -81,7 +82,8 @@ namespace fwork ScreenBase const & convertor, shared_ptr const & paintEvent, int scaleLevel, - shared_ptr const & renderState); + shared_ptr const & renderState, + yg::GlyphCache * glyphCache); bool operator() (FeatureType const & f); }; diff --git a/map/render_queue_routine.cpp b/map/render_queue_routine.cpp index f86b93f271..e673a8948c 100644 --- a/map/render_queue_routine.cpp +++ b/map/render_queue_routine.cpp @@ -176,8 +176,7 @@ void RenderQueueRoutine::getUpdateAreas( { areas.push_back(newRect); - /* - int rectW = (newRect.SizeX() + 9) / 5; +/* int rectW = (newRect.SizeX() + 9) / 5; int rectH = (newRect.SizeY() + 9) / 5; m2::RectI r( 2 * rectW, 2 * rectH, 3 * rectW, 3 * rectH); areas.push_back(r); @@ -205,7 +204,7 @@ void RenderQueueRoutine::getUpdateAreas( areas.push_back(m2::Offset(r, 0, 2*rectH)); areas.push_back(m2::Offset(r, -rectW, 2*rectH)); areas.push_back(m2::Offset(r, -2*rectW, 2*rectH)); - */ +*/ } } diff --git a/yg/glyph_cache.cpp b/yg/glyph_cache.cpp index cf6fa0d4b9..9a232b8703 100644 --- a/yg/glyph_cache.cpp +++ b/yg/glyph_cache.cpp @@ -7,6 +7,7 @@ #include "ft2_debug.hpp" #include "../coding/lodepng_io.hpp" +#include "../coding/strutil.hpp" #include "../base/logging.hpp" @@ -237,6 +238,19 @@ namespace yg return info; } + double GlyphCache::getTextLength(double fontSize, string const & text) + { + wstring s = FromUtf8(text); + double len = 0; + for (unsigned i = 0; i < s.size(); ++i) + { + GlyphKey k(s[i], fontSize, false, yg::Color(0, 0, 0, 255)); + len += getGlyphMetrics(k).m_xAdvance; + } + + return len; + } + void GlyphInfo::dump(const char * /*fileName */) { /* gil::lodepng_write_view(fileName, diff --git a/yg/glyph_cache.hpp b/yg/glyph_cache.hpp index 5f0b0c1155..8c8c5f0aea 100644 --- a/yg/glyph_cache.hpp +++ b/yg/glyph_cache.hpp @@ -72,5 +72,7 @@ namespace yg shared_ptr const getGlyph(GlyphKey const & key); /// return control box(could be slightly larger than the precise bound box). GlyphMetrics const getGlyphMetrics(GlyphKey const & key); + + double getTextLength(double fontSize, string const & text); }; } diff --git a/yg/glyph_layout.cpp b/yg/glyph_layout.cpp index d88e1dbec5..2321ac6ba2 100644 --- a/yg/glyph_layout.cpp +++ b/yg/glyph_layout.cpp @@ -324,4 +324,35 @@ namespace yg { return m_entries; } + + m2::RectD const GlyphLayout::limitRect() const + { + bool isFirst = true; + m2::RectD res; + + for (unsigned i = m_firstVisible; i < m_lastVisible; ++i) + { + m2::AARectD symRectAA( + m_entries[i].m_pt.Move(m_entries[i].m_metrics.m_height, m_entries[i].m_angle - math::pi / 2), + m_entries[i].m_angle, + m2::RectD(m_entries[i].m_metrics.m_xOffset, + m_entries[i].m_metrics.m_yOffset, + m_entries[i].m_metrics.m_xOffset + m_entries[i].m_metrics.m_width, + m_entries[i].m_metrics.m_yOffset + m_entries[i].m_metrics.m_height)); + + m2::PointD pts[4]; + symRectAA.GetGlobalPoints(pts); + + if (isFirst) + res = m2::RectD(pts[0].x, pts[0].y, pts[0].x, pts[0].y); + else + res.Add(pts[0]); + + res.Add(pts[1]); + res.Add(pts[2]); + res.Add(pts[3]); + } + + return res; + } } diff --git a/yg/glyph_layout.hpp b/yg/glyph_layout.hpp index 3032e968ca..342631e8e8 100644 --- a/yg/glyph_layout.hpp +++ b/yg/glyph_layout.hpp @@ -1,6 +1,7 @@ #pragma once #include "defines.hpp" +#include "../geometry/rect2d.hpp" #include "../std/vector.hpp" #include "../std/string.hpp" @@ -53,5 +54,7 @@ namespace yg size_t lastVisible() const; vector const & entries() const; + + m2::RectD const limitRect() const; }; } diff --git a/yg/resource_manager.cpp b/yg/resource_manager.cpp index f4611f84b1..a85c575d3e 100644 --- a/yg/resource_manager.cpp +++ b/yg/resource_manager.cpp @@ -203,6 +203,11 @@ namespace yg return m_glyphCache.getGlyphMetrics(key); } + GlyphCache * ResourceManager::getGlyphCache() + { + return &m_glyphCache; + } + void ResourceManager::addFonts(vector const & fontNames) { m_glyphCache.addFonts(fontNames); diff --git a/yg/resource_manager.hpp b/yg/resource_manager.hpp index f9e6653dad..869913fa69 100644 --- a/yg/resource_manager.hpp +++ b/yg/resource_manager.hpp @@ -96,6 +96,7 @@ namespace yg shared_ptr const getGlyph(GlyphKey const & key); GlyphMetrics const getGlyphMetrics(GlyphKey const & key); + GlyphCache * getGlyphCache(); void addFonts(vector const & fontNames);