Welcome to mirror list, hosted at ThFree Co, Russian Federation.

text_path.cpp « graphics - github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 30c7c8b60887b21b2c66955303f953cca6bd8647 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include "graphics/text_path.hpp"
#include "graphics/glyph_cache.hpp"

#include "geometry/angles.hpp"


namespace graphics
{
  TextPath::TextPath()
    : m_pv(),
      m_fullLength(0),
      m_pathOffset(0)
  {}

  TextPath::TextPath(TextPath const & src, math::Matrix<double, 3, 3> const & m)
  {
    m_arr.resize(src.m_arr.size());
    for (unsigned i = 0; i < m_arr.size(); ++i)
      m_arr[i] = src.m_arr[i] * m;

    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)
      checkReverse();
    else
      setIsReverse(src.isReverse());
  }

  TextPath::TextPath(m2::PointD const * arr, size_t sz, double fullLength, double pathOffset)
    : m_fullLength(fullLength),
      m_pathOffset(pathOffset)
  {
    ASSERT ( sz > 1, () );

    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):
     *    /   o
     *   /     \
     *  /   or  \
     * o         \
     */

    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
      double len = 0.0;
      for (size_t i = 1; i < m_arr.size(); ++i)
        len += m_arr[i-1].Length(m_arr[i]);

      m_pathOffset = m_fullLength - m_pathOffset - len;
      ASSERT ( m_pathOffset >= -1.0E-6, () );
      if (m_pathOffset < 0.0)
        m_pathOffset = 0.0;

      setIsReverse(true);
    }
    else
      setIsReverse(false);
  }

  double TextPath::fullLength() const
  {
    return m_fullLength;
  }

  double TextPath::pathOffset() const
  {
    return m_pathOffset;
  }

  size_t TextPath::size() const
  {
    return m_pv.size();
  }

  m2::PointD TextPath::get(size_t i) const
  {
    return m_pv.get(i);
  }

  m2::PointD TextPath::operator[](size_t i) const
  {
    return get(i);
  }

  PathPoint const TextPath::offsetPoint(PathPoint const & pp, double offset) const
  {
    return m_pv.offsetPoint(pp, offset);
  }

  void TextPath::copyWithOffset(double offset, vector<m2::PointD> & path) const
  {
    PathPoint pt = m_pv.offsetPoint(front(), m_pathOffset + offset);
    path.push_back(pt.m_pt);
    path.insert(path.end(), m_arr.begin() + pt.m_i, m_arr.end());
  }

  PivotPoint TextPath::findPivotPoint(PathPoint const & pp, GlyphMetrics const & sym) const
  {
    const PivotPoint ptStart = m_pv.findPivotPoint(pp, sym.m_xOffset - sym.m_width);
    const PivotPoint ptEnd = m_pv.findPivotPoint(pp, sym.m_xOffset + sym.m_width * 2);

    // both start and end are on the same segment, no need to calculate
    if (ptStart.m_pp.m_i == ptEnd.m_pp.m_i)
      return PivotPoint(ptStart.m_angle,
                        PathPoint(ptStart.m_pp.m_i, ptStart.m_angle, (ptStart.m_pp.m_pt + ptEnd.m_pp.m_pt) / 2.0));

    // points are on different segments, average the angle and middle point
    const PivotPoint ptMid = m_pv.findPivotPoint(pp, sym.m_xOffset + sym.m_width / 2.0);
    if ((ptStart.m_pp.m_i != -1) && (ptMid.m_pp.m_i != -1) && (ptEnd.m_pp.m_i != -1))
    {
      const ang::AngleD avgAngle(ang::GetMiddleAngle(ptStart.m_angle.val(), ptEnd.m_angle.val()));

      return PivotPoint(avgAngle,
                        PathPoint(ptMid.m_pp.m_i, ptMid.m_angle,
                                  (ptStart.m_pp.m_pt +
                                   ptMid.m_pp.m_pt + ptMid.m_pp.m_pt + // twice to compensate for long distance
                                   ptEnd.m_pp.m_pt) / 4.0));
    }
    else
    {
      // if some of the pivot points are outside of the path, just take the middle value
      return ptMid;
    }
  }

  PathPoint const TextPath::front() const
  {
    return m_pv.front();
  }
}