PathTextElement and StraightTextElement implementation.

This commit is contained in:
rachytski 2011-06-02 00:40:24 +03:00 committed by Alex Zolotarev
parent 7435ad01cf
commit 76880dbdf5
16 changed files with 647 additions and 322 deletions

View file

@ -236,7 +236,7 @@ namespace fwork
if (fontSize != 0)
{
double textLength = m_glyphCache->getTextLength(fontSize, ptr->m_name);
typedef calc_length<base_screen> functor_t;
typedef calc_length<base_global> functor_t;
functor_t::params p1;
p1.m_convertor = &m_convertor;
p1.m_rect = &m_rect;

View file

@ -9,6 +9,7 @@
using std::istringstream;
using std::ostringstream;
using std::stringstream;
using std::endl;
#ifdef DEBUG_NEW

View file

@ -2,10 +2,14 @@
#include "glyph_layout.hpp"
#include "resource_manager.hpp"
#include "skin.hpp"
#include "font_desc.hpp"
#include "resource_style.hpp"
#include "text_path.hpp"
#include "../base/logging.hpp"
#include "../base/math.hpp"
#include "../std/sstream.hpp"
#include "../geometry/angles.hpp"
#include "../geometry/aa_rect2d.hpp"
@ -27,10 +31,8 @@ namespace yg
{
double m_angle;
PathPoint m_pp;
/// @todo Need to initialize or not ???
//PivotPoint(double angle = 0, PathPoint const & pp = PathPoint())
//{}
PivotPoint(double angle = 0, PathPoint const & pp = PathPoint())
{}
};
class pts_array
@ -187,6 +189,98 @@ namespace yg
return res;
}
GlyphLayout::GlyphLayout(shared_ptr<ResourceManager> const & resourceManager,
shared_ptr<Skin> const & skin,
FontDesc const & fontDesc,
m2::PointD const & pt,
wstring const & text,
yg::EPosition pos)
: m_resourceManager(resourceManager),
m_firstVisible(0),
m_lastVisible(text.size())
{
m2::PointD pv = pt;
for (size_t i = 0; i < text.size(); ++i)
{
GlyphKey glyphKey(text[i], fontDesc.m_size, fontDesc.m_isMasked, fontDesc.m_color);
if (fontDesc.m_isStatic)
{
uint32_t glyphID = skin->mapGlyph(glyphKey, fontDesc.m_isStatic);
CharStyle const * p = static_cast<CharStyle const *>(skin->fromID(glyphID));
if (p != 0)
{
if (i == 0)
m_limitRect = m2::RectD(p->m_xOffset + pv.x,
p->m_yOffset + pv.y,
p->m_xOffset + pv.x,
p->m_yOffset + pv.y);
else
m_limitRect.Add(m2::PointD(p->m_xOffset, p->m_yOffset) + pv);
m_limitRect.Add(m2::PointD(p->m_xOffset + p->m_texRect.SizeX() - 4,
p->m_yOffset + p->m_texRect.SizeY() - 4) + pv);
}
GlyphLayoutElem elem;
elem.m_sym = text[i];
elem.m_angle = 0;
elem.m_pt = pv;
elem.m_metrics.m_height = p->m_texRect.SizeY() - 4;
elem.m_metrics.m_width = p->m_texRect.SizeX() - 4;
elem.m_metrics.m_xAdvance = p->m_xAdvance;
elem.m_metrics.m_xOffset = p->m_xOffset;
elem.m_metrics.m_yOffset = p->m_yOffset;
elem.m_metrics.m_yAdvance = 0;
m_entries.push_back(elem);
pv += m2::PointD(p->m_xAdvance, 0);
}
else
{
GlyphMetrics const m = resourceManager->getGlyphMetrics(glyphKey);
if (i == 0)
m_limitRect = m2::RectD(m.m_xOffset + pv.x, m.m_yOffset + pv.y, m.m_xOffset + pv.x, m.m_yOffset + pv.y);
else
m_limitRect.Add(m2::PointD(m.m_xOffset, m.m_yOffset) + pv);
m_limitRect.Add(m2::PointD(m.m_xOffset + m.m_xAdvance,
m.m_yOffset + m.m_yAdvance) + pv);
GlyphLayoutElem elem;
elem.m_sym = text[i];
elem.m_angle = 0;
elem.m_pt = pv;
elem.m_metrics = m;
m_entries.push_back(elem);
pv += m2::PointD(m.m_xAdvance, m.m_yAdvance);
}
}
m2::PointD ptOffs(-m_limitRect.SizeX() / 2,
-m_limitRect.SizeY() / 2);
/// adjusting according to position
if (pos & EPosLeft)
ptOffs += m2::PointD(-m_limitRect.SizeX() / 2, 0);
if (pos & EPosRight)
ptOffs += m2::PointD(m_limitRect.SizeX() / 2, 0);
if (pos & EPosAbove)
ptOffs += m2::PointD(0, m_limitRect.SizeY() / 2);
if (pos & EPosUnder)
ptOffs += m2::PointD(0, -m_limitRect.SizeY() / 2);
offset(ptOffs);
}
GlyphLayout::GlyphLayout(shared_ptr<ResourceManager> const & resourceManager,
FontDesc const & fontDesc,
m2::PointD const * pts,
@ -199,7 +293,7 @@ namespace yg
m_firstVisible(0),
m_lastVisible(0)
{
pts_array arrPath(pts, ptsCount, fullLength, pathOffset);
TextPath arrPath(pts, ptsCount, fullLength, pathOffset);
// get vector of glyphs and calculate string length
double strLength = 0.0;
@ -311,6 +405,31 @@ namespace yg
m_lastVisible = symPos + 1;
}
bool isFirst = true;
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)
m_limitRect = m2::RectD(pts[0].x, pts[0].y, pts[0].x, pts[0].y);
else
m_limitRect.Add(pts[0]);
m_limitRect.Add(pts[1]);
m_limitRect.Add(pts[2]);
m_limitRect.Add(pts[3]);
}
}
size_t GlyphLayout::firstVisible() const
@ -330,32 +449,13 @@ namespace yg
m2::RectD const GlyphLayout::limitRect() const
{
bool isFirst = true;
m2::RectD res;
return m_limitRect;
}
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;
void GlyphLayout::offset(m2::PointD const & offs)
{
for (unsigned i = 0; i < m_entries.size(); ++i)
m_entries[i].m_pt += offs;
m_limitRect.Offset(offs);
}
}

View file

@ -2,6 +2,7 @@
#include "defines.hpp"
#include "../geometry/rect2d.hpp"
#include "../geometry/point2d.hpp"
#include "../std/vector.hpp"
#include "../std/string.hpp"
@ -14,6 +15,7 @@
namespace yg
{
class ResourceManager;
class Skin;
struct FontDesc;
struct GlyphLayoutElem
@ -35,12 +37,21 @@ namespace yg
vector<GlyphLayoutElem> m_entries;
m2::RectD m_limitRect;
double getKerning(GlyphLayoutElem const & prevElem, GlyphLayoutElem const & curElem);
public:
GlyphLayout(GlyphLayout const & layout, double shift);
GlyphLayout(shared_ptr<ResourceManager> const & resourceManager,
shared_ptr<Skin> const & skin,
FontDesc const & font,
m2::PointD const & pt,
wstring const & text,
yg::EPosition pos);
GlyphLayout(shared_ptr<ResourceManager> const & resourceManager,
FontDesc const & font,
m2::PointD const * pts,
@ -56,5 +67,7 @@ namespace yg
vector<GlyphLayoutElem> const & entries() const;
m2::RectD const limitRect() const;
void offset(m2::PointD const & offs);
};
}

View file

@ -1,56 +0,0 @@
#include "../base/SRC_FIRST.hpp"
#include "layout_element.hpp"
#include "screen.hpp"
namespace yg
{
LayoutElement::LayoutElement(int groupID, m2::PointD const & pivot, EPosition pos)
: m_groupID(groupID), m_pivot(pivot), m_pos(pos)
{}
int LayoutElement::groupID() const
{
return m_groupID;
}
m2::PointD const & LayoutElement::pivot() const
{
return m_pivot;
}
EPosition LayoutElement::position() const
{
return m_pos;
}
bool LayoutElement::isFreeElement() const
{
return m_isFreeElement;
}
void LayoutElement::setIsFreeElement(bool flag) const
{
m_isFreeElement = flag;
}
bool LayoutElement::isFrozen() const
{
return m_isFrozen;
}
void LayoutElement::setIsFrozen(bool flag) const
{
m_isFrozen = flag;
}
bool LayoutElement::doNeedRedraw() const
{
return m_doNeedRedraw;
}
void LayoutElement::setNeedRedraw(bool flag) const
{
m_doNeedRedraw = flag;
}
}

View file

@ -1,47 +0,0 @@
#pragma once
#include "../geometry/point2d.hpp"
#include "../geometry/rect2d.hpp"
#include "defines.hpp"
namespace yg
{
class Screen;
struct FontDesc;
class LayoutElement
{
private:
int m_groupID;
m2::PointD m_pivot;
EPosition m_pos;
mutable bool m_isFreeElement;
mutable bool m_isFrozen;
mutable bool m_doNeedRedraw;
public:
LayoutElement(int groupID, m2::PointD const & pivot, EPosition pos);
/// id of the group, composed of several layoutElements
int groupID() const;
/// pivot is expressed in group coordinates
m2::PointD const & pivot() const;
/// position of the element related to pivot point
EPosition position() const;
bool isFreeElement() const;
void setIsFreeElement(bool flag) const;
bool isFrozen() const;
void setIsFrozen(bool flag) const;
bool doNeedRedraw() const;
void setNeedRedraw(bool flag) const;
/// bounding rect in pivot-aligned coordinates
virtual m2::RectD const boundRect() const = 0;
/// draw layout element
virtual void draw(Screen * screen) = 0;
};
}

View file

@ -1,16 +0,0 @@
#pragma once
#include "layout_element.hpp"
namespace yg
{
class SymbolLayoutElement : public LayoutElement
{
public:
SymbolLayoutElement();
m2::RectD const boundRect() const;
void draw(Screen * screen);
};
}

134
yg/text_element.cpp Normal file
View file

@ -0,0 +1,134 @@
#include "../base/SRC_FIRST.hpp"
#include "text_element.hpp"
#include "screen.hpp"
#include "skin.hpp"
#include "resource_style.hpp"
#include "../base/string_utils.hpp"
namespace yg
{
OverlayElement::OverlayElement(Params const & p)
: m_pivot(p.m_pivot), m_position(p.m_position)
{}
void OverlayElement::offset(m2::PointD const & offs)
{
m_pivot += offs;
}
m2::PointD const & OverlayElement::pivot() const
{
return m_pivot;
}
void OverlayElement::setPivot(m2::PointD const & pivot)
{
m_pivot = pivot;
}
yg::EPosition OverlayElement::position() const
{
return m_position;
}
void OverlayElement::setPosition(yg::EPosition pos)
{
m_position = pos;
}
TextElement::TextElement(Params const & p)
: OverlayElement(p),
m_fontDesc(p.m_fontDesc),
m_utf8Text(p.m_utf8Text),
m_depth(p.m_depth),
m_log2vis(p.m_log2vis),
m_rm(p.m_rm),
m_skin(p.m_skin)
{
}
void TextElement::drawTextImpl(GlyphLayout const & layout, gl::Screen * screen, FontDesc const & fontDesc)
{
for (unsigned i = layout.firstVisible(); i < layout.lastVisible(); ++i)
{
shared_ptr<Skin> skin = screen->skin();
GlyphLayoutElem elem = layout.entries()[i];
uint32_t const glyphID = skin->mapGlyph(GlyphKey(elem.m_sym, fontDesc.m_size, fontDesc.m_isMasked, fontDesc.m_isMasked ? fontDesc.m_maskColor : fontDesc.m_color), fontDesc.m_isStatic);
CharStyle const * charStyle = static_cast<CharStyle const *>(skin->fromID(glyphID));
screen->drawGlyph(elem.m_pt, m2::PointD(0.0, 0.0), elem.m_angle, 0, charStyle, m_depth);
}
}
StraightTextElement::StraightTextElement(Params const & p)
: TextElement(p),
m_glyphLayout(p.m_rm,
p.m_skin,
p.m_fontDesc,
p.m_pivot,
strings::FromUtf8(p.m_utf8Text),
p.m_position)
{
}
m2::RectD const StraightTextElement::boundRect() const
{
return m_glyphLayout.limitRect();
}
void StraightTextElement::draw(gl::Screen * screen)
{
yg::FontDesc desc = m_fontDesc;
if (m_fontDesc.m_isMasked)
{
drawTextImpl(m_glyphLayout, screen, m_fontDesc);
desc.m_isMasked = false;
}
drawTextImpl(m_glyphLayout, screen, desc);
}
void StraightTextElement::offset(m2::PointD const & offs)
{
TextElement::offset(offs);
m_glyphLayout.offset(offs);
}
PathTextElement::PathTextElement(Params const & p)
: TextElement(p),
m_glyphLayout(p.m_rm,
p.m_fontDesc,
p.m_pts,
p.m_ptsCount,
strings::FromUtf8(p.m_utf8Text),
p.m_fullLength,
p.m_pathOffset,
p.m_position)
{
}
m2::RectD const PathTextElement::boundRect() const
{
return m_glyphLayout.limitRect();
}
void PathTextElement::draw(gl::Screen * screen)
{
yg::FontDesc desc = m_fontDesc;
if (m_fontDesc.m_isMasked)
{
drawTextImpl(m_glyphLayout, screen, m_fontDesc);
desc.m_isMasked = false;
}
drawTextImpl(m_glyphLayout, screen, desc);
}
void PathTextElement::offset(m2::PointD const & offs)
{
TextElement::offset(offs);
m_glyphLayout.offset(offs);
}
}

118
yg/text_element.hpp Normal file
View file

@ -0,0 +1,118 @@
#pragma once
#include "../geometry/point2d.hpp"
#include "../geometry/rect2d.hpp"
#include "../std/shared_ptr.hpp"
#include "defines.hpp"
#include "font_desc.hpp"
#include "glyph_layout.hpp"
namespace yg
{
class ResourceManager;
class Skin;
namespace gl
{
class Screen;
}
class OverlayElement
{
private:
m2::PointD m_pivot;
yg::EPosition m_position;
public:
struct Params
{
m2::PointD m_pivot;
yg::EPosition m_position;
};
OverlayElement(Params const & p);
virtual void offset(m2::PointD const & offs) = 0;
virtual m2::RectD const boundRect() const = 0;
virtual void draw(gl::Screen * screen) = 0;
m2::PointD const & pivot() const;
void setPivot(m2::PointD const & pv);
yg::EPosition position() const;
void setPosition(yg::EPosition pos);
};
class TextElement : public OverlayElement
{
protected:
/// text-element specific
FontDesc m_fontDesc;
string m_utf8Text;
double m_depth;
bool m_log2vis;
shared_ptr<ResourceManager> m_rm;
shared_ptr<Skin> m_skin;
public:
struct Params : OverlayElement::Params
{
FontDesc m_fontDesc;
string m_utf8Text;
double m_depth;
bool m_log2vis;
shared_ptr<ResourceManager> m_rm;
shared_ptr<Skin> m_skin;
};
TextElement(Params const & p);
void drawTextImpl(GlyphLayout const & layout, gl::Screen * screen, FontDesc const & desc);
};
class StraightTextElement : public TextElement
{
private:
GlyphLayout m_glyphLayout;
public:
struct Params : TextElement::Params
{};
StraightTextElement(Params const & p);
m2::RectD const boundRect() const;
void draw(gl::Screen * screen);
void offset(m2::PointD const & offs);
};
class PathTextElement : public TextElement
{
private:
GlyphLayout m_glyphLayout;
public:
struct Params : TextElement::Params
{
m2::PointD const * m_pts;
size_t m_ptsCount;
double m_fullLength;
double m_pathOffset;
};
PathTextElement(Params const & p);
m2::RectD const boundRect() const;
void draw(gl::Screen * screen);
void offset(m2::PointD const & offs);
};
}

View file

@ -1,95 +0,0 @@
#include "../base/SRC_FIRST.hpp"
#include "../base/string_utils.hpp"
#include "text_layout_element.hpp"
#include "glyph_cache.hpp"
#include "screen.hpp"
#include "resource_manager.hpp"
#include "resource_style.hpp"
#include "skin.hpp"
namespace yg
{
TextLayoutElement::TextLayoutElement(
char const * text,
double depth,
FontDesc const & fontDesc,
bool log2vis,
shared_ptr<Skin> const & skin,
shared_ptr<ResourceManager> const & rm,
m2::PointD const & pivot,
yg::EPosition pos)
: LayoutElement(0, pivot, pos),
m_text(strings::FromUtf8(text)),
m_depth(depth),
m_fontDesc(fontDesc),
m_skin(skin),
m_rm(rm),
m_log2vis(log2vis)
{
for (size_t i = 0; i < m_text.size(); ++i)
{
GlyphKey glyphKey(m_text[i], m_fontDesc.m_size, m_fontDesc.m_isMasked, m_fontDesc.m_color);
if (m_fontDesc.m_isStatic)
{
uint32_t glyphID = m_skin->mapGlyph(glyphKey, m_fontDesc.m_isStatic);
CharStyle const * p = static_cast<CharStyle const *>(m_skin->fromID(glyphID));
if (p != 0)
{
if (i == 0)
m_limitRect = m2::RectD(p->m_xOffset, p->m_yOffset, p->m_xOffset, p->m_yOffset);
else
m_limitRect.Add(m2::PointD(p->m_xOffset, p->m_yOffset));
m_limitRect.Add(m2::PointD(p->m_xOffset + p->m_texRect.SizeX() - 4,
p->m_yOffset + p->m_texRect.SizeY() - 4));
}
}
else
{
GlyphMetrics const m = m_rm->getGlyphMetrics(glyphKey);
if (i == 0)
m_limitRect = m2::RectD(m.m_xOffset, m.m_yOffset, m.m_xOffset, m.m_yOffset);
else
m_limitRect.Add(m2::PointD(m.m_xOffset, m.m_yOffset));
m_limitRect.Add(m2::PointD(m.m_xOffset + m.m_xAdvance,
m.m_yOffset + m.m_yAdvance));
}
}
/// centered by default
m_limitRect.Offset(-m_limitRect.SizeX() / 2,
-m_limitRect.SizeY() / 2);
/// adjusting according to position
if (position() & EPosLeft)
m_limitRect.Offset(-m_limitRect.SizeX() / 2, 0);
if (position() & EPosRight)
m_limitRect.Offset(m_limitRect.SizeX() / 2, 0);
if (position() & EPosAbove)
m_limitRect.Offset(0, m_limitRect.SizeY() / 2);
if (position() & EPosUnder)
m_limitRect.Offset(0, -m_limitRect.SizeY() / 2);
}
m2::RectD const TextLayoutElement::boundRect() const
{
return m_limitRect;
}
void TextLayoutElement::draw(Screen * /*screen*/)
{
/*
yg::FontDesc desc = m_fontDesc;
if (desc.m_isMasked)
{
desc.m_isMasked = false;
}
*/
}
}

View file

@ -1,42 +0,0 @@
#pragma once
#include "layout_element.hpp"
#include "skin.hpp"
#include "font_desc.hpp"
#include "../std/shared_ptr.hpp"
namespace yg
{
class Skin;
class ResourceManager;
class TextLayoutElement : public LayoutElement
{
private:
wstring m_text;
double m_depth;
FontDesc m_fontDesc;
shared_ptr<Skin> m_skin;
shared_ptr<ResourceManager> m_rm;
bool m_log2vis;
m2::RectD m_limitRect;
public:
TextLayoutElement(
char const * text,
double depth,
FontDesc const & fontDesc,
bool log2vis,
shared_ptr<Skin> const & skin,
shared_ptr<ResourceManager> const & rm,
m2::PointD const & pivot,
yg::EPosition pos);
m2::RectD const boundRect() const;
void draw(Screen * screen);
};
}

View file

@ -1,23 +0,0 @@
#pragma once
#include "text_layout_element.hpp"
#include "../std/shared_ptr.hpp"
namespace yg
{
struct FontDesc;
class TextPath;
class TextOnPathLayoutElement : public TextLayoutElement
{
public:
TextOnPathLayoutElement(shared_ptr<TextPath> const & path,
char const * text,
double depth,
FontDesc const & fontDesc);
m2::RectD const boundRect() const;
void draw(Screen * screen);
};
}

122
yg/text_path.cpp Normal file
View file

@ -0,0 +1,122 @@
#include "../base/SRC_FIRST.hpp"
#include "text_path.hpp"
#include "../geometry/angles.hpp"
namespace yg
{
PathPoint::PathPoint(int i, m2::PointD const & pt)
: m_i(i),
m_pt(pt)
{}
PivotPoint::PivotPoint(double angle, PathPoint const & pp)
: m_angle(angle), m_pp(pp)
{}
TextPath::TextPath(m2::PointD const * arr, size_t sz, double fullLength, double & pathOffset)
: m_arr(arr), m_size(sz), m_reverse(false)
{
ASSERT ( m_size > 1, () );
/* 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_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_size; ++i)
len += m_arr[i-1].Length(m_arr[i]);
pathOffset = fullLength - pathOffset - len;
ASSERT ( pathOffset >= -1.0E-6, () );
if (pathOffset < 0.0) pathOffset = 0.0;
m_reverse = true;
}
}
size_t TextPath::size() const { return m_size; }
m2::PointD TextPath::get(size_t i) const
{
ASSERT ( i < m_size, ("Index out of range") );
return m_arr[m_reverse ? m_size - i - 1 : 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;
for (size_t i = res.m_i; i < size() - 1; ++i)
{
double l = res.m_pt.Length(get(i + 1));
res.m_pt = res.m_pt.Move(min(l, offset), ang::AngleTo(get(i), get(i + 1)));
res.m_i = i;
if (offset <= l)
break;
else
offset -= l;
}
return res;
}
PivotPoint TextPath::findPivotPoint(PathPoint const & pp, GlyphMetrics const & sym, double kern)
{
PathPoint startPt = offsetPoint(pp, kern);
PivotPoint res;
res.m_pp.m_i = -1;
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);
angle += ang::AngleTo(get(j), get(j + 1));
if (l < advance)
{
advance -= l;
pt1 = get(j + 1);
++j;
}
else
{
res.m_pp.m_i = j;
res.m_pp.m_pt = pt1.Move(advance, ang::AngleTo(get(j), get(j + 1)));
advance = 0;
angle /= (res.m_pp.m_i - startPt.m_i + 1);
res.m_angle = angle;
break;
}
}
return res;
}
}

40
yg/text_path.hpp Normal file
View file

@ -0,0 +1,40 @@
#pragma once
#include "../geometry/point2d.hpp"
#include "glyph_cache.hpp"
namespace yg
{
struct PathPoint
{
int m_i;
m2::PointD m_pt;
PathPoint(int i = -1,
m2::PointD const & pt = m2::PointD());
};
struct PivotPoint
{
double m_angle;
PathPoint m_pp;
PivotPoint(double angle = 0, PathPoint const & pp = PathPoint());
};
class TextPath
{
m2::PointD const * m_arr;
size_t m_size;
bool m_reverse;
public:
TextPath(m2::PointD const * arr, size_t sz, double fullLength, double & pathOffset);
size_t size() const;
m2::PointD get(size_t i) const;
m2::PointD operator[](size_t i) const;
PathPoint const offsetPoint(PathPoint const & pp, double offset);
PivotPoint findPivotPoint(PathPoint const & pp, GlyphMetrics const & sym, double kern);
};
}

View file

@ -55,10 +55,10 @@ SOURCES += \
symbol_renderer.cpp \
circle_info.cpp \
area_renderer.cpp \
layout_element.cpp \
font_desc.cpp \
glyph_layout.cpp \
text_layout_element.cpp
text_element.cpp \
text_path.cpp
HEADERS += \
internal/opengl.hpp \
@ -106,12 +106,10 @@ HEADERS += \
symbol_renderer.hpp \
circle_info.hpp \
area_renderer.hpp \
layout_element.hpp \
font_desc.hpp \
glyph_layout.hpp \
text_on_path_layout_element.hpp \
text_layout_element.hpp \
symbol_layout_element.hpp
text_element.hpp \
text_path.hpp
win32 {
HEADERS += internal/opengl_win32.hpp

View file

@ -7,6 +7,7 @@
#include "../../yg/skin.hpp"
#include "../../yg/pen_info.hpp"
#include "../../yg/circle_info.hpp"
#include "../../yg/text_element.hpp"
#include "../../qt_tstfrm/macros.hpp"
@ -832,6 +833,81 @@ namespace
}
};
struct TestDrawStraightTextElement
{
yg::PenInfo m_penInfo;
vector<m2::PointD> m_path;
TestDrawStraightTextElement()
{
m_path.push_back(m2::PointD(100, 200));
m_path.push_back(m2::PointD(500, 200));
double pat[] = { 2, 2 };
m_penInfo = yg::PenInfo(yg::Color(0, 0, 0, 0xFF), 2, &pat[0], ARRAY_SIZE(pat), 0);
}
void DoDraw(shared_ptr<yg::gl::Screen> p)
{
yg::StraightTextElement::Params params;
params.m_fontDesc = yg::FontDesc(false, 20);
params.m_utf8Text = "Simplicity is the ultimate sophistication. Leonardo Da Vinci.";
params.m_depth = 10;
params.m_log2vis = false;
params.m_rm = p->resourceManager();
params.m_skin = p->skin();
params.m_pivot = m_path[0];
params.m_position = yg::EPosRight;
yg::StraightTextElement ste(params);
p->drawPath(&m_path[0], m_path.size(), 0, p->skin()->mapPenInfo(m_penInfo), 0);
ste.draw(p.get());
}
};
struct TestDrawPathTextElement
{
vector<m2::PointD> m_path;
yg::PenInfo m_penInfo;
TestDrawPathTextElement()
{
m_path.push_back(m2::PointD(40, 200));
m_path.push_back(m2::PointD(100, 100));
m_path.push_back(m2::PointD(160, 200));
m_path.push_back(m2::PointD(200, 100));
m_path.push_back(m2::PointD(240, 200));
m_path.push_back(m2::PointD(280, 100));
m_path.push_back(m2::PointD(320, 200));
m_path.push_back(m2::PointD(360, 100));
m_path.push_back(m2::PointD(400, 200));
double pat[] = { 2, 2 };
m_penInfo = yg::PenInfo(yg::Color(0, 0, 0, 0xFF), 2, &pat[0], ARRAY_SIZE(pat), 0);
}
void DoDraw(shared_ptr<yg::gl::Screen> p)
{
yg::PathTextElement::Params params;
params.m_pts = &m_path[0];
params.m_ptsCount = m_path.size();
params.m_fullLength = calc_length(m_path);
params.m_pathOffset = 0;
params.m_fontDesc = yg::FontDesc(false, 20);
params.m_utf8Text = "Simplicity is the ultimate sophistication. Leonardo Da Vinci.";
params.m_depth = 10;
params.m_log2vis = false;
params.m_rm = p->resourceManager();
params.m_skin = p->skin();
params.m_pivot = m_path[0];
params.m_position = yg::EPosCenter;
yg::PathTextElement pte(params);
p->drawPath(&m_path[0], m_path.size(), 0, p->skin()->mapPenInfo(m_penInfo), 0);
pte.draw(p.get());
}
};
struct TestDrawTextOnPathZigZag
{
std::vector<m2::PointD> m_path;
@ -1166,11 +1242,13 @@ namespace
// UNIT_TEST_GL(TestDrawUnicodeSymbols);
// UNIT_TEST_GL(TestDrawTextRectWithFixedFont);
// UNIT_TEST_GL(TestDrawStringOnString);
UNIT_TEST_GL(TestDrawTextOnPathInteractive);
UNIT_TEST_GL(TestDrawTextOnPathBigSymbols);
UNIT_TEST_GL(TestDrawTextOnPath);
UNIT_TEST_GL(TestDrawTextOnPathZigZag);
UNIT_TEST_GL(TestDrawTextOnPathWithOffset);
// UNIT_TEST_GL(TestDrawTextOnPathInteractive);
// UNIT_TEST_GL(TestDrawTextOnPathBigSymbols);
// UNIT_TEST_GL(TestDrawTextOnPath);
// UNIT_TEST_GL(TestDrawTextOnPathZigZag);
// UNIT_TEST_GL(TestDrawTextOnPathWithOffset);
UNIT_TEST_GL(TestDrawStraightTextElement);
UNIT_TEST_GL(TestDrawPathTextElement);
// UNIT_TEST_GL(TestDrawTextOverflow);
// UNIT_TEST_GL(TestDrawTextFiltering);
// UNIT_TEST_GL(TestDrawRandomTextFiltering);