more precise OverlayElement filtering in InfoLayer.

This commit is contained in:
rachytski 2011-09-30 17:20:20 +03:00 committed by Alex Zolotarev
parent eccc30ec2f
commit e52ea5566d
8 changed files with 116 additions and 108 deletions

View file

@ -68,7 +68,7 @@ namespace yg
m_lastVisible(visText.size()),
m_pivot(pt)
{
m2::RectD limitRect;
m2::RectD boundRect;
m2::PointD curPt(0, 0);
bool isFirst = true;
@ -81,16 +81,16 @@ namespace yg
if (isFirst)
{
limitRect = m2::RectD(m.m_xOffset,
boundRect = m2::RectD(m.m_xOffset,
-m.m_yOffset,
m.m_xOffset,
-m.m_yOffset);
isFirst = false;
}
else
limitRect.Add(m2::PointD(m.m_xOffset + curPt.x, -m.m_yOffset + curPt.y));
boundRect.Add(m2::PointD(m.m_xOffset + curPt.x, -m.m_yOffset + curPt.y));
limitRect.Add(m2::PointD(m.m_xOffset + m.m_width,
boundRect.Add(m2::PointD(m.m_xOffset + m.m_width,
-(m.m_yOffset + m.m_height)) + curPt);
GlyphLayoutElem elem;
@ -103,29 +103,30 @@ namespace yg
curPt += m2::PointD(m.m_xAdvance, m.m_yAdvance);
}
limitRect.Inflate(2, 2);
boundRect.Inflate(2, 2);
m2::PointD ptOffs(-limitRect.SizeX() / 2 - limitRect.minX(),
-limitRect.SizeY() / 2 - limitRect.minY());
m2::PointD ptOffs(-boundRect.SizeX() / 2 - boundRect.minX(),
-boundRect.SizeY() / 2 - boundRect.minY());
/// adjusting according to position
if (pos & EPosLeft)
ptOffs += m2::PointD(-limitRect.SizeX() / 2, 0);
ptOffs += m2::PointD(-boundRect.SizeX() / 2, 0);
if (pos & EPosRight)
ptOffs += m2::PointD(limitRect.SizeX() / 2, 0);
ptOffs += m2::PointD(boundRect.SizeX() / 2, 0);
if (pos & EPosAbove)
ptOffs += m2::PointD(0, -limitRect.SizeY() / 2);
ptOffs += m2::PointD(0, -boundRect.SizeY() / 2);
if (pos & EPosUnder)
ptOffs += m2::PointD(0, limitRect.SizeY() / 2);
m_limitRect = m2::AARectD(limitRect);
ptOffs += m2::PointD(0, boundRect.SizeY() / 2);
for (unsigned i = 0; i < m_entries.size(); ++i)
m_entries[i].m_pt += ptOffs;
m_limitRect.Offset(ptOffs);
boundRect.Offset(ptOffs);
m_boundRects.push_back(boundRect);
}
GlyphLayout::GlyphLayout(GlyphLayout const & src,
@ -137,9 +138,9 @@ namespace yg
m_pos(src.m_pos),
m_fontDesc(src.m_fontDesc),
m_metrics(src.m_metrics),
m_limitRect(m2::RectD(0, 0, 0, 0)),
m_pivot(0, 0)
{
m_boundRects.push_back(m2::AARectD(m2::RectD(0, 0, 0, 0)));
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);
recalcAlongPath();
@ -161,9 +162,9 @@ namespace yg
m_visText(visText),
m_pos(pos),
m_fontDesc(fontDesc),
m_limitRect(m2::RectD(0, 0, 0, 0)),
m_pivot(0, 0)
{
m_boundRects.push_back(m2::AARectD(m2::RectD(0, 0, 0, 0)));
for (size_t i = 0; i < m_visText.size(); ++i)
m_metrics.push_back(glyphCache->getGlyphMetrics(GlyphKey(visText[i], m_fontDesc.m_size, m_fontDesc.m_isMasked, yg::Color(0, 0, 0, 0))));
recalcAlongPath();
@ -317,17 +318,10 @@ namespace yg
for (unsigned i = m_firstVisible; i < m_lastVisible; ++i)
m_entries[i].m_pt -= m_pivot;
computeMinLimitRect();
// recalcPivot();
computeBoundRects();
}
void GlyphLayout::recalcPivot()
{
}
void GlyphLayout::computeMinLimitRect()
void GlyphLayout::computeBoundRects()
{
map<double, m2::AARectD> rects;
@ -337,58 +331,39 @@ namespace yg
{
map<double, m2::AARectD>::iterator it = rects.find(m_entries[i].m_angle.val());
if (it == rects.end())
{
m2::AARectD symRectAA(
m_entries[i].m_pt.Move(m_metrics[i].m_height, -m_entries[i].m_angle.cos(), m_entries[i].m_angle.sin()), //< moving by angle = m_entries[i].m_angle - math::pi / 2
m_entries[i].m_angle,
m2::RectD(m_metrics[i].m_xOffset,
m_metrics[i].m_yOffset,
m_metrics[i].m_xOffset + m_metrics[i].m_width,
m_metrics[i].m_yOffset + m_metrics[i].m_height
));
rects[m_entries[i].m_angle.val()] = symRectAA;
}
}
}
for (unsigned i = m_firstVisible; i < m_lastVisible; ++i)
{
if (m_metrics[i].m_width != 0)
{
m2::AARectD symRectAA(
m_entries[i].m_pt.Move(m_metrics[i].m_height, -m_entries[i].m_angle.cos(), m_entries[i].m_angle.sin()), //< moving by angle = m_entries[i].m_angle - math::pi / 2
m_entries[i].m_angle,
m2::RectD(m_metrics[i].m_xOffset,
m_metrics[i].m_yOffset,
m_metrics[i].m_xOffset + m_metrics[i].m_width,
m_metrics[i].m_yOffset + m_metrics[i].m_height));
m_metrics[i].m_yOffset + m_metrics[i].m_height
));
for (map<double, m2::AARectD>::iterator it = rects.begin(); it != rects.end(); ++it)
it->second.Add(symRectAA);
if (it == rects.end())
rects[m_entries[i].m_angle.val()] = symRectAA;
else
rects[m_entries[i].m_angle.val()].Add(symRectAA);
}
}
double square = numeric_limits<double>::max();
m_boundRects.clear();
for (map<double, m2::AARectD>::iterator it = rects.begin(); it != rects.end(); ++it)
for (map<double, m2::AARectD>::const_iterator it = rects.begin(); it != rects.end(); ++it)
{
m2::RectD r = it->second.GetLocalRect();
if (square > r.SizeX() * r.SizeY())
{
m_limitRect = it->second;
square = r.SizeX() * r.SizeY();
}
m2::AARectD r(it->second);
m2::PointD zero = r.zero();
zero = r.ConvertFrom(zero);
double dx = zero.x - floor(zero.x);
double dy = zero.y - floor(zero.y);
r.Offset(m2::PointD(-dx, -dy));
r.Offset(m_pivot);
m_boundRects.push_back(r);
}
m2::PointD zero = m_limitRect.zero();
zero = m_limitRect.ConvertFrom(zero);
double dx = zero.x - floor(zero.x);
double dy = zero.y - floor(zero.y);
m_limitRect.Offset(m2::PointD(-dx, -dy));
}
size_t GlyphLayout::firstVisible() const
@ -411,9 +386,9 @@ namespace yg
return m_metrics;
}
m2::AARectD const GlyphLayout::limitRect() const
vector<m2::AARectD> const & GlyphLayout::boundRects() const
{
return m2::Offset(m_limitRect, pivot());
return m_boundRects;
}
m2::PointD const & GlyphLayout::pivot() const
@ -423,6 +398,9 @@ namespace yg
void GlyphLayout::setPivot(m2::PointD const & pivot)
{
for (unsigned i = 0; i < m_boundRects.size(); ++i)
m_boundRects[i].Offset(pivot - m_pivot);
m_pivot = pivot;
}
}

View file

@ -50,12 +50,12 @@ namespace yg
vector<GlyphMetrics> m_metrics;
vector<GlyphLayoutElem> m_entries;
m2::AARectD m_limitRect;
vector<m2::AARectD> m_boundRects;
m2::PointD m_pivot;
double getKerning(GlyphLayoutElem const & prevElem, GlyphMetrics const & prevMetrics, GlyphLayoutElem const & curElem, GlyphMetrics const & curMetrics);
void computeMinLimitRect();
void computeBoundRects();
void recalcPivot();
void recalcAlongPath();
@ -88,7 +88,7 @@ namespace yg
vector<GlyphLayoutElem> const & entries() const;
vector<GlyphMetrics> const & metrics() const;
m2::AARectD const limitRect() const;
vector<m2::AARectD> const & boundRects() const;
m2::PointD const & pivot() const;

View file

@ -14,29 +14,10 @@ namespace yg
bool betterOverlayElement(shared_ptr<OverlayElement> const & l,
shared_ptr<OverlayElement> const & r)
{
/// "frozen" object shouldn't be popped out.
if (r->isFrozen())
return false;
vector<m2::AARectD> const & lr = l->boundRects();
vector<m2::AARectD> const & rr = r->boundRects();
bool isIntersect = false;
for (vector<m2::AARectD>::const_iterator lit = lr.begin(); lit != lr.end(); ++lit)
{
for (vector<m2::AARectD>::const_iterator rit = rr.begin(); rit != rr.end(); ++rit)
{
isIntersect = lit->IsIntersect(*rit);
if (isIntersect)
break;
}
if (isIntersect)
break;
}
if (!isIntersect)
return true;
/// for the composite elements, collected in OverlayRenderer to replace the part elements
return l->visualRank() >= r->visualRank();
}
@ -117,9 +98,45 @@ namespace yg
m_tree.Add(oe);
}
struct DoPreciseIntersect
{
shared_ptr<OverlayElement> m_oe;
bool * m_isIntersect;
DoPreciseIntersect(shared_ptr<OverlayElement> const & oe, bool * isIntersect)
: m_oe(oe),
m_isIntersect(isIntersect)
{}
void operator()(shared_ptr<OverlayElement> const & e)
{
if (*m_isIntersect)
return;
vector<m2::AARectD> const & lr = m_oe->boundRects();
vector<m2::AARectD> const & rr = e->boundRects();
for (vector<m2::AARectD>::const_iterator lit = lr.begin(); lit != lr.end(); ++lit)
{
for (vector<m2::AARectD>::const_iterator rit = rr.begin(); rit != rr.end(); ++rit)
{
*m_isIntersect = lit->IsIntersect(*rit);
if (*m_isIntersect)
return;
}
}
}
};
void InfoLayer::replaceOverlayElement(shared_ptr<OverlayElement> const & oe)
{
m_tree.ReplaceIf(oe, &betterOverlayElement);
bool isIntersect = false;
DoPreciseIntersect fn(oe, &isIntersect);
m_tree.ForEachInRect(oe->roughBoundRect(), fn);
if (isIntersect)
m_tree.ReplaceIf(oe, &betterOverlayElement);
else
m_tree.Add(oe);
}
void InfoLayer::processOverlayElement(shared_ptr<OverlayElement> const & oe, math::Matrix<double, 3, 3> const & m)
@ -132,10 +149,11 @@ namespace yg
void InfoLayer::processOverlayElement(shared_ptr<OverlayElement> const & oe)
{
if (m_couldOverlap)
addOverlayElement(oe);
else
replaceOverlayElement(oe);
if (oe->isVisible())
if (m_couldOverlap)
addOverlayElement(oe);
else
replaceOverlayElement(oe);
}
void InfoLayer::merge(InfoLayer const & layer, math::Matrix<double, 3, 3> const & m)

View file

@ -16,6 +16,7 @@ namespace yg
m_depth(p.m_depth),
m_isNeedRedraw(true),
m_isFrozen(false),
m_isVisible(true),
m_isDirtyRect(true),
m_isDirtyRoughRect(true)
{}
@ -102,6 +103,16 @@ namespace yg
m_isNeedRedraw = flag;
}
bool OverlayElement::isVisible() const
{
return m_isVisible;
}
void OverlayElement::setIsVisible(bool flag)
{
m_isVisible = flag;
}
bool OverlayElement::isDirtyRect() const
{
return m_isDirtyRect;

View file

@ -25,6 +25,7 @@ namespace yg
bool m_isNeedRedraw;
bool m_isFrozen;
bool m_isVisible;
mutable bool m_isDirtyRect;
mutable bool m_isDirtyRoughRect;
@ -79,6 +80,9 @@ namespace yg
bool isDirtyRect() const;
void setIsDirtyRect(bool flag) const;
bool isVisible() const;
void setIsVisible(bool flag);
m2::RectD const & roughBoundRect() const;
virtual void offset(m2::PointD const & offs);

View file

@ -16,6 +16,7 @@ namespace yg
p.m_position)
{
setPivot(m_glyphLayout.pivot());
setIsVisible((m_glyphLayout.firstVisible() == 0) && (m_glyphLayout.lastVisible() == visText().size()));
}
PathTextElement::PathTextElement(PathTextElement const & src, math::Matrix<double, 3, 3> const & m)
@ -23,21 +24,17 @@ namespace yg
m_glyphLayout(src.m_glyphLayout, m)
{
setPivot(m_glyphLayout.pivot());
}
m2::AARectD const PathTextElement::boundRect() const
{
// return m2::Inflate(m_glyphLayout.limitRect(), m2::PointD(2, 2));
return m2::Inflate(m_glyphLayout.limitRect(), m2::PointD(10, 2));
// return m2::Inflate(m_glyphLayout.limitRect(), m2::PointD(40, 2)); //< to create more sparse street names structure
setIsVisible((m_glyphLayout.firstVisible() == 0) && (m_glyphLayout.lastVisible() == visText().size()));
}
vector<m2::AARectD> const & PathTextElement::boundRects() const
{
if (isDirtyRect())
{
m_boundRects.clear();
m_boundRects.push_back(boundRect());
m_boundRects = m_glyphLayout.boundRects();
for (unsigned i = 0; i < m_boundRects.size(); ++i)
m_boundRects[i] = m2::Inflate(m_boundRects[i], m2::PointD(10, 2));
// m_boundRects[i].m2::Inflate(m2::PointD(40, 2)); //< to create more sparse street names structure
setIsDirtyRect(false);
}

View file

@ -10,8 +10,6 @@ namespace yg
GlyphLayout m_glyphLayout;
m2::AARectD const boundRect() const;
public:
struct Params : TextElement::Params

View file

@ -102,7 +102,7 @@ namespace yg
for (unsigned i = 0; i < res.size(); ++i)
{
m_glyphLayouts.push_back(GlyphLayout(p.m_glyphCache, p.m_fontDesc, m2::PointD(0, 0), res[i], yg::EPosCenter));
m2::RectD r = m_glyphLayouts.back().limitRect().GetGlobalRect();
m2::RectD r = m_glyphLayouts.back().boundRects().back().GetGlobalRect();
allElemWidth = max(r.SizeX(), allElemWidth);
allElemHeight += r.SizeY();
}
@ -113,7 +113,7 @@ namespace yg
for (unsigned i = 0; i < res.size(); ++i)
{
double elemSize = m_glyphLayouts[i].limitRect().GetGlobalRect().SizeY();
double elemSize = m_glyphLayouts[i].boundRects().back().GetGlobalRect().SizeY();
m_glyphLayouts[i].setPivot(m_glyphLayouts[i].pivot() + m2::PointD(0, -curShift + elemSize / 2));
curShift -= elemSize;
}
@ -169,7 +169,9 @@ namespace yg
m_boundRects.clear();
for (size_t i = 0; i < m_glyphLayouts.size(); ++i)
m_boundRects.push_back(m_glyphLayouts[i].limitRect());
copy(m_glyphLayouts[i].boundRects().begin(),
m_glyphLayouts[i].boundRects().end(),
back_inserter(m_boundRects));
setIsDirtyRect(false);
}