forked from organicmaps/organicmaps
"base class extraction" refactoring for TextPath.
This commit is contained in:
parent
ee425ef178
commit
178f6fa4fa
6 changed files with 249 additions and 127 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
144
graphics/path_view.cpp
Normal file
144
graphics/path_view.cpp
Normal file
|
@ -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));
|
||||
}
|
||||
}
|
51
graphics/path_view.hpp
Normal file
51
graphics/path_view.hpp
Normal file
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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<double, 3, 3> 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<m2::PointD, 8> 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;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue