File indexing completed on 2024-04-28 03:50:17

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2009 Torsten Rahn <tackat@kde.org>
0004 //
0005 
0006 #include "GraticulePlugin.h"
0007 #include "ui_GraticuleConfigWidget.h"
0008 
0009 #include "MarbleDebug.h"
0010 #include "MarbleDirs.h"
0011 #include "GeoPainter.h"
0012 #include "GeoDataLineString.h"
0013 #include "Planet.h"
0014 #include "MarbleModel.h"
0015 #include "PluginAboutDialog.h"
0016 
0017 #include "ViewportParams.h"
0018 
0019 // Qt
0020 #include <QPushButton>
0021 #include <QRect>
0022 #include <QColor>
0023 #include <QBrush>
0024 #include <QDebug>
0025 
0026 
0027 
0028 namespace Marble
0029 {
0030 
0031 GraticulePlugin::GraticulePlugin()
0032     : RenderPlugin( nullptr ),
0033       m_showPrimaryLabels( true ),
0034       m_showSecondaryLabels( true ),
0035       m_isInitialized( false ),
0036       ui_configWidget( nullptr ),
0037       m_configDialog( nullptr )
0038 {
0039 }
0040 
0041 GraticulePlugin::GraticulePlugin( const MarbleModel *marbleModel )
0042     : RenderPlugin( marbleModel ),
0043       m_equatorCirclePen( Qt::yellow ),
0044       m_tropicsCirclePen( Qt::yellow ),
0045       m_gridCirclePen( Qt::white ),
0046       m_showPrimaryLabels( true ),
0047       m_showSecondaryLabels( true ),
0048       m_isInitialized( false ),
0049       ui_configWidget( nullptr ),
0050       m_configDialog( nullptr )
0051 {
0052 }
0053 
0054 QStringList GraticulePlugin::backendTypes() const
0055 {
0056     return QStringList(QStringLiteral("graticule"));
0057 }
0058 
0059 QString GraticulePlugin::renderPolicy() const
0060 {
0061     return QStringLiteral("ALWAYS");
0062 }
0063 
0064 QStringList GraticulePlugin::renderPosition() const
0065 {
0066     return QStringList(QStringLiteral("GRATICULE"));
0067 }
0068 
0069 QString GraticulePlugin::name() const
0070 {
0071     return tr( "Coordinate Grid" );
0072 }
0073 
0074 QString GraticulePlugin::guiString() const
0075 {
0076     return tr( "Coordinate &Grid" );
0077 }
0078 
0079 QString GraticulePlugin::nameId() const
0080 {
0081     return QStringLiteral("coordinate-grid");
0082 }
0083 
0084 QString GraticulePlugin::version() const
0085 {
0086     return QStringLiteral("1.0");
0087 }
0088 
0089 QString GraticulePlugin::description() const
0090 {
0091     return tr( "A plugin that shows a coordinate grid." );
0092 }
0093 
0094 QString GraticulePlugin::copyrightYears() const
0095 {
0096     return QStringLiteral("2009");
0097 }
0098 
0099 QVector<PluginAuthor> GraticulePlugin::pluginAuthors() const
0100 {
0101     return QVector<PluginAuthor>()
0102             << PluginAuthor(QStringLiteral("Torsten Rahn"), QStringLiteral("tackat@kde.org"));
0103 }
0104 
0105 QIcon GraticulePlugin::icon () const
0106 {
0107     return QIcon(QStringLiteral(":/icons/coordinate.png"));
0108 }
0109 
0110 void GraticulePlugin::initialize ()
0111 {
0112     // Initialize range maps that map the zoom to the number of coordinate grid lines.
0113     
0114     initLineMaps( GeoDataCoordinates::defaultNotation() );                
0115 
0116     m_isInitialized = true;
0117 }
0118 
0119 bool GraticulePlugin::isInitialized () const
0120 {
0121     return m_isInitialized;
0122 }
0123 
0124 QDialog *GraticulePlugin::configDialog()
0125 {
0126     if ( !m_configDialog ) {
0127         m_configDialog = new QDialog();
0128         ui_configWidget = new Ui::GraticuleConfigWidget;
0129         ui_configWidget->setupUi( m_configDialog );
0130 
0131         connect( ui_configWidget->gridPushButton, SIGNAL(clicked()), this,
0132                 SLOT(gridGetColor()) );
0133         connect( ui_configWidget->tropicsPushButton, SIGNAL(clicked()), this,
0134                 SLOT(tropicsGetColor()) );
0135         connect( ui_configWidget->equatorPushButton, SIGNAL(clicked()), this,
0136                 SLOT(equatorGetColor()) );
0137 
0138 
0139         connect( ui_configWidget->m_buttonBox, SIGNAL(accepted()), this, 
0140                 SLOT(writeSettings()) );
0141         connect( ui_configWidget->m_buttonBox->button( QDialogButtonBox::Reset ), SIGNAL(clicked()),
0142                  SLOT(restoreDefaultSettings()) );
0143         QPushButton *applyButton = ui_configWidget->m_buttonBox->button( QDialogButtonBox::Apply );
0144         connect( applyButton, SIGNAL(clicked()),
0145                  this,        SLOT(writeSettings()) );
0146     }
0147 
0148     readSettings();
0149 
0150     return m_configDialog;
0151 }
0152 
0153 
0154 QHash<QString,QVariant> GraticulePlugin::settings() const
0155 {
0156     QHash<QString, QVariant> settings = RenderPlugin::settings();
0157 
0158     settings.insert(QStringLiteral("gridColor"), m_gridCirclePen.color().name());
0159     settings.insert(QStringLiteral("tropicsColor"), m_tropicsCirclePen.color().name());
0160     settings.insert(QStringLiteral("equatorColor"), m_equatorCirclePen.color().name());
0161     settings.insert(QStringLiteral("primaryLabels"), m_showPrimaryLabels);
0162     settings.insert(QStringLiteral("secondaryLabels"), m_showSecondaryLabels);
0163 
0164     return settings;
0165 }
0166 
0167 void GraticulePlugin::setSettings( const QHash<QString,QVariant> &settings )
0168 {
0169     RenderPlugin::setSettings( settings );
0170 
0171     const QColor gridColor = settings.value(QStringLiteral("gridColor"), QColor(Qt::white)).value<QColor>();
0172     const QColor tropicsColor = settings.value(QStringLiteral("tropicsColor"), QColor(Qt::yellow)).value<QColor>();
0173     const QColor equatorColor = settings.value(QStringLiteral("equatorColor"), QColor(Qt::yellow)).value<QColor>();
0174     bool primaryLabels = settings.value(QStringLiteral("primaryLabels"), true).toBool();
0175     bool secondaryLabels = settings.value(QStringLiteral("secondaryLabels"), true).toBool();
0176 
0177     m_gridCirclePen.setColor( gridColor );
0178     m_tropicsCirclePen.setColor( tropicsColor );
0179     m_equatorCirclePen.setColor( equatorColor );
0180 
0181     m_showPrimaryLabels = primaryLabels;
0182     m_showSecondaryLabels = secondaryLabels;
0183 
0184     readSettings();
0185 }
0186 
0187 
0188 void GraticulePlugin::readSettings()
0189 {
0190     if ( !m_configDialog )
0191         return;
0192 
0193     QPalette gridPalette;
0194     gridPalette.setColor( QPalette::Button, m_gridCirclePen.color() );
0195     ui_configWidget->gridPushButton->setPalette( gridPalette );
0196 
0197     QPalette tropicsPalette;
0198     tropicsPalette.setColor( QPalette::Button, m_tropicsCirclePen.color() );
0199     ui_configWidget->tropicsPushButton->setPalette( tropicsPalette );
0200 
0201 
0202     QPalette equatorPalette;
0203     equatorPalette.setColor( QPalette::Button, m_equatorCirclePen.color() );
0204     ui_configWidget->equatorPushButton->setPalette( equatorPalette );
0205     ui_configWidget->primaryCheckBox->setChecked( m_showPrimaryLabels );
0206     ui_configWidget->secondaryCheckBox->setChecked( m_showSecondaryLabels );
0207 }
0208 
0209 void GraticulePlugin::gridGetColor()
0210 {
0211     const QColor c = QColorDialog::getColor( m_gridCirclePen.color(), nullptr, tr("Please choose the color for the coordinate grid.") );
0212 
0213     if ( c.isValid() ) {
0214         QPalette palette = ui_configWidget->gridPushButton->palette();
0215         palette.setColor( QPalette::Button, c );
0216         ui_configWidget->gridPushButton->setPalette( palette );
0217     }
0218 }
0219 
0220 void GraticulePlugin::tropicsGetColor()
0221 {
0222     const QColor c = QColorDialog::getColor( m_tropicsCirclePen.color(), nullptr, tr("Please choose the color for the tropic circles.") );
0223 
0224     if ( c.isValid() ) {
0225         QPalette palette = ui_configWidget->tropicsPushButton->palette();
0226         palette.setColor( QPalette::Button, c );
0227         ui_configWidget->tropicsPushButton->setPalette( palette );
0228     }
0229 }
0230 
0231 void GraticulePlugin::equatorGetColor()
0232 {
0233     const QColor c = QColorDialog::getColor( m_equatorCirclePen.color(), nullptr, tr("Please choose the color for the equator.") );
0234 
0235     if ( c.isValid() ) {
0236         QPalette palette = ui_configWidget->equatorPushButton->palette();
0237         palette.setColor( QPalette::Button, c );
0238         ui_configWidget->equatorPushButton->setPalette( palette );
0239     }
0240 }
0241 
0242 void GraticulePlugin::writeSettings()
0243 {
0244     m_equatorCirclePen.setColor( ui_configWidget->equatorPushButton->palette().color( QPalette::Button ) );
0245     m_tropicsCirclePen.setColor( ui_configWidget->tropicsPushButton->palette().color( QPalette::Button ) );
0246     m_gridCirclePen.setColor( ui_configWidget->gridPushButton->palette().color( QPalette::Button) );
0247     m_showPrimaryLabels = ui_configWidget->primaryCheckBox->isChecked();
0248     m_showSecondaryLabels = ui_configWidget->secondaryCheckBox->isChecked();
0249 
0250     emit settingsChanged( nameId() );
0251 }
0252 
0253 bool GraticulePlugin::render( GeoPainter *painter, ViewportParams *viewport,
0254                 const QString& renderPos,
0255                 GeoSceneLayer * layer )
0256 {
0257     Q_UNUSED( layer )
0258     Q_UNUSED( renderPos )
0259 
0260     if ( m_currentNotation != GeoDataCoordinates::defaultNotation() ) {
0261         initLineMaps( GeoDataCoordinates::defaultNotation() );
0262     }
0263 
0264     // Setting the label font for the coordinate lines.
0265 #ifdef Q_OS_MACX
0266     int defaultFontSize = 10;
0267 #else
0268     int defaultFontSize = 8;
0269 #endif
0270 
0271     QFont gridFont("Sans Serif");
0272     gridFont.setPointSize( defaultFontSize );    
0273     gridFont.setBold( true );
0274 
0275     painter->save();
0276 
0277     painter->setFont( gridFont );
0278 
0279     renderGrid( painter, viewport, m_equatorCirclePen, m_tropicsCirclePen, m_gridCirclePen );
0280 
0281     painter->restore();
0282 
0283     return true;
0284 }
0285 
0286 qreal GraticulePlugin::zValue() const
0287 {
0288     return 1.0;
0289 }
0290 
0291 void GraticulePlugin::renderGrid( GeoPainter *painter, ViewportParams *viewport,
0292                                   const QPen& equatorCirclePen,
0293                                   const QPen& tropicsCirclePen,
0294                                   const QPen& gridCirclePen )
0295 {
0296     GeoDataLatLonAltBox viewLatLonAltBox = viewport->viewLatLonAltBox();
0297 
0298     painter->setPen( equatorCirclePen );
0299 
0300     LabelPositionFlags mainPosition(NoLabel);
0301     if ( m_showPrimaryLabels ) {
0302         mainPosition = LineCenter;
0303     }
0304     // Render the equator
0305     renderLatitudeLine( painter, 0.0, viewLatLonAltBox, tr( "Equator" ), mainPosition );
0306 
0307     // Render the Prime Meridian and Antimeridian
0308     GeoDataCoordinates::Notation notation = GeoDataCoordinates::defaultNotation();
0309     if (marbleModel()->planet()->id() != QLatin1String("sky") && notation != GeoDataCoordinates::Astro) {
0310         renderLongitudeLine( painter, 0.0, viewLatLonAltBox, 0.0, 0.0, tr( "Prime Meridian" ), mainPosition );
0311         renderLongitudeLine( painter, 180.0, viewLatLonAltBox, 0.0, 0.0, tr( "Antimeridian" ), mainPosition );
0312     }
0313 
0314     painter->setPen( gridCirclePen );
0315     // painter->setPen( QPen( QBrush( Qt::white ), 0.75 ) );
0316 
0317     // Render UTM grid zones
0318     if ( m_currentNotation == GeoDataCoordinates::UTM ) {
0319         renderLatitudeLine( painter, 84.0, viewLatLonAltBox );
0320 
0321         renderLongitudeLines( painter, viewLatLonAltBox,
0322                     6.0, 0.0,
0323                     18.0, 154.0, LineEnd | IgnoreXMargin );
0324         renderLongitudeLines( painter, viewLatLonAltBox,
0325                     6.0, 0.0,
0326                     34.0, 10.0, LineStart | IgnoreXMargin );
0327 
0328         // Paint longitudes with exceptions
0329         renderLongitudeLines( painter, viewLatLonAltBox,
0330                     6.0, 0.0,
0331                     6.0, 162.0, LineEnd | IgnoreXMargin );
0332         renderLongitudeLines( painter, viewLatLonAltBox,
0333                     6.0, 0.0,
0334                     26.0, 146.0, LineEnd | IgnoreXMargin  );
0335 
0336         renderLatitudeLines( painter, viewLatLonAltBox, 8.0, 0.0 /*,
0337                              LineStart | IgnoreYMargin */ );
0338 
0339         return;
0340     }
0341 
0342     // Render the normal grid
0343 
0344     // calculate the angular distance between coordinate lines of the normal grid
0345     qreal normalDegreeStep = 360.0 / m_normalLineMap.lowerBound(viewport->radius()).value();
0346 
0347     LabelPositionFlags labelXPosition(NoLabel), labelYPosition(NoLabel);
0348     if ( m_showSecondaryLabels ) {
0349         labelXPosition = LineStart | IgnoreXMargin;
0350         labelYPosition = LineStart | IgnoreYMargin;
0351     }
0352     qreal boldDegreeStep = 360.0 / m_boldLineMap.lowerBound(viewport->radius()).value();
0353     renderLongitudeLines( painter, viewLatLonAltBox,
0354                           normalDegreeStep, boldDegreeStep,
0355                           normalDegreeStep, normalDegreeStep,
0356                           labelXPosition );
0357     renderLatitudeLines(  painter, viewLatLonAltBox, normalDegreeStep, boldDegreeStep,
0358                           labelYPosition );
0359 
0360     // Render some non-cut off longitude lines ..
0361     renderLongitudeLine( painter, +90.0, viewLatLonAltBox );
0362     renderLongitudeLine( painter, -90.0, viewLatLonAltBox );
0363 
0364     // Render the bold grid
0365 
0366     if (    painter->mapQuality() == HighQuality
0367          || painter->mapQuality() == PrintQuality ) {
0368 
0369         QPen boldPen = gridCirclePen;
0370         boldPen.setWidthF( 2.0 );
0371         painter->setPen( boldPen );
0372     }
0373 
0374     // calculate the angular distance between coordinate lines of the bold grid
0375 
0376     renderLongitudeLines( painter, viewLatLonAltBox,
0377                         boldDegreeStep, 0.0,
0378                         normalDegreeStep, normalDegreeStep,
0379                         NoLabel
0380                         );
0381 
0382     renderLatitudeLines(  painter, viewLatLonAltBox, boldDegreeStep, 0.0,
0383                         NoLabel );
0384 
0385     QPen tropicsPen = tropicsCirclePen;
0386     if (   painter->mapQuality() != OutlineQuality
0387         && painter->mapQuality() != LowQuality ) {
0388         tropicsPen.setStyle( Qt::DotLine );
0389     }
0390     painter->setPen( tropicsPen );
0391 
0392     // Determine the planet's axial tilt
0393     qreal axialTilt = RAD2DEG * marbleModel()->planet()->epsilon();
0394 
0395     if ( axialTilt > 0 ) {
0396         // Render the tropics
0397         renderLatitudeLine( painter, +axialTilt, viewLatLonAltBox, tr( "Tropic of Cancer" ), mainPosition  );
0398         renderLatitudeLine( painter, -axialTilt, viewLatLonAltBox, tr( "Tropic of Capricorn" ), mainPosition );
0399 
0400         // Render the arctics
0401         renderLatitudeLine( painter, +90.0 - axialTilt, viewLatLonAltBox, tr( "Arctic Circle" ), mainPosition );
0402         renderLatitudeLine( painter, -90.0 + axialTilt, viewLatLonAltBox, tr( "Antarctic Circle" ), mainPosition );
0403     }    
0404 }
0405 
0406 void GraticulePlugin::renderLatitudeLine( GeoPainter *painter, qreal latitude,
0407                                           const GeoDataLatLonAltBox& viewLatLonAltBox,
0408                                           const QString& lineLabel,
0409                                           LabelPositionFlags labelPositionFlags )
0410 {
0411     qreal fromSouthLat = viewLatLonAltBox.south( GeoDataCoordinates::Degree );
0412     qreal toNorthLat   = viewLatLonAltBox.north( GeoDataCoordinates::Degree );
0413 
0414     // Coordinate line is not displayed inside the viewport
0415     if ( latitude < fromSouthLat || toNorthLat < latitude ) {
0416         // mDebug() << "Lat: Out of View";
0417         return;
0418     }
0419 
0420     GeoDataLineString line( Tessellate | RespectLatitudeCircle ) ;
0421 
0422     qreal fromWestLon = viewLatLonAltBox.west( GeoDataCoordinates::Degree );
0423     qreal toEastLon   = viewLatLonAltBox.east( GeoDataCoordinates::Degree );
0424 
0425     if ( fromWestLon < toEastLon ) {
0426         qreal step = ( toEastLon - fromWestLon ) * 0.25;
0427 
0428         for ( int i = 0; i < 5; ++i ) {
0429             line << GeoDataCoordinates( fromWestLon + i * step, latitude, 0.0, GeoDataCoordinates::Degree );
0430         }
0431     }
0432     else {
0433         qreal step = ( +180.0 - toEastLon ) * 0.25;
0434 
0435         for ( int i = 0; i < 5; ++i ) {
0436             line << GeoDataCoordinates( toEastLon + i * step, latitude, 0.0, GeoDataCoordinates::Degree );
0437         }
0438 
0439         step = ( +180 + fromWestLon ) * 0.25;
0440 
0441         for ( int i = 0; i < 5; ++i ) {
0442             line << GeoDataCoordinates( -180 + i * step, latitude, 0.0, GeoDataCoordinates::Degree );
0443         }
0444     }
0445 
0446     painter->drawPolyline( line, lineLabel, labelPositionFlags, painter->pen().color() );
0447 }
0448 
0449 void GraticulePlugin::renderLongitudeLine( GeoPainter *painter, qreal longitude,
0450                                            const GeoDataLatLonAltBox& viewLatLonAltBox, 
0451                                            qreal northPolarGap, qreal southPolarGap,
0452                                            const QString& lineLabel,
0453                                            LabelPositionFlags labelPositionFlags )
0454 {
0455     const qreal fromWestLon = viewLatLonAltBox.west();
0456     const qreal toEastLon   = viewLatLonAltBox.east();
0457 
0458     // Coordinate line is not displayed inside the viewport
0459     if ( ( !viewLatLonAltBox.crossesDateLine() 
0460            && ( longitude * DEG2RAD < fromWestLon || toEastLon < longitude * DEG2RAD ) ) ||
0461          (  viewLatLonAltBox.crossesDateLine() &&
0462             longitude * DEG2RAD < toEastLon && fromWestLon < longitude * DEG2RAD &&
0463             fromWestLon != -M_PI && toEastLon != +M_PI )
0464        ) {
0465         // mDebug() << "Lon: Out of View:" << viewLatLonAltBox.toString() << " Crossing: "<< viewLatLonAltBox.crossesDateLine() << "Longitude: " << longitude;
0466         return;
0467     }
0468 
0469     qreal fromSouthLat = viewLatLonAltBox.south( GeoDataCoordinates::Degree );
0470     qreal toNorthLat   = viewLatLonAltBox.north( GeoDataCoordinates::Degree );
0471     
0472     qreal southLat = ( fromSouthLat < -90.0 + southPolarGap ) ? -90.0 + southPolarGap : fromSouthLat;
0473     qreal northLat = ( toNorthLat   > +90.0 - northPolarGap ) ? +90.0 - northPolarGap : toNorthLat;
0474 
0475     GeoDataCoordinates n1( longitude, southLat, 0.0, GeoDataCoordinates::Degree );
0476     GeoDataCoordinates n3( longitude, northLat, 0.0, GeoDataCoordinates::Degree );
0477 
0478     GeoDataLineString line( Tessellate );
0479 
0480     if ( northLat > 0 && southLat < 0 )
0481     {
0482         GeoDataCoordinates n2( longitude, 0.0, 0.0, GeoDataCoordinates::Degree );
0483         line << n1 << n2 << n3;
0484     }
0485     else {
0486         line << n1 << n3;
0487     }
0488 
0489     painter->drawPolyline( line, lineLabel, labelPositionFlags, painter->pen().color() );
0490 }
0491 
0492 void GraticulePlugin::renderLatitudeLines( GeoPainter *painter,
0493                                            const GeoDataLatLonAltBox& viewLatLonAltBox,
0494                                            qreal step, qreal skipStep,
0495                                            LabelPositionFlags labelPositionFlags
0496                                          )
0497 {
0498     if ( step <= 0 ) {
0499         return;
0500     }
0501 
0502     // Latitude
0503     qreal southLat = viewLatLonAltBox.south( GeoDataCoordinates::Degree );
0504     qreal northLat = viewLatLonAltBox.north( GeoDataCoordinates::Degree );
0505 
0506     qreal southLineLat = step * static_cast<int>( southLat / step ); 
0507     qreal northLineLat = step * ( static_cast<int>( northLat / step ) + 1 );
0508     
0509     if ( m_currentNotation == GeoDataCoordinates::UTM ) {
0510         if ( northLineLat > 84.0 ) {
0511             northLineLat = 76.0;
0512         }
0513 
0514         if ( southLineLat < -80.0 ) {
0515             southLineLat = -80.0;
0516         }
0517     }
0518 
0519     qreal itStep = southLineLat;
0520 
0521     GeoDataCoordinates::Notation notation = GeoDataCoordinates::defaultNotation();
0522 
0523     while ( itStep < northLineLat ) {
0524         // Create a matching label
0525         QString label = GeoDataCoordinates::latToString( itStep, notation,
0526                                  GeoDataCoordinates::Degree, -1, 'g' );
0527 
0528         // No additional labels for the equator
0529         if ( labelPositionFlags.testFlag( LineCenter ) && itStep == 0.0 ) {
0530             label.clear();
0531         }
0532 
0533         // Paint all latitude coordinate lines except for the equator
0534         if ( itStep != 0.0 && fmod(itStep, skipStep) != 0 ) {
0535             renderLatitudeLine( painter, itStep, viewLatLonAltBox, label, labelPositionFlags );
0536         }
0537 
0538         itStep += step;
0539     }
0540 }
0541 
0542 
0543 void GraticulePlugin::renderUtmExceptions( GeoPainter *painter,
0544                                             const GeoDataLatLonAltBox& viewLatLonAltBox,
0545                                             qreal itStep, qreal northPolarGap, qreal southPolarGap,
0546                                             const QString & label,
0547                                             LabelPositionFlags labelPositionFlags )
0548 {
0549     // This code renders the so called "exceptions" in the UTM coordinate grid
0550     // See: https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system#Exceptions
0551     if ( northPolarGap == 6.0 && southPolarGap == 162.0) {
0552         if (label == QLatin1String("33")) {
0553             renderLongitudeLine( painter, itStep-3.0, viewLatLonAltBox, northPolarGap,
0554             southPolarGap, label, labelPositionFlags );
0555         } else if (label == QLatin1String("35")) {
0556             renderLongitudeLine( painter, itStep-3.0, viewLatLonAltBox, northPolarGap,
0557             southPolarGap, label, labelPositionFlags );
0558         } else if (label == QLatin1String("37")) {
0559             renderLongitudeLine( painter, itStep-3.0, viewLatLonAltBox, northPolarGap,
0560             southPolarGap, label, labelPositionFlags );
0561         } else if (label == QLatin1String("32") || label == QLatin1String("34") || label == QLatin1String("36")) {
0562             // paint nothing
0563         } else {
0564             renderLongitudeLine( painter, itStep, viewLatLonAltBox, northPolarGap,
0565             southPolarGap, label, labelPositionFlags );
0566         }
0567     }
0568     else if ( northPolarGap == 26.0 && southPolarGap == 146.0 ) {
0569         if (label == QLatin1String("32")) {
0570             renderLongitudeLine( painter, itStep-3.0, viewLatLonAltBox, northPolarGap,
0571             southPolarGap, label, labelPositionFlags );
0572         } else {
0573             renderLongitudeLine( painter, itStep, viewLatLonAltBox, northPolarGap,
0574             southPolarGap, label, labelPositionFlags );
0575         }
0576     }
0577     else {
0578         renderLongitudeLine( painter, itStep, viewLatLonAltBox, northPolarGap,
0579         southPolarGap, label, labelPositionFlags );
0580     }
0581 }
0582 
0583 void GraticulePlugin::renderLongitudeLines( GeoPainter *painter, 
0584                                             const GeoDataLatLonAltBox& viewLatLonAltBox, 
0585                                             qreal step, qreal skipStep,
0586                                             qreal northPolarGap, qreal southPolarGap,
0587                                             LabelPositionFlags labelPositionFlags) const
0588 {
0589     if ( step <= 0 ) {
0590         return;
0591     }
0592 
0593     const bool isSky = (marbleModel()->planet()->id() == QLatin1String("sky"));
0594     const GeoDataCoordinates::Notation notation = isSky ? GeoDataCoordinates::Astro : GeoDataCoordinates::defaultNotation();
0595 
0596     // Set precision to 0 in UTM in order to show only zone number.
0597     int precision = (notation == GeoDataCoordinates::UTM) ? 0 : -1;
0598 
0599     // Longitude
0600     qreal westLon = viewLatLonAltBox.west( GeoDataCoordinates::Degree );
0601     qreal eastLon = viewLatLonAltBox.east( GeoDataCoordinates::Degree );
0602 
0603     qreal westLineLon = step * static_cast<int>( westLon / step );
0604     qreal eastLineLon = step * ( static_cast<int>( eastLon / step ) + 1 );
0605 
0606     if ( !viewLatLonAltBox.crossesDateLine() ||
0607          ( westLon == -180.0 && eastLon == +180.0 ) ) {
0608         qreal itStep = westLineLon;
0609 
0610         while ( itStep < eastLineLon ) {
0611             // Create a matching label
0612             QString label = GeoDataCoordinates::lonToString( itStep,
0613                                   notation, GeoDataCoordinates::Degree,
0614                                   precision, 'g' );
0615 
0616             // No additional labels for the prime meridian and the antimeridian
0617 
0618             if ( labelPositionFlags.testFlag( LineCenter ) && ( itStep == 0.0 || itStep == 180.0 || itStep == -180.0 ) )
0619             {
0620                 label.clear();
0621             }
0622 
0623             // Paint all longitude coordinate lines (except for the meridians in non-UTM mode)
0624             if (notation == GeoDataCoordinates::UTM ) {
0625                 renderUtmExceptions( painter, viewLatLonAltBox, itStep, northPolarGap,
0626                 southPolarGap, label, labelPositionFlags );
0627             } else if ( itStep != 0.0 && itStep != 180.0 && itStep != -180.0 ) {
0628                 if (fmod(itStep, skipStep) != 0 || skipStep == 0.0) {
0629                     renderLongitudeLine( painter, itStep, viewLatLonAltBox, northPolarGap,
0630                     southPolarGap, label, labelPositionFlags );
0631                 }
0632             }
0633             itStep += step;
0634         }
0635     }
0636     else {
0637         qreal itStep = eastLineLon;
0638 
0639         while ( itStep < 180.0 ) {
0640             // Create a matching label
0641             QString label = GeoDataCoordinates::lonToString( itStep,
0642                                   notation, GeoDataCoordinates::Degree,
0643                                   precision, 'g' );
0644 
0645             // No additional labels for the prime meridian and the antimeridian
0646 
0647             if ( labelPositionFlags.testFlag( LineCenter ) && ( itStep == 0.0 || itStep == 180.0 || itStep == -180.0 ) )
0648             {
0649                 label.clear();
0650             }
0651 
0652             // Paint all longitude coordinate lines (except for the meridians in non-UTM mode)
0653             if (notation == GeoDataCoordinates::UTM ) {
0654                 renderUtmExceptions( painter, viewLatLonAltBox, itStep, northPolarGap,
0655                 southPolarGap, label, labelPositionFlags );
0656             } else if ( itStep != 0.0 && itStep != 180.0 && itStep != -180.0 ) {
0657                 if (fmod((itStep), skipStep) != 0 || skipStep == 0.0) {
0658                     renderLongitudeLine( painter, itStep, viewLatLonAltBox, northPolarGap,
0659                     southPolarGap, label, labelPositionFlags );
0660                 }
0661             }
0662             itStep += step;
0663         }
0664 
0665         itStep = -180.0;
0666 
0667         while ( itStep < westLineLon ) {
0668             // Create a matching label
0669             QString label = GeoDataCoordinates::lonToString( itStep,
0670                                   notation, GeoDataCoordinates::Degree,
0671                                   precision, 'g' );
0672 
0673             // No additional labels for the prime meridian and the antimeridian
0674             if ( labelPositionFlags.testFlag( LineCenter ) && ( itStep == 0.0 || itStep == 180.0 || itStep == -180.0 ) )
0675             {
0676                 label.clear();
0677             }
0678 
0679             // Paint all longitude coordinate lines (except for the meridians in non-UTM mode)
0680             if (notation == GeoDataCoordinates::UTM ) {
0681                 renderUtmExceptions( painter, viewLatLonAltBox, itStep, northPolarGap,
0682                 southPolarGap, label, labelPositionFlags );
0683             } else if ( itStep != 0.0 && itStep != 180.0 && itStep != -180.0 ) {
0684                 if (fmod((itStep+180), skipStep) != 0 || skipStep == 0.0) {
0685                     renderLongitudeLine( painter, itStep, viewLatLonAltBox, northPolarGap,
0686                     southPolarGap, label, labelPositionFlags );
0687                 }
0688             }
0689             itStep += step;
0690         }
0691     }
0692 }
0693 
0694 void GraticulePlugin::initLineMaps( GeoDataCoordinates::Notation notation)
0695 {
0696     /* Define Upper Bound keys and associated values:
0697        The key number is the globe radius in pixel.
0698        The value number is the amount of grid lines for the full range.
0699 
0700        Example: up to a 100 pixel radius the globe is covered
0701        with 4 longitude lines (4 half-circles).
0702      */
0703 
0704     if (marbleModel()->planet()->id() == QLatin1String("sky") ||
0705         notation == GeoDataCoordinates::Astro) {
0706         m_normalLineMap[100]     = 4;          // 6h
0707         m_normalLineMap[1000]    = 12;          // 2h
0708         m_normalLineMap[2000]   = 24;         // 1h
0709         m_normalLineMap[4000]   = 48;         // 30 min
0710         m_normalLineMap[8000]   = 96;         // 15 min
0711         m_normalLineMap[16000]  = 288;        // 5 min
0712         m_normalLineMap[100000]  = 24 * 60;     // 1 min
0713         m_normalLineMap[200000]  = 24 * 60 * 2; // 30 sec
0714         m_normalLineMap[400000]  = 24 * 60 * 4; // 15 sec
0715         m_normalLineMap[1200000] = 24 * 60 * 12; // 5 sec
0716         m_normalLineMap[6000000] = 24 * 60 * 60; // 1 sec
0717         m_normalLineMap[12000000] = 24 * 60 * 60 * 2; // 0.5 sec
0718         m_normalLineMap[24000000] = 24 * 60 * 60 * 4; // 0.25 sec
0719 
0720         m_boldLineMap[1000]     = 0;        // 0h
0721         m_boldLineMap[2000]    = 4;         //  6h
0722         m_boldLineMap[16000]    = 24;       //  30 deg
0723         return;
0724     }
0725 
0726     m_normalLineMap[100]     = 4;          // 90 deg
0727     m_normalLineMap[1000]    = 12;          // 30 deg
0728     m_normalLineMap[4000]   = 36;         // 10 deg
0729     m_normalLineMap[16000]   = 72;         // 5 deg
0730     m_normalLineMap[64000]  = 360;         //  1 deg
0731     m_normalLineMap[128000] = 720;        //  0.5 deg
0732 
0733     m_boldLineMap[1000]     = 0;         //  0 deg
0734     m_boldLineMap[4000]    = 12;         //  30 deg
0735     m_boldLineMap[16000]   = 36;         //  10 deg
0736 
0737     switch ( notation )
0738     {
0739         case GeoDataCoordinates::Decimal :
0740             
0741             m_normalLineMap[512000]  = 360 * 10;       //  0.1 deg
0742             m_normalLineMap[2048000] = 360 * 20;       //  0.05 deg
0743             m_normalLineMap[8192000] = 360 * 100;      //  0.01 deg
0744             m_normalLineMap[16384000] = 360 * 200;      //  0.005 deg
0745             m_normalLineMap[32768000] = 360 * 1000;    //  0.001 deg
0746             m_normalLineMap[131072000] = 360 * 2000;    //  0.0005 deg
0747             m_normalLineMap[524288000] = 360 * 10000;  //  0.00001 deg
0748 
0749             m_boldLineMap[512000]     = 360;          // 0.1 deg
0750             m_boldLineMap[2048000]    = 720;          // 0.05 deg
0751             m_boldLineMap[8192000]   = 360 * 10;     // 0.01 deg
0752             m_boldLineMap[1638400]   = 360 * 20;     // 0.005 deg
0753             m_boldLineMap[32768000]  = 360 * 100;    // 0.001 deg
0754             m_boldLineMap[131072000]  = 360 * 200;    // 0.0005 deg
0755             m_boldLineMap[524288000] = 360 * 1000;   // 0.00001 deg
0756 
0757         break;
0758         default:
0759         case GeoDataCoordinates::DMS :            
0760             m_normalLineMap[512000]  = 360 * 6;         //  10'
0761             m_normalLineMap[1024000] = 360 * 12;        //  5'
0762             m_normalLineMap[4096000] = 360 * 60;        //  1'
0763             m_normalLineMap[8192000] = 360 * 60 * 2;    //  30"
0764             m_normalLineMap[16384000] = 360 * 60 * 6;   //  10"
0765             m_normalLineMap[65535000] = 360 * 60 * 12;  //  5"
0766             m_normalLineMap[524288000] = 360 * 60 * 60; //  1"
0767 
0768             m_boldLineMap[512000]     = 360;          // 10'
0769             m_boldLineMap[1024000]    = 720;          // 5'
0770             m_boldLineMap[4096000]   = 360 * 6;      // 1'
0771             m_boldLineMap[8192000]   = 360 * 12;     // 30"
0772             m_boldLineMap[16384000]  = 360 * 60;     // 10"
0773             m_boldLineMap[65535000]  = 360 * 60 * 2; // 5"
0774             m_boldLineMap[524288000] = 360 * 60 * 6; // 1"
0775 
0776         break;
0777     }
0778     m_normalLineMap[999999999] = m_normalLineMap.value(262144000);     //  last
0779     m_boldLineMap[999999999]   = m_boldLineMap.value(262144000);     //  last
0780 
0781     m_currentNotation = notation;
0782 }
0783 
0784 }
0785 
0786 #include "moc_GraticulePlugin.cpp"