forked from organicmaps/organicmaps
more precise OverlayElement filtering in InfoLayer.
This commit is contained in:
parent
eccc30ec2f
commit
e52ea5566d
8 changed files with 116 additions and 108 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@ namespace yg
|
|||
|
||||
GlyphLayout m_glyphLayout;
|
||||
|
||||
m2::AARectD const boundRect() const;
|
||||
|
||||
public:
|
||||
|
||||
struct Params : TextElement::Params
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue