diff --git a/graphics/glyph_layout.cpp b/graphics/glyph_layout.cpp index 6894340f90..92133320cd 100644 --- a/graphics/glyph_layout.cpp +++ b/graphics/glyph_layout.cpp @@ -223,7 +223,7 @@ namespace graphics if (m_path.fullLength() < strLength) return; - PathPoint arrPathStart(0, ang::AngleD(ang::AngleTo(m_path.get(0), m_path.get(1))), m_path.get(0)); + PathPoint arrPathStart = m_path.front(); m_pivot = m_path.offsetPoint(arrPathStart, m_path.fullLength() / 2.0).m_pt; diff --git a/graphics/graphics.pro b/graphics/graphics.pro index ee961f3464..892d5e57d6 100644 --- a/graphics/graphics.pro +++ b/graphics/graphics.pro @@ -72,7 +72,8 @@ SOURCES += \ icon.cpp \ brush.cpp \ geometry_pipeline.cpp \ - pipeline_manager.cpp + pipeline_manager.cpp \ + path_view.cpp \ HEADERS += \ opengl/opengl.hpp \ @@ -140,7 +141,8 @@ HEADERS += \ brush.hpp \ geometry_pipeline.hpp \ pipeline_manager.hpp \ - vertex_stream.hpp + vertex_stream.hpp \ + path_view.hpp \ win32* { SOURCES += opengl/opengl_win32.cpp diff --git a/graphics/path_view.cpp b/graphics/path_view.cpp new file mode 100644 index 0000000000..b46a5d93ec --- /dev/null +++ b/graphics/path_view.cpp @@ -0,0 +1,144 @@ +#include "path_view.hpp" + +namespace graphics +{ + PathPoint::PathPoint(int i, ang::AngleD const & segAngle, m2::PointD const & pt) + : m_i(i), + m_segAngle(segAngle), + m_pt(pt) + {} + + PivotPoint::PivotPoint(ang::AngleD const & angle, PathPoint const & pp) + : m_angle(angle), m_pp(pp) + {} + + PathView::PathView() + : m_pts(0), + m_ptsCount(0), + m_isReverse(false) + {} + + PathView::PathView(m2::PointD const * pts, + size_t ptsCount) + : m_pts(pts), + m_ptsCount(ptsCount), + m_isReverse(false) + { + } + + size_t PathView::size() const + { + return m_ptsCount; + } + + m2::PointD const & PathView::get(size_t i) const + { + ASSERT(i < m_ptsCount, ("index out of range")); + return m_pts[m_isReverse ? m_ptsCount - i - 1 : i]; + } + + void PathView::setIsReverse(bool flag) + { + m_isReverse = flag; + } + + bool PathView::isReverse() const + { + return m_isReverse; + } + + PathPoint const PathView::offsetPoint(PathPoint const & pp, double offset) + { + PathPoint res = pp; + + if (res.m_i == -1) + return res; + + if (offset == 0) + return pp; + + bool found = false; + + for (size_t i = res.m_i; i < size() - 1; ++i) + { + double l = res.m_pt.Length(get(i + 1)); + + if (offset <= l) + { + if (i != res.m_i) + res.m_segAngle = ang::AngleD(ang::AngleTo(get(i), get(i + 1))); + + res.m_pt = res.m_pt.Move(offset, res.m_segAngle.sin(), res.m_segAngle.cos()); + res.m_i = i; + found = true; + break; + } + else + { + offset -= l; + res.m_pt = get(i + 1); + } + } + + if (!found) + res.m_i = -1; + + return res; + } + + PivotPoint PathView::findPivotPoint(PathPoint const & pp, double advance, double kern) + { + PathPoint startPt = offsetPoint(pp, kern); + + PivotPoint res; + if (startPt.m_i == -1) + return res; + + m2::PointD pt1 = startPt.m_pt; + + double angle = 0; + + int j = startPt.m_i; + + while (advance > 0) + { + if (j + 1 == size()) + return res; + + double l = get(j + 1).Length(pt1); + + double segAngle = j == startPt.m_i ? startPt.m_segAngle.val() + : ang::AngleTo(get(j), get(j + 1)); + + angle += segAngle; + + if (l < advance) + { + advance -= l; + pt1 = get(j + 1); + ++j; + } + else + { + ang::AngleD a(segAngle); + + res.m_pp.m_i = j; + res.m_pp.m_pt = pt1.Move(advance, a.sin(), a.cos()); + advance = 0; + + angle /= (res.m_pp.m_i - startPt.m_i + 1); + res.m_angle = ang::AngleD(angle); + res.m_pp.m_segAngle = a; + + break; + } + } + + return res; + } + + PathPoint const PathView::front() const + { + return PathPoint(0, ang::AngleD(ang::AngleTo(get(0), get(1))), get(0)); + } +} diff --git a/graphics/path_view.hpp b/graphics/path_view.hpp new file mode 100644 index 0000000000..133517aa41 --- /dev/null +++ b/graphics/path_view.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include "../geometry/point2d.hpp" +#include "../geometry/angles.hpp" + +namespace graphics +{ + struct PathPoint + { + int m_i; //< segment number + ang::AngleD m_segAngle; + m2::PointD m_pt; //< point on segment + PathPoint(int i = -1, + ang::AngleD const & segAngle = ang::AngleD(), + m2::PointD const & pt = m2::PointD()); + }; + + struct PivotPoint + { + ang::AngleD m_angle; + PathPoint m_pp; + PivotPoint(ang::AngleD const & angle = ang::AngleD(), PathPoint const & pp = PathPoint()); + }; + + class PathView + { + private: + + m2::PointD const * m_pts; + size_t m_ptsCount; + bool m_isReverse; + + public: + + PathView(); + PathView(m2::PointD const * pts, size_t ptsCount); + + size_t size() const; + + m2::PointD const & get(size_t i) const; + + void setIsReverse(bool flag); + bool isReverse() const; + + PathPoint const offsetPoint(PathPoint const & pp, double offset); + PivotPoint findPivotPoint(PathPoint const & pp, double advance, double kern); + + PathPoint const front() const; + }; + +} diff --git a/graphics/text_path.cpp b/graphics/text_path.cpp index e83beddcc5..b727e21d9b 100644 --- a/graphics/text_path.cpp +++ b/graphics/text_path.cpp @@ -6,17 +6,10 @@ namespace graphics { - PathPoint::PathPoint(int i, ang::AngleD const & segAngle, m2::PointD const & pt) - : m_i(i), - m_segAngle(segAngle), - m_pt(pt) - {} - - PivotPoint::PivotPoint(ang::AngleD const & angle, PathPoint const & pp) - : m_angle(angle), m_pp(pp) - {} - - TextPath::TextPath() : m_reverse(false), m_fullLength(0), m_pathOffset(0) + TextPath::TextPath() + : m_pv(), + m_fullLength(0), + m_pathOffset(0) {} TextPath::TextPath(TextPath const & src, math::Matrix const & m) @@ -28,21 +21,19 @@ namespace graphics m_fullLength = (m2::PointD(src.m_fullLength, 0) * m).Length(m2::PointD(0, 0) * m); m_pathOffset = (m2::PointD(src.m_pathOffset, 0) * m).Length(m2::PointD(0, 0) * m); + m_pv = PathView(&m_arr[0], m_arr.size()); + /// Fix: Check for reversing only when rotation is active, /// otherwise we have some flicker-blit issues for street names on zooming. /// @todo Should investigate this stuff. if (m(0, 1) != 0.0 && m(1, 0) != 0.0) - { - m_reverse = false; checkReverse(); - } else - m_reverse = src.m_reverse; + setIsReverse(src.isReverse()); } TextPath::TextPath(m2::PointD const * arr, size_t sz, double fullLength, double pathOffset) - : m_reverse(false), - m_fullLength(fullLength), + : m_fullLength(fullLength), m_pathOffset(pathOffset) { ASSERT ( sz > 1, () ); @@ -50,9 +41,21 @@ namespace graphics m_arr.resize(sz); copy(arr, arr + sz, m_arr.begin()); + m_pv = PathView(&m_arr[0], m_arr.size()); + checkReverse(); } + bool TextPath::isReverse() const + { + return m_pv.isReverse(); + } + + void TextPath::setIsReverse(bool flag) + { + m_pv.setIsReverse(flag); + } + void TextPath::checkReverse() { /* assume, that readable text in path should be ('o' - start draw point): @@ -63,6 +66,7 @@ namespace graphics */ double const a = ang::AngleTo(m_arr[0], m_arr[m_arr.size() - 1]); + if (fabs(a) > math::pi / 2.0) { // if we swap direction, we need to recalculate path offset from the end @@ -75,8 +79,10 @@ namespace graphics if (m_pathOffset < 0.0) m_pathOffset = 0.0; - m_reverse = true; + setIsReverse(true); } + else + setIsReverse(false); } double TextPath::fullLength() const @@ -89,104 +95,34 @@ namespace graphics return m_pathOffset; } - size_t TextPath::size() const { return m_arr.size(); } + size_t TextPath::size() const + { + return m_pv.size(); + } m2::PointD TextPath::get(size_t i) const { - ASSERT ( i < m_arr.size(), ("Index out of range") ); - return m_arr[m_reverse ? m_arr.size() - i - 1 : i]; + return m_pv.get(i); } - m2::PointD TextPath::operator[](size_t i) const { return get(i); } + m2::PointD TextPath::operator[](size_t i) const + { + return get(i); + } PathPoint const TextPath::offsetPoint(PathPoint const & pp, double offset) { - PathPoint res = pp; - - if (res.m_i == -1) - return res; - - if (offset == 0) - return pp; - - bool found = false; - - for (size_t i = res.m_i; i < size() - 1; ++i) - { - double l = res.m_pt.Length(get(i + 1)); - - if (offset <= l) - { - if (i != res.m_i) - res.m_segAngle = ang::AngleD(ang::AngleTo(get(i), get(i + 1))); - - res.m_pt = res.m_pt.Move(offset, res.m_segAngle.sin(), res.m_segAngle.cos()); - res.m_i = i; - found = true; - break; - } - else - { - offset -= l; - res.m_pt = get(i + 1); - } - } - - if (!found) - res.m_i = -1; - - return res; + return m_pv.offsetPoint(pp, offset); } PivotPoint TextPath::findPivotPoint(PathPoint const & pp, GlyphMetrics const & sym, double kern) { - PathPoint startPt = offsetPoint(pp, kern); + return m_pv.findPivotPoint(pp, sym.m_xOffset + sym.m_width / 2.0, kern); + } - PivotPoint res; - if (startPt.m_i == -1) - return res; - - m2::PointD pt1 = startPt.m_pt; - - double angle = 0; - double advance = sym.m_xOffset + sym.m_width / 2.0; - - int j = startPt.m_i; - - while (advance > 0) - { - if (j + 1 == size()) - return res; - - double l = get(j + 1).Length(pt1); - - double segAngle = j == startPt.m_i ? startPt.m_segAngle.val() : ang::AngleTo(get(j), get(j + 1)); - - angle += segAngle; - - if (l < advance) - { - advance -= l; - pt1 = get(j + 1); - ++j; - } - else - { - ang::AngleD a(segAngle); - - res.m_pp.m_i = j; - res.m_pp.m_pt = pt1.Move(advance, a.sin(), a.cos()); - advance = 0; - - angle /= (res.m_pp.m_i - startPt.m_i + 1); - res.m_angle = ang::AngleD(angle); - res.m_pp.m_segAngle = a; - - break; - } - } - - return res; + PathPoint const TextPath::front() const + { + return m_pv.front(); } } diff --git a/graphics/text_path.hpp b/graphics/text_path.hpp index e35c4f4fc9..dd23d3c905 100644 --- a/graphics/text_path.hpp +++ b/graphics/text_path.hpp @@ -1,35 +1,20 @@ #pragma once -#include "../geometry/point2d.hpp" -#include "../geometry/angles.hpp" #include "../base/matrix.hpp" +#include "../base/buffer_vector.hpp" + #include "glyph_cache.hpp" +#include "path_view.hpp" namespace graphics { - struct PathPoint - { - int m_i; //< segment number - ang::AngleD m_segAngle; - m2::PointD m_pt; //< point on segment - PathPoint(int i = -1, - ang::AngleD const & segAngle = ang::AngleD(), - m2::PointD const & pt = m2::PointD()); - }; - - struct PivotPoint - { - ang::AngleD m_angle; - PathPoint m_pp; - PivotPoint(ang::AngleD const & angle = ang::AngleD(), PathPoint const & pp = PathPoint()); - }; - class TextPath { private: buffer_vector m_arr; - bool m_reverse; + PathView m_pv; + double m_fullLength; double m_pathOffset; @@ -49,8 +34,12 @@ namespace graphics double fullLength() const; double pathOffset() const; - PathPoint const offsetPoint(PathPoint const & pp, double offset); + void setIsReverse(bool flag); + bool isReverse() const; + PathPoint const offsetPoint(PathPoint const & pp, double offset); PivotPoint findPivotPoint(PathPoint const & pp, GlyphMetrics const & sym, double kern); + + PathPoint const front() const; }; }