From 6173f9337a67504d9a29b7d46983655011267f85 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 14 Apr 2020 15:24:05 +0200 Subject: [PATCH] [locale] Refactor long+lat -> x,y mapping - Move this code to a static method since it only depends on the expected image size (which here, is managed by the image list). --- src/modules/locale/Tests.cpp | 3 +- .../locale/timezonewidget/TimeZoneImage.cpp | 95 ++++++++++++++++--- .../locale/timezonewidget/TimeZoneImage.h | 14 ++- .../locale/timezonewidget/timezonewidget.cpp | 80 +--------------- .../locale/timezonewidget/timezonewidget.h | 6 +- 5 files changed, 103 insertions(+), 95 deletions(-) diff --git a/src/modules/locale/Tests.cpp b/src/modules/locale/Tests.cpp index 902297678..3c08ccef5 100644 --- a/src/modules/locale/Tests.cpp +++ b/src/modules/locale/Tests.cpp @@ -90,8 +90,7 @@ LocaleTests::testTZImages() // // auto images = TimeZoneImageList::fromDirectory( SOURCE_DIR ); - QCOMPARE( images.count(), images.zoneCount() ); - QCOMPARE( images.count(), 38 ); // counted by hand + QCOMPARE( images.count(), images.zoneCount ); // All image sizes consistent // diff --git a/src/modules/locale/timezonewidget/TimeZoneImage.cpp b/src/modules/locale/timezonewidget/TimeZoneImage.cpp index 314f35768..b49c9b201 100644 --- a/src/modules/locale/timezonewidget/TimeZoneImage.cpp +++ b/src/modules/locale/timezonewidget/TimeZoneImage.cpp @@ -22,16 +22,17 @@ #include -static const char* zoneNames[] = - { "0.0", "1.0", "2.0", "3.0", "3.5", "4.0", "4.5", "5.0", "5.5", "5.75", "6.0", "6.5", "7.0", - "8.0", "9.0", "9.5", "10.0", "10.5", "11.0", "11.5", "12.0", "12.75", "13.0", "-1.0", "-2.0", "-3.0", - "-3.5", "-4.0", "-4.5", "-5.0", "-5.5", "-6.0", "-7.0", "-8.0", "-9.0", "-9.5", "-10.0", "-11.0" } ; +static const char* zoneNames[] + = { "0.0", "1.0", "2.0", "3.0", "3.5", "4.0", "4.5", "5.0", "5.5", "5.75", "6.0", "6.5", "7.0", + "8.0", "9.0", "9.5", "10.0", "10.5", "11.0", "11.5", "12.0", "12.75", "13.0", "-1.0", "-2.0", "-3.0", + "-3.5", "-4.0", "-4.5", "-5.0", "-5.5", "-6.0", "-7.0", "-8.0", "-9.0", "-9.5", "-10.0", "-11.0" }; +static_assert( TimeZoneImageList::zoneCount == ( sizeof( zoneNames ) / sizeof( zoneNames[ 0 ] ) ), + "Incorrect number of zones" ); -TimeZoneImageList::TimeZoneImageList() -{ -} +TimeZoneImageList::TimeZoneImageList() {} -TimeZoneImageList TimeZoneImageList::fromQRC() +TimeZoneImageList +TimeZoneImageList::fromQRC() { TimeZoneImageList l; for ( const auto* zoneName : zoneNames ) @@ -43,7 +44,8 @@ TimeZoneImageList TimeZoneImageList::fromQRC() return l; } -TimeZoneImageList TimeZoneImageList::fromDirectory(const QString& dirName) +TimeZoneImageList +TimeZoneImageList::fromDirectory( const QString& dirName ) { TimeZoneImageList l; QDir dir( dirName ); @@ -55,14 +57,83 @@ TimeZoneImageList TimeZoneImageList::fromDirectory(const QString& dirName) for ( const auto* zoneName : zoneNames ) { - l.append( QImage( dir.filePath( QStringLiteral("timezone_" ) + zoneName + ".png" ) ) ); + l.append( QImage( dir.filePath( QStringLiteral( "timezone_" ) + zoneName + ".png" ) ) ); l.last().setText( QStringLiteral( "zone" ), zoneName ); } return l; } -int TimeZoneImageList::zoneCount() +QPoint +TimeZoneImageList::getLocationPosition( double longitude, double latitude ) { - return sizeof(zoneNames) / sizeof(zoneNames[0]); + constexpr double MAP_Y_OFFSET = 0.125; + constexpr double MAP_X_OFFSET = -0.0370; + constexpr double MATH_PI = 3.14159265; + + const int width = imageSize.width(); + const int height = imageSize.height(); + + double x = ( width / 2.0 + ( width / 2.0 ) * longitude / 180.0 ) + MAP_X_OFFSET * width; + double y = ( height / 2.0 - ( height / 2.0 ) * latitude / 90.0 ) + MAP_Y_OFFSET * height; + + // Far north, the MAP_Y_OFFSET no longer holds, cancel the Y offset; it's noticeable + // from 62 degrees north, so scale those 28 degrees as if the world is flat south + // of there, and we have a funny "rounded" top of the world. In practice the locations + // of the different cities / regions looks ok -- at least Thule ends up in the right + // country, and Inuvik isn't in the ocean. + if ( latitude > 70.0 ) + { + y -= sin( MATH_PI * ( latitude - 70.0 ) / 56.0 ) * MAP_Y_OFFSET * height * 0.8; + } + if ( latitude > 74.0 ) + { + y += 4; + } + if ( latitude > 69.0 ) + { + y -= 2; + } + if ( latitude > 59.0 ) + { + y -= 4 * int( ( latitude - 54.0 ) / 5.0 ); + } + if ( latitude > 54.0 ) + { + y -= 2; + } + if ( latitude > 49.0 ) + { + y -= int( ( latitude - 44.0 ) / 5.0 ); + } + // Far south, some stretching occurs as well, but it is less pronounced. + // Move down by 1 pixel per 5 degrees past 10 south + if ( latitude < 0 ) + { + y += int( ( -latitude ) / 5.0 ); + } + // Antarctica isn't shown on the map, but you could try clicking there + if ( latitude < -60 ) + { + y = height - 1; + } + + if ( x < 0 ) + { + x = width + x; + } + if ( x >= width ) + { + x -= width; + } + if ( y < 0 ) + { + y = height + y; + } + if ( y >= height ) + { + y -= height; + } + + return QPoint( int( x ), int( y ) ); } diff --git a/src/modules/locale/timezonewidget/TimeZoneImage.h b/src/modules/locale/timezonewidget/TimeZoneImage.h index 654ff1a09..3c79939bf 100644 --- a/src/modules/locale/timezonewidget/TimeZoneImage.h +++ b/src/modules/locale/timezonewidget/TimeZoneImage.h @@ -33,6 +33,7 @@ class TimeZoneImageList : public QList< TimeZoneImage > { private: TimeZoneImageList(); + public: /** @brief loads all the images from QRC. * @@ -46,8 +47,19 @@ public: */ static TimeZoneImageList fromDirectory( const QString& dirName ); + /** @brief Map longitude and latitude to pixel positions + * + * The image is flat, and stretched at the poles and generally + * a bit weird, so this maps the global coordinates (as found in + * the zones table as a floating-point longitude and latitude value) + * to an x,y position. + */ + static QPoint getLocationPosition( double longitude, double latitude ); + /// @brief The **expected** number of zones in the list. - static int zoneCount(); + static constexpr const int zoneCount = 38; + /// @brief The expected size of each zone image. + static constexpr const QSize imageSize = QSize( 780, 340 ); }; #endif diff --git a/src/modules/locale/timezonewidget/timezonewidget.cpp b/src/modules/locale/timezonewidget/timezonewidget.cpp index ba684f5f3..d5d33a594 100644 --- a/src/modules/locale/timezonewidget/timezonewidget.cpp +++ b/src/modules/locale/timezonewidget/timezonewidget.cpp @@ -31,10 +31,6 @@ // Pixel value indicating that a spot is outside of a zone #define RGB_TRANSPARENT 0 -static constexpr double MAP_Y_OFFSET = 0.125; -static constexpr double MAP_X_OFFSET = -0.0370; -constexpr static double MATH_PI = 3.14159265; - #ifdef DEBUG_TIMEZONES // Adds a label to the timezone with this name #define ZONE_NAME QStringLiteral( "zone" ) @@ -134,78 +130,6 @@ TimeZoneWidget::setCurrentLocation( const CalamaresUtils::Locale::TZZone* locati //### Private //### - -QPoint -TimeZoneWidget::getLocationPosition( double longitude, double latitude ) -{ - const int width = this->width(); - const int height = this->height(); - - double x = ( width / 2.0 + ( width / 2.0 ) * longitude / 180.0 ) + MAP_X_OFFSET * width; - double y = ( height / 2.0 - ( height / 2.0 ) * latitude / 90.0 ) + MAP_Y_OFFSET * height; - - // Far north, the MAP_Y_OFFSET no longer holds, cancel the Y offset; it's noticeable - // from 62 degrees north, so scale those 28 degrees as if the world is flat south - // of there, and we have a funny "rounded" top of the world. In practice the locations - // of the different cities / regions looks ok -- at least Thule ends up in the right - // country, and Inuvik isn't in the ocean. - if ( latitude > 70.0 ) - { - y -= sin( MATH_PI * ( latitude - 70.0 ) / 56.0 ) * MAP_Y_OFFSET * height * 0.8; - } - if ( latitude > 74.0 ) - { - y += 4; - } - if ( latitude > 69.0 ) - { - y -= 2; - } - if ( latitude > 59.0 ) - { - y -= 4 * int( ( latitude - 54.0 ) / 5.0 ); - } - if ( latitude > 54.0 ) - { - y -= 2; - } - if ( latitude > 49.0 ) - { - y -= int( ( latitude - 44.0 ) / 5.0 ); - } - // Far south, some stretching occurs as well, but it is less pronounced. - // Move down by 1 pixel per 5 degrees past 10 south - if ( latitude < 0 ) - { - y += int( ( -latitude ) / 5.0 ); - } - // Antarctica isn't shown on the map, but you could try clicking there - if ( latitude < -60 ) - { - y = height - 1; - } - - if ( x < 0 ) - { - x = width + x; - } - if ( x >= width ) - { - x -= width; - } - if ( y < 0 ) - { - y = height + y; - } - if ( y >= height ) - { - y -= height; - } - - return QPoint( int( x ), int( y ) ); -} - - void TimeZoneWidget::paintEvent( QPaintEvent* ) { @@ -229,7 +153,7 @@ TimeZoneWidget::paintEvent( QPaintEvent* ) QPen p( y_lat ? Qt::black : Qt::red ); p.setWidth( 0 ); painter.setPen( p ); - QPoint latLine0( getLocationPosition( 0, y_lat ) ); + QPoint latLine0( TimeZoneImageList::getLocationPosition( 0, y_lat ) ); painter.drawLine( 0, latLine0.y(), this->width() - 1, latLine0.y() ); } // Just a dot in the selected location, no label @@ -309,7 +233,7 @@ TimeZoneWidget::mousePressEvent( QMouseEvent* event ) const auto* zone = dynamic_cast< const TZZone* >( zone_p ); if ( zone ) { - QPoint locPos = getLocationPosition( zone->longitude(), zone->latitude() ); + QPoint locPos = TimeZoneImageList::getLocationPosition( zone->longitude(), zone->latitude() ); if ( ( abs( mX - locPos.x() ) + abs( mY - locPos.y() ) < abs( mX - nX ) + abs( mY - nY ) ) ) { diff --git a/src/modules/locale/timezonewidget/timezonewidget.h b/src/modules/locale/timezonewidget/timezonewidget.h index 2a8d5ebde..6ae79add6 100644 --- a/src/modules/locale/timezonewidget/timezonewidget.h +++ b/src/modules/locale/timezonewidget/timezonewidget.h @@ -59,8 +59,10 @@ private: TimeZoneImageList timeZoneImages; const TZZone* m_currentLocation = nullptr; // Not owned by me - QPoint getLocationPosition( const TZZone* l ) { return getLocationPosition( l->longitude(), l->latitude() ); } - QPoint getLocationPosition( double longitude, double latitude ); + QPoint getLocationPosition( const TZZone* l ) + { + return timeZoneImages.getLocationPosition( l->longitude(), l->latitude() ); + } void paintEvent( QPaintEvent* event ); void mousePressEvent( QMouseEvent* event );