diff --git a/drape/overlay_handle.cpp b/drape/overlay_handle.cpp index 69d10c9f5f..5dbf714287 100644 --- a/drape/overlay_handle.cpp +++ b/drape/overlay_handle.cpp @@ -37,6 +37,8 @@ bool OverlayHandle::IsVisible() const void OverlayHandle::SetIsVisible(bool isVisible) { m_isVisible = isVisible; + if (m_isVisible && IsMinVisibilityTimeUp()) + m_visibilityTimestamp = steady_clock::now(); } m2::PointD OverlayHandle::GetPivot(ScreenBase const & screen) const @@ -136,6 +138,13 @@ void OverlayHandle::GetExtendedPixelShape(ScreenBase const & screen, Rects & rec rect.Inflate(m_extendingSize, m_extendingSize); } +bool OverlayHandle::IsMinVisibilityTimeUp() const +{ + uint32_t const kMinVisibilityTimeMs = 500; + uint32_t const t = duration_cast(steady_clock::now() - m_visibilityTimestamp).count(); + return t > kMinVisibilityTimeMs; +} + SquareHandle::SquareHandle(FeatureID const & id, dp::Anchor anchor, m2::PointD const & gbPivot, m2::PointD const & pxSize, uint64_t priority) diff --git a/drape/overlay_handle.hpp b/drape/overlay_handle.hpp index d6aed64b57..ad17da2a7e 100644 --- a/drape/overlay_handle.hpp +++ b/drape/overlay_handle.hpp @@ -14,6 +14,8 @@ #include "base/buffer_vector.hpp" +#include "std/chrono.hpp" + namespace dp { @@ -76,6 +78,8 @@ public: int GetOverlayRank() const { return m_overlayRank; } void SetOverlayRank(int overlayRank) { m_overlayRank = overlayRank; } + bool IsMinVisibilityTimeUp() const; + protected: FeatureID const m_id; dp::Anchor const m_anchor; @@ -84,6 +88,8 @@ protected: int m_overlayRank; double m_extendingSize; + steady_clock::time_point m_visibilityTimestamp; + typedef pair TOffsetNode; TOffsetNode const & GetOffsetNode(uint8_t bufferID) const; diff --git a/drape/overlay_tree.cpp b/drape/overlay_tree.cpp index c3ecc9174a..94b497a2cf 100644 --- a/drape/overlay_tree.cpp +++ b/drape/overlay_tree.cpp @@ -126,26 +126,30 @@ void OverlayTree::InsertHandle(ref_ptr handle, bool isTransparent elements.push_back(info); }); - bool const boundToParent = (parentOverlay.m_handle != nullptr && handle->IsBound()); - - // If handle is bound to its parent, parent's handle will be used. - ref_ptr handleToCompare = handle; - if (boundToParent) - handleToCompare = parentOverlay.m_handle; - - // In this loop we decide which element must be visible. - // If input element "handle" more priority than all "Intersected elements" - // than we remove all "Intersected elements" and insert input element "handle". - // But if some of already inserted elements more priority than we don't insert "handle". - HandleComparator comparator; - for (auto const & info : elements) + if (handle->IsMinVisibilityTimeUp()) { - if (comparator.IsGreater(info.m_handle, handleToCompare)) + bool const boundToParent = (parentOverlay.m_handle != nullptr && handle->IsBound()); + + // If handle is bound to its parent, parent's handle will be used. + ref_ptr handleToCompare = handle; + if (boundToParent) + handleToCompare = parentOverlay.m_handle; + + // In this loop we decide which element must be visible. + // If input element "handle" more priority than all "Intersected elements" + // than we remove all "Intersected elements" and insert input element "handle". + // But if some of already inserted elements more priority than we don't insert "handle". + HandleComparator comparator; + for (auto const & info : elements) { - // Handle is displaced and bound to its parent, parent will be displaced too. - if (boundToParent) - Erase(parentOverlay); - return; + bool const timeReject = !info.m_handle->IsMinVisibilityTimeUp(); + if (timeReject || comparator.IsGreater(info.m_handle, handleToCompare)) + { + // Handle is displaced and bound to its parent, parent will be displaced too. + if (boundToParent) + Erase(parentOverlay); + return; + } } } diff --git a/drape_frontend/path_text_shape.cpp b/drape_frontend/path_text_shape.cpp index 815d5eebed..c4b78ab1ec 100644 --- a/drape_frontend/path_text_shape.cpp +++ b/drape_frontend/path_text_shape.cpp @@ -111,7 +111,15 @@ PathTextShape::PathTextShape(m2::SharedSpline const & spline, uint64_t PathTextShape::GetOverlayPriority() const { - return dp::CalculateOverlayPriority(m_params.m_minVisibleScale, m_params.m_rank, m_params.m_depth); + // Overlay priority for path text shapes considers length of the text. + // Greater test length has more priority, because smaller texts have more chances to be shown along the road. + // [6 bytes - standard overlay priority][1 byte - reserved][1 byte - length]. + static uint64_t constexpr kMask = ~static_cast(0xFF); + uint64_t priority = dp::CalculateOverlayPriority(m_params.m_minVisibleScale, m_params.m_rank, m_params.m_depth); + priority &= kMask; + priority |= (static_cast(m_params.m_text.size())); + + return priority; } void PathTextShape::DrawPathTextPlain(ref_ptr textures, @@ -205,56 +213,34 @@ void PathTextShape::Draw(ref_ptr batcher, ref_ptrGetPixelLength(); - float const textHalfLength = textLength / 2.0f; + float const kTextBorder = 4.0f; + float const textLength = kTextBorder + layout->GetPixelLength(); float const pathGlbLength = m_spline->GetLength(); // on next readable scale m_scaleGtoP will be twice - if (textLength > pathGlbLength * 2 * m_params.m_baseGtoPScale) + if (textLength > pathGlbLength * 2.0 * m_params.m_baseGtoPScale) return; - float const pathLength = m_params.m_baseGtoPScale * m_spline->GetLength(); + float const kPathLengthScalar = 0.75; + float const pathLength = kPathLengthScalar * m_params.m_baseGtoPScale * pathGlbLength; - /// copied from old code - /// @todo Choose best constant for minimal space. - float const etalonEmpty = max(200 * df::VisualParams::Instance().GetVisualScale(), (double)textLength); + float const etalonEmpty = max(300 * df::VisualParams::Instance().GetVisualScale(), (double)textLength); float const minPeriodSize = etalonEmpty + textLength; float const twoTextAndEmpty = minPeriodSize + textLength; buffer_vector offsets; - - float const scalePtoG = 1.0f / m_params.m_baseGtoPScale; - if (pathLength < twoTextAndEmpty) { // if we can't place 2 text and empty part on path // we place only one text on center of path offsets.push_back(pathGlbLength / 2.0f); - - } - else if (pathLength < twoTextAndEmpty + minPeriodSize) - { - // if we can't place 3 text and 2 empty path - // we place 2 text with empty space beetwen - // and some offset from path end - float const endOffset = (pathLength - (2 * textLength + etalonEmpty)) / 2; - - // division on m_scaleGtoP give as global coord frame (Mercator) - offsets.push_back((endOffset + textHalfLength) * scalePtoG); - offsets.push_back((pathLength - (textHalfLength + endOffset)) * scalePtoG); } else { - // here we place 2 text on the ends of path - // then we place as much as possible text on center path uniformly - offsets.push_back(textHalfLength * scalePtoG); - offsets.push_back((pathLength - textHalfLength) * scalePtoG); - float const emptySpace = pathLength - 2 * textLength; - uint32_t textCount = static_cast(ceil(emptySpace / minPeriodSize)); - float const offset = (emptySpace - textCount * textLength) / (textCount + 1); - for (size_t i = 0; i < textCount; ++i) - offsets.push_back((textHalfLength + (textLength + offset) * (i + 1)) * scalePtoG); + double const textCount = max(floor(pathLength / minPeriodSize), 1.0); + double const glbTextLen = pathGlbLength / textCount; + for (double offset = 0.5 * glbTextLen; offset < pathGlbLength; offset += glbTextLen) + offsets.push_back(offset); } if (m_params.m_textFont.m_outlineColor == dp::Color::Transparent())