From 97a982f9843009f20b3ed7432707f65403b0dd09 Mon Sep 17 00:00:00 2001 From: rachytski Date: Wed, 14 Sep 2011 18:57:03 +0300 Subject: [PATCH] added separate Ruler class. --- map/framework.cpp | 7 +- map/framework.hpp | 1 + map/information_display.cpp | 133 ++++++----------------- map/information_display.hpp | 7 +- map/map.pro | 8 +- map/ruler.cpp | 208 ++++++++++++++++++++++++++++++++++++ map/ruler.hpp | 67 ++++++++++++ yg/overlay_element.cpp | 4 + yg/overlay_element.hpp | 1 + 9 files changed, 326 insertions(+), 110 deletions(-) create mode 100644 map/ruler.cpp create mode 100644 map/ruler.hpp diff --git a/map/framework.cpp b/map/framework.cpp index 938ee5d1e0..b96f6501fb 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -83,7 +83,12 @@ Framework::Framework(shared_ptr windowHandle, size_t bottomShift) : m_windowHandle(windowHandle), m_metresMinWidth(20), + m_metresMaxWidth(1000000), +#if defined(OMIM_OS_MAC) || defined(OMIM_OS_WINDOWS) || defined(OMIM_OS_LINUX) m_minRulerWidth(97), +#else + m_minRulerWidth(48), +#endif m_centeringMode(EDoNothing), m_tileSize(GetPlatform().TileSize()) { @@ -105,7 +110,7 @@ Framework::Framework(shared_ptr windowHandle, m_informationDisplay.enableCenter(true); m_informationDisplay.enableRuler(true); - m_informationDisplay.setRulerParams(m_minRulerWidth, m_metresMinWidth); + m_informationDisplay.setRulerParams(m_minRulerWidth, m_metresMinWidth, m_metresMaxWidth); m_navigator.SetMinScreenParams(m_minRulerWidth, m_metresMinWidth); #ifdef DEBUG diff --git a/map/framework.hpp b/map/framework.hpp index 0b2f8c0ffb..0331dd9327 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -107,6 +107,7 @@ protected: InformationDisplay m_informationDisplay; double const m_metresMinWidth; + double const m_metresMaxWidth; int const m_minRulerWidth; enum TGpsCenteringMode diff --git a/map/information_display.cpp b/map/information_display.cpp index bac78154ab..7338699b69 100644 --- a/map/information_display.cpp +++ b/map/information_display.cpp @@ -20,6 +20,7 @@ #include "../std/iomanip.hpp" InformationDisplay::InformationDisplay() + : m_ruler(Ruler::Params()) { enableDebugPoints(false); enableRuler(false); @@ -40,6 +41,7 @@ InformationDisplay::InformationDisplay() void InformationDisplay::setScreen(ScreenBase const & screen) { m_screen = screen; + m_ruler.setScreen(screen); } void InformationDisplay::setBottomShift(double bottomShift) @@ -77,116 +79,33 @@ void InformationDisplay::enableRuler(bool doEnable) m_isRulerEnabled = doEnable; } -void InformationDisplay::setRulerParams(unsigned pxMinWidth, double metresMinWidth) +void InformationDisplay::setRulerParams(unsigned pxMinWidth, double metresMinWidth, double metresMaxWidth) { - m_pxMinWidth = pxMinWidth; - m_metresMinWidth = metresMinWidth; + m_ruler.setMinPxWidth(pxMinWidth); + m_ruler.setMinUnitsWidth(metresMinWidth); + m_ruler.setMaxUnitsWidth(metresMaxWidth); } void InformationDisplay::drawRuler(DrawerYG * pDrawer) { - /// Compute Scaler - /// scaler should be between minPixSize and maxPixSize - int minPixSize = m_pxMinWidth; + m_ruler.setFontDesc(m_fontDesc); + m_ruler.setVisualScale(m_visualScale); - m2::PointD const scalerOrg = - m2::PointD(m_displayRect.minX(), m_displayRect.maxY() - m_bottomShift * m_visualScale) - + m2::PointD(10 * m_visualScale, -10 * m_visualScale); +#ifdef OMIM_OS_IPHONE + m2::PointD pivot(m2::PointD(m_displayRect.maxX(), m_displayRect.maxY() - m_bottomShift * m_visualScale) + + m2::PointD(-10 * m_visualScale, -10 * m_visualScale)); + m_ruler.setPosition(yg::EPosAboveLeft); +#else + m2::PointD pivot(m2::PointD(m_displayRect.minX(), m_displayRect.maxY() - m_bottomShift * m_visualScale) + + m2::PointD(10 * m_visualScale, -10 * m_visualScale)); - m2::PointD pt0 = m_screen.PtoG(scalerOrg); - m2::PointD pt1 = m_screen.PtoG(m_screen.GtoP(pt0) + m2::PointD(minPixSize, 0)); + m_ruler.setPosition(yg::EPosAboveRight); +#endif + m_ruler.setPivot(pivot); + m_ruler.update(); - double const lonDiffCorrection = cos(MercatorBounds::YToLat(pt0.y) / 180.0 * math::pi); - - double lonDiff = fabs(MercatorBounds::XToLon(pt1.x) - MercatorBounds::XToLon(pt0.x)); - double metresDiff = lonDiff / MercatorBounds::degreeInMetres * lonDiffCorrection; - - - /// finding the closest higher metric value - unsigned curFirstDigit = 2; - unsigned curVal = static_cast(m_metresMinWidth); - unsigned maxVal = 1000000; - bool lessThanMin = false; - bool isInfinity = false; - - if (metresDiff > maxVal) - { - isInfinity = true; - curVal = maxVal; - } - else - if (metresDiff < curVal) - lessThanMin = true; - else - while (true) - { - unsigned nextVal = curFirstDigit == 2 ? (curVal * 5 / 2) : curVal * 2; - unsigned nextFirstDigit = curFirstDigit == 2 ? (curFirstDigit * 5 / 2) : curFirstDigit * 2; - - if (nextFirstDigit >= 10) - nextFirstDigit /= 10; - - if ((curVal <= metresDiff) && (nextVal > metresDiff)) - { - curVal = nextVal; - curFirstDigit = nextFirstDigit; - break; - } - - curVal = nextVal; - curFirstDigit = nextFirstDigit; - } - - /// translating meters to pixels - double scalerWidthLatDiff = (double)curVal * MercatorBounds::degreeInMetres / lonDiffCorrection; - double scalerWidthXDiff = MercatorBounds::LonToX(pt0.x + scalerWidthLatDiff) - MercatorBounds::LonToX(pt0.x); - - double scalerWidthInPx = m_screen.GtoP(pt0).x - m_screen.GtoP(pt0 + m2::PointD(scalerWidthXDiff, 0)).x; - scalerWidthInPx = (lessThanMin || isInfinity) ? minPixSize : abs(my::rounds(scalerWidthInPx)); - - string scalerText; - - if (isInfinity) - scalerText = ">"; - else - if (lessThanMin) - scalerText = "<"; - - if (curVal >= 1000) - scalerText += strings::to_string(curVal / 1000) + " km"; - else - scalerText += strings::to_string(curVal) + " m"; - - m2::PointD scalerPts[4]; - scalerPts[0] = scalerOrg + m2::PointD(0, -14 * m_visualScale); - scalerPts[1] = scalerOrg; - scalerPts[2] = scalerOrg + m2::PointD(scalerWidthInPx, 0); - scalerPts[3] = scalerPts[2] + m2::PointD(0, -14 * m_visualScale); - - pDrawer->screen()->drawPath( - scalerPts, 4, 0, - pDrawer->screen()->skin()->mapPenInfo(yg::PenInfo(yg::Color(0, 0, 0, 255), 2, 0, 0, 0)), - yg::maxDepth); - -// m2::RectD textRect = pDrawer->screen()->textRect(fontDesc, scalerText.c_str(), false); - pDrawer->screen()->drawText(m_fontDesc, - scalerPts[1] + m2::PointD(7, -7), - yg::EPosAboveRight, - scalerText.c_str(), - yg::maxDepth, - false); - -/* m2::PointD minPixPath[4]; - minPixPath[0] = scalerOrg + m2::PointD(0, -14); - minPixPath[1] = scalerOrg; - minPixPath[2] = scalerOrg + m2::PointD(minPixSize, 0); - minPixPath[3] = minPixPath[2] + m2::PointD(0, -14); - - pDrawer->screen()->drawPath( - minPixPath, 4, 0, - pDrawer->screen()->skin()->mapPenInfo(yg::PenInfo(yg::Color(255, 0, 0, 255), 4, 0, 0, 0)), - yg::maxDepth); - */ + m_ruler.draw(pDrawer->screen().get(), math::Identity()); +// pDrawer->screen()->drawRectangle(m2::Inflate(m2::RectD(pivot, pivot), 2.0, 2.0), yg::Color(0, 0, 0, 255), yg::maxDepth); } void InformationDisplay::setVisualScale(double visualScale) @@ -215,11 +134,19 @@ void InformationDisplay::drawCenter(DrawerYG * drawer) << fixed << setprecision(4) << setw(8) << m_centerPtLonLat.x << ")"; yg::StraightTextElement::Params params; + params.m_depth = yg::maxDepth; params.m_fontDesc = m_fontDesc; params.m_log2vis = false; + +#ifdef OMIM_OS_IPHONE params.m_pivot = m2::PointD(m_displayRect.maxX() - 10 * m_visualScale, - m_displayRect.maxY() - (m_bottomShift + 10) * m_visualScale - 5); + m_displayRect.maxY() - 20 * m_visualScale - 5); +#else + params.m_pivot = m2::PointD(m_displayRect.maxX() - 10 * m_visualScale, + m_displayRect.maxY() - (/*m_bottomShift*/ + 14) * m_visualScale - 5); +#endif + params.m_position = yg::EPosAboveLeft; params.m_glyphCache = drawer->screen()->glyphCache(); params.m_logText = strings::MakeUniString(out.str()); diff --git a/map/information_display.hpp b/map/information_display.hpp index a44c8a3b1a..86e59b0a9d 100644 --- a/map/information_display.hpp +++ b/map/information_display.hpp @@ -1,6 +1,7 @@ #pragma once #include "window_handle.hpp" +#include "ruler.hpp" #include "../geometry/point2d.hpp" #include "../geometry/rect2d.hpp" #include "../geometry/screenbase.hpp" @@ -33,9 +34,7 @@ private: m2::PointD m_DebugPts[10]; bool m_isRulerEnabled; - m2::PointD m_basePoint; - unsigned m_pxMinWidth; - double m_metresMinWidth; + Ruler m_ruler; bool m_isCenterEnabled; m2::PointD m_centerPtLonLat; @@ -87,7 +86,7 @@ public: void enableRuler(bool doEnable); void drawRuler(DrawerYG * pDrawer); - void setRulerParams(unsigned pxMinWidth, double metresMinWidth); + void setRulerParams(unsigned pxMinWidth, double metresMinWidth, double metresMaxWidth); void enableCenter(bool doEnable); void setCenter(m2::PointD const & latLongPt); diff --git a/map/map.pro b/map/map.pro index 1f9ce3921e..a2db0f06d3 100644 --- a/map/map.pro +++ b/map/map.pro @@ -38,7 +38,8 @@ HEADERS += \ render_policy_mt.hpp \ render_queue.hpp \ render_queue_routine.hpp \ - benchmark_render_policy_mt.hpp + benchmark_render_policy_mt.hpp \ + ruler.hpp \ SOURCES += \ feature_vec_model.cpp \ @@ -66,7 +67,8 @@ SOURCES += \ render_policy_mt.cpp \ render_queue_routine.cpp \ render_queue.cpp \ - benchmark_render_policy_mt.cpp + benchmark_render_policy_mt.cpp \ + ruler.cpp \ !iphone*:!bada*:!android* { HEADERS += qgl_render_context.hpp @@ -75,3 +77,5 @@ SOURCES += \ } + + diff --git a/map/ruler.cpp b/map/ruler.cpp new file mode 100644 index 0000000000..3df442d49b --- /dev/null +++ b/map/ruler.cpp @@ -0,0 +1,208 @@ +#include "../base/SRC_FIRST.hpp" + +#include "ruler.hpp" + +#include "../yg/overlay_renderer.hpp" +#include "../yg/skin.hpp" + +#include "../indexer/mercator.hpp" +#include "../base/logging.hpp" +#include "../base/string_utils.hpp" + +Ruler::Ruler(Params const & p) + : base_t(p) +{} + +void Ruler::setScreen(ScreenBase const & screen) +{ + m_screen = screen; +} + +ScreenBase const & Ruler::screen() const +{ + return m_screen; +} + +void Ruler::setMinPxWidth(unsigned minPxWidth) +{ + m_minPxWidth = minPxWidth; +} + +void Ruler::setMinUnitsWidth(double minUnitsWidth) +{ + m_minUnitsWidth = minUnitsWidth; +} + +void Ruler::setMaxUnitsWidth(double maxUnitsWidth) +{ + m_maxUnitsWidth = maxUnitsWidth; +} + +void Ruler::setVisualScale(double visualScale) +{ + m_visualScale = visualScale; +} + +void Ruler::setFontDesc(yg::FontDesc const & fontDesc) +{ + m_fontDesc = fontDesc; +} + +unsigned Ruler::ceil(double unitsDiff) +{ + /// finding the closest higher metric value + unsigned curVal = (unsigned)m_minUnitsWidth; + + unsigned curFirstDigit = m_minUnitsWidth; + while (curFirstDigit > 10) + curFirstDigit /= 10; + + if (unitsDiff > m_maxUnitsWidth) + curVal = m_maxUnitsWidth + 1; + else + if (unitsDiff < m_minUnitsWidth) + curVal = m_minUnitsWidth - 1; + else + while (true) + { + unsigned nextVal = curFirstDigit == 2 ? (curVal * 5 / 2) : curVal * 2; + unsigned nextFirstDigit = curFirstDigit == 2 ? (curFirstDigit * 5 / 2) : curFirstDigit * 2; + + if (nextFirstDigit >= 10) + nextFirstDigit /= 10; + + if ((curVal <= unitsDiff) && (nextVal > unitsDiff)) + { + curVal = nextVal; + curFirstDigit = nextFirstDigit; + break; + } + + curVal = nextVal; + curFirstDigit = nextFirstDigit; + } + + return curVal; +} + +void Ruler::update() +{ + m2::PointD glbPivot = m_screen.PtoG(pivot()); + + int rulerHeight = 14 * m_visualScale; + unsigned minPxWidth = m_minPxWidth * m_visualScale; + + m2::PointD pt0 = m_screen.PtoG(pivot() - m2::PointD(minPxWidth / 2, 0)); + m2::PointD pt1 = m_screen.PtoG(pivot() + m2::PointD(minPxWidth / 2, 0)); + + /// correction factor, calculated from Y-coordinate. + double const lonDiffCorrection = cos(MercatorBounds::YToLat(glbPivot.y) / 180.0 * math::pi); + + /// longitude difference between two points + double lonDiff = fabs(MercatorBounds::XToLon(pt0.x) - MercatorBounds::XToLon(pt1.x)); + + /// converting into metres + /// TODO : calculate in different units + + m_unitsDiff = lonDiff / MercatorBounds::degreeInMetres * lonDiffCorrection; + m_unitsDiff = ceil(m_unitsDiff); + + /// updating scaler text + + bool higherThanMax = m_unitsDiff > m_maxUnitsWidth; + bool lessThanMin = m_unitsDiff < m_minUnitsWidth; + + m_scalerText = ""; + if (higherThanMax) + { + m_scalerText = ">"; + m_unitsDiff = m_maxUnitsWidth; + } + else + if (lessThanMin) + { + m_scalerText = "<"; + m_unitsDiff = m_minUnitsWidth; + } + + if (m_unitsDiff >= 1000) + m_scalerText += strings::to_string(m_unitsDiff / 1000) + " km"; + else + m_scalerText += strings::to_string(m_unitsDiff) + " m"; + + /// translating units into pixels + double scalerWidthLatDiff = (double)m_unitsDiff * MercatorBounds::degreeInMetres / lonDiffCorrection; + double scalerWidthXDiff = MercatorBounds::LonToX(glbPivot.x + scalerWidthLatDiff / 2) + - MercatorBounds::LonToX(glbPivot.x - scalerWidthLatDiff / 2); + + double scalerWidthInPx = m_screen.GtoP(glbPivot).x - m_screen.GtoP(glbPivot + m2::PointD(scalerWidthXDiff, 0)).x; + scalerWidthInPx = (higherThanMax || lessThanMin) ? minPxWidth : abs(my::rounds(scalerWidthInPx)); + + m2::PointD scalerOrg = pivot() + m2::PointD(-scalerWidthInPx / 2, rulerHeight / 2); + + if (position() & yg::EPosLeft) + scalerOrg.x -= scalerWidthInPx / 2; + + if (position() & yg::EPosRight) + scalerOrg.x += scalerWidthInPx / 2; + + if (position() & yg::EPosAbove) + scalerOrg.y -= rulerHeight / 2; + + if (position() & yg::EPosUnder) + scalerOrg.y += rulerHeight / 2; + + m_path.clear(); + m_path.push_back(scalerOrg + m2::PointD(0, -rulerHeight)); + m_path.push_back(scalerOrg); + m_path.push_back(scalerOrg + m2::PointD(scalerWidthInPx, 0)); + m_path.push_back(m_path[2] + m2::PointD(0, -rulerHeight)); + + /// calculating bound rect + + m_boundRect = m2::RectD(m_path[0], m_path[0]); + m_boundRect.Add(m_path[1]); + m_boundRect.Add(m_path[2]); + m_boundRect.Add(m_path[3]); +} + +m2::AARectD const Ruler::boundRect() const +{ + return m2::AARectD(m_boundRect); +} + +void Ruler::draw(yg::gl::OverlayRenderer * s, math::Matrix const & m) const +{ + s->drawPath( + &m_path[0], m_path.size(), 0, + s->skin()->mapPenInfo(yg::PenInfo(yg::Color(0, 0, 0, 255), 2, 0, 0, 0)), + depth()); + + if (position() & yg::EPosLeft) + s->drawText(m_fontDesc, + m_path[2] + m2::PointD(-7, -7), + yg::EPosAboveLeft, + m_scalerText.c_str(), + depth(), + false); + else + if (position() & yg::EPosRight) + s->drawText(m_fontDesc, + m_path[1] + m2::PointD(7, -7), + yg::EPosAboveRight, + m_scalerText.c_str(), + depth(), + false); + else + s->drawText(m_fontDesc, + (m_path[1] + m_path[2]) * 0.5 + m2::PointD(0, -7), + yg::EPosAbove, + m_scalerText.c_str(), + depth(), + false); + +} + +void Ruler::cache(yg::StylesCache * stylesCache) +{ +} diff --git a/map/ruler.hpp b/map/ruler.hpp new file mode 100644 index 0000000000..ee57ac38c8 --- /dev/null +++ b/map/ruler.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include "../geometry/screenbase.hpp" +#include "../geometry/point2d.hpp" +#include "../geometry/aa_rect2d.hpp" +#include "../yg/overlay_element.hpp" +#include "../yg/font_desc.hpp" + +namespace yg +{ + class StylesCache; + + namespace gl + { + class Screen; + class OverlayRenderer; + } +} + +class Ruler : public yg::OverlayElement +{ +private: + + unsigned m_minPxWidth; + unsigned m_maxPxWidth; + + double m_minUnitsWidth; + double m_maxUnitsWidth; + double m_visualScale; + + yg::FontDesc m_fontDesc; + ScreenBase m_screen; + + float m_unitsDiff; //< current diff in units between two endpoints of the ruler. + string m_scalerText; + vector m_path; + + m2::RectD m_boundRect; + + unsigned ceil(double unitsDiff); + + typedef OverlayElement base_t; + +public: + + void update(); //< update internal params after some other params changed. + + struct Params : public base_t::Params + { + }; + + Ruler(Params const & p); + + void setScreen(ScreenBase const & screen); + ScreenBase const & screen() const; + + void setMinPxWidth(unsigned minPxWidth); + void setMinUnitsWidth(double minUnitsWidth); + void setMaxUnitsWidth(double maxUnitsWidth); + void setVisualScale(double visualScale); + void setFontDesc(yg::FontDesc const & fontDesc); + + m2::AARectD const boundRect() const; + void draw(yg::gl::OverlayRenderer * r, math::Matrix const & m) const; + + void cache(yg::StylesCache * stylesCache); +}; diff --git a/yg/overlay_element.cpp b/yg/overlay_element.cpp index bd1a5cc746..d5b3b0e224 100644 --- a/yg/overlay_element.cpp +++ b/yg/overlay_element.cpp @@ -3,6 +3,10 @@ namespace yg { + OverlayElement::Params::Params() + : m_pivot(), m_position(yg::EPosAboveRight), m_depth(yg::maxDepth) + {} + OverlayElement::OverlayElement(Params const & p) : m_pivot(p.m_pivot), m_position(p.m_position), diff --git a/yg/overlay_element.hpp b/yg/overlay_element.hpp index 3fe7b2fd60..0bb4a41d30 100644 --- a/yg/overlay_element.hpp +++ b/yg/overlay_element.hpp @@ -34,6 +34,7 @@ namespace yg m2::PointD m_pivot; yg::EPosition m_position; double m_depth; + Params(); }; OverlayElement(Params const & p);